refactor: replace BinOp string with typed enum in Expr AST

Previously Expr::BinOp(String, ...) accepted any string as an operator.
Invalid operators (e.g. "diagonal") would compile fine and silently
return CellValue::Empty at eval time.

Now BinOp is an enum with variants Add/Sub/Mul/Div/Pow/Eq/Ne/Lt/Gt/Le/Ge.
The parser produces enum variants directly; the evaluator pattern-matches
exhaustively with no fallback branch. An invalid operator is now a
compile error at the call site, and the compiler ensures every variant
is handled in both eval_expr and eval_bool.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ed L
2026-03-24 00:20:08 -07:00
parent 5434a60cc4
commit 599f1adcbd
4 changed files with 60 additions and 34 deletions

View File

@ -9,6 +9,25 @@ pub enum AggFunc {
Count,
}
/// Arithmetic and comparison operators used in binary expressions.
/// Having an enum (rather than a raw String) means the parser must
/// produce a valid operator; invalid operators are caught at parse
/// time rather than silently returning Empty at eval time.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Pow,
Eq,
Ne,
Lt,
Gt,
Le,
Ge,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Filter {
pub category: String,
@ -19,7 +38,7 @@ pub struct Filter {
pub enum Expr {
Number(f64),
Ref(String),
BinOp(String, Box<Expr>, Box<Expr>),
BinOp(BinOp, Box<Expr>, Box<Expr>),
UnaryMinus(Box<Expr>),
Agg(AggFunc, Box<Expr>, Option<Filter>),
If(Box<Expr>, Box<Expr>, Box<Expr>),