Joos1W Compiler Framework
All Classes Functions Typedefs Pages
ExprNode.h
1 #pragma once
2 
3 #include <string>
4 #include <string_view>
5 #include <variant>
6 
7 #include "ast/AstNode.h"
8 #include "ast/Decl.h"
9 #include "diagnostics/Location.h"
10 #include "utils/BumpAllocator.h"
11 #include "utils/EnumMacros.h"
12 #include "utils/Generator.h"
13 
14 namespace ast {
15 class ExprNodeList;
16 
17 template <typename T>
18 class ExprEvaluator;
19 
20 /* ===--------------------------------------------------------------------=== */
21 // ExprNode and ExprNodeList
22 /* ===--------------------------------------------------------------------=== */
23 
24 class ExprNode {
25 public:
26  explicit ExprNode(SourceRange loc) : next_{nullptr}, loc_{loc} {}
27  virtual std::ostream& print(std::ostream& os) const { return os << "ExprNode"; }
28  virtual ~ExprNode() = default;
29 
30 public:
31  void setNext(ExprNode* new_next_) {
32  assert(!locked_ && "Attempt to mutate locked node");
33  next_ = new_next_;
34  }
35  const ExprNode* next() const { return next_; }
36  ExprNode* mut_next() const { return next_; }
37  void dump() const;
38  SourceRange location() const { return loc_; }
39 
40 private:
41  template <typename T>
42  friend class ExprEvaluator;
43 
44  void const_lock() const { locked_ = true; }
45  void const_unlock() const { locked_ = false; }
46 
47 private:
48  // The next node is mutable because it can be modified on-the-fly during
49  // evaluation. That being said, it's the responsibility of the evaluator
50  // to ensure the correct order of unlocking nodes.
51  ExprNode* next_;
52 
53  // The lock for the previous node.
54  mutable bool locked_ = false;
55 
56  SourceRange loc_;
57 };
58 
59 /// @brief A list of ExprNodes* that can be iterated and concatenated
60 class ExprNodeList final {
61 public:
62  explicit ExprNodeList(ExprNode* node) : head_{node}, tail_{node}, size_{1} {
63  node->setNext(nullptr);
64  }
65  ExprNodeList() : head_{nullptr}, tail_{nullptr}, size_{0} {}
66  bool isBracketed = false;
67 
68  /**
69  * @brief Pushes a node to the back of the list
70  * @param node The node to push
71  */
72  void push_back(ExprNode* node) {
73  if(node == nullptr) return;
74  if(head_ == nullptr) {
75  head_ = node;
76  tail_ = node;
77  } else {
78  tail_->setNext(node);
79  tail_ = node;
80  }
81  node->setNext(nullptr);
82  size_ += 1;
83  check_invariants();
84  }
85 
86  /**
87  * @brief Concatenates another list to the end of this list.
88  * @param other The list to concatenate (rvalue reference)
89  */
90  void concat(ExprNodeList&& other) {
91  if(other.size_ == 0) return;
92  if(head_ == nullptr) {
93  head_ = other.head_;
94  tail_ = other.tail_;
95  } else {
96  tail_->setNext(other.head_);
97  tail_ = other.tail_;
98  }
99  size_ += other.size_;
100  check_invariants();
101  }
102 
103  /**
104  * @brief Concatenates another list to the end of this list. The other list
105  * will be invalidated and empty after this operation.
106  * @param other The list to concatenate
107  */
108  void concat(ExprNodeList& other) {
109  concat(std::move(other));
110  other.head_ = nullptr;
111  other.tail_ = nullptr;
112  other.size_ = 0;
113  }
114 
115  /// @brief Returns the number of nodes in the list
116  [[nodiscard]] auto size() const { return size_; }
117 
118  /// @brief Returns a generator that yields each node in the list
119  utils::Generator<ExprNode const*> nodes() const {
120  size_t i = 0;
121  for(auto const* node = head_; i < size_; node = node->next(), i++) {
122  co_yield node;
123  }
124  }
125 
126  /// @brief Non-const version of nodes()
128  size_t i = 0;
129  for(auto node = head_; i < size_; node = node->mut_next(), i++) {
130  co_yield node;
131  }
132  }
133 
134  ExprNode* mut_head() const { return head_; }
135  ExprNode const* tail() const { return tail_; }
136 
137  void dump() const;
138  std::ostream& print(std::ostream&) const;
139 
140 private:
141  void check_invariants() const;
142 
143 private:
144  ExprNode* head_;
145  ExprNode* tail_;
146  size_t size_;
147 };
148 
149 } // namespace ast
150 
151 namespace ast::exprnode {
152 
153 /* ===--------------------------------------------------------------------=== */
154 // ExprValue Subclasses
155 /* ===--------------------------------------------------------------------=== */
156 
157 class ExprValue : public ExprNode {
158 public:
159  explicit ExprValue(SourceRange loc, ast::Type const* type = nullptr)
160  : ExprNode{loc}, decl_{nullptr}, type_{type} {}
161  ast::Decl const* decl() const { return decl_; }
162  virtual bool isDeclResolved() const { return decl_ != nullptr; }
163  bool isTypeResolved() const { return type_ != nullptr; }
164  void resolveDeclAndType(ast::Decl const* decl, ast::Type const* type) {
165  assert(!decl_ && "Tried to resolve expression decl twice");
166  decl_ = decl;
167  assert(!type_ && "Tried to resolve expression type twice");
168  assert((!type || type->isResolved()) &&
169  "Tried to resolve expression with unresolved type");
170  type_ = type;
171  }
172  void overrideDecl(ast::Decl const* decl) { decl_ = decl; }
173  ast::Type const* type() const { return type_; }
174 
175 protected:
176  ast::Type const* set_type(ast::Type const* type) {
177  assert(!type_ && "Tried to set type twice");
178  type_ = type;
179  return type;
180  }
181 
182 private:
183  ast::Decl const* decl_;
184  ast::Type const* type_;
185 };
186 
187 class MemberName : public ExprValue {
188 public:
189  MemberName(BumpAllocator& alloc, std::string_view name, SourceRange loc)
190  : ExprValue{loc}, name_{name, alloc} {}
191  std::ostream& print(std::ostream& os) const;
192  std::string_view name() const { return name_; }
193 
194 private:
195  std::pmr::string name_;
196 };
197 
198 class MethodName : public MemberName {
199 public:
200  MethodName(BumpAllocator& alloc, std::string_view name, SourceRange loc)
201  : MemberName{alloc, name, loc} {}
202  std::ostream& print(std::ostream& os) const override;
203 };
204 
205 class ThisNode final : public ExprValue {
206 public:
207  ThisNode(SourceRange loc) : ExprValue{loc} {}
208  std::ostream& print(std::ostream& os) const override;
209 };
210 
211 class TypeNode final : public ExprValue {
212 public:
213  TypeNode(Type* type, SourceRange loc) : ExprValue{loc}, unres_type_{type} {}
214  void resolveUnderlyingType(TypeResolver& NR) {
215  assert(unres_type_ && "Tried to resolve underlying type twice");
216  // Resolve underlying type if it's not already resolved
217  if(!unres_type_->isResolved()) unres_type_->resolve(NR);
218 
219  // NOTE: We cannot assume that unres_type_ is resolved as import-on-demand
220  // conflicts will result in unresolved types (null), but is valid.
221 
222  set_type(unres_type_);
223  }
224  bool isDeclResolved() const override { return true; }
225  std::ostream& print(std::ostream& os) const override;
226 
227 private:
228  ast::Type* unres_type_;
229 };
230 
231 class LiteralNode final : public ExprValue {
232 public:
233  LiteralNode(BumpAllocator&, parsetree::Literal const* node,
234  ast::BuiltInType* type, SourceRange loc);
235  bool isDeclResolved() const override { return true; }
236  std::ostream& print(std::ostream& os) const override;
237  ast::BuiltInType const* builtinType() const;
238  uint32_t getAsInt() const { return std::get<uint32_t>(value_); }
239  auto const& getAsString() const { return std::get<std::pmr::string>(value_); }
240 
241 private:
242  std::variant<uint32_t, std::pmr::string> value_;
243 };
244 
245 /* ===--------------------------------------------------------------------=== */
246 // ExprOp Subclasses
247 /* ===--------------------------------------------------------------------=== */
248 
249 class ExprOp : public ExprNode {
250 protected:
251  ExprOp(int num_args, SourceRange loc)
252  : ExprNode{loc}, num_args_{num_args}, result_type_{nullptr} {}
253 
254 public:
255  auto nargs() const { return num_args_; }
256  std::ostream& print(std::ostream& os) const override = 0;
257  ast::Type const* resolveResultType(ast::Type const* type) {
258  assert(!result_type_ && "Tried to operator-resolve result type twice");
259  assert((!type || type->isResolved()) &&
260  "Tried to resolve operator with unresolved type");
261  result_type_ = type;
262  return type;
263  }
264  ast::Type const* resultType() const { return result_type_; }
265 
266 private:
267  int num_args_;
268  ast::Type const* result_type_;
269 };
270 
271 class MemberAccess final : public ExprOp {
272 public:
273  MemberAccess() : ExprOp(2, SourceRange{}) {}
274  std::ostream& print(std::ostream& os) const override;
275 };
276 
277 class MethodInvocation final : public ExprOp {
278 public:
279  MethodInvocation(int num_args) : ExprOp(num_args, SourceRange{}) {}
280  std::ostream& print(std::ostream& os) const override;
281 };
282 
283 class ClassInstanceCreation final : public ExprOp {
284 public:
285  ClassInstanceCreation(int num_args) : ExprOp(num_args, SourceRange{}) {}
286  std::ostream& print(std::ostream& os) const override;
287 };
288 
289 class ArrayInstanceCreation final : public ExprOp {
290 public:
291  ArrayInstanceCreation() : ExprOp(2, SourceRange{}) {}
292  std::ostream& print(std::ostream& os) const override;
293 };
294 
295 class ArrayAccess final : public ExprOp {
296 public:
297  ArrayAccess() : ExprOp(2, SourceRange{}) {}
298  std::ostream& print(std::ostream& os) const override;
299 };
300 
301 class Cast final : public ExprOp {
302 public:
303  Cast() : ExprOp(2, SourceRange{}) {}
304  std::ostream& print(std::ostream& os) const override;
305 };
306 
307 class UnaryOp final : public ExprOp {
308 #define UNARY_OP_TYPE_LIST(F)
309  /* Leaf nodes */
310  F(Not)
311  F(BitwiseNot)
312  F(Plus)
313  F(Minus)
314 public:
315  DECLARE_ENUM(OpType, UNARY_OP_TYPE_LIST)
316  DECLARE_STRING_TABLE(OpType, type_strings, UNARY_OP_TYPE_LIST)
317 #undef UNARY_OP_TYPE_LIST
318 
319 private:
320  OpType type;
321 
322 public:
323  UnaryOp(OpType type, SourceRange loc) : ExprOp(1, loc), type{type} {}
324  std::ostream& print(std::ostream& os) const override;
325  OpType opType() const { return type; }
326 };
327 
328 class BinaryOp final : public ExprOp {
329 #define BINARY_OP_TYPE_LIST(F)
330  F(Assignment)
331  F(GreaterThan)
332  F(GreaterThanOrEqual)
333  F(LessThan)
334  F(LessThanOrEqual)
335  F(Equal)
336  F(NotEqual)
337  F(And)
338  F(Or)
339  F(BitwiseAnd)
340  F(BitwiseOr)
341  F(BitwiseXor)
342  F(Add)
343  F(Subtract)
344  F(Multiply)
345  F(Divide)
346  F(Modulo)
347  F(InstanceOf)
348 public:
349  DECLARE_ENUM(OpType, BINARY_OP_TYPE_LIST)
350  DECLARE_STRING_TABLE(OpType, type_strings, BINARY_OP_TYPE_LIST)
351 #undef BINARY_OP_TYPE_LIST
352 
353 private:
354  OpType type;
355  // the variable using assigned, only used for assignment
356  const ast::VarDecl* varAssigned = nullptr;
357 
358 public:
359  BinaryOp(OpType type, SourceRange loc) : ExprOp(2, loc), type{type} {}
360  std::ostream& print(std::ostream& os) const override;
361  OpType opType() const { return type; }
362  void setVarAssigned(const ast::VarDecl* var) {
363  assert(!varAssigned && "Tried to set varAssigned twice");
364  varAssigned = var;
365  }
366  const ast::VarDecl* getVarAssigned() const { return varAssigned; }
367 };
368 
369 } // namespace ast::exprnode