1213dda68SMehdi Amini //===- AST.cpp - Helper for printing out the Toy AST ----------------------===//
2213dda68SMehdi Amini //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6213dda68SMehdi Amini //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8213dda68SMehdi Amini //
9213dda68SMehdi Amini // This file implements the AST dump for the Toy language.
10213dda68SMehdi Amini //
11213dda68SMehdi Amini //===----------------------------------------------------------------------===//
12213dda68SMehdi Amini
13213dda68SMehdi Amini #include "toy/AST.h"
14213dda68SMehdi Amini
15213dda68SMehdi Amini #include "llvm/ADT/Twine.h"
16ebf190fcSRiver Riddle #include "llvm/ADT/TypeSwitch.h"
17213dda68SMehdi Amini #include "llvm/Support/raw_ostream.h"
18213dda68SMehdi Amini
19213dda68SMehdi Amini using namespace toy;
20213dda68SMehdi Amini
21213dda68SMehdi Amini namespace {
22213dda68SMehdi Amini
23213dda68SMehdi Amini // RAII helper to manage increasing/decreasing the indentation as we traverse
24213dda68SMehdi Amini // the AST
25213dda68SMehdi Amini struct Indent {
Indent__anona73f187c0111::Indent26213dda68SMehdi Amini Indent(int &level) : level(level) { ++level; }
~Indent__anona73f187c0111::Indent27213dda68SMehdi Amini ~Indent() { --level; }
28213dda68SMehdi Amini int &level;
29213dda68SMehdi Amini };
30213dda68SMehdi Amini
31213dda68SMehdi Amini /// Helper class that implement the AST tree traversal and print the nodes along
32213dda68SMehdi Amini /// the way. The only data member is the current indentation level.
33213dda68SMehdi Amini class ASTDumper {
34213dda68SMehdi Amini public:
3522cfff70SRiver Riddle void dump(ModuleAST *node);
36213dda68SMehdi Amini
37213dda68SMehdi Amini private:
3822cfff70SRiver Riddle void dump(const VarType &type);
39213dda68SMehdi Amini void dump(VarDeclExprAST *varDecl);
40213dda68SMehdi Amini void dump(ExprAST *expr);
41213dda68SMehdi Amini void dump(ExprASTList *exprList);
42213dda68SMehdi Amini void dump(NumberExprAST *num);
4322cfff70SRiver Riddle void dump(LiteralExprAST *node);
4422cfff70SRiver Riddle void dump(VariableExprAST *node);
4522cfff70SRiver Riddle void dump(ReturnExprAST *node);
4622cfff70SRiver Riddle void dump(BinaryExprAST *node);
4722cfff70SRiver Riddle void dump(CallExprAST *node);
4822cfff70SRiver Riddle void dump(PrintExprAST *node);
4922cfff70SRiver Riddle void dump(PrototypeAST *node);
5022cfff70SRiver Riddle void dump(FunctionAST *node);
51213dda68SMehdi Amini
52213dda68SMehdi Amini // Actually print spaces matching the current indentation level
indent()53213dda68SMehdi Amini void indent() {
54213dda68SMehdi Amini for (int i = 0; i < curIndent; i++)
55213dda68SMehdi Amini llvm::errs() << " ";
56213dda68SMehdi Amini }
57213dda68SMehdi Amini int curIndent = 0;
58213dda68SMehdi Amini };
59213dda68SMehdi Amini
60213dda68SMehdi Amini } // namespace
61213dda68SMehdi Amini
62213dda68SMehdi Amini /// Return a formatted string for the location of any node
63*b7f93c28SJeff Niu template <typename T>
loc(T * node)64*b7f93c28SJeff Niu static std::string loc(T *node) {
6522cfff70SRiver Riddle const auto &loc = node->loc();
66213dda68SMehdi Amini return (llvm::Twine("@") + *loc.file + ":" + llvm::Twine(loc.line) + ":" +
67213dda68SMehdi Amini llvm::Twine(loc.col))
68213dda68SMehdi Amini .str();
69213dda68SMehdi Amini }
70213dda68SMehdi Amini
71213dda68SMehdi Amini // Helper Macro to bump the indentation level and print the leading spaces for
72213dda68SMehdi Amini // the current indentations
73213dda68SMehdi Amini #define INDENT() \
74213dda68SMehdi Amini Indent level_(curIndent); \
75213dda68SMehdi Amini indent();
76213dda68SMehdi Amini
77213dda68SMehdi Amini /// Dispatch to a generic expressions to the appropriate subclass using RTTI
dump(ExprAST * expr)78213dda68SMehdi Amini void ASTDumper::dump(ExprAST *expr) {
79ebf190fcSRiver Riddle llvm::TypeSwitch<ExprAST *>(expr)
8074278dd0SRiver Riddle .Case<BinaryExprAST, CallExprAST, LiteralExprAST, NumberExprAST,
8174278dd0SRiver Riddle PrintExprAST, ReturnExprAST, VarDeclExprAST, VariableExprAST>(
825a0d4803SRiver Riddle [&](auto *node) { this->dump(node); })
8374278dd0SRiver Riddle .Default([&](ExprAST *) {
84213dda68SMehdi Amini // No match, fallback to a generic message
85213dda68SMehdi Amini INDENT();
86213dda68SMehdi Amini llvm::errs() << "<unknown Expr, kind " << expr->getKind() << ">\n";
8774278dd0SRiver Riddle });
88213dda68SMehdi Amini }
89213dda68SMehdi Amini
90213dda68SMehdi Amini /// A variable declaration is printing the variable name, the type, and then
91213dda68SMehdi Amini /// recurse in the initializer value.
dump(VarDeclExprAST * varDecl)92213dda68SMehdi Amini void ASTDumper::dump(VarDeclExprAST *varDecl) {
93213dda68SMehdi Amini INDENT();
94213dda68SMehdi Amini llvm::errs() << "VarDecl " << varDecl->getName();
95213dda68SMehdi Amini dump(varDecl->getType());
96213dda68SMehdi Amini llvm::errs() << " " << loc(varDecl) << "\n";
97213dda68SMehdi Amini dump(varDecl->getInitVal());
98213dda68SMehdi Amini }
99213dda68SMehdi Amini
100213dda68SMehdi Amini /// A "block", or a list of expression
dump(ExprASTList * exprList)101213dda68SMehdi Amini void ASTDumper::dump(ExprASTList *exprList) {
102213dda68SMehdi Amini INDENT();
103213dda68SMehdi Amini llvm::errs() << "Block {\n";
104213dda68SMehdi Amini for (auto &expr : *exprList)
105213dda68SMehdi Amini dump(expr.get());
106213dda68SMehdi Amini indent();
107213dda68SMehdi Amini llvm::errs() << "} // Block\n";
108213dda68SMehdi Amini }
109213dda68SMehdi Amini
110213dda68SMehdi Amini /// A literal number, just print the value.
dump(NumberExprAST * num)111213dda68SMehdi Amini void ASTDumper::dump(NumberExprAST *num) {
112213dda68SMehdi Amini INDENT();
113213dda68SMehdi Amini llvm::errs() << num->getValue() << " " << loc(num) << "\n";
114213dda68SMehdi Amini }
115213dda68SMehdi Amini
116f28c5acaSKazuaki Ishizaki /// Helper to print recursively a literal. This handles nested array like:
117213dda68SMehdi Amini /// [ [ 1, 2 ], [ 3, 4 ] ]
118213dda68SMehdi Amini /// We print out such array with the dimensions spelled out at every level:
119213dda68SMehdi Amini /// <2,2>[<2>[ 1, 2 ], <2>[ 3, 4 ] ]
printLitHelper(ExprAST * litOrNum)12022cfff70SRiver Riddle void printLitHelper(ExprAST *litOrNum) {
121213dda68SMehdi Amini // Inside a literal expression we can have either a number or another literal
12202b6fb21SMehdi Amini if (auto *num = llvm::dyn_cast<NumberExprAST>(litOrNum)) {
123213dda68SMehdi Amini llvm::errs() << num->getValue();
124213dda68SMehdi Amini return;
125213dda68SMehdi Amini }
12622cfff70SRiver Riddle auto *literal = llvm::cast<LiteralExprAST>(litOrNum);
127213dda68SMehdi Amini
128213dda68SMehdi Amini // Print the dimension for this literal first
129213dda68SMehdi Amini llvm::errs() << "<";
1302f21a579SRiver Riddle llvm::interleaveComma(literal->getDims(), llvm::errs());
131213dda68SMehdi Amini llvm::errs() << ">";
132213dda68SMehdi Amini
133213dda68SMehdi Amini // Now print the content, recursing on every element of the list
134213dda68SMehdi Amini llvm::errs() << "[ ";
1352f21a579SRiver Riddle llvm::interleaveComma(literal->getValues(), llvm::errs(),
13622cfff70SRiver Riddle [&](auto &elt) { printLitHelper(elt.get()); });
137213dda68SMehdi Amini llvm::errs() << "]";
138213dda68SMehdi Amini }
139213dda68SMehdi Amini
140213dda68SMehdi Amini /// Print a literal, see the recursive helper above for the implementation.
dump(LiteralExprAST * node)14122cfff70SRiver Riddle void ASTDumper::dump(LiteralExprAST *node) {
142213dda68SMehdi Amini INDENT();
143213dda68SMehdi Amini llvm::errs() << "Literal: ";
14422cfff70SRiver Riddle printLitHelper(node);
14522cfff70SRiver Riddle llvm::errs() << " " << loc(node) << "\n";
146213dda68SMehdi Amini }
147213dda68SMehdi Amini
148213dda68SMehdi Amini /// Print a variable reference (just a name).
dump(VariableExprAST * node)14922cfff70SRiver Riddle void ASTDumper::dump(VariableExprAST *node) {
150213dda68SMehdi Amini INDENT();
15122cfff70SRiver Riddle llvm::errs() << "var: " << node->getName() << " " << loc(node) << "\n";
152213dda68SMehdi Amini }
153213dda68SMehdi Amini
154213dda68SMehdi Amini /// Return statement print the return and its (optional) argument.
dump(ReturnExprAST * node)15522cfff70SRiver Riddle void ASTDumper::dump(ReturnExprAST *node) {
156213dda68SMehdi Amini INDENT();
157213dda68SMehdi Amini llvm::errs() << "Return\n";
15822cfff70SRiver Riddle if (node->getExpr().hasValue())
15922cfff70SRiver Riddle return dump(*node->getExpr());
160213dda68SMehdi Amini {
161213dda68SMehdi Amini INDENT();
162213dda68SMehdi Amini llvm::errs() << "(void)\n";
163213dda68SMehdi Amini }
164213dda68SMehdi Amini }
165213dda68SMehdi Amini
166213dda68SMehdi Amini /// Print a binary operation, first the operator, then recurse into LHS and RHS.
dump(BinaryExprAST * node)16722cfff70SRiver Riddle void ASTDumper::dump(BinaryExprAST *node) {
168213dda68SMehdi Amini INDENT();
16922cfff70SRiver Riddle llvm::errs() << "BinOp: " << node->getOp() << " " << loc(node) << "\n";
17022cfff70SRiver Riddle dump(node->getLHS());
17122cfff70SRiver Riddle dump(node->getRHS());
172213dda68SMehdi Amini }
173213dda68SMehdi Amini
174213dda68SMehdi Amini /// Print a call expression, first the callee name and the list of args by
175213dda68SMehdi Amini /// recursing into each individual argument.
dump(CallExprAST * node)17622cfff70SRiver Riddle void ASTDumper::dump(CallExprAST *node) {
177213dda68SMehdi Amini INDENT();
17822cfff70SRiver Riddle llvm::errs() << "Call '" << node->getCallee() << "' [ " << loc(node) << "\n";
17922cfff70SRiver Riddle for (auto &arg : node->getArgs())
180213dda68SMehdi Amini dump(arg.get());
181213dda68SMehdi Amini indent();
182213dda68SMehdi Amini llvm::errs() << "]\n";
183213dda68SMehdi Amini }
184213dda68SMehdi Amini
185213dda68SMehdi Amini /// Print a builtin print call, first the builtin name and then the argument.
dump(PrintExprAST * node)18622cfff70SRiver Riddle void ASTDumper::dump(PrintExprAST *node) {
187213dda68SMehdi Amini INDENT();
18822cfff70SRiver Riddle llvm::errs() << "Print [ " << loc(node) << "\n";
18922cfff70SRiver Riddle dump(node->getArg());
190213dda68SMehdi Amini indent();
191213dda68SMehdi Amini llvm::errs() << "]\n";
192213dda68SMehdi Amini }
193213dda68SMehdi Amini
194213dda68SMehdi Amini /// Print type: only the shape is printed in between '<' and '>'
dump(const VarType & type)19522cfff70SRiver Riddle void ASTDumper::dump(const VarType &type) {
196213dda68SMehdi Amini llvm::errs() << "<";
1972f21a579SRiver Riddle llvm::interleaveComma(type.shape, llvm::errs());
198213dda68SMehdi Amini llvm::errs() << ">";
199213dda68SMehdi Amini }
200213dda68SMehdi Amini
201213dda68SMehdi Amini /// Print a function prototype, first the function name, and then the list of
202213dda68SMehdi Amini /// parameters names.
dump(PrototypeAST * node)20322cfff70SRiver Riddle void ASTDumper::dump(PrototypeAST *node) {
204213dda68SMehdi Amini INDENT();
2055633813bSRahul Joshi llvm::errs() << "Proto '" << node->getName() << "' " << loc(node) << "\n";
206213dda68SMehdi Amini indent();
207213dda68SMehdi Amini llvm::errs() << "Params: [";
2082f21a579SRiver Riddle llvm::interleaveComma(node->getArgs(), llvm::errs(),
20922cfff70SRiver Riddle [](auto &arg) { llvm::errs() << arg->getName(); });
210213dda68SMehdi Amini llvm::errs() << "]\n";
211213dda68SMehdi Amini }
212213dda68SMehdi Amini
213213dda68SMehdi Amini /// Print a function, first the prototype and then the body.
dump(FunctionAST * node)21422cfff70SRiver Riddle void ASTDumper::dump(FunctionAST *node) {
215213dda68SMehdi Amini INDENT();
216213dda68SMehdi Amini llvm::errs() << "Function \n";
21722cfff70SRiver Riddle dump(node->getProto());
21822cfff70SRiver Riddle dump(node->getBody());
219213dda68SMehdi Amini }
220213dda68SMehdi Amini
221213dda68SMehdi Amini /// Print a module, actually loop over the functions and print them in sequence.
dump(ModuleAST * node)22222cfff70SRiver Riddle void ASTDumper::dump(ModuleAST *node) {
223213dda68SMehdi Amini INDENT();
224213dda68SMehdi Amini llvm::errs() << "Module:\n";
22522cfff70SRiver Riddle for (auto &f : *node)
22622cfff70SRiver Riddle dump(&f);
227213dda68SMehdi Amini }
228213dda68SMehdi Amini
229213dda68SMehdi Amini namespace toy {
230213dda68SMehdi Amini
231213dda68SMehdi Amini // Public API
dump(ModuleAST & module)232213dda68SMehdi Amini void dump(ModuleAST &module) { ASTDumper().dump(&module); }
233213dda68SMehdi Amini
234213dda68SMehdi Amini } // namespace toy
235