1use crate::{
2 ast::{BinaryExpression, BinaryOperator, ErrorToken, Expression},
3 parser::{
4 simple_expr,
5 utils::{keyword, IResult, LocatedSpan},
6 },
7};
8use nom::{
9 branch::alt,
10 bytes::complete::tag,
11 combinator::value,
12 error::{FromExternalError, ParseError},
13 multi::many1,
14 sequence::tuple,
15};
16use std::{iter::Peekable, vec::IntoIter};
17
18#[derive(Debug, PartialEq, Clone)]
19enum Token {
20 Operator(BinaryOperator),
21 Expression(Expression),
22}
23impl Token {
24 pub fn precedence(&self) -> u8 {
25 match self {
26 Token::Operator(op) => op.precedence(),
27 _ => u8::max_value(),
28 }
29 }
30}
31#[derive(Debug)]
32enum AstError {
33 ExpectedOperator,
34 ExpectedToken,
35}
36
37impl<'a> ParseError<LocatedSpan<'a>> for AstError {
38 fn from_error_kind(_: LocatedSpan, _: nom::error::ErrorKind) -> Self {
39 todo!()
40 }
41 fn append(_: LocatedSpan, _: nom::error::ErrorKind, _: Self) -> Self {
42 todo!()
43 }
44}
45
46struct PrecedenceSolver {
47 token_iter: Peekable<IntoIter<Token>>,
48}
49
50impl PrecedenceSolver {
51 fn nud(&mut self, t: Token) -> Expression {
52 match t {
53 Token::Expression(e) => e,
54 _ => Expression::Error(ErrorToken::Unexpected),
55 }
56 }
57
58 fn led(&mut self, bp: u8, left: Expression, op: Token) -> Result<Expression, AstError> {
59 match op {
60 Token::Operator(operator) => {
61 let right = self.expr(bp)?;
62
63 Ok(Expression::BinaryExpression(Box::new(BinaryExpression {
64 lhs: left,
65 rhs: right,
66 op: operator,
67 })))
68 }
69 _ => Err(AstError::ExpectedOperator),
70 }
71 }
72
73 fn expr(&mut self, rbp: u8) -> Result<Expression, AstError> {
74 let first_token = self.token_iter.next().ok_or(AstError::ExpectedToken)?;
75 let mut left = self.nud(first_token);
76
77 while let Some(peeked) = self.token_iter.peek() {
78 if rbp >= peeked.precedence() {
79 break;
80 }
81
82 let op = self.token_iter.next().unwrap();
83 left = self.led(op.precedence(), left, op)?;
84 }
85
86 Ok(left)
87 }
88
89 fn solve(tokens: IntoIter<Token>) -> Result<Expression, AstError> {
90 let mut solver = PrecedenceSolver {
91 token_iter: tokens.peekable(),
92 };
93 solver.expr(0)
94 }
95}
96
97pub(crate) fn binary_expr(i: LocatedSpan) -> IResult<Expression> {
98 let (i, first_expr) = simple_expr(i)?;
99 let first_token = Token::Expression(first_expr);
100 let (i, other_tokens) = many1(tuple((binary_operator, simple_expr)))(i)?;
101 let mut tokens = vec![first_token];
102 for (sep, expr) in other_tokens {
103 tokens.push(Token::Operator(sep));
104 tokens.push(Token::Expression(expr));
105 }
106
107 match PrecedenceSolver::solve(tokens.into_iter()) {
108 Ok(expr) => Ok((i, expr)),
109 Err(err) => Err(nom::Err::Error(nom::error::Error::from_external_error(
110 i,
111 nom::error::ErrorKind::MapRes,
112 err,
113 ))),
114 }
115}
116
117fn binary_operator(i: LocatedSpan) -> IResult<BinaryOperator> {
118 alt((
119 op_and, op_or, op_before, op_after, op_eq, op_ne, op_lte, op_lt, op_gte, op_gt, op_match,
120 op_imatch,
121 ))(i)
122}
123fn op_and(i: LocatedSpan) -> IResult<BinaryOperator> {
124 value(BinaryOperator::And, keyword("and"))(i)
125}
126fn op_or(i: LocatedSpan) -> IResult<BinaryOperator> {
127 value(BinaryOperator::Or, keyword("or"))(i)
128}
129fn op_before(i: LocatedSpan) -> IResult<BinaryOperator> {
130 value(BinaryOperator::Lte, keyword("before"))(i)
131}
132fn op_after(i: LocatedSpan) -> IResult<BinaryOperator> {
133 value(BinaryOperator::Gte, keyword("after"))(i)
134}
135fn op_eq(i: LocatedSpan) -> IResult<BinaryOperator> {
136 value(BinaryOperator::Eq, tag("=="))(i)
137}
138fn op_ne(i: LocatedSpan) -> IResult<BinaryOperator> {
139 value(BinaryOperator::Ne, tag("!="))(i)
140}
141fn op_lt(i: LocatedSpan) -> IResult<BinaryOperator> {
142 value(BinaryOperator::Lt, tag("<"))(i)
143}
144fn op_lte(i: LocatedSpan) -> IResult<BinaryOperator> {
145 value(BinaryOperator::Lte, tag("<="))(i)
146}
147fn op_gt(i: LocatedSpan) -> IResult<BinaryOperator> {
148 value(BinaryOperator::Gt, tag(">"))(i)
149}
150fn op_gte(i: LocatedSpan) -> IResult<BinaryOperator> {
151 value(BinaryOperator::Gte, tag(">="))(i)
152}
153fn op_match(i: LocatedSpan) -> IResult<BinaryOperator> {
154 value(BinaryOperator::Match, keyword("match"))(i)
155}
156fn op_imatch(i: LocatedSpan) -> IResult<BinaryOperator> {
157 value(BinaryOperator::IMatch, keyword("imatch"))(i)
158}
159
160#[cfg(test)]
161mod tests {
162 use crate::{
163 ast::{
164 BinaryExpression, BinaryOperator, Duration, Expression, RelativeTime, TimeAnchor, Value,
165 },
166 parser::{
167 binary_expr,
168 utils::{span, unwrap_span},
169 },
170 };
171
172 #[test]
173
174 fn test_binary_expr() {
175 assert_eq!(
176 binary_expr(span(".a.b.c and true")).map(unwrap_span),
177 Ok((
178 "",
179 Expression::BinaryExpression(Box::new(BinaryExpression {
180 lhs: Expression::AbsolutePath(vec!["a".to_string(), "b".to_string(), "c".to_string(),]),
181 op: BinaryOperator::And,
182 rhs: Expression::Value(Value::Bool(true)),
183 }))
184 ))
185 );
186
187 assert_eq!(
188 binary_expr(span("true and false or false and true")).map(unwrap_span),
189 Ok((
190 "",
191 Expression::BinaryExpression(Box::new(BinaryExpression {
192 lhs: Expression::BinaryExpression(Box::new(BinaryExpression {
193 lhs: Expression::Value(Value::Bool(true)),
194 op: BinaryOperator::And,
195 rhs: Expression::Value(Value::Bool(false)),
196 })),
197 op: BinaryOperator::Or,
198 rhs: Expression::BinaryExpression(Box::new(BinaryExpression {
199 lhs: Expression::Value(Value::Bool(false)),
200 op: BinaryOperator::And,
201 rhs: Expression::Value(Value::Bool(true)),
202 })),
203 }))
204 ))
205 );
206
207 assert_eq!(
208 binary_expr(span("true and false or false and true == 0 > 3")).map(unwrap_span),
209 Ok((
210 "",
211 Expression::BinaryExpression(Box::new(BinaryExpression {
212 lhs: Expression::BinaryExpression(Box::new(BinaryExpression {
213 lhs: Expression::Value(Value::Bool(true)),
214 op: BinaryOperator::And,
215 rhs: Expression::Value(Value::Bool(false)),
216 })),
217 op: BinaryOperator::Or,
218 rhs: Expression::BinaryExpression(Box::new(BinaryExpression {
219 lhs: Expression::Value(Value::Bool(false)),
220 op: BinaryOperator::And,
221 rhs: Expression::BinaryExpression(Box::new(BinaryExpression {
222 lhs: Expression::Value(Value::Bool(true)),
223 op: BinaryOperator::Eq,
224 rhs: Expression::BinaryExpression(Box::new(BinaryExpression {
225 lhs: Expression::Value(Value::Int(0)),
226 op: BinaryOperator::Gt,
227 rhs: Expression::Value(Value::Int(3)),
228 })),
229 }))
230 })),
231 }))
232 ))
233 );
234
235 assert_eq!(
236 binary_expr(span(".time after 10 minutes ago")).map(unwrap_span),
237 Ok((
238 "",
239 Expression::BinaryExpression(Box::new(BinaryExpression {
240 lhs: Expression::AbsolutePath(vec!["time".to_string()]),
241 op: BinaryOperator::Gte,
242 rhs: Expression::Value(Value::RelativeTime(RelativeTime::Duration(
243 Duration::Minutes(10),
244 TimeAnchor::Ago
245 ))),
246 }))
247 ))
248 );
249 }
250}