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"]
x11 = ["gdkx11", "x11rb"]
wayland = ["gtk-layer-shell", "gtk-layer-shell-sys"]
no-x11-wayland = []
[dependencies.cairo-sys-rs]
version = "0.10.0"
@ -70,9 +69,8 @@ notify = "5.0.0-pre.7"
codespan-reporting = "0.11"
simplexpr = { path = "../simplexpr" }
yuck = { path = "../yuck", default-features = false}
eww_shared_util = { path = "../eww_shared_util" }
yuck = { path = "../yuck", default-features = false}
[dev-dependencies]
pretty_assertions = "0.7.1"

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
use crate::dynval::DynVal;
use eww_shared_util::Span;
use eww_shared_util::{Span, Spanned};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
@ -69,8 +69,9 @@ impl SimplExpr {
pub fn synth_literal<T: Into<DynVal>>(s: T) -> Self {
Self::Literal(Span::DUMMY, s.into())
}
pub fn span(&self) -> Span {
}
impl Spanned for SimplExpr {
fn span(&self) -> Span {
match self {
SimplExpr::Literal(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 serde::{Deserialize, Serialize};
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 {
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
}
}
@ -111,15 +112,17 @@ impl From<&serde_json::Value> for DynVal {
}
}
impl Spanned for DynVal {
fn span(&self) -> Span {
self.1
}
}
impl DynVal {
pub fn at(self, span: Span) -> Self {
DynVal(self.0, span)
}
pub fn span(&self) -> Span {
self.1
}
pub fn from_string(s: String) -> Self {
DynVal(s, Span::DUMMY)
}

View file

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

View file

@ -4,7 +4,7 @@ use crate::{
ast::{BinOp, SimplExpr, UnaryOp},
dynval::{ConversionError, DynVal},
};
use eww_shared_util::{Span, VarName};
use eww_shared_util::{Span, Spanned, VarName};
use std::collections::HashMap;
#[derive(Debug, thiserror::Error)]
@ -18,7 +18,7 @@ pub enum EvalError {
#[error("got unresolved variable `{0}`")]
UnresolvedVariable(VarName),
#[error("Type error: {0}")]
#[error(transparent)]
ConversionError(#[from] ConversionError),
#[error("Incorrect number of arguments given to function: {0}")]
@ -38,17 +38,19 @@ pub enum 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 {
EvalError::Spanned(span, _) => *span,
EvalError::ConversionError(err) => err.span(),
_ => Span::DUMMY,
}
}
pub fn at(self, span: Span) -> Self {
Self::Spanned(span, Box::new(self))
}
}
impl SimplExpr {
@ -98,7 +100,6 @@ impl SimplExpr {
pub fn resolve_refs(self, variables: &HashMap<VarName, DynVal>) -> Result<Self, EvalError> {
use SimplExpr::*;
match self {
// Literal(x) => Ok(Literal(AttrValue::from_primitive(x.resolve_fully(&variables)?))),
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)?)),
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 regex::Regex;
@ -48,10 +49,15 @@ pub enum Token {
Error,
}
// TODO can i include the fileid here already?
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
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 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Lexical error at {}..{}", self.0, self.1)

View file

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

View file

@ -13,7 +13,7 @@ use crate::{
error::AstError,
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)]
pub enum AttrError {
@ -27,8 +27,8 @@ pub enum AttrError {
Other(Span, Box<dyn std::error::Error + Sync + Send + 'static>),
}
impl AttrError {
pub fn span(&self) -> Span {
impl Spanned for AttrError {
fn span(&self) -> Span {
match self {
AttrError::MissingRequiredAttr(span, _) => *span,
AttrError::EvaluationError(span, _) => *span,
@ -90,7 +90,7 @@ impl Attributes {
let ast: SimplExpr = self.ast_required(&key)?;
Ok(ast
.eval_no_vars()
.map_err(|err| AttrError::EvaluationError(ast.span().into(), err))?
.map_err(|err| AttrError::EvaluationError(ast.span(), err))?
.read_as()
.map_err(|e| AttrError::Other(ast.span().into(), Box::new(e)))?)
}
@ -106,7 +106,7 @@ impl Attributes {
};
Ok(Some(
ast.eval_no_vars()
.map_err(|err| AttrError::EvaluationError(ast.span().into(), err))?
.map_err(|err| AttrError::EvaluationError(ast.span(), err))?
.read_as()
.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.
/// TODO actually use this and implement warnings,... lol
pub fn get_unused(self, definition_span: Span) -> UnusedAttrs {
UnusedAttrs {
definition_span,
attrs: self.attrs.into_iter().map(|(k, v)| (v.key_span.to(v.value.span().into()), k)).collect(),
}
UnusedAttrs { definition_span, attrs: self.attrs.into_iter().map(|(k, v)| (v.key_span.to(v.value.span()), k)).collect() }
}
}

View file

@ -121,7 +121,7 @@ mod backend {
}
}
#[cfg(feature = "no-x11-wayland")]
#[cfg(not(any(feature = "x11", feature = "wayland")))]
mod backend {
use super::*;
#[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 backend_window_options;
pub mod config;
pub mod config_parse_error;
pub mod file_provider;
pub mod script_var_definition;
#[cfg(test)]

View file

@ -8,7 +8,7 @@ use crate::{
};
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)]
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 },
}
impl ValidationError {
pub fn span(&self) -> Span {
impl Spanned for ValidationError {
fn span(&self) -> Span {
match self {
ValidationError::UnknownWidget(span, _) => *span,
ValidationError::MissingAttr { use_span, .. } => *use_span,

View file

@ -7,7 +7,7 @@ use crate::{
},
};
use codespan_reporting::{diagnostic, files};
use eww_shared_util::{AttrName, Span, VarName};
use eww_shared_util::{AttrName, Span, Spanned, VarName};
use simplexpr::dynval;
use thiserror::Error;
@ -66,7 +66,16 @@ impl AstError {
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 {
AstError::UnknownToplevel(span, _) => *span,
AstError::MissingNode(span) => *span,
@ -80,30 +89,20 @@ impl AstError {
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::ParseError { file_id, source } => get_parse_error_span(*file_id, source),
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>(
file_id: usize,
err: &lalrpop_util::ParseError<usize, T, E>,
handle_user: impl FnOnce(&E) -> Span,
) -> Span {
pub fn get_parse_error_span<T, E: Spanned>(file_id: usize, err: &lalrpop_util::ParseError<usize, T, E>) -> Span {
use lalrpop_util::ParseError::*;
match err {
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),
InvalidToken { location } => Span(*location, *location, file_id),
UnrecognizedEOF { location, expected } => Span(*location, *location, file_id),
UnrecognizedToken { token, expected } => Span(token.0, token.2, file_id),
ExtraToken { token } => Span(token.0, token.2, file_id),
User { error } => error.span(),
}
}

View file

@ -9,7 +9,7 @@ use crate::{
};
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> {
Label::secondary(span.2, span.0..span.1)
@ -38,16 +38,12 @@ macro_rules! gen_diagnostic {
}
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> {
fn with_opt_label(self, label: Option<Label<usize>>) -> Self {
if let Some(label) = label {
self.with_labels(vec![label])
} else {
self
}
fn with_label(self, label: Label<usize>) -> Self {
self.with_labels(vec![label])
}
}
@ -83,16 +79,14 @@ impl ToDiagnostic for AstError {
note = format!("Got: {}", actual),
},
AstError::ParseError { file_id, source } => {
lalrpop_error_to_diagnostic(source, *file_id, |error| error.to_diagnostic())
}
AstError::ParseError { file_id, source } => lalrpop_error_to_diagnostic(source, *file_id),
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)))
main_err.to_diagnostic().with_label(span_to_secondary_label(*label_span).with_message(context))
}
AstError::ConversionError(source) => source.to_diagnostic(),
@ -118,7 +112,7 @@ impl ToDiagnostic for parse_error::ParseError {
fn to_diagnostic(&self) -> Diagnostic<usize> {
match self {
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,
label = span => "Used here",
},
ValidationError::MissingAttr { widget_name, arg_name, arg_list_span, use_span } => gen_diagnostic!(self)
.with_opt_label(Some(span_to_secondary_label(*use_span).with_message("Argument missing here")))
.with_opt_label(arg_list_span.map(|s| span_to_secondary_label(s).with_message("but is required here"))),
ValidationError::MissingAttr { widget_name, arg_name, arg_list_span, use_span } => {
let mut diag =
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>,
file_id: usize,
handle_user_error: impl FnOnce(&E) -> Diagnostic<usize>,
) -> Diagnostic<usize> {
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 {
InvalidToken { location } => gen_diagnostic!("Invalid token", span),
InvalidToken { location } => gen_diagnostic!("Invalid token", Span::point(*location, file_id)),
UnrecognizedEOF { location, expected } => gen_diagnostic! {
msg = "Input ended unexpectedly. Check if you have any unclosed delimiters",
label = span
label = Span::point(*location, file_id),
},
UnrecognizedToken { token, expected } => gen_diagnostic! {
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)),
User { error } => handle_user_error(error),
User { error } => error.to_diagnostic(),
}
}
impl ToDiagnostic for simplexpr::error::Error {
// TODO this needs a lot of improvement
fn to_diagnostic(&self) -> Diagnostic<usize> {
use simplexpr::error::Error::*;
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))
}
ParseError { source, file_id } => lalrpop_error_to_diagnostic(source, *file_id),
ConversionError(error) => error.to_diagnostic(),
Eval(error) => error.to_diagnostic(),
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 {
// TODO this needs a lot of improvement
fn to_diagnostic(&self) -> Diagnostic<usize> {
gen_diagnostic!(self, self.span())
}
@ -206,8 +203,7 @@ impl ToDiagnostic for dynval::ConversionError {
}
}
/// Generate a simple diagnostic indicating a lexical error
fn lexical_error_diagnostic(span: Span) -> Diagnostic<usize> {
fn generate_lexical_error_diagnostic(span: Span) -> Diagnostic<usize> {
gen_diagnostic! {
msg = "Invalid token",
label = span => "Invalid token"

View file

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

View file

@ -2,7 +2,7 @@ use super::{
ast::{Ast, AstType},
ast_iterator::AstIterator,
};
use crate::{error::*, parser, util};
use crate::{error::*, parser};
use eww_shared_util::{AttrName, Span, VarName};
use itertools::Itertools;
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)]
pub enum ParseError {
@ -8,8 +8,8 @@ pub enum ParseError {
LexicalError(Span),
}
impl ParseError {
pub fn span(&self) -> Span {
impl Spanned for ParseError {
fn span(&self) -> Span {
match self {
ParseError::SimplExpr(err) => err.span(),
ParseError::LexicalError(span) => *span,