MimIR
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
9// Node map: Parser::import holds the slot across the nested parses that may insert further entries.
10struct AST::Files : absl::node_hash_map<const fe::Src*, Ptr<File>> {};
11
13 : world_(&world)
14 , files_(std::make_unique<Files>()) {}
15
16AST::AST(AST&& other)
17 : AST(other.world()) {
18 swap(*this, other);
19}
20
21AST::~AST() = default;
22
23std::pair<Ptr<File>&, bool> AST::file(const fe::Src* src) {
24 auto [i, fresh] = files_->try_emplace(src);
25 return {i->second, fresh};
26}
27
28void AST::bootstrap(Sym plugin, std::ostream& h) {
29 auto tab = fe::Tab::spaces();
30 std::println(h, "{}#pragma once\n", tab);
31 std::println(h, "{}#include <mim/axm.h>", tab);
32 std::println(h, "#include <mim/plugin.h>\n", tab);
33 std::println(h, "{}/// @namespace mim::plug::{} @ref {}", tab, plugin, plugin);
34 std::println(h, "{}namespace mim {{", tab);
35 std::println(h, "{}namespace plug::{} {{\n", tab, plugin);
36
37 plugin_t plugin_id = *Annex::mangle(plugin);
38 std::vector<std::ostringstream> normalizers, outer_namespace;
39
40 std::println(h, "{}static constexpr plugin_t Plugin_Id = 0x{:x};\n", tab, plugin_id);
41
42 const auto& unordered = plugin2annexes(plugin);
43 std::deque<std::pair<Sym, AnnexInfo>> infos(unordered.begin(), unordered.end());
44 std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.id.tag < p2.second.id.tag; });
45
46 // clang-format off
47 for (const auto& [key, annex] : infos) {
48 const auto& sym = annex.sym;
49 if (sym.plugin != plugin) continue; // this is from an import
50
51 std::println(h, "{}/// @name %%{}.{}\n///@{{", tab, plugin, sym.tag);
52 std::println(h, "{}enum class {} : flags_t {{", tab, sym.tag);
53 ++tab;
54 flags_t ax_id = annex.base();
55
56 auto& os = outer_namespace.emplace_back();
57 std::print(os, "template<> constexpr flags_t Annex::Base<plug::{}::{}> = 0x{:x};\n", plugin, sym.tag, ax_id);
58
59 if (auto& subs = annex.subs; !subs.empty()) {
60 for (const auto& aliases : subs) {
61 auto id = ax_id++;
62 for (const auto alias : aliases)
63 std::println(h, "{}{} = 0x{:x},", tab, alias, id);
64
65 if (auto norm = annex.normalizer) {
66 auto sub = aliases.front();
67 auto& os = normalizers.emplace_back();
68 std::print(os, "normalizers[flags_t({}::{})] = &{}<{}::{}>;", sym.tag, sub, norm, sym.tag, sub);
69 }
70 }
71 } else {
72 if (auto norm = annex.normalizer)
73 std::print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", sym.tag, norm);
74 }
75 --tab;
76 std::println(h, "{}}};\n", tab);
77
78 std::println(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num<plug::{}::{}> = {};", plugin, sym.tag, annex.subs.size());
79
80 if (auto norm = annex.normalizer) {
81 if (auto& subs = annex.subs; !subs.empty()) {
82 std::println(h, "{}template<{}>\nconst Def* {}(const Def*, const Def*, const Def*);\n", tab, sym.tag,
83 norm);
84 } else {
85 std::println(h, "{}const Def* {}(const Def*, const Def*, const Def*);", tab, norm);
86 }
87 }
88 std::println(h, "{}///@}}\n", tab);
89 }
90 // clang-format on
91
92 if (!normalizers.empty()) {
93 std::println(h, "{}void register_normalizers(Normalizers& normalizers);\n", tab);
94 std::println(h, "{}#define MIM_{}_NORMALIZER_IMPL \\", tab, plugin);
95 ++tab;
96 std::println(h, "{}void register_normalizers(Normalizers& normalizers) {{\\", tab);
97 ++tab;
98 for (const auto& normalizer : normalizers)
99 std::println(h, "{}{} \\", tab, normalizer.str());
100 --tab;
101 std::println(h, "{}}}", tab);
102 --tab;
103 }
104
105 std::println(h, "{}}} // namespace plug::{}\n", tab, plugin);
106
107 std::println(h, "{}#ifndef DOXYGEN // don't include in Doxygen documentation\n", tab);
108 for (const auto& line : outer_namespace)
109 std::print(h, "{}{}", tab, line.str());
110 std::println(h, "{}", tab);
111
112 // emit helpers for non-function axm
113 for (const auto& [tag, ax] : infos) {
114 auto sym = ax.sym;
115 if ((ax.pi && *ax.pi) || sym.plugin != plugin) continue; // from function or other plugin?
116 std::println(h, "{}template<> struct Axm::IsANode<plug::{}::{}> {{ using type = Axm; }};", tab, sym.plugin,
117 sym.tag);
118 }
119
120 std::println(h, "{}\n#endif", tab);
121 std::println(h, "{}}} // namespace mim\n", tab);
122
123 std::println(h, "{}#ifndef DOXYGEN // don't include in Doxygen documentation\n", tab);
124 for (const auto& [key, annex] : infos) {
125 if (!annex.subs.empty()) {
126 auto sym = annex.sym;
127 std::println(h, "{}template<> struct fe::is_bit_enum<mim::plug::{}::{}> : std::true_type {{}};", tab,
128 sym.plugin, sym.tag);
129 }
130 }
131
132 std::println(h, "{}\n#endif", tab);
133}
134
135void AST::bootstrap_py(Sym plugin, std::ostream& h) {
136 fe::Tab tab;
137 plugin_t plugin_id = *Annex::mangle(plugin);
138
139 std::print(h, "from enum import IntEnum\n\n");
140 std::println(h, "class {}(IntEnum):", plugin);
141 ++tab;
142 std::println(h, "{}ID = 0x{:x}", tab, plugin_id);
143 std::vector<mim::ast::AnnexInfo> annexes_with_subs;
144
145 const auto& unordered = plugin2annexes(plugin);
146 std::deque<std::pair<Sym, AnnexInfo>> infos(unordered.begin(), unordered.end());
147 std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.id.tag < p2.second.id.tag; });
148 for (const auto& [key, annex] : infos) {
149 const auto& sym = annex.sym;
150 if (sym.plugin != plugin) continue;
151
152 flags_t ax_id = annex.base();
153
154 if (auto& subs = annex.subs; subs.empty())
155 std::println(h, "{}{} = 0x{:x}", tab, sym.tag, ax_id);
156 else
157 annexes_with_subs.push_back(annex);
158 }
159 std::print(h, "\n");
160
161 if (!annexes_with_subs.empty()) {
162 for (const auto& annex : annexes_with_subs) {
163 flags_t ax_id = annex.base();
164 std::println(h, "class _{}_{}(IntEnum):", plugin, annex.sym.tag);
165 ++tab;
166
167 for (const auto& aliases : annex.subs) {
168 auto id = ax_id++;
169 for (const auto alias : aliases)
170 std::println(h, "{}{} = 0x{:x}", tab, alias, id);
171 }
172
173 --tab;
174 std::println(h, "\n{}.{} = _{}_{}\n", plugin, annex.sym.tag, plugin, annex.sym.tag);
175 }
176 }
177}
178
179/*
180 * Other
181 */
182
184 : Expr(lam->loc())
185 , lam_(lam) {}
186
187/*
188 * Ptrn::to_expr
189 */
190
192 if (auto idp = ptrn->isa<IdPtrn>(); idp && !idp->dbg() && idp->type()) {
193 if (auto pe = idp->type()->isa<PathExpr>())
194 return ast.ptr<PathExpr>(ast.ptr<Path>(pe->path()->loc(), pe->path()->dbgs()));
195 } else if (auto tuple = ptrn->isa<TuplePtrn>(); tuple && tuple->is_brckt()) {
196 return ast.ptr<SigmaExpr>(Ptr<TuplePtrn>(tuple));
197 }
198 return {};
199}
200
201void File::compile(AST& ast) const {
202 bind(ast);
203 ast.error().ack();
204 emit(ast);
205 ast.error().report();
206}
207
208AST load_plugins(World& world, fe::View<std::string> plugins) {
209 auto tag = world.driver().flags().bootstrap ? Tok::Tag::K_import : Tok::Tag::K_plugin;
210 auto ast = AST(world);
211 auto parser = Parser(ast);
212
213 if (!plugins.empty()) {
214 auto imports = parser.import_plugins(plugins, tag);
215 auto decls = Ptrs<ValDecl>();
216 for (auto import : imports)
217 decls.emplace_back(import);
218
219 // No Loc: this File spans no source, and hulling the imports would mix Loc%s of different files.
220 auto file = ast.ptr<File>(Loc(), ast.scope(), ast.copy(decls));
221 file->compile(ast);
222 }
223
224 return ast;
225}
226
227} // namespace mim::ast
Flags & flags()
Definition driver.h:76
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:40
Driver & driver()
Definition world.h:103
Owns the arena all AST nodes live in as well as the AnnexInfos of all plugins.
Definition ast.h:99
friend void swap(AST &a1, AST &a2) noexcept
Definition ast.h:162
void bootstrap_py(Sym plugin, std::ostream &h)
Definition ast.cpp:135
World & world() const
Definition ast.h:108
const auto & plugin2annexes(Sym plugin)
Definition ast.h:153
void bootstrap(Sym plugin, std::ostream &h)
Definition ast.cpp:28
Sym sym(const char *s)
Definition ast.h:115
AST(const AST &)=delete
std::pair< Ptr< File > &, bool > file(const fe::Src *src)
Definition ast.cpp:23
Expr(Loc loc)
Definition ast.h:209
The AST of one source file: an anonymous ModDecl that a UseDecl binds under a name of its own.
Definition ast.h:1204
void compile(AST &) const
Definition ast.cpp:201
void bind(AST &) const
Definition bind.cpp:140
void emit(AST &) const
Definition emit.cpp:43
dbg: type
Definition ast.h:311
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
Definition ast.h:318
const LamDecl * lam() const
Definition ast.h:741
LamExpr(Ptr< LamDecl > lam)
Definition ast.cpp:183
Loc loc() const
Definition ast.h:197
Parser(AST &ast)
Definition parser.h:34
dbg_0.....dbg_n-1.
Definition ast.h:450
static Ptr< Expr > to_expr(AST &, Ptr< Ptrn >)
Definition ast.cpp:191
Wraps a TuplePtrn as Expr.
Definition ast.h:804
(ptrn_0, ..., ptrn_n-1), [ptrn_0, ..., ptrn_n-1], or {ptrn_0, ..., ptrn_n-1}
Definition ast.h:390
bool is_brckt() const
Definition ast.h:401
Definition ast.h:16
AST load_plugins(World &, fe::View< std::string >)
Definition ast.cpp:208
fe::Arena::Ref< const T > Ptr
Nodes live in the AST's Arena and are never destroyed, so this merely points at one.
Definition ast.h:26
fe::Vector< Ptr< T > > Ptrs
Definition ast.h:33
u64 flags_t
Definition types.h:39
u64 plugin_t
Definition types.h:40
static std::optional< plugin_t > mangle(std::string_view plugin)
Mangles s into a dense 48-bit representation.
Definition plugin.cpp:5
bool bootstrap
Definition flags.h:25