summaryrefslogtreecommitdiff
path: root/type_checker.c
diff options
context:
space:
mode:
Diffstat (limited to 'type_checker.c')
-rw-r--r--type_checker.c87
1 files changed, 63 insertions, 24 deletions
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 <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
#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) {