10using namespace std::string_literals;
17std::string html(std::string_view s) {
21 case '&': res +=
"&";
break;
22 case '<': res +=
"<";
break;
23 case '>': res +=
">";
break;
32std::string quote(std::string_view s) {
36 case '\\': res +=
"\\\\";
break;
37 case '"': res +=
"\\\"";
break;
38 case '\n': res +=
"\\n";
break;
46constexpr auto DARK_FG =
"#c9d1d9";
50 Dot(std::ostream& ostream, DotConfig cfg,
const Def* root =
nullptr)
56 std::println(os_,
"{}digraph {{", tab_);
60 std::println(os_,
"{}bgcolor=\"transparent\";", tab_);
61 std::println(os_,
"{}edge [color=\"{}\"];", tab_, DARK_FG);
63 std::println(os_,
"{}ordering=out;", tab_);
64 std::println(os_,
"{}splines=ortho;", tab_);
65 std::println(os_,
"{}newrank=true;", tab_);
66 std::println(os_,
"{}margin=0;", tab_);
68 std::println(os_,
"{}nodesep={};", tab_, cfg_.inline_consts ?
"0.25" :
"0.6");
69 std::println(os_,
"{}ranksep={};", tab_, cfg_.inline_consts ?
"0.4" :
"1.2");
70 std::println(os_,
"{}node [shape=box,style=filled,fontname=\"monospace\"];", tab_);
75 std::println(os_,
"{}}}", tab_);
78 void run(
const Def* root,
int max) {
86 void emit_node(std::string_view nid,
const Def* def) {
87 std::print(os_,
"{}{}[", tab_, nid);
91 std::print(os_,
"style=\"filled,diagonals,bold\",");
93 std::print(os_,
"style=\"filled,diagonals\",penwidth=2,");
94 else if (def == root_)
95 std::print(os_,
"style=\"filled,bold\",");
102 if (def->is_closed() && (!cfg_.inline_consts || def->isa_mut())) std::print(os_,
"rank=min,");
104 std::println(os_,
"];");
107 void recurse(
const Def* def,
int max) {
108 if (max == 0 || !done_.emplace(def).second)
return;
110 emit_node(std::format(
"_{}", def->gid()), def);
113 for (
size_t i = 0, e = def->num_ops(); i != e; ++i) {
114 auto op = def->op(i);
117 if (!cfg_.default_filter && i == 0)
118 if (
auto lam = def->isa<Lam>();
126 if (cfg_.inline_consts && (
op->isa<Lit>() ||
op->isa<Axm>())) {
127 auto dup = std::format(
"_{}_{}", def->gid(), i);
129 std::println(os_,
"{}{} -> {};", tab_,
tail(def, i), dup);
130 type_edge(dup, op, max - 1);
132 recurse(op, max - 1);
134 = !cfg_.inline_consts && (
op->isa<
Lit>() ||
op->isa<
Axm>() ||
op->isa<
Nat>() ||
op->isa<
Idx>());
138 auto edge_color = cfg_.show_hidden ?
"gray" :
"#00000000";
139 std::println(os_,
"{}{} -> _{}[color=\"{}\",constraint=false];", tab_,
tail(def, i),
op->gid(),
142 std::println(os_,
"{}{} -> _{};", tab_,
tail(def, i),
op->gid());
147 if (
auto var = def->isa<Var>()) {
148 recurse(var->binder(), max - 1);
149 std::println(os_,
"{}_{} -> _{}[color=\"{}\",constraint=false];", tab_, def->gid(), var->binder()->gid(),
150 cfg_.show_hidden ?
"gray" :
"#00000000");
153 type_edge(std::format(
"_{}", def->gid()), def, max - 1);
158 void type_edge(std::string_view nid,
const Def* def,
int max) {
159 if (
auto t = def->type(); t && cfg_.follow_types) {
161 auto edge_color = cfg_.show_hidden ?
"gray" :
"#00000000";
162 std::println(os_,
"{}{} -> _{}[color=\"{}\",constraint=false,style=dashed];", tab_, nid,
t->gid(),
168 void label(
const Def* def) {
169 if (cfg_.lean_labels) {
170 std::print(os_,
"label=\"{}\",", quote(std::format(
"{} {}", caption(def), def->unique_name())));
174 auto n = def->is_set() ? def->num_ops() : size_t(0);
176 std::print(os_,
"label=<<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td colspan=\"{}\">",
179 std::print(os_,
"</td></tr><tr>");
180 for (
size_t i = 0; i < n; ++i)
181 std::print(os_,
"<td port=\"{}\" height=\"1\" width=\"8\"></td>", i);
182 std::print(os_,
"</tr></table>>,");
184 std::print(os_,
"label=<");
186 std::print(os_,
">,");
191 std::string caption(
const Def* def) {
192 auto lit = def->isa<
Lit>();
193 return lit ? std::format(
"{}", lit) : std::string(def->node_name());
196 void emit_name(
const Def* def) {
197 std::print(os_,
"{}<br/><font point-size=\"9\">{}</font>", html(caption(def)), html(def->unique_name()));
201 std::string
tail(
const Def* def,
size_t i) {
202 return cfg_.lean_labels ? std::format(
"_{}", def->gid()) : std::format(
"_{}:{}", def->
gid(), i);
205 void color(
const Def* def) {
208 if (def->is_form()) hue = 0.60f;
209 else if (def->is_intro()) hue = 0.35f;
210 else if (def->is_elim()) hue = 0.00f;
211 else if (def->is_meta()) hue = 0.15f;
214 std::print(os_,
"fillcolor=\"{} 0.5 0.75\",", hue);
220 void tooltip(
const Def* def) {
221 if (cfg_.no_tooltip)
return;
224 auto add = [&, sep =
""](std::string_view key,
const auto& val)
mutable {
225 s += std::format(
"{}{}: {}", sep, key, val);
230 add(
"type", def->type());
231 add(
"name", def->sym());
232 add(
"gid", def->gid());
233 add(
"flags", std::format(
"0x{:x}", def->flags()));
234 add(
"mark", std::format(
"0x{:x}", def->mark()));
235 add(
"local_muts", fe::Join(def->local_muts()));
236 add(
"local_vars", fe::Join(def->local_vars()));
237 add(
"free_vars", fe::Join(def->free_vars()));
238 if (
auto mut = def->isa_mut())
add(
"users", std::format(
"{{{}}}", fe::Join(mut->users())));
239 add(
"loc", def->loc());
241 std::print(os_,
"tooltip=\"{}\",", quote(s));
248 fe::Tab tab_ = fe::Tab::spaces();
253void dot_to(
const T& t,
const char* file,
DotConfig cfg) {
254 if (!file)
return t.dot(std::cout, cfg);
255 auto ofs = std::ofstream(file);
271 dot.recurse(external, cfg.
max);
282 auto tab = fe::Tab::spaces();
283 std::println(os,
"{}digraph {{", tab);
286 std::println(os,
"{}bgcolor=\"transparent\";", tab);
287 std::println(os,
"{}edge [color=\"{}\"];", tab, DARK_FG);
289 std::println(os,
"{}ordering=out;", tab);
290 std::println(os,
"{}node [shape=box,style=filled];", tab);
291 root()->dot(tab, os);
293 std::println(os,
"{}}}", tab);
296void Nest::Node::dot(fe::Tab tab, std::ostream& os)
const {
298 for (
const auto&
scc : topo_) {
300 for (
auto sep =
""s;
auto n : *
scc) {
301 s += sep + n->name();
308 std::println(os,
"{}\"{}\":s -> \"{}\":s [style=dashed,constraint=false,splines=true]", tab,
name(),
312 auto label = std::format(
"<b>{}</b>", html(
name()));
313 if (*rec) label += std::format(
"<br/><i>{}</i>", rec);
314 label += std::format(
"<br/><font point-size=\"8\">depth {}</font>",
loop_depth());
315 std::println(os,
"{}\"{}\" [label=<{}>,tooltip=\"{}\"]", tab,
name(), label, quote(s));
317 std::println(os,
"{}\"{}\" -> \"{}\" [splines=false]", tab,
name(), child->name());
323 std::println(os,
"{}\"{}\" -> \"{}\" [color=red,style=bold,constraint=false]", tab,
idom()->
name(),
name());
World & world() const noexcept
void dot(std::ostream &os, DotConfig cfg={}) const
static const Lam * isa_cn(const Def *d)
const Node * idom() const
Immediate Dominator for children in connected components; used for late code placement in [Nest::lca]...
const SiblDeps & sibl_deps() const
const Children & children() const
const SCC & scc() const
The SCC among its siblings this Node belongs to; the Nest::root() has none.
bool is_directly_recursive() const
bool is_mutually_recursive() const
uint32_t loop_depth() const
void dot(std::ostream &os, DotConfig cfg={}) const
const Node * root() const
void dot(std::ostream &os, DotConfig cfg={}) const
Dumps DOT to os, configured via cfg (see DotConfig).
const Externals & externals() const
int max
Maximum recursion depth.
bool dark
Drop the white background and lighten the edges for a dark backdrop.
GIDSet< const Def * > DefSet
Options for Def::dot, World::dot, and Nest::dot.