docs/current/07-质量与裁定/20260919_S3解析器执行记录.md
GitHub ↗
当前有效

S3 解析器执行记录(vitro/engine/parser)

5102 字·约 13 分钟 阅读 2026-10-10 17:07

执行:2026-09-19 | 上位文档:MoonBit迁移总计划.md §10 S3 行 范围:vitro/engine/parser(深度统一入口;J1 语义不复刻)——验收锚 = E1–E4 + 病态输入"同等拒绝"12 样本 + 活性内部断言。 开工输入:勘察档案 parser 报告(提交 917251e 取回)+ S2 执行记录(lexer 侧复核债:L3 诊断面与 CI 接线随本片 E1–E4 管道统一建)。 状态:✅ 主体收官——597 真实语料样本(baseline 363 + K&R 81 + leetcode 138 + gap 15)AST dump + 诊断序列归一逐字节一致;病态 12 样本同等拒绝;E4 反向锚两侧成功。未发布(随下一 minor 版本一起,见遗留)。

1. 交付物清单

组件 位置 说明
facade 包 moonbit/parser/(六文件) parse(tokens, cpp_mode?) -> ParseResult;parser.mbt(结构/原语/顶层分发/后置双预算)+ expr.mbt(21 帧瀑布 + sizeof/alignof/offsetof/cast/C++ 表达式)+ type_.mbt(类型说明符 + 声明符螺旋 + param_list 壳)+ decl.mbt(声明族 + C++ class/template + eval_enum_const)+ stmt.mbt(语句族 + static_assert + 属性跳过)+ cpp.mbt(内置类型注册 + 类外定义试探 + 顶层 C++ 分发)
ast 包消费面补齐 moonbit/ast/types_predicates.mbt name/array_size/dims/is_vla/is_const/set_const/is_array/subscript_type/base_element_type/total_elements + compute_type_size(Rust 归属 vitro_ast 对齐;T4"消费面待补"边界的 S3 消费触发)+ json_emit 控制字符转义修复
差分出口 moonbit/cmd/dump_ast/(native) 批量 AST JSON + 诊断序列 + stall_count(与 Rust serve ast.dump 响应同构)
Rust 侧防线维护 native/src/session_api.rs ast.dump 补 parse_errors 明细(成功/失败路径都带)+ stall_count: 0 键位对齐;既有测试全绿
比对驱动 scripts/parser_diff/(Go) <corpus>(E1/E2/活性)+ --pathological(E3 12 样本)+ --legal-deep(E4)+ --selftest J9 埋雷;单 serve 进程批量请求;fail loud

2. 验收数字(对真值)

  • E1/E2:597 样本(四目录)AST dump + parse_errors 序列经 canonicalize 归一后逐字节一致——含错误样本的 message 文案(两侧照搬自同一源)。
  • E3:勘察 6-4/6-11 全部 12 条病态样本(括号 63 / 花括号 300 / 初始化列表 3000 / 赋值链 3000 / 一元链 5000 / 指针链 100 / 后缀链 5000 / 声明符后缀 1300 / typedef 1500 / sizeof 抽象 1400 / 形参 1500 / 字段 1500)同等拒绝:两侧进程不崩溃、错误码序列 + 位置一致。
  • E4:合法深嵌套(30 层括号 + 100 项加法;声明符后缀 1200 层)两侧成功且 AST 一致。
  • 活性:全语料 MoonBit 侧 stall_count = 0(主循环计数器只记账不改变控制流——推进逻辑照搬 Rust 三层活性约定;G1 修复后另有熔断下界,见 §7)。
  • 单测:MoonBit workspace 136/136(parser 23:黑盒锚 15 + 白盒 6 + README 文档测试 2);Rust 全量测试 0 失败(防线维护无回归)。
  • J9:parser_diff --selftest 三模式注入差异全部证红(exit 1)。
  • facts 键:moonbit_parser_diff_samples = 597(audit 判读区间以 audit.go 规则表为准;行内不写区间裸数字——会被就近绑定误判漂移,本批实测)。

3. 防护形态改造(J1 语义不复刻——计划 P1 落地)

3.1 depth 参数化(勘察 M1)

Rust 的共享计数器字段 + 8 处壳挂点(statement / assign / ternary / unary / primary / init_list / abstract_declarator / param_list——勘察报告后 P1 批新增了第 8 个)改为显式 depth : Int 参数沿调用链传递:

  • 壳函数首行检查 depth >= MAX_PARSE_DEPTH(对应 Rust enter_depth 的"先检后增");body 与下层壳传 depth + 1;瀑布兄弟函数(or/and/bit_or/…/postfix)透传。
  • 计数口径与 Rust 完全同构(depth ≡ 进入本壳前的共享计数器值):括号嵌套 62 层通过 / 63 层 E1006 的实测边界逐位一致(E3 样本对拍全过是构造性证明)。
  • 收益:新增递归点必须声明 depth(编译器强制),不再依赖人工枚举挂点——J1 的方法论根因("保险丝靠人工枚举")被类型系统封死。

3.2 声明符 Array 链迭代化(勘察 M2 的落地形态差异)

勘察 M2 建议"合并 parse_declarator_node → interpret_declarator_node 两次递归"。实际落地发现更精准的病灶:interpret 的纯 Array 链通道在 wasm 测试运行时 900 层过 / 1200 层栈溢出(Rust native 递归 1200 层存活——MoonBit wasm 栈预算更紧)。修复:Array(inner) 的多维合并分支改为下钻收集 + 由内向外折叠(merge_array_wrap 单层包装函数,语义与 Rust 递归的 _ 合并分支逐层同构),1250 层(MAX_DECLARATOR_SUFFIX 预算上限)全存活——E4 的 1200 层存活锚两侧 AST 一致证明等价性。两次递归未合并(合并会改 DeclaratorNode 中间形态且收益已由迭代化覆盖——登记为决策偏差)。

3.3 回滚快照全量(勘察 M3)

Rollback 从 Rust 的三元(pos/errors/anonymous_structs)扩为七字段全量(+ typedef_names/template_names 整表拷贝 + current_class 长度 + next_lambda_id)——A5"回滚面第 4 类缺口"结构性消除;Rust 三处手工补 typedef_names 的快照点在 restore 内统一覆盖。core Map/Set 是可变哈希结构(勘察 M3 设想的不可变结构共享不成立——实测 API),快照 = .copy()(教学符号表小,O(n) 可接受)。可观测等价性:手工补的三处随 restore 覆盖;sizeof 处差异按 A5 分析不可观测(污染值与首次写入同值 + 合法 C 不可达)。白盒测试构造性验证七字段回滚。

3.4 四常量照搬

MAX_PARSE_DEPTH=256 / MAX_AST_DEPTH=512 / MAX_DECLARATOR_SUFFIX=1250 / MAX_TYPE_DEPTH=1250(P1 批 Rust 现值;勘察报告时 J1 尚为活缺陷,S0.5 P1 止血后 Rust 侧已诊断拒绝——E3 因此是真"同等拒绝"可比)。

4. 差分过程中修掉的移植缺陷(红→绿留痕)

  1. GlobalDecl loc 取值时机:Rust 在初始化器解析后取 previous(loc 落在初始化器末 token——int g = 42; 的 loc.column=9 是 42 的列);MoonBit 初版取在 declarator 后(column=5)——rich 样本 diff 抓出,挪到 init 解析后。
  2. JSON 控制字符未转义:"\x4" 解析出的真字节 0x04 原样写出即非法 JSON——baseline 的 string_escape_octal_hex.c 抓出;ast 包 emit_json_str 与 dump_ast 的 message 转义补 \u00XX(serde_json 口径)。
  3. dims 数组引用别名:多维合并的 inner_dims 直接引用内层数组再 push 会写进内层(Rust clone 语义)——拷贝展开。
  4. 非 cpp 模式未知标识符不消费:Rust parse_base_type 的 fallback 分支无 advance(token 留给声明符作名字)——初版多写了 advance。
  5. unsigned 修饰检查覆盖全部非 Int/Char kind(初版只列 6 个 kind,漏 Union 等的"此"消息分支)。
  6. 子流解析器(X1 等价形态):Rust mem::take 切片 → 显式 view 数组 + 共享符号表引用 + errors 推回 + pos 回填;深度超限在子流内只跳 view 尾(Rust 跳父流尾)——256 层模板实参嵌套属语料外病态,登记为已知等价边界。

5. 决策登记(与勘察报告的偏差)

  1. TypeKind 枚举未引入:其 16 变体与 Type 的 17 构造器大面积同名,入包即污染裸构造器名空间(Array(..) 歧义,S1 手册陷阱 4 实测复现)——parser 的 kind 消费点(unsigned 检查/ctor-init 判定/enum 底层/compute_type_size)全部直写模式匹配。S4 typeck 若需大面积 kind 消费再独立裁定。
  2. 错误收集照搬 Option 形态:勘察 M6 建议 raise 承载控制流——未采纳(等价优先:Rust 的 errors.push + Option 返回直译,E2 面零分叉风险)。M7 的 Result 改造同理未采纳。
  3. 两次声明符递归未合并(见 3.2)。
  4. C++ 语义照搬同一包:M10 独立包切分留 S9 裁定批(A10)——is_cpp_mode 布尔贯穿形态照搬(Z1 债现状登记)。
  5. interpret 递归不改 depth 参数:树深被 1250 收集期预算封顶(各后端余量内);Rust 同款无防护。若未来语料出现 Pointer/Function 交织的深声明符形态再评估。
  6. compute_type_size 入 ast 包:Rust 归属 vitro_ast(对齐);T4 计划边界"不入包"因 S3 消费出现而变更。
  7. 62/63 层括号测试断言修正:Rust 语义下深度触发不返回 None(errors 非空但 program 仍带占位 AST,上层丢弃)——"是否 None"不是对拍面(初版测试断言写错)。
  8. long 单写 = int(Vitro 语义):单 long 在限定符循环被消费后 fallback(unsigned long = unsigned int);long long 双写才是 LongLong——测试期望曾按直觉写 64 位,Rust 真值仲裁修正。

6. 遗留

  • 发布:vitro/engine/parser 随下一 minor(0.4.0)发布;ast 包公共面新增(谓词/compute_type_size/emit 修复)同批。
  • CI 接线:parser_diff 未进 CI(已清偿——2026-09-20 审阅修复批接入 ci.yml 三模式 + facts --run,见 §7-7;lexer_diff 仍待统一裁定)。
  • parser_cpp_unit_test 33 条搬运:C++ 单测锚未搬运(C++ 差分面属 S9 裁定后;C++ 解析路径已随全量平移,597 语料为 C 模式)。
  • 模板实参子流深度超限的父流跳尾差异(见 §4-6):语料外病态,登记不修。
  • 随机语料生成器(parser 层的 gen_corpus 等价物)未建——597 真实语料 + 12 病态 + 2 反向锚为当前锚面;随机构造随 S4 消费侧需要再评估。

7. 审阅修复批(2026-09-20,审阅报告 v3 → 逐项落地)

审阅报告《20260920_S3提交8085e81审阅报告》(v3)三项严重缺陷 + 三项任务书 级漏项,本批逐项修复,全部红→绿(--threshold 模式先证红后修):

  1. G3 阈值样本收编(勘察 §8-E3"新语言重标定后的阈值样本"): parser_diff 新增 --threshold 模式——A 族(offsetof 嵌套深链 k=16/64/128,两侧一致)+ B 族(enum/_Static_assert 常量链 600/1200/1200, 两侧一致)+ C 族(指针括号+多维数组 8 形状,MoonBit 侧 C 语义结构断言); --selftest 两类断言证红(A 篡改 Rust 输出 / C 篡改期望骨架)。 修复前实跑:B 族样本崩溃(0xC00000FD)即整体红。

  2. F1(P0)offsetof 深度护栏失效:parse_offsetof 加 depth 形参、 parse_base_type(depth) 透传(与 sizeof/alignof 写法对齐)。修复后 A 族 k=64/128 与 Rust 同等拒绝且诊断面逐位一致。

  3. F2(P0)enum 常量求值器深递归崩溃:eval_enum_const 显式栈迭代化 (J14 纪律;求值序与递归版等价——Binary 先左后右、strict 短路)。 白盒锚:1200 项深链求值 + checked 语义抽查(移位量/除零 None)。 oracle 同族缺陷登记:Rust decl.rs 同款递归无护栏(实测约 5000 项 崩)——冻结区不改,S8 差异台账落地时按 DIFF 条目收编。

  4. F3(P1)声明符 Array 链撕裂折叠:按用户裁定 (b) 向 C 语义修正—— 收集循环尾为 Pointer 时整条维度进入指针指向类型(int (*p)[2][3] → Pointer(Array{dims:[2,3]}),"后缀先作用于基类型、指针在最外层")。 有意分叉登记:该形态族(指针括号+括号外 ≥2 维数组:全局/字段/形参/ 抽象声明符/typedef 传播)MoonBit 与 Rust oracle 不一致——oracle 撕裂折叠 自身不符 C 语义(int (*p)[2][3] → Array[3](Pointer(Array[2]))); 597 语料该形态 0 命中,E1/E2 不受影响;语料一旦新增该形态样本, E1/E2 需按本条白名单排除(S8 差异台账落地时收编为 DIFF 条目)。 白盒锚:多维折叠 + 纯数组链对照;E4 复跑 1250 层存活未回退。

  5. G1(M4 部分落地)零推进熔断:MAX_STALL_ROUNDS=1000 熔断 (stall_synchronize 与主循环两处:超限 E1006 + 强推一个 token, 终止性下界)。M4 偏差登记:勘察 M4 的 parse_repeat 组合子 (类型级不变量)未完整落地——三层活性约定保持照搬 + 熔断兜底为 本批形态;组合子化涉及主循环/恢复路径重构,收益/风险比不划算, 留 S4+ 若语料出现活性病态再评估。

  6. G2(M9)顶层分发收口:parse_program 重构为只读前瞻判定函数 classify_top_level(索引扫描不动 pos,替代分支内联 save/advance/ restore 试探——勘察 M9 点名的 18GB 事故病灶形态)+ TopLevelKind 穷尽分发(新增构造漏分支即编译红)。行为逐字节一致:141 单测 + E3/E4/threshold 三锚 + 597 全量复跑全绿。

  7. F5 防线可持续性:canonicalize 预构建复用(E3 实测 45s+ → 3.9s; 597 全量 34min → 分钟级);facts 采集超时 10→20min + --threshold 接线;CI 接线(§6 遗留项清偿):ci.yml 加 MoonBit 工具链安装 + parser_diff 三模式步骤(此前不在 CI 与 F1/F2 崩溃互为因果)。

  8. F7:parseParserDiffPass 补绿/红一对测试(J9——此前注释声称 埋雷覆盖但无测试)。

  9. F8:check 警告清理——S3 范围清零(7 处 missing_priv 加 priv、 弃用 substring→切片 / StringBuilder() / to_owned、unused V 帧删除); 顺手清 S2 存量(lexer pp 17 处 + dump_tokens 5 处 + ast/json_emit 2 处 + unused_trait_bound)。遗留 Show 弃用噪音(inspect 系 API 依赖 core 的 Show trait,moonbitlang/core Show→Debug 迁移期, 无本仓侧干净替代——待 core 稳定后统一处理,登记于此)。 口径更正(复审指正):§7 原写"仅余 5 条"有误——实测 --target all 12 条 = 6 Show + 6 unused_trait_bound;后者系 pp.mbt 的 substring→切片替换改变类型推断、使 6 个 Pp 方法的 bound 被重新判定为未用(归因经 stash 回滚实验坐实),已在 F3-v2 批(§8-4)去 bound 清零。

  10. F10:文档/注释收敛——"26 项"→19 项(同步修正:勘察 R4 的 "26 项"亦有误)、dump_ast E2 面注释(message 已在逐字节面内)、 测试数 136→141(+5 白盒锚,分解 parser 23→28)、包注释"编译器 强制/完全同构"精确化(F1 教训)、"零推进只计数"限定主循环计数器。 F11 不修(basename_no_ext 不去扩展名——驱动注释已把它当规格, 输出名 <stem>.c.ast.json 为 parser_diff 既有对拍约定,改动即 破坏两侧输出名匹配;如需修正应连同驱动一起改,非本批)。

  11. 收尾批(同日):gen_diag -check 在 CRLF 工作树(autocrlf checkout)fail loud"未处理的 Rust 转义 0x0d"——hash 层有行尾归一 而解析层没有(存量缺口,非本批引入,环境形态暴露);两处读源 (codesPath / 卡片源)统一归一后回写,修复转绿(LF 工作树语义 不变——归一幂等)。docs/README.md 补审阅报告索引条目 + 本记录 描述更新;facts --run 本地真值刷新(141/597/threshold 批次口径)。

验收快照(2026-09-20,含 F3-v2 批更新):moon test 144/144; moon check --target all 余 10 条 Show 迁移期噪音(8 旧 + F3-v2 新锚 inspect 2,unused_trait_bound 已清零);parser_diff 四模式全绿 (E1/E2 597 全量 363+81+138+15(含 2 例已知分叉白名单 FORK,见 §8-3)

  • E3 12 + E4 2 + threshold 23)+ 四 selftest 证红;lexer_diff baseline 726 TSV 复绿(弃用清理波及面);go test ./scripts/facts 绿; gen_diag -check 绿(收尾批后)。

8. F3-v2 修复批(2026-09-20 复审 · 声明符解释器换算法一次收口)

复审报告(Clang 22.1.4 为最终判据)确认 F3 首修为部分闭合:补丁 形态只覆盖"括号内是最内层指针"拓扑,int (*p[2])[3][4](c02)、 int (*p[2][3])[4][5](c03)、int (*(*p)[2][3])[4][5](c04,层级 颠倒)、int (*f(void))[2][3](f01,函数/指针嵌套颠倒)、int *p[2][3] (c05,oracle 双错族)仍错。根因定性成立:自底向上折叠无法表达 "维度归属",继续加特例无出路——按复审处方换算法。

  1. 累加器一次收口:interpret_declarator_node 改为自顶向下 累加器(外层节点先消费 T:Pointer→Pointer(T) / Array→维度头插 / Function→函数 decay / Base→返回累积 T),一次取代全部三个自底 向上特判分支(Pointer(Array) / Array(Pointer) / 尾 Pointer 整包)。 迭代实现(链为线性结构,while 下钻无递归——J14),E4 复跑 1250 层存活未回退。函数 decay 约定照搬原表示:Function 值语义 = 函数指针,紧邻内层 Pointer 被 decay 层吸收(int (*fp)(void) → 单层 Pointer(Function),(*fp[2])(void) → Array(Pointer(Function)))。
  2. size 方向语义状态机(VLA 语料对拍抓出):Array 维度乘积与 Rust 由内向外折叠逐序等价(最外维 0 恒 0;最外起向内连乘正数、 遇 0 停)——int a[n][3] 的 size=3 而非 0(vla_2d/vla_sizeof_type 两语料首跑抓红);连续 Array 层才相乘,跨 Pointer/Function 重置 (int (*p[2])[3][4] 外层 size=2 而非 24——白盒锚抓出)。
  3. E1/E2 已知分叉白名单(knownForkFiles,命中报 FORK 不计败、 诚实显示):597 语料中 2 例命中——function_pointer_return_ptr.c (局部 int*(*fp)(int):oracle 局部路径双层 Pointer(Pointer(Function)) 不符 C,Clang 单层)与 kr_5_11.c(局部函数原型 char*month_name(int) 同族)。oracle 全局/局部两处函数声明符实现互不一致(全局单层), 双层侧登记为 oracle 缺陷;其余分叉族(c02/c03/c04/f01/f02/c05 多维族)597 语料 0 命中。全部待 S8 差异台账落地收编。
  4. 阈值锚扩族:C 族 8→16 条(c02/c03/c04/c05/f01/f02 + 函数指针 双守卫;期望值按 Clang -ast-dump 拼写派生,f01/f02 最外 Pointer 为 Vitro decay 约定);skeleton 补 Function 面;A 族补 k=140 (崩溃悬崖侧下界)。修复前证红 6 处(守卫与 k=140 绿)。
  5. 白盒锚:+3 条(内层数组维度归属 / 函数返回数组指针 decay / 函数指针 decay 双守卫;首版链构造序写错被真锚抓出——parse 的 建链序为"括号内前缀最后包",与手推直觉相反)。
  6. unused_trait_bound 清零(§7-9 归因的 6 处):去 P bound (与 Pp::err 同款处理)。
  7. 验收(2026-09-20 F3-v2 批时点快照):moon test 144/144;threshold 23 条全绿;E3/E4 全绿; 597 四目录全 PASS(2 FORK 白名单);check --target all 余 10 条 Show 迁移期噪音(含新锚 inspect 2 条)。