# L Language 架构改进路线图 > 2026-06-05 | 基于架构审查报告 --- ## 1. TypeKind 耦合问题 (HIGH) **当前状态**: 新增一个类型需要修改 7+ 个文件。 ``` TypeKind 修改 → l_lang.h (枚举 + type_name switch) → token.h (TokenKind 枚举) → token.c (tok_is_type) → lexer.c (KW 宏) → parser.c (is_type_token + token_to_type) → sema.c (promote, is_numeric, 各运算符类型检查) → codegen.c (to_llvm_type, to_llvm_const) ``` **建议方案**: 引入类型注册表。 ```c // types.h typedef struct { const char* name; // "i64" TypeKind kind; // TYPE_I64 TokenKind tok; // TOK_I64 LLVMTypeRef (*to_llvm)(LLVMContextRef); // 代码生成回调 bool is_numeric; // 可用于算术 bool is_comparable; // 可用于比较 bool promote_to; // 可隐式转换的目标类型 } TypeDef; // 集中定义所有类型 static const TypeDef TYPES[] = { { "i64", TYPE_I64, TOK_I64, /*...*/, .is_numeric=true, .is_comparable=true }, { "f64", TYPE_F64, TOK_F64, /*...*/, .is_numeric=true, .is_comparable=true }, { "bool", TYPE_BOOL, TOK_BOOL, /*...*/, .is_comparable=true }, { "str", TYPE_STR, TOK_STR, /*...*/ }, { "void", TYPE_VOID, TOK_VOID, /*...*/ }, }; ``` 加新类型只需往 `TYPES[]` 数组加一行。预计改动量: 新增 types.h/c,各模块改为查表。工时: 2 天。 --- ## 2. AST Visitor 模式缺失 (HIGH) **当前状态**: 每个模块手写 switch-case 遍历 AST。新 AST 节点需要修改所有 switch。 ``` 新节点 AstNewNode → sema.c:analyze_expr() switch → sema.c:analyze_node() switch → codegen.c:codegen_expr() switch → codegen.c:codegen_stmt() switch 至少 4 处 ``` **建议方案**: 宏驱动的 Visitor。 ```c // ast_visitor.h #define AST_VISIT_CASES(V) \ V(AST_PROGRAM) V(AST_FUNCTION) V(AST_PARAMETER) \ V(AST_BLOCK) V(AST_LET_STMT) V(AST_ASSIGN_STMT) \ ... // sema.c switch (node->kind) { #define V(k) case k: analyze_##k(node, scope, errors); break; AST_VISIT_CASES(V) #undef V } ``` 更完整的方案: 传函数指针的 `ast_walk(AstNode*, Visitor* v)` 接口。工时: 3 天。 --- ## 3. SourceLoc 抽象缺失 (HIGH) **当前状态**: 每个 AST 工厂函数有独立的 `int line, int col` 参数。 ```c // 当前: 参数膨胀 AstNode* ast_make_let(void* alloc, const char* name, TypeKind annot_type, bool has_type_annot, bool is_mut, AstNode* init, int line, int col); // 8 个参数 // 建议: SourceLoc 聚合 typedef struct { int line; int col; const char* file; } SourceLoc; AstNode* ast_make_let(void* alloc, const char* name, TypeKind annot_type, bool has_type_annot, bool is_mut, AstNode* init, SourceLoc loc); // 7 个参数 ``` 额外收益: 错误报告可以统一使用 `SourceLoc`,不再分别传 file/line/col。工时: 1 天。 --- ## 4. 去糖逻辑应独立 (MEDIUM) **当前状态**: for 循环和复合赋值的去糖逻辑直接在 `parser.c` 中。 ``` parser.c:parse_statement() ├── TOK_FOR → 直接构造 let mut + while + assign AST (~60行) └── TOK_IDENT += → 直接构造 assign(binary) AST (~25行) ``` **建议方案**: 独立 `parser_desugar.c` pass。 ```c // parser_desugar.h AstNode* desugar(AstNode* raw_ast, Arena* a, ErrorInfo* error); // 职责: 将 FOR_STMT、COMPOUND_ASSIGN 等语法糖节点 // 转换为已有原语节点 (let mut + while + assign 等) // 在 sema 之前运行 ``` 架构收益: - parser.c 保持纯解析逻辑,缩短 ~85 行 - 去糖逻辑可独立测试 - 新增语法糖只需改 desugar.c,不动 parser 工时: 1 天。 --- ## 5. tok_is_type 重复定义 (MEDIUM) **当前状态**: ```c // token.c:34 bool tok_is_type(TokenKind kind) { return kind == TOK_I64 || kind == TOK_F64 || kind == TOK_BOOL || kind == TOK_VOID; } // parser.c:236 — 完全相同的逻辑 static bool is_type_token(TokenKind k) { return k == TOK_I64 || k == TOK_F64 || k == TOK_BOOL || k == TOK_VOID || k == TOK_STR; } ``` 两处不同步 (parser 多了 TOK_STR,token 少了 TOK_STR)。若加 TOK_U8 很可能只改一处。 **修复**: 删除 `is_type_token()`,统一使用 `tok_is_type()`,并在 token.c 中补上 TOK_STR。工时: 10 分钟。 --- ## 6. 实施优先级 | 优先级 | 项目 | 工时 | 收益 | |--------|------|------|------| | 1 | tok_is_type 统一 | 10 分钟 | 消除 bug 源 | | 2 | SourceLoc 抽象 | 1 天 | 减少参数,可加文件名 | | 3 | 去糖独立 pass | 1 天 | parser 解耦 | | 4 | TypeDef 注册表 | 2 天 | 新类型本地化 | | 5 | AST Visitor | 3 天 | 新节点安全 | 建议 v0.5 按 1→2→3 顺序,v0.6 做 4→5。