第6天 通过解释器执行程序

第6天 通过解释器执行程序围绕eval方法与环境对象、各种类型的eval方法、关于GluonJ、执行程序推进Stone语言,实现从源文本、Token、AST到求值、优化或代码生成的可回归增量。 覆盖5个正式目录层级。

为什么不能只看最终输出

、、、、共同构成本页坐标。第6天 通过解释器执行程序围绕eval方法与环境对象、各种类型的eval方法、关于GluonJ、执行程序推进Stone语言,实现从源文本、Token、AST到求值、优化或代码生成的可回归增量。

最终输出相同不代表实现相同:词法器可能吞掉错误字符,解析器可能生成错误结合性的树,解释器可能从调用点而非定义点捕获环境,优化器也可能只在当前样本上碰巧得到正确值。因此每次增量都保留源文本、Token范围、AST快照、环境或帧状态、标准输出、错误输出与退出状态。

Stone增量实现台账

先冻结上一日全部样本和公开接口,再为本日功能写一个最小成功程序、一个边界程序、一个故意失败程序和一个跨功能程序。成功样本证明新语法能到达执行层;边界样本暴露空输入、嵌套、遮蔽、短路、越界或缓存失效;失败样本必须在最早确定的位置停止;跨功能样本防止新节点破坏旧的表达式、控制流与函数语义。

处理流水线分为六个可观察检查点:源字符是否完整消费,Token是否携带类型和值及源位置,文法是否选择唯一分支,AST是否表达优先级与作用域,运行环境或虚拟机是否遵守所有权和调用约定,最终值与错误是否满足语言合同。只记录最终打印文本会丢失前五层最有诊断价值的证据。

每个错误对象至少含阶段、源文件、行列范围、实际符号、期望集合、原因和恢复建议。不要在底层捕获后返回null继续执行,因为后续空指针会掩盖真正错误;也不要把Java反射异常原样暴露给Stone程序,而应保留cause并映射为稳定的语言错误类别。

性能增量采用差分验证:同一语料分别运行基线解释器和优化版本,先比较值、输出、错误类别与位置,再比较预热后的时间、分配量与查找次数。若槽位分配、内联缓存或字节码改变异常顺序,性能再高也不能通过语义验收。

每次提交还要附带增量契约:本日新增哪些Token、文法产生式、AST节点、环境槽位、虚拟指令或类型规则,哪些旧接口保持不变,失败后如何回退到上一日可运行状态。将生成的Token、AST或字节码快照纳入版本比较,但不把快照更新本身当成修复;先解释结构变化为何符合语言设计,再接受新的基线。这样可把19天连续演进变成可二分、可撤销、可复查的工程历史。

六阶段证据链

1. 建立根环境

围绕eval方法与环境对象保存输入、结构化中间状态与输出。进入“求值叶子节点”前,先断言当前检查点成立并记录首个偏离。

2. 求值叶子节点

围绕各种类型的eval方法保存输入、结构化中间状态与输出。进入“传播控制流”前,先断言当前检查点成立并记录首个偏离。

3. 传播控制流

围绕关于GluonJ保存输入、结构化中间状态与输出。进入“更新变量绑定”前,先断言当前检查点成立并记录首个偏离。

4. 更新变量绑定

围绕执行程序保存输入、结构化中间状态与输出。进入“记录运行错误”前,先断言当前检查点成立并记录首个偏离。

5. 记录运行错误

围绕eval方法保存输入、结构化中间状态与输出。进入“核对最终环境”前,先断言当前检查点成立并记录首个偏离。

6. 核对最终环境

围绕eval方法与环境对象保存输入、结构化中间状态与输出。进入“建立根环境”前,先断言当前检查点成立并记录首个偏离。

可运行骨架

sum = 0
i = 1
while i <= 4 { sum = sum + i; i = i + 1 }
sum
Object eval(Environment env) {
  Object left = left().eval(env);
  Object right = right().eval(env);
  return apply(op(), left, right);
}
java stone.BasicInterpreter < samples/loop.stone
printf 'sum=10\n' | diff -u - actual.txt

正式目录逐项讲解

第6天 通过解释器执行程序

“第6天 通过解释器执行程序”要求先给出可运行正例,再列出语法、环境、对象、返回值和失败合同,最后沿处理流水线停在第一处分叉。在本日增量中,“eval方法与环境对象”服务于“建立根环境”:输入保存原始Stone源码、预期Token或AST、初始环境与宿主版本,输出保存结构化结果、标准错误和退出状态。

验证时只改变一个运算符、分隔符、绑定、对象布局、类型标注或输入规模,并在进入“求值叶子节点”前停住第一条Token范围、语法分支、AST节点、环境绑定、虚拟指令或类型约束分叉。修复后重放此前所有日次样本;若旧语义改变,必须说明是有意语言演进还是回归。

6.1 eval方法与环境对象

“6.1 eval方法与环境对象”要求画出词法环境、调用帧、参数绑定、返回值和闭包捕获关系,逐节点记录求值顺序、副作用与异常传播。在本日增量中,“各种类型的eval方法”服务于“求值叶子节点”:输入保存原始Stone源码、预期Token或AST、初始环境与宿主版本,输出保存结构化结果、标准错误和退出状态。

验证时只改变一个运算符、分隔符、绑定、对象布局、类型标注或输入规模,并在进入“传播控制流”前停住第一条Token范围、语法分支、AST节点、环境绑定、虚拟指令或类型约束分叉。修复后重放此前所有日次样本;若旧语义改变,必须说明是有意语言演进还是回归。

6.2 各种类型的eval方法

“6.2 各种类型的eval方法”要求画出词法环境、调用帧、参数绑定、返回值和闭包捕获关系,逐节点记录求值顺序、副作用与异常传播。在本日增量中,“关于GluonJ”服务于“传播控制流”:输入保存原始Stone源码、预期Token或AST、初始环境与宿主版本,输出保存结构化结果、标准错误和退出状态。

验证时只改变一个运算符、分隔符、绑定、对象布局、类型标注或输入规模,并在进入“更新变量绑定”前停住第一条Token范围、语法分支、AST节点、环境绑定、虚拟指令或类型约束分叉。修复后重放此前所有日次样本;若旧语义改变,必须说明是有意语言演进还是回归。

6.3 关于GluonJ

“6.3 关于GluonJ”要求标明Stone与Java边界上的成员解析、参数转换、返回包装、异常映射和类路径依赖,避免宿主细节泄漏为语言语义。在本日增量中,“执行程序”服务于“更新变量绑定”:输入保存原始Stone源码、预期Token或AST、初始环境与宿主版本,输出保存结构化结果、标准错误和退出状态。

验证时只改变一个运算符、分隔符、绑定、对象布局、类型标注或输入规模,并在进入“记录运行错误”前停住第一条Token范围、语法分支、AST节点、环境绑定、虚拟指令或类型约束分叉。修复后重放此前所有日次样本;若旧语义改变,必须说明是有意语言演进还是回归。

6.4 执行程序

“6.4 执行程序”要求先给出可运行正例,再列出语法、环境、对象、返回值和失败合同,最后沿处理流水线停在第一处分叉。在本日增量中,“eval方法”服务于“记录运行错误”:输入保存原始Stone源码、预期Token或AST、初始环境与宿主版本,输出保存结构化结果、标准错误和退出状态。

验证时只改变一个运算符、分隔符、绑定、对象布局、类型标注或输入规模,并在进入“核对最终环境”前停住第一条Token范围、语法分支、AST节点、环境绑定、虚拟指令或类型约束分叉。修复后重放此前所有日次样本;若旧语义改变,必须说明是有意语言演进还是回归。

分步视觉验证

常见误区

四类样本与验收

样本只改变什么必查证据通过条件
正常一个最小语言功能Token、AST、状态与输出与手工预测一致
边界空值、嵌套、遮蔽或规模首个边界分支与源位置边界可解释
非法一个字符、规则、绑定或类型最早错误类别与期望集合不继续污染状态
回归与上一日相同语料结构、值、错误与性能基线旧语义保持

练习

小结

  • eval方法与环境对象:连接“建立根环境”的源文本、中间结构、运行状态与回归证据。
  • 各种类型的eval方法:连接“求值叶子节点”的源文本、中间结构、运行状态与回归证据。
  • 关于GluonJ:连接“传播控制流”的源文本、中间结构、运行状态与回归证据。
  • 执行程序:连接“更新变量绑定”的源文本、中间结构、运行状态与回归证据。
  • eval方法:连接“记录运行错误”的源文本、中间结构、运行状态与回归证据。
  • 本页5个正式目录层级全部进入Stone可运行增量与差分回归链。

术语表

讨论

评论区加载中…