From bc9aa6e8ad03cd739cd54a9b97f78a14287b9fbd Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Tue, 25 Jun 2024 17:45:27 +0200 Subject: Add inner struct typechecking --- src/main.c | 206 +++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 133 insertions(+), 73 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index f792b10..d3c171c 100644 --- a/src/main.c +++ b/src/main.c @@ -9,11 +9,10 @@ // TODO: in a let/set expression if the type is a struct check that we // are assigning a struct literal, not just a symbol. -// TODO: nested structs // TODO: unions // TODO: match deconstruct structs // TODO: arrays and pointers -// TODO: struct literals +// TODO: struct literals with compound types typedef enum ExecMode { RUN_NORMAL, @@ -68,20 +67,15 @@ typedef struct Fun { Str return_type; } Fun; -typedef struct Field { - Str name; - Str type; - Node *val; -} Field; - typedef struct Enum { Str name; - struct FieldMap *fields; + Node *val; } Enum; typedef struct Struct { Str name; - struct FieldMap *fields; + Str type; + Node *val; } Struct; MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq) @@ -89,7 +83,6 @@ MAPDEF(TypeMap, typemap, Str, Type, str_hash, str_eq) MAPDEF(FunMap, funmap, Str, Fun, str_hash, str_eq) MAPDEF(EnumMap, enummap, Str, Enum, str_hash, str_eq) MAPDEF(StructMap, structmap, Str, Struct, str_hash, str_eq) -MAPDEF(FieldMap, fieldmap, Str, Field, str_hash, str_eq) typedef struct Scope { sz id; @@ -382,6 +375,65 @@ emit_semantic_error(Analyzer *a, Node *n, Str msg) { eprintln("%s:%d:%d: error: %s", a->file_name, n->line, n->col, msg); } +Type type_inference(Analyzer *a, Node *node, TypeScope *scope); + +void +typecheck_field(Analyzer *a, + Node *node, + TypeScope *scope, + Str symbol, + StructMap *map) { + // TODO: ensure the tables are filled properly. + if (node->field_type->kind == NODE_COMPOUND_TYPE) { + Str field_name = str_concat(symbol, cstr("."), a->storage); + field_name = str_concat(field_name, node->value.str, a->storage); + if (structmap_lookup(&map, field_name)) { + eprintln("%s:%d:%d: error: struct field '%s' already exists", + a->file_name, node->line, node->col, field_name); + } + Str type = cstr("\\{ "); + for (sz i = 0; i < array_size(node->field_type->elements); i++) { + Node *field = node->field_type->elements[i]; + typecheck_field(a, field, scope, field_name, map); + type = str_concat(type, field->type, a->storage); + type = str_concat(type, cstr(" "), a->storage); + } + type = str_concat(type, cstr("\\}"), a->storage); + node->type = type; + } else { + Str field_name = str_concat(symbol, cstr("."), a->storage); + field_name = str_concat(field_name, node->value.str, a->storage); + Str field_type = node->field_type->value.str; + if (!find_type(scope, field_type)) { + eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, + node->field_type->line, node->field_type->col, field_type); + } + if (structmap_lookup(&map, field_name)) { + eprintln("%s:%d:%d: error: struct field '%s' already exists", + a->file_name, node->line, node->col, field_name); + } + if (node->field_val) { + Type type = type_inference(a, node->field_val, scope); + if (!str_eq(type, field_type)) { + eprintln( + "%s:%d:%d: error: mismatched types in struct " + "value " + "for '%s': %s expected %s", + a->file_name, node->line, node->col, field_name, type, + field_type); + } + } + structmap_insert(&map, field_name, + (Struct){ + .name = field_name, + .type = field_type, + .val = node->field_val, + }, + a->storage); + node->type = field_type; + } +} + void typecheck_returns(Analyzer *a, Node *node, Str expected) { if (!node) { @@ -534,35 +586,10 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { // TODO: make sure it didn't exist before. StructMap *e = structmap_insert( &scope->structs, symbol, (Struct){.name = symbol}, a->storage); - // for (sz i = 0; i < array_size(node->struct_field); i++) { - // Node *field = node->struct_field[i]; - // // TODO: handle compound types - // Str field_name = field->value.str; - // Str field_type = field->field_type->value.str; - // if (fieldmap_lookup(&e->val.fields, field_name)) { - // eprintln( - // "%s:%d:%d: error: struct field '%s.%s' already exists", - // a->file_name, field->line, field->col, symbol, - // field_name); - // } - // if (field->field_val) { - // Type type = type_inference(a, field->field_val, scope); - // if (!str_eq(type, field_type)) { - // eprintln( - // "%s:%d:%d: error: mismatched types in struct " - // "value " - // "for '%s.%s': %s expected %s", - // a->file_name, field->line, field->col, symbol, - // field_name, type, field_type); - // } - // } - // fieldmap_insert(&e->val.fields, field_name, - // (Field){.name = field_name, - // .type = field_type, - // .val = field->field_val}, - // a->storage); - // field->type = field_type; - // } + for (sz i = 0; i < array_size(node->struct_field); i++) { + Node *field = node->struct_field[i]; + typecheck_field(a, field, scope, symbol, e); + } typemap_insert(&scope->types, symbol, symbol, a->storage); return node->type; } break; @@ -574,12 +601,12 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { (Enum){.name = symbol}, a->storage); for (sz i = 0; i < array_size(node->struct_field); i++) { Node *field = node->struct_field[i]; - Str field_name = field->value.str; - if (fieldmap_lookup(&e->val.fields, field_name)) { - eprintln( - "%s:%d:%d: error: enum field '%s.%s' already exists", - a->file_name, field->line, field->col, symbol, - field_name); + Str field_name = str_concat(symbol, cstr("."), a->storage); + field_name = + str_concat(field_name, field->value.str, a->storage); + if (enummap_lookup(&e, field_name)) { + eprintln("%s:%d:%d: error: enum field '%s' already exists", + a->file_name, field->line, field->col, field_name); } if (field->field_val) { Type type = type_inference(a, field->field_val, scope); @@ -590,11 +617,8 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { field_name); } } - fieldmap_insert(&e->val.fields, field_name, - (Field){.name = field_name, - .type = cstr("int"), - .val = field->field_val}, - a->storage); + enummap_insert(&e, field_name, (Enum){.name = field_name}, + a->storage); field->type = cstr("int"); } typemap_insert(&scope->types, symbol, symbol, a->storage); @@ -825,11 +849,14 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { return cstr(""); } // Check if there is a next and it matches the enum field. - if (!fieldmap_lookup(&e->val.fields, node->next->value.str)) { + Str field = str_concat(type->val, cstr("."), a->storage); + field = str_concat(field, node->next->value.str, a->storage); + if (!find_enum(scope, field)) { eprintln( - "%s:%d:%d: error: unknown enum field for symbol " - "'%s'", - a->file_name, node->line, node->col, symbol); + "%s:%d:%d: error: unknown enum field for " + "'%s': %s", + a->file_name, node->line, node->col, symbol, + node->next->value.str); return cstr(""); } node->next->type = cstr("int"); @@ -1159,7 +1186,7 @@ analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { Str field_name = field->value.str; if (symmap_lookup(&map->val.fields, field_name) != NULL) { eprintln( - "%s:%d:%d: error: enum field '%s.%s' already exists", + "%s:%d:%d: error: struct field '%s.%s' already exists", a->file_name, field->line, field->col, symbol, field_name); return; @@ -1439,26 +1466,59 @@ process_file(Str path) { } #if DEBUG == 1 - for (sz i = 0; i < array_size(analyzer.scopes); i++) { + println("======== enums ========"); + for (sz i = 0; i < array_size(analyzer.types); i++) { Arena scratch = lexer_arena; - Scope *scope = analyzer.scopes[i]; - SymbolMapIter iter = symmap_iterator(scope->symbols, &scratch); - SymbolMap *sym = symmap_next(&iter, &scratch); - while (sym) { - println("%s: SCOPE: %d DEPTH: %d\t%s %s", path, scope->id, - scope->depth, sym_kind_str[sym->val.kind], sym->val.name); - SymbolMapIter field_iter = - symmap_iterator(sym->val.fields, &scratch); - SymbolMap *field = symmap_next(&field_iter, &scratch); - while (field) { - println("%s: SCOPE: %d DEPTH: %d\t%s %s.%s", path, scope->id, - scope->depth, sym_kind_str[field->val.kind], - sym->val.name, field->val.name); - field = symmap_next(&field_iter, &scratch); - } - sym = symmap_next(&iter, &lexer_arena); + TypeScope *scope = analyzer.types[i]; + EnumMapIter iter = enummap_iterator(scope->enums, &scratch); + EnumMap *m = enummap_next(&iter, &scratch); + while (m) { + println("%s: enum: %s", path, m->val.name); + m = enummap_next(&iter, &scratch); } } + println("======== structs ========"); + for (sz i = 0; i < array_size(analyzer.types); i++) { + Arena scratch = lexer_arena; + TypeScope *scope = analyzer.types[i]; + StructMapIter iter = structmap_iterator(scope->structs, &scratch); + StructMap *m = structmap_next(&iter, &scratch); + while (m) { + println("%s: struct: %s", path, m->val.name); + m = structmap_next(&iter, &scratch); + } + } + println("======== functions ========"); + for (sz i = 0; i < array_size(analyzer.types); i++) { + Arena scratch = lexer_arena; + TypeScope *scope = analyzer.types[i]; + FunMapIter iter = funmap_iterator(scope->funcs, &scratch); + FunMap *m = funmap_next(&iter, &scratch); + while (m) { + println("%s: func: %s(%s): (%s)", path, m->val.name, + m->val.param_type, m->val.return_type); + m = funmap_next(&iter, &scratch); + } + } + // println("======== symbols ========"); + // SymbolMapIter iter = symmap_iterator(scope->symbols, &scratch); + // SymbolMap *sym = symmap_next(&iter, &scratch); + // while (sym) { + // println("%s: SCOPE: %d DEPTH: %d\t%s %s", path, scope->id, + // scope->depth, sym_kind_str[sym->val.kind], + // sym->val.name); + // SymbolMapIter field_iter = + // symmap_iterator(sym->val.fields, &scratch); + // SymbolMap *field = symmap_next(&field_iter, &scratch); + // while (field) { + // println("%s: SCOPE: %d DEPTH: %d\t%s %s.%s", path, scope->id, + // scope->depth, sym_kind_str[field->val.kind], + // sym->val.name, field->val.name); + // field = symmap_next(&field_iter, &scratch); + // } + // sym = symmap_next(&iter, &lexer_arena); + // } + // } #endif // TODO: Type checking. -- cgit v1.2.1