1d33a9dccSMehdi Amini //===- AST.cpp - Helper for printing out the Toy AST ----------------------===//
2d33a9dccSMehdi 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
6d33a9dccSMehdi Amini //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8d33a9dccSMehdi Amini //
9d33a9dccSMehdi Amini // This file implements the AST dump for the Toy language.
10d33a9dccSMehdi Amini //
11d33a9dccSMehdi Amini //===----------------------------------------------------------------------===//
12d33a9dccSMehdi Amini
13d33a9dccSMehdi Amini #include "toy/AST.h"
14d33a9dccSMehdi Amini
15*ec6da065SMehdi Amini #include "llvm/ADT/STLExtras.h"
16d33a9dccSMehdi Amini #include "llvm/ADT/Twine.h"
17ebf190fcSRiver Riddle #include "llvm/ADT/TypeSwitch.h"
18*ec6da065SMehdi Amini #include "llvm/Support/Casting.h"
19d33a9dccSMehdi Amini #include "llvm/Support/raw_ostream.h"
20*ec6da065SMehdi Amini #include <string>
21d33a9dccSMehdi Amini
22d33a9dccSMehdi Amini using namespace toy;
23d33a9dccSMehdi Amini
24d33a9dccSMehdi Amini namespace {
25d33a9dccSMehdi Amini
26d33a9dccSMehdi Amini // RAII helper to manage increasing/decreasing the indentation as we traverse
27d33a9dccSMehdi Amini // the AST
28d33a9dccSMehdi Amini struct Indent {
Indent__anon16d009e10111::Indent29d33a9dccSMehdi Amini Indent(int &level) : level(level) { ++level; }
~Indent__anon16d009e10111::Indent30d33a9dccSMehdi Amini ~Indent() { --level; }
31d33a9dccSMehdi Amini int &level;
32d33a9dccSMehdi Amini };
33d33a9dccSMehdi Amini
34d33a9dccSMehdi Amini /// Helper class that implement the AST tree traversal and print the nodes along
35d33a9dccSMehdi Amini /// the way. The only data member is the current indentation level.
36d33a9dccSMehdi Amini class ASTDumper {
37d33a9dccSMehdi Amini public:
3822cfff70SRiver Riddle void dump(ModuleAST *node);
39d33a9dccSMehdi Amini
40d33a9dccSMehdi Amini private:
4122cfff70SRiver Riddle void dump(const VarType &type);
42d33a9dccSMehdi Amini void dump(VarDeclExprAST *varDecl);
43d33a9dccSMehdi Amini void dump(ExprAST *expr);
44d33a9dccSMehdi Amini void dump(ExprASTList *exprList);
45d33a9dccSMehdi Amini void dump(NumberExprAST *num);
4622cfff70SRiver Riddle void dump(LiteralExprAST *node);
4722cfff70SRiver Riddle void dump(VariableExprAST *node);
4822cfff70SRiver Riddle void dump(ReturnExprAST *node);
4922cfff70SRiver Riddle void dump(BinaryExprAST *node);
5022cfff70SRiver Riddle void dump(CallExprAST *node);
5122cfff70SRiver Riddle void dump(PrintExprAST *node);
5222cfff70SRiver Riddle void dump(PrototypeAST *node);
5322cfff70SRiver Riddle void dump(FunctionAST *node);
54d33a9dccSMehdi Amini
55d33a9dccSMehdi Amini // Actually print spaces matching the current indentation level
indent()56d33a9dccSMehdi Amini void indent() {
57d33a9dccSMehdi Amini for (int i = 0; i < curIndent; i++)
58d33a9dccSMehdi Amini llvm::errs() << " ";
59d33a9dccSMehdi Amini }
60d33a9dccSMehdi Amini int curIndent = 0;
61d33a9dccSMehdi Amini };
62d33a9dccSMehdi Amini
63d33a9dccSMehdi Amini } // namespace
64d33a9dccSMehdi Amini
65d33a9dccSMehdi Amini /// Return a formatted string for the location of any node
66b7f93c28SJeff Niu template <typename T>
loc(T * node)67b7f93c28SJeff Niu static std::string loc(T *node) {
6822cfff70SRiver Riddle const auto &loc = node->loc();
69d33a9dccSMehdi Amini return (llvm::Twine("@") + *loc.file + ":" + llvm::Twine(loc.line) + ":" +
70d33a9dccSMehdi Amini llvm::Twine(loc.col))
71d33a9dccSMehdi Amini .str();
72d33a9dccSMehdi Amini }
73d33a9dccSMehdi Amini
74d33a9dccSMehdi Amini // Helper Macro to bump the indentation level and print the leading spaces for
75d33a9dccSMehdi Amini // the current indentations
76d33a9dccSMehdi Amini #define INDENT() \
77d33a9dccSMehdi Amini Indent level_(curIndent); \
78d33a9dccSMehdi Amini indent();
79d33a9dccSMehdi Amini
80d33a9dccSMehdi Amini /// Dispatch to a generic expressions to the appropriate subclass using RTTI
dump(ExprAST * expr)81d33a9dccSMehdi Amini void ASTDumper::dump(ExprAST *expr) {
82ebf190fcSRiver Riddle llvm::TypeSwitch<ExprAST *>(expr)
8374278dd0SRiver Riddle .Case<BinaryExprAST, CallExprAST, LiteralExprAST, NumberExprAST,
8474278dd0SRiver Riddle PrintExprAST, ReturnExprAST, VarDeclExprAST, VariableExprAST>(
855a0d4803SRiver Riddle [&](auto *node) { this->dump(node); })
8674278dd0SRiver Riddle .Default([&](ExprAST *) {
87d33a9dccSMehdi Amini // No match, fallback to a generic message
88d33a9dccSMehdi Amini INDENT();
89d33a9dccSMehdi Amini llvm::errs() << "<unknown Expr, kind " << expr->getKind() << ">\n";
9074278dd0SRiver Riddle });
91d33a9dccSMehdi Amini }
92d33a9dccSMehdi Amini
93d33a9dccSMehdi Amini /// A variable declaration is printing the variable name, the type, and then
94d33a9dccSMehdi Amini /// recurse in the initializer value.
dump(VarDeclExprAST * varDecl)95d33a9dccSMehdi Amini void ASTDumper::dump(VarDeclExprAST *varDecl) {
96d33a9dccSMehdi Amini INDENT();
97d33a9dccSMehdi Amini llvm::errs() << "VarDecl " << varDecl->getName();
98d33a9dccSMehdi Amini dump(varDecl->getType());
99d33a9dccSMehdi Amini llvm::errs() << " " << loc(varDecl) << "\n";
100d33a9dccSMehdi Amini dump(varDecl->getInitVal());
101d33a9dccSMehdi Amini }
102d33a9dccSMehdi Amini
103d33a9dccSMehdi Amini /// A "block", or a list of expression
dump(ExprASTList * exprList)104d33a9dccSMehdi Amini void ASTDumper::dump(ExprASTList *exprList) {
105d33a9dccSMehdi Amini INDENT();
106d33a9dccSMehdi Amini llvm::errs() << "Block {\n";
107d33a9dccSMehdi Amini for (auto &expr : *exprList)
108d33a9dccSMehdi Amini dump(expr.get());
109d33a9dccSMehdi Amini indent();
110d33a9dccSMehdi Amini llvm::errs() << "} // Block\n";
111d33a9dccSMehdi Amini }
112d33a9dccSMehdi Amini
113d33a9dccSMehdi Amini /// A literal number, just print the value.
dump(NumberExprAST * num)114d33a9dccSMehdi Amini void ASTDumper::dump(NumberExprAST *num) {
115d33a9dccSMehdi Amini INDENT();
116d33a9dccSMehdi Amini llvm::errs() << num->getValue() << " " << loc(num) << "\n";
117d33a9dccSMehdi Amini }
118d33a9dccSMehdi Amini
119f28c5acaSKazuaki Ishizaki /// Helper to print recursively a literal. This handles nested array like:
120d33a9dccSMehdi Amini /// [ [ 1, 2 ], [ 3, 4 ] ]
121d33a9dccSMehdi Amini /// We print out such array with the dimensions spelled out at every level:
122d33a9dccSMehdi Amini /// <2,2>[<2>[ 1, 2 ], <2>[ 3, 4 ] ]
printLitHelper(ExprAST * litOrNum)12322cfff70SRiver Riddle void printLitHelper(ExprAST *litOrNum) {
124d33a9dccSMehdi Amini // Inside a literal expression we can have either a number or another literal
12502b6fb21SMehdi Amini if (auto *num = llvm::dyn_cast<NumberExprAST>(litOrNum)) {
126d33a9dccSMehdi Amini llvm::errs() << num->getValue();
127d33a9dccSMehdi Amini return;
128d33a9dccSMehdi Amini }
12922cfff70SRiver Riddle auto *literal = llvm::cast<LiteralExprAST>(litOrNum);
130d33a9dccSMehdi Amini
131d33a9dccSMehdi Amini // Print the dimension for this literal first
132d33a9dccSMehdi Amini llvm::errs() << "<";
1332f21a579SRiver Riddle llvm::interleaveComma(literal->getDims(), llvm::errs());
134d33a9dccSMehdi Amini llvm::errs() << ">";
135d33a9dccSMehdi Amini
136d33a9dccSMehdi Amini // Now print the content, recursing on every element of the list
137d33a9dccSMehdi Amini llvm::errs() << "[ ";
1382f21a579SRiver Riddle llvm::interleaveComma(literal->getValues(), llvm::errs(),
13922cfff70SRiver Riddle [&](auto &elt) { printLitHelper(elt.get()); });
140d33a9dccSMehdi Amini llvm::errs() << "]";
141d33a9dccSMehdi Amini }
142d33a9dccSMehdi Amini
143d33a9dccSMehdi Amini /// Print a literal, see the recursive helper above for the implementation.
dump(LiteralExprAST * node)14422cfff70SRiver Riddle void ASTDumper::dump(LiteralExprAST *node) {
145d33a9dccSMehdi Amini INDENT();
146d33a9dccSMehdi Amini llvm::errs() << "Literal: ";
14722cfff70SRiver Riddle printLitHelper(node);
14822cfff70SRiver Riddle llvm::errs() << " " << loc(node) << "\n";
149d33a9dccSMehdi Amini }
150d33a9dccSMehdi Amini
151d33a9dccSMehdi Amini /// Print a variable reference (just a name).
dump(VariableExprAST * node)15222cfff70SRiver Riddle void ASTDumper::dump(VariableExprAST *node) {
153d33a9dccSMehdi Amini INDENT();
15422cfff70SRiver Riddle llvm::errs() << "var: " << node->getName() << " " << loc(node) << "\n";
155d33a9dccSMehdi Amini }
156d33a9dccSMehdi Amini
157d33a9dccSMehdi Amini /// Return statement print the return and its (optional) argument.
dump(ReturnExprAST * node)15822cfff70SRiver Riddle void ASTDumper::dump(ReturnExprAST *node) {
159d33a9dccSMehdi Amini INDENT();
160d33a9dccSMehdi Amini llvm::errs() << "Return\n";
1617430894aSFangrui Song if (node->getExpr().has_value())
16222cfff70SRiver Riddle return dump(*node->getExpr());
163d33a9dccSMehdi Amini {
164d33a9dccSMehdi Amini INDENT();
165d33a9dccSMehdi Amini llvm::errs() << "(void)\n";
166d33a9dccSMehdi Amini }
167d33a9dccSMehdi Amini }
168d33a9dccSMehdi Amini
169d33a9dccSMehdi Amini /// Print a binary operation, first the operator, then recurse into LHS and RHS.
dump(BinaryExprAST * node)17022cfff70SRiver Riddle void ASTDumper::dump(BinaryExprAST *node) {
171d33a9dccSMehdi Amini INDENT();
17222cfff70SRiver Riddle llvm::errs() << "BinOp: " << node->getOp() << " " << loc(node) << "\n";
17322cfff70SRiver Riddle dump(node->getLHS());
17422cfff70SRiver Riddle dump(node->getRHS());
175d33a9dccSMehdi Amini }
176d33a9dccSMehdi Amini
177d33a9dccSMehdi Amini /// Print a call expression, first the callee name and the list of args by
178d33a9dccSMehdi Amini /// recursing into each individual argument.
dump(CallExprAST * node)17922cfff70SRiver Riddle void ASTDumper::dump(CallExprAST *node) {
180d33a9dccSMehdi Amini INDENT();
18122cfff70SRiver Riddle llvm::errs() << "Call '" << node->getCallee() << "' [ " << loc(node) << "\n";
18222cfff70SRiver Riddle for (auto &arg : node->getArgs())
183d33a9dccSMehdi Amini dump(arg.get());
184d33a9dccSMehdi Amini indent();
185d33a9dccSMehdi Amini llvm::errs() << "]\n";
186d33a9dccSMehdi Amini }
187d33a9dccSMehdi Amini
188d33a9dccSMehdi Amini /// Print a builtin print call, first the builtin name and then the argument.
dump(PrintExprAST * node)18922cfff70SRiver Riddle void ASTDumper::dump(PrintExprAST *node) {
190d33a9dccSMehdi Amini INDENT();
19122cfff70SRiver Riddle llvm::errs() << "Print [ " << loc(node) << "\n";
19222cfff70SRiver Riddle dump(node->getArg());
193d33a9dccSMehdi Amini indent();
194d33a9dccSMehdi Amini llvm::errs() << "]\n";
195d33a9dccSMehdi Amini }
196d33a9dccSMehdi Amini
197d33a9dccSMehdi Amini /// Print type: only the shape is printed in between '<' and '>'
dump(const VarType & type)19822cfff70SRiver Riddle void ASTDumper::dump(const VarType &type) {
199d33a9dccSMehdi Amini llvm::errs() << "<";
2002f21a579SRiver Riddle llvm::interleaveComma(type.shape, llvm::errs());
201d33a9dccSMehdi Amini llvm::errs() << ">";
202d33a9dccSMehdi Amini }
203d33a9dccSMehdi Amini
204d33a9dccSMehdi Amini /// Print a function prototype, first the function name, and then the list of
205d33a9dccSMehdi Amini /// parameters names.
dump(PrototypeAST * node)20622cfff70SRiver Riddle void ASTDumper::dump(PrototypeAST *node) {
207d33a9dccSMehdi Amini INDENT();
2085633813bSRahul Joshi llvm::errs() << "Proto '" << node->getName() << "' " << loc(node) << "\n";
209d33a9dccSMehdi Amini indent();
210d33a9dccSMehdi Amini llvm::errs() << "Params: [";
2112f21a579SRiver Riddle llvm::interleaveComma(node->getArgs(), llvm::errs(),
21222cfff70SRiver Riddle [](auto &arg) { llvm::errs() << arg->getName(); });
213d33a9dccSMehdi Amini llvm::errs() << "]\n";
214d33a9dccSMehdi Amini }
215d33a9dccSMehdi Amini
216d33a9dccSMehdi Amini /// Print a function, first the prototype and then the body.
dump(FunctionAST * node)21722cfff70SRiver Riddle void ASTDumper::dump(FunctionAST *node) {
218d33a9dccSMehdi Amini INDENT();
219d33a9dccSMehdi Amini llvm::errs() << "Function \n";
22022cfff70SRiver Riddle dump(node->getProto());
22122cfff70SRiver Riddle dump(node->getBody());
222d33a9dccSMehdi Amini }
223d33a9dccSMehdi Amini
224d33a9dccSMehdi Amini /// Print a module, actually loop over the functions and print them in sequence.
dump(ModuleAST * node)22522cfff70SRiver Riddle void ASTDumper::dump(ModuleAST *node) {
226d33a9dccSMehdi Amini INDENT();
227d33a9dccSMehdi Amini llvm::errs() << "Module:\n";
22822cfff70SRiver Riddle for (auto &f : *node)
22922cfff70SRiver Riddle dump(&f);
230d33a9dccSMehdi Amini }
231d33a9dccSMehdi Amini
232d33a9dccSMehdi Amini namespace toy {
233d33a9dccSMehdi Amini
234d33a9dccSMehdi Amini // Public API
dump(ModuleAST & module)235d33a9dccSMehdi Amini void dump(ModuleAST &module) { ASTDumper().dump(&module); }
236d33a9dccSMehdi Amini
237d33a9dccSMehdi Amini } // namespace toy
238