Joos1W Compiler Framework
All Classes Functions Typedefs Pages
Semantic.h
1 #pragma once
2 
3 #include <unordered_set>
4 
5 #include "ast/AST.h"
6 #include "ast/AstNode.h"
7 #include "ast/DeclContext.h"
8 #include "ast/Type.h"
9 #include "diagnostics/Diagnostics.h"
10 #include "diagnostics/Location.h"
11 #include "parsetree/ParseTree.h"
12 #include "utils/BumpAllocator.h"
13 
14 namespace ast {
15 class Semantic {
16  using string = std::string;
17 
18 public:
19  Semantic(BumpAllocator& alloc, diagnostics::DiagnosticEngine& diag);
20 
21 public:
22  /* ===-----------------------------------------------------------------=== */
23  // ast/Type.h
24  /* ===-----------------------------------------------------------------=== */
25 
26  UnresolvedType* BuildUnresolvedType(SourceRange loc = {});
27  ReferenceType* BuildReferenceType(Decl const* decl);
28  ArrayType* BuildArrayType(Type* elementType, SourceRange loc = {});
29  BuiltInType* BuildBuiltInType(parsetree::BasicType::Type type,
30  SourceRange loc = {});
31  BuiltInType* BuildBuiltInType(parsetree::Literal::Type type);
32  BuiltInType* BuildBuiltInType(ast::BuiltInType::Kind type);
33 
34  /* ===-----------------------------------------------------------------=== */
35  // ast/Decl.h
36  /* ===-----------------------------------------------------------------=== */
37 
38  VarDecl* BuildVarDecl(Type* type, SourceRange location, string_view name,
39  ScopeID const* scope, Expr* init = nullptr);
40  FieldDecl* BuildFieldDecl(Modifiers modifiers, SourceRange location, Type* type,
41  string_view name, Expr* init = nullptr,
42  bool allowFinal = false);
43 
44  /* ===-----------------------------------------------------------------=== */
45  // ast/DeclContext.h
46  /* ===-----------------------------------------------------------------=== */
47 
48  LinkingUnit* BuildLinkingUnit(array_ref<CompilationUnit*> compilationUnits);
49  CompilationUnit* BuildCompilationUnit(ReferenceType* package,
50  array_ref<ImportDeclaration> imports,
51  SourceRange location, DeclContext* body);
52  ClassDecl* BuildClassDecl(Modifiers modifiers, SourceRange location,
53  string_view name, ReferenceType* superClass,
54  array_ref<ReferenceType*> interfaces,
55  array_ref<Decl*> classBodyDecls);
56  InterfaceDecl* BuildInterfaceDecl(Modifiers modifiers, SourceRange location,
57  string_view name,
58  array_ref<ReferenceType*> extends,
59  array_ref<Decl*> interfaceBodyDecls);
60  MethodDecl* BuildMethodDecl(Modifiers modifiers, SourceRange location,
61  string_view name, Type* returnType,
62  array_ref<VarDecl*> parameters, bool isConstructor,
63  Stmt* body);
64  /* ===-----------------------------------------------------------------=== */
65  // ast/Stmt.h
66  /* ===-----------------------------------------------------------------=== */
67 
68  BlockStatement* BuildBlockStatement(array_ref<Stmt*> stmts);
69  DeclStmt* BuildDeclStmt(VarDecl* decl);
70  ExprStmt* BuildExprStmt(Expr* expr);
71  IfStmt* BuildIfStmt(Expr* condition, Stmt* thenStmt, Stmt* elseStmt = nullptr);
72  WhileStmt* BuildWhileStmt(Expr* condition, Stmt* body);
73  ForStmt* BuildForStmt(Stmt* init, Expr* condition, Stmt* update, Stmt* body);
74  ReturnStmt* BuildReturnStmt(SourceRange loc, Expr* expr);
75  NullStmt* BuildNullStmt() { return alloc.new_object<NullStmt>(); }
76 
77 public:
78  BumpAllocator& allocator() { return alloc; }
79 
80 public:
81  /// @brief Clears the lexical local scope names
83  lexicalLocalScope.clear();
84  lexicalLocalDecls.clear();
85  lexicalLocalDeclStack.clear();
86  currentScope_ = ScopeID::New(alloc);
87  }
88 
89  /**
90  * @brief Checks if a name is in the lexical local scope
91  * and if it is not, add it to the scope.
92  * @param name The name to add to the scope
93  * @return true If the name was added to the scope
94  * @return false If the name was already in the scope
95  */
96  bool AddLexicalLocal(VarDecl* decl) {
97  std::string nameCpy{decl->name()};
98  if(lexicalLocalScope.find(nameCpy) != lexicalLocalScope.end()) return false;
99  lexicalLocalScope[nameCpy] = decl;
100  lexicalLocalDecls.push_back(decl);
101  lexicalLocalDeclStack.push_back(decl);
102  return true;
103  }
104 
105  /**
106  * @brief Called when a new lexical scope is entered. Returns the size of the
107  * local declaration stack so it can be restored when the scope is exited.
108  * @return int Returns the size of the local declaration stack
109  */
111  int size = lexicalLocalDeclStack.size();
112  currentScope_ = currentScope_->next(alloc, currentScope_);
113  return size;
114  }
115 
116  /**
117  * @brief Called when a lexical scope is exited. Resizes the local decl
118  * stack to the size it was when the scope was entered. Deletes the locals
119  * from the set as well.
120  * @param size The size of the local declaration stack when the scope was
121  * entered
122  */
123  void ExitLexicalScope(int size) {
124  for(int i = lexicalLocalDeclStack.size() - 1; i >= size; --i)
125  lexicalLocalScope.erase(lexicalLocalDeclStack[i]->name().data());
126  lexicalLocalDeclStack.resize(size);
127  assert(currentScope_->parent() != nullptr);
128  currentScope_ =
129  currentScope_->next(alloc, currentScope_->parent()->parent());
130  }
131 
132  /**
133  * @brief Get all the lexical declarations in the current scope.
134  */
135  auto getAllLexicalDecls() const { return std::views::all(lexicalLocalDecls); }
136 
137  ast::ScopeID const* NextScopeID() {
138  currentScope_ = currentScope_->next(alloc, currentScope_->parent());
139  return currentScope_;
140  }
141 
142  ast::ScopeID const* CurrentScopeID() const { return currentScope_; }
143 
144  ast::ScopeID const* NextFieldScopeID() {
145  currentFieldScope_ = currentFieldScope_->next(alloc, currentFieldScope_);
146  return currentFieldScope_;
147  }
148 
149  ast::ScopeID const* CurrentFieldScopeID() const { return currentFieldScope_; }
150 
151  void ResetFieldScope() {
152  currentFieldScope_ = ScopeID::New(alloc);
153  }
154 
155 private:
156  BumpAllocator& alloc;
157  diagnostics::DiagnosticEngine& diag;
158  std::vector<VarDecl*> lexicalLocalDeclStack;
159  std::vector<VarDecl*> lexicalLocalDecls;
160  std::unordered_map<std::string, VarDecl const*> lexicalLocalScope;
161  // java.lang.Object type
162  ast::ReferenceType* objectType_;
163  // Current lexical local scope
164  ast::ScopeID const* currentScope_;
165  // Current field scope
166  ast::ScopeID const* currentFieldScope_;
167 };
168 
169 } // namespace ast