1use gruel_parser::ast::{
13 AnonFnExpr, AnonStructField, ArgMode, ArrayLitExpr, AssignStatement, AssignTarget,
14 AssocFnCallExpr, Ast, BinaryExpr, BinaryOp, BlockExpr, BoolLit, BreakExpr, CallArg, CallExpr,
15 CharLit, CheckedBlockExpr, ComptimeBlockExpr, ComptimeUnrollForExpr, ConstDecl, ContinueExpr,
16 DeriveDecl, Directive, DirectiveArg, EnumDecl, EnumStructLitExpr, EnumVariant,
17 EnumVariantField, EnumVariantKind, Expr, ExternFn, FieldDecl, FieldExpr, FieldInit,
18 FieldPattern, FloatLit, ForExpr, Function, IfExpr, IndexExpr, IntLit, InterfaceDecl,
19 IntrinsicArg, IntrinsicCallExpr, Item, LetStatement, LinkExternBlock, LinkMode, LoopExpr,
20 MatchArm, MatchExpr, Method, MethodCallExpr, MethodSig, NegIntLit, Param, ParamMode, ParenExpr,
21 PathExpr, PathPattern, Pattern, RangeExpr, ReturnExpr, SelfParam, SelfReceiverKind, Statement,
22 StringLit, StructDecl, StructLitExpr, TupleElemPattern, TupleExpr, TupleIndexExpr, TypeExpr,
23 TypeLitExpr, UnaryExpr, UnaryOp, UnitLit, Visibility, WhileExpr,
24};
25use gruel_util::Span;
26
27use crate::Printer;
28
29fn item_span(item: &Item) -> Span {
30 match item {
31 Item::Function(f) => f.span,
32 Item::Struct(s) => s.span,
33 Item::Enum(e) => e.span,
34 Item::Interface(i) => i.span,
35 Item::Derive(d) => d.span,
36 Item::Const(c) => c.span,
37 Item::LinkExtern(b) => b.span,
38 Item::Error(s) => *s,
39 }
40}
41
42fn statement_span(s: &Statement) -> Span {
43 match s {
44 Statement::Let(l) => l.span,
45 Statement::Assign(a) => a.span,
46 Statement::Expr(e) => e.span(),
47 }
48}
49
50pub fn emit_ast(p: &mut Printer<'_>, ast: &Ast) {
53 if let Some(doc) = &ast.module_doc {
54 emit_doc(p, doc);
56 }
57 for (i, item) in ast.items.iter().enumerate() {
58 let span = item_span(item);
59 if i > 0 || ast.module_doc.is_some() {
60 p.blank_line();
61 }
62 p.drain_trivia_before(span.start);
64 emit_item(p, item);
65 p.mark_emitted_end(span.end);
66 }
67 p.drain_trivia_remaining();
69}
70
71pub fn emit_item(p: &mut Printer<'_>, item: &Item) {
72 match item {
73 Item::Function(f) => emit_function(p, f),
74 Item::Struct(s) => emit_struct_decl(p, s),
75 Item::Enum(e) => emit_enum_decl(p, e),
76 Item::Interface(i) => emit_interface_decl(p, i),
77 Item::Derive(d) => emit_derive_decl(p, d),
78 Item::Const(c) => emit_const_decl(p, c),
79 Item::LinkExtern(b) => emit_link_extern(p, b),
80 Item::Error(_) => panic!("gruel-fmt: Item::Error in successfully-parsed AST"),
81 }
82}
83
84fn emit_doc(p: &mut Printer<'_>, doc: &gruel_parser::ast::Doc) {
87 for line in doc.body.split('\n') {
88 if line.is_empty() {
89 p.write_str("///");
90 } else {
91 p.write_str("/// ");
92 p.write_str(line);
93 }
94 p.newline();
95 }
96}
97
98fn emit_directives(p: &mut Printer<'_>, dirs: &[Directive]) {
99 for dir in dirs {
100 emit_directive(p, dir);
101 p.newline();
102 }
103}
104
105fn emit_directive(p: &mut Printer<'_>, dir: &Directive) {
106 p.write_str("@");
107 p.write_ident(dir.name.name);
108 if !dir.args.is_empty() {
109 p.write_str("(");
110 for (i, arg) in dir.args.iter().enumerate() {
111 if i > 0 {
112 p.write_str(", ");
113 }
114 emit_directive_arg(p, arg);
115 }
116 p.write_str(")");
117 }
118}
119
120fn emit_directive_arg(p: &mut Printer<'_>, arg: &DirectiveArg) {
121 match arg {
122 DirectiveArg::Ident(ident) => p.write_ident(ident.name),
123 DirectiveArg::String(lit) => emit_string_literal(p, lit),
124 }
125}
126
127fn emit_visibility(p: &mut Printer<'_>, vis: Visibility) {
128 if matches!(vis, Visibility::Public) {
129 p.write_str("pub ");
130 }
131}
132
133fn emit_function(p: &mut Printer<'_>, f: &Function) {
134 if let Some(doc) = &f.doc {
135 emit_doc(p, doc);
136 }
137 emit_directives(p, &f.directives);
138 emit_visibility(p, f.visibility);
139 p.write_str("fn ");
142 p.write_ident(f.name.name);
143 emit_param_list(p, &f.params);
144 if let Some(ret) = &f.return_type {
145 p.write_str(" -> ");
146 emit_type_expr(p, ret);
147 }
148 p.write_str(" ");
149 if let Expr::Block(block) = &f.body {
150 emit_block(p, block);
151 } else {
152 panic!("gruel-fmt: Function body is not a BlockExpr");
155 }
156 p.newline();
157}
158
159fn emit_struct_decl(p: &mut Printer<'_>, s: &StructDecl) {
160 if let Some(doc) = &s.doc {
161 emit_doc(p, doc);
162 }
163 emit_directives(p, &s.directives);
164 emit_visibility(p, s.visibility);
165 p.write_str("struct ");
166 p.write_ident(s.name.name);
167 p.write_str(" {");
168 if s.fields.is_empty() && s.methods.is_empty() {
169 p.drain_trivia_before(s.span.end);
170 p.write_str("}");
171 } else {
172 p.newline();
173 p.indent();
174 for field in &s.fields {
175 p.drain_trivia_before(field.span.start);
176 emit_field_decl(p, field);
177 p.mark_emitted_end(field.span.end);
178 p.write_str(",");
179 p.drain_trailing_comment_on_line();
180 p.newline();
181 }
182 if !s.fields.is_empty() && !s.methods.is_empty() {
183 p.blank_line();
184 }
185 for (i, m) in s.methods.iter().enumerate() {
186 if i > 0 {
187 p.blank_line();
188 }
189 p.drain_trivia_before(m.span.start);
190 emit_method(p, m);
191 p.mark_emitted_end(m.span.end);
192 p.newline();
193 }
194 p.drain_trivia_before(s.span.end);
195 p.dedent();
196 p.write_str("}");
197 }
198 p.newline();
199}
200
201fn emit_field_decl(p: &mut Printer<'_>, field: &FieldDecl) {
202 if let Some(doc) = &field.doc {
203 emit_doc(p, doc);
204 }
205 emit_visibility(p, field.visibility);
206 p.write_ident(field.name.name);
207 p.write_str(": ");
208 emit_type_expr(p, &field.ty);
209}
210
211fn emit_enum_decl(p: &mut Printer<'_>, e: &EnumDecl) {
212 if let Some(doc) = &e.doc {
213 emit_doc(p, doc);
214 }
215 emit_directives(p, &e.directives);
216 emit_visibility(p, e.visibility);
217 p.write_str("enum ");
218 p.write_ident(e.name.name);
219 p.write_str(" {");
220 if e.variants.is_empty() && e.methods.is_empty() {
221 p.write_str("}");
222 } else {
223 p.newline();
224 p.indent();
225 for variant in &e.variants {
226 emit_enum_variant(p, variant);
227 p.write_str(",");
228 p.newline();
229 }
230 if !e.variants.is_empty() && !e.methods.is_empty() {
231 p.blank_line();
232 }
233 for (i, m) in e.methods.iter().enumerate() {
234 if i > 0 {
235 p.blank_line();
236 }
237 emit_method(p, m);
238 p.newline();
239 }
240 p.dedent();
241 p.write_str("}");
242 }
243 p.newline();
244}
245
246fn emit_enum_variant(p: &mut Printer<'_>, v: &EnumVariant) {
247 if let Some(doc) = &v.doc {
248 emit_doc(p, doc);
249 }
250 p.write_ident(v.name.name);
251 match &v.kind {
252 EnumVariantKind::Unit => {}
253 EnumVariantKind::Tuple(tys) => {
254 p.write_str("(");
255 for (i, ty) in tys.iter().enumerate() {
256 if i > 0 {
257 p.write_str(", ");
258 }
259 emit_type_expr(p, ty);
260 }
261 p.write_str(")");
262 }
263 EnumVariantKind::Struct(fields) => {
264 p.write_str(" {");
265 if fields.is_empty() {
266 p.write_str("}");
267 } else {
268 p.newline();
269 p.indent();
270 for f in fields {
271 emit_enum_variant_field(p, f);
272 p.write_str(",");
273 p.newline();
274 }
275 p.dedent();
276 p.write_str("}");
277 }
278 }
279 }
280}
281
282fn emit_enum_variant_field(p: &mut Printer<'_>, f: &EnumVariantField) {
283 if let Some(doc) = &f.doc {
284 emit_doc(p, doc);
285 }
286 emit_visibility(p, f.visibility);
287 p.write_ident(f.name.name);
288 p.write_str(": ");
289 emit_type_expr(p, &f.ty);
290}
291
292fn emit_interface_decl(p: &mut Printer<'_>, i: &InterfaceDecl) {
293 if let Some(doc) = &i.doc {
294 emit_doc(p, doc);
295 }
296 emit_directives(p, &i.directives);
297 emit_visibility(p, i.visibility);
298 p.write_str("interface ");
299 p.write_ident(i.name.name);
300 p.write_str(" {");
301 if i.methods.is_empty() {
302 p.write_str("}");
303 } else {
304 p.newline();
305 p.indent();
306 for (idx, sig) in i.methods.iter().enumerate() {
307 if idx > 0 {
308 p.newline();
309 }
310 emit_method_sig(p, sig);
311 p.newline();
312 }
313 p.dedent();
314 p.write_str("}");
315 }
316 p.newline();
317}
318
319fn emit_method_sig(p: &mut Printer<'_>, sig: &MethodSig) {
320 if let Some(doc) = &sig.doc {
321 emit_doc(p, doc);
322 }
323 emit_directives(p, &sig.directives);
324 p.write_str("fn ");
326 p.write_ident(sig.name.name);
327 p.write_str("(");
328 emit_self_param(p, &sig.receiver);
329 for param in &sig.params {
330 p.write_str(", ");
331 emit_param(p, param);
332 }
333 p.write_str(")");
334 if let Some(ret) = &sig.return_type {
335 p.write_str(" -> ");
336 emit_type_expr(p, ret);
337 }
338 p.write_str(";");
339}
340
341fn emit_derive_decl(p: &mut Printer<'_>, d: &DeriveDecl) {
342 if let Some(doc) = &d.doc {
343 emit_doc(p, doc);
344 }
345 p.write_str("derive ");
346 p.write_ident(d.name.name);
347 p.write_str(" {");
348 if d.methods.is_empty() {
349 p.write_str("}");
350 } else {
351 p.newline();
352 p.indent();
353 for (idx, m) in d.methods.iter().enumerate() {
354 if idx > 0 {
355 p.blank_line();
356 }
357 emit_method(p, m);
358 p.newline();
359 }
360 p.dedent();
361 p.write_str("}");
362 }
363 p.newline();
364}
365
366fn emit_const_decl(p: &mut Printer<'_>, c: &ConstDecl) {
367 if let Some(doc) = &c.doc {
368 emit_doc(p, doc);
369 }
370 emit_directives(p, &c.directives);
371 emit_visibility(p, c.visibility);
372 p.write_str("const ");
373 p.write_ident(c.name.name);
374 if let Some(ty) = &c.ty {
375 p.write_str(": ");
376 emit_type_expr(p, ty);
377 }
378 p.write_str(" = ");
379 emit_expr(p, &c.init);
380 p.write_str(";");
381 p.newline();
382}
383
384fn emit_link_extern(p: &mut Printer<'_>, b: &LinkExternBlock) {
385 if let Some(doc) = &b.doc {
386 emit_doc(p, doc);
387 }
388 match b.link_mode {
389 LinkMode::Dynamic => p.write_str("link_extern("),
390 LinkMode::Static => p.write_str("static_link_extern("),
391 }
392 emit_string_literal(p, &b.library);
393 p.write_str(") {");
394 if b.items.is_empty() {
395 p.write_str("}");
396 } else {
397 p.newline();
398 p.indent();
399 for (idx, item) in b.items.iter().enumerate() {
400 if idx > 0 {
401 p.newline();
402 }
403 emit_extern_fn(p, item);
404 p.newline();
405 }
406 p.dedent();
407 p.write_str("}");
408 }
409 p.newline();
410}
411
412fn emit_extern_fn(p: &mut Printer<'_>, f: &ExternFn) {
413 if let Some(doc) = &f.doc {
414 emit_doc(p, doc);
415 }
416 emit_directives(p, &f.directives);
417 p.write_str("fn ");
418 p.write_ident(f.name.name);
419 emit_param_list(p, &f.params);
420 if let Some(ret) = &f.return_type {
421 p.write_str(" -> ");
422 emit_type_expr(p, ret);
423 }
424 p.write_str(";");
425}
426
427fn emit_method(p: &mut Printer<'_>, m: &Method) {
428 if let Some(doc) = &m.doc {
429 emit_doc(p, doc);
430 }
431 emit_directives(p, &m.directives);
432 emit_visibility(p, m.visibility);
433 p.write_str("fn ");
435 p.write_ident(m.name.name);
436 p.write_str("(");
437 let mut first = true;
438 if let Some(recv) = &m.receiver {
439 emit_self_param(p, recv);
440 first = false;
441 }
442 for param in &m.params {
443 if !first {
444 p.write_str(", ");
445 }
446 emit_param(p, param);
447 first = false;
448 }
449 p.write_str(")");
450 if let Some(ret) = &m.return_type {
451 p.write_str(" -> ");
452 emit_type_expr(p, ret);
453 }
454 p.write_str(" ");
455 if let Expr::Block(b) = &m.body {
456 emit_block(p, b);
457 } else {
458 panic!("gruel-fmt: Method body is not a BlockExpr");
459 }
460}
461
462fn emit_param_list(p: &mut Printer<'_>, params: &[Param]) {
463 p.write_str("(");
464 for (i, param) in params.iter().enumerate() {
465 if i > 0 {
466 p.write_str(", ");
467 }
468 emit_param(p, param);
469 }
470 p.write_str(")");
471}
472
473fn emit_param(p: &mut Printer<'_>, param: &Param) {
474 if param.is_comptime || matches!(param.mode, ParamMode::Comptime) {
475 p.write_str("comptime ");
476 }
477 p.write_ident(param.name.name);
478 p.write_str(": ");
479 emit_type_expr(p, ¶m.ty);
480}
481
482fn emit_self_param(p: &mut Printer<'_>, sp: &SelfParam) {
483 match sp.kind {
484 SelfReceiverKind::ByValue => p.write_str("self"),
485 SelfReceiverKind::Ref => p.write_str("self: Ref(Self)"),
486 SelfReceiverKind::MutRef => p.write_str("self: MutRef(Self)"),
487 }
488}
489
490pub fn emit_expr(p: &mut Printer<'_>, expr: &Expr) {
493 match expr {
494 Expr::Int(lit) => emit_int_literal(p, lit),
495 Expr::Float(lit) => emit_float_literal(p, lit),
496 Expr::String(lit) => emit_string_literal(p, lit),
497 Expr::Char(lit) => emit_char_literal(p, lit),
498 Expr::Bool(lit) => emit_bool_literal(p, lit),
499 Expr::Unit(lit) => emit_unit_literal(p, lit),
500 Expr::Ident(ident) => p.write_ident(ident.name),
501 Expr::SelfExpr(_) => p.write_str("self"),
502 Expr::Binary(b) => emit_binary(p, b),
503 Expr::Unary(u) => emit_unary(p, u),
504 Expr::Paren(par) => emit_paren(p, par),
505 Expr::Block(b) => emit_block(p, b),
506 Expr::If(if_expr) => emit_if(p, if_expr),
507 Expr::Match(m) => emit_match(p, m),
508 Expr::While(w) => emit_while(p, w),
509 Expr::For(f) => emit_for(p, f),
510 Expr::Loop(l) => emit_loop(p, l),
511 Expr::Call(c) => emit_call(p, c),
512 Expr::Break(b) => emit_break(p, b),
513 Expr::Continue(c) => emit_continue(p, c),
514 Expr::Return(r) => emit_return(p, r),
515 Expr::StructLit(s) => emit_struct_lit(p, s),
516 Expr::Field(f) => emit_field_expr(p, f),
517 Expr::MethodCall(mc) => emit_method_call(p, mc),
518 Expr::IntrinsicCall(ic) => emit_intrinsic_call(p, ic),
519 Expr::ArrayLit(a) => emit_array_lit(p, a),
520 Expr::Index(idx) => emit_index(p, idx),
521 Expr::Path(path) => emit_path(p, path),
522 Expr::EnumStructLit(e) => emit_enum_struct_lit(p, e),
523 Expr::AssocFnCall(a) => emit_assoc_fn_call(p, a),
524 Expr::Comptime(c) => emit_comptime_block(p, c),
525 Expr::ComptimeUnrollFor(c) => emit_comptime_unroll_for(p, c),
526 Expr::Checked(c) => emit_checked_block(p, c),
527 Expr::TypeLit(t) => emit_type_lit(p, t),
528 Expr::Tuple(t) => emit_tuple(p, t),
529 Expr::TupleIndex(t) => emit_tuple_index(p, t),
530 Expr::Range(r) => emit_range(p, r),
531 Expr::AnonFn(a) => emit_anon_fn(p, a),
532 Expr::Error(_) => panic!("gruel-fmt: Expr::Error in successfully-parsed AST"),
533 }
534}
535
536fn emit_int_literal(p: &mut Printer<'_>, lit: &IntLit) {
537 p.write_str(&lit.value.to_string());
538}
539
540fn emit_float_literal(p: &mut Printer<'_>, lit: &FloatLit) {
541 let v = f64::from_bits(lit.bits);
542 let s = format!("{}", v);
543 if s.contains('.')
544 || s.contains('e')
545 || s.contains('E')
546 || s.contains("inf")
547 || s.contains("NaN")
548 {
549 p.write_str(&s);
550 } else {
551 p.write_str(&s);
552 p.write_str(".0");
553 }
554}
555
556fn emit_string_literal(p: &mut Printer<'_>, lit: &StringLit) {
557 p.write_str("\"");
558 let s = p.resolve(lit.value).to_string();
559 for c in s.chars() {
560 match c {
561 '\\' => p.write_str("\\\\"),
562 '"' => p.write_str("\\\""),
563 '\n' => p.write_str("\\n"),
564 '\t' => p.write_str("\\t"),
565 '\r' => p.write_str("\\r"),
566 '\0' => p.write_str("\\0"),
567 c => {
568 let mut buf = [0u8; 4];
569 p.write_str(c.encode_utf8(&mut buf));
570 }
571 }
572 }
573 p.write_str("\"");
574}
575
576fn emit_char_literal(p: &mut Printer<'_>, lit: &CharLit) {
577 p.write_str("'");
578 match char::from_u32(lit.value) {
579 Some(c) => match c {
580 '\\' => p.write_str("\\\\"),
581 '\'' => p.write_str("\\'"),
582 '\n' => p.write_str("\\n"),
583 '\t' => p.write_str("\\t"),
584 '\r' => p.write_str("\\r"),
585 '\0' => p.write_str("\\0"),
586 c => {
587 let mut buf = [0u8; 4];
588 p.write_str(c.encode_utf8(&mut buf));
589 }
590 },
591 None => {
592 p.write_str(&format!("\\u{{{:X}}}", lit.value));
595 }
596 }
597 p.write_str("'");
598}
599
600fn emit_bool_literal(p: &mut Printer<'_>, lit: &BoolLit) {
601 p.write_str(if lit.value { "true" } else { "false" });
602}
603
604fn emit_unit_literal(p: &mut Printer<'_>, _lit: &UnitLit) {
605 p.write_str("()");
606}
607
608fn emit_binary(p: &mut Printer<'_>, b: &BinaryExpr) {
609 emit_expr(p, &b.left);
610 p.write_str(" ");
611 p.write_str(binary_op_str(b.op));
612 p.write_str(" ");
613 emit_expr(p, &b.right);
614}
615
616fn emit_unary(p: &mut Printer<'_>, u: &UnaryExpr) {
617 p.write_str(unary_op_str(u.op));
618 emit_expr(p, &u.operand);
619}
620
621fn emit_paren(p: &mut Printer<'_>, par: &ParenExpr) {
622 p.write_str("(");
623 emit_expr(p, &par.inner);
624 p.write_str(")");
625}
626
627pub fn emit_block(p: &mut Printer<'_>, block: &BlockExpr) {
628 p.write_str("{");
629 if block.statements.is_empty() && matches!(*block.expr, Expr::Unit(_)) {
630 p.drain_trivia_before(block.span.end);
633 p.write_str("}");
634 return;
635 }
636 p.newline();
637 p.indent();
638 for stmt in &block.statements {
639 let span = statement_span(stmt);
640 p.drain_trivia_before(span.start);
641 emit_statement(p, stmt);
642 p.mark_emitted_end(span.end);
643 p.drain_trailing_comment_on_line();
644 p.newline();
645 }
646 if !matches!(*block.expr, Expr::Unit(_)) {
647 let span = block.expr.span();
648 p.drain_trivia_before(span.start);
649 emit_expr(p, &block.expr);
650 p.mark_emitted_end(span.end);
651 p.drain_trailing_comment_on_line();
652 p.newline();
653 }
654 p.drain_trivia_before(block.span.end);
656 p.dedent();
657 p.write_str("}");
658}
659
660fn emit_if(p: &mut Printer<'_>, e: &IfExpr) {
661 if e.is_comptime {
662 p.write_str("comptime ");
663 }
664 p.write_str("if ");
665 emit_expr(p, &e.cond);
666 p.write_str(" ");
667 emit_block(p, &e.then_block);
668 if let Some(else_block) = &e.else_block {
669 p.write_str(" else ");
670 if else_block.statements.is_empty()
673 && let Expr::If(inner) = &*else_block.expr
674 {
675 emit_if(p, inner);
676 return;
677 }
678 emit_block(p, else_block);
679 }
680}
681
682fn emit_match(p: &mut Printer<'_>, m: &MatchExpr) {
683 p.write_str("match ");
684 emit_expr(p, &m.scrutinee);
685 p.write_str(" {");
686 if m.arms.is_empty() {
687 p.write_str("}");
688 return;
689 }
690 p.newline();
691 p.indent();
692 for arm in &m.arms {
693 emit_match_arm(p, arm);
694 p.write_str(",");
695 p.newline();
696 }
697 p.dedent();
698 p.write_str("}");
699}
700
701fn emit_match_arm(p: &mut Printer<'_>, arm: &MatchArm) {
702 emit_pattern(p, &arm.pattern);
703 match &arm.pattern {
707 Pattern::ComptimeUnrollArm { .. } => p.write_str(" "),
708 _ => p.write_str(" => "),
709 }
710 emit_expr(p, &arm.body);
711}
712
713fn emit_while(p: &mut Printer<'_>, w: &WhileExpr) {
714 p.write_str("while ");
715 emit_expr(p, &w.cond);
716 p.write_str(" ");
717 emit_block(p, &w.body);
718}
719
720fn emit_for(p: &mut Printer<'_>, f: &ForExpr) {
721 p.write_str("for ");
722 if f.is_mut {
723 p.write_str("mut ");
724 }
725 p.write_ident(f.binding.name);
726 p.write_str(" in ");
727 emit_expr(p, &f.iterable);
728 p.write_str(" ");
729 emit_block(p, &f.body);
730}
731
732fn emit_loop(p: &mut Printer<'_>, l: &LoopExpr) {
733 p.write_str("loop ");
734 emit_block(p, &l.body);
735}
736
737fn emit_call(p: &mut Printer<'_>, c: &CallExpr) {
738 p.write_ident(c.name.name);
739 emit_call_args(p, &c.args);
740}
741
742fn emit_call_args(p: &mut Printer<'_>, args: &[CallArg]) {
743 p.write_str("(");
744 for (i, arg) in args.iter().enumerate() {
745 if i > 0 {
746 p.write_str(", ");
747 }
748 match arg.mode {
749 ArgMode::Normal => {}
750 }
751 emit_expr(p, &arg.expr);
752 }
753 p.write_str(")");
754}
755
756fn emit_break(p: &mut Printer<'_>, _b: &BreakExpr) {
757 p.write_str("break");
758}
759
760fn emit_continue(p: &mut Printer<'_>, _c: &ContinueExpr) {
761 p.write_str("continue");
762}
763
764fn emit_return(p: &mut Printer<'_>, r: &ReturnExpr) {
765 p.write_str("return");
766 if let Some(value) = &r.value {
767 p.write_str(" ");
768 emit_expr(p, value);
769 }
770}
771
772fn emit_struct_lit(p: &mut Printer<'_>, s: &StructLitExpr) {
773 if let Some(base) = &s.base {
774 emit_expr(p, base);
775 p.write_str(".");
776 }
777 p.write_ident(s.name.name);
778 emit_field_inits(p, &s.fields);
779}
780
781fn emit_field_inits(p: &mut Printer<'_>, fields: &[FieldInit]) {
782 if fields.is_empty() {
783 p.write_str(" {}");
784 return;
785 }
786 p.write_str(" { ");
787 for (i, f) in fields.iter().enumerate() {
788 if i > 0 {
789 p.write_str(", ");
790 }
791 emit_field_init(p, f);
792 }
793 p.write_str(" }");
794}
795
796fn emit_field_init(p: &mut Printer<'_>, f: &FieldInit) {
797 p.write_ident(f.name.name);
798 p.write_str(": ");
799 emit_expr(p, &f.value);
800}
801
802fn emit_field_expr(p: &mut Printer<'_>, f: &FieldExpr) {
803 emit_expr(p, &f.base);
804 p.write_str(".");
805 p.write_ident(f.field.name);
806}
807
808fn emit_method_call(p: &mut Printer<'_>, m: &MethodCallExpr) {
809 emit_expr(p, &m.receiver);
810 p.write_str(".");
811 p.write_ident(m.method.name);
812 emit_call_args(p, &m.args);
813}
814
815fn emit_intrinsic_call(p: &mut Printer<'_>, c: &IntrinsicCallExpr) {
816 p.write_str("@");
817 p.write_ident(c.name.name);
818 p.write_str("(");
819 for (i, arg) in c.args.iter().enumerate() {
820 if i > 0 {
821 p.write_str(", ");
822 }
823 match arg {
824 IntrinsicArg::Expr(e) => emit_expr(p, e),
825 IntrinsicArg::Type(t) => emit_type_expr(p, t),
826 }
827 }
828 p.write_str(")");
829}
830
831fn emit_array_lit(p: &mut Printer<'_>, a: &ArrayLitExpr) {
832 p.write_str("[");
833 for (i, elem) in a.elements.iter().enumerate() {
834 if i > 0 {
835 p.write_str(", ");
836 }
837 emit_expr(p, elem);
838 }
839 p.write_str("]");
840}
841
842fn emit_index(p: &mut Printer<'_>, i: &IndexExpr) {
843 emit_expr(p, &i.base);
844 p.write_str("[");
845 emit_expr(p, &i.index);
846 p.write_str("]");
847}
848
849fn emit_path(p: &mut Printer<'_>, path: &PathExpr) {
850 if let Some(base) = &path.base {
851 emit_expr(p, base);
852 p.write_str(".");
853 }
854 p.write_ident(path.type_name.name);
855 p.write_str("::");
856 p.write_ident(path.variant.name);
857}
858
859fn emit_enum_struct_lit(p: &mut Printer<'_>, e: &EnumStructLitExpr) {
860 if let Some(base) = &e.base {
861 emit_expr(p, base);
862 p.write_str(".");
863 }
864 p.write_ident(e.type_name.name);
865 p.write_str("::");
866 p.write_ident(e.variant.name);
867 emit_field_inits(p, &e.fields);
868}
869
870fn emit_assoc_fn_call(p: &mut Printer<'_>, a: &AssocFnCallExpr) {
871 if let Some(base) = &a.base {
872 emit_expr(p, base);
873 p.write_str(".");
874 }
875 p.write_ident(a.type_name.name);
876 if !a.type_args.is_empty() {
877 p.write_str("(");
878 for (i, t) in a.type_args.iter().enumerate() {
879 if i > 0 {
880 p.write_str(", ");
881 }
882 emit_expr(p, t);
883 }
884 p.write_str(")");
885 }
886 p.write_str("::");
887 p.write_ident(a.function.name);
888 emit_call_args(p, &a.args);
889}
890
891fn emit_comptime_block(p: &mut Printer<'_>, c: &ComptimeBlockExpr) {
892 p.write_str("comptime ");
893 if let Expr::Block(b) = &*c.expr {
894 emit_block(p, b);
895 } else {
896 emit_expr(p, &c.expr);
898 }
899}
900
901fn emit_comptime_unroll_for(p: &mut Printer<'_>, c: &ComptimeUnrollForExpr) {
902 p.write_str("comptime_unroll for ");
903 p.write_ident(c.binding.name);
904 p.write_str(" in ");
905 emit_expr(p, &c.iterable);
906 p.write_str(" ");
907 emit_block(p, &c.body);
908}
909
910fn emit_checked_block(p: &mut Printer<'_>, c: &CheckedBlockExpr) {
911 p.write_str("checked ");
912 if let Expr::Block(b) = &*c.expr {
913 emit_block(p, b);
914 } else {
915 emit_expr(p, &c.expr);
916 }
917}
918
919fn emit_type_lit(p: &mut Printer<'_>, t: &TypeLitExpr) {
920 emit_type_expr(p, &t.type_expr);
921}
922
923fn emit_tuple(p: &mut Printer<'_>, t: &TupleExpr) {
924 p.write_str("(");
925 for (i, elem) in t.elems.iter().enumerate() {
926 if i > 0 {
927 p.write_str(", ");
928 }
929 emit_expr(p, elem);
930 }
931 if t.elems.len() == 1 {
932 p.write_str(",");
934 }
935 p.write_str(")");
936}
937
938fn emit_tuple_index(p: &mut Printer<'_>, t: &TupleIndexExpr) {
939 emit_expr(p, &t.base);
940 p.write_str(".");
941 p.write_str(&t.index.to_string());
942}
943
944fn emit_range(p: &mut Printer<'_>, r: &RangeExpr) {
945 if let Some(lo) = &r.lo {
946 emit_expr(p, lo);
947 }
948 p.write_str("..");
949 if let Some(hi) = &r.hi {
950 emit_expr(p, hi);
951 }
952}
953
954fn emit_anon_fn(p: &mut Printer<'_>, a: &AnonFnExpr) {
955 p.write_str("fn");
956 emit_param_list(p, &a.params);
957 if let Some(ret) = &a.return_type {
958 p.write_str(" -> ");
959 emit_type_expr(p, ret);
960 }
961 p.write_str(" ");
962 emit_block(p, &a.body);
963}
964
965pub fn emit_statement(p: &mut Printer<'_>, stmt: &Statement) {
968 match stmt {
969 Statement::Let(l) => emit_let(p, l),
970 Statement::Assign(a) => emit_assign(p, a),
971 Statement::Expr(e) => {
972 emit_expr(p, e);
973 if !is_block_like_expr(e) {
977 p.write_str(";");
978 }
979 }
980 }
981}
982
983fn is_block_like_expr(e: &Expr) -> bool {
984 matches!(
990 e,
991 Expr::Block(_)
992 | Expr::If(_)
993 | Expr::Match(_)
994 | Expr::While(_)
995 | Expr::For(_)
996 | Expr::Loop(_)
997 )
998}
999
1000fn emit_let(p: &mut Printer<'_>, l: &LetStatement) {
1001 emit_directives(p, &l.directives);
1002 p.write_str("let ");
1003 if let Pattern::Ident { name, .. } = &l.pattern {
1004 if l.is_mut {
1005 p.write_str("mut ");
1006 }
1007 p.write_ident(name.name);
1008 } else {
1009 emit_pattern(p, &l.pattern);
1010 }
1011 if let Some(ty) = &l.ty {
1012 p.write_str(": ");
1013 emit_type_expr(p, ty);
1014 }
1015 p.write_str(" = ");
1016 emit_expr(p, &l.init);
1017 p.write_str(";");
1018}
1019
1020fn emit_assign(p: &mut Printer<'_>, a: &AssignStatement) {
1021 emit_assign_target(p, &a.target);
1022 p.write_str(" = ");
1023 emit_expr(p, &a.value);
1024 p.write_str(";");
1025}
1026
1027fn emit_assign_target(p: &mut Printer<'_>, target: &AssignTarget) {
1028 match target {
1029 AssignTarget::Var(ident) => p.write_ident(ident.name),
1030 AssignTarget::Field(f) => emit_field_expr(p, f),
1031 AssignTarget::Index(i) => emit_index(p, i),
1032 }
1033}
1034
1035pub fn emit_pattern(p: &mut Printer<'_>, pat: &Pattern) {
1038 match pat {
1039 Pattern::Wildcard(_) => p.write_str("_"),
1040 Pattern::Ident { is_mut, name, .. } => {
1041 if *is_mut {
1042 p.write_str("mut ");
1043 }
1044 p.write_ident(name.name);
1045 }
1046 Pattern::Int(lit) => p.write_str(&lit.value.to_string()),
1047 Pattern::NegInt(NegIntLit { value, .. }) => {
1048 p.write_str("-");
1049 p.write_str(&value.to_string());
1050 }
1051 Pattern::Bool(BoolLit { value, .. }) => {
1052 p.write_str(if *value { "true" } else { "false" });
1053 }
1054 Pattern::Path(pp) => emit_path_pattern(p, pp),
1055 Pattern::DataVariant {
1056 base,
1057 type_name,
1058 variant,
1059 fields,
1060 ..
1061 } => {
1062 if let Some(b) = base {
1063 emit_expr(p, b);
1064 p.write_str(".");
1065 }
1066 p.write_ident(type_name.name);
1067 p.write_str("::");
1068 p.write_ident(variant.name);
1069 p.write_str("(");
1070 for (i, fld) in fields.iter().enumerate() {
1071 if i > 0 {
1072 p.write_str(", ");
1073 }
1074 emit_tuple_elem_pattern(p, fld);
1075 }
1076 p.write_str(")");
1077 }
1078 Pattern::StructVariant {
1079 base,
1080 type_name,
1081 variant,
1082 fields,
1083 ..
1084 } => {
1085 if let Some(b) = base {
1086 emit_expr(p, b);
1087 p.write_str(".");
1088 }
1089 p.write_ident(type_name.name);
1090 p.write_str("::");
1091 p.write_ident(variant.name);
1092 emit_field_patterns(p, fields);
1093 }
1094 Pattern::Struct {
1095 type_name, fields, ..
1096 } => {
1097 p.write_ident(type_name.name);
1098 emit_field_patterns(p, fields);
1099 }
1100 Pattern::Tuple { elems, .. } => {
1101 p.write_str("(");
1102 for (i, e) in elems.iter().enumerate() {
1103 if i > 0 {
1104 p.write_str(", ");
1105 }
1106 emit_tuple_elem_pattern(p, e);
1107 }
1108 if elems.len() == 1 {
1109 p.write_str(",");
1110 }
1111 p.write_str(")");
1112 }
1113 Pattern::ComptimeUnrollArm {
1114 binding, iterable, ..
1115 } => {
1116 p.write_str("comptime_unroll for ");
1117 p.write_ident(binding.name);
1118 p.write_str(" in ");
1119 emit_expr(p, iterable);
1120 }
1121 }
1122}
1123
1124fn emit_path_pattern(p: &mut Printer<'_>, pp: &PathPattern) {
1125 if let Some(base) = &pp.base {
1126 emit_expr(p, base);
1127 p.write_str(".");
1128 }
1129 p.write_ident(pp.type_name.name);
1130 p.write_str("::");
1131 p.write_ident(pp.variant.name);
1132}
1133
1134fn emit_field_patterns(p: &mut Printer<'_>, fields: &[FieldPattern]) {
1135 if fields.is_empty() {
1136 p.write_str(" {}");
1137 return;
1138 }
1139 p.write_str(" { ");
1140 for (i, fp) in fields.iter().enumerate() {
1141 if i > 0 {
1142 p.write_str(", ");
1143 }
1144 emit_field_pattern(p, fp);
1145 }
1146 p.write_str(" }");
1147}
1148
1149fn emit_field_pattern(p: &mut Printer<'_>, fp: &FieldPattern) {
1150 match &fp.field_name {
1151 None => p.write_str(".."),
1152 Some(name) => match &fp.sub {
1153 None => {
1154 if fp.is_mut {
1155 p.write_str("mut ");
1156 }
1157 p.write_ident(name.name);
1158 }
1159 Some(sub) => {
1160 p.write_ident(name.name);
1161 p.write_str(": ");
1162 emit_pattern(p, sub);
1163 }
1164 },
1165 }
1166}
1167
1168fn emit_tuple_elem_pattern(p: &mut Printer<'_>, te: &TupleElemPattern) {
1169 match te {
1170 TupleElemPattern::Pattern(pat) => emit_pattern(p, pat),
1171 TupleElemPattern::Rest(_) => p.write_str(".."),
1172 }
1173}
1174
1175pub fn emit_type_expr(p: &mut Printer<'_>, ty: &TypeExpr) {
1178 match ty {
1179 TypeExpr::Named(ident) => p.write_ident(ident.name),
1180 TypeExpr::Unit(_) => p.write_str("()"),
1181 TypeExpr::Never(_) => p.write_str("!"),
1182 TypeExpr::Array {
1183 element, length, ..
1184 } => {
1185 p.write_str("[");
1186 emit_type_expr(p, element);
1187 p.write_str("; ");
1188 p.write_str(&length.to_string());
1189 p.write_str("]");
1190 }
1191 TypeExpr::AnonymousStruct {
1192 directives,
1193 fields,
1194 methods,
1195 ..
1196 } => {
1197 emit_directives_inline(p, directives);
1198 p.write_str("struct {");
1199 if fields.is_empty() && methods.is_empty() {
1200 p.write_str("}");
1201 } else {
1202 p.newline();
1203 p.indent();
1204 for f in fields {
1205 emit_anon_struct_field(p, f);
1206 p.write_str(",");
1207 p.newline();
1208 }
1209 if !fields.is_empty() && !methods.is_empty() {
1210 p.blank_line();
1211 }
1212 for (i, m) in methods.iter().enumerate() {
1213 if i > 0 {
1214 p.blank_line();
1215 }
1216 emit_method(p, m);
1217 p.newline();
1218 }
1219 p.dedent();
1220 p.write_str("}");
1221 }
1222 }
1223 TypeExpr::AnonymousEnum {
1224 directives,
1225 variants,
1226 methods,
1227 ..
1228 } => {
1229 emit_directives_inline(p, directives);
1230 p.write_str("enum {");
1231 if variants.is_empty() && methods.is_empty() {
1232 p.write_str("}");
1233 } else {
1234 p.newline();
1235 p.indent();
1236 for v in variants {
1237 emit_enum_variant(p, v);
1238 p.write_str(",");
1239 p.newline();
1240 }
1241 if !variants.is_empty() && !methods.is_empty() {
1242 p.blank_line();
1243 }
1244 for (i, m) in methods.iter().enumerate() {
1245 if i > 0 {
1246 p.blank_line();
1247 }
1248 emit_method(p, m);
1249 p.newline();
1250 }
1251 p.dedent();
1252 p.write_str("}");
1253 }
1254 }
1255 TypeExpr::AnonymousInterface { methods, .. } => {
1256 p.write_str("interface {");
1257 if methods.is_empty() {
1258 p.write_str("}");
1259 } else {
1260 p.newline();
1261 p.indent();
1262 for sig in methods {
1263 emit_method_sig(p, sig);
1264 p.newline();
1265 }
1266 p.dedent();
1267 p.write_str("}");
1268 }
1269 }
1270 TypeExpr::TypeCall { callee, args, .. } => {
1271 p.write_ident(callee.name);
1272 p.write_str("(");
1273 for (i, a) in args.iter().enumerate() {
1274 if i > 0 {
1275 p.write_str(", ");
1276 }
1277 emit_type_expr(p, a);
1278 }
1279 p.write_str(")");
1280 }
1281 TypeExpr::Tuple { elems, .. } => {
1282 p.write_str("(");
1283 for (i, t) in elems.iter().enumerate() {
1284 if i > 0 {
1285 p.write_str(", ");
1286 }
1287 emit_type_expr(p, t);
1288 }
1289 if elems.len() == 1 {
1290 p.write_str(",");
1291 }
1292 p.write_str(")");
1293 }
1294 }
1295}
1296
1297fn emit_directives_inline(p: &mut Printer<'_>, dirs: &[Directive]) {
1298 for dir in dirs {
1299 emit_directive(p, dir);
1300 p.write_str(" ");
1301 }
1302}
1303
1304fn emit_anon_struct_field(p: &mut Printer<'_>, f: &AnonStructField) {
1305 if let Some(doc) = &f.doc {
1306 emit_doc(p, doc);
1307 }
1308 p.write_ident(f.name.name);
1309 p.write_str(": ");
1310 emit_type_expr(p, &f.ty);
1311}
1312
1313fn binary_op_str(op: BinaryOp) -> &'static str {
1316 match op {
1317 BinaryOp::Add => "+",
1318 BinaryOp::Sub => "-",
1319 BinaryOp::Mul => "*",
1320 BinaryOp::Div => "/",
1321 BinaryOp::Mod => "%",
1322 BinaryOp::Eq => "==",
1323 BinaryOp::Ne => "!=",
1324 BinaryOp::Lt => "<",
1325 BinaryOp::Gt => ">",
1326 BinaryOp::Le => "<=",
1327 BinaryOp::Ge => ">=",
1328 BinaryOp::And => "&&",
1329 BinaryOp::Or => "||",
1330 BinaryOp::BitAnd => "&",
1331 BinaryOp::BitOr => "|",
1332 BinaryOp::BitXor => "^",
1333 BinaryOp::Shl => "<<",
1334 BinaryOp::Shr => ">>",
1335 }
1336}
1337
1338fn unary_op_str(op: UnaryOp) -> &'static str {
1339 match op {
1340 UnaryOp::Neg => "-",
1341 UnaryOp::Not => "!",
1342 UnaryOp::BitNot => "~",
1343 UnaryOp::Ref => "&",
1344 UnaryOp::MutRef => "&mut ",
1345 }
1346}