summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-07-29 23:58:55 -0400
committerCarson Fleming <cflems@cflems.net>2026-07-29 23:58:55 -0400
commit3445947c072a4cd533f5f3a53178f77361859123 (patch)
tree9ba7d330b1091fdad76bbb190579491e022dc3d3
parent29510d33cab6e86b28b12c6246bca58acdab26e2 (diff)
downloadccc-3445947c072a4cd533f5f3a53178f77361859123.tar.gz
improve type system
-rw-r--r--ast.c4
-rw-r--r--ast.h4
-rw-r--r--parser.c21
-rw-r--r--type.c24
-rw-r--r--type.h9
-rw-r--r--type_checker.c67
6 files changed, 65 insertions, 64 deletions
diff --git a/ast.c b/ast.c
index f224e72..22d3181 100644
--- a/ast.c
+++ b/ast.c
@@ -25,8 +25,6 @@ static void expr_list_destroy(struct expr_list_node* node) {
expr_list_destroy(node->next);
free(node->next);
}
-
- if (node->resolved_type != NULL) free(node->resolved_type);
}
static void assign_destroy(struct assign_node* node) {
@@ -136,8 +134,6 @@ static void expr_destroy(struct expr_node* node) {
paren_destroy(&node->inner.paren);
break;
}
-
- if (node->resolved_type != NULL) free(node->resolved_type);
}
static void if_destroy(struct if_node* node) {
diff --git a/ast.h b/ast.h
index a6d0388..e77c779 100644
--- a/ast.h
+++ b/ast.h
@@ -11,7 +11,7 @@ struct expr_list_node {
struct expr_node* expr;
struct expr_list_node* next;
- struct type* resolved_type;
+ const struct type* resolved_type;
};
struct int_lit_node {
@@ -104,7 +104,7 @@ struct expr_node {
struct paren_node paren;
} inner;
- struct type* resolved_type;
+ const struct type* resolved_type;
};
struct group_node {
diff --git a/parser.c b/parser.c
index 40d5bbd..b92ff8b 100644
--- a/parser.c
+++ b/parser.c
@@ -121,13 +121,32 @@ static void parse_literal(struct expr_node* p_node) {
case TK_INT_LIT:
expect(TK_INT_LIT);
p_node->type = EXPR_INT_LIT;
- p_node->inner.int_lit.val = tok.data.int_lit;
+ p_node->inner.int_lit = (struct int_lit_node) {
+ .val = tok.data.int_lit,
+ };
break;
case TK_CHAR_LIT:
expect(TK_CHAR_LIT);
p_node->type = EXPR_CHAR_LIT;
+ p_node->inner.char_lit = (struct char_lit_node) {
+ .val = tok.data.char_lit,
+ };
p_node->inner.char_lit.val = tok.data.char_lit;
break;
+ case TK_FLOAT_LIT:
+ expect(TK_FLOAT_LIT);
+ p_node->type = EXPR_FLOAT_LIT;
+ p_node->inner.float_lit = (struct float_lit_node) {
+ .val = tok.data.float_lit,
+ };
+ break;
+ case TK_STR_LIT:
+ expect(TK_STR_LIT);
+ p_node->type = EXPR_STR_LIT;
+ p_node->inner.str_lit = (struct str_lit_node) {
+ .val = tok.data.str_lit,
+ };
+ break;
default:
PARSER_PANIC("invalid literal type");
}
diff --git a/type.c b/type.c
index c5f6e65..4bff103 100644
--- a/type.c
+++ b/type.c
@@ -42,11 +42,29 @@ const struct data_type double_type = {
.is_floating = true,
};
-const struct data_type* integral_type = &long_type;
-const struct data_type* floating_type = &double_type;
-const struct data_type* character_type = &char_type;
const struct data_type* primitive_types[] = {
&void_type, &char_type, &short_type, &int_type, &long_type, &long_long_type,
&float_type, &double_type,
NULL
};
+
+const struct type integral_type = {
+ .type = TP_DATA,
+ .data.data_type = &long_type,
+ .data.is_signed = true,
+};
+const struct type floating_type = {
+ .type = TP_DATA,
+ .data.data_type = &double_type,
+ .data.is_signed = true,
+};
+const struct type character_type = {
+ .type = TP_DATA,
+ .data.data_type = &char_type,
+ .data.is_signed = true, /* impl defined */
+};
+const struct type string_type = {
+ .type = TP_PTR,
+ .pointer.data_type = &char_type,
+ .pointer.ptr_level = 1,
+};
diff --git a/type.h b/type.h
index 1217b71..ef848c5 100644
--- a/type.h
+++ b/type.h
@@ -34,10 +34,11 @@ extern const struct data_type long_type;
extern const struct data_type long_long_type;
extern const struct data_type float_type;
extern const struct data_type double_type;
-
-extern const struct data_type* integral_type;
-extern const struct data_type* floating_type;
-extern const struct data_type* character_type;
extern const struct data_type* primitive_types[];
+extern const struct type integral_type;
+extern const struct type floating_type;
+extern const struct type character_type;
+extern const struct type string_type;
+
#endif
diff --git a/type_checker.c b/type_checker.c
index 8b4763c..86fe63a 100644
--- a/type_checker.c
+++ b/type_checker.c
@@ -58,41 +58,10 @@ static void exit_scope(struct scope* child_scope) {
scope = child_scope->next_out;
}
-static struct type* allocate_data_type(
- const struct data_type* data_type,
- bool is_unsigned
-) {
- if (is_unsigned && data_type->is_floating)
- TYPE_PANIC("floating type '%s' cannot be unsigned", data_type->name);
-
- struct type* type = ccc_alloc(sizeof(struct type));
- type->type = TP_DATA;
- type->data.data_type = data_type;
- type->data.is_signed = !is_unsigned;
- return type;
-}
-
-static struct type* allocate_pointer_type(
- const struct data_type* data_type,
- integral_t ptr_level
-) {
- struct type* type = ccc_alloc(sizeof(struct type));
- type->type = TP_PTR;
- type->pointer.data_type = data_type;
- type->pointer.ptr_level = ptr_level;
- return type;
-}
-
-static struct type* copy_type(const struct type* source_type) {
- struct type* type = ccc_alloc(sizeof(struct type));
- *type = *source_type;
- return type;
-}
-
-static struct type* resolve_var_ref(struct var_ref_node* node) {
+static const struct type* resolve_var_ref(struct var_ref_node* node) {
if (node->def_ref->type == NULL)
TYPE_PANIC("variable '%s' has undefined type.", node->def_ref->name);
- return copy_type(node->def_ref->type);
+ return node->def_ref->type;
}
static void type_check_decl(
@@ -112,7 +81,7 @@ static void type_check_decl_list(struct decl_list_node* node) {
type_check_decl(&node->type, cur);
}
-static struct type* resolve_assign(struct assign_node* node) {
+static const struct type* resolve_assign(struct assign_node* node) {
switch (node->lval->type) {
case EXPR_VAR_REF:
break;
@@ -126,19 +95,17 @@ static struct type* resolve_assign(struct assign_node* node) {
const struct type* rval_type = node->rval->resolved_type;
assert_cast_compatible(lval_type, rval_type);
- return copy_type(lval_type);
+ return lval_type;
}
static void type_check_expr_list(struct expr_list_node* node) {
- const struct type* last_item_type;
for (; node != NULL; node = node->next) {
type_check_expr(node->expr);
- last_item_type = node->expr->resolved_type;
+ node->resolved_type = node->expr->resolved_type;
}
- node->resolved_type = copy_type(last_item_type);
}
-static struct type* resolve_call(struct call_node* node) {
+static const struct type* resolve_call(struct call_node* node) {
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;
@@ -157,41 +124,41 @@ static struct type* resolve_call(struct call_node* node) {
if (arg_eval != NULL)
TYPE_PANIC("too many arguments to function '%s'", node->fn_ref->name);
- return copy_type(&node->fn_ref->return_type);
+ return &node->fn_ref->return_type;
}
-static struct type* resolve_unary(struct unary_node* node) {
+static const struct type* resolve_unary(struct unary_node* node) {
type_check_expr(node->expr);
/* TODO: delegate by individual operation to prohibit shit like -"yes" */
- return copy_type(node->expr->resolved_type);
+ return node->expr->resolved_type;
}
-static struct type* resolve_binary(struct binary_node* node) {
+static const struct type* resolve_binary(struct binary_node* node) {
/* TODO: math rules and such lol */
type_check_expr(node->lhs);
type_check_expr(node->rhs);
assert_cast_compatible(node->lhs->resolved_type, node->rhs->resolved_type);
- return copy_type(node->lhs->resolved_type);
+ return node->lhs->resolved_type;
}
-static struct type* resolve_paren(struct paren_node* node) {
+static const struct type* resolve_paren(struct paren_node* node) {
type_check_expr_list(node->expr_list);
- return copy_type(node->expr_list->resolved_type);
+ return node->expr_list->resolved_type;
}
static void type_check_expr(struct expr_node* node) {
switch (node->type) {
case EXPR_INT_LIT:
- node->resolved_type = allocate_data_type(integral_type, false);
+ node->resolved_type = &integral_type;
break;
case EXPR_FLOAT_LIT:
- node->resolved_type = allocate_data_type(floating_type, false);
+ node->resolved_type = &floating_type;
break;
case EXPR_CHAR_LIT:
- node->resolved_type = allocate_data_type(character_type, false);
+ node->resolved_type = &character_type;
break;
case EXPR_STR_LIT:
- node->resolved_type = allocate_pointer_type(character_type, 1);
+ node->resolved_type = &string_type;
break;
case EXPR_VAR_REF:
node->resolved_type = resolve_var_ref(&node->inner.var_ref);