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        }
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 = "naga-ext")]
301            Attribute::Task => write!(f, "@task"),
302            #[cfg(feature = "naga-ext")]
303            Attribute::Payload(p) => write!(f, "@payload({p})"),
304            #[cfg(feature = "naga-ext")]
305            Attribute::Mesh(m) => write!(f, "@mesh({m})"),
306            #[cfg(feature = "imports")]
307            Attribute::Publish => write!(f, "@publish"),
308            #[cfg(feature = "condcomp")]
309            Attribute::If(e1) => write!(f, "@if({e1})"),
310            #[cfg(feature = "condcomp")]
311            Attribute::Elif(e1) => write!(f, "@elif({e1})"),
312            #[cfg(feature = "condcomp")]
313            Attribute::Else => write!(f, "@else"),
314            #[cfg(feature = "generics")]
315            Attribute::Type(e1) => write!(f, "@type({e1})"),
316            #[cfg(feature = "naga-ext")]
317            Attribute::EarlyDepthTest(None) => write!(f, "@early_depth_test"),
318            #[cfg(feature = "naga-ext")]
319            Attribute::EarlyDepthTest(Some(e1)) => write!(f, "@early_depth_test({e1})"),
320            Attribute::Custom(custom) => {
321                let name = &custom.name;
322                let args = custom.arguments.iter().format_with("", |args, f| {
323                    f(&format_args!("({})", args.iter().format(", ")))
324                });
325                write!(f, "@{name}{args}")
326            }
327        }
328    }
329}
330
331#[cfg(feature = "generics")]
332impl Display for TypeConstraint {
333    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
334        let name = &self.ident;
335        let variants = self.variants.iter().format(" | ");
336        write!(f, "{name}, {variants}")
337    }
338}
339
340fn fmt_attrs(attrs: &[AttributeNode], inline: bool) -> impl fmt::Display + '_ {
341    FormatFn(move |f| {
342        let print = attrs.iter().format(" ");
343        let suffix = if attrs.is_empty() {
344            ""
345        } else if inline {
346            " "
347        } else {
348            "\n"
349        };
350        write!(f, "{print}{suffix}")
351    })
352}
353
354impl Display for Expression {
355    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
356        match self {
357            Expression::Literal(print) => write!(f, "{print}"),
358            Expression::Parenthesized(print) => {
359                write!(f, "{print}")
360            }
361            Expression::NamedComponent(print) => write!(f, "{print}"),
362            Expression::Indexing(print) => write!(f, "{print}"),
363            Expression::Unary(print) => write!(f, "{print}"),
364            Expression::Binary(print) => write!(f, "{print}"),
365            Expression::FunctionCall(print) => write!(f, "{print}"),
366            Expression::TypeOrIdentifier(print) => write!(f, "{print}"),
367        }
368    }
369}
370
371impl Display for LiteralExpression {
372    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
373        match self {
374            LiteralExpression::Bool(true) => write!(f, "true"),
375            LiteralExpression::Bool(false) => write!(f, "false"),
376            LiteralExpression::AbstractInt(num) => write!(f, "{num}"),
377            LiteralExpression::AbstractFloat(num) => write!(f, "{num:?}"), // using the Debug formatter to print the trailing .0 in floats representing integers. because format!("{}", 3.0f32) == "3"
378            LiteralExpression::I32(num) => write!(f, "{num}i"),
379            LiteralExpression::U32(num) => write!(f, "{num}u"),
380            LiteralExpression::F32(num) => write!(f, "{num}f"),
381            LiteralExpression::F16(num) => write!(f, "{num}h"),
382            #[cfg(feature = "naga-ext")]
383            LiteralExpression::I64(num) => write!(f, "{num}li"),
384            #[cfg(feature = "naga-ext")]
385            LiteralExpression::U64(num) => write!(f, "{num}lu"),
386            #[cfg(feature = "naga-ext")]
387            LiteralExpression::F64(num) => write!(f, "{num}lf"),
388        }
389    }
390}
391
392impl Display for ParenthesizedExpression {
393    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
394        let expr = &self.expression;
395        write!(f, "({expr})")
396    }
397}
398
399impl Display for NamedComponentExpression {
400    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
401        let base = &self.base;
402        let component = &self.component;
403        write!(f, "{base}.{component}")
404    }
405}
406
407impl Display for IndexingExpression {
408    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
409        let base = &self.base;
410        let index = &self.index;
411        write!(f, "{base}[{index}]")
412    }
413}
414
415impl Display for UnaryExpression {
416    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
417        let operator = &self.operator;
418        let operand = &self.operand;
419        write!(f, "{operator}{operand}")
420    }
421}
422
423impl Display for BinaryExpression {
424    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
425        let operator = &self.operator;
426        let left = &self.left;
427        let right = &self.right;
428        write!(f, "{left} {operator} {right}")
429    }
430}
431
432impl Display for FunctionCall {
433    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
434        let ty = &self.ty;
435        let args = self.arguments.iter().format(", ");
436        write!(f, "{ty}({args})")
437    }
438}
439
440impl Display for TypeExpression {
441    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
442        #[cfg(feature = "imports")]
443        if let Some(path) = &self.path {
444            write!(f, "{path}::")?;
445        }
446
447        let name = &self.ident;
448        let tplt = fmt_template(&self.template_args);
449        write!(f, "{name}{tplt}")
450    }
451}
452
453impl Display for TemplateArg {
454    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
455        let expr = &self.expression;
456        write!(f, "{expr}")
457    }
458}
459
460fn fmt_template(tplt: &Option<Vec<TemplateArg>>) -> impl fmt::Display + '_ {
461    tplt.iter().format_with("", |tplt, f| {
462        f(&format_args!("<{}>", tplt.iter().format(", ")))
463    })
464}
465
466impl Display for Statement {
467    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
468        match self {
469            Statement::Void => write!(f, ";"),
470            Statement::Compound(print) => write!(f, "{print}"),
471            Statement::Assignment(print) => write!(f, "{print}"),
472            Statement::Increment(print) => write!(f, "{print}"),
473            Statement::Decrement(print) => write!(f, "{print}"),
474            Statement::If(print) => write!(f, "{print}"),
475            Statement::Switch(print) => write!(f, "{print}"),
476            Statement::Loop(print) => write!(f, "{print}"),
477            Statement::For(print) => write!(f, "{print}"),
478            Statement::While(print) => write!(f, "{print}"),
479            Statement::Break(print) => write!(f, "{print}"),
480            Statement::Continue(print) => write!(f, "{print}"),
481            Statement::Return(print) => write!(f, "{print}"),
482            Statement::Discard(print) => write!(f, "{print}"),
483            Statement::FunctionCall(print) => write!(f, "{print}"),
484            Statement::ConstAssert(print) => write!(f, "{print}"),
485            Statement::Declaration(print) => write!(f, "{print}"),
486        }
487    }
488}
489
490impl Display for CompoundStatement {
491    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
492        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
493        let stmts = Indent(
494            self.statements
495                .iter()
496                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
497                .format("\n"),
498        );
499        write!(f, "{{\n{stmts}\n}}")
500    }
501}
502
503impl Display for AssignmentStatement {
504    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
505        #[cfg(feature = "attributes")]
506        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
507        let operator = &self.operator;
508        let lhs = &self.lhs;
509        let rhs = &self.rhs;
510        write!(f, "{lhs} {operator} {rhs};")
511    }
512}
513
514impl Display for IncrementStatement {
515    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
516        #[cfg(feature = "attributes")]
517        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
518        let expr = &self.expression;
519        write!(f, "{expr}++;")
520    }
521}
522
523impl Display for DecrementStatement {
524    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
525        #[cfg(feature = "attributes")]
526        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
527        let expr = &self.expression;
528        write!(f, "{expr}--;")
529    }
530}
531
532impl Display for IfStatement {
533    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
534        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
535        let if_clause = &self.if_clause;
536        write!(f, "{if_clause}")?;
537        for else_if_clause in self.else_if_clauses.iter() {
538            write!(f, "\n{else_if_clause}")?;
539        }
540        if let Some(else_clause) = &self.else_clause {
541            write!(f, "\n{else_clause}")?;
542        }
543        Ok(())
544    }
545}
546
547impl Display for IfClause {
548    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
549        let expr = &self.expression;
550        let stmt = &self.body;
551        write!(f, "if {expr} {stmt}")
552    }
553}
554
555impl Display for ElseIfClause {
556    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
557        #[cfg(feature = "attributes")]
558        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
559        let expr = &self.expression;
560        let stmt = &self.body;
561        write!(f, "else if {expr} {stmt}")
562    }
563}
564
565impl Display for ElseClause {
566    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
567        #[cfg(feature = "attributes")]
568        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
569        let stmt = &self.body;
570        write!(f, "else {stmt}")
571    }
572}
573
574impl Display for SwitchStatement {
575    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
576        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
577        let expr = &self.expression;
578        let body_attrs = fmt_attrs(&self.body_attributes, false);
579        let clauses = Indent(self.clauses.iter().format("\n"));
580        write!(f, "switch {expr} {body_attrs}{{\n{clauses}\n}}")
581    }
582}
583
584impl Display for SwitchClause {
585    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
586        #[cfg(feature = "attributes")]
587        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
588        let cases = self.case_selectors.iter().format(", ");
589        let body = &self.body;
590        write!(f, "case {cases} {body}")
591    }
592}
593
594impl Display for CaseSelector {
595    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
596        match self {
597            CaseSelector::Default => write!(f, "default"),
598            CaseSelector::Expression(expr) => {
599                write!(f, "{expr}")
600            }
601        }
602    }
603}
604
605impl Display for LoopStatement {
606    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
607        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
608        let body_attrs = fmt_attrs(&self.body.attributes, false);
609        let stmts = Indent(
610            self.body
611                .statements
612                .iter()
613                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
614                .format("\n"),
615        );
616        let continuing = self
617            .continuing
618            .iter()
619            .format_with("", |cont, f| f(&format_args!("{}\n", Indent(cont))));
620        write!(f, "loop {body_attrs}{{\n{stmts}\n{continuing}}}")
621    }
622}
623
624impl Display for ContinuingStatement {
625    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
626        #[cfg(feature = "attributes")]
627        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
628        let body_attrs = fmt_attrs(&self.body.attributes, false);
629        let stmts = Indent(
630            self.body
631                .statements
632                .iter()
633                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
634                .format("\n"),
635        );
636        let break_if = self
637            .break_if
638            .iter()
639            .format_with("", |stmt, f| f(&format_args!("{}\n", Indent(stmt))));
640        write!(f, "continuing {body_attrs}{{\n{stmts}\n{break_if}}}")
641    }
642}
643
644impl Display for BreakIfStatement {
645    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
646        #[cfg(feature = "attributes")]
647        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
648        let expr = &self.expression;
649        write!(f, "break if {expr};")
650    }
651}
652
653impl Display for ForStatement {
654    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
655        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
656        let mut init = self
657            .initializer
658            .as_ref()
659            .map(|stmt| format!("{stmt}"))
660            .unwrap_or_default();
661        if init.ends_with(';') {
662            init.pop();
663        }
664        let cond = self
665            .condition
666            .iter()
667            .format_with("", |expr, f| f(&format_args!("{expr}")));
668        let mut updt = self
669            .update
670            .as_ref()
671            .map(|stmt| format!("{stmt}"))
672            .unwrap_or_default();
673        if updt.ends_with(';') {
674            updt.pop();
675        }
676        let body = &self.body;
677        write!(f, "for ({init}; {cond}; {updt}) {body}")
678    }
679}
680
681impl Display for WhileStatement {
682    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
683        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
684        let cond = &self.condition;
685        let body = &self.body;
686        write!(f, "while ({cond}) {body}")
687    }
688}
689
690impl Display for BreakStatement {
691    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
692        #[cfg(feature = "attributes")]
693        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
694        write!(f, "break;")
695    }
696}
697
698impl Display for ContinueStatement {
699    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
700        #[cfg(feature = "attributes")]
701        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
702        write!(f, "continue;")
703    }
704}
705
706impl Display for ReturnStatement {
707    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
708        #[cfg(feature = "attributes")]
709        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
710        let expr = self
711            .expression
712            .iter()
713            .format_with("", |expr, f| f(&format_args!(" {expr}")));
714        write!(f, "return{expr};")
715    }
716}
717
718impl Display for DiscardStatement {
719    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
720        #[cfg(feature = "attributes")]
721        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
722        write!(f, "discard;")
723    }
724}
725
726impl Display for FunctionCallStatement {
727    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
728        #[cfg(feature = "attributes")]
729        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
730        let call = &self.call;
731        write!(f, "{call};")
732    }
733}
734
735#[cfg(test)]
736mod test {
737    #[cfg(feature = "imports")]
738    use crate::syntax::ModulePath;
739    use crate::syntax::{Ident, TypeExpression};
740
741    #[test]
742    fn type_expression_display() {
743        let expr = TypeExpression {
744            #[cfg(feature = "imports")]
745            path: None,
746            ident: Ident::new("foo".into()),
747            template_args: None,
748        };
749
750        assert_eq!(expr.to_string(), "foo");
751
752        let expr = TypeExpression {
753            #[cfg(feature = "imports")]
754            path: Some(ModulePath::new(
755                crate::syntax::PathOrigin::Absolute,
756                vec!["bar".into(), "qux".into()],
757            )),
758            ident: Ident::new("foo".into()),
759            template_args: None,
760        };
761
762        if cfg!(feature = "imports") {
763            assert_eq!(expr.to_string(), "package::bar::qux::foo");
764        } else {
765            assert_eq!(expr.to_string(), "foo");
766        }
767    }
768}