Skip to main content

wgsl_parse/
syntax_display.rs

1use crate::{span::Spanned, syntax::*};
2use core::fmt;
3use std::fmt::{Display, Formatter};
4
5use itertools::Itertools;
6
7// unstable: https://doc.rust-lang.org/std/fmt/struct.FormatterFn.html
8struct FormatFn<F: (Fn(&mut Formatter) -> fmt::Result)>(F);
9
10impl<F: Fn(&mut Formatter) -> fmt::Result> Display for FormatFn<F> {
11    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
12        (self.0)(f)
13    }
14}
15
16impl<T: Display> Display for Spanned<T> {
17    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
18        self.node().fmt(f)
19    }
20}
21
22struct Indent<T: Display>(pub T);
23
24impl<T: Display> Display for Indent<T> {
25    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
26        let indent = "    ";
27        let inner_display = self.0.to_string();
28        let fmt = inner_display
29            .lines()
30            .format_with("\n", |l, f| f(&format_args!("{indent}{l}")));
31        write!(f, "{fmt}")?;
32        Ok(())
33    }
34}
35
36impl Display for TranslationUnit {
37    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
38        if !self.imports.is_empty() {
39            for import in &self.imports {
40                writeln!(f, "{import}\n")?;
41            }
42        }
43        if !self.global_directives.is_empty() {
44            let directives = self.global_directives.iter().format("\n");
45            write!(f, "{directives}\n\n")?;
46        }
47        let declarations = self
48            .global_declarations
49            .iter()
50            .filter(|decl| !matches!(decl.node(), GlobalDeclaration::Void))
51            .format("\n\n");
52        writeln!(f, "{declarations}")
53    }
54}
55
56impl Display for Ident {
57    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
58        write!(f, "{}", self.name())
59    }
60}
61
62impl Display for Visibility {
63    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
64        match self {
65            Visibility::Private => f.write_str("private"),
66            Visibility::Package => f.write_str("package"),
67            Visibility::Public => f.write_str("public"),
68        }
69    }
70}
71
72impl Display for ImportStatement {
73    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
74        write!(
75            f,
76            "{}{}",
77            fmt_attrs(&self.attributes, false),
78            fmt_visibility(self.visibility)
79        )?;
80        let content = &self.content;
81        if let Some(path) = &self.path {
82            write!(f, "import {path}::{content};")
83        } else {
84            write!(f, "import {content};")
85        }
86    }
87}
88
89impl Display for ModulePath {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        match &self.origin {
92            PathOrigin::Absolute => write!(f, "package")?,
93            PathOrigin::Relative(0) => write!(f, "self")?,
94            PathOrigin::Relative(n) => write!(f, "{}", (0..*n).map(|_| "super").format("::"))?,
95            PathOrigin::Package(p) => write!(f, "{p}")?,
96        };
97        if !self.components.is_empty() {
98            write!(f, "::{}", self.components.iter().format("::"))?;
99        }
100        Ok(())
101    }
102}
103
104impl Display for Import {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        if !self.path.is_empty() {
107            let path = self.path.iter().format("::");
108            write!(f, "{path}::")?;
109        }
110        let content = &self.content;
111        write!(f, "{content}")
112    }
113}
114
115impl Display for ImportContent {
116    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117        match self {
118            ImportContent::Item(item) => {
119                write!(f, "{}", item.ident)?;
120                if let Some(rename) = &item.rename {
121                    write!(f, " as {rename}")?;
122                }
123                Ok(())
124            }
125            ImportContent::Collection(coll) => {
126                let coll = coll.iter().format(", ");
127                write!(f, "{{ {coll} }}")
128            }
129        }
130    }
131}
132
133impl Display for GlobalDirective {
134    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
135        match self {
136            GlobalDirective::Diagnostic(print) => write!(f, "{print}"),
137            GlobalDirective::Enable(print) => write!(f, "{print}"),
138            GlobalDirective::Requires(print) => write!(f, "{print}"),
139        }
140    }
141}
142
143impl Display for DiagnosticDirective {
144    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
145        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
146        let severity = &self.severity;
147        let rule = &self.rule_name;
148        write!(f, "diagnostic ({severity}, {rule});")
149    }
150}
151
152impl Display for EnableDirective {
153    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
154        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
155        let exts = self.extensions.iter().format(", ");
156        write!(f, "enable {exts};")
157    }
158}
159
160impl Display for RequiresDirective {
161    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
162        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
163        let exts = self.extensions.iter().format(", ");
164        write!(f, "requires {exts};")
165    }
166}
167
168impl Display for GlobalDeclaration {
169    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
170        match self {
171            GlobalDeclaration::Void => write!(f, ";"),
172            GlobalDeclaration::Declaration(print) => write!(f, "{print}"),
173            GlobalDeclaration::TypeAlias(print) => write!(f, "{print}"),
174            GlobalDeclaration::Struct(print) => write!(f, "{print}"),
175            GlobalDeclaration::Function(print) => write!(f, "{print}"),
176            GlobalDeclaration::ConstAssert(print) => write!(f, "{print}"),
177            GlobalDeclaration::Compound(print) => write!(f, "{print}"),
178        }
179    }
180}
181
182impl Display for Declaration {
183    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
184        write!(
185            f,
186            "{}{}",
187            fmt_attrs(&self.attributes, false),
188            fmt_visibility(self.visibility)
189        )?;
190        let kind = &self.kind;
191        let name = &self.ident;
192        let ty = self
193            .ty
194            .iter()
195            .format_with("", |ty, f| f(&format_args!(": {ty}")));
196        let init = self
197            .initializer
198            .iter()
199            .format_with("", |ty, f| f(&format_args!(" = {ty}")));
200        write!(f, "{kind} {name}{ty}{init};")
201    }
202}
203
204impl Display for DeclarationKind {
205    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
206        match self {
207            Self::Const => write!(f, "const"),
208            Self::Override => write!(f, "override"),
209            Self::Let => write!(f, "let"),
210            Self::Var(None) => write!(f, "var"),
211            Self::Var(Some((a_s, None))) => write!(f, "var<{a_s}>"),
212            Self::Var(Some((a_s, Some(a_m)))) => write!(f, "var<{a_s}, {a_m}>"),
213        }
214    }
215}
216
217impl Display for TypeAlias {
218    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
219        write!(
220            f,
221            "{}{}",
222            fmt_attrs(&self.attributes, false),
223            fmt_visibility(self.visibility)
224        )?;
225        let name = &self.ident;
226        let ty = &self.ty;
227        write!(f, "alias {name} = {ty};")
228    }
229}
230
231impl Display for Struct {
232    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
233        write!(
234            f,
235            "{}{}",
236            fmt_attrs(&self.attributes, false),
237            fmt_visibility(self.visibility)
238        )?;
239        let name = &self.ident;
240        let members = Indent(self.members.iter().format(",\n"));
241        write!(f, "struct {name} {{\n{members}\n}}")
242    }
243}
244
245impl Display for StructMember {
246    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
247        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
248        let name = &self.ident;
249        let ty = &self.ty;
250        write!(f, "{name}: {ty}")
251    }
252}
253
254impl Display for Function {
255    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
256        write!(
257            f,
258            "{}{}",
259            fmt_attrs(&self.attributes, false),
260            fmt_visibility(self.visibility)
261        )?;
262        let name = &self.ident;
263        let params = self.parameters.iter().format(", ");
264        let ret_ty = self.return_type.iter().format_with("", |ty, f| {
265            f(&FormatFn(|f: &mut Formatter| {
266                write!(f, "-> ")?;
267                write!(f, "{}", fmt_attrs(&self.return_attributes, true))?;
268                write!(f, "{ty} ")?;
269                Ok(())
270            }))
271        });
272        let body = &self.body;
273        write!(f, "fn {name}({params}) {ret_ty}{body}")
274    }
275}
276
277impl Display for FormalParameter {
278    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
279        write!(f, "{}", fmt_attrs(&self.attributes, true))?;
280        let name = &self.ident;
281        let ty = &self.ty;
282        write!(f, "{name}: {ty}")
283    }
284}
285
286impl Display for ConstAssert {
287    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
288        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
289        let expr = &self.expression;
290        write!(f, "const_assert {expr};",)
291    }
292}
293
294impl Display for CompoundGlobalDeclaration {
295    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
296        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
297        let stmts = Indent(self.body.iter().format("\n"));
298        write!(f, "{{\n{stmts}\n}}")
299    }
300}
301
302impl Display for Attribute {
303    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
304        match self {
305            Attribute::Align(e1) => write!(f, "@align({e1})"),
306            Attribute::Binding(e1) => write!(f, "@binding({e1})"),
307            Attribute::BlendSrc(e1) => write!(f, "@blend_src({e1})"),
308            Attribute::Builtin(e1) => write!(f, "@builtin({e1})"),
309            Attribute::Const => write!(f, "@const"),
310            Attribute::Diagnostic(DiagnosticAttribute { severity, rule }) => {
311                write!(f, "@diagnostic({severity}, {rule})")
312            }
313            Attribute::Group(e1) => write!(f, "@group({e1})"),
314            Attribute::Id(e1) => write!(f, "@id({e1})"),
315            Attribute::Interpolate(InterpolateAttribute { ty, sampling }) => {
316                if let Some(sampling) = sampling {
317                    write!(f, "@interpolate({ty}, {sampling})")
318                } else {
319                    write!(f, "@interpolate({ty})")
320                }
321            }
322            Attribute::Invariant => write!(f, "@invariant"),
323            Attribute::Location(e1) => write!(f, "@location({e1})"),
324            Attribute::MustUse => write!(f, "@must_use"),
325            Attribute::Size(e1) => write!(f, "@size({e1})"),
326            Attribute::WorkgroupSize(WorkgroupSizeAttribute { x, y, z }) => {
327                let xyz = std::iter::once(x).chain(y).chain(z).format(", ");
328                write!(f, "@workgroup_size({xyz})")
329            }
330            Attribute::Vertex => write!(f, "@vertex"),
331            Attribute::Fragment => write!(f, "@fragment"),
332            Attribute::Compute => write!(f, "@compute"),
333
334            // wesl extensions
335            Attribute::If(e1) => write!(f, "@if({e1})"),
336            Attribute::Elif(e1) => write!(f, "@elif({e1})"),
337            Attribute::Else => write!(f, "@else"),
338            #[cfg(feature = "generics")]
339            Attribute::Type(e1) => write!(f, "@type({e1})"),
340
341            // naga extensions
342            #[cfg(feature = "naga-ext")]
343            Attribute::Task => write!(f, "@task"),
344            #[cfg(feature = "naga-ext")]
345            Attribute::Payload(p) => write!(f, "@payload({p})"),
346            #[cfg(feature = "naga-ext")]
347            Attribute::Mesh(m) => write!(f, "@mesh({m})"),
348            #[cfg(feature = "naga-ext")]
349            Attribute::RayGeneration => write!(f, "@ray_generation"),
350            #[cfg(feature = "naga-ext")]
351            Attribute::AnyHit => write!(f, "@any_hit"),
352            #[cfg(feature = "naga-ext")]
353            Attribute::ClosestHit => write!(f, "@closest_hit"),
354            #[cfg(feature = "naga-ext")]
355            Attribute::Miss => write!(f, "@miss"),
356            #[cfg(feature = "naga-ext")]
357            Attribute::IncomingPayload(p) => write!(f, "@incoming_payload({p})"),
358            #[cfg(feature = "naga-ext")]
359            Attribute::EarlyDepthTest(None) => write!(f, "@early_depth_test"),
360            #[cfg(feature = "naga-ext")]
361            Attribute::EarlyDepthTest(Some(e1)) => write!(f, "@early_depth_test({e1})"),
362            Attribute::Custom(custom) => {
363                let name = &custom.name;
364                let args = custom.arguments.iter().format_with("", |args, f| {
365                    f(&format_args!("({})", args.iter().format(", ")))
366                });
367                write!(f, "@{name}{args}")
368            }
369        }
370    }
371}
372
373#[cfg(feature = "generics")]
374impl Display for TypeConstraint {
375    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
376        let name = &self.ident;
377        let variants = self.variants.iter().format(" | ");
378        write!(f, "{name}, {variants}")
379    }
380}
381
382fn fmt_attrs(attrs: &[AttributeNode], inline: bool) -> impl fmt::Display + '_ {
383    FormatFn(move |f| {
384        let print = attrs.iter().format(" ");
385        let suffix = if attrs.is_empty() {
386            ""
387        } else if inline {
388            " "
389        } else {
390            "\n"
391        };
392        write!(f, "{print}{suffix}")
393    })
394}
395
396fn fmt_visibility(vis: Visibility) -> impl fmt::Display {
397    FormatFn(move |f| match vis {
398        Visibility::Public => f.write_str("public "),
399        Visibility::Package => Ok(()),
400        Visibility::Private => f.write_str("private "),
401    })
402}
403
404impl Display for Expression {
405    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
406        match self {
407            Expression::Literal(print) => write!(f, "{print}"),
408            Expression::Parenthesized(print) => {
409                write!(f, "{print}")
410            }
411            Expression::NamedComponent(print) => write!(f, "{print}"),
412            Expression::Indexing(print) => write!(f, "{print}"),
413            Expression::Unary(print) => write!(f, "{print}"),
414            Expression::Binary(print) => write!(f, "{print}"),
415            Expression::FunctionCall(print) => write!(f, "{print}"),
416            Expression::TypeOrIdentifier(print) => write!(f, "{print}"),
417        }
418    }
419}
420
421impl Display for LiteralExpression {
422    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
423        match self {
424            LiteralExpression::Bool(true) => write!(f, "true"),
425            LiteralExpression::Bool(false) => write!(f, "false"),
426            LiteralExpression::AbstractInt(num) => write!(f, "{num}"),
427            LiteralExpression::AbstractFloat(num) => write!(f, "{num:?}"), // using the Debug formatter to print the trailing .0 in floats representing integers. because format!("{}", 3.0f32) == "3"
428            LiteralExpression::I32(num) => write!(f, "{num}i"),
429            LiteralExpression::U32(num) => write!(f, "{num}u"),
430            LiteralExpression::F32(num) => write!(f, "{num}f"),
431            LiteralExpression::F16(num) => write!(f, "{num}h"),
432            #[cfg(feature = "naga-ext")]
433            LiteralExpression::I64(num) => write!(f, "{num}li"),
434            #[cfg(feature = "naga-ext")]
435            LiteralExpression::U64(num) => write!(f, "{num}lu"),
436            #[cfg(feature = "naga-ext")]
437            LiteralExpression::F64(num) => write!(f, "{num}lf"),
438        }
439    }
440}
441
442impl Display for ParenthesizedExpression {
443    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
444        let expr = &self.expression;
445        write!(f, "({expr})")
446    }
447}
448
449impl Display for NamedComponentExpression {
450    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
451        let base = &self.base;
452        let component = &self.component;
453        write!(f, "{base}.{component}")
454    }
455}
456
457impl Display for IndexingExpression {
458    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
459        let base = &self.base;
460        let index = &self.index;
461        write!(f, "{base}[{index}]")
462    }
463}
464
465impl Display for UnaryExpression {
466    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
467        let operator = &self.operator;
468        let operand = &self.operand;
469        write!(f, "{operator}{operand}")
470    }
471}
472
473impl Display for BinaryExpression {
474    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
475        let operator = &self.operator;
476        let left = &self.left;
477        let right = &self.right;
478        write!(f, "{left} {operator} {right}")
479    }
480}
481
482impl Display for FunctionCall {
483    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
484        let ty = &self.ty;
485        let args = self.arguments.iter().format(", ");
486        write!(f, "{ty}({args})")
487    }
488}
489
490impl Display for TypeExpression {
491    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
492        if let Some(path) = &self.path {
493            write!(f, "{path}::")?;
494        }
495
496        let name = &self.ident;
497        let tplt = fmt_template(&self.template_args);
498        write!(f, "{name}{tplt}")
499    }
500}
501
502impl Display for TemplateArg {
503    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
504        let expr = &self.expression;
505        write!(f, "{expr}")
506    }
507}
508
509fn fmt_template(tplt: &Option<Vec<TemplateArg>>) -> impl fmt::Display + '_ {
510    tplt.iter().format_with("", |tplt, f| {
511        f(&format_args!("<{}>", tplt.iter().format(", ")))
512    })
513}
514
515impl Display for Statement {
516    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
517        match self {
518            Statement::Void => write!(f, ";"),
519            Statement::Compound(print) => write!(f, "{print}"),
520            Statement::Assignment(print) => write!(f, "{print}"),
521            Statement::Increment(print) => write!(f, "{print}"),
522            Statement::Decrement(print) => write!(f, "{print}"),
523            Statement::If(print) => write!(f, "{print}"),
524            Statement::Switch(print) => write!(f, "{print}"),
525            Statement::Loop(print) => write!(f, "{print}"),
526            Statement::For(print) => write!(f, "{print}"),
527            Statement::While(print) => write!(f, "{print}"),
528            Statement::Break(print) => write!(f, "{print}"),
529            Statement::Continue(print) => write!(f, "{print}"),
530            Statement::Return(print) => write!(f, "{print}"),
531            Statement::Discard(print) => write!(f, "{print}"),
532            Statement::FunctionCall(print) => write!(f, "{print}"),
533            Statement::ConstAssert(print) => write!(f, "{print}"),
534            Statement::Declaration(print) => write!(f, "{print}"),
535        }
536    }
537}
538
539impl Display for CompoundStatement {
540    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
541        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
542        let stmts = Indent(
543            self.statements
544                .iter()
545                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
546                .format("\n"),
547        );
548        write!(f, "{{\n{stmts}\n}}")
549    }
550}
551
552impl Display for AssignmentStatement {
553    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
554        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
555        let operator = &self.operator;
556        let lhs = &self.lhs;
557        let rhs = &self.rhs;
558        write!(f, "{lhs} {operator} {rhs};")
559    }
560}
561
562impl Display for IncrementStatement {
563    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
564        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
565        let expr = &self.expression;
566        write!(f, "{expr}++;")
567    }
568}
569
570impl Display for DecrementStatement {
571    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
572        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
573        let expr = &self.expression;
574        write!(f, "{expr}--;")
575    }
576}
577
578impl Display for IfStatement {
579    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
580        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
581        let if_clause = &self.if_clause;
582        write!(f, "{if_clause}")?;
583        for else_if_clause in self.else_if_clauses.iter() {
584            write!(f, "\n{else_if_clause}")?;
585        }
586        if let Some(else_clause) = &self.else_clause {
587            write!(f, "\n{else_clause}")?;
588        }
589        Ok(())
590    }
591}
592
593impl Display for IfClause {
594    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
595        let expr = &self.expression;
596        let stmt = &self.body;
597        write!(f, "if {expr} {stmt}")
598    }
599}
600
601impl Display for ElseIfClause {
602    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
603        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
604        let expr = &self.expression;
605        let stmt = &self.body;
606        write!(f, "else if {expr} {stmt}")
607    }
608}
609
610impl Display for ElseClause {
611    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
612        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
613        let stmt = &self.body;
614        write!(f, "else {stmt}")
615    }
616}
617
618impl Display for SwitchStatement {
619    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
620        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
621        let expr = &self.expression;
622        let body_attrs = fmt_attrs(&self.body_attributes, false);
623        let clauses = Indent(self.clauses.iter().format("\n"));
624        write!(f, "switch {expr} {body_attrs}{{\n{clauses}\n}}")
625    }
626}
627
628impl Display for SwitchClause {
629    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
630        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
631        let cases = self.case_selectors.iter().format(", ");
632        let body = &self.body;
633        write!(f, "case {cases} {body}")
634    }
635}
636
637impl Display for CaseSelector {
638    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
639        match self {
640            CaseSelector::Default => write!(f, "default"),
641            CaseSelector::Expression(expr) => {
642                write!(f, "{expr}")
643            }
644        }
645    }
646}
647
648impl Display for LoopStatement {
649    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
650        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
651        let body_attrs = fmt_attrs(&self.body.attributes, false);
652        let stmts = Indent(
653            self.body
654                .statements
655                .iter()
656                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
657                .format("\n"),
658        );
659        let continuing = self
660            .continuing
661            .iter()
662            .format_with("", |cont, f| f(&format_args!("{}\n", Indent(cont))));
663        write!(f, "loop {body_attrs}{{\n{stmts}\n{continuing}}}")
664    }
665}
666
667impl Display for ContinuingStatement {
668    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
669        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
670        let body_attrs = fmt_attrs(&self.body.attributes, false);
671        let stmts = Indent(
672            self.body
673                .statements
674                .iter()
675                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
676                .format("\n"),
677        );
678        let break_if = self
679            .break_if
680            .iter()
681            .format_with("", |stmt, f| f(&format_args!("{}\n", Indent(stmt))));
682        write!(f, "continuing {body_attrs}{{\n{stmts}\n{break_if}}}")
683    }
684}
685
686impl Display for BreakIfStatement {
687    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
688        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
689        let expr = &self.expression;
690        write!(f, "break if {expr};")
691    }
692}
693
694impl Display for ForStatement {
695    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
696        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
697        let mut init = self
698            .initializer
699            .as_ref()
700            .map(|stmt| format!("{stmt}"))
701            .unwrap_or_default();
702        if init.ends_with(';') {
703            init.pop();
704        }
705        let cond = self
706            .condition
707            .iter()
708            .format_with("", |expr, f| f(&format_args!("{expr}")));
709        let mut updt = self
710            .update
711            .as_ref()
712            .map(|stmt| format!("{stmt}"))
713            .unwrap_or_default();
714        if updt.ends_with(';') {
715            updt.pop();
716        }
717        let body = &self.body;
718        write!(f, "for ({init}; {cond}; {updt}) {body}")
719    }
720}
721
722impl Display for WhileStatement {
723    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
724        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
725        let cond = &self.condition;
726        let body = &self.body;
727        write!(f, "while {cond} {body}")
728    }
729}
730
731impl Display for BreakStatement {
732    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
733        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
734        write!(f, "break;")
735    }
736}
737
738impl Display for ContinueStatement {
739    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
740        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
741        write!(f, "continue;")
742    }
743}
744
745impl Display for ReturnStatement {
746    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
747        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
748        let expr = self
749            .expression
750            .iter()
751            .format_with("", |expr, f| f(&format_args!(" {expr}")));
752        write!(f, "return{expr};")
753    }
754}
755
756impl Display for DiscardStatement {
757    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
758        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
759        write!(f, "discard;")
760    }
761}
762
763impl Display for FunctionCallStatement {
764    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
765        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
766        let call = &self.call;
767        write!(f, "{call};")
768    }
769}
770
771#[cfg(test)]
772mod test {
773    use crate::syntax::ModulePath;
774    use crate::syntax::{Ident, TypeExpression};
775
776    #[test]
777    fn type_expression_display() {
778        let expr = TypeExpression {
779            path: None,
780            ident: Ident::new("foo".into()),
781            template_args: None,
782        };
783
784        assert_eq!(expr.to_string(), "foo");
785
786        let expr = TypeExpression {
787            path: Some(ModulePath::new(
788                crate::syntax::PathOrigin::Absolute,
789                vec!["bar".into(), "qux".into()],
790            )),
791            ident: Ident::new("foo".into()),
792            template_args: None,
793        };
794
795        assert_eq!(expr.to_string(), "package::bar::qux::foo");
796    }
797}