Skip to main content

parser/
evaluator.rs

1use crate::parser::Parser;
2use crate::error::ParseError;
3use crate::arena::*;
4use crate::tokens::TokenType;
5
6use std::collections::HashMap;
7use std::fmt;
8
9// ============================================================================
10// PUBLIC API
11// ============================================================================
12
13/// User-provided values for variable substitution
14#[derive(Debug, Clone, PartialEq)]
15pub enum RuntimeValue {
16    /// 64-bit integer value
17    Integer(i64),
18    /// 64-bit floating point value
19    Float(f64),
20    /// String value
21    String(String),
22    /// Boolean value
23    Boolean(bool),
24    /// SQL NULL value
25    Null,
26}
27
28/// Comprehensive error type for evaluation failures
29#[derive(Debug, Clone, PartialEq)]
30pub enum EvalError {
31    /// Parse error from the parser
32    EvalParseError(/// Error message
33        String),
34
35    /// Variable referenced but not found in value map
36    UnboundVariable {
37        /// Variable name
38        name: String,
39    },
40
41    /// Type mismatch in operation
42    TypeError {
43        /// Operation that failed
44        operation: String,
45        /// Expected type
46        expected: String,
47        /// Actual type found
48        actual: String,
49        /// Expression context
50        context: String,
51    },
52
53    /// NULL used in arithmetic or comparison operation (not IS NULL/IS NOT NULL)
54    NullInOperation {
55        /// Operation that failed
56        operation: String,
57        /// Expression context
58        context: String,
59    },
60
61    /// Division by zero
62    DivisionByZero {
63        /// Expression that caused division by zero
64        expression: String,
65    },
66
67    /// Invalid literal format
68    InvalidLiteral {
69        /// The literal value
70        literal: String,
71        /// The expected type
72        literal_type: String,
73        /// The parse error
74        error: String,
75    },
76}
77
78impl fmt::Display for EvalError {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        match self {
81            EvalError::EvalParseError(msg) => write!(f, "Parse error: {}", msg),
82            EvalError::UnboundVariable { name } => {
83                write!(f, "Unbound variable '{}' - not found in value map", name)
84            }
85            EvalError::TypeError { operation, expected, actual, context } => {
86                write!(f, "Type error in {}: expected {}, got {} (context: {})",
87                    operation, expected, actual, context)
88            }
89            EvalError::NullInOperation { operation, context } => {
90                write!(f, "NULL value in {} operation (context: {}). NULL is only allowed in IS NULL/IS NOT NULL",
91                    operation, context)
92            }
93            EvalError::DivisionByZero { expression } => {
94                write!(f, "Division by zero in expression: {}", expression)
95            }
96            EvalError::InvalidLiteral { literal, literal_type, error } => {
97                write!(f, "Invalid {} literal '{}': {}", literal_type, literal, error)
98            }
99        }
100    }
101}
102
103impl std::error::Error for EvalError {}
104
105impl From<String> for EvalError {
106    fn from(msg: String) -> Self {
107        EvalError::EvalParseError(msg)
108    }
109}
110
111impl From<&str> for EvalError {
112    fn from(msg: &str) -> Self {
113        EvalError::EvalParseError(msg.to_string())
114    }
115}
116
117impl From<ParseError> for EvalError {
118    fn from(msg: ParseError) -> Self {
119        EvalError::EvalParseError(msg.to_string())
120    }
121}
122
123/// Evaluate a SQL boolean expression string with variable bindings.
124///
125/// # Arguments
126/// * `input` - SQL expression string to evaluate (must be boolean-valued)
127/// * `map` - Variable name to value bindings for substitution
128///
129/// # Returns
130/// * `Ok(bool)` - The evaluated boolean result
131/// * `Err(EvalError)` - Error during parsing, variable resolution, type checking, or evaluation
132///
133/// # Examples
134/// ```ignore
135/// use std::collections::HashMap;
136/// use parser::{evaluate, RuntimeValue};
137///
138/// let mut map = HashMap::new();
139/// map.insert("x".to_string(), RuntimeValue::Integer(42));
140///
141/// let result = evaluate("x > 10", &map).unwrap();
142/// assert_eq!(result, true);
143/// ```
144pub fn evaluate(input: &str, map: &HashMap<String, RuntimeValue>) -> Result<bool, EvalError> {
145    let evaluator = Evaluator::new(input, map)?;
146    let result = evaluator.eval_node(evaluator.root)?;
147    match result {
148        EvalValue::Bool(b) => Ok(b),
149        other => Err(EvalError::TypeError {
150            operation: "top-level evaluation".to_string(),
151            expected: "boolean".to_string(),
152            actual: other.type_name().to_string(),
153            context: input.to_string(),
154        }),
155    }
156}
157
158// ============================================================================
159// INTERNAL VALUE TYPE
160// ============================================================================
161
162#[derive(Debug, Clone, PartialEq)]
163enum EvalValue {
164    Integer(i64),
165    Float(f64),
166    Str(String),
167    Bool(bool),
168    Null,
169}
170
171impl EvalValue {
172    fn type_name(&self) -> &'static str {
173        match self {
174            EvalValue::Integer(_) => "integer",
175            EvalValue::Float(_) => "float",
176            EvalValue::Str(_) => "string",
177            EvalValue::Bool(_) => "boolean",
178            EvalValue::Null => "null",
179        }
180    }
181}
182
183impl From<&RuntimeValue> for EvalValue {
184    fn from(rv: &RuntimeValue) -> Self {
185        match rv {
186            RuntimeValue::Integer(i) => EvalValue::Integer(*i),
187            RuntimeValue::Float(f) => EvalValue::Float(*f),
188            RuntimeValue::String(s) => EvalValue::Str(s.clone()),
189            RuntimeValue::Boolean(b) => EvalValue::Bool(*b),
190            RuntimeValue::Null => EvalValue::Null,
191        }
192    }
193}
194
195// ============================================================================
196// EVALUATOR
197// ============================================================================
198
199struct Evaluator<'a> {
200    parser: Parser,
201    root: NodeId,
202    value_map: &'a HashMap<String, RuntimeValue>,
203}
204
205impl<'a> Evaluator<'a> {
206    fn new(input: &str, value_map: &'a HashMap<String, RuntimeValue>) -> Result<Self, EvalError> {
207        let mut parser = Parser::new(input.to_string())?;
208        let root = parser.parse()?;
209        Ok(Evaluator {
210            parser,
211            root,
212            value_map,
213        })
214    }
215
216    fn arena(&self) -> &Arena {
217        self.parser.arena()
218    }
219
220    fn input(&self) -> &str {
221        self.parser.input()
222    }
223
224    // ========================================================================
225    // CORE DISPATCH
226    // ========================================================================
227
228    fn eval_node(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
229        match self.arena().get_node(node_id) {
230            AstNode::JmsSelector(_) => self.eval_jms_selector(node_id),
231            AstNode::OrExpression(_) => self.eval_or(node_id),
232            AstNode::AndExpression(_) => self.eval_and(node_id),
233            AstNode::EqualityExpression(_) => self.eval_equality(node_id),
234            AstNode::ComparisonExpression(_) => self.eval_comparison(node_id),
235            AstNode::AddExpression(_) => self.eval_add(node_id),
236            AstNode::MultExpr(_) => self.eval_mult(node_id),
237            AstNode::UnaryExpr(_) => self.eval_unary(node_id),
238            AstNode::PrimaryExpr(_) => self.eval_primary(node_id),
239            AstNode::Literal(_) => self.eval_literal(node_id),
240            AstNode::StringLiteral(_) => self.eval_string_literal(node_id),
241            AstNode::Variable(_) => self.eval_variable(node_id),
242        }
243    }
244
245    // ========================================================================
246    // NODE EVALUATION METHODS
247    // ========================================================================
248
249    fn eval_jms_selector(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
250        let children = self.get_children(node_id);
251        self.eval_node(children[0])
252    }
253
254    fn eval_or(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
255        let children = self.get_children(node_id);
256        // Single child: pass-through (no OR operator present)
257        if children.len() == 1 {
258            return self.eval_node(children[0]);
259        }
260        for child_id in &children {
261            let val = self.eval_node(*child_id)?;
262            match val {
263                EvalValue::Bool(true) => return Ok(EvalValue::Bool(true)),
264                EvalValue::Bool(false) => {}
265                other => {
266                    return Err(EvalError::TypeError {
267                        operation: "OR".to_string(),
268                        expected: "boolean".to_string(),
269                        actual: other.type_name().to_string(),
270                        context: self.input().to_string(),
271                    });
272                }
273            }
274        }
275        Ok(EvalValue::Bool(false))
276    }
277
278    fn eval_and(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
279        let children = self.get_children(node_id);
280        // Single child: pass-through (no AND operator present)
281        if children.len() == 1 {
282            return self.eval_node(children[0]);
283        }
284        for child_id in &children {
285            let val = self.eval_node(*child_id)?;
286            match val {
287                EvalValue::Bool(false) => return Ok(EvalValue::Bool(false)),
288                EvalValue::Bool(true) => {}
289                other => {
290                    return Err(EvalError::TypeError {
291                        operation: "AND".to_string(),
292                        expected: "boolean".to_string(),
293                        actual: other.type_name().to_string(),
294                        context: self.input().to_string(),
295                    });
296                }
297            }
298        }
299        Ok(EvalValue::Bool(true))
300    }
301
302    fn eval_equality(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
303        let (children, operators) = match self.arena().get_node(node_id) {
304            AstNode::EqualityExpression(n) => (n.children.clone(), n.operators.clone()),
305            other => return Err(EvalError::EvalParseError(
306                format!("Internal error: expected EqualityExpression node, found {:?}", other),
307            )),
308        };
309
310        let mut current = self.eval_node(children[0])?;
311        let mut child_idx = 1;
312
313        for op in &operators {
314            match op {
315                EqualityOp::Equal => {
316                    let right = self.eval_node(children[child_idx])?;
317                    child_idx += 1;
318                    current = self.eval_eq_values(&current, &right, "Equal")?;
319                }
320                EqualityOp::NotEqual => {
321                    let right = self.eval_node(children[child_idx])?;
322                    child_idx += 1;
323                    let eq_result = self.eval_eq_values(&current, &right, "NotEqual")?;
324                    current = match eq_result {
325                        EvalValue::Bool(b) => EvalValue::Bool(!b),
326                        other => return Err(EvalError::EvalParseError(
327                            format!("Internal error: equality comparison returned non-boolean {:?}", other.type_name()),
328                        )),
329                    };
330                }
331                EqualityOp::IsNull => {
332                    current = EvalValue::Bool(matches!(current, EvalValue::Null));
333                }
334                EqualityOp::IsNotNull => {
335                    current = EvalValue::Bool(!matches!(current, EvalValue::Null));
336                }
337            }
338        }
339
340        Ok(current)
341    }
342
343    fn eval_comparison(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
344        let (children, operators) = match self.arena().get_node(node_id) {
345            AstNode::ComparisonExpression(n) => (n.children.clone(), n.operators.clone()),
346            other => return Err(EvalError::EvalParseError(
347                format!("Internal error: expected ComparisonExpression node, found {:?}", other),
348            )),
349        };
350
351        let mut current = self.eval_node(children[0])?;
352        let mut child_idx = 1;
353
354        for op in &operators {
355            match op {
356                ComparisonOp::GreaterThan
357                | ComparisonOp::GreaterThanEqual
358                | ComparisonOp::LessThan
359                | ComparisonOp::LessThanEqual => {
360                    let right = self.eval_node(children[child_idx])?;
361                    child_idx += 1;
362                    current = self.eval_ordering_comparison(&current, &right, *op)?;
363                }
364                ComparisonOp::Like | ComparisonOp::NotLike => {
365                    let pattern = self.eval_node(children[child_idx])?;
366                    child_idx += 1;
367                    current = self.eval_like(&current, &pattern, None, *op)?;
368                }
369                ComparisonOp::LikeEscape | ComparisonOp::NotLikeEscape => {
370                    let pattern = self.eval_node(children[child_idx])?;
371                    child_idx += 1;
372                    let escape = self.eval_node(children[child_idx])?;
373                    child_idx += 1;
374                    let escape_char = match &escape {
375                        EvalValue::Str(s) => {
376                            if s.len() != 1 {
377                                return Err(EvalError::TypeError {
378                                    operation: "LIKE ESCAPE".to_string(),
379                                    expected: "single character string".to_string(),
380                                    actual: format!("string of length {}", s.len()),
381                                    context: self.input().to_string(),
382                                });
383                            }
384                            Some(s.chars().next().unwrap())
385                        }
386                        _ => {
387                            return Err(EvalError::TypeError {
388                                operation: "LIKE ESCAPE".to_string(),
389                                expected: "string".to_string(),
390                                actual: escape.type_name().to_string(),
391                                context: self.input().to_string(),
392                            });
393                        }
394                    };
395                    let base_op = if *op == ComparisonOp::LikeEscape {
396                        ComparisonOp::Like
397                    } else {
398                        ComparisonOp::NotLike
399                    };
400                    current = self.eval_like(&current, &pattern, escape_char, base_op)?;
401                }
402                ComparisonOp::Between | ComparisonOp::NotBetween => {
403                    let low = self.eval_node(children[child_idx])?;
404                    child_idx += 1;
405                    let high = self.eval_node(children[child_idx])?;
406                    child_idx += 1;
407                    current = self.eval_between(&current, &low, &high, *op)?;
408                }
409                ComparisonOp::In | ComparisonOp::NotIn => {
410                    let elements: Vec<EvalValue> = children[child_idx..]
411                        .iter()
412                        .map(|id| self.eval_node(*id))
413                        .collect::<Result<Vec<_>, _>>()?;
414                    child_idx = children.len();
415                    current = self.eval_in(&current, &elements, *op)?;
416                }
417            }
418        }
419
420        Ok(current)
421    }
422
423    fn eval_add(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
424        let (children, operators) = match self.arena().get_node(node_id) {
425            AstNode::AddExpression(n) => (n.children.clone(), n.operators.clone()),
426            other => return Err(EvalError::EvalParseError(
427                format!("Internal error: expected AddExpression node, found {:?}", other),
428            )),
429        };
430
431        let mut result = self.eval_node(children[0])?;
432        for (i, op) in operators.iter().enumerate() {
433            let right = self.eval_node(children[i + 1])?;
434            result = self.eval_arithmetic_add(&result, &right, *op)?;
435        }
436        Ok(result)
437    }
438
439    fn eval_mult(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
440        let (children, operators) = match self.arena().get_node(node_id) {
441            AstNode::MultExpr(n) => (n.children.clone(), n.operators.clone()),
442            other => return Err(EvalError::EvalParseError(
443                format!("Internal error: expected MultExpr node, found {:?}", other),
444            )),
445        };
446
447        let mut result = self.eval_node(children[0])?;
448        for (i, op) in operators.iter().enumerate() {
449            let right = self.eval_node(children[i + 1])?;
450            result = self.eval_arithmetic_mult(&result, &right, *op)?;
451        }
452        Ok(result)
453    }
454
455    fn eval_unary(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
456        let (children, operator) = match self.arena().get_node(node_id) {
457            AstNode::UnaryExpr(n) => (n.children.clone(), n.operator),
458            other => return Err(EvalError::EvalParseError(
459                format!("Internal error: expected UnaryExpr node, found {:?}", other),
460            )),
461        };
462
463        let child_val = self.eval_node(children[0])?;
464        match operator {
465            None => Ok(child_val),
466            Some(UnaryOp::Plus) => {
467                match &child_val {
468                    EvalValue::Integer(_) | EvalValue::Float(_) => Ok(child_val),
469                    EvalValue::Null => Err(EvalError::NullInOperation {
470                        operation: "unary +".to_string(),
471                        context: self.input().to_string(),
472                    }),
473                    _ => Err(EvalError::TypeError {
474                        operation: "unary +".to_string(),
475                        expected: "numeric".to_string(),
476                        actual: child_val.type_name().to_string(),
477                        context: self.input().to_string(),
478                    }),
479                }
480            }
481            Some(UnaryOp::Negate) => {
482                match &child_val {
483                    EvalValue::Integer(i) => Ok(EvalValue::Integer(-i)),
484                    EvalValue::Float(f) => Ok(EvalValue::Float(-f)),
485                    EvalValue::Null => Err(EvalError::NullInOperation {
486                        operation: "unary minus".to_string(),
487                        context: self.input().to_string(),
488                    }),
489                    _ => Err(EvalError::TypeError {
490                        operation: "unary minus".to_string(),
491                        expected: "numeric".to_string(),
492                        actual: child_val.type_name().to_string(),
493                        context: self.input().to_string(),
494                    }),
495                }
496            }
497            Some(UnaryOp::Not) => {
498                match &child_val {
499                    EvalValue::Bool(b) => Ok(EvalValue::Bool(!b)),
500                    _ => Err(EvalError::TypeError {
501                        operation: "NOT".to_string(),
502                        expected: "boolean".to_string(),
503                        actual: child_val.type_name().to_string(),
504                        context: self.input().to_string(),
505                    }),
506                }
507            }
508        }
509    }
510
511    fn eval_primary(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
512        let children = self.get_children(node_id);
513        self.eval_node(children[0])
514    }
515
516    fn eval_literal(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
517        let node = match self.arena().get_node(node_id) {
518            AstNode::Literal(n) => n.clone(),
519            other => return Err(EvalError::EvalParseError(
520                format!("Internal error: expected Literal node, found {:?}", other),
521            )),
522        };
523
524        if !node.children.is_empty() {
525            // Has StringLiteral child
526            return self.eval_node(node.children[0]);
527        }
528
529        let token = self.arena().get_token(node.begin_token);
530        let image = &token.image;
531        match token.token_type {
532            TokenType::TRUE => Ok(EvalValue::Bool(true)),
533            TokenType::FALSE => Ok(EvalValue::Bool(false)),
534            TokenType::NULL => Ok(EvalValue::Null),
535            TokenType::FLOATING_POINT_LITERAL => {
536                let f: f64 = image.parse().map_err(|e: std::num::ParseFloatError| {
537                    EvalError::InvalidLiteral {
538                        literal: image.clone(),
539                        literal_type: "float".to_string(),
540                        error: e.to_string(),
541                    }
542                })?;
543                Ok(EvalValue::Float(f))
544            }
545            TokenType::DECIMAL_LITERAL => {
546                let clean = image.strip_suffix('L').or_else(|| image.strip_suffix('l')).unwrap_or(image);
547                if clean.contains('.') {
548                    let f: f64 = clean.parse().map_err(|e: std::num::ParseFloatError| {
549                        EvalError::InvalidLiteral {
550                            literal: image.clone(),
551                            literal_type: "float".to_string(),
552                            error: e.to_string(),
553                        }
554                    })?;
555                    Ok(EvalValue::Float(f))
556                } else {
557                    let i: i64 = clean.parse().map_err(|e: std::num::ParseIntError| {
558                        EvalError::InvalidLiteral {
559                            literal: image.clone(),
560                            literal_type: "integer".to_string(),
561                            error: e.to_string(),
562                        }
563                    })?;
564                    Ok(EvalValue::Integer(i))
565                }
566            }
567            TokenType::HEX_LITERAL => {
568                let clean = image.strip_suffix('L').or_else(|| image.strip_suffix('l')).unwrap_or(image);
569                let hex_str = clean.strip_prefix("0x")
570                    .or_else(|| clean.strip_prefix("0X"))
571                    .unwrap_or(clean);
572                let i = i64::from_str_radix(hex_str, 16).map_err(|e| {
573                    EvalError::InvalidLiteral {
574                        literal: image.clone(),
575                        literal_type: "hex".to_string(),
576                        error: e.to_string(),
577                    }
578                })?;
579                Ok(EvalValue::Integer(i))
580            }
581            TokenType::OCTAL_LITERAL => {
582                let clean = image.strip_suffix('L').or_else(|| image.strip_suffix('l')).unwrap_or(image);
583                let oct_str = clean.strip_prefix('0').unwrap_or(clean);
584                let i = i64::from_str_radix(oct_str, 8).map_err(|e| {
585                    EvalError::InvalidLiteral {
586                        literal: image.clone(),
587                        literal_type: "octal".to_string(),
588                        error: e.to_string(),
589                    }
590                })?;
591                Ok(EvalValue::Integer(i))
592            }
593            _ => Err(EvalError::InvalidLiteral {
594                literal: image.clone(),
595                literal_type: format!("{:?}", token.token_type),
596                error: "unsupported literal type".to_string(),
597            }),
598        }
599    }
600
601    fn eval_string_literal(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
602        let node = match self.arena().get_node(node_id) {
603            AstNode::StringLiteral(n) => n.clone(),
604            other => return Err(EvalError::EvalParseError(
605                format!("Internal error: expected StringLiteral node, found {:?}", other),
606            )),
607        };
608
609        let token = self.arena().get_token(node.begin_token);
610        let image = &token.image;
611        // Strip surrounding single quotes
612        let inner = &image[1..image.len() - 1];
613        Ok(EvalValue::Str(inner.to_string()))
614    }
615
616    fn eval_variable(&self, node_id: NodeId) -> Result<EvalValue, EvalError> {
617        let node = match self.arena().get_node(node_id) {
618            AstNode::Variable(n) => n.clone(),
619            other => return Err(EvalError::EvalParseError(
620                format!("Internal error: expected Variable node, found {:?}", other),
621            )),
622        };
623
624        let token = self.arena().get_token(node.begin_token);
625        let name = &token.image;
626
627        match self.value_map.get(name) {
628            Some(rv) => Ok(EvalValue::from(rv)),
629            None => Err(EvalError::UnboundVariable {
630                name: name.clone(),
631            }),
632        }
633    }
634
635    // ========================================================================
636    // TYPE CHECKING AND ARITHMETIC HELPERS
637    // ========================================================================
638
639    fn eval_eq_values(&self, left: &EvalValue, right: &EvalValue, op_name: &str) -> Result<EvalValue, EvalError> {
640        match (left, right) {
641            (EvalValue::Null, _) | (_, EvalValue::Null) => {
642                Err(EvalError::NullInOperation {
643                    operation: op_name.to_string(),
644                    context: self.input().to_string(),
645                })
646            }
647            (EvalValue::Integer(a), EvalValue::Integer(b)) => Ok(EvalValue::Bool(a == b)),
648            (EvalValue::Float(a), EvalValue::Float(b)) => Ok(EvalValue::Bool(a == b)),
649            (EvalValue::Integer(a), EvalValue::Float(b)) => Ok(EvalValue::Bool((*a as f64) == *b)),
650            (EvalValue::Float(a), EvalValue::Integer(b)) => Ok(EvalValue::Bool(*a == (*b as f64))),
651            (EvalValue::Str(a), EvalValue::Str(b)) => Ok(EvalValue::Bool(a == b)),
652            (EvalValue::Bool(a), EvalValue::Bool(b)) => Ok(EvalValue::Bool(a == b)),
653            _ => Err(EvalError::TypeError {
654                operation: op_name.to_string(),
655                expected: left.type_name().to_string(),
656                actual: right.type_name().to_string(),
657                context: self.input().to_string(),
658            }),
659        }
660    }
661
662    fn eval_ordering_comparison(&self, left: &EvalValue, right: &EvalValue, op: ComparisonOp) -> Result<EvalValue, EvalError> {
663        let op_name = match op {
664            ComparisonOp::GreaterThan => "GreaterThan",
665            ComparisonOp::GreaterThanEqual => "GreaterThanEqual",
666            ComparisonOp::LessThan => "LessThan",
667            ComparisonOp::LessThanEqual => "LessThanEqual",
668            other => return Err(EvalError::EvalParseError(
669                format!("Internal error: unexpected operator {:?} in ordering comparison", other),
670            )),
671        };
672
673        match (left, right) {
674            (EvalValue::Null, _) | (_, EvalValue::Null) => {
675                Err(EvalError::NullInOperation {
676                    operation: op_name.to_string(),
677                    context: self.input().to_string(),
678                })
679            }
680            (EvalValue::Integer(a), EvalValue::Integer(b)) => {
681                Ok(EvalValue::Bool(apply_ordering(*a, *b, op)?))
682            }
683            (EvalValue::Float(a), EvalValue::Float(b)) => {
684                Ok(EvalValue::Bool(apply_ordering_f64(*a, *b, op)?))
685            }
686            (EvalValue::Integer(a), EvalValue::Float(b)) => {
687                Ok(EvalValue::Bool(apply_ordering_f64(*a as f64, *b, op)?))
688            }
689            (EvalValue::Float(a), EvalValue::Integer(b)) => {
690                Ok(EvalValue::Bool(apply_ordering_f64(*a, *b as f64, op)?))
691            }
692            (EvalValue::Str(a), EvalValue::Str(b)) => {
693                Ok(EvalValue::Bool(apply_ordering(a.as_str(), b.as_str(), op)?))
694            }
695            _ => Err(EvalError::TypeError {
696                operation: op_name.to_string(),
697                expected: left.type_name().to_string(),
698                actual: right.type_name().to_string(),
699                context: self.input().to_string(),
700            }),
701        }
702    }
703
704    fn eval_arithmetic_add(&self, left: &EvalValue, right: &EvalValue, op: AddOp) -> Result<EvalValue, EvalError> {
705        let op_name = match op {
706            AddOp::Plus => "addition",
707            AddOp::Minus => "subtraction",
708        };
709
710        match (left, right) {
711            (EvalValue::Null, _) | (_, EvalValue::Null) => {
712                Err(EvalError::NullInOperation {
713                    operation: op_name.to_string(),
714                    context: self.input().to_string(),
715                })
716            }
717            (EvalValue::Integer(a), EvalValue::Integer(b)) => {
718                match op {
719                    AddOp::Plus => Ok(EvalValue::Integer(a + b)),
720                    AddOp::Minus => Ok(EvalValue::Integer(a - b)),
721                }
722            }
723            (EvalValue::Float(a), EvalValue::Float(b)) => {
724                match op {
725                    AddOp::Plus => Ok(EvalValue::Float(a + b)),
726                    AddOp::Minus => Ok(EvalValue::Float(a - b)),
727                }
728            }
729            (EvalValue::Integer(a), EvalValue::Float(b)) => {
730                let a = *a as f64;
731                match op {
732                    AddOp::Plus => Ok(EvalValue::Float(a + b)),
733                    AddOp::Minus => Ok(EvalValue::Float(a - b)),
734                }
735            }
736            (EvalValue::Float(a), EvalValue::Integer(b)) => {
737                let b = *b as f64;
738                match op {
739                    AddOp::Plus => Ok(EvalValue::Float(a + b)),
740                    AddOp::Minus => Ok(EvalValue::Float(a - b)),
741                }
742            }
743            _ => Err(EvalError::TypeError {
744                operation: op_name.to_string(),
745                expected: "numeric".to_string(),
746                actual: format!("{} and {}", left.type_name(), right.type_name()),
747                context: self.input().to_string(),
748            }),
749        }
750    }
751
752    fn eval_arithmetic_mult(&self, left: &EvalValue, right: &EvalValue, op: MultExprOp) -> Result<EvalValue, EvalError> {
753        let op_name = match op {
754            MultExprOp::Star => "*",
755            MultExprOp::Slash => "/",
756            MultExprOp::Percent => "%",
757        };
758
759        match (left, right) {
760            (EvalValue::Null, _) | (_, EvalValue::Null) => {
761                Err(EvalError::NullInOperation {
762                    operation: op_name.to_string(),
763                    context: self.input().to_string(),
764                })
765            }
766            (EvalValue::Integer(a), EvalValue::Integer(b)) => {
767                match op {
768                    MultExprOp::Star => Ok(EvalValue::Integer(a * b)),
769                    MultExprOp::Slash => {
770                        if *b == 0 {
771                            return Err(EvalError::DivisionByZero {
772                                expression: self.input().to_string(),
773                            });
774                        }
775                        Ok(EvalValue::Float(*a as f64 / *b as f64))
776                    }
777                    MultExprOp::Percent => {
778                        if *b == 0 {
779                            return Err(EvalError::DivisionByZero {
780                                expression: self.input().to_string(),
781                            });
782                        }
783                        Ok(EvalValue::Integer(a % b))
784                    }
785                }
786            }
787            (EvalValue::Float(a), EvalValue::Float(b)) => {
788                match op {
789                    MultExprOp::Star => Ok(EvalValue::Float(a * b)),
790                    MultExprOp::Slash => {
791                        if *b == 0.0 {
792                            return Err(EvalError::DivisionByZero {
793                                expression: self.input().to_string(),
794                            });
795                        }
796                        Ok(EvalValue::Float(a / b))
797                    }
798                    MultExprOp::Percent => {
799                        if *b == 0.0 {
800                            return Err(EvalError::DivisionByZero {
801                                expression: self.input().to_string(),
802                            });
803                        }
804                        Ok(EvalValue::Float(a % b))
805                    }
806                }
807            }
808            (EvalValue::Integer(a), EvalValue::Float(b)) => {
809                let a = *a as f64;
810                match op {
811                    MultExprOp::Star => Ok(EvalValue::Float(a * b)),
812                    MultExprOp::Slash => {
813                        if *b == 0.0 {
814                            return Err(EvalError::DivisionByZero {
815                                expression: self.input().to_string(),
816                            });
817                        }
818                        Ok(EvalValue::Float(a / b))
819                    }
820                    MultExprOp::Percent => {
821                        if *b == 0.0 {
822                            return Err(EvalError::DivisionByZero {
823                                expression: self.input().to_string(),
824                            });
825                        }
826                        Ok(EvalValue::Float(a % b))
827                    }
828                }
829            }
830            (EvalValue::Float(a), EvalValue::Integer(b)) => {
831                let b = *b as f64;
832                match op {
833                    MultExprOp::Star => Ok(EvalValue::Float(a * b)),
834                    MultExprOp::Slash => {
835                        if b == 0.0 {
836                            return Err(EvalError::DivisionByZero {
837                                expression: self.input().to_string(),
838                            });
839                        }
840                        Ok(EvalValue::Float(a / b))
841                    }
842                    MultExprOp::Percent => {
843                        if b == 0.0 {
844                            return Err(EvalError::DivisionByZero {
845                                expression: self.input().to_string(),
846                            });
847                        }
848                        Ok(EvalValue::Float(a % b))
849                    }
850                }
851            }
852            _ => Err(EvalError::TypeError {
853                operation: op_name.to_string(),
854                expected: "numeric".to_string(),
855                actual: format!("{} and {}", left.type_name(), right.type_name()),
856                context: self.input().to_string(),
857            }),
858        }
859    }
860
861    fn eval_between(&self, value: &EvalValue, low: &EvalValue, high: &EvalValue, op: ComparisonOp) -> Result<EvalValue, EvalError> {
862        let between_name = match op {
863            ComparisonOp::Between => "BETWEEN",
864            ComparisonOp::NotBetween => "NOT BETWEEN",
865            other => return Err(EvalError::EvalParseError(
866                format!("Internal error: unexpected operator {:?} in BETWEEN evaluation", other),
867            )),
868        };
869        // Check for NULL at the BETWEEN level so the error names the right operation
870        if matches!(value, EvalValue::Null) || matches!(low, EvalValue::Null) || matches!(high, EvalValue::Null) {
871            return Err(EvalError::NullInOperation {
872                operation: between_name.to_string(),
873                context: self.input().to_string(),
874            });
875        }
876        // low <= value AND value <= high
877        let ge_low = self.eval_ordering_comparison(value, low, ComparisonOp::GreaterThanEqual)?;
878        let le_high = self.eval_ordering_comparison(value, high, ComparisonOp::LessThanEqual)?;
879
880        let result = match (&ge_low, &le_high) {
881            (EvalValue::Bool(a), EvalValue::Bool(b)) => *a && *b,
882            _ => return Err(EvalError::EvalParseError(
883                format!("Internal error: BETWEEN comparison returned non-boolean results ({}, {})",
884                    ge_low.type_name(), le_high.type_name()),
885            )),
886        };
887
888        match op {
889            ComparisonOp::Between => Ok(EvalValue::Bool(result)),
890            ComparisonOp::NotBetween => Ok(EvalValue::Bool(!result)),
891            other => Err(EvalError::EvalParseError(
892                format!("Internal error: unexpected operator {:?} in BETWEEN result", other),
893            )),
894        }
895    }
896
897    fn eval_in(&self, value: &EvalValue, elements: &[EvalValue], op: ComparisonOp) -> Result<EvalValue, EvalError> {
898        // Check that the value type is compatible with the list element type.
899        // Null is handled by eval_eq_values (produces NullInOperation).
900        // Integer and Float are compatible (numeric coercion).
901        if let Some(first) = elements.first()
902            && !matches!(value, EvalValue::Null) && !Self::in_types_compatible(value, first) {
903                return Err(EvalError::TypeError {
904                    operation: "IN".to_string(),
905                    expected: first.type_name().to_string(),
906                    actual: value.type_name().to_string(),
907                    context: self.input().to_string(),
908                });
909            }
910        for elem in elements {
911            let eq = self.eval_eq_values(value, elem, "IN")?;
912            if eq == EvalValue::Bool(true) {
913                return match op {
914                    ComparisonOp::In => Ok(EvalValue::Bool(true)),
915                    ComparisonOp::NotIn => Ok(EvalValue::Bool(false)),
916                    other => Err(EvalError::EvalParseError(
917                        format!("Internal error: unexpected operator {:?} in IN evaluation", other),
918                    )),
919                };
920            }
921        }
922        match op {
923            ComparisonOp::In => Ok(EvalValue::Bool(false)),
924            ComparisonOp::NotIn => Ok(EvalValue::Bool(true)),
925            other => Err(EvalError::EvalParseError(
926                format!("Internal error: unexpected operator {:?} in IN evaluation", other),
927            )),
928        }
929    }
930
931    fn eval_like(&self, value: &EvalValue, pattern: &EvalValue, escape: Option<char>, op: ComparisonOp) -> Result<EvalValue, EvalError> {
932        let op_name = match op {
933            ComparisonOp::Like => "LIKE",
934            ComparisonOp::NotLike => "NOT LIKE",
935            other => return Err(EvalError::EvalParseError(
936                format!("Internal error: unexpected operator {:?} in LIKE evaluation", other),
937            )),
938        };
939
940        match (value, pattern) {
941            (EvalValue::Null, _) | (_, EvalValue::Null) => {
942                Err(EvalError::NullInOperation {
943                    operation: op_name.to_string(),
944                    context: self.input().to_string(),
945                })
946            }
947            (EvalValue::Str(val), EvalValue::Str(pat)) => {
948                let matched = sql_like_match(val, pat, escape);
949                match op {
950                    ComparisonOp::Like => Ok(EvalValue::Bool(matched)),
951                    ComparisonOp::NotLike => Ok(EvalValue::Bool(!matched)),
952                    other => Err(EvalError::EvalParseError(
953                        format!("Internal error: unexpected operator {:?} in LIKE result", other),
954                    )),
955                }
956            }
957            _ => Err(EvalError::TypeError {
958                operation: op_name.to_string(),
959                expected: "string".to_string(),
960                actual: format!("{} and {}", value.type_name(), pattern.type_name()),
961                context: self.input().to_string(),
962            }),
963        }
964    }
965
966    // ========================================================================
967    // UTILITY
968    // ========================================================================
969
970    /// Check if a value type is compatible with an IN list element type.
971    /// Integer and Float are mutually compatible (numeric coercion).
972    fn in_types_compatible(a: &EvalValue, b: &EvalValue) -> bool {
973        matches!((a, b),
974            (EvalValue::Integer(_), EvalValue::Integer(_))
975            | (EvalValue::Float(_), EvalValue::Float(_))
976            | (EvalValue::Integer(_), EvalValue::Float(_))
977            | (EvalValue::Float(_), EvalValue::Integer(_))
978            | (EvalValue::Str(_), EvalValue::Str(_))
979            | (EvalValue::Bool(_), EvalValue::Bool(_))
980        )
981    }
982
983    fn get_children(&self, node_id: NodeId) -> Vec<NodeId> {
984        match self.arena().get_node(node_id) {
985            AstNode::JmsSelector(n) => n.children.clone(),
986            AstNode::OrExpression(n) => n.children.clone(),
987            AstNode::AndExpression(n) => n.children.clone(),
988            AstNode::EqualityExpression(n) => n.children.clone(),
989            AstNode::ComparisonExpression(n) => n.children.clone(),
990            AstNode::AddExpression(n) => n.children.clone(),
991            AstNode::MultExpr(n) => n.children.clone(),
992            AstNode::UnaryExpr(n) => n.children.clone(),
993            AstNode::PrimaryExpr(n) => n.children.clone(),
994            AstNode::Literal(n) => n.children.clone(),
995            AstNode::StringLiteral(n) => n.children.clone(),
996            AstNode::Variable(n) => n.children.clone(),
997        }
998    }
999}
1000
1001// ============================================================================
1002// ORDERING HELPERS
1003// ============================================================================
1004
1005fn apply_ordering<T: PartialOrd>(a: T, b: T, op: ComparisonOp) -> Result<bool, EvalError> {
1006    match op {
1007        ComparisonOp::GreaterThan => Ok(a > b),
1008        ComparisonOp::GreaterThanEqual => Ok(a >= b),
1009        ComparisonOp::LessThan => Ok(a < b),
1010        ComparisonOp::LessThanEqual => Ok(a <= b),
1011        other => Err(EvalError::EvalParseError(
1012            format!("Internal error: unexpected operator {:?} in ordering comparison", other),
1013        )),
1014    }
1015}
1016
1017fn apply_ordering_f64(a: f64, b: f64, op: ComparisonOp) -> Result<bool, EvalError> {
1018    match op {
1019        ComparisonOp::GreaterThan => Ok(a > b),
1020        ComparisonOp::GreaterThanEqual => Ok(a >= b),
1021        ComparisonOp::LessThan => Ok(a < b),
1022        ComparisonOp::LessThanEqual => Ok(a <= b),
1023        other => Err(EvalError::EvalParseError(
1024            format!("Internal error: unexpected operator {:?} in ordering comparison", other),
1025        )),
1026    }
1027}
1028
1029// ============================================================================
1030// SQL LIKE PATTERN MATCHING
1031// ============================================================================
1032
1033#[derive(Debug)]
1034enum PatternElement {
1035    Percent,
1036    Underscore,
1037    Literal(char),
1038}
1039
1040fn sql_like_match(value: &str, pattern: &str, escape: Option<char>) -> bool {
1041    // Pre-process pattern into elements
1042    let mut elements = Vec::new();
1043    let mut chars = pattern.chars().peekable();
1044
1045    while let Some(c) = chars.next() {
1046        if Some(c) == escape {
1047            // Next char is a literal
1048            if let Some(next) = chars.next() {
1049                elements.push(PatternElement::Literal(next));
1050            }
1051        } else if c == '%' {
1052            elements.push(PatternElement::Percent);
1053        } else if c == '_' {
1054            elements.push(PatternElement::Underscore);
1055        } else {
1056            elements.push(PatternElement::Literal(c));
1057        }
1058    }
1059
1060    // DP matching
1061    let val_chars: Vec<char> = value.chars().collect();
1062    let n = val_chars.len();
1063    let m = elements.len();
1064
1065    // dp[i][j] = true if val[0..i] matches pattern[0..j]
1066    let mut dp = vec![vec![false; m + 1]; n + 1];
1067    dp[0][0] = true;
1068
1069    // Handle leading % patterns
1070    for j in 1..=m {
1071        if matches!(elements[j - 1], PatternElement::Percent) {
1072            dp[0][j] = dp[0][j - 1];
1073        } else {
1074            break;
1075        }
1076    }
1077
1078    for i in 1..=n {
1079        for j in 1..=m {
1080            match &elements[j - 1] {
1081                PatternElement::Percent => {
1082                    // % matches zero or more characters
1083                    dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
1084                }
1085                PatternElement::Underscore => {
1086                    // _ matches exactly one character
1087                    dp[i][j] = dp[i - 1][j - 1];
1088                }
1089                PatternElement::Literal(c) => {
1090                    dp[i][j] = dp[i - 1][j - 1] && val_chars[i - 1] == *c;
1091                }
1092            }
1093        }
1094    }
1095
1096    dp[n][m]
1097}