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 (def_->dep_const())
return true;
59 if (
auto mut = def_->isa_mut()) {
60 if (isa_decl(mut))
return false;
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<Axiom>())
return app->callee_type()->num_doms() <= 1;
78 friend std::ostream&
operator<<(std::ostream&, Inline);
82template<
bool L>
struct LRPrec {
83 LRPrec(
const Def* l,
const Def* r)
91 friend std::ostream&
operator<<(std::ostream& os,
const LRPrec& p) {
94 return print(os,
"{}", p.l);
97 return print(os,
"{}", p.r);
102using LPrec = LRPrec<true>;
103using RPrec = LRPrec<false>;
105std::ostream&
operator<<(std::ostream& os, Inline u) {
106 if (
u.dump_gid_ == 2 || (
u.dump_gid_ == 1 && !
u->isa<Var>() &&
u->num_ops() != 0))
print(os,
"/*{}*/",
u->gid());
107 if (
auto mut =
u->isa_mut(); mut && !mut->is_set())
return os <<
"unset";
109 bool ascii =
u->world().flags().ascii;
110 auto arw = ascii ?
"->" :
"→";
111 auto al = ascii ?
"<<" :
"«";
112 auto ar = ascii ?
">>" :
"»";
113 auto pl = ascii ?
"(<" :
"‹";
114 auto pr = ascii ?
">)" :
"›";
116 if (
auto type =
u->isa<Type>()) {
117 if (
auto level =
Lit::isa(type->level()); level && !ascii) {
118 if (level == 0)
return print(os,
"★");
119 if (level == 1)
return print(os,
"□");
121 return print(os,
"(.Type {})", type->level());
122 }
else if (
u->isa<Nat>()) {
123 return print(os,
".Nat");
124 }
else if (
u->isa<Idx>()) {
125 return print(os,
".Idx");
126 }
else if (
auto ext =
u->isa<Ext>()) {
127 auto x = ext->isa<
Bot>() ? (ascii ?
".bot" :
"⊥") : (ascii ?
".top" :
"⊤");
128 if (ext->type()->isa<Nat>())
return print(os,
"{}:{}", x, ext->type());
129 return print(os,
"{}:({})", x, ext->type());
130 }
else if (
auto top =
u->isa<
Top>()) {
131 return print(os,
"{}:({})", ascii ?
".top" :
"⊤",
top->type());
132 }
else if (
auto axiom =
u->isa<Axiom>()) {
133 const auto name = axiom->sym();
134 return print(os,
"{}{}", name[0] ==
'%' ?
"" :
"%", name);
135 }
else if (
auto lit =
u->isa<Lit>()) {
136 if (
lit->type()->isa<Nat>()) {
137 switch (
lit->get()) {
139 case 0x0'0000'0100_n:
return os <<
".i8";
140 case 0x0'0001'0000_n:
return os <<
".i16";
141 case 0x1'0000'0000_n:
return os <<
".i32";
143 default:
return print(os,
"{}",
lit->get());
149 case 0x0'0000'0002_n:
return os << (
lit->get<
bool>() ?
".tt" :
".ff");
150 case 0x0'0000'0100_n:
return os <<
lit->get() <<
"I8";
151 case 0x0'0001'0000_n:
return os <<
lit->get() <<
"I16";
152 case 0x1'0000'0000_n:
return os <<
lit->get() <<
"I32";
153 case 0_n:
return os <<
lit->get() <<
"I64";
156 std::vector<uint8_t> digits;
157 for (
auto z = *s; z; z /= 10) digits.emplace_back(z % 10);
161 for (
auto d : digits |
std::ranges::views::reverse)
164 for (
auto d : digits |
std::ranges::views::reverse)
165 os << uint8_t(0xE2) << uint8_t(0x82) << (uint8_t(0x80 +
d));
173 if (
lit->type()->isa<App>())
return print(os,
"{}:({})",
lit->get(),
lit->type());
174 return print(os,
"{}:{}",
lit->get(),
lit->type());
175 }
else if (
auto ex =
u->isa<Extract>()) {
176 if (ex->tuple()->isa<Var>() && ex->index()->isa<Lit>())
return print(os,
"{}", ex->unique_name());
177 return print(os,
"{}#{}", ex->tuple(), ex->index());
178 }
else if (
auto var =
u->isa<Var>()) {
179 return print(os,
"{}", var->unique_name());
180 }
else if (
auto pi =
u->isa<Pi>()) {
182 if (
auto mut = pi->isa_mut<Pi>(); mut && mut->var())
183 return print(os,
"Π {}: {} {} {}", mut->var(), pi->dom(), arw, pi->codom());
184 return print(os,
"Π {} {} {}", pi->dom(), arw, pi->codom());
185 }
else if (
auto lam =
u->isa<Lam>()) {
186 return print(os,
"{}, {}", lam->filter(), lam->body());
187 }
else if (
auto app =
u->isa<App>()) {
192 case 0x0'0000'0002_n:
return os <<
".Bool";
193 case 0x0'0000'0100_n:
return os <<
".I8";
194 case 0x0'0001'0000_n:
return os <<
".I16";
195 case 0x1'0000'0000_n:
return os <<
".I32";
196 case 0_n:
return os <<
".I64";
202 return print(os,
"{} {}", LPrec(app->callee(), app), RPrec(app, app->arg()));
203 }
else if (
auto sigma =
u->isa<Sigma>()) {
204 if (
auto mut = sigma->isa_mut<Sigma>(); mut && mut->var()) {
206 return print(os,
"[{, }]", Elem(sigma->ops(), [&](
auto op) {
207 if (auto v = mut->var(i++))
208 print(os,
"{}: {}", v, op);
213 return print(os,
"[{, }]", sigma->ops());
214 }
else if (
auto tuple =
u->isa<Tuple>()) {
215 print(os,
"({, })", tuple->ops());
216 return tuple->type()->isa_mut() ?
print(os,
":{}", tuple->type()) : os;
217 }
else if (
auto arr =
u->isa<Arr>()) {
218 if (
auto mut = arr->isa_mut<Arr>(); mut && mut->var())
219 return print(os,
"{}{}: {}; {}{}", al, mut->var(), mut->shape(), mut->body(), ar);
220 return print(os,
"{}{}; {}{}", al, arr->shape(), arr->body(), ar);
221 }
else if (
auto pack =
u->isa<Pack>()) {
222 if (
auto mut = pack->isa_mut<Pack>(); mut && mut->var())
223 return print(os,
"{}{}: {}; {}{}", pl, mut->var(), mut->shape(), mut->body(), pr);
224 return print(os,
"{}{}; {}{}", pl, pack->shape(), pack->body(), pr);
225 }
else if (
auto proxy =
u->isa<Proxy>()) {
226 return print(os,
".proxy#{}#{} {, }", proxy->pass(), proxy->tag(), proxy->ops());
227 }
else if (
auto bound =
u->isa<Bound>()) {
228 auto op = bound->isa<
Join>() ?
"∪" :
"∩";
229 if (
auto mut =
u->isa_mut())
print(os,
"{}{}: {}", op, mut->unique_name(), mut->type());
230 return print(os,
"{}({, })", op, bound->ops());
234 if (
u->flags() == 0)
return print(os,
"(.{} {, })",
u->node_name(),
u->ops());
235 return print(os,
"(.{}#{} {, })",
u->node_name(),
u->flags(),
u->ops());
248 Dumper(std::ostream& os,
const DepTree* dep =
nullptr)
254 void dump_let(
const Def*);
255 void dump_ptrn(
const Def*,
const Def*);
256 void recurse(
const DepNode*);
257 void recurse(
const Def*,
bool first =
false);
262 unique_queue<MutSet> muts;
266void Dumper::dump(Def* mut) {
267 if (
auto lam = mut->isa<Lam>()) {
272 auto mut_prefix = [&](
const Def* def) {
273 if (def->isa<Sigma>())
return ".Sigma";
274 if (def->isa<Arr>())
return ".Arr";
275 if (def->isa<Pack>())
return ".pack";
276 if (def->isa<Pi>())
return ".Pi";
280 auto mut_op0 = [&](
const Def* def) -> std::ostream& {
281 if (
auto sig = def->isa<Sigma>())
return print(os,
", {}", sig->num_ops());
282 if (
auto arr = def->isa<Arr>())
return print(os,
", {}", arr->shape());
283 if (
auto pack = def->isa<Pack>())
return print(os,
", {}", pack->shape());
284 if (
auto pi = def->isa<Pi>())
return print(os,
", {}", pi->dom());
288 if (!mut->is_set()) {
289 tab.print(os,
"{}: {} = {{ <unset> }};",
id(mut), mut->type());
293 tab.print(os,
"{} {}{}: {}", mut_prefix(mut), external(mut),
id(mut), mut->type());
296 if (
auto e = mut->num_vars();
e != 1) {
297 print(os,
"{, }", Elem(mut->vars(), [&](
auto def) {
299 os << def->unique_name();
304 print(os,
", @{}", mut->var()->unique_name());
307 tab.println(os,
" = {{");
309 if (dep) recurse(dep->mut2node(mut));
311 tab.print(os,
"{, }\n", mut->ops());
313 tab.print(os,
"}};\n");
316void Dumper::dump(Lam* lam) {
318 auto ptrn = [&](
auto&) { dump_ptrn(lam->var(), lam->type()->dom()); };
321 tab.println(os,
".con {}{} {}@({}) = {{", external(lam),
id(lam), ptrn, lam->filter());
323 tab.println(os,
".lam {}{} {}: {} = {{", external(lam),
id(lam), ptrn, lam->type()->codom());
327 if (dep) recurse(dep->mut2node(lam));
328 recurse(lam->filter());
329 recurse(lam->body(),
true);
330 if (lam->body()->isa_mut())
331 tab.print(os,
"{}\n", lam->body());
333 tab.print(os,
"{}\n", Inline(lam->body()));
335 tab.print(os,
" <unset>\n");
338 tab.print(os,
"}};\n");
341void Dumper::dump_let(
const Def* def) {
342 tab.print(os,
".let {}: {} = {};\n", def->unique_name(), def->type(), Inline(def, 0));
345void Dumper::dump_ptrn(
const Def* def,
const Def* type) {
349 auto projs = def->tprojs();
350 if (projs.size() == 1 || std::ranges::all_of(projs, [](
auto def) { return !def; })) {
351 print(os,
"{}: {}", def->unique_name(), type);
354 print(os,
"{}::[{, }]", def->unique_name(),
355 Elem(projs, [&](
auto proj) { dump_ptrn(proj, type->proj(i++)); }));
360void Dumper::recurse(
const DepNode* node) {
361 for (
auto child : node->children())
362 if (auto mut = isa_decl(child->mut())) dump(mut);
365void Dumper::recurse(
const Def* def,
bool first ) {
366 if (
auto mut = isa_decl(def)) {
367 if (!dep) muts.push(mut);
371 if (!defs.emplace(def).second)
return;
373 for (
auto op : def->partial_ops()) {
378 if (!first && !Inline(def)) dump_let(def);
392 if (def ==
nullptr)
return os <<
"<nullptr>";
395 return os << Inline(def);
397 return os << id(def);
402 auto dumper = Dumper(os);
405 os <<
this << std::endl;
406 }
else if (
auto mut = isa_decl(
this)) {
407 dumper.muts.push(mut);
409 dumper.recurse(
this);
410 dumper.tab.print(os,
"{}\n", Inline(
this));
414 for (; !dumper.muts.empty() && max > 0; --max) dumper.dump(dumper.muts.pop());
419void Def::dump()
const { std::cout <<
this << std::endl; }
423 auto ofs = std::ofstream(file);
428 auto file = id(
this) +
".thorin"s;
429 write(max, file.c_str());
440 if (
flags().dump_recursive) {
441 auto dumper = Dumper(os);
442 for (
const auto& [_, mut] :
externals()) dumper.muts.push(mut);
443 while (!dumper.muts.empty()) dumper.dump(dumper.muts.pop());
446 auto dumper = Dumper(os, &dep);
450 dumper.recurse(dep.root());
453 assertf(old_gid ==
curr_gid(),
"new nodes created during dump. old_gid: {}; curr_gid: {}", old_gid,
curr_gid());
463 auto ofs = std::ofstream(file);
468 auto file =
name().str() +
".thorin"s;
void write(int max) const
std::ostream & stream(std::ostream &, int max) const
bool is_loaded(Sym sym) const
static Ref size(Ref def)
Checks if def is a .Idx s and returns s or nullptr otherwise.
static const Lam * isa_cn(Ref d)
static std::optional< T > isa(Ref def)
static const Pi * isa_cn(Ref d)
Is this a continuation - i.e. is the Pi::codom thorin::Bottom?
Helper class to retrieve Infer::arg if present.
static constexpr std::array< Prec, 2 > prec(Prec p)
void write()
Same above but file name defaults to World::name.
Flags & flags()
Retrive compile Flags.
const auto & externals() const
const Driver & driver() const
void dump()
Dump to std::cout.
void debug_dump()
Dump in Debug build if World::log::level is Log::Level::Debug.
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
Ref op(trait o, Ref type)
std::ostream & print(std::ostream &os, const char *s)
Base case.
GIDSet< const Def * > DefSet
std::ostream & operator<<(std::ostream &, const CFNode *)
#define assertf(condition,...)
Use to World::freeze and automatically unfreeze at the end of scope.