1use crate::{span::Spanned, syntax::*};
2use core::fmt;
3use std::fmt::{Display, Formatter};
4
5use itertools::Itertools;
6
7struct 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:?}"), 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}