Add more concrete error messages for missing argument list
This commit is contained in:
parent
eb3c2646a0
commit
142894c3ce
5 changed files with 75 additions and 21 deletions
|
@ -62,6 +62,7 @@ pub fn stringify_diagnostic(mut diagnostic: codespan_reporting::diagnostic::Diag
|
|||
let mut chars = Chars::box_drawing();
|
||||
chars.single_primary_caret = '─';
|
||||
config.chars = chars;
|
||||
config.chars.note_bullet = '→';
|
||||
let mut buf = Vec::new();
|
||||
let mut writer = term::termcolor::Ansi::new(&mut buf);
|
||||
let files = YUCK_FILES.read().unwrap();
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||
use simplexpr::SimplExpr;
|
||||
|
||||
use crate::{
|
||||
error::AstResult,
|
||||
error::{AstError::WrongExprType, AstResult, AstResultExt, FormFormatError},
|
||||
parser::{
|
||||
ast::Ast,
|
||||
ast_iterator::AstIterator,
|
||||
|
@ -26,11 +26,16 @@ impl FromAstElementContent for WidgetDefinition {
|
|||
const ELEMENT_NAME: &'static str = "defwidget";
|
||||
|
||||
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
||||
let (_, name) = iter.expect_symbol()?;
|
||||
let (args_span, expected_args) = iter.expect_array()?;
|
||||
let (name_span, name) = iter.expect_symbol().note(EXPECTED_WIDGET_DEF_FORMAT)?;
|
||||
let (args_span, expected_args) = iter
|
||||
.expect_array()
|
||||
.wrong_expr_type_to(|_| FormFormatError::WidgetDefArglistMissing(name_span.point_span_at_end()))
|
||||
.note(EXPECTED_WIDGET_DEF_FORMAT)?;
|
||||
let expected_args = expected_args.into_iter().map(|x| x.as_symbol().map(AttrName)).collect::<AstResult<_>>()?;
|
||||
let widget = iter.expect_any().and_then(WidgetUse::from_ast)?;
|
||||
let widget = iter.expect_any().note(EXPECTED_WIDGET_DEF_FORMAT).and_then(WidgetUse::from_ast)?;
|
||||
iter.expect_done()?;
|
||||
Ok(Self { name, expected_args, widget, span, args_span })
|
||||
}
|
||||
}
|
||||
|
||||
static EXPECTED_WIDGET_DEF_FORMAT: &str = r#"Expected format: `(defwidget name [] (contained-widgets))`"#;
|
||||
|
|
|
@ -24,6 +24,9 @@ pub enum AstError {
|
|||
#[error("Did not expect any further elements here. Make sure your format is correct")]
|
||||
NoMoreElementsExpected(Span),
|
||||
|
||||
#[error(transparent)]
|
||||
FormFormatError(#[from] FormFormatError),
|
||||
|
||||
#[error("Wrong type of expression: Expected {1} but got {2}")]
|
||||
WrongExprType(Span, AstType, AstType),
|
||||
#[error("Expected to get a value, but got {1}")]
|
||||
|
@ -77,6 +80,14 @@ impl AstError {
|
|||
) -> AstError {
|
||||
AstError::ParseError { file_id, source: err }
|
||||
}
|
||||
|
||||
pub fn wrong_expr_type_to(self, f: impl FnOnce(Span) -> FormFormatError) -> AstError {
|
||||
match self {
|
||||
AstError::WrongExprType(span, ..) => AstError::FormFormatError(f(span.point_span())),
|
||||
AstError::ErrorNote(s, err) => AstError::ErrorNote(s, Box::new(err.wrong_expr_type_to(f))),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for AstError {
|
||||
|
@ -98,6 +109,7 @@ impl Spanned for AstError {
|
|||
AstError::ErrorNote(_, err) => err.span(),
|
||||
AstError::NoMoreElementsExpected(span) => *span,
|
||||
AstError::SimplExpr(err) => err.span(),
|
||||
AstError::FormFormatError(err) => err.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,6 +137,9 @@ impl<T> OptionAstErrorExt<T> for Option<T> {
|
|||
pub trait AstResultExt<T> {
|
||||
fn context_label(self, label_span: Span, context: &str) -> AstResult<T>;
|
||||
fn note(self, note: &str) -> AstResult<T>;
|
||||
|
||||
/// Map any [AstError::WrongExprType]s error to a [FormFormatError]
|
||||
fn wrong_expr_type_to(self, f: impl FnOnce(Span) -> FormFormatError) -> AstResult<T>;
|
||||
}
|
||||
|
||||
impl<T> AstResultExt<T> for AstResult<T> {
|
||||
|
@ -135,4 +150,22 @@ impl<T> AstResultExt<T> for AstResult<T> {
|
|||
fn note(self, note: &str) -> AstResult<T> {
|
||||
self.map_err(|e| e.note(note))
|
||||
}
|
||||
|
||||
fn wrong_expr_type_to(self, f: impl FnOnce(Span) -> FormFormatError) -> AstResult<T> {
|
||||
self.map_err(|err| err.wrong_expr_type_to(f))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FormFormatError {
|
||||
#[error("Widget definition missing argument list")]
|
||||
WidgetDefArglistMissing(Span),
|
||||
}
|
||||
|
||||
impl Spanned for FormFormatError {
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
FormFormatError::WidgetDefArglistMissing(span) => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use diagnostic::*;
|
|||
|
||||
use crate::{
|
||||
config::{attributes::AttrError, config, validate::ValidationError},
|
||||
error::{get_parse_error_span, AstError},
|
||||
error::{get_parse_error_span, AstError, FormFormatError},
|
||||
};
|
||||
|
||||
use super::parser::parse_error;
|
||||
|
@ -124,6 +124,7 @@ impl ToDiagnostic for AstError {
|
|||
AstError::ValidationError(source) => source.to_diagnostic(),
|
||||
AstError::NoMoreElementsExpected(span) => gen_diagnostic!(self, span),
|
||||
AstError::SimplExpr(source) => source.to_diagnostic(),
|
||||
AstError::FormFormatError(error) => error.to_diagnostic(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -246,3 +247,15 @@ fn generate_lexical_error_diagnostic(span: Span) -> Diagnostic<usize> {
|
|||
label = span => "Invalid token"
|
||||
}
|
||||
}
|
||||
|
||||
impl ToDiagnostic for FormFormatError {
|
||||
fn to_diagnostic(&self) -> diagnostic::Diagnostic<usize> {
|
||||
match self {
|
||||
FormFormatError::WidgetDefArglistMissing(span) => gen_diagnostic! {
|
||||
msg = self,
|
||||
label = span => "Insert the argument list (e.g.: `[]`) here",
|
||||
note = "This list will in the future need to declare all the non-global variables / attributes used in this widget.\nThis is not yet neccessary, but is still considered good style.",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,28 +20,30 @@ pub struct AstIterator<I: Iterator<Item = Ast>> {
|
|||
}
|
||||
|
||||
macro_rules! return_or_put_back {
|
||||
($name:ident, $expr_type:expr, $t:ty = $p:pat => $ret:expr) => {
|
||||
pub fn $name(&mut self) -> AstResult<$t> {
|
||||
let expr_type = $expr_type;
|
||||
match self.expect_any()? {
|
||||
$p => Ok($ret),
|
||||
other => {
|
||||
let span = other.span();
|
||||
let actual_type = other.expr_type();
|
||||
self.put_back(other);
|
||||
Err(AstError::WrongExprType(span, expr_type, actual_type))
|
||||
($(fn $name:ident -> $expr_type:expr, $t:ty = $p:pat => $ret:expr)*) => {
|
||||
$(
|
||||
pub fn $name(&mut self) -> AstResult<$t> {
|
||||
let expr_type = $expr_type;
|
||||
match self.expect_any()? {
|
||||
$p => Ok($ret),
|
||||
other => {
|
||||
let span = other.span();
|
||||
let actual_type = other.expr_type();
|
||||
self.put_back(other);
|
||||
Err(AstError::WrongExprType(span, expr_type, actual_type))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl<I: Iterator<Item = Ast>> AstIterator<I> {
|
||||
return_or_put_back!(expect_symbol, AstType::Symbol, (Span, String) = Ast::Symbol(span, x) => (span, x));
|
||||
|
||||
return_or_put_back!(expect_list, AstType::List, (Span, Vec<Ast>) = Ast::List(span, x) => (span, x));
|
||||
|
||||
return_or_put_back!(expect_array, AstType::Array, (Span, Vec<Ast>) = Ast::Array(span, x) => (span, x));
|
||||
return_or_put_back! {
|
||||
fn expect_symbol -> AstType::Symbol, (Span, String) = Ast::Symbol(span, x) => (span, x)
|
||||
fn expect_list -> AstType::List, (Span, Vec<Ast>) = Ast::List(span, x) => (span, x)
|
||||
fn expect_array -> AstType::Array, (Span, Vec<Ast>) = Ast::Array(span, x) => (span, x)
|
||||
}
|
||||
|
||||
pub fn expect_literal(&mut self) -> AstResult<(Span, DynVal)> {
|
||||
// TODO add some others
|
||||
|
|
Loading…
Add table
Reference in a new issue