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/world.h"
7
8#include "mim/util/print.h"
9
10// Do not zonk here!
11// We want to see all Refs in the DOT graph.
12
13namespace mim {
14
15namespace {
16
17template<class T> std::string escape(const T& val) {
18 std::ostringstream oss;
19 oss << val;
20 auto str = oss.str();
21 find_and_replace(str, "<", "&lt;");
22 find_and_replace(str, ">", "&gt;");
23 return str;
24}
25
26class Dot {
27public:
28 Dot(std::ostream& ostream, bool types, const Def* root = nullptr)
29 : os_(ostream)
30 , types_(types)
31 , root_(root) {}
32
33 void prologue() {
34 (tab_++).println(os_, "digraph {{");
35 tab_.println(os_, "ordering=out;");
36 tab_.println(os_, "splines=false;");
37 tab_.println(os_, "node [shape=box,style=filled];");
38 }
39
40 void epilogue() { (tab_--).println(os_, "}}"); }
41
42 void run(const Def* root, uint32_t max) {
43 prologue();
44 recurse(root, max);
45 epilogue();
46 }
47
48 void recurse(const Def* def, uint32_t max) {
49 if (max == 0 || !done_.emplace(def).second) return;
50 tab_.print(os_, "_{}[", def->gid());
51 if (def->isa_mut())
52 if (def == root_)
53 os_ << "style=\"filled,diagonals,bold\"";
54 else
55 os_ << "style=\"filled,diagonals\"";
56 else if (def == root_)
57 os_ << "style=\"filled,bold\"";
58 label(def) << ',';
59 color(def) << ',';
60 if (def->free_vars().empty()) os_ << "rank=min,";
61 tooltip(def) << "];\n";
62
63 if (!def->is_set()) return;
64
65 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
66 auto op = def->op(i).def();
67 recurse(op, max - 1);
68 tab_.print(os_, "_{} -> _{}[taillabel=\"{}\",", def->gid(), op->gid(), i);
69 if (op->isa<Lit>() || op->isa<Axiom>() || def->isa<Var>() || def->isa<Nat>() || def->isa<Idx>())
70 print(os_, "fontcolor=\"#00000000\",color=\"#00000000\",constraint=false];\n");
71 else
72 print(os_, "];\n");
73 }
74
75 if (auto t = def->type().def(); t && types_) {
76 recurse(t, max - 1);
77 tab_.println(os_, "_{} -> _{}[color=\"#00000000\",constraint=false,style=dashed];", def->gid(), t->gid());
78 }
79 }
80
81 std::ostream& label(const Def* def) {
82 print(os_, "label=<{}<br/>", def->unique_name());
83 if (auto lit = def->isa<Lit>())
84 lit->stream(os_, 0);
85 else
86 os_ << def->node_name();
87 return os_ << '>';
88 }
89
90 std::ostream& color(const Def* def) {
91 return print(os_, "fillcolor=\"{} 0.5 0.75\"", def->node() / (float)Node::Num_Nodes);
92 }
93
94 std::ostream& tooltip(const Def* def) {
95 static constexpr auto NL = "&#13;&#10;";
96 auto loc = escape(def->loc());
97 auto type = escape(def->type().def());
98 escape(loc);
99 print(os_, "tooltip=\"");
100 print(os_, "<b>expr:</b> {}{}", def, NL);
101 print(os_, "<b>type:</b> {}{}", type, NL);
102 print(os_, "<b>name:</b> {}{}", def->sym(), NL);
103 print(os_, "<b>gid:</b> {}{}", def->gid(), NL);
104 print(os_, "<b>flags:</b> 0x{x}{}", def->flags(), NL);
105 print(os_, "<b>free_vars:</b> {{{, }}}{}", def->free_vars(), NL);
106 print(os_, "<b>local_vars:</b> {{{, }}}{}", def->local_vars(), NL);
107 print(os_, "<b>local_muts:</b> {{{, }}}{}", def->local_muts(), NL);
108 if (auto mut = def->isa_mut()) print(os_, "<b>fv_consumers:</b> {{{, }}}{}", mut->fv_consumers(), NL);
109 print(os_, "<b>loc:</b> {}", loc);
110 return print(os_, "\"");
111 }
112
113private:
114 std::ostream& os_;
115 bool types_;
116 const Def* root_;
117 Tab tab_;
118 DefSet done_;
119};
120
121} // namespace
122
123void Def::dot(std::ostream& ostream, uint32_t max, bool types) const { Dot(ostream, types, this).run(this, max); }
124
125void Def::dot(const char* file, uint32_t max, bool types) const {
126 if (!file) {
127 dot(std::cout, max, types);
128 } else {
129 auto of = std::ofstream(file);
130 dot(of, max, types);
131 }
132}
133
134void World::dot(const char* file, bool annexes, bool types) const {
135 if (!file) {
136 dot(std::cout, annexes, types);
137 } else {
138 auto of = std::ofstream(file);
139 dot(of, annexes, types);
140 }
141}
142
143void World::dot(std::ostream& os, bool anx, bool types) const {
144 Dot dot(os, types);
145 dot.prologue();
146 for (auto [_, external] : externals()) dot.recurse(external, uint32_t(-1));
147 if (anx)
148 for (auto [_, annex] : annexes()) dot.recurse(annex, uint32_t(-1));
149 dot.epilogue();
150}
151
152} // namespace mim
void dot(std::ostream &os, uint32_t max=0xFFFFFF, bool types=false) const
Definition dot.cpp:123
Ref op(size_t i) const
Definition def.h:272
u32 gid() const
Definition def.h:242
const Def * def() const
Retrieve wrapped Def without Infer::refering.
Definition def.h:97
const auto & annexes() const
Definition world.h:167
const auto & externals() const
Definition world.h:168
Def * external(Sym name)
Lookup by name.
Definition world.h:182
void dot(std::ostream &os, bool annexes=false, bool types=false) const
Definition dot.cpp:143
const Def * annex()
Get Axiom from a plugin.
Definition world.h:194
constexpr auto Num_Nodes
Definition def.h:44
Ref op(trait o, Ref 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 cfg.h:11
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:70
GIDSet< const Def * > DefSet
Definition def.h:59
std::ostream & println(std::ostream &os, const char *fmt, Args &&... args)
As above but end with std::endl.
Definition print.h:150