MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
dump.cpp
Go to the documentation of this file.
1#include <fstream>
2#include <ostream>
3#include <ranges>
4
5#include <fe/assert.h>
6#include <fe/worklist.h>
7
8#include "mim/driver.h"
9#include "mim/nest.h"
10
11#include "mim/ast/lexer.h"
12#include "mim/ast/tok.h"
13
14using namespace std::literals;
15
16// During dumping, we classify Defs according to the following logic:
17// * Inline: These Defs are *always* displayed with all of its operands "inline".
18// E.g.: (1, 2, 3).
19// * All other Defs are referenced by its name/unique_name (see id) when they appear as an operand.
20// * Mutables are either classifed as "decl" (see isa_decl).
21// In this case, recursing through the Defs' operands stops and this particular Decl is dumped as its own thing.
22// * Or - if they are not a "decl" - they are basicallally handled like immutables.
23
24namespace mim {
25
26namespace {
27
28Def* isa_decl(const Def* def) {
29 if (auto mut = def->isa_mut()) {
30 if (mut->is_external() || mut->isa<Lam>() || (mut->sym() && mut->sym() != '_')) return mut;
31 }
32 return nullptr;
33}
34
35/// Def::unique_name - or the plain Def::sym while a diagnostic is being formatted, where a gid is noise.
36std::string name(const Def* def) {
37 if (auto sym = def->sym(); sym && sym != '_' && PlainNames::claim(def->world().driver(), sym, def->gid()))
38 return sym.str();
39 return def->unique_name();
40}
41
42std::string id(const Def* def) {
43 if (def->is_external() || (!def->is_set() && def->isa<Lam>())) return def->sym().str();
44 return name(def);
45}
46
47std::string_view external(const Def* def) {
48 if (def->is_external()) return "extern "sv;
49 return ""sv;
50}
51
52using ast::Assoc;
53using ast::Prec;
54using ast::prec_assoc;
55
56Prec def2prec(const Def* def) {
57 if (def->isa<Extract>()) return Prec::Extract;
58 if (def->isa<Insert>()) return Prec::Ins;
59 if (def->isa<Join>()) return Prec::Union;
60 if (def->isa<Inj>()) return Prec::Inj;
61 if (def->isa<Reform>()) return Prec::App;
62 if (auto pi = def->isa<Pi>(); pi && !Pi::isa_cn(pi)) return Prec::Arrow;
63 if (auto app = def->isa<App>()) {
64 if (auto size = Idx::isa(app)) {
65 if (auto l = Lit::isa(size)) {
66 // clang-format off
67 switch (*l) {
68 case 0x0'0000'0002_n:
69 case 0x0'0000'0100_n:
70 case 0x0'0001'0000_n:
71 case 0x1'0000'0000_n:
72 case 0_n: return Prec::Lit;
73 default: break;
74 }
75 // clang-format on
76 }
77 }
78 return Prec::App;
79 }
80
81 return Prec::Lit;
82}
83
84/// This is a wrapper to dump a Def.
85class Op {
86public:
87 Op(const Def* def, Prec prec = Prec::Bot, bool is_left = false)
88 : def_(def)
89 , prec_(prec)
90 , is_left_(is_left) {}
91 static Op l(const Def* def, Prec prec = Prec::Bot) { return {def, prec, true}; }
92 static Op r(const Def* def, Prec prec = Prec::Bot) { return {def, prec, false}; }
93
94 static auto map(const auto& range, const char* sep = ", ", Prec prec = Prec::Bot) {
95 return fe::Join(range | std::views::transform([prec](auto op) { return Op(op, prec); }), sep);
96 }
97
98 /// @name Getters
99 ///@{
100 Prec prec() const { return prec_; }
101 bool is_left() const { return is_left_; }
102 const Def* def() const { return def_; }
103 const Def* operator->() const { return def_; }
104 const Def* operator*() const { return def_; }
105 explicit operator bool() const { return def_ != nullptr; }
106 ///@}
107
108private:
109 const Def* def_;
110 Prec prec_;
111 bool is_left_;
112
113 /// This will stream @p def as an operand.
114 /// This is usually `id(def)` unless it can be displayed Inline.
115 friend std::ostream& operator<<(std::ostream&, Op);
116};
117
118/// This is a wrapper to dump a Def "inline" and print it with all of its operands.
119class Dump : public Op {
120public:
121 Dump(const Def* def, Prec prec = Prec::Bot, bool is_left = false)
122 : Op(def, prec, is_left) {}
123 Dump(Op op)
124 : Dump(op.def(), op.prec(), op.is_left()) {}
125
126 explicit operator bool() const { return is_inline(); }
127
128 bool is_inline() const {
129 if (auto mut = def()->isa_mut()) {
130 if (isa_decl(mut)) return false;
131 return true;
132 }
133
134 if (def()->is_closed()) return true;
135
136 if (auto app = def()->isa<App>()) {
137 if (app->type()->isa<Pi>()) return true; // curried apps are printed inline
138 if (app->type()->isa<Type>()) return true;
139 if (app->callee()->isa<Axm>()) return app->callee_type()->num_doms() <= 1;
140 return false;
141 }
142
143 return true;
144 }
145
146 bool needs_parens() const {
147 if (!is_inline()) return false;
148
149 auto child_prec = def2prec(def());
150 if (child_prec < prec()) return true;
151 if (child_prec > prec()) return false;
152
153 switch (prec_assoc(prec())) {
154 case Assoc::R: return is_left();
155 case Assoc::L: return !is_left();
156 case Assoc::N: return false;
157 }
158 fe::unreachable();
159 }
160
161 friend std::ostream& operator<<(std::ostream&, Dump);
162};
163
164} // namespace
165} // namespace mim
166
167#ifndef DOXYGEN // clang-format off
168template<> struct std::formatter<mim::Op > : fe::ostream_formatter {};
169template<> struct std::formatter<mim::Dump> : fe::ostream_formatter {};
170#endif // clang-format on
171
172namespace mim {
173namespace {
174
175std::ostream& ptrn(std::ostream& os, const Def* def, const Def* type) {
176 if (!def) return os << std::format("_: {}", Op(type));
177
178 auto projs = def->tprojs();
179 if (projs.size() == 1 || std::ranges::all_of(projs, [](auto d) { return !d; }))
180 return os << std::format("{}: {}", name(def), Op(type));
181
182 size_t i = 0;
183 os << '(';
184 for (auto sep = ""; auto proj : projs) {
185 os << sep;
186 ptrn(os, proj, type->proj(i++));
187 sep = ", ";
188 }
189 return os << std::format(") as {}", name(def));
190}
191
192std::ostream& bndr(std::ostream& os, const Def* def, const Def* type) {
193 if (def) return ptrn(os, def, type);
194 return os << std::format("_: {}", Op(type));
195}
196
197std::ostream& curry(std::ostream& os, const Def* def, const Def* type, bool implicit, size_t limit, bool alias) {
198 auto l = implicit ? '{' : '(';
199 auto r = implicit ? '}' : ')';
200
201 if (limit == 0) return os << l << r;
202 if (limit == 1) {
203 os << l;
204 bndr(os, def ? def->tproj(0) : nullptr, type->tproj(0));
205 return os << r;
206 }
207
208 os << l;
209 for (auto sep = ""; auto i : std::views::iota(size_t(0), limit)) {
210 os << sep;
211 bndr(os, def ? def->tproj(i) : nullptr, type->tproj(i));
212 sep = ", ";
213 }
214 os << r;
215 if (alias && def) os << std::format(" as {}", name(def));
216 return os;
217}
218
219std::ostream& operator<<(std::ostream& os, Op op) {
220 if (*op == nullptr) return os << "<nullptr>";
221 if (auto d = Dump(op)) return os << d;
222 return os << id(*op);
223}
224
225std::ostream& operator<<(std::ostream& os, Dump d) {
226 if (auto mut = d->isa_mut(); mut && !mut->is_set()) return os << "unset";
227 if (d.needs_parens()) return os << std::format("({})", Dump(*d));
228
229 bool ascii = d->world().flags().ascii;
230 auto arw = ascii ? "->" : "→";
231 auto al = ascii ? "<<" : "«";
232 auto ar = ascii ? ">>" : "»";
233 auto pl = ascii ? "(<" : "‹";
234 auto pr = ascii ? ">)" : "›";
235 auto bot = ascii ? "bot" : "⊥";
236 auto top = ascii ? "top" : "⊤";
237
238 if (auto type = d->isa<Type>()) {
239 if (auto level = Lit::isa(type->level()); level && !ascii) {
240 if (level == 0) return os << "*";
241 if (level == 1) return os << "□";
242 }
243 return os << std::format("Type {}", Op::r(type->level(), Prec::App));
244 } else if (auto reform = d->isa<Reform>()) {
245 return os << std::format("Rule {}", Op::r(reform->dom(), Prec::App));
246 } else if (d->isa<Univ>()) {
247 return os << "Univ";
248 } else if (d->isa<Nat>()) {
249 return os << "Nat";
250 } else if (d->isa<Idx>()) {
251 return os << "Idx";
252 } else if (auto ext = d->isa<Ext>()) {
253 return os << std::format("{}:{}", ext->isa<Bot>() ? bot : top, Op::r(ext->type(), Prec::Lit));
254 } else if (auto axm = d->isa<Axm>()) {
255 return os << axm->sym();
256 } else if (auto lit = d->isa<Lit>()) {
257 if (lit->type()->isa<Nat>()) {
258 // clang-format off
259 switch (lit->get()) {
260 case 0x0'0000'0100_n: return os << "i8";
261 case 0x0'0001'0000_n: return os << "i16";
262 case 0x1'0000'0000_n: return os << "i32";
263 default: return os << std::format("{}", lit->get());
264 }
265 // clang-format on
266 } else if (auto size = Idx::isa(lit->type())) {
267 if (auto s = Lit::isa(size)) {
268 // clang-format off
269 switch (*s) {
270 case 0x0'0000'0002_n: return os << (lit->get<bool>() ? "tt" : "ff");
271 case 0x0'0000'0100_n: return os << lit->get() << "I8";
272 case 0x0'0001'0000_n: return os << lit->get() << "I16";
273 case 0x1'0000'0000_n: return os << lit->get() << "I32";
274 case 0_n: return os << lit->get() << "I64";
275 default: {
276 os << lit->get();
277 std::vector<uint8_t> digits;
278 for (auto z = *s; z; z /= 10) digits.emplace_back(z % 10);
279
280 if (ascii) {
281 os << '_';
282 for (auto d : digits | std::views::reverse)
283 os << char('0' + d);
284 } else {
285 for (auto d : digits | std::views::reverse)
286 os << uint8_t(0xE2) << uint8_t(0x82) << (uint8_t(0x80 + d));
287 }
288 return os;
289 }
290 }
291 // clang-format on
292 }
293 }
294 return os << std::format("{}:{}", lit->get(), Op::r(lit->type(), Prec::Lit));
295 } else if (auto ex = d->isa<Extract>()) {
296 if (ex->tuple()->isa<Var>() && ex->index()->isa<Lit>()) return os << name(ex);
297 return os << std::format("{}#{}", Op::l(ex->tuple(), Prec::Extract), Op::r(ex->index(), Prec::Extract));
298 } else if (auto ins = d->isa<Insert>()) {
299 auto tup = Op::l(ins->tuple(), Prec::Extract);
300 // `←` updates the whole `#`-path, so an Extract target needs parens to re-parse.
301 if (auto ex = ins->tuple()->isa<Extract>(); ex && !(ex->tuple()->isa<Var>() && ex->index()->isa<Lit>()))
302 os << std::format("({})", tup);
303 else
304 os << std::format("{}", tup);
305 return os << std::format("#{} ← {}", Op::r(ins->index(), Prec::Extract), Op::r(ins->value(), Prec::Ins));
306 } else if (auto var = d->isa<Var>()) {
307 return os << name(var);
308 } else if (auto [pi, var] = d->isa_binder<Pi>(); pi) {
309 auto l = pi->is_implicit() ? '{' : '[';
310 auto r = pi->is_implicit() ? '}' : ']';
311 return os << std::format("{}{}: {}{} {} {}", l, Op(var), Op(pi->dom()), r, arw,
312 Op::r(pi->codom(), Prec::Arrow));
313 } else if (auto pi = d->isa<Pi>()) {
314 if (Pi::isa_cn(pi)) return os << std::format("Cn {}", Op(pi->dom()));
315 return os << std::format("{} {} {}", Op::l(pi->dom(), Prec::Arrow), arw, Op::r(pi->codom(), Prec::Arrow));
316 } else if (auto lam = d->isa<Lam>()) {
317 // TODO this output is really confuinsg
318 return os << std::format("{}, {}", Op(lam->filter()), Op(lam->body()));
319 } else if (auto app = d->isa<App>()) {
320 if (auto size = Idx::isa(app)) {
321 if (auto l = Lit::isa(size)) {
322 // clang-format off
323 switch (*l) {
324 case 0x0'0000'0002_n: return os << "Bool";
325 case 0x0'0000'0100_n: return os << "I8";
326 case 0x0'0001'0000_n: return os << "I16";
327 case 0x1'0000'0000_n: return os << "I32";
328 case 0_n: return os << "I64";
329 default: break;
330 }
331 // clang-format on
332 }
333 }
334
335 return os << std::format("{} {}", Op::l(app->callee(), Prec::App), Op::r(app->arg(), Prec::App));
336 } else if (auto [sigma, var] = d->isa_binder<Sigma>(); sigma) {
337 size_t i = 0;
338 auto elem = fe::StreamFn{[&](std::ostream& os) -> std::ostream& {
339 auto sep = "";
340 for (auto op : sigma->ops()) {
341 os << sep;
342 if (auto v = sigma->var(i++))
343 os << std::format("{}: {}", v, Op(op));
344 else
345 os << Op(op);
346 sep = ", ";
347 }
348 return os;
349 }};
350
351 return os << std::format("[{}]", elem);
352 } else if (auto sigma = d->isa<Sigma>()) {
353 return os << std::format("[{}]", Op::map(sigma->ops()));
354 } else if (auto tuple = d->isa<Tuple>()) {
355 return os << std::format("({})", Op::map(tuple->ops()));
356 } else if (auto [arr, var] = d->isa_binder<Arr>(); arr) {
357 return os << std::format("{}{}: {}; {}{}", al, var, Op(arr->arity()), Op(arr->body()), ar);
358 } else if (auto arr = d->isa<Arr>()) {
359 return os << std::format("{}{}; {}{}", al, Op(arr->arity()), Op(arr->body()), ar);
360 } else if (auto [pack, var] = d->isa_binder<Pack>(); pack) {
361 return os << std::format("{}{}: {}; {}{}", pl, pack->var(), Op(pack->arity()), Op(pack->body()), pr);
362 } else if (auto pack = d->isa<Pack>()) {
363 return os << std::format("{}{}; {}{}", pl, Op(pack->arity()), Op(pack->body()), pr);
364 } else if (auto proxy = d->isa<Proxy>()) {
365 return os << std::format("(proxy#{} {})", proxy->tag(), Op::map(proxy->ops()));
366 } else if (auto bound = d->isa<Bound>()) {
367 auto op = bound->isa<Join>() ? "∪" : "∩"; // TODO ascii
368 if (auto mut = d->isa_mut()) std::print(os, "{}{}: {}", op, name(mut), Op(mut->type()));
369 if (!bound->isa<Join>()) return os << std::format("{}({})", op, Op::map(bound->ops()));
370 return os << Op::map(bound->ops(), " ∪ ", Prec::Union);
371 } else if (auto inj = d->isa<Inj>()) {
372 return os << std::format("{} inj {}", Op::l(inj->value(), Prec::Inj), Op::r(inj->type(), Prec::Inj));
373 } else if (auto uniq = d->isa<Uniq>()) {
374 return os << std::format("⦃{}⦄", Op(uniq->op())); // TODO ascii
375 }
376
377 // other
378 auto tag = d->flags() == 0 ? std::string(d->node_name()) : std::format("{}#{}", d->node_name(), d->flags());
379 if (d->ops().empty()) return os << std::format("({})", tag);
380 return os << std::format("({} {})", tag, Op::map(d->ops(), " "));
381}
382
383/*
384 * Dumper
385 */
386
387/// This thing operates in two modes:
388/// 1. The output of decls is driven by the Nest.
389/// 2. Alternatively, decls are output as soon as they appear somewhere during recurse%ing.
390/// Then, they are pushed to Dumper::muts.
391class Dumper {
392public:
393 Dumper(std::ostream& os, const Nest* nest = nullptr)
394 : os(os)
395 , nest(nest) {}
396
397 void dump(Def*);
398 void dump_lam(Lam*);
399 void dump_let(const Def*);
400 void recurse(const Nest::Node*);
401 void recurse(const Def*, bool first = false);
402
403 std::ostream& os;
404 const Nest* nest;
405 fe::Tab tab = fe::Tab::spaces();
406 fe::BFSWorklist<MutSet> muts;
407 DefSet defs;
408};
409
410void Dumper::dump(Def* mut) {
411 if (auto lam = mut->isa<Lam>()) {
412 dump_lam(lam);
413 return;
414 }
415
416 auto mut_prefix = [&](const Def* def) {
417 if (def->isa<Sigma>()) return "Sigma";
418 if (def->isa<Arr>()) return "Arr";
419 if (def->isa<Pack>()) return "pack";
420 if (def->isa<Pi>()) return "Pi";
421 if (def->isa<Hole>()) return "Hole";
422 if (def->isa<Rule>()) return "Rule";
423 fe::unreachable();
424 };
425
426 auto mut_op0 = [&](const Def* def) -> std::ostream& {
427 if (auto sig = def->isa<Sigma>()) return os << std::format(", {}", sig->num_ops());
428 if (auto arr = def->isa<Arr>()) return os << std::format(", {}", arr->arity());
429 if (auto pack = def->isa<Pack>()) return os << std::format(", {}", pack->arity());
430 if (auto pi = def->isa<Pi>()) return os << std::format(", {}", pi->dom());
431 if (auto hole = def->isa_mut<Hole>())
432 return hole->is_set() ? (os << std::format(", {}", hole->op())) : (os << ", ??");
433 if (auto rule = def->isa<Rule>()) return os << std::format("{} => {}", rule->lhs(), rule->rhs());
434 fe::unreachable();
435 };
436
437 if (!mut->is_set()) {
438 std::print(os, "{}{}: {} = {{ <unset> }};", tab, id(mut), mut->type());
439 return;
440 }
441
442 std::print(os, "{}{} {}{}: {}", tab, mut_prefix(mut), external(mut), id(mut), mut->type());
443 mut_op0(mut);
444 if (mut->var()) { // TODO rewrite with dedicated methods
445 if (auto e = mut->num_vars(); e != 1) {
446 for (auto sep = ""; auto def : mut->vars()) {
447 os << sep;
448 if (def)
449 os << def->unique_name();
450 else
451 os << "<TODO>";
452 sep = ", ";
453 }
454 } else {
455 std::print(os, ", @{}", mut->var()->unique_name());
456 }
457 }
458 std::println(os, "{} = {{", tab);
459 ++tab;
460 if (nest) recurse((*nest)[mut]);
461 recurse(mut);
462 std::println(os, "{}{}", tab, fe::Join(mut->ops()));
463 --tab;
464 std::println(os, "{}}};", tab);
465}
466
467void Dumper::dump_lam(Lam* lam) {
468 std::vector<Lam*> currys;
469 for (Lam* curr = lam;;) {
470 currys.emplace_back(curr);
471 if (auto body = curr->body())
472 if (auto next = body->isa_mut<Lam>()) {
473 curr = next;
474 continue;
475 }
476 break;
477 }
478
479 auto last = currys.back();
480 auto is_fun = Lam::isa_returning(last);
481 auto is_con = Lam::isa_cn(last) && !is_fun;
482
483 std::print(os, "{}{}{} {}", tab, external(lam), is_fun ? "fun" : is_con ? "con" : "lam", id(lam));
484 for (auto* c : currys) {
485 os << ' ';
486 auto num_doms = c->var() ? c->var()->num_tprojs() : c->type()->dom()->num_tprojs();
487 auto limit = is_fun && c == last ? num_doms - 1 : num_doms;
488 curry(os, c->var(), c->type()->dom(), c->type()->is_implicit(), limit, !is_fun || c != last);
489 if (is_con && c == last) std::print(os, "@({})", c->filter());
490 }
491
492 if (is_fun)
493 std::print(os, ": {} =", last->ret_dom());
494 else if (!is_con)
495 std::print(os, ": {} =", last->type()->codom());
496 else
497 std::print(os, " =");
498 os << '\n';
499
500 ++tab;
501 if (last->is_set()) {
502 if (nest && currys.size() == 1) recurse((*nest)[lam]);
503 for (auto* curry : currys)
504 recurse(curry->filter());
505 recurse(last->body(), true);
506 if (last->body()->isa_mut())
507 std::println(os, "{}{};", tab, last->body());
508 else
509 std::println(os, "{}{};", tab, Dump(last->body()));
510 } else {
511 std::println(os, "{}<unset>;", tab);
512 }
513 --tab;
514 std::println(os, "{}", tab);
515}
516
517void Dumper::dump_let(const Def* def) {
518 std::println(os, "{}let {}: {} = {};", tab, def->unique_name(), Op(def->type()), Dump(def));
519}
520
521void Dumper::recurse(const Nest::Node* node) {
522 for (auto child : node->children().muts())
523 if (auto mut = isa_decl(child)) dump(mut);
524}
525
526void Dumper::recurse(const Def* def, bool first /*= false*/) {
527 if (auto mut = isa_decl(def)) {
528 if (!nest) muts.push(mut);
529 return;
530 }
531
532 if (!defs.emplace(def).second) return;
533
534 for (auto op : def->deps())
535 recurse(op);
536
537 if (!first && !Dump(def)) dump_let(def);
538}
539
540} // namespace
541
542/*
543 * Def
544 */
545
546/// This will stream @p def as an operand.
547/// This is usually `id(def)` unless it can be displayed Inline.
548std::ostream& operator<<(std::ostream& os, const Def* def) {
549 if (def == nullptr) return os << "<nullptr>";
550 if (auto d = Dump(def)) {
551 auto _ = def->world().freeze();
552 return os << d;
553 }
554 return os << id(def);
555}
556
557std::ostream& Def::stream(std::ostream& os, int max) const {
558 auto _ = world().freeze();
559 auto dumper = Dumper(os);
560
561 if (max == 0) {
562 os << this << std::endl;
563 } else if (auto mut = isa_decl(this)) {
564 dumper.muts.push(mut);
565 } else {
566 dumper.recurse(this);
567 std::println(os, "{}{}", dumper.tab, Dump(this));
568 --max;
569 }
570
571 for (; !dumper.muts.empty() && max > 0; --max)
572 dumper.dump(dumper.muts.pop());
573
574 return os;
575}
576
577void Def::dump() const { std::cout << this << std::endl; }
578void Def::dump(int max) const { stream(std::cout, max) << std::endl; }
579
580void Def::write(int max, const char* file) const {
581 auto ofs = std::ofstream(file);
582 stream(ofs, max);
583}
584
585void Def::write(int max) const {
586 auto file = id(this) + ".mim"s;
587 write(max, file.c_str());
588}
589
590/*
591 * World
592 */
593
594void World::dump(std::ostream& os) {
595 auto _ = freeze();
596 auto old_gid = curr_gid();
597
598 if (flags().dump_recursive) {
599 auto dumper = Dumper(os);
600 for (auto mut : externals().muts())
601 dumper.muts.push(mut);
602 while (!dumper.muts.empty())
603 dumper.dump(dumper.muts.pop());
604 } else {
605 auto nest = Nest(*this);
606 auto dumper = Dumper(os, &nest);
607
608 for (const auto& import : driver().imports()) {
609 auto kw = import.tag == ast::Tok::Tag::K_plugin ? "plugin" : "import";
610 // The spelling was relative to the importing file; only the resolved path re-parses from here.
611 // Generic format: a native Windows `\` would lex as an escape sequence inside the string literal.
612 if (import.path)
613 std::print(os, "{} \"{}\";\n", kw, ast::Lexer::escape(import.src->path().generic_string()));
614 else
615 std::print(os, "{} {};\n", kw, import.sym);
616 }
617 dumper.recurse(nest.root());
618 }
619
620 assertf(old_gid == curr_gid(), "new nodes created during dump. old_gid: {}; curr_gid: {}", old_gid, curr_gid());
621}
622
623void World::dump() { dump(std::cout); }
624
626 if (log().level() >= fe::Log::Level::Debug) dump(log().ostream());
627}
628
629void World::write(const char* file) {
630 auto ofs = std::ofstream(file);
631 dump(ofs);
632}
633
635 auto file = (name() ? name() : sym("_default")).str() + ".mim"s;
636 write(file.c_str());
637}
638
639} // namespace mim
A (possibly paramterized) Array.
Definition tuple.h:110
Definition axm.h:9
Common base for TBound.
Definition lattice.h:13
Base class for all Defs.
Definition def.h:273
void dump() const
Definition dump.cpp:577
World & world() const noexcept
Definition def.h:1097
friend std::ostream & operator<<(std::ostream &, const Def *)
This will stream def as an operand.
Definition dump.cpp:548
void write(int max) const
Definition dump.cpp:585
std::ostream & stream(std::ostream &, int max) const
Definition dump.cpp:557
std::string unique_name() const
name + "_" + Def::gid
Definition def.cpp:616
Common base for TExtremum.
Definition lattice.h:135
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition tuple.h:161
A built-in constant of type Nat -> *.
Definition def.h:974
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
Definition def.cpp:645
Constructs a Join value.
Definition lattice.h:67
Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
Definition tuple.h:186
A function.
Definition lam.h:113
static std::optional< T > isa(const Def *def)
Definition def.h:937
Nest(Def *root)
Definition nest.cpp:9
A (possibly paramterized) Tuple.
Definition tuple.h:137
A dependent function type.
Definition lam.h:14
static const Pi * isa_cn(const Def *d)
Definition lam.h:46
static bool claim(const Driver &, Sym sym, uint32_t gid)
Registers that gid renders as sym and reports whether the plain sym may be used.
Definition driver.cpp:208
Used as intermediate value during optimizatinos such as Analysis.
Definition def.h:1032
Type formation of a rewrite Rule.
Definition rule.h:9
A dependent tuple type.
Definition tuple.h:23
Data constructor for a Sigma.
Definition tuple.h:61
A singleton wraps a type into a higher order type.
Definition lattice.h:173
A variable introduced by a binder (mutable).
Definition def.h:825
auto & muts()
Definition world.h:695
Driver & driver()
Definition world.h:103
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
Definition world.h:114
Sym name() const
Definition world.h:109
const fe::Log & log() const
Log via log().e("...", args) etc.; owned by the Driver.
Definition world.cpp:129
void dump()
Dump to std::cout.
Definition dump.cpp:623
void write()
Same above but file name defaults to World::name.
Definition dump.cpp:634
Flags & flags()
Retrieve compile Flags.
Definition world.cpp:130
void debug_dump()
Dump in Debug build if World::log::level is fe::Log::Level::Debug.
Definition dump.cpp:625
Sym sym(std::string_view)
Definition world.cpp:133
void write(const char *file)
Write to a file named file.
Definition dump.cpp:629
const Externals & externals() const
Definition world.h:278
auto freeze() const
Freezes the World until the end of the scope and restores the previous frozen state afterwards:
Definition world.h:154
void dump(std::ostream &os)
Dump to os.
Definition dump.cpp:594
static std::string escape(std::string_view str)
Inverse of Lexer::lex_char: renders str as the body of a Mim string literal.
Definition lexer.cpp:199
Assoc
Associativity of an infix expression.
Definition tok.h:47
constexpr Assoc prec_assoc(Prec p)
Associativity of precedence level p.
Definition tok.h:57
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
Definition tok.h:50
@ bot
Alias for Mode::fast.
Definition math.h:38
Definition ast.h:16
TBound< true > Join
AKA union.
Definition lattice.h:167
GIDSet< const Def * > DefSet
Definition def.h:89
std::ostream & operator<<(std::ostream &os, const Def *def)
This will stream def as an operand.
Definition dump.cpp:548
TExt< false > Bot
Definition lattice.h:164
constexpr Assoc prec_assoc(Prec p)
Associativity of precedence level p.
Definition tok.h:57
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
Definition tok.h:50