1 //===- AST.cpp - Helper for printing out the Toy AST ----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the AST dump for the Toy language.
11 //===----------------------------------------------------------------------===//
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/Twine.h"
17 #include "llvm/ADT/TypeSwitch.h"
18 #include "llvm/Support/Casting.h"
19 #include "llvm/Support/raw_ostream.h"
26 // RAII helper to manage increasing/decreasing the indentation as we traverse
29 Indent(int &level
) : level(level
) { ++level
; }
30 ~Indent() { --level
; }
34 /// Helper class that implement the AST tree traversal and print the nodes along
35 /// the way. The only data member is the current indentation level.
38 void dump(ModuleAST
*node
);
41 void dump(const VarType
&type
);
42 void dump(VarDeclExprAST
*varDecl
);
43 void dump(ExprAST
*expr
);
44 void dump(ExprASTList
*exprList
);
45 void dump(NumberExprAST
*num
);
46 void dump(LiteralExprAST
*node
);
47 void dump(VariableExprAST
*node
);
48 void dump(ReturnExprAST
*node
);
49 void dump(BinaryExprAST
*node
);
50 void dump(CallExprAST
*node
);
51 void dump(PrintExprAST
*node
);
52 void dump(PrototypeAST
*node
);
53 void dump(FunctionAST
*node
);
55 // Actually print spaces matching the current indentation level
57 for (int i
= 0; i
< curIndent
; i
++)
65 /// Return a formatted string for the location of any node
67 static std::string
loc(T
*node
) {
68 const auto &loc
= node
->loc();
69 return (llvm::Twine("@") + *loc
.file
+ ":" + llvm::Twine(loc
.line
) + ":" +
74 // Helper Macro to bump the indentation level and print the leading spaces for
75 // the current indentations
77 Indent level_(curIndent); \
80 /// Dispatch to a generic expressions to the appropriate subclass using RTTI
81 void ASTDumper::dump(ExprAST
*expr
) {
82 llvm::TypeSwitch
<ExprAST
*>(expr
)
83 .Case
<BinaryExprAST
, CallExprAST
, LiteralExprAST
, NumberExprAST
,
84 PrintExprAST
, ReturnExprAST
, VarDeclExprAST
, VariableExprAST
>(
85 [&](auto *node
) { this->dump(node
); })
86 .Default([&](ExprAST
*) {
87 // No match, fallback to a generic message
89 llvm::errs() << "<unknown Expr, kind " << expr
->getKind() << ">\n";
93 /// A variable declaration is printing the variable name, the type, and then
94 /// recurse in the initializer value.
95 void ASTDumper::dump(VarDeclExprAST
*varDecl
) {
97 llvm::errs() << "VarDecl " << varDecl
->getName();
98 dump(varDecl
->getType());
99 llvm::errs() << " " << loc(varDecl
) << "\n";
100 dump(varDecl
->getInitVal());
103 /// A "block", or a list of expression
104 void ASTDumper::dump(ExprASTList
*exprList
) {
106 llvm::errs() << "Block {\n";
107 for (auto &expr
: *exprList
)
110 llvm::errs() << "} // Block\n";
113 /// A literal number, just print the value.
114 void ASTDumper::dump(NumberExprAST
*num
) {
116 llvm::errs() << num
->getValue() << " " << loc(num
) << "\n";
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 ] ]
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();
129 auto *literal
= llvm::cast
<LiteralExprAST
>(litOrNum
);
131 // Print the dimension for this literal first
133 llvm::interleaveComma(literal
->getDims(), llvm::errs());
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()); });
143 /// Print a literal, see the recursive helper above for the implementation.
144 void ASTDumper::dump(LiteralExprAST
*node
) {
146 llvm::errs() << "Literal: ";
147 printLitHelper(node
);
148 llvm::errs() << " " << loc(node
) << "\n";
151 /// Print a variable reference (just a name).
152 void ASTDumper::dump(VariableExprAST
*node
) {
154 llvm::errs() << "var: " << node
->getName() << " " << loc(node
) << "\n";
157 /// Return statement print the return and its (optional) argument.
158 void ASTDumper::dump(ReturnExprAST
*node
) {
160 llvm::errs() << "Return\n";
161 if (node
->getExpr().has_value())
162 return dump(*node
->getExpr());
165 llvm::errs() << "(void)\n";
169 /// Print a binary operation, first the operator, then recurse into LHS and RHS.
170 void ASTDumper::dump(BinaryExprAST
*node
) {
172 llvm::errs() << "BinOp: " << node
->getOp() << " " << loc(node
) << "\n";
173 dump(node
->getLHS());
174 dump(node
->getRHS());
177 /// Print a call expression, first the callee name and the list of args by
178 /// recursing into each individual argument.
179 void ASTDumper::dump(CallExprAST
*node
) {
181 llvm::errs() << "Call '" << node
->getCallee() << "' [ " << loc(node
) << "\n";
182 for (auto &arg
: node
->getArgs())
185 llvm::errs() << "]\n";
188 /// Print a builtin print call, first the builtin name and then the argument.
189 void ASTDumper::dump(PrintExprAST
*node
) {
191 llvm::errs() << "Print [ " << loc(node
) << "\n";
192 dump(node
->getArg());
194 llvm::errs() << "]\n";
197 /// Print type: only the shape is printed in between '<' and '>'
198 void ASTDumper::dump(const VarType
&type
) {
200 llvm::interleaveComma(type
.shape
, llvm::errs());
204 /// Print a function prototype, first the function name, and then the list of
205 /// parameters names.
206 void ASTDumper::dump(PrototypeAST
*node
) {
208 llvm::errs() << "Proto '" << node
->getName() << "' " << loc(node
) << "\n";
210 llvm::errs() << "Params: [";
211 llvm::interleaveComma(node
->getArgs(), llvm::errs(),
212 [](auto &arg
) { llvm::errs() << arg
->getName(); });
213 llvm::errs() << "]\n";
216 /// Print a function, first the prototype and then the body.
217 void ASTDumper::dump(FunctionAST
*node
) {
219 llvm::errs() << "Function \n";
220 dump(node
->getProto());
221 dump(node
->getBody());
224 /// Print a module, actually loop over the functions and print them in sequence.
225 void ASTDumper::dump(ModuleAST
*node
) {
227 llvm::errs() << "Module:\n";
228 for (auto &f
: *node
)
235 void dump(ModuleAST
&module
) { ASTDumper().dump(&module
); }