From 142894c3ce65fca7e823188aaad4a16b2b5c6dee Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Mon, 2 Aug 2021 16:35:43 +0200 Subject: [PATCH] Add more concrete error messages for missing argument list --- crates/eww/src/error_handling_ctx.rs | 1 + crates/yuck/src/config/widget_definition.rs | 13 +++++--- crates/yuck/src/error.rs | 33 ++++++++++++++++++++ crates/yuck/src/format_diagnostic.rs | 15 ++++++++- crates/yuck/src/parser/ast_iterator.rs | 34 +++++++++++---------- 5 files changed, 75 insertions(+), 21 deletions(-) diff --git a/crates/eww/src/error_handling_ctx.rs b/crates/eww/src/error_handling_ctx.rs index dd0d2fb..af05638 100644 --- a/crates/eww/src/error_handling_ctx.rs +++ b/crates/eww/src/error_handling_ctx.rs @@ -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(); diff --git a/crates/yuck/src/config/widget_definition.rs b/crates/yuck/src/config/widget_definition.rs index 6dea6ee..4aaf41b 100644 --- a/crates/yuck/src/config/widget_definition.rs +++ b/crates/yuck/src/config/widget_definition.rs @@ -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>(span: Span, mut iter: AstIterator) -> AstResult { - 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::>()?; - 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))`"#; diff --git a/crates/yuck/src/error.rs b/crates/yuck/src/error.rs index c12756c..76c9972 100644 --- a/crates/yuck/src/error.rs +++ b/crates/yuck/src/error.rs @@ -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 OptionAstErrorExt for Option { pub trait AstResultExt { fn context_label(self, label_span: Span, context: &str) -> AstResult; fn note(self, note: &str) -> AstResult; + + /// Map any [AstError::WrongExprType]s error to a [FormFormatError] + fn wrong_expr_type_to(self, f: impl FnOnce(Span) -> FormFormatError) -> AstResult; } impl AstResultExt for AstResult { @@ -135,4 +150,22 @@ impl AstResultExt for AstResult { fn note(self, note: &str) -> AstResult { self.map_err(|e| e.note(note)) } + + fn wrong_expr_type_to(self, f: impl FnOnce(Span) -> FormFormatError) -> AstResult { + 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, + } + } } diff --git a/crates/yuck/src/format_diagnostic.rs b/crates/yuck/src/format_diagnostic.rs index c9b82dd..58a192a 100644 --- a/crates/yuck/src/format_diagnostic.rs +++ b/crates/yuck/src/format_diagnostic.rs @@ -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 { label = span => "Invalid token" } } + +impl ToDiagnostic for FormFormatError { + fn to_diagnostic(&self) -> diagnostic::Diagnostic { + 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.", + }, + } + } +} diff --git a/crates/yuck/src/parser/ast_iterator.rs b/crates/yuck/src/parser/ast_iterator.rs index d2db491..f1e9414 100644 --- a/crates/yuck/src/parser/ast_iterator.rs +++ b/crates/yuck/src/parser/ast_iterator.rs @@ -20,28 +20,30 @@ pub struct AstIterator> { } 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> AstIterator { - 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::List(span, x) => (span, x)); - - return_or_put_back!(expect_array, AstType::Array, (Span, Vec) = 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::List(span, x) => (span, x) + fn expect_array -> AstType::Array, (Span, Vec) = Ast::Array(span, x) => (span, x) + } pub fn expect_literal(&mut self) -> AstResult<(Span, DynVal)> { // TODO add some others