brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · 8416424 Raw
238 lines · cpp
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-exception6//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/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"20#include <string>21 22using namespace toy;23 24namespace {25 26// RAII helper to manage increasing/decreasing the indentation as we traverse27// the AST28struct Indent {29  Indent(int &level) : level(level) { ++level; }30  ~Indent() { --level; }31  int &level;32};33 34/// Helper class that implement the AST tree traversal and print the nodes along35/// the way. The only data member is the current indentation level.36class ASTDumper {37public:38  void dump(ModuleAST *node);39 40private: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);54 55  // Actually print spaces matching the current indentation level56  void indent() {57    for (int i = 0; i < curIndent; i++)58      llvm::errs() << "  ";59  }60  int curIndent = 0;61};62 63} // namespace64 65/// Return a formatted string for the location of any node66template <typename T>67static std::string loc(T *node) {68  const auto &loc = node->loc();69  return (llvm::Twine("@") + *loc.file + ":" + llvm::Twine(loc.line) + ":" +70          llvm::Twine(loc.col))71      .str();72}73 74// Helper Macro to bump the indentation level and print the leading spaces for75// the current indentations76#define INDENT()                                                               \77  Indent level_(curIndent);                                                    \78  indent();79 80/// Dispatch to a generic expressions to the appropriate subclass using RTTI81void 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 message88        INDENT();89        llvm::errs() << "<unknown Expr, kind " << expr->getKind() << ">\n";90      });91}92 93/// A variable declaration is printing the variable name, the type, and then94/// recurse in the initializer value.95void ASTDumper::dump(VarDeclExprAST *varDecl) {96  INDENT();97  llvm::errs() << "VarDecl " << varDecl->getName();98  dump(varDecl->getType());99  llvm::errs() << " " << loc(varDecl) << "\n";100  dump(varDecl->getInitVal());101}102 103/// A "block", or a list of expression104void 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.114void 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 ] ]123static void printLitHelper(ExprAST *litOrNum) {124  // Inside a literal expression we can have either a number or another literal125  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 first132  llvm::errs() << "<";133  llvm::interleaveComma(literal->getDims(), llvm::errs());134  llvm::errs() << ">";135 136  // Now print the content, recursing on every element of the list137  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.144void ASTDumper::dump(LiteralExprAST *node) {145  INDENT();146  llvm::errs() << "Literal: ";147  printLitHelper(node);148  llvm::errs() << " " << loc(node) << "\n";149}150 151/// Print a variable reference (just a name).152void ASTDumper::dump(VariableExprAST *node) {153  INDENT();154  llvm::errs() << "var: " << node->getName() << " " << loc(node) << "\n";155}156 157/// Return statement print the return and its (optional) argument.158void ASTDumper::dump(ReturnExprAST *node) {159  INDENT();160  llvm::errs() << "Return\n";161  if (node->getExpr().has_value())162    return dump(*node->getExpr());163  {164    INDENT();165    llvm::errs() << "(void)\n";166  }167}168 169/// Print a binary operation, first the operator, then recurse into LHS and RHS.170void ASTDumper::dump(BinaryExprAST *node) {171  INDENT();172  llvm::errs() << "BinOp: " << node->getOp() << " " << loc(node) << "\n";173  dump(node->getLHS());174  dump(node->getRHS());175}176 177/// Print a call expression, first the callee name and the list of args by178/// recursing into each individual argument.179void ASTDumper::dump(CallExprAST *node) {180  INDENT();181  llvm::errs() << "Call '" << node->getCallee() << "' [ " << loc(node) << "\n";182  for (auto &arg : node->getArgs())183    dump(arg.get());184  indent();185  llvm::errs() << "]\n";186}187 188/// Print a builtin print call, first the builtin name and then the argument.189void ASTDumper::dump(PrintExprAST *node) {190  INDENT();191  llvm::errs() << "Print [ " << loc(node) << "\n";192  dump(node->getArg());193  indent();194  llvm::errs() << "]\n";195}196 197/// Print type: only the shape is printed in between '<' and '>'198void ASTDumper::dump(const VarType &type) {199  llvm::errs() << "<";200  llvm::interleaveComma(type.shape, llvm::errs());201  llvm::errs() << ">";202}203 204/// Print a function prototype, first the function name, and then the list of205/// parameters names.206void ASTDumper::dump(PrototypeAST *node) {207  INDENT();208  llvm::errs() << "Proto '" << node->getName() << "' " << loc(node) << "\n";209  indent();210  llvm::errs() << "Params: [";211  llvm::interleaveComma(node->getArgs(), llvm::errs(),212                        [](auto &arg) { llvm::errs() << arg->getName(); });213  llvm::errs() << "]\n";214}215 216/// Print a function, first the prototype and then the body.217void ASTDumper::dump(FunctionAST *node) {218  INDENT();219  llvm::errs() << "Function \n";220  dump(node->getProto());221  dump(node->getBody());222}223 224/// Print a module, actually loop over the functions and print them in sequence.225void ASTDumper::dump(ModuleAST *node) {226  INDENT();227  llvm::errs() << "Module:\n";228  for (auto &f : *node)229    dump(&f);230}231 232namespace toy {233 234// Public API235void dump(ModuleAST &module) { ASTDumper().dump(&module); }236 237} // namespace toy238