Add more concrete error messages for missing argument list

This commit is contained in:
elkowar 2021-08-02 16:35:43 +02:00
parent eb3c2646a0
commit 142894c3ce
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F
5 changed files with 75 additions and 21 deletions

View file

@ -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();

View file

@ -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))`"#;

View file

@ -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,
}
}
}

View file

@ -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.",
},
}
}
}

View file

@ -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