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 = "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:?}"), 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}