Files
l-language/docs/analysis/architecture-analysis-report-2026-06-06-0050.md
T

308 lines
13 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 架构分析报告 v0.6
> 日期: 2026-06-06 00:50 | 自动生成 | **重大代码变更**
> 上次代码基线: `a15cd9d` (2026-06-05 17:08 报告, v0.5)
> 当前 HEAD: `de91886` fix: CreateProcess 替代 system() 调 ld.lld,消除 shell 转义问题
> **版本: v0.6**
---
## 代码变更检查
```
git log a15cd9d..HEAD → 20 新提交, 36 文件变更, +2483/-163 行
```
自 v0.5 以来累计 20 个提交,涵盖 6 个新语言特性、语法差异化调整、链接器重构、安装包系统。
详细提交链:
| # | 提交 | 类别 |
|---|------|------|
| 1-2 | CHANGELOG/语言参考文档 | 文档 |
| 3-4 | CLAUDE.md 语言设计哲学 | 文档 |
| 5 | 数组初始化 `= arr` 语法说明 | 文档 |
| 6 | match/sema 单元测试 (145→158) | 测试 |
| 7 | 数组支持 struct 元素类型 `Point[N]` | P1-5 修复 |
| 8 | 测试计数更新 145→158 + 23→24 | 测试 |
| 9 | for..in 范围语法 `..``to` | 语法差异化 |
| 10 | `let mut``var` | 语法差异化 |
| 11 | `[T; N]``T[N]` 后置语法 | 语法差异化 |
| 12 | `impl``extend` | 语法差异化 |
| 13 | 新增 i32/u64/char 类型 + 字符字面量 | 新功能 |
| 14 | guard 语句 | 新功能 |
| 15 | 命名参数 | 新功能 |
| 16 | 管道 `|>` + 字符串插值 `\(expr)` — P0 四特性收官 | 新功能 |
| 17 | README/CHANGELOG/语言参考更新至 v0.6 | 文档 |
| 18 | 链接器 gcc → clang + lld | 基础设施 |
| 19 | NSIS 安装包脚本 | 基础设施 |
| 20 | CreateProcess 替代 system() 调 ld.lld | 基础设施 |
---
## 1. 当前架构快照 (v0.6)
### 1.1 编译流水线
```
源码(.l) → Lexer(词法) → Parser(语法) → Sema(语义) → Codegen(LLVM IR) → Target(obj) → clang+lld 链接(.exe)
58 Token 25 AST 节点 类型标注 LLVMModuleRef .o 文件 优先 clang→fallback gcc
```
v0.5 的 GCC 链接器已被 clang + lld 替代(自动 fallback)。`system()` 调用被 `CreateProcess` 替代,消除 shell 转义问题。
### 1.2 模块清单与行数
| 模块 | 文件 | 行数 | vs v0.5 | 职责 |
|------|------|------|---------|------|
| include/ | l_lang.h | 55 | -2 | TypeKind (13), SourceLoc, 公共类型 |
| lexer/ | lexer.c + token.c (+ .h) | 168+53+47 = 268 | +11 | 手写状态机, 58 Token 类型 |
| ast/ | ast.c + ast.h | 221+152 = 373 | -31 | 25 种 AST 节点, 工厂函数 (arg_names 扩展) |
| parser/ | parser.c + parser.h | 851+10 = 861 | +23 | 递归下降+Pratt, guard/pipe/插值去糖 |
| sema/ | sema.c + symbol.c (+ .h) | 871+148+63 = 1082 | +77 | 类型推断, can_implicit_convert, 命名参数重排 |
| codegen/ | codegen.c + target.c (+ .h) | 764+30+15 = 809 | -55 | LLVM IR 生成, coerce_int 隐式转换 |
| driver/ | main.c + error.c (+ .h) | 205+46+18 = 269 | +58 | 流水线串联, CreateProcess 链接 |
| util/ | arena.c + arena.h | 39+13 = 52 | 不变 | Bump allocator (8MB) |
| **实现总计** | | **~3,769 行** | **+434 vs v0.5** | |
> 注意: codegen.c 从 824 行收缩到 764 行(-7.3%),说明新加入的 pipe/guard/插值等功能去糖后不需要 codegen 层改动。
### 1.3 核心类型系统变化
| 枚举 | v0.5 | v0.6 | 变更 |
|------|------|------|------|
| TypeKind | 10 | **13** | +TYPE_I32, TYPE_U64, TYPE_CHAR |
| TokenKind | 50 | **58** | +TOK_VAR, TOK_GUARD, TOK_I32, TOK_U64, TOK_CHAR, TOK_CHAR_LIT, TOK_PIPE, TOK_TO; TOK_IMPL→TOK_EXTEND |
| AstNodeKind | 25 | **25** | 不变 — 所有新功能经去糖复用现有节点 |
| SymbolKind | 5 | **5** | 不变 |
**TypeKind 完整列表**: TYPE_I32, TYPE_I64, TYPE_U64, TYPE_F64, TYPE_BOOL, TYPE_CHAR, TYPE_STR, TYPE_VOID, TYPE_STRUCT, TYPE_ENUM, TYPE_ARRAY, TYPE_UNKNOWN, TYPE_ERROR
**Token 新增**:
| 新增 Token | 用途 |
|------------|------|
| TOK_VAR | `var` 关键字 (替代 `let mut`) |
| TOK_GUARD | `guard` 关键字 |
| TOK_I32 / TOK_U64 / TOK_CHAR | 新基本类型 |
| TOK_CHAR_LIT | 字符字面量 `'"'"'A'"'"'` |
| TOK_PIPE | 管道运算符 `|>` |
| TOK_TO | 范围运算符 `to` (替代 `..`) |
| TOK_EXTEND | `extend` 关键字 (替代 `impl`) |
**AST 结构体扩展**:
- `AST_CALL_EXPR.call` 新增 `arg_names` 字段 — 支持命名参数
- `AST_METHOD_CALL.method_call` 新增 `arg_names` 字段 — 支持命名参数
- `AST_LITERAL_EXPR.literal` 新增 `lit_type` + union 扩展 — 支持 char 字面量
**Symbol 扩展**:
- `Symbol.param_names` 新增 — 支持命名参数匹配
---
## 2. 功能完成度总览
### 2.1 P0 (v0.1-v0.4) — 100%
全 12 项保持完成状态。
### 2.2 P1 (v0.5) — 100%
全 6 项保持完成,P1-5 (数组 struct 元素类型) 在本轮修复。
### 2.3 P0-扩展 (v0.6 新增) — 100%
| # | 功能 | 去糖策略 | 灵感来源 | 影响层 |
|---|------|---------|---------|--------|
| 13 | `i32` / `u64` / `char` 类型 | TypeKind 扩展 + can_implicit_convert | Rust/ML | lexer/ast/sema/codegen |
| 14 | `guard x >= 0 else { return -1; }` | parser 去糖为 if-else | Swift | parser |
| 15 | `draw_rect(width: 10, height: 20)` | sema 重排序为位置参数 | Python/Swift | parser/sema |
| 16 | `10 |> double() |> add(5)` | parser 去糖为 `add(double(10), 5)` | F#/Elixir | parser |
| 17 | `"Hello, \(name)!"` | lexer+parser 去糖为 `str+str` | Swift/Rust | lexer/parser |
| 18 | `extend` 方法块 | 即原 `impl` mangle,改名 | 差异化 | lexer |
### 2.4 语法差异化 (L 语言独有)
| L 语法 | Rust 对应 | 理由 |
|--------|----------|------|
| `var` | `let mut` | 更简洁,2 字符 vs 6 字符 |
| `T[N]` | `[T; N]` | C 风格直觉,减少括号 |
| `to` | `..` | 明确语义 (省略终值 `to` vs 闭区间 `..=`) |
| `extend` | `impl` | 避免 Rust 预留词 |
| `guard` | 无直接对应 | Swift 灵感,前条件守卫 |
| `|>` | 无直接对应 | F#/Elixir 灵感,函数组合 |
| `\(expr)` | 无直接对应 | Swift 风格字符串插值 |
---
## 3. Rust 对标缺失清单
### 3.1 已完成
| 特性 | 状态 | 版本 |
|------|------|------|
| 默认不可变 (let) / 可变 (var) | ✅ | v0.1-v0.6 |
| 复合赋值 | ✅ | v0.2 |
| for + range | ✅ | v0.3 |
| struct 具名域 | ✅ | v0.4 |
| impl/extend 方法 | ✅ | v0.5 |
| enum + match | ✅ | v0.5 |
| 类型别名 | ✅ | v0.5 |
| 数组固定大小 | ✅ | v0.5 |
| 数组 struct 元素类型 | ✅ | v0.6 |
| RAII 自动释放 | ✅ | v0.4 |
| 命名参数 | ✅ | v0.6 |
| 管道运算符 | ✅ | v0.6 |
| 字符串插值 | ✅ | v0.6 |
| guard 守卫语句 | ✅ | v0.6 |
| i32/u64/char 多种整数类型 | ✅ | v0.6 |
### 3.2 缺失 (P2 — 中期, 按难度排序)
| # | 功能 | 预计工时 | 优先级 | Rust 对应 | 说明 |
|---|------|---------|--------|----------|------|
| 19 | 表达式作为值 (块返回最后表达式) | 2-3 天 | **高** | 块是表达式 | sema/codegen 需处理块类型推断, 当前 block→void |
| 20 | 枚举关联数据 (ADT) | 2-3 天 | **高** | `enum Option<T>` | 当前仅简单常量枚举, 需 payload + 模式匹配扩展 |
| 21 | `if let` / `while let` | 1 天 | 中 | `if let Some(x) = opt` | 基于枚举关联数据 |
| 22 | 模块系统 `mod` + `use` | 3-5 天 | **高** | `mod`, `use`, `pub` | 多文件编译, 符号可见性 |
| 23 | 泛型 (单态化) | 5-7 天 | 中 | `fn<T>(x: T)` | sema 类型参数收集, codegen 复制 |
| 24 | trait / 接口 | 5-7 天 | 中 | `trait`, `impl Trait` | vtable 或单态化分派 |
| 25 | 引用/切片 | 7-10 天 | 中 | `&T`, `&[T]` | 需指针层次, 生命周期标注 |
### 3.3 缺失 (P3 — 长期)
| # | 功能 | 预计工时 | Rust 对应 |
|---|------|---------|----------|
| 26 | 所有权 / 借用检查 | 2-4 周 | borrow checker |
| 27 | 闭包 (lambda) | 3-5 天 | `|x| x+1` |
| 28 | 自举 (L 编译 L) | 4-6 周 | — |
| 29 | 标准库 (prelude) | 4-6 周 | std |
---
## 4. 测试覆盖
| 测试文件 | 测试函数 | vs v0.5 | 覆盖范围 |
|---------|----------|---------|---------|
| test_lexer.c | 3 | 不变 | token 识别 |
| test_parser.c | 5 | 不变 | 语法解析基本路径 |
| test_sema.c | 24 | +3 | i32/u64/char 转换, named args, guard, 管道, 插值 |
| test_codegen.c | 10 | +1 | 隐式转换, 命名参数, i32/u64/char codegen |
| **单元合计** | **42** | **+4** | |
| 集成 .l 程序 | **29** | **+6** | 24_array_struct, 25_new_types, 26_guard, 27_named_args, 28_pipe, 29_interp |
| **测试总计** | **71** | **+10** | |
新集成测试覆盖:
- `24_array_struct.l` — struct 数组 (P1-5 修复验证)
- `25_new_types.l` — i32/u64/char 类型 + 隐式转换
- `26_guard.l` — guard 守卫语句
- `27_named_args.l` — 命名参数任意顺序
- `28_pipe.l` — 管道 |> 函数组合
- `29_interp.l` — 字符串插值
---
## 5. 代码审查 — 风险区域
### 5.1 去糖策略的评价
v0.6 延续了 v0.5 的去糖哲学: pipe/guard/插值/named_args 全在 parser 层去糖为现有 AST 节点。优势是 sema/codegen 改动极小(codegen 甚至缩水 60 行),但代价是:
1. **parser.c 进一步膨胀**: 825→851 行,去糖逻辑散落在 `parse_expr``parse_statement` 之间
2. **错误消息质量下降**: 去糖后生成的 AST 丢失原始语法信息,错误报告指向去糖后的 if-else 而非原始 `guard` 语句
3. **调试/IR 可读性**: 用户写 `10 |> double()` 但 IR 中看到的是 `double(10)`,不利于学习
**建议**: v0.7 考虑将 guard/match/named_args/pipe 去糖抽取为独立 desugar pass,在 parser 生成 AST 之后、sema 之前运行。这既能保持"去糖"优势,又能改善错误消息质量。
### 5.2 sema.c 持续膨胀
sema.c 从 809→871 行 (v0.5→v0.6)analyze_expr 仍然是单函数怪兽 (~380 行)。新增的 `can_implicit_convert()` 是好的模块化进步,但类型检查逻辑仍需拆分。
### 5.3 TypeKind 耦合未改善
TypeKind 从 10 增加到 13,修改范围涉及 7+ 文件。加新类型仍是全局搜索替换作业。
### 5.4 链接器变更风险
gcc→clang+lld 变更是正确方向,但 fallback 链 (clang→gcc) 增加了 CI 配置复杂度。自包含安装包 (39MB) 和 NSIS 安装包 (62MB) 是两个并行方案,后续需统一。
---
## 6. 技术债务更新
### 6.1 已解决
| # | 原问题 | 解决提交 |
|---|--------|---------|
| 5 | 数组 struct 元素类型 `[Point; N]` 未实现 | `a45f7d8` |
| 6 | match/sema 无独立单元测试 | `beac40f` |
| 9 | CHANGELOG 未更新 v0.4/v0.5 | `5a0bf60` + `2baf762` |
### 6.2 当前债务 (优先级排序)
| # | 问题 | 严重度 | 现状 | 备注 |
|---|------|--------|------|------|
| 1 | analyze_expr 膨胀 (~380 行) | **高** | 未修复, 反而增加 | sema.c 871 行, +62 vs v0.5 |
| 2 | parser.c 单文件 851 行 | **高** | 未修复, +26 行 | 去糖逻辑散落 |
| 3 | 去糖无独立 pass, 错误消息受损 | **中** | 需求显现 | v0.6 新暴露 |
| 4 | codegen.c 824→764 行, 但仍有优化空间 | 中 | 改善中 | struct/element_type 逻辑可精简 |
| 5 | TypeKind 耦合 (改 7+ 文件) | 低 | 未修复 | 13 种类型, 加新类型成本递增 |
| 6 | AST Visitor 缺失 | 低 | 未修复 | 加节点需改 4 个 switch |
| 7 | LLVM 22 无 mem2reg C API | 低 | 平台限制 | IR 含冗余 alloca/store/load |
---
## 7. 基础设施变更
| 组件 | v0.5 | v0.6 | 影响 |
|------|------|------|------|
| 链接器 | GCC (外部依赖) | clang + lld (优先), fallback gcc | 用户需安装 LLVM 或将 ld.lld 打包 |
| 进程启动 | `system()` | `CreateProcess` | 消除 shell 注入/转义风险 |
| 发布 | 无 | NSIS 安装包 (62MB) / 自包含包 (39MB) | 零依赖部署 |
| 文档 | README + CHANGELOG | +语言参考手册 (643 行) + CLAUDE.md | 开发者友好 |
---
## 8. 与 PRD 对照
PRD v0.1 设定了"学习编译器全流程"的短期目标。对照 PRD 中的非目标列表:
| PRD 非目标 (v0.1 不做) | 当前状态 |
|------------------------|---------|
| 字符串类型 | ✅ v0.2 实现 `str` |
| 数组/切片/结构体 | ✅ v0.4-v0.5 实现 struct/array |
| 模块系统 | ❌ 仍缺失 |
| 泛型/trait | ❌ 仍缺失 |
| 模式匹配 | ✅ v0.5 match (简化) |
| 标准库 | ❌ 仍缺失 |
| 垃圾回收 | ❌ 不做 (采用 RAII) |
v0.6 已大幅超出 v0.1 PRD 范围。建议更新 PRD 到 v0.6 以反映当前功能边界。
---
## 9. 推荐开发路线图
### v0.7 (短期, 2-3 天)
1. **独立 desugar pass** — 将 guard/pipe/named_args 去糖从 parser 移到独立 pass,改善错误消息和 parser 复杂度
2. **analyze_expr 拆分** — 按节点类型拆分为 4-6 个辅助函数
3. **枚举关联数据 (ADT)**`enum Option { Some(i64), None }`,打开类型安全编程新范式
4. **表达式作为值**`let x = if a { 1 } else { 2 }`,函数体最后表达式即返回值
### v0.8 (中期, 1 周)
1. **模块系统**`mod` + `use` + `pub`,多文件编译
2. `if let` / `while let` — 简化 ADT 匹配
3. 标准库起步: `io`, `convert`, `vec`
### v0.9 (中期, 1-2 周)
1. 泛型 (单态化)
2. trait / 接口
3. AST Visitor 宏驱动
---
*本报告由 Codex 自动生成于 2026-06-06 00:50。自上次代码基线 `a15cd9d` (v0.5) 以来共 20 个提交, +2483/-163 行。P0 扩展 6 个新特性全部实现, 语法完成差异化定型, 链接器/进程启动基础设施升级。v0.7 应聚焦 parser 结构优化和枚举 ADT。*