Joos1W Compiler Framework
All Classes Functions Typedefs Pages
VisitStatement.cc
1 #include <utils/Error.h>
2 #include <utility>
3 
4 #include "ast/AST.h"
5 #include "parsetree/ParseTree.h"
6 #include "parsetree/ParseTreeVisitor.h"
7 
8 namespace parsetree {
9 
10 using pty = Node::Type;
11 using ptv = ParseTreeVisitor;
12 
13 // pty::Block //////////////////////////////////////////////////////////////////
14 
15 ast::BlockStatement* ptv::visitBlock(Node* node) {
16  check_node_type(node, pty::Block);
17  check_num_children(node, 1, 1);
18  ast::pmr_vector<ast::Stmt*> stmts;
19  auto scope = sem.EnterLexicalScope();
20  visitListPattern<pty::BlockStatementList, ast::Stmt*, true>(node->child(0),
21  stmts);
22  sem.ExitLexicalScope(scope);
23  return sem.BuildBlockStatement(stmts);
24 }
25 
26 template <>
27 ast::Stmt* ptv::visit<pty::BlockStatementList>(Node* node) {
28  return visitStatement(node);
29 }
30 
31 // pty::Statement //////////////////////////////////////////////////////////////
32 
33 ast::Stmt* ptv::visitStatement(Node* node) {
34  check_node_type(node, pty::Statement);
35  check_num_children(node, 0, 1);
36  if(node->num_children() == 0) return sem.BuildNullStmt();
37  check_num_children(node, 1, 1);
38  auto child = node->child(0);
39  assert(child);
40  auto nodety = child->get_node_type();
41  switch(nodety) {
42  case pty::Block:
43  return visitBlock(child);
44  case pty::IfThenStatement:
45  return visitIfThenStatement(child);
46  case pty::WhileStatement:
47  return visitWhileStatement(child);
48  case pty::ForStatement:
49  return visitForStatement(child);
50  case pty::ReturnStatement:
51  return visitReturnStatement(child);
52  case pty::LocalVariableDeclaration:
53  return visitLocalVariableDeclarationStatement(child);
54  case pty::StatementExpression:
55  return visitExpressionStatement(child);
56  default:
57  std::unreachable();
58  }
59 }
60 
61 // pty::IfThenStatement ////////////////////////////////////////////////////////
62 
63 ast::IfStmt* ptv::visitIfThenStatement(Node* node) {
64  check_node_type(node, pty::IfThenStatement);
65  check_num_children(node, 2, 3);
66 
67  if(node->child(0) == nullptr || node->child(1) == nullptr)
68  throw utils::FatalError("Invalid if-then statement");
69 
70  // $1: Visit the expression
71  auto expr = visitExpr(node->child(0));
72  // $2: Visit the statement
73  auto scope = sem.EnterLexicalScope();
74  auto stmt = visitStatement(node->child(1));
75  sem.ExitLexicalScope(scope);
76 
77  if(node->num_children() == 3) {
78  auto scope = sem.EnterLexicalScope();
79  auto elseStmt = visitStatement(node->child(2));
80  sem.ExitLexicalScope(scope);
81  return sem.BuildIfStmt(expr, stmt, elseStmt);
82  }
83 
84  return sem.BuildIfStmt(expr, stmt);
85 }
86 
87 // pty::WhileStatement /////////////////////////////////////////////////////////
88 
89 ast::WhileStmt* ptv::visitWhileStatement(Node* node) {
90  check_node_type(node, pty::WhileStatement);
91  check_num_children(node, 2, 2);
92 
93  if(node->child(0) == nullptr || node->child(1) == nullptr)
94  throw utils::FatalError("Invalid while statement");
95 
96  // $1: Visit the condition
97  auto condition = visitExpr(node->child(0));
98  // $2: Visit the body
99  auto scope = sem.EnterLexicalScope();
100  auto body = visitStatement(node->child(1));
101  sem.ExitLexicalScope(scope);
102  return sem.BuildWhileStmt(condition, body);
103 }
104 
105 // pty::ForStatement ///////////////////////////////////////////////////////////
106 
107 ast::ForStmt* ptv::visitForStatement(Node* node) {
108  check_node_type(node, pty::ForStatement);
109  check_num_children(node, 4, 4);
110 
111  if(node->child(3) == nullptr) throw utils::FatalError("Invalid for statement");
112 
113  ast::Stmt* init = nullptr;
114  ast::Expr* condition = nullptr;
115  ast::Stmt* update = nullptr;
116  ast::Stmt* body = nullptr;
117 
118  auto scope = sem.EnterLexicalScope();
119  if(node->child(0) != nullptr) init = visitStatement(node->child(0));
120  if(node->child(1) != nullptr) condition = visitExpr(node->child(1));
121  if(node->child(2) != nullptr) update = visitStatement(node->child(2));
122  body = visitStatement(node->child(3));
123  sem.ExitLexicalScope(scope);
124 
125  return sem.BuildForStmt(init, condition, update, body);
126 }
127 
128 // pty::ReturnStatement ////////////////////////////////////////////////////////
129 
130 ast::ReturnStmt* ptv::visitReturnStatement(Node* node) {
131  check_node_type(node, pty::ReturnStatement);
132  check_num_children(node, 0, 1);
133  if(node->child(0) == nullptr) {
134  return sem.BuildReturnStmt(node->location(), nullptr);
135  }
136  auto expr = visitExpr(node->child(0));
137  return sem.BuildReturnStmt(node->location(), expr);
138 }
139 
140 // pty::ExpressionStatement ////////////////////////////////////////////////////
141 
142 ast::ExprStmt* ptv::visitExpressionStatement(Node* node) {
143  check_node_type(node, pty::StatementExpression);
144  check_num_children(node, 1, 1);
145  auto expr = visitExpr(node->child(0));
146  return sem.BuildExprStmt(expr);
147 }
148 
149 // pty::VariableDeclarator /////////////////////////////////////////////////////
150 
151 ptv::TmpVarDecl ptv::visitVariableDeclarator(Node* tyNode, Node* declNode) {
152  check_node_type(declNode, pty::VariableDeclarator);
153  check_num_children(declNode, 1, 2);
154  // $?: Get the type of the variable
155  auto type = visitType(tyNode);
156  // $1: Get the name of the variable
157  auto nameNode = declNode->child(0);
158  auto name = visitIdentifier(nameNode);
159  // $2: Get the initializer of the variable
160  ast::Expr* init = nullptr;
161  if(declNode->num_children() == 2) {
162  init = visitExpr(declNode->child(1));
163  }
164  return TmpVarDecl{type, nameNode->location(), name, init};
165 }
166 
167 // pty::LocalVariableDeclarationStatement //////////////////////////////////////
168 
169 ast::DeclStmt* ptv::visitLocalVariableDeclarationStatement(Node* node) {
170  check_node_type(node, pty::LocalVariableDeclaration);
171  check_num_children(node, 2, 2);
172  // Get the ID at the beginning
173  auto nextId = sem.NextScopeID();
174  // $0: Get the type of the variable
175  auto tyNode = node->child(0);
176  // $1: Get the variable declarator
177  auto declNode = node->child(1);
178  auto decl = visitVariableDeclarator(tyNode, declNode);
179  auto astDecl =
180  sem.BuildVarDecl(decl.type, decl.loc, decl.name, nextId, decl.init);
181  return sem.BuildDeclStmt(astDecl);
182 }
183 
184 } // namespace parsetree