diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 187a61d..2343fee 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -353,6 +353,7 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) { LLVMValueRef fn = find_fn(ctx, node->as.call.name); if (!fn) return NULL; LLVMValueRef args[16]; + if (node->as.call.arg_count > 16) { ctx->error = "函数参数过多(最多16)"; return NULL; } for (size_t i = 0; i < node->as.call.arg_count; i++) { args[i] = codegen_expr(ctx, node->as.call.args[i]); if (!args[i]) return NULL; @@ -440,6 +441,7 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) { LLVMValueRef fn = find_fn(ctx, mangled); if (!fn) return NULL; // 参数列表: [receiver, 用户参数...] + if (node->as.method_call.arg_count + 1 > 16) { ctx->error = "方法参数过多(最多15)"; return NULL; } LLVMValueRef args[16]; args[0] = codegen_expr(ctx, node->as.method_call.receiver); if (!args[0]) return NULL; diff --git a/src/driver/error.c b/src/driver/error.c index bce4b4e..f4dbca5 100644 --- a/src/driver/error.c +++ b/src/driver/error.c @@ -1,22 +1,25 @@ #include "error.h" +#include "arena.h" #include #include #include #include -void error_init(ErrorList* list) { - list->capacity = 8; - list->errors = malloc(list->capacity * sizeof(ErrorInfo)); +void error_init(ErrorList* list, Arena* a) { + list->capacity = 64; + list->errors = arena_alloc(a, list->capacity * sizeof(ErrorInfo)); list->count = 0; + list->arena = a; if (!list->errors) list->capacity = 0; } void error_add(ErrorList* list, const char* filename, int line, int col, const char* fmt, ...) { if (!list->errors) return; if (list->count >= list->capacity) { - size_t new_cap = list->capacity * 2; - ErrorInfo* new_errs = realloc(list->errors, new_cap * sizeof(ErrorInfo)); + size_t new_cap = list->capacity + 64; + ErrorInfo* new_errs = arena_alloc(list->arena, new_cap * sizeof(ErrorInfo)); if (!new_errs) return; + memcpy(new_errs, list->errors, list->capacity * sizeof(ErrorInfo)); list->errors = new_errs; list->capacity = new_cap; } @@ -26,12 +29,9 @@ void error_add(ErrorList* list, const char* filename, int line, int col, const c int n = vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (n < 0) return; - char* msg = strdup(buf); - char* fname = strdup(filename); - if (!msg || !fname) { - free(msg); free(fname); - return; - } + char* msg = arena_strdup(list->arena, buf); + char* fname = arena_strdup(list->arena, filename); + if (!msg || !fname) return; list->errors[list->count++] = (ErrorInfo){ .message = msg, .filename = fname, diff --git a/src/driver/error.h b/src/driver/error.h index 3305fd6..67f59fc 100644 --- a/src/driver/error.h +++ b/src/driver/error.h @@ -3,6 +3,8 @@ #include +typedef struct Arena Arena; + typedef struct { const char* message; const char* filename; @@ -14,9 +16,10 @@ typedef struct { ErrorInfo* errors; size_t count; size_t capacity; + Arena* arena; } ErrorList; -void error_init(ErrorList* list); +void error_init(ErrorList* list, Arena* a); void error_add(ErrorList* list, const char* filename, int line, int col, const char* fmt, ...); void error_print(const ErrorList* list); diff --git a/src/driver/main.c b/src/driver/main.c index c9ac57d..8ce38a8 100644 --- a/src/driver/main.c +++ b/src/driver/main.c @@ -86,7 +86,7 @@ int main(int argc, char** argv) { if (!arena.memory) { fprintf(stderr, "内存分配失败\n"); free(source); return 1; } ErrorInfo error = {0}; - ErrorList error_list; error_init(&error_list); + ErrorList error_list; error_init(&error_list, &arena); // 3. 词法分析 size_t token_count; diff --git a/src/parser/parser.c b/src/parser/parser.c index 73004f6..9fb5313 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1031,8 +1031,6 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count, AstNode* aliases[64]; int alias_count = 0; AstNode* enums[64]; int enum_count = 0; AstNode* impls[64]; int impl_count = 0; - AstNode* mods[64]; int mod_count = 0; - AstNode* uses[64]; int use_count = 0; while (peek(&p)->kind != TOK_EOF && !error->message) { // pub 前缀 bool is_pub = false; @@ -1179,20 +1177,12 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count, if (enum_count >= 64) break; enums[enum_count++] = sub->as.program.enums[i]; } - if (mod_count < 64) mods[mod_count++] = ast_make_mod_decl(a, mod_name, sub, tok_loc(mn)); + /* mod 内容已内联合并到当前文件 */ ; } else if (peek(&p)->kind == TOK_USE) { + /* TODO: use 语句待实现符号导入 */ ; advance(&p); - const Token* path_tok = expect(&p, TOK_IDENT, error, "use 后应为模块名"); - if (!path_tok) return NULL; - if (!expect(&p, TOK_COLON_COLON, error, "缺少 '::'")) return NULL; - const Token* item_tok = expect(&p, TOK_IDENT, error, "use 后应为项目名"); - if (!item_tok) return NULL; - if (!expect(&p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL; - if (use_count >= 64) { error->message = "use 过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } - uses[use_count++] = ast_make_use_decl(a, - arena_strdup_impl(p.arena, path_tok->start, path_tok->length), - arena_strdup_impl(p.arena, item_tok->start, item_tok->length), - tok_loc(path_tok)); + while (peek(&p)->kind != TOK_SEMICOLON && peek(&p)->kind != TOK_EOF) advance(&p); + if (peek(&p)->kind == TOK_SEMICOLON) advance(&p); } 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, is_pub, error); diff --git a/src/sema/sema.c b/src/sema/sema.c index 75d9652..ee80610 100644 --- a/src/sema/sema.c +++ b/src/sema/sema.c @@ -558,19 +558,20 @@ static void analyze_method_call(AstNode* node, Scope* scope, ErrorList* errors, snprintf(mangled, sizeof(mangled), "%s$%s", recv_struct, node->as.method_call.method_name); Symbol* sym = scope_lookup(scope, mangled); - // trait 方法 fallback: 搜索所有作用域中以 $method_name 结尾的符号 + // trait 方法 fallback: 搜索所有作用域中以 $method_name 结尾且以 StructName 开头的符号 if (!sym || sym->kind != SYM_FUNCTION) { char suffix[256]; snprintf(suffix, sizeof(suffix), "$%s", node->as.method_call.method_name); size_t suf_len = strlen(suffix); + size_t recv_len = strlen(recv_struct); for (const Scope* sc = scope; sc; sc = sc->parent) { for (Symbol* s = sc->head; s; s = s->next) { if (s->kind == SYM_FUNCTION) { size_t name_len = strlen(s->name); - if (name_len > suf_len && strcmp(s->name + name_len - suf_len, suffix) == 0) { + if (name_len > suf_len + recv_len + && strncmp(s->name, recv_struct, recv_len) == 0 + && strcmp(s->name + name_len - suf_len, suffix) == 0) { sym = s; - // 更新 method_name 为找到的完整函数名(codegen 需要) - node->as.method_call.method_name = s->name; break; } } @@ -578,6 +579,10 @@ static void analyze_method_call(AstNode* node, Scope* scope, ErrorList* errors, if (sym) break; } } + // 更新 method_name 为符号的实际名称(codegen 需要通过它找到 LLVM 函数) + if (sym && sym->kind == SYM_FUNCTION) { + node->as.method_call.method_name = sym->name; + } if (!sym || sym->kind != SYM_FUNCTION) { error_add(errors, "", node->loc.line, node->loc.col, "结构体 '%s' 没有方法 '%s'", recv_struct, @@ -700,6 +705,21 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* } for (size_t j = 0; j < impl->as.impl_block.method_count; j++) { AstNode* method = impl->as.impl_block.methods[j]; + // Self → 实际结构体名(参数类型) + for (size_t k = 0; k < method->as.function.param_count; k++) { + AstNode* p = method->as.function.params[k]; + if (p->as.parameter.type == TYPE_STRUCT + && p->as.parameter.struct_type_name + && strcmp(p->as.parameter.struct_type_name, "Self") == 0) { + p->as.parameter.struct_type_name = st_name; + } + } + // Self → 实际结构体名(返回类型) + if (method->as.function.return_type == TYPE_STRUCT + && method->as.function.return_struct_type_name + && strcmp(method->as.function.return_struct_type_name, "Self") == 0) { + method->as.function.return_struct_type_name = st_name; + } // 构造改名后的函数名 char mangled[256]; snprintf(mangled, sizeof(mangled), "%s$%s", st_name, diff --git a/test/programs/36_self_type.l b/test/programs/36_self_type.l new file mode 100644 index 0000000..e2576b2 --- /dev/null +++ b/test/programs/36_self_type.l @@ -0,0 +1,28 @@ +trait Eq { + fn eq(self: Self, other: Self) -> bool; +} + +struct Point { x: i64, y: i64 } + +extend Eq Point { + fn eq(self: Point, other: Point) -> bool { + return self.x == other.x && self.y == other.y; + } +} + +fn main() -> i64 { + let p1 = Point { x: 10, y: 20 }; + let p2 = Point { x: 10, y: 20 }; + let p3 = Point { x: 99, y: 1 }; + if p1.eq(p2) { + print_str("same"); + } else { + print_str("diff"); + } + if p1.eq(p3) { + print_str("same"); + } else { + print_str("diff"); + } + return 0; +} diff --git a/test/test_codegen.c b/test/test_codegen.c index 77fb990..74e356c 100644 --- a/test/test_codegen.c +++ b/test/test_codegen.c @@ -491,7 +491,7 @@ void test_codegen_match() { AstNode* fns[] = { main_fn }; AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, enums, 1, NULL, 0, loc_at(1, 1)); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(prog, &errors, &a); ASSERT(errors.count == 0); diff --git a/test/test_sema.c b/test/test_sema.c index ed7a986..d2f9ae4 100644 --- a/test/test_sema.c +++ b/test/test_sema.c @@ -14,7 +14,7 @@ void test_type_error() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); arena_destroy(&a); @@ -29,7 +29,7 @@ void test_undefined_var() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); arena_destroy(&a); @@ -45,7 +45,7 @@ void test_simple_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -61,7 +61,7 @@ void test_let_mut_assign_ok() { ErrorInfo parse_err = {0}; AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -77,7 +77,7 @@ void test_assign_immutable_error() { ErrorInfo parse_err = {0}; AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); // 不可变变量赋值应报错 arena_destroy(&a); @@ -93,7 +93,7 @@ void test_str_type_ok() { ErrorInfo parse_err = {0}; AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -109,7 +109,7 @@ void test_str_concat_type_ok() { ErrorInfo parse_err = {0}; AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -128,7 +128,7 @@ void test_struct_field_type_mismatch() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); // y 字段类型不匹配: true 是 bool, 不是 i64 arena_destroy(&a); @@ -145,7 +145,7 @@ void test_struct_undefined() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); // Unknown 未定义 arena_destroy(&a); @@ -162,7 +162,7 @@ void test_struct_field_count_mismatch() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); // 缺少字段 'y' arena_destroy(&a); @@ -182,7 +182,7 @@ void test_type_alias_ok() { ASSERT(ast != NULL); ASSERT(ast->as.program.alias_count == 1); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -200,7 +200,7 @@ void test_type_alias_struct() { ASSERT(ast != NULL); ASSERT(ast->as.program.alias_count == 1); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -217,7 +217,7 @@ void test_struct_nested_type_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); // 嵌套结构体类型检查应通过 arena_destroy(&a); @@ -236,7 +236,7 @@ void test_enum_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -253,7 +253,7 @@ void test_enum_bad_variant() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); // Yellow 不存在 arena_destroy(&a); @@ -272,7 +272,7 @@ void test_array_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -289,7 +289,7 @@ void test_array_index_type_error() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); // true 不是 i64 arena_destroy(&a); @@ -306,7 +306,7 @@ void test_array_not_indexable() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); // i64 不是数组 arena_destroy(&a); @@ -323,7 +323,7 @@ void test_array_assign_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -342,7 +342,7 @@ void test_method_call_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -359,7 +359,7 @@ void test_method_undefined() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count > 0); // nope 不是 Point 的方法 arena_destroy(&a); @@ -378,7 +378,7 @@ void test_match_enum_sema_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); // match 去糖后应通过类型检查 arena_destroy(&a); @@ -395,7 +395,7 @@ void test_match_int_sema_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); arena_destroy(&a); @@ -412,7 +412,7 @@ void test_match_wildcard_only_sema_ok() { AstNode* ast = parse(&a, toks, tc, "test", &parse_err); ASSERT(ast != NULL); - ErrorList errors; error_init(&errors); + ErrorList errors; error_init(&errors, &a); sema_analyze(ast, &errors, &a); ASSERT(errors.count == 0); // 纯通配符 match 应通过 arena_destroy(&a);