grammar: WHERE-expression fragment + Expr AST + build_expr (ADR-0026 step 2)
The stratified WHERE-expression grammar — or / and / not / bool_primary / predicate tiers as named `static` Node fragments, recursing through `Subgrammar`. Covers the six comparison operators (`<>` and `!=` both NotEq), AND / OR / NOT, parentheses, LIKE / IN / BETWEEN with optional infix NOT, and IS [NOT] NULL. `predicate_tail` factors the shared operand prefix and the infix NOT so the Choice branches discriminate on a cleanly-failing first token. New recursive Expr / Predicate / Operand / CompareOp AST in dsl::command. `build_expr` folds the flat matched-terminal slice into an Expr — a deterministic recursive descent mirroring the grammar tiers, with single-child tiers collapsing. Per ADR-0026 §3 option 1: the walker stays a pure structural matcher; Expr is assembled only in this submit-time fold. Fragment + builder are unit-tested standalone (walk against &OR_EXPR, then build_expr); not yet wired into any command.
This commit is contained in:
@@ -239,6 +239,83 @@ pub enum RowFilter {
|
||||
AllRows,
|
||||
}
|
||||
|
||||
/// A complex WHERE expression (ADR-0026 §4).
|
||||
///
|
||||
/// Built by `grammar::expr::build_expr` from the flat
|
||||
/// matched-terminal slice the walker produces for a `where`
|
||||
/// clause. The recursion mirrors the stratified expression
|
||||
/// grammar — `Or` / `And` are n-ary (a flat `a AND b AND c` is
|
||||
/// one `And` of three children), and single-child precedence
|
||||
/// tiers collapse so a bare predicate reached through the
|
||||
/// `or → and → not` layers is just the `Predicate`, not three
|
||||
/// wrappers.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Expr {
|
||||
/// `a OR b OR …` — at least two children.
|
||||
Or(Vec<Self>),
|
||||
/// `a AND b AND …` — at least two children.
|
||||
And(Vec<Self>),
|
||||
/// `NOT <expr>`.
|
||||
Not(Box<Self>),
|
||||
/// A leaf comparison / match test.
|
||||
Predicate(Predicate),
|
||||
}
|
||||
|
||||
/// A single comparison or match test inside an [`Expr`]
|
||||
/// (ADR-0026 §4). Operands are always a column reference or a
|
||||
/// literal — never a nested expression.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Predicate {
|
||||
/// `<operand> <op> <operand>` — one of the six comparisons.
|
||||
Compare {
|
||||
left: Operand,
|
||||
op: CompareOp,
|
||||
right: Operand,
|
||||
},
|
||||
/// `<operand> [NOT] LIKE <operand>` — `%` / `_` wildcards.
|
||||
Like {
|
||||
target: Operand,
|
||||
pattern: Operand,
|
||||
negated: bool,
|
||||
},
|
||||
/// `<operand> [NOT] BETWEEN <operand> AND <operand>`.
|
||||
Between {
|
||||
target: Operand,
|
||||
low: Operand,
|
||||
high: Operand,
|
||||
negated: bool,
|
||||
},
|
||||
/// `<operand> [NOT] IN (<operand>[, …])`.
|
||||
In {
|
||||
target: Operand,
|
||||
items: Vec<Operand>,
|
||||
negated: bool,
|
||||
},
|
||||
/// `<operand> IS [NOT] NULL`.
|
||||
IsNull { target: Operand, negated: bool },
|
||||
}
|
||||
|
||||
/// A comparison operand — a column reference or a literal
|
||||
/// (ADR-0026 §1: operands are never nested expressions).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Operand {
|
||||
Column(String),
|
||||
Literal(Value),
|
||||
}
|
||||
|
||||
/// The six comparison operators. `<>` and `!=` both parse to
|
||||
/// `NotEq` — `<>` is standard SQL, `!=` the common variant
|
||||
/// (ADR-0026 §1).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum CompareOp {
|
||||
Eq,
|
||||
NotEq,
|
||||
Lt,
|
||||
LtEq,
|
||||
Gt,
|
||||
GtEq,
|
||||
}
|
||||
|
||||
/// How a `drop relationship` command identifies the relationship
|
||||
/// to remove. Both forms are accepted; the executor resolves to
|
||||
/// a single row in the metadata table.
|
||||
|
||||
Reference in New Issue
Block a user