tan  0.0.1
organize_packages.cpp
1 #include <iostream>
2 #include "analysis/organize_packages.h"
3 #include "ast/package.h"
4 #include "ast/context.h"
5 #include "ast/stmt.h"
6 #include "ast/decl.h"
7 #include "ast/intrinsic.h"
8 
9 #include <filesystem>
10 namespace fs = std::filesystem;
11 
12 using namespace tanlang;
13 
14 vector<Package *> OrganizePackages::run_impl(vector<Program *> ps) {
15  // reset
16  _package_top_level_ctx.clear();
17  _package_top_level_asts.clear();
18 
19  // visit top-level ASTs and remember top-level ASTs
20  for (auto *p : ps) {
21  visit(p);
22  }
23 
24  vector<Package *> ret{};
25  for (auto [name, asts] : _package_top_level_asts) {
26  auto *package = new Package(name, asts);
27 
28  // merge contexts from multiple Program's to get Package-level context
29  vector<Context *> ctx = _package_top_level_ctx[name];
30  auto *package_ctx = package->ctx();
31  for (Context *c : ctx) {
32  for (auto *d : c->get_decls()) {
33  package_ctx->set_decl(d->get_name(), d);
34  }
35  for (auto *d : c->get_func_decls()) {
36  package_ctx->set_function_decl(d);
37  }
38  }
39 
40  ret.push_back(package);
41  }
42 
43  return ret;
44 }
45 
46 DEFINE_AST_VISITOR_IMPL(OrganizePackages, Program) {
47  // get a list of top-level ASTs
48  vector<ASTBase *> asts{};
49  str package_name;
50  for (auto *n : p->get_children()) {
51  if (n->get_node_type() == ASTNodeType::PACKAGE_DECL) {
52 
53  if (!package_name.empty()) { // repeated declaration
54  Error(ErrorType::SEMANTIC_ERROR, fmt::format("Can only have one package stmt in {}", p->src()->get_filename()))
55  .raise();
56  }
57 
58  package_name = pcast<PackageDecl>(n)->get_name();
59  } else {
60  visit(n);
61  asts.push_back(n);
62  }
63  }
64 
65  if (package_name.empty()) { // default package name
66  package_name = fs::path(p->src()->get_filename()).filename().replace_extension().string();
67 
68  if (package_name.empty()) { // ".tan" is invalid
69  Error(ErrorType::GENERIC_ERROR,
70  fmt::format("Cannot deduce default package name for {}", p->src()->get_filename()))
71  .raise();
72  }
73  }
74 
75  // register ASTs
76  {
77  auto q = _package_top_level_asts.find(package_name);
78  if (q == _package_top_level_asts.end()) {
79  _package_top_level_asts[package_name] = asts;
80  } else {
81  q->second.insert(q->second.end(), asts.begin(), asts.end());
82  }
83  }
84 
85  // register context
86  {
87  auto q = _package_top_level_ctx.find(package_name);
88  if (q == _package_top_level_ctx.end()) {
89  _package_top_level_ctx[package_name] = vector<Context *>{p->ctx()};
90  } else {
91  q->second.push_back(p->ctx());
92  }
93  }
94 }
95 
96 DEFINE_AST_VISITOR_IMPL(OrganizePackages, Intrinsic) {
97  // check children if this is @test_comp_error
98  if (p->get_intrinsic_type() == IntrinsicType::TEST_COMP_ERROR) {
99 
100  try {
101  auto *sub = p->get_sub();
102  if (sub) {
103  TAN_ASSERT(sub->get_node_type() == ASTNodeType::COMPOUND_STATEMENT);
104  for (auto *c : sub->get_children())
105  visit(c);
106  }
107  } catch (const CompileException &e) {
108  std::cerr << fmt::format("Caught expected compile error: {}\nContinue compilation...\n", e.what());
109  p->set_sub(nullptr); // no need to check again in later stages
110  }
111  }
112 }
A generic representation of Intrinsic variables/functions.
Definition: intrinsic.h:55
Organize a list of source files into their corresponding packages according to the code....