10using namespace std::string_literals;
17std::string
escape(
const T& val) {
18 std::ostringstream oss;
28 Dot(std::ostream& ostream, DotConfig cfg,
const Def* root =
nullptr)
34 std::println(os_,
"{}digraph {{", tab_);
36 std::println(os_,
"{}ordering=out;", tab_);
37 std::println(os_,
"{}splines=ortho;", tab_);
38 std::println(os_,
"{}newrank=true;", tab_);
39 std::println(os_,
"{}margin=0;", tab_);
41 std::println(os_,
"{}nodesep={};", tab_, cfg_.inline_consts ?
"0.25" :
"0.6");
42 std::println(os_,
"{}ranksep={};", tab_, cfg_.inline_consts ?
"0.4" :
"1.2");
43 std::println(os_,
"{}node [shape=box,style=filled,fontname=\"monospace\"];", tab_);
48 std::println(os_,
"{}}}", tab_);
51 void run(
const Def* root,
int max) {
59 void emit_node(std::string_view nid,
const Def* def) {
60 std::print(os_,
"{}{}[", tab_, nid);
64 os_ <<
"style=\"filled,diagonals,bold\",";
66 os_ <<
"style=\"filled,diagonals\",penwidth=2,";
67 else if (def == root_)
68 os_ <<
"style=\"filled,bold\",";
75 if (def->is_closed() && (!cfg_.inline_consts || def->isa_mut())) os_ <<
"rank=min,";
76 tooltip(def) <<
"];\n";
79 void recurse(
const Def* def,
int max) {
80 if (max == 0 || !done_.emplace(def).second)
return;
82 emit_node(std::format(
"_{}", def->gid()), def);
85 for (
size_t i = 0, e = def->num_ops(); i != e; ++i) {
89 if (!cfg_.default_filter && i == 0)
90 if (
auto lam = def->isa<
Lam>();
98 if (cfg_.inline_consts && (
op->isa<
Lit>() ||
op->isa<
Axm>())) {
99 auto dup = std::format(
"_{}_{}", def->gid(), i);
101 std::println(os_,
"{}_{}:{} -> {};", tab_, def->gid(), i, dup);
102 type_edge(dup, op, max - 1);
104 recurse(op, max - 1);
105 bool detach = def->isa<
Var>()
106 || (!cfg_.inline_consts
107 && (
op->isa<
Lit>() ||
op->isa<
Axm>() || def->isa<
Nat>() || def->isa<
Idx>()));
111 auto edge_color = cfg_.show_hidden ?
"gray" :
"#00000000";
112 std::println(os_,
"{}_{}:{} -> _{}[color=\"{}\",constraint=false];", tab_, def->gid(), i,
113 op->gid(), edge_color);
115 std::println(os_,
"{}_{}:{} -> _{};", tab_, def->gid(), i,
op->gid());
120 type_edge(std::format(
"_{}", def->gid()), def, max - 1);
125 void type_edge(std::string_view nid,
const Def* def,
int max) {
126 if (
auto t = def->type(); t && cfg_.follow_types) {
128 auto edge_color = cfg_.show_hidden ?
"gray" :
"#00000000";
129 std::println(os_,
"{}{} -> _{}[color=\"{}\",constraint=false,style=dashed];", tab_, nid,
t->gid(),
134 std::ostream& label(
const Def* def) {
135 auto n = def->is_set() ? def->num_ops() : size_t(0);
137 std::print(os_,
"label=<<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td colspan=\"{}\">",
140 os_ <<
"</td></tr><tr>";
141 for (
size_t i = 0; i < n; ++i)
142 std::print(os_,
"<td port=\"{}\" cellpadding=\"0\" height=\"1\" width=\"8\"></td>", i);
143 os_ <<
"</tr></table>>";
152 void emit_name(
const Def* def) {
153 if (
auto lit = def->isa<
Lit>())
156 os_ << def->node_name();
157 std::print(os_,
"<br/><font point-size=\"9\">{}</font>",
escape(def->unique_name()));
160 std::ostream& color(
const Def* def) {
163 if (def->is_form()) hue = 0.60f;
164 else if (def->is_intro()) hue = 0.35f;
165 else if (def->is_elim()) hue = 0.00f;
166 else if (def->is_meta()) hue = 0.15f;
169 return os_ << std::format(
"fillcolor=\"{} 0.5 0.75\"", hue);
172 std::ostream& tooltip(
const Def* def) {
173 static constexpr auto NL =
" ";
175 auto loc =
escape(def->loc());
177 std::print(os_,
"tooltip=\"");
178 std::print(os_,
"<b>expr:</b> {}{}", def, NL);
179 std::print(os_,
"<b>type:</b> {}{}", type, NL);
180 std::print(os_,
"<b>name:</b> {}{}", def->sym(), NL);
181 std::print(os_,
"<b>gid:</b> {}{}", def->gid(), NL);
182 std::print(os_,
"<b>flags:</b> 0x{:x}{}", def->flags(), NL);
183 std::print(os_,
"<b>mark:</b> 0x{:x}{}", def->mark(), NL);
184 std::print(os_,
"<b>local_muts:</b> {}{}", fe::Join(def->local_muts()), NL);
185 std::print(os_,
"<b>local_vars:</b> {}{}", fe::Join(def->local_vars()), NL);
186 std::print(os_,
"<b>free_vars:</b> {}{}", fe::Join(def->free_vars()), NL);
187 if (
auto mut = def->isa_mut()) std::print(os_,
"<b>users:</b> {{{}}}{}", fe::Join(mut->users()), NL);
188 std::print(os_,
"<b>loc:</b> {}", loc);
189 return os_ << std::format(
"\"");
196 fe::Tab tab_ = fe::Tab::spaces();
208 auto of = std::ofstream(file);
217 auto of = std::ofstream(file);
226 dot.recurse(external, cfg.
max);
241 auto of = std::ofstream(file);
247 auto tab = fe::Tab::spaces();
248 std::println(os,
"{}digraph {{", tab);
250 std::println(os,
"{}ordering=out;", tab);
251 std::println(os,
"{}node [shape=box,style=filled];", tab);
252 root()->dot(tab, os);
254 std::println(os,
"{}}}", tab);
257void Nest::Node::dot(fe::Tab tab, std::ostream& os)
const {
259 for (
const auto& scc : topo_) {
261 for (
auto sep =
""s;
auto n : *scc) {
262 s += sep + n->name();
269 std::println(os,
"{}\"{}\":s -> \"{}\":s [style=dashed,constraint=false,splines=true]", tab,
name(),
273 auto html =
"<b>" +
name() +
"</b>";
274 if (*rec) html +=
"<br/><i>"s + rec +
"</i>";
275 html +=
"<br/><font point-size=\"8\">depth " + std::to_string(
loop_depth()) +
"</font>";
276 std::println(os,
"{}\"{}\" [label=<{}>,tooltip=\"{}\"]", tab,
name(), html, s);
278 std::println(os,
"{}\"{}\" -> \"{}\" [splines=false]", tab,
name(), child->name());
284 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 run(std::string cmd, std::string args={})
Wraps sys::system and puts .exe at the back (Windows) and ./ at the front (otherwise) of cmd.
std::string escape(const std::filesystem::path &path)
Returns the path as std::string and escapes all whitespaces with backslash.
int max
Maximum recursion depth.
bool all_annexes
Include all annexes - even if unused (World::dot only).
void find_and_replace(std::string &str, std::string_view what, std::string_view repl)
Replaces all occurrences of what with repl.
GIDSet< const Def * > DefSet
Options for Def::dot and World::dot.