diff options
author | Bad Diode <bd@badd10de.dev> | 2022-04-08 08:25:48 -0300 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2022-04-08 08:25:48 -0300 |
commit | 55ecfb3b7713172f76ddbff022fa4d6a80d0661a (patch) | |
tree | 6a6baae20d67824d5f79b801b27f58cc967a3ba1 /src/viz.c | |
parent | 9f934cbc0f0fd60a6938ac1c4c84edc270de94ca (diff) | |
download | bdl-55ecfb3b7713172f76ddbff022fa4d6a80d0661a.tar.gz bdl-55ecfb3b7713172f76ddbff022fa4d6a80d0661a.zip |
Add initial implementation of AST vizualization
Diffstat (limited to 'src/viz.c')
-rw-r--r-- | src/viz.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/viz.c b/src/viz.c new file mode 100644 index 0000000..d409472 --- /dev/null +++ b/src/viz.c | |||
@@ -0,0 +1,152 @@ | |||
1 | static const char* node_str[] = { | ||
2 | [NODE_BUILTIN] = "BUILTIN", | ||
3 | [NODE_NUMBER] = "NUMBER", | ||
4 | [NODE_BOOL] = "BOOL", | ||
5 | [NODE_STRING] = "STRING", | ||
6 | [NODE_SYMBOL] = "SYMBOL", | ||
7 | [NODE_TYPE] = "TYPE", | ||
8 | [NODE_DEF] = "DEF", | ||
9 | [NODE_SET] = "SET", | ||
10 | [NODE_FUN] = "FUN", | ||
11 | [NODE_BLOCK] = "BLOCK", | ||
12 | [NODE_IF] = "IF", | ||
13 | }; | ||
14 | |||
15 | void | ||
16 | viz_node(Node *node) { | ||
17 | if (node == NULL) { | ||
18 | return; | ||
19 | } | ||
20 | printf("%zu [width=2.5,shape=Mrecord,label=\"", node->id); | ||
21 | printf("<top> %s -- [%4ld:%-4ld] ", node_str[node->type], node->line, node->col); | ||
22 | switch (node->type) { | ||
23 | case NODE_NUMBER: { | ||
24 | printf("| Value: "); | ||
25 | if (node->number.negative) { | ||
26 | printf("-"); | ||
27 | } | ||
28 | if (node->number.fractional != 0) { | ||
29 | printf("%zu.%zu", node->number.integral, node->number.fractional); | ||
30 | } else { | ||
31 | printf("%zu", node->number.integral); | ||
32 | } | ||
33 | printf("\"];\n"); | ||
34 | } break; | ||
35 | case NODE_SYMBOL: | ||
36 | case NODE_TYPE: | ||
37 | case NODE_STRING: { | ||
38 | printf(" | Value: "); | ||
39 | sv_write(&node->string); | ||
40 | printf("\"];\n"); | ||
41 | } break; | ||
42 | case NODE_BOOL: { | ||
43 | printf(" | Value: "); | ||
44 | if (node->boolean) { | ||
45 | printf("true"); | ||
46 | } else { | ||
47 | printf("false"); | ||
48 | } | ||
49 | printf("\"];\n"); | ||
50 | } break; | ||
51 | case NODE_BUILTIN: { | ||
52 | printf(" | Name: %s", token_str[node->builtin.type]); | ||
53 | printf(" | <args> Args: "); | ||
54 | printf("\"];\n"); | ||
55 | size_t n_args = array_size(node->builtin.args); | ||
56 | for (size_t i = 0; i < n_args; ++i) { | ||
57 | viz_node(node->builtin.args[i]); | ||
58 | printf("%zu:args:e->%zu:top:w;\n", node->id, node->builtin.args[i]->id); | ||
59 | } | ||
60 | } break; | ||
61 | case NODE_DEF: { | ||
62 | printf(" | Name: "); | ||
63 | sv_write(&node->def.symbol->string); | ||
64 | printf(" | Type: "); | ||
65 | sv_write(&node->def.type->string); | ||
66 | printf(" | <val> Expr: "); | ||
67 | printf("\"];\n"); | ||
68 | viz_node(node->def.value); | ||
69 | printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); | ||
70 | } break; | ||
71 | case NODE_SET: { | ||
72 | printf(" | Name: "); | ||
73 | sv_write(&node->set.symbol->string); | ||
74 | printf(" | <val> Expr: "); | ||
75 | printf("\"];\n"); | ||
76 | viz_node(node->set.value); | ||
77 | printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); | ||
78 | } break; | ||
79 | case NODE_BLOCK: { | ||
80 | printf(" | <expr> Exprs: "); | ||
81 | printf("\"];\n"); | ||
82 | size_t n_expr = array_size(node->block.expr); | ||
83 | for (size_t i = 0; i < n_expr; ++i) { | ||
84 | viz_node(node->block.expr[i]); | ||
85 | printf("%zu:expr:e->%zu:top:w;\n", node->id, node->block.expr[i]->id); | ||
86 | } | ||
87 | } break; | ||
88 | case NODE_IF: { | ||
89 | printf(" | <cond> Cond: "); | ||
90 | printf(" | <t> ExprTrue:"); | ||
91 | if (node->ifexpr.expr_false != NULL) { | ||
92 | printf(" | <f> ExprFalse: "); | ||
93 | } | ||
94 | printf("\"];\n"); | ||
95 | viz_node(node->ifexpr.cond); | ||
96 | printf("%zu:cond:e->%zu:top:w;\n", node->id, node->ifexpr.cond->id); | ||
97 | viz_node(node->ifexpr.expr_true); | ||
98 | printf("%zu:t:e->%zu:top:w;\n", node->id, node->ifexpr.expr_true->id); | ||
99 | if (node->ifexpr.expr_false != NULL) { | ||
100 | viz_node(node->ifexpr.expr_false); | ||
101 | printf("%zu:f:e->%zu:top:w;\n", node->id, node->ifexpr.expr_false->id); | ||
102 | } | ||
103 | } break; | ||
104 | case NODE_FUN: { | ||
105 | printf(" | Name: "); | ||
106 | sv_write(&node->fun.name->string); | ||
107 | printf(" | Type: "); | ||
108 | printf("("); | ||
109 | size_t n_params = array_size(node->fun.param_names); | ||
110 | for (size_t i = 0; i < n_params; ++i) { | ||
111 | printf(":"); | ||
112 | sv_write(&node->fun.param_types[i]->string); | ||
113 | if (i < n_params - 1) { | ||
114 | printf(" "); | ||
115 | } | ||
116 | } | ||
117 | printf("):"); | ||
118 | sv_write(&node->fun.return_type->string); | ||
119 | if (n_params > 0) { | ||
120 | printf(" | Parameters: ("); | ||
121 | for (size_t i = 0; i < n_params; ++i) { | ||
122 | sv_write(&node->fun.param_names[i]->string); | ||
123 | if (i < n_params - 1) { | ||
124 | printf(" "); | ||
125 | } | ||
126 | } | ||
127 | printf(")"); | ||
128 | } | ||
129 | printf(" | <bod> Body: "); | ||
130 | printf("\"];\n"); | ||
131 | viz_node(node->fun.body); | ||
132 | printf("%zu:bod:e->%zu:top:w;\n", node->id, node->fun.body->id); | ||
133 | } break; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | void | ||
138 | viz_ast(ParseTree *parse_tree) { | ||
139 | printf("digraph ast {\n"); | ||
140 | printf("rankdir=LR;\n"); | ||
141 | printf("ranksep=\"0.95 equally\";\n"); | ||
142 | printf("nodesep=\"0.5 equally\";\n"); | ||
143 | printf("overlap=scale;\n"); | ||
144 | for (size_t i = 0; i < array_size(parse_tree->roots); ++i) { | ||
145 | printf("subgraph %zu {\n", i); | ||
146 | Node *root = parse_tree->roots[array_size(parse_tree->roots) - 1 - i]; | ||
147 | viz_node(root); | ||
148 | printf("}\n"); | ||
149 | } | ||
150 | printf("}\n"); | ||
151 | } | ||
152 | |||