11using namespace std::string_literals;
18std::string escape(
const T& val) {
19 std::ostringstream oss;
22 fe::find_and_replace(str,
"<",
"<");
23 fe::find_and_replace(str,
">",
">");
29 Dot(std::ostream& ostream, DotConfig cfg,
const Def* root =
nullptr)
35 std::println(os_,
"{}digraph {{", tab_);
37 std::println(os_,
"{}ordering=out;", tab_);
38 std::println(os_,
"{}splines=ortho;", tab_);
39 std::println(os_,
"{}newrank=true;", tab_);
40 std::println(os_,
"{}margin=0;", tab_);
42 std::println(os_,
"{}nodesep={};", tab_, cfg_.inline_consts ?
"0.25" :
"0.6");
43 std::println(os_,
"{}ranksep={};", tab_, cfg_.inline_consts ?
"0.4" :
"1.2");
44 std::println(os_,
"{}node [shape=box,style=filled,fontname=\"monospace\"];", tab_);
49 std::println(os_,
"{}}}", tab_);
52 void run(
const Def* root,
int max) {
60 void emit_node(std::string_view nid,
const Def* def) {
61 std::print(os_,
"{}{}[", tab_, nid);
65 os_ <<
"style=\"filled,diagonals,bold\",";
67 os_ <<
"style=\"filled,diagonals\",penwidth=2,";
68 else if (def == root_)
69 os_ <<
"style=\"filled,bold\",";
76 if (def->is_closed() && (!cfg_.inline_consts || def->isa_mut())) os_ <<
"rank=min,";
77 tooltip(def) <<
"];\n";
80 void recurse(
const Def* def,
int max) {
81 if (max == 0 || !done_.emplace(def).second)
return;
83 emit_node(std::format(
"_{}", def->gid()), def);
86 for (
size_t i = 0, e = def->num_ops(); i != e; ++i) {
90 if (!cfg_.default_filter && i == 0)
91 if (
auto lam = def->isa<Lam>();
99 if (cfg_.inline_consts && (
op->isa<Lit>() ||
op->isa<Axm>())) {
100 auto dup = std::format(
"_{}_{}", def->gid(), i);
102 std::println(os_,
"{}_{}:{} -> {};", tab_, def->gid(), i, dup);
103 type_edge(dup, op, max - 1);
105 recurse(op, max - 1);
106 bool detach = def->isa<
Var>()
107 || (!cfg_.inline_consts
108 && (
op->isa<Lit>() ||
op->isa<Axm>() || def->isa<Nat>() || def->isa<Idx>()));
112 auto edge_color = cfg_.show_hidden ?
"gray" :
"#00000000";
113 std::println(os_,
"{}_{}:{} -> _{}[color=\"{}\",constraint=false];", tab_, def->gid(), i,
114 op->gid(), edge_color);
116 std::println(os_,
"{}_{}:{} -> _{};", tab_, def->gid(), i,
op->gid());
121 type_edge(std::format(
"_{}", def->gid()), def, max - 1);
126 void type_edge(std::string_view nid,
const Def* def,
int max) {
127 if (
auto t = def->type(); t && cfg_.follow_types) {
129 auto edge_color = cfg_.show_hidden ?
"gray" :
"#00000000";
130 std::println(os_,
"{}{} -> _{}[color=\"{}\",constraint=false,style=dashed];", tab_, nid,
t->gid(),
135 std::ostream& label(
const Def* def) {
136 auto n = def->is_set() ? def->num_ops() : size_t(0);
138 std::print(os_,
"label=<<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td colspan=\"{}\">",
141 os_ <<
"</td></tr><tr>";
142 for (
size_t i = 0; i < n; ++i)
143 std::print(os_,
"<td port=\"{}\" cellpadding=\"0\" height=\"1\" width=\"8\"></td>", i);
144 os_ <<
"</tr></table>>";
153 void emit_name(
const Def* def) {
154 if (
auto lit = def->isa<Lit>())
157 os_ << def->node_name();
158 std::print(os_,
"<br/><font point-size=\"9\">{}</font>", escape(def->unique_name()));
161 std::ostream& color(
const Def* def) {
164 if (def->is_form()) hue = 0.60f;
165 else if (def->is_intro()) hue = 0.35f;
166 else if (def->is_elim()) hue = 0.00f;
167 else if (def->is_meta()) hue = 0.15f;
170 return os_ << std::format(
"fillcolor=\"{} 0.5 0.75\"", hue);
173 std::ostream& tooltip(
const Def* def) {
174 static constexpr auto NL =
" ";
176 auto loc = escape(def->loc());
177 auto type = escape(def->type());
178 std::print(os_,
"tooltip=\"");
179 std::print(os_,
"<b>expr:</b> {}{}", def, NL);
180 std::print(os_,
"<b>type:</b> {}{}", type, NL);
181 std::print(os_,
"<b>name:</b> {}{}", def->sym(), NL);
182 std::print(os_,
"<b>gid:</b> {}{}", def->gid(), NL);
183 std::print(os_,
"<b>flags:</b> 0x{:x}{}", def->flags(), NL);
184 std::print(os_,
"<b>mark:</b> 0x{:x}{}", def->mark(), NL);
185 std::print(os_,
"<b>local_muts:</b> {}{}", fe::Join(def->local_muts()), NL);
186 std::print(os_,
"<b>local_vars:</b> {}{}", fe::Join(def->local_vars()), NL);
187 std::print(os_,
"<b>free_vars:</b> {}{}", fe::Join(def->free_vars()), NL);
188 if (
auto mut = def->isa_mut()) std::print(os_,
"<b>users:</b> {{{}}}{}", fe::Join(mut->users()), NL);
189 std::print(os_,
"<b>loc:</b> {}", loc);
190 return os_ << std::format(
"\"");
197 fe::Tab tab_ = fe::Tab::spaces();
209 auto of = std::ofstream(file);
218 auto of = std::ofstream(file);
227 dot.recurse(external, cfg.
max);
242 auto of = std::ofstream(file);
248 auto tab = fe::Tab::spaces();
249 std::println(os,
"{}digraph {{", tab);
251 std::println(os,
"{}ordering=out;", tab);
252 std::println(os,
"{}node [shape=box,style=filled];", tab);
253 root()->dot(tab, os);
255 std::println(os,
"{}}}", tab);
258void Nest::Node::dot(fe::Tab tab, std::ostream& os)
const {
260 for (
const auto& scc : topo_) {
262 for (
auto sep =
""s;
auto n : *scc) {
263 s += sep + n->name();
270 std::println(os,
"{}\"{}\":s -> \"{}\":s [style=dashed,constraint=false,splines=true]", tab,
name(),
274 auto html =
"<b>" +
name() +
"</b>";
275 if (*rec) html +=
"<br/><i>"s + rec +
"</i>";
276 html +=
"<br/><font point-size=\"8\">depth " + std::to_string(
loop_depth()) +
"</font>";
277 std::println(os,
"{}\"{}\" [label=<{}>,tooltip=\"{}\"]", tab,
name(), html, s);
279 std::println(os,
"{}\"{}\" -> \"{}\" [splines=false]", tab,
name(), child->name());
285 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 Children & children() const
auto idom() const
Immediate Dominator for children in connected components.
bool is_directly_recursive() const
bool is_mutually_recursive() const
uint32_t loop_depth() const
void dot(std::ostream &os) const
const Node * root() const
void dot(std::ostream &os, DotConfig cfg={}) const
Dumps DOT to os, configured via cfg (see DotConfig).
const Def * annex(Sym sym)
Lookup annex by Sym.
const Externals & externals() const
int max
Maximum recursion depth.
bool all_annexes
Include all annexes - even if unused (World::dot only).
GIDSet< const Def * > DefSet
Options for Def::dot and World::dot.