Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions ezc/src/codegen/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,19 @@ static void emit_func_declaration(CodeGen *cg, AstNode *node, bool is_main) {
cg->indent++;
AstNode *prev_func = cg->current_func;
cg->current_func = node;

/* Emit named return variable declarations */
if (node->data.func_decl.return_names) {
for (int i = 0; i < node->data.func_decl.return_type_count; i++) {
if (node->data.func_decl.return_names[i]) {
emit_indent(cg);
emitf(cg, "%s %s;\n",
ez_type_to_c_cg(cg, node->data.func_decl.return_types[i]),
node->data.func_decl.return_names[i]);
}
}
}

if (node->data.func_decl.body) {
emit_block(cg, node->data.func_decl.body);
/* Emit ensure cleanup at end of function (for implicit returns) */
Expand Down
1 change: 1 addition & 0 deletions ezc/src/parser/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ struct AstNode {
Param *params;
int param_count;
const char **return_types;
const char **return_names; /* Named return params (NULL if unnamed) */
int return_type_count;
AstNode *body;
int visibility; /* 0 = public, 1 = private */
Expand Down
37 changes: 25 additions & 12 deletions ezc/src/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,13 +670,16 @@ static AstNode *parse_func_declaration(Parser *p) {
/* Return type(s) */
node->data.func_decl.return_type_count = 0;
node->data.func_decl.return_types = NULL;
node->data.func_decl.return_names = NULL;

if (peek_token_is(p, TOK_ARROW)) {
next_token(p); /* skip -> */
next_token(p);

int ret_cap = 4;
int ret_cap = 8;
node->data.func_decl.return_types = arena_alloc(p->arena, sizeof(const char *) * ret_cap);
node->data.func_decl.return_names = arena_alloc(p->arena, sizeof(const char *) * ret_cap);
memset(node->data.func_decl.return_names, 0, sizeof(const char *) * ret_cap);

if (cur_token_is(p, TOK_LPAREN)) {
/* Multiple/named return types:
Expand Down Expand Up @@ -706,31 +709,41 @@ static AstNode *parse_func_declaration(Parser *p) {
}

if (cur_token_is(p, TOK_IDENT) && peek_token_is(p, TOK_IDENT) && !is_type) {
/* Named return: name type — skip name, use type */
/* Named return: name type — store both */
const char *ret_name = p->cur_token.literal;
next_token(p);
node->data.func_decl.return_types[node->data.func_decl.return_type_count++] =
p->cur_token.literal;
int idx = node->data.func_decl.return_type_count;
node->data.func_decl.return_names[idx] = ret_name;
node->data.func_decl.return_types[idx] = p->cur_token.literal;
node->data.func_decl.return_type_count++;
} else if (cur_token_is(p, TOK_IDENT) && peek_token_is(p, TOK_COMMA) && !is_type) {
/* Shared type: (x, y int) — count names, assign same type to all */
int shared = 1;
/* Shared type: (x, y int) — collect names, assign same type */
const char *names[16];
int shared = 0;
names[shared++] = p->cur_token.literal;
while (peek_token_is(p, TOK_COMMA)) {
next_token(p); /* skip comma */
next_token(p); /* next name */
shared++;
names[shared++] = p->cur_token.literal;
if (shared >= 16) break;
if (!peek_token_is(p, TOK_COMMA)) break;
}
/* cur is last name, peek should be the shared type */
if (peek_token_is(p, TOK_IDENT)) {
next_token(p);
for (int s = 0; s < shared; s++) {
node->data.func_decl.return_types[node->data.func_decl.return_type_count++] =
p->cur_token.literal;
int idx = node->data.func_decl.return_type_count;
node->data.func_decl.return_names[idx] = names[s];
node->data.func_decl.return_types[idx] = p->cur_token.literal;
node->data.func_decl.return_type_count++;
}
}
} else {
/* Plain type */
node->data.func_decl.return_types[node->data.func_decl.return_type_count++] =
p->cur_token.literal;
/* Plain type (no name) */
int idx = node->data.func_decl.return_type_count;
node->data.func_decl.return_names[idx] = NULL;
node->data.func_decl.return_types[idx] = p->cur_token.literal;
node->data.func_decl.return_type_count++;
}
if (peek_token_is(p, TOK_COMMA)) {
next_token(p);
Expand Down
20 changes: 14 additions & 6 deletions ezc/src/typechecker/typechecker.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,14 +356,12 @@ static void check_statement(TypeChecker *tc, AstNode *node) {
resolve_expr(tc, node->data.expr_stmt.expr);
break;

case NODE_BLOCK_STMT: {
Scope *inner = scope_create(tc->current_scope);
Scope *outer = tc->current_scope;
tc->current_scope = inner;
case NODE_BLOCK_STMT:
/* Inline blocks (from multi-var expansion) share parent scope.
* Only control flow blocks (if, for, etc.) create new scopes,
* and those are handled by their own cases. */
check_block(tc, node);
tc->current_scope = outer;
break;
}

case NODE_IF_STMT:
resolve_expr(tc, node->data.if_stmt.condition);
Expand Down Expand Up @@ -428,6 +426,16 @@ static void check_statement(TypeChecker *tc, AstNode *node) {
scope_define(func_scope, p->name, ptype, p->mutable);
}

/* Define named return variables in function scope */
if (node->data.func_decl.return_names) {
for (int i = 0; i < node->data.func_decl.return_type_count; i++) {
if (node->data.func_decl.return_names[i]) {
EzType *rt = type_from_name(node->data.func_decl.return_types[i]);
scope_define(func_scope, node->data.func_decl.return_names[i], rt, true);
}
}
}

check_block(tc, node->data.func_decl.body);
tc->current_scope = outer;
break;
Expand Down
Loading