feat: struct方法 impl (P1 #9)
- lexer: TOK_IMPL 关键字
- ast: AST_IMPL_BLOCK, AST_METHOD_CALL + AST_PROGRAM impls数组
- parser: impl StructName { fn ... } + p.method() 方法调用
- sema: 方法名mangle(StructName$method), self参数, 类型检查
- codegen: METHOD_CALL→mangled函数调用(recv为第一参数)
- 新增集成测试: 19_struct_method.l
P1 4项全部完成: type alias + enum + array + impl
测试: 145 通过 (41+15+65+24)
This commit is contained in:
+44
-6
@@ -220,14 +220,30 @@ static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error
|
||||
while (!error->message) {
|
||||
TokenKind kind = peek(p)->kind;
|
||||
|
||||
// 后置字段访问: expr.field
|
||||
// 后置字段访问: expr.field 或 expr.method(args)
|
||||
if (kind == TOK_DOT) {
|
||||
advance(p); // 跳过 '.'
|
||||
const Token* field = expect(p, TOK_IDENT, error, "缺少字段名");
|
||||
if (!field) return NULL;
|
||||
left = ast_make_field_access(p->arena, left,
|
||||
arena_strdup_impl(p->arena, field->start, field->length),
|
||||
tok_loc(field));
|
||||
const char* member_name = arena_strdup_impl(p->arena, field->start, field->length);
|
||||
// 方法调用: expr.method(args)
|
||||
if (peek(p)->kind == TOK_LPAREN) {
|
||||
advance(p); // 跳过 '('
|
||||
AstNode* args[16]; int arg_count = 0;
|
||||
while (peek(p)->kind != TOK_RPAREN && !error->message) {
|
||||
if (arg_count >= 16) { error->message = "参数过多"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
|
||||
args[arg_count] = parse_expr(p, error);
|
||||
if (!args[arg_count]) return NULL;
|
||||
arg_count++;
|
||||
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
|
||||
}
|
||||
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
|
||||
AstNode** arg_arr = arena_alloc_impl(p->arena, arg_count * sizeof(AstNode*));
|
||||
memcpy(arg_arr, args, arg_count * sizeof(AstNode*));
|
||||
left = ast_make_method_call(p->arena, left, member_name, arg_arr, arg_count, tok_loc(field));
|
||||
} else {
|
||||
left = ast_make_field_access(p->arena, left, member_name, tok_loc(field));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -634,6 +650,7 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
||||
AstNode* structs[64]; int struct_count = 0;
|
||||
AstNode* aliases[64]; int alias_count = 0;
|
||||
AstNode* enums[64]; int enum_count = 0;
|
||||
AstNode* impls[64]; int impl_count = 0;
|
||||
while (peek(&p)->kind != TOK_EOF && !error->message) {
|
||||
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; }
|
||||
@@ -669,11 +686,29 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
||||
AstNode* enum_decl = ast_make_enum_decl(p.arena, arena_strdup_impl(p.arena, name->start, name->length), v_arr, vcount, tok_loc(name));
|
||||
if (enum_count >= 64) { error->message = "枚举过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||||
enums[enum_count++] = enum_decl;
|
||||
} else if (peek(&p)->kind == TOK_IMPL) {
|
||||
const Token* i_tok = advance(&p);
|
||||
const Token* st_name = expect(&p, TOK_IDENT, error, "impl 后应为结构体名");
|
||||
if (!st_name) 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 = "方法过多 (最多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 = "impl 块内只允许 fn"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
|
||||
methods[mcount++] = parse_function(&p, error);
|
||||
}
|
||||
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 = "impl 块过多 (最多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));
|
||||
} 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, error);
|
||||
} else {
|
||||
error->message = "顶层只允许 fn、struct、type 或 enum";
|
||||
error->message = "顶层只允许 fn、struct、type、enum 或 impl";
|
||||
error->filename = p.filename;
|
||||
error->line = peek(&p)->line;
|
||||
error->col = peek(&p)->col;
|
||||
@@ -689,6 +724,9 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
|
||||
memcpy(al_arr, aliases, alias_count * sizeof(AstNode*));
|
||||
AstNode** en_arr = arena_alloc_impl(a, enum_count * sizeof(AstNode*));
|
||||
memcpy(en_arr, enums, enum_count * sizeof(AstNode*));
|
||||
AstNode** im_arr = arena_alloc_impl(a, impl_count * sizeof(AstNode*));
|
||||
memcpy(im_arr, impls, impl_count * sizeof(AstNode*));
|
||||
return ast_make_program(a, fn_arr, fn_count, st_arr, struct_count,
|
||||
al_arr, alias_count, en_arr, enum_count, loc_at(0, 0));
|
||||
al_arr, alias_count, en_arr, enum_count,
|
||||
im_arr, impl_count, loc_at(0, 0));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user