20 BB(
BB&& other)
noexcept =
default;
23 std::deque<std::ostringstream>&
head() {
return parts[0]; }
24 std::deque<std::ostringstream>&
body() {
return parts[1]; }
25 std::deque<std::ostringstream>&
tail() {
return parts[2]; }
27 template<
class... Args>
28 void body(
const char* s, Args&&... args) {
29 print(
body().emplace_back(), s, std::forward<Args>(args)...);
32 template<
class... Args>
33 void tail(
const char* s, Args&&... args) {
34 print(
tail().emplace_back(), s, std::forward<Args>(args)...);
37 template<
class... Args>
38 std::string
assign(
Tab tab, std::string name,
const char* s, Args&&... args) {
41 auto& os =
body().emplace_back();
42 print(tab.
lnprint(os,
"(let {} ", name), s, std::forward<Args>(args)...);
48 std::string
assign(
Tab tab, std::string name, Fn&& print_term) {
51 auto& os =
body().emplace_back();
52 tab.
lnprint(os,
"(let {} ", name);
60 swap(a.parts, b.parts);
63 std::array<std::deque<std::ostringstream>, 3>
parts;
76 bool is_valid(std::string_view s) {
return !s.empty(); }
77 void start()
override;
86 std::string
emit_cons(std::vector<std::string> op_vals);
87 std::string
emit_node(
BB& bb,
const Def* def, std::string node_name,
bool variadic =
false,
bool with_type =
false);
91 std::string id(
const Def*,
bool is_var_use =
false)
const;
92 std::string indent(
size_t tabs, std::string term);
93 std::string
flatten(std::string term);
97 bool slotted()
const {
return slotted_; }
100 std::ostringstream decls_;
101 std::ostringstream func_decls_;
102 std::ostringstream func_impls_;
105std::string Emitter::id(
const Def* def,
bool is_var_use)
const {
106 std::string prefix = slotted() ?
"$" :
"";
110 auto var_wrap = [&](std::string id) {
return slotted() && is_var_use ?
"(var " +
id +
")" : id; };
114 id = def->sym().str();
115 else if (def->isa<
Rule>())
116 id = def->sym().str();
117 else if (def->isa<
Lam>() && !def->is_set())
118 id = def->sym().str();
119 else if (def->is_external())
120 id = def->sym().str();
122 id = def->unique_name();
124 return var_wrap(prefix +
id);
141std::string Emitter::indent(
size_t tabs, std::string term) {
142 std::string indent(tabs * 4,
' ');
146 while (!term.empty() && (term.front() ==
'\n' || term.front() ==
'\r'))
149 std::stringstream term_stream(term);
150 size_t min_indent = term.find_first_not_of(
' ');
151 while (std::getline(term_stream, line)) {
153 if (line.find_first_not_of(
" \t\r\n") == std::string::npos)
continue;
154 result +=
"\n" + indent + line.substr(min_indent);
171std::string Emitter::flatten(std::string term) {
172 term = std::regex_replace(term, std::regex(
"( {4})"),
"");
174 while (!term.empty() && (term.front() ==
'\n' || term.front() ==
'\r'))
177 term = std::regex_replace(term, std::regex(
"(\\r|\\n)"),
" ");
185 ostream() << func_decls_.str();
186 ostream() << func_impls_.str();
196 const std::string ext = lam->
is_external() ?
"extern" :
"intern";
199 print(func_decls_,
"(con {} {}", ext,
id(lam));
211 if (
root()->sym().str() ==
"_fallback_compile")
return;
236 auto unclosed_bindings = 0;
237 for (
auto op : lam->
deps()) {
239 if (
auto next =
nest()[mut]) {
240 if (next->mut()->isa<
Lam>() && !done.contains(next->mut())) {
241 auto next_lam = next->mut()->as_mut<
Lam>();
248 for (
auto& term : bb.body()) {
249 auto opened = std::ranges::count(term.str(),
'(');
250 auto closed = std::ranges::count(term.str(),
')');
251 unclosed_bindings += opened - closed;
252 print(func_impls_,
"{}", indent(
tab.indent(), term.str()));
255 for (
auto& term : bb.tail())
256 print(func_impls_,
"{}", indent(
tab.indent(), term.str()));
258 std::string closing_parens(unclosed_bindings,
')');
259 print(func_impls_,
"{}", closing_parens);
263 print(func_impls_,
")\n\n");
266 print(func_impls_,
")");
271 std::ostringstream os;
275 tab.lnprint(os,
"{}",
id(var));
282 auto projs = var->
projs();
283 if (projs.size() == 1 || std::ranges::all_of(projs, [](
auto proj) { return proj->sym().empty(); }))
284 tab.lnprint(os,
"(var {} {})",
id(var),
emit_type(bb, type));
286 tab.lnprint(os,
"(var {}",
id(var));
288 for (
auto proj : projs)
289 tab.print(os,
" {}",
emit_var(bb, proj, type->proj(i++)));
299 std::ostringstream os;
303 const std::string lam_kind = lam->
isa_cn(lam) ?
"con" :
"lam";
304 const std::string ext = lam->
is_external() ?
"extern" :
"intern";
307 tab.lnprint(os,
"(let {}",
id(lam));
309 tab.lnprint(os,
"({} {} {}", lam_kind, ext,
id(lam));
311 tab.print(os,
"({} {} {}", lam_kind, ext,
id(lam));
318 tab.lnprint(os,
"(sigma");
320 for (
auto codom : lam->codoms())
333 if (
auto i =
types_.find(type); i !=
types_.end())
return i->second;
335 std::ostringstream os;
336 if (type->isa<
Nat>()) {
338 }
else if (
auto size =
Idx::isa(type)) {
341 case 1:
return types_[type] =
"Bool";
342 case 8:
return types_[type] =
"I8";
343 case 16:
return types_[type] =
"I16";
344 case 32:
return types_[type] =
"I32";
345 case 64:
return types_[type] =
"I64";
349 print(os,
"(idx (lit {}))", size);
350 }
else if (
auto lit = type->isa<
Lit>()) {
351 if (lit->type()->isa<
Nat>())
352 print(os,
"(lit {})", lit->get());
355 }
else if (
auto arr = type->isa<
Arr>()) {
356 if (
auto arity =
Lit::isa(arr->arity())) {
359 }
else if (
auto top = arr->arity()->isa<
Top>()) {
364 }
else if (
auto pi = type->isa<
Pi>()) {
369 }
else if (
auto sigma = type->isa<
Sigma>()) {
370 print(os,
"(sigma { })",
Elem(sigma->ops(), [&](
auto op) { print(os,
"{}", emit_type(bb, op)); }));
371 }
else if (
auto tuple = type->isa<
Tuple>()) {
372 print(os,
"(tuple { })",
Elem(tuple->ops(), [&](
auto op) { print(os,
"{}", emit_type(bb, op)); }));
373 }
else if (
auto app = type->isa<
App>()) {
375 }
else if (
auto axm = type->isa<
Axm>()) {
376 print(os,
"{}",
id(axm));
377 if (!
world().flags2annex().contains(axm->flags()))
378 print(decls_,
"(axm {} {})\n\n",
id(axm),
emit_type(bb, axm->type()));
379 }
else if (
auto var = type->isa<
Var>()) {
380 print(os,
"{}",
id(var));
381 }
else if (
auto hole = type->isa<
Hole>()) {
382 print(os,
"(hole {})",
id(hole));
383 }
else if (
auto extract = type->isa<
Extract>()) {
384 auto tuple = extract->tuple();
385 auto index = extract->index();
387 auto is_nested_proj =
false;
389 auto curr_tuple = tuple;
390 auto curr_index = index;
391 while (curr_tuple !=
nullptr && curr_index !=
nullptr)
392 if (
auto lit =
Lit::isa(curr_index); lit && curr_tuple->isa<
Extract>()) {
393 curr_tuple = tuple->as<
Extract>()->tuple();
394 curr_index = tuple->as<
Extract>()->index();
396 }
else if (
auto lit =
Lit::isa(curr_index); lit && curr_tuple->isa<
Var>()) {
397 is_nested_proj =
true;
403 if (!slotted() && ((
Lit::isa(index) && tuple->isa<
Var>()) || is_nested_proj))
404 print(os,
"{}",
id(extract));
407 }
else if (
auto mType = type->isa<
Type>()) {
409 }
else if (type->isa<
Univ>()) {
411 }
else if (
auto reform = type->isa<
Reform>()) {
413 }
else if (
auto join = type->isa<
Join>()) {
414 print(os,
"(join { })",
Elem(join->ops(), [&](
auto op) { print(os,
"{}", emit_type(bb, op)); }));
415 }
else if (
auto meet = type->isa<
Meet>()) {
416 print(os,
"(meet { })",
Elem(meet->ops(), [&](
auto op) { print(os,
"{}", emit_type(bb, op)); }));
418 error(
"unsupported type '{}'", type);
422 return types_[type] = os.str();
429 std::ostringstream os;
432 for (
auto op_val : op_vals) {
434 tab.lnprint(os,
"(cons");
436 tab.print(os,
"{}", indent(
tab.indent(), op_val));
438 if (op_idx == op_vals.size() - 1)
tab.lnprint(os,
"nil");
444 std::string closing_brackets(op_vals.size(),
')');
445 print(os,
"{}", closing_brackets);
451 std::ostringstream os;
453 std::vector<std::string> op_vals;
456 if (
auto type_val =
emit_bb(bb, def->
type()); !type_val.empty()) op_vals.push_back(type_val);
460 if (
auto pack = def->isa<
Pack>())
461 if (
auto arity_val =
emit_bb(bb, pack->arity()); !arity_val.empty()) op_vals.push_back(arity_val);
463 for (
auto op : def->
ops())
464 if (
auto op_val =
emit_bb(bb, op); !op_val.empty()) op_vals.push_back(op_val);
466 if (def->
sym().empty()) {
467 tab.lnprint(os,
"({}", node_name);
469 if (slotted() && variadic)
472 for (
auto op_val : op_vals)
473 tab.print(os,
"{}", op_val);
480 tab.lnprint(os,
"({}", node_name);
482 if (slotted() && variadic)
486 for (
auto op_val : op_vals)
487 tab.print(os,
"{}", indent(
tab.indent(), op_val));
494 tab.lnprint(os,
"{}",
id(def,
true));
501 std::ostringstream os;
507 }
else if (
auto lam = def->isa<
Lam>()) {
508 tab.lnprint(os,
"{}",
id(lam,
true));
511 }
else if (
auto lit = def->isa<
Lit>()) {
512 if (lit->type()->isa<
Nat>()) {
514 auto nat_val = lit->get<
u64>();
516 case 0x100: alias =
"i8";
break;
517 case 0x10000: alias =
"i16";
break;
518 case 0x100000000: alias =
"i32";
break;
522 tab.lnprint(os,
"(lit {})", alias);
524 tab.lnprint(os,
"(lit {})", nat_val);
525 }
else if (
auto size =
Idx::isa(lit->type()))
527 tab.lnprint(os,
"(lit {})", lit);
529 tab.lnprint(os,
"(lit {} {})", lit->get(),
emit_type(bb, lit->type()));
531 tab.lnprint(os,
"(lit {})", lit);
533 }
else if (
auto tuple = def->isa<
Tuple>()) {
534 tab.print(os,
"{}",
emit_node(bb, tuple,
"tuple",
true));
536 }
else if (
auto pack = def->isa<
Pack>()) {
539 }
else if (
auto extract = def->isa<
Extract>()) {
540 auto tuple = extract->tuple();
541 auto index = extract->index();
546 auto is_nested_proj =
false;
548 auto curr_tuple = tuple;
549 auto curr_index = index;
550 while (curr_tuple !=
nullptr && curr_index !=
nullptr)
551 if (
auto lit =
Lit::isa(curr_index); lit && curr_tuple->isa<
Extract>()) {
552 curr_tuple = tuple->as<
Extract>()->tuple();
553 curr_index = tuple->as<
Extract>()->index();
555 }
else if (
auto lit =
Lit::isa(curr_index); lit && curr_tuple->isa<
Var>()) {
556 is_nested_proj =
true;
562 if (!slotted() && ((
Lit::isa(index) && tuple->isa<
Var>()) || is_nested_proj))
563 tab.lnprint(os,
"{}",
id(extract));
567 }
else if (
auto insert = def->isa<
Insert>()) {
570 }
else if (
auto var = def->isa<
Var>()) {
571 tab.lnprint(os,
"{}",
id(var,
true));
573 }
else if (
auto app = def->isa<
App>()) {
576 }
else if (
auto axm = def->isa<
Axm>()) {
577 tab.lnprint(os,
"{}",
id(axm));
578 if (!
world().flags2annex().contains(axm->flags()))
579 print(decls_,
"(axm {} {})\n\n",
id(axm),
emit_type(bb, axm->type()));
581 }
else if (
auto bot = def->isa<
Bot>()) {
582 if (bot->sym().empty())
583 tab.lnprint(os,
"(bot {})",
emit_type(bb, bot->type()));
586 tab.lnprint(os,
"{}",
id(bot,
true));
589 }
else if (
auto top = def->isa<
Top>()) {
590 if (top->sym().empty())
591 tab.lnprint(os,
"(top {})",
emit_type(bb, top->type()));
594 tab.lnprint(os,
"{}",
id(top,
true));
597 }
else if (
auto rule = def->isa<
Rule>()) {
598 auto lhs_val =
emit_bb(bb, rule->lhs());
599 auto rhs_val =
emit_bb(bb, rule->rhs());
600 auto guard_val =
emit_bb(bb, rule->guard());
601 tab.lnprint(os,
"(rule {} {} {})", lhs_val, rhs_val, guard_val);
602 print(decls_,
"(rule {} {} {})\n\n", indent(1, lhs_val), indent(1, rhs_val), indent(1, guard_val));
604 }
else if (
auto inj = def->isa<
Inj>()) {
605 tab.print(os,
"{}",
emit_node(bb, inj,
"inj",
false,
true));
607 }
else if (
auto merge = def->isa<
Merge>()) {
608 tab.print(os,
"{}",
emit_node(bb, merge,
"merge",
true,
true));
610 }
else if (
auto match = def->isa<
Match>()) {
611 tab.print(os,
"{}",
emit_node(bb, match,
"match",
true));
613 }
else if (
auto proxy = def->isa<
Proxy>()) {
614 auto type_val =
emit_bb(bb, proxy->type());
615 auto pass_val = proxy->pass();
616 auto tag_val = proxy->tag();
617 std::vector<std::string> op_vals;
618 for (
auto op : proxy->
ops())
619 if (
auto op_val =
emit_bb(bb, op); !op_val.empty()) op_vals.push_back(op_val);
621 if (proxy->sym().empty()) {
622 tab.lnprint(os,
"(proxy");
623 tab.print(os,
"{}", type_val);
627 tab.lnprint(os,
"{}", pass_val);
628 tab.lnprint(os,
"{}", tag_val);
630 for (
auto op_val : op_vals)
631 tab.print(os,
"{}", op_val);
634 bb.
assign(
tab,
id(proxy), [&](
auto& os) {
636 tab.lnprint(os,
"(proxy");
638 tab.print(os,
"{}", type_val);
640 tab.lnprint(os,
"{}", pass_val);
641 tab.lnprint(os,
"{}", tag_val);
643 for (
auto op_val : op_vals)
644 tab.print(os,
"{}", indent(
tab.indent(), op_val));
649 tab.lnprint(os,
"{}",
id(proxy,
true));
653 error(
"Unhandled Def in SExpr backend: {} : {}", def, def->
type());
662 Emitter emitter(world, ostream);
667 Emitter emitter(world, ostream,
true);
A (possibly paramterized) Array.
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
Defs deps() const noexcept
constexpr auto ops() const noexcept
const Def * var(nat_t a, nat_t i) noexcept
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
bool is_external() const noexcept
std::string unique_name() const
name + "_" + Def::gid
bool is_closed() const
Has no free_vars()?
std::string emit(const Def *def)
std::ostream & ostream() const
DefMap< std::string > types_
This node is a hole in the IR that is inferred by its context later on.
static constexpr nat_t size2bitwidth(nat_t n)
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
const Def * filter() const
static const Lam * isa_cn(const Def *d)
static std::optional< T > isa(const Def *def)
Scrutinize Match::scrutinee() and dispatch to Match::arms.
const Nest & nest() const
Def * mut() const
The mutable capsulated in this Node or nullptr, if it's a virtual root comprising several Nodes.
const Node * root() const
A (possibly paramterized) Tuple.
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
virtual void start()=0
Actual entry.
A dependent function type.
static const Pi * isa_cn(const Def *d)
Is this a continuation - i.e. is the Pi::codom mim::Bottom?
Keeps track of indentation level.
std::ostream & lnprint(std::ostream &os, const char *s, Args &&... args)
Same as Tab::print but prepends a std::endl to os.
Data constructor for a Sigma.
A variable introduced by a binder (mutable).
The World represents the whole program and manages creation of MimIR nodes (Defs).
void start() override
Actual entry.
std::string emit_node(BB &bb, const Def *def, std::string node_name, bool variadic=false, bool with_type=false)
std::string emit_head(BB &bb, Lam *lam, bool as_binding=false)
std::string emit_var(BB &bb, const Def *var, const Def *type)
void emit_lam(Lam *lam, MutSet &done)
Emitter(World &world, std::ostream &ostream, bool slotted=false)
std::string emit_type(BB &bb, const Def *type)
void emit_imported(Lam *)
std::string emit_cons(std::vector< std::string > op_vals)
bool is_valid(std::string_view s)
mim::Emitter< std::string, std::string, BB, Emitter > Super
std::string emit_bb(BB &bb, const Def *def)
void emit_epilogue(Lam *)
void emit_slotted(World &, std::ostream &)
void emit(World &, std::ostream &)
const Def * flatten(const Def *def)
Flattens a sigma/array/pack/tuple.
std::ostream & print(std::ostream &os, const char *s)
Base case.
TBound< true > Join
AKA union.
void error(Loc loc, const char *f, Args &&... args)
TBound< false > Meet
AKA intersection.
Use with print to output complicated std::ranges::ranges.
std::array< std::deque< std::ostringstream >, 3 > parts
BB & operator=(BB other) noexcept
void body(const char *s, Args &&... args)
std::deque< std::ostringstream > & tail()
BB(BB &&other) noexcept=default
std::string assign(Tab tab, std::string name, const char *s, Args &&... args)
std::string assign(Tab tab, std::string name, Fn &&print_term)
std::deque< std::ostringstream > & head()
friend void swap(BB &a, BB &b) noexcept
std::deque< std::ostringstream > & body()
std::set< std::string > assigned
void tail(const char *s, Args &&... args)