sql_cli/sql/parser/expressions/
arithmetic.rs1use 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
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!(parser.current_token(), Token::Plus | Token::Minus) {
22 let op = match parser.current_token() {
23 Token::Plus => "+",
24 Token::Minus => "-",
25 _ => unreachable!(),
26 };
27
28 log_parse_decision(
29 "parse_additive",
30 parser.current_token(),
31 &format!("Binary operator '{}' found, parsing right operand", op),
32 );
33
34 parser.advance();
35 let right = parser.parse_multiplicative()?;
36
37 debug!(operator = op, "Creating additive binary operation");
38
39 left = SqlExpression::BinaryOp {
40 left: Box::new(left),
41 op: op.to_string(),
42 right: Box::new(right),
43 };
44 }
45
46 let result = Ok(left);
47 trace_parse_exit("parse_additive", &result);
48 result
49}
50
51pub fn parse_multiplicative<P>(parser: &mut P) -> Result<SqlExpression, String>
55where
56 P: ParseArithmetic + ?Sized,
57{
58 trace_parse_entry("parse_multiplicative", parser.current_token());
59
60 let mut left = parser.parse_primary()?;
61
62 while matches!(parser.current_token(), Token::Dot) {
65 debug!("Found dot operator, parsing method call");
66 parser.advance();
67
68 if let Token::Identifier(method) = parser.current_token() {
69 let method_name = method.clone();
70 parser.advance();
71
72 if matches!(parser.current_token(), Token::LeftParen) {
73 log_parse_decision(
74 "parse_multiplicative",
75 parser.current_token(),
76 &format!("Method call '{}' detected", method_name),
77 );
78
79 parser.advance();
80 let args = parser.parse_method_args()?;
81 parser.consume(Token::RightParen)?;
82
83 left = match left {
85 SqlExpression::Column(obj) => {
86 debug!(
88 column = %obj,
89 method = %method_name,
90 "Creating method call on column"
91 );
92 SqlExpression::MethodCall {
93 object: obj,
94 method: method_name,
95 args,
96 }
97 }
98 SqlExpression::MethodCall { .. } | SqlExpression::ChainedMethodCall { .. } => {
99 debug!(
101 method = %method_name,
102 "Creating chained method call"
103 );
104 SqlExpression::ChainedMethodCall {
105 base: Box::new(left),
106 method: method_name,
107 args,
108 }
109 }
110 _ => {
111 debug!(
113 method = %method_name,
114 "Creating method call on expression"
115 );
116 SqlExpression::ChainedMethodCall {
117 base: Box::new(left),
118 method: method_name,
119 args,
120 }
121 }
122 };
123 } else {
124 return Err(format!("Expected '(' after method name '{method_name}'"));
125 }
126 } else {
127 return Err("Expected method name after '.'".to_string());
128 }
129 }
130
131 while matches!(
133 parser.current_token(),
134 Token::Star | Token::Divide | Token::Modulo
135 ) {
136 let op = match parser.current_token() {
137 Token::Star => "*",
138 Token::Divide => "/",
139 Token::Modulo => "%",
140 _ => unreachable!(),
141 };
142
143 log_parse_decision(
144 "parse_multiplicative",
145 parser.current_token(),
146 &format!("Binary operator '{}' found, parsing right operand", op),
147 );
148
149 parser.advance();
150 let right = parser.parse_primary()?;
151
152 debug!(operator = op, "Creating multiplicative binary operation");
153
154 left = SqlExpression::BinaryOp {
155 left: Box::new(left),
156 op: op.to_string(),
157 right: Box::new(right),
158 };
159 }
160
161 let result = Ok(left);
162 trace_parse_exit("parse_multiplicative", &result);
163 result
164}
165
166pub trait ParseArithmetic {
168 fn current_token(&self) -> &Token;
169 fn advance(&mut self);
170 fn consume(&mut self, expected: Token) -> Result<(), String>;
171
172 fn parse_primary(&mut self) -> Result<SqlExpression, String>;
174 fn parse_multiplicative(&mut self) -> Result<SqlExpression, String>;
175 fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String>;
176}