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