Joos1W Compiler Framework
All Classes Functions Typedefs Pages
ParseTreeVisitor.h
1 #pragma once
2 
3 #include "diagnostics/Location.h"
4 #include "parsetree/ParseTree.h"
5 #include "semantic/Semantic.h"
6 #include <utils/Error.h>
7 
8 namespace parsetree {
9 
10 class ParseTreeException : public std::exception {
11 public:
12  ParseTreeException(Node* where, const std::string& what)
13  : msg{what}, where{where} {}
14 
15  const char* what() const noexcept override { return msg.c_str(); }
16 
17  Node* get_where() const { return where; }
18 
19 private:
20  std::string msg;
21  Node* where;
22 };
23 
25  using pty = Node::Type;
26 
27 public:
28  ParseTreeVisitor(ast::Semantic& sem) : sem{sem}, alloc{sem.allocator()} {}
29  ParseTreeVisitor(ast::Semantic& sem, BumpAllocator& alloc)
30  : sem{sem}, alloc{alloc} {}
31 
32 private:
33  // Basic helper functions ///////////////////////////////////////////////////
34 
35  static inline void check_node_type(Node* node, Node::Type type) {
36  if(node->get_node_type() != type) {
37  throw ParseTreeException(node,
38  "Called on a node that is not the correct type!"
39  " Expected: " +
41  " Actual: " + node->type_string());
42  }
43  }
44 
45  static inline void check_num_children(Node* node, size_t min, size_t max) {
46  if(node->num_children() < min || node->num_children() > max) {
47  throw utils::FatalError(
48  "Node has incorrect number of children!"
49  " Type: " +
50  node->type_string() + " Expected: " + std::to_string(min) + " to " +
51  std::to_string(max) +
52  " Actual: " + std::to_string(node->num_children()));
53  }
54  }
55 
56  // Templated visitor patterns ///////////////////////////////////////////////
57 
58  // NOTE(kevin): Technically we can re-implement all our visitors using the
59  // template patterns. However, the syntax is ugly at best. We only use these
60  // for the list patterns, which are more tedious and benefit from templates.
61 
62  /**
63  * @brief This function is not intended to be called.
64  * Instead, the function should to be template-specialized to be used by the
65  * visitListPattern<N, T> function.
66  *
67  * @tparam N This parameter must match the N parameter of the
68  * visitListPattern function that calls this function.
69  * @tparam T This parameter must match the T parameter of the
70  * visitListPattern function that calls this function.
71  * @param node The node to visit.
72  * @return T The result of visiting the node.
73  */
74  template <parsetree::Node::Type N, typename T>
75  T visit(Node* node) {
76  throw utils::FatalError("No visitor for node type " + node->type_string());
77  }
78 
79  /**
80  * @brief Visits a list-pattern node. A list pattern is a node that is
81  * recursive in the first-child. The node either has 1 or 2 children.
82  * If the node has 1 child, the list is simply the result of visiting the
83  * child. The visitor will be implemented by the visit<N, T> function
84  * (which you need to specialize in order to use this function).
85  *
86  * @tparam N The type of the node to visit.
87  * @tparam T The type of the list elements.
88  * @tparam nullable If true, the node can be null (for empty lists).
89  * @param node The node to visit.
90  * @param list The list to append the results to.
91  */
92  template <parsetree::Node::Type N, typename T, bool nullable = false>
93  void visitListPattern(Node* node, ast::array_ref<T> list) {
94  if(nullable && node == nullptr) return;
95  if(!nullable && node == nullptr)
96  throw utils::FatalError("Visited a null node!");
97  check_node_type(node, N);
98  check_num_children(node, 1, 2);
99  if(node->num_children() == 1) {
100  list.push_back(visit<N, T>(node->child(0)));
101  } else if(node->num_children() == 2) {
102  visitListPattern<N, T, nullable>(node->child(0), list);
103  list.push_back(visit<N, T>(node->child(1)));
104  }
105  }
106 
107 public:
108  // Compilation unit visitors ////////////////////////////////////////////////
109 
110  ast::CompilationUnit* visitCompilationUnit(Node* node);
111  ast::ReferenceType* visitPackageDeclaration(Node* node);
112  template <>
113  ast::ImportDeclaration visit<pty::ImportDeclarationList>(Node* node);
114 
115  // Classes & interfaces visitors ////////////////////////////////////////////
116 
117  ast::ClassDecl* visitClassDeclaration(Node* node);
118  ast::InterfaceDecl* visitInterfaceDeclaration(Node* node);
119  ast::ReferenceType* visitSuperOpt(Node* node);
120  ast::FieldDecl* visitFieldDeclaration(Node* node);
121  ast::MethodDecl* visitMethodDeclaration(Node* node);
122  ast::MethodDecl* visitConstructorDeclaration(Node* node);
123  ast::MethodDecl* visitAbstractMethodDeclaration(Node* node);
124 
125  template <>
126  ast::Decl* visit<pty::ClassBodyDeclarationList>(Node* node);
127  template <>
128  ast::VarDecl* visit<pty::FormalParameterList>(Node* node);
129  template <>
130  ast::Decl* visit<pty::InterfaceMemberDeclarationList>(Node* node);
131 
132  // Statements visitors //////////////////////////////////////////////////////
133 
134  struct TmpVarDecl {
135  ast::Type* type;
136  SourceRange loc;
137  std::string_view name;
138  ast::Expr* init;
139  };
140 
141  TmpVarDecl visitVariableDeclarator(Node* ty, Node* node);
142  ast::DeclStmt* visitLocalVariableDeclarationStatement(Node* node);
143 
144  ast::BlockStatement* visitBlock(Node* node);
145  ast::Stmt* visitStatement(Node* node);
146  ast::IfStmt* visitIfThenStatement(Node* node);
147  ast::WhileStmt* visitWhileStatement(Node* node);
148  ast::ForStmt* visitForStatement(Node* node);
149  ast::ReturnStmt* visitReturnStatement(Node* node);
150  ast::ExprStmt* visitExpressionStatement(Node* node);
151 
152  // Expression visitors //////////////////////////////////////////////////////
153 
154  ast::Expr* visitExpr(Node* node);
155  ast::ExprNodeList visitExprChild(Node* node);
156  ast::ExprNodeList visitExprNode(Node* node);
157  ast::ExprNodeList visitMethodInvocation(Node* node);
158  ast::ExprNodeList visitQualifiedIdentifierInExpr(Node* node, bool isMethodInvocation = false);
159  ast::ExprNodeList visitFieldAccess(Node* node);
160  ast::ExprNodeList visitClassCreation(Node* node);
161  ast::ExprNodeList visitArrayAccess(Node* node);
162  ast::ExprNodeList visitArrayCreation(Node* node);
163  ast::ExprNodeList visitCastExpression(Node* node);
164  ast::ExprNode* visitRegularType(Node* node);
165  ast::ExprNode* visitArrayType(Node* node);
166 
167  ast::exprnode::LiteralNode* visitLiteral(Node* node);
168 
169  ast::exprnode::UnaryOp* convertToUnaryOp(Operator::Type type, SourceRange loc);
170  ast::exprnode::BinaryOp* convertToBinaryOp(Operator::Type type, SourceRange loc);
171  int visitArgumentList(Node* node, ast::ExprNodeList& ops);
172 
173  template <>
174  ast::Stmt* visit<pty::BlockStatementList>(Node* node);
175 
176  // Leaf node visitors ///////////////////////////////////////////////////////
177 
178  ast::UnresolvedType* visitReferenceType(
179  Node* node, ast::UnresolvedType* ast_node = nullptr);
180  std::string_view visitIdentifier(Node* node);
181  ast::Modifiers visitModifierList(Node* node,
182  ast::Modifiers modifiers = ast::Modifiers{});
183  Modifier visitModifier(Node* node);
184  ast::Type* visitType(Node* node);
185 
186 private:
187  ast::Semantic& sem;
188  BumpAllocator& alloc;
189 };
190 
191 } // namespace parsetree