From 29510d33cab6e86b28b12c6246bca58acdab26e2 Mon Sep 17 00:00:00 2001 From: Carson Fleming Date: Wed, 29 Jul 2026 23:35:15 -0400 Subject: support for comma-separated expression lists where valid --- ast.c | 69 +++++++++++++++++++++++--------------- ast.h | 59 ++++++++++++++++++++------------ codegen.c | 100 ++++++++++++++++++++++++++++-------------------------- parser.c | 104 ++++++++++++++++++++++++++++++++++++--------------------- type_checker.c | 91 ++++++++++++++++++++++++++++++++------------------ 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); -- cgit v1.2.3