1use nom::{
47 IResult, Parser,
48 branch::alt,
49 character::complete::char,
50 combinator::{opt, peek},
51 multi::separated_list0,
52 sequence::{delimited, preceded, terminated},
53};
54
55use crate::ast::{Aggregation, BinaryExpr, Call, Expr, SubqueryExpr, UnaryExpr};
56use crate::lexer::{
57 duration::duration,
58 identifier::{Keyword, aggregation_op, metric_name},
59 number::number,
60 string::string_literal,
61 whitespace::ws_opt,
62};
63use crate::parser::{
64 aggregation::grouping,
65 binary::{binary_modifier, binary_op},
66 selector::{label_matchers, parse_modifiers},
67 subquery::{looks_like_subquery, subquery_range},
68 unary::unary_op,
69};
70
71pub fn expr(input: &str) -> IResult<&str, Expr> {
93 preceded(ws_opt, |i| parse_binary_expr(i, 0)).parse(input)
95}
96
97fn parse_binary_expr(input: &str, min_precedence: u8) -> IResult<&str, Expr> {
102 let (mut input, mut lhs) = parse_unary_expr(input)?;
103
104 loop {
105 let Ok((after_ws, _)) = ws_opt(input) else {
107 break;
108 };
109 let Ok((after_op, op)) = binary_op(after_ws) else {
110 break;
111 };
112
113 let op_precedence = op.precedence();
115 if op_precedence < min_precedence {
116 break;
117 }
118
119 let next_min_precedence = if op.is_right_associative() {
122 op_precedence
123 } else {
124 op_precedence + 1
125 };
126
127 let (remaining, (_, modifier, _, rhs)) = (ws_opt, opt(binary_modifier), ws_opt, |i| {
129 parse_binary_expr(i, next_min_precedence)
130 })
131 .parse(after_op)?;
132
133 lhs = Expr::Binary(Box::new(BinaryExpr {
134 op,
135 lhs,
136 rhs,
137 modifier,
138 }));
139 input = remaining;
140 }
141
142 Ok((input, lhs))
143}
144
145fn parse_unary_expr(input: &str) -> IResult<&str, Expr> {
147 alt((
148 (unary_op, ws_opt, parse_unary_expr)
152 .map(|(op, _, operand)| Expr::Unary(Box::new(UnaryExpr { op, expr: operand }))),
153 parse_postfix_expr,
155 ))
156 .parse(input)
157}
158
159fn parse_postfix_expr(input: &str) -> IResult<&str, Expr> {
165 let (mut rest, mut expr) = parse_primary_expr(input)?;
166
167 while (ws_opt, peek_subquery_start).parse(rest).is_ok() {
170 let (remaining, (_, ((range, step), (at, offset)))) =
171 (ws_opt, (subquery_range, parse_modifiers)).parse(rest)?;
172
173 expr = Expr::Subquery(Box::new(SubqueryExpr {
174 expr,
175 range,
176 step,
177 offset,
178 at,
179 }));
180 rest = remaining;
181 }
182
183 Ok((rest, expr))
184}
185
186fn peek_subquery_start(input: &str) -> IResult<&str, ()> {
189 if looks_like_subquery(input) {
190 Ok((input, ()))
191 } else {
192 Err(nom::Err::Error(nom::error::Error::new(
193 input,
194 nom::error::ErrorKind::Tag,
195 )))
196 }
197}
198
199fn parse_primary_expr(input: &str) -> IResult<&str, Expr> {
201 alt((
202 parse_paren_expr,
204 parse_number_literal,
206 parse_string_literal,
208 parse_labels_only_selector,
210 parse_identifier_expr,
213 ))
214 .parse(input)
215}
216
217fn parse_paren_expr(input: &str) -> IResult<&str, Expr> {
219 delimited((char('('), ws_opt), expr, (ws_opt, char(')')))
220 .map(|inner| Expr::Paren(Box::new(inner)))
221 .parse(input)
222}
223
224fn parse_number_literal(input: &str) -> IResult<&str, Expr> {
226 number.map(Expr::Number).parse(input)
227}
228
229fn parse_string_literal(input: &str) -> IResult<&str, Expr> {
231 string_literal.map(Expr::String).parse(input)
232}
233
234fn parse_identifier_expr(input: &str) -> IResult<&str, Expr> {
241 if let Ok((rest, op)) = aggregation_op(input) {
243 return parse_aggregation_expr(rest, op);
244 }
245
246 let (rest, (name, _)) = (metric_name, ws_opt).parse(input)?;
248
249 if peek_open_paren(rest).is_ok() {
251 parse_function_call(rest, name)
252 } else {
253 parse_vector_selector_with_name(rest, name)
254 }
255}
256
257fn peek_open_paren(input: &str) -> IResult<&str, char> {
260 peek(char('(')).parse(input)
261}
262
263fn peek_open_brace(input: &str) -> IResult<&str, char> {
266 peek(char('{')).parse(input)
267}
268
269fn parse_aggregation_expr(input: &str, op: Keyword) -> IResult<&str, Expr> {
271 let (rest, grouping_before) =
273 preceded(ws_opt, opt(terminated(grouping, ws_opt))).parse(input)?;
274
275 let (rest, (param, inner_expr)) = delimited(
277 (char('('), ws_opt),
278 |i| {
279 if op.is_aggregation_with_param() {
280 let (rest, (param, _, _, _, inner)) =
282 (expr, ws_opt, char(','), ws_opt, expr).parse(i)?;
283 Ok((rest, (Some(param), inner)))
284 } else {
285 expr.map(|inner| (None, inner)).parse(i)
287 }
288 },
289 (ws_opt, char(')')),
290 )
291 .parse(rest)?;
292
293 let (rest, grouping_after) = if grouping_before.is_none() {
295 preceded(ws_opt, opt(grouping)).parse(rest)?
296 } else {
297 (rest, None)
298 };
299
300 let agg = Aggregation {
301 op: op.as_str().to_string(),
302 expr: inner_expr,
303 param,
304 grouping: grouping_before.or(grouping_after),
305 };
306
307 Ok((rest, Expr::Aggregation(Box::new(agg))))
308}
309
310fn parse_function_call<'a>(input: &'a str, name: &str) -> IResult<&'a str, Expr> {
312 delimited(
313 (char('('), ws_opt),
314 separated_list0((ws_opt, char(','), ws_opt), expr),
315 (ws_opt, opt((char(','), ws_opt)), char(')')),
316 )
317 .map(|args| Expr::Call(Call::new(name, args)))
318 .parse(input)
319}
320
321fn parse_vector_selector_with_name<'a>(input: &'a str, name: &str) -> IResult<&'a str, Expr> {
323 use crate::parser::selector::{MatrixSelector, VectorSelector};
324
325 let (rest, matchers) = if peek_open_brace(input).is_ok() {
328 label_matchers(input)?
329 } else {
330 (input, Vec::new())
331 };
332
333 if (ws_opt, peek_matrix_bracket).parse(rest).is_ok() {
335 return (ws_opt, char('['), duration, char(']'), parse_modifiers)
337 .map(|(_, _, range, _, (at, offset))| {
338 let selector = VectorSelector {
339 name: Some(name.to_string()),
340 matchers: matchers.clone(),
341 offset,
342 at,
343 };
344 Expr::MatrixSelector(MatrixSelector { selector, range })
345 })
346 .parse(rest);
347 }
348
349 (ws_opt, parse_modifiers)
351 .map(|(_, (at, offset))| {
352 let selector = VectorSelector {
353 name: Some(name.to_string()),
354 matchers: matchers.clone(),
355 offset,
356 at,
357 };
358 Expr::VectorSelector(selector)
359 })
360 .parse(rest)
361}
362
363fn peek_matrix_bracket(input: &str) -> IResult<&str, char> {
366 let (rest, c) = peek(char('[')).parse(input)?;
367 if looks_like_subquery(input) {
369 return Err(nom::Err::Error(nom::error::Error::new(
370 input,
371 nom::error::ErrorKind::Tag,
372 )));
373 }
374 Ok((rest, c))
375}
376
377fn parse_labels_only_selector(input: &str) -> IResult<&str, Expr> {
379 use crate::parser::selector::{LabelMatchOp, MatrixSelector, VectorSelector};
380
381 let (rest, matchers) = label_matchers(input)?;
382
383 let name = matchers
385 .iter()
386 .find(|m| m.name == "__name__" && m.op == LabelMatchOp::Equal)
387 .map(|m| m.value.clone());
388
389 let other_matchers: Vec<_> = if name.is_some() {
391 matchers
392 .into_iter()
393 .filter(|m| !(m.name == "__name__" && m.op == LabelMatchOp::Equal))
394 .collect()
395 } else {
396 matchers
397 };
398
399 if (ws_opt, peek_matrix_bracket).parse(rest).is_ok() {
401 return (ws_opt, char('['), duration, char(']'), parse_modifiers)
402 .map(|(_, _, range, _, (at, offset))| {
403 let selector = VectorSelector {
404 name: name.clone(),
405 matchers: other_matchers.clone(),
406 offset,
407 at,
408 };
409 Expr::MatrixSelector(MatrixSelector { selector, range })
410 })
411 .parse(rest);
412 }
413
414 (ws_opt, parse_modifiers)
416 .map(|(_, (at, offset))| {
417 let selector = VectorSelector {
418 name: name.clone(),
419 matchers: other_matchers.clone(),
420 offset,
421 at,
422 };
423 Expr::VectorSelector(selector)
424 })
425 .parse(rest)
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431 use crate::ast::{BinaryOp, UnaryOp};
432
433 #[test]
434 fn test_parse_number() {
435 let (rest, e) = expr("42").unwrap();
436 assert!(rest.is_empty());
437 assert_eq!(e, Expr::Number(42.0));
438 }
439
440 #[test]
441 fn test_parse_string() {
442 let (rest, e) = expr(r#""hello""#).unwrap();
443 assert!(rest.is_empty());
444 assert_eq!(e, Expr::String("hello".to_string()));
445 }
446
447 #[test]
448 fn test_parse_vector_selector() {
449 let (rest, e) = expr("http_requests").unwrap();
450 assert!(rest.is_empty());
451 match e {
452 Expr::VectorSelector(v) => {
453 assert_eq!(v.name, Some("http_requests".to_string()));
454 }
455 _ => panic!("Expected VectorSelector"),
456 }
457 }
458
459 #[test]
460 fn test_parse_vector_selector_with_labels() {
461 let (rest, e) = expr(r#"http_requests{job="api"}"#).unwrap();
462 assert!(rest.is_empty());
463 match e {
464 Expr::VectorSelector(v) => {
465 assert_eq!(v.name, Some("http_requests".to_string()));
466 assert_eq!(v.matchers.len(), 1);
467 assert_eq!(v.matchers[0].name, "job");
468 assert_eq!(v.matchers[0].value, "api");
469 }
470 _ => panic!("Expected VectorSelector"),
471 }
472 }
473
474 #[test]
475 fn test_parse_matrix_selector() {
476 let (rest, e) = expr("http_requests[5m]").unwrap();
477 assert!(rest.is_empty());
478 match e {
479 Expr::MatrixSelector(m) => {
480 assert_eq!(m.selector.name, Some("http_requests".to_string()));
481 assert_eq!(m.range.as_millis(), 5 * 60 * 1000);
482 }
483 _ => panic!("Expected MatrixSelector"),
484 }
485 }
486
487 #[test]
488 fn test_parse_function_call() {
489 let (rest, e) = expr("rate(http_requests[5m])").unwrap();
490 assert!(rest.is_empty());
491 match e {
492 Expr::Call(c) => {
493 assert_eq!(c.name, "rate");
494 assert_eq!(c.args.len(), 1);
495 }
496 _ => panic!("Expected Call"),
497 }
498 }
499
500 #[test]
501 fn test_parse_aggregation() {
502 let (rest, e) = expr("sum(metric)").unwrap();
503 assert!(rest.is_empty());
504 match e {
505 Expr::Aggregation(a) => {
506 assert_eq!(a.op, "sum");
507 }
508 _ => panic!("Expected Aggregation"),
509 }
510 }
511
512 #[test]
513 fn test_parse_aggregation_with_grouping() {
514 let (rest, e) = expr("sum by (job) (metric)").unwrap();
515 assert!(rest.is_empty());
516 match e {
517 Expr::Aggregation(a) => {
518 assert_eq!(a.op, "sum");
519 assert!(a.grouping.is_some());
520 }
521 _ => panic!("Expected Aggregation"),
522 }
523 }
524
525 #[test]
526 fn test_parse_binary_add() {
527 let (rest, e) = expr("1 + 2").unwrap();
528 assert!(rest.is_empty());
529 match e {
530 Expr::Binary(b) => {
531 assert_eq!(b.op, BinaryOp::Add);
532 }
533 _ => panic!("Expected Binary"),
534 }
535 }
536
537 #[test]
538 fn test_parse_binary_precedence() {
539 let (rest, e) = expr("1 + 2 * 3").unwrap();
541 assert!(rest.is_empty());
542 match e {
543 Expr::Binary(b) => {
544 assert_eq!(b.op, BinaryOp::Add);
545 match b.rhs {
546 Expr::Binary(inner) => {
547 assert_eq!(inner.op, BinaryOp::Mul);
548 }
549 _ => panic!("Expected inner Binary"),
550 }
551 }
552 _ => panic!("Expected Binary"),
553 }
554 }
555
556 #[test]
557 fn test_parse_binary_right_associative() {
558 let (rest, e) = expr("2 ^ 3 ^ 2").unwrap();
560 assert!(rest.is_empty());
561 match e {
562 Expr::Binary(b) => {
563 assert_eq!(b.op, BinaryOp::Pow);
564 assert_eq!(b.lhs, Expr::Number(2.0));
565 match b.rhs {
566 Expr::Binary(inner) => {
567 assert_eq!(inner.op, BinaryOp::Pow);
568 assert_eq!(inner.lhs, Expr::Number(3.0));
569 assert_eq!(inner.rhs, Expr::Number(2.0));
570 }
571 _ => panic!("Expected inner Binary"),
572 }
573 }
574 _ => panic!("Expected Binary"),
575 }
576 }
577
578 #[test]
579 fn test_parse_unary_minus() {
580 let (rest, e) = expr("-42").unwrap();
581 assert!(rest.is_empty());
582 match e {
583 Expr::Unary(u) => {
584 assert_eq!(u.op, UnaryOp::Minus);
585 assert_eq!(u.expr, Expr::Number(42.0));
586 }
587 _ => panic!("Expected Unary"),
588 }
589 }
590
591 #[test]
592 fn test_parse_unary_with_binary() {
593 let (rest, e) = expr("-1 + 2").unwrap();
595 assert!(rest.is_empty());
596 match e {
597 Expr::Binary(b) => {
598 assert_eq!(b.op, BinaryOp::Add);
599 match b.lhs {
600 Expr::Unary(u) => {
601 assert_eq!(u.op, UnaryOp::Minus);
602 }
603 _ => panic!("Expected Unary as lhs"),
604 }
605 }
606 _ => panic!("Expected Binary"),
607 }
608 }
609
610 #[test]
611 fn test_parse_paren() {
612 let (rest, e) = expr("(1 + 2)").unwrap();
613 assert!(rest.is_empty());
614 match e {
615 Expr::Paren(inner) => match *inner {
616 Expr::Binary(b) => {
617 assert_eq!(b.op, BinaryOp::Add);
618 }
619 _ => panic!("Expected Binary inside Paren"),
620 },
621 _ => panic!("Expected Paren"),
622 }
623 }
624
625 #[test]
626 fn test_parse_paren_affects_precedence() {
627 let (rest, e) = expr("(1 + 2) * 3").unwrap();
629 assert!(rest.is_empty());
630 match e {
631 Expr::Binary(b) => {
632 assert_eq!(b.op, BinaryOp::Mul);
633 match b.lhs {
634 Expr::Paren(inner) => match *inner {
635 Expr::Binary(b) => {
636 assert_eq!(b.op, BinaryOp::Add);
637 }
638 _ => panic!("Expected Binary inside Paren"),
639 },
640 _ => panic!("Expected Paren as lhs"),
641 }
642 }
643 _ => panic!("Expected Binary"),
644 }
645 }
646
647 #[test]
648 fn test_parse_subquery() {
649 let (rest, e) = expr("metric[5m:1m]").unwrap();
650 assert!(rest.is_empty());
651 match e {
652 Expr::Subquery(s) => {
653 assert_eq!(s.range.as_millis(), 5 * 60 * 1000);
654 assert_eq!(s.step.unwrap().as_millis(), 60 * 1000);
655 }
656 _ => panic!("Expected Subquery"),
657 }
658 }
659
660 #[test]
661 fn test_parse_complex_expression() {
662 let (rest, e) = expr("sum(rate(http_requests[5m])) by (job)").unwrap();
663 assert!(rest.is_empty());
664 match e {
665 Expr::Aggregation(a) => {
666 assert_eq!(a.op, "sum");
667 match a.expr {
668 Expr::Call(c) => {
669 assert_eq!(c.name, "rate");
670 }
671 _ => panic!("Expected Call inside Aggregation"),
672 }
673 }
674 _ => panic!("Expected Aggregation"),
675 }
676 }
677
678 #[test]
679 fn test_parse_binary_with_modifier() {
680 let (rest, e) = expr("foo + on(job) bar").unwrap();
681 assert!(rest.is_empty());
682 match e {
683 Expr::Binary(b) => {
684 assert_eq!(b.op, BinaryOp::Add);
685 assert!(b.modifier.is_some());
686 let m = b.modifier.unwrap();
687 assert!(m.matching.is_some());
688 }
689 _ => panic!("Expected Binary"),
690 }
691 }
692
693 #[test]
694 fn test_parse_binary_bool() {
695 let (rest, e) = expr("foo == bool bar").unwrap();
696 assert!(rest.is_empty());
697 match e {
698 Expr::Binary(b) => {
699 assert_eq!(b.op, BinaryOp::Eq);
700 assert!(b.modifier.is_some());
701 let m = b.modifier.unwrap();
702 assert!(m.return_bool);
703 }
704 _ => panic!("Expected Binary"),
705 }
706 }
707
708 #[test]
709 fn test_parse_set_operators() {
710 for (input, expected_op) in [
711 ("foo and bar", BinaryOp::And),
712 ("foo or bar", BinaryOp::Or),
713 ("foo unless bar", BinaryOp::Unless),
714 ] {
715 let (rest, e) = expr(input).unwrap();
716 assert!(rest.is_empty(), "Failed for: {}", input);
717 match e {
718 Expr::Binary(b) => {
719 assert_eq!(b.op, expected_op, "Failed for: {}", input);
720 }
721 _ => panic!("Expected Binary for: {}", input),
722 }
723 }
724 }
725
726 #[test]
727 fn test_parse_offset_modifier() {
728 let (rest, e) = expr("foo offset 5m").unwrap();
729 assert!(rest.is_empty());
730 match e {
731 Expr::VectorSelector(v) => {
732 assert!(v.offset.is_some());
733 assert_eq!(v.offset.unwrap().as_millis(), 5 * 60 * 1000);
734 }
735 _ => panic!("Expected VectorSelector"),
736 }
737 }
738
739 #[test]
740 fn test_parse_at_modifier() {
741 let (rest, e) = expr("foo @ 1609459200").unwrap();
742 assert!(rest.is_empty());
743 match e {
744 Expr::VectorSelector(v) => {
745 assert!(v.at.is_some());
746 }
747 _ => panic!("Expected VectorSelector"),
748 }
749 }
750
751 #[test]
752 fn test_parse_topk() {
753 let (rest, e) = expr("topk(5, metric)").unwrap();
754 assert!(rest.is_empty());
755 match e {
756 Expr::Aggregation(a) => {
757 assert_eq!(a.op, "topk");
758 assert!(a.param.is_some());
759 assert_eq!(*a.param.as_ref().unwrap(), Expr::Number(5.0));
760 }
761 _ => panic!("Expected Aggregation"),
762 }
763 }
764
765 #[test]
766 fn test_parse_whitespace_handling() {
767 let (rest, e) = expr(" foo + bar ").unwrap();
768 assert_eq!(rest.trim(), "");
769 match e {
770 Expr::Binary(b) => {
771 assert_eq!(b.op, BinaryOp::Add);
772 }
773 _ => panic!("Expected Binary"),
774 }
775 }
776
777 #[test]
778 fn test_parse_subquery_with_both_modifiers() {
779 let (rest, e) = expr("some_metric[5m:1m] @ 1609459200 offset 10m").unwrap();
781 assert!(rest.is_empty());
782 match e {
783 Expr::Subquery(s) => {
784 assert!(s.at.is_some(), "@ modifier should be present");
785 assert!(s.offset.is_some(), "offset modifier should be present");
786 }
787 _ => panic!("Expected Subquery"),
788 }
789
790 let (rest, e) = expr("some_metric[5m:1m] offset 10m @ 1609459200").unwrap();
792 assert!(
793 rest.is_empty(),
794 "Parser did not consume entire input, remaining: '{}'",
795 rest
796 );
797 match e {
798 Expr::Subquery(s) => {
799 assert!(s.at.is_some(), "@ modifier should be present");
800 assert!(s.offset.is_some(), "offset modifier should be present");
801 }
802 _ => panic!("Expected Subquery"),
803 }
804 }
805}