13using namespace std::literals;
24using Srcs = ankerl::unordered_dense::set<const fe::Src*>;
27bool is_anx_nom(
const Def* def) {
return def->isa<
Nom>() && def->
sym().view().contains(
'.'); }
29Def* isa_decl(
const Def* def) {
30 if (
auto mut = def->isa_mut()) {
31 if (mut->isa<
Hole>())
return nullptr;
32 if (mut->is_external() || mut->isa<
Lam>() || (mut->sym() && mut->sym() !=
'_'))
return mut;
38using Args = fe::Vector<std::pair<DefVec, bool>>;
44 DefMap<std::string> names;
53 DefMap<const Def*> aliases;
55 ankerl::unordered_dense::set<std::string> taken;
56 ankerl::unordered_dense::map<std::string, size_t> counters;
57 fe::Tab tab = fe::Tab::spaces();
59 bool in_header =
false;
64 const DefSet* live =
nullptr;
70const std::pair<Sym, Args>* isa_inst(
const Ctx* ctx,
const Def* def) {
71 return ctx && def->isa<
Nom>() ? fe::lookup(ctx->insts, def) : nullptr;
75bool has_decl(
const Ctx* ctx,
const Def* def) {
76 return isa_decl(def) || (def->isa<
Nom>() && !is_anx_nom(def) && !isa_inst(ctx, def));
80std::string annex_sym(Ctx* ctx, Sym annex) {
81 auto sym = annex.view();
82 if (ctx && !ctx->self.empty() && sym.starts_with(ctx->self)) {
83 sym.remove_prefix(ctx->self.size());
84 if (!ctx->mod.empty() && sym.starts_with(ctx->mod)) sym.remove_prefix(ctx->mod.size());
86 return std::string(sym);
91 auto proj = def->
proj(n, i);
92 return proj && ctx && ctx->live && !ctx->live->contains(proj) ? nullptr : proj;
96std::string fresh_name(Ctx* ctx,
const std::string& base) {
97 auto sep = base ==
"_" ?
"" :
"_";
98 auto& i = ctx->counters[base];
99 auto name = std::string();
101 name = std::format(
"{}{}{}", base, sep, ++i);
102 while (ctx->taken.contains(name));
103 ctx->taken.emplace(name);
107std::string pick_name(Ctx* ctx,
const Def* def) {
108 auto sym = def->sym();
111 auto name = base ==
"_" || def->world().driver().keys().find(sym) || ctx->taken.contains(base)
112 ? fresh_name(ctx, base)
114 ctx->taken.emplace(name);
115 return ctx->names.emplace(def, name).first->second;
119bool is_opaque(Ctx* ctx,
const Def* def) {
120 auto split = fe::lookup(ctx->split, def);
121 return split && !*split;
125const Def* alias_proj(Ctx* ctx,
const Def* def) {
126 if (
auto ex = def->isa<
Extract>())
127 if (
auto var = fe::lookup(ctx->aliases, ex->tuple()); var && !is_opaque(ctx, var))
128 if (
auto l =
Lit::isa(ex->index()))
return live_proj(ctx, var, ex->tuple()->num_tprojs(), *l);
133bool by_name(Ctx* ctx,
const Extract* ex) {
134 if (!ex->index()->isa<
Lit>())
return false;
135 if (!ctx)
return ex->tuple()->isa<
Var>();
136 if (ctx->bound.contains(ex))
return true;
138 if (is_opaque(ctx, ex->tuple()))
return false;
140 if (ctx->aliases.contains(ex->tuple()) && !alias_proj(ctx, ex))
return false;
141 return ex->tuple()->isa<
Var>() || ctx->split.contains(ex->tuple());
146std::string name(Ctx* ctx,
const Def* def) {
148 if (
auto n = fe::lookup(ctx->names, def))
return *n;
149 if (
auto alias = fe::lookup(ctx->aliases, def))
return name(ctx, alias);
150 if (
auto proj = alias_proj(ctx, def)) {
151 auto res = name(ctx, proj);
152 return ctx->names.emplace(def, std::move(res)).first->second;
154 if (
auto ex = def->isa<
Extract>())
155 if (
auto i = fe::lookup(ctx->ret_projs, ex->tuple()); i &&
Lit::isa(ex->index()) == *i)
return "return"s;
156 if (ctx->plain)
return pick_name(ctx, def);
158 if (
auto sym = def->sym(); sym && sym !=
'_' &&
PlainNames::claim(def->world().driver(), sym, def->gid()))
160 return def->unique_name();
163std::string
id(Ctx* ctx,
const Def* def) {
164 if (def->is_external() || (!def->is_set() && def->isa<
Lam>()))
return def->sym().str();
165 return name(ctx, def);
168std::string_view external(
const Def* def) {
169 if (def->is_external())
return "extern "sv;
179std::optional<std::string_view> idx_name(
nat_t size) {
182 case 0x0'0000'0002_n:
return "Bool";
183 case 0x0'0000'0100_n:
return "I8";
184 case 0x0'0001'0000_n:
return "I16";
185 case 0x1'0000'0000_n:
return "I32";
186 case 0_n:
return "I64";
187 default:
return std::nullopt;
192Prec def2prec(Ctx* ctx,
const Def* def) {
193 if (
auto ex = def->isa<
Extract>())
return by_name(ctx, ex) ? Prec::Lit : Prec::Extract;
194 if (def->isa<
Insert>())
return Prec::Ins;
195 if (def->isa<
Join>())
return Prec::Union;
196 if (
auto inj = def->isa<
Inj>()) {
197 if (
auto variant = inj->type()->isa<
Variant>())
198 return variant->op(inj->index()) == def->world().sigma() ? Prec::Extract : Prec::App;
201 if (def->isa<
Name>())
return Prec::Inj;
202 if (def->isa<
Struc>())
return Prec::Prefix;
203 if (def->isa<
Variant>())
return Prec::Lit;
204 if (isa_inst(ctx, def) || def->isa<
Reform>())
return Prec::App;
206 if (
auto pi = def->isa<
Pi>())
return Pi::isa_cn(pi) ? Prec::Bot : Prec::Arrow;
207 if (def->isa<
Lam>() || def->isa<
Match>())
209 if (
auto app = def->isa<
App>()) {
211 if (
auto l =
Lit::isa(size);
l && idx_name(*l))
return Prec::Lit;
221 Op(Ctx* ctx,
const Def* def,
Prec prec = Prec::Bot,
bool is_left =
false)
225 , is_left_(is_left) {}
230 Op
op(
const Def* def,
Prec prec = Prec::Bot,
bool is_left =
false)
const {
return {ctx_, def, prec, is_left}; }
231 Op
l(
const Def* def,
Prec prec = Prec::Bot)
const {
return {ctx_, def, prec,
true}; }
232 Op
r(
const Def* def,
Prec prec = Prec::Bot)
const {
return {ctx_, def, prec,
false}; }
235 static auto map(Ctx* ctx,
const auto& range,
const char* sep =
", ",
Prec prec = Prec::Bot) {
236 return fe::Join(range | std::views::transform([ctx, prec](
auto op) {
return Op(ctx, op, prec); }), sep);
241 Ctx* ctx()
const {
return ctx_; }
242 Prec prec()
const {
return prec_; }
243 bool is_left()
const {
return is_left_; }
244 const Def* def()
const {
return def_; }
245 const Def* operator->()
const {
return def_; }
246 const Def* operator*()
const {
return def_; }
247 explicit operator bool()
const {
return def_ !=
nullptr; }
257 friend std::ostream&
operator<<(std::ostream&, Op);
261class Full :
public Op {
263 Full(Ctx* ctx,
const Def* def,
Prec prec = Prec::Bot,
bool is_left =
false)
264 : Op(ctx, def, prec, is_left) {}
266 : Full(
op.ctx(),
op.def(),
op.prec(),
op.is_left()) {}
268 explicit operator bool()
const {
return is_full(); }
271 bool is_full()
const {
273 if (def()->isa<Nom>())
return is_anx_nom(def()) || isa_inst(ctx(), def());
274 if (
auto ctx = this->ctx()) {
275 if (ctx->inlined.contains(def()))
return true;
276 if (ctx->in_header && ctx->header.contains(def()))
return true;
278 if (
auto mut = def()->isa_mut())
return !isa_decl(mut);
282 if (
auto app = def()->isa<App>()) {
283 if (app->type()->isa<Pi>())
return true;
284 if (app->type()->isa<Type>())
return true;
285 if (app->callee()->isa<Axm>())
return app->callee_type()->num_doms() <= 1;
292 bool needs_parens()
const {
293 if (!is_full())
return false;
295 auto child_prec = def2prec(ctx(), def());
296 if (child_prec < prec())
return true;
297 if (child_prec > prec())
return false;
300 case Assoc::R:
return is_left();
301 case Assoc::L:
return !is_left();
302 case Assoc::N:
return false;
307 friend std::ostream&
operator<<(std::ostream&, Full);
314template<>
struct std::formatter<
mim::Op > : fe::ostream_formatter {};
315template<>
struct std::formatter<
mim::Full> : fe::ostream_formatter {};
325 return type->num_tprojs();
330std::string
shape(Ctx* ctx,
const Seq* seq) {
331 auto s = seq->shape();
333 if (!r || *r <= 1)
return std::format(
"{}", Op(ctx, *s));
335 auto axes =
s->projs(*r);
336 if (std::ranges::any_of(axes, [](
auto a) {
return !
a; }))
return std::format(
"{}", Op(ctx, *s));
337 return std::format(
"{}", Op::map(ctx, axes));
341std::string
shape(Ctx* ctx,
const Seq* seq,
const Def* var) {
342 if (!var)
return shape(ctx, seq);
343 auto s = seq->shape();
345 if (!r || *r <= 1)
return std::format(
"{}: {}", Op(ctx, var), Op(ctx, *s));
347 auto res = std::string();
348 for (
auto sep =
"";
auto i : std::views::iota(
nat_t(0), *r)) {
349 auto axis = live_proj(ctx, var, *r, i);
351 if (!extent)
return std::format(
"{}: {}", Op(ctx, var), Op(ctx, *s));
353 res += std::format(
"{}{}: {}", sep, axis ? std::format(
"{}", Op(ctx, axis)) :
"_"s, Op(ctx, extent));
360bool only_projs(
const Def* t,
const Var* var,
DefSet& done) {
361 if (!
t->has_free_var(var) || !done.emplace(t).second)
return true;
362 if (t == var)
return false;
363 if (
auto ex =
t->isa<
Extract>(); ex && ex->
tuple() == var)
return ex->index()->isa<
Lit>();
364 return std::ranges::all_of(
t->deps(), [&](
const Def* d) { return only_projs(d, var, done); });
368const Def* binder_proj(
const Def* type,
size_t n,
size_t i) {
369 if (
auto [_, var] =
type->isa_binder<
Sigma>(); var)
return var->
proj(n, i);
377bool destructible(Ctx* ctx,
const Def* def,
const Def* type,
size_t n) {
378 if (!def || n <= 1)
return false;
379 auto var =
type->isa_mut<
Sigma>() ?
type->has_var() :
nullptr;
382 for (
size_t i = 0; i != n; ++i) {
383 if (live_proj(ctx, def, n, i))
continue;
384 auto t =
type->proj(n, i);
385 if (!t || (var && !only_projs(t, var, done)))
return false;
391bool split(Ctx* ctx,
const Def* def,
const Def* type,
size_t n) {
392 if (!ctx || !def)
return destructible(ctx, def, type, n);
393 if (
auto res = fe::lookup(ctx->split, def))
return *res;
394 auto res = destructible(ctx, def, type, n);
396 if (res || n > 1 || def->num_projs() > 1) ctx->split.emplace(def, res);
401void alias_sigma(Ctx* ctx,
const Def* type,
const Def* def) {
402 if (
auto [_, var] =
type->isa_binder<
Sigma>(); ctx && var) ctx->aliases.emplace(var, def);
405void ptrn(std::ostream&, Ctx*,
const Def*,
const Def*,
bool =
false,
const Def* =
nullptr);
408void ptrns(std::ostream& os, Ctx* ctx,
const Def* def,
const Def* type,
size_t n,
size_t limit,
bool brckt) {
409 for (
auto sep =
"";
auto i : std::views::iota(
size_t(0), limit)) {
410 auto proj = def ? live_proj(ctx, def, n, i) : nullptr;
413 ptrn(os, ctx, proj, proj ? proj->type() :
type->proj(n, i), brckt, binder_proj(type, n, i));
420void ptrn(std::ostream& os, Ctx* ctx,
const Def* def,
const Def* type,
bool brckt,
const Def* binder) {
422 if (!binder || !ctx)
return std::print(os,
"_: {}", Op(ctx, type));
423 ctx->bound.emplace(binder);
424 return std::print(os,
"{}: {}", name(ctx, binder), Op(ctx, type));
427 auto n = def->num_tprojs();
430 = std::ranges::any_of(std::views::iota(
size_t(0), n), [&](
size_t i) {
return live_proj(ctx, def, n, i); });
431 if (!used || !split(ctx, def, type, n))
return std::print(os,
"{}: {}", name(ctx, def), Op(ctx, type));
432 alias_sigma(ctx, type, def);
434 os << (brckt ?
'[' :
'(');
435 ptrns(os, ctx, def, type, n, n, brckt);
437 std::print(os,
"{} as {}", brckt ?
']' :
')', name(ctx, def));
441void dom_ptrn(std::ostream& os, Ctx* ctx,
const Def* var,
const Def* type,
bool implicit) {
442 auto l = implicit ?
'{' :
'[';
443 auto r = implicit ?
'}' :
']';
444 auto n = var->num_tprojs();
445 if (!split(ctx, var, type, n))
return std::print(os,
"{}{}: {}{}", l, name(ctx, var), Op(ctx, type), r);
448 ptrns(os, ctx, var, type, n, n,
true);
449 std::print(os,
"{} as {}", r, name(ctx, var));
454void curry(std::ostream& os,
463 auto l = implicit ?
'{' :
'(';
464 auto r = implicit ?
'}' :
')';
466 if (limit == 0)
return (
void)(os <<
l <<
r);
468 if (def)
return std::print(os,
"{}{}: {}{}", l, name(ctx, def), Op(ctx, type), r);
469 return std::print(os,
"{}_: {}{}", l, Op(ctx, type), r);
473 ptrns(os, ctx, def, type, num, limit,
false);
475 if (alias && def) std::print(os,
" as {}", name(ctx, def));
480bool isa_fun(
const Lam* lam) {
481 auto pi = lam->type();
488bool isa_fun(Ctx* ctx,
const Lam* lam) {
490 return isa_fun(lam) && !(ctx && var && ctx->whole_vars.contains(var));
495void lam_ptrn(std::ostream& os, Ctx* ctx,
Lam* lam,
bool fun,
bool con,
bool last,
bool alias) {
496 auto num = num_binders(lam->type()->dom());
497 auto limit = fun &&
last ? num - 1 : num;
498 auto var = lam->has_var();
500 auto parts = limit != num || (limit != 0 && split(ctx, var, lam->dom(), num));
502 if (
auto pi_var = lam->type()->has_var()) ctx->aliases.emplace(pi_var, var);
504 if (parts) alias_sigma(ctx, lam->dom(), var);
506 curry(os, ctx, var, lam->type()->dom(), lam->type()->is_implicit(), num, limit, parts, alias);
507 auto&
w = lam->world();
508 if (
auto dflt = last && (fun || con) ?
w.lit_ff() :
w.lit_tt(); lam->filter() != dflt)
509 std::print(os,
"@({})", Op(ctx, lam->filter()));
513void lam_codom(std::ostream& os, Ctx* ctx,
Lam* lam,
bool fun,
bool con) {
515 std::print(os,
": {}", Op(ctx, lam->ret_dom()));
517 std::print(os,
": {}", Op(ctx, lam->type()->codom()));
521std::string ctors(Ctx* ctx,
const Variant* variant) {
522 if (variant->num_ops() == 0)
return "|";
523 auto res = std::string();
524 for (
auto sep =
"";
auto i : std::views::iota(
size_t(0), variant->num_ops())) {
525 res += std::format(
"{}| _{}", sep, i);
526 if (
auto op = variant->op(i); op != variant->world().sigma()) res += std::format(
": {}", Op(ctx, op));
532std::ostream&
operator<<(std::ostream& os, Op op) {
533 if (*op ==
nullptr)
return os <<
"<nullptr>";
534 if (
auto d = Full(op))
return os <<
d;
535 return os <<
id(
op.ctx(), *op);
539std::string
tail(Ctx* ctx,
const Def* def) {
540 return has_decl(ctx, def) ? std::format(
"{}", Op(ctx, def)) : std::format(
"{}", Full(ctx, def));
544void full(std::ostream& os, Full d) {
545 if (
auto hole =
d->isa_mut<
Hole>()) {
546 if (hole->is_set())
return std::print(os,
"{}",
d.op(hole->op()));
547 return std::print(os,
"?");
549 if (
auto mut =
d->isa_mut(); mut && !mut->is_set())
return std::print(os,
"unset");
550 if (
d.needs_parens())
return std::print(os,
"({})", Full(
d.ctx(), *d));
552 bool ascii =
d->world().flags().ascii;
553 auto arw = ascii ?
"->" :
"→";
554 auto al = ascii ?
"<<" :
"«";
555 auto ar = ascii ?
">>" :
"»";
556 auto pl = ascii ?
"(<" :
"‹";
557 auto pr = ascii ?
">)" :
"›";
558 auto bot = ascii ?
"bot" :
"⊥";
559 auto top = ascii ?
"top" :
"⊤";
561 if (
auto type =
d->isa<
Type>()) {
562 if (
auto level =
Lit::isa(
type->level()); level && !ascii) {
563 if (level == 0)
return std::print(os,
"*");
564 if (level == 1)
return std::print(os,
"□");
566 return std::print(os,
"Type {}",
d.r(
type->level(), Prec::App));
567 }
else if (
auto reform =
d->isa<
Reform>()) {
568 return std::print(os,
"Rule {}",
d.r(reform->dom(), Prec::App));
569 }
else if (
d->isa<
Level>()) {
570 return std::print(os,
"Level");
571 }
else if (
d->isa<
Nat>()) {
572 return std::print(os,
"Nat");
573 }
else if (
d->isa<
Idx>()) {
574 return std::print(os,
"Idx");
575 }
else if (
auto ext =
d->isa<
Ext>()) {
576 return std::print(os,
"{}:{}", ext->isa<
Bot>() ? bot : top,
d.r(ext->type(), Prec::Lit));
577 }
else if (
d->isa<
Axm>() || is_anx_nom(*d)) {
578 return std::print(os,
"{}", annex_sym(
d.ctx(),
d->sym()));
579 }
else if (
auto inst = isa_inst(
d.ctx(), *d)) {
580 std::print(os,
"{}", annex_sym(
d.ctx(), inst->first));
581 for (
const auto& [arg, implicit] : inst->second) {
582 os << (implicit ?
" @ " :
" ");
584 std::print(os,
"{}",
d.r(arg.front(), Prec::App));
586 std::print(os,
"({})", Op::map(
d.ctx(), arg));
589 }
else if (
auto lit =
d->isa<
Lit>()) {
590 if (
lit->type()->isa<
Nat>()) {
592 switch (
lit->get()) {
593 case 0x0'0000'0100_n:
return std::print(os,
"i8");
594 case 0x0'0001'0000_n:
return std::print(os,
"i16");
595 case 0x1'0000'0000_n:
return std::print(os,
"i32");
596 default:
return std::print(os,
"{}",
lit->get());
601 if (*s == 2)
return std::print(os,
"{}",
lit->get<
bool>() ?
"tt" :
"ff");
602 if (
auto suffix = idx_name(*s))
return std::print(os,
"{}{}",
lit->get(), *suffix);
603 std::print(os,
"{}",
lit->get());
604 auto digits = std::to_string(*s);
609 for (
auto d : digits)
610 os <<
"\xE2\x82" << char(0x80 + d -
'0');
615 return std::print(os,
"{}:{}",
lit->get(),
d.r(
lit->type(), Prec::Lit));
616 }
else if (
auto ex =
d->isa<
Extract>()) {
617 if (by_name(
d.ctx(), ex))
return std::print(os,
"{}", name(
d.ctx(), ex));
618 return std::print(os,
"{}#{}",
d.l(ex->tuple(), Prec::Extract),
d.r(ex->index(), Prec::Extract));
619 }
else if (
auto ins =
d->isa<
Insert>()) {
620 auto tup =
d.l(ins->tuple(), Prec::Extract);
622 if (
auto ex = ins->tuple()->isa<
Extract>(); ex && !by_name(
d.ctx(), ex))
623 std::print(os,
"({})", tup);
625 std::print(os,
"{}", tup);
626 return std::print(os,
"#{} ← {}",
d.r(ins->index(), Prec::Extract),
d.r(ins->value(), Prec::Ins));
627 }
else if (
auto var =
d->isa<
Var>()) {
628 return std::print(os,
"{}", name(
d.ctx(), var));
630 dom_ptrn(os,
d.ctx(), var, pi->dom(), pi->is_implicit());
631 return std::print(os,
" {} {}", arw,
d.r(pi->codom(), Prec::Arrow));
632 }
else if (
auto pi =
d->isa<
Pi>()) {
633 if (
Pi::isa_cn(pi))
return std::print(os,
"Cn {}",
d.op(pi->dom()));
634 if (pi->is_implicit())
635 return std::print(os,
"{{_: {}}} {} {}",
d.op(pi->dom()), arw,
d.r(pi->codom(), Prec::Arrow));
636 return std::print(os,
"{} {} {}",
d.l(pi->dom(), Prec::Arrow), arw,
d.r(pi->codom(), Prec::Arrow));
637 }
else if (
auto lam =
d->isa_mut<
Lam>()) {
639 auto fun = isa_fun(
d.ctx(), lam);
641 std::print(os,
"{}", fun ?
"fn " : con ?
"cn " :
"λ ");
642 lam_ptrn(os,
d.ctx(), lam, fun, con,
true,
true);
643 lam_codom(os,
d.ctx(), lam, fun, con);
645 return std::print(os,
" = {}",
tail(
d.ctx(), lam->body()));
646 }
else if (
auto app =
d->isa<
App>()) {
649 if (
auto name = idx_name(*l))
return std::print(os,
"{}", *name);
653 if (app->arg()->has_hole())
return std::print(os,
"{}",
d.op(app->callee(),
d.prec(),
d.is_left()));
655 return std::print(os,
"{} @ {}",
d.l(app->callee(), Prec::App),
d.r(app->arg(), Prec::App));
657 return std::print(os,
"{} {}",
d.l(app->callee(), Prec::App),
d.r(app->arg(), Prec::App));
658 }
else if (
auto sigma =
d->isa<
Sigma>()) {
659 auto var = sigma->has_var();
661 auto elem = fe::StreamFn{[&](std::ostream& os) -> std::ostream& {
663 for (
auto op : sigma->ops()) {
665 if (
auto v = var ? var->proj(sigma->num_ops(), i) :
nullptr)
666 std::print(os,
"{}: {}",
d.op(v),
d.op(op));
675 return std::print(os,
"[{}]", elem);
676 }
else if (
auto tuple =
d->isa<
Tuple>()) {
677 return std::print(os,
"({})", Op::map(
d.ctx(), tuple->ops()));
678 }
else if (
auto arr =
d->isa<
Arr>()) {
679 return std::print(os,
"{}{}; {}{}", al,
shape(
d.ctx(), arr, arr->has_var()),
d.op(arr->body()), ar);
680 }
else if (
auto pack =
d->isa<
Pack>()) {
681 return std::print(os,
"{}{}; {}{}", pl,
shape(
d.ctx(), pack, pack->has_var()),
d.op(pack->body()), pr);
682 }
else if (
auto proxy =
d->isa<
Proxy>()) {
683 return std::print(os,
"(proxy#{} {})", proxy->tag(), Op::map(
d.ctx(), proxy->ops()));
684 }
else if (
auto join =
d->isa<
Join>()) {
685 return std::print(os,
"{}", Op::map(
d.ctx(), join->ops(),
" ∪ ", Prec::Union));
686 }
else if (
auto variant =
d->isa<
Variant>()) {
687 return std::print(os,
"({})", ctors(
d.ctx(), variant));
688 }
else if (
auto inj =
d->isa<
Inj>()) {
689 if (
auto variant = inj->type()->isa<
Variant>()) {
690 auto ctor = std::format(
"{}#{}",
d.l(variant, Prec::Extract), inj->index());
691 if (variant->op(inj->index()) ==
d->world().sigma())
return std::print(os,
"{}", ctor);
692 return std::print(os,
"{} {}", ctor,
d.r(inj->value(), Prec::App));
694 return std::print(os,
"{} inj {}",
d.l(inj->value(), Prec::Inj),
d.r(inj->type(), Prec::Inj));
695 }
else if (
auto name =
d->isa<
Name>()) {
696 return std::print(os,
"{} inj {}",
d.l(name->op(), Prec::Inj),
d.r(name->nom(), Prec::Inj));
697 }
else if (
auto struc =
d->isa<
Struc>()) {
698 return std::print(os,
"#{}",
d.r(
struc->op(), Prec::Prefix));
699 }
else if (
auto single =
d->isa<
Single>()) {
700 return std::print(os,
"{}{}{}", al,
d.op(single->op()), ar);
701 }
else if (
auto wrap =
d->isa<
Wrap>()) {
702 return std::print(os,
"{}{}{}", pl,
d.op(
wrap->op()), pr);
703 }
else if (
auto match =
d->isa<
Match>(); match &&
d.ctx() && match->num_arms() != 0) {
704 std::print(os,
"match {} with",
d.op(match->scrutinee()));
705 auto variant = match->scrutinee()->type()->isa<
Variant>();
706 auto& tab =
d.ctx()->tab;
708 for (
size_t i = 0;
auto arm : match->arms()) {
709 auto dom = arm->type()->as<
Pi>()->dom();
710 std::print(os,
"\n{}| ", tab);
712 if (variant) std::print(os,
"_{}", i++);
713 auto binds = !variant || dom !=
d->world().sigma();
714 if (binds && variant) os <<
' ';
715 if (
d.ctx()->arms.contains(arm)) {
716 auto lam = arm->as_mut<
Lam>();
717 if (binds) ptrn(os,
d.ctx(), lam->has_var(), dom);
719 std::print(os,
" => {}",
d.op(lam->body(), Prec::Where));
721 auto x = binds ? fresh_name(
d.ctx(),
"_") :
"()"s;
722 if (binds) std::print(os,
"{}: {}", x,
d.op(dom));
723 std::print(os,
" => {} {}",
d.l(arm, Prec::App), x);
731 auto tag =
d->flags() == 0 ? std::string(
d->node_name()) : std::format(
"{}#{}",
d->node_name(),
d->flags());
732 if (
d->ops().empty())
return std::print(os,
"({})", tag);
733 std::print(os,
"({} {})", tag, Op::map(
d.ctx(),
d->ops(),
" "));
736std::ostream&
operator<<(std::ostream& os, Full d) {
746fe::Vector<Lam*> curry_chain(
Lam* lam) {
747 auto chain = fe::Vector<Lam*>();
748 for (
auto* curr = lam;;) {
749 chain.emplace_back(curr);
750 if (
auto body = curr->body())
751 if (
auto next = body->isa_mut<
Lam>(); next && !next->
is_external()) {
765 explicit Instantiation(
const fe::Vector<Lam*>& chain)
767 for (
auto lam : chain)
768 if (
auto var = lam->has_var()) vars_.emplace(var);
772 std::optional<Args> args(
const Nom* inst) {
773 auto generic = chain_.back()->body()->as<
Nom>();
774 if (inst == generic || !match(generic->op(), inst->op()))
return {};
777 for (
auto lam : chain_) {
778 auto var = lam->has_var();
779 auto implicit = lam->type()->is_implicit();
781 if (
auto whole = fe::lookup(subst_, var)) {
782 res.emplace_back(
DefVec{whole}, implicit);
786 if (!n || *n < 2)
return {};
787 auto comps =
DefVec(*n,
nullptr);
788 for (
auto [g, i] : subst_)
789 if (
auto ex =
g->isa<Extract>(); ex && ex->tuple() == var) comps[*
Lit::isa(ex->index())] = i;
790 if (std::ranges::contains(comps,
nullptr))
return {};
791 res.emplace_back(std::move(comps), implicit);
797 bool is_param(
const Def* def)
const {
798 if (
auto ex = def->isa<Extract>(); ex && ex->index()->isa<Lit>()) def = ex->tuple();
799 return vars_.contains(def);
802 bool match(
const Def* g,
const Def* i) {
803 if (g == i)
return true;
805 if (!g || !i)
return false;
807 if (
auto [j, ins] = subst_.emplace(g, i); !ins)
return j->second == i;
808 if (is_param(g))
return true;
809 if (
g->node() != i->node() ||
g->flags() != i->flags() ||
g->num_ops() != i->num_ops())
return false;
810 if (!match(
g->type(), i->type()))
return false;
811 for (
size_t k = 0, n =
g->num_ops(); k != n; ++k)
812 if (!match(
g->op(k), i->op(k)))
return false;
816 const fe::Vector<Lam*>& chain_;
818 DefMap<const Def*> subst_;
823 std::string mod, name;
834 Dumper(std::ostream& os, Dump mode,
bool typed_let =
false, Srcs srcs = {})
837 , typed_let_(typed_let)
838 , srcs_(std::move(srcs)) {}
841 void live(
const DefSet& live) { ctx_.live = &live; }
843 void insts(
DefMap<std::pair<Sym, Args>> insts) { ctx_.insts = std::move(insts); }
846 void plain(std::span<const std::string> reserved) {
848 ctx_.taken.insert(reserved.begin(), reserved.end());
853 void dump_annexes(std::string self, std::span<const DumpAnnex> annexes) {
854 ctx_.self = std::move(self);
855 auto content = [](
const Def* def) {
return def->isa<
Axm>() ? def->type() : def->as<
Nom>()->
op(); };
856 auto muts = fe::Vector<Def*>();
857 for (
const auto& [_, __, annex] : annexes)
858 for (
auto mut : content(annex)->local_muts())
859 if (isa_decl(mut)) muts.emplace_back(mut);
865 auto bodies = fe::Vector<Def*>();
866 for (
const auto& a : annexes)
867 if (
auto nom =
a.def->isa<Nom>()) {
868 noms.emplace_back(nom);
870 for (
auto mut : nom->local_muts())
871 bodies.emplace_back(mut);
873 if (!bodies.empty()) group_noms(
Nest(bodies.front()->world(), bodies,
true), noms);
874 std::string_view curr_mod;
875 for (
const auto& [mod, name, def] : annexes) {
876 if (mod != curr_mod) {
877 if (!curr_mod.empty()) std::println(os_,
"{}end", --ctx_.tab);
878 if (!mod.empty()) std::println(os_,
"{}mod {}", ctx_.tab, mod), ++ctx_.tab;
880 ctx_.mod = mod.empty() ? std::string() : std::string(mod) +
".";
882 if (deferred_.contains(def))
continue;
883 if (
auto group = fe::lookup(mutual_, def)) {
884 emit_mutual(*group, [&](
const Def* m) { emit_nom(
"anx nom", names[m], m->as<Nom>()); });
887 if (
auto nom = def->isa<Nom>()) {
888 emit_nom(
"anx nom", name, nom);
891 auto axm = def->as<
Axm>();
892 std::print(os_,
"{}axm {}: {}", ctx_.tab, name, Op(&ctx_, axm->type()));
894 if (axm->curry() != curry || axm->trip() != trip) std::print(os_,
", {}", axm->curry());
895 if (axm->trip() != trip) std::print(os_,
", {}", axm->trip());
896 std::println(os_,
";");
898 if (!curr_mod.empty()) std::println(os_,
"{}end", --ctx_.tab);
905 void dump(
const Def* def) {
906 if (
auto mut = isa_decl(def))
return dump_muts({mut});
908 auto muts = fe::Vector<Def*>();
909 for (
auto mut : def->local_muts())
910 if (isa_decl(mut)) muts.emplace_back(mut);
911 dump_muts(muts, def);
914 void dump(fe::View<Def*> muts) { dump_muts(muts); }
919 enum class Prev { None, Let, Decl };
923 bool is_imported(Def* mut)
const {
return mut->is_external() && srcs_.contains(mut->loc().src); }
926 void emit_top(
const auto& roots) {
927 for (
auto root : roots)
937 void dump_muts(fe::View<Def*> muts,
const Def* tail =
nullptr) {
938 if (muts.empty() && !tail)
return;
939 auto todo = fe::Vector<Def*>();
940 for (
auto mut : muts)
942 for (
auto [lam, match] : arm_of_)
943 if (match && is_spellable(lam)) ctx_.arms.emplace(lam);
946 auto roots = fe::Vector<Def*>();
947 for (
auto mut : todo) {
948 if (!mut->is_closed() || ctx_.arms.contains(mut))
continue;
949 if (is_imported(mut))
952 roots.emplace_back(mut);
954 if (mode_ == Dump::Scope) scope_.insert(muts.begin(), muts.end());
956 const auto nest =
Nest(tail ?
tail->world() : muts.front()->world(), muts,
true);
957 auto _ = fe::Restore(nest_, &nest);
960 emit_top(std::array{
tail});
966 static bool is_spellable(
const Def* arm) {
967 auto lam = arm->isa_mut<
Lam>();
968 return lam && lam->is_set() && lam->filter() == lam->world().lit_tt();
973 void post_order(Def* mut, fe::Vector<Def*>& todo) {
974 if (!scheduled_.emplace(mut).second)
return;
976 auto muts = fe::Vector<Def*>();
978 printed_deps(mut, [&](
const Def* op) {
979 note_use(op,
nullptr);
980 local_muts(op, seen, muts);
982 for (
auto local_mut : muts)
985 todo.emplace_back(mut);
988 void local_muts(
const Def* def,
DefSet& seen, fe::Vector<Def*>& muts) {
989 if (!def || def->local_muts().empty() || !seen.emplace(def).second)
return;
990 if (
auto mut = def->isa_mut())
return (
void)muts.emplace_back(mut);
991 auto match = def->isa<
Match>();
992 printed_deps(def, [&](
const Def* op) {
994 auto arm = match && std::ranges::count(match->arms(), op) == 1;
995 note_use(op, arm ? match :
nullptr);
996 local_muts(op, seen, muts);
1001 void note_use(
const Def* op,
const Match* match) {
1002 if (!op || !
op->isa_mut<Lam>())
return;
1003 if (
auto [i, ins] = arm_of_.emplace(op, match); !ins && i->second != match) i->second =
nullptr;
1008 void printed_deps(
const Def* def,
auto f)
const {
1009 if (
auto inst = isa_inst(&ctx_, def)) {
1010 for (
const auto& [arg, _] : inst->second)
1015 if (
auto lam = def->isa_mut<Lam>()) {
1016 f(lam->type()->dom());
1017 f(lam->type()->codom());
1018 for (
auto op : lam->ops())
1022 if (typed_let_ || def->isa<Lit>() || def->isa<Ext>() || def->isa<Inj>() || def->isa<Name>())
f(def->type());
1023 for (
auto op : def->ops())
1027 void note_vars(
const Def* def) {
1028 if (
auto inst = isa_inst(&ctx_, def)) {
1029 for (
const auto& [arg, _] : inst->second)
1031 if (
op->isa<Var>()) ctx_.whole_vars.emplace(op);
1034 auto ex = def->isa<
Extract>();
1035 for (
auto op : def->ops())
1036 if (op &&
op->isa<Var>() && !(ex && op == ex->tuple() && ex->index()->isa<Lit>()))
1037 ctx_.whole_vars.emplace(op);
1040 void schedule_(
const Def* def) {
1042 if (
auto mut = isa_decl(def); mut && !ctx_.arms.contains(mut))
return schedule_mut(mut);
1043 if (!done_.emplace(def).second)
return finish(def);
1044 if (ctx_.arms.contains(def)) {
1046 auto lam = def->as_mut<
Lam>();
1047 if (lam->body()->isa<Var>()) ctx_.whole_vars.emplace(lam->body());
1048 schedule_inline(lam->dom(), ctx_.inlined);
1049 schedule_inline(lam->body(), ctx_.inlined);
1054 if (!Full(&ctx_, def)) order_.emplace_back(def);
1057 void schedule_deps(
const Def* def) {
1058 pending_.emplace(def);
1059 printed_deps(def, [&](
const Def* op) { schedule_(op); });
1060 pending_.erase(def);
1064 void finish(
const Def* def) {
1065 if (pending_.erase(def)) printed_deps(def, [&](
const Def* op) { schedule_(op); });
1068 void schedule_mut(Def* mut) {
1069 if (!enter(mut) || done_.contains(mut))
return;
1071 auto group = sibling_group(mut);
1072 for (
auto m : group)
1074 for (
auto m : group)
1076 order_.emplace_back(group.front());
1077 if (group.size() > 1) mutual_.emplace(group.front(),
DefVec(group.begin(), group.end()));
1081 fe::Vector<Def*> sibling_group(Def* mut)
const {
1082 auto node = (*nest_)[mut];
1083 if (!node || !node->is_mutually_recursive())
return {mut};
1084 if (
auto key = owner(node->inest()); key && inlines(key))
return {mut};
1086 auto group = fe::Vector<Def*>();
1087 for (
auto member : node->scc())
1088 if (
auto m = member->mut(); m == mut || !done_.contains(m)) group.emplace_back(m);
1089 if (group.size() < 2 || !std::ranges::all_of(group, [
this](Def* m) { return groupable(m); }))
return {mut};
1093 bool groupable(Def* mut)
const {
1094 if (!isa_decl(mut) || ctx_.arms.contains(mut) || mut->isa<Rule>() || !mut->is_set())
return false;
1095 if (
auto lam = mut->isa_mut<Lam>())
return curry_chain(lam).back()->is_set();
1099 void schedule_body(Def* mut) {
1100 auto chain = mut->isa_mut<
Lam>() ? curry_chain(mut->as_mut<Lam>()) : fe::Vector<
Lam*>();
1102 if (
auto rule = mut->isa_mut<Rule>()) {
1104 printed_deps(rule->type(), [&](const Def* op) { schedule_inline(op, ctx_.inlined); });
1105 printed_deps(rule, [&](
const Def* op) { schedule_inline(op, ctx_.inlined); });
1106 }
else if (chain.empty()) {
1107 for (
auto op : mut->deps())
1110 for (
auto* lam : chain)
1111 if (lam != mut) done_.emplace(lam), absorbed_.emplace(lam, mut);
1113 for (
auto* lam : chain) {
1114 schedule_inline(lam->type()->dom(), ctx_.header);
1115 if (
auto var = lam->has_var()) schedule_proj_types(var);
1116 schedule_inline(lam->filter(), ctx_.header);
1117 if (lam == chain.back()) {
1118 schedule_inline(lam->type()->codom(), ctx_.header);
1119 schedule_tail(lam->body());
1126 void schedule_proj_types(
const Def* def) {
1127 auto n = def->num_tprojs();
1129 for (
size_t i = 0; i != n; ++i)
1130 if (
auto proj = def->proj(n, i)) {
1131 schedule_inline(proj->type(), ctx_.header);
1132 schedule_proj_types(proj);
1137 void schedule_inline(
const Def* def,
DefSet& inline_set) {
1138 if (!def || def->is_closed() || has_decl(&ctx_, def))
return schedule_(def);
1139 if (!inline_set.emplace(def).second)
return;
1141 printed_deps(def, [&](
const Def* op) { schedule_inline(op, inline_set); });
1145 void schedule_tail(
const Def* def) {
1146 if (def && def->isa<
Var>()) ctx_.whole_vars.emplace(def);
1147 if (!def || has_decl(&ctx_, def))
return schedule_(def);
1148 if (!done_.emplace(def).second)
return finish(def);
1155 bool enter(
Def* mut)
const {
1156 auto node = (*nest_)[mut];
1157 if (!node || mode_ != Dump::Scope)
return node !=
nullptr;
1158 while (!node->inest()->is_root())
1159 node = node->inest();
1160 return scope_.contains(node->mut());
1165 for (
auto def : order_) {
1166 auto mut = isa_decl(def);
1167 auto key = owner(nest_->inest(def));
1169 if (def->isa<
Nom>()) {
1170 while (key && inlines(key))
1171 key = owner((*nest_)[key]->inest());
1175 if (key && inlines(key) && !(mut && is_recursive(mut))) {
1176 ctx_.inlined.emplace(def);
1179 (key ? bucket_[key] : top_).emplace_back(def);
1185 bool inlines(
Def* mut)
const {
1186 for (
auto node = (*nest_)[mut]; node; node = node->inest())
1187 if (
auto m = owner(node); m && (!isa_decl(m) || ctx_.arms.contains(m)))
return true;
1191 bool is_recursive(
Def* mut)
const {
return (*nest_)[mut]->is_recursive(); }
1195 if (!node)
return nullptr;
1196 auto mut = node->mut();
1197 if (!mut)
return nullptr;
1198 if (
auto outer = fe::lookup(absorbed_, mut))
return outer;
1206 auto defs = key ? std::move(bucket_[key]) : std::move(top_);
1207 group_noms(*nest_, defs);
1208 for (
auto def : defs) {
1209 if (deferred_.contains(def))
continue;
1210 auto group = fe::lookup(mutual_, def);
1211 sep(group || isa_decl(def) ? Prev::Decl : Prev::Let);
1213 emit_mutual(*group, [
this](
const Def* m) { emit_item(m); });
1219 void emit_item(
const Def* def) {
1220 if (
auto mut = isa_decl(def))
return emit_decl(mut);
1225 void emit_nom(std::string_view kw, std::string_view name,
const Nom* nom) {
1226 if (
auto variant = nom->op()->isa<
Variant>())
1227 return std::println(os_,
"{}{} {} = {};", ctx_.tab, kw, name, ctors(&ctx_, variant));
1228 std::println(os_,
"{}{} {} = {};", ctx_.tab, kw, name, Op(&ctx_, nom->op()));
1234 void group_noms(
const Nest& nest,
const DefVec& defs) {
1236 for (
auto def : defs) {
1237 auto nom = def->isa<
Nom>();
1238 if (!nom || grouped.contains(nom))
continue;
1239 for (
auto mut : nom->local_muts()) {
1240 auto node = nest[mut];
1241 if (!node || !node->is_recursive())
continue;
1242 auto on_cycle = scc_noms(nest, node->scc());
1245 if (on_cycle.contains(d)) cycle.emplace_back(d);
1246 if (cycle.size() > 1) {
1247 grouped.insert(cycle.begin(), cycle.end());
1248 deferred_.insert(cycle.begin(), cycle.end() - 1);
1249 mutual_.emplace(cycle.back(), std::move(cycle));
1258 auto reaches_scc = [&](
const Def* nom) {
1259 return std::ranges::any_of(nom->local_muts(), [&](
Def* mut) { return scc.contains(nest[mut]); });
1264 for (
auto node : scc)
1265 for (
auto dep : node->mut()->deps())
1266 if (dep && seen.emplace(dep).second) todo.emplace_back(dep);
1267 while (!todo.empty()) {
1268 auto def = todo.back();
1270 if (def->isa_mut())
continue;
1271 if (def->isa<
Nom>() && reaches_scc(def)) res.emplace(def);
1272 for (
auto dep : def->deps())
1273 if (dep && seen.emplace(dep).second) todo.emplace_back(dep);
1278 void emit_mutual(
const DefVec& group,
auto emit_member) {
1279 std::println(os_,
"{}mutual", ctx_.tab);
1282 auto _ = fe::Restore(prev_, Prev::None);
1283 for (
auto def : group) {
1284 sep(isa_decl(def) ? Prev::Decl : Prev::Let);
1288 std::println(os_,
"{}end", --ctx_.tab);
1292 void sep(Prev curr) {
1293 if (prev_ == Prev::Decl || (prev_ == Prev::Let && curr == Prev::Decl)) os_ <<
'\n';
1297 void emit_let(
const Def* def) {
1298 if (
auto nom = def->isa<
Nom>())
return emit_nom(
"nom", name(&ctx_, nom), nom);
1299 auto type = typed_let_ ? std::format(
": {}", Op(&ctx_, def->type())) : std::string();
1300 std::println(os_,
"{}let {}{} = {};", ctx_.tab, name(&ctx_, def), type, Full(&ctx_, def));
1303 void emit_decl(
Def* mut) {
1304 if (
auto lam = mut->isa_mut<
Lam>())
return emit_lam(lam);
1305 if (
auto rule = mut->isa_mut<
Rule>(); rule && rule->
is_set())
return emit_rule(rule);
1306 if (!mut->is_set())
return emit_unset(mut);
1308 auto kw = is_recursive(mut) ?
"rec " :
"let ";
1310 if (
auto variant = mut->isa<
Variant>())
1311 return std::println(os_,
"{}{}{} = {};", ctx_.tab, kw,
id(&ctx_, mut), ctors(&ctx_, variant));
1312 std::println(os_,
"{}{}{} = {};", ctx_.tab, kw,
id(&ctx_, mut), Full(&ctx_, mut));
1315 void emit_rule(
Rule* rule) {
1316 auto dom = rule->dom();
1317 auto num = num_binders(dom);
1318 std::print(os_,
"{}rule {} ", ctx_.tab,
id(&ctx_, rule));
1319 auto var = rule->has_var();
1320 curry(os_, &ctx_, var, dom,
false, num, num, num != 0 && split(&ctx_, var, dom, num),
false);
1321 std::print(os_,
": {}", Full(&ctx_, rule->lhs()));
1322 if (rule->guard() != rule->world().lit_tt()) std::print(os_,
" when {}", Full(&ctx_, rule->guard()));
1323 std::println(os_,
" => {};", Full(&ctx_, rule->rhs()));
1327 void emit_unset(
Def* mut) {
1328 std::println(os_,
"{}// `{}: {}` is unset", ctx_.tab,
id(&ctx_, mut), Op(&ctx_, mut->type()));
1331 void emit_lam(
Lam* lam) {
1332 auto chain = curry_chain(lam);
1333 auto last = chain.back();
1334 auto fun = isa_fun(&ctx_, last) && !shadows_ret(last);
1339 if (
auto var =
last->has_var()) {
1340 if (
auto num = num_binders(
last->type()->dom()); num == 1)
1341 ctx_.names.emplace(var,
"return");
1343 ctx_.ret_projs.emplace(var, num - 1);
1348 if (!
last->is_set())
return emit_bodyless(lam, chain, fun, con);
1351 auto ref =
id(&ctx_, lam);
1352 for (
size_t i = 1; i != chain.size(); ++i) {
1353 auto var = chain[i - 1]->has_var();
1355 ref += std::format(
" {}{}", chain[i - 1]->
type()->is_implicit() ?
"@" :
"", name(&ctx_, var));
1356 ctx_.names.emplace(chain[i], std::format(
"({})", ref));
1359 std::print(os_,
"{}{}{} {}", ctx_.tab, external(lam), fun ?
"fun" : con ?
"con" :
"lam",
id(&ctx_, lam));
1361 auto _ = fe::Restore(ctx_.in_header,
true);
1362 for (
auto* c : chain) {
1364 lam_ptrn(os_, &ctx_, c, fun, con, c == last, !fun || c != last);
1366 lam_codom(os_, &ctx_, last, fun, con);
1371 rets_.emplace_back(fun ?
last->has_var() :
nullptr);
1372 auto _ = fe::Restore(prev_, Prev::None);
1375 emit_tail(
last->body(),
";");
1381 void emit_bodyless(
Lam* lam,
const fe::Vector<Lam*>& chain,
bool fun,
bool con) {
1382 auto last = chain.back();
1383 auto dom =
last->type()->dom();
1384 std::print(os_,
"{}extern {} {}", ctx_.tab, fun ?
"fun" : con ?
"con" :
"lam",
id(&ctx_, lam));
1385 auto num = num_binders(dom);
1387 std::println(os_,
"[{}]: {};", Op(&ctx_, dom->proj(num, 0)), Op(&ctx_,
last->ret_dom()));
1388 }
else if (
auto [_, var] = dom->isa_binder<
Sigma>(); var) {
1390 std::println(os_,
"{}{};", Op(&ctx_, dom),
1391 con ? std::string() : std::format(
": {}", Op(&ctx_,
last->type()->codom())));
1393 std::println(os_,
"[{}]{};", Op::map(&ctx_, dom->projs(num)),
1394 con ? std::string() : std::format(
": {}", Op(&ctx_,
last->type()->codom())));
1398 void emit_tail(
const Def* def, std::string_view end) {
1399 std::println(os_,
"{}{}{}", ctx_.tab,
tail(&ctx_, def), end);
1404 bool shadows_ret(
Lam* lam)
const {
1405 for (
auto* var : rets_)
1406 if (var && lam->has_free_var(var))
return true;
1414 const Nest* nest_ =
nullptr;
1415 Prev prev_ = Prev::None;
1416 fe::Vector<const Var*> rets_;
1441 if (def ==
nullptr)
return os <<
"<nullptr>";
1443 return os << Op(
nullptr, def);
1447 auto _ =
world().freeze();
1448 if (mode ==
Dump::Expr)
return os <<
this << std::endl;
1449 Dumper(os, mode,
world().
flags().mim_typed_let).dump(
this);
1457 auto ofs = std::ofstream(file);
1462 auto file = id(
nullptr,
this) +
".mim"s;
1463 write(mode, file.c_str());
1477 auto reserved = fe::Vector<std::string>{
"return"};
1478 for (
const auto&
import :
driver().imports()) {
1479 srcs.emplace(
import.src);
1480 auto kw =
import.tag == ast::Tok::Tag::K_plugin ?
"plugin" :
"import";
1481 auto module = import.src->path().stem().string();
1484 if (is_mod) reserved.emplace_back(std::move(module));
1488 std::print(os,
"{} \"{}\"{};\n", kw,
ast::Lexer::escape(
import.src->path().generic_string()),
1489 is_mod ?
"" :
" as *");
1491 std::print(os,
"{} {};\n", kw,
import.
sym);
1494 if (!
driver().imports().entries().empty() &&
externals().size() != 0) os <<
'\n';
1497 reserved.emplace_back(mut->sym().str());
1502 auto generics = ankerl::unordered_dense::map<flags_t, std::pair<Sym, fe::Vector<Lam*>>>();
1503 auto lib =
driver().library();
1504 for (
auto world : {
this, lib ==
this ? nullptr : lib})
1506 for (
auto [
sym, def] : world->annexes().entries())
1507 if (
auto lam = def->isa_mut<
Lam>();
lam && !
sym.view().starts_with(self)) {
1508 auto chain = curry_chain(
lam);
1509 if (
auto body = chain.back()->body())
1510 if (
auto nom = body->isa<
Nom>()) generics.emplace(
nom->key(), std::pair{sym, std::move(chain)});
1515 auto annexes = fe::Vector<DumpAnnex>();
1517 auto seen =
DefSet(todo.begin(), todo.end());
1518 while (!todo.empty()) {
1519 auto def = todo.back();
1521 if ((def->isa<
Axm>() || is_anx_nom(def)) && def->sym().view().starts_with(self)) {
1522 auto sym = def->sym();
1523 auto name =
sym.view().substr(self.size());
1525 auto mod =
dot == std::string_view::npos ? std::string_view() :
name.substr(0,
dot);
1526 reserved.emplace_back(mod.empty() ?
name : mod);
1527 annexes.emplace_back(std::string(mod), std::string(mod.empty() ?
name :
name.substr(
dot + 1)), def);
1529 if (
auto nom = def->isa<
Nom>())
1530 if (
auto generic = fe::lookup(generics,
nom->key()))
1531 if (
auto args = Instantiation(generic->second).args(
nom))
1532 insts.emplace(
nom, std::pair{
generic->first, std::move(*args)});
1533 for (
auto dep : def->deps())
1534 if (dep && seen.emplace(dep).second) todo.emplace_back(dep);
1536 std::ranges::sort(
annexes, {}, [](
const auto& a) {
return a.def->flags(); });
1539 dumper.plain(reserved);
1541 dumper.insts(std::move(insts));
1542 if (!
annexes.empty()) dumper.dump_annexes(std::move(self),
annexes);
1545 assertf(old_gid ==
curr_gid(),
"new nodes created during dump. old_gid: {}; curr_gid: {}", old_gid,
curr_gid());
1555 auto ofs = std::ofstream(file);
1561 write(file.c_str());
A (possibly paramterized) Array.
static std::pair< u8, u8 > infer_curry_and_trip(const Def *type)
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
void dump() const
Dump::Expr - one line, no analysis.
World & world() const noexcept
constexpr flags_t flags() const noexcept
friend std::ostream & operator<<(std::ostream &, const Def *)
Def::Dump::Expr: one Def, one line, no analysis - and the backend of std::formatter for every Def poi...
bool has_free_var(const Var *) const
Same as free_vars().contains(var).
std::ostream & stream(std::ostream &, Dump) const
bool is_external() const noexcept
@ Expr
Only this Def; whatever does not inline is referenced by its name.
@ All
Plus everything else that is reachable.
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
Common base for TExtremum.
This node is a hole in the IR that is inferred by its context later on.
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.
Constructs a Join or Variant value.
Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
A union type whose ops are sorted and deduplicated: T ∪ T is T.
static const Lam * isa_cn(const Def *d)
static const Lam * isa_returning(const Def *d)
static std::optional< T > isa(const Def *def)
Scrutinize Match::scrutinee() and dispatch to Match::arms.
Nominal newtype term introduction.
GIDSet< const Node * > SCC
Strongly Connected Component.
Builds a nesting tree for all mutables/binders.
Nominal newtype formation.
A (possibly paramterized) Tuple.
A dependent function type.
static const Pi * isa_cn(const Def *d)
static const Pi * isa_basicblock(const Def *d)
const Def * codom() const
static const Pi * isa_implicit(const Def *d)
Is d an Pi::is_implicit Pi?
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.
Used as intermediate value during optimizatinos such as Analysis.
Base class for Arr and Pack.
bool is_fused() const
Does this span several axes? Also true for a dynamic rank.
Singleton type formation.
Nominal newtype term elimination.
Data constructor for a Sigma.
A variable introduced by a binder (mutable).
A sum type whose cases are positional: unlike a Join, they are neither sorted nor deduplicated.
The World represents the whole program and manages creation of MimIR nodes (Defs).
const Def * level(Defs types)
The lmax of the levels of all types, each of which must be a Type level.
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
const fe::Log & log() const
Log via log().e("...", args) etc.; owned by the Driver.
void dot(std::ostream &os, DotConfig cfg={}) const
Dumps DOT to os, configured via cfg (see DotConfig).
const Lam * lam(const Pi *pi, Lam::Filter f, const Def *body)
Flags & flags()
Retrieve compile Flags.
void debug_dump()
Dump in Debug build if World::log::level is fe::Log::Level::Debug.
Sym sym(std::string_view)
void write(const char *file)
Write to a file named file.
const Nom * nom(flags_t key, const Def *type)
Make type Nominal under key.
const Externals & externals() const
auto freeze() const
Freezes the World until the end of the scope and restores the previous frozen state afterwards:
void dump(std::ostream &os)
Dump to os.
Singleton term introduction.
static bool is_id(std::string_view str)
Does str match the id production - the same rule Lexer::lex_id applies to the input?
static std::string escape(std::string_view str)
Inverse of Lexer::lex_char: renders str as the body of a Mim string literal.
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.
@ bot
Alias for Mode::fast.
void post_order(Def *mut, MutSet &done, fe::Vector< Def * > &res, MutPred auto descend, MutPred auto collect)
Appends the mutables reachable from mut via Def::deps / Def::local_muts to res in post-order: callees...
GIDMap< const Def *, To > DefMap
static std::string file_stem(World &world)
The name of the file a World is dumped to - and hence the module its own annexes live in.
fe::Vector< const Def * > DefVec
GIDSet< const Def * > DefSet
std::ostream & operator<<(std::ostream &os, const Def *def)
Def::Dump::Expr: one Def, one line, no analysis - and the backend of std::formatter for every Def poi...
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.
GIDMap< Def *, To > MutMap