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}