summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-07-29 23:35:15 -0400
committerCarson Fleming <cflems@cflems.net>2026-07-29 23:35:15 -0400
commit29510d33cab6e86b28b12c6246bca58acdab26e2 (patch)
tree8513245e730aa68fb119e88932ab658fea1dc169
parent4f9d0247549b06ddb25b76bb425541190105cb48 (diff)
downloadccc-29510d33cab6e86b28b12c6246bca58acdab26e2.tar.gz
support for comma-separated expression lists where valid
-rw-r--r--ast.c69
-rw-r--r--ast.h59
-rw-r--r--codegen.c100
-rw-r--r--parser.c104
-rw-r--r--type_checker.c91
5 files changed, 257 insertions, 166 deletions
diff --git a/ast.c b/ast.c
index df3b7f6..f224e72 100644
--- a/ast.c
+++ b/ast.c
@@ -5,11 +5,28 @@
static void expr_destroy(struct expr_node* node);
static void stmt_destroy(struct stmt_node* node);
-static void var_decl_destroy(struct var_decl_node* node) {
+static void decl_destroy(struct decl_node* node) {
if (node->initial_value != NULL) {
expr_destroy(node->initial_value);
free(node->initial_value);
}
+
+ if (node->next != NULL) {
+ decl_destroy(node->next);
+ free(node->next);
+ }
+}
+
+static void expr_list_destroy(struct expr_list_node* node) {
+ expr_destroy(node->expr);
+ free(node->expr);
+
+ if (node->next != NULL) {
+ 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) {
@@ -33,18 +50,20 @@ static void group_destroy(struct group_node* node) {
}
static void decl_list_destroy(struct decl_list_node* node) {
- var_decl_destroy(node->decl);
- free(node->decl);
+ decl_destroy(node->head);
+ free(node->head);
+}
+static void fn_arg_destroy(struct arg_decl_node* node) {
if (node->next != NULL) {
- decl_list_destroy(node->next);
+ fn_arg_destroy(node->next);
free(node->next);
}
}
static void fn_decl_destroy(struct fn_decl_node* node) {
if (node->args != NULL) {
- decl_list_destroy(node->args);
+ fn_arg_destroy(node->args);
free(node->args);
}
@@ -56,7 +75,7 @@ static void fn_decl_destroy(struct fn_decl_node* node) {
static void return_destroy(struct return_node* node) {
if (node->ret_val != NULL) {
- expr_destroy(node->ret_val);
+ expr_list_destroy(node->ret_val);
free(node->ret_val);
}
}
@@ -65,16 +84,6 @@ static void str_lit_destroy(struct str_lit_node* node) {
free(node->val);
}
-static void expr_list_destroy(struct expr_list_node* node) {
- expr_destroy(node->expr);
- free(node->expr);
-
- if (node->next != NULL) {
- expr_list_destroy(node->next);
- free(node->next);
- }
-}
-
static void call_destroy(struct call_node* node) {
if (node->args != NULL) {
expr_list_destroy(node->args);
@@ -95,6 +104,11 @@ static void binary_destroy(struct binary_node* node) {
free(node->rhs);
}
+static void paren_destroy(struct paren_node* node) {
+ expr_list_destroy(node->expr_list);
+ free(node->expr_list);
+}
+
static void expr_destroy(struct expr_node* node) {
switch (node->type) {
case EXPR_INT_LIT:
@@ -118,13 +132,16 @@ static void expr_destroy(struct expr_node* node) {
case EXPR_BINARY:
binary_destroy(&node->inner.binary);
break;
+ case EXPR_PAREN:
+ paren_destroy(&node->inner.paren);
+ break;
}
if (node->resolved_type != NULL) free(node->resolved_type);
}
static void if_destroy(struct if_node* node) {
- expr_destroy(node->cond);
+ expr_list_destroy(node->cond);
free(node->cond);
stmt_destroy(node->true_branch);
@@ -145,9 +162,9 @@ static void loop_init_destroy(struct loop_init_node* node) {
expr_list_destroy(node->expr_list);
free(node->expr_list);
break;
- case INIT_DECL:
- var_decl_destroy(node->decl);
- free(node->decl);
+ case INIT_DECL_LIST:
+ decl_list_destroy(node->decl_list);
+ free(node->decl_list);
break;
}
}
@@ -158,11 +175,11 @@ static void loop_destroy(struct loop_node* node) {
free(node->init);
}
if (node->cond != NULL) {
- expr_destroy(node->cond);
+ expr_list_destroy(node->cond);
free(node->cond);
}
if (node->incr != NULL) {
- expr_destroy(node->incr);
+ expr_list_destroy(node->incr);
free(node->incr);
}
@@ -177,11 +194,11 @@ static void stmt_destroy(struct stmt_node* node) {
switch (node->type) {
case STMT_EMPTY:
break;
- case STMT_EXPR:
- expr_destroy(&node->inner.expr);
+ case STMT_EXPR_LIST:
+ expr_list_destroy(&node->inner.expr_list);
break;
- case STMT_VAR_DECL:
- var_decl_destroy(&node->inner.var_decl);
+ case STMT_DECL_LIST:
+ decl_list_destroy(&node->inner.decl_list);
break;
case STMT_RETURN:
return_destroy(&node->inner.return_);
diff --git a/ast.h b/ast.h
index 18c0fd3..a6d0388 100644
--- a/ast.h
+++ b/ast.h
@@ -7,6 +7,13 @@
struct stmt_node;
struct expr_node;
+struct expr_list_node {
+ struct expr_node* expr;
+ struct expr_list_node* next;
+
+ struct type* resolved_type;
+};
+
struct int_lit_node {
integral_t val;
};
@@ -27,10 +34,15 @@ struct var_ref_node {
struct var_def* def_ref;
};
-struct var_decl_node {
- struct type type;
+struct decl_node {
struct var_def* def_ref;
struct expr_node* initial_value;
+ struct decl_node* next;
+};
+
+struct decl_list_node {
+ struct type type;
+ struct decl_node* head;
};
struct assign_node {
@@ -38,14 +50,9 @@ struct assign_node {
struct expr_node* rval;
};
-struct expr_list_node {
- struct expr_node* expr;
- struct expr_list_node* next;
-};
-
struct call_node {
/* TODO: function pointers */
- struct fn_decl_node* called_fn_ref; /* borrowed */
+ struct fn_decl_node* fn_ref; /* borrowed */
struct expr_list_node* args;
};
@@ -67,6 +74,10 @@ struct binary_node {
struct expr_node* rhs;
};
+struct paren_node {
+ struct expr_list_node* expr_list;
+};
+
struct expr_node {
enum {
EXPR_INT_LIT,
@@ -78,6 +89,7 @@ struct expr_node {
EXPR_CALL,
EXPR_UNARY,
EXPR_BINARY,
+ EXPR_PAREN,
} type;
union {
struct int_lit_node int_lit;
@@ -89,6 +101,7 @@ struct expr_node {
struct call_node call;
struct unary_node unary;
struct binary_node binary;
+ struct paren_node paren;
} inner;
struct type* resolved_type;
@@ -99,25 +112,27 @@ struct group_node {
struct scope* scope;
};
-struct decl_list_node {
- struct var_decl_node* decl;
- struct decl_list_node* next;
+struct arg_decl_node {
+ struct type type;
+ struct var_def* def_ref;
+ struct arg_decl_node* next;
};
struct fn_decl_node {
struct type return_type;
const char* name;
- struct decl_list_node* args;
+ struct arg_decl_node* args;
struct group_node body;
struct scope* scope;
};
struct return_node {
- struct expr_node* ret_val; /* null to return void */
+ struct fn_decl_node* fn_ref;
+ struct expr_list_node* ret_val; /* null to return void */
};
struct if_node {
- struct expr_node* cond;
+ struct expr_list_node* cond;
struct stmt_node* true_branch;
struct stmt_node* false_branch;
struct scope* scope;
@@ -126,18 +141,18 @@ struct if_node {
struct loop_init_node {
enum {
INIT_EXPR_LIST,
- INIT_DECL,
+ INIT_DECL_LIST,
} type;
union {
struct expr_list_node* expr_list;
- struct var_decl_node* decl;
+ struct decl_list_node* decl_list;
};
};
struct loop_node {
struct loop_init_node* init; /* null if absent */
- struct expr_node* cond; /* null if absent */
- struct expr_node* incr; /* null if absent */
+ struct expr_list_node* cond; /* null if absent */
+ struct expr_list_node* incr; /* null if absent */
struct stmt_node* body;
struct scope* scope;
};
@@ -145,16 +160,16 @@ struct loop_node {
struct stmt_node {
enum {
STMT_EMPTY,
- STMT_EXPR,
- STMT_VAR_DECL,
+ STMT_EXPR_LIST,
+ STMT_DECL_LIST,
STMT_RETURN,
STMT_GROUP,
STMT_IF,
STMT_LOOP,
} type;
union {
- struct expr_node expr;
- struct var_decl_node var_decl;
+ struct expr_list_node expr_list;
+ struct decl_list_node decl_list;
struct return_node return_;
struct group_node group;
struct if_node if_;
diff --git a/codegen.c b/codegen.c
index d274fb7..6d55d2c 100644
--- a/codegen.c
+++ b/codegen.c
@@ -311,9 +311,9 @@ static void emit_var_ref(
static void emit_stmt(FILE* outfile, const struct stmt_node* node);
-static void emit_var_decl(
+static void emit_decl(
FILE* outfile,
- const struct var_decl_node* node
+ const struct decl_node* node
) {
struct lval_def var_dst =
allocate_stack(outfile, node->def_ref->type);
@@ -328,6 +328,16 @@ static void emit_var_decl(
emit_expr(outfile, node->initial_value, &var_dst);
}
+static void emit_decl_list(
+ FILE* outfile,
+ const struct decl_list_node* node
+) {
+ for (const struct decl_node* cur = node->head;
+ cur != NULL;
+ cur = cur->next)
+ emit_decl(outfile, cur);
+}
+
static void emit_assignment(
FILE* outfile,
const struct assign_node* node,
@@ -357,31 +367,21 @@ static void emit_call(
integral_t orig_bp_offset = scope->bp_offset;
integral_t arg_bp_offset = orig_bp_offset;
- struct decl_list_node* arg_decl = node->called_fn_ref->args;
+ struct arg_decl_node* arg_decl = node->fn_ref->args;
struct expr_list_node* arg_eval = node->args;
while (arg_decl != NULL && arg_eval != NULL) {
struct lval_def arg_dst =
- allocate_stack(outfile, arg_decl->decl->def_ref->type);
+ allocate_stack(outfile, arg_decl->def_ref->type);
emit_expr(outfile, arg_eval->expr, &arg_dst);
arg_decl = arg_decl->next;
arg_eval = arg_eval->next;
}
- if (arg_decl != NULL)
- CGEN_PANIC(
- "too many arguments to function %s",
- node->called_fn_ref->name);
- if (arg_eval != NULL)
- CGEN_PANIC(
- "missing arguments to function %s",
- node->called_fn_ref->name);
-
unsigned char arg_regnum = 0;
- arg_decl = node->called_fn_ref->args;
+ arg_decl = node->fn_ref->args;
while (arg_decl != NULL) {
- const struct type* arg_type =
- arg_decl->decl->def_ref->type;
+ const struct type* arg_type = arg_decl->def_ref->type;
arg_bp_offset += get_effective_data_type(arg_type)->sz;
struct lval_def arg_dst;
@@ -405,10 +405,10 @@ static void emit_call(
arg_decl = arg_decl->next;
}
- fprintf(outfile, "\tcall %s\n", node->called_fn_ref->name);
+ fprintf(outfile, "\tcall %s\n", node->fn_ref->name);
if (dst != NULL) {
if (get_effective_data_type(
- &node->called_fn_ref->return_type) == &void_type)
+ &node->fn_ref->return_type) == &void_type)
CGEN_PANIC("can't assign the result of a void function");
emit_mov(outfile, dst, &RV_LOC);
@@ -506,6 +506,23 @@ static void emit_binary(
deallocate_temporary(outfile, &rhs_dst);
}
+static void emit_expr_list(
+ FILE* outfile,
+ const struct expr_list_node* node,
+ const struct lval_def* dst
+) {
+ for (; node != NULL; node = node->next)
+ emit_expr(outfile, node->expr, node->next == NULL ? dst : NULL);
+}
+
+static void emit_paren(
+ FILE* outfile,
+ const struct paren_node* node,
+ const struct lval_def* dst
+) {
+ emit_expr_list(outfile, node->expr_list, dst);
+}
+
static void emit_expr(
FILE* outfile,
const struct expr_node* node,
@@ -539,30 +556,22 @@ static void emit_expr(
case EXPR_BINARY:
emit_binary(outfile, &node->inner.binary, dst);
break;
+ case EXPR_PAREN:
+ emit_paren(outfile, &node->inner.paren, dst);
+ break;
}
}
static void emit_return(FILE* outfile, const struct return_node* node) {
if (active_fn == NULL) CGEN_PANIC("must be inside a function to return");
- bool is_void_fn =
- get_effective_data_type(&active_fn->return_type) == &void_type;
-
- if (node->ret_val != NULL) {
- if (is_void_fn)
- CGEN_PANIC(
- "returning a value from void function %s", active_fn->name);
-
- emit_expr(
+ if (node->ret_val != NULL)
+ emit_expr_list(
outfile,
node->ret_val,
&(struct lval_def) {
.loc = RV_LOC,
.type = &active_fn->return_type,
});
- } else if (!is_void_fn) {
- CGEN_PANIC(
- "non-void function %s should return a value", active_fn->name);
- }
fprintf(outfile, "\tjmp " RETURN_LABEL_FMT "\n", active_fn->name);
}
@@ -590,7 +599,7 @@ static void emit_if(FILE* outfile, const struct if_node* node) {
struct lval_def cond_result =
allocate_temporary(outfile, node->cond->resolved_type);
- emit_expr(outfile, node->cond, &cond_result);
+ emit_expr_list(outfile, node->cond, &cond_result);
emit_cmp_zero(outfile, &cond_result);
integral_t branch_num = ++branch_counter;
@@ -609,18 +618,13 @@ static void emit_if(FILE* outfile, const struct if_node* node) {
exit_scope(node->scope, true);
}
-static void emit_expr_list(FILE* outfile, const struct expr_list_node* node) {
- for (; node != NULL; node = node->next)
- emit_expr(outfile, node->expr, NULL);
-}
-
static void emit_loop_init(FILE* outfile, const struct loop_init_node* node) {
switch (node->type) {
case INIT_EXPR_LIST:
- emit_expr_list(outfile, node->expr_list);
+ emit_expr_list(outfile, node->expr_list, NULL);
break;
- case INIT_DECL:
- emit_var_decl(outfile, node->decl);
+ case INIT_DECL_LIST:
+ emit_decl_list(outfile, node->decl_list);
break;
}
}
@@ -635,7 +639,7 @@ static void emit_loop(FILE* outfile, const struct loop_node* node) {
struct lval_def cond_dst =
allocate_temporary(outfile, node->cond->resolved_type);
fprintf(outfile, "loop_head@%lld:\n", loop_num);
- emit_expr(outfile, node->cond, &cond_dst);
+ emit_expr_list(outfile, node->cond, &cond_dst);
emit_cmp_zero(outfile, &cond_dst);
fprintf(outfile, "\tjz loop_done@%lld\n", loop_num);
} else {
@@ -643,7 +647,7 @@ static void emit_loop(FILE* outfile, const struct loop_node* node) {
}
emit_stmt(outfile, node->body);
- if (node->incr != NULL) emit_expr(outfile, node->incr, NULL);
+ if (node->incr != NULL) emit_expr_list(outfile, node->incr, NULL);
fprintf(outfile, "\tjmp loop_head@%lld\n", loop_num);
fprintf(outfile, "loop_done@%lld:\n", loop_num);
@@ -655,14 +659,14 @@ static void emit_stmt(FILE* outfile, const struct stmt_node* node) {
switch (node->type) {
case STMT_EMPTY:
break;
- case STMT_VAR_DECL:
- emit_var_decl(outfile, &node->inner.var_decl);
+ case STMT_DECL_LIST:
+ emit_decl_list(outfile, &node->inner.decl_list);
break;
case STMT_RETURN:
emit_return(outfile, &node->inner.return_);
break;
- case STMT_EXPR:
- emit_expr(outfile, &node->inner.expr, NULL);
+ case STMT_EXPR_LIST:
+ emit_expr_list(outfile, &node->inner.expr_list, NULL);
break;
case STMT_GROUP:
emit_group(outfile, &node->inner.group);
@@ -695,9 +699,9 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
long long spilled_bp_ofs = -16; // return address + old bp
unsigned char arg_regnum = 0;
- struct decl_list_node* arg_decl = node->args;
+ struct arg_decl_node* arg_decl = node->args;
for (; arg_decl != NULL; arg_decl = arg_decl->next) {
- struct var_def* arg_def = arg_decl->decl->def_ref;
+ struct var_def* arg_def = arg_decl->def_ref;
struct lval_def arg_dst =
allocate_stack(outfile, arg_def->type);
arg_def->loc = arg_dst.loc;
diff --git a/parser.c b/parser.c
index c2eadbe..40d5bbd 100644
--- a/parser.c
+++ b/parser.c
@@ -178,7 +178,7 @@ static void parse_expr_call(struct expr_node* p_node) {
if (var_def->loc.type != STO_FN)
PARSER_PANIC("called object is not a function");
- p_node->inner.call.called_fn_ref = var_def->loc.decl;
+ p_node->inner.call.fn_ref = var_def->loc.decl;
break;
default:
PARSER_PANIC("expression is not callable");
@@ -250,13 +250,19 @@ static void parse_expr_binary(struct expr_node* p_node) {
parse_expr(rhs);
}
+static void parse_paren(struct paren_node* p_node) {
+ expect(TK_LPAREN);
+ p_node->expr_list = ccc_alloc(sizeof(struct expr_list_node));
+ parse_expr_list(p_node->expr_list);
+ expect(TK_RPAREN);
+}
+
static void parse_expr(struct expr_node* p_node) {
peek_or_panic();
switch (tok.type) {
case TK_LPAREN:
- expect(TK_LPAREN);
- parse_expr(p_node);
- expect(TK_RPAREN);
+ p_node->type = EXPR_PAREN;
+ parse_paren(&p_node->inner.paren);
break;
case TK_NEG:
p_node->type = EXPR_UNARY;
@@ -294,23 +300,38 @@ static void parse_expr(struct expr_node* p_node) {
}
}
-static void parse_var_decl(struct var_decl_node* p_node) {
- parse_type_ref(&p_node->type);
+static void parse_decl(const struct type* type, struct decl_node* p_node) {
expect(TK_IDENT);
-
p_node->def_ref = scope_define_var(scope, (struct var_def) {
- .type = &p_node->type,
+ .type = type,
.name = tok.data.ident,
.loc.type = STO_UNRESOLVED,
});
if (p_node->def_ref == NULL)
- PARSER_PANIC("redefinition of '%s'", tok.data.ident);
+ PARSER_PANIC("redefinition of '%s' in same scope", tok.data.ident);
peek_or_panic();
if (tok.type == TK_ASSIGN) {
expect(TK_ASSIGN);
p_node->initial_value = ccc_alloc(sizeof(struct expr_node));
parse_expr(p_node->initial_value);
+ peek_or_panic();
+ }
+
+ if (tok.type == TK_COMMA) {
+ expect(TK_COMMA);
+ p_node->next = ccc_alloc(sizeof(struct decl_node));
+ parse_decl(type, p_node->next);
+ }
+}
+
+static void parse_decl_list(struct decl_list_node* p_node) {
+ parse_type_ref(&p_node->type);
+
+ peek_or_panic();
+ if (tok.type == TK_IDENT) {
+ p_node->head = ccc_alloc(sizeof(struct decl_node));
+ parse_decl(&p_node->type, p_node->head);
}
}
@@ -325,8 +346,8 @@ static void parse_return(struct return_node* p_node) {
return;
}
- p_node->ret_val = ccc_alloc(sizeof(struct expr_node));
- parse_expr(p_node->ret_val);
+ p_node->ret_val = ccc_alloc(sizeof(struct expr_list_node));
+ parse_expr_list(p_node->ret_val);
}
static void parse_group(struct group_node* p_node) {
@@ -357,8 +378,8 @@ static void parse_if(struct if_node* p_node) {
p_node->scope = scope;
expect(TK_LPAREN);
- p_node->cond = ccc_alloc(sizeof(struct expr_node));
- parse_expr(p_node->cond);
+ p_node->cond = ccc_alloc(sizeof(struct expr_list_node));
+ parse_expr_list(p_node->cond);
expect(TK_RPAREN);
p_node->true_branch = ccc_alloc(sizeof(struct stmt_node));
@@ -382,8 +403,8 @@ static void parse_while(struct loop_node* p_node) {
p_node->scope = scope;
expect(TK_LPAREN);
- p_node->cond = ccc_alloc(sizeof(struct expr_node));
- parse_expr(p_node->cond);
+ p_node->cond = ccc_alloc(sizeof(struct expr_list_node));
+ parse_expr_list(p_node->cond);
expect(TK_RPAREN);
p_node->body = ccc_alloc(sizeof(struct stmt_node));
@@ -406,14 +427,14 @@ static bool is_type_token() {
static void parse_loop_init(struct loop_init_node* p_node) {
peek_or_panic();
- if (!is_type_token()) {
+ if (is_type_token()) {
+ p_node->type = INIT_DECL_LIST;
+ p_node->decl_list = ccc_alloc(sizeof(struct decl_list_node));
+ parse_decl_list(p_node->decl_list);
+ } else {
p_node->type = INIT_EXPR_LIST;
p_node->expr_list = ccc_alloc(sizeof(struct expr_list_node));
parse_expr_list(p_node->expr_list);
- } else {
- p_node->type = INIT_DECL;
- p_node->decl = ccc_alloc(sizeof(struct var_decl_node));
- parse_var_decl(p_node->decl);
}
}
@@ -432,14 +453,14 @@ static void parse_for(struct loop_node* p_node) {
expect(TK_SEMI);
peek_or_panic();
if (tok.type != TK_SEMI) {
- p_node->cond = ccc_alloc(sizeof(struct expr_node));
- parse_expr(p_node->cond);
+ p_node->cond = ccc_alloc(sizeof(struct expr_list_node));
+ parse_expr_list(p_node->cond);
}
expect(TK_SEMI);
peek_or_panic();
if (tok.type != TK_RPAREN) {
- p_node->incr = ccc_alloc(sizeof(struct expr_node));
- parse_expr(p_node->incr);
+ p_node->incr = ccc_alloc(sizeof(struct expr_list_node));
+ parse_expr_list(p_node->incr);
}
expect(TK_RPAREN);
@@ -477,29 +498,36 @@ static void parse_stmt(struct stmt_node* p_node) {
parse_return(&p_node->inner.return_);
break;
} else if (is_type_token()) {
- p_node->type = STMT_VAR_DECL;
- parse_var_decl(&p_node->inner.var_decl);
+ p_node->type = STMT_DECL_LIST;
+ parse_decl_list(&p_node->inner.decl_list);
break;
}
default:
- p_node->type = STMT_EXPR;
- parse_expr(&p_node->inner.expr);
+ p_node->type = STMT_EXPR_LIST;
+ parse_expr_list(&p_node->inner.expr_list);
}
expect(TK_SEMI);
}
-static void parse_decl_list(struct decl_list_node* p_node) {
- for (;;) {
- p_node->decl = ccc_alloc(sizeof(struct var_decl_node));
- parse_var_decl(p_node->decl);
+static void parse_fn_arg(struct arg_decl_node* p_node) {
+ parse_type_ref(&p_node->type);
- peek_or_panic();
- if (tok.type != TK_COMMA) break;
+ expect(TK_IDENT);
+ p_node->def_ref = scope_define_var(scope, (struct var_def) {
+ .type = &p_node->type,
+ .name = tok.data.ident,
+ .loc.type = STO_UNRESOLVED,
+ });
+ if (p_node->def_ref == NULL)
+ PARSER_PANIC("redefinition of parameter '%s'", tok.data.ident);
+
+ peek_or_panic();
+ if (tok.type == TK_COMMA) {
expect(TK_COMMA);
- p_node->next = ccc_alloc(sizeof(struct decl_list_node));
- p_node = p_node->next;
+ p_node->next = ccc_alloc(sizeof(struct arg_decl_node));
+ parse_fn_arg(p_node->next);
}
}
@@ -529,8 +557,8 @@ static void parse_fn_decl(struct fn_decl_node* p_node) {
peek_or_panic();
if (tok.type != TK_RPAREN) {
- p_node->args = ccc_alloc(sizeof(struct decl_list_node));
- parse_decl_list(p_node->args);
+ p_node->args = ccc_alloc(sizeof(struct arg_decl_node));
+ parse_fn_arg(p_node->args);
}
expect(TK_RPAREN);
diff --git a/type_checker.c b/type_checker.c
index ccd816f..8b4763c 100644
--- a/type_checker.c
+++ b/type_checker.c
@@ -95,14 +95,23 @@ static struct type* resolve_var_ref(struct var_ref_node* node) {
return copy_type(node->def_ref->type);
}
-static void type_check_var_decl(struct var_decl_node* node) {
- node->def_ref->type = &node->type;
+static void type_check_decl(
+ const struct type* decl_type,
+ struct decl_node* node
+) {
+ node->def_ref->type = decl_type;
+
if (node->initial_value != NULL) {
type_check_expr(node->initial_value);
- assert_cast_compatible(&node->type, node->initial_value->resolved_type);
+ assert_cast_compatible(decl_type, node->initial_value->resolved_type);
}
}
+static void type_check_decl_list(struct decl_list_node* node) {
+ for (struct decl_node* cur = node->head; cur != NULL; cur = cur->next)
+ type_check_decl(&node->type, cur);
+}
+
static struct type* resolve_assign(struct assign_node* node) {
switch (node->lval->type) {
case EXPR_VAR_REF:
@@ -120,29 +129,35 @@ static struct type* resolve_assign(struct assign_node* node) {
return copy_type(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 = copy_type(last_item_type);
+}
+
static struct type* resolve_call(struct call_node* node) {
- struct decl_list_node* arg_decl = node->called_fn_ref->args;
+ 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 expr_list_node* arg_eval = node->args;
while (arg_decl != NULL && arg_eval != NULL) {
- if (arg_decl->decl->initial_value != NULL)
- TYPE_PANIC("C does not support default arguments");
-
- type_check_var_decl(arg_decl->decl);
- const struct type* decl_type =
- arg_decl->decl->def_ref->type;
- type_check_expr(arg_eval->expr);
+ const struct type* decl_type = &arg_decl->type;
const struct type* eval_type = arg_eval->expr->resolved_type;
assert_cast_compatible(decl_type, eval_type);
arg_decl = arg_decl->next;
arg_eval = arg_eval->next;
}
- if (arg_decl != NULL || arg_eval != NULL)
- TYPE_PANIC(
- "mismatched argument count in call to '%s'",
- node->called_fn_ref->name);
- return copy_type(&node->called_fn_ref->return_type);
+ if (arg_decl != NULL)
+ TYPE_PANIC("missing arguments to function '%s'", node->fn_ref->name);
+ if (arg_eval != NULL)
+ TYPE_PANIC("too many arguments to function '%s'", node->fn_ref->name);
+
+ return copy_type(&node->fn_ref->return_type);
}
static struct type* resolve_unary(struct unary_node* node) {
@@ -159,6 +174,11 @@ static struct type* resolve_binary(struct binary_node* node) {
return copy_type(node->lhs->resolved_type);
}
+static struct type* resolve_paren(struct paren_node* node) {
+ type_check_expr_list(node->expr_list);
+ return copy_type(node->expr_list->resolved_type);
+}
+
static void type_check_expr(struct expr_node* node) {
switch (node->type) {
case EXPR_INT_LIT:
@@ -188,34 +208,41 @@ static void type_check_expr(struct expr_node* node) {
case EXPR_BINARY:
node->resolved_type = resolve_binary(&node->inner.binary);
break;
+ case EXPR_PAREN:
+ node->resolved_type = resolve_paren(&node->inner.paren);
+ break;
}
}
static void type_check_return(struct return_node* node) {
- if (node->ret_val != NULL) type_check_expr(node->ret_val);
+ const struct type* return_type = &node->fn_ref->return_type;
+ if (node->ret_val != NULL) {
+ type_check_expr_list(node->ret_val);
+ assert_cast_compatible(return_type, node->ret_val->resolved_type);
+ } else if (return_type->type != TP_DATA
+ || return_type->data.data_type != &void_type)
+ TYPE_PANIC(
+ "void function '%s' should not return a value",
+ node->fn_ref->name);
}
static void type_check_if(struct if_node* node) {
enter_scope(node->scope);
- type_check_expr(node->cond);
+ type_check_expr_list(node->cond);
type_check_stmt(node->true_branch);
if (node->false_branch != NULL) type_check_stmt(node->false_branch);
exit_scope(node->scope);
}
-static void type_check_expr_list(struct expr_list_node* node) {
- for (; node != NULL; node = node->next) type_check_expr(node->expr);
-}
-
static void type_check_loop_init(struct loop_init_node* node) {
switch (node->type) {
case INIT_EXPR_LIST:
type_check_expr_list(node->expr_list);
break;
- case INIT_DECL:
- type_check_var_decl(node->decl);
+ case INIT_DECL_LIST:
+ type_check_decl_list(node->decl_list);
break;
}
}
@@ -224,8 +251,8 @@ static void type_check_loop(struct loop_node* node) {
enter_scope(node->scope);
if (node->init != NULL) type_check_loop_init(node->init);
- if (node->cond != NULL) type_check_expr(node->cond);
- if (node->incr != NULL) type_check_expr(node->incr);
+ if (node->cond != NULL) type_check_expr_list(node->cond);
+ if (node->incr != NULL) type_check_expr_list(node->incr);
type_check_stmt(node->body);
exit_scope(node->scope);
@@ -235,11 +262,11 @@ static void type_check_stmt(struct stmt_node* node) {
switch (node->type) {
case STMT_EMPTY:
break;
- case STMT_EXPR:
- type_check_expr(&node->inner.expr);
+ case STMT_EXPR_LIST:
+ type_check_expr_list(&node->inner.expr_list);
break;
- case STMT_VAR_DECL:
- type_check_var_decl(&node->inner.var_decl);
+ case STMT_DECL_LIST:
+ type_check_decl_list(&node->inner.decl_list);
break;
case STMT_RETURN:
type_check_return(&node->inner.return_);
@@ -271,10 +298,10 @@ static void type_check_group(struct group_node* node) {
static void type_check_fn_decl(struct fn_decl_node* node) {
enter_scope(node->scope);
- for (struct decl_list_node* arg_decl = node->args;
+ for (struct arg_decl_node* arg_decl = node->args;
arg_decl != NULL;
arg_decl = arg_decl->next)
- type_check_var_decl(arg_decl->decl);
+ arg_decl->def_ref->type = &arg_decl->type;
type_check_group(&node->body);