Joos1W Compiler Framework
All Classes Functions Typedefs Pages
SemanticPasses.cc
1 #include "CompilerPasses.h"
2 #include "ast/AstNode.h"
3 #include "ast/Decl.h"
4 #include "semantic/AstValidator.h"
5 #include "semantic/ConstantTypeResolver.h"
6 #include "semantic/DataflowAnalysis.h"
7 #include "semantic/ExprResolver.h"
8 #include "semantic/ExprStaticChecker.h"
9 #include "semantic/ExprTypeResolver.h"
10 #include "utils/BumpAllocator.h"
11 #include "utils/PassManager.h"
12 
13 using namespace joos1;
14 using namespace semantic;
15 using std::string_view;
16 using utils::Pass;
17 using utils::PassManager;
18 
19 /* ===--------------------------------------------------------------------=== */
20 // ExprResolverPass
21 /* ===--------------------------------------------------------------------=== */
22 
23 class ExprResolverPass final : public Pass {
24  struct Data {
25  ExprResolver& ER;
26  ExprTypeResolver& TR;
27  ExprStaticChecker& ESC;
28  semantic::ExprStaticCheckerState state;
29  };
30 
31 public:
32  ExprResolverPass(PassManager& PM) noexcept : Pass(PM) {}
33  string_view Name() const override { return "sema-expr"; }
34  string_view Desc() const override { return "Expression Resolution"; }
35  void Run() override {
36  auto LU = GetPass<LinkerPass>().LinkingUnit();
37  auto& NR = GetPass<NameResolverPass>().Resolver();
38  auto& HC = GetPass<HierarchyCheckerPass>().Checker();
39  auto& Sema = GetPass<AstContextPass>().Sema();
40  ExprResolver ER{PM().Diag(), NewHeap()};
41  ExprTypeResolver TR{PM().Diag(), NewHeap(), Sema};
42  ExprStaticChecker ESC{PM().Diag(), NR, HC};
43  BumpAllocator alloc{NewHeap()};
44  AstChecker AC{alloc, PM().Diag(), TR};
45  ER.Init(&TR, &NR, &Sema, &HC);
46  TR.Init(&HC, &NR);
47 
48  Data data{ER, TR, ESC, semantic::ExprStaticCheckerState{}};
49 
50  try {
51  resolveRecursive(data, LU);
52  AC.ValidateLU(*LU);
53  } catch(const diagnostics::DiagnosticBuilder&) {
54  // Print the errors from diag in the next step
55  }
56  }
57 
58 private:
59  void evaluateAsList(Data d, ast::Expr* expr) {
60  if(PM().Diag().Verbose(2)) {
61  auto dbg = PM().Diag().ReportDebug(2);
62  dbg << "[*] Location: ";
63  expr->location().print(dbg.get()) << "\n";
64  dbg << "[*] Printing expression before resolution:\n";
65  expr->print(dbg.get(), 1);
66  }
67  ast::ExprNodeList list = d.ER.Evaluate(expr);
68  if(PM().Diag().Verbose(2)) {
69  auto dbg = PM().Diag().ReportDebug(2);
70  dbg << "[*] Printing expression after resolution:\n ";
71  list.print(dbg.get());
72  }
73  expr->replace(list);
74  d.TR.Evaluate(expr);
75  d.ESC.Evaluate(expr, d.state);
76  }
77 
78  void resolveRecursive(Data d, ast::AstNode* node) {
79  // Set the CU and context
80  if(auto* cu = dyn_cast<ast::CompilationUnit>(node)) d.ER.BeginCU(cu);
81  if(auto* ctx = dyn_cast<ast::DeclContext>(node)) d.ER.BeginContext(ctx);
82  if(auto* classDecl = dyn_cast<ast::ClassDecl>(node))
83  d.state.currentClass = classDecl;
84 
85  // If we're inside a method or field decl, see if its static
86  d.state.isInstFieldInitializer = false;
87  d.state.fieldScope = nullptr;
88  if(auto* field = dyn_cast<ast::FieldDecl>(node)) {
89  d.state.isStaticContext = field->modifiers().isStatic();
90  if(field->hasInit()) {
91  d.state.isInstFieldInitializer = !field->modifiers().isStatic();
92  d.state.fieldScope = field->init()->scope();
93  }
94  } else if(auto* method = dyn_cast<ast::MethodDecl>(node)) {
95  d.state.isStaticContext = method->modifiers().isStatic();
96  }
97 
98  // Visit the expression nodes
99  if(auto* decl = dynamic_cast<ast::TypedDecl*>(node)) {
100  if(auto* init = decl->mut_init()) {
101  if(PM().Diag().Verbose(2)) {
102  PM().Diag().ReportDebug(2)
103  << "[*] Resolving initializer for variable: " << decl->name();
104  }
105  evaluateAsList(d, init);
106  }
107  } else if(auto* stmt = dynamic_cast<ast::Stmt*>(node)) {
108  for(auto* expr : stmt->mut_exprs()) {
109  if(!expr) continue;
110  if(PM().Diag().Verbose(2)) {
111  PM().Diag().ReportDebug(2)
112  << "[*] Resolving expression in statement:";
113  }
114  evaluateAsList(d, expr);
115  }
116  }
117  // We want to avoid visiting nodes twice
118  if(dynamic_cast<ast::DeclStmt*>(node)) return;
119  // Visit the children recursively
120  for(auto* child : node->mut_children()) {
121  if(child) resolveRecursive(d, child);
122  }
123  }
124 
125 private:
126  void computeDependencies() override {
127  ComputeDependency(GetPass<AstContextPass>());
128  ComputeDependency(GetPass<NameResolverPass>());
129  ComputeDependency(GetPass<HierarchyCheckerPass>());
130  }
131 };
132 
133 /* ===--------------------------------------------------------------------=== */
134 // DFAPass
135 /* ===--------------------------------------------------------------------=== */
136 
137 class DFAPass final : public Pass {
138 public:
139  DFAPass(PassManager& PM) noexcept : Pass(PM) {}
140  string_view Name() const override { return "dfa"; }
141  string_view Desc() const override { return "Dataflow Analysis"; }
142  void Init() override {
143  optEnable = PM().PO().GetExistingOption("--enable-dfa-check")->count();
144  }
145  void Run() override {
146  if(!optEnable) return;
147  auto LU = GetPass<LinkerPass>().LinkingUnit();
148  auto& Sema = GetPass<AstContextPass>().Sema();
149  ConstantTypeResolver CTR{NewHeap()};
150  DataflowAnalysis DFA{PM().Diag(), NewHeap(), Sema, LU};
151  CFGBuilder builder{PM().Diag(), &CTR, NewHeap(), Sema};
152  DFA.init(&builder);
153 
154  try {
155  DFA.Check();
156  } catch(const diagnostics::DiagnosticBuilder&) {
157  // Print the errors from diag in the next step
158  }
159  }
160 
161 private:
162  void computeDependencies() override {
163  ComputeDependency(GetPass<AstContextPass>());
164  ComputeDependency(GetPass<LinkerPass>());
165  ComputeDependency(GetPass<ExprResolverPass>());
166  }
167  bool optEnable;
168 };
169 
170 /* ===--------------------------------------------------------------------=== */
171 // Register all the passes here
172 /* ===--------------------------------------------------------------------=== */
173 
174 REGISTER_PASS(ExprResolverPass);
175 REGISTER_PASS(DFAPass);