1use crate::ast::*;
2
3use crate::ast::Expr::*;
4use crate::ast::Stmt::*;
5use crate::interner::{ArcStr, Interner, Name};
6
7macro_rules! dump {
8 ($self_:ident, $($message:tt)*) => {{
9 for _ in 0..($self_.indent*2) {
10 print!(" ");
11 }
12
13 println!($($message)*);
14 }};
15}
16
17pub fn dump(ast: &Ast, interner: &Interner) {
18 let mut dumper = AstDumper {
19 interner,
20 indent: 0,
21 };
22
23 dumper.dump_ast(ast);
24}
25
26pub fn dump_fct(fct: &Function, interner: &Interner) {
27 let mut dumper = AstDumper {
28 interner,
29 indent: 0,
30 };
31
32 dumper.dump_fct(fct);
33}
34
35pub fn dump_expr<'a>(expr: &'a Expr, interner: &'a Interner) {
36 let mut dumper = AstDumper {
37 interner,
38 indent: 0,
39 };
40
41 dumper.dump_expr(expr);
42}
43
44pub fn dump_stmt<'a>(stmt: &'a Stmt, interner: &'a Interner) {
45 let mut dumper = AstDumper {
46 interner,
47 indent: 0,
48 };
49
50 dumper.dump_stmt(stmt);
51}
52
53struct AstDumper<'a> {
54 interner: &'a Interner,
55 indent: u32,
56}
57
58impl<'a> AstDumper<'a> {
59 fn dump_ast(&mut self, ast: &Ast) {
60 for f in &ast.files {
61 dump!(self, "file {}", &f.path);
62
63 self.indent(|d| {
64 d.dump_file(f);
65 })
66 }
67 }
68
69 fn dump_file(&mut self, f: &File) {
70 for el in &f.elements {
71 match *el {
72 ElemFunction(ref fct) => self.dump_fct(fct),
73 ElemClass(ref cls) => self.dump_class(cls),
74 ElemStruct(ref struc) => self.dump_struct(struc),
75 ElemTrait(ref xtrait) => self.dump_trait(xtrait),
76 ElemImpl(ref ximpl) => self.dump_impl(ximpl),
77 ElemModule(ref module) => self.dump_module(module),
78 ElemGlobal(ref global) => self.dump_global(global),
79 ElemConst(ref xconst) => self.dump_const(xconst),
80 ElemEnum(ref xenum) => self.dump_enum(xenum),
81 }
82 }
83 }
84
85 fn dump_global(&mut self, global: &Global) {
86 dump!(
87 self,
88 "global {} @ {} {}",
89 self.str(global.name),
90 global.pos,
91 global.id
92 );
93
94 self.indent(|d| {
95 d.dump_type(&global.data_type);
96
97 if let Some(ref expr) = global.expr {
98 d.dump_expr(expr);
99 } else {
100 dump!(d, "<no expr given>");
101 }
102 });
103 }
104
105 fn dump_const(&mut self, xconst: &Const) {
106 dump!(
107 self,
108 "const {} @ {} {}",
109 self.str(xconst.name),
110 xconst.pos,
111 xconst.id
112 );
113
114 self.indent(|d| {
115 d.dump_type(&xconst.data_type);
116 d.dump_expr(&xconst.expr);
117 });
118 }
119
120 fn dump_enum(&mut self, xenum: &Enum) {
121 dump!(
122 self,
123 "enum {} @ {} {}",
124 self.str(xenum.name),
125 xenum.pos,
126 xenum.id
127 );
128
129 self.indent(|d| {
130 for value in &xenum.values {
131 d.dump_expr(value)
132 }
133 });
134 }
135
136 fn dump_impl(&mut self, ximpl: &Impl) {
137 dump!(self, "impl @ {} {}", ximpl.pos, ximpl.id);
138
139 self.indent(|d| {
140 if let Some(trait_type) = ximpl.trait_type.as_ref() {
141 d.dump_type(trait_type);
142 dump!(d, "for");
143 }
144
145 d.dump_type(&ximpl.class_type);
146
147 for mtd in &ximpl.methods {
148 d.dump_fct(mtd);
149 }
150 });
151 }
152
153 fn dump_struct(&mut self, struc: &Struct) {
154 dump!(
155 self,
156 "struct {} @ {} {}",
157 self.str(struc.name),
158 struc.pos,
159 struc.id
160 );
161
162 self.indent(|d| {
163 for field in &struc.fields {
164 d.dump_struct_field(field);
165 }
166 });
167 }
168
169 fn dump_struct_field(&mut self, field: &StructField) {
170 dump!(
171 self,
172 "field {} @ {} {}",
173 self.str(field.name),
174 field.pos,
175 field.id
176 );
177 self.indent(|d| d.dump_type(&field.data_type));
178 }
179
180 fn dump_trait(&mut self, t: &Trait) {
181 dump!(self, "trait {} @ {} {}", self.str(t.name), t.pos, t.id);
182 self.indent(|d| {
183 for m in &t.methods {
184 d.dump_fct(m);
185 }
186 });
187 }
188
189 fn dump_class(&mut self, cls: &Class) {
190 dump!(
191 self,
192 "class {} @ {} {}",
193 self.str(cls.name),
194 cls.pos,
195 cls.id
196 );
197
198 self.indent(|d| {
199 dump!(d, "open = {}", cls.has_open);
200
201 if let Some(ref parent_class) = cls.parent_class {
202 dump!(
203 d,
204 "super (name={} @ {})",
205 d.str(parent_class.name),
206 parent_class.pos
207 );
208 }
209
210 dump!(d, "fields");
211
212 d.indent(|d| {
213 for field in &cls.fields {
214 d.dump_field(field);
215 }
216 });
217
218 dump!(d, "constructor");
219 if let Some(ctor) = &cls.constructor {
220 d.indent(|d| d.dump_fct(ctor));
221 }
222
223 dump!(d, "methods");
224 d.indent(|d| {
225 for mtd in &cls.methods {
226 d.dump_fct(mtd);
227 }
228 });
229 });
230 }
231
232 fn dump_module(&mut self, modu: &Module) {
233 dump!(
234 self,
235 "module {} @ {} {}",
236 self.str(modu.name),
237 modu.pos,
238 modu.id
239 );
240
241 self.indent(|d| {
242 if let Some(ref parent_class) = modu.parent_class {
243 dump!(
244 d,
245 "super (name={} @ {})",
246 d.str(parent_class.name),
247 parent_class.pos
248 );
249 }
250
251 dump!(d, "fields");
252
253 d.indent(|d| {
254 for field in &modu.fields {
255 d.dump_field(field);
256 }
257 });
258
259 dump!(d, "constructor");
260 if let Some(ctor) = &modu.constructor {
261 d.indent(|d| d.dump_fct(ctor));
262 }
263
264 dump!(d, "methods");
265 d.indent(|d| {
266 for mtd in &modu.methods {
267 d.dump_fct(mtd);
268 }
269 });
270 });
271 }
272
273 fn dump_field(&mut self, field: &Field) {
274 dump!(
275 self,
276 "field {} @ {} {}",
277 self.str(field.name),
278 field.pos,
279 field.id
280 );
281 self.indent(|d| d.dump_type(&field.data_type));
282 }
283
284 fn dump_fct(&mut self, fct: &Function) {
285 dump!(self, "fct {} @ {} {}", self.str(fct.name), fct.pos, fct.id);
286
287 self.indent(|d| {
288 dump!(d, "open = {}", fct.has_open);
289 dump!(d, "override = {}", fct.has_override);
290 dump!(d, "final = {}", fct.has_final);
291 dump!(d, "internal = {}", fct.internal);
292 dump!(d, "throws = {}", fct.throws);
293 dump!(d, "params");
294 d.indent(|d| {
295 if fct.params.is_empty() {
296 dump!(d, "no params");
297 } else {
298 for param in &fct.params {
299 d.dump_param(param);
300 }
301 }
302 });
303
304 dump!(d, "returns");
305
306 if let Some(ref ty) = fct.return_type {
307 d.indent(|d| d.dump_type(ty));
308 } else {
309 d.indent(|d| dump!(d, "<no return type>"))
310 }
311
312 dump!(d, "executes");
313
314 if let Some(ref block) = fct.block {
315 d.indent(|d| d.dump_expr_block(block));
316 }
317 });
318 }
319
320 fn dump_param(&mut self, param: &Param) {
321 dump!(
322 self,
323 "param {} @ {} {}",
324 self.str(param.name),
325 param.pos,
326 param.id
327 );
328
329 self.indent(|d| d.dump_type(¶m.data_type));
330 }
331
332 fn dump_type(&mut self, ty: &Type) {
333 dump!(
334 self,
335 "type `{}` @ {:?} {}",
336 ty.to_string(self.interner),
337 ty.pos(),
338 ty.id()
339 );
340 }
341
342 fn dump_stmt(&mut self, stmt: &Stmt) {
343 match *stmt {
344 StmtReturn(ref ret) => self.dump_stmt_return(ret),
345 StmtBreak(ref stmt) => self.dump_stmt_break(stmt),
346 StmtContinue(ref stmt) => self.dump_stmt_continue(stmt),
347 StmtExpr(ref expr) => self.dump_stmt_expr(expr),
348 StmtVar(ref stmt) => self.dump_stmt_var(stmt),
349 StmtWhile(ref stmt) => self.dump_stmt_while(stmt),
350 StmtLoop(ref stmt) => self.dump_stmt_loop(stmt),
351 StmtThrow(ref stmt) => self.dump_stmt_throw(stmt),
352 StmtDefer(ref stmt) => self.dump_stmt_defer(stmt),
353 StmtDo(ref stmt) => self.dump_stmt_do(stmt),
354 StmtFor(ref stmt) => self.dump_stmt_for(stmt),
355 }
356 }
357
358 fn dump_stmt_var(&mut self, stmt: &StmtVarType) {
359 dump!(
360 self,
361 "let {} @ {} {}",
362 self.str(stmt.name),
363 stmt.pos,
364 stmt.id
365 );
366
367 self.indent(|d| {
368 dump!(d, "type");
369 d.indent(|d| {
370 if let Some(ref ty) = stmt.data_type {
371 d.dump_type(ty);
372 } else {
373 dump!(d, "<no type given>");
374 }
375 });
376
377 dump!(d, "expr");
378 d.indent(|d| {
379 if let Some(ref expr) = stmt.expr {
380 d.dump_expr(expr);
381 } else {
382 dump!(d, "<no expr given>");
383 }
384 });
385 });
386 }
387
388 fn dump_stmt_for(&mut self, stmt: &StmtForType) {
389 dump!(self, "for @ {} {}", stmt.pos, stmt.id);
390
391 self.indent(|d| {
392 dump!(d, "name {:?}", stmt.name);
393 dump!(d, "cond");
394 d.indent(|d| {
395 d.dump_expr(&stmt.expr);
396 });
397 dump!(d, "body");
398 d.indent(|d| {
399 d.dump_stmt(&stmt.block);
400 });
401 });
402 }
403
404 fn dump_stmt_while(&mut self, stmt: &StmtWhileType) {
405 dump!(self, "while @ {} {}", stmt.pos, stmt.id);
406
407 self.indent(|d| {
408 dump!(d, "cond");
409 d.indent(|d| {
410 d.dump_expr(&stmt.cond);
411 });
412
413 dump!(d, "body");
414 d.indent(|d| {
415 d.dump_stmt(&stmt.block);
416 });
417 });
418 }
419
420 fn dump_stmt_loop(&mut self, stmt: &StmtLoopType) {
421 dump!(self, "loop @ {} {}", stmt.pos, stmt.id);
422 self.indent(|d| {
423 d.dump_stmt(&stmt.block);
424 });
425 }
426
427 fn dump_stmt_expr(&mut self, stmt: &StmtExprType) {
428 dump!(self, "expr stmt @ {} {}", stmt.pos, stmt.id);
429 self.indent(|d| {
430 d.dump_expr(&stmt.expr);
431 });
432 }
433
434 fn dump_stmt_return(&mut self, ret: &StmtReturnType) {
435 dump!(self, "return @ {} {}", ret.pos, ret.id);
436
437 self.indent(|d| {
438 if let Some(ref expr) = ret.expr {
439 d.dump_expr(expr);
440 } else {
441 dump!(d, "<nothing>");
442 }
443 });
444 }
445
446 fn dump_stmt_break(&mut self, stmt: &StmtBreakType) {
447 dump!(self, "break @ {} {}", stmt.pos, stmt.id);
448 }
449
450 fn dump_stmt_continue(&mut self, stmt: &StmtContinueType) {
451 dump!(self, "continue @ {} {}", stmt.pos, stmt.id);
452 }
453
454 fn dump_stmt_throw(&mut self, stmt: &StmtThrowType) {
455 dump!(self, "throw @ {} {}", stmt.pos, stmt.id);
456 self.indent(|d| d.dump_expr(&stmt.expr));
457 }
458
459 fn dump_stmt_defer(&mut self, stmt: &StmtDeferType) {
460 dump!(self, "defer @ {} {}", stmt.pos, stmt.id);
461 self.indent(|d| d.dump_expr(&stmt.expr));
462 }
463
464 fn dump_stmt_do(&mut self, stmt: &StmtDoType) {
465 dump!(self, "try @ {} {}", stmt.pos, stmt.id);
466 self.indent(|d| d.dump_stmt(&stmt.do_block));
467
468 for catch in &stmt.catch_blocks {
469 dump!(self, "catch (var={})", self.str(catch.name));
470 self.indent(|d| {
471 d.dump_type(&catch.data_type);
472 d.dump_stmt(&catch.block);
473 });
474 }
475
476 if let Some(ref finally_block) = stmt.finally_block {
477 dump!(self, "finally");
478 self.dump_stmt(&finally_block.block);
479 }
480 }
481
482 fn dump_expr(&mut self, expr: &Expr) {
483 match *expr {
484 ExprUn(ref un) => self.dump_expr_un(un),
485 ExprBin(ref bin) => self.dump_expr_bin(bin),
486 ExprDot(ref field) => self.dump_expr_dot(field),
487 ExprLitChar(ref lit) => self.dump_expr_lit_char(lit),
488 ExprLitInt(ref lit) => self.dump_expr_lit_int(lit),
489 ExprLitFloat(ref lit) => self.dump_expr_lit_float(lit),
490 ExprLitStr(ref lit) => self.dump_expr_lit_str(lit),
491 ExprTemplate(ref tmpl) => self.dump_expr_template(tmpl),
492 ExprLitBool(ref lit) => self.dump_expr_lit_bool(lit),
493 ExprIdent(ref ident) => self.dump_expr_ident(ident),
494 ExprCall(ref call) => self.dump_expr_call(call),
495 ExprTypeParam(ref expr) => self.dump_expr_type_param(expr),
496 ExprPath(ref path) => self.dump_expr_path(path),
497 ExprDelegation(ref call) => self.dump_expr_delegation(call),
498 ExprSelf(ref selfie) => self.dump_expr_self(selfie),
499 ExprSuper(ref expr) => self.dump_expr_super(expr),
500 ExprNil(ref nil) => self.dump_expr_nil(nil),
501 ExprConv(ref expr) => self.dump_expr_conv(expr),
502 ExprTry(ref expr) => self.dump_expr_try(expr),
503 ExprLambda(ref expr) => self.dump_expr_lambda(expr),
504 ExprBlock(ref expr) => self.dump_expr_block(expr),
505 ExprIf(ref expr) => self.dump_expr_if(expr),
506 ExprTuple(ref expr) => self.dump_expr_tuple(expr),
507 }
508 }
509
510 fn dump_expr_block(&mut self, block: &ExprBlockType) {
511 dump!(
512 self,
513 "block ({} statement(s)) @ {} {}",
514 block.stmts.len(),
515 block.pos,
516 block.id
517 );
518
519 self.indent(|d| {
520 if block.stmts.is_empty() {
521 dump!(d, "no statements");
522 } else {
523 for stmt in &block.stmts {
524 d.dump_stmt(stmt);
525 }
526 }
527
528 if let Some(ref expr) = block.expr {
529 dump!(d, "value");
530 d.dump_expr(expr);
531 }
532 });
533
534 dump!(self, "block end");
535 }
536
537 fn dump_expr_if(&mut self, expr: &ExprIfType) {
538 dump!(self, "if @ {} {}", expr.pos, expr.id);
539
540 self.indent(|d| {
541 d.indent(|d| {
542 d.dump_expr(&expr.cond);
543 });
544 dump!(d, "then");
545 d.indent(|d| {
546 d.dump_expr(&expr.then_block);
547 });
548 dump!(d, "else");
549 d.indent(|d| {
550 d.dump_expr(&expr.then_block);
551 });
552 });
553 }
554
555 fn dump_expr_conv(&mut self, expr: &ExprConvType) {
556 self.indent(|d| d.dump_expr(&expr.object));
557 let op = if expr.is { "is" } else { "as" };
558 dump!(self, "{} @ {} {}", op, expr.pos, expr.id);
559 self.indent(|d| d.dump_type(&expr.data_type));
560 }
561
562 fn dump_expr_try(&mut self, expr: &ExprTryType) {
563 dump!(self, "try @ {} {}", expr.pos, expr.id);
564 self.indent(|d| d.dump_expr(&expr.expr));
565 }
566
567 fn dump_expr_delegation(&mut self, expr: &ExprDelegationType) {
568 dump!(self, "super @ {} {}", expr.pos, expr.id);
569
570 self.indent(|d| {
571 for arg in &expr.args {
572 d.dump_expr(arg);
573 }
574 });
575 }
576
577 fn dump_expr_self(&mut self, selfie: &ExprSelfType) {
578 dump!(self, "self @ {} {}", selfie.pos, selfie.id);
579 }
580
581 fn dump_expr_super(&mut self, selfie: &ExprSuperType) {
582 dump!(self, "super @ {} {}", selfie.pos, selfie.id);
583 }
584
585 fn dump_expr_nil(&mut self, nil: &ExprNilType) {
586 dump!(self, "nil @ {} {}", nil.pos, nil.id);
587 }
588
589 fn dump_expr_lit_char(&mut self, lit: &ExprLitCharType) {
590 dump!(
591 self,
592 "lit char {} {} @ {} {}",
593 lit.value,
594 lit.value as u32,
595 lit.pos,
596 lit.id
597 );
598 }
599
600 fn dump_expr_lit_int(&mut self, lit: &ExprLitIntType) {
601 dump!(self, "lit int {} @ {} {}", lit.value, lit.pos, lit.id);
602 }
603
604 fn dump_expr_lit_float(&mut self, lit: &ExprLitFloatType) {
605 dump!(self, "lit float {} @ {} {}", lit.value, lit.pos, lit.id);
606 }
607
608 fn dump_expr_lit_str(&mut self, lit: &ExprLitStrType) {
609 dump!(self, "lit string {:?} @ {} {}", lit.value, lit.pos, lit.id);
610 }
611
612 fn dump_expr_template(&mut self, tmpl: &ExprTemplateType) {
613 dump!(self, "template @ {} {}", tmpl.pos, tmpl.id);
614 self.indent(|d| {
615 for part in &tmpl.parts {
616 d.dump_expr(part)
617 }
618 });
619 }
620
621 fn dump_expr_lit_bool(&mut self, lit: &ExprLitBoolType) {
622 dump!(self, "lit bool {} @ {} {}", lit.value, lit.pos, lit.id);
623 }
624
625 fn dump_expr_ident(&mut self, ident: &ExprIdentType) {
626 dump!(
627 self,
628 "ident {} @ {} {}",
629 self.str(ident.name),
630 ident.pos,
631 ident.id
632 );
633 }
634
635 fn dump_expr_un(&mut self, expr: &ExprUnType) {
636 dump!(self, "unary {:?} @ {} {}", expr.op, expr.pos, expr.id);
637 self.indent(|d| d.dump_expr(&expr.opnd));
638 }
639
640 fn dump_expr_bin(&mut self, expr: &ExprBinType) {
641 self.indent(|d| d.dump_expr(&expr.rhs));
642 dump!(self, "binary {:?} @ {} {}", expr.op, expr.pos, expr.id);
643 self.indent(|d| d.dump_expr(&expr.lhs));
644 }
645
646 fn dump_expr_lambda(&mut self, expr: &ExprLambdaType) {
647 dump!(self, "lambda @ {} {}", expr.pos, expr.id);
648 self.indent(|d| d.dump_stmt(&expr.block));
649 }
650
651 fn dump_expr_tuple(&mut self, expr: &ExprTupleType) {
652 dump!(self, "tuple @ {} {}", expr.pos, expr.id);
653 self.indent(|d| {
654 for expr in &expr.values {
655 d.dump_expr(expr);
656 }
657 });
658 }
659
660 fn dump_expr_dot(&mut self, expr: &ExprDotType) {
661 self.indent(|d| d.dump_expr(&expr.rhs));
662 dump!(self, "dot @ {} {}", expr.pos, expr.id);
663 self.indent(|d| d.dump_expr(&expr.lhs));
664 }
665
666 fn dump_expr_path(&mut self, expr: &ExprPathType) {
667 self.indent(|d| d.dump_expr(&expr.rhs));
668 dump!(self, "path (::) @ {} {}", expr.pos, expr.id);
669 self.indent(|d| d.dump_expr(&expr.lhs));
670 }
671
672 fn dump_expr_call(&mut self, expr: &ExprCallType) {
673 dump!(self, "call @ {} {}", expr.pos, expr.id);
674
675 self.indent(|d| {
676 dump!(d, "callee");
677 d.indent(|d| d.dump_expr(&expr.callee));
678
679 for arg in &expr.args {
680 d.dump_expr(arg);
681 }
682 });
683 }
684
685 fn dump_expr_type_param(&mut self, expr: &ExprTypeParamType) {
686 dump!(self, "type param @ {} {}", expr.pos, expr.id);
687
688 self.indent(|d| {
689 dump!(d, "callee");
690 d.indent(|d| d.dump_expr(&expr.callee));
691
692 for arg in &expr.args {
693 d.dump_type(arg);
694 }
695 });
696 }
697
698 fn indent<F>(&mut self, fct: F)
699 where
700 F: Fn(&mut AstDumper) -> (),
701 {
702 let old = self.indent;
703 self.indent = old + 1;
704
705 fct(self);
706
707 self.indent = old;
708 }
709
710 fn str(&self, name: Name) -> ArcStr {
711 self.interner.str(name)
712 }
713}