Skip to main content

mpl_lang/
parser.rs

1use core::result;
2use std::{collections::HashMap, hash::BuildHasher, num::ParseFloatError, str::FromStr};
3
4use chrono::DateTime;
5use miette::SourceSpan;
6use pest::iterators::{Pair, Pairs};
7use regex::Regex;
8
9use crate::{
10    ParseError,
11    errors::pair_to_source_span,
12    linker::{
13        AlignFunction, ComputeFunction, Function, FunctionId, GroupFunction, Module, ModuleId,
14    },
15    query::{
16        Aggregate, Align, As, BucketBy, Cmp, DirectiveValue, Directives, Expr, Filter,
17        FilterOrIfDef, GroupBy, Mapping, MetricId, ParamDeclaration, ParamType, ParamValue, Params,
18        Query, RelativeTime, Source, StringFragment, TagExtend, TagType, TerminalParamType, Time,
19        TimeRange, TimeUnit, WarningReason, Warnings,
20    },
21    stdlib::STDLIB,
22    tags::TagValue,
23    types::{BucketSpec, BucketType, ConversionMethod, Dataset, Metric, Parameterized},
24};
25
26#[cfg(test)]
27mod tests;
28
29// Wrapped in a private module so `#![allow(missing_docs)]` can suppress the
30// `pest_derive`-generated `Rule` enum's undocumented variants without
31// affecting the rest of the crate.
32mod mpl_parser_impl {
33    #![allow(missing_docs)]
34    use pest_derive::Parser;
35
36    /// PEG parser for MPL. Use with `pest::Parser`'s `parse(rule, src)`.
37    /// The associated `Rule` enum is auto-generated by `pest_derive` and
38    /// is re-exported at the crate root.
39    #[derive(Parser)]
40    #[grammar = "mpl.pest"]
41    pub struct MPLParser;
42}
43pub use mpl_parser_impl::{MPLParser, Rule};
44
45const SYSTEM_PARAM_PREFIX: &str = "__";
46
47type Result<T> = std::result::Result<T, ParseError>;
48
49trait PairsHelper<'i, R>
50where
51    R: pest::RuleType,
52{
53    fn n(&mut self) -> Result<Pair<'i, R>>;
54    fn assert_empty(&mut self) -> Result<()>;
55}
56
57impl<'i> PairsHelper<'i, Rule> for Pairs<'i, Rule> {
58    fn n(&mut self) -> Result<Pair<'i, Rule>> {
59        self.peek()
60            .map(|p| pair_to_source_span(&p))
61            .ok_or_else(|| ParseError::EOF {
62                span: miette::SourceSpan::new(0.into(), 0),
63            })
64            .and_then(|span| self.next().ok_or(ParseError::EOF { span }))
65    }
66    fn assert_empty(&mut self) -> Result<()> {
67        if !Pairs::is_empty(self) {
68            let first = self.peek();
69            let span = first.map_or_else(
70                || miette::SourceSpan::new(0.into(), 0),
71                |p| pair_to_source_span(&p),
72            );
73            return Err(ParseError::UnexpectedTokens {
74                span,
75                rules: self.map(|p| p.as_rule()).collect(),
76            });
77        }
78        Ok(())
79    }
80}
81
82trait PairHelper<R>
83where
84    R: pest::RuleType,
85{
86    fn assert_type(&self, expected: R) -> Result<()>;
87}
88
89impl PairHelper<Rule> for Pair<'_, Rule> {
90    fn assert_type(&self, expected: Rule) -> Result<()> {
91        if self.as_rule() != expected {
92            return Err(ParseError::Unexpected {
93                span: pair_to_source_span(self),
94                rule: self.as_rule(),
95                expected: vec![expected],
96            });
97        }
98        Ok(())
99    }
100}
101
102fn unescape_and_trim(data: &str, delim: char) -> String {
103    unescape(
104        data.trim_start_matches(delim).trim_end_matches(delim),
105        delim,
106    )
107}
108
109fn unescape(data: &str, delim: char) -> String {
110    let mut escaped = false;
111    let mut res = String::with_capacity(data.len());
112    for c in data.chars() {
113        if escaped {
114            escaped = false;
115            match c {
116                'r' => res.push('\r'),
117                'n' => res.push('\n'),
118                't' => res.push('\t'),
119                'b' => res.push('\x08'),
120                'f' => res.push('\x0C'),
121                '\\' => res.push('\\'),
122                '$' => res.push('$'),
123                c if c == delim => res.push(delim),
124                _ => {
125                    res.push('\\');
126                    res.push(c);
127                }
128            }
129        } else if c == '\\' {
130            escaped = true;
131        } else {
132            res.push(c);
133        }
134    }
135    res
136}
137
138fn parse_ident(source: &Pair<'_, Rule>) -> Result<String> {
139    match source.as_rule() {
140        Rule::plain_ident => Ok(source.as_str().to_string()),
141        Rule::escaped_ident => Ok(unescape_and_trim(source.as_str(), '`')),
142        rule => Err(ParseError::Unexpected {
143            span: pair_to_source_span(source),
144            rule,
145            expected: vec![Rule::plain_ident, Rule::escaped_ident],
146        }),
147    }
148}
149
150fn resolve_param<'p>(source: &Pair<'_, Rule>, state: &'p State) -> Result<&'p ParamDeclaration> {
151    let param = match source.as_rule() {
152        Rule::plain_ident => source.as_str().to_string(),
153        Rule::escaped_ident => unescape_and_trim(source.as_str(), '`'),
154        rule => {
155            return Err(ParseError::Unexpected {
156                span: pair_to_source_span(source),
157                rule,
158                expected: vec![Rule::plain_ident],
159            });
160        }
161    };
162
163    state
164        .params
165        .iter()
166        .find(|p| p.name == param)
167        .ok_or(ParseError::UndefinedParam {
168            span: pair_to_source_span(source),
169            param,
170        })
171}
172
173fn parse_source_ident(source: &Pair<'_, Rule>) -> Result<String> {
174    match source.as_rule() {
175        Rule::plain_ident => Ok(source.as_str().to_string()),
176        Rule::escaped_ident => Ok(unescape_and_trim(source.as_str(), '`').clone()),
177        rule => Err(ParseError::Unexpected {
178            span: pair_to_source_span(source),
179            rule,
180            expected: vec![Rule::ident],
181        }),
182    }
183}
184
185fn parse_source_ident_param(
186    source: Pair<'_, Rule>,
187    state: &State,
188) -> Result<Parameterized<String>> {
189    match source.as_rule() {
190        Rule::plain_ident => Ok(Parameterized::Concrete(source.as_str().to_string())),
191        Rule::escaped_ident => Ok(Parameterized::Concrete(
192            unescape_and_trim(source.as_str(), '`').clone(),
193        )),
194        Rule::param_ident => {
195            let span = pair_to_source_span(&source);
196            let mut inner = source.into_inner();
197            let next = inner.n()?;
198            let param = resolve_param(&next, state)?;
199            Ok(Parameterized::Param {
200                span,
201                param: param.clone(),
202            })
203        }
204        rule => Err(ParseError::Unexpected {
205            span: pair_to_source_span(&source),
206            rule,
207            expected: vec![Rule::ident, Rule::param_ident],
208        }),
209    }
210}
211
212fn parse_param_ident(source: Pair<'_, Rule>) -> Result<String> {
213    match source.as_rule() {
214        Rule::param_ident => {
215            let mut inner = source.into_inner();
216            let next = inner.n()?;
217            match next.as_rule() {
218                Rule::plain_ident => Ok(next.as_str().to_string()),
219                rule => Err(ParseError::Unexpected {
220                    span: pair_to_source_span(&next),
221                    rule,
222                    expected: vec![Rule::plain_ident],
223                }),
224            }
225        }
226        rule => Err(ParseError::Unexpected {
227            span: pair_to_source_span(&source),
228            rule,
229            expected: vec![Rule::param_ident],
230        }),
231    }
232}
233
234fn parse_dataset(source: Pair<Rule>, state: &State) -> Result<Parameterized<Dataset>> {
235    source.assert_type(Rule::dataset)?;
236    let mut inner = source.into_inner();
237
238    let source = inner.n()?;
239    let dataset = parse_source_ident_param(source, state)?.map_concrete(Dataset::new);
240    Ok(dataset)
241}
242
243fn parse_metric_name(source: Pair<Rule>) -> Result<Metric> {
244    source.assert_type(Rule::metric_name)?;
245    let mut inner = source.into_inner();
246
247    let source = inner.n()?;
248    let metric = Metric::try_from(parse_source_ident(&source)?)?;
249    Ok(metric)
250}
251
252fn parse_metric_id(source: Pair<Rule>, state: &State) -> Result<MetricId> {
253    source.assert_type(Rule::metric_id)?;
254    let mut inner = source.into_inner();
255    let dataset = parse_dataset(inner.n()?, state)?;
256    let metric = parse_metric_name(inner.n()?)?;
257    inner.assert_empty()?;
258    Ok(MetricId { dataset, metric })
259}
260
261fn parse_parameterized_relative_time(
262    source: Pair<Rule>,
263    state: &State,
264) -> Result<Parameterized<RelativeTime>> {
265    source.assert_type(Rule::time_relative_parameterized)?;
266    let mut inner = source.into_inner();
267
268    let next = inner.n()?;
269
270    // do we have a param that we need to resolve first?
271    if matches!(next.as_rule(), Rule::param_ident) {
272        let span = pair_to_source_span(&next);
273        let mut inner = next.into_inner();
274        let next = inner.n()?;
275        let param = resolve_param(&next, state)?;
276        return Ok(Parameterized::Param {
277            span,
278            param: param.clone(),
279        });
280    }
281
282    parse_relative_time_inner(inner, &next).map(Parameterized::Concrete)
283}
284
285fn parse_relative_time(source: Pair<Rule>) -> Result<RelativeTime> {
286    source.assert_type(Rule::time_relative)?;
287    let mut inner = source.into_inner();
288    let next = inner.n()?;
289    parse_relative_time_inner(inner, &next)
290}
291
292fn parse_relative_time_inner(
293    mut inner: Pairs<'_, Rule>,
294    next: &Pair<Rule>,
295) -> Result<RelativeTime> {
296    let value = next.as_str().parse::<u64>()?;
297    let unit = inner.n()?;
298    let unit = match unit.as_rule() {
299        Rule::time_unit_ms => TimeUnit::Millisecond,
300        Rule::time_unit_second => TimeUnit::Second,
301        Rule::time_unit_minute => TimeUnit::Minute,
302        Rule::time_unit_hour => TimeUnit::Hour,
303        Rule::time_unit_day => TimeUnit::Day,
304        Rule::time_unit_week => TimeUnit::Week,
305        Rule::time_unit_month => TimeUnit::Month,
306        Rule::time_unit_year => TimeUnit::Year,
307        rule => {
308            return Err(ParseError::Unexpected {
309                span: pair_to_source_span(&unit),
310                rule,
311                expected: vec![
312                    Rule::time_unit_ms,
313                    Rule::time_unit_second,
314                    Rule::time_unit_minute,
315                    Rule::time_unit_hour,
316                    Rule::time_unit_day,
317                    Rule::time_unit_week,
318                    Rule::time_unit_month,
319                    Rule::time_unit_year,
320                ],
321            });
322        }
323    };
324
325    Ok(RelativeTime { value, unit })
326}
327
328fn parse_time(source: Pair<Rule>) -> Result<Time> {
329    match source.as_rule() {
330        Rule::time_relative => Ok(Time::Relative(parse_relative_time(source)?)),
331        Rule::time_timestamp => Ok(Time::Timestamp(source.as_str().parse()?)),
332        Rule::time_rfc_3339 => Ok(Time::RFC3339(DateTime::parse_from_rfc3339(
333            source.as_str(),
334        )?)),
335        Rule::time_modifier => Ok(Time::Modifier(source.as_str().to_string())),
336        rule => Err(ParseError::Unexpected {
337            span: pair_to_source_span(&source),
338            rule,
339            expected: vec![
340                Rule::time_relative,
341                Rule::time_timestamp,
342                Rule::time_rfc_3339,
343                Rule::time_modifier,
344            ],
345        }),
346    }
347}
348
349fn parse_time_range(source: Pair<Rule>) -> Result<TimeRange> {
350    source.assert_type(Rule::time_range)?;
351    let mut inner = source.into_inner();
352
353    let start = parse_time(inner.n()?)?;
354    let end = if inner.is_empty() {
355        None
356    } else {
357        Some(parse_time(inner.n()?)?)
358    };
359    inner.assert_empty()?;
360    Ok(TimeRange { start, end })
361}
362
363pub(crate) fn parse_source(source: Pair<Rule>, state: &State) -> Result<(Source, Option<As>)> {
364    source.assert_type(Rule::source)?;
365    let mut inner = source.into_inner();
366
367    let metric_id = parse_metric_id(inner.n()?, state)?;
368    let next = inner.next();
369
370    match next {
371        Some(next) if next.as_rule() == Rule::r#as => {
372            let as_ = parse_as(next)?;
373            inner.assert_empty()?;
374            Ok((
375                Source {
376                    metric_id,
377                    time: None,
378                },
379                Some(as_),
380            ))
381        }
382        Some(next) if next.as_rule() == Rule::time_range => {
383            let time = Some(parse_time_range(next)?);
384            if let Some(next) = inner.next() {
385                let as_ = parse_as(next)?;
386                inner.assert_empty()?;
387                Ok((Source { metric_id, time }, Some(as_)))
388            } else {
389                Ok((Source { metric_id, time }, None))
390            }
391        }
392        Some(next) => Err(ParseError::Unexpected {
393            span: pair_to_source_span(&next),
394            rule: next.as_rule(),
395            expected: vec![Rule::r#as, Rule::time_range],
396        }),
397        None => Ok((
398            Source {
399                metric_id,
400                time: None,
401            },
402            None,
403        )),
404    }
405}
406
407fn parse_cmp<'input>(source: &Pair<'input, Rule>) -> Result<&'input str> {
408    source.assert_type(Rule::cmp)?;
409    Ok(source.as_str())
410}
411fn parse_cmp_re<'input>(source: &Pair<'input, Rule>) -> Result<&'input str> {
412    source.assert_type(Rule::cmp_re)?;
413    Ok(source.as_str())
414}
415
416#[derive(Debug, Clone, PartialEq, Copy)]
417enum Number {
418    Int(i64),
419    Float(f64),
420}
421impl Number {
422    // Can't do anything about it
423    #[allow(clippy::cast_precision_loss)]
424    fn as_f64(self) -> f64 {
425        match self {
426            Number::Int(value) => value as f64,
427            Number::Float(value) => value,
428        }
429    }
430}
431
432fn parse_int(source: &Pair<Rule>) -> Result<i64> {
433    source.assert_type(Rule::int)?;
434    let res = source.as_str().trim().parse()?;
435    Ok(res)
436}
437
438fn parse_float(next: &Pair<Rule>) -> Result<f64> {
439    match next.as_rule() {
440        Rule::float => Ok(next.as_str().parse()?),
441        Rule::inf => match next.as_str() {
442            "inf" | "+inf" => Ok(f64::INFINITY),
443            "-inf" => Ok(f64::NEG_INFINITY),
444            _ => Err(ParseError::Unexpected {
445                span: pair_to_source_span(next),
446                rule: next.as_rule(),
447                expected: vec![],
448            }),
449        },
450        rule => Err(ParseError::Unexpected {
451            span: pair_to_source_span(next),
452            rule,
453            expected: vec![Rule::inf, Rule::float],
454        }),
455    }
456}
457
458fn parse_number(source: Pair<Rule>) -> Result<Number> {
459    source.assert_type(Rule::number)?;
460    let mut inner = source.into_inner();
461    let next = inner.n()?;
462    let res = match next.as_rule() {
463        Rule::int => Ok(Number::Int(parse_int(&next)?)),
464        Rule::float | Rule::inf => Ok(Number::Float(parse_float(&next)?)),
465        rule => Err(ParseError::Unexpected {
466            span: pair_to_source_span(&next),
467            rule,
468            expected: vec![Rule::int, Rule::inf, Rule::float],
469        }),
470    };
471    inner.assert_empty()?;
472    res
473}
474
475fn parse_directive_value(source: Pair<Rule>) -> Result<DirectiveValue> {
476    source.assert_type(Rule::r#const)?;
477    let mut inner = source.into_inner();
478    let next = inner.n()?;
479    match next.as_rule() {
480        Rule::string => Ok(DirectiveValue::String(unescape_and_trim(
481            next.as_str(),
482            '"',
483        ))),
484        Rule::int => Ok(DirectiveValue::Int(parse_int(&next)?)),
485        Rule::float | Rule::inf => Ok(DirectiveValue::Float(parse_float(&next)?)),
486        Rule::bool => Ok(DirectiveValue::Bool(next.as_str().to_string().parse()?)),
487        rule => Err(ParseError::Unexpected {
488            span: pair_to_source_span(&next),
489            rule,
490            expected: vec![Rule::string, Rule::int, Rule::float, Rule::inf, Rule::bool],
491        }),
492    }
493}
494fn parse_param_native_type(state: &mut State, source: &Pair<Rule>) -> Result<TerminalParamType> {
495    source.assert_type(Rule::param_native_type)?;
496    let span = pair_to_source_span(source);
497    match source.as_str() {
498        "Dataset" => Ok(TerminalParamType::Dataset),
499        "Duration" => Ok(TerminalParamType::Duration),
500        "duration" => {
501            state.warnings.push_span(span, WarningReason::OldDuration);
502            Ok(TerminalParamType::Duration)
503        }
504        "Regex" => Ok(TerminalParamType::Regex),
505        _ => Err(ParseError::Unexpected {
506            span: pair_to_source_span(source),
507            rule: Rule::param_type,
508            expected: vec![Rule::param_type],
509        }),
510    }
511}
512
513fn parse_param_type(state: &mut State, source: Pair<Rule>) -> Result<ParamType> {
514    source.assert_type(Rule::param_type)?;
515    let mut inner = source.into_inner();
516    let next = inner.n()?;
517    let r = match next.as_rule() {
518        Rule::tag_type => ParamType::Terminal(TerminalParamType::Tag(parse_tag_type(&next)?)),
519        Rule::param_native_type => ParamType::Terminal(parse_param_native_type(state, &next)?),
520        Rule::optional_type => {
521            let mut inner = next.into_inner();
522            let next = inner.n()?;
523            let r = match next.as_rule() {
524                Rule::tag_type => {
525                    ParamType::Optional(TerminalParamType::Tag(parse_tag_type(&next)?))
526                }
527                Rule::param_native_type => match parse_param_native_type(state, &next)? {
528                    TerminalParamType::Duration | TerminalParamType::Dataset => {
529                        return Err(ParseError::Unexpected {
530                            span: pair_to_source_span(&next),
531                            rule: Rule::param_native_type,
532                            expected: vec![Rule::tag_type],
533                        });
534                    }
535                    TerminalParamType::Regex => ParamType::Optional(TerminalParamType::Regex),
536                    TerminalParamType::Tag(tag_type) => {
537                        ParamType::Optional(TerminalParamType::Tag(tag_type))
538                    }
539                },
540                _ => {
541                    return Err(ParseError::Unexpected {
542                        span: pair_to_source_span(&next),
543                        rule: Rule::param_type,
544                        expected: vec![
545                            Rule::tag_type,
546                            Rule::param_native_type,
547                            Rule::optional_type,
548                        ],
549                    });
550                }
551            };
552            inner.assert_empty()?;
553            r
554        }
555        _ => {
556            return Err(ParseError::Unexpected {
557                span: pair_to_source_span(&next),
558                rule: Rule::param_type,
559                expected: vec![Rule::tag_type, Rule::param_native_type, Rule::optional_type],
560            });
561        }
562    };
563    inner.assert_empty()?;
564    Ok(r)
565}
566
567fn parse_regex(source: &Pair<'_, Rule>) -> Result<Regex> {
568    source.assert_type(Rule::regex)?;
569    Ok(regex::Regex::new(&unescape_and_trim(
570        &source.as_str()[1..],
571        '/',
572    ))?)
573}
574
575fn parse_array(source: Pair<Rule>, state: &State) -> Result<Vec<Expr>> {
576    source.assert_type(Rule::array)?;
577    let inner = source.into_inner();
578    let mut res = Vec::new();
579    for next in inner {
580        res.push(parse_const(next, state)?);
581    }
582    Ok(res)
583}
584
585fn parse_const(source: Pair<Rule>, state: &State) -> Result<Expr> {
586    let mut inner = source.into_inner();
587    let next = inner.n()?;
588
589    // concrete value
590    match next.as_rule() {
591        Rule::string => parse_string(next, state),
592        Rule::float | Rule::inf => Ok(Expr::Const(TagValue::Float(parse_float(&next)?))),
593        Rule::int => Ok(Expr::Const(TagValue::Int(parse_int(&next)?))),
594        Rule::bool => Ok(Expr::Const(TagValue::Bool(
595            next.as_str().to_string().parse()?,
596        ))),
597        Rule::array => Ok(Expr::Array(parse_array(next, state)?)),
598        rule => Err(ParseError::Unexpected {
599            span: pair_to_source_span(&next),
600            rule,
601            expected: vec![Rule::string, Rule::float, Rule::inf, Rule::int, Rule::bool],
602        }),
603    }
604}
605
606fn parse_expr(source: Pair<Rule>, state: &State) -> Result<Expr> {
607    source.assert_type(Rule::expr)?;
608    let mut inner = source.into_inner();
609    let next = inner.n()?;
610
611    match next.as_rule() {
612        Rule::param_ident => {
613            // param
614            let span = pair_to_source_span(&next);
615            let mut inner = next.into_inner();
616            let next = inner.n()?;
617            let param = resolve_param(&next, state)?;
618            Ok(Expr::Param {
619                span,
620                param: param.clone(),
621            })
622        }
623        Rule::r#const => parse_const(next, state),
624        Rule::plain_ident | Rule::escaped_ident => Ok(Expr::Tag(parse_ident(&next)?)),
625        _ => Err(ParseError::Unexpected {
626            span: pair_to_source_span(&next),
627            rule: next.as_rule(),
628            expected: vec![Rule::param_ident, Rule::r#const, Rule::ident],
629        }),
630    }
631}
632
633fn parse_string(source: Pair<Rule>, state: &State) -> Result<Expr> {
634    source.assert_type(Rule::string)?;
635    let inner = source.into_inner();
636
637    let mut parts = Vec::new();
638    for part in inner {
639        part.assert_type(Rule::string_inner)?;
640        let mut inner_part = part.into_inner();
641        let next = inner_part.n()?;
642        inner_part.assert_empty()?;
643        match next.as_rule() {
644            Rule::string_chars => parts.push(StringFragment::Text(unescape(next.as_str(), '"'))),
645            Rule::expr => parts.push(StringFragment::Expr(parse_expr(next, state)?)),
646            _ => {
647                return Err(ParseError::Unexpected {
648                    span: pair_to_source_span(&next),
649                    rule: next.as_rule(),
650                    expected: vec![Rule::string, Rule::expr],
651                });
652            }
653        }
654    }
655    if parts
656        .iter()
657        .all(|part| matches!(part, StringFragment::Text(_)))
658    {
659        return Ok(Expr::Const(TagValue::String(
660            parts
661                .into_iter()
662                .map(|part| match part {
663                    StringFragment::Text(text) => text,
664                    StringFragment::Expr(_) => {
665                        unreachable!("we tested that all fragments are Text")
666                    }
667                })
668                .collect::<String>()
669                .try_into()?,
670        )));
671    }
672    Ok(Expr::String(parts))
673}
674
675fn parse_value_filter(field: String, source: Pair<Rule>, state: &State) -> Result<Filter> {
676    source.assert_type(Rule::value_filter)?;
677    let mut inner = source.into_inner();
678    let operator_pair = inner.n()?;
679    let operator = parse_cmp(&operator_pair)?;
680    let next = inner.n()?;
681    let value_span = pair_to_source_span(&next);
682
683    let value = parse_expr(next, state)?;
684
685    let rhs = match operator {
686        "==" => Cmp::Eq(value),
687        "!=" => Cmp::Ne(value),
688        ">" => Cmp::Gt(value),
689        ">=" => Cmp::Ge(value),
690        "<" => Cmp::Lt(value),
691        "<=" => Cmp::Le(value),
692        "in" => match value {
693            Expr::Const(TagValue::Array(_)) | Expr::Array(_) => Cmp::In(value),
694            Expr::Param { ref param, .. }
695                if param.typ() == TerminalParamType::Tag(TagType::Array) =>
696            {
697                Cmp::In(value)
698            }
699            _ => {
700                return Err(ParseError::InRequiresArray { span: value_span });
701            }
702        },
703        other => {
704            return Err(ParseError::UnsupportedTagComparison {
705                span: pair_to_source_span(&operator_pair),
706                op: other.to_string(),
707            });
708        }
709    };
710    Ok(Filter::Cmp { field, rhs })
711}
712
713#[derive(Debug, thiserror::Error)]
714pub enum ParseParamError {
715    #[error("Failed to parse: {0}")]
716    Parse(#[from] ParseError),
717    #[error("Failed to param as bool: {0}")]
718    ParseBool(<bool as FromStr>::Err),
719    #[error("Failed to parse as float: {0}")]
720    ParseFloat(#[from] ParseFloatError),
721    #[error("Failed to parse identifier: {0}")]
722    SharedStringError(#[from] strumbra::Error),
723    #[error(
724        "Param is declared as type {declared_typ}, but the provided type was parsed as `{rule:?}`"
725    )]
726    TypeMismatch { declared_typ: ParamType, rule: Rule },
727    #[error("None Type Params are not supported")]
728    NoneParam,
729    #[error("Unsupported Array element")]
730    UnsupportedArrayElement,
731}
732
733fn expr_to_array(e: Expr) -> result::Result<TagValue, ParseParamError> {
734    match e {
735        Expr::Const(tag_value) => Ok(tag_value),
736        Expr::Param { .. } | Expr::String(_) | Expr::Tag(_) => {
737            Err(ParseParamError::UnsupportedArrayElement)
738        }
739        Expr::Array(exprs) => exprs
740            .into_iter()
741            .map(expr_to_array)
742            .collect::<result::Result<_, ParseParamError>>()
743            .map(TagValue::Array),
744    }
745}
746
747pub(crate) fn parse_param_value(
748    param: &ParamDeclaration,
749    mut source: Pairs<'_, Rule>,
750) -> result::Result<ParamValue, ParseParamError> {
751    let next = source.n()?;
752    next.assert_type(Rule::param_value)?;
753    let mut inner = next.into_inner();
754    let next = inner.n()?;
755
756    match param.typ() {
757        TerminalParamType::Dataset => match next.as_rule() {
758            Rule::plain_ident | Rule::escaped_ident => {
759                Ok(ParamValue::Dataset(Dataset::new(parse_ident(&next)?)))
760            }
761            rule => Err(ParseParamError::TypeMismatch {
762                declared_typ: param.typ,
763                rule,
764            }),
765        },
766        TerminalParamType::Duration => match next.as_rule() {
767            Rule::time_relative => Ok(ParamValue::Duration(parse_relative_time(next)?)),
768            rule => Err(ParseParamError::TypeMismatch {
769                declared_typ: param.typ,
770                rule,
771            }),
772        },
773        TerminalParamType::Regex => match next.as_rule() {
774            Rule::regex => Ok(ParamValue::Regex(parse_regex(&next)?.into())),
775            rule => Err(ParseParamError::TypeMismatch {
776                declared_typ: param.typ,
777                rule,
778            }),
779        },
780        // TODO: how should we handle interpolsted strings here?
781        TerminalParamType::Tag(TagType::String) => Ok(ParamValue::String(unescape_and_trim(
782            const_type(next, Rule::string, param.typ)?.as_str(),
783            '"',
784        ))),
785        TerminalParamType::Tag(TagType::Int) => Ok(ParamValue::Int(parse_int(&const_type(
786            next,
787            Rule::int,
788            param.typ,
789        )?)?)),
790        TerminalParamType::Tag(TagType::Array) => {
791            let state = State {
792                params: Vec::new(),
793                directives: HashMap::new(),
794                warnings: Warnings::new(),
795            };
796            let a = parse_array(const_type(next, Rule::array, param.typ)?, &state)?;
797            let a = a
798                .into_iter()
799                .map(expr_to_array)
800                .collect::<result::Result<_, ParseParamError>>()?;
801            Ok(ParamValue::Array(a))
802        }
803        TerminalParamType::Tag(TagType::Float) => {
804            let declared_typ = param.typ;
805            if next.as_rule() != Rule::r#const {
806                return Err(ParseParamError::TypeMismatch {
807                    declared_typ,
808                    rule: next.as_rule(),
809                });
810            }
811            let mut inner = next.into_inner();
812            let next = inner.n()?;
813            match next.as_rule() {
814                Rule::float => Ok(ParamValue::Float(next.as_str().parse()?)),
815                Rule::inf if next.as_str() == "inf" || next.as_str() == "+inf" => {
816                    Ok(ParamValue::Float(f64::INFINITY))
817                }
818                Rule::inf if next.as_str() == "-inf" => Ok(ParamValue::Float(f64::NEG_INFINITY)),
819                _ => Err(ParseParamError::TypeMismatch {
820                    declared_typ,
821                    rule: next.as_rule(),
822                }),
823            }
824        }
825        TerminalParamType::Tag(TagType::Bool) => Ok(ParamValue::Bool(
826            const_type(next, Rule::bool, param.typ)?
827                .as_str()
828                .parse()
829                .map_err(ParseParamError::ParseBool)?,
830        )),
831        TerminalParamType::Tag(TagType::Null) => Err(ParseParamError::NoneParam),
832    }
833}
834
835fn const_type(
836    src: Pair<Rule>,
837    rule_type: Rule,
838    declared_typ: ParamType,
839) -> result::Result<Pair<Rule>, ParseParamError> {
840    if src.as_rule() != Rule::r#const {
841        return Err(ParseParamError::TypeMismatch {
842            declared_typ,
843            rule: src.as_rule(),
844        });
845    }
846    let mut inner = src.into_inner();
847    let next = inner.n()?;
848    if next.as_rule() != rule_type {
849        return Err(ParseParamError::TypeMismatch {
850            declared_typ,
851            rule: next.as_rule(),
852        });
853    }
854    Ok(next)
855}
856
857fn parse_regex_filter(field: String, source: Pair<Rule>) -> Result<Filter> {
858    source.assert_type(Rule::regex_filter)?;
859    let mut inner = source.into_inner();
860    let operator_pair = inner.n()?;
861    let operator = parse_cmp_re(&operator_pair)?;
862    let rhs = match operator {
863        // we always use a concrete value because we matched on the regex syntax
864        "==" => Cmp::RegEx(Parameterized::Concrete(parse_regex(&inner.n()?)?.into())),
865        "!=" => Cmp::RegExNot(Parameterized::Concrete(parse_regex(&inner.n()?)?.into())),
866        other => {
867            return Err(ParseError::UnsupportedRegexpComparison {
868                span: pair_to_source_span(&operator_pair),
869                op: other.to_string(),
870            });
871        }
872    };
873    inner.assert_empty()?;
874    Ok(Filter::Cmp { field, rhs })
875}
876
877fn parse_tag_type(source: &Pair<Rule>) -> Result<TagType> {
878    source.assert_type(Rule::tag_type)?;
879    let tpe = source.as_str();
880    match tpe {
881        "array" => Ok(TagType::Array),
882        "string" => Ok(TagType::String),
883        "int" => Ok(TagType::Int),
884        "float" => Ok(TagType::Float),
885        "bool" => Ok(TagType::Bool),
886        other => Err(ParseError::InvalidTagType {
887            span: pair_to_source_span(source),
888            tpe: other.to_string(),
889        }),
890    }
891}
892
893fn parse_is_filter(field: String, source: Pair<Rule>) -> Result<Filter> {
894    source.assert_type(Rule::is_filter)?;
895    let mut inner = source.into_inner();
896    let operator = inner.n()?;
897    operator.assert_type(Rule::kw_is)?;
898    let tpe = parse_tag_type(&inner.n()?)?;
899    let rhs = Cmp::Is(tpe);
900    inner.assert_empty()?;
901    Ok(Filter::Cmp { field, rhs })
902}
903
904fn parse_filter_atom(source: Pair<Rule>, state: &State) -> Result<Filter> {
905    source.assert_type(Rule::filter_atom)?;
906    let mut inner = source.into_inner();
907
908    let next = inner.n()?;
909    let field = parse_ident(&next)?;
910
911    let next = inner.n()?;
912    let res = match next.as_rule() {
913        Rule::regex_filter => parse_regex_filter(field, next),
914        Rule::value_filter => parse_value_filter(field, next, state),
915        Rule::is_filter => parse_is_filter(field, next),
916        rule => Err(ParseError::Unexpected {
917            span: pair_to_source_span(&next),
918            rule,
919            expected: vec![Rule::regex_filter, Rule::value_filter, Rule::is_filter],
920        }),
921    }?;
922
923    inner.assert_empty()?;
924    Ok(res)
925}
926
927fn parse_filter_clause(source: Pair<'_, Rule>, state: &State) -> Result<Filter> {
928    source.assert_type(Rule::filter_clause)?;
929    let mut inner = source.into_inner();
930    let next = inner.n()?;
931    let res = match next.as_rule() {
932        Rule::filter_atom => parse_filter_atom(next, state),
933        Rule::filter_or => parse_or(next, state),
934        rule => Err(ParseError::Unexpected {
935            span: pair_to_source_span(&next),
936            rule,
937            expected: vec![Rule::filter_atom, Rule::filter_or],
938        }),
939    }?;
940
941    inner.assert_empty()?;
942    Ok(res)
943}
944
945fn parse_filter_not(source: Pair<'_, Rule>, state: &State) -> Result<Filter> {
946    source.assert_type(Rule::filter_not)?;
947    let mut inner = source.into_inner();
948    let next = inner.n()?;
949    let res = if next.as_rule() == Rule::kw_not {
950        Filter::Not(Box::new(parse_filter_clause(inner.n()?, state)?))
951    } else {
952        parse_filter_clause(next, state)?
953    };
954    inner.assert_empty()?;
955    Ok(res)
956}
957fn parse_and(source: Pair<Rule>, state: &State) -> Result<Filter> {
958    source.assert_type(Rule::filter_and)?;
959    let inner = source.into_inner();
960    let mut res = inner
961        .into_iter()
962        .map(|source| parse_filter_not(source, state))
963        .collect::<Result<Vec<_>>>()?;
964    if res.len() == 1 {
965        res.pop().ok_or(ParseError::Unreachable(
966            "len 1 filter should never be empty",
967        ))
968    } else {
969        Ok(Filter::And(res))
970    }
971}
972fn parse_or(source: Pair<Rule>, state: &State) -> Result<Filter> {
973    source.assert_type(Rule::filter_or)?;
974    let inner = source.into_inner();
975    let mut res = inner
976        .into_iter()
977        .map(|source| parse_and(source, state))
978        .collect::<Result<Vec<_>>>()?;
979    if res.len() == 1 {
980        res.pop().ok_or(ParseError::Unreachable(
981            "len 1 filter should never be empty",
982        ))
983    } else {
984        Ok(Filter::Or(res))
985    }
986}
987
988pub(crate) fn parse_filter(source: Pair<Rule>, state: &State) -> Result<Filter> {
989    source.assert_type(Rule::filter_rule)?;
990    let mut inner = source.into_inner();
991
992    let keyword = inner.n()?;
993    keyword.assert_type(Rule::pipe_keyword)?;
994
995    parse_where_part(&mut inner, state)
996}
997
998fn parse_where_part(source: &mut Pairs<Rule>, state: &State) -> Result<Filter> {
999    let _filter_kw = source.n()?; // kw_filter / kw_where
1000    let next = source.n()?;
1001    parse_or(next, state)
1002    // Intentionally no `assert_empty`: `parse_ifdef` reuses this to parse the
1003    // if-branch and then expects more pairs (`kw_else`, the else-branch's
1004    // `kw_where` + `filter_or`). The grammar already prevents trailing
1005    // garbage in `filter_rule`, so the defensive check is redundant.
1006}
1007
1008pub(crate) fn parse_ifdef(
1009    source: Pair<Rule>,
1010    state: &State,
1011) -> Result<(ParamDeclaration, Filter, Option<Filter>)> {
1012    source.assert_type(Rule::ifdef_rule)?;
1013    let mut inner = source.into_inner();
1014
1015    let keyword = inner.n()?;
1016    keyword.assert_type(Rule::pipe_keyword)?;
1017
1018    let kw_ifdef = inner.n()?;
1019    kw_ifdef.assert_type(Rule::kw_ifdef)?;
1020
1021    let param = inner.n()?;
1022    let span = pair_to_source_span(&param);
1023    let param = if matches!(param.as_rule(), Rule::param_ident) {
1024        let mut inner = param.into_inner();
1025        let next = inner.n()?;
1026        let param = resolve_param(&next, state)?.clone();
1027        if !param.is_optional() {
1028            return Err(ParseError::IfdefNotOptional { span, param });
1029        }
1030        param
1031    } else {
1032        return Err(ParseError::Unexpected {
1033            span,
1034            rule: param.as_rule(),
1035            expected: vec![Rule::param_ident],
1036        });
1037    };
1038
1039    let filter = parse_where_part(&mut inner, state)?;
1040    let Ok(kw_else) = inner.n() else {
1041        return Ok((param, filter, None));
1042    };
1043    kw_else.assert_type(Rule::kw_else)?;
1044    let filter_else = parse_where_part(&mut inner, state)?;
1045    Ok((param, filter, Some(filter_else)))
1046}
1047
1048pub(crate) fn parse_sample(source: Pair<Rule>) -> Result<f64> {
1049    source.assert_type(Rule::sample_rule)?;
1050    let mut inner = source.into_inner();
1051
1052    let keyword = inner.n()?;
1053    keyword.assert_type(Rule::pipe_keyword)?;
1054
1055    let next = inner.n()?;
1056    next.assert_type(Rule::sample_expr)?;
1057    let mut inner = next.into_inner();
1058    let next = inner.n()?;
1059    next.assert_type(Rule::kw_sample)?;
1060    let next = inner.n()?;
1061    let res = parse_number(next)?;
1062    inner.assert_empty()?;
1063    Ok(res.as_f64())
1064}
1065
1066// FIXME(arne): Should params work in the `as` statement?
1067fn parse_as(source: Pair<Rule>) -> Result<As> {
1068    source.assert_type(Rule::r#as)?;
1069    let mut inner = source.into_inner();
1070    let name = parse_metric_name(inner.n()?)?;
1071    inner.assert_empty()?;
1072    Ok(As { name })
1073}
1074
1075fn parse_bucket_by_fn(source: &Pair<'_, Rule>) -> Result<BucketType> {
1076    source.assert_type(Rule::bucket_by_fn)?;
1077    match source.as_str() {
1078        "histogram" => Ok(BucketType::Histogram),
1079        "interpolate_delta_histogram" => Ok(BucketType::InterpolateDeltaHistogram),
1080        other => Err(ParseError::UnsupportedBucketFunction {
1081            span: pair_to_source_span(source),
1082            name: other.to_string(),
1083        }),
1084    }
1085}
1086
1087fn parse_bucket_conversion(source: &Pair<'_, Rule>) -> Result<ConversionMethod> {
1088    source.assert_type(Rule::bucket_conversion)?;
1089    match source.as_str() {
1090        "rate" => Ok(ConversionMethod::Rate),
1091        "increase" => Ok(ConversionMethod::Increase),
1092        other => Err(ParseError::UnsupportedBucketFunction {
1093            span: pair_to_source_span(source),
1094            name: other.to_string(),
1095        }),
1096    }
1097}
1098
1099fn parse_bucket_spec(source: Pair<Rule>) -> Result<BucketSpec> {
1100    source.assert_type(Rule::bucket_spec)?;
1101    Ok(match source.as_str() {
1102        "count" => BucketSpec::Count,
1103        "avg" => BucketSpec::Avg,
1104        "sum" => BucketSpec::Sum,
1105        "min" => BucketSpec::Min,
1106        "max" => BucketSpec::Max,
1107        _ => {
1108            let mut inner = source.into_inner();
1109            let next = inner.n()?;
1110            let perc = parse_number(next)?;
1111            BucketSpec::Percentile(perc.as_f64())
1112        }
1113    })
1114}
1115
1116fn parse_bucket_specs(source: Pair<Rule>) -> Result<Vec<BucketSpec>> {
1117    source.assert_type(Rule::bucket_specs)?;
1118    source
1119        .into_inner()
1120        .map(parse_bucket_spec)
1121        .collect::<Result<_>>()
1122}
1123
1124fn parse_bucket_fn_call_simple(source: Pair<Rule>) -> Result<(BucketType, Vec<BucketSpec>)> {
1125    source.assert_type(Rule::bucket_fn_call_simple)?;
1126    let mut inner = source.into_inner();
1127    let function = parse_bucket_by_fn(&inner.n()?)?;
1128    let specs = parse_bucket_specs(inner.n()?)?;
1129    inner.assert_empty()?;
1130    Ok((function, specs))
1131}
1132
1133fn parse_bucket_fn_call_with_conversion(
1134    source: Pair<Rule>,
1135) -> Result<(BucketType, Vec<BucketSpec>)> {
1136    source.assert_type(Rule::bucket_fn_call_with_conversion)?;
1137    let mut inner = source.into_inner();
1138    let _fn_name = inner.n()?;
1139    let mode = parse_bucket_conversion(&inner.n()?)?;
1140    let specs = parse_bucket_specs(inner.n()?)?;
1141    inner.assert_empty()?;
1142    Ok((BucketType::InterpolateCumulativeHistogram(mode), specs))
1143}
1144
1145fn parse_bucket_fn_call(source: Pair<Rule>) -> Result<(BucketType, Vec<BucketSpec>)> {
1146    source.assert_type(Rule::bucket_fn_call)?;
1147    let mut inner = source.into_inner();
1148    let next = inner.n()?;
1149    let result = match next.as_rule() {
1150        Rule::bucket_fn_call_simple => parse_bucket_fn_call_simple(next),
1151        Rule::bucket_fn_call_with_conversion => parse_bucket_fn_call_with_conversion(next),
1152        rule => Err(ParseError::Unexpected {
1153            span: pair_to_source_span(&next),
1154            rule,
1155            expected: vec![
1156                Rule::bucket_fn_call_simple,
1157                Rule::bucket_fn_call_with_conversion,
1158            ],
1159        }),
1160    };
1161    inner.assert_empty()?;
1162    result
1163}
1164
1165fn parse_bucket_by(source: Pair<Rule>, state: &State) -> Result<BucketBy> {
1166    source.assert_type(Rule::bucket_by)?;
1167    let span = pair_to_source_span(&source);
1168    let mut inner = source.into_inner();
1169    let next = inner.n()?;
1170
1171    let (tags, next) = if next.as_rule() == Rule::tags {
1172        let fields = next
1173            .into_inner()
1174            .map(|field| parse_ident(&field))
1175            .collect::<Result<_>>()?;
1176        (fields, inner.n()?)
1177    } else {
1178        (Vec::new(), next)
1179    };
1180
1181    if next.as_rule() == Rule::bucket_fn_call {
1182        let (function, spec) = parse_bucket_fn_call(next)?;
1183        inner.assert_empty()?;
1184
1185        Ok(BucketBy {
1186            span,
1187            function,
1188            time: None,
1189            tags,
1190            spec,
1191        })
1192    } else {
1193        let time = parse_parameterized_relative_time(next, state)?;
1194        let (function, spec) = parse_bucket_fn_call(inner.n()?)?;
1195
1196        inner.assert_empty()?;
1197        Ok(BucketBy {
1198            span,
1199            function,
1200            time: Some(time),
1201            tags,
1202            spec,
1203        })
1204    }
1205}
1206
1207fn parse_function_id(source: Pair<Rule>) -> Result<Function> {
1208    let mut inner = source.into_inner();
1209    let mut next = inner.n()?;
1210    let mut module = Vec::new();
1211    while next.as_rule() == Rule::module {
1212        let mut this = std::mem::replace(&mut next, inner.n()?).into_inner();
1213        let name = parse_ident(&this.n()?)?;
1214        this.assert_empty()?;
1215        module.push(ModuleId(name));
1216    }
1217    let name = parse_ident(&next)?;
1218    let name = FunctionId(name);
1219    inner.assert_empty()?;
1220    Ok(Function {
1221        name,
1222        module_path: module,
1223    })
1224}
1225
1226pub(crate) struct State {
1227    params: Params,
1228    directives: Directives,
1229    warnings: Warnings,
1230}
1231
1232impl Parser {
1233    pub(crate) fn parse_query<H: BuildHasher>(
1234        &self,
1235        pairs: &mut Pairs<Rule>,
1236        system_params: HashMap<String, ParamType, H>,
1237    ) -> Result<(Query, Warnings)> {
1238        let mut next = pairs.next().ok_or(ParseError::EOF {
1239            span: miette::SourceSpan::new(0.into(), 0),
1240        })?;
1241
1242        let mut params = Params::default();
1243
1244        // add system params
1245        for (name, typ) in system_params {
1246            if !name.starts_with(SYSTEM_PARAM_PREFIX) {
1247                return Err(ParseError::SystemParamMissingPrefix { param: name });
1248            }
1249            params.push(ParamDeclaration {
1250                span: SourceSpan::new(0.into(), 0),
1251                name,
1252                typ,
1253            });
1254        }
1255
1256        let mut state = State {
1257            params,
1258            directives: Directives::default(),
1259            warnings: Warnings::new(),
1260        };
1261
1262        loop {
1263            match next.as_rule() {
1264                Rule::directive => {
1265                    let span = pair_to_source_span(&next);
1266                    let (directive, value) = Parser::parse_directive(next)?;
1267                    state.directives.insert(directive, value);
1268                    next = pairs.next().ok_or(ParseError::EOF { span })?;
1269                }
1270                Rule::param => {
1271                    let span = pair_to_source_span(&next);
1272                    let param = Parser::parse_param(&mut state, next)?;
1273                    state.params.push(param);
1274                    next = pairs.next().ok_or(ParseError::EOF { span })?;
1275                }
1276                _ => break,
1277            }
1278        }
1279
1280        let r = self.parse_query_(&state, next)?;
1281        Ok((r, state.warnings))
1282    }
1283
1284    pub(crate) fn parse_directive(source: Pair<'_, Rule>) -> Result<(String, DirectiveValue)> {
1285        let mut inner = source.into_inner();
1286        let directive = parse_ident(&inner.n()?)?;
1287        let value = if let Some(v) = inner.next() {
1288            match v.as_rule() {
1289                Rule::plain_ident | Rule::escaped_ident => DirectiveValue::Ident(parse_ident(&v)?),
1290                Rule::r#const => parse_directive_value(v)?,
1291                rule => Err(ParseError::Unexpected {
1292                    span: pair_to_source_span(&v),
1293                    rule,
1294                    expected: vec![Rule::escaped_ident, Rule::plain_ident, Rule::r#const],
1295                })?,
1296            }
1297        } else {
1298            DirectiveValue::None
1299        };
1300        Ok((directive, value))
1301    }
1302
1303    pub(crate) fn parse_param(
1304        state: &mut State,
1305        source: Pair<'_, Rule>,
1306    ) -> Result<ParamDeclaration> {
1307        let mut inner = source.into_inner();
1308        let next = inner.n()?;
1309        let span = pair_to_source_span(&next);
1310
1311        let name = parse_param_ident(next)?;
1312
1313        if name.starts_with(SYSTEM_PARAM_PREFIX) {
1314            state.warnings.push_span(
1315                span,
1316                WarningReason::ParamUsingSystemPrefix {
1317                    param: name.clone(),
1318                },
1319            );
1320        } else if state.params.iter().any(|p| p.name == name) {
1321            return Err(ParseError::ParamDefinedMultipleTimes { span, param: name });
1322        }
1323
1324        let typ = parse_param_type(state, inner.n()?)?;
1325
1326        Ok(ParamDeclaration { span, name, typ })
1327    }
1328
1329    fn parse_query_(&self, state: &State, query: Pair<Rule>) -> Result<Query> {
1330        match query.as_rule() {
1331            Rule::simple_query => {
1332                let inner = query.into_inner();
1333                self.parse_simple_query(state, inner)
1334            }
1335            Rule::compute_query => {
1336                let inner = query.into_inner();
1337                self.parse_compute_query(state, inner)
1338            }
1339            rule => Err(ParseError::Unexpected {
1340                span: pair_to_source_span(&query),
1341                rule,
1342                expected: vec![Rule::simple_query, Rule::compute_query],
1343            }),
1344        }
1345    }
1346
1347    fn parse_compute_query(&self, state: &State, mut pairs: Pairs<Rule>) -> Result<Query> {
1348        let next = pairs.next().ok_or(ParseError::EOF {
1349            span: miette::SourceSpan::new(0.into(), 0),
1350        })?;
1351        let left = Box::new(self.parse_query_(state, next)?);
1352        let next = pairs.next().ok_or(ParseError::EOF {
1353            span: miette::SourceSpan::new(0.into(), 0),
1354        })?;
1355        let right = Box::new(self.parse_query_(state, next)?);
1356
1357        let next = pairs.next().ok_or(ParseError::EOF {
1358            span: miette::SourceSpan::new(0.into(), 0),
1359        })?;
1360        match next.as_rule() {
1361            Rule::compute_rule => {}
1362            Rule::time_range => {
1363                return Err(ParseError::NotSupported {
1364                    span: pair_to_source_span(&next),
1365                    rule: Rule::time_range,
1366                });
1367            }
1368            rule => {
1369                return Err(ParseError::Unexpected {
1370                    span: pair_to_source_span(&next),
1371                    rule,
1372                    expected: vec![Rule::compute_rule, Rule::time_range],
1373                });
1374            }
1375        }
1376        let mut compute_rule = next.into_inner();
1377
1378        let keyword = compute_rule.n()?;
1379        keyword.assert_type(Rule::pipe_keyword)?;
1380
1381        let next = compute_rule.next().ok_or(ParseError::EOF {
1382            span: pair_to_source_span(&keyword),
1383        })?;
1384        let name = parse_metric_name(next)?;
1385
1386        let next = compute_rule.next().ok_or(ParseError::EOF {
1387            span: pair_to_source_span(&keyword),
1388        })?;
1389        let op = self.parse_compute_fn(next)?;
1390
1391        let mut aggregates = Vec::new();
1392        let mut extends = Vec::new();
1393
1394        // Read post-compute pipe_rule* from compute_query (the outer pairs),
1395        for next in &mut pairs {
1396            match next.as_rule() {
1397                Rule::EOI => break,
1398                Rule::pipe_rule => aggregates.push(self.parse_pipe(next, state)?),
1399                Rule::extend_rule => extends.extend(self.parse_extend(next, state)?),
1400
1401                rule => {
1402                    return Err(ParseError::Unexpected {
1403                        span: pair_to_source_span(&next),
1404                        rule,
1405                        expected: vec![Rule::EOI, Rule::pipe_rule],
1406                    });
1407                }
1408            }
1409        }
1410
1411        Ok(Query::Compute {
1412            left,
1413            right,
1414            name,
1415            op,
1416            aggregates,
1417            extends,
1418            directives: state.directives.clone(),
1419            params: state.params.clone(),
1420        })
1421    }
1422    fn parse_simple_query(&self, state: &State, mut pairs: Pairs<Rule>) -> Result<Query> {
1423        let (source, as_) = parse_source(pairs.n()?, state)?;
1424        let mut sample = None;
1425        let mut filters = Vec::new();
1426        let mut aggregates = Vec::new();
1427        let mut extends = Vec::new();
1428        if let Some(as_) = as_ {
1429            aggregates.push(Aggregate::As(as_));
1430        }
1431
1432        for next in &mut pairs {
1433            match next.as_rule() {
1434                Rule::EOI => break,
1435                // we only allow one sample rule
1436                Rule::sample_rule if sample.is_some() => {}
1437                Rule::sample_rule => sample = Some(parse_sample(next)?),
1438                Rule::ifdef_rule => {
1439                    let (param, filter, else_filter) = parse_ifdef(next, state)?;
1440                    filters.push(FilterOrIfDef::Ifdef {
1441                        param,
1442                        filter,
1443                        else_filter,
1444                    });
1445                }
1446                Rule::filter_rule => {
1447                    filters.push(FilterOrIfDef::Filter(parse_filter(next, state)?));
1448                }
1449                Rule::pipe_rule => aggregates.push(self.parse_pipe(next, state)?),
1450                Rule::extend_rule => extends.extend(self.parse_extend(next, state)?),
1451                rule => {
1452                    return Err(ParseError::Unexpected {
1453                        span: pair_to_source_span(&next),
1454                        rule,
1455                        expected: vec![Rule::EOI, Rule::filter_rule, Rule::pipe_rule],
1456                    });
1457                }
1458            }
1459        }
1460
1461        Ok(Query::Simple {
1462            sample,
1463            source,
1464            filters,
1465            aggregates,
1466            extends,
1467            directives: state.directives.clone(),
1468            params: state.params.clone(),
1469        })
1470    }
1471
1472    pub(crate) fn parse_pipe(&self, source: Pair<Rule>, state: &State) -> Result<Aggregate> {
1473        source.assert_type(Rule::pipe_rule)?;
1474        let mut inner = source.into_inner();
1475
1476        let keyword = inner.n()?;
1477        keyword.assert_type(Rule::pipe_keyword)?;
1478
1479        let next = inner.n()?;
1480        inner.assert_empty()?;
1481        match next.as_rule() {
1482            Rule::map => Ok(Aggregate::Map(self.parse_map(next)?)),
1483            Rule::align => Ok(Aggregate::Align(self.parse_align(next, state)?)),
1484            Rule::group_by => Ok(Aggregate::GroupBy(self.parse_group_by(next)?)),
1485            Rule::bucket_by => Ok(Aggregate::Bucket(parse_bucket_by(next, state)?)),
1486            rule @ (Rule::join | Rule::replace) => Err(ParseError::NotSupported {
1487                span: pair_to_source_span(&next),
1488                rule,
1489            }),
1490            Rule::r#as => Ok(Aggregate::As(parse_as(next)?)),
1491            rule => Err(ParseError::Unexpected {
1492                span: pair_to_source_span(&next),
1493                rule,
1494                expected: vec![
1495                    Rule::map,
1496                    Rule::align,
1497                    Rule::group_by,
1498                    Rule::bucket_by,
1499                    Rule::join,
1500                    Rule::replace,
1501                    Rule::r#as,
1502                ],
1503            }),
1504        }
1505    }
1506
1507    #[allow(clippy::unused_self)] // we will need self
1508    fn parse_extend_expr(&self, source: Pair<Rule>, state: &State) -> Result<TagExtend> {
1509        source.assert_type(Rule::extend_expr)?;
1510        let mut inner = source.into_inner();
1511
1512        let next = inner.n()?;
1513        let tag = parse_ident(&next)?;
1514        let next = inner.n()?;
1515        let value = parse_expr(next, state)?;
1516        Ok(TagExtend { tag, value })
1517    }
1518
1519    #[allow(clippy::unused_self)] // we will need self
1520    fn parse_extend(&self, source: Pair<Rule>, state: &State) -> Result<Vec<TagExtend>> {
1521        source.assert_type(Rule::extend_rule)?;
1522        let mut inner = source.into_inner();
1523
1524        let keyword = inner.n()?;
1525        keyword.assert_type(Rule::pipe_keyword)?;
1526        let keyword = inner.n()?;
1527        keyword.assert_type(Rule::kw_extend)?;
1528
1529        let mut result = Vec::with_capacity(1);
1530
1531        let next = inner.n()?;
1532        result.push(self.parse_extend_expr(next, state)?);
1533        while let Ok(next) = inner.n() {
1534            result.push(self.parse_extend_expr(next, state)?);
1535        }
1536        Ok(result)
1537    }
1538
1539    fn parse_map(&self, source: Pair<Rule>) -> Result<Mapping> {
1540        source.assert_type(Rule::map)?;
1541        let mut inner = source.into_inner();
1542        let next = inner.n()?;
1543        let map = match next.as_rule() {
1544            Rule::map_fn => self.parse_map_fn(next),
1545            Rule::map_eval => self.parse_map_eval(next),
1546            rule => Err(ParseError::Unexpected {
1547                span: pair_to_source_span(&next),
1548                rule,
1549                expected: vec![Rule::map_fn, Rule::map_eval],
1550            }),
1551        }?;
1552        inner.assert_empty()?;
1553        Ok(map)
1554    }
1555    fn parse_map_fn(&self, source: Pair<Rule>) -> Result<Mapping> {
1556        source.assert_type(Rule::map_fn)?;
1557        let span = pair_to_source_span(&source);
1558        let mut inner = source.into_inner();
1559        let func_pair = inner.n()?;
1560        let func = parse_function_id(func_pair)?;
1561        let arg = inner
1562            .next()
1563            .map(|n| parse_number(n).map(Number::as_f64))
1564            .transpose()?;
1565        let Some(function) = self.stdlib.map_fn(&func) else {
1566            return Err(ParseError::UnsupportedMapFunction {
1567                span,
1568                name: func.to_string(),
1569            });
1570        };
1571
1572        inner.assert_empty()?;
1573
1574        Ok(Mapping {
1575            function: function.clone(),
1576            arg,
1577        })
1578    }
1579
1580    fn parse_map_eval(&self, source: Pair<Rule>) -> Result<Mapping> {
1581        source.assert_type(Rule::map_eval)?;
1582        let span = pair_to_source_span(&source);
1583        let mut inner = source.into_inner();
1584        let next = inner.n()?;
1585        let func = match next.as_rule() {
1586            Rule::func => parse_function_id(next)?,
1587            Rule::map_calc_op => Function {
1588                module_path: vec![],
1589                name: FunctionId::new(next.as_str()),
1590            },
1591            rule => {
1592                return Err(ParseError::Unexpected {
1593                    span: pair_to_source_span(&next),
1594                    rule,
1595                    expected: vec![Rule::func, Rule::map_calc_op],
1596                });
1597            }
1598        };
1599        let Some(function) = self.stdlib.map_fn(&func) else {
1600            return Err(ParseError::UnsupportedMapEvaluation {
1601                span,
1602                name: func.to_string(),
1603            });
1604        };
1605        let arg = Some(parse_number(inner.n()?)?.as_f64());
1606        Ok(Mapping {
1607            function: function.clone(),
1608            arg,
1609        })
1610    }
1611
1612    fn parse_align(&self, source: Pair<Rule>, state: &State) -> Result<Align> {
1613        source.assert_type(Rule::align)?;
1614        let mut inner = source.into_inner();
1615
1616        let next = inner.n()?;
1617        next.assert_type(Rule::kw_align)?;
1618
1619        let next = inner.n()?;
1620        if next.as_rule() == Rule::kw_using {
1621            let next = inner.n()?;
1622            let function = self.parse_align_fn(next)?;
1623            inner.assert_empty()?;
1624            return Ok(Align {
1625                function,
1626                time: None,
1627            });
1628        }
1629        next.assert_type(Rule::kw_to)?;
1630        let next = inner.n()?;
1631        let time = parse_parameterized_relative_time(next, state)?;
1632        let next = inner.n()?;
1633        if next.as_rule() == Rule::kw_over {
1634            let next = inner.n()?;
1635            let _sliding_window = parse_parameterized_relative_time(next, state)?;
1636            let next = inner.n()?;
1637            next.assert_type(Rule::kw_using)?;
1638            let _function = self.parse_align_fn(inner.n()?)?;
1639            inner.assert_empty()?;
1640            Err(ParseError::NotImplemented("sliding windows"))
1641        } else if next.as_rule() == Rule::kw_using {
1642            let next = inner.n()?;
1643            let function = self.parse_align_fn(next)?;
1644            inner.assert_empty()?;
1645            Ok(Align {
1646                function,
1647                time: Some(time),
1648            })
1649        } else {
1650            Err(ParseError::Unexpected {
1651                span: pair_to_source_span(&next),
1652                rule: next.as_rule(),
1653                expected: vec![Rule::kw_using],
1654            })
1655        }
1656    }
1657
1658    fn parse_align_fn(&self, source: Pair<Rule>) -> Result<AlignFunction> {
1659        source.assert_type(Rule::func)?;
1660        let span = pair_to_source_span(&source);
1661        let f = parse_function_id(source)?;
1662        let Some(function) = self.stdlib.align_fn(&f) else {
1663            return Err(ParseError::UnsupportedAlignFunction {
1664                span,
1665                name: f.to_string(),
1666            });
1667        };
1668
1669        Ok(function.clone())
1670    }
1671
1672    fn parse_group_by_fn(&self, source: Pair<Rule>) -> Result<GroupFunction> {
1673        let span = pair_to_source_span(&source);
1674        let f = parse_function_id(source)?;
1675        let Some(function) = self.stdlib.group_fn(&f) else {
1676            return Err(ParseError::UnsupportedGroupFunction {
1677                span,
1678                name: f.to_string(),
1679            });
1680        };
1681
1682        Ok(function.clone())
1683    }
1684
1685    fn parse_group_by(&self, source: Pair<Rule>) -> Result<GroupBy> {
1686        source.assert_type(Rule::group_by)?;
1687        let span = pair_to_source_span(&source);
1688
1689        let mut inner = source.into_inner();
1690        let next = inner.n()?;
1691        next.assert_type(Rule::kw_group)?;
1692
1693        let next = inner.n()?;
1694        let (tags, function) = if next.as_rule() == Rule::kw_by {
1695            let next = inner.n()?;
1696            next.assert_type(Rule::tags)?;
1697            let fields = next
1698                .into_inner()
1699                .map(|field| parse_ident(&field))
1700                .collect::<Result<_>>()?;
1701            let next = inner.n()?;
1702            next.assert_type(Rule::kw_using)?;
1703            let function = self.parse_group_by_fn(inner.n()?)?;
1704            (fields, function)
1705        } else {
1706            next.assert_type(Rule::kw_using)?;
1707            let next = inner.n()?;
1708            (Vec::new(), self.parse_group_by_fn(next)?)
1709        };
1710        inner.assert_empty()?;
1711        Ok(GroupBy {
1712            span,
1713            function,
1714            tags,
1715        })
1716    }
1717
1718    pub(crate) fn parse_compute_fn(&self, source: Pair<Rule>) -> Result<ComputeFunction> {
1719        source.assert_type(Rule::compute_fn)?;
1720        let span = pair_to_source_span(&source);
1721        let mut inner = source.into_inner();
1722        let next = inner.n()?;
1723        let f = match next.as_rule() {
1724            Rule::func => parse_function_id(next)?,
1725            Rule::compute_op => Function {
1726                module_path: vec![],
1727                name: FunctionId::new(next.as_str()),
1728            },
1729            rule => {
1730                return Err(ParseError::Unexpected {
1731                    span: pair_to_source_span(&next),
1732                    rule,
1733                    expected: vec![Rule::func, Rule::compute_op],
1734                });
1735            }
1736        };
1737        inner.assert_empty()?;
1738        let Some(function) = self.stdlib.compute_fn(&f) else {
1739            return Err(ParseError::UnsupportedComputeFunction {
1740                span,
1741                name: f.to_string(),
1742            });
1743        };
1744
1745        Ok(function.clone())
1746    }
1747}
1748
1749pub(crate) struct Parser {
1750    stdlib: &'static Module,
1751}
1752
1753impl Default for Parser {
1754    fn default() -> Self {
1755        Parser { stdlib: &STDLIB }
1756    }
1757}