diff --git a/examples/errors.rs b/examples/errors.rs index f86bf68..a5b26ba 100644 --- a/examples/errors.rs +++ b/examples/errors.rs @@ -1,20 +1,20 @@ -use eww_config::{ - format_diagnostic::ToDiagnostic, - parser::{ast::*, from_ast::FromAst}, -}; +// use eww_config::{ +// format_diagnostic::ToDiagnostic, +// parser::{ast::*, from_ast::FromAst}, +//}; fn main() { - let mut files = codespan_reporting::files::SimpleFiles::new(); + // let mut files = codespan_reporting::files::SimpleFiles::new(); - let input = r#" - (heyho ; :foo { "foo \" } bar " } - ; :baz {(foo == bar ? 12.2 : 12)} - (foo) - (defwidget foo [something bla] "foo") - (baz))"#; + // let input = r#" + //(heyho ; :foo { "foo \" } bar " } + //; :baz {(foo == bar ? 12.2 : 12)} + //(foo) + //(defwidget foo [something bla] "foo") + //(baz))"#; - let file_id = files.add("foo.eww", input); - let ast = eww_config::parser::parse_string(file_id, input); + // let file_id = files.add("foo.eww", input); + // let ast = eww_config::parser::parse_string(file_id, input); // match ast.and_then(eww_config::parser::from_ast::Element::::from_ast) { // Ok(ast) => { // println!("{:?}", ast); diff --git a/src/config/config.rs b/src/config/config.rs index 556c850..b969b4f 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -14,7 +14,6 @@ use crate::{ ast_iterator::AstIterator, from_ast::{FromAst, FromAstElementContent}, }, - spanned, value::{AttrName, VarName}, }; @@ -28,25 +27,19 @@ pub enum TopLevel { impl FromAst for TopLevel { fn from_ast(e: Ast) -> AstResult { let span = e.span(); - spanned!(e.span(), { - let mut iter = e.try_ast_iter()?; - let (sym_span, element_name) = iter.expect_symbol()?; - match element_name.as_str() { - x if x == WidgetDefinition::get_element_name() => { - Self::WidgetDefinition(WidgetDefinition::from_tail(span, iter)?) - } - x if x == VarDefinition::get_element_name() => Self::VarDefinition(VarDefinition::from_tail(span, iter)?), - x if x == PollScriptVar::get_element_name() => { - Self::ScriptVarDefinition(ScriptVarDefinition::Poll(PollScriptVar::from_tail(span, iter)?)) - } - x if x == TailScriptVar::get_element_name() => { - Self::ScriptVarDefinition(ScriptVarDefinition::Tail(TailScriptVar::from_tail(span, iter)?)) - } - x if x == WindowDefinition::get_element_name() => { - Self::WindowDefinition(WindowDefinition::from_tail(span, iter)?) - } - x => return Err(AstError::UnknownToplevel(Some(sym_span), x.to_string())), + let mut iter = e.try_ast_iter()?; + let (sym_span, element_name) = iter.expect_symbol()?; + Ok(match element_name.as_str() { + x if x == WidgetDefinition::get_element_name() => Self::WidgetDefinition(WidgetDefinition::from_tail(span, iter)?), + x if x == VarDefinition::get_element_name() => Self::VarDefinition(VarDefinition::from_tail(span, iter)?), + x if x == PollScriptVar::get_element_name() => { + Self::ScriptVarDefinition(ScriptVarDefinition::Poll(PollScriptVar::from_tail(span, iter)?)) } + x if x == TailScriptVar::get_element_name() => { + Self::ScriptVarDefinition(ScriptVarDefinition::Tail(TailScriptVar::from_tail(span, iter)?)) + } + x if x == WindowDefinition::get_element_name() => Self::WindowDefinition(WindowDefinition::from_tail(span, iter)?), + x => return Err(AstError::UnknownToplevel(sym_span, x.to_string())), }) } } diff --git a/src/config/script_var_definition.rs b/src/config/script_var_definition.rs index 4089cda..2d12424 100644 --- a/src/config/script_var_definition.rs +++ b/src/config/script_var_definition.rs @@ -9,7 +9,6 @@ use crate::{ ast_iterator::AstIterator, from_ast::{FromAst, FromAstElementContent}, }, - spanned, value::{AttrName, VarName}, }; @@ -50,8 +49,8 @@ impl FromAstElementContent for PollScriptVar { fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { let (_, name) = iter.expect_symbol()?; let mut attrs = iter.expect_key_values()?; - let interval: String = attrs.primitive_required("interval")?; - let interval = crate::util::parse_duration(&interval).map_err(|e| AstError::Other(Some(span), e.into()))?; + let interval = attrs.primitive_required::("interval")?.as_duration()?; + // let interval = interval.as_duration()?; let (_, script) = iter.expect_literal()?; Ok(Self { name: VarName(name), command: VarSource::Shell(script.to_string()), interval }) } diff --git a/src/config/validate.rs b/src/config/validate.rs index e4ca804..153656a 100644 --- a/src/config/validate.rs +++ b/src/config/validate.rs @@ -9,7 +9,6 @@ use crate::{ ast_iterator::AstIterator, from_ast::FromAst, }, - spanned, value::{AttrName, VarName}, }; diff --git a/src/config/var_definition.rs b/src/config/var_definition.rs index 29d5364..da458d5 100644 --- a/src/config/var_definition.rs +++ b/src/config/var_definition.rs @@ -9,7 +9,6 @@ use crate::{ ast_iterator::AstIterator, from_ast::{FromAst, FromAstElementContent}, }, - spanned, value::{AttrName, VarName}, }; diff --git a/src/config/widget_definition.rs b/src/config/widget_definition.rs index 7418a71..b7bf2d9 100644 --- a/src/config/widget_definition.rs +++ b/src/config/widget_definition.rs @@ -9,7 +9,6 @@ use crate::{ ast_iterator::AstIterator, from_ast::{FromAst, FromAstElementContent}, }, - spanned, value::{AttrName, VarName}, }; diff --git a/src/config/widget_use.rs b/src/config/widget_use.rs index 6ce0332..78a6cfc 100644 --- a/src/config/widget_use.rs +++ b/src/config/widget_use.rs @@ -10,7 +10,6 @@ use crate::{ ast_iterator::AstIterator, from_ast::FromAst, }, - spanned, value::AttrName, }; @@ -27,29 +26,27 @@ pub struct WidgetUse { impl FromAst for WidgetUse { fn from_ast(e: Ast) -> AstResult { let span = e.span(); - spanned!(e.span(), { - if let Ok(text) = e.as_literal_ref() { - Self { - name: "text".to_string(), - attrs: Attributes::new( - span.into(), - maplit::hashmap! { - AttrName("text".to_string()) => AttrEntry::new( - span.into(), - Ast::Literal(span.into(), text.clone()) - ) - }, - ), - children: Vec::new(), - span, - } - } else { - let mut iter = e.try_ast_iter()?; - let (_, name) = iter.expect_symbol()?; - let attrs = iter.expect_key_values()?; - let children = iter.map(WidgetUse::from_ast).collect::>>()?; - Self { name, attrs, children, span } - } - }) + if let Ok(text) = e.as_literal_ref() { + Ok(Self { + name: "text".to_string(), + attrs: Attributes::new( + span.into(), + maplit::hashmap! { + AttrName("text".to_string()) => AttrEntry::new( + span.into(), + Ast::Literal(span.into(), text.clone()) + ) + }, + ), + children: Vec::new(), + span, + }) + } else { + let mut iter = e.try_ast_iter()?; + let (_, name) = iter.expect_symbol()?; + let attrs = iter.expect_key_values()?; + let children = iter.map(WidgetUse::from_ast).collect::>>()?; + Ok(Self { name, attrs, children, span }) + } } } diff --git a/src/config/window_definition.rs b/src/config/window_definition.rs index 1ae9c99..f49f940 100644 --- a/src/config/window_definition.rs +++ b/src/config/window_definition.rs @@ -9,7 +9,6 @@ use crate::{ ast_iterator::AstIterator, from_ast::{FromAst, FromAstElementContent}, }, - spanned, value::{AttrName, NumWithUnit, VarName}, }; diff --git a/src/config/window_geometry.rs b/src/config/window_geometry.rs index db9f93d..16aac88 100644 --- a/src/config/window_geometry.rs +++ b/src/config/window_geometry.rs @@ -5,7 +5,7 @@ use simplexpr::{dynval::DynVal, SimplExpr}; use crate::{enum_parse, error::{AstError, AstResult}, parser::{ ast::{Ast, Span}, ast_iterator::AstIterator, from_ast::{FromAst, FromAstElementContent}, - }, spanned, value::{AttrName, Coords, VarName}}; + }, value::{AttrName, Coords, VarName}}; use super::{widget_use::WidgetUse, window_definition::EnumParseError}; use serde::{Serialize, Deserialize}; diff --git a/src/error.rs b/src/error.rs index 53126f9..ac99e07 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,6 +6,7 @@ use crate::{ }, }; use codespan_reporting::{diagnostic, files}; +use simplexpr::dynval; use thiserror::Error; pub type AstResult = Result; @@ -13,15 +14,18 @@ pub type AstResult = Result; #[derive(Debug, Error)] pub enum AstError { #[error("Unknown toplevel declaration `{1}`")] - UnknownToplevel(Option, String), + UnknownToplevel(Span, String), #[error("Expected another element, but got nothing")] - MissingNode(Option), + MissingNode(Span), #[error("Wrong type of expression: Expected {1} but got {2}")] - WrongExprType(Option, AstType, AstType), + WrongExprType(Span, AstType, AstType), #[error("Expected to get a value, but got {1}")] - NotAValue(Option, AstType), + NotAValue(Span, AstType), #[error("Expected element {1}, but read {2}")] - MismatchedElementName(Option, String, String), + MismatchedElementName(Span, String, String), + + #[error(transparent)] + ConversionError(#[from] dynval::ConversionError), #[error("{1}")] Other(Option, Box), @@ -29,13 +33,6 @@ pub enum AstError { #[error(transparent)] AttrError(#[from] AttrError), - //#[error("{msg}: {source}")] - // Context { - // span: Option, - //#[source] - // source: Box, - // msg: String, - //}, #[error(transparent)] ValidationError(#[from] ValidationError), @@ -46,14 +43,14 @@ pub enum AstError { impl AstError { pub fn get_span(&self) -> Option { match self { - AstError::UnknownToplevel(span, _) => *span, - AstError::MissingNode(span) => *span, - AstError::WrongExprType(span, ..) => *span, - AstError::NotAValue(span, ..) => *span, - AstError::MismatchedElementName(span, ..) => *span, + AstError::UnknownToplevel(span, _) => Some(*span), + AstError::MissingNode(span) => Some(*span), + AstError::WrongExprType(span, ..) => Some(*span), + AstError::NotAValue(span, ..) => Some(*span), + AstError::MismatchedElementName(span, ..) => Some(*span), AstError::AttrError(err) => Some(err.span()), AstError::Other(span, ..) => *span, - // AstError::Context { span, .. } => *span, + AstError::ConversionError(err) => err.value.span().map(|x| x.into()), AstError::ValidationError(error) => None, // TODO none here is stupid AstError::ParseError { file_id, source } => file_id.and_then(|id| get_parse_error_span(id, source)), } @@ -83,55 +80,25 @@ fn get_parse_error_span( } } -pub fn spanned(span: Span, err: impl Into) -> AstError { - use AstError::*; - match err.into() { - UnknownToplevel(None, x) => UnknownToplevel(Some(span), x), - MissingNode(None) => MissingNode(Some(span)), - WrongExprType(None, x, y) => WrongExprType(Some(span), x, y), - UnknownToplevel(None, x) => UnknownToplevel(Some(span), x), - MissingNode(None) => MissingNode(Some(span)), - NotAValue(None, x) => NotAValue(Some(span), x), - MismatchedElementName(None, x, y) => MismatchedElementName(Some(span), x, y), - // Context { span: None, source, msg } => Context { span: Some(span), source, msg }, - Other(None, x) => Other(Some(span), x), - x => x, - } -} - -pub trait OptionAstErrorExt { - fn or_missing(self) -> Result; -} -impl OptionAstErrorExt for Option { - fn or_missing(self) -> Result { - self.ok_or(AstError::MissingNode(None)) - } -} - -pub trait AstResultExt { - fn at(self, span: Span) -> Result; -} - -pub trait Context { - fn context(self, span: Span, msg: String) -> Result; -} - -impl> AstResultExt for Result { - fn at(self, span: Span) -> Result { - self.map_err(|err| spanned(span, err)) - } -} - -// impl Context for Result { -// fn context(self, span: Span, msg: String) -> Result { -// self.map_err(|x| AstError::Context { msg, span: Some(span), source: Box::new(x) }) +// pub fn spanned(span: Span, err: impl Into) -> AstError { +// use AstError::*; +// match err.into() { +// UnknownToplevel(s, x) => UnknownToplevel(Some(s.unwrap_or(span)), x), +// MissingNode(s) => MissingNode(Some(s.unwrap_or(span))), +// WrongExprType(s, x, y) => WrongExprType(Some(s.unwrap_or(span)), x, y), +// UnknownToplevel(s, x) => UnknownToplevel(Some(s.unwrap_or(span)), x), +// MissingNode(s) => MissingNode(Some(s.unwrap_or(span))), +// NotAValue(s, x) => NotAValue(Some(s.unwrap_or(span)), x), +// MismatchedElementName(s, expected, got) => MismatchedElementName(Some(s.unwrap_or(span)), expected, got), +// Other(s, x) => Other(Some(s.unwrap_or(span)), x), +// x @ ConversionError(_) | x @ AttrError(_) | x @ ValidationError(_) | x @ ParseError { .. } => x, //} -#[macro_export] -macro_rules! spanned { - ($span:expr, $block:expr) => {{ - let span = $span; - let result: Result<_, crate::error::AstError> = try { $block }; - crate::error::AstResultExt::at(result, span) - }}; +pub trait OptionAstErrorExt { + fn or_missing(self, span: Span) -> Result; +} +impl OptionAstErrorExt for Option { + fn or_missing(self, span: Span) -> Result { + self.ok_or(AstError::MissingNode(span)) + } } diff --git a/src/format_diagnostic.rs b/src/format_diagnostic.rs index 6ad8f8f..a1238c3 100644 --- a/src/format_diagnostic.rs +++ b/src/format_diagnostic.rs @@ -14,7 +14,7 @@ macro_rules! gen_diagnostic { $(, note = $note:expr)? $(,)? ) => { Diagnostic::error() - $(.with_message($msg))? + $(.with_message($msg.to_string()))? $(.with_labels(vec![ Label::primary($span.2, $span.0..$span.1) $(.with_message($label))? @@ -23,7 +23,7 @@ macro_rules! gen_diagnostic { }; ($msg:expr $(, $span:expr $(,)?)?) => {{ Diagnostic::error() - .with_message($msg) + .with_message($msg.to_string()) $(.with_labels(vec![Label::primary($span.2, $span.0..$span.1)]))? }}; } @@ -64,7 +64,7 @@ impl ToDiagnostic for AstError { note = format!("Expected: {}\nGot: {}", expected, actual), }, AstError::NotAValue(_, actual) => gen_diagnostic! { - msg = format!("Expected value, but got {}", actual), + msg = format!("Expected value, but got `{}`", actual), label = span => "Expected some value here", note = format!("Got: {}", actual), }, @@ -73,7 +73,15 @@ impl ToDiagnostic for AstError { parse_error::ParseError::SimplExpr(_, error) => simplexpr_error_to_diagnostic(error, span), parse_error::ParseError::LexicalError(_) => lexical_error_to_diagnostic(span), }), - _ => panic!(), + AstError::MismatchedElementName(_, expected, got) => gen_diagnostic! { + msg = format!("Expected element `{}`, but found `{}`", expected, got), + label = span => format!("Expected `{}` here", expected), + note = format!("Expected: {}\nGot: {}", expected, got), + }, + AstError::ConversionError(err) => conversion_error_to_diagnostic(err, span), + AstError::Other(_, source) => gen_diagnostic!(source, span), + AstError::AttrError(source) => gen_diagnostic!(source, span), + AstError::ValidationError(_) => todo!(), } } else { Diagnostic::error().with_message(format!("{}", self)) @@ -107,9 +115,9 @@ fn simplexpr_error_to_diagnostic(error: &simplexpr::error::Error, span: Span) -> match error { ParseError { source, .. } => lalrpop_error_to_diagnostic(source, span, move |error| lexical_error_to_diagnostic(span)), ConversionError(error) => conversion_error_to_diagnostic(error, span), - Eval(error) => gen_diagnostic!(format!("{}", error), span), - Other(error) => gen_diagnostic!(format!("{}", error), span), - Spanned(_, error) => gen_diagnostic!(format!("{}", error), span), + Eval(error) => gen_diagnostic!(error, span), + Other(error) => gen_diagnostic!(error, span), + Spanned(_, error) => gen_diagnostic!(error, span), } } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index eb0b45a..24a6abc 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -92,14 +92,14 @@ macro_rules! as_func { pub fn $name(self) -> Result<$t, AstError> { match self { $p => Ok($value), - x => Err(AstError::WrongExprType(Some(x.span()), $exprtype, x.expr_type())), + x => Err(AstError::WrongExprType(x.span(), $exprtype, x.expr_type())), } } pub fn $nameref(&self) -> Result<&$t, AstError> { match self { $p => Ok($value), - x => Err(AstError::WrongExprType(Some(x.span()), $exprtype, x.expr_type())), + x => Err(AstError::WrongExprType(x.span(), $exprtype, x.expr_type())), } } }; @@ -145,7 +145,7 @@ impl Ast { // Ast::Symbol(_, _) => todo!(), Ast::Literal(span, x) => Ok(SimplExpr::Literal(span.into(), x)), Ast::SimplExpr(span, x) => Ok(x), - _ => Err(AstError::WrongExprType(Some(self.span()), AstType::IntoPrimitive, self.expr_type())), + _ => Err(AstError::WrongExprType(self.span(), AstType::IntoPrimitive, self.expr_type())), } } diff --git a/src/parser/ast_iterator.rs b/src/parser/ast_iterator.rs index 097e330..6f841d0 100644 --- a/src/parser/ast_iterator.rs +++ b/src/parser/ast_iterator.rs @@ -23,19 +23,18 @@ 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.next() { - Some($p) => { + match self.expect_any()? { + $p => { let (span, value) = $ret; self.remaining_span.1 = span.1; Ok((span, value)) } - Some(other) => { + other => { let span = other.span(); let actual_type = other.expr_type(); self.iter.put_back(other); - Err(AstError::WrongExprType(Some(span), expr_type, actual_type)) + Err(AstError::WrongExprType(span, expr_type, actual_type)) } - None => Err(AstError::MissingNode(None)), } } }; @@ -55,7 +54,7 @@ impl> AstIterator { } pub fn expect_any(&mut self) -> AstResult { - self.iter.next().or_missing().and_then(T::from_ast) + self.iter.next().or_missing(self.remaining_span.with_length(0)).and_then(T::from_ast) } pub fn expect_key_values(&mut self) -> AstResult { diff --git a/src/parser/from_ast.rs b/src/parser/from_ast.rs index ed495d8..bca20b4 100644 --- a/src/parser/from_ast.rs +++ b/src/parser/from_ast.rs @@ -2,7 +2,7 @@ use super::{ ast::{Ast, AstType, Span}, ast_iterator::AstIterator, }; -use crate::{error::*, parser, spanned, util, value::AttrName}; +use crate::{error::*, parser, util, value::AttrName}; use itertools::Itertools; use simplexpr::{ast::SimplExpr, dynval::DynVal}; use std::{ @@ -37,14 +37,12 @@ pub trait FromAstElementContent: Sized { impl FromAst for T { fn from_ast(e: Ast) -> AstResult { let span = e.span(); - spanned!(e.span(), { - let mut iter = e.try_ast_iter()?; - let (_, element_name) = iter.expect_symbol()?; - if Self::get_element_name() != element_name { - return Err(AstError::MismatchedElementName(Some(span), Self::get_element_name().to_string(), element_name)); - } - Self::from_tail(span, iter)? - }) + let mut iter = e.try_ast_iter()?; + let (_, 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)); + } + Self::from_tail(span, iter) } } @@ -54,7 +52,7 @@ impl FromAst for SimplExpr { Ast::Symbol(span, x) => Ok(SimplExpr::VarRef(span.into(), x)), Ast::Literal(span, x) => Ok(SimplExpr::Literal(span.into(), x)), Ast::SimplExpr(span, x) => Ok(x), - _ => Err(AstError::NotAValue(Some(e.span()), e.expr_type())), + _ => Err(AstError::NotAValue(e.span(), e.expr_type())), } } } diff --git a/src/util.rs b/src/util.rs index a15474f..e69de29 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,14 +0,0 @@ -pub fn parse_duration(s: &str) -> anyhow::Result { - use std::time::Duration; - if s.ends_with("ms") { - Ok(Duration::from_millis(s.trim_end_matches("ms").parse()?)) - } else if s.ends_with('s') { - Ok(Duration::from_secs(s.trim_end_matches('s').parse()?)) - } else if s.ends_with('m') { - Ok(Duration::from_secs(s.trim_end_matches('m').parse::()? * 60)) - } else if s.ends_with('h') { - Ok(Duration::from_secs(s.trim_end_matches('h').parse::()? * 60 * 60)) - } else { - Err(anyhow::anyhow!("Failed to parse duration `{}`", s)) - } -}