1use 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 Rule::And => BinOp::And,
1125 Rule::Or => BinOp::Or,
1126 Rule::Implies => BinOp::Implies,
1127 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 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 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 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 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 "∫" | "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 }
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 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 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), 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(¶meter_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 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, '.'); let (dec_digits, exp_str) = split_at!(suffix, 'e');
1539
1540 let digits = int_digits.to_string() + dec_digits; 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 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 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 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 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 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 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 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 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 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 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 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 }
2296
2297 #[test]
2298 fn build_full_template_spec_type_two_eval() {
2299 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 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 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 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}