prometheus_parser/
parser.rs

1// (C) Copyright 2019-2020 Hewlett Packard Enterprise Development LP
2
3use std::f64;
4
5use lazy_static::lazy_static;
6use pest::prec_climber as pcl;
7use pest::prec_climber::PrecClimber;
8use pest_consume::{match_nodes, Error, Parser};
9use enquote::unquote;
10
11use crate::types::*;
12
13pub type Result<T> = std::result::Result<T, Error<Rule>>;
14pub(crate) type Node<'i> = pest_consume::Node<'i, Rule, ()>;
15
16lazy_static! {
17  static ref PRECCLIMBER: PrecClimber<Rule> = PrecClimber::new(
18    vec![
19      pcl::Operator::new(Rule::op_or, pcl::Assoc::Left),
20      pcl::Operator::new(Rule::op_unless, pcl::Assoc::Left),
21      pcl::Operator::new(Rule::op_and, pcl::Assoc::Left),
22      pcl::Operator::new(Rule::op_greater_than, pcl::Assoc::Left),
23      pcl::Operator::new(Rule::op_greater_than_equal, pcl::Assoc::Left),
24      pcl::Operator::new(Rule::op_less_than, pcl::Assoc::Left),
25      pcl::Operator::new(Rule::op_less_than_equal, pcl::Assoc::Left),
26      pcl::Operator::new(Rule::op_not_equal, pcl::Assoc::Left),
27      pcl::Operator::new(Rule::op_equal, pcl::Assoc::Left),
28      pcl::Operator::new(Rule::op_subtract, pcl::Assoc::Left),
29      pcl::Operator::new(Rule::op_add, pcl::Assoc::Left),
30      pcl::Operator::new(Rule::op_modulo, pcl::Assoc::Left),
31      pcl::Operator::new(Rule::op_divide, pcl::Assoc::Left),
32      pcl::Operator::new(Rule::op_multiply, pcl::Assoc::Left),
33      pcl::Operator::new(Rule::op_power, pcl::Assoc::Right)
34    ]
35  );
36}
37
38/// An intermediate struct for selectors with a named metric.
39/// Label-only selectors may evaluate immediately to a Selector
40struct MetricSelectorIntermediate {
41  metric: String,
42  labels: Vec<Label>
43}
44
45struct MatchingIntermediate {
46  op: MatchingOp,
47  labels: Vec<String>
48}
49
50#[derive(Parser)]
51#[grammar = "prometheus.pest"]
52struct PrometheusParser;
53
54#[allow(clippy::int_plus_one)]
55#[pest_consume::parser]
56impl PrometheusParser {
57  fn EOI(_input: Node) -> Result<()> {
58    Ok(())
59  }
60
61  fn signed_float(input: Node) -> Result<Expression> {
62    let val = match input.as_str().trim() {
63      "Inf" | "+Inf" => f64::INFINITY,
64      "-Inf" => f64::NEG_INFINITY,
65      "NaN" | "+NaN" | "-NaN" => f64::NAN,
66      f => f.parse().map_err(|e| input.error(e))?
67    };
68
69    Ok(Expression::Float(val))
70  }
71
72  fn string(input: Node) -> Result<Expression> {
73    let s = unquote(input.as_str()).map_err(|e| input.error(e))?;
74
75    Ok(Expression::String(s))
76  }
77
78  fn label_key(input: Node) -> Result<String> {
79    Ok(input.as_str().trim().to_string())
80  }
81
82  fn label_value(input: Node) -> Result<String> {
83    unquote(input.as_str()).map_err(|e| input.error(e))
84  }
85
86  fn group(input: Node) -> Result<Expression> {
87    let span = Span::from_node(&input);
88    Ok(match_nodes!(input.into_children();
89      [expression(e)] => Group::new(e).span(span).wrap(),
90      [expression(e), subquery(s)] => Group::new(e)
91        .subquery(s)
92        .span(span)
93        .wrap()
94    ))
95  }
96
97  fn selector_metric(input: Node) -> Result<String> {
98    Ok(input.as_str().trim().to_string())
99  }
100
101  fn label_op_equal(_input: Node) -> Result<LabelOp> {
102    Ok(LabelOp::Equal)
103  }
104
105  fn label_op_not_equal(_input: Node) -> Result<LabelOp> {
106    Ok(LabelOp::NotEqual)
107  }
108
109  fn label_op_regex_equal(_input: Node) -> Result<LabelOp> {
110    Ok(LabelOp::RegexEqual)
111  }
112
113  fn label_op_regex_not_equal(_input: Node) -> Result<LabelOp> {
114    Ok(LabelOp::RegexNotEqual)
115  }
116
117  fn label_operator(input: Node) -> Result<LabelOp> {
118    Ok(match_nodes!(input.into_children();
119      [label_op_equal(op)] => op,
120      [label_op_not_equal(op)] => op,
121      [label_op_regex_equal(op)] => op,
122      [label_op_regex_not_equal(op)] => op,
123    ))
124  }
125
126  fn label(input: Node) -> Result<Label> {
127    let span = Some(Span::from_node(&input));
128    Ok(match_nodes!(input.into_children();
129      [label_key(key), label_operator(op), label_value(value)] => Label {
130        op, key, value, span
131      }
132    ))
133  }
134
135  fn selector_label(input: Node) -> Result<Vec<Label>> {
136    Ok(match_nodes!(input.into_children();
137      [label(l)..] => l.collect()
138    ))
139  }
140
141  fn duration_value(input: Node) -> Result<u64> {
142    Ok(input.as_str().trim().parse().map_err(|e| input.error(e))?)
143  }
144
145  fn duration_unit(input: Node) -> Result<String> {
146    Ok(input.as_str().trim().to_string())
147  }
148
149  fn subquery_duration(input: Node) -> Result<PromDuration> {
150    Ok(match_nodes!(input.children();
151      [duration_value(val), duration_unit(unit)] => {
152        PromDuration::from_pair(&unit, val).map_err(|e| input.error(e))?
153      }
154    ))
155  }
156
157  fn subquery(input: Node) -> Result<Subquery> {
158    let span = Some(Span::from_node(&input));
159    Ok(match_nodes!(input.children();
160      [subquery_duration(range)] => Subquery {
161        range, resolution: None, span
162      },
163      [subquery_duration(range), subquery_duration(resolution)] => Subquery {
164        range, resolution: Some(resolution), span
165      }
166    ))
167  }
168
169  fn selector_range(input: Node) -> Result<PromDuration> {
170    Ok(match_nodes!(input.children();
171      [duration_value(val), duration_unit(unit)] => {
172        PromDuration::from_pair(&unit, val).map_err(|e| input.error(e))?
173      }
174    ))
175  }
176
177  fn offset(input: Node) -> Result<PromDuration> {
178    Ok(match_nodes!(input.children();
179      [duration_value(val), duration_unit(unit)] => {
180        PromDuration::from_pair(&unit, val).map_err(|e| input.error(e))?
181      }
182    ))
183  }
184
185  fn metric_selector(input: Node) -> Result<MetricSelectorIntermediate> {
186    Ok(match_nodes!(input.into_children();
187      [selector_metric(metric)] => MetricSelectorIntermediate {
188        metric, labels: vec![]
189      },
190      [selector_metric(metric), selector_label(labels)] => {
191        MetricSelectorIntermediate {
192          metric, labels
193        }
194      }
195    ))
196  }
197
198  fn selector(input: Node) -> Result<Expression> {
199    let span = Some(Span::from_node(&input));
200
201    let mut metric = None;
202    let mut labels = None;
203    let mut range = None;
204    let mut offset = None;
205    let mut subquery = None;
206
207    for child in input.into_children() {
208      match child.as_rule() {
209        Rule::metric_selector => {
210          let intermediate = PrometheusParser::metric_selector(child)?;
211          metric = Some(intermediate.metric);
212          labels = Some(intermediate.labels);
213        },
214        Rule::selector_label => {
215          labels = Some(PrometheusParser::selector_label(child)?);
216        },
217        Rule::selector_range => {
218          range = Some(PrometheusParser::selector_range(child)?);
219        },
220        Rule::offset => {
221          offset = Some(PrometheusParser::offset(child)?);
222        },
223        Rule::subquery => {
224          subquery = Some(PrometheusParser::subquery(child)?);
225        },
226        r => return Err(child.error(format!(
227          "invalid rule {:?} in selector", r
228        )))
229      }
230    }
231
232    let labels = labels.unwrap_or_else(|| vec![]);
233
234    Ok(Expression::Selector(Selector {
235      metric,
236      labels,
237      range,
238      offset,
239      subquery,
240      span
241    }))
242  }
243
244  fn function_name(input: Node) -> Result<String> {
245    Ok(input.as_str().trim().to_string())
246  }
247
248  fn function_agg_op_by(_input: Node) -> Result<AggregationOp> {
249    Ok(AggregationOp::By)
250  }
251
252  fn function_agg_op_without(_input: Node) -> Result<AggregationOp> {
253    Ok(AggregationOp::Without)
254  }
255
256  fn function_agg_op(input: Node) -> Result<AggregationOp> {
257    Ok(match_nodes!(input.into_children();
258      [function_agg_op_by(o)] => o,
259      [function_agg_op_without(o)] => o
260    ))
261  }
262
263  fn function_agg(input: Node) -> Result<Aggregation> {
264    let span = Some(Span::from_node(&input));
265
266    Ok(match_nodes!(input.into_children();
267      [function_agg_op(op), label_key(labels)..] => Aggregation {
268        op,
269        labels: labels.collect(),
270        span
271      }
272    ))
273  }
274
275  fn function(input: Node) -> Result<Expression> {
276    let span = Some(Span::from_node(&input));
277
278    let mut name = None;
279    let mut args = Vec::new();
280    let mut aggregation = None;
281    let mut subquery = None;
282
283    // match_nodes gets unruly with optional aggregations (2 forms) and
284    // subqueries, so break out into a manual conversion
285    for child in input.children() {
286      match child.as_rule() {
287        Rule::function_name => name = Some(PrometheusParser::function_name(child)?),
288        Rule::expression => args.push(Box::new(PrometheusParser::expression(child)?)),
289        Rule::function_agg => aggregation = Some(PrometheusParser::function_agg(child)?),
290        Rule::subquery => subquery = Some(PrometheusParser::subquery(child)?),
291        r => return Err(child.error(format!(
292          "invalid rule {:?} in function", r
293        )))
294      }
295    }
296
297    let name = match name {
298      Some(name) => name,
299      None => return Err(input.error("function name is required"))
300    };
301    
302    Ok(Expression::Function(Function {
303      name,
304      args,
305      aggregation,
306      subquery,
307      span
308    }))
309  }
310
311  fn matching_on(_input: Node) -> Result<MatchingOp> {
312    Ok(MatchingOp::On)
313  }
314
315  fn matching_ignoring(_input: Node) -> Result<MatchingOp> {
316    Ok(MatchingOp::Ignoring)
317  }
318
319  fn matching(input: Node) -> Result<MatchingIntermediate> {
320    Ok(match_nodes!(input.into_children();
321      [matching_on(op), label_key(labels)..] => MatchingIntermediate {
322        op, labels: labels.collect()
323      },
324      [matching_ignoring(op), label_key(labels)..] => MatchingIntermediate {
325        op, labels: labels.collect()
326      }
327    ))
328  }
329
330  fn matching_group_left(_input: Node) -> Result<MatchingGroupOp> {
331    Ok(MatchingGroupOp::Left)
332  }
333
334  fn matching_group_right(_input: Node) -> Result<MatchingGroupOp> {
335    Ok(MatchingGroupOp::Right)
336  }
337
338  fn matching_group(input: Node) -> Result<MatchingGroup> {
339    let span = Some(Span::from_node(&input));
340
341    Ok(match_nodes!(input.into_children();
342      [matching_group_left(op), label_key(labels)..] => MatchingGroup {
343        op, labels: labels.collect(), span
344      },
345      [matching_group_right(op), label_key(labels)..] => MatchingGroup {
346        op, labels: labels.collect(), span
347      }
348    ))
349  }
350
351  fn matching_expression(input: Node) -> Result<Matching> {
352    let span = Some(Span::from_node(&input));
353
354    Ok(match_nodes!(input.into_children();
355      [matching(m)] => Matching {
356        op: m.op,
357        labels: m.labels,
358
359        group: None,
360
361        span
362      },
363      [matching(m), matching_group(g)] => Matching {
364        op: m.op,
365        labels: m.labels,
366
367        group: Some(g),
368
369        span
370      }
371    ))
372  }
373
374  #[prec_climb(expression_term, PRECCLIMBER)]
375  fn expression(lhs: Expression, op: Node, rhs: Expression) -> Result<Expression> {
376    let span = Some(Span::from_node(&op));
377
378    use Rule::*;
379    let kind = match op.as_rule() {
380      op_or => OperatorKind::Or,
381      op_unless => OperatorKind::Unless,
382      op_and => OperatorKind::And,
383      op_greater_than => OperatorKind::GreaterThan,
384      op_greater_than_equal => OperatorKind::GreaterThanEqual,
385      op_less_than => OperatorKind::LessThan,
386      op_less_than_equal => OperatorKind::LessThanEqual,
387      op_not_equal => OperatorKind::NotEqual,
388      op_equal => OperatorKind::Equal,
389      op_subtract => OperatorKind::Subtract,
390      op_add => OperatorKind::Add,
391      op_modulo => OperatorKind::Modulo,
392      op_divide => OperatorKind::Divide,
393      op_multiply => OperatorKind::Multiply,
394      op_power => OperatorKind::Power,
395      r => return Err(op.error(format!("rule {:?} isn't an operator", r)))
396    };
397
398    // gotta break out of pest_consume slightly for this...
399    let mut matching_clause = None;
400    for child in op.into_children() {
401      if let Rule::matching_expression = child.as_rule() {
402        matching_clause = Some(PrometheusParser::matching_expression(child)?);
403        break;
404      }
405    }
406
407    Ok(Expression::Operator(Operator {
408      kind,
409      lhs: Box::new(lhs),
410      rhs: Box::new(rhs),
411
412      matching: matching_clause,
413
414      span
415    }))
416  }
417
418  fn expression_term(input: Node) -> Result<Expression> {
419    Ok(match_nodes!(input.into_children();
420      [signed_float(f)] => f,
421      [string(s)] => s,
422      [group(g)] => g,
423      [function(f)] => f,
424      [selector(s)] => s
425    ))
426  }
427
428  fn prometheus(input: Node) -> Result<Expression> {
429    Ok(match_nodes!(input.into_children();
430      [expression(e), EOI(_)] => e,
431    ))
432  }
433
434}
435
436/// Parses a Prometheus expression into a syntax tree.
437///
438/// # Examples 
439///
440/// ```
441/// use prometheus_parser::*;
442///
443/// let ast = parse_expr("foo > bar").unwrap();
444/// 
445/// assert_eq!(ast, Operator::new(
446///   OperatorKind::GreaterThan,
447///   Selector::new().metric("foo").span((0, 3)).wrap(),
448///   Selector::new().metric("bar").span((6, 9)).wrap()
449/// ).span((3, 6)).wrap());
450/// ```
451pub fn parse_expr(expr: &str) -> Result<Expression> {
452  let inputs = PrometheusParser::parse(Rule::prometheus, expr)?;
453  let input = inputs.single()?;
454
455  let expr = PrometheusParser::prometheus(input)?;
456
457  Ok(expr)
458}