sql_cli/sql/parser/expressions/
logical.rs

1// Logical expression parsing
2// Handles logical operators (AND, OR) and NOT operator
3// These operators are used for combining boolean expressions
4
5use crate::sql::parser::ast::SqlExpression;
6use crate::sql::parser::lexer::Token;
7use tracing::debug;
8
9use super::{log_parse_decision, trace_parse_entry, trace_parse_exit};
10
11/// Parse a logical OR expression
12/// OR has the lowest precedence of the logical operators
13pub fn parse_logical_or<P>(parser: &mut P) -> Result<SqlExpression, String>
14where
15    P: ParseLogical + ?Sized,
16{
17    trace_parse_entry("parse_logical_or", parser.current_token());
18
19    let mut left = parser.parse_logical_and()?;
20
21    while matches!(parser.current_token(), Token::Or) {
22        log_parse_decision(
23            "parse_logical_or",
24            parser.current_token(),
25            "OR operator found, parsing right operand",
26        );
27
28        debug!("Processing logical OR operator");
29        parser.advance();
30        let right = parser.parse_logical_and()?;
31
32        // Use BinaryOp to represent OR operations
33        left = SqlExpression::BinaryOp {
34            left: Box::new(left),
35            op: "OR".to_string(),
36            right: Box::new(right),
37        };
38
39        debug!("Created OR expression");
40    }
41
42    let result = Ok(left);
43    trace_parse_exit("parse_logical_or", &result);
44    result
45}
46
47/// Parse a logical AND expression
48/// AND has higher precedence than OR but lower than comparison operators
49pub fn parse_logical_and<P>(parser: &mut P) -> Result<SqlExpression, String>
50where
51    P: ParseLogical + ?Sized,
52{
53    trace_parse_entry("parse_logical_and", parser.current_token());
54
55    // Parse the base expression (comparison or lower)
56    let mut left = parser.parse_base_logical_expression()?;
57
58    while matches!(parser.current_token(), Token::And) {
59        log_parse_decision(
60            "parse_logical_and",
61            parser.current_token(),
62            "AND operator found, parsing right operand",
63        );
64
65        debug!("Processing logical AND operator");
66        parser.advance();
67        let right = parser.parse_base_logical_expression()?;
68
69        // Use BinaryOp to represent AND operations
70        left = SqlExpression::BinaryOp {
71            left: Box::new(left),
72            op: "AND".to_string(),
73            right: Box::new(right),
74        };
75
76        debug!("Created AND expression");
77    }
78
79    let result = Ok(left);
80    trace_parse_exit("parse_logical_and", &result);
81    result
82}
83
84/// Parse a NOT expression (unary logical operator)
85/// This is handled as part of primary expression parsing
86pub fn parse_not_expression<P>(parser: &mut P) -> Result<SqlExpression, String>
87where
88    P: ParseLogical + ?Sized,
89{
90    trace_parse_entry("parse_not_expression", parser.current_token());
91
92    if !matches!(parser.current_token(), Token::Not) {
93        return Err("Expected NOT token".to_string());
94    }
95
96    log_parse_decision(
97        "parse_not_expression",
98        parser.current_token(),
99        "NOT operator found, parsing operand",
100    );
101
102    debug!("Processing NOT operator");
103    parser.advance(); // consume NOT
104
105    // Check if this is a NOT IN expression
106    let inner_expr = parser.parse_comparison()?;
107
108    // After parsing the inner expression, check if we're followed by IN
109    if matches!(parser.current_token(), Token::In) {
110        debug!("NOT IN expression detected");
111        parser.advance(); // consume IN
112        parser.consume(Token::LeftParen)?;
113        let values = parser.parse_expression_list()?;
114        parser.consume(Token::RightParen)?;
115
116        let result = Ok(SqlExpression::NotInList {
117            expr: Box::new(inner_expr),
118            values,
119        });
120        trace_parse_exit("parse_not_expression", &result);
121        result
122    } else {
123        // Regular NOT expression
124        debug!("Creating NOT expression");
125        let result = Ok(SqlExpression::Not {
126            expr: Box::new(inner_expr),
127        });
128        trace_parse_exit("parse_not_expression", &result);
129        result
130    }
131}
132
133/// Trait that parsers must implement to use logical expression parsing
134pub trait ParseLogical {
135    fn current_token(&self) -> &Token;
136    fn advance(&mut self);
137    fn consume(&mut self, expected: Token) -> Result<(), String>;
138
139    // These methods are called from logical parsing
140    fn parse_logical_and(&mut self) -> Result<SqlExpression, String>;
141    fn parse_base_logical_expression(&mut self) -> Result<SqlExpression, String>;
142    fn parse_comparison(&mut self) -> Result<SqlExpression, String>;
143    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String>;
144}