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