Joos1W Compiler Framework
All Classes Functions Typedefs Pages
NameResolver.h
1 #pragma once
2 
3 #include <iostream>
4 #include <memory_resource>
5 #include <optional>
6 #include <string_view>
7 #include <unordered_map>
8 #include <variant>
9 
10 #include "ast/AstNode.h"
11 #include "diagnostics/Diagnostics.h"
12 #include "utils/BumpAllocator.h"
13 
14 // Forward declarations
15 namespace ast {
16 class LinkingUnit;
17 class CompilationUnit;
18 class UnresolvedType;
19 class InterfaceDecl;
20 class ClassDecl;
21 class MethodDecl;
22 class ReferenceType;
23 class Semantic;
24 class Expr;
25 } // namespace ast
26 
27 namespace semantic {
28 
29 class NameResolver final : public ast::TypeResolver {
30 public:
31  struct Pkg;
32  using ConstImport = std::variant<ast::Decl const*, Pkg const*>;
33  using ConstImportOpt = std::optional<ConstImport>;
34 
35  /// @brief Represents a tree of packages. The leaf nodes are declarations.
36  struct Pkg {
37  private:
38  using Child = std::variant<ast::Decl*, Pkg*>;
39  friend class NameResolver;
40  std::string_view name;
41  std::pmr::unordered_map<std::pmr::string, Child> children;
42 
43  public:
44  Pkg(BumpAllocator& alloc) : name{}, children{alloc} {}
45  Pkg(BumpAllocator& alloc, std::string_view name)
46  : name{name}, children{alloc} {}
47 
48  /**
49  * @brief Gets a child package by name. If the child is not found, then
50  * nullptr is returned.
51  * @param name The name of the child package to get.
52  * @param alloc The allocator to use for the string.
53  * @return Pkg const* The child package if found, otherwise nullptr.
54  */
55  ConstImportOpt lookup(std::string_view name, BumpAllocator& alloc) const {
56  auto it = children.find(std::pmr::string{name, alloc});
57  if(it == children.end()) return std::nullopt;
58  if(auto* pkg = std::get_if<Pkg*>(&it->second)) return *pkg;
59  return std::get<ast::Decl*>(it->second);
60  }
61 
62  public:
63  std::ostream& print(std::ostream& os, int indentation = 0) const;
64  void dump() const;
65  };
66 
67 private:
68  // Delete copy and move constructors and assignment operators
69  NameResolver(NameResolver const&) = delete;
70  NameResolver(NameResolver&&) = delete;
71  NameResolver& operator=(NameResolver const&) = delete;
72  NameResolver& operator=(NameResolver&&) = delete;
73 
74 public:
75  /**
76  * @brief Construct a new Name Resolver object.
77  *
78  * @param alloc The bump allocator to use for all allocations.
79  * @param diag The diagnostic engine to use for all diagnostics.
80  */
81  NameResolver(BumpAllocator& alloc, diagnostics::DiagnosticEngine& diag)
82  : alloc{alloc}, diag{diag}, lu_{nullptr}, importsMap_{alloc} {}
83 
84  /**
85  * @brief Initializes a new Name Resolver object given the entire linking
86  * unit (and all its symbols). After this, call Resolve() to resolve all
87  * types in the linking unit.
88  *
89  * @param lu The linking unit to resolve.
90  */
91  void Init(ast::LinkingUnit* lu, ast::Semantic* sema) {
92  lu_ = lu;
93  sema_ = sema;
94  buildSymbolTable();
95  populateJavaLangCache();
96  }
97 
98  /**
99  * @brief Resolves the type in-place (does not return anything)
100  *
101  * @param type The unresolved type to resolve.
102  */
103  void ResolveType(ast::UnresolvedType* type) override;
104 
105  /**
106  * @brief Get an import object from the import table of the given
107  * compilation unit. This object can either be a package or a declaration.
108  *
109  * @param cu The compilation unit to get the import from.
110  * @param name The name of the import to get.
111  * @param r An optional memory resource to use for allocations.
112  * @return ConstImport Returns nullopt if the import is not found. Otheriwse,
113  * returns the import object from the import table. Note, the package object
114  * will never be null. However, a declaration object can be null if the
115  * import-on-demand results in an unresolvable declaration.
116  */
117  ConstImportOpt GetImport(
118  ast::CompilationUnit const* cu, std::string_view name,
119  std::pmr::memory_resource* r = std::pmr::get_default_resource()) const;
120 
121  /**
122  * @brief Get a struct with all the java.lang.* classes and interfaces.
123  * Also includes java.io.Serializable for some reason.
124  * @return auto An anonymous struct with all the java.lang.* types.
125  */
126  auto GetJavaLang() const { return java_lang_; }
127 
128  /**
129  * @brief Get the Array Prototype object. This is a decl representing
130  * the prototype of the array class.
131  */
132  auto GetArrayPrototype() const { return arrayPrototype_; }
133 
134  /**
135  * @brief Called to begin the resolution of a compilation unit.
136  * This will build the import table (and any other data structures) to help
137  * resolve types within the compilation unit.
138  *
139  * @param cu The compilation unit to begin resolution for.
140  */
141  void BeginContext(ast::CompilationUnit* cu);
142 
143  /**
144  * @brief Called to end the resolution of a compilation unit.
145  * This will clear the current compilation unit being resolved.
146  */
147  void EndContext() { currentCU_ = nullptr; }
148 
149 public:
150  /// @brief Dumps the symbol and import tables to the output stream.
151  void dump() const;
152 
153  /// @brief Dumps the import table to the output stream.
154  void dumpImports(ast::CompilationUnit const* cu) const;
155 
156  /// @brief Dumps the import table to the output stream.
157  void dumpImports() const;
158 
159 private:
160  using ChildOpt = std::optional<Pkg::Child>;
161 
162  /// @brief Builds the symbol lookup tables and any other data structures
163  /// or maps to facilitate name resolution.
164  void buildSymbolTable();
165 
166  /**
167  * @brief Populates the java.lang.* cache with all the classes and interfaces
168  * into the java_lang_ struct.
169  */
170  void populateJavaLangCache();
171 
172  /// @brief Resolves an unresolved type to a non-leaf node in the tree
173  /// @param t The unresolved type to resolve.
174  /// @return The package node that the unresolved type resolves to.
175  ChildOpt resolveImport(ast::UnresolvedType const* t) const;
176 
177 private:
178  BumpAllocator& alloc;
179  diagnostics::DiagnosticEngine& diag;
180  ast::Semantic* sema_;
181  ast::LinkingUnit* lu_;
182  /// @brief The current compilation unit being resolved
183  ast::CompilationUnit* currentCU_;
184  /// @brief The import map for all the compilation units
185  std::pmr::unordered_map<ast::CompilationUnit const*,
186  std::pmr::unordered_map<std::pmr::string, Pkg::Child>>
187  importsMap_;
188  /// @brief The root of the symbol table (more of a tree than table).
189  Pkg* rootPkg_;
190  /// @brief A cache of the java.lang.* pkg
191  struct {
192  ast::ClassDecl* Boolean;
193  ast::ClassDecl* Byte;
194  ast::ClassDecl* Character;
195  ast::ClassDecl* Class;
196  ast::InterfaceDecl* Cloneable;
197  ast::ClassDecl* Integer;
198  ast::ClassDecl* Number;
199  ast::ClassDecl* Object;
200  ast::ClassDecl* Short;
201  ast::ClassDecl* String;
202  ast::ClassDecl* System;
203  ast::InterfaceDecl* Serializable;
204  } java_lang_;
205  // Array class prototype
206  ast::ClassDecl* arrayPrototype_;
207  // The type for the array prototype
208  ast::ReferenceType* arrayClassType_;
209 };
210 
211 } // namespace semantic