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