diff --git a/crates/simplexpr/src/ast.rs b/crates/simplexpr/src/ast.rs index 4b56cfb..4edf00b 100644 --- a/crates/simplexpr/src/ast.rs +++ b/crates/simplexpr/src/ast.rs @@ -17,6 +17,8 @@ pub enum BinOp { #[strum(serialize = "!=")] NotEquals, #[strum(serialize = "&&")] And, #[strum(serialize = "||")] Or, + #[strum(serialize = ">=") ] GE, + #[strum(serialize = "<=") ] LE, #[strum(serialize = ">") ] GT, #[strum(serialize = "<") ] LT, #[strum(serialize = "?:")] Elvis, @@ -27,6 +29,8 @@ pub enum BinOp { pub enum UnaryOp { #[strum(serialize = "!")] Not, + #[strum(serialize = "-")] + Negative, } #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/crates/simplexpr/src/eval.rs b/crates/simplexpr/src/eval.rs index a3f1789..910dbb7 100644 --- a/crates/simplexpr/src/eval.rs +++ b/crates/simplexpr/src/eval.rs @@ -190,6 +190,8 @@ impl SimplExpr { 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()?), #[allow(clippy::useless_conversion)] BinOp::Elvis => DynVal::from(if a.0.is_empty() { b } else { a }), BinOp::RegexMatch => { @@ -203,6 +205,7 @@ impl SimplExpr { let a = a.eval(values)?; Ok(match op { UnaryOp::Not => DynVal::from(!a.as_bool()?).at(*span), + UnaryOp::Negative => DynVal::from(-a.as_f64()?).at(*span), }) } SimplExpr::IfElse(_, cond, yes, no) => { diff --git a/crates/simplexpr/src/parser/lexer.rs b/crates/simplexpr/src/parser/lexer.rs index e7a4ce0..36e2418 100644 --- a/crates/simplexpr/src/parser/lexer.rs +++ b/crates/simplexpr/src/parser/lexer.rs @@ -23,12 +23,15 @@ pub enum Token { NotEquals, And, Or, + GE, + LE, GT, LT, Elvis, RegexMatch, Not, + Negative, Comma, Question, @@ -80,12 +83,15 @@ regex_rules! { escape(r"!=") => |_| Token::NotEquals, escape(r"&&") => |_| Token::And, escape(r"||") => |_| Token::Or, + escape(r">=") => |_| Token::GE, + escape(r"<=") => |_| Token::LE, escape(r">") => |_| Token::GT, escape(r"<") => |_| Token::LT, escape(r"?:") => |_| Token::Elvis, escape(r"=~") => |_| Token::RegexMatch, escape(r"!" ) => |_| Token::Not, + escape(r"-" ) => |_| Token::Negative, escape(r",") => |_| Token::Comma, escape(r"?") => |_| Token::Question, diff --git a/crates/simplexpr/src/simplexpr_parser.lalrpop b/crates/simplexpr/src/simplexpr_parser.lalrpop index fd4d1f7..c63a644 100644 --- a/crates/simplexpr/src/simplexpr_parser.lalrpop +++ b/crates/simplexpr/src/simplexpr_parser.lalrpop @@ -20,6 +20,8 @@ extern { "!=" => Token::NotEquals, "&&" => Token::And, "||" => Token::Or, + ">=" => Token::GE, + "<=" => Token::LE, ">" => Token::GT, "<" => Token::LT, "?:" => Token::Elvis, @@ -81,6 +83,7 @@ pub Expr: SimplExpr = { #[precedence(level="2")] #[assoc(side="right")] "!" => UnaryOp(Span(l, r, fid), Not, b(e)), + "-" => UnaryOp(Span(l, r, fid), Negative, b(e)), #[precedence(level="3")] #[assoc(side="left")] "*" => BinOp(Span(l, r, fid), b(le), Times, b(re)), @@ -94,6 +97,8 @@ pub Expr: SimplExpr = { #[precedence(level="5")] #[assoc(side="left")] "==" => BinOp(Span(l, r, fid), b(le), Equals, b(re)), "!=" => BinOp(Span(l, r, fid), b(le), NotEquals, b(re)), + ">=" => BinOp(Span(l, r, fid), b(le), GE, b(re)), + "<=" => BinOp(Span(l, r, fid), b(le), LE, b(re)), ">" => BinOp(Span(l, r, fid), b(le), GT, b(re)), "<" => BinOp(Span(l, r, fid), b(le), LT, b(re)), "=~" => BinOp(Span(l, r, fid), b(le), RegexMatch, b(re)), diff --git a/docs/src/expression_language.md b/docs/src/expression_language.md index 6b051ce..a98daf3 100644 --- a/docs/src/expression_language.md +++ b/docs/src/expression_language.md @@ -21,7 +21,7 @@ as well as within strings, inside string-interpolation blocks (`"foo ${ ... } ba Supported currently are the following features: - simple mathematical operations (`+`, `-`, `*`, `/`, `%`) -- comparisons (`==`, `!=`, `>`, `<`) +- comparisons (`==`, `!=`, `>`, `<`, `<=`, `>=`) - boolean operations (`||`, `&&`, `!`) - elvis operator (`?:`) - if the left side is `""`, then returns the right side, otherwise evaluates to the left side.