Skip to main content

rtlola_parser/
parse.rs

1//! This module contains the parser for the Lola Language.
2
3use std::convert::TryInto;
4use std::rc::Rc;
5use std::str::FromStr;
6
7use lazy_static::lazy_static;
8use num::rational::Rational64 as Rational;
9use num::traits::Pow;
10use num::{BigInt, BigRational, FromPrimitive, ToPrimitive};
11use pest::iterators::{Pair, Pairs};
12use pest::pratt_parser::{Assoc, Op, PrattParser};
13use pest::Parser;
14use pest_derive::Parser;
15use rtlola_reporting::{Diagnostic, RtLolaError, Span};
16use unicode_normalization::UnicodeNormalization;
17
18use super::ast::*;
19use crate::ast::Literal;
20use crate::syntactic_sugar::Desugarizer;
21use crate::ParserConfig;
22
23#[derive(Parser)]
24#[grammar = "lola.pest"]
25struct LolaParser;
26
27#[derive(Debug, Clone)]
28pub(crate) struct RtLolaParser<'a> {
29    spec: RtLolaAst,
30    config: &'a ParserConfig,
31}
32
33lazy_static! {
34    static ref PRATT_PARSER: PrattParser<Rule> = {
35        use self::Assoc::*;
36        use self::Rule::*;
37
38        PrattParser::new()
39            .op(Op::infix(Implies, Right))
40            .op(Op::infix(Or, Left))
41            .op(Op::infix(And, Left))
42            .op(Op::infix(BitOr, Left))
43            .op(Op::infix(BitXor, Left))
44            .op(Op::infix(BitAnd, Left))
45            .op(Op::infix(Equal, Left) | Op::infix(NotEqual, Left))
46            .op(Op::infix(LessThan, Left)
47                | Op::infix(LessThanOrEqual, Left)
48                | Op::infix(MoreThan, Left)
49                | Op::infix(MoreThanOrEqual, Left))
50            .op(Op::infix(ShiftLeft, Left) | Op::infix(ShiftRight, Left))
51            .op(Op::infix(Add, Left) | Op::infix(Subtract, Left))
52            .op(Op::infix(Multiply, Left) | Op::infix(Divide, Left) | Op::infix(Mod, Left))
53            .op(Op::infix(Power, Right))
54            .op(Op::infix(Dot, Left))
55            .op(Op::infix(OpeningBracket, Left))
56    };
57}
58
59impl<'a> RtLolaParser<'a> {
60    pub(crate) fn new(config: &'a ParserConfig) -> Self {
61        RtLolaParser {
62            spec: RtLolaAst::empty(),
63            config,
64        }
65    }
66
67    /// Transforms a textual representation of a Lola specification into
68    /// an AST representation.
69    pub(crate) fn parse(config: &ParserConfig) -> Result<RtLolaAst, RtLolaError> {
70        RtLolaParser::new(config)
71            .parse_spec()
72            .and_then(|ast| Desugarizer::all().remove_syn_sugar(ast))
73    }
74
75    /// Runs the parser on the give spec.
76    pub(crate) fn parse_spec(mut self) -> Result<RtLolaAst, RtLolaError> {
77        let mut pairs =
78            LolaParser::parse(Rule::Spec, &self.config.spec).map_err(to_rtlola_error)?;
79        assert!(pairs.clone().count() == 1, "Spec must not be empty.");
80        let spec_pair = pairs.next().unwrap();
81        assert!(spec_pair.as_rule() == Rule::Spec);
82        let mut error = RtLolaError::new();
83        for pair in spec_pair.into_inner() {
84            match pair.as_rule() {
85                Rule::ImportStmt => {
86                    let import = self.parse_import(pair);
87                    self.spec.imports.push(import);
88                }
89                Rule::ConstantStream => {
90                    let constant = self.parse_constant(pair);
91                    self.spec.constants.push(Rc::new(constant));
92                }
93                Rule::InputStream => {
94                    let inputs = self.parse_inputs(pair);
95                    self.spec.inputs.extend(inputs.into_iter().map(Rc::new));
96                }
97                Rule::MirrorStream => match self.parse_mirror(pair) {
98                    Ok(mirror) => self.spec.mirrors.push(Rc::new(mirror)),
99                    Err(e) => error.join(e),
100                },
101                Rule::OutputStream => match self.parse_output(pair) {
102                    Ok(output) => self.spec.outputs.push(Rc::new(output)),
103                    Err(e) => error.join(e),
104                },
105                Rule::SimpleTrigger => match self.parse_trigger(pair) {
106                    Ok(trigger) => self.spec.outputs.push(Rc::new(trigger)),
107                    Err(e) => error.join(e),
108                },
109                Rule::TypeDecl => {
110                    let type_decl = self.parse_type_declaration(pair);
111                    self.spec.type_declarations.push(type_decl);
112                }
113                Rule::GlobalTagList => {
114                    let tags = self.parse_tag_list(pair);
115                    self.spec.global_tags.extend(tags);
116                }
117                Rule::EOI => {}
118                _ => unreachable!(),
119            }
120        }
121        Result::from(error)?;
122        Ok(self.spec)
123    }
124
125    fn parse_import(&self, pair: Pair<Rule>) -> Import {
126        assert_eq!(pair.as_rule(), Rule::ImportStmt);
127        let span = pair.as_span().into();
128        let mut pairs = pair.into_inner();
129        let name = self.parse_ident(&pairs.next().expect("mismatch between grammar and AST"));
130        Import {
131            name,
132            id: self.spec.next_id(),
133            span,
134        }
135    }
136
137    /**
138     * Transforms a `Rule::ConstantStream` into `Constant` AST node.
139     * Panics if input is not `Rule::ConstantStream`.
140     * The constant rule consists of the following tokens:
141     * - `Rule::Ident`
142     * - `Rule::Type`
143     * - `Rule::Literal`
144     */
145    fn parse_constant(&self, pair: Pair<'_, Rule>) -> Constant {
146        assert_eq!(pair.as_rule(), Rule::ConstantStream);
147        let span = pair.as_span().into();
148        let mut pairs = pair.into_inner();
149        let name = self.parse_ident(&pairs.next().expect("mismatch between grammar and AST"));
150        let ty = self.parse_type(pairs.next().expect("mismatch between grammar and AST"));
151        let literal = self.parse_literal(pairs.next().expect("mismatch between grammar and AST"));
152        Constant {
153            id: self.spec.next_id(),
154            name,
155            ty: Some(ty),
156            literal,
157            span,
158        }
159    }
160
161    /**
162     * Transforms a `Rule::InputStream` into `Input` AST node.
163     * Panics if input is not `Rule::InputStream`.
164     * The input rule consists of non-empty sequences of following tokens:
165     * - (`Rule::TagLists`)?
166     * - `Rule::Ident`
167     * - (`Rule::ParamList`)?
168     * - `Rule::Type`
169     */
170    fn parse_inputs(&self, pair: Pair<'_, Rule>) -> Vec<Input> {
171        assert_eq!(pair.as_rule(), Rule::InputStream);
172        let mut inputs = Vec::new();
173        let mut pairs = pair.into_inner();
174
175        let tags = if let Rule::TagLists = pairs.peek().unwrap().as_rule() {
176            self.parse_tag_lists(pairs.next().unwrap())
177        } else {
178            Vec::new()
179        };
180        while let Some(pair) = pairs.next() {
181            let start = pair.as_span().start();
182
183            let name = self.parse_ident(&pair);
184
185            let mut pair = pairs.next().expect("mismatch between grammar and AST");
186            let params = if let Rule::ParamList = pair.as_rule() {
187                let res = self.parse_parameter_list(pair.into_inner());
188                pair = pairs.next().expect("mismatch between grammar and AST");
189
190                res
191            } else {
192                Vec::new()
193            };
194            let end = pair.as_span().end();
195            let ty = self.parse_type(pair);
196            inputs.push(Input {
197                id: self.spec.next_id(),
198                name,
199                params: params.into_iter().map(Rc::new).collect(),
200                ty,
201                tags: tags.clone(),
202                span: Span::Direct { start, end },
203            })
204        }
205
206        assert!(!inputs.is_empty());
207        inputs
208    }
209
210    /**
211     * Transforms a `Rule::MirrorStream` into `Mirror` AST node.
212     * Panics if input is not `Rule::MirrorStream`.
213     * The mirror rule consists of the following tokens:
214     * - `Rule::Ident` (name)
215     * - `Rule::Ident` (target)
216     * - `Rule::Expr` (mirror condition)
217     */
218    fn parse_mirror(&self, pair: Pair<'_, Rule>) -> Result<Mirror, RtLolaError> {
219        assert_eq!(pair.as_rule(), Rule::MirrorStream);
220        let span = pair.as_span().into();
221        let mut pairs = pair.into_inner();
222        let name = self.parse_ident(&pairs.next().expect("mismatch between grammar and AST"));
223        let target = self.parse_ident(&pairs.next().expect("mismatch between grammar and AST"));
224        let condition = self.build_expression_ast(
225            pairs
226                .next()
227                .expect("mismatch between grammar and AST")
228                .into_inner(),
229        )?;
230        Ok(Mirror {
231            name,
232            target,
233            filter: condition,
234            id: self.spec.next_id(),
235            span,
236        })
237    }
238
239    /**
240     * Transforms a `Rule::OutputStream` into `Output` AST node.
241     * Panics if input is not `Rule::OutputStream`.
242     * The output rule consists of the following tokens:
243     * - `Rule::Ident`
244     * - `Rule::Type`
245     * - `Rule::Expr`
246     */
247    fn parse_output(&self, pair: Pair<'_, Rule>) -> Result<Output, RtLolaError> {
248        assert_eq!(pair.as_rule(), Rule::OutputStream);
249
250        let span = pair.as_span().into();
251        let mut pairs = pair.into_inner().peekable();
252        let mut pacing_annotation_default_span = Span::default();
253
254        let tags = if let Rule::TagLists = pairs.peek().unwrap().as_rule() {
255            self.parse_tag_lists(pairs.next().unwrap())
256        } else {
257            Vec::new()
258        };
259
260        let pair = pairs.next().unwrap();
261        let kind = match pair.as_rule() {
262            Rule::TriggerDecl => OutputKind::Trigger,
263            Rule::NamedOutputDecl => {
264                let next_pair = &pair
265                    .into_inner()
266                    .next()
267                    .expect("mismatch between grammar and AST");
268                let pos = next_pair.as_span().end();
269                pacing_annotation_default_span = Span::Direct {
270                    start: pos,
271                    end: pos,
272                };
273                OutputKind::NamedOutput(self.parse_ident(next_pair))
274            }
275            _ => panic!("mismatch between grammar and AST"),
276        };
277
278        let mut error = RtLolaError::new();
279        let mut eval = Vec::new();
280        let mut spawn: Option<SpawnSpec> = None;
281        let mut close: Option<CloseSpec> = None;
282
283        let mut pair = pairs.peek().expect("mismatch between grammar and AST");
284        let params = if let Rule::ParamList = pair.as_rule() {
285            let local_pair = pairs.next().expect("mismatch between grammar and AST");
286            let pos = local_pair.as_span().end();
287            pacing_annotation_default_span = Span::Direct {
288                start: pos,
289                end: pos,
290            };
291            self.parse_parameter_list(local_pair.into_inner())
292        } else {
293            Vec::new()
294        };
295
296        pair = pairs.peek().expect("mismatch between grammar and AST");
297        let annotated_type = if let Rule::Type = pair.as_rule() {
298            let local_pair = pairs.next().expect("mismatch between grammar and AST");
299            let pos = local_pair.as_span().end();
300            pacing_annotation_default_span = Span::Direct {
301                start: pos,
302                end: pos,
303            };
304            let ty = self.parse_type(local_pair);
305            Some(ty)
306        } else {
307            None
308        };
309
310        pairs.for_each(|pair| match pair.as_rule() {
311            Rule::SpawnDecl => {
312                if let Some(old_spawn) = &spawn {
313                    let err = Diagnostic::error("Multiple Spawn clauses found")
314                        .add_span_with_label(old_spawn.span, Some("first Spawn here"), true)
315                        .add_span_with_label(
316                            pair.as_span().into(),
317                            Some("Second Spawn clause found here"),
318                            false,
319                        );
320                    error.add(err);
321                }
322                let spawn_spec = self.parse_spawn_spec(pair);
323                spawn = spawn_spec.map_or_else(
324                    |e| {
325                        error.join(e);
326                        None
327                    },
328                    Some,
329                )
330            }
331            Rule::CloseDecl => {
332                if let Some(old_close) = &close {
333                    let err = Diagnostic::error("Multiple Close clauses found")
334                        .add_span_with_label(old_close.span, Some("first Close here"), true)
335                        .add_span_with_label(
336                            pair.as_span().into(),
337                            Some("Second Close clause found here"),
338                            false,
339                        );
340                    error.add(err);
341                }
342                let close_spec = self.parse_close_spec(pair);
343                close = close_spec.map_or_else(
344                    |e| {
345                        error.join(e);
346                        None
347                    },
348                    Some,
349                );
350            }
351            Rule::EvalDecl => {
352                let eval_spec = self.parse_eval_spec(pair);
353                match eval_spec {
354                    Ok(eval_spec) => eval.push(eval_spec),
355                    Err(e) => error.join(e),
356                }
357            }
358            Rule::SimpleEvalDecl => {
359                let eval_spec =
360                    self.parse_eval_spec_simple(pair.clone(), pacing_annotation_default_span);
361                match eval_spec {
362                    Ok(eval_spec) => {
363                        debug_assert!(eval.is_empty(), "must be empty due to grammar restrictions");
364                        eval.push(eval_spec)
365                    }
366                    Err(e) => error.join(e),
367                }
368            }
369            _ => {
370                unreachable!("mismatch between grammar and AST")
371            }
372        });
373
374        let eval = eval
375            .into_iter()
376            .map(|mut eval| {
377                // if the output is a trigger, a missing eval-with clause is replaced with an empty trigger message
378                // if the output is a named output, a missing eval-with clause is replaced by an empty tuple
379                eval.eval_expression.get_or_insert_with(|| {
380                    let kind = match kind {
381                        OutputKind::Trigger => ExpressionKind::Lit(Literal {
382                            kind: LitKind::Str("".into()),
383                            id: self.spec.next_id(),
384                            span: Span::Unknown,
385                        }),
386                        OutputKind::NamedOutput(_) => ExpressionKind::Tuple(vec![]),
387                    };
388                    Expression {
389                        kind,
390                        id: self.spec.next_id(),
391                        span: Span::Unknown,
392                    }
393                });
394                eval
395            })
396            .collect();
397
398        Result::from(error)?;
399        Ok(Output {
400            id: self.spec.next_id(),
401            kind,
402            annotated_type,
403            params: params.into_iter().map(Rc::new).collect(),
404            spawn,
405            eval,
406            close,
407            tags,
408            span,
409        })
410    }
411
412    fn parse_parameter_list(&self, param_list: Pairs<'_, Rule>) -> Vec<Parameter> {
413        let mut params = Vec::new();
414        for (ix, param_decl) in param_list.enumerate() {
415            assert_eq!(Rule::ParameterDecl, param_decl.as_rule());
416            let span = param_decl.as_span().into();
417            let mut decl = param_decl.into_inner();
418            let name = self.parse_ident(&decl.next().expect("mismatch between grammar and AST"));
419            let ty = if let Some(type_pair) = decl.next() {
420                assert_eq!(Rule::Type, type_pair.as_rule());
421                Some(self.parse_type(type_pair))
422            } else {
423                None
424            };
425            params.push(Parameter {
426                name,
427                ty,
428                param_idx: ix,
429                id: self.spec.next_id(),
430                span,
431            });
432        }
433        params
434    }
435
436    fn parse_spawn_spec(&self, spawn_pair: Pair<'_, Rule>) -> Result<SpawnSpec, RtLolaError> {
437        let span_inv: Span = spawn_pair.as_span().into();
438
439        let mut spawn_children = spawn_pair.into_inner().peekable();
440        let next_pair = spawn_children.peek();
441
442        let mut error = RtLolaError::new();
443
444        let annotated_pacing = if let Some(pair) = next_pair {
445            if let Rule::ActivationCondition = pair.as_rule() {
446                let expr = self.parse_activation_condition(spawn_children.next().unwrap());
447                expr.map_or_else(
448                    |e| {
449                        error.join(e);
450                        None
451                    },
452                    Some,
453                )
454            } else {
455                None
456            }
457        } else {
458            None
459        }
460        .unwrap_or_else(|| {
461            let pos = span_inv.get_bounds().0 + "spawn ".len();
462            AnnotatedPacingType::NotAnnotated(Span::Direct {
463                start: pos,
464                end: pos,
465            })
466        });
467
468        let mut condition: Option<Expression> = None;
469        let mut expression: Option<Expression> = None;
470        for pair in spawn_children {
471            match pair.as_rule() {
472                Rule::SpawnWhen => {
473                    if let Some(old_condition) = &condition {
474                        let err = Diagnostic::error("Multiple Spawn conditions found")
475                            .add_span_with_label(
476                                old_condition.span,
477                                Some("first spawn condition here"),
478                                true,
479                            )
480                            .add_span_with_label(
481                                pair.as_span().into(),
482                                Some("Second condition found here"),
483                                false,
484                            );
485                        error.add(err);
486                    }
487                    let condition_pair = pair
488                        .into_inner()
489                        .next()
490                        .expect("mismatch between grammar and AST");
491                    let condition_exp = self.build_expression_ast(condition_pair.into_inner());
492                    condition = condition_exp.map_or_else(
493                        |e| {
494                            error.join(e);
495                            None
496                        },
497                        Some,
498                    )
499                }
500                Rule::SpawnWith => {
501                    if let Some(old_expression) = &expression {
502                        let err = Diagnostic::error("Multiple Spawn expressions found")
503                            .add_span_with_label(
504                                old_expression.span,
505                                Some("first spawn expression here"),
506                                true,
507                            )
508                            .add_span_with_label(
509                                pair.as_span().into(),
510                                Some("Second expression found here"),
511                                false,
512                            );
513                        error.add(err);
514                    }
515                    let expression_pair = pair
516                        .into_inner()
517                        .next()
518                        .expect("mismatch between grammar and AST");
519                    let spawn_expr = self.build_expression_ast(expression_pair.into_inner());
520                    expression = spawn_expr.map_or_else(
521                        |e| {
522                            error.join(e);
523                            None
524                        },
525                        Some,
526                    )
527                }
528                _ => unreachable!("mismatch between grammar and AST"),
529            }
530        }
531
532        if expression.is_none()
533            && condition.is_none()
534            && matches!(annotated_pacing, AnnotatedPacingType::NotAnnotated(_))
535        {
536            error.add(
537                Diagnostic::error("Spawn clause needs a condition, expression or pacing")
538                    .add_span_with_label(span_inv, Some("found spawn here"), true),
539            );
540        }
541
542        Result::from(error)?;
543
544        Ok(SpawnSpec {
545            expression,
546            annotated_pacing,
547            condition,
548            id: self.spec.next_id(),
549            span: span_inv,
550        })
551    }
552
553    fn parse_eval_spec_simple(
554        &self,
555        ext_pair: Pair<'_, Rule>,
556        default_annotation_span: Span,
557    ) -> Result<EvalSpec, RtLolaError> {
558        let span_ext: Span = ext_pair.as_span().into();
559
560        let mut children = ext_pair.into_inner();
561        let mut next_pair = children.next();
562
563        let annotated_pacing =
564            if let Some(Rule::ActivationCondition) = next_pair.as_ref().map(|p| p.as_rule()) {
565                let annotated_pacing = self.parse_activation_condition(next_pair.unwrap())?;
566                next_pair = children.next();
567                annotated_pacing
568            } else {
569                AnnotatedPacingType::NotAnnotated(default_annotation_span)
570            };
571
572        let exp_res = self.build_expression_ast(
573            next_pair
574                .expect("Mismatch between grammar and AST")
575                .into_inner(),
576        )?;
577
578        Ok(EvalSpec {
579            annotated_pacing,
580            condition: None,
581            eval_expression: Some(exp_res),
582            id: self.spec.next_id(),
583            span: span_ext,
584        })
585    }
586
587    fn parse_eval_spec(&self, ext_pair: Pair<'_, Rule>) -> Result<EvalSpec, RtLolaError> {
588        let span_ext: Span = ext_pair.as_span().into();
589
590        let mut children = ext_pair.into_inner().peekable();
591        let next_pair = children.peek();
592
593        let mut error = RtLolaError::new();
594
595        let annotated_pacing =
596            if let Some(Rule::ActivationCondition) = next_pair.map(|p| p.as_rule()) {
597                self.parse_activation_condition(children.next().unwrap())?
598            } else {
599                let pos = span_ext.get_bounds().0 + "eval ".len();
600                AnnotatedPacingType::NotAnnotated(Span::Direct {
601                    start: pos,
602                    end: pos,
603                })
604            };
605
606        let mut condition: Option<Expression> = None;
607        let mut eval_expr: Option<Expression> = None;
608        for pair in children {
609            match pair.as_rule() {
610                Rule::EvalWhen => {
611                    if let Some(old_cond) = &condition {
612                        let err = Diagnostic::error("Multiple evaluation conditions found")
613                            .add_span_with_label(old_cond.span, Some("first condition here"), true)
614                            .add_span_with_label(
615                                pair.as_span().into(),
616                                Some("Second condition found here"),
617                                false,
618                            );
619                        error.add(err);
620                    }
621                    let condition_pair = pair
622                        .into_inner()
623                        .next()
624                        .expect("mismatch between grammar and AST");
625                    let cond_expr = self.build_expression_ast(condition_pair.into_inner());
626                    condition = cond_expr.map_or_else(
627                        |e| {
628                            error.join(e);
629                            None
630                        },
631                        Some,
632                    )
633                }
634                Rule::EvalWith => {
635                    if let Some(old_eval) = &eval_expr {
636                        let err = Diagnostic::error("Multiple eval expressions found")
637                            .add_span_with_label(
638                                old_eval.span,
639                                Some("first eval expression here"),
640                                true,
641                            )
642                            .add_span_with_label(
643                                pair.as_span().into(),
644                                Some("Second expression found here"),
645                                false,
646                            );
647                        error.add(err);
648                    }
649                    let expression_pair = pair
650                        .into_inner()
651                        .next()
652                        .expect("mismatch between grammar and AST");
653                    let target_exp = self.build_expression_ast(expression_pair.into_inner());
654                    eval_expr = target_exp.map_or_else(
655                        |e| {
656                            error.join(e);
657                            None
658                        },
659                        Some,
660                    )
661                }
662                _ => unreachable!("mismatch between grammar and AST"),
663            }
664        }
665
666        if eval_expr.is_none()
667            && condition.is_none()
668            && matches!(annotated_pacing, AnnotatedPacingType::NotAnnotated(_))
669        {
670            error.add(
671                Diagnostic::error("Eval clause needs either expression or condition")
672                    .add_span_with_label(span_ext, Some("found eval clause here"), true),
673            );
674        }
675
676        Result::from(error)?;
677
678        Ok(EvalSpec {
679            annotated_pacing,
680            condition,
681            eval_expression: eval_expr,
682            id: self.spec.next_id(),
683            span: span_ext,
684        })
685    }
686
687    fn parse_close_spec(&self, close_pair: Pair<'_, Rule>) -> Result<CloseSpec, RtLolaError> {
688        let span_close: Span = close_pair.as_span().into();
689
690        let mut children = close_pair.into_inner();
691
692        let mut next_pair = children.next();
693
694        let annotated_pacing =
695            if let Some(Rule::ActivationCondition) = next_pair.as_ref().map(|p| p.as_rule()) {
696                let expr = self.parse_activation_condition(next_pair.unwrap())?;
697                next_pair = children.next();
698                expr
699            } else {
700                let pos = span_close.get_bounds().0 + "close ".len();
701                AnnotatedPacingType::NotAnnotated(Span::Direct {
702                    start: pos,
703                    end: pos,
704                })
705            };
706
707        let condition = if let Some(pair) = next_pair {
708            assert_eq!(pair.as_rule(), Rule::Expr);
709            self.build_expression_ast(pair.into_inner())?
710        } else {
711            Expression {
712                kind: ExpressionKind::Lit(Literal::new_bool(
713                    self.spec.next_id(),
714                    true,
715                    Span::Unknown,
716                )),
717                id: self.spec.next_id(),
718                span: Span::Unknown,
719            }
720        };
721
722        Ok(CloseSpec {
723            condition,
724            annotated_pacing,
725            id: self.spec.next_id(),
726            span: span_close,
727        })
728    }
729
730    /**
731     * Transforms a `Rule::Trigger` into `Trigger` AST node.
732     * Panics if input is not `Rule::Trigger`.
733     * The output rule consists of the following tokens:
734     * - (`Rule::TagLists`)?
735     * - (`Rule::ActivationCondition`)?
736     * - `Rule::Expr`
737     * - (`Rule::StringLiteral`)?
738     */
739    fn parse_trigger(&self, pair: Pair<'_, Rule>) -> Result<Output, RtLolaError> {
740        assert_eq!(pair.as_rule(), Rule::SimpleTrigger);
741        let span: Span = pair.as_span().into();
742        let mut pairs = pair.into_inner();
743
744        let mut pair = pairs.next().expect("mismatch between grammar and AST");
745
746        let tags = if let Rule::TagLists = pair.as_rule() {
747            let tags = self.parse_tag_lists(pair);
748            pair = pairs.next().expect("mismatch between grammar and AST");
749            tags
750        } else {
751            Vec::new()
752        };
753
754        let trigger_keyword = pair;
755        pair = pairs.next().expect("mistmatch between grammar and AST");
756
757        // Parse the `@ [Expr]` part of output declaration
758        let annotated_pacing_type = if let Rule::ActivationCondition = pair.as_rule() {
759            let expr = self.parse_activation_condition(pair)?;
760            pair = pairs.next().expect("mismatch between grammar and AST");
761            expr
762        } else {
763            let pos = trigger_keyword.as_span().end();
764            AnnotatedPacingType::NotAnnotated(Span::Direct {
765                start: pos,
766                end: pos,
767            })
768        };
769
770        let expression = self.build_expression_ast(pair.into_inner())?;
771
772        let (msg, msg_span) = pairs
773            .next()
774            .map(|pair| {
775                assert_eq!(pair.as_rule(), Rule::String);
776                (pair.as_str().to_owned(), pair.as_span().into())
777            })
778            .unwrap_or(("".into(), Span::Unknown));
779
780        let msg_expr = Expression {
781            kind: ExpressionKind::Lit(Literal::new_str(self.spec.next_id(), &msg, span)),
782            id: self.spec.next_id(),
783            span: msg_span,
784        };
785
786        Ok(Output {
787            kind: OutputKind::Trigger,
788            annotated_type: None,
789            params: Vec::new(),
790            spawn: None,
791            eval: vec![EvalSpec {
792                annotated_pacing: annotated_pacing_type,
793                condition: Some(expression),
794                eval_expression: Some(msg_expr),
795                id: self.spec.next_id(),
796                span,
797            }],
798            close: None,
799            tags,
800            id: self.spec.next_id(),
801            span,
802        })
803    }
804
805    fn parse_activation_condition(
806        &self,
807        pair: Pair<'_, Rule>,
808    ) -> Result<AnnotatedPacingType, RtLolaError> {
809        assert_eq!(pair.as_rule(), Rule::ActivationCondition);
810        let inner = pair.into_inner().next().unwrap();
811        match inner.as_rule() {
812            Rule::GlobalActivationCondition => {
813                let expr = self.parse_ac_expression(inner.into_inner().next().unwrap())?;
814                Ok(AnnotatedPacingType::Global(expr))
815            }
816            Rule::LocalActivationCondition => {
817                let expr = self.parse_ac_expression(inner.into_inner().next().unwrap())?;
818                Ok(AnnotatedPacingType::Local(expr))
819            }
820            Rule::AcExpr => {
821                let expr = self.parse_ac_expression(inner)?;
822                Ok(AnnotatedPacingType::Unspecified(expr))
823            }
824            _ => unreachable!("mismatch between grammar and AST"),
825        }
826    }
827
828    fn parse_ac_expression(&self, pair: Pair<'_, Rule>) -> Result<Expression, RtLolaError> {
829        assert_eq!(pair.as_rule(), Rule::AcExpr);
830        let inner = pair.into_inner().next().unwrap();
831        let span: Span = inner.as_span().into();
832        match inner.as_rule() {
833            Rule::NumberLiteral => Ok(Expression::new(
834                self.spec.next_id(),
835                ExpressionKind::Lit(self.parse_number_literal(inner)),
836                span,
837            )),
838            Rule::PositiveBooleanExpr => self.parse_positive_boolean_expr(inner.into_inner()),
839            _ => unreachable!(),
840        }
841    }
842
843    fn parse_positive_boolean_expr(&self, pairs: Pairs<Rule>) -> Result<Expression, RtLolaError> {
844        PRATT_PARSER
845            .map_primary(|primary| match primary.as_rule() {
846                Rule::PositiveBooleanExpr => self.parse_positive_boolean_expr(primary.into_inner()),
847                Rule::Ident => Ok(Expression::new(
848                    self.spec.next_id(),
849                    ExpressionKind::Ident(self.parse_ident(&primary)),
850                    primary.as_span().into(),
851                )),
852                Rule::True => Ok(Expression::new(
853                    self.spec.next_id(),
854                    ExpressionKind::Lit(Literal::new_bool(
855                        self.spec.next_id(),
856                        true,
857                        primary.as_span().into(),
858                    )),
859                    primary.as_span().into(),
860                )),
861                _ => unreachable!(),
862            })
863            .map_infix(|lhs, op, rhs| {
864                let lhs = lhs?;
865                let rhs = rhs?;
866                let span = lhs.span.union(&rhs.span);
867                let op = match op.as_rule() {
868                    Rule::And => BinOp::And,
869                    Rule::BitAnd => BinOp::And,
870                    Rule::Or => BinOp::Or,
871                    Rule::BitOr => BinOp::Or,
872                    _ => unreachable!(),
873                };
874                Ok(Expression::new(
875                    self.spec.next_id(),
876                    ExpressionKind::Binary(op, Box::new(lhs), Box::new(rhs)),
877                    span,
878                ))
879            })
880            .parse(pairs)
881    }
882
883    /**
884     * Transforms a `Rule::Ident` into `Ident` AST node.
885     * Panics if input is not `Rule::Ident`.
886     */
887    fn parse_ident(&self, pair: &Pair<'_, Rule>) -> Ident {
888        assert_eq!(pair.as_rule(), Rule::Ident);
889        let name = pair.as_str();
890        let normalized_name = name.nfc().collect::<String>();
891        Ident::new(normalized_name, pair.as_span().into())
892    }
893
894    /**
895     * Transforms a `Rule::TypeDecl` into `TypeDeclaration` AST node.
896     * Panics if input is not `Rule::TypeDecl`.
897     */
898    fn parse_type_declaration(&self, pair: Pair<'_, Rule>) -> TypeDeclaration {
899        assert_eq!(pair.as_rule(), Rule::TypeDecl);
900        let span = pair.as_span().into();
901        let mut pairs = pair.into_inner();
902        let name = self.parse_ident(&pairs.next().expect("mismatch between grammar and AST"));
903        let mut fields = Vec::new();
904        while let Some(pair) = pairs.next() {
905            let field_name = pair.as_str().to_string();
906            let ty = self.parse_type(pairs.next().expect("mismatch between grammar and AST"));
907            fields.push(Box::new(TypeDeclField {
908                name: field_name,
909                ty,
910                id: self.spec.next_id(),
911                span: pair.as_span().into(),
912            }));
913        }
914
915        TypeDeclaration {
916            name: Some(name),
917            span,
918            id: self.spec.next_id(),
919            fields,
920        }
921    }
922
923    fn parse_tag_lists(&self, pair: Pair<'_, Rule>) -> Vec<Tag> {
924        assert_eq!(pair.as_rule(), Rule::TagLists);
925        pair.into_inner()
926            .flat_map(|tag_list| self.parse_tag_list(tag_list))
927            .collect()
928    }
929
930    fn parse_tag_list(&self, pair: Pair<'_, Rule>) -> Vec<Tag> {
931        assert!(matches!(
932            pair.as_rule(),
933            Rule::TagList | Rule::GlobalTagList
934        ));
935        pair.into_inner()
936            .map(|tag| {
937                let span = tag.as_span().into();
938                let mut pairs = tag.into_inner();
939                let key = pairs
940                    .next()
941                    .expect("mismatch between grammar ans AST")
942                    .as_str()
943                    .to_owned();
944                let value = pairs.next().map(|value| value.as_str().to_owned());
945                Tag { key, value, span }
946            })
947            .collect()
948    }
949
950    /**
951     * Transforms a `Rule::Type` into `Type` AST node.
952     * Panics if input is not `Rule::Type`.
953     */
954    fn parse_type(&self, pair: Pair<'_, Rule>) -> Type {
955        assert_eq!(pair.as_rule(), Rule::Type);
956        let span = pair.as_span();
957        let mut tuple = Vec::new();
958        for pair in pair.into_inner() {
959            match pair.as_rule() {
960                Rule::Ident => {
961                    return Type::new_simple(
962                        self.spec.next_id(),
963                        pair.as_str().to_string(),
964                        pair.as_span().into(),
965                    );
966                }
967                Rule::Type => tuple.push(self.parse_type(pair)),
968                Rule::Optional => {
969                    let span = pair.as_span();
970                    let inner = pair
971                        .into_inner()
972                        .next()
973                        .expect("mismatch between grammar and AST: first argument is a type");
974                    let inner_ty = Type::new_simple(
975                        self.spec.next_id(),
976                        inner.as_str().to_string(),
977                        inner.as_span().into(),
978                    );
979                    return Type::new_optional(self.spec.next_id(), inner_ty, span.into());
980                }
981                _ => unreachable!("{:?} is not a type, ensured by grammar", pair.as_rule()),
982            }
983        }
984        Type::new_tuple(self.spec.next_id(), tuple, span.into())
985    }
986
987    /**
988     * Transforms a `Rule::Literal` into `Literal` AST node.
989     * Panics if input is not `Rule::Literal`.
990     */
991    fn parse_literal(&self, pair: Pair<'_, Rule>) -> Literal {
992        assert!(matches!(
993            pair.as_rule(),
994            Rule::Literal | Rule::ConstantLiteral
995        ));
996        let inner = pair
997            .into_inner()
998            .next()
999            .expect("Rule::Literal has exactly one child");
1000        match inner.as_rule() {
1001            Rule::String => {
1002                let str_rep = inner.as_str();
1003                Literal::new_str(self.spec.next_id(), str_rep, inner.as_span().into())
1004            }
1005            Rule::RawString => {
1006                let str_rep = inner.as_str();
1007                Literal::new_raw_str(self.spec.next_id(), str_rep, inner.as_span().into())
1008            }
1009            Rule::TupleLiteral => {
1010                let span: Span = inner.as_span().into();
1011                let elements: Vec<Literal> =
1012                    inner.into_inner().map(|p| self.parse_literal(p)).collect();
1013                Literal::new_tuple(self.spec.next_id(), elements, span)
1014            }
1015            Rule::NumberLiteral => self.parse_number_literal(inner),
1016            Rule::True => Literal::new_bool(self.spec.next_id(), true, inner.as_span().into()),
1017            Rule::False => Literal::new_bool(self.spec.next_id(), false, inner.as_span().into()),
1018            _ => unreachable!(),
1019        }
1020    }
1021
1022    fn parse_number_literal(&self, pair: Pair<'_, Rule>) -> Literal {
1023        assert_eq!(pair.as_rule(), Rule::NumberLiteral);
1024        let span = pair.as_span();
1025        let mut pairs = pair.into_inner();
1026        let value = pairs.next().expect("Mismatch between AST and grammar");
1027
1028        let str_rep: &str = value.as_str();
1029        let unit = pairs.next().map(|unit| unit.as_str().to_string());
1030
1031        Literal::new_numeric(self.spec.next_id(), str_rep, unit, span.into())
1032    }
1033
1034    #[allow(clippy::vec_box)]
1035    fn parse_vec_of_expressions(
1036        &self,
1037        pairs: Pairs<'_, Rule>,
1038    ) -> Result<Vec<Expression>, RtLolaError> {
1039        type ExprRes = Result<Expression, RtLolaError>;
1040        let (exprs, errs): (Vec<ExprRes>, Vec<ExprRes>) = pairs
1041            .map(|expr| self.build_expression_ast(expr.into_inner()))
1042            .partition(Result::is_ok);
1043        Result::from(
1044            errs.into_iter()
1045                .flat_map(Result::unwrap_err)
1046                .collect::<RtLolaError>(),
1047        )?;
1048        Ok(exprs.into_iter().map(Result::unwrap).collect())
1049    }
1050
1051    fn parse_vec_of_types(&self, pairs: Pairs<'_, Rule>) -> Vec<Type> {
1052        pairs.map(|p| self.parse_type(p)).collect()
1053    }
1054
1055    fn build_function_expression(
1056        &self,
1057        pair: Pair<'_, Rule>,
1058        span: Span,
1059    ) -> Result<Expression, RtLolaError> {
1060        let mut children = pair.into_inner();
1061        let fun_name = self.parse_ident(&children.next().unwrap());
1062        let mut next = children.next().expect("Mismatch between AST and parser");
1063        let type_params = match next.as_rule() {
1064            Rule::GenericParam => {
1065                let params = self.parse_vec_of_types(next.into_inner());
1066                next = children.next().expect("Mismatch between AST and parser");
1067                params
1068            }
1069            Rule::FunctionArgs => Vec::new(),
1070            _ => unreachable!(),
1071        };
1072        assert_eq!(next.as_rule(), Rule::FunctionArgs);
1073        let mut args = Vec::new();
1074        let mut error = RtLolaError::new();
1075        let mut arg_names = Vec::new();
1076        for pair in next.into_inner() {
1077            assert_eq!(pair.as_rule(), Rule::FunctionArg);
1078            let mut pairs = pair.into_inner();
1079            let mut pair = pairs.next().expect("Mismatch between AST and parser");
1080            if pair.as_rule() == Rule::Ident {
1081                // named argument
1082                arg_names.push(Some(self.parse_ident(&pair)));
1083                pair = pairs.next().expect("Mismatch between AST and parser");
1084            } else {
1085                arg_names.push(None);
1086            }
1087            match self.build_expression_ast(pair.into_inner()) {
1088                Ok(e) => args.push(e),
1089                Err(e) => error.join(e),
1090            }
1091        }
1092        Result::from(error)?;
1093        let name = FunctionName {
1094            name: fun_name,
1095            arg_names,
1096        };
1097        Ok(Expression::new(
1098            self.spec.next_id(),
1099            ExpressionKind::Function(name, type_params, args),
1100            span,
1101        ))
1102    }
1103
1104    /**
1105     * Builds the Expr AST.
1106     */
1107    fn build_expression_ast(&self, pairs: Pairs<'_, Rule>) -> Result<Expression, RtLolaError> {
1108        PRATT_PARSER
1109            .map_primary(|primary| self.build_term_ast(primary))
1110            .map_infix(|lhs, op, rhs| {
1111
1112                // Reduce function combining `Expression`s to `Expression`s with the correct precs
1113                let (lhs, rhs) = RtLolaError::combine(lhs, rhs, |a, b| (a, b))?;
1114                let span = lhs.span.union(&rhs.span);
1115                let op = match op.as_rule() {
1116                    // Arithmetic
1117                    Rule::Add => BinOp::Add,
1118                    Rule::Subtract => BinOp::Sub,
1119                    Rule::Multiply => BinOp::Mul,
1120                    Rule::Divide => BinOp::Div,
1121                    Rule::Mod => BinOp::Rem,
1122                    Rule::Power => BinOp::Pow,
1123                    // Logical
1124                    Rule::And => BinOp::And,
1125                    Rule::Or => BinOp::Or,
1126                    Rule::Implies => BinOp::Implies,
1127                    // Comparison
1128                    Rule::LessThan => BinOp::Lt,
1129                    Rule::LessThanOrEqual => BinOp::Le,
1130                    Rule::MoreThan => BinOp::Gt,
1131                    Rule::MoreThanOrEqual => BinOp::Ge,
1132                    Rule::Equal => BinOp::Eq,
1133                    Rule::NotEqual => BinOp::Ne,
1134                    // Bitwise
1135                    Rule::BitAnd => BinOp::BitAnd,
1136                    Rule::BitOr => BinOp::BitOr,
1137                    Rule::BitXor => BinOp::BitXor,
1138                    Rule::ShiftLeft => BinOp::Shl,
1139                    Rule::ShiftRight => BinOp::Shr,
1140                    // bubble up the unary operator on the lhs (if it exists) to fix precedence
1141                    Rule::Dot => {
1142                        let (unop, binop_span, inner) = match lhs.kind {
1143                            ExpressionKind::Unary(unop, inner) => (Some(unop), inner.span.union(&rhs.span), inner),
1144                            _ => (None, span, Box::new(lhs)),
1145                        };
1146                        match rhs.kind {
1147                            // access to a tuple
1148                            ExpressionKind::Lit(l) => {
1149                                let ident = match l.kind {
1150                                    LitKind::Numeric(val, unit) => {
1151                                        assert!(unit.is_none());
1152                                        Ident::new(val, l.span)
1153                                    }
1154                                    _ => {
1155                                        return Err(Diagnostic::error(&format!("expected unsigned integer, found {l}")).add_span_with_label(rhs.span, Some("unexpected"), true).into());
1156                                    }
1157                                };
1158                                let binop_expr =
1159                                    Expression::new(self.spec.next_id(), ExpressionKind::Field(inner, ident), binop_span);
1160                                match unop {
1161                                    None => return Ok(binop_expr),
1162                                    Some(unop) => {
1163                                        return Ok(Expression::new(
1164                                            self.spec.next_id(),
1165                                            ExpressionKind::Unary(unop, Box::new(binop_expr)),
1166                                            span,
1167                                        ));
1168                                    }
1169                                }
1170                            }
1171                            ExpressionKind::Function(name, types, args) => {
1172                                // match for builtin function names and transform them into appropriate AST nodes
1173                                let signature = name.to_string();
1174                                let kind = match signature.as_str() {
1175                                    "defaults(to:)" => {
1176                                        assert_eq!(args.len(), 1);
1177                                        ExpressionKind::Default(inner, Box::new(args[0].clone()))
1178                                    }
1179                                    "offset(by:)" => {
1180                                        assert_eq!(args.len(), 1);
1181                                        let offset_expr = &args[0];
1182                                        let rhs_span = rhs.span;
1183                                        let offset = offset_expr.parse_offset().map_err(|reason| Diagnostic::error("failed to parse offset").add_span_with_label(rhs_span, Some(&reason), true))?;
1184
1185                                        ExpressionKind::Offset(inner, offset)
1186                                    }
1187                                    "hold()" => {
1188                                        assert_eq!(args.len(), 0);
1189                                        ExpressionKind::StreamAccess(inner, StreamAccessKind::Hold)
1190                                    }
1191                                    "hold(or:)" => {
1192                                        assert_eq!(args.len(), 1);
1193                                        let lhs = Expression::new(
1194                                            self.spec.next_id(),
1195                                            ExpressionKind::StreamAccess(inner, StreamAccessKind::Hold),
1196                                            span,
1197                                        );
1198                                        ExpressionKind::Default(Box::new(lhs), Box::new(args[0].clone()))
1199                                    }
1200                                    "get()" => {
1201                                        assert_eq!(args.len(), 0);
1202                                        ExpressionKind::StreamAccess(inner, StreamAccessKind::Get)
1203                                    }
1204                                    "get(or:)" => {
1205                                        assert_eq!(args.len(), 1);
1206                                        let lhs = Expression::new(
1207                                            self.spec.next_id(),
1208                                            ExpressionKind::StreamAccess(inner, StreamAccessKind::Get),
1209                                            span,
1210                                        );
1211                                        ExpressionKind::Default(Box::new(lhs), Box::new(args[0].clone()))
1212                                    }
1213                                    "is_fresh()" => {
1214                                        assert_eq!(args.len(), 0);
1215                                        ExpressionKind::StreamAccess(inner, StreamAccessKind::Fresh)
1216                                    }
1217                                    "aggregate(over_discrete:using:)" | "aggregate(over_exactly_discrete:using:)" | "aggregate(over:using:)" | "aggregate(over_exactly:using:)" | "aggregate(over_instances:using:)" => {
1218                                        assert_eq!(args.len(), 2);
1219                                        let window_op = match &args[1].kind {
1220                                            ExpressionKind::Ident(i) => match i.name.as_str() {
1221                                                "Σ" | "sum" => WindowOperation::Sum,
1222                                                "#" | "count" => WindowOperation::Count,
1223                                                //"Π" | "prod" | "product" => WindowOperation::Product,
1224                                                "∫" | "integral" => WindowOperation::Integral,
1225                                                "avg" | "average" => WindowOperation::Average,
1226                                                "min" => WindowOperation::Min,
1227                                                "max" => WindowOperation::Max,
1228                                                "∃" | "disjunction" | "∨" | "exists" => {
1229                                                    WindowOperation::Disjunction
1230                                                }
1231                                                "∀" | "conjunction" | "∧" | "forall" => {
1232                                                    WindowOperation::Conjunction
1233                                                }
1234                                                "last" => WindowOperation::Last,
1235                                                "variance" | "var" | "σ²" => WindowOperation::Variance,
1236                                                "covariance" | "cov" => WindowOperation::Covariance,
1237                                                "standard_deviation" | "sd" | "σ" => WindowOperation::StandardDeviation,
1238                                                "median" | "med" | "µ" => WindowOperation::NthPercentile(50),
1239                                                _ if i.name.as_str().starts_with("pctl") &&
1240                                                    i.name.as_str().chars().skip("pctl".len()).all(|c| c.is_numeric()) => {
1241                                                    let n_string = i.name.as_str().to_string();
1242                                                    let n_string: String = n_string.chars().skip("pctl".len()).collect();
1243                                                    let percentile: usize = n_string.parse::<usize>().map_err(|_|
1244                                                        RtLolaError::from(Diagnostic::error(&format!("unknown aggregation function {}, invalid number-percentile suffix {}", i.name, n_string)).add_span_with_label(i.span, Some("available: count, min, max, sum, average, exists, forall, integral, last, variance, covariance, standard_deviation, median, pctlX with 0 ≤ X ≤ 100 (e.g. pctl25)"), true))
1245                                                    )?;
1246                                                    if percentile > 100 {
1247                                                        return Err(Diagnostic::error(&format!("unknown aggregation function {}, invalid percentile suffix", i.name)).add_span_with_label(i.span, Some("available: count, min, max, sum, average, exists, forall, integral, last, variance, covariance, standard_deviation, median, pctlX with 0 ≤ X ≤ 100 (e.g. pctl25)"), true).into());
1248                                                    }
1249                                                    WindowOperation::NthPercentile(percentile as u8)
1250                                                }
1251                                                "true_ratio" | "trueRatio" | "ratio" => WindowOperation::TrueRatio,
1252                                                fun => {
1253                                                    return Err(Diagnostic::error(&format!("unknown aggregation function {fun}")).add_span_with_label(i.span, Some("available: count, min, max, sum, average, exists, forall, integral, last, variance, covariance, standard_deviation, median, pctlX with 0 ≤ X ≤ 100 (e.g. pctl25)"), true).into());
1254                                                }
1255                                            },
1256                                            _ => {
1257                                                return Err(Diagnostic::error("expected aggregation function").add_span_with_label(args[1].span, Some("available: count, min, max, sum, average, exists, forall, integral, last, variance, covariance, standard_deviation, median, pctlX with 0 ≤ X ≤ 100 (e.g. pctl25), ratio"), true).into());
1258                                            }
1259                                        };
1260                                        if signature.contains("instances") {
1261                                            let instances = match &args[0].kind {
1262                                                ExpressionKind::Ident(i) => match i.name.as_str() {
1263                                                    "fresh" | "Fresh" => InstanceSelection::Fresh,
1264                                                    "all" | "All" => InstanceSelection::All,
1265                                                    sel => {
1266                                                        return Err(Diagnostic::error(&format!("unknown instance selection {sel}")).add_span_with_label(i.span, Some("available: fresh, all, fresh(where: ...), all(where: ...)"), true).into());
1267                                                    }
1268                                                }
1269                                                ExpressionKind::Function(name, _ty, expr) => {
1270                                                    let signature = name.to_string();
1271                                                    if expr.len() != 1 {
1272                                                        return Err(Diagnostic::error("filtered instance selection can only have one argument").add_span_with_label(args[0].span, None, true).into());
1273                                                    }
1274                                                    let Expression { kind: ExpressionKind::Lambda(lambda), id:_ , span:_  } = expr[0].clone() else {
1275                                                        return Err(Diagnostic::error("expect lambda expression in filtered instance aggregation").add_span_with_label(expr[0].span, None, true).into());
1276                                                    };
1277                                                    match signature.as_str() {
1278                                                        "fresh(where:)" | "Fresh(where:)" => InstanceSelection::FilteredFresh(lambda),
1279                                                        "all(where:)" | "All(where:)" => InstanceSelection::FilteredAll (lambda),
1280                                                        sel => {
1281                                                            return Err(Diagnostic::error(&format!("unknown instance selection {sel}")).add_span_with_label(args[0].span, Some("available: fresh, all, fresh(where: ...), all(where: ...)"), true).into());
1282                                                        }
1283                                                    }
1284                                                }
1285                                                _ => {
1286                                                    return Err(Diagnostic::error("expected instance selection").add_span_with_label(args[0].span, Some("available: fresh, all"), true).into());
1287                                                }
1288                                            };
1289                                            let aggregation = window_op.try_into().map_err(|reason| Diagnostic::error(&format!("Operation not supported: {reason}")).add_span_with_label(args[1].span, Some("available: count, min, max, sum, average, exists, forall, variance, covariance, standard_deviation, median, pctlX with 0 ≤ X ≤ 100 (e.g. pctl25)"), true))?;
1290                                            ExpressionKind::InstanceAggregation { expr: inner, selection: instances, aggregation }
1291                                        } else if signature.contains("discrete") {
1292                                            if window_op == WindowOperation::Last {
1293                                                // Todo: This should be a warning
1294                                                // return Err(Diagnostic::error("discrete window operation: last has same semantics as .offset(by:-1) and is more expensive").add_span_with_label(args[1].span.clone(), Some("don't use last for discrete windows"), true).into());
1295                                            }
1296                                            ExpressionKind::DiscreteWindowAggregation {
1297                                                expr: inner,
1298                                                duration: Box::new(args[0].clone()),
1299                                                wait: signature.contains("over_exactly"),
1300                                                aggregation: window_op,
1301                                            }
1302                                        } else {
1303                                            ExpressionKind::SlidingWindowAggregation {
1304                                                expr: inner,
1305                                                duration: Box::new(args[0].clone()),
1306                                                wait: signature.contains("over_exactly"),
1307                                                aggregation: window_op,
1308                                            }
1309                                        }
1310                                    }
1311                                    _ => ExpressionKind::Method(inner, name, types, args),
1312                                };
1313                                let binop_expr = Expression::new(self.spec.next_id(), kind, binop_span);
1314                                match unop {
1315                                    None => return Ok(binop_expr),
1316                                    Some(unop) => {
1317                                        return Ok(Expression::new(
1318                                            self.spec.next_id(),
1319                                            ExpressionKind::Unary(unop, Box::new(binop_expr)),
1320                                            span,
1321                                        ));
1322                                    }
1323                                }
1324                            }
1325                            _ => {
1326                                return Err(Diagnostic::error(&format!("expected method call or tuple access, found {rhs}")).add_span_with_label(rhs.span, Some("unexpected"), true).into());
1327                            }
1328                        }
1329                    }
1330                    Rule::OpeningBracket => {
1331                        let rhs_span = rhs.span;
1332                        let offset = rhs.parse_offset().map_err(|reason| Diagnostic::error("failed to parse offset expression").add_span_with_label(rhs_span, Some(&reason), true))?;
1333                        match lhs.kind {
1334                            ExpressionKind::Unary(unop, inner) => {
1335                                let inner_span = inner.span.union(&rhs.span);
1336                                let new_inner =
1337                                    Expression::new(self.spec.next_id(), ExpressionKind::Offset(inner, offset), inner_span);
1338                                return Ok(Expression::new(
1339                                    self.spec.next_id(),
1340                                    ExpressionKind::Unary(unop, Box::new(new_inner)),
1341                                    span,
1342                                ));
1343                            }
1344                            _ => {
1345                                return Ok(Expression::new(
1346                                    self.spec.next_id(),
1347                                    ExpressionKind::Offset(lhs.into(), offset),
1348                                    span,
1349                                ));
1350                            }
1351                        }
1352                    }
1353                    _ => unreachable!(),
1354                };
1355                Ok(Expression::new(self.spec.next_id(), ExpressionKind::Binary(op, Box::new(lhs), Box::new(rhs)), span))
1356            }).parse(pairs)
1357    }
1358
1359    fn build_term_ast(&self, pair: Pair<'_, Rule>) -> Result<Expression, RtLolaError> {
1360        let span = pair.as_span();
1361        match pair.as_rule() {
1362            // Map function from `Pair` to AST data structure `Expression`
1363            Rule::Literal => Ok(Expression::new(
1364                self.spec.next_id(),
1365                ExpressionKind::Lit(self.parse_literal(pair)),
1366                span.into(),
1367            )),
1368            Rule::Ident => Ok(Expression::new(
1369                self.spec.next_id(),
1370                ExpressionKind::Ident(self.parse_ident(&pair)),
1371                span.into(),
1372            )),
1373            Rule::ParenthesizedExpression => {
1374                let mut inner = pair.into_inner();
1375                let opp = inner.next().expect(
1376                    "Rule::ParenthesizedExpression has a token for the (potentialy missing) opening parenthesis",
1377                );
1378
1379                let inner_expression = inner.next().expect(
1380                    "Rule::ParenthesizedExpression has a token for the contained expression",
1381                );
1382
1383                let closing = inner.next().expect(
1384                    "Rule::ParenthesizedExpression has a token for the (potentialy missing) closing parenthesis",
1385                );
1386                if let Rule::MissingClosingParenthesis = closing.as_rule() {
1387                    return Err(Diagnostic::error(
1388                        "The expression is missing a closing parenthesis.",
1389                    )
1390                    .add_span_with_label(
1391                        opp.as_span().into(),
1392                        Some("found opening parenthesis here"),
1393                        false,
1394                    )
1395                    .add_span_with_label(
1396                        closing.as_span().into(),
1397                        Some("expected closing parenthesis here"),
1398                        true,
1399                    )
1400                    .into());
1401                };
1402
1403                Ok(Expression::new(
1404                    self.spec.next_id(),
1405                    ExpressionKind::ParenthesizedExpression(Box::new(
1406                        self.build_expression_ast(inner_expression.into_inner())?,
1407                    )),
1408                    span.into(),
1409                ))
1410            }
1411            Rule::UnaryExpr => {
1412                // First child is the operator, second the operand.
1413                let mut children = pair.into_inner();
1414                let pest_operator = children
1415                    .next()
1416                    .expect("Unary expressions need to have an operator.");
1417                let operand = children
1418                    .next()
1419                    .expect("Unary expressions need to have an operand.");
1420                let operand = self.build_term_ast(operand)?;
1421                let operator = match pest_operator.as_rule() {
1422                    Rule::Add => return Ok(operand), // Discard unary plus because it is semantically null.
1423                    Rule::Subtract => UnOp::Neg,
1424                    Rule::Neg => UnOp::Not,
1425                    Rule::BitNot => UnOp::BitNot,
1426                    _ => unreachable!(),
1427                };
1428                Ok(Expression::new(
1429                    self.spec.next_id(),
1430                    ExpressionKind::Unary(operator, Box::new(operand)),
1431                    span.into(),
1432                ))
1433            }
1434            Rule::TernaryExpr => {
1435                let mut children = self.parse_vec_of_expressions(pair.into_inner())?;
1436                assert_eq!(
1437                    children.len(),
1438                    3,
1439                    "A ternary expression needs exactly three children."
1440                );
1441                Ok(Expression::new(
1442                    self.spec.next_id(),
1443                    ExpressionKind::Ite(
1444                        Box::new(children.remove(0)),
1445                        Box::new(children.remove(0)),
1446                        Box::new(children.remove(0)),
1447                    ),
1448                    span.into(),
1449                ))
1450            }
1451            Rule::Tuple => {
1452                let elements = self.parse_vec_of_expressions(pair.into_inner())?;
1453                assert!(
1454                    elements.len() != 1,
1455                    "Tuples may not have exactly one element."
1456                );
1457                Ok(Expression::new(
1458                    self.spec.next_id(),
1459                    ExpressionKind::Tuple(elements),
1460                    span.into(),
1461                ))
1462            }
1463            Rule::Expr => self.build_expression_ast(pair.into_inner()),
1464            Rule::FunctionExpr => self.build_function_expression(pair, span.into()),
1465            Rule::IntegerLiteral => {
1466                let span: Span = span.into();
1467                Ok(Expression::new(
1468                    self.spec.next_id(),
1469                    ExpressionKind::Lit(Literal::new_numeric(
1470                        self.spec.next_id(),
1471                        pair.as_str(),
1472                        None,
1473                        span,
1474                    )),
1475                    span,
1476                ))
1477            }
1478            Rule::MissingExpression => {
1479                let span = span.into();
1480                Ok(Expression::new(
1481                    self.spec.next_id(),
1482                    ExpressionKind::MissingExpression,
1483                    span,
1484                ))
1485            }
1486            Rule::LambdaExpr => {
1487                let span = span.into();
1488                let mut inner = pair.into_inner();
1489                let parameter_pair = inner.next().unwrap();
1490                let parameters = match parameter_pair.as_rule() {
1491                    Rule::ParamList => self.parse_parameter_list(parameter_pair.into_inner()),
1492                    Rule::Ident => vec![Parameter {
1493                        name: self.parse_ident(&parameter_pair),
1494                        ty: None,
1495                        param_idx: 0,
1496                        id: self.spec.next_id(),
1497                        span: parameter_pair.as_span().into(),
1498                    }],
1499                    _ => unreachable!("mismatch between AST and grammar"),
1500                };
1501                let expr_pair = inner.next().expect("mismatch between grammar and AST");
1502                assert_eq!(expr_pair.as_rule(), Rule::Expr);
1503                let expr = self.build_expression_ast(expr_pair.into_inner())?;
1504                let lambda = LambdaExpr {
1505                    parameters: parameters.into_iter().map(Rc::new).collect(),
1506                    expr: Box::new(expr),
1507                };
1508                Ok(Expression::new(
1509                    self.spec.next_id(),
1510                    ExpressionKind::Lambda(lambda),
1511                    span,
1512                ))
1513            }
1514            _ => unreachable!(
1515                "Unexpected rule when parsing expression ast: {:?}",
1516                pair.as_rule()
1517            ),
1518        }
1519    }
1520
1521    pub(crate) fn parse_rational(repr: &str) -> Result<Rational, String> {
1522        // precondition: repr is a valid floating point literal
1523        debug_assert!(repr.parse::<f64>().is_ok());
1524
1525        macro_rules! split_at {
1526            ($s:expr, $c:literal) => {{
1527                let (prefix, suffix) = $s.split_at($s.find($c).unwrap_or($s.len()));
1528                let suffix = if suffix.len() > 0 {
1529                    &suffix[1..]
1530                } else {
1531                    suffix
1532                };
1533                (prefix, suffix)
1534            }};
1535        }
1536
1537        let (int_digits, suffix) = split_at!(repr, '.'); // actually sign + int_digits
1538        let (dec_digits, exp_str) = split_at!(suffix, 'e');
1539
1540        let digits = int_digits.to_string() + dec_digits; // actually sign + digits
1541        let integer = match BigInt::from_str(digits.as_str()) {
1542            Ok(i) => i,
1543            Err(e) => return Err(format!("parsing rational '{repr}' failed: {e}")),
1544        };
1545        let mut r = BigRational::from(integer);
1546        if !dec_digits.is_empty() {
1547            // divide by 10 for each decimal place
1548            r /= BigInt::from_u8(10).unwrap().pow(dec_digits.len());
1549        }
1550
1551        if !exp_str.is_empty() {
1552            let exp = match BigInt::from_str(exp_str) {
1553                Ok(i) => i,
1554                Err(e) => return Err(format!("parsing rational '{repr}' failed: {e}")),
1555            };
1556            let exp = match exp.to_i16() {
1557                Some(i) => i,
1558                None => {
1559                    return Err(format!(
1560                        "parsing rational '{repr}' failed: e exponent {exp} does not fit into i16"
1561                    ));
1562                }
1563            };
1564            let factor = BigInt::from_u8(10).unwrap().pow(exp.unsigned_abs());
1565            if exp.is_negative() {
1566                r /= factor;
1567            } else {
1568                r *= factor;
1569            }
1570        }
1571
1572        let p = match (r.numer().to_i64(), r.denom().to_i64()) {
1573            (Some(n), Some(d)) => (n, d),
1574            _ => {
1575                return Err(format!(
1576                    "parsing rational failed: rational {r} does not fit into Rational64"
1577                ));
1578            }
1579        };
1580        Ok(Rational::from(p))
1581    }
1582}
1583
1584pub(crate) fn to_rtlola_error(err: pest::error::Error<Rule>) -> RtLolaError {
1585    use pest::error::*;
1586    let msg = match err.variant {
1587        ErrorVariant::ParsingError {
1588            positives: pos,
1589            negatives: neg,
1590        } => match (neg.is_empty(), pos.is_empty()) {
1591            (false, false) => {
1592                format!(
1593                    "unexpected {}; expected {}",
1594                    neg.iter()
1595                        .map(|r| format!("{r:?}"))
1596                        .collect::<Vec<String>>()
1597                        .join(", "),
1598                    pos.iter()
1599                        .map(|r| format!("{r:?}"))
1600                        .collect::<Vec<String>>()
1601                        .join(", ")
1602                )
1603            }
1604            (false, true) => {
1605                format!(
1606                    "unexpected {}",
1607                    neg.iter()
1608                        .map(|r| format!("{r:?}"))
1609                        .collect::<Vec<String>>()
1610                        .join(", ")
1611                )
1612            }
1613            (true, false) => {
1614                format!(
1615                    "expected {}",
1616                    pos.iter()
1617                        .map(|r| format!("{r:?}"))
1618                        .collect::<Vec<String>>()
1619                        .join(", ")
1620                )
1621            }
1622            (true, true) => "unknown parsing error".to_owned(),
1623        },
1624        ErrorVariant::CustomError { message: msg } => msg,
1625    };
1626    let span = match err.location {
1627        InputLocation::Pos(start) => Span::Direct { start, end: start },
1628        InputLocation::Span(s) => Span::Direct {
1629            start: s.0,
1630            end: s.1,
1631        },
1632    };
1633    Diagnostic::error(&msg)
1634        .add_span_with_label(span, Some("here"), true)
1635        .into()
1636}
1637
1638#[cfg(test)]
1639mod tests {
1640    use pest::{consumes_to, parses_to};
1641
1642    use super::*;
1643
1644    fn parse(spec: &str) -> RtLolaAst {
1645        super::super::parse(&ParserConfig::for_string(spec.into()))
1646            .unwrap_or_else(|e| panic!("{:?}", e))
1647    }
1648
1649    fn parse_without_desugar(spec: &str) -> RtLolaAst {
1650        let cfg = ParserConfig::for_string(spec.into());
1651        RtLolaParser::new(&cfg)
1652            .parse_spec()
1653            .unwrap_or_else(|e| panic!("{:?}", e))
1654    }
1655
1656    fn cmp_ast_spec(ast: &RtLolaAst, spec: &str) -> bool {
1657        // Todo: Make more robust, e.g. against changes in whitespace.
1658        assert_eq!(format!("{}", ast), spec);
1659        true
1660    }
1661
1662    #[test]
1663    fn parse_simple() {
1664        let _ = LolaParser::parse(
1665            Rule::Spec,
1666            "input in: Int\noutput out: Int := in\ntrigger in ≠ out",
1667        )
1668        .unwrap_or_else(|e| panic!("{}", e));
1669    }
1670
1671    #[test]
1672    fn parse_constant() {
1673        parses_to! {
1674            parser: LolaParser,
1675            input:  "constant five : Int := 5",
1676            rule:   Rule::ConstantStream,
1677            tokens: [
1678                ConstantStream(0, 24, [
1679                    Ident(9, 13, []),
1680                    Type(16, 19, [
1681                        Ident(16, 19, []),
1682                    ]),
1683                    ConstantLiteral(23, 24, [
1684                        NumberLiteral(23, 24, [
1685                            NumberLiteralValue(23, 24, [])
1686                        ]),
1687                    ]),
1688                ]),
1689            ]
1690        };
1691    }
1692
1693    #[test]
1694    fn parse_constant_ast() {
1695        let spec = "constant five : Int := 5";
1696        let config = ParserConfig::for_string(spec.into());
1697        let parser = RtLolaParser::new(&config);
1698        let pair = LolaParser::parse(Rule::ConstantStream, spec)
1699            .unwrap_or_else(|e| panic!("{}", e))
1700            .next()
1701            .unwrap();
1702        let ast = parser.parse_constant(pair);
1703        assert_eq!(format!("{}", ast), "constant five: Int := 5")
1704    }
1705
1706    #[test]
1707    fn parse_constant_double() {
1708        let spec = "constant fiveoh: Double := 5.0";
1709        let config = ParserConfig::for_string(spec.into());
1710        let parser = RtLolaParser::new(&config);
1711        let pair = LolaParser::parse(Rule::ConstantStream, spec)
1712            .unwrap_or_else(|e| panic!("{}", e))
1713            .next()
1714            .unwrap();
1715        let ast = parser.parse_constant(pair);
1716        assert_eq!(format!("{}", ast), "constant fiveoh: Double := 5.0")
1717    }
1718
1719    #[test]
1720    fn parse_input() {
1721        parses_to! {
1722            parser: LolaParser,
1723            input:  "input in: Int",
1724            rule:   Rule::InputStream,
1725            tokens: [
1726                InputStream(0, 13, [
1727                    Ident(6, 8, []),
1728                    Type(10, 13, [
1729                        Ident(10, 13, []),
1730                    ]),
1731                ]),
1732            ]
1733        };
1734    }
1735
1736    #[test]
1737    fn parse_input_ast() {
1738        let spec = "input a: Int, b: Int, c: Bool";
1739        let config = ParserConfig::for_string(spec.into());
1740        let parser = RtLolaParser::new(&config);
1741        let pair = LolaParser::parse(Rule::InputStream, spec)
1742            .unwrap_or_else(|e| panic!("{}", e))
1743            .next()
1744            .unwrap();
1745        let inputs = parser.parse_inputs(pair);
1746        assert_eq!(inputs.len(), 3);
1747        assert_eq!(format!("{}", inputs[0]), "input a: Int");
1748        assert_eq!(format!("{}", inputs[1]), "input b: Int");
1749        assert_eq!(format!("{}", inputs[2]), "input c: Bool");
1750    }
1751
1752    #[test]
1753    fn parse_mirror_ast() {
1754        let spec = "output a mirrors b when 3 > 5";
1755        let config = ParserConfig::for_string(spec.into());
1756        let parser = RtLolaParser::new(&config);
1757        let pair = LolaParser::parse(Rule::MirrorStream, spec)
1758            .unwrap_or_else(|e| panic!("{}", e))
1759            .next()
1760            .unwrap();
1761        let mirror = parser
1762            .parse_mirror(pair)
1763            .expect("failed to parse eval condition");
1764        assert_eq!(format!("{}", mirror), "output a mirror b when 3 > 5");
1765    }
1766
1767    #[test]
1768    fn build_ast_parameterized_input() {
1769        let spec = "input in (ab: Int8): Int8\n";
1770        let ast = parse(spec);
1771        cmp_ast_spec(&ast, spec);
1772    }
1773
1774    #[test]
1775    fn parse_output() {
1776        parses_to! {
1777            parser: LolaParser,
1778            input:  "output out: Int := in + 1",
1779            rule:   Rule::OutputStream,
1780            tokens: [
1781                OutputStream(0, 25, [
1782                    NamedOutputDecl(0, 10, [Ident(7, 10)]),
1783                    Type(12, 15, [
1784                        Ident(12, 15, []),
1785                    ]),
1786                    SimpleEvalDecl(16, 25, [
1787                        Expr(19, 25, [
1788                            Ident(19, 21, []),
1789                            Add(22, 23, []),
1790                            Literal(24, 25, [
1791                                NumberLiteral(24, 25, [
1792                                    NumberLiteralValue(24, 25, [])
1793                                ]),
1794                            ]),
1795                        ]),
1796                    ]),
1797                ]),
1798            ]
1799        };
1800    }
1801
1802    #[test]
1803    fn parse_output_ast() {
1804        let spec = "output out: Int eval with in + 1";
1805        let config = ParserConfig::for_string(spec.into());
1806        let parser = RtLolaParser::new(&config);
1807        let pair = LolaParser::parse(Rule::OutputStream, spec)
1808            .unwrap_or_else(|e| panic!("{}", e))
1809            .next()
1810            .unwrap();
1811        let ast = parser.parse_output(pair).unwrap();
1812        assert_eq!(format!("{}", ast), spec)
1813    }
1814
1815    #[test]
1816    fn parse_trigger() {
1817        parses_to! {
1818            parser: LolaParser,
1819            input:  "trigger in != out \"some message\"",
1820            rule:   Rule::SimpleTrigger,
1821            tokens: [
1822                SimpleTrigger(0, 32, [
1823                    SimpleTriggerDecl(0, 8),
1824                    Expr(8, 17, [
1825                        Ident(8, 10, []),
1826                        NotEqual(11, 13, []),
1827                        Ident(14, 17, []),
1828                    ]),
1829                    String(19, 31, []),
1830                ]),
1831            ]
1832        };
1833    }
1834
1835    #[test]
1836    fn parse_trigger_ast() {
1837        let spec = "trigger in ≠ out \"some message\"";
1838        let config = ParserConfig::for_string(spec.into());
1839        let parser = RtLolaParser::new(&config);
1840        let pair = LolaParser::parse(Rule::SimpleTrigger, spec)
1841            .unwrap_or_else(|e| panic!("{}", e))
1842            .next()
1843            .unwrap();
1844        let ast = parser.parse_trigger(pair).unwrap();
1845        assert_eq!(
1846            format!("{}", ast),
1847            "trigger eval when in ≠ out with \"some message\""
1848        )
1849    }
1850
1851    #[test]
1852    fn parse_complex_trigger() {
1853        let spec =
1854            "trigger (p) spawn when a = 0 with b eval @1Hz when b = 0 with \"msg\".format(a) close @2Hz when true";
1855        let config = ParserConfig::for_string(spec.into());
1856        let parser = RtLolaParser::new(&config);
1857        let pair = LolaParser::parse(Rule::OutputStream, spec)
1858            .unwrap_or_else(|e| panic!("{}", e))
1859            .next()
1860            .unwrap();
1861        let ast = parser.parse_output(pair).unwrap();
1862        assert_eq!(format!("{}", ast), spec)
1863    }
1864
1865    #[test]
1866    fn trigger_missing_message() {
1867        let spec = "trigger eval when a = 0";
1868        let config = ParserConfig::for_string(spec.into());
1869        let parser = RtLolaParser::new(&config);
1870        let pair = LolaParser::parse(Rule::OutputStream, spec)
1871            .unwrap_or_else(|e| panic!("{}", e))
1872            .next()
1873            .unwrap();
1874        let ast = parser.parse_output(pair).unwrap();
1875        assert_eq!(format!("{}", ast), "trigger eval when a = 0 with \"\"");
1876    }
1877
1878    #[test]
1879    fn trigger_missing_message2() {
1880        let spec = "trigger a = 0";
1881        let config = ParserConfig::for_string(spec.into());
1882        let parser = RtLolaParser::new(&config);
1883        let pair = LolaParser::parse(Rule::SimpleTrigger, spec)
1884            .unwrap_or_else(|e| panic!("{}", e))
1885            .next()
1886            .unwrap();
1887        let ast = parser.parse_trigger(pair).unwrap();
1888        assert_eq!(format!("{}", ast), "trigger eval when a = 0 with \"\"");
1889    }
1890
1891    #[test]
1892    fn parse_expression() {
1893        let content = "in + 1";
1894        let config = ParserConfig::for_string(content.into());
1895        let parser = RtLolaParser::new(&config);
1896        let expr = LolaParser::parse(Rule::Expr, content)
1897            .unwrap_or_else(|e| panic!("{}", e))
1898            .next()
1899            .unwrap();
1900        let ast = parser.build_expression_ast(expr.into_inner()).unwrap();
1901        assert_eq!(format!("{}", ast), content)
1902    }
1903
1904    #[test]
1905    fn parse_expression_precedence() {
1906        let content = "(a ∨ b ∧ c)";
1907        let config = ParserConfig::for_string(content.into());
1908        let parser = RtLolaParser::new(&config);
1909        let expr = LolaParser::parse(Rule::Expr, content)
1910            .unwrap_or_else(|e| panic!("{}", e))
1911            .next()
1912            .unwrap();
1913        let ast = parser.build_expression_ast(expr.into_inner()).unwrap();
1914        assert_eq!(format!("{}", ast), content)
1915    }
1916
1917    #[test]
1918    fn build_simple_ast() {
1919        let spec =
1920            "input in: Int\noutput out: Int eval with in\ntrigger eval when in ≠ out with \"\"\n";
1921        let ast = parse(spec);
1922        cmp_ast_spec(&ast, spec);
1923    }
1924
1925    #[test]
1926    fn build_ast_input() {
1927        let spec = "input in: Int\ninput in2: Int\ninput in3: (Int, Bool)\ninput in4: Bool\n";
1928        let ast = parse(spec);
1929        cmp_ast_spec(&ast, spec);
1930    }
1931
1932    #[test]
1933    fn build_parenthesized_expression() {
1934        let spec = "output s: Bool eval with (true ∨ true)\n";
1935        let ast = parse(spec);
1936        cmp_ast_spec(&ast, spec);
1937    }
1938
1939    #[test]
1940    fn build_optional_type() {
1941        let spec = "output s: Bool? eval with (false ∨ true)\n";
1942        let ast = parse(spec);
1943        cmp_ast_spec(&ast, spec);
1944    }
1945
1946    #[test]
1947    fn build_lookup_expression_default() {
1948        let spec = "output s: Int eval with s.offset(by: -1).defaults(to: (3 * 4))\n";
1949        let ast = parse(spec);
1950        cmp_ast_spec(&ast, spec);
1951    }
1952
1953    #[test]
1954    fn build_lookup_expression_hold() {
1955        let spec = "output s: Int eval with s.offset(by: -1).hold().defaults(to: 3 * 4)\n";
1956        let ast = parse(spec);
1957        cmp_ast_spec(&ast, spec);
1958    }
1959
1960    #[test]
1961    fn build_get_expression_def() {
1962        let spec = "output s: Int eval with s.get().defaults(to: -1)\n";
1963        let ast = parse(spec);
1964        cmp_ast_spec(&ast, spec);
1965    }
1966
1967    #[test]
1968    fn build_check_expression_def() {
1969        let spec = "input i: Int\noutput s: Int eval @1Hz with if i.is_fresh() then -1 else 1\n";
1970        let ast = parse(spec);
1971        cmp_ast_spec(&ast, spec);
1972    }
1973
1974    #[test]
1975    fn build_ternary_expression() {
1976        let spec = "input in: Int\noutput s: Int eval with if in = 3 then 4 else in + 2\n";
1977        let ast = parse(spec);
1978        cmp_ast_spec(&ast, spec);
1979    }
1980
1981    #[test]
1982    fn build_function_expression() {
1983        let spec = "input in: (Int, Bool)\noutput s: Int eval with nroot(1, sin(1, in))\n";
1984        let ast = parse(spec);
1985        cmp_ast_spec(&ast, spec);
1986    }
1987
1988    #[test]
1989    fn build_trigger() {
1990        let spec = "input in: Int\ntrigger eval when in > 5 with \"\"\n";
1991        let ast = parse(spec);
1992        cmp_ast_spec(&ast, spec);
1993    }
1994
1995    #[test]
1996    fn build_trigger_extend() {
1997        let spec = "trigger eval @1Hz when in > 5 with \"\"\n";
1998        let ast = parse(spec);
1999        cmp_ast_spec(&ast, spec);
2000    }
2001
2002    #[test]
2003    fn build_trigger_message() {
2004        let spec = "trigger eval when in > 5 with \"test trigger\"\n";
2005        let ast = parse(spec);
2006        cmp_ast_spec(&ast, spec);
2007        let eval = &ast.outputs[0].eval[0];
2008        assert!(
2009            matches!(&eval.eval_expression, Some(Expression {kind: ExpressionKind::Lit(Literal {kind:LitKind::Str(s),..}),..}) if s == "test trigger")
2010        );
2011    }
2012
2013    #[test]
2014    fn build_simple_trigger() {
2015        let spec = "trigger x > 10 \"msg\"";
2016        let reference = "trigger eval when x > 10 with \"msg\"\n";
2017        let ast = parse(spec);
2018        cmp_ast_spec(&ast, reference);
2019    }
2020
2021    #[test]
2022    fn build_complex_expression() {
2023        let spec =
2024            "output s: Double eval with if !((s.offset(by: -1).defaults(to: (3 * 4)) + -4) = 12) ∨ true = false then 2.0 else 4.1\n";
2025        let ast = parse(spec);
2026        cmp_ast_spec(&ast, spec);
2027    }
2028
2029    #[test]
2030    fn build_type_declaration() {
2031        let spec = "type VerifiedUser { name: String }\n";
2032        let ast = parse(spec);
2033        cmp_ast_spec(&ast, spec);
2034    }
2035
2036    #[test]
2037    fn build_parameter_list() {
2038        let spec = "output s (a: B, c: D): E eval with 3\n";
2039        let ast = parse(spec);
2040        cmp_ast_spec(&ast, spec);
2041    }
2042
2043    #[test]
2044    fn build_termination_spec() {
2045        let spec = "output s (a: Int): Int eval with 3 close when s > 10\n";
2046        let ast = parse(spec);
2047        cmp_ast_spec(&ast, spec);
2048    }
2049
2050    #[test]
2051    fn build_tuple_expression() {
2052        let spec = "input in: (Int, Bool)\noutput s: Int eval with (1, in.0).1\n";
2053        let ast = parse(spec);
2054        cmp_ast_spec(&ast, spec);
2055    }
2056
2057    #[test]
2058    fn parse_string() {
2059        let spec = r#"constant s: String := "a string with \n newline"
2060"#;
2061        let ast = parse(spec);
2062        cmp_ast_spec(&ast, spec);
2063    }
2064
2065    #[test]
2066    fn parse_raw_string() {
2067        let spec = r##"constant s: String := r#"a raw \ string that " needs padding"#
2068"##;
2069        let ast = parse(spec);
2070        cmp_ast_spec(&ast, spec);
2071    }
2072
2073    #[test]
2074    fn parse_import() {
2075        let spec = "import math\ninput in: UInt8\n";
2076        let ast = parse(spec);
2077        cmp_ast_spec(&ast, spec);
2078    }
2079
2080    #[test]
2081    fn parse_max() {
2082        let spec = "import math\ninput a: Int32\ninput b: Int32\noutput maxres: Int32 eval with max<Int32>(a, b)\n";
2083        let ast = parse(spec);
2084        cmp_ast_spec(&ast, spec);
2085    }
2086
2087    #[test]
2088    fn parse_method_call() {
2089        let spec = "output count eval with count.offset(-1).default(0) + 1\n";
2090        let ast = parse(spec);
2091        cmp_ast_spec(&ast, spec);
2092    }
2093
2094    #[test]
2095    fn parse_method_call_with_param() {
2096        let spec = "output count eval with count.offset<Int8>(-1).default(0) + 1\n";
2097        let ast = parse(spec);
2098        cmp_ast_spec(&ast, spec);
2099    }
2100
2101    #[test]
2102    fn parse_realtime_offset() {
2103        let spec = "output a eval with b.offset(by: -1s)\n";
2104        let ast = parse(spec);
2105        cmp_ast_spec(&ast, spec);
2106    }
2107
2108    #[test]
2109    fn parse_future_offset() {
2110        let spec = "output a eval with b.offset(by: 1)\n";
2111        let ast = parse(spec);
2112        cmp_ast_spec(&ast, spec);
2113    }
2114
2115    #[test]
2116    fn parse_function_argument_name() {
2117        let spec = "output a eval with b.hold().defaults(to: 0)\n";
2118        let ast = parse(spec);
2119        cmp_ast_spec(&ast, spec);
2120    }
2121
2122    #[test]
2123    fn parse_precedence_not_regression() {
2124        parses_to! {
2125            parser: LolaParser,
2126            input:  "!(fast || false) && fast",
2127            rule:   Rule::Expr,
2128            tokens: [
2129                Expr(0, 24, [
2130                    UnaryExpr(0, 16, [
2131                        Neg(0, 1, []),
2132                        ParenthesizedExpression(1, 16, [
2133                            OpeningParenthesis(1, 2, []),
2134                            Expr(2, 15, [
2135                                Ident(2, 6, []),
2136                                Or(7, 9, []),
2137                                Literal(10, 15, [
2138                                    False(10, 15, [])
2139                                ])
2140                            ]),
2141                            ClosingParenthesis(15, 16, [])
2142                        ])
2143                    ]),
2144                    And(17, 19, []),
2145                    Ident(20, 24, [])
2146                ]),
2147            ]
2148        };
2149    }
2150
2151    #[test]
2152    fn handle_bom() {
2153        let spec = "\u{feff}input a: Bool\n";
2154        let ast = parse(spec);
2155        cmp_ast_spec(&ast, "input a: Bool\n");
2156    }
2157
2158    #[test]
2159    fn regression71_and_simple_decl() {
2160        let spec = "output outputstream := 42 output c := outputstream";
2161        let ast = parse(spec);
2162        cmp_ast_spec(
2163            &ast,
2164            "output outputstream eval with 42\noutput c eval with outputstream\n",
2165        );
2166    }
2167
2168    #[test]
2169    fn parse_bitwise() {
2170        let spec = "output x eval with 1 ^ 0 & 23123 | 111\n";
2171        let ast = parse(spec);
2172        cmp_ast_spec(&ast, spec);
2173    }
2174
2175    #[test]
2176    fn spawn_no_expression() {
2177        let spec = "output x spawn when true eval with 5\n";
2178        let ast = parse(spec);
2179        cmp_ast_spec(&ast, spec);
2180    }
2181
2182    #[test]
2183    fn spawn_no_cond_with_pacing() {
2184        let spec = "output x (y: Int32) spawn @1Hz with 1 eval with 5 close @1Hz when true\n";
2185        let ast = parse(spec);
2186        cmp_ast_spec(&ast, spec);
2187    }
2188
2189    #[test]
2190    fn build_template_spec() {
2191        let spec =
2192            "output x (y: Int8) spawn with 42 eval @1Hz when y = 1337 with 5 close when false\n";
2193        let ast = parse(spec);
2194        cmp_ast_spec(&ast, spec);
2195    }
2196
2197    #[test]
2198    fn build_full_template_spec_type() {
2199        let spec =
2200            "output x (y: Int8): Bool spawn when y = 3 with 42 eval @1Hz when y = 1337 with 5 close when false\n";
2201        let ast = parse(spec);
2202        cmp_ast_spec(&ast, spec);
2203    }
2204
2205    #[test]
2206    fn build_full_template_spec() {
2207        //spawn eval close
2208        let spec = "output x (y: Int8) spawn when y = 17 with 42 eval @1Hz when y = 1337 with 5 close when false\n";
2209        let ast = parse(spec);
2210        cmp_ast_spec(
2211            &ast,
2212            "output x (y: Int8) spawn when y = 17 with 42 eval @1Hz when y = 1337 with 5 close when false\n",
2213        );
2214    }
2215
2216    #[test]
2217    fn build_full_order1() {
2218        // close eval spawn
2219        let spec = "output x (y: Int8) close when false eval @1Hz when y = 1337 with 5 spawn when y = 17 with 42\n";
2220        let ast = parse(spec);
2221        cmp_ast_spec(
2222            &ast,
2223            "output x (y: Int8) spawn when y = 17 with 42 eval @1Hz when y = 1337 with 5 close when false\n",
2224        );
2225    }
2226
2227    #[test]
2228    fn build_full_order2() {
2229        // eval close spawn
2230        let spec = "output x (y: Int8) eval @1Hz when y = 1337 with 5  close when false spawn when y = 17 with 42\n";
2231        let ast = parse(spec);
2232        cmp_ast_spec(
2233            &ast,
2234            "output x (y: Int8) spawn when y = 17 with 42 eval @1Hz when y = 1337 with 5 close when false\n",
2235        );
2236    }
2237
2238    #[test]
2239    fn build_full_order3() {
2240        // eval spawn close
2241        let spec = "output x (y: Int8) eval @1Hz when y = 1337 with 5 spawn when y = 17 with 42 close when false\n";
2242        let ast = parse(spec);
2243        cmp_ast_spec(
2244            &ast,
2245            "output x (y: Int8) spawn when y = 17 with 42 eval @1Hz when y = 1337 with 5 close when false\n",
2246        );
2247    }
2248
2249    #[test]
2250    fn build_full_order4() {
2251        // close spawn eval
2252        let spec = "output x (y: Int8) close when false spawn when y = 17 with 42 eval @1Hz when y = 1337 with 5\n";
2253        let ast = parse(spec);
2254        cmp_ast_spec(
2255            &ast,
2256            "output x (y: Int8) spawn when y = 17 with 42 eval @1Hz when y = 1337 with 5 close when false\n",
2257        );
2258    }
2259
2260    #[test]
2261    fn build_full_order5() {
2262        // spawn close eval
2263        let spec = "output x (y: Int8) spawn when y = 17 with 42 close when false eval @1Hz when y = 1337 with 5\n";
2264        let ast = parse(spec);
2265        cmp_ast_spec(
2266            &ast,
2267            "output x (y: Int8) spawn when y = 17 with 42 eval @1Hz when y = 1337 with 5 close when false\n",
2268        );
2269    }
2270
2271    #[test]
2272    fn multiple_eval_inputs() {
2273        // eval eval eval
2274        let spec = "output x (y: Int8) eval @1Hz when y = 1336 with 4 eval @1Hz when y = 1337 with 5 eval @1Hz when y = 1338 with 6\n";
2275        let ast = parse_without_desugar(spec);
2276        cmp_ast_spec(&ast, spec);
2277    }
2278
2279    #[test]
2280    fn multiple_eval_inputs_with_spawn() {
2281        // eval eval eval spawn
2282        let spec = "output x (y: Int8) eval @1Hz when y = 1336 with 4 eval @1Hz when y = 1337 with 5 eval @1Hz when y = 1338 with 6 spawn when y = 17 with 42\n";
2283        let ast = parse_without_desugar(spec);
2284        cmp_ast_spec(&ast, "output x (y: Int8) spawn when y = 17 with 42 eval @1Hz when y = 1336 with 4 eval @1Hz when y = 1337 with 5 eval @1Hz when y = 1338 with 6\n");
2285    }
2286
2287    #[test]
2288    fn multiple_eval_inputs_with_close() {
2289        // close eval eval eval
2290        let spec = "output x (y: Int8) close when false eval when y = 1336 with 4 eval when y = 1337 with 5 eval when y = 1338 with 6\n";
2291        let ast = parse_without_desugar(spec);
2292        cmp_ast_spec(&ast, "output x (y: Int8) eval when y = 1336 with 4 eval when y = 1337 with 5 eval when y = 1338 with 6 close when false\n");
2293        //let ast2 = parse(spec);
2294        //cmp_ast_spec(&ast2, "output x (y: Int8) eval when y = 1336 ∨ y = 1337 ∨ y = 1338 with if y = 1336 then 4 else if y = 1337 then 5 else 6 close when false\n");
2295    }
2296
2297    #[test]
2298    fn build_full_template_spec_type_two_eval() {
2299        // spawn eval eval close
2300        let spec = "output x (y: Int8): Bool spawn when y = 17 with 42 eval @1Hz when y = 1336 with 4 eval when y = 1337 with 5 close when false\n";
2301        let ast = parse_without_desugar(spec);
2302        cmp_ast_spec(&ast, spec);
2303    }
2304
2305    #[test]
2306    fn build_multiple_close() {
2307        let spec = "output x close when true eval with 5 close when false\n";
2308        let config = ParserConfig::for_string(spec.into());
2309        let parser = RtLolaParser::new(&config);
2310        match parser.parse_spec() {
2311            Ok(_) => panic!("Expected error"),
2312            Err(e) => assert_eq!(e.num_errors(), 1),
2313        }
2314    }
2315
2316    #[test]
2317    fn spawn_parts_order1() {
2318        let spec = "output x (y: Int8) spawn with 42 when y = 1 eval with 5\n";
2319        let ast = parse(spec);
2320        cmp_ast_spec(
2321            &ast,
2322            "output x (y: Int8) spawn when y = 1 with 42 eval with 5\n",
2323        );
2324    }
2325
2326    #[test]
2327    fn spawn_parts_order2() {
2328        let spec = "output x (y: Int8) spawn when y = 1 with 42 eval with 5\n";
2329        let ast = parse(spec);
2330        cmp_ast_spec(&ast, spec);
2331    }
2332
2333    #[test]
2334    fn eval_parts_order1() {
2335        let spec = "output x (y: Int8) spawn with 42 eval with 5 when y = 42\n";
2336        let ast = parse(spec);
2337        cmp_ast_spec(
2338            &ast,
2339            "output x (y: Int8) spawn with 42 eval when y = 42 with 5\n",
2340        );
2341    }
2342
2343    #[test]
2344    fn eval_parts_order2() {
2345        let spec = "output x (y: Int8) spawn with 42 eval when y = 42 with 5\n";
2346        let ast = parse(spec);
2347        cmp_ast_spec(&ast, spec);
2348    }
2349
2350    #[test]
2351    fn spawn_duplicate_when() {
2352        let spec = "output x spawn when true when true eval with 5\n";
2353        let config = ParserConfig::for_string(spec.into());
2354        let parser = RtLolaParser::new(&config);
2355
2356        match parser.parse_spec() {
2357            Ok(_) => panic!("Expected error"),
2358            Err(e) => {
2359                //use rtlola_reporting::Handler;
2360                //let h = Handler::from(ParserConfig::for_string(spec.to_string()));
2361                //h.emit_error(&e);
2362                assert_eq!(e.num_errors(), 1)
2363            }
2364        }
2365    }
2366
2367    #[test]
2368    fn spawn_duplicate_with() {
2369        let spec = "output x (p) spawn @1Hz with 3 with 3 eval with 5\n";
2370        let config = ParserConfig::for_string(spec.into());
2371        let parser = RtLolaParser::new(&config);
2372        match parser.parse_spec() {
2373            Ok(_) => panic!("Expected error"),
2374            Err(e) => {
2375                //use rtlola_reporting::Handler;
2376                //let h = Handler::from(ParserConfig::for_string(spec.to_string()));
2377                //h.emit_error(&e);
2378                assert_eq!(e.num_errors(), 1)
2379            }
2380        }
2381    }
2382
2383    #[test]
2384    fn duplicate_close_clauses() {
2385        let spec = "output x eval with 5 close when true close when x == 5\n";
2386        let config = ParserConfig::for_string(spec.into());
2387        let parser = RtLolaParser::new(&config);
2388        match parser.parse_spec() {
2389            Ok(_) => panic!("Expected error"),
2390            Err(e) => {
2391                //use rtlola_reporting::Handler;
2392                //let h = Handler::from(ParserConfig::for_string(spec.to_string()));
2393                //h.emit_error(&e);
2394                assert_eq!(e.num_errors(), 1)
2395            }
2396        }
2397    }
2398
2399    #[test]
2400    fn spawn_no_expr_no_condition_np_pacing() {
2401        let spec = "output x spawn eval with 5\n";
2402        let config = ParserConfig::for_string(spec.into());
2403        let parser = RtLolaParser::new(&config);
2404        match parser.parse_spec() {
2405            Ok(_) => panic!("Expected error"),
2406            Err(e) => assert_eq!(e.num_errors(), 1),
2407        }
2408    }
2409
2410    #[test]
2411    fn eval_no_expr() {
2412        let spec = "output x (y: Int8) spawn when true with 42 eval @1Hz when y = 42\n";
2413        let ast = parse(spec);
2414        cmp_ast_spec(
2415            &ast,
2416            "output x (y: Int8) spawn when true with 42 eval @1Hz when y = 42 with ()\n",
2417        );
2418    }
2419
2420    #[test]
2421    fn valid_percentile() {
2422        let spec = "output x eval with x.aggregate(over: 3s, using: pctl15)\n";
2423        let ast = parse(spec);
2424        cmp_ast_spec(&ast, spec);
2425    }
2426
2427    #[test]
2428    fn spawn_with_pacing() {
2429        let spec = "output x eval with 5 spawn @3Hz with (x)\n";
2430        let ast = parse(spec);
2431        cmp_ast_spec(&ast, "output x spawn @3Hz with (x) eval with 5\n");
2432    }
2433
2434    #[test]
2435    fn test_instance_window() {
2436        let spec = "input a: Int32\n\
2437        output b (p: Bool) spawn with a = 42 eval with a\n\
2438        output c eval @1Hz with b(false).aggregate(over: 1s, using: Σ)\n";
2439        let ast = parse(spec);
2440        cmp_ast_spec(&ast, spec);
2441    }
2442
2443    #[test]
2444    fn parse_impl_simpl() {
2445        let spec = "input a: Bool\n\
2446        input b: Bool\n\
2447        output c eval with a -> b\n";
2448        let ast = parse(spec);
2449        cmp_ast_spec(
2450            &ast,
2451            "input a: Bool\n\
2452            input b: Bool\n\
2453            output c eval with !a ∨ b\n",
2454        );
2455    }
2456
2457    #[test]
2458    fn parse_impl_right_associative() {
2459        let spec = "input a: Bool\ninput b: Bool\noutput c eval with a -> b -> c\n";
2460        let ast = parse(spec);
2461        cmp_ast_spec(
2462            &ast,
2463            "input a: Bool\ninput b: Bool\noutput c eval with !a ∨ !b ∨ c\n",
2464        );
2465    }
2466
2467    #[test]
2468    fn parse_impl_left() {
2469        let spec = "input a: Bool\ninput b: Bool\noutput c eval with (a -> b) -> c\n";
2470        let ast = parse(spec);
2471        cmp_ast_spec(
2472            &ast,
2473            "input a: Bool\ninput b: Bool\noutput c eval with !(!a ∨ b) ∨ c\n",
2474        );
2475    }
2476
2477    #[test]
2478    fn parse_impl_nested() {
2479        let spec = "input a: Bool\ninput b: Bool\noutput c eval with a ∧ b -> c\n";
2480        let ast = parse(spec);
2481        cmp_ast_spec(
2482            &ast,
2483            "input a: Bool\ninput b: Bool\noutput c eval with !(a ∧ b) ∨ c\n",
2484        );
2485    }
2486
2487    #[test]
2488    fn instance_aggregation_simpl_fresh() {
2489        let spec = "input a: Int32\n\
2490        output b (p) spawn with a eval when a > 5 with b(p).offset(by: -1).defaults(to: 0) + 1\n\
2491        output c eval with b.aggregate(over_instances: fresh, using: Σ)\n";
2492        let ast = parse(spec);
2493        cmp_ast_spec(&ast, spec);
2494    }
2495
2496    #[test]
2497    fn instance_aggregation_simpl_all() {
2498        let spec = "input a: Int32\n\
2499        output b (p) spawn with a eval when a > 5 with b(p).offset(by: -1).defaults(to: 0) + 1\n\
2500        output c eval with b.aggregate(over_instances: all, using: Σ)\n";
2501        let ast = parse(spec);
2502        cmp_ast_spec(&ast, spec);
2503    }
2504
2505    #[test]
2506    fn global_and_local_frequencies() {
2507        let spec = "input a: Int32\n\
2508        output not (p) spawn with a eval @1Hz with global(p).offset(by: -1).defaults(to: 0) + 1\n\
2509        output global (p) spawn with a eval @Global(1Hz) with global(p).offset(by: -1).defaults(to: 0) + 1\n\
2510        output local (p) spawn with a eval @Local(1Hz) with local(p).offset(by: -1).defaults(to: 0) + 1\n";
2511        let ast = parse(spec);
2512        cmp_ast_spec(&ast, spec);
2513    }
2514
2515    #[test]
2516    fn parse_tags() {
2517        let spec = "#[key=\"value\"]\n\
2518        input a: Int32\n\
2519        #[key2]\n\
2520        output b eval with a + 1\n\
2521        #[key=\"value\",key_without_value,other_key=\"other_value\"]\n\
2522        trigger eval when b > 10 with \"test\"\n";
2523        let ast = parse(spec);
2524        cmp_ast_spec(&ast, spec);
2525    }
2526
2527    #[test]
2528    fn missing_closing_parenthesis() {
2529        let spec = "input a: Int32\n\
2530        output b := 1 + (1 * 2\n\
2531        output c := 1 * (1 + 2";
2532        let e = super::super::parse(&ParserConfig::for_string(spec.into())).unwrap_err();
2533        assert_eq!(e.num_errors(), 2);
2534    }
2535
2536    #[test]
2537    fn tuple_literal() {
2538        let spec = "constant test: (Float, (String, Bool)) := (1.0, (\"Hello World\", true))\n";
2539        let ast = parse(spec);
2540        cmp_ast_spec(&ast, spec);
2541    }
2542
2543    #[test]
2544    fn invalid_op_in_ac() {
2545        let spec = "input in: Int8\n output out: Int16 @!in := 5";
2546        let e = super::super::parse(&ParserConfig::for_string(spec.into())).unwrap_err();
2547        assert_eq!(e.num_errors(), 1);
2548    }
2549
2550    #[test]
2551    fn trigger_and_ac_bug() {
2552        let spec = "input in: Int8\n trigger @in (true)";
2553        assert!(super::super::parse(&ParserConfig::for_string(spec.into())).is_ok())
2554    }
2555
2556    #[test]
2557    fn parenthesis_freq_activation() {
2558        let spec = "trigger @(1Hz) (true)";
2559        assert!(super::super::parse(&ParserConfig::for_string(spec.into())).is_ok())
2560    }
2561
2562    #[test]
2563    fn parse_global_tags() {
2564        let spec = "#![key=\"value\"]\n\
2565        #![key2=\"value\"]\n\
2566        input a: Int32\n\
2567        trigger eval when b > 10 with \"test\"\n";
2568        let ast = parse(spec);
2569        let ref_spec = "#![key=\"value\",key2=\"value\"]\n\
2570        input a: Int32\n\
2571        trigger eval when b > 10 with \"test\"\n";
2572        cmp_ast_spec(&ast, ref_spec);
2573    }
2574
2575    #[test]
2576    fn parse_unicode_identifier() {
2577        parses_to! {
2578            parser: LolaParser,
2579            input:  "input ζ: Int32",
2580            rule:   Rule::InputStream,
2581            tokens: [
2582                InputStream(0, 15, [
2583                    Ident(6, 8, []),
2584                    Type(10, 15, [Ident(10, 15, [])])
2585                ]),
2586            ]
2587        };
2588    }
2589
2590    #[test]
2591    fn unicode_normalization() {
2592        let precomposed = "é";
2593        let decomposed = "e\u{0301}";
2594        assert!(precomposed != decomposed);
2595
2596        let pair1 = LolaParser::parse(Rule::Ident, precomposed)
2597            .unwrap_or_else(|e| panic!("{}", e))
2598            .next()
2599            .unwrap();
2600        let pair2 = LolaParser::parse(Rule::Ident, decomposed)
2601            .unwrap_or_else(|e| panic!("{}", e))
2602            .next()
2603            .unwrap();
2604
2605        let config = ParserConfig::for_string("".into());
2606        let parser = RtLolaParser::new(&config);
2607        let ident1 = parser.parse_ident(&pair1);
2608        let ident2 = parser.parse_ident(&pair2);
2609        assert_eq!(ident1, ident2)
2610    }
2611
2612    #[test]
2613    fn filtered_all_instance_aggregation() {
2614        let spec = "input a: Int32\n\
2615        output b (p1, p2) \
2616            spawn with (a, a + 1) \
2617            eval with p1 + p2 + 1\n\
2618        output c (p1) \
2619            spawn with a \
2620            eval with b.aggregate(over_instances: all(where: (p1,p2) => p2 = a), using: Σ)\n";
2621        let ast = parse(spec);
2622        cmp_ast_spec(&ast, spec);
2623    }
2624
2625    #[test]
2626    fn filtered_fresh_instance_aggregation() {
2627        let spec = "input a: Int32\n\
2628        output b (p1, p2) \
2629            spawn with (a, a + 1) \
2630            eval with p1 + p2 + 1\n\
2631        output c (p1) \
2632            spawn with a \
2633            eval with b.aggregate(over_instances: fresh(where: (p1,p2) => p2 = a), using: Σ)\n";
2634        let ast = parse(spec);
2635        cmp_ast_spec(&ast, spec);
2636    }
2637
2638    #[test]
2639    fn lambda_expr() {
2640        let spec = "input a: Int32\n\
2641        output b eval with (p1,p2) => a = 5\n";
2642        let ast = parse(spec);
2643        cmp_ast_spec(&ast, spec);
2644    }
2645
2646    #[test]
2647    fn lambda_single_parameter() {
2648        let spec = "input a: Int32\n\
2649        output b eval with p1 => a = 5\n";
2650        let r = "input a: Int32\n\
2651        output b eval with (p1) => a = 5\n";
2652        let ast = parse(spec);
2653        cmp_ast_spec(&ast, r);
2654    }
2655
2656    #[test]
2657    fn true_ratio_check() {
2658        let spec = "input a: Bool\n\
2659        output b eval @1Hz with a.aggregate(over: 1s, using: true_ratio)\n";
2660        let ast = parse_without_desugar(spec);
2661        cmp_ast_spec(&ast, spec);
2662    }
2663
2664    #[test]
2665    fn true_ratio_check_parameterized() {
2666        let spec = "input a: Bool\n\
2667        output b (p) spawn with a eval @1Hz with (a).aggregate(over: 1s, using: true_ratio)\n";
2668        let ast = parse_without_desugar(spec);
2669        cmp_ast_spec(&ast, spec);
2670    }
2671
2672    #[test]
2673    fn true_ratio_check_parameterized_2() {
2674        let spec = "input a: Bool\n\
2675        output b (p) spawn with a eval when a = p with a\n\
2676        output c (p) spawn with a eval @1Hz with c(p).aggregate(over: 1s, using: true_ratio)\n";
2677        let ast = parse_without_desugar(spec);
2678        cmp_ast_spec(&ast, spec);
2679    }
2680
2681    #[test]
2682    fn true_ratio_check_instances() {
2683        let spec = "input a: UInt8\n\
2684        output a' (p) spawn @a with a eval @a when a = p with a + p > 5\n\
2685        output b eval @1Hz with a'.aggregate(over_instances: all, using: true_ratio)\n";
2686        let ast = parse_without_desugar(spec);
2687        cmp_ast_spec(&ast, spec);
2688    }
2689
2690    #[test]
2691    fn true_ratio_check_name() {
2692        let spec = "input a: Bool\n\
2693        input a': Boolean\n\
2694        input a'': Boolean\n\
2695        input a''': Boolean\n\
2696        output b eval @1Hz with (a').aggregate(over: 1s, using: true_ratio)\n";
2697        let ast = parse_without_desugar(spec);
2698        cmp_ast_spec(&ast, spec);
2699    }
2700}