Include spans in var_refs of simplexpr

This commit is contained in:
elkowar 2021-08-17 11:53:45 +02:00
parent c20b172662
commit 7abf38cbfc
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F
5 changed files with 39 additions and 23 deletions

View file

@ -15,7 +15,7 @@ pub struct StateChangeHandler {
impl StateChangeHandler { impl StateChangeHandler {
fn used_variables(&self) -> impl Iterator<Item = &VarName> { fn used_variables(&self) -> impl Iterator<Item = &VarName> {
self.unresolved_values.iter().flat_map(|(_, value)| value.var_refs()) self.unresolved_values.iter().flat_map(|(_, value)| value.var_refs()).map(|(_, value)| value)
} }
/// Run the StateChangeHandler. /// Run the StateChangeHandler.

View file

@ -80,7 +80,7 @@ impl Generic {
/// returns all the variables that are referenced in this widget /// returns all the variables that are referenced in this widget
pub fn referenced_vars(&self) -> impl Iterator<Item = &VarName> { pub fn referenced_vars(&self) -> impl Iterator<Item = &VarName> {
self.attrs.iter().flat_map(|(_, value)| value.var_refs()) self.attrs.iter().flat_map(|(_, value)| value.var_refs()).map(|(_, value)| value)
} }
} }

View file

@ -5,7 +5,7 @@ use crate::{
dynval::{ConversionError, DynVal}, dynval::{ConversionError, DynVal},
}; };
use eww_shared_util::{Span, Spanned, VarName}; use eww_shared_util::{Span, Spanned, VarName};
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum EvalError { pub enum EvalError {
@ -102,12 +102,12 @@ impl SimplExpr {
}) })
} }
pub fn var_refs(&self) -> HashSet<&VarName> { pub fn var_refs(&self) -> Vec<(Span, &VarName)> {
use SimplExpr::*; use SimplExpr::*;
match self { match self {
Literal(..) => HashSet::new(), Literal(..) => Vec::new(),
VarRef(span, name) => vec![(*span, name)],
Concat(_, elems) => elems.iter().flat_map(|x| x.var_refs().into_iter()).collect(), Concat(_, elems) => elems.iter().flat_map(|x| x.var_refs().into_iter()).collect(),
VarRef(_, name) => maplit::hashset! { name },
BinOp(_, box a, _, box b) | JsonAccess(_, box a, box b) => { BinOp(_, box a, _, box b) | JsonAccess(_, box a, box b) => {
let mut refs = a.var_refs(); let mut refs = a.var_refs();
refs.extend(b.var_refs().iter()); refs.extend(b.var_refs().iter());
@ -141,7 +141,7 @@ impl SimplExpr {
SimplExpr::Concat(span, elems) => { SimplExpr::Concat(span, elems) => {
let mut output = String::new(); let mut output = String::new();
for elem in elems { for elem in elems {
let result = elem.eval(values)?; let result = dbg!(elem.eval(values))?;
output.push_str(&result.0); output.push_str(&result.0);
} }
Ok(DynVal(output, *span)) Ok(DynVal(output, *span))

View file

@ -10,24 +10,36 @@ pub fn b<T>(x: T) -> Box<T> {
pub fn parse_stringlit( pub fn parse_stringlit(
span: Span, span: Span,
segs: Vec<Sp<StrLitSegment>>, mut segs: Vec<Sp<StrLitSegment>>,
) -> Result<SimplExpr, lalrpop_util::ParseError<usize, Token, LexicalError>> { ) -> Result<SimplExpr, lalrpop_util::ParseError<usize, Token, LexicalError>> {
let file_id = span.2; let file_id = span.2;
let parser = crate::simplexpr_parser::ExprParser::new(); let parser = crate::simplexpr_parser::ExprParser::new();
let elems = segs if segs.len() == 1 {
.into_iter() let (lo, seg, hi) = segs.remove(0);
.filter_map(|(lo, segment, hi)| { let span = Span(lo, hi, file_id);
let span = Span(lo, hi, file_id); match seg {
match segment { StrLitSegment::Literal(lit) => Ok(SimplExpr::Literal(DynVal(lit, span))),
StrLitSegment::Literal(lit) if lit.is_empty() => None, StrLitSegment::Interp(toks) => {
StrLitSegment::Literal(lit) => Some(Ok(SimplExpr::Literal(DynVal(lit, span)))), let token_stream = toks.into_iter().map(|x| Ok(x));
StrLitSegment::Interp(toks) => { parser.parse(file_id, token_stream)
let token_stream = toks.into_iter().map(|x| Ok(x));
Some(parser.parse(file_id, token_stream))
}
} }
}) }
.collect::<Result<Vec<SimplExpr>, _>>()?; } else {
Ok(SimplExpr::Concat(span, elems)) let elems = segs
.into_iter()
.filter_map(|(lo, segment, hi)| {
let span = Span(lo, hi, file_id);
match segment {
StrLitSegment::Literal(lit) if lit.is_empty() => None,
StrLitSegment::Literal(lit) => Some(Ok(SimplExpr::Literal(DynVal(lit, span)))),
StrLitSegment::Interp(toks) => {
let token_stream = toks.into_iter().map(|x| Ok(x));
Some(parser.parse(file_id, token_stream))
}
}
})
.collect::<Result<Vec<SimplExpr>, _>>()?;
Ok(SimplExpr::Concat(span, elems))
}
} }

View file

@ -87,7 +87,11 @@ pub fn validate_variables_in_widget_use(
let values = widget.attrs.attrs.values(); let values = widget.attrs.attrs.values();
let unknown_var = values.filter_map(|value| value.value.as_simplexpr().ok()).find_map(|expr: SimplExpr| { let unknown_var = values.filter_map(|value| value.value.as_simplexpr().ok()).find_map(|expr: SimplExpr| {
let span = expr.span(); let span = expr.span();
expr.var_refs().iter().map(move |&x| (span, x.clone())).find(|(span, var_ref)| !variables.contains(var_ref)) expr.var_refs()
.iter()
.cloned()
.map(|(span, var_ref)| (span, var_ref.clone()))
.find(|(_, var_ref)| !variables.contains(var_ref))
}); });
if let Some((span, var)) = unknown_var { if let Some((span, var)) = unknown_var {
return Err(ValidationError::UnknownVariable { span, name: var.clone(), in_definition: is_in_definition }); return Err(ValidationError::UnknownVariable { span, name: var.clone(), in_definition: is_in_definition });