11using namespace std::literals;
25Def* isa_decl(
const Def* def) {
26 if (
auto mut = def->isa_mut()) {
27 if (mut->is_external() || mut->isa<
Lam>() || (mut->sym() && mut->sym() !=
'_'))
return mut;
32std::string
id(
const Def* def) {
33 if (def->is_external() || (!def->is_set() && def->isa<
Lam>()))
return def->sym().str();
34 return def->unique_name();
37std::string_view external(
const Def* def) {
38 if (def->is_external())
return "extern "sv;
48 Inline(
const Def* def,
int dump_gid)
50 , dump_gid_(dump_gid) {}
51 Inline(
const Def* def)
52 : Inline(def, def->world().flags().dump_gid) {}
54 const Def* operator->()
const {
return def_; }
55 const Def* operator*()
const {
return def_; }
56 explicit operator bool()
const {
57 if (
auto mut = def_->isa_mut()) {
58 if (isa_decl(mut))
return false;
62 if (def_->is_closed())
return true;
64 if (
auto app = def_->isa<
App>()) {
65 if (app->type()->isa<
Pi>())
return true;
66 if (app->type()->isa<
Type>())
return true;
67 if (app->callee()->isa<
Axm>())
return app->callee_type()->num_doms() <= 1;
78 friend std::ostream&
operator<<(std::ostream&, Inline);
85bool is_atomic_app(
const Def* def) {
86 if (
auto app = def->isa<
App>()) {
95 case 0_n:
return true;
106 if (def->isa<
Extract>())
return Prec::Extract;
107 if (
auto pi = def->isa<
Pi>(); pi && !
Pi::isa_cn(pi))
return Prec::Arrow;
108 if (def->isa<
App>() && !is_atomic_app(def))
return Prec::App;
112bool needs_parens(
Prec parent,
const Def* child,
bool is_left) {
113 if (!Inline(child))
return false;
115 auto child_prec = def2prec(child);
116 if (child_prec < parent)
return true;
117 if (child_prec > parent)
return false;
120 case Assoc::R:
return is_left;
121 case Assoc::L:
return !is_left;
122 case Assoc::N:
return false;
127std::ostream& dump_child(std::ostream& os,
Prec parent,
const Def* child,
bool is_left) {
128 if (needs_parens(parent, child, is_left))
return print(os,
"({})", child);
129 return print(os,
"{}", child);
132std::ostream& dump_ascribed(std::ostream& os,
const auto& value,
const Def* type) {
134 if (def2prec(type) == Prec::Lit)
return print(os,
"{}", type);
135 return print(os,
"({})", type);
138std::ostream& dump_pi_dom(std::ostream& os,
const Pi* pi) {
139 auto mut = pi->isa_mut<
Pi>();
140 auto l = pi->is_implicit() ?
'{' :
'[';
141 auto r = pi->is_implicit() ?
'}' :
']';
143 if (mut && mut->var()) {
144 os <<
l << mut->var() <<
": ";
145 dump_child(os, Prec::Arrow, pi->dom(),
true);
149 return dump_child(os, Prec::Arrow, pi->dom(),
true);
152std::ostream&
operator<<(std::ostream& os, Inline u) {
153 if (
u.dump_gid_ == 2 || (
u.dump_gid_ == 1 && !
u->isa<
Var>() &&
u->num_ops() != 0))
print(os,
"/*{}*/",
u->gid());
154 if (
auto mut =
u->isa_mut(); mut && !mut->is_set())
return os <<
"unset";
156 bool ascii =
u->world().flags().ascii;
157 auto arw = ascii ?
"->" :
"→";
158 auto al = ascii ?
"<<" :
"«";
159 auto ar = ascii ?
">>" :
"»";
160 auto pl = ascii ?
"(<" :
"‹";
161 auto pr = ascii ?
">)" :
"›";
163 if (
auto type =
u->isa<
Type>()) {
164 if (
auto level =
Lit::isa(
type->level()); level && !ascii) {
165 if (level == 0)
return print(os,
"*");
166 if (level == 1)
return print(os,
"□");
169 return dump_child(os, Prec::App,
type->level(),
false);
170 }
else if (
u->isa<
Nat>()) {
171 return print(os,
"Nat");
172 }
else if (
u->isa<
Idx>()) {
173 return print(os,
"Idx");
174 }
else if (
auto ext =
u->isa<
Ext>()) {
175 auto x = ext->isa<
Bot>() ? (ascii ?
"bot" :
"⊥") : (ascii ?
"top" :
"⊤");
176 return dump_ascribed(os, x, ext->type());
177 }
else if (
auto top =
u->isa<
Top>()) {
178 return dump_ascribed(os, ascii ?
"top" :
"⊤",
top->type());
179 }
else if (
auto axm =
u->isa<
Axm>()) {
180 const auto name = axm->sym();
181 return print(os,
"{}{}", name[0] ==
'%' ?
"" :
"%", name);
182 }
else if (
auto lit =
u->isa<
Lit>()) {
183 if (
lit->type()->isa<
Nat>()) {
184 switch (
lit->get()) {
186 case 0x0'0000'0100_n:
return os <<
"i8";
187 case 0x0'0001'0000_n:
return os <<
"i16";
188 case 0x1'0000'0000_n:
return os <<
"i32";
190 default:
return print(os,
"{}",
lit->get());
196 case 0x0'0000'0002_n:
return os << (
lit->get<
bool>() ?
"tt" :
"ff");
197 case 0x0'0000'0100_n:
return os <<
lit->get() <<
"I8";
198 case 0x0'0001'0000_n:
return os <<
lit->get() <<
"I16";
199 case 0x1'0000'0000_n:
return os <<
lit->get() <<
"I32";
200 case 0_n:
return os <<
lit->get() <<
"I64";
203 std::vector<uint8_t> digits;
204 for (
auto z = *s; z; z /= 10) digits.emplace_back(z % 10);
208 for (
auto d : digits | std::ranges::views::reverse)
211 for (
auto d : digits | std::ranges::views::reverse)
212 os << uint8_t(0xE2) << uint8_t(0x82) << (uint8_t(0x80 + d));
220 return dump_ascribed(os,
lit->get(),
lit->type());
221 }
else if (
auto ex =
u->isa<
Extract>()) {
222 if (ex->tuple()->isa<
Var>() && ex->index()->isa<
Lit>())
return print(os,
"{}", ex->unique_name());
223 dump_child(os, Prec::Extract, ex->tuple(),
true);
225 return dump_child(os, Prec::Extract, ex->index(),
false);
226 }
else if (
auto var =
u->isa<
Var>()) {
227 return print(os,
"{}", var->unique_name());
228 }
else if (
auto pi =
u->isa<
Pi>()) {
231 return dump_pi_dom(os, pi);
234 os <<
' ' << arw <<
' ';
235 return dump_child(os, Prec::Arrow, pi->codom(),
false);
236 }
else if (
auto lam =
u->isa<
Lam>()) {
237 return print(os,
"{}, {}", lam->filter(), lam->body());
238 }
else if (
auto app =
u->isa<
App>()) {
243 case 0x0'0000'0002_n:
return os <<
"Bool";
244 case 0x0'0000'0100_n:
return os <<
"I8";
245 case 0x0'0001'0000_n:
return os <<
"I16";
246 case 0x1'0000'0000_n:
return os <<
"I32";
247 case 0_n:
return os <<
"I64";
253 dump_child(os, Prec::App, app->callee(),
true);
255 return dump_child(os, Prec::App, app->arg(),
false);
256 }
else if (
auto sigma =
u->isa<
Sigma>()) {
257 if (
auto mut = sigma->isa_mut<
Sigma>(); mut && mut->
var()) {
259 return print(os,
"[{, }]",
Elem(sigma->ops(), [&](
auto op) {
260 if (auto v = mut->var(i++))
261 print(os,
"{}: {}", v, op);
266 return print(os,
"[{, }]", sigma->ops());
267 }
else if (
auto tuple =
u->isa<
Tuple>()) {
268 print(os,
"({, })", tuple->ops());
269 return tuple->type()->isa_mut() ?
print(os,
":{}", tuple->type()) : os;
270 }
else if (
auto arr =
u->isa<
Arr>()) {
271 if (
auto mut = arr->isa_mut<
Arr>(); mut && mut->
var())
272 return print(os,
"{}{}: {}; {}{}", al, mut->var(), mut->arity(), mut->body(), ar);
273 return print(os,
"{}{}; {}{}", al, arr->arity(), arr->body(), ar);
274 }
else if (
auto pack =
u->isa<
Pack>()) {
275 if (
auto mut = pack->isa_mut<
Pack>(); mut && mut->
var())
276 return print(os,
"{}{}: {}; {}{}", pl, mut->var(), mut->arity(), mut->body(), pr);
277 return print(os,
"{}{}; {}{}", pl, pack->arity(), pack->body(), pr);
278 }
else if (
auto proxy =
u->isa<
Proxy>()) {
279 return print(os,
".proxy#{}#{} {, }", proxy->pass(), proxy->tag(), proxy->ops());
280 }
else if (
auto bound =
u->isa<
Bound>()) {
281 auto op = bound->isa<
Join>() ?
"∪" :
"∩";
282 if (
auto mut =
u->isa_mut())
print(os,
"{}{}: {}", op, mut->unique_name(), mut->type());
283 return print(os,
"{}({, })", op, bound->ops());
287 if (
u->flags() == 0)
return print(os,
"(.{} {, })",
u->node_name(),
u->ops());
288 return print(os,
"(.{}#{} {, })",
u->node_name(),
u->flags(),
u->ops());
301 Dumper(std::ostream& os,
const Nest* nest =
nullptr)
307 void dump_let(
const Def*);
308 void dump_ptrn(
const Def*,
const Def*);
309 void dump_group(
const Def*,
const Def*,
bool implicit,
bool paren_style,
size_t limit,
bool alias =
true);
310 void recurse(
const Nest::Node*);
311 void recurse(
const Def*,
bool first =
false);
316 unique_queue<MutSet> muts;
320void Dumper::dump(
Def* mut) {
321 if (
auto lam = mut->isa<Lam>()) {
326 auto mut_prefix = [&](
const Def* def) {
327 if (def->isa<Sigma>())
return "Sigma";
328 if (def->isa<Arr>())
return "Arr";
329 if (def->isa<Pack>())
return "pack";
330 if (def->isa<Pi>())
return "Pi";
331 if (def->isa<Hole>())
return "Hole";
332 if (def->isa<Rule>())
return "Rule";
336 auto mut_op0 = [&](
const Def* def) -> std::ostream& {
337 if (
auto sig = def->isa<Sigma>())
return print(os,
", {}", sig->num_ops());
338 if (
auto arr = def->isa<Arr>())
return print(os,
", {}", arr->arity());
339 if (
auto pack = def->isa<Pack>())
return print(os,
", {}", pack->arity());
340 if (
auto pi = def->isa<Pi>())
return print(os,
", {}", pi->dom());
341 if (
auto hole = def->isa_mut<Hole>())
return hole->is_set() ?
print(os,
", {}", hole->op()) :
print(os,
", ??");
342 if (
auto rule = def->isa<Rule>())
return print(os,
"{} => {}", rule->lhs(), rule->rhs());
346 if (!mut->is_set()) {
347 tab.
print(os,
"{}: {} = {{ <unset> }};",
id(mut), mut->type());
351 tab.
print(os,
"{} {}{}: {}", mut_prefix(mut), external(mut),
id(mut), mut->type());
354 if (
auto e = mut->num_vars(); e != 1) {
355 print(os,
"{, }", Elem(mut->vars(), [&](
auto def) {
357 os << def->unique_name();
362 print(os,
", @{}", mut->var()->unique_name());
367 if (nest) recurse((*nest)[mut]);
369 tab.
print(os,
"{, }\n", mut->ops());
371 tab.
print(os,
"}};\n");
374void Dumper::dump(
Lam* lam) {
375 std::vector<Lam*> groups;
376 for (Lam* curr = lam;;) {
377 groups.emplace_back(curr);
378 auto body = curr->body();
380 auto next = body->isa<
Lam>();
382 curr =
const_cast<Lam*
>(next);
385 auto last = groups.back();
386 auto is_fun = Lam::isa_returning(last);
387 auto is_con = Lam::isa_cn(last) && !is_fun;
389 tab.
print(os,
"{} {}{}", is_fun ?
"fun" : is_con ?
"con" :
"lam", external(lam),
id(lam));
390 for (
auto* group : groups) {
392 auto num_doms = group->var() ? group->var()->num_tprojs() : group->type()->dom()->num_tprojs();
393 auto limit = is_fun && group ==
last ? num_doms - 1 : num_doms;
394 dump_group(group->var(),
395 group->type()->dom(),
396 group->type()->is_implicit(),
399 !is_fun || group != last);
400 if (is_con && group == last)
print(os,
"@({})", group->filter());
406 print(os,
": {} =",
last->type()->codom());
412 if (
last->is_set()) {
413 if (nest && groups.size() == 1) recurse((*nest)[lam]);
414 for (
auto* group : groups)
415 recurse(group->filter());
416 recurse(
last->body(),
true);
417 if (
last->body()->isa_mut())
420 tab.
print(os,
"{};\n", Inline(
last->body()));
422 tab.
print(os,
"<unset>;\n");
428void Dumper::dump_let(
const Def* def) {
429 tab.
print(os,
"let {}: {} = {};\n", def->unique_name(), def->type(), Inline(def, 0));
432void Dumper::dump_ptrn(
const Def* def,
const Def* type) {
436 auto projs = def->tprojs();
437 if (projs.size() == 1 || std::ranges::all_of(projs, [](
auto def) { return !def; })) {
438 print(os,
"{}: {}", def->unique_name(), type);
443 Elem(projs, [&](
auto proj) { dump_ptrn(proj,
type->proj(i++)); }),
449void Dumper::dump_group(
const Def* def,
const Def* type,
bool implicit,
bool paren_style,
size_t limit,
bool alias) {
450 auto l = implicit ?
'{' : paren_style ?
'(' :
'[';
451 auto r = implicit ?
'}' : paren_style ?
')' :
']';
452 auto dump_binder = [&](
const Def* binder,
const Def* binder_type) {
454 dump_ptrn(binder, binder_type);
456 print(os,
"_: {}", binder_type);
466 dump_binder(def ? def->tproj(0) :
nullptr,
type->tproj(0));
474 Elem(std::views::iota(
size_t(0), limit), [&](
auto i) { dump_binder(def ? def->tproj(i) :
nullptr,
type->tproj(i)); }));
476 if (alias && def)
print(os,
" as {}", def->unique_name());
479void Dumper::recurse(
const Nest::Node* node) {
480 for (
auto child : node->children().muts())
481 if (
auto mut = isa_decl(child)) dump(mut);
484void Dumper::recurse(
const Def* def,
bool first ) {
485 if (
auto mut = isa_decl(def)) {
486 if (!nest) muts.push(mut);
490 if (!defs.emplace(def).second)
return;
492 for (
auto op : def->deps())
495 if (!first && !Inline(def)) dump_let(def);
507 if (def ==
nullptr)
return os <<
"<nullptr>";
510 return os << Inline(def);
512 return os << id(def);
517 auto dumper = Dumper(os);
520 os <<
this << std::endl;
521 }
else if (
auto mut = isa_decl(
this)) {
522 dumper.muts.push(mut);
524 dumper.recurse(
this);
525 dumper.tab.print(os,
"{}\n", Inline(
this));
529 for (; !dumper.muts.empty() && max > 0; --max)
530 dumper.dump(dumper.muts.pop());
535void Def::dump()
const { std::cout <<
this << std::endl; }
539 auto ofs = std::ofstream(file);
544 auto file = id(
this) +
".mim"s;
545 write(max, file.c_str());
556 if (
flags().dump_recursive) {
557 auto dumper = Dumper(os);
559 dumper.muts.push(mut);
560 while (!dumper.muts.empty())
561 dumper.dump(dumper.muts.pop());
563 auto nest =
Nest(*
this);
564 auto dumper = Dumper(os, &nest);
566 for (
const auto&
import :
driver().imports())
569 import.tag == ast::Tok::Tag::K_plugin ?
"plugin" :
"import",
571 dumper.recurse(nest.root());
574 assertf(old_gid ==
curr_gid(),
"new nodes created during dump. old_gid: {}; curr_gid: {}", old_gid,
curr_gid());
584 auto ofs = std::ofstream(file);
589 auto file =
name().str() +
".mim"s;
A (possibly paramterized) Array.
World & world() const noexcept
const Def * var(nat_t a, nat_t i) noexcept
void write(int max) const
std::ostream & stream(std::ostream &, int max) const
Common base for TExtremum.
A built-in constant of type Nat -> *.
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
static std::optional< T > isa(const Def *def)
Builds a nesting tree of all mutables/binders.
A (possibly paramterized) Tuple.
A dependent function type.
static const Pi * isa_cn(const Def *d)
Is this a continuation - i.e. is the Pi::codom mim::Bottom?
std::ostream & println(std::ostream &os, const char *s, Args &&... args)
Same as Tab::print but appends a std::endl to os.
std::ostream & print(std::ostream &os, const char *s, Args &&... args)
Data constructor for a Sigma.
A variable introduced by a binder (mutable).
const Driver & driver() const
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
void dump()
Dump to std::cout.
void write()
Same above but file name defaults to World::name.
Flags & flags()
Retrieve compile Flags.
void debug_dump()
Dump in Debug build if World::log::level is Log::Level::Debug.
Sym sym(std::string_view)
void write(const char *file)
Write to a file named file.
const Externals & externals() const
void dump(std::ostream &os)
Dump to os.
Assoc
Associativity of an infix expression.
constexpr Assoc prec_assoc(Prec p)
Associativity of precedence level p.
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
const Def * op(trait o, const Def *type)
std::ostream & print(std::ostream &os, const char *s)
Base case.
TBound< true > Join
AKA union.
GIDSet< const Def * > DefSet
std::ostream & operator<<(std::ostream &os, const Def *def)
This will stream def as an operand.
constexpr Assoc prec_assoc(Prec p)
Associativity of precedence level p.
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
#define assertf(condition,...)
Use with print to output complicated std::ranges::ranges.
Use to World::freeze and automatically unfreeze at the end of scope.