aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.c
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-24 17:28:46 +0200
committerBad Diode <bd@badd10de.dev>2024-06-24 17:28:46 +0200
commit2560da172f15982da7464a6534702c08f9b7575d (patch)
tree29dd60aeb65e40c17e52b5bad677502dbb18e163 /src/main.c
parent6d8b7b0bf66d22d6de13474b18617204adfe32e9 (diff)
downloadbdl-2560da172f15982da7464a6534702c08f9b7575d.tar.gz
bdl-2560da172f15982da7464a6534702c08f9b7575d.zip
Add typechecking for enum fields
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c60
1 files changed, 51 insertions, 9 deletions
diff --git a/src/main.c b/src/main.c
index 4cbce58..f2c4d4f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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
19typedef enum ExecMode { 13typedef 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
66typedef struct Field {
67 Str name;
68 Node *val;
69} Field;
70
71typedef struct Enum {
72 Str name;
73 struct FieldMap *fields;
74} Enum;
75
72MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq) 76MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq)
73MAPDEF(TypeMap, typemap, Str, Type, str_hash, str_eq) 77MAPDEF(TypeMap, typemap, Str, Type, str_hash, str_eq)
74MAPDEF(FunMap, funmap, Str, Fun, str_hash, str_eq) 78MAPDEF(FunMap, funmap, Str, Fun, str_hash, str_eq)
79MAPDEF(EnumMap, enummap, Str, Enum, str_hash, str_eq)
80MAPDEF(FieldMap, fieldmap, Str, Field, str_hash, str_eq)
75 81
76typedef struct Scope { 82typedef 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: {