From 3b9cfd8b515d5b2969e242ea730792ae26f5fbfe Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 26 Jun 2024 17:36:21 +0200 Subject: Add enum de-structuring and int matching on match expr --- src/main.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 11 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index 5c99a10..8026d0d 100644 --- a/src/main.c +++ b/src/main.c @@ -8,8 +8,8 @@ #include "vm.c" // TODO: unions -// TODO: match deconstruct enums // TODO: arrays and pointers +// TODO: embed (binary file) and include (source file) typedef enum ExecMode { RUN_NORMAL, @@ -600,7 +600,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { &scope->symbols, field_name, (Symbol){.name = field_name, .kind = SYM_ENUM_FIELD}, a->storage); - field->type = cstr("int"); + field->type = symbol; } symmap_insert(&scope->symbols, symbol, (Symbol){.name = symbol, .kind = SYM_ENUM}, @@ -652,11 +652,57 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { node->type = cstr("nil"); return node->type; } break; - case NODE_COND: + case NODE_COND: { + Str previous = cstr(""); + for (sz i = 0; i < array_size(node->match_cases); i++) { + Node *expr = node->match_cases[i]; + Str next = type_inference(a, expr, scope); + if (i != 0 && !str_eq(next, previous)) { + emit_semantic_error( + a, node, + cstr("non-matching types for cond expressions")); + return cstr(""); + } + previous = next; + } + node->type = previous; + return node->type; + } break; case NODE_MATCH: { - // TODO: proper typecheck matchcase expressions here... - if (node->match_expr) { - type_inference(a, node->match_expr, scope); + Str e = type_inference(a, node->match_expr, scope); + if (str_eq(e, cstr("int"))) { + // Integer matching. + for (sz i = 0; i < array_size(node->match_cases); i++) { + Node *field = node->match_cases[i]; + if (field->case_value) { + if (field->case_value->kind != NODE_NUM_INT && + field->case_value->kind != NODE_NUM_UINT) { + emit_semantic_error( + a, field->case_value, + cstr( + "non-integer or enum types on match case")); + } + } + } + } else { + // Get enum type and de-structure the match. + FindEnumResult res = find_enum(scope, e); + Str enum_prefix = + str_concat(res.map->val.name, cstr("."), a->storage); + for (sz i = 0; i < array_size(node->match_cases); i++) { + Node *field = node->match_cases[i]; + if (field->case_value) { + Str field_name = str_concat( + enum_prefix, field->case_value->value.str, + a->storage); + if (!enummap_lookup(&res.scope->enums, field_name)) { + eprintln("%s:%d:%d: error: unknown enum field '%s'", + a->file_name, field->case_value->line, + field->case_value->col, field_name); + a->err = true; + } + } + } } Str previous = cstr(""); for (sz i = 0; i < array_size(node->match_cases); i++) { @@ -665,7 +711,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { if (i != 0 && !str_eq(next, previous)) { emit_semantic_error( a, node, - cstr("non-matching types for case expressions")); + cstr("non-matching types for match expressions")); return cstr(""); } previous = next; @@ -674,9 +720,6 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { return node->type; } break; case NODE_CASE_MATCH: { - if (node->case_value) { - type_inference(a, node->case_value, scope); - } if (node->case_expr->kind != NODE_BLOCK) { scope = typescope_alloc(a, scope); } @@ -846,7 +889,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { a->err = true; return cstr(""); } - node->next->type = cstr("int"); + node->next->type = type->val.name; node->type = type->val.name; return node->next->type; } -- cgit v1.2.1