docs/current/07-质量与裁定/列号口径冻结.md
GitHub ↗
当前有效

列号口径冻结(现状锚定 + MoonBit 双坐标契约输入)

1112 字·约 3 分钟 阅读 2026-10-10 17:07

冻结日期:2026-09-19 | 状态:现状口径冻结(缺陷不修——S1 vitro/source 以双坐标根治,该双坐标已随 S1 收官落地〔2026-09-19,moonbit/source 的 Pos{byte_off, col_scalar, col_utf16} + wbtest 在库〕,本档案是契约输入与防漂移锚) 上位文档:MoonBit迁移第一阶段计划(已归档) §2 P6、MoonBit迁移总计划 防漂移锚:native/tests/source_column_convention_test.rs(八形状探针矩阵,断言精确输出值)


1. 现状口径(全部实测,探针见 §3)

1.1 词法路径(E1001 等 LexerError)

报错列 = 非法字符的 1-based Unicode 字符列 + 1(报错发生在 advance 之后, current 已越过非法字符)。列计数语义 = 字符(Unicode scalar)列,非字节列:

探针 非法字符 字符列(1-based) 实报 规律
int @; @ 5 1:6 +1
int a = @; @ 9 1:10 +1
int a = "中" @; @ 13(中按 1 字符计) 1:14 +1(字符列,非字节列)
int main(){ 中文 x; } 中/文 13 / 14 1:14 / 1:15 各 +1

1.2 解析路径(E2005 等 ParseError)

报错列 = current token 的 column 字段(consume 失败时取 current)。 Token 列字段由 make_token 生成(vitro_lexer/src/lib.rs:448):

column: self.column - text.len() as i32,

self.column 是 advance 逐字符 +1 的计数(1-based),而 text.len() 是 Rust String 的 UTF-8 字节数——两个量纲混算:

  • 纯 ASCII token:字节数 == 字符数,无差——列语义 = 1-based 字符列,正确;
  • 含非 ASCII 的 token(StringLiteral 等):起始列被多扣(字节数 − 字符数), 且叠加扫描路径的 off-by-one,实测 "中文" 形状整体偏移 −4。
探针 报错 token 正确字符列 实报 偏差
int main(){ int "ab"; } String "ab" 17 1:17 0(ASCII)
int main(){ char* "abc"; } String "abc" 19 1:19 0(ASCII)
int "ab";(全局) String "ab" 6 1:6 0(ASCII)
int main(){ int "aaaaaaaaaa"; } String(长 ASCII) 17 1:17 0(长度无关)
int main(){ int "中文"; } String "中文" 17 1:13 −4(原始锚)
int main(){ int 5x; } Literal 5 17 1:17 0(ASCII token 自洽)

两路径区分本身是关键发现(第八轮复核):词法路径字符列自洽(+1 规律稳定), 偏差集中在解析路径的非 ASCII token 列字段;ASCII 全对——差分锚用例必须 覆盖非 ASCII 形状,纯 ASCII 探针对此缺陷零感。

2. MoonBit vitro/source 坐标契约(S1 T1 输入)

以本档案现状为反面输入,S1 vitro/source 的 SourceLoc 契约:

  1. 主坐标 = 字节偏移 + 1(byte_off):单值、全路径唯一语义(词法/解析/ 诊断共用),从行首起算的 UTF-8 字节偏移,1-based 与本仓库现状列显示对齐;
  2. 双坐标预留:Pos{byte_off, col_scalar, col_utf16}——col_scalar 为 Unicode 字符列(现状词法语义),col_utf16 为 JS 生态列语义(前端/协议 消费方);三值同源派生,任一可由 byte_off + 行首信息重算;
  3. 禁止字节/字符量纲混算(make_token 的根因模式):token 起始列必须取 进入扫描前的快照,禁止"扫描后计数 − 长度"的回推;
  4. 词法 +1 现状不复刻:报错列应指向非法字符本体(字符列/字节偏移), 不继承"advance 后报错"的 +1;
  5. 诊断帧列字段语义在 S1 锚(E3 诊断帧)冻结时以本契约为准。

3. 防漂移锚

native/tests/source_column_convention_test.rs:§1 两个矩阵共 10 个形状 全部固化为精确断言(编译 → 断言 (line, column, code) 三元组)。该锚的意义:

  • Rust oracle 侧:列口径的任何无意变化(词法/解析重构触碰 column 语义) 立即红——冻结不是口头约定而是测试防线;
  • MoonBit 侧对拍:E3 诊断帧锚建立时,本矩阵即两侧列号差异的已登记 差异清单(MoonBit 按契约 §2 出列,不再与 Rust 侧的 −4/+1 对齐—— 差分时这两类形状列入已知差异而非缺陷)。