From b48e27f5cc31af65d8bb92d4b81cd03a60c5bcdb Mon Sep 17 00:00:00 2001 From: Carson Fleming Date: Thu, 6 Aug 2026 00:24:49 -0400 Subject: clean up yesterday's hacks + functions in type system --- type_checker.c | 87 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 24 deletions(-) (limited to 'type_checker.c') diff --git a/type_checker.c b/type_checker.c index 00f57d0..f689a46 100644 --- a/type_checker.c +++ b/type_checker.c @@ -2,6 +2,8 @@ #include "scope.h" #include #include +#include +#include #define TYPE_PANIC(format, ...) {\ fprintf(\ @@ -11,22 +13,42 @@ exit(1);\ } -static struct ast* ast_ref; +static const struct ast* ast_ref; static struct scope* scope; +static struct var_def* active_fn; static void type_check_expr(struct expr_node* node); static void type_check_stmt(struct stmt_node* node); static void type_check_group(struct group_node* node); -static const char* get_type_name(const struct type* type) { +static char* get_type_name(const struct type* type) { switch (type->type) { case TP_DATA: - return type->data.data_type->name; + return strdup(type->data.data_type->name); case TP_PTR: - /* TODO: this is a stub */ - return type->pointer.data_type->name; + char* stars = malloc((type->pointer.ptr_level + 1) * sizeof(char)); + memset(stars, '*', type->pointer.ptr_level); + stars[type->pointer.ptr_level] = 0; + char* name = + ccc_sprintf("%s%s", type->pointer.data_type->name, stars); + free(stars); + return name; + case TP_FN: + /* TODO: un-stub :'( */ + return "function"; } - TYPE_PANIC("unhandled type of type case"); + unreachable(); +} + +static bool is_callable(const struct type* type) { + switch (type->type) { + case TP_DATA: + case TP_PTR: + return false; + case TP_FN: + return true; + } + unreachable(); } static void assert_cast_compatible( @@ -116,25 +138,31 @@ static void type_check_expr_list(struct expr_list_node* node) { } static const struct type* resolve_call(struct call_node* node) { + type_check_expr(node->expr); + const struct fn_type* fn_type = &node->expr->resolved_type->fn; + if (!is_callable(node->expr->resolved_type)) + TYPE_PANIC( + "called object '%s' is not a function", + get_type_name(node->expr->resolved_type)); + type_check_expr_list(node->args); - /* TODO: enforce that the function has been type checked prior to this */ - struct arg_decl_node* arg_decl = node->fn_ref->args; + struct type_list* arg_type = fn_type->arg_types; struct expr_list_node* arg_eval = node->args; - while (arg_decl != NULL && arg_eval != NULL) { - const struct type* decl_type = &arg_decl->type; + while (arg_type != NULL && arg_eval != NULL) { + const struct type* decl_type = arg_type->type; const struct type* eval_type = arg_eval->expr->resolved_type; assert_cast_compatible(decl_type, eval_type); - arg_decl = arg_decl->next; + arg_type = arg_type->next; arg_eval = arg_eval->next; } - if (arg_decl != NULL) - TYPE_PANIC("missing arguments to function '%s'", node->fn_ref->name); + if (arg_type != NULL) + TYPE_PANIC("missing arguments to function"); if (arg_eval != NULL) - TYPE_PANIC("too many arguments to function '%s'", node->fn_ref->name); + TYPE_PANIC("too many arguments to function"); - return &node->fn_ref->return_type; + return fn_type->return_type; } static const struct type* resolve_unary(struct unary_node* node) { @@ -201,7 +229,8 @@ static void type_check_expr(struct expr_node* node) { } static void type_check_return(struct return_node* node) { - const struct type* return_type = &node->fn_ref->return_type; + if (active_fn == NULL) TYPE_PANIC("must be inside a function to return"); + const struct type* return_type = active_fn->type->fn.return_type; if (node->ret_val != NULL) { type_check_expr_list(node->ret_val); assert_cast_compatible(return_type, node->ret_val->resolved_type); @@ -209,7 +238,7 @@ static void type_check_return(struct return_node* node) { || return_type->data.data_type != &void_type) TYPE_PANIC( "void function '%s' should not return a value", - node->fn_ref->name); + active_fn->name); } static void type_check_if(struct if_node* node) { @@ -284,16 +313,26 @@ static void type_check_group(struct group_node* node) { /* TODO: type check redefinition arguments against each other */ /* TODO: wire the body to the definition either here or in the parser */ static void type_check_fn_decl(struct fn_decl_node* node) { - enter_scope(node->scope); - - for (struct arg_decl_node* arg_decl = node->args; - arg_decl != NULL; - arg_decl = arg_decl->next) - arg_decl->def_ref->type = &arg_decl->type; + if (!is_callable(&node->type)) + TYPE_PANIC("function definition does not have function type"); + if (active_fn != NULL) + TYPE_PANIC( + "can't define function '%s' inside function '%s'", + node->name, + active_fn->name); + if (!scope_get_var(scope, &active_fn, node->name)) + TYPE_PANIC("scopes are borked, missing symbol: '%s'", node->name); - if (node->body != NULL) type_check_group(node->body); + assert_cast_compatible(active_fn->type, &node->type); + enter_scope(node->scope); + if (node->body != NULL) { + type_check_group(node->body); + active_fn->fn.resolved = true; + } exit_scope(node->scope); + + active_fn = NULL; } static void type_check_root(struct root_node* node) { -- cgit v1.2.3