diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-24 17:28:46 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-24 17:28:46 +0200 |
commit | 2560da172f15982da7464a6534702c08f9b7575d (patch) | |
tree | 29dd60aeb65e40c17e52b5bad677502dbb18e163 /src | |
parent | 6d8b7b0bf66d22d6de13474b18617204adfe32e9 (diff) | |
download | bdl-2560da172f15982da7464a6534702c08f9b7575d.tar.gz bdl-2560da172f15982da7464a6534702c08f9b7575d.zip |
Add typechecking for enum fields
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 60 |
1 files changed, 51 insertions, 9 deletions
@@ -6,15 +6,9 @@ | |||
6 | #include "lexer.c" | 6 | #include "lexer.c" |
7 | #include "parser.c" | 7 | #include "parser.c" |
8 | #include "vm.c" | 8 | #include "vm.c" |
9 | // TODO: To typecheck IF we need to make sure it always returns a value if we | 9 | |
10 | // are using it as an expression. Not as straightforward as I initially | 10 | // TODO: typecheck structs |
11 | // imagined! An alternative is implicit zero value in the previous case: | 11 | // TODO: add field accessor for struct/enum symbols |
12 | // | ||
13 | // let a = if (expr) 123 | ||
14 | // | ||
15 | // If the expression evalueates to `true`, a will be 123, otherwise, 0. | ||
16 | // | ||
17 | // This pattern seems quite common in practice no? | ||
18 | 12 | ||
19 | typedef enum ExecMode { | 13 | typedef enum ExecMode { |
20 | RUN_NORMAL, | 14 | RUN_NORMAL, |
@@ -69,9 +63,21 @@ typedef struct Fun { | |||
69 | Str return_type; | 63 | Str return_type; |
70 | } Fun; | 64 | } Fun; |
71 | 65 | ||
66 | typedef struct Field { | ||
67 | Str name; | ||
68 | Node *val; | ||
69 | } Field; | ||
70 | |||
71 | typedef struct Enum { | ||
72 | Str name; | ||
73 | struct FieldMap *fields; | ||
74 | } Enum; | ||
75 | |||
72 | MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq) | 76 | MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq) |
73 | MAPDEF(TypeMap, typemap, Str, Type, str_hash, str_eq) | 77 | MAPDEF(TypeMap, typemap, Str, Type, str_hash, str_eq) |
74 | MAPDEF(FunMap, funmap, Str, Fun, str_hash, str_eq) | 78 | MAPDEF(FunMap, funmap, Str, Fun, str_hash, str_eq) |
79 | MAPDEF(EnumMap, enummap, Str, Enum, str_hash, str_eq) | ||
80 | MAPDEF(FieldMap, fieldmap, Str, Field, str_hash, str_eq) | ||
75 | 81 | ||
76 | typedef struct Scope { | 82 | typedef struct Scope { |
77 | sz id; | 83 | sz id; |
@@ -85,6 +91,7 @@ typedef struct TypeScope { | |||
85 | Str name; | 91 | Str name; |
86 | TypeMap *types; | 92 | TypeMap *types; |
87 | FunMap *funcs; | 93 | FunMap *funcs; |
94 | EnumMap *enums; | ||
88 | struct TypeScope *parent; | 95 | struct TypeScope *parent; |
89 | } TypeScope; | 96 | } TypeScope; |
90 | 97 | ||
@@ -471,6 +478,37 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
471 | node->type = cstr("nil"); | 478 | node->type = cstr("nil"); |
472 | return node->type; | 479 | return node->type; |
473 | } break; | 480 | } break; |
481 | case NODE_ENUM: { | ||
482 | node->type = cstr("nil"); | ||
483 | Str symbol = node->value.str; | ||
484 | EnumMap *e = enummap_insert(&scope->enums, symbol, | ||
485 | (Enum){.name = symbol}, a->storage); | ||
486 | for (sz i = 0; i < array_size(node->struct_field); i++) { | ||
487 | Node *field = node->struct_field[i]; | ||
488 | Str field_name = field->field_name->value.str; | ||
489 | if (fieldmap_lookup(&e->val.fields, field_name)) { | ||
490 | eprintln( | ||
491 | "%s:%d:%d: error: enum field '%s.%s' already exists", | ||
492 | a->file_name, field->line, field->col, symbol, | ||
493 | field_name); | ||
494 | } | ||
495 | if (field->field_val) { | ||
496 | Type type = type_inference(a, field->field_val, scope); | ||
497 | if (!str_eq(type, cstr("int"))) { | ||
498 | eprintln( | ||
499 | "%s:%d:%d: error: non int enum value for '%s.%s'", | ||
500 | a->file_name, field->line, field->col, symbol, | ||
501 | field_name); | ||
502 | } | ||
503 | } | ||
504 | fieldmap_insert( | ||
505 | &e->val.fields, field_name, | ||
506 | (Field){.name = field_name, .val = field->field_val}, | ||
507 | a->storage); | ||
508 | field->type = cstr("int"); | ||
509 | } | ||
510 | return node->type; | ||
511 | } break; | ||
474 | case NODE_IF: { | 512 | case NODE_IF: { |
475 | Type cond_type = type_inference(a, node->cond_if, scope); | 513 | Type cond_type = type_inference(a, node->cond_if, scope); |
476 | if (!str_eq(cond_type, cstr("bool"))) { | 514 | if (!str_eq(cond_type, cstr("bool"))) { |
@@ -566,6 +604,10 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
566 | node->type = cstr("bool"); | 604 | node->type = cstr("bool"); |
567 | return node->type; | 605 | return node->type; |
568 | } break; | 606 | } break; |
607 | case NODE_NIL: { | ||
608 | node->type = cstr("nil"); | ||
609 | return node->type; | ||
610 | } break; | ||
569 | case NODE_NOT: | 611 | case NODE_NOT: |
570 | case NODE_AND: | 612 | case NODE_AND: |
571 | case NODE_OR: { | 613 | case NODE_OR: { |