1 //===- AST.cpp - Helper for printing out the Toy AST ----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the AST dump for the Toy language.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "toy/AST.h"
14
15 #include "llvm/ADT/Twine.h"
16 #include "llvm/ADT/TypeSwitch.h"
17 #include "llvm/Support/raw_ostream.h"
18
19 using namespace toy;
20
21 namespace {
22
23 // RAII helper to manage increasing/decreasing the indentation as we traverse
24 // the AST
25 struct Indent {
Indent__anone448d5e10111::Indent26 Indent(int &level) : level(level) { ++level; }
~Indent__anone448d5e10111::Indent27 ~Indent() { --level; }
28 int &level;
29 };
30
31 /// Helper class that implement the AST tree traversal and print the nodes along
32 /// the way. The only data member is the current indentation level.
33 class ASTDumper {
34 public:
35 void dump(ModuleAST *node);
36
37 private:
38 void dump(const VarType &type);
39 void dump(VarDeclExprAST *varDecl);
40 void dump(ExprAST *expr);
41 void dump(ExprASTList *exprList);
42 void dump(NumberExprAST *num);
43 void dump(LiteralExprAST *node);
44 void dump(StructLiteralExprAST *node);
45 void dump(VariableExprAST *node);
46 void dump(ReturnExprAST *node);
47 void dump(BinaryExprAST *node);
48 void dump(CallExprAST *node);
49 void dump(PrintExprAST *node);
50 void dump(PrototypeAST *node);
51 void dump(FunctionAST *node);
52 void dump(StructAST *node);
53
54 // Actually print spaces matching the current indentation level
indent()55 void indent() {
56 for (int i = 0; i < curIndent; i++)
57 llvm::errs() << " ";
58 }
59 int curIndent = 0;
60 };
61
62 } // namespace
63
64 /// Return a formatted string for the location of any node
65 template <typename T>
loc(T * node)66 static std::string loc(T *node) {
67 const auto &loc = node->loc();
68 return (llvm::Twine("@") + *loc.file + ":" + llvm::Twine(loc.line) + ":" +
69 llvm::Twine(loc.col))
70 .str();
71 }
72
73 // Helper Macro to bump the indentation level and print the leading spaces for
74 // the current indentations
75 #define INDENT() \
76 Indent level_(curIndent); \
77 indent();
78
79 /// Dispatch to a generic expressions to the appropriate subclass using RTTI
dump(ExprAST * expr)80 void ASTDumper::dump(ExprAST *expr) {
81 llvm::TypeSwitch<ExprAST *>(expr)
82 .Case<BinaryExprAST, CallExprAST, LiteralExprAST, NumberExprAST,
83 PrintExprAST, ReturnExprAST, StructLiteralExprAST, VarDeclExprAST,
84 VariableExprAST>([&](auto *node) { this->dump(node); })
85 .Default([&](ExprAST *) {
86 // No match, fallback to a generic message
87 INDENT();
88 llvm::errs() << "<unknown Expr, kind " << expr->getKind() << ">\n";
89 });
90 }
91
92 /// A variable declaration is printing the variable name, the type, and then
93 /// recurse in the initializer value.
dump(VarDeclExprAST * varDecl)94 void ASTDumper::dump(VarDeclExprAST *varDecl) {
95 INDENT();
96 llvm::errs() << "VarDecl " << varDecl->getName();
97 dump(varDecl->getType());
98 llvm::errs() << " " << loc(varDecl) << "\n";
99 if (auto *initVal = varDecl->getInitVal())
100 dump(initVal);
101 }
102
103 /// A "block", or a list of expression
dump(ExprASTList * exprList)104 void ASTDumper::dump(ExprASTList *exprList) {
105 INDENT();
106 llvm::errs() << "Block {\n";
107 for (auto &expr : *exprList)
108 dump(expr.get());
109 indent();
110 llvm::errs() << "} // Block\n";
111 }
112
113 /// A literal number, just print the value.
dump(NumberExprAST * num)114 void ASTDumper::dump(NumberExprAST *num) {
115 INDENT();
116 llvm::errs() << num->getValue() << " " << loc(num) << "\n";
117 }
118
119 /// Helper to print recursively a literal. This handles nested array like:
120 /// [ [ 1, 2 ], [ 3, 4 ] ]
121 /// We print out such array with the dimensions spelled out at every level:
122 /// <2,2>[<2>[ 1, 2 ], <2>[ 3, 4 ] ]
printLitHelper(ExprAST * litOrNum)123 void printLitHelper(ExprAST *litOrNum) {
124 // Inside a literal expression we can have either a number or another literal
125 if (auto *num = llvm::dyn_cast<NumberExprAST>(litOrNum)) {
126 llvm::errs() << num->getValue();
127 return;
128 }
129 auto *literal = llvm::cast<LiteralExprAST>(litOrNum);
130
131 // Print the dimension for this literal first
132 llvm::errs() << "<";
133 llvm::interleaveComma(literal->getDims(), llvm::errs());
134 llvm::errs() << ">";
135
136 // Now print the content, recursing on every element of the list
137 llvm::errs() << "[ ";
138 llvm::interleaveComma(literal->getValues(), llvm::errs(),
139 [&](auto &elt) { printLitHelper(elt.get()); });
140 llvm::errs() << "]";
141 }
142
143 /// Print a literal, see the recursive helper above for the implementation.
dump(LiteralExprAST * node)144 void ASTDumper::dump(LiteralExprAST *node) {
145 INDENT();
146 llvm::errs() << "Literal: ";
147 printLitHelper(node);
148 llvm::errs() << " " << loc(node) << "\n";
149 }
150
151 /// Print a struct literal.
dump(StructLiteralExprAST * node)152 void ASTDumper::dump(StructLiteralExprAST *node) {
153 INDENT();
154 llvm::errs() << "Struct Literal: ";
155 for (auto &value : node->getValues())
156 dump(value.get());
157 indent();
158 llvm::errs() << " " << loc(node) << "\n";
159 }
160
161 /// Print a variable reference (just a name).
dump(VariableExprAST * node)162 void ASTDumper::dump(VariableExprAST *node) {
163 INDENT();
164 llvm::errs() << "var: " << node->getName() << " " << loc(node) << "\n";
165 }
166
167 /// Return statement print the return and its (optional) argument.
dump(ReturnExprAST * node)168 void ASTDumper::dump(ReturnExprAST *node) {
169 INDENT();
170 llvm::errs() << "Return\n";
171 if (node->getExpr().hasValue())
172 return dump(*node->getExpr());
173 {
174 INDENT();
175 llvm::errs() << "(void)\n";
176 }
177 }
178
179 /// Print a binary operation, first the operator, then recurse into LHS and RHS.
dump(BinaryExprAST * node)180 void ASTDumper::dump(BinaryExprAST *node) {
181 INDENT();
182 llvm::errs() << "BinOp: " << node->getOp() << " " << loc(node) << "\n";
183 dump(node->getLHS());
184 dump(node->getRHS());
185 }
186
187 /// Print a call expression, first the callee name and the list of args by
188 /// recursing into each individual argument.
dump(CallExprAST * node)189 void ASTDumper::dump(CallExprAST *node) {
190 INDENT();
191 llvm::errs() << "Call '" << node->getCallee() << "' [ " << loc(node) << "\n";
192 for (auto &arg : node->getArgs())
193 dump(arg.get());
194 indent();
195 llvm::errs() << "]\n";
196 }
197
198 /// Print a builtin print call, first the builtin name and then the argument.
dump(PrintExprAST * node)199 void ASTDumper::dump(PrintExprAST *node) {
200 INDENT();
201 llvm::errs() << "Print [ " << loc(node) << "\n";
202 dump(node->getArg());
203 indent();
204 llvm::errs() << "]\n";
205 }
206
207 /// Print type: only the shape is printed in between '<' and '>'
dump(const VarType & type)208 void ASTDumper::dump(const VarType &type) {
209 llvm::errs() << "<";
210 if (!type.name.empty())
211 llvm::errs() << type.name;
212 else
213 llvm::interleaveComma(type.shape, llvm::errs());
214 llvm::errs() << ">";
215 }
216
217 /// Print a function prototype, first the function name, and then the list of
218 /// parameters names.
dump(PrototypeAST * node)219 void ASTDumper::dump(PrototypeAST *node) {
220 INDENT();
221 llvm::errs() << "Proto '" << node->getName() << "' " << loc(node) << "\n";
222 indent();
223 llvm::errs() << "Params: [";
224 llvm::interleaveComma(node->getArgs(), llvm::errs(),
225 [](auto &arg) { llvm::errs() << arg->getName(); });
226 llvm::errs() << "]\n";
227 }
228
229 /// Print a function, first the prototype and then the body.
dump(FunctionAST * node)230 void ASTDumper::dump(FunctionAST *node) {
231 INDENT();
232 llvm::errs() << "Function \n";
233 dump(node->getProto());
234 dump(node->getBody());
235 }
236
237 /// Print a struct.
dump(StructAST * node)238 void ASTDumper::dump(StructAST *node) {
239 INDENT();
240 llvm::errs() << "Struct: " << node->getName() << " " << loc(node) << "\n";
241
242 {
243 INDENT();
244 llvm::errs() << "Variables: [\n";
245 for (auto &variable : node->getVariables())
246 dump(variable.get());
247 indent();
248 llvm::errs() << "]\n";
249 }
250 }
251
252 /// Print a module, actually loop over the functions and print them in sequence.
dump(ModuleAST * node)253 void ASTDumper::dump(ModuleAST *node) {
254 INDENT();
255 llvm::errs() << "Module:\n";
256 for (auto &record : *node) {
257 if (FunctionAST *function = llvm::dyn_cast<FunctionAST>(record.get()))
258 dump(function);
259 else if (StructAST *str = llvm::dyn_cast<StructAST>(record.get()))
260 dump(str);
261 else
262 llvm::errs() << "<unknown Record, kind " << record->getKind() << ">\n";
263 }
264 }
265
266 namespace toy {
267
268 // Public API
dump(ModuleAST & module)269 void dump(ModuleAST &module) { ASTDumper().dump(&module); }
270
271 } // namespace toy
272