docs: 固化语法 TDD 与 C99 合同

This commit is contained in:
pikastech
2026-07-21 13:57:49 +02:00
parent 0bca0a4034
commit 7d4a0b0af8
2 changed files with 143 additions and 18 deletions
@@ -6,10 +6,11 @@
| --- | --- | --- | --- |
| v0.1 | `205e3a70` | 2026-07-21 | 定义 V2 动态子集重写内核的架构原则、能力边界和量化验收合同。 |
| v0.2 | `d72a1f52` | 2026-07-21 | 已批准:明确阶段性 V1 parser 适配器、原子 capability、职责化实现命名、候选内核比较和 cold/warm benchmark 生命周期。 |
| v0.3 | `待追溯` | 2026-07-21 | 已批准:增加语法能力组 TDD、CPython 逐字节脚本回归和严格 ISO C99 硬门禁。 |
修改历史只记录规格语义变更,不记录实现进度、阶段基线或一次性证据。
v0.2 及其引用的 PIKA-CAP v0.1 已批准生效,作为当前实现合同。
v0.3 及其引用的 PIKA-CAP v0.2 已批准生效,作为当前实现合同。
## 正文
@@ -23,12 +24,19 @@ v0.2 及其引用的 PIKA-CAP v0.1 已批准生效,作为当前实现合同。
| 短名 | V2内核 |
| 层级 | L1 方向 |
| 规格状态 | 已生效 |
| 当前生效版本 | v0.2 |
| 实现引用版本 | v0.2 |
| 当前生效版本 | v0.3 |
| 实现引用版本 | v0.3 |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-05 PikaPython 总规格](PJ2026-05-pikapython.md) |
本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版。正文只定义 V2 的预期终态、稳定边界、目标架构、原子需求和验收合同。
本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版。
正文只定义:
- V2 的预期终态;
- 稳定边界;
- 目标架构;
- 原子需求;
- 验收合同。
## 2. 目的和范围
@@ -59,6 +67,8 @@ V2 的目标是:
- 编译期和构建期的语法、opcode、对象、模块与平台裁剪。
- C 模块绑定、平台抽象和可预测错误合同。
- 实现文件和代码标识符的职责化命名合同。
- 项目自有 C 源码的严格 ISO C99 编译合同。
- 分层内部测试和与 CPython 逐字节对照的脚本回归。
- Linux 快速性能裁决及真实 Cortex-M、RV32 目标的功能、性能、Flash 和 RAM 确认。
### 2.3 范围外
@@ -87,6 +97,8 @@ V2 的目标是:
| 中性类型化 V2 IR | V2 前端与后端之间版本化、结构节点和操作数类别显式、无 V1 对象和 ABI 依赖的唯一长期合同;不表示静态类型证明。 |
| 能力等价配置 | 所需 capability 闭包、被测语义和必需平台模块一致的比较配置。 |
| 职责化命名 | 文件名和代码标识符表达内核职责、数据语义或生命周期,不携带路线代际缩写。 |
| 语法能力组 | 一次 TDD 迭代选择的 capability 根集合、依赖闭包、正负测试和资源比较单元。 |
| 逐字节脚本回归 | 对相同受支持源码比较目标运行时与 CPython 的退出状态和 stdout 原始字节,不做空白或换行归一化。 |
## 4. 系统边界和接口
@@ -176,7 +188,11 @@ V2 对 capability 的应用必须满足以下要求:
### 5.5 单一内核与证据驱动专用化
V2 必须以一个共享内核架构作为默认实现,通过 capability 闭包在构建期移除不需要的代码和数据。profile 不得默认选择完整独立的 VM。
V2 的默认实现必须满足以下要求:
- 使用一个共享内核架构;
- 通过 capability 闭包在构建期移除不需要的代码和数据;
- profile 不得默认选择完整独立的 VM。
候选架构包括:
@@ -185,12 +201,15 @@ V2 必须以一个共享内核架构作为默认实现,通过 capability 闭
- 变长字节码编码;
- 其他适合目标平台的编码或 dispatch 方案。
本规格不预先承诺候选终态。结构选择必须在相同 capability 闭包、相同 workload 和相同资源预算下完成 A/B 验证,并同时比较:
本规格不预先承诺候选终态。
结构选择必须满足以下要求:
- 动态能力等价 suite 的吞吐、延迟和离散度
- Flash、静态 RAM、峰值堆、VM 栈和宿主栈;
- 热路径动态分配、错误路径和实现复杂度;
- 真实 Cortex-M 或 RV32 目标上的对应结果。
- 在相同 capability 闭包、workload 和资源预算下完成 A/B 验证
- 同时比较:
- 动态能力等价 suite 的吞吐、延迟和离散度;
- Flash、静态 RAM、峰值堆、VM 栈和宿主栈;
- 热路径动态分配、错误路径和实现复杂度;
- 真实 Cortex-M 或 RV32 目标上的对应结果。
局部专用化只在上述验证证明有稳定收益时允许,并且必须满足:
@@ -258,7 +277,11 @@ V2 不得以复用 V1 内部架构为默认目标。热点处理顺序如下:
| --- | --- | --- | --- |
| V2-L1-REQ-002 | 动态子集 | PJ2026-050101 语言编译 | PJ2026-050102 VM执行、PJ2026-050105 验证基准 |
V2 必须支持不带 type hint 的动态 Python 子集。类型注解即使被语法接受,也不得成为执行正确性、性能快速路径或函数准入的必要条件。
动态 Python 子集必须满足以下要求:
- 支持不带 type hint 的源码;
- 类型注解即使被语法接受,也不得成为执行正确性的必要条件;
- 类型注解不得成为性能快速路径或函数准入的必要条件。
V1 lexer/parser 只能作为可选、阶段性的主机侧引导适配器。复用必须满足以下边界:
@@ -329,7 +352,17 @@ V2 必须延续并强化 V1 的可裁剪能力:
- 裁剪覆盖模块、C binding 和平台能力;
- 未启用功能的代码、只读数据和注册表能够从最终产物中移除。
每个 capability 必须声明依赖、测试和资源变化。裁剪不得产生无法解释的链接失败、静默行为变化或只在完整配置可见的错误诊断。
每个 capability 必须声明
- 依赖;
- 测试;
- 资源变化。
裁剪不得产生:
- 无法解释的链接失败;
- 静默行为变化;
- 只在完整配置可见的错误诊断。
### 6.6 V2-L1-REQ-006 Runtime 性能优先
@@ -366,7 +399,14 @@ V2 必须延续并强化 V1 的可裁剪能力:
运行时必须区分可恢复异常与致命资源故障,并为两者提供稳定、可测试的可见信息。
非法输入不得导致未报告崩溃、越界执行、静默退出或无诊断循环。致命故障允许停机,但停机前必须输出最小可靠诊断。
非法输入不得导致
- 未报告崩溃;
- 越界执行;
- 静默退出;
- 无诊断循环。
致命故障允许停机,但停机前必须输出最小可靠诊断。
### 6.8 V2-L1-REQ-008 原子 capability 与 profile
@@ -412,6 +452,59 @@ V2 作为路线和规格称谓,不得进入实现仓库的文件名或项目
- 路线名称可以出现在规格、阶段报告和产品版本元数据中,但不得成为实现结构或 ABI 名称;
- 版本控制内全部实现文件名和项目自有代码标识符必须由自动扫描验证。
### 6.11 V2-L1-REQ-011 语法能力组 TDD
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| V2-L1-REQ-011 | 语法 TDD | PJ2026-050101 语言编译 | PJ2026-050102 VM执行、PJ2026-050105 验证基准 |
每组新增语法必须先冻结 capability 根集合和依赖闭包,再按以下顺序交付:
- 先增加能够因缺失能力而稳定失败的 lexer、parser、IR、verifier 和 VM 细粒度测试;
- 同时增加输入单个 `.py` 文件和输入目录的最终回归,目录默认执行 `main.py`
- 记录红测例的预期失败位置和诊断后,才实现满足该能力组的最小前端和 runtime 语义;
- 内部测试通过后,使用相同工作目录和源码由目标运行时与 CPython 执行;
- 对受支持且成功执行的脚本逐字节比较 stdout,并比较退出状态;
- 最后在相同环境运行实现前后 benchmark,报告性能和资源变化。
脚本回归必须满足以下边界:
- 输入文件必须是单个 `.py` 文件;输入目录必须包含默认入口 `main.py`
- 目录中的其他 `.py` 文件只有在对应模块能力已启用时才可被加载,不得隐式全部执行;
- stdout 比较不得裁剪空白、修改换行或忽略末尾字节;
- stderr 和编译诊断必须保持可见,但不得混入 stdout 对照结果;
- 不支持的语法必须由对应负向测试验证稳定拒绝,不得为了通过 CPython 对照而静默接受。
测试组织必须满足以下要求:
- 可以参考稳定 PikaPython 的能力分类和脚本粒度;
- 不得复制其测试实现、内部断言或 runtime 假设。
每个语法能力组必须同时具备:
- lexer、parser 和编译结果的细粒度测试;
- opcode、控制流、存储和错误恢复的 VM 测试;
- 单文件和目录入口的最终脚本回归;
- 禁用 capability 和依赖缺失的负向测试。
### 6.12 V2-L1-REQ-012 严格 ISO C99
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| V2-L1-REQ-012 | C99 合同 | PJ2026-050104 裁剪移植 | PJ2026-050101 语言编译、PJ2026-050102 VM执行、PJ2026-050103 对象内存、PJ2026-050105 验证基准 |
全部项目自有 C 源码和 C 头文件必须符合严格 ISO C99。
本要求是本次唯一新增硬门禁:
- C 编译标准固定为 C99,不得提升到 C11 或更高版本;
- GNU 语言扩展必须关闭,不得使用 `gnu99` 或编译器默认 GNU 方言;
- GCC 和 Clang 构建:
- 必须使用 `-std=c99` 或等价参数;
- 必须启用 `-pedantic-errors`
- 默认内核、显式候选、smoke 和工具中的每个 C 编译单元都必须进入该检查;
- 构建系统配置和实际编译命令必须同时验证,任一编译单元偏离即构建失败;
- C++ 仅可用于主机测试和 benchmark harness,不得成为目标 runtime 或 C ABI 的依赖。
## 7. 验收合同
### 7.1 语义验收
@@ -426,6 +519,9 @@ V2 作为路线和规格称谓,不得进入实现仓库的文件名或项目
- 测试粒度参考 V1,但不要求继承 V1 测试或内部行为;
- 不支持能力必须有负向测试,验证明确拒绝和错误可见性;
- 模块裁剪组合必须验证功能依赖和最终链接结果。
- 每组语法能力必须保存先失败后通过的 TDD 证据,并覆盖前端、IR、verifier、VM 和最终脚本五个层次。
- 回归执行器必须接受单个 `.py` 文件或目录;目录未包含 `main.py` 时返回明确错误。
- 对受支持的成功脚本,目标运行时和 CPython 的退出状态与 stdout 原始字节必须完全一致。
### 7.2 性能验收
@@ -462,6 +558,10 @@ V2 作为路线和规格称谓,不得进入实现仓库的文件名或项目
- 相对 MicroPython 的 suite 几何平均吞吐提升 5% 仅作为延伸目标,不作为第一阶段完成条件;
- 单一 workload 不得独立支撑上述结论;
- 报告同时披露每项原始值、样本数、median、p95、标准差、变异系数、几何平均和退化项。
- 每个语法能力组进入默认内核前必须完成实现前后对照:
- 使用相同工具链、环境、CPU 亲和性和 workload
- 比较热执行、字节码、执行存储、宿主栈、动态分配和二进制尺寸。
- 前端解析和编译成本单独报告,不得混入 warm execution;目标 runtime 不得因主机前端链接而虚增 Flash 结论。
### 7.3 资源验收
@@ -470,13 +570,18 @@ V2 作为路线和规格称谓,不得进入实现仓库的文件名或项目
- 初始化数据和 `bss`
- 峰值堆、峰值 VM 栈和宿主栈;
- benchmark 热路径动态分配次数。
- 资源指标必须来自 allocator、执行存储水位、栈水位或等价 instrumentation;无法测量的字段必须报告 unavailable 和原因,不得填写推测值或手工零值。
- 资源指标
- 必须来自 allocator、执行存储水位、栈水位或等价 instrumentation
- 无法测量的字段必须报告 unavailable 和原因;
- 不得填写推测值或手工零值。
- 每个命名或定制 profile 均不得超过 owning YAML 声明的资源预算。
- V2 的可比较配置应满足:
- Flash 不高于 V1 同能力配置;
- 峰值 RAM 不高于 V1 同能力配置;
- 相对 MicroPython 的性能、Flash 和峰值 RAM 按 7.2 的预算约束做 Pareto 分析。
- 高频整数算术、局部控制流和已优化函数调用路径应保持零堆分配;该结论必须由分配器计数或等价 trace 证明,不得使用手工源码计数代替。
- 高频整数算术、局部控制流和已优化函数调用路径应保持零堆分配
- 该结论必须由分配器计数或等价 trace 证明;
- 不得使用手工源码计数代替。
- 宿主 C 栈或目标栈上的帧、寄存器数组和临时缓冲必须单独计入峰值栈,不得因“零堆分配”而省略。
- 构建产物必须证明只链接 capability 闭包需要的 opcode、对象、模块和辅助路径。
@@ -506,11 +611,19 @@ V2 作为路线和规格称谓,不得进入实现仓库的文件名或项目
- 公开头文件、链接符号、构建 target 和测试 fixture 不得保留兼容别名;
- 第三方依赖必须位于明确的 vendored 边界,其上游标识符不构成本项目公开 API。
### 7.7 C99 验收
- 配置阶段必须断言 C 标准为 99 且扩展关闭;
- 编译命令清单必须证明全部项目自有 `.c` 文件使用严格 C99 方言和 `-pedantic-errors`
- 默认构建和显式候选构建都必须通过同一 C99 合同检查;
- 任意 GNU extension、C11 语法或漏检 C 编译单元都必须使测试失败。
## 8. 过程控制
- V2 新增或修改的手写内核源码应标注 `SPEC: PJ2026-0501 V2内核 v0.2` 和文件职责。
- V2 新增或修改的手写内核源码应标注 `SPEC: PJ2026-0501 V2内核 v0.3` 和文件职责。
- 自动生成、vendored、配置和二进制产物可不加源码头,但生成器或配置入口必须能追溯本规格。
- 架构选择必须记录候选方案、适用前提、benchmark 热点和资源影响;当前结果进入 TaskTree 或 issue,不进入 SPEC。
- 任何实现若让 V1 内部结构越过中性类型化 V2 IR 边界,必须先更新本规格或作为偏离停止合并。
- capability 和 profile 实现引用 `PIKA-CAP v0.1`
- capability 和 profile 实现引用 `PIKA-CAP v0.2`
- 语法能力组的红测例、通过证据和 benchmark 数值进入 TaskTree 或 issue,不进入 SPEC。
- 若后续决定引入 strict type、LLVM、JIT 或 native emitter,应归入独立静态加速规格,不得直接修改 V2 默认路线。
@@ -5,6 +5,7 @@
| 版本 | 对应 commit id | 更新日期 | 变更说明 |
| --- | --- | --- | --- |
| v0.1 | `d72a1f52` | 2026-07-21 | 已批准:建立原子 capability、显式依赖图和命名 profile 合同。 |
| v0.2 | `待追溯` | 2026-07-21 | 已批准:增加最小 stdout `print` 能力及其逐字节回归合同。 |
修改历史只记录规格语义变更,不记录实现进度、阶段基线或一次性证据。
@@ -20,7 +21,8 @@
| 短名 | 能力配置档 |
| 层级 | L0 共享规范 |
| 规格状态 | 已生效 |
| 实现引用版本 | v0.1 |
| 当前生效版本 | v0.2 |
| 实现引用版本 | v0.2 |
| 上级规格 | [PJ2026-05 PikaPython 总规格](PJ2026-05-pikapython.md) |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
@@ -87,6 +89,7 @@ capability 描述对外语义和可裁剪单元,不规定 parser、IR、字节
| `flow.branch` | 条件分支。 | `protocol.truth` |
| `flow.loop` | `while``break``continue`。 | `flow.branch` |
| `logic.short-circuit` | `and``or``not` 的短路语义。 | `flow.branch` |
| `builtin.print` | 使用默认格式向 stdout 输出一个已启用标量值并追加换行;不包含多参数、`sep``end`。 | `exec.module` |
| `call.positional` | 位置参数函数、调用、返回和递归。 | `name.local` |
| `call.defaults` | 默认参数绑定。 | `call.positional` |
| `call.keyword` | 关键字参数绑定。 | `call.positional` |
@@ -183,6 +186,12 @@ profile 合同如下:
- 产品可以声明定制 profile,但必须记录完整根集合、依赖闭包和资源预算;
- 同名 profile 在不同路线中必须保持语义等价,内部实现可以不同。
`builtin.print` 不默认加入现有命名 profile。
需要脚本输出的产品或测试配置必须:
- 把它作为显式 capability 根;
- 同时选择被输出值类型的 capability。
### 5.3 产物与加载
- 编译产物必须携带 capability schema 版本和所需能力清单;
@@ -224,6 +233,9 @@ profile 合同如下:
- 资源报告必须绑定 capability 闭包,并分别披露 Flash、静态 RAM、峰值堆、VM 栈、宿主栈和动态分配;
- 跨 V1、V2 和 MicroPython 的产品比较必须使用能力等价配置;
- profile 名称相同但能力闭包不同的结果不得声明为可比较。
- `builtin.print` 的正向测试:
- 必须把目标 stdout 与 CPython 对相同受支持值的输出逐字节比较;
- 输出通道失败必须返回明确错误。
## 8. 过程控制