diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-24 17:51:18 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-24 17:51:18 +0200 |
commit | 8658d71e8a0761f8407b35cdf08b4b80229f560e (patch) | |
tree | 80440edae7a8c6083c903a39f6531fd106c1988c | |
parent | 2560da172f15982da7464a6534702c08f9b7575d (diff) | |
download | bdl-8658d71e8a0761f8407b35cdf08b4b80229f560e.tar.gz bdl-8658d71e8a0761f8407b35cdf08b4b80229f560e.zip |
Add field accessor for typechecking enum fields
-rw-r--r-- | src/main.c | 45 | ||||
-rw-r--r-- | tests/semantics.bad | 3 |
2 files changed, 43 insertions, 5 deletions
@@ -8,7 +8,7 @@ | |||
8 | #include "vm.c" | 8 | #include "vm.c" |
9 | 9 | ||
10 | // TODO: typecheck structs | 10 | // TODO: typecheck structs |
11 | // TODO: add field accessor for struct/enum symbols | 11 | // TODO: add field accessor for struct symbols |
12 | 12 | ||
13 | typedef enum ExecMode { | 13 | typedef enum ExecMode { |
14 | RUN_NORMAL, | 14 | RUN_NORMAL, |
@@ -162,6 +162,18 @@ find_fun(TypeScope *scope, Str type) { | |||
162 | return NULL; | 162 | return NULL; |
163 | } | 163 | } |
164 | 164 | ||
165 | EnumMap * | ||
166 | find_enum(TypeScope *scope, Str type) { | ||
167 | while (scope != NULL) { | ||
168 | EnumMap *val = enummap_lookup(&scope->enums, type); | ||
169 | if (val != NULL) { | ||
170 | return val; | ||
171 | } | ||
172 | scope = scope->parent; | ||
173 | } | ||
174 | return NULL; | ||
175 | } | ||
176 | |||
165 | void | 177 | void |
166 | graph_scope(Scope *scope, Arena a) { | 178 | graph_scope(Scope *scope, Arena a) { |
167 | if (!scope->symbols) { | 179 | if (!scope->symbols) { |
@@ -507,6 +519,7 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
507 | a->storage); | 519 | a->storage); |
508 | field->type = cstr("int"); | 520 | field->type = cstr("int"); |
509 | } | 521 | } |
522 | typemap_insert(&scope->types, symbol, symbol, a->storage); | ||
510 | return node->type; | 523 | return node->type; |
511 | } break; | 524 | } break; |
512 | case NODE_IF: { | 525 | case NODE_IF: { |
@@ -716,11 +729,33 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
716 | return node->type; | 729 | return node->type; |
717 | } break; | 730 | } break; |
718 | case NODE_SYMBOL: { | 731 | case NODE_SYMBOL: { |
719 | TypeMap *type = find_type(scope, node->value.str); | 732 | Str symbol = node->value.str; |
720 | if (type) { | 733 | TypeMap *type = find_type(scope, symbol); |
721 | node->type = type->val; | 734 | if (!type) { |
722 | return node->type; | 735 | eprintln("%s:%d:%d: error: couldn't resolve symbol '%s'", |
736 | a->file_name, node->line, node->col, symbol); | ||
737 | return cstr(""); | ||
723 | } | 738 | } |
739 | EnumMap *e = find_enum(scope, type->val); | ||
740 | if (e && str_eq(symbol, type->val)) { | ||
741 | if (!node->next) { | ||
742 | eprintln( | ||
743 | "%s:%d:%d: error: unspecified enum field for symbol " | ||
744 | "'%s'", | ||
745 | a->file_name, node->line, node->col, symbol); | ||
746 | return cstr(""); | ||
747 | } | ||
748 | // Check if there is a next and it matches the enum field. | ||
749 | if (!fieldmap_lookup(&e->val.fields, node->next->value.str)) { | ||
750 | eprintln( | ||
751 | "%s:%d:%d: error: unknown enum field for symbol " | ||
752 | "'%s'", | ||
753 | a->file_name, node->line, node->col, symbol); | ||
754 | return cstr(""); | ||
755 | } | ||
756 | node->next->type = symbol; | ||
757 | } | ||
758 | node->type = type->val; | ||
724 | return node->type; | 759 | return node->type; |
725 | } break; | 760 | } break; |
726 | case NODE_FUNCALL: { | 761 | case NODE_FUNCALL: { |
diff --git a/tests/semantics.bad b/tests/semantics.bad index ee56c14..486f6c0 100644 --- a/tests/semantics.bad +++ b/tests/semantics.bad | |||
@@ -7,6 +7,9 @@ enum weekdays { | |||
7 | sat | 7 | sat |
8 | sun | 8 | sun |
9 | } | 9 | } |
10 | let a = weekdays.tue | ||
11 | let b = a | ||
12 | |||
10 | ; fun add10(a: int, b: str): int { | 13 | ; fun add10(a: int, b: str): int { |
11 | ; a + 10 | 14 | ; a + 10 |
12 | ; } | 15 | ; } |