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

8.9 KiB
Raw Blame History

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 行调度器:

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 灵感)
` >`
\(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 天 `
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 项。