Files
l-language/docs/analysis/architecture-analysis-report-2026-06-05-1152.md
T
Serendipity b390d390f3 feat: 结构体 struct — 最后一项 P0 功能
- lexer: TOK_STRUCT, TOK_DOT 关键字和运算符
- ast: AST_STRUCT_DECL/STRUCT_INIT/FIELD_ACCESS 3 种新节点
- parser: struct 声明 + .field 访问 + Name{field:val} 初始化
- sema: struct 类型符号表,字段类型解析,初始化字段检查
- codegen: LLVMStructType + extractvalue/insertvalue 字段操作
- 新增集成测试: 12_struct.l, 13_struct_nested.l
- 基于 Codex 分析报告 P0 #4

所有 P0 功能已全部完成。
2026-06-05 12:21:22 +08:00

348 lines
15 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.3 — 无代码变更)
> 日期: 2026-06-05 11:52 | 自动生成 | 自上次源代码基线无变更
> 上次代码分析基线: `382cd08` (2026-06-05 08:29 报告)
> 当前 HEAD: `620cec4` (CHANGELOG 更新 v0.3.0)
---
## 变更摘要 (自上次代码基线)
**源代码无变更。**`382cd08` 以来,仅有 2 个纯文档提交 (`620cec4`)
| 文件 | 变更 | 行数 |
|------|------|------|
| CHANGELOG.md | 新增 v0.3.0 条目 (for 循环 + 测试补全 + Known Issues) | +14 |
| docs/analysis/architecture-analysis-report-2026-06-05-0703.md | 上一轮自动化分析报告提交 | +288 |
**结论**: 编译器源代码、测试代码、构建系统均无变化。本次运行与 08:29 报告相比,唯一差异是 CHANGELOG v0.3.0 已正式提交(上次报告列为技术债 #8「CHANGELOG 未更新 v0.3」)。
---
## 1. 当前架构全景
### 1.1 编译流水线
```
源码(.l) → Lexer(词法) → Parser(语法) → Sema(语义) → Codegen(LLVM IR) → Target(obj) → GCC 链接(.exe)
Token[] AstNode* 类型标注 LLVMModuleRef .o 文件
```
全流水线 6 个阶段,**无架构变化**。
### 1.2 模块清单与指标
| 模块 | 文件 | 行数 | 关键职责 |
|------|------|------|---------|
| include/ | l_lang.h | 34 | TypeKind 枚举 (7 种), 向前声明, arena_alloc_impl |
| util/ | arena.c(39) + .h(13) | 52 | 8MB bump allocator, strdup |
| lexer/ | lexer.c(137) token.c(45) + .h(40) | 222 | 手写状态机, **37** Token 类型, peek_next |
| ast/ | ast.c(107) ast.h(93) | 200 | **15** 种节点类型, 工厂函数 |
| parser/ | parser.c(390) parser.h(10) | 400 | Pratt 表达式解析 + 递归下降 + for/复合赋值去糖 |
| sema/ | sema.c(294) symbol.c(46) + .h(32) | 372 | 类型推断, 作用域链 (Scope), 可变性检查 |
| codegen/ | codegen.c(421) target.c(30) + .h(15) | 466 | LLVM IR 生成, 4 内置函数, 目标平台初始化 |
| driver/ | main.c(133) error.c(46) + .h(18) | 197 | 流水线串联, CLI (`l_lang <file.l> [-o <out>] [--emit-ir]`), 错误报告 |
| test/ | test_*.c(4 文件) + test_utils.h(23) | 353 | 19 测试函数, 59 断言, 11 集成程序 |
**总计: 23 源文件, 1,688 行实现代码 + 308 行头文件 + 330 行测试 = 2,326 行**
### 1.3 关键架构决策 (v0.2v0.3 沉淀)
| 决策 | 描述 | 技术理由 |
|------|------|---------|
| **去糖策略** | 复合赋值 (`+=` 等) 和 for 循环在 parser 层降级为已有原语 | 零 codegen/sema 入侵, 零新 AST 节点, 降低维护成本 |
| **for 去糖路径** | `for i in 0..5 {body}``let mut i=0; while i<5 {body; i=i+1;}` | 步长固定为 1, 如需自定义步长需扩展语法 |
| **Arena 统一分配** | 编译器内部所有动态内存走 arena bump allocator (8MB) | 零 free 调用, 编译器结束时一次性释放 |
| **LLVM-C API 19.x** | 绑定 LLVM 19.x 的 C API | LLVM 22 移除 mem2reg C API (已记录注释) |
| **GCC 链接** | `system("gcc ...")` 链接目标文件 | 简单但平台绑定 (Windows/MinGW) |
| **Pratt 表达式解析** | 9 级优先级, 零左递归问题 | 比纯递归下降更优雅处理表达式 |
### 1.4 核心数据结构
**Token (37 种)**
```
关键字: fn let mut if else while for in return
类型: i64 f64 bool str void
字面量: 整数 浮点数 true false 字符串
运算符: + - * / % == != < > <= >= && || ! -> .. += -= *= /=
分隔符: ( ) { } , : ; =
特殊: EOF ERROR
```
**AST 节点 (15 种)**
```
Program Function Parameter Block LetStmt AssignStmt IfStmt WhileStmt
ReturnStmt ExprStmt BinaryExpr UnaryExpr CallExpr LiteralExpr IdentExpr
```
**类型系统 (7 种)**
```
TypeKind: I64 F64 BOOL STR VOID UNKNOWN ERROR
转换规则:
隐式: i64 → f64 (算术混合)
显式: 函数参数/返回值必须标注
不可转换: str ↔ 数值, bool ↔ 数值
```
**符号表**
```
Scope (链表栈): 全局 → 函数 → 块
- SymbolKind: VARIABLE | PARAMETER | FUNCTION
- 变量属性: is_mut (可变性)
- 函数属性: return_type + param_types[] + param_count
- 作用域退出时释放 (arena 生命周期管理)
```
---
## 2. 功能清单与成熟度
### 2.1 v0.1 基线功能 (全部完成)
- [x] 基本类型: i64, f64, bool, void
- [x] 算术: + - * / %
- [x] 比较: == != < > <= >=
- [x] 逻辑: && || !
- [x] let 不可变变量, 类型标注 + 类型推断
- [x] 控制流: if/else (含 else if), while, return
- [x] 函数定义与调用, 递归
- [x] 内置函数: print_i64, print_f64, print_bool
- [x] 注释: // 行注释, /* */ 块注释
- [x] 错误报告: 词法/语法即时终止, 语义错误批量输出
### 2.2 v0.2 新增功能 (全部完成)
- [x] let mut 可变变量 + 赋值语句
- [x] 可变性检查 — 不可变变量赋值报编译错误
- [x] 字符串类型 str + 双引号字面量
- [x] print_str 内置函数
- [x] str+str 运行时拼接 (malloc + strlen + memcpy)
- [x] 复合赋值 += -= *= /= (parser 去糖)
- [x] LLVM 目标初始化解耦 (target.h/c)
- [x] codegen malloc → arena 统一
### 2.3 v0.3 新增功能 (全部完成)
- [x] **for 循环 + range**`for i in start..end { ... }`parser 去糖
- [x] **浮点数 lexer 修复**`peek_next``..``.` 冲突
- [x] **sema 测试补全** — +5 测试 (let mut assign, immutable error, str type, str concat)
- [x] **codegen 测试补全** — +1 测试 (while 循环)
- [x] **2 个新集成测试**: `10_for_range.l` (0..5), `11_for_step2.l` (变量边界)
- [x] LLVM 22 mem2reg 不可用注释
- [x] CHANGELOG v0.3.0 提交 (本次运行时已就绪)
---
## 3. 与 Rust 对标: 缺失功能清单及优先级
### P0: 短期 (12 天/项)
| # | 功能 | Rust 启发 | 改动范围 | 状态 |
|---|------|----------|---------|------|
| 1 | 复合赋值 += -= *= /= | 复合赋值运算符 | lexer + parser(desugar) | **✅ v0.2** |
| 2 | str+str 运行时拼接 | — | codegen(malloc/strlen/memcpy) | **✅ v0.2** |
| 3 | for 循环 + range | `for i in 0..10 {}` | lexer + parser(desugar) | **✅ v0.3** |
| 4 | **结构体 struct** | struct 具名域 + GEP | lexer/parser/sema/codegen | **待实施** |
**P0 完成度: 3/4 (75%)**。struct 是解锁复合类型的最后一块 P0 拼图。
### P1: 中期 (35 天/项)
| # | 功能 | 改动范围 | 学习价值 | 状态 |
|---|------|---------|---------|------|
| 5 | 数组 + 索引 `[i64; N]`, `arr[i]` | lexer/parser/sema/codegen(GEP) | GEP 指针计算 | 待实施 |
| 6 | 枚举 (C 风格) | lexer/parser/sema/codegen(i64) | 为代数类型铺路 | 待实施 |
| 7 | match 表达式 | lexer/parser/sema(穷举) + codegen | 模式匹配核心 | 待实施 |
| 8 | 类型别名 `type Meters = i64` | lexer/parser/sema(展开) | 名称等价 vs 结构等价 | 待实施 |
### P2: 中后期 (12 周/项)
| # | 功能 | 学习价值 | 状态 |
|---|------|---------|------|
| 9 | 模块系统 `mod` + `use` | 单文件→多文件编译 | 待实施 |
| 10 | 自定义 IR 层 (三地址码/SSA) | 编译器核心抽象 | 待实施 |
| 11 | 泛型 (单态化) | Rust 零成本抽象基石 | 待实施 |
| 12 | 解释器模式 (walk AST) | 快速验证语义 | 待实施 |
### P3: 长期 (24 周/项)
| # | 功能 | 备注 | 状态 |
|---|------|------|------|
| 13 | trait / 接口 | 需泛型 + 虚表 | 待实施 |
| 14 | Option/Result | 需泛型 + enum | 待实施 |
| 15 | 所有权 / 借用检查 | 极度复杂 | 待实施 |
| 16 | 自举 (L 编译 L) | 终极考验 | 待实施 |
### Rust 设计哲学吸收进度
| Rust 特性 | 状态 | 备注 |
|-----------|------|------|
| 默认不可变 (let vs let mut) | ✅ 已实现 | 编译期检查, 可变性追踪 |
| 复合赋值 | ✅ 已实现 | parser desugar 模式 |
| for + range | ✅ 已实现 | desugar 为 while |
| str 拼接 | ✅ 已实现 | 运行时 malloc |
| 表达式 vs 语句 | ❌ | if/match/block 作为表达式 (目前只支持语句) |
| 模式匹配 | ❌ | P1 优先级 |
| 代数数据类型 | ❌ | 需泛型 |
| 所有权 / 借用 | ❌ | 远期 |
---
## 4. 测试覆盖分析
### 4.1 单元测试
| 测试文件 | 测试函数 | 断言数 | 覆盖范围 |
|---------|----------|--------|---------|
| test_lexer.c | 3 | 14 | token 识别, 关键字, 操作符, 注释 |
| test_parser.c | 5 | 15 | 算术, let, if, while, 函数 |
| test_sema.c | 7 | 21 | 类型错误, 未定义变量, let mut, immutable error, str type, str concat |
| test_codegen.c | 4 | 9 | 简单函数, if/else, 二元运算, while |
| **合计** | **19** | **59** | |
### 4.2 集成测试 (11 程序)
| 文件 | 功能 | 版本 |
|------|------|------|
| 01_arithmetic.l | 算术运算 | v0.1 |
| 02_if_else.l | if/else 控制流 | v0.1 |
| 03_recurse.l | 递归函数 | v0.1 |
| 04_fib_recursive.l | 斐波那契 (递归) | v0.1 |
| 05_float.l | 浮点数 | v0.1 |
| 06_mut_while.l | let mut + while | v0.2 |
| 07_hello_str.l | 字符串输出 | v0.2 |
| 08_str_concat.l | 字符串拼接 | v0.2 |
| 09_compound_assign.l | 复合赋值 | v0.2 |
| 10_for_range.l | for range 循环 | v0.3 |
| 11_for_step2.l | for range (变量边界) | v0.3 |
### 4.3 测试缺口
| 缺口 | 严重度 | 说明 |
|------|--------|------|
| 复合赋值无独立 desugar 测试 | 低 | 仅通过 `09_compound_assign.l` 间接覆盖 |
| for 循环无独立 desugar 测试 | 低 | 仅通过 `10_for_range.l` / `11_for_step2.l` 间接覆盖 |
| codegen 缺 call/str/compound/for 路径 | 中 | 4 测试仅覆盖基础路径: simple, if/else, binary, while |
| parser 缺 for 错误恢复测试 | 低 | 缺少 for/in/.. 错误提示验证 |
| 无 LLVM IR 输出一致性测试 | 低 | 无法检测 LLVM IR 生成回归 |
---
## 5. 技术债务与风险
| # | 问题 | 状态 | 严重度 | 说明 |
|---|------|------|--------|------|
| 1 | str concat malloc 内存泄漏 | **存留** | 中 | x + y 每次 malloc 无 free,编译后程序运行会泄漏 (编译器自身不受影响) |
| 2 | 复合赋值无独立 desugar 测试 | **存留** | 低 | 集成测试间接覆盖 |
| 3 | codegen 测试覆盖率低 (4/9 路径) | **存留** | 中 | call/str/compound/for/return 路径无单元测试 |
| 4 | `system("gcc ...")` 平台绑定 | **存留** | 低 | Windows/MinGW 正常,Linux/Unix 需 `gcc`/`cc` 替换 |
| 5 | LLVM 22 无 mem2reg C API | **已记录** | 低 | codegen.c 注释说明需用 `opt` 工具 |
| 6 | 错误类型分散 (ErrorInfo + ErrorList) | **存留** | 低 | 不影响功能,但 API 不统一 |
| 7 | CHANGELOG 未更新 v0.3 | **✅ 已解决** | — | `620cec4` 提交了 v0.3.0 条目 |
| 8 | parser.c 函数 `parse_function` 过长 | **存留** | 低 | 约 60 行,可拆分为多个子函数 |
| 9 | 无 fuzzing / 边界输入测试 | **新增** | 低 | 超大源文件、超长标识符、深层嵌套等未覆盖 |
### 风险矩阵
| 风险 | 概率 | 影响 | 缓解 |
|------|------|------|------|
| LLVM API 版本升级 break | 中 | 高 | 当前锁定 19.x,文档记录不兼容点 |
| GCC 链接在非 MinGW 环境失败 | 中 | 中 | 可接受链接器参数或使用 LLVM lld |
| Arena 内存耗尽 (8MB) | 极低 | 中 | 巨型程序才触发,编译器中止即可 |
| str 泄漏导致大程序 OOM | 低 | 中 | 短期替代方案: arena 化 str 拼接 |
---
## 6. 推荐开发路线图
### v0.4 目标 (下一迭代)
| 优先级 | 功能 | 预计工时 | 依赖/备注 |
|--------|------|---------|----------|
| **P0** | **结构体 struct** | 2–3 天 | 解锁 GEP 和复合类型,全流水线 |
| P1 | str concat arena 化 (修复技术债 #1) | 0.5 天 | 替换 malloc 为 arena 分配 |
| P1 | codegen 测试扩展 (call/str/for) | 0.5 天 | 覆盖率补偿 |
| P1 | parser 测试补全 (for 错误恢复) | 0.5 天 | 回归保护 |
### v0.5 目标
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P1 | 数组 + 索引 | 2 天 |
| P1 | 枚举 (C 风格) | 1 天 |
| P1 | match 表达式 | 23 天 |
| P1 | 类型别名 | 0.5 天 |
### 长期方向
| 优先级 | 功能 | 预计工时 |
|--------|------|---------|
| P2 | 自定义 IR 层 | 35 天 |
| P2 | 模块系统 | 35 天 |
| P2 | 解释器模式 | 2 天 |
| P3 | 泛型 (单态化) | 57 天 |
| P3 | trait / 接口 | 57 天 |
| P3 | 自举尝试 | 数周 |
---
## 7. 度量汇总
| 指标 | 值 | 较 v0.2 (72a971e) | 较 v0.3 基线 (382cd08) |
|------|-----|-------------------|----------------------|
| 源文件数 (.c) | 12 | — | 无变化 |
| 头文件数 (.h) | 12 | — | 无变化 |
| 实现代码 | 1,688 行 | +52 | 无变化 |
| 头文件 | 308 行 | +23 | 无变化 |
| 测试代码 | 330 行 | +88 | 无变化 |
| 总代码量 | 2,326 行 | +163 | 无变化 |
| Token 类型 | 37 | +3 (FOR/IN/DOT_DOT) | 无变化 |
| AST 节点类型 | 15 | +1 (ASSIGN_STMT) | 无变化 |
| TypeKind | 7 | +2 (STR, ERROR) | 无变化 |
| 内置函数 | 4 (print_i64/f64/bool/str) | +1 (print_str) | 无变化 |
| C 运行时依赖 | printf, malloc, strlen, memcpy | +malloc/strlen/memcpy | 无变化 |
| 单元测试函数 | 19 | +5 | 无变化 |
| 单元测试断言 | 59 | +14 | 无变化 |
| 集成测试程序 | 11 | +2 (for_range, for_step2) | 无变化 |
| P0 完成度 | 3/4 (75%) | +for | 无变化 |
| P0 遗留 | struct | — | 无变化 |
| 编译产物 | 6 个 .exe | — | 无变化 |
| Git 提交数 | 11 | +2 | +1 (CHANGELOG) |
---
## 8. 代码质量评估
### 8.1 模块内聚度
| 模块 | 内聚度 | 评价 |
|------|--------|------|
| lexer | 高 | 纯函数接口,状态机集中在单文件,token 定义与值提取分离 |
| parser | 高 | 递归下降 + Pratt 组合清晰,去糖逻辑局部化 |
| ast | 高 | 工厂函数模式统一,union 节点设计节省内存 |
| sema | 高 | 遍历器模式,analyze_node/analyze_expr 双入口,职责明确 |
| codegen | 中高 | `codegen_stmt` 单一大函数处理所有节点,可拆分但暂不紧急 |
| driver | 中 | main.c 串联流水线,error.c 独立,接口清晰 |
| util | 高 | 单一职责 (arena 分配器),零外部依赖 |
### 8.2 代码风格一致性
- 蛇形命名 (snake_case) 贯穿全部源文件
- 头文件守卫 (`#ifndef X_H` / `#define X_H` / `#endif`) 统一
- 工厂函数模式 (`ast_make_*`) 跨 AST 模块一致
- 错误处理模式: `ErrorInfo*` (即时错误) + `ErrorList*` (批量错误) 两类
### 8.3 编译警告
未在本次运行中编译,但从代码结构推断:
- 全局变量 `_tests_run` / `_tests_failed``test_utils.h``static` 声明 (每个翻译单元独立副本, 跨文件统计不准确)
- `Arena*` 通过 `void*` 跨模块传递 (`arena_alloc_impl(void* alloc, ...)`),丢失类型安全, 但避免了模块间循环依赖
---
*本报告由 Codex 自动生成于 2026-06-05 11:52。自上次代码基线 `382cd08` 后无源代码变更。当前 HEAD `620cec4` 仅增加 CHANGELOG.md v0.3.0 条目 (14 行) + 上一轮分析报告 (288 行)。编译器源码、测试、构建系统均不变。P0 struct 仍为唯一待实施的 P0 功能。*