aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-24 15:03:27 +0200
committerBad Diode <bd@badd10de.dev>2024-06-24 15:03:27 +0200
commitc9d686a1a6f49f8c8c4aa698c14448d961a0f024 (patch)
tree57a7a94b1dd39b2d5158ff9e81e1e72bc7e80525
parent6fbe06eda046bd3b261e2ba84e1f728ecdf55a47 (diff)
downloadbdl-c9d686a1a6f49f8c8c4aa698c14448d961a0f024.tar.gz
bdl-c9d686a1a6f49f8c8c4aa698c14448d961a0f024.zip
Add more graph viz for function maps and types
-rw-r--r--src/main.c193
-rw-r--r--tests/semantics.bad56
2 files changed, 205 insertions, 44 deletions
diff --git a/src/main.c b/src/main.c
index 33ab4ed..4bfd104 100644
--- a/src/main.c
+++ b/src/main.c
@@ -63,8 +63,15 @@ typedef struct Symbol {
63 struct SymbolMap *fields; 63 struct SymbolMap *fields;
64} Symbol; 64} Symbol;
65 65
66typedef struct Fun {
67 Str name;
68 Str param_type;
69 Str return_type;
70} Fun;
71
66MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq) 72MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq)
67MAPDEF(TypeMap, typemap, Str, Type, str_hash, str_eq) 73MAPDEF(TypeMap, typemap, Str, Type, str_hash, str_eq)
74MAPDEF(FunMap, funmap, Str, Fun, str_hash, str_eq)
68 75
69typedef struct Scope { 76typedef struct Scope {
70 sz id; 77 sz id;
@@ -74,13 +81,17 @@ typedef struct Scope {
74} Scope; 81} Scope;
75 82
76typedef struct TypeScope { 83typedef struct TypeScope {
84 sz id;
85 Str name;
77 TypeMap *types; 86 TypeMap *types;
87 FunMap *funcs;
78 struct TypeScope *parent; 88 struct TypeScope *parent;
79} TypeScope; 89} TypeScope;
80 90
81typedef struct Analyzer { 91typedef struct Analyzer {
82 Arena *storage; 92 Arena *storage;
83 Str file_name; 93 Str file_name;
94 sz typescope_gen;
84 sz scope_gen; 95 sz scope_gen;
85 Scope **scopes; 96 Scope **scopes;
86 TypeScope **types; 97 TypeScope **types;
@@ -103,6 +114,7 @@ TypeScope *
103typescope_alloc(Analyzer *a, TypeScope *parent) { 114typescope_alloc(Analyzer *a, TypeScope *parent) {
104 TypeScope *scope = arena_calloc(sizeof(TypeScope), a->storage); 115 TypeScope *scope = arena_calloc(sizeof(TypeScope), a->storage);
105 scope->parent = parent; 116 scope->parent = parent;
117 scope->id = a->typescope_gen++;
106 array_push(a->types, scope, a->storage); 118 array_push(a->types, scope, a->storage);
107 return scope; 119 return scope;
108} 120}
@@ -139,25 +151,35 @@ graph_scope(Scope *scope, Arena a) {
139 SymbolMapIter iter = symmap_iterator(scope->symbols, &a); 151 SymbolMapIter iter = symmap_iterator(scope->symbols, &a);
140 SymbolMap *sym = symmap_next(&iter, &a); 152 SymbolMap *sym = symmap_next(&iter, &a);
141 print( 153 print(
142 "%d[shape=\"none\" label=<\ 154 "%d[shape=\"none\" label=<<TABLE ALIGN=\"left\" STYLE=\"rounded\" "
143<TABLE ALIGN=\"left\" STYLE=\"rounded\" BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"6\" COLUMNS=\"*\">\ 155 "BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"6\" "
144 <TR style=\"rounded\" ><TD COLSPAN=\"3\">ID: %d</TD></TR>", 156 "COLUMNS=\"*\">"
157 "<TR style=\"rounded\"><TD COLSPAN=\"3\">ID: %d</TD></TR>",
145 scope->id, scope->id); 158 scope->id, scope->id);
146 print( 159 print(
147 "<TR ><TD ALIGN=\"left\" > NAME </TD><TD ALIGN=\"left\" > KIND " 160 "<TR >"
148 "</TD><TD ALIGN=\"left\" > TYPE </TD></TR>"); 161 "<TD ALIGN=\"left\" > NAME </TD>"
162 "<TD ALIGN=\"left\" > KIND </TD>"
163 "<TD ALIGN=\"left\" > TYPE </TD>"
164 "</TR>");
149 while (sym) { 165 while (sym) {
150 Str type_name = cstr("nil"); 166 Str type_name = cstr("nil");
151 print( 167 print(
152 "<TR><TD ALIGN=\"left\"> %s </TD><TD ALIGN=\"left\"> %s </TD><TD " 168 "<TR>"
153 "ALIGN=\"left\"> %s </TD></TR>", 169 "<TD ALIGN=\"left\"> %s </TD>"
170 "<TD ALIGN=\"left\"> %s </TD>"
171 "<TD ALIGN=\"left\"> %s </TD>"
172 "</TR>",
154 sym->val.name, sym_kind_str[sym->val.kind], type_name); 173 sym->val.name, sym_kind_str[sym->val.kind], type_name);
155 SymbolMapIter field_iter = symmap_iterator(sym->val.fields, &a); 174 SymbolMapIter field_iter = symmap_iterator(sym->val.fields, &a);
156 SymbolMap *field = symmap_next(&field_iter, &a); 175 SymbolMap *field = symmap_next(&field_iter, &a);
157 while (field) { 176 while (field) {
158 print( 177 print(
159 "<TR><TD ALIGN=\"left\"> %s.%s </TD><TD ALIGN=\"left\"> %s " 178 "<TR>"
160 "</TD></TR>", 179 "<TD ALIGN=\"left\"> %s.%s </TD>"
180 "<TD ALIGN=\"left\"> %s "
181 "</TD>"
182 "</TR>",
161 sym->val.name, field->val.name, sym_kind_str[field->val.kind]); 183 sym->val.name, field->val.name, sym_kind_str[field->val.kind]);
162 field = symmap_next(&field_iter, &a); 184 field = symmap_next(&field_iter, &a);
163 } 185 }
@@ -176,6 +198,85 @@ graph_scope(Scope *scope, Arena a) {
176} 198}
177 199
178void 200void
201graph_typescope(TypeScope *scope, Arena a) {
202 if (!scope->types) {
203 return;
204 }
205 TypeMapIter iter = typemap_iterator(scope->types, &a);
206 TypeMap *type = typemap_next(&iter, &a);
207 print(
208 "%d[shape=\"none\" label=<<TABLE ALIGN=\"left\" STYLE=\"rounded\" "
209 "BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"6\" "
210 "COLUMNS=\"*\">",
211 scope->id);
212 print(
213 "<TR >"
214 "<TD ALIGN=\"left\" > NAME </TD>"
215 "<TD ALIGN=\"left\" > TYPE </TD>"
216 "</TR>");
217 while (type) {
218 print(
219 "<TR>"
220 "<TD ALIGN=\"left\"> %s </TD>"
221 "<TD ALIGN=\"left\"> %s</TD>"
222 "</TR>",
223 type->key, type->val);
224 type = typemap_next(&iter, &a);
225 }
226 println("</TABLE>>];");
227
228 sz this_id = scope->id;
229 while (scope->parent) {
230 if (scope->parent->types) {
231 println("%d:e->%d:w;", this_id, scope->parent->id);
232 break;
233 } else {
234 scope = scope->parent;
235 }
236 }
237}
238
239void
240graph_functions(TypeScope *scope, Arena a) {
241 if (!scope->funcs) {
242 return;
243 }
244 FunMapIter iter = funmap_iterator(scope->funcs, &a);
245 FunMap *func = funmap_next(&iter, &a);
246 print(
247 "fun_%d[shape=\"none\" label=<<TABLE ALIGN=\"left\" STYLE=\"rounded\" "
248 "BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"6\" "
249 "COLUMNS=\"*\">",
250 scope->id);
251 print(
252 "<TR >"
253 "<TD ALIGN=\"left\" > NAME </TD>"
254 "<TD ALIGN=\"left\" > PARAMS </TD>"
255 "<TD ALIGN=\"left\" > RETURN </TD>"
256 "</TR>");
257 while (func) {
258 print(
259 "<TR>"
260 "<TD PORT=\"%s\" ALIGN=\"left\" > %s </TD>"
261 "<TD ALIGN=\"left\" > %s </TD>"
262 "<TD ALIGN=\"left\" > %s </TD>"
263 "</TR>",
264 func->val.name, func->val.name, func->val.param_type, func->val.return_type);
265 func = funmap_next(&iter, &a);
266 }
267 println("</TABLE>>];");
268 sz this_id = scope->id;
269 while (scope->parent) {
270 if (scope->parent->types) {
271 println("fun_%d:e->fun_%d:%s:w;", this_id, scope->parent->id, scope->name);
272 break;
273 } else {
274 scope = scope->parent;
275 }
276 }
277}
278
279void
179graph_symbols(Scope **scopes, Arena a) { 280graph_symbols(Scope **scopes, Arena a) {
180 if (scopes == NULL) return; 281 if (scopes == NULL) return;
181 println("digraph symbols {"); 282 println("digraph symbols {");
@@ -197,6 +298,28 @@ graph_symbols(Scope **scopes, Arena a) {
197} 298}
198 299
199void 300void
301graph_types(TypeScope **scopes, Arena a) {
302 if (scopes == NULL) return;
303 println("digraph symbols {");
304 println("rankdir=LR;");
305 println("ranksep=\"0.95 equally\";");
306 println("nodesep=\"0.5 equally\";");
307 println("overlap=scale;");
308 println("bgcolor=\"transparent\";");
309 for (sz i = 0; i < array_size(scopes); i++) {
310 TypeScope *scope = scopes[i];
311 if (!scope) {
312 continue;
313 }
314 println("subgraph %d {", i);
315 graph_typescope(scope, a);
316 graph_functions(scope, a);
317 println("}");
318 }
319 println("}");
320}
321
322void
200emit_semantic_error(Analyzer *a, Node *n, Str msg) { 323emit_semantic_error(Analyzer *a, Node *n, Str msg) {
201 eprintln("%s:%d:%d: error: %s", a->file_name, n->line, n->col, msg); 324 eprintln("%s:%d:%d: error: %s", a->file_name, n->line, n->col, msg);
202} 325}
@@ -219,7 +342,9 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) {
219 case NODE_RETURN: { 342 case NODE_RETURN: {
220 bool err = !str_eq(node->type, expected); 343 bool err = !str_eq(node->type, expected);
221 if (err) { 344 if (err) {
222 emit_semantic_error(a, node, cstr("mismatched return types")); 345 eprintln(
346 "%s:%d:%d: error: mismatched return type %s, expected %s",
347 a->file_name, node->line, node->col, node->type, expected);
223 } 348 }
224 } break; 349 } break;
225 case NODE_BLOCK: { 350 case NODE_BLOCK: {
@@ -242,7 +367,25 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) {
242 typecheck_returns(a, node->var_val, expected); 367 typecheck_returns(a, node->var_val, expected);
243 } 368 }
244 } break; 369 } break;
245 default: { 370 case NODE_ADD:
371 case NODE_SUB:
372 case NODE_DIV:
373 case NODE_MUL:
374 case NODE_MOD:
375 case NODE_NOT:
376 case NODE_AND:
377 case NODE_OR:
378 case NODE_EQ:
379 case NODE_NEQ:
380 case NODE_LT:
381 case NODE_GT:
382 case NODE_LE:
383 case NODE_GE:
384 case NODE_BITNOT:
385 case NODE_BITAND:
386 case NODE_BITOR:
387 case NODE_BITLSHIFT:
388 case NODE_BITRSHIFT: {
246 if (node->left) { 389 if (node->left) {
247 typecheck_returns(a, node->left, expected); 390 typecheck_returns(a, node->left, expected);
248 } 391 }
@@ -250,6 +393,7 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) {
250 typecheck_returns(a, node->right, expected); 393 typecheck_returns(a, node->right, expected);
251 } 394 }
252 } break; 395 } break;
396 default: break;
253 } 397 }
254} 398}
255 399
@@ -543,7 +687,7 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) {
543 return node->type; 687 return node->type;
544 } break; 688 } break;
545 case NODE_RETURN: { 689 case NODE_RETURN: {
546 Type ret_type = cstr("("); 690 Type ret_type = cstr("");
547 for (sz i = 0; i < array_size(node->elements); i++) { 691 for (sz i = 0; i < array_size(node->elements); i++) {
548 Node *expr = node->elements[i]; 692 Node *expr = node->elements[i];
549 Type type = type_inference(a, expr, scope); 693 Type type = type_inference(a, expr, scope);
@@ -552,7 +696,6 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) {
552 ret_type = str_concat(ret_type, cstr(","), a->storage); 696 ret_type = str_concat(ret_type, cstr(","), a->storage);
553 } 697 }
554 } 698 }
555 ret_type = str_concat(ret_type, cstr(")"), a->storage);
556 node->type = ret_type; 699 node->type = ret_type;
557 return node->type; 700 return node->type;
558 } break; 701 } break;
@@ -576,8 +719,9 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) {
576 // } 719 // }
577 720
578 node->type = cstr("nil"); 721 node->type = cstr("nil");
722 TypeScope *prev_scope = scope;
579 scope = typescope_alloc(a, scope); 723 scope = typescope_alloc(a, scope);
580 Type param_type = cstr("("); 724 Type param_type = cstr("");
581 for (sz i = 0; i < array_size(node->func_params); i++) { 725 for (sz i = 0; i < array_size(node->func_params); i++) {
582 Node *param = node->func_params[i]; 726 Node *param = node->func_params[i];
583 Str symbol = param->param_name->value.str; 727 Str symbol = param->param_name->value.str;
@@ -591,10 +735,9 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) {
591 param_type = str_concat(param_type, cstr(","), a->storage); 735 param_type = str_concat(param_type, cstr(","), a->storage);
592 } 736 }
593 } 737 }
594 param_type = str_concat(param_type, cstr(")"), a->storage);
595 node->fun_params = param_type; 738 node->fun_params = param_type;
596 739
597 Type ret_type = cstr("("); 740 Type ret_type = cstr("");
598 for (sz i = 0; i < array_size(node->func_ret); i++) { 741 for (sz i = 0; i < array_size(node->func_ret); i++) {
599 Node *expr = node->func_ret[i]; 742 Node *expr = node->func_ret[i];
600 Type type = type_inference(a, expr, scope); 743 Type type = type_inference(a, expr, scope);
@@ -603,9 +746,17 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) {
603 ret_type = str_concat(ret_type, cstr(","), a->storage); 746 ret_type = str_concat(ret_type, cstr(","), a->storage);
604 } 747 }
605 } 748 }
606 ret_type = str_concat(ret_type, cstr(")"), a->storage);
607 node->fun_return = ret_type; 749 node->fun_return = ret_type;
608 750
751 Str symbol = node->func_name->value.str;
752 // TODO: check it was not defined before.
753 scope->name = symbol;
754 funmap_insert(&prev_scope->funcs, symbol,
755 (Fun){.name = symbol,
756 .param_type = param_type,
757 .return_type = ret_type},
758 a->storage);
759
609 if (node->func_body->kind == NODE_BLOCK) { 760 if (node->func_body->kind == NODE_BLOCK) {
610 Type type; 761 Type type;
611 for (sz i = 0; i < array_size(node->func_body->elements); i++) { 762 for (sz i = 0; i < array_size(node->func_body->elements); i++) {
@@ -619,7 +770,10 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) {
619 770
620 // Ensure main body return matches the prototype. 771 // Ensure main body return matches the prototype.
621 if (!str_eq(node->func_body->type, ret_type)) { 772 if (!str_eq(node->func_body->type, ret_type)) {
622 emit_semantic_error(a, node, cstr("mismatched return types")); 773 eprintln(
774 "%s:%d:%d: error: mismatched return type %s, expected %s",
775 a->file_name, node->line, node->col, node->func_body->type,
776 ret_type);
623 } 777 }
624 778
625 // Ensure ALL return statements match the function prototype. 779 // Ensure ALL return statements match the function prototype.
@@ -1017,7 +1171,8 @@ process_file(Str path) {
1017 1171
1018 // Printing symbol tables. 1172 // Printing symbol tables.
1019 if (mode == PRINT_SYMTABLES) { 1173 if (mode == PRINT_SYMTABLES) {
1020 graph_symbols(analyzer.scopes, lexer_arena); 1174 // graph_symbols(analyzer.scopes, lexer_arena);
1175 graph_types(analyzer.types, lexer_arena);
1021 } 1176 }
1022 if (mode == PRINT_SEMANTIC) { 1177 if (mode == PRINT_SEMANTIC) {
1023 graph_ast(parser.nodes); 1178 graph_ast(parser.nodes);
diff --git a/tests/semantics.bad b/tests/semantics.bad
index 518ef40..3305222 100644
--- a/tests/semantics.bad
+++ b/tests/semantics.bad
@@ -1,22 +1,22 @@
1; let a:f32 = (1.0 + 2.0 * 2.0) / 2.0 1; let a:f32 = (1.0 + 2.0 * 2.0) / 2.0
2 2
3; let annotated:int = (1 + 2 * 2) / 2 3let annotated:int = (1 + 2 * 2) / 2
4; let numbers = 1 4let numbers = 1
5; let symbols = numbers 5let symbols = numbers
6; let arith = 1 + 2 * 4 6let arith = 1 + 2 * 4
7; let cmp = 1 <= 2 7let cmp = 1 <= 2
8; let logic = !true && false || (1 <= 2) 8let logic = !true && false || (1 <= 2)
9; let bits = 0xff & 0b00001111 9let bits = 0xff & 0b00001111
10; let block = { 10let block = {
11; let a = 1 + 2 11 let a = 1 + 2
12; a + 3 12 a + 3
13; } 13}
14 14
15; let maybe = if (1 == 2) { 15let maybe = if (1 == 2) {
16; 32 16 32
17; } else { 17} else {
18; 44 18 44
19; } 19}
20 20
21; let single = if (true) { 21; let single = if (true) {
22; 123 22; 123
@@ -46,15 +46,18 @@
46; let a:my_struct 46; let a:my_struct
47; set a.field_a = 1 47; set a.field_a = 1
48 48
49; fun nested(): u32 { 49fun nested(): int {
50; fun adder(a: u32, b: u32): u32 a + b 50 fun adder(a: u32, b: u32): u32 {
51; if (1 + 1 == 2) { 51 a + b
52; { 52 }
53; let b = 32 53 if (1 + 1 == 2) {
54; } 54 let b = 15
55; } 55 5 + b
56; adder(1,2) 56 ; {
57; } 57 ; let b = 32
58 ; }
59 }
60}
58 61
59; enum field { 62; enum field {
60; a 63; a
@@ -110,6 +113,9 @@
110; 1 + 1 + c 113; 1 + 1 + c
111; } 114; }
112fun foo(a: int b: str): (f64, f64) { 115fun foo(a: int b: str): (f64, f64) {
116 fun bar(): nil {
117 println("ding")
118 }
113 if (a == 1) { 119 if (a == 1) {
114 ; return("test", b) 120 ; return("test", b)
115 return(3.0, 4.0) 121 return(3.0, 4.0)