qail_core/parser/grammar/
binary_ops.rs1use super::expressions::parse_json_or_ident;
9use crate::ast::*;
10use nom::{IResult, Parser, bytes::complete::tag, character::complete::multispace0};
11
12pub fn parse_concat_expr(input: &str) -> IResult<&str, Expr> {
14 let (input, left) = parse_additive_expr(input)?;
15 parse_binary_chain(
16 input,
17 left,
18 parse_additive_expr,
19 &[("||", BinaryOp::Concat)],
20 )
21}
22
23pub fn parse_additive_expr(input: &str) -> IResult<&str, Expr> {
25 let (input, left) = parse_multiplicative_expr(input)?;
26 parse_binary_chain(
27 input,
28 left,
29 parse_multiplicative_expr,
30 &[("+", BinaryOp::Add), ("-", BinaryOp::Sub)],
31 )
32}
33
34pub fn parse_multiplicative_expr(input: &str) -> IResult<&str, Expr> {
36 let (input, left) = parse_json_or_ident(input)?;
37 parse_binary_chain(
38 input,
39 left,
40 parse_json_or_ident,
41 &[
42 ("*", BinaryOp::Mul),
43 ("/", BinaryOp::Div),
44 ("%", BinaryOp::Rem),
45 ],
46 )
47}
48
49pub fn parse_binary_chain<'a, F>(
51 mut input: &'a str,
52 mut left: Expr,
53 parse_operand: F,
54 operators: &[(&str, BinaryOp)],
55) -> IResult<&'a str, Expr>
56where
57 F: Fn(&'a str) -> IResult<&'a str, Expr>,
58{
59 loop {
60 let (remaining, _) = multispace0(input)?;
61
62 let mut matched = None;
64 for (op_str, op_enum) in operators {
65 if let Ok((after_op, _)) =
66 tag::<_, _, nom::error::Error<&str>>(*op_str).parse(remaining)
67 {
68 matched = Some((after_op, *op_enum));
69 break;
70 }
71 }
72
73 if let Some((after_op, op)) = matched {
74 let (after_ws, _) = multispace0(after_op)?;
75 let (after_right, right) = parse_operand(after_ws)?;
76 left = Expr::Binary {
77 left: Box::new(left),
78 op,
79 right: Box::new(right),
80 alias: None,
81 };
82 input = after_right;
83 } else {
84 break;
85 }
86 }
87
88 Ok((input, left))
89}