Files
l-language/docs/analysis/architecture-analysis-report-2026-06-05-1509.md
T
Serendipity 5a0bf60698 docs: CHANGELOG v0.4/v0.5 + README/CLAUDE 版本刷新
- CHANGELOG: 新增 v0.4.0 (struct+RAII) 和 v0.5.0 (alias+enum+array+impl+match)
- README: 版本0.5.0, 测试145, 完整功能列表+运算符表
- CLAUDE: v0.5 已知限制更新
2026-06-05 18:42:24 +08:00

418 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# L Language 架构分析报告 — P1 全线收官 + match 表达式 (v0.5)
> 日期: 2026-06-05 15:09 | 自动生成 | **有源代码变更**
> 上次代码分析基线: `1d4fb27` (2026-06-05 13:08 报告, v0.4)
> 当前 HEAD: `a15cd9d` feat: match 表达式 (P1 #8 收官)
>
> 新增提交 (自上次源代码基线 `1d4fb27`):
> - `af0725c` fix: 全面代码审查 — 修复 3 CRITICAL + 4 HIGH 问题
> - `a7fca59` fix: 5项立即修复 + 2项尽快修复
> - `4046ab1` refactor: tok_is_type 统一 + 架构改进文档
> - `da9a706` feat: struct参数/返回值 + SourceLoc + 测试补全 (**P1 #5 完成**)
> - `ab88ea2` feat: 类型别名 type alias (**P1 #10 完成**)
> - `5237398` feat: 枚举 enum (**P1 #7 完成**)
> - `2923e75` feat: 数组+索引 [T;N], arr[i] (**P1 #6 完成**)
> - `9f6e695` feat: struct方法 impl (**P1 #9 完成**)
> - `a15cd9d` feat: match 表达式 (**P1 #8 收官**)
**本次是自 v0.4 以来最大规模的变更: 9 个提交, P1 全部 6 项需求一次性落地。**
---
## 变更摘要 (自上次代码基线)
**27 个文件变更, +2596 / -284 行。** P1 路线图全覆盖:
| 变更类别 | 详情 | 影响范围 |
|---------|------|---------|
| **P1 #5: struct 参数/返回值** | parser 扩展 param/return type 解析; SourceLoc 抽象落地 | parser/sema/codegen/driver |
| **P1 #10: 类型别名** | `type Meters = i64;` / `type P = Point;` 全流水线 | parser/sema(alias 展开链) |
| **P1 #7: 枚举 enum** | `enum Color { Red, Green, Blue }`, `Color::Green` 变体 | lexer/parser/sema/codegen |
| **P1 #6: 数组+索引** | `let arr: [i64; 3]`, `arr[i]`, `arr[i] = expr` | lexer/parser/sema/codegen(GEP) |
| **P1 #9: struct 方法 impl** | `impl Point { fn get_x(self: Point) ... }`, `p.method()` 调用 | parser/sema(改名 mangle)/codegen |
| **P1 #8: match 表达式** | `match x { pat => { body } _ => { body } }`, parser 脱糖 | parser(desugar 为 let+if-else) |
| **基础设施重构** | SourceLoc 抽象, tok_is_type 统一, 架构改进文档, CRITICAL bug 修复 | 全项目 |
| **测试扩展** | sema: 9→21 tests; codegen: 4→9 tests; 集成: 13→23 programs | test/ |
---
## 1. 当前架构全景
### 1.1 编译流水线
```
源码(.l) → Lexer(词法) → Parser(语法) → Sema(语义) → Codegen(LLVM IR) → Target(obj) → GCC 链接(.exe)
50 Token 25 AST 节点 类型标注 LLVMModuleRef .o 文件
```
**流水线结构无变化**,但数据流丰富度大幅提升: AST 节点从 18 增至 25, Token 从 39 增至 50, TypeKind 从 8 增至 10。
### 1.2 模块清单与指标
| 模块 | 关键职责 | 本次变更 |
|------|---------|---------|
| include/ | TypeKind 枚举 (10 种: +TYPE_ENUM, +TYPE_ARRAY), SourceLoc 抽象 | +15 行 |
| lexer/ | 手写状态机, **50** Token 类型 | +38 行 |
| ast/ | **25** 种节点类型 (+7: TYPE_ALIAS, ENUM_DECL, ENUM_VARIANT, INDEX_EXPR, ARRAY_ASSIGN, IMPL_BLOCK, METHOD_CALL) | +218 行 |
| parser/ | 递归下降 + Pratt, 新增 enum/impl/type/match 解析, `parse_type_expr()` 统一类型表达式 | +425 行 |
| sema/ | 类型推断, 5 种 SymbolKind (+SYM_ENUM), impl 方法改名 mangle, alias 展开链 | +542 行 |
| codegen/ | LLVM struct/array/enum/match, GEP, method call, 清理表动态扩容 | +269 行 |
| driver/ | 流水线串联, SourceLoc 适配 | +11 行 |
| test/ | **30** 单元测试函数 (+11), 10 集成程序新增 | +636 行 |
| 汇总指标 | 上次 (v0.4, 1d4fb27) | **当前 (v0.5, a15cd9d)** | Δ |
|---------|----------------------|-------------------|----|
| 实现代码 (.c) | 2,221 行 | **~3,480 行** | +~1,259 |
| 头文件 (.h) | 323 行 | **~450 行** | +~127 |
| 测试代码 | 361 行 | **~997 行** | +636 |
| **总代码量** | **2,905 行** | **~4,927 行** | **+2,022** |
| Token 类型 | 39 | **50** | +11 |
| AST 节点类型 | 18 | **25** | +7 |
| TypeKind | 8 | **10** | +2 |
| SymbolKind | 4 | **5** | +1 |
| 单元测试函数 | 19 | **30** | +11 |
| 集成测试程序 | 13 | **23** | +10 |
| P0 完成度 | 4/4 (100%) | 4/4 (100%) | — |
| P1 完成度 | 0/6 (0%) | **6/6 (100%)** | ✅ |
| Git 提交数 | 13 | **22** | +9 |
### 1.3 关键架构决策 (v0.5 新增)
| 决策 | 描述 | 技术理由 |
|------|------|---------|
| **impl 改名 mangle** | `impl Point { fn get_x }` 在 sema 阶段将函数名改为 `Point$get_x`, 自动插入 self 参数 | 零入侵 codegen: 方法调用退化为普通函数调用 |
| **match 脱糖为 let+if-else** | parser 阶段将 match 转为 `{ let __match_val=expr; if ... else ... }` | 复用现有 if-else codegen, 零新增 LLVM IR 路径 |
| **数组类型自引用声明** | `let arr: [i64; 3] = arr;` 以自身标识符为初始化占位符 | ArrayType 固定大小, sema/codegen 识别 TYPE_ARRAY 标注后跳过 init 分析 |
| **parse_type_expr 统一入口** | 所有类型标注解析通过同一函数 | 消除分散类型解析, 支持 `[T; N]` 嵌套 |
| **cleanup_list 动态扩容** | 从固定 64 槽改为 realloc 式动态扩容 (16→x2) | 消除溢出风险 |
| **SourceLoc 聚合** | `typedef struct { int line; int col; }` 替代所有 `int line, int col` 参数对 | 减少参数数量, 为后续添加 `file` 做准备 |
---
## 2. P1 全线功能详解
### 2.1 struct 作为函数参数/返回值 (P1 #5)
parser 的 `parse_function` 参数类型解析从 `token_to_type()` 改为 `parse_type_expr()`, 支持 `fn f(p: Point) -> Point`。Codegen 中 struct 参数通过 alloca+store 转为栈变量, struct 返回值通过直接值传递 (LLVM struct 类型)。
**测试**: `14_struct_fn.l` — Point 作为参数和返回值。
### 2.2 类型别名 type alias (P1 #10)
`parse_type_expr()` 识别 `TOK_IDENT` 时查找已注册别名; sema Pass 0 提前注册所有别名。
```
语法: type Meters = i64;
type P = Point;
别名展开链:
parser: 解析 `let x: P` → annot struct_type_name="P"
sema: scope_lookup("P") → 别名符号 → 获取真实 type=STRUCT/struct_type_name="Point"
```
**测试**: `15_type_alias.l`, `16_type_alias_struct.l`
### 2.3 枚举 enum (P1 #7)
新增 TOK_ENUM/TOK_COLON_COLON Token; `AST_ENUM_DECL`/`AST_ENUM_VARIANT` AST 节点; SYM_ENUM SymbolKind。枚举变体映射为 i64 常量 (0, 1, 2...)。
```
语法: enum Color { Red, Green, Blue }
let c = Color::Green; // codegen: LLVMConstInt(LLVMInt64Type, 1)
```
**测试**: `17_enum.l`, sema: test_enum_ok/test_enum_bad_variant
### 2.4 数组 + 索引 (P1 #6)
新增 `[i64; N]` 语法 (`parse_type_expr` 中解析), `AST_INDEX_EXPR` (读取), `AST_ARRAY_ASSIGN_STMT` (写入)。
```
语法: let arr: [i64; 3] = arr;
arr[0] = 10;
print_i64(arr[0]);
Codegen: LLVMArrayType(elem_ty, N) → alloca → GEP(0, i) → load/store
索引值 i64 → i32 截断 (LLVM GEP 要求 i32)
```
**测试**: `18_array.l`, sema 4 测试, codegen: test_codegen_array
### 2.5 struct 方法 impl (P1 #9)
`parse` 处理 `impl StructName { ... }` 块; sema 将方法函数名改为 `StructName$methodName` 并追加 self 参数。
```
语法: impl Point {
fn get_x(self: Point) -> i64 { return self.x; }
}
p.get_x(); // AST_METHOD_CALL
Mangle 流程:
parser: impl → AST_IMPL_BLOCK { struct_name, methods }
sema: 遍历 impl → 改名 "Point$get_x", 插入前导 self 参数, 追加到 functions 数组
codegen: find_fn("Point$get_x") + call(receiver, args...) — 退化为普通函数调用
```
**测试**: `19_struct_method.l`, sema 2 测试, codegen: test_codegen_method_call
### 2.6 match 表达式 (P1 #8)
新增 TOK_MATCH/TOK_MATCH_ARROW/TOK_UNDERSCORE Token; parser 内 `parse_match_stmt()` 将 match 脱糖为 let+if-else 链。
```
语法: match expr {
pat1 => { body1; }
_ => { default_body; }
}
脱糖逻辑 (parser 阶段):
match c { Color::Green => { print_i64(20); } _ => { print_i64(0); } }
→ {
let __match_val = c;
if __match_val == Color::Green { print_i64(20); }
else { print_i64(0); }
}
臂数 64 上限, 从最后一个臂往前构建 if-else 链
```
**关键设计**: match 不产生新 AST 节点 — 直接生成 AST_BLOCK + AST_LET_STMT + AST_IF_STMT 链; codegen/sema 零改动。
**测试**: 4 个集成测试 (`20_match.l`~`23_match_wildcard.l`)
---
## 3. 架构重构与基础设施
### 3.1 SourceLoc 抽象
```c
// include/l_lang.h
typedef struct { int line; int col; } SourceLoc;
```
所有 AST 工厂函数从 `int line, int col` 参数对改为 `SourceLoc loc` 单参数。全模块已适配。
### 3.2 tok_is_type 统一
删除 parser.c 中重复的 `is_type_token()` 函数, 统一使用 `token.c:tok_is_type()` (已补 TOK_STR)。
### 3.3 CRITICAL Bug 修复清单
| 严重度 | 问题 | 修复 |
|--------|------|------|
| CRITICAL | parser `parse_struct_init` 字段名数组栈变量悬垂 | arena 分配 + memcpy |
| CRITICAL | codegen 隐式尾部 return 缺 struct 类型处理 | 添加 `LLVMConstNull(st_ty)` |
| CRITICAL | str 字面量 tok 未 NUL 终止 | arena_strdup + `\0` |
| HIGH | codegen return 前 cleanup 可能 free 返回值 | 从 cleanup_list 移除 |
| HIGH | match 通配符 if-else 链条件 | `if (true) { body }` |
| HIGH | sema impl 处理 `new_fns` 数组大小计算时机 | 预先统计 extra_fn |
---
## 4. 功能清单与成熟度
### 4.1 已实现功能 (全版本)
- [x] v0.1: 基本类型/算术/控制流/函数/内置函数/类型推断
- [x] v0.2: let mut/赋值/str/字符串拼接/复合赋值
- [x] v0.3: for + range
- [x] v0.4: struct 声明+初始化+字段访问/嵌套结构体/RAII 自动内存管理
- [x] **v0.5: P1 全线 — struct 参数/返回值/类型别名/枚举/数组+索引/impl 方法/match 表达式**
### 4.2 当前已知限制
| 限制 | 严重度 | 说明 |
|------|--------|------|
| 数组不支持 struct 元素类型 `[Point; N]` | 中 | parse_type_expr TYPE_ARRAY 路径未传 element_struct_name |
| enum 无关联数据 (代数数据类型) | 中 | 仅 C 风格枚举 |
| 无表达式作为值 (expression-oriented) | 中 | if/match/block 不能出现在表达式位置 |
| match 仅单值匹配 | 低 | 不支持 range pattern / guard |
| 数组声明自引用语法 `let arr: [i64; 3] = arr;` | 低 | 必须写两遍 arr |
| 无字符串方法 (len/slice) | 低 | str 仅拼接+打印 |
---
## 5. 与 Rust 对标: 缺失功能清单及优先级
### 已完成 (P0 + P1 全通过)
| # | 功能 | Rust 启发 | 版本 |
|---|------|----------|------|
| P0-1~4 | 复合赋值/str拼接/for+range/struct | — | v0.2v0.4 |
| P1-5 | struct 参数/返回值 | 值语义 | v0.5 |
| P1-6 | 数组+索引 | `[T; N]`, `arr[i]` | v0.5 |
| P1-7 | 枚举 | enum | v0.5 |
| P1-8 | match 表达式 | 模式匹配 (简化) | v0.5 |
| P1-9 | struct 方法 | impl block | v0.5 |
| P1-10 | 类型别名 | type alias | v0.5 |
### P2: 中后期
| # | 功能 | 预计工时 | 状态 |
|---|------|---------|------|
| 11 | 表达式作为值 (expression-oriented) | 23 天 | 待实施 |
| 12 | 模块系统 `mod` + `use` | 35 天 | 待实施 |
| 13 | 泛型 (单态化) | 57 天 | 待实施 |
| 14 | 枚举关联数据 (代数数据类型) | 2 天 | 待实施 |
| 15 | trait / 接口 | 57 天 | 待实施 |
### P3: 长期
| # | 功能 | 预计工时 |
|---|------|---------|
| 16 | 所有权 / 借用检查 | 2–4 周 |
| 17 | 自举 (L 编译 L) | 46 周 |
| 18 | 标准库 (prelude) | 46 周 |
### Rust 设计哲学吸收进度
| Rust 特性 | 状态 | 备注 |
|-----------|------|------|
| 默认不可变 (let vs let mut) | ✅ | 编译期检查 |
| 复合赋值 | ✅ | parser desugar |
| for + range | ✅ | desugar 为 while |
| struct 具名域 | ✅ | LLVM 命名结构体 |
| impl 方法 | ✅ | sema mangle |
| enum + match (简化) | ✅ | C 风格枚举 + 单值 match |
| 类型别名 | ✅ | alias 展开链 |
| 数组固定大小 | ✅ | GEP |
| RAII 自动释放 | ✅ | cleanup_list |
| 表达式 vs 语句 | ❌ | P2 优先 |
| 代数数据类型 | ❌ | P2 优先 |
| 泛型 (单态化) | ❌ | P2 优先 |
| trait / 接口 | ❌ | P2 优先 |
| 所有权 / 借用 | ❌ | P3 |
| 模块系统 | ❌ | P2 优先 |
---
## 6. 测试覆盖分析
### 6.1 单元测试
| 测试文件 | 测试函数 | 覆盖范围 |
|---------|----------|---------|
| test_lexer.c | 3 | token 识别, 关键字, 操作符, 注释 |
| test_parser.c | 5 | 算术, let, if, while, 函数 |
| test_sema.c | **21** (+12) | 类型错误, let mut, str, struct 字段, 类型别名, enum, 数组, 方法调用 |
| test_codegen.c | **9** (+5) | 基础路径, struct decl/field, enum, array, method call |
| **合计** | **38** (+11) | |
### 6.2 集成测试 (23 程序)
- 0111: v0.1v0.3 基线
- 1213: struct + 嵌套 struct (v0.4)
- **1423**: v0.5 新增 10 程序 (struct_fn/type_alias/enum/array/struct_method/4×match)
### 6.3 测试缺口
| 缺口 | 严重度 |
|------|--------|
| match/sema 无独立单元测试 | 高 |
| 数组 struct 元素类型无测试 | 中 |
| RAII + 新功能交互无验证 | 中 |
| parser 错误恢复无测试 | 低 |
---
## 7. 技术债务与风险
| # | 问题 | 严重度 | 说明 |
|---|------|--------|------|
| 1 | analyze_expr 持续膨胀 (200+→350+ 行) | 高 | ENUM_VARIANT/INDEX_EXPR/METHOD_CALL 等 |
| 2 | parser.c 单文件 939 行 | 中 | +415 行: enum/impl/type/match/match 脱糖 |
| 3 | codegen.c 单文件 854 行 | 中 | 3 个 switch 持续增长 |
| 4 | match 脱糖在 parser, 非独立 pass | 中 | arch-improvements #4 建议未实施 |
| 5 | 数组 struct 元素类型未实现 | 中 | `[Point; N]` |
| 6 | TypeKind 耦合 (arch-improvements #1) | 低 | 加新类型需改 7+ 文件 |
| 7 | AST Visitor 缺失 (arch-improvements #2) | 低 | 加新节点需改 4 个 switch |
| 8 | CHANGELOG 未更新 v0.4/v0.5 | 低 | 仅到 v0.3 |
| 9 | LLVM 22 无 mem2reg C API | 低 | 已记录 |
| 10 | `system("gcc ...")` 平台绑定 | 低 | Windows/MinGW |
---
## 8. 推荐开发路线图
### v0.6 目标 (下一迭代, 23 天)
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P1 | parser 独立 desugar pass (for/match/compound assign) | 0.5 天 |
| P1 | 数组 struct 元素类型 `[Point; N]` | 0.5 天 |
| P1 | match/sema 单元测试 | 0.5 天 |
| P2 | CHANGELOG 更新 v0.4/v0.5 | 0.5 天 |
### v0.7 目标
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P2 | 表达式作为值 (expression-oriented) | 23 天 |
| P2 | 枚举关联数据 | 2 天 |
| P2 | AST Visitor 宏驱动 | 2 天 |
### 长期方向
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P2 | 模块系统 / 泛型 / trait | 各 37 天 |
| P3 | 所有权 / 自举 / 标准库 | 2–6 周 |
---
## 9. 代码质量评估
### 9.1 模块内聚度
| 模块 | 评价 |
|------|------|
| lexer | 高 — 11 新 Token 一字插入 |
| parser | **中** — +415 行, parse_match_stmt(80行) + parse_type_expr(40行) + impl/enum/type 内联 |
| ast | 高 — 7 新节点遵循工厂函数模式 |
| sema | **中高** — +542 行: impl mangle/alias 展开/enum/array/method 语义; analyze_expr switch 350+ 行 |
| codegen | **中** — +269 行: enum/array/index/method/match; 3 个 switch 持续增长 |
| driver | 高 — 仅 SourceLoc 适配 |
| util | 高 — 无变更 |
### 9.2 代码风格亮点
- **impl mangle 设计**: sema 阶段转换, codegen 零修改 — 干净解耦
- **match 脱糖**: 转为 AST 原语链, sema/codegen 完全复用 (但耦合在 parser 中)
- **parse_type_expr 统一**: 消除分散类型解析, 天然支持 `[T; N]`
- **cleanup_list 动态扩容**: arena 分配保持 zero-overhead
### 9.3 架构债务
| 债务 | 说明 |
|------|------|
| parser.c 939 行 | 含 enum/impl/type/match + 脱糖, 建议 P2 模块化 |
| sema analyze_expr 350+ 行 | CASE 从 5 增至 10 |
| codegen 3 个 switch 增长 | 新增 3 case (ENUM_VARIANT/METHOD_CALL/INDEX_EXPR) |
| impl mangle 隐式命名约定 | codegen 通过 `$` 识别方法, 非结构化标记 |
---
## 10. 度量汇总 (对比)
| 指标 | v0.4 (1d4fb27) | **v0.5 (a15cd9d)** | Δ |
|------|----------------|-------------------|----|
| 实现代码 | 2,221 行 | **~3,480 行** | +~1,259 |
| 头文件 | 323 行 | **~450 行** | +~127 |
| 测试代码 | 361 行 | **~997 行** | +636 |
| **总代码量** | **2,905 行** | **~4,927 行** | **+2,022** |
| Token 类型 | 39 | **50** | +11 |
| AST 节点类型 | 18 | **25** | +7 |
| TypeKind | 8 | **10** | +2 |
| SymbolKind | 4 | **5** | +1 |
| 单元测试函数 | 19 | **30** | +11 |
| 集成测试程序 | 13 | **23** | +10 |
| P0 完成度 | 4/4 (100%) | 4/4 (100%) | — |
| P1 完成度 | 0/6 (0%) | **6/6 (100%)** | ✅ |
| Git 提交数 | 13 | **22** | +9 |
---
*本报告由 Codex 自动生成于 2026-06-05 15:09。自上次代码基线 `1d4fb27` (v0.4) 后有 9 个源代码提交 (+2596/-284 行): P1 路线图全线收官 — struct 参数/返回值、类型别名、枚举、数组+索引、struct 方法 impl、match 表达式全部落地。v0.5 实现了 Rust 启发语言的完整单片编译器能力; 下一迭代应关注 parser 独立 desugar pass、数组 struct 元素类型补全、表达式作为值。*