Add Spanned trait and use it

This commit is contained in:
elkowar 2021-07-26 20:17:36 +02:00
parent 16ebf7683a
commit 680ab9d633
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F
22 changed files with 117 additions and 113 deletions

View file

@ -13,7 +13,6 @@ homepage = "https://github.com/elkowar/eww"
default = ["x11"] default = ["x11"]
x11 = ["gdkx11", "x11rb"] x11 = ["gdkx11", "x11rb"]
wayland = ["gtk-layer-shell", "gtk-layer-shell-sys"] wayland = ["gtk-layer-shell", "gtk-layer-shell-sys"]
no-x11-wayland = []
[dependencies.cairo-sys-rs] [dependencies.cairo-sys-rs]
version = "0.10.0" version = "0.10.0"
@ -70,9 +69,8 @@ notify = "5.0.0-pre.7"
codespan-reporting = "0.11" codespan-reporting = "0.11"
simplexpr = { path = "../simplexpr" } simplexpr = { path = "../simplexpr" }
yuck = { path = "../yuck", default-features = false}
eww_shared_util = { path = "../eww_shared_util" } eww_shared_util = { path = "../eww_shared_util" }
yuck = { path = "../yuck", default-features = false}
[dev-dependencies] [dev-dependencies]
pretty_assertions = "0.7.1" pretty_assertions = "0.7.1"

View file

@ -1,6 +1,6 @@
pub use platform::*; pub use platform::*;
#[cfg(feature = "no-x11-wayland")] #[cfg(not(any(feature = "x11", feature = "wayland")))]
mod platform { mod platform {
use crate::config::EwwWindowDefinition; use crate::config::EwwWindowDefinition;

View file

@ -1,7 +1,7 @@
use crate::eww_state::EwwState; use crate::eww_state::EwwState;
use anyhow::*; use anyhow::*;
use dyn_clone; use dyn_clone;
use eww_shared_util::{AttrName, Span, VarName}; use eww_shared_util::{AttrName, Span, Spanned, VarName};
use simplexpr::SimplExpr; use simplexpr::SimplExpr;
use std::collections::HashMap; use std::collections::HashMap;
use yuck::{ use yuck::{
@ -11,7 +11,6 @@ use yuck::{
pub trait WidgetNode: std::fmt::Debug + dyn_clone::DynClone + Send + Sync { pub trait WidgetNode: std::fmt::Debug + dyn_clone::DynClone + Send + Sync {
fn get_name(&self) -> &str; fn get_name(&self) -> &str;
fn span(&self) -> Option<Span>;
/// Generate a [gtk::Widget] from a [element::WidgetUse]. /// Generate a [gtk::Widget] from a [element::WidgetUse].
/// ///
@ -32,7 +31,7 @@ dyn_clone::clone_trait_object!(WidgetNode);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct UserDefined { pub struct UserDefined {
name: String, name: String,
span: Option<Span>, span: Span,
content: Box<dyn WidgetNode>, content: Box<dyn WidgetNode>,
} }
@ -41,10 +40,6 @@ impl WidgetNode for UserDefined {
&self.name &self.name
} }
fn span(&self) -> Option<Span> {
self.span
}
fn render( fn render(
&self, &self,
eww_state: &mut EwwState, eww_state: &mut EwwState,
@ -55,6 +50,12 @@ impl WidgetNode for UserDefined {
} }
} }
impl Spanned for UserDefined {
fn span(&self) -> Span {
self.span
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Generic { pub struct Generic {
pub name: String, pub name: String,
@ -88,10 +89,6 @@ impl WidgetNode for Generic {
&self.name &self.name
} }
fn span(&self) -> Option<Span> {
Some(self.span)
}
fn render( fn render(
&self, &self,
eww_state: &mut EwwState, eww_state: &mut EwwState,
@ -103,6 +100,11 @@ impl WidgetNode for Generic {
})?) })?)
} }
} }
impl Spanned for Generic {
fn span(&self) -> Span {
self.span
}
}
pub fn generate_generic_widget_node( pub fn generate_generic_widget_node(
defs: &HashMap<String, WidgetDefinition>, defs: &HashMap<String, WidgetDefinition>,
@ -122,7 +124,7 @@ pub fn generate_generic_widget_node(
.collect::<AstResult<HashMap<VarName, _>>>()?; .collect::<AstResult<HashMap<VarName, _>>>()?;
let content = generate_generic_widget_node(defs, &new_local_env, def.widget.clone())?; let content = generate_generic_widget_node(defs, &new_local_env, def.widget.clone())?;
Ok(Box::new(UserDefined { name: w.name, span: Some(w.span), content })) Ok(Box::new(UserDefined { name: w.name, span: w.span, content }))
} else { } else {
Ok(Box::new(Generic { Ok(Box::new(Generic {
name: w.name, name: w.name,

View file

@ -54,3 +54,7 @@ impl std::fmt::Debug for Span {
write!(f, "{}..{}", self.0, self.1) write!(f, "{}..{}", self.0, self.1)
} }
} }
pub trait Spanned {
fn span(&self) -> Span;
}

View file

@ -1,5 +1,5 @@
use crate::dynval::DynVal; use crate::dynval::DynVal;
use eww_shared_util::Span; use eww_shared_util::{Span, Spanned};
use itertools::Itertools; use itertools::Itertools;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -69,8 +69,9 @@ impl SimplExpr {
pub fn synth_literal<T: Into<DynVal>>(s: T) -> Self { pub fn synth_literal<T: Into<DynVal>>(s: T) -> Self {
Self::Literal(Span::DUMMY, s.into()) Self::Literal(Span::DUMMY, s.into())
} }
}
pub fn span(&self) -> Span { impl Spanned for SimplExpr {
fn span(&self) -> Span {
match self { match self {
SimplExpr::Literal(span, _) => *span, SimplExpr::Literal(span, _) => *span,
SimplExpr::VarRef(span, _) => *span, SimplExpr::VarRef(span, _) => *span,

View file

@ -1,4 +1,4 @@
use eww_shared_util::Span; use eww_shared_util::{Span, Spanned};
use itertools::Itertools; use itertools::Itertools;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fmt, iter::FromIterator, str::FromStr}; use std::{fmt, iter::FromIterator, str::FromStr};
@ -17,8 +17,9 @@ impl ConversionError {
fn new(value: DynVal, target_type: &'static str, source: impl std::error::Error + 'static + Sync + Send) -> Self { fn new(value: DynVal, target_type: &'static str, source: impl std::error::Error + 'static + Sync + Send) -> Self {
ConversionError { value, target_type, source: Some(Box::new(source)) } ConversionError { value, target_type, source: Some(Box::new(source)) }
} }
}
pub fn span(&self) -> Span { impl Spanned for ConversionError {
fn span(&self) -> Span {
self.value.1 self.value.1
} }
} }
@ -111,15 +112,17 @@ impl From<&serde_json::Value> for DynVal {
} }
} }
impl Spanned for DynVal {
fn span(&self) -> Span {
self.1
}
}
impl DynVal { impl DynVal {
pub fn at(self, span: Span) -> Self { pub fn at(self, span: Span) -> Self {
DynVal(self.0, span) DynVal(self.0, span)
} }
pub fn span(&self) -> Span {
self.1
}
pub fn from_string(s: String) -> Self { pub fn from_string(s: String) -> Self {
DynVal(s, Span::DUMMY) DynVal(s, Span::DUMMY)
} }

View file

@ -2,15 +2,15 @@ use crate::{
dynval, dynval,
parser::lexer::{self, LexicalError}, parser::lexer::{self, LexicalError},
}; };
use eww_shared_util::Span; use eww_shared_util::{Span, Spanned};
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
#[error("Parse error: {source}")] #[error("Error parsing expression: {source}")]
ParseError { file_id: usize, source: lalrpop_util::ParseError<usize, lexer::Token, lexer::LexicalError> }, ParseError { file_id: usize, source: lalrpop_util::ParseError<usize, lexer::Token, lexer::LexicalError> },
#[error("Type error: {0}")] #[error(transparent)]
ConversionError(#[from] dynval::ConversionError), ConversionError(#[from] dynval::ConversionError),
#[error("{1}")] #[error("{1}")]
@ -31,8 +31,10 @@ impl Error {
pub fn at(self, span: Span) -> Self { pub fn at(self, span: Span) -> Self {
Self::Spanned(span, Box::new(self)) Self::Spanned(span, Box::new(self))
} }
}
pub fn span(&self) -> Span { impl Spanned for Error {
fn span(&self) -> Span {
match self { match self {
Self::ParseError { file_id, source } => get_parse_error_span(*file_id, source), Self::ParseError { file_id, source } => get_parse_error_span(*file_id, source),
Self::Spanned(span, _) => *span, Self::Spanned(span, _) => *span,

View file

@ -4,7 +4,7 @@ use crate::{
ast::{BinOp, SimplExpr, UnaryOp}, ast::{BinOp, SimplExpr, UnaryOp},
dynval::{ConversionError, DynVal}, dynval::{ConversionError, DynVal},
}; };
use eww_shared_util::{Span, VarName}; use eww_shared_util::{Span, Spanned, VarName};
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -18,7 +18,7 @@ pub enum EvalError {
#[error("got unresolved variable `{0}`")] #[error("got unresolved variable `{0}`")]
UnresolvedVariable(VarName), UnresolvedVariable(VarName),
#[error("Type error: {0}")] #[error(transparent)]
ConversionError(#[from] ConversionError), ConversionError(#[from] ConversionError),
#[error("Incorrect number of arguments given to function: {0}")] #[error("Incorrect number of arguments given to function: {0}")]
@ -38,17 +38,19 @@ pub enum EvalError {
} }
impl EvalError { impl EvalError {
pub fn span(&self) -> Span { pub fn at(self, span: Span) -> Self {
Self::Spanned(span, Box::new(self))
}
}
impl Spanned for EvalError {
fn span(&self) -> Span {
match self { match self {
EvalError::Spanned(span, _) => *span, EvalError::Spanned(span, _) => *span,
EvalError::ConversionError(err) => err.span(), EvalError::ConversionError(err) => err.span(),
_ => Span::DUMMY, _ => Span::DUMMY,
} }
} }
pub fn at(self, span: Span) -> Self {
Self::Spanned(span, Box::new(self))
}
} }
impl SimplExpr { impl SimplExpr {
@ -98,7 +100,6 @@ impl SimplExpr {
pub fn resolve_refs(self, variables: &HashMap<VarName, DynVal>) -> Result<Self, EvalError> { pub fn resolve_refs(self, variables: &HashMap<VarName, DynVal>) -> Result<Self, EvalError> {
use SimplExpr::*; use SimplExpr::*;
match self { match self {
// Literal(x) => Ok(Literal(AttrValue::from_primitive(x.resolve_fully(&variables)?))),
Literal(span, x) => Ok(Literal(span, x)), Literal(span, x) => Ok(Literal(span, x)),
BinOp(span, box a, op, box b) => Ok(BinOp(span, box a.resolve_refs(variables)?, op, box b.resolve_refs(variables)?)), BinOp(span, box a, op, box b) => Ok(BinOp(span, box a.resolve_refs(variables)?, op, box b.resolve_refs(variables)?)),
UnaryOp(span, op, box x) => Ok(UnaryOp(span, op, box x.resolve_refs(variables)?)), UnaryOp(span, op, box x) => Ok(UnaryOp(span, op, box x.resolve_refs(variables)?)),

View file

@ -1,3 +1,4 @@
use eww_shared_util::{Span, Spanned};
use logos::Logos; use logos::Logos;
use regex::Regex; use regex::Regex;
@ -48,10 +49,15 @@ pub enum Token {
Error, Error,
} }
// TODO can i include the fileid here already?
#[derive(Debug, Eq, PartialEq, Copy, Clone)] #[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct LexicalError(pub usize, pub usize, pub usize); pub struct LexicalError(pub usize, pub usize, pub usize);
impl Spanned for LexicalError {
fn span(&self) -> Span {
Span(self.0, self.1, self.2)
}
}
impl std::fmt::Display for LexicalError { impl std::fmt::Display for LexicalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Lexical error at {}..{}", self.0, self.1) write!(f, "Lexical error at {}..{}", self.0, self.1)

View file

@ -10,7 +10,6 @@ build = "build.rs"
default = ["x11"] default = ["x11"]
x11 = [] x11 = []
wayland = [] wayland = []
no-x11-wayland = []
[dependencies] [dependencies]
lalrpop-util = "0.19.5" lalrpop-util = "0.19.5"

View file

@ -13,7 +13,7 @@ use crate::{
error::AstError, error::AstError,
parser::{ast::Ast, from_ast::FromAst}, parser::{ast::Ast, from_ast::FromAst},
}; };
use eww_shared_util::{AttrName, Span, VarName}; use eww_shared_util::{AttrName, Span, Spanned, VarName};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum AttrError { pub enum AttrError {
@ -27,8 +27,8 @@ pub enum AttrError {
Other(Span, Box<dyn std::error::Error + Sync + Send + 'static>), Other(Span, Box<dyn std::error::Error + Sync + Send + 'static>),
} }
impl AttrError { impl Spanned for AttrError {
pub fn span(&self) -> Span { fn span(&self) -> Span {
match self { match self {
AttrError::MissingRequiredAttr(span, _) => *span, AttrError::MissingRequiredAttr(span, _) => *span,
AttrError::EvaluationError(span, _) => *span, AttrError::EvaluationError(span, _) => *span,
@ -90,7 +90,7 @@ impl Attributes {
let ast: SimplExpr = self.ast_required(&key)?; let ast: SimplExpr = self.ast_required(&key)?;
Ok(ast Ok(ast
.eval_no_vars() .eval_no_vars()
.map_err(|err| AttrError::EvaluationError(ast.span().into(), err))? .map_err(|err| AttrError::EvaluationError(ast.span(), err))?
.read_as() .read_as()
.map_err(|e| AttrError::Other(ast.span().into(), Box::new(e)))?) .map_err(|e| AttrError::Other(ast.span().into(), Box::new(e)))?)
} }
@ -106,7 +106,7 @@ impl Attributes {
}; };
Ok(Some( Ok(Some(
ast.eval_no_vars() ast.eval_no_vars()
.map_err(|err| AttrError::EvaluationError(ast.span().into(), err))? .map_err(|err| AttrError::EvaluationError(ast.span(), err))?
.read_as() .read_as()
.map_err(|e| AttrError::Other(ast.span().into(), Box::new(e)))?, .map_err(|e| AttrError::Other(ast.span().into(), Box::new(e)))?,
)) ))
@ -115,9 +115,6 @@ impl Attributes {
/// Consumes the attributes to return a list of unused attributes which may be used to emit a warning. /// Consumes the attributes to return a list of unused attributes which may be used to emit a warning.
/// TODO actually use this and implement warnings,... lol /// TODO actually use this and implement warnings,... lol
pub fn get_unused(self, definition_span: Span) -> UnusedAttrs { pub fn get_unused(self, definition_span: Span) -> UnusedAttrs {
UnusedAttrs { UnusedAttrs { definition_span, attrs: self.attrs.into_iter().map(|(k, v)| (v.key_span.to(v.value.span()), k)).collect() }
definition_span,
attrs: self.attrs.into_iter().map(|(k, v)| (v.key_span.to(v.value.span().into()), k)).collect(),
}
} }
} }

View file

@ -121,7 +121,7 @@ mod backend {
} }
} }
#[cfg(feature = "no-x11-wayland")] #[cfg(not(any(feature = "x11", feature = "wayland")))]
mod backend { mod backend {
use super::*; use super::*;
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]

View file

@ -1,2 +0,0 @@
#[derive(Debug, thiserror::Error)]
pub enum ConfigParseError {}

View file

@ -1,7 +1,6 @@
pub mod attributes; pub mod attributes;
pub mod backend_window_options; pub mod backend_window_options;
pub mod config; pub mod config;
pub mod config_parse_error;
pub mod file_provider; pub mod file_provider;
pub mod script_var_definition; pub mod script_var_definition;
#[cfg(test)] #[cfg(test)]

View file

@ -8,7 +8,7 @@ use crate::{
}; };
use super::{widget_definition::WidgetDefinition, widget_use::WidgetUse}; use super::{widget_definition::WidgetDefinition, widget_use::WidgetUse};
use eww_shared_util::{AttrName, Span, VarName}; use eww_shared_util::{AttrName, Span, Spanned, VarName};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum ValidationError { pub enum ValidationError {
@ -19,8 +19,8 @@ pub enum ValidationError {
MissingAttr { widget_name: String, arg_name: AttrName, arg_list_span: Option<Span>, use_span: Span }, MissingAttr { widget_name: String, arg_name: AttrName, arg_list_span: Option<Span>, use_span: Span },
} }
impl ValidationError { impl Spanned for ValidationError {
pub fn span(&self) -> Span { fn span(&self) -> Span {
match self { match self {
ValidationError::UnknownWidget(span, _) => *span, ValidationError::UnknownWidget(span, _) => *span,
ValidationError::MissingAttr { use_span, .. } => *use_span, ValidationError::MissingAttr { use_span, .. } => *use_span,

View file

@ -7,7 +7,7 @@ use crate::{
}, },
}; };
use codespan_reporting::{diagnostic, files}; use codespan_reporting::{diagnostic, files};
use eww_shared_util::{AttrName, Span, VarName}; use eww_shared_util::{AttrName, Span, Spanned, VarName};
use simplexpr::dynval; use simplexpr::dynval;
use thiserror::Error; use thiserror::Error;
@ -66,7 +66,16 @@ impl AstError {
AstError::ErrorContext { label_span, context: context.to_string(), main_err: Box::new(self) } AstError::ErrorContext { label_span, context: context.to_string(), main_err: Box::new(self) }
} }
pub fn span(&self) -> Span { pub fn from_parse_error(
file_id: usize,
err: lalrpop_util::ParseError<usize, lexer::Token, parse_error::ParseError>,
) -> AstError {
AstError::ParseError { file_id, source: err }
}
}
impl Spanned for AstError {
fn span(&self) -> Span {
match self { match self {
AstError::UnknownToplevel(span, _) => *span, AstError::UnknownToplevel(span, _) => *span,
AstError::MissingNode(span) => *span, AstError::MissingNode(span) => *span,
@ -80,30 +89,20 @@ impl AstError {
AstError::TooManyNodes(span, ..) => *span, AstError::TooManyNodes(span, ..) => *span,
AstError::ErrorContext { label_span, .. } => *label_span, AstError::ErrorContext { label_span, .. } => *label_span,
AstError::ValidationError(error) => error.span(), AstError::ValidationError(error) => error.span(),
AstError::ParseError { file_id, source } => get_parse_error_span(*file_id, source, |err| err.span()), AstError::ParseError { file_id, source } => get_parse_error_span(*file_id, source),
AstError::ErrorNote(_, err) => err.span(), AstError::ErrorNote(_, err) => err.span(),
} }
} }
pub fn from_parse_error(
file_id: usize,
err: lalrpop_util::ParseError<usize, lexer::Token, parse_error::ParseError>,
) -> AstError {
AstError::ParseError { file_id, source: err }
}
} }
pub fn get_parse_error_span<T, E>( pub fn get_parse_error_span<T, E: Spanned>(file_id: usize, err: &lalrpop_util::ParseError<usize, T, E>) -> Span {
file_id: usize, use lalrpop_util::ParseError::*;
err: &lalrpop_util::ParseError<usize, T, E>,
handle_user: impl FnOnce(&E) -> Span,
) -> Span {
match err { match err {
lalrpop_util::ParseError::InvalidToken { location } => Span(*location, *location, file_id), InvalidToken { location } => Span(*location, *location, file_id),
lalrpop_util::ParseError::UnrecognizedEOF { location, expected } => Span(*location, *location, file_id), UnrecognizedEOF { location, expected } => Span(*location, *location, file_id),
lalrpop_util::ParseError::UnrecognizedToken { token, expected } => Span(token.0, token.2, file_id), UnrecognizedToken { token, expected } => Span(token.0, token.2, file_id),
lalrpop_util::ParseError::ExtraToken { token } => Span(token.0, token.2, file_id), ExtraToken { token } => Span(token.0, token.2, file_id),
lalrpop_util::ParseError::User { error } => handle_user(error), User { error } => error.span(),
} }
} }

View file

@ -9,7 +9,7 @@ use crate::{
}; };
use super::parser::parse_error; use super::parser::parse_error;
use eww_shared_util::{AttrName, Span, VarName}; use eww_shared_util::{AttrName, Span, Spanned, VarName};
fn span_to_secondary_label(span: Span) -> Label<usize> { fn span_to_secondary_label(span: Span) -> Label<usize> {
Label::secondary(span.2, span.0..span.1) Label::secondary(span.2, span.0..span.1)
@ -38,16 +38,12 @@ macro_rules! gen_diagnostic {
} }
pub trait DiagnosticExt: Sized { pub trait DiagnosticExt: Sized {
fn with_opt_label(self, label: Option<Label<usize>>) -> Self; fn with_label(self, label: Label<usize>) -> Self;
} }
impl DiagnosticExt for Diagnostic<usize> { impl DiagnosticExt for Diagnostic<usize> {
fn with_opt_label(self, label: Option<Label<usize>>) -> Self { fn with_label(self, label: Label<usize>) -> Self {
if let Some(label) = label { self.with_labels(vec![label])
self.with_labels(vec![label])
} else {
self
}
} }
} }
@ -83,16 +79,14 @@ impl ToDiagnostic for AstError {
note = format!("Got: {}", actual), note = format!("Got: {}", actual),
}, },
AstError::ParseError { file_id, source } => { AstError::ParseError { file_id, source } => lalrpop_error_to_diagnostic(source, *file_id),
lalrpop_error_to_diagnostic(source, *file_id, |error| error.to_diagnostic())
}
AstError::MismatchedElementName(span, expected, got) => gen_diagnostic! { AstError::MismatchedElementName(span, expected, got) => gen_diagnostic! {
msg = format!("Expected element `{}`, but found `{}`", expected, got), msg = format!("Expected element `{}`, but found `{}`", expected, got),
label = span => format!("Expected `{}` here", expected), label = span => format!("Expected `{}` here", expected),
note = format!("Expected: {}\nGot: {}", expected, got), note = format!("Expected: {}\nGot: {}", expected, got),
}, },
AstError::ErrorContext { label_span, context, main_err } => { AstError::ErrorContext { label_span, context, main_err } => {
main_err.to_diagnostic().with_opt_label(Some(span_to_secondary_label(*label_span).with_message(context))) main_err.to_diagnostic().with_label(span_to_secondary_label(*label_span).with_message(context))
} }
AstError::ConversionError(source) => source.to_diagnostic(), AstError::ConversionError(source) => source.to_diagnostic(),
@ -118,7 +112,7 @@ impl ToDiagnostic for parse_error::ParseError {
fn to_diagnostic(&self) -> Diagnostic<usize> { fn to_diagnostic(&self) -> Diagnostic<usize> {
match self { match self {
parse_error::ParseError::SimplExpr(error) => error.to_diagnostic(), parse_error::ParseError::SimplExpr(error) => error.to_diagnostic(),
parse_error::ParseError::LexicalError(span) => lexical_error_diagnostic(*span), parse_error::ParseError::LexicalError(span) => generate_lexical_error_diagnostic(*span),
} }
} }
} }
@ -142,45 +136,43 @@ impl ToDiagnostic for ValidationError {
msg = self, msg = self,
label = span => "Used here", label = span => "Used here",
}, },
ValidationError::MissingAttr { widget_name, arg_name, arg_list_span, use_span } => gen_diagnostic!(self) ValidationError::MissingAttr { widget_name, arg_name, arg_list_span, use_span } => {
.with_opt_label(Some(span_to_secondary_label(*use_span).with_message("Argument missing here"))) let mut diag =
.with_opt_label(arg_list_span.map(|s| span_to_secondary_label(s).with_message("but is required here"))), gen_diagnostic!(self).with_label(span_to_secondary_label(*use_span).with_message("Argument missing here"));
if let Some(arg_list_span) = arg_list_span {
diag = diag.with_label(span_to_secondary_label(*arg_list_span).with_message("But is required here"));
}
diag
}
} }
} }
} }
fn lalrpop_error_to_diagnostic<T: std::fmt::Display, E: std::fmt::Display>( fn lalrpop_error_to_diagnostic<T: std::fmt::Display, E: Spanned + ToDiagnostic>(
error: &lalrpop_util::ParseError<usize, T, E>, error: &lalrpop_util::ParseError<usize, T, E>,
file_id: usize, file_id: usize,
handle_user_error: impl FnOnce(&E) -> Diagnostic<usize>,
) -> Diagnostic<usize> { ) -> Diagnostic<usize> {
use lalrpop_util::ParseError::*; 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| Span::DUMMY);
match error { match error {
InvalidToken { location } => gen_diagnostic!("Invalid token", span), InvalidToken { location } => gen_diagnostic!("Invalid token", Span::point(*location, file_id)),
UnrecognizedEOF { location, expected } => gen_diagnostic! { UnrecognizedEOF { location, expected } => gen_diagnostic! {
msg = "Input ended unexpectedly. Check if you have any unclosed delimiters", msg = "Input ended unexpectedly. Check if you have any unclosed delimiters",
label = span label = Span::point(*location, file_id),
}, },
UnrecognizedToken { token, expected } => gen_diagnostic! { UnrecognizedToken { token, expected } => gen_diagnostic! {
msg = format!("Unexpected token `{}` encountered", token.1), msg = format!("Unexpected token `{}` encountered", token.1),
label = span => "Token unexpected", label = Span(token.0, token.2, file_id) => "Token unexpected",
}, },
ExtraToken { token } => gen_diagnostic!(format!("Extra token encountered: `{}`", token.1)), ExtraToken { token } => gen_diagnostic!(format!("Extra token encountered: `{}`", token.1)),
User { error } => handle_user_error(error), User { error } => error.to_diagnostic(),
} }
} }
impl ToDiagnostic for simplexpr::error::Error { impl ToDiagnostic for simplexpr::error::Error {
// TODO this needs a lot of improvement
fn to_diagnostic(&self) -> Diagnostic<usize> { fn to_diagnostic(&self) -> Diagnostic<usize> {
use simplexpr::error::Error::*; use simplexpr::error::Error::*;
match self { match self {
ParseError { source, file_id } => { ParseError { source, file_id } => lalrpop_error_to_diagnostic(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))
}
ConversionError(error) => error.to_diagnostic(), ConversionError(error) => error.to_diagnostic(),
Eval(error) => error.to_diagnostic(), Eval(error) => error.to_diagnostic(),
Other(error) => gen_diagnostic!(error), Other(error) => gen_diagnostic!(error),
@ -189,8 +181,13 @@ impl ToDiagnostic for simplexpr::error::Error {
} }
} }
impl ToDiagnostic for simplexpr::parser::lexer::LexicalError {
fn to_diagnostic(&self) -> Diagnostic<usize> {
generate_lexical_error_diagnostic(self.span())
}
}
impl ToDiagnostic for simplexpr::eval::EvalError { impl ToDiagnostic for simplexpr::eval::EvalError {
// TODO this needs a lot of improvement
fn to_diagnostic(&self) -> Diagnostic<usize> { fn to_diagnostic(&self) -> Diagnostic<usize> {
gen_diagnostic!(self, self.span()) gen_diagnostic!(self, self.span())
} }
@ -206,8 +203,7 @@ impl ToDiagnostic for dynval::ConversionError {
} }
} }
/// Generate a simple diagnostic indicating a lexical error fn generate_lexical_error_diagnostic(span: Span) -> Diagnostic<usize> {
fn lexical_error_diagnostic(span: Span) -> Diagnostic<usize> {
gen_diagnostic! { gen_diagnostic! {
msg = "Invalid token", msg = "Invalid token",
label = span => "Invalid token" label = span => "Invalid token"

View file

@ -6,5 +6,4 @@ pub mod config;
pub mod error; pub mod error;
pub mod format_diagnostic; pub mod format_diagnostic;
pub mod parser; pub mod parser;
mod util;
pub mod value; pub mod value;

View file

@ -2,7 +2,7 @@ use super::{
ast::{Ast, AstType}, ast::{Ast, AstType},
ast_iterator::AstIterator, ast_iterator::AstIterator,
}; };
use crate::{error::*, parser, util}; use crate::{error::*, parser};
use eww_shared_util::{AttrName, Span, VarName}; use eww_shared_util::{AttrName, Span, VarName};
use itertools::Itertools; use itertools::Itertools;
use simplexpr::{ast::SimplExpr, dynval::DynVal}; use simplexpr::{ast::SimplExpr, dynval::DynVal};

View file

@ -1,4 +1,4 @@
use eww_shared_util::{AttrName, Span, VarName}; use eww_shared_util::{AttrName, Span, Spanned, VarName};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum ParseError { pub enum ParseError {
@ -8,8 +8,8 @@ pub enum ParseError {
LexicalError(Span), LexicalError(Span),
} }
impl ParseError { impl Spanned for ParseError {
pub fn span(&self) -> Span { fn span(&self) -> Span {
match self { match self {
ParseError::SimplExpr(err) => err.span(), ParseError::SimplExpr(err) => err.span(),
ParseError::LexicalError(span) => *span, ParseError::LexicalError(span) => *span,