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