From 6b6925b2b8338069066d08bdff624cd2786cc16b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Fri, 5 Jun 2026 20:54:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=91=BD=E5=90=8D=E5=8F=82=E6=95=B0=20?= =?UTF-8?q?draw=5Frect(width:=2010,=20height:=2020)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 142 ++++++++++++++++++++++++++++++++++ src/ast/ast.c | 7 +- src/ast/ast.h | 8 +- src/parser/parser.c | 36 ++++++++- src/sema/sema.c | 66 ++++++++++++++-- src/sema/symbol.c | 10 ++- src/sema/symbol.h | 4 +- test/programs/27_named_args.l | 17 ++++ test/test_codegen.c | 6 +- 9 files changed, 272 insertions(+), 24 deletions(-) create mode 100644 AGENTS.md create mode 100644 test/programs/27_named_args.l diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e8ea546 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,142 @@ +# AGENTS.md + +本文件为 L Language 项目的 Codex 上下文文件,定义项目架构、构建命令、核心 API 和开发约定。 + +## 项目概述 + +L Language v0.5 — C17 实现的静态类型编译型语言,Rust 风格语法,LLVM 22.x 后端。5 阶段流水线:词法 → 语法 → 语义 → IR → 可执行文件。38 单元测试 + 23 集成程序。 + +## 目录结构 + +``` +├── include/l_lang.h TypeKind(10), SourceLoc 公共头文件 +├── src/ +│ ├── lexer/ {token,lexer} 手写状态机, 50 Token 类型 +│ ├── parser/ parser.c 递归下降 + Pratt, 825 行 +│ ├── ast/ ast.{c,h} 25 种 AST 节点 + 工厂函数 +│ ├── sema/ {symbol,sema} 作用域链 + 类型推断 + impl mangle +│ ├── codegen/{codegen,target} LLVM-C API → 目标代码, 824 行 +│ ├── driver/ {main,error} 入口 + 命令行解析 + 错误报告 +│ └── util/ arena.c Bump allocator (8MB) +├── test/ +│ ├── test_{lexer,parser,sema,codegen}.c 单元测试 (38) +│ └── programs/*.l 集成测试 (23) +└── docs/ + ├── PRD.md 产品需求文档 (v0.1) + ├── analysis/ 架构分析报告 + └── architecture-improvements.md +``` + +## 构建命令 + +```powershell +cd build +cmake .. -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH="D:/settings/Language/LLVM" +mingw32-make -j4 +mingw32-make l_lang # 仅编译器 +``` + +## 编译流水线 + +``` +源码(.l) → Lexer → Parser → Sema → Codegen → Target(obj) → GCC 链接(.exe) + 50 Tok 25 AST 类型标注 LLVM IR .o 可执行文件 +``` + +## 核心 API + +```c +// lexer.h — 词法分析 +Token* lex(Arena* a, const char* source, const char* filename, + size_t* count, ErrorInfo* error); + +// parser.h — 语法分析 +AstNode* parse(Arena* a, const Token* tokens, size_t count, + const char* filename, ErrorInfo* error); + +// sema.h — 语义分析 +void sema_analyze(AstNode* ast, ErrorList* errors, Arena* arena); + +// codegen.h — IR 生成 +LLVMModuleRef codegen_module(AstNode* ast, const char* module_name, + const char** error_msg); +``` + +## 类型系统 + +| L 类型 | LLVM 类型 | TypeKind | +|--------|-----------|----------| +| i64 | LLVMInt64Type() | TYPE_I64 | +| f64 | LLVMDoubleType() | TYPE_F64 | +| bool | LLVMInt1Type() | TYPE_BOOL | +| str | LLVMInt8PtrType() | TYPE_STR | +| void | LLVMVoidType() | TYPE_VOID | +| struct | LLVMStructType() | TYPE_STRUCT | +| enum | (i64 常量) | TYPE_ENUM | +| [T; N] | LLVMArrayType() | TYPE_ARRAY | + +## 运算符优先级 (Pratt) + +| 优先级 | 运算符 | +|--------|--------| +| 70 (最高) | `-`(一元负) `!` | +| 60 | `*` `/` `%` | +| 50 | `+` `-` | +| 40 | `==` `!=` `<` `>` `<=` `>=` | +| 30 | `&&` | +| 20 | `\|\|` | + +## 关键架构决策 + +| 决策 | 说明 | +|------|------| +| impl mangle | sema 将 `impl S { fn f }` 改名为 `S$f`,codegen 零修改 | +| match 脱糖 | parser 将 match 转为 let+if-else 链,sema/codegen 完全复用 | +| for 脱糖 | for 转为 let mut+while+assign | +| 复合赋值脱糖 | `x += 1` → `x = x + 1` | +| parse_type_expr 统一 | 所有类型标注经同一函数解析 | +| RAII cleanup_list | 作用域级自动 free,dynamic resize | + +## 版本状态 + +| 指标 | v0.5 | +|------|------| +| 实现代码 | ~3,336 行 | +| Token 类型 | 50 | +| AST 节点 | 25 | +| TypeKind | 10 | +| SymbolKind | 5 (VAR/PARAM/FN/STRUCT/ENUM) | +| P0 完成度 | 4/4 (100%) | +| P1 完成度 | 6/6 (100%) | +| 已知技术债务 | 10 项 | + +## 开发约定 + +- **语言标准**: C17,`-Wall -Wextra -g`,零警告 +- **内存管理**: Token/AST/符号表均在 arena 分配,禁止 malloc/free 散落 +- **错误消息**: 中文,格式 `文件名:行号:列号: 描述` +- **平台**: Windows 11 + MinGW-w64,链接器用 gcc(非 clang) +- **LLVM 路径**: `D:\settings\Language\LLVM`(v22.1.7,C API) +- **去糖优先**: 复杂语法优先在 parser 层去糖为简单原语,减少 sema/codegen 改动 +- **新增功能流程**: lexer token → ast 节点 → parser 解析 → sema 检查 → codegen 生成 → 测试 + +## 测试 + +```powershell +./l_lang_lexer_test.exe # 3 测试 +./l_lang_test.exe # 5 测试 +./l_lang_sema_test.exe # 21 测试 +./l_lang_codegen_test.exe # 9 测试 + +# 集成测试 +Get-ChildItem test/programs/*.l | ForEach-Object { + ./l_lang.exe $_.FullName -o test.exe + ./test.exe +} +``` + +## 当前技术债务 (优先级排序) + +1. **高**: analyze_expr 膨胀 (350+ 行),match/sema 无单元测试 +2. **中**: parser.c 825 行单文件,codegen.c 824 行单文件,match 脱糖在 parser 非独立 pass,`[Point; N]` 未实现 +3. **低**: TypeKind 耦合 (改 7+ 文件),AST Visitor 缺失,CHANGELOG 未更新 v0.4/v0.5,LLVM 22 无 mem2reg C API diff --git a/src/ast/ast.c b/src/ast/ast.c index 5ca1d32..842d2d8 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -110,9 +110,9 @@ AstNode* ast_make_unary(void* alloc, BinaryOp op, AstNode* operand, SourceLoc lo return n; } -AstNode* ast_make_call(void* alloc, const char* name, AstNode** args, size_t count, SourceLoc loc) { +AstNode* ast_make_call(void* alloc, const char* name, AstNode** args, const char** arg_names, size_t count, SourceLoc loc) { NEW(alloc, AST_CALL_EXPR); - n->as.call.name = name; n->as.call.args = args; n->as.call.arg_count = count; + n->as.call.name = name; n->as.call.args = args; n->as.call.arg_names = arg_names; n->as.call.arg_count = count; return n; } @@ -242,11 +242,12 @@ AstNode* ast_make_impl_block(void* alloc, const char* struct_name, AstNode** met } AstNode* ast_make_method_call(void* alloc, AstNode* receiver, const char* method, - AstNode** args, size_t count, SourceLoc loc) { + AstNode** args, const char** arg_names, size_t count, SourceLoc loc) { NEW(alloc, AST_METHOD_CALL); n->as.method_call.receiver = receiver; n->as.method_call.method_name = method; n->as.method_call.args = args; + n->as.method_call.arg_names = arg_names; n->as.method_call.arg_count = count; return n; } diff --git a/src/ast/ast.h b/src/ast/ast.h index cba368e..05c4a3b 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -89,7 +89,7 @@ struct AstNode { // AST_UNARY_EXPR struct { BinaryOp op; struct AstNode* operand; } unary; // AST_CALL_EXPR - struct { const char* name; struct AstNode** args; size_t arg_count; } call; + struct { const char* name; struct AstNode** args; const char** arg_names; size_t arg_count; } call; // AST_LITERAL_EXPR struct { TypeKind lit_type; union { int64_t i64_val; double f64_val; bool bool_val; const char* str_val; }; } literal; // AST_IDENT_EXPR @@ -114,7 +114,7 @@ struct AstNode { // AST_IMPL_BLOCK struct { const char* struct_name; struct AstNode** methods; size_t method_count; } impl_block; // AST_METHOD_CALL - struct { struct AstNode* receiver; const char* method_name; struct AstNode** args; size_t arg_count; } method_call; + struct { struct AstNode* receiver; const char* method_name; struct AstNode** args; const char** arg_names; size_t arg_count; } method_call; } as; }; @@ -138,7 +138,7 @@ AstNode* ast_make_return(void* alloc, AstNode* expr, SourceLoc loc); AstNode* ast_make_expr_stmt(void* alloc, AstNode* expr, SourceLoc loc); AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc); AstNode* ast_make_unary(void* alloc, BinaryOp op, AstNode* operand, SourceLoc loc); -AstNode* ast_make_call(void* alloc, const char* name, AstNode** args, size_t count, SourceLoc loc); +AstNode* ast_make_call(void* alloc, const char* name, AstNode** args, const char** arg_names, size_t count, SourceLoc loc); AstNode* ast_make_literal_i64(void* alloc, int64_t val, SourceLoc loc); AstNode* ast_make_literal_f64(void* alloc, double val, SourceLoc loc); AstNode* ast_make_literal_bool(void* alloc, bool val, SourceLoc loc); @@ -155,6 +155,6 @@ AstNode* ast_make_enum_variant(void* alloc, const char* enum_name, const char* v AstNode* ast_make_index_expr(void* alloc, AstNode* array, AstNode* index, SourceLoc loc); AstNode* ast_make_array_assign(void* alloc, const char* name, AstNode* index, AstNode* value, SourceLoc loc); AstNode* ast_make_impl_block(void* alloc, const char* struct_name, AstNode** methods, size_t count, SourceLoc loc); -AstNode* ast_make_method_call(void* alloc, AstNode* receiver, const char* method, AstNode** args, size_t count, SourceLoc loc); +AstNode* ast_make_method_call(void* alloc, AstNode* receiver, const char* method, AstNode** args, const char** arg_names, size_t count, SourceLoc loc); #endif diff --git a/src/parser/parser.c b/src/parser/parser.c index 8825635..57444bc 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -185,12 +185,25 @@ static AstNode* parse_ident_or_call(Parser* p, ErrorInfo* error) { // 函数调用: name(...) if (match(p, TOK_LPAREN)) { - AstNode* args[16]; int arg_count = 0; + AstNode* args[16]; const char* arg_names[16]; int arg_count = 0; + bool seen_named = false; 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; } + // 命名参数: name: expr + if (peek(p)->kind == TOK_IDENT && (p->tokens[p->pos + 1].kind == TOK_COLON)) { + const Token* aname = advance(p); advance(p); // 跳过标识符和 ':' + arg_names[arg_count] = arena_strdup_impl(p->arena, aname->start, aname->length); + seen_named = true; + } else { + if (seen_named) { + error->message = "命名参数必须放在位置参数之后"; error->filename = p->filename; + error->line = peek(p)->line; error->col = peek(p)->col; return NULL; + } + arg_names[arg_count] = NULL; + } args[arg_count] = parse_expr(p, error); if (!args[arg_count]) return NULL; arg_count++; @@ -200,8 +213,11 @@ static AstNode* parse_ident_or_call(Parser* p, ErrorInfo* error) { 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*)); + const char** name_arr = seen_named + ? memcpy(arena_alloc_impl(p->arena, arg_count * sizeof(const char*)), arg_names, arg_count * sizeof(const char*)) + : NULL; return ast_make_call(p->arena, arena_strdup_impl(p->arena, name->start, name->length), - arg_arr, arg_count, tok_loc(name)); + arg_arr, name_arr, arg_count, tok_loc(name)); } return ast_make_ident(p->arena, arena_strdup_impl(p->arena, name->start, name->length), @@ -245,9 +261,18 @@ static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error // 方法调用: expr.method(args) if (peek(p)->kind == TOK_LPAREN) { advance(p); // 跳过 '(' - AstNode* args[16]; int arg_count = 0; + AstNode* args[16]; const char* arg_names[16]; int arg_count = 0; + bool seen_named = false; 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; } + if (peek(p)->kind == TOK_IDENT && (p->tokens[p->pos + 1].kind == TOK_COLON)) { + const Token* aname = advance(p); advance(p); + arg_names[arg_count] = arena_strdup_impl(p->arena, aname->start, aname->length); + seen_named = true; + } else { + if (seen_named) { error->message = "命名参数必须放在位置参数之后"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; } + arg_names[arg_count] = NULL; + } args[arg_count] = parse_expr(p, error); if (!args[arg_count]) return NULL; arg_count++; @@ -256,7 +281,10 @@ static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error 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)); + const char** name_arr = seen_named + ? memcpy(arena_alloc_impl(p->arena, arg_count * sizeof(const char*)), arg_names, arg_count * sizeof(const char*)) + : NULL; + left = ast_make_method_call(p->arena, left, member_name, arg_arr, name_arr, arg_count, tok_loc(field)); } else { left = ast_make_field_access(p->arena, left, member_name, tok_loc(field)); } diff --git a/src/sema/sema.c b/src/sema/sema.c index 6a73296..26da16e 100644 --- a/src/sema/sema.c +++ b/src/sema/sema.c @@ -191,6 +191,34 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* } break; } + // 命名参数重排序: 将命名 arg 按参数名映射到正确位置 + if (node->as.call.arg_names) { + AstNode* reordered[16] = {0}; + for (size_t i = 0; i < node->as.call.arg_count; i++) { + if (node->as.call.arg_names[i]) { + // 查找参数名匹配 + bool found = false; + for (size_t j = 0; j < sym->param_count; j++) { + if (sym->param_names && sym->param_names[j] && + strcmp(node->as.call.arg_names[i], sym->param_names[j]) == 0) { + reordered[j] = node->as.call.args[i]; + found = true; break; + } + } + if (!found) { + error_add(errors, "", node->loc.line, node->loc.col, + "函数 '%s' 没有名为 '%s' 的参数", + node->as.call.name, node->as.call.arg_names[i]); + node->type.kind = TYPE_ERROR; return; + } + } else { + // 位置参数保持原位 + reordered[i] = node->as.call.args[i]; + } + } + // 填充未指定的命名参数(用 NULL 跳过,后续检查会报错) + memcpy(node->as.call.args, reordered, node->as.call.arg_count * sizeof(AstNode*)); + } for (size_t i = 0; i < node->as.call.arg_count; i++) { analyze_expr(node->as.call.args[i], scope, errors, a); TypeKind actual = node->as.call.args[i]->type.kind; @@ -402,6 +430,31 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* node->as.method_call.arg_count); node->type.kind = TYPE_ERROR; break; } + // 命名参数重排序(同 CALL_EXPR 逻辑) + if (node->as.method_call.arg_names) { + AstNode* reordered[16] = {0}; + for (size_t i = 0; i < node->as.method_call.arg_count; i++) { + if (node->as.method_call.arg_names[i]) { + bool found = false; + for (size_t j = 1; j < sym->param_count; j++) { // skip self + if (sym->param_names && sym->param_names[j] && + strcmp(node->as.method_call.arg_names[i], sym->param_names[j]) == 0) { + reordered[j - 1] = node->as.method_call.args[i]; + found = true; break; + } + } + if (!found) { + error_add(errors, "", node->loc.line, node->loc.col, + "方法 '%s' 没有名为 '%s' 的参数", + node->as.method_call.method_name, node->as.method_call.arg_names[i]); + node->type.kind = TYPE_ERROR; return; + } + } else { + reordered[i] = node->as.method_call.args[i]; + } + } + memcpy(node->as.method_call.args, reordered, node->as.method_call.arg_count * sizeof(AstNode*)); + } // 对每个参数进行类型检查(跳过 self 参数,即 sym->param_types[0] 是 self 的类型) for (size_t i = 0; i < node->as.method_call.arg_count; i++) { analyze_expr(node->as.method_call.args[i], scope, errors, a); @@ -530,10 +583,12 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* for (size_t i = 0; i < node->as.program.fn_count; i++) { AstNode* fn = node->as.program.functions[i]; TypeKind* pts = (TypeKind*)arena_alloc_impl(a, fn->as.function.param_count * sizeof(TypeKind)); + const char** pnames = (const char**)arena_alloc_impl(a, fn->as.function.param_count * sizeof(const char*)); const char** pstruct_names = (const char**)arena_alloc_impl(a, fn->as.function.param_count * sizeof(const char*)); for (size_t j = 0; j < fn->as.function.param_count; j++) { TypeKind pt = fn->as.function.params[j]->as.parameter.type; const char* psn = fn->as.function.params[j]->as.parameter.struct_type_name; + const char* pn = fn->as.function.params[j]->as.parameter.name; // 解析参数类型的别名 if (psn) { Symbol* as = scope_lookup(scope, psn); @@ -543,6 +598,7 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* } } pts[j] = pt; + pnames[j] = pn; pstruct_names[j] = psn; } // 解析返回类型的别名 @@ -557,7 +613,7 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* } scope_insert_function(scope, a, fn->as.function.name, ret_t, ret_sn, - pts, pstruct_names, + pts, pnames, pstruct_names, fn->as.function.param_count); } // 第三遍:分析每个函数体 @@ -840,13 +896,13 @@ void sema_analyze(AstNode* ast, ErrorList* errors, Arena* arena) { // 注册内置函数 TypeKind params_i64[] = {TYPE_I64}; - scope_insert_function(global_scope, arena, "print_i64", TYPE_VOID, NULL, params_i64, NULL, 1); + scope_insert_function(global_scope, arena, "print_i64", TYPE_VOID, NULL, params_i64, NULL, NULL, 1); TypeKind params_f64[] = {TYPE_F64}; - scope_insert_function(global_scope, arena, "print_f64", TYPE_VOID, NULL, params_f64, NULL, 1); + scope_insert_function(global_scope, arena, "print_f64", TYPE_VOID, NULL, params_f64, NULL, NULL, 1); TypeKind params_bool[] = {TYPE_BOOL}; - scope_insert_function(global_scope, arena, "print_bool", TYPE_VOID, NULL, params_bool, NULL, 1); + scope_insert_function(global_scope, arena, "print_bool", TYPE_VOID, NULL, params_bool, NULL, NULL, 1); TypeKind params_str[] = {TYPE_STR}; - scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, NULL, params_str, NULL, 1); + scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, NULL, params_str, NULL, NULL, 1); analyze_node(ast, global_scope, errors, arena); } diff --git a/src/sema/symbol.c b/src/sema/symbol.c index 50b4759..4097247 100644 --- a/src/sema/symbol.c +++ b/src/sema/symbol.c @@ -30,7 +30,7 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name, if (!sym) return NULL; sym->name = name; sym->kind = kind; sym->type = type; sym->is_mut = false; sym->return_type = TYPE_VOID; - sym->param_types = NULL; sym->param_count = 0; + sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0; sym->struct_field_names = NULL; sym->struct_field_types = NULL; sym->struct_field_count = 0; @@ -46,7 +46,8 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name, Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name, TypeKind ret, const char* ret_struct_name, - TypeKind* pt, const char** pstruct_names, size_t pc) { + TypeKind* pt, const char** pnames, + const char** pstruct_names, size_t pc) { if (scope->head) { for (Symbol* sym = scope->head; sym; sym = sym->next) { if (strcmp(sym->name, name) == 0) return NULL; @@ -58,6 +59,7 @@ Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name, sym->return_type = ret; sym->return_struct_type_name = ret_struct_name; sym->param_types = pt; + sym->param_names = pnames; sym->param_struct_names = pstruct_names; sym->param_count = pc; sym->struct_field_names = NULL; @@ -85,7 +87,7 @@ Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name, if (!sym) return NULL; sym->name = name; sym->kind = SYM_STRUCT; sym->type = TYPE_STRUCT; sym->is_mut = false; sym->return_type = TYPE_VOID; - sym->param_types = NULL; sym->param_count = 0; + sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0; sym->struct_field_names = fnames; sym->struct_field_types = ftypes; sym->struct_field_struct_names = fstruct_names; @@ -130,7 +132,7 @@ Symbol* scope_insert_enum(Scope* scope, void* alloc, const char* name, if (!sym) return NULL; sym->name = name; sym->kind = SYM_ENUM; sym->type = TYPE_ENUM; sym->is_mut = false; sym->return_type = TYPE_VOID; - sym->param_types = NULL; sym->param_count = 0; + sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0; sym->struct_field_names = vnames; sym->struct_field_types = NULL; sym->struct_field_struct_names = NULL; diff --git a/src/sema/symbol.h b/src/sema/symbol.h index 4777274..4afd344 100644 --- a/src/sema/symbol.h +++ b/src/sema/symbol.h @@ -15,6 +15,7 @@ typedef struct Symbol { TypeKind return_type; const char* return_struct_type_name; // 返回类型为 struct 时的类型名 TypeKind* param_types; + const char** param_names; // 参数名(用于命名参数匹配) const char** param_struct_names; // 参数为 struct 时的类型名 size_t param_count; // 结构体特有(SYM_STRUCT) @@ -52,7 +53,8 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name, // 插入函数符号 Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name, TypeKind ret, const char* ret_struct_name, - TypeKind* pt, const char** pstruct_names, size_t pc); + TypeKind* pt, const char** pnames, + const char** pstruct_names, size_t pc); // 插入结构体符号 Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name, diff --git a/test/programs/27_named_args.l b/test/programs/27_named_args.l new file mode 100644 index 0000000..084ba50 --- /dev/null +++ b/test/programs/27_named_args.l @@ -0,0 +1,17 @@ +fn draw_rect(x: i64, y: i64, w: i64, h: i64) -> i64 { + print_i64(x); + print_i64(y); + print_i64(w); + print_i64(h); + return 0; +} + +fn main() -> i64 { + // 位置参数 + draw_rect(0, 0, 100, 200); + + // 命名参数(任意顺序) + draw_rect(w: 10, h: 20, x: 1, y: 2); + + return 0; +} diff --git a/test/test_codegen.c b/test/test_codegen.c index 80eeff5..313494d 100644 --- a/test/test_codegen.c +++ b/test/test_codegen.c @@ -258,7 +258,7 @@ void test_codegen_enum() { AstNode* c_ident = ast_make_ident(&a, "c", loc_at(1, 1)); c_ident->type.kind = TYPE_ENUM; AstNode* args[] = { c_ident }; - AstNode* print_call = ast_make_call(&a, "print_i64", args, 1, loc_at(1, 1)); + AstNode* print_call = ast_make_call(&a, "print_i64", args, NULL, 1, loc_at(1, 1)); /* return 0; */ AstNode* ret = ast_make_return(&a, ast_make_literal_i64(&a, 0, loc_at(1, 1)), loc_at(1, 1)); @@ -323,7 +323,7 @@ void test_codegen_array() { // print_i64(arr[0]); AstNode* args[] = { idx_expr }; - AstNode* print_call = ast_make_call(&a, "print_i64", args, 1, loc_at(1, 1)); + AstNode* print_call = ast_make_call(&a, "print_i64", args, NULL, 1, loc_at(1, 1)); // return 0; AstNode* ret = ast_make_return(&a, ast_make_literal_i64(&a, 0, loc_at(1, 1)), loc_at(1, 1)); @@ -393,7 +393,7 @@ void test_codegen_method_call() { 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)); + AstNode* method_call = ast_make_method_call(&a, p_ident, "get_x", NULL, 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));