summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-07-18 23:38:59 -0700
committerCarson Fleming <cflems@cflems.net>2026-07-18 23:38:59 -0700
commit1e712cf04567c48100526f9a3a0f796497168268 (patch)
tree28a1676d36620500578d1a386d8d0b976637ce9f
parentfeb1cac139ca5aa2ba76ac6a0a318bced03d8638 (diff)
downloadccc-1e712cf04567c48100526f9a3a0f796497168268.tar.gz
type system surely
-rw-r--r--ast.h7
-rw-r--r--codegen.c34
-rw-r--r--parser.c9
-rw-r--r--scope.c2
-rw-r--r--scope.h6
-rw-r--r--type_checker.c9
6 files changed, 37 insertions, 30 deletions
diff --git a/ast.h b/ast.h
index 71c400c..bc23a1c 100644
--- a/ast.h
+++ b/ast.h
@@ -7,8 +7,7 @@ struct stmt_node;
struct expr_node;
struct type_ref_node {
- unsigned char ptr_level;
- const struct type_def* def_ref;
+ struct type type;
};
struct int_lit_node {
@@ -126,6 +125,8 @@ struct fn_decl_node {
struct args_decl_node* args;
struct group_node body;
struct scope* scope;
+
+ const struct type_def* resolved_return_type;
};
struct return_node {
@@ -189,7 +190,7 @@ struct ast {
const struct type_def* char_type;
const struct type_def* integral_type;
const struct type_def* decimal_type;
- const struct type_def* string_type;
+ const struct type_def* pointer_type;
};
void ast_destroy(struct ast* ast);
diff --git a/codegen.c b/codegen.c
index f9dbc15..955a095 100644
--- a/codegen.c
+++ b/codegen.c
@@ -225,12 +225,6 @@ static void emit_cmp_zero(FILE* outfile, const struct lval_def* lval) {
fprintf(outfile, ", 0\n");
}
-/* TODO: move this utility to the type checker and use resolved_type */
-static unsigned long long get_type_size(const struct type_ref_node* type) {
- if (type->ptr_level > 0) return PTR_SIZE;
- return type->def_ref->sz;
-}
-
static inline struct lval_def make_stack_lval(
FILE* outfile,
const struct type_def* type
@@ -310,7 +304,8 @@ static struct var_def* emit_var_decl(
FILE* outfile,
const struct var_decl_node* node
) {
- struct lval_def var_dst = make_stack_lval(outfile, node->type.def_ref);
+ struct lval_def var_dst =
+ make_stack_lval(outfile, node->def_ref->resolved_type);
fprintf(outfile, "\t; '%s' lives in: ", node->def_ref->name);
emit_storage_loc(outfile, &var_dst.loc, var_dst.type->sz);
@@ -365,7 +360,7 @@ static void emit_call(
struct args_eval_node* arg_eval = node->args;
while (arg_decl != NULL && arg_eval != NULL) {
struct lval_def arg_dst =
- make_stack_lval(outfile, arg_decl->decl->type.def_ref);
+ make_stack_lval(outfile, arg_decl->decl->def_ref->resolved_type);
emit_expr(outfile, arg_eval->expr, &arg_dst);
arg_decl = arg_decl->next;
@@ -384,20 +379,21 @@ static void emit_call(
unsigned char arg_regnum = 0;
arg_decl = node->called_fn_ref->args;
while (arg_decl != NULL) {
- unsigned long long type_sz = get_type_size(&arg_decl->decl->type);
- arg_bp_offset += type_sz;
+ const struct type_def* arg_type =
+ arg_decl->decl->def_ref->resolved_type;
+ arg_bp_offset += arg_type->sz;
struct lval_def arg_dst;
if (arg_regnum < CC_N_REGS)
arg_dst = (struct lval_def) {
- .type = arg_decl->decl->type.def_ref,
+ .type = arg_type,
.loc = (struct storage_location) {
.type = STO_REG,
.reg = CALLING_CONV[arg_regnum++],
},
};
else
- arg_dst = make_stack_lval(outfile, arg_decl->decl->type.def_ref);
+ arg_dst = make_stack_lval(outfile, arg_type);
emit_mov(outfile, &arg_dst, &(struct storage_location) {
.type = STO_STACK,
@@ -408,7 +404,7 @@ static void emit_call(
fprintf(outfile, "\tcall %s\n", node->called_fn_ref->name);
if (dst != NULL) {
- if (get_type_size(&node->called_fn_ref->return_type) == 0)
+ if (node->called_fn_ref->resolved_return_type->sz == 0)
CGEN_PANIC("can't assign the result of a void function");
emit_mov(outfile, dst, &RV_LOC);
@@ -542,10 +538,9 @@ static void emit_expr(
static void emit_return(FILE* outfile, const struct return_node* node) {
if (active_fn == NULL) CGEN_PANIC("must be inside a function to return");
- const struct type_def* return_type = active_fn->return_type.def_ref;
if (node->ret_val != NULL) {
- if (return_type->sz == 0)
+ if (active_fn->resolved_return_type->sz == 0)
CGEN_PANIC(
"returning a value from void function %s", active_fn->name);
@@ -554,9 +549,9 @@ static void emit_return(FILE* outfile, const struct return_node* node) {
node->ret_val,
&(struct lval_def) {
.loc = RV_LOC,
- .type = return_type,
+ .type = active_fn->resolved_return_type,
});
- } else if (return_type > 0) {
+ } else if (active_fn->resolved_return_type > 0) {
CGEN_PANIC(
"non-void function %s should return a value", active_fn->name);
}
@@ -667,6 +662,7 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
active_fn->name);
active_fn = node;
+ /* TODO: we need to account for the base pointer moving in var locs */
fprintf(outfile, "%s:\n", node->name);
fprintf(outfile, "\tpush rbp\n");
fprintf(outfile, "\tmov rbp, rsp\n");
@@ -679,7 +675,7 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
for (; arg_decl != NULL; arg_decl = arg_decl->next) {
struct var_def* arg_def = arg_decl->decl->def_ref;
struct lval_def arg_dst =
- make_stack_lval(outfile, arg_decl->decl->type.def_ref);
+ make_stack_lval(outfile, arg_def->resolved_type);
arg_def->loc = arg_dst.loc;
struct storage_location arg_src;
@@ -693,7 +689,7 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
.type = STO_STACK,
.bp_offset = spilled_bp_ofs,
};
- spilled_bp_ofs -= arg_decl->decl->type.def_ref->sz;
+ spilled_bp_ofs -= arg_def->resolved_type->sz;
}
emit_mov(outfile, &arg_dst, &arg_src);
}
diff --git a/parser.c b/parser.c
index b094780..14bbbf5 100644
--- a/parser.c
+++ b/parser.c
@@ -79,13 +79,15 @@ static void parse_type_ref(struct type_ref_node* p_node) {
PARSER_PANIC("unknown type name: %s", tok.data.ident);
free(tok.data.ident);
- p_node->def_ref = type_def;
+ p_node->type = (struct type) {
+ .raw_type = type_def,
+ .ptr_level = 0,
+ };
peek_or_panic();
- p_node->ptr_level = 0;
while (tok.type == TK_STAR) {
expect(TK_STAR);
- p_node->ptr_level++;
+ p_node->type.ptr_level++;
peek_or_panic();
}
}
@@ -278,6 +280,7 @@ static void parse_var_decl(struct var_decl_node* p_node) {
expect(TK_IDENT);
p_node->def_ref = scope_define_var(scope, (struct var_def) {
+ .type = &p_node->type.type,
.name = tok.data.ident,
.loc.type = STO_UNRESOLVED,
});
diff --git a/scope.c b/scope.c
index 1d15ff2..014c404 100644
--- a/scope.c
+++ b/scope.c
@@ -221,7 +221,7 @@ void scope_install_default_types(struct ast* ast) {
.is_signed = true,
.is_floating = false,
});
- ast->string_type = ast->integral_type; /* TODO: support pointers */
+ ast->pointer_type = ast->integral_type; /* TODO: support pointers */
scope_define_type(ast->root_scope, (struct type_def) {
.key = {
diff --git a/scope.h b/scope.h
index 19561e0..5761f54 100644
--- a/scope.h
+++ b/scope.h
@@ -21,6 +21,11 @@ struct storage_location {
};
};
+struct type {
+ const struct type_def* raw_type;
+ unsigned char ptr_level;
+};
+
struct type_key {
char* name;
unsigned char how_long;
@@ -36,6 +41,7 @@ struct type_def {
};
struct var_def {
+ const struct type* type;
char* name;
struct storage_location loc;
const struct type_def* resolved_type;
diff --git a/type_checker.c b/type_checker.c
index d8534e2..8a07f2a 100644
--- a/type_checker.c
+++ b/type_checker.c
@@ -50,8 +50,9 @@ static void exit_scope(struct scope* child_scope) {
static const struct type_def* resolve_type_ref(struct type_ref_node* node) {
/* TODO: support pointers and such */
- if (node->def_ref == NULL) TYPE_PANIC("use of unresolved type");
- return node->def_ref;
+ if (node->type.raw_type == NULL) TYPE_PANIC("use of unresolved type");
+ if (node->type.ptr_level > 0) return ast_ref->pointer_type;
+ return node->type.raw_type;
}
static const struct type_def* resolve_int_lit(struct int_lit_node* node) {
@@ -67,7 +68,7 @@ static const struct type_def* resolve_char_lit(struct char_lit_node* node) {
}
static const struct type_def* resolve_str_lit(struct str_lit_node* node) {
- return ast_ref->string_type;
+ return ast_ref->pointer_type;
}
static const struct type_def* resolve_var_ref(struct var_ref_node* node) {
@@ -235,7 +236,7 @@ static void type_check_group(struct group_node* node) {
static void type_check_fn_decl(struct fn_decl_node* node) {
enter_scope(node->scope);
- node->return_type.def_ref = resolve_type_ref(&node->return_type);
+ node->resolved_return_type = resolve_type_ref(&node->return_type);
for (struct args_decl_node* arg_decl = node->args;
arg_decl != NULL;