partiql/parser/
math.rs

1use nom::branch::alt;
2use nom::character::complete::{char, space0};
3use nom::combinator::map;
4use nom::multi::many0;
5use nom::number::complete::double;
6use nom::sequence::{delimited, tuple};
7use nom::IResult;
8
9use crate::sql::Expr;
10
11use crate::parser;
12
13pub fn parse(input: &str) -> IResult<&str, Expr> {
14    parse_math_expr(input)
15}
16
17fn parse_parens(input: &str) -> IResult<&str, Expr> {
18    delimited(
19        space0,
20        delimited(char('('), parse_math_expr, char(')')),
21        space0,
22    )(input)
23}
24
25fn parse_operation(input: &str) -> IResult<&str, Expr> {
26    alt((parse_parens, parse_path_or_num))(input)
27}
28
29fn parse_factor(input: &str) -> IResult<&str, Expr> {
30    let (input, num1) = parse_operation(input)?;
31    let (input, exprs) = many0(tuple((char('^'), parse_factor)))(input)?;
32    Ok((input, parse_expr(num1, exprs)))
33}
34
35fn parse_term(input: &str) -> IResult<&str, Expr> {
36    let (input, num1) = parse_factor(input)?;
37    let (input, exprs) = many0(tuple((
38        alt((char('/'), char('*'), char('%'))),
39        parse_factor,
40    )))(input)?;
41    Ok((input, parse_expr(num1, exprs)))
42}
43
44fn parse_math_expr(input: &str) -> IResult<&str, Expr> {
45    let (input, num1) = parse_term(input)?;
46    let (input, exprs) = many0(tuple((alt((char('+'), char('-'))), parse_term)))(input)?;
47    Ok((input, parse_expr(num1, exprs)))
48}
49
50fn parse_expr(expr: Expr, rem: Vec<(char, Expr)>) -> Expr {
51    rem.into_iter().fold(expr, |acc, val| parse_op(val, acc))
52}
53
54fn parse_op(tup: (char, Expr), expr1: Expr) -> Expr {
55    let (op, expr2) = tup;
56    match op {
57        '+' => Expr::Add(Box::new(expr1), Box::new(expr2)),
58        '-' => Expr::Sub(Box::new(expr1), Box::new(expr2)),
59        '*' => Expr::Mul(Box::new(expr1), Box::new(expr2)),
60        '/' => Expr::Div(Box::new(expr1), Box::new(expr2)),
61        '%' => Expr::Rem(Box::new(expr1), Box::new(expr2)),
62        '^' => Expr::Exp(Box::new(expr1), Box::new(expr2)),
63        _ => unreachable!(),
64    }
65}
66
67pub fn parse_path_or_num(input: &str) -> IResult<&str, Expr> {
68    delimited(
69        space0,
70        alt((
71            parser::float_number,
72            parser::func::count,
73            parser::parse_path_as_expr,
74        )),
75        space0,
76    )(input)
77}
78
79fn parse_number(input: &str) -> IResult<&str, Expr> {
80    map(double, |f| Expr::from(f as f64))(input)
81}
82
83#[cfg(test)]
84mod tests {
85    use super::parse;
86    use crate::sql::{Expr, Selector};
87
88    #[test]
89    fn parse_sub_sub_path() {
90        let parsed = parse("a- b -c");
91        assert_eq!(
92            parsed,
93            Ok((
94                "",
95                Expr::Sub(
96                    Box::new(Expr::Sub(
97                        Box::new(Expr::Selector(Selector::from("a"))),
98                        Box::new(Expr::Selector(Selector::from("b"))),
99                    )),
100                    Box::new(Expr::Selector(Selector::from("c"))),
101                )
102            ))
103        );
104    }
105
106    #[test]
107    fn parse_sub_sub() {
108        let parsed = parse("1-2-3");
109        assert_eq!(
110            parsed,
111            Ok((
112                "",
113                Expr::Sub(
114                    Box::new(Expr::Sub(
115                        Box::new(Expr::from(1.0)),
116                        Box::new(Expr::from(2.0)),
117                    )),
118                    Box::new(Expr::from(3.0)),
119                )
120            ))
121        );
122    }
123
124    #[test]
125    fn parse_add_statement() {
126        let parsed = parse("12 + 34");
127        assert_eq!(
128            parsed,
129            Ok((
130                "",
131                Expr::Add(Box::new(Expr::from(12.0)), Box::new(Expr::from(34.0)))
132            ))
133        );
134    }
135
136    #[test]
137    fn parse_subtract_statement() {
138        let parsed = parse("12 - 34");
139        assert_eq!(
140            parsed,
141            Ok((
142                "",
143                Expr::Sub(Box::new(Expr::from(12.0)), Box::new(Expr::from(34.0)))
144            ))
145        );
146    }
147
148    #[test]
149    fn parse_nested_add_sub_statements() {
150        let parsed = parse("12 - 34 + 15 - 9");
151        assert_eq!(
152            parsed,
153            Ok((
154                "",
155                Expr::Sub(
156                    Box::new(Expr::Add(
157                        Box::new(Expr::Sub(
158                            Box::new(Expr::from(12.0)),
159                            Box::new(Expr::from(34.0))
160                        )),
161                        Box::new(Expr::from(15.0))
162                    )),
163                    Box::new(Expr::from(9.0))
164                )
165            ))
166        );
167    }
168
169    #[test]
170    fn test_parse_multi_level_expression() {
171        let parsed = parse("1 * 2 + 3 / 4 ^ 6");
172        let expected = Expr::Add(
173            Box::new(Expr::Mul(
174                Box::new(Expr::from(1.0)),
175                Box::new(Expr::from(2.0)),
176            )),
177            Box::new(Expr::Div(
178                Box::new(Expr::from(3.0)),
179                Box::new(Expr::Exp(
180                    Box::new(Expr::from(4.0)),
181                    Box::new(Expr::from(6.0)),
182                )),
183            )),
184        );
185        assert_eq!(parsed, Ok(("", expected)));
186    }
187
188    #[test]
189    fn test_parse_expression_with_parantheses() {
190        let parsed = parse("(1 + 2) * 3");
191        let expected = Expr::Mul(
192            Box::new(Expr::Add(
193                Box::new(Expr::from(1.0)),
194                Box::new(Expr::from(2.0)),
195            )),
196            Box::new(Expr::from(3.0)),
197        );
198        assert_eq!(parsed, Ok(("", expected)));
199    }
200}