1use std::fmt::{Display, Formatter, Result};
4
5use itertools::Itertools;
6
7use crate::ast::*;
8
9fn 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
28fn 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
37fn 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 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 Add => write!(f, "+"),
458 Sub => write!(f, "-"),
459 Mul => write!(f, "*"),
460 Div => write!(f, "/"),
461 Rem => write!(f, "%"),
462 Pow => write!(f, "**"),
463 And => write!(f, "∧"),
465 Or => write!(f, "∨"),
466 Implies => write!(f, "->"),
467 Eq => write!(f, "="),
469 Lt => write!(f, "<"),
470 Le => write!(f, "≤"),
471 Ne => write!(f, "≠"),
472 Gt => write!(f, ">"),
473 Ge => write!(f, "≥"),
474 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}