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, "enum class {} : flags_t {{\n", sym.tag);
78 ++tab;
79 flags_t ax_id = plugin_id | (annex.id.tag << 8u);
80
81 auto& os = outer_namespace.emplace_back();
82 print(os, "template<> constexpr flags_t Annex::Base<plug::{}::{}> = 0x{x};\n", plugin, sym.tag, ax_id);
83
84 if (auto& subs = annex.subs; !subs.empty()) {
85 for (const auto& aliases : subs) {
86 const auto& sub = aliases.front();
87 tab.print(h, "{} = 0x{x},\n", sub, ax_id++);
88 for (size_t i = 1; i < aliases.size(); ++i) tab.print(h, "{} = {},\n", aliases[i], sub);
89
90 if (auto norm = annex.normalizer) {
91 auto& os = normalizers.emplace_back();
92 print(os, "normalizers[flags_t({}::{})] = &{}<{}::{}>;", sym.tag, sub, norm, sym.tag, sub);
93 }
94 }
95 } else {
96 if (auto norm = annex.normalizer)
97 print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", sym.tag, norm);
98 }
99 --tab;
100 tab.print(h, "}};\n\n");
101
102 print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num<plug::{}::{}> = {};\n", plugin, sym.tag, annex.subs.size());
103
104 if (auto norm = annex.normalizer) {
105 if (auto& subs = annex.subs; !subs.empty()) {
106 tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", sym.tag, norm);
107 } else {
108 tab.print(h, "Ref {}(Ref, Ref, Ref);\n", norm);
109 }
110 }
111 tab.print(h, "///@}}\n\n");
112 }
113 // clang-format on
114
115 if (!normalizers.empty()) {
116 tab.print(h, "void register_normalizers(Normalizers& normalizers);\n\n");
117 tab.print(h, "#define MIM_{}_NORMALIZER_IMPL \\\n", plugin);
118 ++tab;
119 tab.print(h, "void register_normalizers(Normalizers& normalizers) {{\\\n");
120 ++tab;
121 for (const auto& normalizer : normalizers) tab.print(h, "{} \\\n", normalizer.str());
122 --tab;
123 tab.print(h, "}}\n");
124 --tab;
125 }
126
127 tab.print(h, "}} // namespace plug::{}\n\n", plugin);
128
129 tab.print(h, "#ifndef DOXYGEN // don't include in Doxygen documentation\n\n");
130 for (const auto& line : outer_namespace) tab.print(h, "{}", line.str());
131 tab.print(h, "\n");
132
133 // emit helpers for non-function axiom
134 for (const auto& [tag, ax] : infos) {
135 auto sym = ax.sym;
136 if (ax.is_pi() || sym.plugin != plugin) continue; // from function or other plugin?
137 tab.print(h, "template<> struct Axiom::Match<plug::{}::{}> {{ using type = Axiom; }};\n", sym.plugin, sym.tag);
138 }
139
140 tab.print(h, "\n#endif\n");
141 tab.print(h, "}} // namespace mim\n\n");
142
143 tab.print(h, "#ifndef DOXYGEN // don't include in Doxygen documentation\n\n");
144 for (const auto& [key, annex] : infos) {
145 if (!annex.subs.empty()) {
146 auto sym = annex.sym;
147 tab.print(h, "template<> struct fe::is_bit_enum<mim::plug::{}::{}> : std::true_type {{}};\n", sym.plugin,
148 sym.tag);
149 }
150 }
151
152 tab.print(h, "\n#endif\n");
153}
154
155/*
156 * Other
157 */
158
160 : Expr(lam->loc())
161 , lam_(std::move(lam)) {}
162
163/*
164 * Ptrn::to_expr/to_ptrn
165 */
166
168 if (auto idp = ptrn->isa<IdPtrn>(); idp && !idp->dbg() && idp->type()) {
169 if (auto ide = idp->type()->isa<IdExpr>()) return ast.ptr<IdExpr>(ide->dbg());
170 } else if (auto tuple = ptrn->isa<TuplePtrn>(); tuple && tuple->is_brckt()) {
171 (void)ptrn.release();
172 return ast.ptr<SigmaExpr>(Ptr<TuplePtrn>(tuple));
173 }
174 return {};
175}
176
178 if (auto sigma = expr->isa<SigmaExpr>())
179 return std::move(const_cast<SigmaExpr*>(sigma)->ptrn_); // TODO get rid off const_cast
180 return {};
181}
182
183void Module::compile(AST& ast) const {
184 bind(ast);
185 ast.error().ack();
186 emit(ast);
187 if (ast.error().num_warnings() != 0) std::cerr << ast.error();
188}
189
190AST load_plugins(World& world, View<Sym> plugins) {
191 auto tag = Tok::Tag::K_import;
192 if (!world.driver().flags().bootstrap) {
193 for (auto plugin : plugins) world.driver().load(plugin);
194 tag = Tok::Tag::K_plugin;
195 }
196
197 auto ast = AST(world);
198 auto parser = Parser(ast);
199 auto imports = Ptrs<Import>();
200
201 for (auto plugin : plugins)
202 if (auto mod = parser.import(plugin, nullptr))
203 imports.emplace_back(ast.ptr<Import>(mod->loc(), tag, Dbg(plugin), std::move(mod)));
204
205 if (!plugins.empty()) {
206 auto mod = ast.ptr<Module>(imports.front()->loc() + imports.back()->loc(), std::move(imports), Ptrs<ValDecl>());
207 mod->compile(ast);
208 }
209
210 return ast;
211}
212
213} // 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:62
auto ptr(Args &&... args)
Definition ast.h:77
AnnexInfo * name2annex(Dbg dbg, sub_t *)
Definition ast.cpp:14
const auto & plugin2annexes(Sym plugin)
Definition ast.h:93
void bootstrap(Sym plugin, std::ostream &h)
Definition ast.cpp:52
Error & error()
Definition ast.h:63
Sym sym(const char *s)
Definition ast.h:69
Sym sym_error()
"_error_".
Definition ast.h:74
dbg: type
Definition ast.h:206
LamExpr(Ptr< LamDecl > &&lam)
Definition ast.cpp:159
void emit(AST &) const
Definition emit.cpp:35
void bind(AST &) const
Definition bind.cpp:77
void compile(AST &) const
Definition ast.cpp:183
Parses Mim code as AST.
Definition parser.h:30
static Ptr< Ptrn > to_ptrn(Ptr< Expr > &&)
Definition ast.cpp:177
static Ptr< Expr > to_expr(AST &, Ptr< Ptrn > &&)
Definition ast.cpp:167
Dbg dbg() const
Definition ast.h:179
Just wraps TuplePtrn as Expr.
Definition ast.h:574
dbg::(ptrn_0, ..., ptrn_n-1) or dbg::[ptrn_0, ..., ptrn_n-1]
Definition ast.h:249
bool is_brckt() const
Definition ast.h:259
Definition ast.h:14
fe::Arena::Ptr< const T > Ptr
Definition ast.h:21
AST load_plugins(World &, View< Sym >)
Definition ast.cpp:190
std::deque< Ptr< T > > Ptrs
Definition ast.h:22
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