aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-21 15:59:32 +0200
committerBad Diode <bd@badd10de.dev>2024-06-21 15:59:32 +0200
commit59b9c661cbdf125b0a17f8f955158a1f77f163f8 (patch)
tree36c5b0abe4bb8202f6b23c30759706cd1c0f8a49
parentd336498c7cf397de496fa46fccc31883480ecb1d (diff)
downloadbdl-59b9c661cbdf125b0a17f8f955158a1f77f163f8.tar.gz
bdl-59b9c661cbdf125b0a17f8f955158a1f77f163f8.zip
Add semantic checking for enum constructs
-rw-r--r--src/main.c56
-rw-r--r--src/parser.c5
-rw-r--r--tests/conditionals.bad17
-rw-r--r--tests/semantics.bad84
4 files changed, 108 insertions, 54 deletions
diff --git a/src/main.c b/src/main.c
index 7cb0b87..8e177e1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -28,16 +28,21 @@ typedef enum {
28 SYM_FUN, 28 SYM_FUN,
29 SYM_VAR, 29 SYM_VAR,
30 SYM_PARAM, 30 SYM_PARAM,
31 SYM_ENUM,
32 SYM_ENUM_FIELD,
31} SymbolKind; 33} SymbolKind;
32 34
33Str sym_kind_str[] = { 35Str sym_kind_str[] = {
34 [SYM_UNKNOWN] = cstr("UNKNOWN "), [SYM_BUILTIN] = cstr("BUILTIN "), 36 [SYM_UNKNOWN] = cstr("UNKNOWN "), [SYM_BUILTIN] = cstr("BUILTIN "),
35 [SYM_FUN] = cstr("FUNCTION "), [SYM_VAR] = cstr("VARIABLE "), 37 [SYM_FUN] = cstr("FUNCTION "), [SYM_VAR] = cstr("VARIABLE "),
36 [SYM_PARAM] = cstr("PARAMETER "), 38 [SYM_PARAM] = cstr("PARAMETER "), [SYM_ENUM] = cstr("ENUM "),
39 [SYM_ENUM_FIELD] = cstr("ENUM FIELD"),
37}; 40};
38 41
39typedef struct Symbol { 42typedef struct Symbol {
40 SymbolKind kind; 43 SymbolKind kind;
44 Str name;
45 struct Symbol *fields;
41} Symbol; 46} Symbol;
42 47
43MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq) 48MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq)
@@ -100,15 +105,18 @@ analyzer_symbols(Analyzer *a, Node *node, Scope *scope) {
100 node->func_name->col, symbol); 105 node->func_name->col, symbol);
101 } 106 }
102 symmap_insert(&scope->symbols, symbol, 107 symmap_insert(&scope->symbols, symbol,
103 (Symbol){.kind = SYM_FUN}, a->storage); 108 (Symbol){.kind = SYM_FUN, .name = symbol},
109 a->storage);
104 } 110 }
105 111
106 scope = scope_alloc(a, scope); 112 scope = scope_alloc(a, scope);
107 node->scope = scope; 113 node->scope = scope;
108 for (sz i = 0; i < array_size(node->func_params); i++) { 114 for (sz i = 0; i < array_size(node->func_params); i++) {
109 Node *param = node->func_params[i]; 115 Node *param = node->func_params[i];
110 symmap_insert(&scope->symbols, param->param_name->value.str, 116 Str param_name = param->param_name->value.str;
111 (Symbol){.kind = SYM_PARAM}, a->storage); 117 symmap_insert(&scope->symbols, param_name,
118 (Symbol){.kind = SYM_PARAM, .name = param_name},
119 a->storage);
112 } 120 }
113 if (node->func_body->kind == NODE_BLOCK) { 121 if (node->func_body->kind == NODE_BLOCK) {
114 node = node->func_body; 122 node = node->func_body;
@@ -150,6 +158,27 @@ analyzer_symbols(Analyzer *a, Node *node, Scope *scope) {
150 analyzer_symbols(a, expr, next); 158 analyzer_symbols(a, expr, next);
151 } 159 }
152 } break; 160 } break;
161 case NODE_ENUM: {
162 Str symbol = node->value.str;
163 if (symmap_lookup(&scope->symbols, symbol) != NULL) {
164 eprintln(
165 "%s:%d:%d: error: symbol '%s' already exists in current "
166 " scope ",
167 a->file_name, node->line, node->col, symbol);
168 }
169 SymbolMap *map = symmap_insert(
170 &scope->symbols, symbol,
171 (Symbol){.kind = SYM_ENUM, .name = symbol}, a->storage);
172 // TODO: symcheck the value expression?
173 for (sz i = 0; i < array_size(node->struct_field); i++) {
174 Node *field = node->struct_field[i];
175 Str field_name = field->field_name->value.str;
176 field_name = str_concat(cstr("."), field_name, a->storage);
177 field_name = str_concat(symbol, field_name, a->storage);
178 Symbol s = (Symbol){.kind = SYM_ENUM_FIELD, .name = field_name};
179 array_push(map->val.fields, s, a->storage);
180 }
181 } break;
153 case NODE_CASE: { 182 case NODE_CASE: {
154 analyzer_symbols(a, node->case_value, scope); 183 analyzer_symbols(a, node->case_value, scope);
155 if (node->case_expr) { 184 if (node->case_expr) {
@@ -225,7 +254,8 @@ analyzer_symbols(Analyzer *a, Node *node, Scope *scope) {
225 a->file_name, node->var_name->line, node->var_name->col, 254 a->file_name, node->var_name->line, node->var_name->col,
226 symbol); 255 symbol);
227 } 256 }
228 symmap_insert(&scope->symbols, symbol, (Symbol){.kind = SYM_VAR}, 257 symmap_insert(&scope->symbols, symbol,
258 (Symbol){.kind = SYM_VAR, .name = symbol},
229 a->storage); 259 a->storage);
230 } break; 260 } break;
231 // Binary ops 261 // Binary ops
@@ -269,7 +299,7 @@ symbolic_analysis(Analyzer *a, Parser *parser) {
269 }; 299 };
270 for (sz i = 0; i < LEN(builtin_functions); i++) { 300 for (sz i = 0; i < LEN(builtin_functions); i++) {
271 Str symbol = builtin_functions[i]; 301 Str symbol = builtin_functions[i];
272 Symbol sym = (Symbol){.kind = SYM_BUILTIN}; 302 Symbol sym = (Symbol){.kind = SYM_BUILTIN, .name = symbol};
273 symmap_insert(&scope->symbols, symbol, sym, a->storage); 303 symmap_insert(&scope->symbols, symbol, sym, a->storage);
274 } 304 }
275 305
@@ -285,7 +315,8 @@ symbolic_analysis(Analyzer *a, Parser *parser) {
285 a->file_name, root->func_name->line, root->func_name->col, 315 a->file_name, root->func_name->line, root->func_name->col,
286 symbol); 316 symbol);
287 } 317 }
288 symmap_insert(&scope->symbols, symbol, (Symbol){.kind = SYM_FUN}, 318 symmap_insert(&scope->symbols, symbol,
319 (Symbol){.kind = SYM_FUN, .name = symbol},
289 a->storage); 320 a->storage);
290 } 321 }
291 } 322 }
@@ -376,7 +407,12 @@ process_file(Str path) {
376 SymbolMap *sym = symmap_next(&iter, &scratch); 407 SymbolMap *sym = symmap_next(&iter, &scratch);
377 while (sym) { 408 while (sym) {
378 println("%s: SCOPE: %d DEPTH: %d\t%s %s", path, scope->id, 409 println("%s: SCOPE: %d DEPTH: %d\t%s %s", path, scope->id,
379 scope->depth, sym_kind_str[sym->val.kind], sym->key); 410 scope->depth, sym_kind_str[sym->val.kind], sym->val.name);
411 for (sz i = 0; i < array_size(sym->val.fields); i++) {
412 Symbol field = sym->val.fields[i];
413 println("%s: SCOPE: %d DEPTH: %d\t%s %s", path, scope->id,
414 scope->depth, sym_kind_str[field.kind], field.name);
415 }
380 sym = symmap_next(&iter, &lexer_arena); 416 sym = symmap_next(&iter, &lexer_arena);
381 } 417 }
382 } 418 }
diff --git a/src/parser.c b/src/parser.c
index 04692b3..67fc739 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -192,7 +192,7 @@ typedef struct Node {
192 }; 192 };
193 }; 193 };
194 bool is_ptr; 194 bool is_ptr;
195 struct Scope* scope; 195 struct Scope *scope;
196} Node; 196} Node;
197 197
198// 198//
@@ -651,6 +651,9 @@ parse_keyword(Parser *parser) {
651 } 651 }
652 array_push(node->struct_field, field, parser->storage); 652 array_push(node->struct_field, field, parser->storage);
653 } 653 }
654 if (array_size(node->struct_field) == 0) {
655 parse_emit_err(parser, prev, cstr("empty enum declaration"));
656 }
654 } break; 657 } break;
655 case TOK_COND: { 658 case TOK_COND: {
656 node = node_alloc(parser, NODE_COND, prev); 659 node = node_alloc(parser, NODE_COND, prev);
diff --git a/tests/conditionals.bad b/tests/conditionals.bad
index e1a456e..b5ef61f 100644
--- a/tests/conditionals.bad
+++ b/tests/conditionals.bad
@@ -34,12 +34,17 @@ enum flags {
34 node_div = 1 << 2 34 node_div = 1 << 2
35 node_mul 35 node_mul
36} 36}
37let a:flags = flags.node_add 37let f:flags = flags.node_add
38 38
39; No need to qualify enum fields inside match-case. 39; TODO: No need to qualify enum fields inside match-case.
40; match (a) {
41; case node_add = "adding something..."
42; case node_add = "subbing something..."
43; else = "default case"
44; }
40match (a) { 45match (a) {
41 case node_add = "adding something..." 46 case flags.node_add = "adding something..."
42 case node_add = "subbing something..." 47 case flags.node_add = "subbing something..."
43 else = "default case" 48 else = "default case"
44} 49}
45 50
@@ -47,6 +52,6 @@ match (a) {
47; statements. 52; statements.
48let msg:str = cond { 53let msg:str = cond {
49 case a == b = "hello" 54 case a == b = "hello"
50 case a != c = "world" 55 case a != f = "world"
51 else = "what" 56 else = "what"
52} 57}
diff --git a/tests/semantics.bad b/tests/semantics.bad
index 4ce40b9..29c91c4 100644
--- a/tests/semantics.bad
+++ b/tests/semantics.bad
@@ -1,49 +1,59 @@
1fun foo(): nil { 1enum field {
2 bar() 2 a
3 b
4 ; a
5 ; c = field.a
6 ; c = field.c
7 ; c = c
8 ; c = a
3} 9}
4 10
5fun bar(): nil { 11; fun foo(): nil {
6 foo() 12; bar()
7} 13; }
8 14
9; There are some builtint functions. 15; fun bar(): nil {
10println("hello world") 16; foo()
17; }
11 18
12; Let/set. 19; ; There are some builtint functions.
13let num = 1 20; println("hello world")
14set num = 2
15set num = 0 + num
16 21
17; Loops and conditionals. 22; ; Let/set.
18if (num) 3 else 1 23; let num = 1
19let val = if (2 + num == 4) num else num 24; set num = 2
20if (true) { 25; set num = 0 + num
21 let c = 1
22 1 + 1 + c
23}
24 26
25match (num) { 27; ; Loops and conditionals.
26 case 1 = 23 28; if (num) 3 else 1
27 case 2 = num 29; let val = if (2 + num == 4) num else num
28 else = num 30; if (true) {
29} 31; let c = 1
32; 1 + 1 + c
33; }
30 34
31cond { 35; match (num) {
32 case 1 == 1 = 23 36; case 1 = 23
33 case 2 != 1 = num 37; case 2 = num
34 else = num 38; else = num
35} 39; }
36 40
37while (num == 1) num 41; cond {
38while (true) { 42; case 1 == 1 = 23
39 let c = 1 43; case 2 != 1 = num
40 1 + 1 + c 44; else = num
41} 45; }
42 46
43fun nested(): u32 { 47; while (num == 1) num
44 fun adder(a: u32, b: u32): u32 a + b 48; while (true) {
45 adder(1,2) 49; let c = 1
46} 50; 1 + 1 + c
51; }
52
53; fun nested(): u32 {
54; fun adder(a: u32, b: u32): u32 a + b
55; adder(1,2)
56; }
47 57
48; This should err. 58; This should err.
49; fun foo(): nil { 59; fun foo(): nil {