1use crate::template::{BoolValue, MatchOp, TextValue};
2use crate::template_parser::structs::operators::{
3 ArithmeticUnaryOp, CompareOp, ListInOp, LogicOp, Paren,
4};
5use crate::template_parser::{ArithmeticExpr, ArithmeticOp, LogicExpr, MaybeValue, TextExpr};
6use crate::{Atomic, AtomicStream, Operator, Sign, VariableChain};
7use proc_macro2::fallback::unforce;
8use std::fmt::Debug;
9
10use crate::template_parser::error::TemplateParseError;
11use crate::template_parser::structs::atomics::{
12 AtomicTrait, GenericAtomic, GenericAtomicStream, MySqlAtomic,
13};
14use crate::template_parser::structs::operators::ConnectOp;
15use tracing::{debug, error};
16
17pub type ParseResult<T> = std::result::Result<T, TemplateParseError>;
18
19#[derive(Debug, Clone, PartialEq)]
20pub enum GenericExpr {
21 Atomic(GenericAtomic),
22 ArithmeticExpr {
23 left: Box<GenericExpr>,
24 op: ArithmeticOp,
25 right: Box<GenericExpr>,
26 },
27 AnnotatedArithmeticExpr {
28 unary_op: ArithmeticUnaryOp,
29 expr: Box<GenericExpr>,
30 },
31 CompareExpr {
32 left: Box<GenericExpr>,
33 op: CompareOp,
34 right: Box<GenericExpr>,
35 },
36 Not(Box<GenericExpr>),
37 LogicExpr {
38 left: Box<GenericExpr>,
39 op: LogicOp,
40 right: Box<GenericExpr>,
41 },
42 CommaExpr {
43 left: Box<GenericExpr>,
44 op: ConnectOp,
45 right: Box<GenericExpr>,
46 },
47 NestedExpr(Box<GenericExpr>),
48 FnCallExpr {
49 name: VariableChain,
50 args: Box<GenericExpr>, },
52 ListInExpr {
53 left: Box<GenericExpr>,
54 op: ListInOp,
55 right: Box<GenericExpr>,
56 },
57}
58
59impl GenericExpr {
60 pub fn parse_str<T>(input: &str) -> ParseResult<GenericExpr>
61 where
62 T: AtomicTrait + Clone + PartialEq + Debug + Into<GenericAtomic>,
63 {
64 let stream = GenericAtomicStream::parse::<T>(input)?;
65 let (remaining, parsed) = Self::parse(stream.atomics)?;
66 Ok(parsed)
67 }
68
69 fn is_inner_comma_expr(&self) -> bool {
70 match self {
71 GenericExpr::CommaExpr { .. } => true,
72 GenericExpr::Atomic(_) => true,
73 GenericExpr::NestedExpr(inner) => inner.is_inner_comma_expr(),
74 _ => false,
75 }
76 }
77 fn is_nested_comma_expr(&self) -> bool {
78 match self {
79 GenericExpr::NestedExpr(inner) => inner.is_inner_comma_expr(),
80 _ => false,
81 }
82 }
83
84 fn is_unary_op(arithmetic_op: ArithmeticOp, prev: &Option<GenericAtomic>) -> bool {
85 match arithmetic_op {
90 ArithmeticOp::Add | ArithmeticOp::Sub => {}
91 _ => return false,
92 }
93
94 match prev {
95 None => true,
96 Some(atomic) => match atomic {
97 GenericAtomic::Operator(_) => true,
98 _ => false,
99 },
100 }
101 }
102
103 fn is_unary_op_sign(sign: &Sign, prev: &Option<GenericAtomic>) -> bool {
104 match sign {
109 Sign::Plus | Sign::Minus => {}
110 _ => return false,
111 }
112
113 match prev {
114 None => true,
115 Some(atomic) => match atomic {
116 GenericAtomic::Operator(_) => true,
117 _ => false,
118 },
119 }
120 }
121
122 fn reduce_recursive(
123 operator: &Operator,
124 operands: &mut Vec<GenericExpr>,
125 operators: &mut Vec<Operator>,
126 ) -> ParseResult<()> {
127 while let Some(top) = operators.last() {
128 if let Operator::Paren(Paren::Left) | Operator::FnCall(_) = top {
130 return Ok(());
131 }
132 if precedence(top) < precedence(&operator) {
134 return Ok(());
135 }
136 Self::reduce(operands, operators)?;
138 }
139 Ok(())
140 }
141 fn consume_token(
142 token: GenericAtomic,
143 index: usize,
144 prev: &Option<GenericAtomic>,
145 operands: &mut Vec<GenericExpr>,
146 operators: &mut Vec<Operator>,
147 ) -> ParseResult<Option<GenericExpr>> {
148 match token {
149 GenericAtomic::Keyword(_) => Ok(Some(GenericExpr::Atomic(token.clone()))),
150
151 GenericAtomic::Null
152 | GenericAtomic::Number(_)
153 | GenericAtomic::Text(_)
154 | GenericAtomic::Bool(_)
155 | GenericAtomic::Maybe(_) => {
156 debug!("GenericExpr::parse() push operands: {:?}", &token);
158 operands.push(GenericExpr::Atomic(token.clone()));
159 Ok(None)
160 }
161
162 GenericAtomic::Sign(sign) => {
163 if let Sign::Star = sign {
165 if index == 0 || &Some(GenericAtomic::Keyword("SELECT")) == prev {
166 return Ok(Some(GenericExpr::Atomic(GenericAtomic::Sign(sign))));
167 }
168 operators.push(Operator::Arithmetic(ArithmeticOp::Add));
169 }
170 if let Sign::Plus = sign {
171 if index == 0 || Self::is_unary_op_sign(&sign, &prev) {
172 operators.push(Operator::ArithmeticUnary(ArithmeticUnaryOp::Add));
173 }
174 } else if let Sign::Minus = sign {
175 if index == 0 || Self::is_unary_op_sign(&sign, &prev) {
176 operators.push(Operator::ArithmeticUnary(ArithmeticUnaryOp::Sub));
177 }
178 } else {
179 operands.push(GenericExpr::Atomic(GenericAtomic::Sign(sign.clone())));
180 }
181 Ok(None)
182 }
183 GenericAtomic::Operator(operator) => {
184 match operator {
185 Operator::Paren(Paren::Left) => {
186 if let Some(GenericExpr::Atomic(GenericAtomic::Maybe(
188 MaybeValue::VariableChain(v),
189 ))) = operands.last()
190 {
191 operators.push(Operator::FnCall(v.clone()));
193 } else {
194 operators.push(Operator::Paren(Paren::Left));
196 }
197 Ok(None)
198 }
199 Operator::Paren(Paren::Right) => {
200 while let Some(top) = operators.last() {
202 match top {
203 Operator::Paren(Paren::Left) | Operator::FnCall(_) => break,
204 _ => Self::reduce(operands, operators)?,
205 }
206 }
207 debug!("GenericExpr::parse() pop left paren or FnCallOp");
209 if let Some(op) = operators.pop() {
210 match op {
211 Operator::Paren(Paren::Left) | Operator::FnCall(_) => {
212 Self::reduce(operands, operators)?;
214 Ok(None)
215 }
216 _ => return Err("Mismatched parentheses".into()),
217 }
218 } else {
219 return Err("Mismatched parentheses".into());
220 }
221 }
222 Operator::Arithmetic(arithmetic_op) => {
223 let is_unary = Self::is_unary_op(arithmetic_op.clone(), &prev);
225
226 if is_unary {
227 match arithmetic_op {
229 ArithmeticOp::Add => operators
230 .push(Operator::ArithmeticUnary(ArithmeticUnaryOp::Add)),
231 ArithmeticOp::Sub => operators
232 .push(Operator::ArithmeticUnary(ArithmeticUnaryOp::Sub)),
233 _ => unreachable!(),
234 }
235 } else {
236 Self::reduce_recursive(&operator, operands, operators)?;
237 operators.push(operator.clone());
239 }
240 debug!(
241 "GenericExpr::parse() operators len[{}]: {:?}",
242 operators.len(),
243 operators
244 );
245 Ok(None)
246 }
247 _ => {
248 Self::reduce_recursive(&operator, operands, operators)?;
250 operators.push(operator.clone());
252 debug!(
253 "GenericExpr::parse() operators len[{}]: {:?}",
254 operators.len(),
255 operators
256 );
257 Ok(None)
258 }
259 }
260 }
261 }
262 }
263 pub fn parse(
264 mut atomics: Vec<GenericAtomic>,
265 ) -> ParseResult<(Vec<GenericAtomic>, GenericExpr)> {
266 debug!("GenericExpr::parse({:?})", atomics);
267 let mut operands: Vec<GenericExpr> = Vec::new(); let mut operators: Vec<Operator> = Vec::new(); let mut prev: Option<GenericAtomic> = None;
270
271 for token in atomics.clone() {
272 let current = token.clone();
273 match token {
274 GenericAtomic::Keyword(_) => {
275 return Ok((atomics, GenericExpr::Atomic(token.clone())));
276 }
277 GenericAtomic::Null
278 | GenericAtomic::Number(_)
279 | GenericAtomic::Text(_)
280 | GenericAtomic::Bool(_)
281 | GenericAtomic::Maybe(_) => {
282 debug!("GenericExpr::parse() push atomic: {:?}", &token);
284 operands.push(GenericExpr::Atomic(token.clone()));
285 }
286 GenericAtomic::Sign(sign) => {
287 if let Sign::Star = sign {}
288 operands.push(GenericExpr::Atomic(GenericAtomic::Sign(sign.clone())));
289 }
290 GenericAtomic::Operator(operator) => {
291 match operator {
292 Operator::Paren(Paren::Left) => {
293 if let Some(GenericExpr::Atomic(GenericAtomic::Maybe(
295 MaybeValue::VariableChain(v),
296 ))) = operands.last()
297 {
298 operators.push(Operator::FnCall(v.clone()));
300 } else {
301 operators.push(Operator::Paren(Paren::Left));
303 }
304 }
305 Operator::Paren(Paren::Right) => {
306 while let Some(top) = operators.last() {
308 match top {
309 Operator::Paren(Paren::Left) | Operator::FnCall(_) => break,
310 _ => Self::reduce(&mut operands, &mut operators)?,
311 }
312 }
313 debug!("GenericExpr::parse() pop left paren or FnCallOp");
315 if let Some(op) = operators.pop() {
316 match op {
317 Operator::Paren(Paren::Left) | Operator::FnCall(_) => {
318 Self::reduce(&mut operands, &mut operators)?
320 }
321 _ => return Err("Mismatched parentheses".into()),
322 }
323 } else {
324 return Err("Mismatched parentheses".into());
325 }
326 }
327 Operator::Arithmetic(arithmetic_op) => {
328 let is_unary = Self::is_unary_op(arithmetic_op.clone(), &prev);
330
331 if is_unary {
332 match arithmetic_op {
334 ArithmeticOp::Add => operators
335 .push(Operator::ArithmeticUnary(ArithmeticUnaryOp::Add)),
336 ArithmeticOp::Sub => operators
337 .push(Operator::ArithmeticUnary(ArithmeticUnaryOp::Sub)),
338 _ => unreachable!(),
339 }
340 } else {
341 Self::reduce_recursive(&operator, &mut operands, &mut operators)?;
342 operators.push(operator.clone());
344 }
345 debug!(
346 "GenericExpr::parse() operators len[{}]: {:?}",
347 operators.len(),
348 operators
349 );
350 }
351 _ => {
352 Self::reduce_recursive(&operator, &mut operands, &mut operators)?;
354 operators.push(operator.clone());
356 debug!(
357 "GenericExpr::parse() operators len[{}]: {:?}",
358 operators.len(),
359 operators
360 );
361 }
362 }
363 }
364 }
365 prev = Some(current);
366 }
367
368 while let Some(op) = operators.last() {
370 if let Operator::Paren(Paren::Left) | Operator::FnCall(_) = op {
371 return Err("Mismatched parentheses".into());
372 }
373 debug!("GenericExpr::parse remaining operator: {:?}", &operators);
374 Self::reduce(&mut operands, &mut operators)?;
375 }
376
377 if operands.len() != 1 {
379 return Err("Invalid expression".into());
383 }
384
385 let expr = operands.pop().unwrap();
386 Ok((Vec::new(), expr))
387 }
388
389 fn reduce(
390 operands: &mut Vec<GenericExpr>,
391 operators: &mut Vec<Operator>,
392 ) -> Result<(), String> {
393 if let Some(op) = operators.pop() {
394 debug!(
395 "GenericExpr::reduce op: ({:?}) remaining len[{:?}]",
396 op,
397 operators.len()
398 );
399 match op {
400 Operator::ArithmeticUnary(unary_op) => match unary_op {
401 ArithmeticUnaryOp::Add => {
402 let operand = operands
403 .pop()
404 .ok_or("Missing operand for UnaryPlus".to_string())?;
405 operands.push(GenericExpr::AnnotatedArithmeticExpr {
406 unary_op: ArithmeticUnaryOp::Add,
407 expr: Box::new(operand),
408 });
409 }
410 ArithmeticUnaryOp::Sub => {
411 let operand = operands
412 .pop()
413 .ok_or("Missing operand for UnaryMinus".to_string())?;
414 operands.push(GenericExpr::AnnotatedArithmeticExpr {
415 unary_op: ArithmeticUnaryOp::Sub,
416 expr: Box::new(operand),
417 });
418 }
419 },
420 Operator::Arithmetic(arithmetic_op) => {
421 let right = operands.pop().ok_or("Missing right operand".to_string())?;
422 let left = operands.pop().ok_or("Missing left operand".to_string())?;
423 operands.push(GenericExpr::ArithmeticExpr {
424 left: Box::new(left),
425 op: arithmetic_op,
426 right: Box::new(right),
427 });
428 }
429 Operator::Compare(compare_op) => {
430 let right = operands.pop().ok_or("Missing right operand".to_string())?;
431 let left = operands.pop().ok_or("Missing left operand".to_string())?;
432 operands.push(GenericExpr::CompareExpr {
433 left: Box::new(left),
434 op: compare_op,
435 right: Box::new(right),
436 });
437 }
438 Operator::Logic(logic_op) => match logic_op {
439 LogicOp::Not => {
440 let operand = operands
441 .pop()
442 .ok_or("Missing operand for Not".to_string())?;
443 operands.push(GenericExpr::Not(Box::new(operand)));
444 }
445 _ => {
446 let right = operands.pop().ok_or("Missing right operand".to_string())?;
447 let left = operands.pop().ok_or("Missing left operand".to_string())?;
448 operands.push(GenericExpr::LogicExpr {
449 left: Box::new(left),
450 op: logic_op,
451 right: Box::new(right),
452 });
453 }
454 },
455 Operator::ListInOp(list_in_op) => {
456 let right = operands.pop().ok_or("Missing right operand".to_string())?;
457 if !right.is_inner_comma_expr() {
458 return Err("right operand must be comma expr".to_string());
459 }
460 let left = operands.pop().ok_or("Missing left operand".to_string())?;
461 operands.push(GenericExpr::ListInExpr {
462 left: Box::new(left),
463 op: list_in_op,
464 right: Box::new(right),
465 });
466 }
467 Operator::Connect(connect_op) => {
468 let right = operands.pop().ok_or("Missing right operand".to_string())?;
469 let left = operands.pop().ok_or("Missing left operand".to_string())?;
470 operands.push(GenericExpr::CommaExpr {
471 left: Box::new(left),
472 op: connect_op,
473 right: Box::new(right),
474 });
475 }
476 Operator::FnCall(variable_chain) => {
477 let args = operands.pop().ok_or("Missing fn call args".to_string())?;
479 if !args.is_inner_comma_expr() {
480 return Err("Function arguments must be a comma expression".to_string());
481 }
482
483 let fn_call = GenericExpr::FnCallExpr {
485 name: variable_chain,
486 args: Box::new(args),
487 };
488 operands.push(fn_call);
489 }
490 Operator::Paren(p) => match p {
491 Paren::Left => {
492 let inner = operands.pop().ok_or("Missing right operand".to_string())?;
493 operands.push(GenericExpr::NestedExpr(Box::new(inner)));
494 }
495 Paren::Right => return Err("Unexpected parenthesis in reduce".to_string()),
496 },
497 }
498 }
499 Ok(())
500 }
501}
502
503fn precedence(op: &Operator) -> u8 {
507 match op {
508 Operator::ArithmeticUnary(_) => 8, Operator::Arithmetic(arithmetic_op) => match arithmetic_op {
510 ArithmeticOp::Mul | ArithmeticOp::Div | ArithmeticOp::Mod => 7,
511 ArithmeticOp::Add | ArithmeticOp::Sub => 6,
512 },
513 Operator::Compare(_) => 5,
514 Operator::ListInOp(_) => 5,
515 Operator::Logic(logic_op) => match logic_op {
516 LogicOp::Not => 4,
517 LogicOp::And => 3,
518 LogicOp::Or => 2,
519 },
520 Operator::Connect(_) => 1,
521 Operator::Paren(_) | Operator::FnCall(_) => 0, }
523}