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:
+79
-8
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user