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