dora_parser/ast/
dump.rs

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(&param.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}