Skip to main content

sqlexpr_rust/
ast.rs

1//! AST (Abstract Syntax Tree) definitions for SQL Expression Parser
2//!
3//! This module defines the AST structure that corresponds to the EBNF grammar.
4//! The design enforces type safety at the grammar level: all top-level expressions
5//! must be boolean, while arithmetic/value expressions can only appear as operands
6//! to relational operators.
7
8use std::fmt;
9
10// ============================================================================
11// BOOLEAN EXPRESSION HIERARCHY (Top Level - Always boolean)
12// ============================================================================
13
14/// Root expression type - must evaluate to boolean
15#[derive(Debug, Clone, PartialEq)]
16pub enum BooleanExpr {
17    /// Logical OR operation (lowest precedence)
18    Or(Box<BooleanExpr>, Box<BooleanExpr>),
19
20    /// Logical AND operation
21    And(Box<BooleanExpr>, Box<BooleanExpr>),
22
23    /// Logical NOT operation
24    Not(Box<BooleanExpr>),
25
26    /// Boolean literal (TRUE or FALSE)
27    Literal(bool),
28
29    /// Variable reference (type checked at runtime)
30    Variable(String),
31
32    /// Relational expression (comparisons that produce boolean results)
33    Relational(RelationalExpr),
34}
35
36// ============================================================================
37// RELATIONAL EXPRESSIONS (Bridge between boolean and value expressions)
38// ============================================================================
39
40/// Relational expressions - produce boolean results from value comparisons
41#[derive(Debug, Clone, PartialEq)]
42pub enum RelationalExpr {
43    /// Equality comparison: =, <>, !=
44    Equality {
45        left: ValueExpr,
46        op: EqualityOp,
47        right: ValueExpr,
48    },
49
50    /// Simple comparison: >, >=, <, <=
51    Comparison {
52        left: ValueExpr,
53        op: ComparisonOp,
54        right: ValueExpr,
55    },
56
57    /// LIKE pattern matching
58    Like {
59        expr: ValueExpr,
60        pattern: String,
61        escape: Option<String>,
62        negated: bool,
63    },
64
65    /// BETWEEN range check
66    Between {
67        expr: ValueExpr,
68        lower: ValueExpr,
69        upper: ValueExpr,
70        negated: bool,
71    },
72
73    /// IN list membership
74    In {
75        expr: ValueExpr,
76        values: Vec<ValueLiteral>,
77        negated: bool,
78    },
79
80    /// IS NULL / IS NOT NULL
81    IsNull {
82        expr: ValueExpr,
83        negated: bool,
84    },
85}
86
87/// Equality operators
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum EqualityOp {
90    Equal,        // =
91    NotEqual,     // <> or !=
92}
93
94/// Simple comparison operators
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub enum ComparisonOp {
97    GreaterThan,       // >
98    GreaterOrEqual,    // >=
99    LessThan,          // <
100    LessOrEqual,       // <=
101}
102
103// ============================================================================
104// VALUE EXPRESSION HIERARCHY (Operands only - numeric/string values)
105// ============================================================================
106
107/// Value expressions - can only appear as operands to relational operators
108#[derive(Debug, Clone, PartialEq)]
109pub enum ValueExpr {
110    /// Binary addition
111    Add(Box<ValueExpr>, Box<ValueExpr>),
112
113    /// Binary subtraction
114    Subtract(Box<ValueExpr>, Box<ValueExpr>),
115
116    /// Binary multiplication
117    Multiply(Box<ValueExpr>, Box<ValueExpr>),
118
119    /// Binary division
120    Divide(Box<ValueExpr>, Box<ValueExpr>),
121
122    /// Binary modulo
123    Modulo(Box<ValueExpr>, Box<ValueExpr>),
124
125    /// Unary plus
126    UnaryPlus(Box<ValueExpr>),
127
128    /// Unary minus (negation)
129    UnaryMinus(Box<ValueExpr>),
130
131    /// Literal value
132    Literal(ValueLiteral),
133
134    /// Variable reference
135    Variable(String),
136}
137
138/// Literal values
139#[derive(Debug, Clone, PartialEq)]
140pub enum ValueLiteral {
141    /// Integer literal (decimal, hex, octal, or with L/l suffix)
142    Integer(i64),
143
144    /// Floating point literal
145    Float(f64),
146
147    /// String literal
148    String(String),
149
150    /// NULL literal
151    Null,
152
153    /// Boolean literal (can be used as value in comparisons)
154    Boolean(bool),
155}
156
157// ============================================================================
158// DISPLAY IMPLEMENTATIONS
159// ============================================================================
160
161impl fmt::Display for BooleanExpr {
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163        match self {
164            BooleanExpr::Or(left, right) => write!(f, "({} OR {})", left, right),
165            BooleanExpr::And(left, right) => write!(f, "({} AND {})", left, right),
166            BooleanExpr::Not(expr) => write!(f, "NOT {}", expr),
167            BooleanExpr::Literal(b) => write!(f, "{}", if *b { "TRUE" } else { "FALSE" }),
168            BooleanExpr::Variable(name) => write!(f, "{}", name),
169            BooleanExpr::Relational(rel) => write!(f, "{}", rel),
170        }
171    }
172}
173
174impl fmt::Display for RelationalExpr {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        match self {
177            RelationalExpr::Equality { left, op, right } => {
178                write!(f, "{} {} {}", left, op, right)
179            }
180            RelationalExpr::Comparison { left, op, right } => {
181                write!(f, "{} {} {}", left, op, right)
182            }
183            RelationalExpr::Like { expr, pattern, escape, negated } => {
184                if *negated {
185                    write!(f, "{} NOT LIKE '{}'", expr, pattern)?;
186                } else {
187                    write!(f, "{} LIKE '{}'", expr, pattern)?;
188                }
189                if let Some(esc) = escape {
190                    write!(f, " ESCAPE '{}'", esc)?;
191                }
192                Ok(())
193            }
194            RelationalExpr::Between { expr, lower, upper, negated } => {
195                if *negated {
196                    write!(f, "{} NOT BETWEEN {} AND {}", expr, lower, upper)
197                } else {
198                    write!(f, "{} BETWEEN {} AND {}", expr, lower, upper)
199                }
200            }
201            RelationalExpr::In { expr, values, negated } => {
202                if *negated {
203                    write!(f, "{} NOT IN (", expr)?;
204                } else {
205                    write!(f, "{} IN (", expr)?;
206                }
207                for (i, val) in values.iter().enumerate() {
208                    if i > 0 {
209                        write!(f, ", ")?;
210                    }
211                    write!(f, "{}", val)?;
212                }
213                write!(f, ")")
214            }
215            RelationalExpr::IsNull { expr, negated } => {
216                if *negated {
217                    write!(f, "{} IS NOT NULL", expr)
218                } else {
219                    write!(f, "{} IS NULL", expr)
220                }
221            }
222        }
223    }
224}
225
226impl fmt::Display for EqualityOp {
227    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228        match self {
229            EqualityOp::Equal => write!(f, "="),
230            EqualityOp::NotEqual => write!(f, "<>"),
231        }
232    }
233}
234
235impl fmt::Display for ComparisonOp {
236    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237        match self {
238            ComparisonOp::GreaterThan => write!(f, ">"),
239            ComparisonOp::GreaterOrEqual => write!(f, ">="),
240            ComparisonOp::LessThan => write!(f, "<"),
241            ComparisonOp::LessOrEqual => write!(f, "<="),
242        }
243    }
244}
245
246impl fmt::Display for ValueExpr {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        match self {
249            ValueExpr::Add(left, right) => write!(f, "({} + {})", left, right),
250            ValueExpr::Subtract(left, right) => write!(f, "({} - {})", left, right),
251            ValueExpr::Multiply(left, right) => write!(f, "({} * {})", left, right),
252            ValueExpr::Divide(left, right) => write!(f, "({} / {})", left, right),
253            ValueExpr::Modulo(left, right) => write!(f, "({} % {})", left, right),
254            ValueExpr::UnaryPlus(expr) => write!(f, "+{}", expr),
255            ValueExpr::UnaryMinus(expr) => write!(f, "-{}", expr),
256            ValueExpr::Literal(lit) => write!(f, "{}", lit),
257            ValueExpr::Variable(name) => write!(f, "{}", name),
258        }
259    }
260}
261
262impl fmt::Display for ValueLiteral {
263    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264        match self {
265            ValueLiteral::Integer(n) => write!(f, "{}", n),
266            ValueLiteral::Float(n) => write!(f, "{}", n),
267            ValueLiteral::String(s) => write!(f, "'{}'", s),
268            ValueLiteral::Null => write!(f, "NULL"),
269            ValueLiteral::Boolean(b) => write!(f, "{}", if *b { "TRUE" } else { "FALSE" }),
270        }
271    }
272}