268 lines
8.9 KiB
Markdown
268 lines
8.9 KiB
Markdown
# L Language 架构分析报告 v0.6.1
|
||
|
||
> 日期: 2026-06-06 06:53 | 自动生成 | **小幅变更**
|
||
> 上次代码基线: `de91886` (2026-06-06 00:50 报告, v0.6)
|
||
> 当前 HEAD: `031dedf` refactor: 拆分 sema analyze_expr 为 9 个辅助函数 + 调度器
|
||
> **版本: v0.6.1** (增量重构, 无功能变更)
|
||
|
||
---
|
||
|
||
## 代码变更检查
|
||
|
||
```
|
||
git log de91886..HEAD → 1 新提交, 2 文件变更, +635/-393 行
|
||
```
|
||
|
||
自 v0.6 以来仅 1 个提交, 聚焦 sema 内部重构。**无新语言特性, 无新增 Token/AST 类型**。
|
||
|
||
| # | 提交 | 类别 |
|
||
|---|------|------|
|
||
| 21 | `031dedf` refactor: 拆分 sema analyze_expr | 重构 |
|
||
|
||
**变更范围**: 仅 [sema.c](D:\Code\doing_exercises\programs\L Language\src\sema\sema.c) + 本报告。
|
||
|
||
---
|
||
|
||
## 1. 当前架构快照 (v0.6.1)
|
||
|
||
### 1.1 编译流水线
|
||
|
||
```
|
||
源码(.l) → Lexer(词法) → Parser(语法) → Sema(语义) → Codegen(LLVM IR) → Target(obj) → clang+lld 链接(.exe)
|
||
58 Token 25 AST 节点 类型标注 LLVMModuleRef .o 文件 优先 clang→fallback gcc
|
||
```
|
||
|
||
流水线拓扑未变。与 v0.6 相同。
|
||
|
||
### 1.2 模块清单与行数
|
||
|
||
| 模块 | 文件 | 行数 | vs v0.6 | 职责 |
|
||
|------|------|------|---------|------|
|
||
| include/ | l_lang.h | 55 | 0 | TypeKind (13), SourceLoc, 公共类型 |
|
||
| lexer/ | lexer.c + token.c (+ .h) | 168+53+47 = 268 | 0 | 手写状态机, 58 Token 类型 |
|
||
| ast/ | ast.c + ast.h | 221+152 = 373 | 0 | 25 种 AST 节点, 工厂函数 |
|
||
| parser/ | parser.c + parser.h | 851+10 = 861 | 0 | 递归下降+Pratt, 去糖逻辑 |
|
||
| sema/ | sema.c + symbol.c (+ .h) | **806**+148+63 = 1017 | **-65** | 类型推断, 9 个辅助函数+调度器 |
|
||
| codegen/ | codegen.c + target.c (+ .h) | 764+30+15 = 809 | 0 | LLVM IR 生成 |
|
||
| driver/ | main.c + error.c (+ .h) | 205+46+18 = 269 | 0 | 流水线串联 |
|
||
| util/ | arena.c + arena.h | 39+13 = 52 | 0 | Bump allocator (8MB) |
|
||
| **实现总计** | | **~3,735 行** | **-34 vs v0.6** | |
|
||
|
||
> sema.c: 871→806 行 (-7.5%), analyze_expr 从 ~380 行单体缩减为 15 行调度器 + 9 个独立辅助函数。
|
||
|
||
### 1.3 核心类型系统
|
||
|
||
| 枚举 | v0.6 | v0.6.1 | 变更 |
|
||
|------|------|--------|------|
|
||
| TypeKind | 13 | 13 | 0 |
|
||
| TokenKind | 58 | 58 | 0 |
|
||
| AstNodeKind | 25 | 25 | 0 |
|
||
| SymbolKind | 5 | 5 | 0 |
|
||
|
||
无新增类型。重构不涉及枚举变更。
|
||
|
||
---
|
||
|
||
## 2. 本轮重构详解: sema analyze_expr 拆分
|
||
|
||
### 2.1 问题背景
|
||
|
||
v0.6 报告中标记为技术债务 #1:
|
||
|
||
> analyze_expr 膨胀 (~380 行) | **高** | 未修复, 反而增加 | sema.c 871 行
|
||
|
||
### 2.2 拆分方案
|
||
|
||
原 `analyze_expr` 是一个 380+ 行的 `switch` 语句, 每种 AST 节点类型的检查逻辑直接内联。本轮重构将其拆分为:
|
||
|
||
| # | 新函数 | 行号 | 职责 |
|
||
|---|--------|------|------|
|
||
| 1 | `analyze_ident_expr` | 58 | 标识符引用类型检查 |
|
||
| 2 | `analyze_unary_expr` | 85 | 一元运算 (`-`, `!`) 类型推导 |
|
||
| 3 | `analyze_binary_expr` | 107 | 二元运算类型检查 + promote |
|
||
| 4 | `analyze_call_expr` | 220 | 函数调用参数/返回值检查 |
|
||
| 5 | `analyze_field_access` | 253 | 结构体字段访问 |
|
||
| 6 | `analyze_struct_init` | 287 | 结构体字面量初始化 |
|
||
| 7 | `analyze_enum_variant` | 333 | 枚举变体初始化 |
|
||
| 8 | `analyze_index_expr` | 352 | 数组索引 |
|
||
| 9 | `analyze_method_call` | 373 | 方法调用 (extend mangle) |
|
||
|
||
`analyze_expr` 现为 15 行调度器:
|
||
|
||
```c
|
||
static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||
switch (node->kind) {
|
||
case AST_LITERAL_EXPR: break;
|
||
case AST_IDENT_EXPR: analyze_ident_expr(node, scope, errors, a); break;
|
||
case AST_UNARY_EXPR: analyze_unary_expr(node, scope, errors, a); break;
|
||
case AST_BINARY_EXPR: analyze_binary_expr(node, scope, errors, a); break;
|
||
case AST_CALL_EXPR: analyze_call_expr(node, scope, errors, a); break;
|
||
case AST_FIELD_ACCESS: analyze_field_access(node, scope, errors, a); break;
|
||
case AST_STRUCT_INIT: analyze_struct_init(node, scope, errors, a); break;
|
||
case AST_ENUM_VARIANT: analyze_enum_variant(node, scope, errors, a); break;
|
||
case AST_INDEX_EXPR: analyze_index_expr(node, scope, errors, a); break;
|
||
case AST_METHOD_CALL: analyze_method_call(node, scope, errors, a); break;
|
||
default: break;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2.3 效果评估
|
||
|
||
| 维度 | 重构前 | 重构后 |
|
||
|------|--------|--------|
|
||
| analyze_expr 行数 | ~380 | 15 (+ 9×30-60 行辅助函数) |
|
||
| 最大函数深度 | 4 层嵌套 switch | 1 层 switch 调度 |
|
||
| 每个 AST 类型可独立修改 | 否 | 是 |
|
||
| 新增 AST 类型成本 | 改动函数中部 | 新增辅助函数 + 添加 case |
|
||
|
||
---
|
||
|
||
## 3. 功能完成度总览 (无变化)
|
||
|
||
### 3.1 P0 (v0.1-v0.4) — 100%
|
||
|
||
全 12 项保持完成状态。
|
||
|
||
### 3.2 P1 (v0.5) — 100%
|
||
|
||
全 6 项保持完成。
|
||
|
||
### 3.3 P0-扩展 (v0.6) — 100%
|
||
|
||
| # | 功能 | 状态 |
|
||
|---|------|------|
|
||
| 13 | i32 / u64 / char 类型 | ✅ |
|
||
| 14 | guard 守卫语句 | ✅ |
|
||
| 15 | 命名参数 | ✅ |
|
||
| 16 | 管道 `|>` | ✅ |
|
||
| 17 | 字符串插值 `\(expr)` | ✅ |
|
||
| 18 | extend 方法块 | ✅ |
|
||
|
||
### 3.4 语法差异化 (无变化)
|
||
|
||
| L 语法 | Rust 对应 |
|
||
|--------|----------|
|
||
| `var` | `let mut` |
|
||
| `T[N]` | `[T; N]` |
|
||
| `to` | `..` |
|
||
| `extend` | `impl` |
|
||
| `guard` | 无 (Swift 灵感) |
|
||
| `|>` | 无 (F#/Elixir 灵感) |
|
||
| `\(expr)` | 无 (Swift 灵感) |
|
||
|
||
---
|
||
|
||
## 4. Rust 对标缺失清单 (无变化)
|
||
|
||
### 4.1 已完成
|
||
|
||
共 15 项, 与 v0.6 报告相同。
|
||
|
||
### 4.2 缺失 (P2 — 中期)
|
||
|
||
| # | 功能 | 预计工时 | 优先级 | Rust 对应 |
|
||
|---|------|---------|--------|----------|
|
||
| 19 | 表达式作为值 (块返回最后表达式) | 2-3 天 | **高** | 块是表达式 |
|
||
| 20 | 枚举关联数据 (ADT) | 2-3 天 | **高** | `enum Option<T>` |
|
||
| 21 | `if let` / `while let` | 1 天 | 中 | 模式匹配简化 |
|
||
| 22 | 模块系统 `mod` + `use` | 3-5 天 | **高** | 多文件编译 |
|
||
| 23 | 泛型 (单态化) | 5-7 天 | 中 | `fn<T>(x: T)` |
|
||
| 24 | trait / 接口 | 5-7 天 | 中 | `trait`, `impl Trait` |
|
||
| 25 | 引用/切片 | 7-10 天 | 中 | `&T`, `&[T]` |
|
||
|
||
### 4.3 缺失 (P3 — 长期)
|
||
|
||
| # | 功能 | 预计工时 | Rust 对应 |
|
||
|---|------|---------|----------|
|
||
| 26 | 所有权 / 借用检查 | 2-4 周 | borrow checker |
|
||
| 27 | 闭包 (lambda) | 3-5 天 | `|x| x+1` |
|
||
| 28 | 自举 | 4-6 周 | — |
|
||
| 29 | 标准库 | 4-6 周 | std |
|
||
|
||
---
|
||
|
||
## 5. 测试覆盖 (无变化)
|
||
|
||
| 测试文件 | 测试函数 | 覆盖范围 |
|
||
|---------|----------|---------|
|
||
| test_lexer.c | 3 | token 识别 |
|
||
| test_parser.c | 5 | 语法解析基本路径 |
|
||
| test_sema.c | 24 | 类型检查 + i32/u64/char + named args + guard + pipe + 插值 |
|
||
| test_codegen.c | 10 | 代码生成 + 隐式转换 |
|
||
| **单元合计** | **42** | |
|
||
| 集成 .l 程序 | **29** | |
|
||
| **测试总计** | **71** | |
|
||
|
||
---
|
||
|
||
## 6. 代码审查
|
||
|
||
### 6.1 本轮重构评价
|
||
|
||
**正面**:
|
||
- analyze_expr 从 380+ 行缩减到 15 行调度器, 可维护性显著提升
|
||
- sema.c 总行数下降 65 行 (871→806), 净减少
|
||
- 每个 AST 类型的类型检查逻辑可独立修改/测试
|
||
- 新增 AST 类型时只需新增辅助函数 + 添加 case, 改动范围可控
|
||
|
||
**保留问题**:
|
||
- 辅助函数间仍有重复模式 (如错误格式化), 但规模不大暂不构成负担
|
||
- 辅助函数的参数签名统一 (`node, scope, errors, a`), 风格一致
|
||
|
||
### 6.2 其他无变化区域
|
||
|
||
- parser.c 仍是 851 行单文件, 去糖逻辑散落 (技术债务 #2)
|
||
- codegen.c 764 行, 未变化
|
||
- TypeKind 耦合未改善 (技术债务 #4)
|
||
- AST Visitor 缺失 (技术债务 #5)
|
||
|
||
---
|
||
|
||
## 7. 技术债务更新
|
||
|
||
### 7.1 已解决
|
||
|
||
| # | 原问题 | 解决提交 |
|
||
|---|--------|---------|
|
||
| 1 | **analyze_expr 膨胀 (~380 行)** | `031dedf` |
|
||
|
||
### 7.2 当前债务 (优先级排序)
|
||
|
||
| # | 问题 | 严重度 | 现状 |
|
||
|---|------|--------|------|
|
||
| 1 | parser.c 单文件 851 行 | **高** | 未修复 |
|
||
| 2 | 去糖无独立 pass, 错误消息受损 | **中** | 需求显现 |
|
||
| 3 | codegen.c 764 行, 仍有优化空间 | 中 | 未变化 |
|
||
| 4 | TypeKind 耦合 (改 7+ 文件) | 低 | 未修复 |
|
||
| 5 | AST Visitor 缺失 | 低 | 未修复 |
|
||
| 6 | LLVM 22 无 mem2reg C API | 低 | 平台限制 |
|
||
|
||
> 从 v0.6 报告的 7 项债务 → 6 项, analyze_expr 膨胀已解决。
|
||
|
||
---
|
||
|
||
## 8. 推荐开发路线图 (与 v0.6 一致)
|
||
|
||
### v0.7 (短期, 2-3 天)
|
||
|
||
1. **独立 desugar pass** — 将 guard/pipe/named_args 去糖从 parser 移到独立 pass
|
||
2. **枚举关联数据 (ADT)** — `enum Option { Some(i64), None }`
|
||
3. **表达式作为值** — `let x = if a { 1 } else { 2 }`
|
||
|
||
### v0.8 (中期, 1 周)
|
||
|
||
1. 模块系统 — `mod` + `use` + `pub`
|
||
2. `if let` / `while let`
|
||
3. 标准库起步: `io`, `convert`, `vec`
|
||
|
||
### v0.9 (中期, 1-2 周)
|
||
|
||
1. 泛型 (单态化)
|
||
2. trait / 接口
|
||
3. AST Visitor 宏驱动
|
||
|
||
---
|
||
|
||
*本报告由 Codex 自动生成于 2026-06-06 06:53。自上次代码基线 `de91886` (v0.6) 以来仅 1 个重构提交, 无功能变更。sema analyze_expr 拆分为 9+1 函数结构, 技术债务从 7 项降至 6 项。*
|