feat: trait 接口系统 — trait Show { fn method } + extend Trait Struct { }
This commit is contained in:
+63
-9
@@ -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 后应为模块名");
|
||||
|
||||
Reference in New Issue
Block a user