15#include <fe/container.h>
17#include <fe/patricia.h>
29 X(Lit, Judge::Intro) \
30 X(Axm, Judge::Intro) \
31 X(Var, Judge::Intro) \
32 X(Proxy, Judge::Intro) \
33 X(Hole, Judge::Hole ) \
34 X(Type, Judge::Meta ) X(Level, Judge::Meta ) X(LMax, Judge::Meta) X(LSucc, (Judge::Meta )) \
35 X(Pi, Judge::Form ) X(Lam, Judge::Intro) X(App, Judge::Elim) \
36 X(Sigma, Judge::Form ) X(Tuple, Judge::Intro) X(Extract, Judge::Elim) X(Insert, (Judge::Intro | Judge::Elim)) \
37 X(Arr, Judge::Form ) X(Pack, Judge::Intro) \
38 X(Join, Judge::Form ) X(Inj, Judge::Intro) X(Match, Judge::Elim) \
39 X(Variant, Judge::Form) \
40 X(Top, Judge::Intro) X(Bot, Judge::Intro) \
41 X(Reform, Judge::Form ) X(Rule, Judge::Intro) \
42 X(Single, Judge::Form ) X(Wrap, Judge::Intro) \
43 X(Nom, Judge::Form ) X(Name, Judge::Intro) X(Struc, Judge::Elim) \
44 X(Nat, Judge::Form ) \
47#define MIM_IMM_NODE(X) \
52 X(Type) X(Level) X(LMax) X(LSucc) \
54 X(Sigma) X(Tuple) X(Extract) X(Insert) \
56 X(Join) X(Inj) X(Match) \
63 X(Nom) X(Name) X(Struc)
65#define MIM_MUT_NODE(X) \
86 static std::ostream&
stream(std::ostream&,
const Def*);
96using Defs = fe::View<const Def*>;
98using DefVec = fe::Vector<const Def*>;
107using Muts = fe::Patricia<Def, DefKey>::Set;
115using Vars = fe::Patricia<const Var, DefKey>::Set;
124#define CODE(node, _) node,
129#define CODE(node, _) +size_t(1)
136#define CODE(node) node = node_t(Node::node),
143#define CODE(node) case Node::node:
147 default:
return false;
154#define CODE(node) buildable[node_t(Node::node)] = true;
158 return std::ranges::all_of(buildable, std::identity());
160 "every Node must be in MIM_IMM_NODE, MIM_MUT_NODE, or both");
178template<>
struct fe::is_bit_enum<
mim::
Judge> : std::true_type {};
185template<
class F>
concept Projector = std::invocable<F, const Def*>;
186template<
class F>
concept DefPred = std::predicate<F, const Def*>;
187template<
class F>
concept MutPred = std::predicate<F, Def*>;
193#define MIM_PROJ(NAME, CONST) \
194 nat_t num_##NAME##s() CONST noexcept { return ((const Def*)NAME())->num_projs(); } \
195 nat_t num_t##NAME##s() CONST noexcept { return ((const Def*)NAME())->num_tprojs(); } \
196 const Def* NAME(nat_t a, nat_t i) CONST noexcept { return ((const Def*)NAME())->proj(a, i); } \
197 const Def* t##NAME(nat_t i) CONST noexcept { return ((const Def*)NAME())->tproj(i); } \
198 template<nat_t A = std::dynamic_extent> \
199 auto NAME##s(Projector auto f) CONST noexcept { \
200 return ((const Def*)NAME())->projs<A>(f); \
202 auto t##NAME##s(Projector auto f) CONST noexcept { return ((const Def*)NAME())->tprojs(f); } \
203 template<nat_t A = std::dynamic_extent> \
204 auto NAME##s() CONST noexcept { \
205 return ((const Def*)NAME())->projs<A>(); \
207 auto t##NAME##s() CONST noexcept { return ((const Def*)NAME())->tprojs(); } \
208 auto NAME##s(nat_t a, Projector auto f) CONST noexcept { return ((const Def*)NAME())->projs(a, f); } \
209 auto NAME##s(nat_t a) CONST noexcept { return ((const Def*)NAME())->projs(a); }
215template<
class P,
class D = Def>
218 __declspec(empty_bases)
222 P* super() {
return static_cast<P*
>(
this); }
223 const P* super()
const {
return static_cast<const P*
>(
this); }
226 template<
bool Ow,
class... Args>
227 static constexpr bool Fwd =
requires(D* d, Args&&... args) { d->template
set<Ow>(std::forward<Args>(args)...); };
231 template<
bool Ow =
false,
class... Args>
requires Fwd<Ow, Args...>
232 const P*
set(Args&&... args)
const { super()->D::template
set<Ow>(std::forward<Args>(args)...);
return super(); }
233 template<
bool Ow =
false,
class... Args>
requires Fwd<Ow, Args...>
234 P*
set(Args&&... args) { super()->D::template
set<Ow>(std::forward<Args>(args)...);
return super(); }
242 int max = std::numeric_limits<int>::max();
289class Def :
public fe::RuntimeCast<Def> {
291 Def& operator=(
const Def&) =
delete;
292 Def(
const Def&) =
delete;
301 Def(
Node, Def* binder);
312 constexpr u32 gid() const noexcept {
return gid_; }
313 constexpr u32 mark() const noexcept {
return mark_; }
314 constexpr size_t hash() const noexcept {
return hash_; }
315 constexpr Node node() const noexcept {
return node_; }
326 fe::Error&
error() const noexcept;
332 template<class... Args>
333 fe::Error&
blame(fe::cite_string<Args...> s, Args&&... args)
const {
334 return error().e(
err_loc(), s, std::forward<Args>(args)...);
358 const Def*
type() const noexcept;
365 return t ? t->template isa<T>() :
nullptr;
373 template<
size_t N = std::dynamic_extent>
374 constexpr auto ops() const noexcept {
375 return fe::View<const Def*, N>(ops_ptr(), num_ops_);
377 const Def*
op(
size_t i)
const noexcept {
return ops()[i]; }
378 constexpr size_t num_ops() const noexcept {
return num_ops_; }
397 if (
num_ops() == 0)
return true;
398 bool result =
ops().back();
399 assert((!result || std::ranges::all_of(
ops().rsubspan(1), [](
auto op) {
return op; }))
400 &&
"the last operand is set but others in front of it aren't");
419 const Def*
dep(
size_t i) const noexcept {
return deps()[i]; }
425 bool has_hole() const noexcept {
return has_hole_; }
456 template<nat_t A = std::dynamic_extent>
458 using R = std::decay_t<
decltype(f(
this))>;
459 if constexpr (A == std::dynamic_extent) {
462 std::array<R, A> array;
463 for (
nat_t i = 0; i != A; ++i)
464 array[i] = f(
proj(A, i));
472 using R = std::decay_t<
decltype(f(
this))>;
473 return fe::Vector<R>(a, [&](
nat_t i) {
return f(
proj(a, i)); });
475 template<nat_t A = std::dynamic_extent>
477 return projs<A>([](
const Def* def) {
return def; });
480 return tprojs([](
const Def* def) {
return def; });
483 return projs(a, [](
const Def* def) {
return def; });
502 template<
class D = Def>
507 return {
nullptr,
nullptr};
587 template<
class T = Def,
bool invert = false>
589 if constexpr (std::is_same_v<T, Def>)
590 return mut_ ^ invert ?
const_cast<Def*
>(
this) :
nullptr;
592 return mut_ ^ invert ?
const_cast<Def*
>(
this)->
template isa<T>() :
nullptr;
596 template<
class T = Def,
bool invert = false>
598 assert(mut_ ^ invert);
599 if constexpr (std::is_same_v<T, Def>)
600 return const_cast<Def*
>(
this);
602 return const_cast<Def*
>(
this)->
template as<T>();
608 template<
class T,
class... Args>
609 T*
expect(fe::cite_string<Args...> fmt, Args&&... args) {
610 if (
auto res = isa<T>())
return res;
611 bail_expected(fe::format_cite(fmt, std::forward<Args>(args)...));
615 template<
class T,
class... Args>
616 const T*
expect(fe::cite_string<Args...> fmt, Args&&... args)
const {
617 return const_cast<Def*
>(
this)->
template expect<T>(fmt, std::forward<Args>(args)...);
621 template<
class T =
Def,
class... Args>
622 T*
expect_mut(fe::cite_string<Args...> fmt, Args&&... args)
const {
624 bail_expected(fe::format_cite(fmt, std::forward<Args>(args)...));
641 template<
bool Ow = false>
const Def*
set(Loc l)
const {
if (
auto d =
dbg(); Ow || !d.loc())
set_dbg(d.set(l));
return this; }
642 template<
bool Ow = false> Def*
set(Loc l) {
if (
auto d =
dbg(); Ow || !d.loc())
set_dbg(d.set(l));
return this; }
643 template<
bool Ow = false>
const Def*
set(Sym s)
const {
if (
auto d =
dbg(); Ow || !d.sym())
set_dbg(d.set(s));
return this; }
644 template<
bool Ow = false> Def*
set(Sym s) {
if (
auto d =
dbg(); Ow || !d.sym())
set_dbg(d.set(s));
return this; }
645 template<
bool Ow = false>
const Def*
set( std::string s)
const {
set<Ow>(
sym(std::move(s)));
return this; }
646 template<
bool Ow = false> Def*
set( std::string s) {
set<Ow>(
sym(std::move(s)));
return this; }
647 template<
bool Ow = false>
const Def*
set(Loc l, Sym s )
const {
set<Ow>(l);
set<Ow>(s);
return this; }
649 template<
bool Ow = false>
const Def*
set(Loc l, std::string s)
const {
set<Ow>(l);
set<Ow>(
sym(std::move(s)));
return this; }
650 template<
bool Ow = false> Def*
set(Loc l, std::string s) {
set<Ow>(l);
set<Ow>(
sym(std::move(s)));
return this; }
651 template<
bool Ow = false>
const Def*
set(Dbg d)
const {
set_dbg_(d, Ow);
return this; }
652 template<
bool Ow = false> Def*
set(Dbg d) {
set_dbg_(d, Ow);
return this; }
655 template<
bool Ow = false>
const Def*
set(DbgKey key)
const {
set_dbg_key_(key, Ow);
return this; }
656 template<
bool Ow = false> Def*
set(DbgKey key) {
set_dbg_key_(key, Ow);
return this; }
668 const Def*
debug_suffix(std::string)
const {
return this; }
680 template<
size_t N = std::dynamic_extent>
681 constexpr auto reduce(
const Def* arg)
const {
682 return reduce_(arg).span<N>();
740 void write(
Dump,
const char* file)
const;
741 std::ostream&
stream(std::ostream&,
Dump)
const;
753 [[nodiscard]]
static Cmp cmp(
const Def* a,
const Def* b);
754 [[nodiscard]]
static bool less(
const Def* a,
const Def* b);
755 [[nodiscard]]
static bool greater(
const Def* a,
const Def* b);
763 void dot(
const char* file =
nullptr, DotConfig cfg = {})
const;
764 void dot(
const std::string& file,
DotConfig cfg = {})
const {
return dot(file.c_str(), cfg); }
771 Sym
sym(
const char*)
const;
772 Sym
sym(std::string_view)
const;
773 Sym
sym(std::string)
const;
780 Defs reduce_(
const Def* arg)
const;
788 const Def** ops_ptr()
const {
return &type_ + 1; }
789 bool equal(
const Def* other)
const;
793 [[nodiscard]]
static bool cmp_(
const Def* a,
const Def* b);
801 mutable World* world_;
811 mutable bool annex_ : 1;
826 mutable const Def* type_;
831 friend std::ostream&
operator<<(std::ostream&,
const Def*);
839static_assert(!std::is_polymorphic_v<Def>,
"Def must not have a vtable; dispatch on Def::node() instead");
845#define CODE(node, judge) judge,
849 return Judges[
node_t(node_)];
873 static std::pair<const Var*, std::optional<nat_t>>
isa_tproj(
const Def* def);
882class Level :
public Def,
public Setters<Level> {
895class LMax :
public Def,
public Setters<LMax> {
899 static constexpr size_t Num_Ops = std::dynamic_extent;
907class LSucc :
public Def,
public Setters<LSucc> {
928class Type :
public Def,
public Setters<Type> {
930 Type(
const Def*
level)
958 template<
class T = flags_t>
960 static_assert(
sizeof(T) <= 8);
961 return fe::bitcast_resize<T>(
flags_);
975 template<
class T = nat_t>
976 static std::optional<T>
isa(
const Def* def) {
978 if (
auto lit = def->isa<Lit>())
return lit->get<T>();
981 template<
class T = nat_t>
982 static T
as(
const Def* def) {
983 return def->as<Lit>()->
get<T>();
986 template<
class T =
nat_t,
class... Args>
987 static T
expect(
const Def* def, fe::cite_string<Args...> fmt, Args&&... args) {
988 if (
auto res =
isa<T>(def))
return *res;
989 def->
bail_expected(fe::format_cite(fmt, std::forward<Args>(args)...));
1015 Idx(
const Def*
type)
1027 static const Def*
isa(
const Def* def);
1028 static const Def*
as(
const Def* def) {
1029 auto res =
isa(def);
1033 static std::optional<nat_t>
isa_lit(
const Def* def);
1046 template<
class... Args>
1050 type->bail_expected(fe::format_cite(fmt, std::forward<Args>(args)...));
1079 using Setters<Proxy>
::set;
1089 static const Proxy*
isa(
const Def* def) {
1090 if (
auto proxy = def->isa<Proxy>(); proxy && proxy->tag() == Tag)
return proxy;
1095 static constexpr size_t Num_Ops = std::dynamic_extent;
1108 for (
auto def =
this;;) {
1109 switch (def->node_) {
1112 case Node::Var: def = def->binder_;
break;
1113 default: def = def->type_;
break;
1124inline bool Def::equal(
const Def* other)
const {
1126 if (mut_ || other->mut_ || node_ ==
Node::Level)
return this == other;
1129 if (
auto var = isa<Var>())
return other->isa<
Var>() &&
var->binder() == other->as<
Var>()->binder();
1131 bool result = this->
node() == other->
node() && this->flags() == other->
flags()
1132 && this->num_ops() == other->
num_ops() && this->type() == other->
type();
1134 for (
size_t i = 0, e =
num_ops(); result && i != e; ++i)
1135 result &= this->
op(i) == other->
op(i);
1145 return fe::StreamFn{[def](std::ostream& os) -> std::ostream& {
1147 return os <<
"<no type>";
1156 if (!done.emplace(mut).second)
return;
1159 for (
auto op : mut->
deps())
1160 for (
auto local_mut : op->local_muts())
1161 post_order(local_mut, done, res, descend, collect);
1163 if (collect(mut)) res.emplace_back(mut);
1170template<class T> requires std::derived_from<T, mim::Def> struct std::formatter< T*> : fe::ostream_formatter {};
1171template<
class T>
requires std::derived_from<T, mim::Def>
struct std::formatter<const T*> : fe::ostream_formatter {};
1172template<>
struct std::formatter<
mim::
Muts> : fe::ostream_formatter {};
1173template<>
struct std::formatter<
mim::
Vars> : fe::ostream_formatter {};
Loc err_loc() const
Returns a blame Loc from World::get_loc, this Def, or its nearest located dependency,...
void set_dbg(Dbg) const
Interns dbg via Driver::dbg and stores the key in Def::dbg_.
size_t num_deps() const noexcept
const Def * zonk_mut() const
If mutable, zonk()s all ops and tries to immutabilize it; otherwise just zonk.
const Def * set(Dbg d) const
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.
constexpr Node node() const noexcept
Def * set(size_t i, const Def *)
Successively set from left to right.
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
const Var * has_var() const
As above if this is a mutable.
void dump() const
Dump::Expr - one line, no analysis.
Defs deps() const noexcept
T * expect(fe::cite_string< Args... > fmt, Args &&... args)
Like Def::as but - instead of merely asserting in Debug builds - bails via Def::bail_expected when th...
bool is_elim() const noexcept
nat_t num_tprojs() const
As above but yields 1, if an Arr/Pack exceeds Flags::scalarize_threshold.
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
World & world() const noexcept
Def * set_type(const Def *)
Update type.
std::string_view node_name() const
fe::Error & error() const noexcept
auto tprojs(Projector auto f) const
bool is_intro() const noexcept
constexpr auto ops() const noexcept
bool in_scope(Def *mut) const
Is every free Var of this bound by mut or by a mutable that nests mut?
Vars local_vars() const
Vars reachable by following immutable deps().
size_t reduction_offset() const noexcept
First Def::op that needs to be dealt with during reduction; e.g.
constexpr flags_t flags() const noexcept
static DefVec cat(const Def *a, Defs bs)
const Def * set(std::string s) const
static DefVec cat(Defs as, const Def *b)
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
static DefVec cat(Defs a, Defs b)
constexpr u32 mark() const noexcept
Used internally by free_vars().
auto projs(nat_t a) const
Judge judge() const noexcept
Def must never become polymorphic: a vptr costs 8 bytes on every node in the World and would shift De...
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 is_term() const
Is this Def a term, i.e. is its type() a Type?
const Def * debug_prefix(std::string) const
const Def * op(size_t i) const noexcept
void dot(std::ostream &os, DotConfig cfg={}) const
DbgKey dbg_key() const
Cheap handle for other->set(this->dbg_key()).
bool is_immutabilizable()
std::pair< D *, const Var * > isa_binder() const
Is this a mutable that introduces a Var?
const Def * var(nat_t a, nat_t i) noexcept
void transfer_external(Def *to)
const Def * unfold_type() const
Yields the type of this Def and builds a new Type (LSucc n) if necessary.
bool has_free_vars() const
Same as !free_vars().empty().
bool is_open() const
Same as has_free_vars().
constexpr size_t hash() const noexcept
bool has_free_var(const Var *) const
Same as free_vars().contains(var).
bool is_form() const noexcept
void set_dbg_(Dbg, bool ow) const
Backs Def::set(Dbg).
std::ostream & stream(std::ostream &, Dump) const
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
bool is_ground() const
Immutable that contains neither mutables nor Vars.
const Def * debug_suffix(std::string) const
auto projs(Projector auto f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
const Def * set(Sym s) const
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Def * outermost_binder() const
Transitively walks up free_vars() till the outermoust binder has been found.
bool nests(Def *mut)
Does this nest mut?
fe::Error & blame(fe::cite_string< Args... > s, Args &&... args) const
Reports an error that blames this; chain Error::n for Notes and Error::bail to throw.
const Def * dep(size_t i) const noexcept
bool is_mutable() const noexcept
bool is_external() const noexcept
const T * expect(fe::cite_string< Args... > fmt, Args &&... args) const
const version.
constexpr MutNode mut_node() const noexcept
node() of a Def whose Node may be mutable, whether this one is or not; see MutNode.
const Def * set(Loc l, Sym s) const
static bool less(const Def *a, const Def *b)
T * expect_mut(fe::cite_string< Args... > fmt, Args &&... args) const
The mutable counterpart of Def::expect.
bool is_meta() const noexcept
static bool greater(const Def *a, const Def *b)
void bail_expected(fe::Cite what) const
Blames this for not being what and bails; where Def::expect and friends funnel their diagnostic.
void dot(const std::string &file, DotConfig cfg={}) const
const Def * set(Loc l) const
const Def * var()
Not necessarily a Var: E.g., if the return type is [], this will yield ().
Def * set(Loc l, std::string s)
static Cmp cmp(const Def *a, const Def *b)
void collect_locals()
Fills in an immutable's local Vars and Muts once it is in the sea.
Driver & driver() const noexcept
nat_t num_projs() const
Yields Def::arity(), if it is a Lit, or 1 otherwise.
const Def * immutabilize()
friend void swap(World &, World &) noexcept
const Def * var_type()
If this is a binder, compute the type of its Variable.
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
const Def * arity() const
Number of elements available to Extract / Insert (may be dynamic).
Def * unset()
Unsets all Def::ops; works even, if not set at all or only partially set.
std::string unique_name() const
name + "_" + Def::gid
constexpr auto reduce(const Def *arg) const
const Def * set(Loc l, std::string s) const
const T * isa_imm() const
bool needs_zonk() const
Yields true, if Def::local_muts() contain a Hole that is set.
void set_dbg_key_(DbgKey, bool ow) const
Backs Def::set(DbgKey).
Muts users()
Set of mutables where this mutable is locally referenced.
bool is_closed() const
Same as !has_free_vars().
Vars free_vars() const
Global set of free Vars: extends local_vars() by transitively following mutables as well.
const Def * set(DbgKey key) const
Adopts the Dbg behind key - just copies the interned index, so nothing is re-interned.
Dbg dbg() const
Looks up Def::dbg_ in Driver::dbg.
const Def * tproj(nat_t i) const
As above but takes Def::num_tprojs.
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
bool has_hole() const noexcept
Is this a Hole or does it reach one through Def::deps() up to (and excluding) the next mutable?
bool has_free_vars_in(Vars) const
Same as vars.has_intersection(free_vars()).
bool is_annex() const noexcept
const T * isa_type() const
Is Def::unfold_type a T? Yields nullptr for Level, which has no type at all.
constexpr size_t num_ops() const noexcept
auto projs(nat_t a, Projector auto f) const
const Def * check()
After all Def::ops have been Def::set, this method will be invoked to check the type of this mutable.
Some "global" variables needed all over the place.
This node is a hole in the IR that is inferred by its context later on.
static constexpr auto Node
static constexpr nat_t size2bitwidth(nat_t n)
static constexpr nat_t bitwidth2size(nat_t n)
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
static std::optional< nat_t > isa_lit(const Def *def)
static constexpr size_t Num_Ops
static const Def * as(const Def *def)
static nat_t expect_bitwidth(const Def *type, fe::cite_string< Args... > fmt, Args &&... args)
Yields the bit width of the Idx type or bails - instead of yielding std::nullopt or dereferencing an ...
static constexpr size_t Num_Ops
static constexpr auto Node
static constexpr auto Node
static constexpr size_t Num_Ops
static constexpr auto Node
static constexpr size_t Num_Ops
static constexpr auto Node
static std::optional< T > isa(const Def *def)
static T as(const Def *def)
static constexpr size_t Num_Ops
static T expect(const Def *def, fe::cite_string< Args... > fmt, Args &&... args)
Like Lit::as but bails via Def::bail_expected instead of merely asserting in Debug; see Def::expect.
static constexpr auto Node
static constexpr size_t Num_Ops
static constexpr size_t Num_Ops
static constexpr flags_t Muts_Bit
static constexpr auto Node
static const Proxy * isa(const Def *def)
static constexpr flags_t Vars_Bit
CRTP-based mixin to declare setters for Def::loc & Def::name using a covariant return type.
const P * set(Args &&... args) const
static constexpr size_t Num_Ops
static constexpr auto Node
const Def * level() const
A variable introduced by a binder (mutable).
static std::pair< const Var *, std::optional< nat_t > > isa_tproj(const Def *def)
Matches a Var v itself or an Extract v#j of it.
static constexpr auto Node
Def * binder() const
The binder of this Var.
static constexpr size_t Num_Ops
Used by Def::proj & friends.
#define MIM_PROJ(NAME, CONST)
Use as mixin to wrap all kind of Def::proj and Def::projs variants.
DefMap< const Def * > Def2Def
ankerl::unordered_dense::map< K, V, GIDHash< K > > GIDMap
bool follow_types
Follow Def::type() dependencies.
bool inline_consts
Wire up literals, axioms, etc. with normal edges instead of detaching them.
fe::View< const Def * > Defs
int max
Maximum recursion depth.
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...
bool no_tooltip
Omit the per-node tooltip; it is by far the bulkiest part of the output.
GIDMap< const Var *, To > VarMap
GIDMap< const Def *, To > DefMap
bool dark
Drop the white background and lighten the edges for a dark backdrop.
MutNode
The Nodes that may be mutable, with the same values as their Node.
bool show_hidden
Render otherwise-transparent detached edges (Var→binder back-edges, shared literals/axioms,...
fe::Vector< const Def * > DefVec
GIDSet< const Def * > DefSet
ankerl::unordered_dense::set< K, GIDHash< K > > GIDSet
fe::Patricia< const Var, DefKey >::Set Vars
static constexpr size_t Num_Nodes
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
constexpr bool is_mut_node(Node node) noexcept
bool lean_labels
Label a node <node_name> <unique_name> instead of the HTML table.
fe::Patricia< Def, DefKey >::Set Muts
@ Intro
Term Introduction like λ(x: Nat): Nat = x.
@ Meta
Meta rules for universe and Type levels.
@ Form
Type Formation like T -> T.
@ Elim
Term Elimination like f a.
auto type_of(const Def *def)
Def::unfold_type of def for a diagnostic - Level is the one Def that has no type at all.
bool default_filter
Show Lam::filter() even if it has its default value.
GIDMap< Def *, To > MutMap
Options for Def::dot, World::dot, and Nest::dot.
Grants fe::Patricia access to Def::gid_.
static std::ostream & stream(std::ostream &, const Def *)
static u32 key(const Def *) noexcept