From 6f1118bda4fe49b0aa30235a4d447a9b3f11dd66 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Wed, 28 Jul 2021 19:58:51 +0200 Subject: [PATCH] Improve error messages for unread elements in nodes and fix span handling in ast iterator --- .../yuck/src/config/backend_window_options.rs | 1 + crates/yuck/src/config/config.rs | 1 + .../yuck/src/config/script_var_definition.rs | 2 + crates/yuck/src/config/var_definition.rs | 1 + crates/yuck/src/config/widget_definition.rs | 3 +- crates/yuck/src/config/window_definition.rs | 3 +- crates/yuck/src/config/window_geometry.rs | 1 + crates/yuck/src/error.rs | 3 + crates/yuck/src/format_diagnostic.rs | 1 + crates/yuck/src/parser/ast_iterator.rs | 31 +++++--- crates/yuck/src/parser/from_ast.rs | 4 +- examples/eww-bar/eww.yuck | 73 ++++++++++--------- 12 files changed, 74 insertions(+), 50 deletions(-) diff --git a/crates/yuck/src/config/backend_window_options.rs b/crates/yuck/src/config/backend_window_options.rs index 6165a46..d5ced8f 100644 --- a/crates/yuck/src/config/backend_window_options.rs +++ b/crates/yuck/src/config/backend_window_options.rs @@ -98,6 +98,7 @@ mod backend { fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { let mut attrs = iter.expect_key_values()?; + iter.expect_done().map_err(|e| e.note("Check if you are missing a colon in front of a key"))?; Ok(StrutDefinition { side: attrs.primitive_required("side")?, dist: attrs.primitive_required("distance")? }) } } diff --git a/crates/yuck/src/config/config.rs b/crates/yuck/src/config/config.rs index 25e7ac9..9e94cb0 100644 --- a/crates/yuck/src/config/config.rs +++ b/crates/yuck/src/config/config.rs @@ -38,6 +38,7 @@ impl FromAstElementContent for Include { fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { let (path_span, path) = iter.expect_literal()?; + iter.expect_done()?; Ok(Include { path: path.to_string(), path_span }) } } diff --git a/crates/yuck/src/config/script_var_definition.rs b/crates/yuck/src/config/script_var_definition.rs index 862c323..176c50e 100644 --- a/crates/yuck/src/config/script_var_definition.rs +++ b/crates/yuck/src/config/script_var_definition.rs @@ -62,6 +62,7 @@ impl FromAstElementContent for PollScriptVar { let mut attrs = iter.expect_key_values()?; let interval = attrs.primitive_required::("interval")?.as_duration()?; let (script_span, script) = iter.expect_literal()?; + iter.expect_done()?; Ok(Self { name: VarName(name), command: VarSource::Shell(script_span, script.to_string()), interval }) } } @@ -80,6 +81,7 @@ impl FromAstElementContent for ListenScriptVar { fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { let (_, name) = iter.expect_symbol()?; let (command_span, script) = iter.expect_literal()?; + iter.expect_done()?; Ok(Self { name: VarName(name), command: script.to_string(), command_span }) } } diff --git a/crates/yuck/src/config/var_definition.rs b/crates/yuck/src/config/var_definition.rs index 065820d..cd39a8e 100644 --- a/crates/yuck/src/config/var_definition.rs +++ b/crates/yuck/src/config/var_definition.rs @@ -27,6 +27,7 @@ impl FromAstElementContent for VarDefinition { fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { let (_, name) = iter.expect_symbol()?; let (_, initial_value) = iter.expect_literal()?; + iter.expect_done()?; Ok(Self { name: VarName(name), initial_value, span }) } } diff --git a/crates/yuck/src/config/widget_definition.rs b/crates/yuck/src/config/widget_definition.rs index 641f587..02d6fdb 100644 --- a/crates/yuck/src/config/widget_definition.rs +++ b/crates/yuck/src/config/widget_definition.rs @@ -32,8 +32,7 @@ impl FromAstElementContent for WidgetDefinition { let (args_span, expected_args) = iter.expect_array()?; 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)?; - // TODO verify that this was the last element in the list - // iter.expect_done()?; + iter.expect_done()?; Ok(Self { name, expected_args, widget, span, args_span }) } } diff --git a/crates/yuck/src/config/window_definition.rs b/crates/yuck/src/config/window_definition.rs index 8687455..58726ea 100644 --- a/crates/yuck/src/config/window_definition.rs +++ b/crates/yuck/src/config/window_definition.rs @@ -39,7 +39,8 @@ impl FromAstElementContent for WindowDefinition { let stacking = attrs.primitive_optional("stacking")?.unwrap_or(WindowStacking::Foreground); let geometry = attrs.ast_optional("geometry")?; let backend_options = BackendWindowOptions::from_attrs(&mut attrs)?; - let widget = iter.expect_any()?; + let widget = iter.expect_any().and_then(WidgetUse::from_ast)?; + iter.expect_done()?; Ok(Self { name, monitor_number, resizable, widget, stacking, geometry, backend_options }) } } diff --git a/crates/yuck/src/config/window_geometry.rs b/crates/yuck/src/config/window_geometry.rs index 4245ab0..49a5059 100644 --- a/crates/yuck/src/config/window_geometry.rs +++ b/crates/yuck/src/config/window_geometry.rs @@ -123,6 +123,7 @@ impl FromAstElementContent for WindowGeometry { fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { let mut attrs = iter.expect_key_values()?; + iter.expect_done().map_err(|e| e.note("Check if you are missing a colon in front of a key"))?; Ok(WindowGeometry { anchor_point: attrs.primitive_optional("anchor")?.unwrap_or_default(), size: Coords { diff --git a/crates/yuck/src/error.rs b/crates/yuck/src/error.rs index ad0db1c..22ea68e 100644 --- a/crates/yuck/src/error.rs +++ b/crates/yuck/src/error.rs @@ -21,6 +21,8 @@ pub enum AstError { MissingNode(Span), #[error("Too many elements, must be exactly {1}")] TooManyNodes(Span, i32), + #[error("Did not expect any further elements here. Make sure your format is correct")] + NoMoreElementsExpected(Span), #[error("Wrong type of expression: Expected {1} but got {2}")] WrongExprType(Span, AstType, AstType), @@ -91,6 +93,7 @@ impl Spanned for AstError { AstError::ValidationError(error) => error.span(), AstError::ParseError { file_id, source } => get_parse_error_span(*file_id, source), AstError::ErrorNote(_, err) => err.span(), + AstError::NoMoreElementsExpected(span) => *span, } } } diff --git a/crates/yuck/src/format_diagnostic.rs b/crates/yuck/src/format_diagnostic.rs index ea35525..1f7237f 100644 --- a/crates/yuck/src/format_diagnostic.rs +++ b/crates/yuck/src/format_diagnostic.rs @@ -117,6 +117,7 @@ impl ToDiagnostic for AstError { }, AstError::ErrorNote(note, source) => source.to_diagnostic().with_notes(vec![note.to_string()]), AstError::ValidationError(source) => source.to_diagnostic(), + AstError::NoMoreElementsExpected(span) => gen_diagnostic!(self, span), } } } diff --git a/crates/yuck/src/parser/ast_iterator.rs b/crates/yuck/src/parser/ast_iterator.rs index e8983c6..aebe312 100644 --- a/crates/yuck/src/parser/ast_iterator.rs +++ b/crates/yuck/src/parser/ast_iterator.rs @@ -24,15 +24,11 @@ macro_rules! return_or_put_back { pub fn $name(&mut self) -> AstResult<$t> { let expr_type = $expr_type; match self.expect_any()? { - $p => { - let (span, value) = $ret; - self.remaining_span.1 = span.1; - Ok((span, value)) - } + $p => Ok($ret), other => { let span = other.span(); let actual_type = other.expr_type(); - self.iter.put_back(other); + self.put_back(other); Err(AstError::WrongExprType(span, expr_type, actual_type)) } } @@ -53,20 +49,37 @@ impl> AstIterator { AstIterator { remaining_span: span, iter: itertools::put_back(iter) } } - pub fn expect_any(&mut self) -> AstResult { - self.iter.next().or_missing(self.remaining_span.point_span()).and_then(T::from_ast) + pub fn expect_any(&mut self) -> AstResult { + self.next().or_missing(self.remaining_span.point_span()) + } + + pub fn expect_done(&mut self) -> AstResult<()> { + if let Some(next) = self.next() { + self.put_back(next); + Err(AstError::NoMoreElementsExpected(self.remaining_span)) + } else { + Ok(()) + } } pub fn expect_key_values(&mut self) -> AstResult { parse_key_values(self) } + + pub fn put_back(&mut self, ast: Ast) { + self.remaining_span.0 = ast.span().0; + self.iter.put_back(ast) + } } impl> Iterator for AstIterator { type Item = Ast; fn next(&mut self) -> Option { - self.iter.next() + self.iter.next().map(|x| { + self.remaining_span.0 = x.span().1; + x + }) } } diff --git a/crates/yuck/src/parser/from_ast.rs b/crates/yuck/src/parser/from_ast.rs index b5f44fd..acff1ef 100644 --- a/crates/yuck/src/parser/from_ast.rs +++ b/crates/yuck/src/parser/from_ast.rs @@ -39,9 +39,9 @@ impl FromAst for T { fn from_ast(e: Ast) -> AstResult { let span = e.span(); let mut iter = e.try_ast_iter()?; - let (_, element_name) = iter.expect_symbol()?; + let (element_name_span, element_name) = iter.expect_symbol()?; if Self::get_element_name() != element_name { - return Err(AstError::MismatchedElementName(span, Self::get_element_name().to_string(), element_name)); + return Err(AstError::MismatchedElementName(element_name_span, Self::get_element_name().to_string(), element_name)); } Self::from_tail(span, iter) } diff --git a/examples/eww-bar/eww.yuck b/examples/eww-bar/eww.yuck index 8ead5d1..ecfa3c2 100644 --- a/examples/eww-bar/eww.yuck +++ b/examples/eww-bar/eww.yuck @@ -1,45 +1,44 @@ (defwidget bar [] - (box :orientation "h" :hexpand true - (workspaces) - (music) - (sidestuff))) - + (box :orientation "h" :hexpand true + (workspaces) + (music) + (sidestuff))) (defwidget sidestuff [] - (box :class "sidestuff" :orientation "h" :space-evenly false :halign "end" - (slider-vol) - (slider-ram) - (time))) + (box :class "sidestuff" :orientation "h" :space-evenly false :halign "end" + (slider-vol) + (slider-ram) + (time))) (defwidget workspaces [] - (box :class "workspaces" :orientation "h" :space-evenly true :halign "start" - (button :onclick "wmctrl -s 0" 1) - (button :onclick "wmctrl -s 1" 2) - (button :onclick "wmctrl -s 2" 3) - (button :onclick "wmctrl -s 3" 4) - (button :onclick "wmctrl -s 4" 5) - (button :onclick "wmctrl -s 5" 6) - (button :onclick "wmctrl -s 6" 7) - (button :onclick "wmctrl -s 7" 8) - (button :onclick "wmctrl -s 8" 9))) + (box :class "workspaces" :orientation "h" :space-evenly true :halign "start" + (button :onclick "wmctrl -s 0" 1) + (button :onclick "wmctrl -s 1" 2) + (button :onclick "wmctrl -s 2" 3) + (button :onclick "wmctrl -s 3" 4) + (button :onclick "wmctrl -s 4" 5) + (button :onclick "wmctrl -s 5" 6) + (button :onclick "wmctrl -s 6" 7) + (button :onclick "wmctrl -s 7" 8) + (button :onclick "wmctrl -s 8" 9))) (defwidget music [] - (box :class "music" :orientation "h" :space-evenly false :halign "center" - { ' ' + music})) + (box :class "music" :orientation "h" :space-evenly false :halign "center" + { ' ' + music})) (defwidget slider-vol [] - (box :class "slider-vol" :orientation "h" :space-evenly "false" - (box :class "label-vol" "" - (scale :min 0 :max 101 :value volume :onchange "amixer -D pulse sset Master {}%")))) + (box :class "slider-vol" :orientation "h" :space-evenly "false" + (box :class "label-vol" "" + (scale :min 0 :max 101 :value volume :onchange "amixer -D pulse sset Master {}%")))) (defwidget slider-ram [] - (box :orientation "h" :class "slider-ram" :space-evenly false - (box :class "label-ram" "" - (scale :min 0 :max 101 :active false :value EWW_RAM)))) + (box :orientation "h" :class "slider-ram" :space-evenly false + (box :class "label-ram" "" + (scale :min 0 :max 101 :active false :value EWW_RAM)))) (defwidget time [] - (box :class "time" - {hour + ":" + min + " " + month + " " + number_day + ", " + year_full})) + (box :class "time" + {hour + ":" + min + " " + month + " " + number_day + ", " + year_full})) (defpoll music :interval "5s" "playerctl metadata --format '{{ artist }} - {{ title }}' || true") @@ -51,12 +50,14 @@ (defpoll hour :interval "1m" "date '+%H'") (defpoll year_full :interval "15h" "date '+%Y'") -(deflisten battery-remaining "/sys/class/power_supply/BAT0/capacity") +(deflisten battery-remaining "tail -f /sys/class/power_supply/BAT0/capacity") (defwindow bar - :screen 0 - :focusable true - :windowtype "dock" - :geometry (geometry :x "0%" :y "0%" :width "100%" :height "4%") - :reserve (struts :side "top" :distance "4%") - (bar)) + :screen 0 + :focusable true + :windowtype "dock" + :geometry (geometry :x "0%" :y "0%" :width "100%" :height "4%") + :reserve (struts :side "top" :distance "4%") + (bar)) + +; asdf