冻结日期: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(
byte_off):单值、全路径唯一语义(词法/解析/ 诊断共用),从行首起算的 UTF-8 字节偏移,1-based 与本仓库现状列显示对齐; - 双坐标预留:
Pos{byte_off, col_scalar, col_utf16}——col_scalar为 Unicode 字符列(现状词法语义),col_utf16为 JS 生态列语义(前端/协议 消费方);三值同源派生,任一可由 byte_off + 行首信息重算; - 禁止字节/字符量纲混算(make_token 的根因模式):token 起始列必须取 进入扫描前的快照,禁止"扫描后计数 − 长度"的回推;
- 词法 +1 现状不复刻:报错列应指向非法字符本体(字符列/字节偏移), 不继承"advance 后报错"的 +1;
- 诊断帧列字段语义在 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 对齐—— 差分时这两类形状列入已知差异而非缺陷)。