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 DiagnosticSeverity {
144    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
145        match self {
146            Self::Error => write!(f, "error"),
147            Self::Warning => write!(f, "warning"),
148            Self::Info => write!(f, "info"),
149            Self::Off => write!(f, "off"),
150        }
151    }
152}
153
154impl Display for EnableDirective {
155    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
156        #[cfg(feature = "attributes")]
157        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
158        let exts = self.extensions.iter().format(", ");
159        write!(f, "enable {exts};")
160    }
161}
162
163impl Display for RequiresDirective {
164    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
165        #[cfg(feature = "attributes")]
166        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
167        let exts = self.extensions.iter().format(", ");
168        write!(f, "requires {exts};")
169    }
170}
171
172impl Display for GlobalDeclaration {
173    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
174        match self {
175            GlobalDeclaration::Void => write!(f, ";"),
176            GlobalDeclaration::Declaration(print) => write!(f, "{print}"),
177            GlobalDeclaration::TypeAlias(print) => write!(f, "{print}"),
178            GlobalDeclaration::Struct(print) => write!(f, "{print}"),
179            GlobalDeclaration::Function(print) => write!(f, "{print}"),
180            GlobalDeclaration::ConstAssert(print) => write!(f, "{print}"),
181        }
182    }
183}
184
185impl Display for Declaration {
186    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
187        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
188        let kind = &self.kind;
189        let name = &self.ident;
190        let ty = self
191            .ty
192            .iter()
193            .format_with("", |ty, f| f(&format_args!(": {ty}")));
194        let init = self
195            .initializer
196            .iter()
197            .format_with("", |ty, f| f(&format_args!(" = {ty}")));
198        write!(f, "{kind} {name}{ty}{init};")
199    }
200}
201
202impl Display for DeclarationKind {
203    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
204        match self {
205            Self::Const => write!(f, "const"),
206            Self::Override => write!(f, "override"),
207            Self::Let => write!(f, "let"),
208            Self::Var(addr_space) => match addr_space {
209                Some(addr_space) => write!(f, "var<{addr_space}>"),
210                None => write!(f, "var"),
211            },
212        }
213    }
214}
215
216impl Display for AddressSpace {
217    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
218        match self {
219            Self::Function => write!(f, "function"),
220            Self::Private => write!(f, "private"),
221            Self::Workgroup => write!(f, "workgroup"),
222            Self::Uniform => write!(f, "uniform"),
223            Self::Storage(access_mode) => match access_mode {
224                Some(access_mode) => write!(f, "storage, {access_mode}"),
225                None => write!(f, "storage"),
226            },
227            Self::Handle => write!(f, "handle"),
228            #[cfg(feature = "push_constant")]
229            Self::PushConstant => write!(f, "push_constant"),
230        }
231    }
232}
233
234impl Display for AccessMode {
235    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
236        match self {
237            Self::Read => write!(f, "read"),
238            Self::Write => write!(f, "write"),
239            Self::ReadWrite => write!(f, "read_write"),
240        }
241    }
242}
243
244impl Display for TypeAlias {
245    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
246        #[cfg(feature = "attributes")]
247        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
248        let name = &self.ident;
249        let ty = &self.ty;
250        write!(f, "alias {name} = {ty};")
251    }
252}
253
254impl Display for Struct {
255    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
256        #[cfg(feature = "attributes")]
257        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
258        let name = &self.ident;
259        let members = Indent(self.members.iter().format(",\n"));
260        write!(f, "struct {name} {{\n{members}\n}}")
261    }
262}
263
264impl Display for StructMember {
265    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
266        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
267        let name = &self.ident;
268        let ty = &self.ty;
269        write!(f, "{name}: {ty}")
270    }
271}
272
273impl Display for Function {
274    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
275        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
276        let name = &self.ident;
277        let params = self.parameters.iter().format(", ");
278        let ret_ty = self.return_type.iter().format_with("", |ty, f| {
279            f(&FormatFn(|f: &mut Formatter| {
280                write!(f, "-> ")?;
281                write!(f, "{}", fmt_attrs(&self.return_attributes, true))?;
282                write!(f, "{ty} ")?;
283                Ok(())
284            }))
285        });
286        let body = &self.body;
287        write!(f, "fn {name}({params}) {ret_ty}{body}")
288    }
289}
290
291impl Display for FormalParameter {
292    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
293        write!(f, "{}", fmt_attrs(&self.attributes, true))?;
294        let name = &self.ident;
295        let ty = &self.ty;
296        write!(f, "{name}: {ty}")
297    }
298}
299
300impl Display for ConstAssert {
301    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
302        #[cfg(feature = "attributes")]
303        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
304        let expr = &self.expression;
305        write!(f, "const_assert {expr};",)
306    }
307}
308
309impl Display for BuiltinValue {
310    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
311        match self {
312            Self::VertexIndex => write!(f, "vertex_index"),
313            Self::InstanceIndex => write!(f, "instance_index"),
314            Self::ClipDistances => write!(f, "clip_distances"),
315            Self::Position => write!(f, "position"),
316            Self::FrontFacing => write!(f, "front_facing"),
317            Self::FragDepth => write!(f, "frag_depth"),
318            Self::SampleIndex => write!(f, "sample_index"),
319            Self::SampleMask => write!(f, "sample_mask"),
320            Self::LocalInvocationId => write!(f, "local_invocation_id"),
321            Self::LocalInvocationIndex => write!(f, "local_invocation_index"),
322            Self::GlobalInvocationId => write!(f, "global_invocation_id"),
323            Self::WorkgroupId => write!(f, "workgroup_id"),
324            Self::NumWorkgroups => write!(f, "num_workgroups"),
325            Self::SubgroupInvocationId => write!(f, "subgroup_invocation_id"),
326            Self::SubgroupSize => write!(f, "subgroup_size"),
327            #[cfg(feature = "naga_ext")]
328            Self::PrimitiveIndex => write!(f, "primitive_index"),
329            #[cfg(feature = "naga_ext")]
330            Self::ViewIndex => write!(f, "view_index"),
331        }
332    }
333}
334
335impl Display for InterpolationType {
336    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
337        match self {
338            InterpolationType::Perspective => write!(f, "perspective"),
339            InterpolationType::Linear => write!(f, "linear"),
340            InterpolationType::Flat => write!(f, "flat"),
341        }
342    }
343}
344
345impl Display for InterpolationSampling {
346    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
347        match self {
348            Self::Center => write!(f, "center"),
349            Self::Centroid => write!(f, "centroid"),
350            Self::Sample => write!(f, "sample"),
351            Self::First => write!(f, "first"),
352            Self::Either => write!(f, "either"),
353        }
354    }
355}
356
357#[cfg(feature = "naga_ext")]
358impl Display for ConservativeDepth {
359    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
360        match self {
361            Self::GreaterEqual => write!(f, "Greater_equal"),
362            Self::LessEqual => write!(f, "less_equal"),
363            Self::Unchanged => write!(f, "unchanged"),
364        }
365    }
366}
367
368impl Display for Attribute {
369    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
370        match self {
371            Attribute::Align(e1) => write!(f, "@align({e1})"),
372            Attribute::Binding(e1) => write!(f, "@binding({e1})"),
373            Attribute::BlendSrc(e1) => write!(f, "@blend_src({e1})"),
374            Attribute::Builtin(e1) => write!(f, "@builtin({e1})"),
375            Attribute::Const => write!(f, "@const"),
376            Attribute::Diagnostic(DiagnosticAttribute { severity, rule }) => {
377                write!(f, "@diagnostic({severity}, {rule})")
378            }
379            Attribute::Group(e1) => write!(f, "@group({e1})"),
380            Attribute::Id(e1) => write!(f, "@id({e1})"),
381            Attribute::Interpolate(InterpolateAttribute { ty, sampling }) => {
382                if let Some(sampling) = sampling {
383                    write!(f, "@interpolate({ty}, {sampling})")
384                } else {
385                    write!(f, "@interpolate({ty})")
386                }
387            }
388            Attribute::Invariant => write!(f, "@invariant"),
389            Attribute::Location(e1) => write!(f, "@location({e1})"),
390            Attribute::MustUse => write!(f, "@must_use"),
391            Attribute::Size(e1) => write!(f, "@size({e1})"),
392            Attribute::WorkgroupSize(WorkgroupSizeAttribute { x, y, z }) => {
393                let xyz = std::iter::once(x).chain(y).chain(z).format(", ");
394                write!(f, "@workgroup_size({xyz})")
395            }
396            Attribute::Vertex => write!(f, "@vertex"),
397            Attribute::Fragment => write!(f, "@fragment"),
398            Attribute::Compute => write!(f, "@compute"),
399            #[cfg(feature = "imports")]
400            Attribute::Publish => write!(f, "@publish"),
401            #[cfg(feature = "condcomp")]
402            Attribute::If(e1) => write!(f, "@if({e1})"),
403            #[cfg(feature = "condcomp")]
404            Attribute::Elif(e1) => write!(f, "@elif({e1})"),
405            #[cfg(feature = "condcomp")]
406            Attribute::Else => write!(f, "@else"),
407            #[cfg(feature = "generics")]
408            Attribute::Type(e1) => write!(f, "@type({e1})"),
409            #[cfg(feature = "naga_ext")]
410            Attribute::EarlyDepthTest(None) => write!(f, "@early_depth_test"),
411            #[cfg(feature = "naga_ext")]
412            Attribute::EarlyDepthTest(Some(e1)) => write!(f, "@early_depth_test({e1})"),
413            Attribute::Custom(custom) => {
414                let name = &custom.name;
415                let args = custom.arguments.iter().format_with("", |args, f| {
416                    f(&format_args!("({})", args.iter().format(", ")))
417                });
418                write!(f, "@{name}{args}")
419            }
420        }
421    }
422}
423
424#[cfg(feature = "generics")]
425impl Display for TypeConstraint {
426    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
427        let name = &self.ident;
428        let variants = self.variants.iter().format(" | ");
429        write!(f, "{name}, {variants}")
430    }
431}
432
433fn fmt_attrs(attrs: &[AttributeNode], inline: bool) -> impl fmt::Display + '_ {
434    FormatFn(move |f| {
435        let print = attrs.iter().format(" ");
436        let suffix = if attrs.is_empty() {
437            ""
438        } else if inline {
439            " "
440        } else {
441            "\n"
442        };
443        write!(f, "{print}{suffix}")
444    })
445}
446
447impl Display for Expression {
448    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
449        match self {
450            Expression::Literal(print) => write!(f, "{print}"),
451            Expression::Parenthesized(print) => {
452                write!(f, "{print}")
453            }
454            Expression::NamedComponent(print) => write!(f, "{print}"),
455            Expression::Indexing(print) => write!(f, "{print}"),
456            Expression::Unary(print) => write!(f, "{print}"),
457            Expression::Binary(print) => write!(f, "{print}"),
458            Expression::FunctionCall(print) => write!(f, "{print}"),
459            Expression::TypeOrIdentifier(print) => write!(f, "{print}"),
460        }
461    }
462}
463
464impl Display for LiteralExpression {
465    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
466        match self {
467            LiteralExpression::Bool(true) => write!(f, "true"),
468            LiteralExpression::Bool(false) => write!(f, "false"),
469            LiteralExpression::AbstractInt(num) => write!(f, "{num}"),
470            LiteralExpression::AbstractFloat(num) => write!(f, "{num:?}"), // using the Debug formatter to print the trailing .0 in floats representing integers. because format!("{}", 3.0f32) == "3"
471            LiteralExpression::I32(num) => write!(f, "{num}i"),
472            LiteralExpression::U32(num) => write!(f, "{num}u"),
473            LiteralExpression::F32(num) => write!(f, "{num}f"),
474            LiteralExpression::F16(num) => write!(f, "{num}h"),
475            #[cfg(feature = "naga_ext")]
476            LiteralExpression::I64(num) => write!(f, "{num}li"),
477            #[cfg(feature = "naga_ext")]
478            LiteralExpression::U64(num) => write!(f, "{num}lu"),
479            #[cfg(feature = "naga_ext")]
480            LiteralExpression::F64(num) => write!(f, "{num}lf"),
481        }
482    }
483}
484
485impl Display for ParenthesizedExpression {
486    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
487        let expr = &self.expression;
488        write!(f, "({expr})")
489    }
490}
491
492impl Display for NamedComponentExpression {
493    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
494        let base = &self.base;
495        let component = &self.component;
496        write!(f, "{base}.{component}")
497    }
498}
499
500impl Display for IndexingExpression {
501    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
502        let base = &self.base;
503        let index = &self.index;
504        write!(f, "{base}[{index}]")
505    }
506}
507
508impl Display for UnaryExpression {
509    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
510        let operator = &self.operator;
511        let operand = &self.operand;
512        write!(f, "{operator}{operand}")
513    }
514}
515
516impl Display for UnaryOperator {
517    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
518        match self {
519            UnaryOperator::LogicalNegation => write!(f, "!"),
520            UnaryOperator::Negation => write!(f, "-"),
521            UnaryOperator::BitwiseComplement => write!(f, "~"),
522            UnaryOperator::AddressOf => write!(f, "&"),
523            UnaryOperator::Indirection => write!(f, "*"),
524        }
525    }
526}
527
528impl Display for BinaryExpression {
529    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
530        let operator = &self.operator;
531        let left = &self.left;
532        let right = &self.right;
533        write!(f, "{left} {operator} {right}")
534    }
535}
536
537impl Display for BinaryOperator {
538    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
539        match self {
540            BinaryOperator::ShortCircuitOr => write!(f, "||"),
541            BinaryOperator::ShortCircuitAnd => write!(f, "&&"),
542            BinaryOperator::Addition => write!(f, "+"),
543            BinaryOperator::Subtraction => write!(f, "-"),
544            BinaryOperator::Multiplication => write!(f, "*"),
545            BinaryOperator::Division => write!(f, "/"),
546            BinaryOperator::Remainder => write!(f, "%"),
547            BinaryOperator::Equality => write!(f, "=="),
548            BinaryOperator::Inequality => write!(f, "!="),
549            BinaryOperator::LessThan => write!(f, "<"),
550            BinaryOperator::LessThanEqual => write!(f, "<="),
551            BinaryOperator::GreaterThan => write!(f, ">"),
552            BinaryOperator::GreaterThanEqual => write!(f, ">="),
553            BinaryOperator::BitwiseOr => write!(f, "|"),
554            BinaryOperator::BitwiseAnd => write!(f, "&"),
555            BinaryOperator::BitwiseXor => write!(f, "^"),
556            BinaryOperator::ShiftLeft => write!(f, "<<"),
557            BinaryOperator::ShiftRight => write!(f, ">>"),
558        }
559    }
560}
561
562impl Display for FunctionCall {
563    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
564        let ty = &self.ty;
565        let args = self.arguments.iter().format(", ");
566        write!(f, "{ty}({args})")
567    }
568}
569
570impl Display for TypeExpression {
571    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
572        let name = &self.ident;
573        let tplt = fmt_template(&self.template_args);
574        write!(f, "{name}{tplt}")
575    }
576}
577
578impl Display for TemplateArg {
579    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
580        let expr = &self.expression;
581        write!(f, "{expr}")
582    }
583}
584
585fn fmt_template(tplt: &Option<Vec<TemplateArg>>) -> impl fmt::Display + '_ {
586    tplt.iter().format_with("", |tplt, f| {
587        f(&format_args!("<{}>", tplt.iter().format(", ")))
588    })
589}
590
591impl Display for Statement {
592    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
593        match self {
594            Statement::Void => write!(f, ";"),
595            Statement::Compound(print) => write!(f, "{print}"),
596            Statement::Assignment(print) => write!(f, "{print}"),
597            Statement::Increment(print) => write!(f, "{print}"),
598            Statement::Decrement(print) => write!(f, "{print}"),
599            Statement::If(print) => write!(f, "{print}"),
600            Statement::Switch(print) => write!(f, "{print}"),
601            Statement::Loop(print) => write!(f, "{print}"),
602            Statement::For(print) => write!(f, "{print}"),
603            Statement::While(print) => write!(f, "{print}"),
604            Statement::Break(print) => write!(f, "{print}"),
605            Statement::Continue(print) => write!(f, "{print}"),
606            Statement::Return(print) => write!(f, "{print}"),
607            Statement::Discard(print) => write!(f, "{print}"),
608            Statement::FunctionCall(print) => write!(f, "{print}"),
609            Statement::ConstAssert(print) => write!(f, "{print}"),
610            Statement::Declaration(print) => write!(f, "{print}"),
611        }
612    }
613}
614
615impl Display for CompoundStatement {
616    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
617        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
618        let stmts = Indent(
619            self.statements
620                .iter()
621                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
622                .format("\n"),
623        );
624        write!(f, "{{\n{stmts}\n}}")
625    }
626}
627
628impl Display for AssignmentStatement {
629    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
630        #[cfg(feature = "attributes")]
631        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
632        let operator = &self.operator;
633        let lhs = &self.lhs;
634        let rhs = &self.rhs;
635        write!(f, "{lhs} {operator} {rhs};")
636    }
637}
638
639impl Display for AssignmentOperator {
640    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
641        match self {
642            AssignmentOperator::Equal => write!(f, "="),
643            AssignmentOperator::PlusEqual => write!(f, "+="),
644            AssignmentOperator::MinusEqual => write!(f, "-="),
645            AssignmentOperator::TimesEqual => write!(f, "*="),
646            AssignmentOperator::DivisionEqual => write!(f, "/="),
647            AssignmentOperator::ModuloEqual => write!(f, "%="),
648            AssignmentOperator::AndEqual => write!(f, "&="),
649            AssignmentOperator::OrEqual => write!(f, "|="),
650            AssignmentOperator::XorEqual => write!(f, "^="),
651            AssignmentOperator::ShiftRightAssign => write!(f, ">>="),
652            AssignmentOperator::ShiftLeftAssign => write!(f, "<<="),
653        }
654    }
655}
656
657impl Display for IncrementStatement {
658    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
659        #[cfg(feature = "attributes")]
660        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
661        let expr = &self.expression;
662        write!(f, "{expr}++;")
663    }
664}
665
666impl Display for DecrementStatement {
667    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
668        #[cfg(feature = "attributes")]
669        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
670        let expr = &self.expression;
671        write!(f, "{expr}--;")
672    }
673}
674
675impl Display for IfStatement {
676    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
677        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
678        let if_clause = &self.if_clause;
679        write!(f, "{if_clause}")?;
680        for else_if_clause in self.else_if_clauses.iter() {
681            write!(f, "\n{else_if_clause}")?;
682        }
683        if let Some(else_clause) = &self.else_clause {
684            write!(f, "\n{else_clause}")?;
685        }
686        Ok(())
687    }
688}
689
690impl Display for IfClause {
691    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
692        let expr = &self.expression;
693        let stmt = &self.body;
694        write!(f, "if {expr} {stmt}")
695    }
696}
697
698impl Display for ElseIfClause {
699    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
700        #[cfg(feature = "attributes")]
701        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
702        let expr = &self.expression;
703        let stmt = &self.body;
704        write!(f, "else if {expr} {stmt}")
705    }
706}
707
708impl Display for ElseClause {
709    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
710        #[cfg(feature = "attributes")]
711        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
712        let stmt = &self.body;
713        write!(f, "else {stmt}")
714    }
715}
716
717impl Display for SwitchStatement {
718    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
719        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
720        let expr = &self.expression;
721        let body_attrs = fmt_attrs(&self.body_attributes, false);
722        let clauses = Indent(self.clauses.iter().format("\n"));
723        write!(f, "switch {expr} {body_attrs}{{\n{clauses}\n}}")
724    }
725}
726
727impl Display for SwitchClause {
728    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
729        #[cfg(feature = "attributes")]
730        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
731        let cases = self.case_selectors.iter().format(", ");
732        let body = &self.body;
733        write!(f, "case {cases} {body}")
734    }
735}
736
737impl Display for CaseSelector {
738    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
739        match self {
740            CaseSelector::Default => write!(f, "default"),
741            CaseSelector::Expression(expr) => {
742                write!(f, "{expr}")
743            }
744        }
745    }
746}
747
748impl Display for LoopStatement {
749    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
750        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
751        let body_attrs = fmt_attrs(&self.body.attributes, false);
752        let stmts = Indent(
753            self.body
754                .statements
755                .iter()
756                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
757                .format("\n"),
758        );
759        let continuing = self
760            .continuing
761            .iter()
762            .format_with("", |cont, f| f(&format_args!("{}\n", Indent(cont))));
763        write!(f, "loop {body_attrs}{{\n{stmts}\n{continuing}}}")
764    }
765}
766
767impl Display for ContinuingStatement {
768    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
769        #[cfg(feature = "attributes")]
770        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
771        let body_attrs = fmt_attrs(&self.body.attributes, false);
772        let stmts = Indent(
773            self.body
774                .statements
775                .iter()
776                .filter(|stmt| !matches!(stmt.node(), Statement::Void))
777                .format("\n"),
778        );
779        let break_if = self
780            .break_if
781            .iter()
782            .format_with("", |stmt, f| f(&format_args!("{}\n", Indent(stmt))));
783        write!(f, "continuing {body_attrs}{{\n{stmts}\n{break_if}}}")
784    }
785}
786
787impl Display for BreakIfStatement {
788    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
789        #[cfg(feature = "attributes")]
790        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
791        let expr = &self.expression;
792        write!(f, "break if {expr};")
793    }
794}
795
796impl Display for ForStatement {
797    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
798        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
799        let mut init = self
800            .initializer
801            .as_ref()
802            .map(|stmt| format!("{stmt}"))
803            .unwrap_or_default();
804        if init.ends_with(';') {
805            init.pop();
806        }
807        let cond = self
808            .condition
809            .iter()
810            .format_with("", |expr, f| f(&format_args!("{expr}")));
811        let mut updt = self
812            .update
813            .as_ref()
814            .map(|stmt| format!("{stmt}"))
815            .unwrap_or_default();
816        if updt.ends_with(';') {
817            updt.pop();
818        }
819        let body = &self.body;
820        write!(f, "for ({init}; {cond}; {updt}) {body}")
821    }
822}
823
824impl Display for WhileStatement {
825    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
826        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
827        let cond = &self.condition;
828        let body = &self.body;
829        write!(f, "while ({cond}) {body}")
830    }
831}
832
833impl Display for BreakStatement {
834    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
835        #[cfg(feature = "attributes")]
836        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
837        write!(f, "break;")
838    }
839}
840
841impl Display for ContinueStatement {
842    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
843        #[cfg(feature = "attributes")]
844        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
845        write!(f, "continue;")
846    }
847}
848
849impl Display for ReturnStatement {
850    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
851        #[cfg(feature = "attributes")]
852        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
853        let expr = self
854            .expression
855            .iter()
856            .format_with("", |expr, f| f(&format_args!(" {expr}")));
857        write!(f, "return{expr};")
858    }
859}
860
861impl Display for DiscardStatement {
862    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
863        #[cfg(feature = "attributes")]
864        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
865        write!(f, "discard;")
866    }
867}
868
869impl Display for FunctionCallStatement {
870    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
871        #[cfg(feature = "attributes")]
872        write!(f, "{}", fmt_attrs(&self.attributes, false))?;
873        let call = &self.call;
874        write!(f, "{call};")
875    }
876}