Skip to content

Commit

Permalink
Make some operators lazily evaluated (#627)
Browse files Browse the repository at this point in the history
* Make some operators lazily evaluated

Fixes #624

* Add to CHANGELOG.md
  • Loading branch information
ModProg authored Jan 5, 2023
1 parent 678e4db commit 3ae3460
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to eww will be listed here, starting at changes since versio
### Features
- Add support for safe access (`?.`) in simplexpr (By: oldwomanjosiah)
- Allow floating-point numbers in percentages for window-geometry
- Made `and`, `or` and `?:` lazily evaluated in simplexpr (By: ModProg)

## [0.4.0] (04.09.2022)

Expand Down
53 changes: 32 additions & 21 deletions crates/simplexpr/src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,35 +179,43 @@ impl SimplExpr {
}
SimplExpr::BinOp(span, a, op, b) => {
let a = a.eval(values)?;
let b = b.eval(values)?;
let b = || b.eval(values);
// Lazy operators
let dynval = match op {
BinOp::Equals => DynVal::from(a == b),
BinOp::NotEquals => DynVal::from(a != b),
BinOp::And => DynVal::from(a.as_bool()? && b.as_bool()?),
BinOp::Or => DynVal::from(a.as_bool()? || b.as_bool()?),
BinOp::Plus => match (a.as_f64(), b.as_f64()) {
(Ok(a), Ok(b)) => DynVal::from(a + b),
_ => DynVal::from(format!("{}{}", a.as_string()?, b.as_string()?)),
},
BinOp::Minus => DynVal::from(a.as_f64()? - b.as_f64()?),
BinOp::Times => DynVal::from(a.as_f64()? * b.as_f64()?),
BinOp::Div => DynVal::from(a.as_f64()? / b.as_f64()?),
BinOp::Mod => DynVal::from(a.as_f64()? % b.as_f64()?),
BinOp::GT => DynVal::from(a.as_f64()? > b.as_f64()?),
BinOp::LT => DynVal::from(a.as_f64()? < b.as_f64()?),
BinOp::GE => DynVal::from(a.as_f64()? >= b.as_f64()?),
BinOp::LE => DynVal::from(a.as_f64()? <= b.as_f64()?),
BinOp::And => DynVal::from(a.as_bool()? && b()?.as_bool()?),
BinOp::Or => DynVal::from(a.as_bool()? || b()?.as_bool()?),
BinOp::Elvis => {
let is_null = matches!(serde_json::from_str(&a.0), Ok(serde_json::Value::Null));
if a.0.is_empty() || is_null {
b
b()?
} else {
a
}
}
BinOp::RegexMatch => {
let regex = regex::Regex::new(&b.as_string()?)?;
DynVal::from(regex.is_match(&a.as_string()?))
// Eager operators
_ => {
let b = b()?;
match op {
BinOp::Equals => DynVal::from(a == b),
BinOp::NotEquals => DynVal::from(a != b),
BinOp::Plus => match (a.as_f64(), b.as_f64()) {
(Ok(a), Ok(b)) => DynVal::from(a + b),
_ => DynVal::from(format!("{}{}", a.as_string()?, b.as_string()?)),
},
BinOp::Minus => DynVal::from(a.as_f64()? - b.as_f64()?),
BinOp::Times => DynVal::from(a.as_f64()? * b.as_f64()?),
BinOp::Div => DynVal::from(a.as_f64()? / b.as_f64()?),
BinOp::Mod => DynVal::from(a.as_f64()? % b.as_f64()?),
BinOp::GT => DynVal::from(a.as_f64()? > b.as_f64()?),
BinOp::LT => DynVal::from(a.as_f64()? < b.as_f64()?),
BinOp::GE => DynVal::from(a.as_f64()? >= b.as_f64()?),
BinOp::LE => DynVal::from(a.as_f64()? <= b.as_f64()?),
BinOp::RegexMatch => {
let regex = regex::Regex::new(&b.as_string()?)?;
DynVal::from(regex.is_match(&a.as_string()?))
}
_ => unreachable!("Lazy operators already handled"),
}
}
};
Ok(dynval.at(*span))
Expand Down Expand Up @@ -395,5 +403,8 @@ mod tests {
safe_access_to_missing(r#"{ "a": { "b": 2 } }.b?.b"#) => Ok(DynVal::from(&serde_json::Value::Null)),
normal_access_to_existing(r#"{ "a": { "b": 2 } }.a.b"#) => Ok(DynVal::from(2)),
normal_access_to_missing(r#"{ "a": { "b": 2 } }.b.b"#) => Err(super::EvalError::CannotIndex("null".to_string())),
lazy_evaluation_and(r#"false && "null".test"#) => Ok(DynVal::from(false)),
lazy_evaluation_or(r#"true || "null".test"#) => Ok(DynVal::from(true)),
lazy_evaluation_elvis(r#""test"?: "null".test"#) => Ok(DynVal::from("test")),
}
}

0 comments on commit 3ae3460

Please sign in to comment.