1use std::fmt;
28
29use crate::lexer::duration::Duration;
30use crate::parser::aggregation::Grouping;
31use crate::parser::selector::{AtModifier, MatrixSelector, VectorSelector};
32
33#[derive(Debug, Clone, PartialEq)]
35pub enum Expr {
36 Number(f64),
38
39 String(String),
41
42 VectorSelector(VectorSelector),
44
45 MatrixSelector(MatrixSelector),
47
48 Call(Call),
50
51 Aggregation(Box<Aggregation>),
53
54 Binary(Box<BinaryExpr>),
56
57 Unary(Box<UnaryExpr>),
59
60 Paren(Box<Expr>),
62
63 Subquery(Box<SubqueryExpr>),
65}
66
67impl Expr {
68 pub fn is_scalar(&self) -> bool {
70 matches!(self, Expr::Number(_))
71 }
72
73 pub fn is_string(&self) -> bool {
75 matches!(self, Expr::String(_))
76 }
77
78 pub fn is_instant_vector(&self) -> bool {
80 matches!(
81 self,
82 Expr::VectorSelector(_)
83 | Expr::Call(_)
84 | Expr::Aggregation(_)
85 | Expr::Binary(_)
86 | Expr::Unary(_)
87 ) || matches!(self, Expr::Paren(e) if e.is_instant_vector())
88 }
89
90 pub fn is_range_vector(&self) -> bool {
92 matches!(self, Expr::MatrixSelector(_) | Expr::Subquery(_))
93 }
94
95 pub fn unwrap_parens(&self) -> &Expr {
97 match self {
98 Expr::Paren(inner) => inner.unwrap_parens(),
99 other => other,
100 }
101 }
102}
103
104impl fmt::Display for Expr {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 match self {
107 Expr::Number(n) => {
108 if n.is_nan() {
109 write!(f, "NaN")
110 } else if n.is_infinite() {
111 if *n > 0.0 {
112 write!(f, "Inf")
113 } else {
114 write!(f, "-Inf")
115 }
116 } else {
117 write!(f, "{}", n)
118 }
119 }
120 Expr::String(s) => write!(f, "\"{}\"", s.escape_default()),
121 Expr::VectorSelector(v) => write!(f, "{}", v),
122 Expr::MatrixSelector(m) => write!(f, "{}", m),
123 Expr::Call(c) => write!(f, "{}", c),
124 Expr::Aggregation(a) => write!(f, "{}", a),
125 Expr::Binary(b) => write!(f, "{}", b),
126 Expr::Unary(u) => write!(f, "{}", u),
127 Expr::Paren(e) => write!(f, "({})", e),
128 Expr::Subquery(s) => write!(f, "{}", s),
129 }
130 }
131}
132
133#[derive(Debug, Clone, PartialEq)]
135pub struct Call {
136 pub name: String,
138 pub args: Vec<Expr>,
140}
141
142impl Call {
143 pub fn new(name: impl Into<String>, args: Vec<Expr>) -> Self {
145 Self {
146 name: name.into(),
147 args,
148 }
149 }
150}
151
152impl fmt::Display for Call {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 write!(f, "{}(", self.name)?;
155 for (i, arg) in self.args.iter().enumerate() {
156 if i > 0 {
157 write!(f, ", ")?;
158 }
159 write!(f, "{}", arg)?;
160 }
161 write!(f, ")")
162 }
163}
164
165#[derive(Debug, Clone, PartialEq)]
167pub struct Aggregation {
168 pub op: String,
170 pub expr: Expr,
172 pub param: Option<Expr>,
174 pub grouping: Option<Grouping>,
176}
177
178impl Aggregation {
179 pub fn new(op: impl Into<String>, expr: Expr) -> Self {
181 Self {
182 op: op.into(),
183 expr,
184 param: None,
185 grouping: None,
186 }
187 }
188
189 pub fn with_param(op: impl Into<String>, param: Expr, expr: Expr) -> Self {
191 Self {
192 op: op.into(),
193 expr,
194 param: Some(param),
195 grouping: None,
196 }
197 }
198
199 pub fn with_grouping(mut self, grouping: Grouping) -> Self {
201 self.grouping = Some(grouping);
202 self
203 }
204}
205
206impl fmt::Display for Aggregation {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 write!(f, "{}", self.op)?;
209 if let Some(ref grouping) = self.grouping {
210 write!(f, " {} ", grouping)?;
211 }
212 write!(f, "(")?;
213 if let Some(ref param) = self.param {
214 write!(f, "{}, ", param)?;
215 }
216 write!(f, "{})", self.expr)
217 }
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq)]
222pub enum BinaryOp {
223 Add, Sub, Mul, Div, Mod, Pow, Atan2, Eq, Ne, Lt, Le, Gt, Ge, And, Or, Unless, }
245
246impl BinaryOp {
247 pub fn as_str(&self) -> &'static str {
249 match self {
250 BinaryOp::Add => "+",
251 BinaryOp::Sub => "-",
252 BinaryOp::Mul => "*",
253 BinaryOp::Div => "/",
254 BinaryOp::Mod => "%",
255 BinaryOp::Pow => "^",
256 BinaryOp::Atan2 => "atan2",
257 BinaryOp::Eq => "==",
258 BinaryOp::Ne => "!=",
259 BinaryOp::Lt => "<",
260 BinaryOp::Le => "<=",
261 BinaryOp::Gt => ">",
262 BinaryOp::Ge => ">=",
263 BinaryOp::And => "and",
264 BinaryOp::Or => "or",
265 BinaryOp::Unless => "unless",
266 }
267 }
268
269 pub fn precedence(&self) -> u8 {
271 match self {
272 BinaryOp::Or => 1, BinaryOp::And | BinaryOp::Unless => 2, BinaryOp::Eq
275 | BinaryOp::Ne
276 | BinaryOp::Lt
277 | BinaryOp::Le
278 | BinaryOp::Gt
279 | BinaryOp::Ge => 3, BinaryOp::Add | BinaryOp::Sub => 4, BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod | BinaryOp::Atan2 => 5, BinaryOp::Pow => 6, }
284 }
285
286 pub fn is_right_associative(&self) -> bool {
288 matches!(self, BinaryOp::Pow)
289 }
290
291 pub fn is_comparison(&self) -> bool {
293 matches!(
294 self,
295 BinaryOp::Eq | BinaryOp::Ne | BinaryOp::Lt | BinaryOp::Le | BinaryOp::Gt | BinaryOp::Ge
296 )
297 }
298
299 pub fn is_set_operator(&self) -> bool {
301 matches!(self, BinaryOp::And | BinaryOp::Or | BinaryOp::Unless)
302 }
303
304 pub fn is_arithmetic(&self) -> bool {
306 matches!(
307 self,
308 BinaryOp::Add
309 | BinaryOp::Sub
310 | BinaryOp::Mul
311 | BinaryOp::Div
312 | BinaryOp::Mod
313 | BinaryOp::Pow
314 | BinaryOp::Atan2
315 )
316 }
317}
318
319impl fmt::Display for BinaryOp {
320 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321 write!(f, "{}", self.as_str())
322 }
323}
324
325#[derive(Debug, Clone, Copy, PartialEq, Eq)]
327pub enum VectorMatchingOp {
328 On, Ignoring, }
331
332impl fmt::Display for VectorMatchingOp {
333 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334 match self {
335 VectorMatchingOp::On => write!(f, "on"),
336 VectorMatchingOp::Ignoring => write!(f, "ignoring"),
337 }
338 }
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
343pub enum GroupSide {
344 Left, Right, }
347
348impl fmt::Display for GroupSide {
349 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350 match self {
351 GroupSide::Left => write!(f, "group_left"),
352 GroupSide::Right => write!(f, "group_right"),
353 }
354 }
355}
356
357#[derive(Debug, Clone, PartialEq, Eq)]
359pub struct GroupModifier {
360 pub side: GroupSide,
362 pub labels: Vec<String>,
364}
365
366impl fmt::Display for GroupModifier {
367 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368 write!(f, "{}", self.side)?;
369 if !self.labels.is_empty() {
370 write!(f, " (")?;
371 for (i, label) in self.labels.iter().enumerate() {
372 if i > 0 {
373 write!(f, ", ")?;
374 }
375 write!(f, "{}", label)?;
376 }
377 write!(f, ")")?;
378 }
379 Ok(())
380 }
381}
382
383#[derive(Debug, Clone, PartialEq, Eq)]
385pub struct VectorMatching {
386 pub op: VectorMatchingOp,
388 pub labels: Vec<String>,
390 pub group: Option<GroupModifier>,
392}
393
394impl fmt::Display for VectorMatching {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 write!(f, "{} (", self.op)?;
397 for (i, label) in self.labels.iter().enumerate() {
398 if i > 0 {
399 write!(f, ", ")?;
400 }
401 write!(f, "{}", label)?;
402 }
403 write!(f, ")")?;
404 if let Some(ref group) = self.group {
405 write!(f, " {}", group)?;
406 }
407 Ok(())
408 }
409}
410
411#[derive(Debug, Clone, PartialEq, Eq, Default)]
413pub struct BinaryModifier {
414 pub return_bool: bool,
416 pub matching: Option<VectorMatching>,
418}
419
420impl BinaryModifier {
421 pub fn with_bool() -> Self {
423 Self {
424 return_bool: true,
425 matching: None,
426 }
427 }
428
429 pub fn with_matching(matching: VectorMatching) -> Self {
431 Self {
432 return_bool: false,
433 matching: Some(matching),
434 }
435 }
436
437 pub fn is_empty(&self) -> bool {
439 !self.return_bool && self.matching.is_none()
440 }
441}
442
443impl fmt::Display for BinaryModifier {
444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445 if self.return_bool {
446 write!(f, "bool")?;
447 if self.matching.is_some() {
448 write!(f, " ")?;
449 }
450 }
451 if let Some(ref matching) = self.matching {
452 write!(f, "{}", matching)?;
453 }
454 Ok(())
455 }
456}
457
458#[derive(Debug, Clone, PartialEq)]
460pub struct BinaryExpr {
461 pub op: BinaryOp,
463 pub lhs: Expr,
465 pub rhs: Expr,
467 pub modifier: Option<BinaryModifier>,
469}
470
471impl BinaryExpr {
472 pub fn new(op: BinaryOp, lhs: Expr, rhs: Expr) -> Self {
474 Self {
475 op,
476 lhs,
477 rhs,
478 modifier: None,
479 }
480 }
481
482 pub fn with_modifier(op: BinaryOp, lhs: Expr, rhs: Expr, modifier: BinaryModifier) -> Self {
484 Self {
485 op,
486 lhs,
487 rhs,
488 modifier: Some(modifier),
489 }
490 }
491}
492
493impl fmt::Display for BinaryExpr {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 write!(f, "{} {}", self.lhs, self.op)?;
496 if let Some(ref modifier) = self.modifier
497 && !modifier.is_empty()
498 {
499 write!(f, " {}", modifier)?;
500 }
501 write!(f, " {}", self.rhs)
502 }
503}
504
505#[derive(Debug, Clone, Copy, PartialEq, Eq)]
507pub enum UnaryOp {
508 Plus,
510 Minus,
512}
513
514impl UnaryOp {
515 pub fn as_str(&self) -> &'static str {
517 match self {
518 UnaryOp::Plus => "+",
519 UnaryOp::Minus => "-",
520 }
521 }
522}
523
524impl fmt::Display for UnaryOp {
525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526 write!(f, "{}", self.as_str())
527 }
528}
529
530#[derive(Debug, Clone, PartialEq)]
532pub struct UnaryExpr {
533 pub op: UnaryOp,
535 pub expr: Expr,
537}
538
539impl UnaryExpr {
540 pub fn new(op: UnaryOp, expr: Expr) -> Self {
542 Self { op, expr }
543 }
544}
545
546impl fmt::Display for UnaryExpr {
547 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
548 write!(f, "{}{}", self.op, self.expr)
549 }
550}
551
552#[derive(Debug, Clone, PartialEq)]
554pub struct SubqueryExpr {
555 pub expr: Expr,
557 pub range: Duration,
559 pub step: Option<Duration>,
561 pub offset: Option<Duration>,
563 pub at: Option<AtModifier>,
565}
566
567impl SubqueryExpr {
568 pub fn new(expr: Expr, range: Duration) -> Self {
570 Self {
571 expr,
572 range,
573 step: None,
574 offset: None,
575 at: None,
576 }
577 }
578
579 pub fn with_step(expr: Expr, range: Duration, step: Duration) -> Self {
581 Self {
582 expr,
583 range,
584 step: Some(step),
585 offset: None,
586 at: None,
587 }
588 }
589}
590
591impl fmt::Display for SubqueryExpr {
592 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
593 write!(f, "{}[{}:", self.expr, self.range)?;
594 if let Some(ref step) = self.step {
595 write!(f, "{}", step)?;
596 }
597 write!(f, "]")?;
598 if let Some(ref at) = self.at {
599 write!(f, " {}", at)?;
600 }
601 if let Some(ref offset) = self.offset {
602 write!(f, " offset {}", offset)?;
603 }
604 Ok(())
605 }
606}
607
608#[cfg(test)]
609mod tests {
610 use super::*;
611
612 #[test]
613 fn test_binary_op_precedence() {
614 assert!(BinaryOp::Or.precedence() < BinaryOp::And.precedence());
616 assert!(BinaryOp::And.precedence() < BinaryOp::Eq.precedence());
617 assert!(BinaryOp::Eq.precedence() < BinaryOp::Add.precedence());
618 assert!(BinaryOp::Add.precedence() < BinaryOp::Mul.precedence());
619 assert!(BinaryOp::Mul.precedence() < BinaryOp::Pow.precedence());
620 }
621
622 #[test]
623 fn test_binary_op_associativity() {
624 assert!(!BinaryOp::Add.is_right_associative());
625 assert!(!BinaryOp::Mul.is_right_associative());
626 assert!(BinaryOp::Pow.is_right_associative());
627 }
628
629 #[test]
630 fn test_binary_op_categories() {
631 assert!(BinaryOp::Add.is_arithmetic());
632 assert!(BinaryOp::Eq.is_comparison());
633 assert!(BinaryOp::And.is_set_operator());
634 }
635
636 #[test]
637 fn test_expr_display_number() {
638 assert_eq!(Expr::Number(42.0).to_string(), "42");
639 assert_eq!(Expr::Number(3.5).to_string(), "3.5");
640 assert_eq!(Expr::Number(f64::INFINITY).to_string(), "Inf");
641 assert_eq!(Expr::Number(f64::NEG_INFINITY).to_string(), "-Inf");
642 assert_eq!(Expr::Number(f64::NAN).to_string(), "NaN");
643 }
644
645 #[test]
646 fn test_expr_display_string() {
647 assert_eq!(Expr::String("hello".to_string()).to_string(), "\"hello\"");
648 }
649
650 #[test]
651 fn test_unary_expr_display() {
652 let expr = UnaryExpr::new(UnaryOp::Minus, Expr::Number(42.0));
653 assert_eq!(expr.to_string(), "-42");
654
655 let expr = UnaryExpr::new(UnaryOp::Plus, Expr::Number(42.0));
656 assert_eq!(expr.to_string(), "+42");
657 }
658
659 #[test]
660 fn test_binary_expr_display() {
661 let expr = BinaryExpr::new(BinaryOp::Add, Expr::Number(1.0), Expr::Number(2.0));
662 assert_eq!(expr.to_string(), "1 + 2");
663 }
664
665 #[test]
666 fn test_call_display() {
667 let call = Call::new(
668 "rate",
669 vec![Expr::VectorSelector(VectorSelector::new("http_requests"))],
670 );
671 assert_eq!(call.to_string(), "rate(http_requests)");
672 }
673
674 #[test]
675 fn test_aggregation_display() {
676 let agg = Aggregation::new("sum", Expr::VectorSelector(VectorSelector::new("metric")));
677 assert_eq!(agg.to_string(), "sum(metric)");
678 }
679
680 #[test]
681 fn test_expr_is_scalar() {
682 assert!(Expr::Number(42.0).is_scalar());
683 assert!(!Expr::String("test".to_string()).is_scalar());
684 }
685
686 #[test]
687 fn test_expr_unwrap_parens() {
688 let inner = Expr::Number(42.0);
689 let paren = Expr::Paren(Box::new(inner.clone()));
690 let double_paren = Expr::Paren(Box::new(paren.clone()));
691
692 assert_eq!(*double_paren.unwrap_parens(), inner);
693 }
694}