sql_cli/sql/parser/expressions/
arithmetic.rs1use crate::sql::parser::ast::{ColumnRef, SqlExpression};
6use crate::sql::parser::lexer::Token;
7use tracing::debug;
8
9use super::{log_parse_decision, trace_parse_entry, trace_parse_exit};
10
11pub fn parse_additive<P>(parser: &mut P) -> Result<SqlExpression, String>
14where
15 P: ParseArithmetic + ?Sized,
16{
17 trace_parse_entry("parse_additive", parser.current_token());
18
19 let mut left = parser.parse_multiplicative()?;
20
21 while matches!(
22 parser.current_token(),
23 Token::Plus | Token::Minus | Token::Concat
24 ) {
25 let op = match parser.current_token() {
26 Token::Plus => "+",
27 Token::Minus => "-",
28 Token::Concat => {
29 log_parse_decision(
31 "parse_additive",
32 parser.current_token(),
33 "String concatenation '||' found, converting to TEXTJOIN",
34 );
35
36 parser.advance();
37 let right = parser.parse_multiplicative()?;
38
39 left = SqlExpression::FunctionCall {
42 name: "TEXTJOIN".to_string(),
43 args: vec![
44 SqlExpression::StringLiteral("".to_string()), SqlExpression::NumberLiteral("1".to_string()), left,
47 right,
48 ],
49 distinct: false,
50 };
51 continue; }
53 _ => unreachable!(),
54 };
55
56 log_parse_decision(
57 "parse_additive",
58 parser.current_token(),
59 &format!("Binary operator '{}' found, parsing right operand", op),
60 );
61
62 parser.advance();
63 let right = parser.parse_multiplicative()?;
64
65 debug!(operator = op, "Creating additive binary operation");
66
67 left = SqlExpression::BinaryOp {
68 left: Box::new(left),
69 op: op.to_string(),
70 right: Box::new(right),
71 };
72 }
73
74 let result = Ok(left);
75 trace_parse_exit("parse_additive", &result);
76 result
77}
78
79pub fn parse_multiplicative<P>(parser: &mut P) -> Result<SqlExpression, String>
83where
84 P: ParseArithmetic + ?Sized,
85{
86 trace_parse_entry("parse_multiplicative", parser.current_token());
87
88 let mut left = parser.parse_primary()?;
89
90 while matches!(parser.current_token(), Token::Dot) {
93 debug!("Found dot operator");
94 parser.advance();
95
96 if let Token::Identifier(name) = parser.current_token() {
97 let name_str = name.clone();
98 parser.advance();
99
100 if matches!(parser.current_token(), Token::LeftParen) {
101 log_parse_decision(
103 "parse_multiplicative",
104 parser.current_token(),
105 &format!("Method call '{}' detected", name_str),
106 );
107
108 parser.advance();
109 let args = parser.parse_method_args()?;
110 parser.consume(Token::RightParen)?;
111
112 left = match left {
114 SqlExpression::Column(obj) => {
115 debug!(
117 column = %obj,
118 method = %name_str,
119 "Creating method call on column"
120 );
121 SqlExpression::MethodCall {
122 object: obj.name,
123 method: name_str,
124 args,
125 }
126 }
127 SqlExpression::MethodCall { .. } | SqlExpression::ChainedMethodCall { .. } => {
128 debug!(
130 method = %name_str,
131 "Creating chained method call"
132 );
133 SqlExpression::ChainedMethodCall {
134 base: Box::new(left),
135 method: name_str,
136 args,
137 }
138 }
139 _ => {
140 debug!(
142 method = %name_str,
143 "Creating method call on expression"
144 );
145 SqlExpression::ChainedMethodCall {
146 base: Box::new(left),
147 method: name_str,
148 args,
149 }
150 }
151 };
152 } else {
153 left = match left {
156 SqlExpression::Column(table_or_alias) => {
157 debug!(
158 table = %table_or_alias,
159 column = %name_str,
160 "Creating qualified column reference"
161 );
162 SqlExpression::Column(ColumnRef::unquoted(format!(
163 "{}.{}",
164 table_or_alias, name_str
165 )))
166 }
167 _ => {
168 return Err(format!(
170 "Invalid qualified column reference with expression"
171 ));
172 }
173 };
174 }
175 } else {
176 return Err("Expected identifier after '.'".to_string());
177 }
178 }
179
180 while matches!(
182 parser.current_token(),
183 Token::Star | Token::Divide | Token::Modulo
184 ) {
185 let op = match parser.current_token() {
186 Token::Star => "*",
187 Token::Divide => "/",
188 Token::Modulo => "%",
189 _ => unreachable!(),
190 };
191
192 log_parse_decision(
193 "parse_multiplicative",
194 parser.current_token(),
195 &format!("Binary operator '{}' found, parsing right operand", op),
196 );
197
198 parser.advance();
199 let right = parser.parse_primary()?;
200
201 debug!(operator = op, "Creating multiplicative binary operation");
202
203 left = SqlExpression::BinaryOp {
204 left: Box::new(left),
205 op: op.to_string(),
206 right: Box::new(right),
207 };
208 }
209
210 let result = Ok(left);
211 trace_parse_exit("parse_multiplicative", &result);
212 result
213}
214
215pub trait ParseArithmetic {
217 fn current_token(&self) -> &Token;
218 fn advance(&mut self);
219 fn consume(&mut self, expected: Token) -> Result<(), String>;
220
221 fn parse_primary(&mut self) -> Result<SqlExpression, String>;
223 fn parse_multiplicative(&mut self) -> Result<SqlExpression, String>;
224 fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String>;
225}