Joos1W Compiler Framework
All Classes Functions Typedefs Pages
DeclContext.cc
1 #include <utils/Assert.h>
2 #include <ostream>
3 #include <ranges>
4 #include <string>
5 
6 #include "ast/AST.h"
7 #include "utils/BumpAllocator.h"
8 #include "utils/Utils.h"
9 
10 namespace ast {
11 
12 using std::ostream;
13 using std::string;
14 
15 // LinkingUnit /////////////////////////////////////////////////////////////
16 
17 LinkingUnit::LinkingUnit(BumpAllocator& alloc,
18  array_ref<CompilationUnit*> compilationUnits) noexcept
19  : compilationUnits_{alloc} {
20  utils::move_vector<CompilationUnit*>(compilationUnits, compilationUnits_);
21 }
22 
23 ostream& LinkingUnit::print(ostream& os, int indentation) const {
24  auto i1 = indent(indentation);
25  auto i2 = indent(indentation + 1);
26  auto i3 = indent(indentation + 2);
27  os << i1 << "LinkingUnit {\n" << i2 << "asts: ";
28 
29  for(auto& cu : compilationUnits_) {
30  cu->print(os, indentation + 1) << "\n";
31  }
32 
33  os << i1 << "}\n";
34  return os;
35 }
36 
37 int LinkingUnit::printDotNode(DotPrinter& dp) const {
38  int id = dp.id();
39  dp.startTLabel(id);
40  dp.printTableSingleRow("LinkingUnit", {"bgcolor", "lightblue"});
41  dp.endTLabel();
42 
43  for(auto& cu : compilationUnits_) {
44  dp.printConnection(id, cu->printDotNode(dp));
45  }
46  return id;
47 }
48 
49 // CompilationUnit /////////////////////////////////////////////////////////////
50 
51 CompilationUnit::CompilationUnit(BumpAllocator& alloc, ReferenceType* package,
52  array_ref<ImportDeclaration> imports,
53  SourceRange location, DeclContext* body) noexcept
54  : package_{package}, imports_{alloc}, body_{body}, location_{location} {
55  if(auto decl = dyn_cast_or_null<Decl*>(body)) {
56  decl->setParent(this);
57  } else if(decl != nullptr) {
58  assert(false && "Body must be a Decl.");
59  }
60  utils::move_vector<ImportDeclaration>(imports, imports_);
61 }
62 
63 ostream& CompilationUnit::print(ostream& os, int indentation) const {
64  auto i1 = indent(indentation);
65  auto i2 = indent(indentation + 1);
66  auto i3 = indent(indentation + 2);
67  os << i1 << "CompilationUnit {\n"
68  << i2 << "package: " << (package_ ? package_->toString() : "null") << "\n"
69  << i2 << "imports: [";
70  for(auto& import : imports_) {
71  os << "\"" << import.type->toString() << (import.isOnDemand ? ".*" : "")
72  << "\",";
73  }
74  os << "]\n";
75  if(body_) {
76  body_->print(os, indentation + 1);
77  }
78  os << i1 << "}\n";
79  return os;
80 }
81 
82 int CompilationUnit::printDotNode(DotPrinter& dp) const {
83  int id = dp.id();
84  dp.startTLabel(id);
85  dp.printTableSingleRow("CompilationUnit", {"bgcolor", "lightblue"});
86  dp.printTableDoubleRow("package", package_ ? package_->toString() : "??");
87  std::string imports;
88  for(auto& import : imports_) {
89  imports += import.type->toString();
90  imports += import.isOnDemand ? ".*" : "";
91  imports += "\n";
92  }
93  dp.printTableDoubleRow("imports", imports);
94  dp.endTLabel();
95  if(body_) dp.printConnection(id, body_->printDotNode(dp));
96  return id;
97 }
98 
99 // ClassDecl ///////////////////////////////////////////////////////////////////
100 
101 ClassDecl::ClassDecl(BumpAllocator& alloc, Modifiers modifiers,
102  SourceRange location, string_view name, ReferenceType* super1,
103  ReferenceType* super2, array_ref<ReferenceType*> interfaces,
104  array_ref<Decl*> classBodyDecls) throw()
105  : Decl{alloc, name},
106  modifiers_{modifiers},
107  superClasses_{super1, super2},
108  interfaces_{alloc},
109  fields_{alloc},
110  methods_{alloc},
111  constructors_{alloc},
112  location_{location} {
113  utils::move_vector<ReferenceType*>(interfaces, interfaces_);
114  // Sort the classBodyDecls into fields, methods, and constructors
115  for(auto bodyDecl : classBodyDecls) {
116  if(auto fieldDecl = dyn_cast<FieldDecl*>(bodyDecl)) {
117  fields_.push_back(fieldDecl);
118  } else if(auto methodDecl = dyn_cast<MethodDecl*>(bodyDecl)) {
119  if(methodDecl->isConstructor())
120  constructors_.push_back(methodDecl);
121  else
122  methods_.push_back(methodDecl);
123  } else {
124  assert(false && "Unexpected class body declaration type");
125  }
126  }
127 }
128 
129 ostream& ClassDecl::print(ostream& os, int indentation) const {
130  auto i1 = indent(indentation);
131  auto i2 = indent(indentation + 1);
132  auto i3 = indent(indentation + 2);
133  os << i1 << "ClassDecl {\n"
134  << i2 << "modifiers: " << modifiers_.toString() << "\n"
135  << i2 << "name: " << this->name()
136  << "\n"
137  // FIXME(kevin): Fix printing of superclasses
138  // << i2 << "superClass: " << (superClass_ ? superClass_->toString() :
139  // "null")
140  // << "\n"
141  << i2 << "interfaces: []\n"
142  << i2 << "fields:\n";
143  for(auto& field : fields_) field->print(os, indentation + 2);
144  os << i2 << "methods:\n";
145  for(auto& method : methods_) method->print(os, indentation + 2);
146  os << i2 << "constructors:\n";
147  for(auto& constructor : constructors_) constructor->print(os, indentation + 2);
148  os << i1 << "}\n";
149  return os;
150 }
151 
152 int ClassDecl::printDotNode(DotPrinter& dp) const {
153  int id = dp.id();
154  dp.startTLabel(id);
155  dp.printTableSingleRow("ClassDecl", {"bgcolor", "lightblue"});
156  dp.printTableDoubleRow("modifiers", modifiers_.toString());
157  dp.printTableDoubleRow("name", name());
158  // FIXME(kevin): Fix printing of superclasses
159  // dp.printTableDoubleRow("superClass",
160  // superClass_ ? superClass_->toString() : "");
161  string intf;
162  for(auto& i : interfaces()) intf += string{i->toString()} + "\n";
163  dp.printTableDoubleRow("interfaces", intf);
164  dp.printTableTripleRow("fields",
165  "ctors",
166  "methods",
167  {"port", "fields"},
168  {"port", "constructors"},
169  {"port", "methods"});
170  dp.endTLabel();
171 
172  for(auto& f : fields())
173  dp.printConnection(id, ":fields:w", f->printDotNode(dp));
174  for(auto& f : constructors())
175  dp.printConnection(id, ":constructors:c", f->printDotNode(dp));
176  for(auto& f : methods())
177  dp.printConnection(id, ":methods:e", f->printDotNode(dp));
178  return id;
179 }
180 
181 void ClassDecl::setParent(DeclContext* parent) {
182  auto cu = cast<CompilationUnit*>(parent);
183  // Set the parent of the class
184  Decl::setParent(parent);
185  // Build the canonical name
186  if(!cu->isDefaultPackage()) {
187  canonicalName_ = cu->getPackageName();
188  canonicalName_ += ".";
189  }
190  canonicalName_ += name();
191 
192  // Propagate the setParent call to the fields, methods, and constructors
193  for(auto& field : fields_) field->setParent(this);
194  for(auto& method : methods_) method->setParent(this);
195  for(auto& constructor : constructors_) constructor->setParent(this);
196 }
197 
198 bool ClassDecl::hasDefaultCtor() const {
199  for(auto& ctor : constructors_) {
200  if(ctor->parameters().empty()) return true;
201  }
202  return false;
203 }
204 
205 // InterfaceDecl ///////////////////////////////////////////////////////////////
206 
207 InterfaceDecl::InterfaceDecl(BumpAllocator& alloc, Modifiers modifiers,
208  SourceRange location, string_view name,
209  array_ref<ReferenceType*> extends,
210  ReferenceType* objectSuperclass,
211  array_ref<Decl*> interfaceBodyDecls) throw()
212  : Decl{alloc, name},
213  modifiers_{modifiers},
214  extends_{alloc},
215  methods_{alloc},
216  location_{location},
217  objectSuperclass_{objectSuperclass} {
218  utils::move_vector<ReferenceType*>(extends, extends_);
219  for(auto bodyDecl : interfaceBodyDecls) {
220  methods_.push_back(cast<MethodDecl*>(bodyDecl));
221  }
222 }
223 
224 ostream& InterfaceDecl::print(ostream& os, int indentation) const {
225  auto i1 = indent(indentation);
226  auto i2 = indent(indentation + 1);
227  auto i3 = indent(indentation + 2);
228  os << i1 << "InterfaceDecl {\n"
229  << i2 << "modifiers: " << modifiers_.toString() << "\n"
230  << i2 << "name: " << this->name() << "\n"
231  << i2 << "extends: []\n"
232  << i2 << "methods:\n";
233  for(auto& method : methods_) {
234  method->print(os, indentation + 2);
235  }
236  os << i1 << "}\n";
237  return os;
238 }
239 
240 int InterfaceDecl::printDotNode(DotPrinter& dp) const {
241  int id = dp.id();
242  dp.startTLabel(id);
243  dp.printTableSingleRow("InterfaceDecl", {"bgcolor", "lightblue"});
244  dp.printTableDoubleRow("modifiers", modifiers_.toString());
245  dp.printTableDoubleRow("name", name());
246  string ext;
247  for(auto& e : extends()) ext += string{e->toString()} + "\n";
248  dp.printTableDoubleRow("extends", ext);
249  dp.printTableDoubleRow("methods", "", {}, {"port", "methods"});
250  dp.endTLabel();
251 
252  for(auto& f : methods())
253  dp.printConnection(id, ":methods", f->printDotNode(dp));
254  return id;
255 }
256 
257 void InterfaceDecl::setParent(DeclContext* parent) {
258  auto cu = cast<CompilationUnit*>(parent);
259  // Set the parent of the interface
260  Decl::setParent(parent);
261  // Build the canonical name
262  if(!cu->isDefaultPackage()) {
263  canonicalName_ = cu->getPackageName();
264  canonicalName_ += ".";
265  }
266  canonicalName_ += name();
267  // Propagate the setParent call to the methods
268  for(auto& method : methods_) method->setParent(this);
269 }
270 
271 // MethodDecl //////////////////////////////////////////////////////////////////
272 
273 ostream& MethodDecl::print(ostream& os, int indentation) const {
274  auto i1 = indent(indentation);
275  auto i2 = indent(indentation + 1);
276  auto i3 = indent(indentation + 2);
277  os << i1 << "MethodDecl {\n"
278  << i2 << "modifiers: " << modifiers_.toString() << "\n"
279  << i2 << "name: " << this->name() << "\n"
280  << i2 << "returnType: " << (returnType_ ? returnType_->toString() : "null")
281  << "\n"
282  << i2 << "parameters:\n";
283  for(auto& parameter : parameters_) {
284  parameter->print(os, indentation + 2);
285  }
286  if(body_) {
287  body_->print(os, indentation + 1);
288  }
289  os << i1 << "}\n";
290  return os;
291 }
292 
293 std::ostream& MethodDecl::printSignature(std::ostream& os) const {
294  os << returnType_->toString() << " " << name() << "(";
295  for(auto& param : parameters_) {
296  os << param->type()->toString() << " " << param->name();
297  if(param != parameters_.back()) os << ", ";
298  }
299  os << ")";
300  return os;
301 }
302 
303 void MethodDecl::dumpSignature() const {
304  printSignature(std::cerr) << "\n";
305 }
306 
307 int MethodDecl::printDotNode(DotPrinter& dp) const {
308  int id = dp.id();
309  int paramSubgraphId = dp.id();
310 
311  // Print the method declaration node itself
312  dp.startTLabel(id);
313  {
314  dp.printTableSingleRow("MethodDecl", {"bgcolor", "lightblue"});
315  dp.printTableDoubleRow("modifiers", modifiers_.toString());
316  dp.printTableDoubleRow("name", name());
317  dp.printTableDoubleRow("returnType",
318  returnType_ ? returnType_->toString() : "null");
320  "Params", "Body", {"port", "parameters"}, {"port", "body"});
321  }
322  dp.endTLabel();
323 
324  // Print the parameter subgraph and connect it to the method node
325  int firstParamId = -1;
326  dp.startSubgraph(paramSubgraphId);
327  if(!parameters().empty()) {
328  dp.print("label=\"Parameters\"");
329  dp.print("color=lightcoral");
330  firstParamId = printDotNodeList(dp, parameters());
331  }
332  dp.endSubgraph();
333  if(firstParamId != -1)
334  dp.printConnection(id, ":parameters", firstParamId, paramSubgraphId);
335 
336  // If there's no body, just bail out here
337  if(!body_) return id;
338 
339  // Print the body subgraph and connect it to the method
340  auto ids = printStmtSubgraph(dp, body_);
341  if(ids.second != -1)
342  dp.printConnection(id, ":body:c", ids.first, ids.second);
343  else
344  dp.printConnection(id, ":body:c", ids.first);
345 
346  // Print backedges here
347  for(auto& p : locals_) {
348  if(int d = dp.getId(p)) {
349  if(d != -1) dp.printBackedge(d, id);
350  }
351  }
352  return id;
353 }
354 
355 void MethodDecl::setParent(DeclContext* parent) {
356  // Check that parent is either a ClassDecl or an InterfaceDecl
357  auto decl = cast<Decl*>(parent);
358  assert(dyn_cast<ClassDecl*>(parent) || dyn_cast<InterfaceDecl*>(parent));
359  // Set the parent of the method
360  Decl::setParent(parent);
361  // Build the canonical name
362  canonicalName_ = decl->getCanonicalName();
363  canonicalName_ += ".";
364  canonicalName_ += name();
365  // Propagate the setParent call to the parameters and the body
366  for(auto& parameter : locals_) parameter->setParent(this);
367  // if(body_) body_->setParent(this);
368 }
369 
370 } // namespace ast