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 = "naga-ext")]
319 Attribute::RayGeneration => write!(f, "@ray_generation"),
320 #[cfg(feature = "naga-ext")]
321 Attribute::AnyHit => write!(f, "@any_hit"),
322 #[cfg(feature = "naga-ext")]
323 Attribute::ClosestHit => write!(f, "@closest_hit"),
324 #[cfg(feature = "naga-ext")]
325 Attribute::Miss => write!(f, "@miss"),
326 #[cfg(feature = "naga-ext")]
327 Attribute::IncomingPayload(p) => write!(f, "@incoming_payload({p})"),
328 #[cfg(feature = "imports")]
329 Attribute::Publish => write!(f, "@publish"),
330 #[cfg(feature = "condcomp")]
331 Attribute::If(e1) => write!(f, "@if({e1})"),
332 #[cfg(feature = "condcomp")]
333 Attribute::Elif(e1) => write!(f, "@elif({e1})"),
334 #[cfg(feature = "condcomp")]
335 Attribute::Else => write!(f, "@else"),
336 #[cfg(feature = "generics")]
337 Attribute::Type(e1) => write!(f, "@type({e1})"),
338 #[cfg(feature = "naga-ext")]
339 Attribute::EarlyDepthTest(None) => write!(f, "@early_depth_test"),
340 #[cfg(feature = "naga-ext")]
341 Attribute::EarlyDepthTest(Some(e1)) => write!(f, "@early_depth_test({e1})"),
342 Attribute::Custom(custom) => {
343 let name = &custom.name;
344 let args = custom.arguments.iter().format_with("", |args, f| {
345 f(&format_args!("({})", args.iter().format(", ")))
346 });
347 write!(f, "@{name}{args}")
348 }
349 }
350 }
351}
352
353#[cfg(feature = "generics")]
354impl Display for TypeConstraint {
355 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
356 let name = &self.ident;
357 let variants = self.variants.iter().format(" | ");
358 write!(f, "{name}, {variants}")
359 }
360}
361
362fn fmt_attrs(attrs: &[AttributeNode], inline: bool) -> impl fmt::Display + '_ {
363 FormatFn(move |f| {
364 let print = attrs.iter().format(" ");
365 let suffix = if attrs.is_empty() {
366 ""
367 } else if inline {
368 " "
369 } else {
370 "\n"
371 };
372 write!(f, "{print}{suffix}")
373 })
374}
375
376impl Display for Expression {
377 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
378 match self {
379 Expression::Literal(print) => write!(f, "{print}"),
380 Expression::Parenthesized(print) => {
381 write!(f, "{print}")
382 }
383 Expression::NamedComponent(print) => write!(f, "{print}"),
384 Expression::Indexing(print) => write!(f, "{print}"),
385 Expression::Unary(print) => write!(f, "{print}"),
386 Expression::Binary(print) => write!(f, "{print}"),
387 Expression::FunctionCall(print) => write!(f, "{print}"),
388 Expression::TypeOrIdentifier(print) => write!(f, "{print}"),
389 }
390 }
391}
392
393impl Display for LiteralExpression {
394 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
395 match self {
396 LiteralExpression::Bool(true) => write!(f, "true"),
397 LiteralExpression::Bool(false) => write!(f, "false"),
398 LiteralExpression::AbstractInt(num) => write!(f, "{num}"),
399 LiteralExpression::AbstractFloat(num) => write!(f, "{num:?}"), LiteralExpression::I32(num) => write!(f, "{num}i"),
401 LiteralExpression::U32(num) => write!(f, "{num}u"),
402 LiteralExpression::F32(num) => write!(f, "{num}f"),
403 LiteralExpression::F16(num) => write!(f, "{num}h"),
404 #[cfg(feature = "naga-ext")]
405 LiteralExpression::I64(num) => write!(f, "{num}li"),
406 #[cfg(feature = "naga-ext")]
407 LiteralExpression::U64(num) => write!(f, "{num}lu"),
408 #[cfg(feature = "naga-ext")]
409 LiteralExpression::F64(num) => write!(f, "{num}lf"),
410 }
411 }
412}
413
414impl Display for ParenthesizedExpression {
415 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
416 let expr = &self.expression;
417 write!(f, "({expr})")
418 }
419}
420
421impl Display for NamedComponentExpression {
422 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
423 let base = &self.base;
424 let component = &self.component;
425 write!(f, "{base}.{component}")
426 }
427}
428
429impl Display for IndexingExpression {
430 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
431 let base = &self.base;
432 let index = &self.index;
433 write!(f, "{base}[{index}]")
434 }
435}
436
437impl Display for UnaryExpression {
438 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
439 let operator = &self.operator;
440 let operand = &self.operand;
441 write!(f, "{operator}{operand}")
442 }
443}
444
445impl Display for BinaryExpression {
446 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
447 let operator = &self.operator;
448 let left = &self.left;
449 let right = &self.right;
450 write!(f, "{left} {operator} {right}")
451 }
452}
453
454impl Display for FunctionCall {
455 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
456 let ty = &self.ty;
457 let args = self.arguments.iter().format(", ");
458 write!(f, "{ty}({args})")
459 }
460}
461
462impl Display for TypeExpression {
463 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
464 #[cfg(feature = "imports")]
465 if let Some(path) = &self.path {
466 write!(f, "{path}::")?;
467 }
468
469 let name = &self.ident;
470 let tplt = fmt_template(&self.template_args);
471 write!(f, "{name}{tplt}")
472 }
473}
474
475impl Display for TemplateArg {
476 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
477 let expr = &self.expression;
478 write!(f, "{expr}")
479 }
480}
481
482fn fmt_template(tplt: &Option<Vec<TemplateArg>>) -> impl fmt::Display + '_ {
483 tplt.iter().format_with("", |tplt, f| {
484 f(&format_args!("<{}>", tplt.iter().format(", ")))
485 })
486}
487
488impl Display for Statement {
489 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
490 match self {
491 Statement::Void => write!(f, ";"),
492 Statement::Compound(print) => write!(f, "{print}"),
493 Statement::Assignment(print) => write!(f, "{print}"),
494 Statement::Increment(print) => write!(f, "{print}"),
495 Statement::Decrement(print) => write!(f, "{print}"),
496 Statement::If(print) => write!(f, "{print}"),
497 Statement::Switch(print) => write!(f, "{print}"),
498 Statement::Loop(print) => write!(f, "{print}"),
499 Statement::For(print) => write!(f, "{print}"),
500 Statement::While(print) => write!(f, "{print}"),
501 Statement::Break(print) => write!(f, "{print}"),
502 Statement::Continue(print) => write!(f, "{print}"),
503 Statement::Return(print) => write!(f, "{print}"),
504 Statement::Discard(print) => write!(f, "{print}"),
505 Statement::FunctionCall(print) => write!(f, "{print}"),
506 Statement::ConstAssert(print) => write!(f, "{print}"),
507 Statement::Declaration(print) => write!(f, "{print}"),
508 }
509 }
510}
511
512impl Display for CompoundStatement {
513 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
514 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
515 let stmts = Indent(
516 self.statements
517 .iter()
518 .filter(|stmt| !matches!(stmt.node(), Statement::Void))
519 .format("\n"),
520 );
521 write!(f, "{{\n{stmts}\n}}")
522 }
523}
524
525impl Display for AssignmentStatement {
526 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
527 #[cfg(feature = "attributes")]
528 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
529 let operator = &self.operator;
530 let lhs = &self.lhs;
531 let rhs = &self.rhs;
532 write!(f, "{lhs} {operator} {rhs};")
533 }
534}
535
536impl Display for IncrementStatement {
537 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
538 #[cfg(feature = "attributes")]
539 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
540 let expr = &self.expression;
541 write!(f, "{expr}++;")
542 }
543}
544
545impl Display for DecrementStatement {
546 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
547 #[cfg(feature = "attributes")]
548 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
549 let expr = &self.expression;
550 write!(f, "{expr}--;")
551 }
552}
553
554impl Display for IfStatement {
555 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
556 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
557 let if_clause = &self.if_clause;
558 write!(f, "{if_clause}")?;
559 for else_if_clause in self.else_if_clauses.iter() {
560 write!(f, "\n{else_if_clause}")?;
561 }
562 if let Some(else_clause) = &self.else_clause {
563 write!(f, "\n{else_clause}")?;
564 }
565 Ok(())
566 }
567}
568
569impl Display for IfClause {
570 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
571 let expr = &self.expression;
572 let stmt = &self.body;
573 write!(f, "if {expr} {stmt}")
574 }
575}
576
577impl Display for ElseIfClause {
578 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
579 #[cfg(feature = "attributes")]
580 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
581 let expr = &self.expression;
582 let stmt = &self.body;
583 write!(f, "else if {expr} {stmt}")
584 }
585}
586
587impl Display for ElseClause {
588 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
589 #[cfg(feature = "attributes")]
590 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
591 let stmt = &self.body;
592 write!(f, "else {stmt}")
593 }
594}
595
596impl Display for SwitchStatement {
597 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
598 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
599 let expr = &self.expression;
600 let body_attrs = fmt_attrs(&self.body_attributes, false);
601 let clauses = Indent(self.clauses.iter().format("\n"));
602 write!(f, "switch {expr} {body_attrs}{{\n{clauses}\n}}")
603 }
604}
605
606impl Display for SwitchClause {
607 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
608 #[cfg(feature = "attributes")]
609 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
610 let cases = self.case_selectors.iter().format(", ");
611 let body = &self.body;
612 write!(f, "case {cases} {body}")
613 }
614}
615
616impl Display for CaseSelector {
617 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
618 match self {
619 CaseSelector::Default => write!(f, "default"),
620 CaseSelector::Expression(expr) => {
621 write!(f, "{expr}")
622 }
623 }
624 }
625}
626
627impl Display for LoopStatement {
628 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
629 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
630 let body_attrs = fmt_attrs(&self.body.attributes, false);
631 let stmts = Indent(
632 self.body
633 .statements
634 .iter()
635 .filter(|stmt| !matches!(stmt.node(), Statement::Void))
636 .format("\n"),
637 );
638 let continuing = self
639 .continuing
640 .iter()
641 .format_with("", |cont, f| f(&format_args!("{}\n", Indent(cont))));
642 write!(f, "loop {body_attrs}{{\n{stmts}\n{continuing}}}")
643 }
644}
645
646impl Display for ContinuingStatement {
647 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
648 #[cfg(feature = "attributes")]
649 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
650 let body_attrs = fmt_attrs(&self.body.attributes, false);
651 let stmts = Indent(
652 self.body
653 .statements
654 .iter()
655 .filter(|stmt| !matches!(stmt.node(), Statement::Void))
656 .format("\n"),
657 );
658 let break_if = self
659 .break_if
660 .iter()
661 .format_with("", |stmt, f| f(&format_args!("{}\n", Indent(stmt))));
662 write!(f, "continuing {body_attrs}{{\n{stmts}\n{break_if}}}")
663 }
664}
665
666impl Display for BreakIfStatement {
667 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
668 #[cfg(feature = "attributes")]
669 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
670 let expr = &self.expression;
671 write!(f, "break if {expr};")
672 }
673}
674
675impl Display for ForStatement {
676 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
677 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
678 let mut init = self
679 .initializer
680 .as_ref()
681 .map(|stmt| format!("{stmt}"))
682 .unwrap_or_default();
683 if init.ends_with(';') {
684 init.pop();
685 }
686 let cond = self
687 .condition
688 .iter()
689 .format_with("", |expr, f| f(&format_args!("{expr}")));
690 let mut updt = self
691 .update
692 .as_ref()
693 .map(|stmt| format!("{stmt}"))
694 .unwrap_or_default();
695 if updt.ends_with(';') {
696 updt.pop();
697 }
698 let body = &self.body;
699 write!(f, "for ({init}; {cond}; {updt}) {body}")
700 }
701}
702
703impl Display for WhileStatement {
704 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
705 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
706 let cond = &self.condition;
707 let body = &self.body;
708 write!(f, "while {cond} {body}")
709 }
710}
711
712impl Display for BreakStatement {
713 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
714 #[cfg(feature = "attributes")]
715 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
716 write!(f, "break;")
717 }
718}
719
720impl Display for ContinueStatement {
721 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
722 #[cfg(feature = "attributes")]
723 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
724 write!(f, "continue;")
725 }
726}
727
728impl Display for ReturnStatement {
729 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
730 #[cfg(feature = "attributes")]
731 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
732 let expr = self
733 .expression
734 .iter()
735 .format_with("", |expr, f| f(&format_args!(" {expr}")));
736 write!(f, "return{expr};")
737 }
738}
739
740impl Display for DiscardStatement {
741 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
742 #[cfg(feature = "attributes")]
743 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
744 write!(f, "discard;")
745 }
746}
747
748impl Display for FunctionCallStatement {
749 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
750 #[cfg(feature = "attributes")]
751 write!(f, "{}", fmt_attrs(&self.attributes, false))?;
752 let call = &self.call;
753 write!(f, "{call};")
754 }
755}
756
757#[cfg(test)]
758mod test {
759 #[cfg(feature = "imports")]
760 use crate::syntax::ModulePath;
761 use crate::syntax::{Ident, TypeExpression};
762
763 #[test]
764 fn type_expression_display() {
765 let expr = TypeExpression {
766 #[cfg(feature = "imports")]
767 path: None,
768 ident: Ident::new("foo".into()),
769 template_args: None,
770 };
771
772 assert_eq!(expr.to_string(), "foo");
773
774 let expr = TypeExpression {
775 #[cfg(feature = "imports")]
776 path: Some(ModulePath::new(
777 crate::syntax::PathOrigin::Absolute,
778 vec!["bar".into(), "qux".into()],
779 )),
780 ident: Ident::new("foo".into()),
781 template_args: None,
782 };
783
784 if cfg!(feature = "imports") {
785 assert_eq!(expr.to_string(), "package::bar::qux::foo");
786 } else {
787 assert_eq!(expr.to_string(), "foo");
788 }
789 }
790}