sql_cli/sql/parser/expressions/
comparison.rs1use crate::sql::parser::ast::SqlExpression;
5use crate::sql::parser::lexer::Token;
6use tracing::debug;
7
8use super::{log_parse_decision, trace_parse_entry, trace_parse_exit};
9
10pub fn parse_comparison<P>(parser: &mut P) -> Result<SqlExpression, String>
13where
14 P: ParseComparison + ?Sized,
15{
16 trace_parse_entry("parse_comparison", parser.current_token());
17
18 let mut left = parser.parse_additive()?;
19
20 if matches!(parser.current_token(), Token::Between) {
22 debug!("BETWEEN operator detected");
23 log_parse_decision(
24 "parse_comparison",
25 parser.current_token(),
26 "BETWEEN operator - parsing range bounds",
27 );
28
29 parser.advance(); let lower = parser.parse_additive()?;
31 parser.consume(Token::And)?; let upper = parser.parse_additive()?;
33
34 let result = Ok(SqlExpression::Between {
35 expr: Box::new(left),
36 lower: Box::new(lower),
37 upper: Box::new(upper),
38 });
39 trace_parse_exit("parse_comparison", &result);
40 return result;
41 }
42
43 if matches!(parser.current_token(), Token::Not) {
45 parser.advance(); if matches!(parser.current_token(), Token::In) {
48 debug!("NOT IN operator detected");
49 log_parse_decision(
50 "parse_comparison",
51 parser.current_token(),
52 "NOT IN operator - parsing value list",
53 );
54
55 parser.advance(); parser.consume(Token::LeftParen)?;
57 let values = parser.parse_expression_list()?;
58 parser.consume(Token::RightParen)?;
59
60 let result = Ok(SqlExpression::NotInList {
61 expr: Box::new(left),
62 values,
63 });
64 trace_parse_exit("parse_comparison", &result);
65 return result;
66 }
67 return Err("Expected IN after NOT".to_string());
68 }
69
70 if matches!(parser.current_token(), Token::Is) {
72 parser.advance(); if matches!(parser.current_token(), Token::Not) {
75 parser.advance(); if matches!(parser.current_token(), Token::Null) {
77 debug!("IS NOT NULL operator detected");
78 log_parse_decision(
79 "parse_comparison",
80 parser.current_token(),
81 "IS NOT NULL operator",
82 );
83
84 parser.advance(); left = SqlExpression::BinaryOp {
86 left: Box::new(left),
87 op: "IS NOT NULL".to_string(),
88 right: Box::new(SqlExpression::Null),
89 };
90 } else {
91 return Err("Expected NULL after IS NOT".to_string());
92 }
93 } else if matches!(parser.current_token(), Token::Null) {
94 debug!("IS NULL operator detected");
95 log_parse_decision(
96 "parse_comparison",
97 parser.current_token(),
98 "IS NULL operator",
99 );
100
101 parser.advance(); left = SqlExpression::BinaryOp {
103 left: Box::new(left),
104 op: "IS NULL".to_string(),
105 right: Box::new(SqlExpression::Null),
106 };
107 } else {
108 return Err("Expected NULL or NOT after IS".to_string());
109 }
110 }
111 else if let Some(op) = get_comparison_op(parser.current_token()) {
113 log_parse_decision(
114 "parse_comparison",
115 parser.current_token(),
116 &format!("Comparison operator '{}' found", op),
117 );
118
119 debug!(operator = %op, "Processing comparison operator");
120
121 parser.advance();
122 let right = parser.parse_additive()?;
123 left = SqlExpression::BinaryOp {
124 left: Box::new(left),
125 op,
126 right: Box::new(right),
127 };
128 }
129
130 let result = Ok(left);
131 trace_parse_exit("parse_comparison", &result);
132 result
133}
134
135pub fn parse_in_operator<P>(parser: &mut P, expr: SqlExpression) -> Result<SqlExpression, String>
138where
139 P: ParseComparison + ?Sized,
140{
141 trace_parse_entry("parse_in_operator", parser.current_token());
142
143 if matches!(parser.current_token(), Token::In) {
144 debug!("IN operator detected");
145 log_parse_decision(
146 "parse_in_operator",
147 parser.current_token(),
148 "IN operator - parsing value list",
149 );
150
151 parser.advance();
152 parser.consume(Token::LeftParen)?;
153 let values = parser.parse_expression_list()?;
154 parser.consume(Token::RightParen)?;
155
156 let result = Ok(SqlExpression::InList {
157 expr: Box::new(expr),
158 values,
159 });
160 trace_parse_exit("parse_in_operator", &result);
161 result
162 } else {
163 Ok(expr)
164 }
165}
166
167fn get_comparison_op(token: &Token) -> Option<String> {
169 match token {
170 Token::Equal => Some("=".to_string()),
171 Token::NotEqual => Some("!=".to_string()),
172 Token::LessThan => Some("<".to_string()),
173 Token::GreaterThan => Some(">".to_string()),
174 Token::LessThanOrEqual => Some("<=".to_string()),
175 Token::GreaterThanOrEqual => Some(">=".to_string()),
176 Token::Like => Some("LIKE".to_string()),
177 _ => None,
178 }
179}
180
181pub trait ParseComparison {
183 fn current_token(&self) -> &Token;
184 fn advance(&mut self);
185 fn consume(&mut self, expected: Token) -> Result<(), String>;
186
187 fn parse_primary(&mut self) -> Result<SqlExpression, String>;
189 fn parse_additive(&mut self) -> Result<SqlExpression, String>;
190 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String>;
191}