add basic config structure parsing and add some validation, mostly to demonstrate
This commit is contained in:
parent
de9d979ce5
commit
bfb7c5a27b
14 changed files with 300 additions and 46 deletions
|
@ -1,23 +1,28 @@
|
|||
use eww_config::{ast::*, config::*, format_diagnostic::ToDiagnostic};
|
||||
use eww_config::{
|
||||
config::*,
|
||||
format_diagnostic::ToDiagnostic,
|
||||
parser::{ast::*, element::FromAst},
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let mut files = codespan_reporting::files::SimpleFiles::new();
|
||||
|
||||
let input = r#"
|
||||
(heyho :foo { "foo \" } bar " }
|
||||
:baz {(foo == bar ? 12.2 : 12)}
|
||||
(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::parse_string(file_id, input);
|
||||
match ast.and_then(Element::<Ast, Ast>::from_ast) {
|
||||
let ast = eww_config::parser::parse_string(file_id, input);
|
||||
match ast.and_then(eww_config::parser::element::Element::<Ast, Ast>::from_ast) {
|
||||
Ok(ast) => {
|
||||
println!("{:?}", ast);
|
||||
}
|
||||
Err(err) => {
|
||||
dbg!(&err);
|
||||
let diag = err.to_diagnostic(&files);
|
||||
let diag = err.to_diagnostic();
|
||||
use codespan_reporting::term;
|
||||
let config = term::Config::default();
|
||||
let mut writer = term::termcolor::StandardStream::stderr(term::termcolor::ColorChoice::Always);
|
||||
|
|
40
examples/validation.rs
Normal file
40
examples/validation.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use eww_config::{
|
||||
config::{widget_definition::WidgetDefinition, widget_use::WidgetUse, *},
|
||||
error::AstError,
|
||||
format_diagnostic::ToDiagnostic,
|
||||
parser::{ast::*, element::FromAst},
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let mut files = codespan_reporting::files::SimpleFiles::new();
|
||||
|
||||
let input_use = r#"
|
||||
(foo :something 12
|
||||
:bla "bruh"
|
||||
"some text")
|
||||
"#;
|
||||
let input_def = r#"
|
||||
(defwidget foo [something bla] "foo")
|
||||
"#;
|
||||
|
||||
let file_id_use = files.add("use.eww", input_use);
|
||||
let file_id_def = files.add("def.eww", input_def);
|
||||
let parsed_use = WidgetUse::from_ast(eww_config::parser::parse_string(file_id_use, input_use).unwrap()).unwrap();
|
||||
let parsed_def = WidgetDefinition::from_ast(eww_config::parser::parse_string(file_id_def, input_def).unwrap()).unwrap();
|
||||
let defs = maplit::hashmap! {
|
||||
"foo".to_string() => parsed_def,
|
||||
};
|
||||
match validate::validate(&defs, &parsed_use) {
|
||||
Ok(ast) => {
|
||||
println!("{:?}", ast);
|
||||
}
|
||||
Err(err) => {
|
||||
let err = AstError::ValidationError(err);
|
||||
let diag = err.to_diagnostic();
|
||||
use codespan_reporting::term;
|
||||
let config = term::Config::default();
|
||||
let mut writer = term::termcolor::StandardStream::stderr(term::termcolor::ColorChoice::Always);
|
||||
term::emit(&mut writer, &config, &files, &diag).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub mod validate;
|
||||
pub mod widget_definition;
|
||||
pub mod widget_use;
|
42
src/config/validate.rs
Normal file
42
src/config/validate.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use simplexpr::SimplExpr;
|
||||
|
||||
use crate::{
|
||||
error::AstResult,
|
||||
parser::{
|
||||
ast::{Ast, AstIterator, Span},
|
||||
element::{Element, FromAst},
|
||||
},
|
||||
spanned,
|
||||
value::{AttrName, VarName},
|
||||
};
|
||||
|
||||
use super::{widget_definition::WidgetDefinition, widget_use::WidgetUse};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ValidationError {
|
||||
#[error("Unknown widget referenced: {1}")]
|
||||
UnknownWidget(Span, String),
|
||||
|
||||
#[error("Missing attribute `{arg_name}` in use of widget `{widget_name}`")]
|
||||
MissingAttr { widget_name: String, arg_name: AttrName, arg_list_span: Span, use_span: Span },
|
||||
}
|
||||
|
||||
pub fn validate(defs: &HashMap<String, WidgetDefinition>, content: &WidgetUse) -> Result<(), ValidationError> {
|
||||
if let Some(def) = defs.get(&content.name) {
|
||||
for expected in def.expected_args.iter() {
|
||||
if !content.attrs.contains_key(expected) {
|
||||
return Err(ValidationError::MissingAttr {
|
||||
widget_name: def.name.to_string(),
|
||||
arg_name: expected.clone(),
|
||||
arg_list_span: def.args_span,
|
||||
use_span: content.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(ValidationError::UnknownWidget(content.span, content.name.to_string()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
44
src/config/widget_definition.rs
Normal file
44
src/config/widget_definition.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use simplexpr::SimplExpr;
|
||||
|
||||
use crate::{
|
||||
error::AstResult,
|
||||
parser::{
|
||||
ast::{Ast, AstIterator, Span},
|
||||
element::{Element, FromAst},
|
||||
},
|
||||
spanned,
|
||||
value::{AttrName, VarName},
|
||||
};
|
||||
|
||||
use super::widget_use::WidgetUse;
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct WidgetDefinition {
|
||||
pub name: String,
|
||||
pub expected_args: Vec<AttrName>,
|
||||
pub widget: WidgetUse,
|
||||
pub span: Span,
|
||||
pub args_span: Span,
|
||||
}
|
||||
|
||||
impl FromAst for WidgetDefinition {
|
||||
fn from_ast(e: Ast) -> AstResult<Self> {
|
||||
let span = e.span();
|
||||
spanned!(e.span(), {
|
||||
let list = e.as_list()?;
|
||||
let mut iter = AstIterator::new(list.into_iter());
|
||||
|
||||
let (_, def_type) = iter.expect_symbol()?;
|
||||
assert!(def_type == "defwidget");
|
||||
|
||||
let (_, name) = iter.expect_symbol()?;
|
||||
let (args_span, expected_args) = iter.expect_array()?;
|
||||
let expected_args = expected_args.into_iter().map(|x| x.as_symbol().map(AttrName)).collect::<AstResult<_>>()?;
|
||||
let widget = iter.expect_any().and_then(WidgetUse::from_ast)?;
|
||||
// TODO verify that this was the last element in the list
|
||||
// iter.expect_done()?;
|
||||
Self { name, expected_args, widget, span, args_span }
|
||||
})
|
||||
}
|
||||
}
|
43
src/config/widget_use.rs
Normal file
43
src/config/widget_use.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use simplexpr::SimplExpr;
|
||||
|
||||
use crate::{
|
||||
error::AstResult,
|
||||
parser::{
|
||||
ast::{Ast, AstIterator, Span},
|
||||
element::{Element, FromAst},
|
||||
},
|
||||
spanned,
|
||||
value::AttrName,
|
||||
};
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct WidgetUse {
|
||||
pub name: String,
|
||||
pub attrs: HashMap<AttrName, SimplExpr>,
|
||||
pub children: Vec<WidgetUse>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl FromAst for WidgetUse {
|
||||
fn from_ast(e: Ast) -> AstResult<Self> {
|
||||
let span = e.span();
|
||||
spanned!(e.span(), {
|
||||
if let Ok(text) = e.as_value_ref() {
|
||||
Self {
|
||||
name: "text".to_string(),
|
||||
attrs: maplit::hashmap! { AttrName("text".to_string()) => SimplExpr::Literal(span.into(), text.clone()) },
|
||||
children: Vec::new(),
|
||||
span,
|
||||
}
|
||||
} else {
|
||||
let list = e.as_list()?;
|
||||
let mut iter = AstIterator::new(list.into_iter());
|
||||
let (_, name) = iter.expect_symbol()?;
|
||||
let attrs = iter.expect_key_values()?.into_iter().map(|(k, v)| (AttrName(k), v)).collect();
|
||||
let children = iter.map(WidgetUse::from_ast).collect::<AstResult<Vec<_>>>()?;
|
||||
Self { name, attrs, children, span }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
34
src/error.rs
34
src/error.rs
|
@ -1,6 +1,9 @@
|
|||
use crate::parser::{
|
||||
ast::{Ast, AstType, Span},
|
||||
lexer, parse_error,
|
||||
use crate::{
|
||||
config::validate::ValidationError,
|
||||
parser::{
|
||||
ast::{Ast, AstType, Span},
|
||||
lexer, parse_error,
|
||||
},
|
||||
};
|
||||
use codespan_reporting::{diagnostic, files};
|
||||
use thiserror::Error;
|
||||
|
@ -11,10 +14,15 @@ pub type AstResult<T> = Result<T, AstError>;
|
|||
pub enum AstError {
|
||||
#[error("Definition invalid")]
|
||||
InvalidDefinition(Option<Span>),
|
||||
#[error("Expected a {1}, but got nothing")]
|
||||
MissingNode(Option<Span>, AstType),
|
||||
#[error("Expected another element, but got nothing")]
|
||||
MissingNode(Option<Span>),
|
||||
#[error("Wrong type of expression: Expected {1} but got {2}")]
|
||||
WrongExprType(Option<Span>, AstType, AstType),
|
||||
#[error("Expected to get a value, but got {1}")]
|
||||
NotAValue(Option<Span>, AstType),
|
||||
|
||||
#[error(transparent)]
|
||||
ValidationError(#[from] ValidationError),
|
||||
|
||||
#[error("Parse error: {source}")]
|
||||
ParseError { file_id: Option<usize>, source: lalrpop_util::ParseError<usize, lexer::Token, parse_error::ParseError> },
|
||||
|
@ -24,8 +32,10 @@ impl AstError {
|
|||
pub fn get_span(&self) -> Option<Span> {
|
||||
match self {
|
||||
AstError::InvalidDefinition(span) => *span,
|
||||
AstError::MissingNode(span, _) => *span,
|
||||
AstError::MissingNode(span) => *span,
|
||||
AstError::WrongExprType(span, ..) => *span,
|
||||
AstError::NotAValue(span, ..) => *span,
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
@ -58,18 +68,18 @@ pub fn spanned(span: Span, err: impl Into<AstError>) -> AstError {
|
|||
use AstError::*;
|
||||
match err.into() {
|
||||
AstError::InvalidDefinition(None) => AstError::InvalidDefinition(Some(span)),
|
||||
AstError::MissingNode(None, x) => AstError::MissingNode(Some(span), x),
|
||||
AstError::MissingNode(None) => AstError::MissingNode(Some(span)),
|
||||
AstError::WrongExprType(None, x, y) => AstError::WrongExprType(Some(span), x, y),
|
||||
x => x,
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OptionAstErrorExt<T> {
|
||||
fn or_missing(self, t: AstType) -> Result<T, AstError>;
|
||||
fn or_missing(self) -> Result<T, AstError>;
|
||||
}
|
||||
impl<T> OptionAstErrorExt<T> for Option<T> {
|
||||
fn or_missing(self, t: AstType) -> Result<T, AstError> {
|
||||
self.ok_or(AstError::MissingNode(None, t))
|
||||
fn or_missing(self) -> Result<T, AstError> {
|
||||
self.ok_or(AstError::MissingNode(None))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +97,7 @@ impl<T, E: Into<AstError>> AstResultExt<T> for Result<T, E> {
|
|||
macro_rules! spanned {
|
||||
($span:expr, $block:expr) => {{
|
||||
let span = $span;
|
||||
let result: Result<_, AstError> = try { $block };
|
||||
result.at(span)
|
||||
let result: Result<_, crate::error::AstError> = try { $block };
|
||||
crate::error::AstResultExt::at(result, span)
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ macro_rules! gen_diagnostic {
|
|||
Diagnostic::error()
|
||||
$(.with_message($msg))?
|
||||
$(.with_labels(vec![
|
||||
Label::primary($span.2, $span.0..$span.1)
|
||||
$(.with_message($label))?
|
||||
Label::primary($span.2, $span.0..$span.1)
|
||||
$(.with_message($label))?
|
||||
]))?
|
||||
$(.with_notes(vec![$note]))?
|
||||
};
|
||||
|
@ -34,15 +34,29 @@ pub trait ToDiagnostic {
|
|||
|
||||
impl ToDiagnostic for AstError {
|
||||
fn to_diagnostic(&self) -> Diagnostic<usize> {
|
||||
let diag = Diagnostic::error();
|
||||
if let Some(span) = self.get_span() {
|
||||
use lalrpop_util::ParseError::*;
|
||||
if let AstError::ValidationError(error) = self {
|
||||
match error {
|
||||
crate::config::validate::ValidationError::UnknownWidget(span, name) => gen_diagnostic! {
|
||||
msg = format!("No widget named {} exists", name),
|
||||
label = span => "Used here",
|
||||
},
|
||||
crate::config::validate::ValidationError::MissingAttr { widget_name, arg_name, arg_list_span, use_span } => {
|
||||
let diag = gen_diagnostic! {
|
||||
msg = format!("{}", error),
|
||||
};
|
||||
diag.with_labels(vec![
|
||||
Label::secondary(use_span.2, use_span.0..use_span.1).with_message("Argument missing here"),
|
||||
Label::secondary(arg_list_span.2, arg_list_span.0..arg_list_span.1).with_message("but is required here"),
|
||||
])
|
||||
}
|
||||
}
|
||||
} else if let Some(span) = self.get_span() {
|
||||
match self {
|
||||
AstError::InvalidDefinition(_) => todo!(),
|
||||
|
||||
AstError::MissingNode(_, expected) => gen_diagnostic! {
|
||||
msg = format!("Missing {}", expected),
|
||||
label = span => format!("Expected `{}` here", expected),
|
||||
AstError::MissingNode(_) => gen_diagnostic! {
|
||||
msg = "Expected another element",
|
||||
label = span => "Expected another element here",
|
||||
},
|
||||
|
||||
AstError::WrongExprType(_, expected, actual) => gen_diagnostic! {
|
||||
|
@ -50,14 +64,20 @@ impl ToDiagnostic for AstError {
|
|||
label = span => format!("Expected a `{}` here", expected),
|
||||
note = format!("Expected: {}\nGot: {}", expected, actual),
|
||||
},
|
||||
AstError::NotAValue(_, 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, span, |error| match error {
|
||||
parse_error::ParseError::SimplExpr(_, error) => simplexpr_error_to_diagnostic(error, span),
|
||||
parse_error::ParseError::LexicalError(_) => lexical_error_to_diagnostic(span),
|
||||
}),
|
||||
_ => panic!(),
|
||||
}
|
||||
} else {
|
||||
diag.with_message(format!("{}", self))
|
||||
Diagnostic::error().with_message(format!("{}", self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +106,7 @@ fn lalrpop_error_to_diagnostic<T: std::fmt::Display, E>(
|
|||
fn simplexpr_error_to_diagnostic(error: &simplexpr::error::Error, span: Span) -> Diagnostic<usize> {
|
||||
use simplexpr::error::Error::*;
|
||||
match error {
|
||||
ParseError { source } => lalrpop_error_to_diagnostic(source, span, move |error| lexical_error_to_diagnostic(span)),
|
||||
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),
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
use itertools::Itertools;
|
||||
use simplexpr::ast::SimplExpr;
|
||||
use simplexpr::{ast::SimplExpr, dynval::DynVal};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::element::FromAst;
|
||||
use crate::error::{AstError, AstResult};
|
||||
use crate::error::{AstError, AstResult, OptionAstErrorExt};
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Copy)]
|
||||
pub struct Span(pub usize, pub usize, pub usize);
|
||||
|
||||
impl Into<simplexpr::Span> for Span {
|
||||
fn into(self) -> simplexpr::Span {
|
||||
simplexpr::Span(self.0, self.1, self.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Span {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}..{}", self.0, self.1)
|
||||
|
@ -45,7 +51,7 @@ pub enum Ast {
|
|||
Array(Span, Vec<Ast>),
|
||||
Keyword(Span, String),
|
||||
Symbol(Span, String),
|
||||
Value(Span, String),
|
||||
Value(Span, DynVal),
|
||||
SimplExpr(Span, SimplExpr),
|
||||
Comment(Span),
|
||||
}
|
||||
|
@ -69,7 +75,7 @@ macro_rules! as_func {
|
|||
}
|
||||
|
||||
impl Ast {
|
||||
as_func!(AstType::Value, as_value as_value_ref<String> = Ast::Value(_, x) => x);
|
||||
as_func!(AstType::Value, as_value as_value_ref<DynVal> = Ast::Value(_, x) => x);
|
||||
|
||||
as_func!(AstType::Symbol, as_symbol as_symbol_ref<String> = Ast::Symbol(_, x) => x);
|
||||
|
||||
|
@ -155,7 +161,7 @@ macro_rules! return_or_put_back {
|
|||
self.iter.put_back(other);
|
||||
Err(AstError::WrongExprType(Some(span), expr_type, actual_type))
|
||||
}
|
||||
None => Err(AstError::MissingNode(None, expr_type)),
|
||||
None => Err(AstError::MissingNode(None)),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -164,14 +170,20 @@ macro_rules! return_or_put_back {
|
|||
impl<I: Iterator<Item = Ast>> AstIterator<I> {
|
||||
return_or_put_back!(expect_symbol, AstType::Symbol, (Span, String) = Ast::Symbol(span, x) => (span, x));
|
||||
|
||||
return_or_put_back!(expect_string, AstType::Value, (Span, String) = Ast::Value(span, x) => (span, x));
|
||||
return_or_put_back!(expect_value, AstType::Value, (Span, DynVal) = Ast::Value(span, x) => (span, x));
|
||||
|
||||
return_or_put_back!(expect_list, AstType::List, (Span, Vec<Ast>) = Ast::List(span, x) => (span, x));
|
||||
|
||||
return_or_put_back!(expect_array, AstType::Array, (Span, Vec<Ast>) = Ast::Array(span, x) => (span, x));
|
||||
|
||||
pub fn new(iter: I) -> Self {
|
||||
AstIterator { iter: itertools::put_back(iter) }
|
||||
}
|
||||
|
||||
pub fn expect_any<T: FromAst>(&mut self) -> AstResult<T> {
|
||||
self.iter.next().or_missing().and_then(T::from_ast)
|
||||
}
|
||||
|
||||
pub fn expect_key_values<T: FromAst>(&mut self) -> AstResult<HashMap<String, T>> {
|
||||
parse_key_values(&mut self.iter)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
use super::ast::{Ast, AstIterator, AstType, Span};
|
||||
use crate::{error::*, parser, spanned};
|
||||
use crate::{error::*, parser, spanned, value::AttrName};
|
||||
use itertools::Itertools;
|
||||
use simplexpr::ast::SimplExpr;
|
||||
use std::{
|
||||
collections::{HashMap, LinkedList},
|
||||
iter::FromIterator,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
type VarName = String;
|
||||
type AttrValue = String;
|
||||
type AttrName = String;
|
||||
|
||||
pub trait FromAst: Sized {
|
||||
fn from_ast(e: Ast) -> AstResult<Self>;
|
||||
}
|
||||
|
@ -21,6 +18,17 @@ impl FromAst for Ast {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromAst for SimplExpr {
|
||||
fn from_ast(e: Ast) -> AstResult<Self> {
|
||||
match e {
|
||||
Ast::Symbol(span, x) => Ok(SimplExpr::VarRef(span.into(), x)),
|
||||
Ast::Value(span, x) => Ok(SimplExpr::Literal(span.into(), x)),
|
||||
Ast::SimplExpr(span, x) => Ok(x),
|
||||
_ => Err(AstError::NotAValue(Some(e.span()), e.expr_type())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Element<C, A> {
|
||||
name: String,
|
||||
|
@ -36,7 +44,7 @@ impl<C: FromAst, A: FromAst> FromAst for Element<C, A> {
|
|||
let list = e.as_list()?;
|
||||
let mut iter = AstIterator::new(list.into_iter());
|
||||
let (_, name) = iter.expect_symbol()?;
|
||||
let attrs = iter.expect_key_values()?;
|
||||
let attrs = iter.expect_key_values()?.into_iter().map(|(k, v)| (AttrName(k), v)).collect();
|
||||
let children = iter.map(C::from_ast).collect::<AstResult<Vec<_>>>()?;
|
||||
Element { span, name, attrs, children }
|
||||
})
|
||||
|
|
|
@ -61,12 +61,12 @@ regex_rules! {
|
|||
r"\(" => |_| Token::LPren,
|
||||
r"\)" => |_| Token::RPren,
|
||||
r"\[" => |_| Token::LBrack,
|
||||
r"\]" => |_| Token::LBrack,
|
||||
r"\]" => |_| Token::RBrack,
|
||||
r"true" => |_| Token::True,
|
||||
r"false" => |_| Token::False,
|
||||
r#""(?:[^"\\]|\\.)*""# => |x| Token::StrLit(x),
|
||||
r#"[+-]?(?:[0-9]+[.])?[0-9]+"# => |x| Token::NumLit(x),
|
||||
r#"[a-zA-Z_!\?<>/.*-+][^\s{}\(\)]*"# => |x| Token::Symbol(x),
|
||||
r#"[a-zA-Z_!\?<>/.*-+][^\s{}\(\)\[\](){}]*"# => |x| Token::Symbol(x),
|
||||
r#":\S+"# => |x| Token::Keyword(x),
|
||||
r#";.*"# => |_| Token::Comment,
|
||||
r"[ \t\n\f]+" => |_| Token::Skip
|
||||
|
@ -141,7 +141,9 @@ impl Iterator for Lexer {
|
|||
self.pos += len;
|
||||
match LEXER_FNS[i](tok_str.to_string()) {
|
||||
Token::Skip => {}
|
||||
token => return Some(Ok((old_pos, token, self.pos))),
|
||||
token => {
|
||||
return Some(Ok((old_pos, token, self.pos)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ pub Ast: Ast = {
|
|||
<l:@L> <expr:SimplExpr> <r:@R> => Ast::SimplExpr(Span(l, r, file_id), expr),
|
||||
<x:Keyword> => x,
|
||||
<x:Symbol> => x,
|
||||
<l:@L> <x:Value> <r:@R> => Ast::Value(Span(l, r, file_id), x),
|
||||
<l:@L> <x:Value> <r:@R> => Ast::Value(Span(l, r, file_id), x.into()),
|
||||
<l:@L> "comment" <r:@R> => Ast::Comment(Span(l, r, file_id)),
|
||||
};
|
||||
|
||||
|
@ -55,8 +55,8 @@ StrLit: String = {
|
|||
SimplExpr: SimplExpr = {
|
||||
<l:@L> <x:"simplexpr"> =>? {
|
||||
let expr = x[1..x.len() - 1].to_string();
|
||||
simplexpr::parse_string(&expr).map_err(|e| {
|
||||
let span = e.get_span().map(|simplexpr::Span(simpl_l, simpl_r)| Span(1 + l + simpl_l, 1 + l + simpl_r, file_id));
|
||||
simplexpr::parse_string(file_id, &expr).map_err(|e| {
|
||||
let span = e.get_span().map(|simplexpr::Span(simpl_l, simpl_r, file_id)| Span(1 + l + simpl_l, 1 + l + simpl_r, file_id));
|
||||
ParseError::User { error: parse_error::ParseError::SimplExpr(span, e) }})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
source: src/parser/element.rs
|
||||
expression: "Element::<Ast, Ast>::from_ast(parser.parse(0, lexer).unwrap()).unwrap()"
|
||||
|
||||
---
|
||||
Element {
|
||||
name: "box",
|
||||
attrs: {
|
||||
":bar": "12",
|
||||
":baz": "hi",
|
||||
},
|
||||
children: [
|
||||
foo,
|
||||
(bar),
|
||||
],
|
||||
span: 0..33,
|
||||
}
|
8
src/parser/snapshots/eww_config__parser__test.snap.new
Normal file
8
src/parser/snapshots/eww_config__parser__test.snap.new
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
source: src/parser/mod.rs
|
||||
expression: "p.parse(0, Lexer::new(0, \"1\".to_string()))"
|
||||
|
||||
---
|
||||
Ok(
|
||||
"1",
|
||||
)
|
Loading…
Add table
Reference in a new issue