rtlola_parser/ast/
print.rs

1//! This module contains `Display` implementations for the AST.
2
3use std::fmt::{Display, Formatter, Result};
4
5use itertools::Itertools;
6
7use crate::ast::*;
8
9/// Writes out the joined vector `v`, enclosed by the given strings `pref` and `suff`.
10fn write_delim_list<T: Display>(
11    f: &mut Formatter<'_>,
12    v: &[T],
13    pref: &str,
14    suff: &str,
15    join: &str,
16) -> Result {
17    write!(f, "{pref}")?;
18    if let Some(e) = v.first() {
19        write!(f, "{e}")?;
20        for b in &v[1..] {
21            write!(f, "{join}{b}")?;
22        }
23    }
24    write!(f, "{suff}")?;
25    Ok(())
26}
27
28/// Helper to format an Optional
29fn format_opt<T: Display>(opt: &Option<T>, pref: &str, suff: &str) -> String {
30    if let Some(ref e) = opt {
31        format!("{pref}{e}{suff}")
32    } else {
33        String::new()
34    }
35}
36
37/// Formats an optional type
38fn format_type(ty: &Option<Type>) -> String {
39    format_opt(ty, ": ", "")
40}
41
42fn format_tags(f: &mut Formatter<'_>, tags: &[Tag], global: bool) -> Result {
43    if tags.is_empty() {
44        return Ok(());
45    }
46    let tag_list = tags
47        .iter()
48        .map(|tag| {
49            if let Some(value) = &tag.value {
50                format!("{}=\"{}\"", &tag.key, value)
51            } else {
52                tag.key.to_string()
53            }
54        })
55        .join(",");
56
57    if global {
58        writeln!(f, "#![{tag_list}]")
59    } else {
60        writeln!(f, "#[{tag_list}]")
61    }
62}
63
64impl Display for Constant {
65    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
66        write!(
67            f,
68            "constant {}{} := {}",
69            self.name,
70            format_type(&self.ty),
71            self.literal
72        )
73    }
74}
75
76impl Display for Input {
77    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
78        format_tags(f, &self.tags, false)?;
79        write!(f, "input {}", self.name)?;
80        if !self.params.is_empty() {
81            write_delim_list(f, &self.params, " (", ")", ", ")?;
82        }
83        write!(f, ": {}", self.ty)
84    }
85}
86
87impl Display for Mirror {
88    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
89        write!(
90            f,
91            "output {} mirror {} when {}",
92            self.name, self.target, self.filter
93        )
94    }
95}
96
97impl Display for Output {
98    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
99        format_tags(f, &self.tags, false)?;
100        match &self.kind {
101            OutputKind::NamedOutput(name) => write!(f, "output {name}")?,
102            OutputKind::Trigger => write!(f, "trigger")?,
103        };
104        if !self.params.is_empty() {
105            write_delim_list(f, &self.params, " (", ")", ", ")?;
106        }
107        if let Some(ty) = &self.annotated_type {
108            write!(f, ": {ty}")?;
109        }
110        if let Some(spawn) = &self.spawn {
111            write!(f, " {spawn}")?;
112        }
113        for eval_spec in self.eval.iter() {
114            write!(f, " {eval_spec}")?;
115        }
116        if let Some(close) = &self.close {
117            write!(f, " {close}")?;
118        }
119        Ok(())
120    }
121}
122
123impl Display for Parameter {
124    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
125        match &self.ty {
126            None => write!(f, "{}", self.name),
127            Some(ty) => write!(f, "{}: {}", self.name, ty),
128        }
129    }
130}
131
132impl Display for AnnotatedPacingType {
133    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
134        match self {
135            AnnotatedPacingType::NotAnnotated(_) => Ok(()),
136            AnnotatedPacingType::Global(freq) => write!(f, " @Global({freq})"),
137            AnnotatedPacingType::Local(freq) => write!(f, " @Local({freq})"),
138            AnnotatedPacingType::Unspecified(expr) => write!(f, " @{expr}"),
139        }
140    }
141}
142
143impl Display for SpawnSpec {
144    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
145        if self.expression.is_some() || self.condition.is_some() {
146            write!(f, "spawn")?;
147        }
148        write!(f, "{}", self.annotated_pacing)?;
149        if let Some(condition) = &self.condition {
150            write!(f, " when {condition}")?;
151        }
152        if let Some(expr) = &self.expression {
153            write!(f, " with {expr}")?;
154        }
155        Ok(())
156    }
157}
158
159impl Display for EvalSpec {
160    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
161        if self.condition.is_some()
162            || self.eval_expression.is_some()
163            || !matches!(self.annotated_pacing, AnnotatedPacingType::NotAnnotated(_))
164        {
165            write!(f, "eval")?;
166        }
167        write!(f, "{}", self.annotated_pacing)?;
168        if let Some(when) = &self.condition {
169            write!(f, " when {when}")?;
170        }
171        if let Some(exp) = &self.eval_expression {
172            write!(f, " with {exp}")?;
173        }
174        Ok(())
175    }
176}
177
178impl Display for CloseSpec {
179    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
180        write!(f, "close")?;
181        write!(f, "{}", self.annotated_pacing)?;
182        write!(f, " when {}", self.condition)
183    }
184}
185
186impl Display for Type {
187    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
188        write!(f, "{}", self.kind)
189    }
190}
191
192impl Display for TypeKind {
193    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
194        match &self {
195            TypeKind::Simple(name) => write!(f, "{name}"),
196            TypeKind::Tuple(types) => write_delim_list(f, types, "(", ")", ", "),
197            TypeKind::Optional(ty) => write!(f, "{ty}?"),
198        }
199    }
200}
201
202impl Display for TypeDeclField {
203    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
204        write!(f, "{}: {}", &self.name, &self.ty)
205    }
206}
207
208impl Display for TypeDeclaration {
209    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
210        write!(f, "type {}", format_opt(&self.name, "", ""))?;
211        write_delim_list(f, &self.fields, " { ", " }", ", ")
212    }
213}
214
215impl Display for Expression {
216    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
217        match &self.kind {
218            ExpressionKind::Lit(l) => write!(f, "{l}"),
219            ExpressionKind::Ident(ident) => write!(f, "{ident}"),
220            ExpressionKind::StreamAccess(expr, access) => match access {
221                StreamAccessKind::Sync => write!(f, "{expr}"),
222                StreamAccessKind::Hold => write!(f, "{expr}.hold()"),
223                StreamAccessKind::Get => write!(f, "{expr}.get()"),
224                StreamAccessKind::Fresh => write!(f, "{expr}.is_fresh()"),
225            },
226            ExpressionKind::Default(expr, val) => write!(f, "{expr}.defaults(to: {val})"),
227            ExpressionKind::Offset(expr, val) => write!(f, "{expr}.offset(by: {val})"),
228            ExpressionKind::DiscreteWindowAggregation {
229                expr,
230                duration,
231                wait,
232                aggregation,
233            } => match wait {
234                true => {
235                    write!(
236                        f,
237                        "{expr}.aggregate(over_exactly_discrete: {duration}, using: {aggregation})"
238                    )
239                }
240                false => {
241                    write!(
242                        f,
243                        "{expr}.aggregate(over_discrete: {duration}, using: {aggregation})"
244                    )
245                }
246            },
247            ExpressionKind::SlidingWindowAggregation {
248                expr,
249                duration,
250                wait,
251                aggregation,
252            } => match wait {
253                true => {
254                    write!(
255                        f,
256                        "{expr}.aggregate(over_exactly: {duration}, using: {aggregation})"
257                    )
258                }
259                false => write!(
260                    f,
261                    "{expr}.aggregate(over: {duration}, using: {aggregation})"
262                ),
263            },
264            ExpressionKind::InstanceAggregation {
265                expr,
266                selection,
267                aggregation,
268            } => write!(
269                f,
270                "{expr}.aggregate(over_instances: {selection}, using: {aggregation})"
271            ),
272            ExpressionKind::Binary(op, lhs, rhs) => write!(f, "{lhs} {op} {rhs}"),
273            ExpressionKind::Unary(operator, operand) => write!(f, "{operator}{operand}"),
274            ExpressionKind::Ite(cond, cons, alt) => {
275                write!(f, "if {cond} then {cons} else {alt}")
276            }
277            ExpressionKind::ParenthesizedExpression(expr) => {
278                write!(f, "({})", expr,)
279            }
280            ExpressionKind::MissingExpression => Ok(()),
281            ExpressionKind::Tuple(exprs) => write_delim_list(f, exprs, "(", ")", ", "),
282            ExpressionKind::Function(name, types, args) => {
283                write!(f, "{}", name.name)?;
284                if !types.is_empty() {
285                    write_delim_list(f, types, "<", ">", ", ")?;
286                }
287                let args: Vec<String> = args
288                    .iter()
289                    .zip(&name.arg_names)
290                    .map(|(arg, arg_name)| match arg_name {
291                        None => format!("{arg}"),
292                        Some(arg_name) => format!("{arg_name}: {arg}"),
293                    })
294                    .collect();
295                write_delim_list(f, &args, "(", ")", ", ")
296            }
297            ExpressionKind::Field(expr, ident) => write!(f, "{expr}.{ident}"),
298            ExpressionKind::Method(expr, name, types, args) => {
299                write!(f, "{}.{}", expr, name.name)?;
300                if !types.is_empty() {
301                    write_delim_list(f, types, "<", ">", ", ")?;
302                }
303                let args: Vec<String> = args
304                    .iter()
305                    .zip(&name.arg_names)
306                    .map(|(arg, arg_name)| match arg_name {
307                        None => format!("{arg}"),
308                        Some(arg_name) => format!("{arg_name}: {arg}"),
309                    })
310                    .collect();
311                write_delim_list(f, &args, "(", ")", ", ")
312            }
313            ExpressionKind::Lambda(lambda) => {
314                write!(f, "{lambda}")
315            }
316        }
317    }
318}
319
320impl Display for LambdaExpr {
321    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
322        let LambdaExpr { parameters, expr } = self;
323        let parameters = parameters.iter().map(|p| p.to_string()).join(",");
324        write!(f, "({parameters}) => {expr}")
325    }
326}
327
328impl Display for FunctionName {
329    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
330        write!(f, "{}", self.name)?;
331        let args: Vec<String> = self
332            .arg_names
333            .iter()
334            .map(|arg_name| match arg_name {
335                None => String::from("_:"),
336                Some(arg_name) => format!("{arg_name}:"),
337            })
338            .collect();
339        write_delim_list(f, &args, "(", ")", "")
340    }
341}
342
343impl Display for Offset {
344    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
345        match self {
346            Offset::Discrete(val) => write!(f, "{val}"),
347            Offset::RealTime(val, unit) => write!(f, "{val}{unit}"),
348        }
349    }
350}
351
352impl Display for TimeUnit {
353    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
354        write!(
355            f,
356            "{}",
357            match self {
358                TimeUnit::Nanosecond => "ns",
359                TimeUnit::Microsecond => "μs",
360                TimeUnit::Millisecond => "ms",
361                TimeUnit::Second => "s",
362                TimeUnit::Minute => "min",
363                TimeUnit::Hour => "h",
364                TimeUnit::Day => "d",
365                TimeUnit::Week => "w",
366                TimeUnit::Year => "a",
367            }
368        )
369    }
370}
371
372impl Display for WindowOperation {
373    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
374        let op_str = match self {
375            WindowOperation::Sum => "Σ",
376            WindowOperation::Product => "Π",
377            WindowOperation::Average => "avg",
378            WindowOperation::Count => "#",
379            WindowOperation::Integral => "∫",
380            WindowOperation::Min => "min",
381            WindowOperation::Max => "max",
382            WindowOperation::Disjunction => "∃",
383            WindowOperation::Conjunction => "∀",
384            WindowOperation::Last => "last",
385            WindowOperation::Variance => "σ²",
386            WindowOperation::Covariance => "cov",
387            WindowOperation::StandardDeviation => "σ",
388            WindowOperation::NthPercentile(p) => return write!(f, "pctl{p}"),
389            WindowOperation::TrueRatio => "true_ratio",
390        };
391        write!(f, "{op_str}")
392    }
393}
394
395impl Display for UnOp {
396    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
397        write!(
398            f,
399            "{}",
400            match self {
401                UnOp::Not => "!",
402                UnOp::Neg => "-",
403                UnOp::BitNot => "~",
404            }
405        )
406    }
407}
408
409impl Display for Literal {
410    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
411        match &self.kind {
412            LitKind::Bool(val) => write!(f, "{val}"),
413            LitKind::Numeric(val, unit) => write!(f, "{}{}", val, unit.clone().unwrap_or_default()),
414            LitKind::Str(s) => write!(f, "\"{s}\""),
415            LitKind::Tuple(elements) => write_delim_list(f, elements, "(", ")", ", "),
416            LitKind::RawStr(s) => {
417                // need to determine padding with `#`
418                let mut padding = 0;
419                while s.contains(&format!("{}\"", "#".repeat(padding))) {
420                    padding += 1;
421                }
422                write!(f, "r{pad}\"{}\"{pad}", s, pad = "#".repeat(padding))
423            }
424        }
425    }
426}
427
428impl Display for Ident {
429    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
430        write!(f, "{}", self.name)
431    }
432}
433
434impl Display for InstanceSelection {
435    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
436        match self {
437            InstanceSelection::Fresh => write!(f, "fresh"),
438            InstanceSelection::All => write!(f, "all"),
439            InstanceSelection::FilteredFresh(lambda) => write!(f, "fresh(where: {lambda})",),
440            InstanceSelection::FilteredAll(lambda) => write!(f, "all(where: {lambda})"),
441        }
442    }
443}
444
445impl Display for InstanceOperation {
446    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
447        let wo: WindowOperation = (*self).into();
448        wo.fmt(f)
449    }
450}
451
452impl Display for BinOp {
453    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
454        use BinOp::*;
455        match &self {
456            // Arithmetic
457            Add => write!(f, "+"),
458            Sub => write!(f, "-"),
459            Mul => write!(f, "*"),
460            Div => write!(f, "/"),
461            Rem => write!(f, "%"),
462            Pow => write!(f, "**"),
463            // Logical
464            And => write!(f, "∧"),
465            Or => write!(f, "∨"),
466            Implies => write!(f, "->"),
467            // Comparison
468            Eq => write!(f, "="),
469            Lt => write!(f, "<"),
470            Le => write!(f, "≤"),
471            Ne => write!(f, "≠"),
472            Gt => write!(f, ">"),
473            Ge => write!(f, "≥"),
474            // Bitwise
475            BitAnd => write!(f, "&"),
476            BitOr => write!(f, "|"),
477            BitXor => write!(f, "^"),
478            Shl => write!(f, "<<"),
479            Shr => write!(f, ">>"),
480        }
481    }
482}
483
484impl Display for Import {
485    fn fmt(&self, f: &mut Formatter) -> Result {
486        write!(f, "import {}", self.name)
487    }
488}
489
490impl Display for RtLolaAst {
491    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
492        format_tags(f, &self.global_tags, true)?;
493        for import in &self.imports {
494            writeln!(f, "{import}")?;
495        }
496        for decl in &self.type_declarations {
497            writeln!(f, "{decl}")?;
498        }
499        for constant in &self.constants {
500            writeln!(f, "{constant}")?;
501        }
502        for input in &self.inputs {
503            writeln!(f, "{input}")?;
504        }
505        for output in &self.outputs {
506            writeln!(f, "{output}")?;
507        }
508        for mirror in &self.mirrors {
509            writeln!(f, "{mirror}")?;
510        }
511        Ok(())
512    }
513}
514
515impl Display for NodeId {
516    fn fmt(&self, f: &mut Formatter) -> Result {
517        write!(f, "{}", self.0)
518    }
519}