mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
ASTDot.cpp
Go to the documentation of this file.
1#include "parse/ASTDot.hpp"
2
3#include <iomanip>
5#include <sstream>
6
7#define q(X) '"' << X << '"' // quote
8#define id(X) q(std::hex << &X << std::dec) // convert virtual address to identifier
9
10
11using namespace m;
12using namespace m::ast;
13
14
15ASTDot::ASTDot(std::ostream &out, int i)
16 : out(out)
17 , indent_(i)
18{
19 out << GRAPH_TYPE << " ast\n{";
20 ++indent_;
21 indent() << "forcelabels=true;";
22 indent() << "graph [fontname = \"DejaVu Sans\"];";
23 indent() << "node [fontname = \"DejaVu Sans\"];";
24 indent() << "edge [fontname = \"DejaVu Sans\"];";
25}
26
28{
29 --indent_;
30 M_insist(indent_ == 0);
31 out << "\n}" << std::endl;
32}
33
34void ASTDot::cluster(Const<Clause> &c, const char *name, const char *label, const char *color)
35{
36 indent() << "subgraph cluster_" << name << '_' << &c;
37 indent() << '{';
38 ++indent_;
39 indent() << "style=\"rounded,filled\";";
40 indent() << "color=\"" << color << "\";";
41 indent() << "penwidth=\"4\";";
42 indent() << id(c) << " [label=\"" << label << "\"];";
43
44 (*this)(c);
45
46 --indent_;
47 indent() << '}';
48}
49
50
51/*--- Expressions ----------------------------------------------------------------------------------------------------*/
52
53void ASTDot::operator()(Const<ErrorExpr> &e)
54{
55 indent() << id(e) << " [label=<<FONT COLOR=\"red\"><B>ErrorExpr</B></FONT>>];";
56}
57
58void ASTDot::operator()(Const<Designator> &e)
59{
60 indent() << id(e) << " [label=<<B>";
61
62 if (e.has_explicit_table_name()) out << e.table_name.text << '.';
63 out << e.attr_name.text << "</B>";
64 if (e.has_type()) {
65 std::ostringstream oss;
66 oss << *e.type();
67 out << "<FONT POINT-SIZE=\"11\"><I> : " << html_escape(oss.str());
68 if (auto pt = cast<const PrimitiveType>(e.type()))
69 out << "<SUB>" << (pt->is_scalar() ? "s" : "v") << "</SUB>";
70 out << "</I></FONT>";
71 }
72 out << ">];";
73
74 /* Dot edge to table. */
75 const auto &t = e.target();
76 if (auto val = std::get_if<const Attribute*>(&t)) {
77 const Attribute &A = **val;
78 indent() << id(e) << EDGE << A.table.name() << ':' << A.name
79 << " [style=\"dashed\",dir=\"forward\",color=\"#404040\"];";
80 } else if (auto val = std::get_if<const Expr*>(&t)) {
81 const Expr *expr = *val;
82 indent() << id(e) << EDGE << id(*expr) << " [style=\"dashed\",dir=\"forward\",color=\"crimson\"];";
83 }
84}
85
86void ASTDot::operator()(Const<Constant> &e)
87{
88 indent() << id(e) << " [label=<<B>";
89
90 if (e.is_string()) {
91 out << html_escape(*e.tok.text);
92 } else {
93 out << e.tok.text;
94 }
95 out << "</B>";
96
97 if (e.has_type()) {
98 std::ostringstream oss;
99 oss << *e.type();
100 out << "<FONT POINT-SIZE=\"11\"><I> : " << html_escape(oss.str()) << "</I></FONT>";
101 }
102
103 out << ">];";
104}
105
106void ASTDot::operator()(Const<FnApplicationExpr> &e)
107{
108 (*this)(*e.fn);
109 indent() << id(e) << " [label=<()";
110
111 if (e.has_type()) {
112 std::ostringstream oss;
113 oss << *e.type();
114 out << "<FONT POINT-SIZE=\"11\"><I> : " << html_escape(oss.str()) << "</I></FONT>";
115 }
116
117 out << ">];";
118 indent() << id(e) << EDGE << id(*e.fn) << ';';
119
120 for (auto &arg : e.args) {
121 (*this)(*arg);
122 indent() << id(e) << EDGE << id(*arg) << ';';
123 }
124}
125
126void ASTDot::operator()(Const<UnaryExpr> &e)
127{
128 (*this)(*e.expr);
129 indent() << id(e) << " [label=<" << html_escape(*e.op().text);
130
131 if (e.has_type()) {
132 std::ostringstream oss;
133 oss << *e.type();
134 out << "<FONT POINT-SIZE=\"11\"><I> : " << html_escape(oss.str()) << "</I></FONT>";
135 }
136
137 out << ">];";
138 indent() << id(e) << EDGE << id(*e.expr) << ';';
139}
140
141void ASTDot::operator()(Const<BinaryExpr> &e)
142{
143 (*this)(*e.lhs);
144 (*this)(*e.rhs);
145 indent() << id(e) << " [label=<" << html_escape(*e.op().text);
146
147 if (e.has_type()) {
148 std::ostringstream oss;
149 oss << *e.type();
150 out << "<FONT POINT-SIZE=\"11\"><I> : " << html_escape(oss.str()) << "</I></FONT>";
151 }
152
153 out << ">];";
154 indent() << id(e) << EDGE << id(*e.lhs) << ';';
155 indent() << id(e) << EDGE << id(*e.rhs) << ';';
156}
157
158void ASTDot::operator()(Const<QueryExpr> &e)
159{
160 (*this)(*e.query);
161 indent() << id(e) << " [label=<QueryExpr";
162
163 if (e.has_type()) {
164 std::ostringstream oss;
165 oss << *e.type();
166 out << "<FONT POINT-SIZE=\"11\"><I> : " << html_escape(oss.str()) << "</I></FONT>";
167 }
168
169 out << ">];";
170 indent() << id(e) << EDGE << id(*e.query) << ';';
171}
172
173
174/*--- Clauses --------------------------------------------------------------------------------------------------------*/
175
176void ASTDot::operator()(Const<ErrorClause> &c)
177{
178 indent() << id(c) << " [label=\"ErrorClause\"];";
179}
180
181void ASTDot::operator()(Const<SelectClause> &c)
182{
183 if (c.select_all) {
184 out << '\n';
185 indent() << q(std::hex << c << '*') << "[label=\"*\"];";
186 indent() << id(c) << EDGE << q(std::hex << c << '*') << ';';
187 }
188 for (auto &s : c.select) {
189 out << '\n';
190 (*this)(*s.first);
191 if (s.second) {
192 indent() << id(s.second) << " [label=\"AS " << s.second.text << "\"];";
193 indent() << id(c) << EDGE << id(s.second) << ';';
194 indent() << id(s.second) << EDGE << id(*s.first) << ';';
195 } else {
196 indent() << id(c) << EDGE << id(*s.first) << ';';
197 }
198 }
199}
200
201void ASTDot::operator()(Const<FromClause> &c)
202{
203 for (auto &t : c.from) {
204 out << '\n';
205 if (auto name = std::get_if<Token>(&t.source)) {
206 if (t.alias) {
207 indent() << id(t.alias) << " [label=\"AS " << t.alias.text << "\"];";
208 indent() << id (*name) << " [label=\"" << name->text << "\"];";
209 indent() << id(c) << EDGE << id(t.alias) << EDGE << id(*name) << ';';
210 } else {
211 indent() << id(*name) << " [label=\"" << name->text << "\"];";
212 indent() << id(c) << EDGE << id(*name) << ';';
213 }
214 } else if (auto stmt = std::get_if<Stmt*>(&t.source)) {
215 M_insist(t.alias, "nested statements must have an alias");
216 indent() << id(t.alias) << " [label=\"AS " << t.alias.text << "\"];";
217 (*this)(**stmt);
218 indent() << id(c) << EDGE << id(t.alias) << EDGE << id(**stmt) << ';';
219 } else {
220 M_unreachable("invalid variant");
221 }
222 if (t.has_table()) {
223 M_insist(std::holds_alternative<Token>(t.source));
224 auto &name = std::get<Token>(t.source);
225 auto &R = t.table();
226 indent() << id(name) << EDGE << R.name() << ":n [dir=\"forward\",color=\"#404040\"];";
227 }
228 }
229}
230
231void ASTDot::operator()(Const<WhereClause> &c)
232{
233 out << '\n';
234 (*this)(*c.where);
235 indent() << id(c) << EDGE << id(*c.where) << ';';
236}
237
238void ASTDot::operator()(Const<GroupByClause> &c)
239{
240 for (auto &[grp, alias] : c.group_by) {
241 out << '\n';
242 (*this)(*grp);
243 indent() << id(c) << EDGE << id(*grp) << ';';
244 }
245}
246
247void ASTDot::operator()(Const<HavingClause> &c)
248{
249 out << '\n';
250 (*this)(*c.having);
251 indent() << id(c) << EDGE << id(*c.having) << ';';
252}
253
254void ASTDot::operator()(Const<OrderByClause> &c)
255{
256 for (auto &o : c.order_by) {
257 out << '\n';
258 if (o.second)
259 indent() << id(o.second) << " [label=\"ASC\"];";
260 else
261 indent() << id(o.second) << " [label=\"DESC\"];";
262 indent() << id(c) << EDGE << id(o.second) << ';';
263 (*this)(*o.first);
264 indent() << id(o.second) << EDGE << id(*o.first) << ';';
265 }
266}
267
268void ASTDot::operator()(Const<LimitClause> &c)
269{
270 out << '\n';
271 indent() << id(c.limit) << " [label=<<B>" << c.limit.text << "</B>>];";
272 indent() << id(c) << EDGE << id(c.limit) << ';';
273
274 if (c.offset) {
275 out << '\n';
276 indent() << id(c.offset) << " [label=<OFFSET <B>" << c.offset.text << "</B>>];";
277 indent() << id(c) << EDGE << id(c.offset) << ';';
278 }
279}
280
281
282/*--- Constraints ----------------------------------------------------------------------------------------------------*/
283
284void ASTDot::operator()(Const<PrimaryKeyConstraint> &c)
285{
286 indent() << id(c) << " [label=<<B>PRIMARY KEY</B>>];";
287}
288
289void ASTDot::operator()(Const<UniqueConstraint> &c)
290{
291 indent() << id(c) << " [label=<<B>UNIQUE</B>>];";
292}
293
294void ASTDot::operator()(Const<NotNullConstraint> &c)
295{
296 indent() << id(c) << " [label=<<B>NOT NULL</B>>];";
297}
298
299void ASTDot::operator()(Const<CheckConditionConstraint> &c)
300{
301 (*this)(*c.cond);
302 indent() << id(c) << " [label=<<B>CHECK()</B>>];";
303 indent() << id(c) << EDGE << id(*c.cond) << ';';
304}
305
306void ASTDot::operator()(Const<ReferenceConstraint> &c)
307{
308 indent() << id(c) << " [label=<<B>REFERENCES " << c.table_name.text << '(' << c.attr_name.text << ")</B>>];";
309}
310
311
312/*----- Instruction --------------------------------------------------------------------------------------------------*/
313
314void ASTDot::operator()(const Instruction &inst)
315{
316 out << '\n';
317 std::ostringstream oss;
318 indent() << id(inst) << " [label=\"" << inst.tok.text << "\"];";
319}
320
321
322/*--- Stmt -----------------------------------------------------------------------------------------------------------*/
323
324void ASTDot::operator()(Const<ErrorStmt>&)
325{
326 // TODO implement
327}
328
329void ASTDot::operator()(Const<EmptyStmt>&)
330{
331 // TODO implement
332}
333
334void ASTDot::operator()(Const<CreateDatabaseStmt>&)
335{
336 // TODO implement
337}
338
339void ASTDot::operator()(Const<DropDatabaseStmt>&)
340{
341 // TODO implement
342}
343
344void ASTDot::operator()(Const<UseDatabaseStmt>&)
345{
346 // TODO implement
347}
348
349void ASTDot::operator()(Const<CreateTableStmt>&)
350{
351 // TODO implement
352}
353
354void ASTDot::operator()(Const<DropTableStmt>&)
355{
356 // TODO implement
357}
358
359void ASTDot::operator()(Const<CreateIndexStmt>&)
360{
361 // TODO implement
362}
363
364void ASTDot::operator()(Const<DropIndexStmt>&)
365{
366 // TODO implement
367}
368
369void ASTDot::operator()(Const<SelectStmt> &s)
370{
371 out << '\n';
372 std::ostringstream oss;
373 indent() << id(s) << " [label=\"SelectStmt\"];";
374
375 if (s.from) {
376 /* Dot the accessed tables first. */
377 indent() << "subgraph sources";
378 indent() << '{';
379 ++indent_;
380 if (auto f = cast<FromClause>(s.from.get())) {
381 for (auto &t : f->from) {
382 if (t.has_table()) {
383 auto &R = t.table();
384
385 indent() << R.name() << "[shape=none,style=filled,fillcolor=white,label=<";
386 ++indent_;
387 indent() << "<TABLE>";
388 ++indent_;
389 indent() << "<TR><TD BORDER=\"0\"><B>" << R.name() << "</B></TD></TR>";
390
391 for (auto &A : R) {
392 oss.str("");
393 oss << *A.type;
394 indent() << "<TR><TD PORT=\"" << A.name << "\">" << A.name
395 << "<FONT POINT-SIZE=\"11\"><I> : " << html_escape(oss.str()) << "</I></FONT>"
396 << "</TD></TR>";
397 }
398
399 --indent_;
400 indent() << "</TABLE>";
401 --indent_;
402 indent() << ">];";
403 }
404 }
405 }
406 --indent_;
407 indent() << "}\n";
408 }
409
410 cluster(*s.select, "select", "SELECT", "#e6194B20");
411 indent() << id(s) << EDGE << id(*s.select) << ';';
412
413#define DOT(NAME, LABEL, COLOR) \
414 if (s.NAME) { \
415 out << '\n'; \
416 cluster(*s.NAME, #NAME, LABEL, COLOR); \
417 indent() << id(s) << EDGE << id(*s.NAME) << ';'; \
418 }
419 DOT(from, "FROM", "#bfef4550");
420 DOT(where, "WHERE", "#42d4f430");
421 DOT(group_by, "GROUP BY", "#3cb44b30");
422 DOT(having, "HAVING", "#aaffc350");
423 DOT(order_by, "ORDER BY", "#ffe11950");
424 DOT(limit, "LIMIT", "#80800040");
425#undef DOT
426}
427
428void ASTDot::operator()(Const<InsertStmt>&)
429{
430 // TODO implement
431}
432
433void ASTDot::operator()(Const<UpdateStmt>&)
434{
435 // TODO implement
436}
437
438void ASTDot::operator()(Const<DeleteStmt>&)
439{
440 // TODO implement
441}
442
443void ASTDot::operator()(Const<DSVImportStmt>&)
444{
445 // TODO implement
446}
#define DOT(NAME, LABEL, COLOR)
#define id(X)
#define q(X)
#define M_unreachable(MSG)
Definition: macro.hpp:146
#define M_insist(...)
Definition: macro.hpp:129
std::ostream & indent(std::ostream &out, unsigned indentation)
Start a new line with proper indentation.
Definition: DataLayout.cpp:100
::wasm::Expression * expr()
Moves the underlying Binaryen ::wasm::Expression out of this.
Definition: WasmDSL.hpp:1558
‍mutable namespace
Definition: Backend.hpp:10
std::string M_EXPORT html_escape(std::string str)
Escapes special characters in a string to be printable in HTML documents.
Definition: fn.cpp:60
An attribute of a table.
Definition: Schema.hpp:289
const PrimitiveType * type
the type of the attribute
Definition: Schema.hpp:294
const Table & table
the table the attribute belongs to
Definition: Schema.hpp:293
ThreadSafePooledString name
the name of the attribute
Definition: Schema.hpp:295
virtual const ThreadSafePooledString & name() const =0
Returns the name of the Table.
static constexpr const char *const GRAPH_TYPE
Definition: ASTDot.hpp:14
ASTDot(std::ostream &out, int indent=0)
Definition: ASTDot.cpp:15
std::ostream & out
the output stream to print to
Definition: ASTDot.hpp:17
static constexpr const char *const EDGE
Definition: ASTDot.hpp:15
int indent_
the current indentation for pretty printing
Definition: ASTDot.hpp:20
An expression.
Definition: AST.hpp:39
Token tok
‍the token of the Instruction; starts with \
Definition: AST.hpp:771
ThreadSafePooledOptionalString text
declared as optional for dummy tokens
Definition: Token.hpp:16