feat: trait 接口系统 — trait Show { fn method } + extend Trait Struct { }

This commit is contained in:
2026-06-06 16:41:21 +08:00
parent 9169796b77
commit b3b3d285f9
9 changed files with 126 additions and 12 deletions
+63 -9
View File
@@ -499,6 +499,14 @@ static TypeInfo parse_type_expr(Parser* p, ErrorInfo* error) {
const Token* t = peek(p);
TypeInfo ti = {0};
// Self 类型(trait 中引用实现者自身类型)
if (t->kind == TOK_SELF) {
advance(p);
ti.kind = TYPE_STRUCT;
ti.struct_name = "Self";
return ti;
}
// 解析基础类型
if (tok_is_type(t->kind)) {
advance(p);
@@ -949,8 +957,14 @@ static AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
ret_struct_name = rti.struct_name;
}
AstNode* body = parse_block(p, error);
if (!body) return NULL;
// trait 方法签名或普通函数体
AstNode* body = NULL;
if (match(p, TOK_SEMICOLON)) {
body = NULL; // trait 方法签名,无实现
} else {
body = parse_block(p, error);
if (!body) return NULL;
}
AstNode** parr = arena_alloc_impl(p->arena, pcount * sizeof(AstNode*));
memcpy(parr, params, pcount * sizeof(AstNode*));
@@ -1026,7 +1040,31 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
if (peek(&p)->kind == TOK_PUB) {
is_pub = true; advance(&p);
}
if (peek(&p)->kind == TOK_STRUCT) {
if (peek(&p)->kind == TOK_TRAIT) {
const Token* tt = advance(&p);
const Token* tname = expect(&p, TOK_IDENT, error, "trait 后应为接口名");
if (!tname) return NULL;
if (!expect(&p, TOK_LBRACE, error, "缺少 '{'")) return NULL;
AstNode* methods[64]; int mcount = 0;
while (peek(&p)->kind != TOK_RBRACE && !error->message) {
if (mcount >= 64) { error->message = "trait 方法过多(最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
if (peek(&p)->kind != TOK_FN) { error->message = "trait 内只允许 fn"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
// trait 方法只解析签名(body 为空)
AstNode* m = parse_function(&p, false, error);
if (!m) return NULL;
m->as.function.body = NULL; // trait 方法无实现
methods[mcount++] = m;
if (peek(&p)->kind == TOK_COMMA) advance(&p);
}
if (!expect(&p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
AstNode** marr = arena_alloc_impl(p.arena, mcount * sizeof(AstNode*));
memcpy(marr, methods, mcount * sizeof(AstNode*));
// 复用 impl_count 存储 trait(共用计数)
if (impl_count >= 64) { error->message = "trait 过多(最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
impls[impl_count++] = ast_make_trait_decl(p.arena,
arena_strdup_impl(p.arena, tname->start, tname->length),
marr, mcount, tok_loc(tt));
} else if (peek(&p)->kind == TOK_STRUCT) {
if (struct_count >= 64) { error->message = "结构体过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
structs[struct_count++] = parse_struct_decl(&p, error);
} else if (peek(&p)->kind == TOK_TYPE) {
@@ -1083,22 +1121,38 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
enums[enum_count++] = enum_decl;
} else if (peek(&p)->kind == TOK_EXTEND) {
const Token* i_tok = advance(&p);
const Token* st_name = expect(&p, TOK_IDENT, error, "extend 后应为结构体名");
if (!st_name) return NULL;
const Token* first = expect(&p, TOK_IDENT, error, "extend 后应为结构体名");
if (!first) return NULL;
const char* trait_name = NULL;
const char* struct_name;
// extend Trait Struct { ... }trait 实现:两个标识符)
if (peek(&p)->kind == TOK_IDENT) {
trait_name = arena_strdup_impl(p.arena, first->start, first->length);
struct_name = arena_strdup_impl(p.arena, peek(&p)->start, peek(&p)->length);
advance(&p);
} else {
struct_name = arena_strdup_impl(p.arena, first->start, first->length);
}
if (!expect(&p, TOK_LBRACE, error, "缺少 '{'")) return NULL;
AstNode* methods[64]; int mcount = 0;
while (peek(&p)->kind != TOK_RBRACE && !error->message) {
if (mcount >= 64) { error->message = "方法过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
if (peek(&p)->kind != TOK_FN) { error->message = "extend 块内只允许 fn"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
methods[mcount++] = parse_function(&p, false, error);
AstNode* m = parse_function(&p, false, error);
if (!m) return NULL;
// trait 实现: 方法名 mangled 为 TraitName$methodName
if (trait_name) {
char* mn = arena_alloc_impl(p.arena, strlen(trait_name) + strlen(m->as.function.name) + 4);
sprintf(mn, "%s$%s", trait_name, m->as.function.name);
m->as.function.name = mn;
}
methods[mcount++] = m;
}
if (!expect(&p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
AstNode** m_arr = arena_alloc_impl(p.arena, mcount * sizeof(AstNode*));
memcpy(m_arr, methods, mcount * sizeof(AstNode*));
if (impl_count >= 64) { error->message = "extend 块过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
impls[impl_count++] = ast_make_impl_block(p.arena,
arena_strdup_impl(p.arena, st_name->start, st_name->length),
m_arr, mcount, tok_loc(i_tok));
impls[impl_count++] = ast_make_impl_block(p.arena, struct_name, m_arr, mcount, tok_loc(i_tok));
} else if (peek(&p)->kind == TOK_MOD) {
advance(&p);
const Token* mn = expect(&p, TOK_IDENT, error, "mod 后应为模块名");