diff --git a/crates/eww/src/widgets/widget_node.rs b/crates/eww/src/widgets/widget_node.rs index ff675cd..d870644 100644 --- a/crates/eww/src/widgets/widget_node.rs +++ b/crates/eww/src/widgets/widget_node.rs @@ -11,7 +11,7 @@ use yuck::{ pub trait WidgetNode: std::fmt::Debug + dyn_clone::DynClone + Send + Sync { fn get_name(&self) -> &str; - fn get_span(&self) -> Option; + fn span(&self) -> Option; /// Generate a [gtk::Widget] from a [element::WidgetUse]. /// @@ -41,7 +41,7 @@ impl WidgetNode for UserDefined { &self.name } - fn get_span(&self) -> Option { + fn span(&self) -> Option { self.span } @@ -88,7 +88,7 @@ impl WidgetNode for Generic { &self.name } - fn get_span(&self) -> Option { + fn span(&self) -> Option { Some(self.span) } diff --git a/crates/eww_shared_util/src/span.rs b/crates/eww_shared_util/src/span.rs index 7bde1fb..a97b263 100644 --- a/crates/eww_shared_util/src/span.rs +++ b/crates/eww_shared_util/src/span.rs @@ -1,8 +1,9 @@ #[derive(Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] pub struct Span(pub usize, pub usize, pub usize); -pub static DUMMY_SPAN: Span = Span(usize::MAX, usize::MAX, usize::MAX); impl Span { + pub const DUMMY: Span = Span(usize::MAX, usize::MAX, usize::MAX); + pub fn point(loc: usize, file_id: usize) -> Self { Span(loc, loc, file_id) } @@ -38,7 +39,7 @@ impl Span { } pub fn is_dummy(&self) -> bool { - *self == DUMMY_SPAN + *self == Self::DUMMY } } diff --git a/crates/simplexpr/src/ast.rs b/crates/simplexpr/src/ast.rs index b0c282d..8d1092b 100644 --- a/crates/simplexpr/src/ast.rs +++ b/crates/simplexpr/src/ast.rs @@ -1,5 +1,5 @@ use crate::dynval::DynVal; -use eww_shared_util::{Span, DUMMY_SPAN}; +use eww_shared_util::Span; use itertools::Itertools; use serde::{Deserialize, Serialize}; @@ -57,17 +57,17 @@ impl std::fmt::Display for SimplExpr { } impl SimplExpr { pub fn literal(span: Span, s: String) -> Self { - Self::Literal(span, DynVal(s, Some(span))) + Self::Literal(span, DynVal(s, span)) } /// Construct a synthetic simplexpr from a literal string, without adding any relevant span information (uses [DUMMY_SPAN]) pub fn synth_string(s: String) -> Self { - Self::Literal(DUMMY_SPAN, DynVal(s, Some(DUMMY_SPAN))) + Self::Literal(Span::DUMMY, DynVal(s, Span::DUMMY)) } /// Construct a synthetic simplexpr from a literal dynval, without adding any relevant span information (uses [DUMMY_SPAN]) pub fn synth_literal>(s: T) -> Self { - Self::Literal(DUMMY_SPAN, s.into()) + Self::Literal(Span::DUMMY, s.into()) } pub fn span(&self) -> Span { diff --git a/crates/simplexpr/src/dynval.rs b/crates/simplexpr/src/dynval.rs index 27edfc7..ebba340 100644 --- a/crates/simplexpr/src/dynval.rs +++ b/crates/simplexpr/src/dynval.rs @@ -18,17 +18,17 @@ impl ConversionError { ConversionError { value, target_type, source: Some(Box::new(source)) } } - pub fn span(&self) -> Option { + pub fn span(&self) -> Span { self.value.1 } } -#[derive(Clone, Deserialize, Serialize, Default, Eq)] -pub struct DynVal(pub String, pub Option); +#[derive(Clone, Deserialize, Serialize, Eq)] +pub struct DynVal(pub String, pub Span); impl From for DynVal { fn from(s: String) -> Self { - DynVal(s, None) + DynVal(s, Span::DUMMY) } } @@ -56,7 +56,7 @@ impl std::cmp::PartialEq for DynVal { impl FromIterator for DynVal { fn from_iter>(iter: T) -> Self { - DynVal(iter.into_iter().join(""), None) + DynVal(iter.into_iter().join(""), Span::DUMMY) } } @@ -86,7 +86,7 @@ impl> FromDynVal for T { macro_rules! impl_dynval_from { ($($t:ty),*) => { $(impl From<$t> for DynVal { - fn from(x: $t) -> Self { DynVal(x.to_string(), None) } + fn from(x: $t) -> Self { DynVal(x.to_string(), Span::DUMMY) } })* }; } @@ -95,7 +95,7 @@ impl_dynval_from!(bool, i32, u32, f32, u8, f64, &str); impl From for DynVal { fn from(d: std::time::Duration) -> Self { - DynVal(format!("{}ms", d.as_millis()), None) + DynVal(format!("{}ms", d.as_millis()), Span::DUMMY) } } @@ -106,22 +106,22 @@ impl From<&serde_json::Value> for DynVal { .map(|x| x.to_string()) .or_else(|| serde_json::to_string(v).ok()) .unwrap_or_else(|| "".to_string()), - None, + Span::DUMMY, ) } } impl DynVal { pub fn at(self, span: Span) -> Self { - DynVal(self.0, Some(span)) + DynVal(self.0, span) } - pub fn span(&self) -> Option { + pub fn span(&self) -> Span { self.1 } pub fn from_string(s: String) -> Self { - DynVal(s, None) + DynVal(s, Span::DUMMY) } pub fn read_as>(&self) -> std::result::Result { diff --git a/crates/simplexpr/src/error.rs b/crates/simplexpr/src/error.rs index 920addf..c583f07 100644 --- a/crates/simplexpr/src/error.rs +++ b/crates/simplexpr/src/error.rs @@ -32,27 +32,24 @@ impl Error { Self::Spanned(span, Box::new(self)) } - pub fn get_span(&self) -> Option { + pub fn span(&self) -> Span { match self { Self::ParseError { file_id, source } => get_parse_error_span(*file_id, source), - Self::Spanned(span, _) => Some(*span), + Self::Spanned(span, _) => *span, Self::Eval(err) => err.span(), Self::ConversionError(err) => err.span(), - _ => None, + _ => Span::DUMMY, } } } -fn get_parse_error_span( - file_id: usize, - err: &lalrpop_util::ParseError, -) -> Option { +fn get_parse_error_span(file_id: usize, err: &lalrpop_util::ParseError) -> Span { match err { - lalrpop_util::ParseError::InvalidToken { location } => Some(Span(*location, *location, file_id)), - lalrpop_util::ParseError::UnrecognizedEOF { location, expected: _ } => Some(Span(*location, *location, file_id)), - lalrpop_util::ParseError::UnrecognizedToken { token, expected: _ } => Some(Span(token.0, token.2, file_id)), - lalrpop_util::ParseError::ExtraToken { token } => Some(Span(token.0, token.2, file_id)), - lalrpop_util::ParseError::User { error: LexicalError(l, r, file_id) } => Some(Span(*l, *r, *file_id)), + lalrpop_util::ParseError::InvalidToken { location } => Span(*location, *location, file_id), + lalrpop_util::ParseError::UnrecognizedEOF { location, expected: _ } => Span(*location, *location, file_id), + lalrpop_util::ParseError::UnrecognizedToken { token, expected: _ } => Span(token.0, token.2, file_id), + lalrpop_util::ParseError::ExtraToken { token } => Span(token.0, token.2, file_id), + lalrpop_util::ParseError::User { error: LexicalError(l, r, file_id) } => Span(*l, *r, *file_id), } } diff --git a/crates/simplexpr/src/eval.rs b/crates/simplexpr/src/eval.rs index ea2bb2a..59f2f5b 100644 --- a/crates/simplexpr/src/eval.rs +++ b/crates/simplexpr/src/eval.rs @@ -38,11 +38,11 @@ pub enum EvalError { } impl EvalError { - pub fn span(&self) -> Option { + pub fn span(&self) -> Span { match self { - EvalError::Spanned(span, _) => Some(*span), + EvalError::Spanned(span, _) => *span, EvalError::ConversionError(err) => err.span(), - _ => None, + _ => Span::DUMMY, } } diff --git a/crates/yuck/src/config/config.rs b/crates/yuck/src/config/config.rs index 81b2113..25e7ac9 100644 --- a/crates/yuck/src/config/config.rs +++ b/crates/yuck/src/config/config.rs @@ -122,7 +122,7 @@ impl Config { pub fn generate_from_main_file(files: &mut YuckFiles, path: impl AsRef) -> AstResult { let (span, top_levels) = files.load_file(path.as_ref().to_path_buf()).map_err(|err| match err { - FilesError::IoError(err) => AstError::Other(None, Box::new(err)), + FilesError::IoError(err) => AstError::Other(Span::DUMMY, Box::new(err)), FilesError::AstError(x) => x, })?; Self::generate(files, top_levels) diff --git a/crates/yuck/src/error.rs b/crates/yuck/src/error.rs index 3b20877..f7278d4 100644 --- a/crates/yuck/src/error.rs +++ b/crates/yuck/src/error.rs @@ -41,7 +41,7 @@ pub enum AstError { ConversionError(#[from] dynval::ConversionError), #[error("{1}")] - Other(Option, Box), + Other(Span, Box), #[error(transparent)] AttrError(#[from] AttrError), @@ -66,22 +66,22 @@ impl AstError { AstError::ErrorContext { label_span, context: context.to_string(), main_err: Box::new(self) } } - pub fn get_span(&self) -> Option { + pub fn span(&self) -> Span { match self { - 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::UnknownToplevel(span, _) => *span, + AstError::MissingNode(span) => *span, + AstError::WrongExprType(span, ..) => *span, + AstError::NotAValue(span, ..) => *span, + AstError::MismatchedElementName(span, ..) => *span, + AstError::AttrError(err) => err.span(), AstError::Other(span, ..) => *span, - AstError::ConversionError(err) => err.value.span().map(|x| x.into()), - AstError::IncludedFileNotFound(include) => Some(include.path_span), - AstError::TooManyNodes(span, ..) => Some(*span), - AstError::ErrorContext { label_span, .. } => Some(*label_span), - AstError::ValidationError(error) => Some(error.span()), + AstError::ConversionError(err) => err.value.span(), + AstError::IncludedFileNotFound(include) => include.path_span, + AstError::TooManyNodes(span, ..) => *span, + AstError::ErrorContext { label_span, .. } => *label_span, + AstError::ValidationError(error) => error.span(), AstError::ParseError { file_id, source } => get_parse_error_span(*file_id, source, |err| err.span()), - AstError::ErrorNote(_, err) => err.get_span(), + AstError::ErrorNote(_, err) => err.span(), } } @@ -96,13 +96,13 @@ impl AstError { pub fn get_parse_error_span( file_id: usize, err: &lalrpop_util::ParseError, - handle_user: impl FnOnce(&E) -> Option, -) -> Option { + handle_user: impl FnOnce(&E) -> Span, +) -> Span { match err { - lalrpop_util::ParseError::InvalidToken { location } => Some(Span(*location, *location, file_id)), - lalrpop_util::ParseError::UnrecognizedEOF { location, expected } => Some(Span(*location, *location, file_id)), - lalrpop_util::ParseError::UnrecognizedToken { token, expected } => Some(Span(token.0, token.2, file_id)), - lalrpop_util::ParseError::ExtraToken { token } => Some(Span(token.0, token.2, file_id)), + lalrpop_util::ParseError::InvalidToken { location } => Span(*location, *location, file_id), + lalrpop_util::ParseError::UnrecognizedEOF { location, expected } => Span(*location, *location, file_id), + lalrpop_util::ParseError::UnrecognizedToken { token, expected } => Span(token.0, token.2, file_id), + lalrpop_util::ParseError::ExtraToken { token } => Span(token.0, token.2, file_id), lalrpop_util::ParseError::User { error } => handle_user(error), } } diff --git a/crates/yuck/src/format_diagnostic.rs b/crates/yuck/src/format_diagnostic.rs index a2f3cd0..f7424c3 100644 --- a/crates/yuck/src/format_diagnostic.rs +++ b/crates/yuck/src/format_diagnostic.rs @@ -65,55 +65,51 @@ impl ToDiagnostic for Diagnostic { } impl ToDiagnostic for AstError { fn to_diagnostic(&self) -> Diagnostic { - // TODO this if let should be unnecessary - if let AstError::ValidationError(error) = self { - error.to_diagnostic() - } else { - match self { - AstError::UnknownToplevel(span, name) => gen_diagnostic!(self, span), - AstError::MissingNode(span) => gen_diagnostic! { - msg = "Expected another element", - label = span => "Expected another element here", - }, + match self { + AstError::UnknownToplevel(span, name) => gen_diagnostic!(self, span), + AstError::MissingNode(span) => gen_diagnostic! { + msg = "Expected another element", + label = span => "Expected another element here", + }, - AstError::WrongExprType(span, expected, actual) => gen_diagnostic! { - msg = "Wrong type of expression", - label = span => format!("Expected a `{}` here", expected), - note = format!("Expected: {}\nGot: {}", expected, actual), - }, - AstError::NotAValue(span, actual) => gen_diagnostic! { - msg = format!("Expected value, but got `{}`", actual), - label = span => "Expected some value here", - note = format!("Got: {}", actual), - }, + AstError::WrongExprType(span, expected, actual) => gen_diagnostic! { + msg = "Wrong type of expression", + label = span => format!("Expected a `{}` here", expected), + note = format!("Expected: {}\nGot: {}", expected, actual), + }, + AstError::NotAValue(span, actual) => gen_diagnostic! { + msg = format!("Expected value, but got `{}`", actual), + label = span => "Expected some value here", + note = format!("Got: {}", actual), + }, - AstError::ParseError { file_id, source } => lalrpop_error_to_diagnostic(source, *file_id, |error| error.to_diagnostic()), - AstError::MismatchedElementName(span, 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::ErrorContext { label_span, context, main_err } => { - main_err.to_diagnostic().with_opt_label(Some(span_to_secondary_label(*label_span).with_message(context))) - } - - AstError::ConversionError(source) => source.to_diagnostic(), - AstError::Other(Some(span), source) => gen_diagnostic!(source, span), - AstError::Other(None, source) => gen_diagnostic!(source), - AstError::AttrError(source) => source.to_diagnostic(), - AstError::IncludedFileNotFound(include) => gen_diagnostic!( - msg = format!("Included file `{}` not found", include.path), - label = include.path_span => "Included here", - ), - - AstError::TooManyNodes(extra_nodes_span, expected) => gen_diagnostic! { - msg = self, - label = extra_nodes_span => "these elements must not be here", - note = "Consider wrapping the elements in some container element", - }, - AstError::ErrorNote(note, source) => source.to_diagnostic().with_notes(vec![note.to_string()]), - AstError::ValidationError(source) => source.to_diagnostic(), + AstError::ParseError { file_id, source } => { + lalrpop_error_to_diagnostic(source, *file_id, |error| error.to_diagnostic()) } + AstError::MismatchedElementName(span, 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::ErrorContext { label_span, context, main_err } => { + main_err.to_diagnostic().with_opt_label(Some(span_to_secondary_label(*label_span).with_message(context))) + } + + AstError::ConversionError(source) => source.to_diagnostic(), + AstError::Other(span, source) => gen_diagnostic!(source, span), + AstError::AttrError(source) => source.to_diagnostic(), + AstError::IncludedFileNotFound(include) => gen_diagnostic!( + msg = format!("Included file `{}` not found", include.path), + label = include.path_span => "Included here", + ), + + AstError::TooManyNodes(extra_nodes_span, expected) => gen_diagnostic! { + msg = self, + label = extra_nodes_span => "these elements must not be here", + note = "Consider wrapping the elements in some container element", + }, + AstError::ErrorNote(note, source) => source.to_diagnostic().with_notes(vec![note.to_string()]), + AstError::ValidationError(source) => source.to_diagnostic(), } } } @@ -160,63 +156,51 @@ fn lalrpop_error_to_diagnostic( ) -> Diagnostic { use lalrpop_util::ParseError::*; // None is okay here, as the case that would be affected by it (User { error }) is manually handled here anyways - let span = get_parse_error_span(file_id, error, |e| None); - let res: Option<_> = try { - match error { - InvalidToken { location } => gen_diagnostic!("Invalid token", span?), - UnrecognizedEOF { location, expected } => gen_diagnostic! { - "Input ended unexpectedly. Check if you have any unclosed delimiters", - span? - }, - UnrecognizedToken { token, expected } => gen_diagnostic! { - msg = format!("Unexpected token `{}` encountered", token.1), - label = span? => "Token unexpected", - }, - ExtraToken { token } => gen_diagnostic!(format!("Extra token encountered: `{}`", token.1)), - User { error } => handle_user_error(error), - } - }; - res.unwrap_or_else(|| gen_diagnostic!(error)) + let span = get_parse_error_span(file_id, error, |e| Span::DUMMY); + match error { + InvalidToken { location } => gen_diagnostic!("Invalid token", span), + UnrecognizedEOF { location, expected } => gen_diagnostic! { + msg = "Input ended unexpectedly. Check if you have any unclosed delimiters", + label = span + }, + UnrecognizedToken { token, expected } => gen_diagnostic! { + msg = format!("Unexpected token `{}` encountered", token.1), + label = span => "Token unexpected", + }, + ExtraToken { token } => gen_diagnostic!(format!("Extra token encountered: `{}`", token.1)), + User { error } => handle_user_error(error), + } } impl ToDiagnostic for simplexpr::error::Error { // TODO this needs a lot of improvement fn to_diagnostic(&self) -> Diagnostic { use simplexpr::error::Error::*; - let res: Option<_> = try { - match self { - ParseError { source, file_id } => { - let span = get_parse_error_span(*file_id, source, |e| Some(Span(e.0, e.1, *file_id)))?; - lalrpop_error_to_diagnostic(source, *file_id, move |error| lexical_error_diagnostic(span)) - } - ConversionError(error) => error.to_diagnostic(), - Eval(error) => error.to_diagnostic(), - Other(error) => gen_diagnostic!(error), - Spanned(span, error) => gen_diagnostic!(error, span), + match self { + ParseError { source, file_id } => { + let span = get_parse_error_span(*file_id, source, |e| Span(e.0, e.1, *file_id)); + lalrpop_error_to_diagnostic(source, *file_id, move |error| lexical_error_diagnostic(span)) } - }; - res.unwrap_or_else(|| gen_diagnostic!(self)) + ConversionError(error) => error.to_diagnostic(), + Eval(error) => error.to_diagnostic(), + Other(error) => gen_diagnostic!(error), + Spanned(span, error) => gen_diagnostic!(error, span), + } } } impl ToDiagnostic for simplexpr::eval::EvalError { // TODO this needs a lot of improvement fn to_diagnostic(&self) -> Diagnostic { - match self.span() { - Some(span) => gen_diagnostic!(self, span), - None => gen_diagnostic!(self), - } + gen_diagnostic!(self, self.span()) } } impl ToDiagnostic for dynval::ConversionError { fn to_diagnostic(&self) -> Diagnostic { - let diag = match self.span() { - Some(span) => gen_diagnostic! { - msg = self, - label = span => format!("`{}` is not of type `{}`", self.value, self.target_type), - }, - None => gen_diagnostic!(self), + let diag = gen_diagnostic! { + msg = self, + label = self.value.span() => format!("`{}` is not of type `{}`", self.value, self.target_type), }; diag.with_notes(self.source.as_ref().map(|x| vec![format!("{}", x)]).unwrap_or_default()) } diff --git a/crates/yuck/src/parser/parse_error.rs b/crates/yuck/src/parser/parse_error.rs index c2a6007..1f24285 100644 --- a/crates/yuck/src/parser/parse_error.rs +++ b/crates/yuck/src/parser/parse_error.rs @@ -9,10 +9,10 @@ pub enum ParseError { } impl ParseError { - pub fn span(&self) -> Option { + pub fn span(&self) -> Span { match self { - ParseError::SimplExpr(err) => err.get_span(), - ParseError::LexicalError(span) => Some(*span), + ParseError::SimplExpr(err) => err.span(), + ParseError::LexicalError(span) => *span, } } }