Joos1W Compiler Framework
All Classes Functions Typedefs Pages
VisitExpression.cc
1 #include <utils/Error.h>
2 
3 #include <utility>
4 
5 #include "diagnostics/Location.h"
6 #include "parsetree/ParseTreeVisitor.h"
7 
8 namespace parsetree {
9 
10 using pty = Node::Type;
11 using ptv = ParseTreeVisitor;
12 using ast::ExprNodeList;
13 using namespace ast;
14 using namespace ast::exprnode;
15 
16 // Check that TmpVarDecl is standard layout and trivially copyable
17 static_assert(std::is_standard_layout_v<ptv::TmpVarDecl>);
18 static_assert(std::is_trivially_copyable_v<ptv::TmpVarDecl>);
19 
20 // NOTE: This is a hack because we want to get the semantic's allocator
21 #define sem_alloc sem.allocator().new_object
22 
23 UnaryOp* ptv::convertToUnaryOp(Operator::Type type, SourceRange loc) {
24  using oty = Operator::Type;
25  switch(type) {
26  case oty::Not:
27  return sem_alloc<UnaryOp>(UnaryOp::OpType::Not, loc);
28  case oty::Minus:
29  return sem_alloc<UnaryOp>(UnaryOp::OpType::Minus, loc);
30  default:
31  throw utils::FatalError("Invalid operator type");
32  }
33 }
34 
35 BinaryOp* ptv::convertToBinaryOp(Operator::Type type, SourceRange loc) {
36  using oty = Operator::Type;
37  switch(type) {
38  case oty::Assign:
39  return sem_alloc<BinaryOp>(BinaryOp::OpType::Assignment, loc);
40  case oty::Or:
41  return sem_alloc<BinaryOp>(BinaryOp::OpType::Or, loc);
42  case oty::And:
43  return sem_alloc<BinaryOp>(BinaryOp::OpType::And, loc);
44  case oty::BitwiseOr:
45  return sem_alloc<BinaryOp>(BinaryOp::OpType::BitwiseOr, loc);
46  case oty::BitwiseXor:
47  return sem_alloc<BinaryOp>(BinaryOp::OpType::BitwiseXor, loc);
48  case oty::BitwiseAnd:
49  return sem_alloc<BinaryOp>(BinaryOp::OpType::BitwiseAnd, loc);
50  case oty::Equal:
51  return sem_alloc<BinaryOp>(BinaryOp::OpType::Equal, loc);
52  case oty::NotEqual:
53  return sem_alloc<BinaryOp>(BinaryOp::OpType::NotEqual, loc);
54  case oty::LessThan:
55  return sem_alloc<BinaryOp>(BinaryOp::OpType::LessThan, loc);
56  break;
57  case oty::LessThanOrEqual:
58  return sem_alloc<BinaryOp>(BinaryOp::OpType::LessThanOrEqual, loc);
59  case oty::GreaterThan:
60  return sem_alloc<BinaryOp>(BinaryOp::OpType::GreaterThan, loc);
61  case oty::GreaterThanOrEqual:
62  return sem_alloc<BinaryOp>(BinaryOp::OpType::GreaterThanOrEqual, loc);
63  case oty::InstanceOf:
64  return sem_alloc<BinaryOp>(BinaryOp::OpType::InstanceOf, loc);
65  case oty::Plus:
66  return sem_alloc<BinaryOp>(BinaryOp::OpType::Add, loc);
67  case oty::Minus:
68  return sem_alloc<BinaryOp>(BinaryOp::OpType::Subtract, loc);
69  case oty::Multiply:
70  return sem_alloc<BinaryOp>(BinaryOp::OpType::Multiply, loc);
71  case oty::Divide:
72  return sem_alloc<BinaryOp>(BinaryOp::OpType::Divide, loc);
73  case oty::Modulo:
74  return sem_alloc<BinaryOp>(BinaryOp::OpType::Modulo, loc);
75  default:
76  assert(false && "Invalid operator type");
77  }
78  std::unreachable();
79 }
80 
81 Expr* ptv::visitExpr(Node* node) {
82  return sem_alloc<Expr>(
83  visitExprChild(node), node->location(), sem.CurrentScopeID());
84 }
85 
86 ExprNodeList ptv::visitExprNode(parsetree::Node* node) {
87  check_node_type(node, pty::Expression);
88  check_num_children(node, 1, 3);
89  if(node->num_children() == 1) {
90  auto list = visitExprChild(node->child(0));
91  list.isBracketed = true;
92  return list;
93  } else if(node->num_children() == 2) {
94  // unary expression
95  ExprNodeList ops{};
96  auto right = visitExprChild(node->child(1));
97  ops.concat(right);
98  auto op = cast<parsetree::Operator>(node->child(0));
99  ops.push_back(convertToUnaryOp(op->get_type(), op->location()));
100  return ops;
101 
102  } else if(node->num_children() == 3) {
103  // binary expression
104  ExprNodeList ops{};
105  auto left = visitExprChild(node->child(0));
106  auto right = visitExprChild(node->child(2));
107  ops.concat(left);
108  ops.concat(right);
109  auto op = cast<parsetree::Operator*>(node->child(1));
110  ops.push_back(convertToBinaryOp(op->get_type(), op->location()));
111  return ops;
112  }
113  std::unreachable();
114 }
115 
116 // expression can have different types of children, so we need to visit them
117 // possible nodes: expression, literal, THIS, qualifiedIdentifier,
118 // methodInvocation, Type, ArrayType,
119 // arrayAccess, fieldAccess, castExpression,
120 // ArrayCreationExpression ClassInstanceCreationExpression
121 ExprNodeList ptv::visitExprChild(Node* node) {
122  switch(node->get_node_type()) {
123  case pty::Expression:
124  return visitExprNode(node);
125  case pty::Literal:
126  return ExprNodeList(visitLiteral(node));
127  case pty::Type:
128  return ExprNodeList(visitRegularType(node));
129  case pty::ArrayType:
130  return ExprNodeList(visitArrayType(node));
131  case pty::Identifier: {
132  auto name = visitIdentifier(node);
133  if(name == "this") {
134  return ExprNodeList(sem_alloc<ThisNode>(node->location()));
135  }
136  return ExprNodeList(
137  sem_alloc<MemberName>(sem.allocator(), name, node->location()));
138  }
139  case pty::QualifiedIdentifier:
140  return visitQualifiedIdentifierInExpr(node);
141  case pty::MethodInvocation:
142  return visitMethodInvocation(node);
143  case pty::ArrayAccess:
144  return visitArrayAccess(node);
145  case pty::FieldAccess:
146  return visitFieldAccess(node);
147  case pty::CastExpression:
148  return visitCastExpression(node);
149  case pty::ArrayCreationExpression:
150  return visitArrayCreation(node);
151  case pty::ClassInstanceCreationExpression:
152  return visitClassCreation(node);
153  default:
154  assert(false && "Invalid node type");
155  }
156  std::unreachable();
157 }
158 
159 ExprNodeList ptv::visitQualifiedIdentifierInExpr(Node* node,
160  bool isMethodInvocation) {
161  check_node_type(node, pty::QualifiedIdentifier);
162  check_num_children(node, 1, 2);
163  ExprNodeList ops{};
164  if(node->num_children() == 1) {
165  if(isMethodInvocation) {
166  ops.push_back(sem_alloc<MethodName>(sem.allocator(),
167  visitIdentifier(node->child(0)),
169  } else {
170  ops.push_back(sem_alloc<MemberName>(sem.allocator(),
171  visitIdentifier(node->child(0)),
173  }
174 
175  } else if(node->num_children() == 2) {
176  ops = visitQualifiedIdentifierInExpr(node->child(0));
177  if(isMethodInvocation) {
178  ops.push_back(sem_alloc<MethodName>(sem.allocator(),
179  visitIdentifier(node->child(1)),
181  } else {
182  ops.push_back(sem_alloc<MemberName>(sem.allocator(),
183  visitIdentifier(node->child(1)),
185  }
186  ops.push_back(sem_alloc<MemberAccess>());
187  }
188  return ops;
189 }
190 
191 ExprNodeList ptv::visitMethodInvocation(Node* node) {
192  check_node_type(node, pty::MethodInvocation);
193  check_num_children(node, 2, 3);
194  ExprNodeList ops{};
195  if(node->num_children() == 2) {
196  ops.concat(visitQualifiedIdentifierInExpr(node->child(0), true));
197 
198  ExprNodeList args{};
199  auto size = visitArgumentList(node->child(1), args) + 1;
200  ops.concat(args);
201 
202  ops.push_back(sem_alloc<MethodInvocation>(size));
203  return ops;
204  } else if(node->num_children() == 3) {
205  ops.concat(visitExprChild(node->child(0)));
206  ops.push_back(sem_alloc<MethodName>(sem.allocator(),
207  visitIdentifier(node->child(1)),
209  ops.push_back(sem_alloc<MemberAccess>());
210 
211  ExprNodeList args{};
212  auto size = visitArgumentList(node->child(2), args) + 1;
213  ops.concat(args);
214 
215  ops.push_back(sem_alloc<MethodInvocation>(size));
216  return ops;
217  }
218  std::unreachable();
219 }
220 
221 ExprNodeList ptv::visitFieldAccess(Node* node) {
222  check_node_type(node, pty::FieldAccess);
223  check_num_children(node, 2, 2);
224  ExprNodeList ops{};
225  ops.concat(visitExprChild(node->child(0)));
226  ops.push_back(sem_alloc<MemberName>(sem.allocator(),
227  visitIdentifier(node->child(1)),
229  ops.push_back(sem_alloc<MemberAccess>());
230  return ops;
231 }
232 
233 ExprNodeList ptv::visitClassCreation(Node* node) {
234  check_node_type(node, pty::ClassInstanceCreationExpression);
235  check_num_children(node, 2, 2);
236  ExprNodeList ops{};
237  auto type = visitReferenceType(node->child(0));
238  ops.push_back(sem_alloc<TypeNode>(type, node->child(0)->location()));
239  ExprNodeList args{};
240  auto size = visitArgumentList(node->child(1), args) + 1;
241  ops.concat(args);
242  ops.push_back(sem_alloc<ClassInstanceCreation>(size));
243  return ops;
244 }
245 
246 ExprNodeList ptv::visitArrayAccess(Node* node) {
247  check_node_type(node, pty::ArrayAccess);
248  check_num_children(node, 2, 2);
249  ExprNodeList ops{};
250  ops.concat(visitExprChild(node->child(0)));
251  ops.concat(visitExprChild(node->child(1)));
252  ops.push_back(sem_alloc<ArrayAccess>());
253  return ops;
254 }
255 
256 ExprNodeList ptv::visitCastExpression(Node* node) {
257  check_node_type(node, pty::CastExpression);
258  check_num_children(node, 2, 3);
259  ExprNodeList ops{};
260  Node* expr;
261  // If there are 3 children, the expr is (type, dims, expr)
262  // Otherwise, the expr is (type, expr)
263  if(node->num_children() == 3) {
264  auto type = visitType(node->child(0));
265  auto dims = node->child(1);
266  if(dims) {
267  type = sem.BuildArrayType(type, type->location());
268  }
269  ops.push_back(sem_alloc<TypeNode>(type, node->child(0)->location()));
270  expr = node->child(2);
271  } else {
272  auto type = visitType(node->child(0));
273  ops.push_back(sem_alloc<TypeNode>(type, node->child(0)->location()));
274  expr = node->child(1);
275  }
276  ops.concat(visitExprChild(expr));
277  ops.push_back(sem_alloc<Cast>());
278  return ops;
279 }
280 
281 ExprNodeList ptv::visitArrayCreation(Node* node) {
282  check_node_type(node, pty::ArrayCreationExpression);
283  check_num_children(node, 2, 2);
284  ExprNodeList ops(visitArrayType(node->child(0)));
285  ops.concat(visitExprChild(node->child(1)));
286  ops.push_back(sem_alloc<ArrayInstanceCreation>());
287  return ops;
288  std::unreachable();
289 }
290 
291 ExprNode* ptv::visitRegularType(Node* node) {
292  return sem_alloc<TypeNode>(visitType(node), node->location());
293 }
294 
295 ExprNode* ptv::visitArrayType(Node* node) {
296  check_node_type(node, pty::ArrayType);
297  return sem_alloc<TypeNode>(visitType(node), node->location());
298 }
299 
300 LiteralNode* ptv::visitLiteral(Node* node) {
301  check_node_type(node, pty::Literal);
302  auto lit = cast<parsetree::Literal>(node);
303  return sem_alloc<LiteralNode>(sem.allocator(),
304  lit,
305  sem.BuildBuiltInType(lit->get_type()),
306  node->location());
307 }
308 
309 int ptv::visitArgumentList(Node* node, ExprNodeList& ops) {
310  if(node == nullptr) return 0;
311  check_node_type(node, pty::ArgumentList);
312  check_num_children(node, 1, 2);
313  int args = -1;
314  if(node->num_children() == 1) {
315  args = 1;
316  ops.concat(visitExprChild(node->child(0)));
317  } else if(node->num_children() == 2) {
318  args = visitArgumentList(node->child(0), ops) + 1;
319  ops.concat(visitExprChild(node->child(1)));
320  }
321  return args;
322 }
323 
324 } // namespace parsetree