MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
dot.cpp
Go to the documentation of this file.
1#include <fstream>
2#include <ostream>
3#include <sstream>
4
5#include "mim/def.h"
6#include "mim/nest.h"
7#include "mim/world.h"
8
9#include "mim/util/print.h"
10
11using namespace std::string_literals;
12
13// Do not zonk here!
14// We want to see all const Def*s in the DOT graph.
15
16namespace mim {
17
18namespace {
19
20template<class T> std::string escape(const T& val) {
21 std::ostringstream oss;
22 oss << val;
23 auto str = oss.str();
24 find_and_replace(str, "<", "&lt;");
25 find_and_replace(str, ">", "&gt;");
26 return str;
27}
28
29class Dot {
30public:
31 Dot(std::ostream& ostream, bool types, const Def* root = nullptr)
32 : os_(ostream)
33 , types_(types)
34 , root_(root) {}
35
36 void prologue() {
37 (tab_++).println(os_, "digraph {{");
38 tab_.println(os_, "ordering=out;");
39 tab_.println(os_, "splines=false;");
40 tab_.println(os_, "node [shape=box,style=filled];");
41 }
42
43 void epilogue() { (--tab_).println(os_, "}}"); }
44
45 void run(const Def* root, uint32_t max) {
46 prologue();
47 recurse(root, max);
48 epilogue();
49 }
50
51 void recurse(const Def* def, uint32_t max) {
52 if (max == 0 || !done_.emplace(def).second) return;
53 tab_.print(os_, "_{}[", def->gid());
54 if (def->isa_mut())
55 if (def == root_)
56 os_ << "style=\"filled,diagonals,bold\"";
57 else
58 os_ << "style=\"filled,diagonals\"";
59 else if (def == root_)
60 os_ << "style=\"filled,bold\"";
61 label(def) << ',';
62 color(def) << ',';
63 if (def->free_vars().empty()) os_ << "rank=min,";
64 tooltip(def) << "];\n";
65
66 if (!def->is_set()) return;
67
68 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
69 auto op = def->op(i);
70 recurse(op, max - 1);
71 tab_.print(os_, "_{} -> _{}[taillabel=\"{}\",", def->gid(), op->gid(), i);
72 if (op->isa<Lit>() || op->isa<Axiom>() || def->isa<Var>() || def->isa<Nat>() || def->isa<Idx>())
73 print(os_, "fontcolor=\"#00000000\",color=\"#00000000\",constraint=false];\n");
74 else
75 print(os_, "];\n");
76 }
77
78 if (auto t = def->type(); t && types_) {
79 recurse(t, max - 1);
80 tab_.println(os_, "_{} -> _{}[color=\"#00000000\",constraint=false,style=dashed];", def->gid(), t->gid());
81 }
82 }
83
84 std::ostream& label(const Def* def) {
85 print(os_, "label=<{}<br/>", def->unique_name());
86 if (auto lit = def->isa<Lit>())
87 lit->stream(os_, 0);
88 else
89 os_ << def->node_name();
90 return os_ << '>';
91 }
92
93 std::ostream& color(const Def* def) {
94 return print(os_, "fillcolor=\"{} 0.5 0.75\"", float(def->node()) / float(Num_Nodes));
95 }
96
97 std::ostream& tooltip(const Def* def) {
98 static constexpr auto NL = "&#13;&#10;";
99 auto loc = escape(def->loc());
100 auto type = escape(def->type());
101 escape(loc);
102 print(os_, "tooltip=\"");
103 print(os_, "<b>expr:</b> {}{}", def, NL);
104 print(os_, "<b>type:</b> {}{}", type, NL);
105 print(os_, "<b>name:</b> {}{}", def->sym(), NL);
106 print(os_, "<b>gid:</b> {}{}", def->gid(), NL);
107 print(os_, "<b>flags:</b> 0x{x}{}", def->flags(), NL);
108 print(os_, "<b>mark:</b> 0x{x}{}", def->mark(), NL);
109 print(os_, "<b>local_muts:</b> {, }{}", def->local_muts(), NL);
110 print(os_, "<b>local_vars:</b> {, }{}", def->local_vars(), NL);
111 print(os_, "<b>free_vars:</b> {, }{}", def->free_vars(), NL);
112 if (auto mut = def->isa_mut()) print(os_, "<b>users:</b> {{{, }}}{}", mut->users(), NL);
113 print(os_, "<b>loc:</b> {}", loc);
114 return print(os_, "\"");
115 }
116
117private:
118 std::ostream& os_;
119 bool types_;
120 const Def* root_;
121 Tab tab_;
122 DefSet done_;
123};
124
125} // namespace
126
127void Def::dot(std::ostream& ostream, uint32_t max, bool types) const { Dot(ostream, types, this).run(this, max); }
128
129void Def::dot(const char* file, uint32_t max, bool types) const {
130 if (!file) {
131 dot(std::cout, max, types);
132 } else {
133 auto of = std::ofstream(file);
134 dot(of, max, types);
135 }
136}
137
138void World::dot(const char* file, bool annexes, bool types) const {
139 if (!file) {
140 dot(std::cout, annexes, types);
141 } else {
142 auto of = std::ofstream(file);
143 dot(of, annexes, types);
144 }
145}
146
147void World::dot(std::ostream& os, bool anx, bool types) const {
148 Dot dot(os, types);
149 dot.prologue();
150 for (auto external : externals()) dot.recurse(external, uint32_t(-1));
151 if (anx)
152 for (auto annex : annexes()) dot.recurse(annex, uint32_t(-1));
153 dot.epilogue();
154}
155
156/*
157 * Nest
158 */
159
160void Nest::dot(const char* file) const {
161 if (!file) {
162 dot(std::cout);
163 } else {
164 auto of = std::ofstream(file);
165 dot(of);
166 }
167}
168
169void Nest::dot(std::ostream& os) const {
170 Tab tab;
171 (tab++).println(os, "digraph {{");
172 tab.println(os, "ordering=out;");
173 tab.println(os, "node [shape=box,style=filled];");
174 root()->dot(tab, os);
175 (--tab).println(os, "}}");
176}
177
178void Nest::Node::dot(Tab tab, std::ostream& os) const {
179 std::string s;
180 for (const auto& scc : topo_) {
181 s += '[';
182 for (auto sep = ""s; auto n : *scc) {
183 s += sep + n->name();
184 sep = ", ";
185 }
186 s += "] ";
187 }
188
189 for (auto dep : depends())
190 tab.println(os, "\"{}\":s -> \"{}\":s [style=dashed,constraint=false,splines=true]", this->name(), dep->name());
191
192 auto rec = is_mutually_recursive() ? "rec*" : (is_directly_recursive() ? "rec" : "");
193 tab.println(os, "\"{}\" [label=\"{} {} {}\",tooltip=\"{}\"]", name(), rec, name(), loop_depth(), s);
194 for (auto child : child_nodes()) {
195 tab.println(os, "\"{}\" -> \"{}\" [splines=false]", name(), child->name());
196 child->dot(tab, os);
197 }
198}
199
200} // namespace mim
void dot(std::ostream &os, uint32_t max=0xFFFFFF, bool types=false) const
Definition dot.cpp:127
const Def * op(size_t i) const noexcept
Definition def.h:264
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
Definition def.h:217
std::string name() const
Definition nest.h:17
const Node * child(Def *mut) const
Definition nest.h:42
auto child_nodes() const
Definition nest.h:33
auto depends() const
Definition nest.h:54
bool is_directly_recursive() const
Definition nest.h:74
bool is_mutually_recursive() const
Definition nest.h:73
uint32_t loop_depth() const
Definition nest.h:27
void dot(std::ostream &os) const
Definition dot.cpp:169
const Node * root() const
Definition nest.h:129
Keeps track of indentation level.
Definition print.h:196
std::ostream & println(std::ostream &os, const char *s, Args &&... args)
Same as Tab::print but appends a std::endl to os.
Definition print.h:221
const Def * annex(Id id)
Lookup annex by Axiom::id.
Definition world.h:171
auto externals() const
Definition world.h:192
Def * external(Sym name)
Lookup by name.
Definition world.h:191
auto annexes() const
Definition world.h:168
void dot(std::ostream &os, bool annexes=false, bool types=false) const
Dumps DOT to os.
Definition dot.cpp:147
const Def * op(trait o, const Def *type)
Definition core.h:33
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.
Definition sys.cpp:77
std::string escape(const std::filesystem::path &path)
Returns the path as std::string and escapes all whitespaces with backslash.
Definition sys.cpp:86
Definition ast.h:14
std::ostream & print(std::ostream &os, const char *s)
Base case.
Definition print.cpp:5
void find_and_replace(std::string &str, std::string_view what, std::string_view repl)
Replaces all occurrences of what with repl.
Definition util.h:72
GIDSet< const Def * > DefSet
Definition def.h:47
static constexpr size_t Num_Nodes
Definition def.h:90
std::ostream & println(std::ostream &os, const char *fmt, Args &&... args)
As above but end with std::endl.
Definition print.h:151
@ Nat
Definition def.h:85
@ Axiom
Definition def.h:85
@ Idx
Definition def.h:85
@ Var
Definition def.h:85
@ Lit
Definition def.h:85