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:
2026-06-05 14:30:24 +08:00
parent 2923e7574d
commit 9f6e695ba8
11 changed files with 340 additions and 20 deletions
+79 -8
View File
@@ -13,7 +13,7 @@ void test_codegen_simple_function() {
AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1));
AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx = NULL;
@@ -47,7 +47,7 @@ void test_codegen_if_else() {
AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1));
AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx2 = NULL;
@@ -78,7 +78,7 @@ void test_codegen_binary_ops() {
AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1));
AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx3 = NULL;
@@ -108,7 +108,7 @@ void test_codegen_while_loop() {
AstNode* fn_body = ast_make_block(&a, stmts, 2, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, fn_body, loc_at(1, 1));
AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx4 = NULL;
@@ -162,7 +162,7 @@ void test_codegen_struct_decl() {
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1));
AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, NULL, 0, loc_at(1, 1));
AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx = NULL;
@@ -217,7 +217,7 @@ void test_codegen_struct_field_access() {
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1));
AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, NULL, 0, loc_at(1, 1));
AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx = NULL;
@@ -267,7 +267,7 @@ void test_codegen_enum() {
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1));
AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, enums, 1, loc_at(1, 1));
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, enums, 1, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx = NULL;
@@ -331,7 +331,7 @@ void test_codegen_array() {
AstNode* body = ast_make_block(&a, stmts, 4, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1));
AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx = NULL;
@@ -348,6 +348,76 @@ void test_codegen_array() {
arena_destroy(&a);
}
/* === 方法调用代码生成测试 === */
void test_codegen_method_call() {
Arena a = arena_create(1);
/* struct Point { x: i64, y: i64 } */
AstNode* fields[2];
fields[0] = ast_make_parameter(&a, "x", TYPE_I64, NULL, loc_at(1, 1));
fields[1] = ast_make_parameter(&a, "y", TYPE_I64, NULL, loc_at(1, 1));
AstNode* struct_decl = ast_make_struct_decl(&a, "Point", fields, 2, loc_at(1, 1));
AstNode* structs[] = { struct_decl };
/* fn Point$get_x(self: Point) -> i64 { return self.x; } */
AstNode* self_param = ast_make_parameter(&a, "self", TYPE_STRUCT, "Point", loc_at(1, 1));
AstNode* params[] = { self_param };
AstNode* self_ident = ast_make_ident(&a, "self", loc_at(1, 1));
self_ident->type.kind = TYPE_STRUCT;
self_ident->type.struct_name = "Point";
AstNode* field_x = ast_make_field_access(&a, self_ident, "x", loc_at(1, 1));
field_x->as.field_access.field_index = 0;
field_x->type.kind = TYPE_I64;
AstNode* ret_body = ast_make_return(&a, field_x, loc_at(1, 1));
AstNode* ret_stmts[] = { ret_body };
AstNode* body = ast_make_block(&a, ret_stmts, 1, loc_at(1, 1));
AstNode* get_x_fn = ast_make_function(&a, "Point$get_x", params, 1, TYPE_I64, NULL, body, loc_at(1, 1));
/* fn main() -> i64 {
let p = Point { x: 42, y: 0 };
return p.get_x();
} */
const char* fnames[] = {"x", "y"};
AstNode* fvals[] = {
ast_make_literal_i64(&a, 42, loc_at(1, 1)),
ast_make_literal_i64(&a, 0, loc_at(1, 1))
};
AstNode* init = ast_make_struct_init(&a, "Point", fnames, fvals, 2, loc_at(1, 1));
init->type.kind = TYPE_STRUCT;
init->type.struct_name = "Point";
AstNode* let_stmt = ast_make_let(&a, "p", TYPE_UNKNOWN, false, false,
init, NULL, 0, NULL, 0, loc_at(1, 1));
AstNode* p_ident = ast_make_ident(&a, "p", loc_at(1, 1));
p_ident->type.kind = TYPE_STRUCT;
p_ident->type.struct_name = "Point";
AstNode* method_call = ast_make_method_call(&a, p_ident, "get_x", NULL, 0, loc_at(1, 1));
method_call->type.kind = TYPE_I64;
AstNode* ret_main = ast_make_return(&a, method_call, loc_at(1, 1));
AstNode* main_stmts[] = { let_stmt, ret_main };
AstNode* main_body = ast_make_block(&a, main_stmts, 2, loc_at(1, 1));
AstNode* main_fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, main_body, loc_at(1, 1));
AstNode* fns[] = { get_x_fn, main_fn };
AstNode* prog = ast_make_program(&a, fns, 2, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
const char* err = NULL;
LLVMContextRef ctx = NULL;
LLVMModuleRef mod = codegen_module(prog, &a, "test_method", &err, &ctx);
ASSERT(mod != NULL);
ASSERT(err == NULL);
char* verify_err = NULL;
int failed = LLVMVerifyModule(mod, LLVMReturnStatusAction, &verify_err);
ASSERT(!failed);
LLVMDisposeModule(mod);
LLVMContextDispose(ctx);
arena_destroy(&a);
}
int main(void) {
TEST_RUN(test_codegen_simple_function);
TEST_RUN(test_codegen_if_else);
@@ -357,5 +427,6 @@ int main(void) {
TEST_RUN(test_codegen_struct_field_access);
TEST_RUN(test_codegen_enum);
TEST_RUN(test_codegen_array);
TEST_RUN(test_codegen_method_call);
return test_summary();
}