feat: 多返回值 fn f(...) -> (T, U) { return (e1, e2); }
Parser: -> (T1,T2) 解析为隐式 struct __ret_funcname, return (e1,e2) 去糖为 struct init 返回的 struct 可访问字段 _0, _1, ... 无 sema/codegen 改动 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,9 @@ AstNode* ast_make_function(void* alloc, const char* name, AstNode** params, size
|
||||
n->as.function.is_pub = is_pub;
|
||||
n->as.function.type_params = type_params;
|
||||
n->as.function.type_param_count = tp_count;
|
||||
n->as.function.multi_ret_types = NULL;
|
||||
n->as.function.multi_ret_snames = NULL;
|
||||
n->as.function.multi_ret_count = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -71,7 +71,8 @@ struct AstNode {
|
||||
struct { const char* name; struct AstNode** params; size_t param_count;
|
||||
TypeKind return_type; const char* return_struct_type_name;
|
||||
struct AstNode* body; bool is_pub;
|
||||
const char** type_params; size_t type_param_count; } function;
|
||||
const char** type_params; size_t type_param_count;
|
||||
TypeKind* multi_ret_types; const char** multi_ret_snames; size_t multi_ret_count; } function;
|
||||
// AST_PARAMETER (也用作结构体字段: name + type)
|
||||
struct { const char* name; TypeKind type; const char* struct_type_name; } parameter;
|
||||
// AST_BLOCK
|
||||
|
||||
+95
-4
@@ -4,6 +4,9 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// 当前解析的函数的多返回值 struct 名 (用于 return 语句)
|
||||
static const char* current_multi_ret_name = NULL;
|
||||
|
||||
// === 结构体声明解析 ===
|
||||
AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) {
|
||||
const Token* s_tok = advance(p); // 跳过 'struct'
|
||||
@@ -195,8 +198,30 @@ AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
|
||||
if (t->kind == TOK_RETURN) {
|
||||
advance(p);
|
||||
if (match(p, TOK_SEMICOLON)) {
|
||||
if (match(p, TOK_SEMICOLON))
|
||||
return ast_make_return(p->arena, NULL, tok_loc(t));
|
||||
// 多返回值: return (e1, e2, ...)
|
||||
if (current_multi_ret_name && peek(p)->kind == TOK_LPAREN) {
|
||||
advance(p); // 跳过 '('
|
||||
AstNode* vals[8]; int vcount = 0;
|
||||
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||||
if (vcount >= 8) { error->message = "返回表达式过多(最多8)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||||
vals[vcount++] = parse_expr(p, error);
|
||||
if (!vals[vcount-1]) return NULL;
|
||||
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
|
||||
}
|
||||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||||
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||||
// 创建 struct init: __ret_funcname { _0: v0, _1: v1, ... }
|
||||
const char** fnames = arena_alloc_impl(p->arena, vcount * sizeof(const char*));
|
||||
for (int i = 0; i < vcount; i++) {
|
||||
char fbuf[4]; snprintf(fbuf, sizeof(fbuf), "_%d", i);
|
||||
fnames[i] = arena_strdup_impl(p->arena, fbuf, strlen(fbuf));
|
||||
}
|
||||
AstNode** varr = arena_alloc_impl(p->arena, vcount * sizeof(AstNode*));
|
||||
memcpy(varr, vals, vcount * sizeof(AstNode*));
|
||||
AstNode* init = ast_make_struct_init(p->arena, current_multi_ret_name, fnames, varr, vcount, tok_loc(t));
|
||||
return ast_make_return(p->arena, init, tok_loc(t));
|
||||
}
|
||||
AstNode* expr = parse_expr(p, error);
|
||||
if (!expr) return NULL;
|
||||
@@ -327,22 +352,63 @@ AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
|
||||
}
|
||||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||||
|
||||
// 多返回值
|
||||
TypeKind* multi_ret_types = NULL;
|
||||
const char** multi_ret_snames = NULL;
|
||||
size_t multi_ret_count = 0;
|
||||
// 返回类型
|
||||
TypeKind ret = TYPE_VOID;
|
||||
const char* ret_struct_name = NULL;
|
||||
if (match(p, TOK_ARROW)) {
|
||||
// 多返回值: -> (T1, T2, ...)
|
||||
if (peek(p)->kind == TOK_LPAREN) {
|
||||
advance(p); // 跳过 '('
|
||||
TypeKind ttypes[8]; const char* tstructs[8]; int tcount = 0;
|
||||
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||||
if (tcount >= 8) { error->message = "返回类型过多(最多8)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||||
TypeInfo ti = parse_type_expr(p, error);
|
||||
if (ti.kind == TYPE_ERROR) return NULL;
|
||||
ttypes[tcount] = ti.kind;
|
||||
tstructs[tcount] = ti.struct_name;
|
||||
tcount++;
|
||||
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
|
||||
}
|
||||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||||
if (tcount == 0) { error->message = "返回元组不能为空"; error->filename = p->filename; return NULL; }
|
||||
if (tcount == 1) {
|
||||
ret = ttypes[0]; ret_struct_name = tstructs[0];
|
||||
} else {
|
||||
// 生成隐式 struct 名: __ret_<funcname>
|
||||
size_t nlen = name->length;
|
||||
char* sname = arena_alloc_impl(p->arena, nlen + 7);
|
||||
memcpy(sname, "__ret_", 6);
|
||||
memcpy(sname + 6, name->start, nlen);
|
||||
sname[nlen + 6] = '\0';
|
||||
ret_struct_name = sname;
|
||||
ret = TYPE_STRUCT;
|
||||
// 暂存多返回类型, parse() 中创建隐式 struct
|
||||
multi_ret_types = arena_alloc_impl(p->arena, tcount * sizeof(TypeKind));
|
||||
memcpy(multi_ret_types, ttypes, tcount * sizeof(TypeKind));
|
||||
multi_ret_snames = arena_alloc_impl(p->arena, tcount * sizeof(const char*));
|
||||
memcpy(multi_ret_snames, tstructs, tcount * sizeof(const char*));
|
||||
multi_ret_count = tcount;
|
||||
}
|
||||
} else {
|
||||
TypeInfo rti = parse_type_expr(p, error);
|
||||
if (rti.kind == TYPE_ERROR) return NULL;
|
||||
ret = rti.kind;
|
||||
ret_struct_name = rti.struct_name;
|
||||
}
|
||||
}
|
||||
|
||||
// trait 方法签名或普通函数体
|
||||
AstNode* body = NULL;
|
||||
if (match(p, TOK_SEMICOLON)) {
|
||||
body = NULL; // trait 方法签名,无实现
|
||||
body = NULL;
|
||||
} else {
|
||||
current_multi_ret_name = (multi_ret_count > 0) ? ret_struct_name : NULL;
|
||||
body = parse_block(p, error);
|
||||
current_multi_ret_name = NULL;
|
||||
if (!body) return NULL;
|
||||
}
|
||||
|
||||
@@ -353,9 +419,15 @@ AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
|
||||
tparr = arena_alloc_impl(p->arena, tp_count * sizeof(const char*));
|
||||
memcpy(tparr, type_params, tp_count * sizeof(const char*));
|
||||
}
|
||||
return ast_make_function(p->arena,
|
||||
AstNode* fn = ast_make_function(p->arena,
|
||||
arena_strdup_impl(p->arena, name->start, name->length),
|
||||
parr, pcount, ret, ret_struct_name, body, is_pub, tparr, tp_count, tok_loc(fn_tok));
|
||||
if (multi_ret_count > 0) {
|
||||
fn->as.function.multi_ret_types = multi_ret_types;
|
||||
fn->as.function.multi_ret_snames = multi_ret_snames;
|
||||
fn->as.function.multi_ret_count = multi_ret_count;
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
||||
// === 模块文件加载 ===
|
||||
@@ -402,6 +474,7 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
||||
const char* filename, ErrorInfo* error) {
|
||||
Parser p = {.tokens = tokens, .count = count, .pos = 0,
|
||||
.filename = filename, .arena = a};
|
||||
current_multi_ret_name = NULL;
|
||||
AstNode* functions[256]; int fn_count = 0;
|
||||
AstNode* structs[64]; int struct_count = 0;
|
||||
AstNode* aliases[64]; int alias_count = 0;
|
||||
@@ -605,7 +678,25 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
||||
}
|
||||
} else if (peek(&p)->kind == TOK_FN) {
|
||||
if (fn_count >= 256) { error->message = "函数过多 (最多256)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||||
functions[fn_count++] = parse_function(&p, is_pub, error);
|
||||
AstNode* fn = parse_function(&p, is_pub, error);
|
||||
if (!fn) return NULL;
|
||||
// 多返回值: 注册隐式 struct
|
||||
if (fn->as.function.multi_ret_count > 0) {
|
||||
size_t mc = fn->as.function.multi_ret_count;
|
||||
AstNode** flds = arena_alloc_impl(p.arena, mc * sizeof(AstNode*));
|
||||
for (size_t i = 0; i < mc; i++) {
|
||||
char fbuf[4]; snprintf(fbuf, sizeof(fbuf), "_%zu", i);
|
||||
flds[i] = ast_make_parameter(p.arena,
|
||||
arena_strdup_impl(p.arena, fbuf, strlen(fbuf)),
|
||||
fn->as.function.multi_ret_types[i],
|
||||
fn->as.function.multi_ret_snames[i],
|
||||
tok_loc(peek(&p)));
|
||||
}
|
||||
if (struct_count >= 64) { error->message = "结构体过多"; return NULL; }
|
||||
structs[struct_count++] = ast_make_struct_decl(p.arena,
|
||||
fn->as.function.return_struct_type_name, flds, mc, fn->loc);
|
||||
}
|
||||
functions[fn_count++] = fn;
|
||||
} else {
|
||||
error->message = "顶层只允许 fn、struct、type、enum、extend、mod 或 use";
|
||||
error->filename = p.filename;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
fn div_mod(a: i64, b: i64) -> (i64, i64) {
|
||||
return (a / b, a % b);
|
||||
}
|
||||
|
||||
fn main() -> i64 {
|
||||
let result = div_mod(10, 3);
|
||||
print_i64(result._0); // 3
|
||||
print_i64(result._1); // 1
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user