MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
ast.cpp
Go to the documentation of this file.
1#include "mim/ast/ast.h"
2
3#include "mim/ast/parser.h"
4
5using namespace std::literals;
6
7namespace mim::ast {
8
10 assert(error().num_errors() == 0 && error().num_warnings() == 0
11 && "please encounter any errors before destroying this class");
12}
13
15 if (!dbg || dbg.sym()[0] != '%') return nullptr;
16
17 auto [plugin_s, tag_s, sub_s] = Annex::split(driver(), dbg.sym());
18 auto plugin_tag = driver().sym("%"s + plugin_s.str() + "."s + tag_s.str());
19 auto& sym2annex = plugin2sym2annex_[plugin_s];
20 auto tag_id = sym2annex.size();
21
22 if (plugin_s == sym_error()) error(dbg.loc(), "plugin name '{}' is reserved", dbg);
23 if (tag_id > std::numeric_limits<tag_t>::max())
24 error(dbg.loc(), "exceeded maxinum number of annexes in current plugin");
25
26 plugin_t plugin_id;
27 if (auto p = Annex::mangle(plugin_s))
28 plugin_id = *p;
29 else {
30 error(dbg.loc(), "invalid annex name '{}'", dbg);
31 plugin_s = sym_error();
32 plugin_id = *Annex::mangle(plugin_s);
33 }
34
35 auto [i, fresh] = sym2annex.emplace(plugin_tag, AnnexInfo{plugin_s, tag_s, plugin_id, (tag_t)sym2annex.size()});
36 auto annex = &i->second;
37
38 if (sub_s) {
39 if (sub_id) {
40 *sub_id = annex->subs.size();
41 auto& aliases = annex->subs.emplace_back();
42 aliases.emplace_back(sub_s);
43 } else {
44 error(dbg.loc(), "annex '{}' must not have a subtag", dbg);
45 }
46 }
47
48 if (!fresh) annex->fresh = false;
49 return annex;
50}
51
52void AST::bootstrap(Sym plugin, std::ostream& h) {
53 Tab tab;
54 tab.print(h, "#pragma once\n\n");
55 tab.print(h, "#include <mim/axiom.h>\n"
56 "#include <mim/plugin.h>\n\n");
57
58 tab.print(h, "/// @namespace mim::plug::{} @ref {} \n", plugin, plugin);
59 tab.print(h, "namespace mim {{\n");
60 tab.print(h, "namespace plug::{} {{\n\n", plugin);
61
62 plugin_t plugin_id = *Annex::mangle(plugin);
63 std::vector<std::ostringstream> normalizers, outer_namespace;
64
65 tab.print(h, "static constexpr plugin_t Plugin_Id = 0x{x};\n\n", plugin_id);
66
67 const auto& unordered = plugin2annexes(plugin);
68 std::deque<std::pair<Sym, AnnexInfo>> infos(unordered.begin(), unordered.end());
69 std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.id.tag < p2.second.id.tag; });
70
71 // clang-format off
72 for (const auto& [key, annex] : infos) {
73 const auto& sym = annex.sym;
74 if (sym.plugin != plugin) continue; // this is from an import
75
76 tab.print(h, "/// @name %%{}.{}\n///@{{\n", plugin, sym.tag);
77 tab.print(h, "#ifdef DOXYGEN // see https://github.com/doxygen/doxygen/issues/9668\n");
78 tab.print(h, "enum {} : flags_t {{\n", sym.tag);
79 tab.print(h, "#else\n");
80 tab.print(h, "enum class {} : flags_t {{\n", sym.tag);
81 tab.print(h, "#endif\n");
82 ++tab;
83 flags_t ax_id = plugin_id | (annex.id.tag << 8u);
84
85 auto& os = outer_namespace.emplace_back();
86 print(os, "template<> constexpr flags_t Annex::Base<plug::{}::{}> = 0x{x};\n", plugin, sym.tag, ax_id);
87
88 if (auto& subs = annex.subs; !subs.empty()) {
89 for (const auto& aliases : subs) {
90 const auto& sub = aliases.front();
91 tab.print(h, "{} = 0x{x},\n", sub, ax_id++);
92 for (size_t i = 1; i < aliases.size(); ++i) tab.print(h, "{} = {},\n", aliases[i], sub);
93
94 if (auto norm = annex.normalizer) {
95 auto& os = normalizers.emplace_back();
96 print(os, "normalizers[flags_t({}::{})] = &{}<{}::{}>;", sym.tag, sub, norm, sym.tag, sub);
97 }
98 }
99 } else {
100 if (auto norm = annex.normalizer)
101 print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", sym.tag, norm);
102 }
103 --tab;
104 tab.print(h, "}};\n\n");
105
106 if (!annex.subs.empty()) tab.print(h, "MIM_ENUM_OPERATORS({})\n", sym.tag);
107 print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num<plug::{}::{}> = {};\n", plugin, sym.tag, annex.subs.size());
108
109 if (auto norm = annex.normalizer) {
110 if (auto& subs = annex.subs; !subs.empty()) {
111 tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", sym.tag, norm);
112 } else {
113 tab.print(h, "Ref {}(Ref, Ref, Ref);\n", norm);
114 }
115 }
116 tab.print(h, "///@}}\n\n");
117 }
118 // clang-format on
119
120 if (!normalizers.empty()) {
121 tab.print(h, "void register_normalizers(Normalizers& normalizers);\n\n");
122 tab.print(h, "#define MIM_{}_NORMALIZER_IMPL \\\n", plugin);
123 ++tab;
124 tab.print(h, "void register_normalizers(Normalizers& normalizers) {{\\\n");
125 ++tab;
126 for (const auto& normalizer : normalizers) tab.print(h, "{} \\\n", normalizer.str());
127 --tab;
128 tab.print(h, "}}\n");
129 --tab;
130 }
131
132 tab.print(h, "}} // namespace plug::{}\n\n", plugin);
133
134 tab.print(h, "#ifndef DOXYGEN // don't include in Doxygen documentation\n");
135 for (const auto& line : outer_namespace) tab.print(h, "{}", line.str());
136 tab.print(h, "\n");
137
138 // emit helpers for non-function axiom
139 for (const auto& [tag, ax] : infos) {
140 const auto& sym = ax.sym;
141 if (ax.is_pi() || sym.plugin != plugin) continue; // from function or other plugin?
142 tab.print(h, "template<> struct Axiom::Match<plug::{}::{}> {{ using type = Axiom; }};\n", sym.plugin, sym.tag);
143 }
144
145 tab.print(h, "#endif\n");
146 tab.print(h, "}} // namespace mim\n");
147}
148
149/*
150 * Other
151 */
152
154 : Expr(lam->loc())
155 , lam_(std::move(lam)) {}
156
157/*
158 * Ptrn::to_expr/to_ptrn
159 */
160
162 if (auto idp = ptrn->isa<IdPtrn>(); idp && !idp->dbg() && idp->type()) {
163 if (auto ide = idp->type()->isa<IdExpr>()) return ast.ptr<IdExpr>(ide->dbg());
164 } else if (auto tuple = ptrn->isa<TuplePtrn>(); tuple && tuple->is_brckt()) {
165 (void)ptrn.release();
166 return ast.ptr<SigmaExpr>(Ptr<TuplePtrn>(tuple));
167 }
168 return {};
169}
170
172 if (auto sigma = expr->isa<SigmaExpr>())
173 return std::move(const_cast<SigmaExpr*>(sigma)->ptrn_); // TODO get rid off const_cast
174 return {};
175}
176
177void Module::compile(AST& ast) const {
178 bind(ast);
179 ast.error().ack();
180 emit(ast);
181 if (ast.error().num_warnings() != 0) std::cerr << ast.error();
182}
183
184AST load_plugins(World& world, View<Sym> plugins) {
185 auto tag = Tok::Tag::K_import;
186 if (!world.driver().flags().bootstrap) {
187 for (auto plugin : plugins) world.driver().load(plugin);
188 tag = Tok::Tag::K_plugin;
189 }
190
191 auto ast = AST(world);
192 auto parser = Parser(ast);
193 auto imports = Ptrs<Import>();
194
195 for (auto plugin : plugins)
196 if (auto mod = parser.import(plugin, nullptr))
197 imports.emplace_back(ast.ptr<Import>(mod->loc(), tag, Dbg(plugin), std::move(mod)));
198
199 if (!plugins.empty()) {
200 auto mod = ast.ptr<Module>(imports.front()->loc() + imports.back()->loc(), std::move(imports), Ptrs<ValDecl>());
201 mod->compile(ast);
202 }
203
204 return ast;
205}
206
207} // namespace mim::ast
void load(Sym name)
Definition driver.cpp:53
Flags & flags()
Definition driver.h:23
size_t num_warnings() const
Definition dbg.h:59
void ack(std::ostream &os=std::cerr)
If errors occured, claim them and throw; if warnings occured, claim them and report to os.
Definition dbg.cpp:15
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:28
Keeps track of indentation level.
Definition print.h:195
std::ostream & print(std::ostream &os, const char *s, Args &&... args)
Definition print.h:211
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:33
const Driver & driver() const
Definition world.h:81
Driver & driver()
Definition ast.h:61
auto ptr(Args &&... args)
Definition ast.h:76
AnnexInfo * name2annex(Dbg dbg, sub_t *)
Definition ast.cpp:14
const auto & plugin2annexes(Sym plugin)
Definition ast.h:92
void bootstrap(Sym plugin, std::ostream &h)
Definition ast.cpp:52
Error & error()
Definition ast.h:62
Sym sym(const char *s)
Definition ast.h:68
Sym sym_error()
"_error_".
Definition ast.h:73
dbg: type
Definition ast.h:205
LamExpr(Ptr< LamDecl > &&lam)
Definition ast.cpp:153
void emit(AST &) const
Definition emit.cpp:35
void bind(AST &) const
Definition bind.cpp:77
void compile(AST &) const
Definition ast.cpp:177
Parses Mim code as AST.
Definition parser.h:30
static Ptr< Ptrn > to_ptrn(Ptr< Expr > &&)
Definition ast.cpp:171
static Ptr< Expr > to_expr(AST &, Ptr< Ptrn > &&)
Definition ast.cpp:161
Dbg dbg() const
Definition ast.h:178
Just wraps TuplePtrn as Expr.
Definition ast.h:570
dbg::(ptrn_0, ..., ptrn_n-1) or dbg::[ptrn_0, ..., ptrn_n-1]
Definition ast.h:248
bool is_brckt() const
Definition ast.h:258
Definition ast.h:13
fe::Arena::Ptr< const T > Ptr
Definition ast.h:20
AST load_plugins(World &, View< Sym >)
Definition ast.cpp:184
std::deque< Ptr< T > > Ptrs
Definition ast.h:21
u8 sub_t
Definition types.h:48
std::ostream & print(std::ostream &os, const char *s)
Base case.
Definition print.cpp:5
u64 flags_t
Definition types.h:45
bool bootstrap
Definition flags.h:17
u64 plugin_t
Definition types.h:46
u8 tag_t
Definition types.h:47
Definition span.h:104
static std::tuple< Sym, Sym, Sym > split(Driver &, Sym)
Definition plugin.cpp:58
static std::optional< plugin_t > mangle(Sym plugin)
Mangles s into a dense 48-bit representation.
Definition plugin.cpp:9