7.8 KiB
7.8 KiB
L Language 架构与代码审查报告
日期: 2026-06-07 | 全面手动审查 | HEAD:
35e2691
1. 项目概览
| 指标 | 数值 |
|---|---|
| 版本 | v0.6 |
| 语言 | C17 (-Wall -Wextra -g) |
| 后端 | LLVM 22.x C API |
| 链接器 | clang+lld (fallback gcc) |
| 平台 | Windows 11 + MinGW-w64 |
| 总源码行数 | 5,039 (32 .c + 20 .h) |
| 单元测试 | 197 断言 (4 文件, 42 测试函数) |
| 集成测试 | 36 程序 |
| 构建警告 | 0 |
2. 编译流水线
源码(.l) → Lexer → Parser(+Desugar) → Sema → Codegen → Target → clang+lld → .exe
72 Token 27 AST 节点 类型标注 LLVM IR .o 文件 可执行文件
2.1 各阶段文件清单
| 阶段 | 文件 | 行数 | 职责 |
|---|---|---|---|
| include/ | l_lang.h | 55 | TypeKind 枚举 (14), TypeInfo, SourceLoc |
| lexer/ | lexer.c (180) + token.c (60) + .h (55+13) | 308 | 手写状态机, 72 Token 类型 |
| parser/ | parser.c (564) + expr.c (484) + desugar.c (109) + parse_internal.h (71) + .h (13+30) | 1,271 | 递归下降+Pratt, 5 种去糖独立化 |
| ast/ | ast.c (284) + ast.h (183) + visit.c (17) + visit.h (25) | 509 | 27 AST 节点 + 工厂函数 + Visitor dispatch |
| sema/ | typeck.c (652) + sema.c (500) + symbol.c (172) + type_table.c (36) + .h (57+84+22) | 1,535 | 类型推断+检查, 泛型单态化, 数据驱动类型表 |
| codegen/ | codegen.c (453) + cg_expr.c (440) + target.c (35) + .h (83+15+21) | 1,047 | LLVM IR 生成, 目标输出, 符号表 |
| driver/ | main.c (232) + error.c (49) + .h (26) | 307 | 流水线串联, 错误报告 |
| util/ | arena.c (45) + arena.h (17) | 62 | Bump allocator (8MB) |
2.2 文件大小分布
所有核心 .c 文件均 ≤ 652 行(限制 800):
typeck.c 652 ████████████████████
parser.c 564 █████████████████
sema.c 500 ████████████████
expr.c 484 ███████████████
codegen.c 453 ██████████████
cg_expr.c 440 ██████████████
3. 类型系统
3.1 Token 类型: 72 种
| 类别 | 数量 | 示例 |
|---|---|---|
| 关键字 | 20 | fn, let, var, if, else, while, for, in, return, guard, struct, type, enum, extend, match, pub, mod, use, trait, Self |
| 类型 | 8 | i32, i64, u64, f64, bool, char, str, void |
| 字面量 | 6 | INT_LIT, FLOAT_LIT, CHAR_LIT, true, false, STR_LIT |
| 标识符 | 2 | IDENT, UNDERSCORE |
| 算术 | 5 | + - * / % |
| 比较 | 6 | == != < > <= >= |
| 逻辑 | 4 | && || |> ! |
| 箭头 | 3 | -> to => |
| 复合赋值 | 4 | += -= *= /= |
| 括号 | 4 | ( ) { } |
| 方括号 | 2 | [ ] |
| 分隔符 | 4 | , : ; = |
| 特殊 | 4 | . :: EOF ERROR |
3.2 TypeKind: 14 种
- 内置: i32, i64, u64, f64, bool, char, str, void
- 复合: struct, enum, array
- 内部: GENERIC (泛型参数), UNKNOWN (未推断), ERROR (类型错误)
3.3 TypeTable 数据驱动
type_table.c 统一管理类型元数据(promote_rank, bit_width, is_signed, is_numeric),promote/can_implicit_convert/is_numeric/is_comparable 全部查表。新增类型只需在 TABLE[] 加一行。
4. AST 节点: 27 种
| 类别 | 节点 |
|---|---|
| 程序结构 | PROGRAM, FUNCTION, PARAMETER, BLOCK, MOD_DECL, USE_DECL |
| 语句 | LET_STMT, ASSIGN_STMT, IF_STMT, WHILE_STMT, RETURN_STMT, EXPR_STMT, ARRAY_ASSIGN_STMT |
| 表达式 | BINARY_EXPR, UNARY_EXPR, CALL_EXPR, LITERAL_EXPR, IDENT_EXPR, FIELD_ACCESS, INDEX_EXPR, METHOD_CALL |
| 类型/声明 | STRUCT_DECL, STRUCT_INIT, TYPE_ALIAS, ENUM_DECL, ENUM_VARIANT, IMPL_BLOCK, TRAIT_DECL |
新增节点流程:ast.h 加枚举 → ast.c 加工厂 → typeck.c 的 analyze_expr_init() 加一行 handler → 编译器检查未初始化的函数指针。
5. 已实现功能
5.1 P0 基础 (10 项)
基础类型 (i64/f64/bool/void), 控制流 (if/else/while/return), let/var 变量, str 类型+拼接, for..in 去糖, struct 声明+初始化+字段访问
5.2 P1 类型与抽象 (5 项)
type 别名, enum 声明+变体, 固定数组+索引, impl/extend 方法块, match 去糖
5.3 P0 扩展 (5 项)
i32/u64/char, guard 守卫, 命名参数, 管道 |>, 字符串插值
5.4 P2 (6 项) — 全部完成
ADT 枚举关联数据, 表达式作为值 (if-expr), if let, 模块系统 (mod), 泛型单态化, trait 接口
6. 测试覆盖
| 测试文件 | 函数 | 断言 | 覆盖范围 |
|---|---|---|---|
| test_lexer.c | 3 | 41 | 基础 token, 关键字, 运算符 |
| test_parser.c | 20 | 54 | 全语法特性 |
| test_sema.c | 24 | 74 | 类型检查, 错误检测 |
| test_codegen.c | 10 | 28 | LLVM IR 生成验证 |
| 单元合计 | 57 | 197 | |
| programs/*.l | — | 36 | 端到端集成 |
全部通过,零失败,零构建警告。
7. 近期重构成果
| 重构 | 效果 |
|---|---|
| parser.c 1211→564+484+109 | 表达式/语句/去糖分离 |
| sema.c 1129→500+652 | 入口/表达式检查分离 |
| codegen.c 947→453+440 | 语句/表达式生成分离 |
| desugar.c 独立化 | match/guard/for/if-let/复合赋值 5 种去糖提取 |
| TypeTable 数据驱动 | promote/convert/numeric 查表,新增类型 7→3-4 文件 |
| AST Visitor dispatch | analyze_expr switch→vtable,新增节点加一行 |
| error.c arena 化 | 消除项目唯一 malloc/realloc/strdup |
| test_parser.c 5→20 函数 | 15→54 断言,覆盖全语法特性 |
8. 代码质量
8.1 优点
- 零编译警告:
-Wall -Wextra干净 - 全测试通过: 197 单元 + 36 集成
- 内存管理统一: 全部通过 Arena bump allocator,无散落 malloc/free(除 driver 文件读取)
- 文件大小受控: 所有核心 .c ≤ 652 行
- 模块边界清晰: 5 阶段流水线,内部头文件隔离实现细节
- 新增类型/节点低摩擦: TypeTable 一行注册,Visitor 一行注册
- 去糖独立化: 5 种语法糖从 parser 内联提取为纯函数,可独立测试
- LLVM 22 适配: 显式 Context 管理,CreateProcess 替代 system()
8.2 待改进
| # | 严重度 | 位置 | 问题 | 建议 |
|---|---|---|---|---|
| 1 | 中 | parser/expr.c:195, parser/parser.c:497,520 | 3 处 sprintf 未使用 snprintf |
替换为 snprintf,防止标识符过长溢出 |
| 2 | 中 | parser/parser.c:535 | use 语句跳过解析,符号导入未实现 |
实现 use 语句的符号导入语义 |
| 3 | 低 | main.c:192 | strcpy(p, ld_args[i]) |
用 memcpy+长度检查替代 |
| 4 | 低 | codegen/cg_expr.c | 表达式生成仍用 switch (440 行) | 后续可转为 Visitor dispatch |
| 5 | 低 | sema/typeck.c:652 | typeck.c 略超 650 行 | 泛型单态化可提取为 mono.c |
| 6 | 信息 | 全局 | 固定数组 [64]/[256] 带边界检查 | 当前均有 if (n>=N) 保护,长期可换动态分配 |
9. 安全审计
| 检查项 | 状态 |
|---|---|
| 缓冲区溢出 | ✅ 全部使用 snprintf(sizeof) 或有边界检查 |
| 格式化字符串 | ✅ 无用户输入直接作为格式串 |
| 空指针解引用 | ✅ 所有 arena_alloc 返回值有 NULL 检查 |
| 内存泄漏 | ✅ Arena bump allocator 统一释放 |
| 栈溢出 | ✅ MAX_PARSE_DEPTH/MAX_CODEGEN_DEPTH 限制递归 |
| LLVM 验证 | ✅ codegen_module 调用 LLVMVerifyModule |
10. 架构评估
评分: 8.5/10
- 流水线设计清晰,每阶段独立可测试
- 近期重构显著改善模块化(文件拆分、去糖独立、数据驱动类型表)
- AST 节点新增流程标准化(枚举→工厂→handler 注册)
- 测试覆盖充足(197 单元 + 36 集成)
- 剩余问题均为中低优先级,无阻塞性缺陷
- 主要不足:codegen 表达式层仍为巨型 switch、use 语句未实现
本报告手动审查生成于 2026-06-07。