diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5c5f07bf..fe16d163 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,22 +1,22 @@ # 贡献指南 Core 的开发流程参考 Rust/Linux:**main 即 mainline,任何人(含维护者)不得直推**。 -全部改动经 PR + 审查 + 合入门槛进入 main。 +全部改动经 PR、审查与合入门槛进入 main。 ## 流程 -1. **fork 仓库**,在 fork 上建 feature 分支(`fix/xxx`、`feat/xxx`、`docs/xxx`) -2. 提交改动(请用 jj,见下),推送分支 +1. **fork 仓库**,在 fork 上建立 feature 分支(`fix/xxx`、`feat/xxx`、`docs/xxx`)。 +2. 提交改动(使用 jj,见下节),并推送分支。 3. **开 PR——base 指向 `develop` 集成分支**(main 不接受直接合入;main 的合入仅维护者可执行),按 `.github/pull_request_template.md` 填写: - - 变更描述、测试记录、语义保鲜影响(IR/类型语义是否变化) -4. 等待审查(≥1 审批,审批人限维护者) -5. 审批通过且 PR 层 CI 全绿后,维护者手动 **squash 合入 develop**(merge queue 因免费计划不可用,已降级;见 spec §3.3),源分支由 GitHub 自动删除 + - 变更描述、测试记录、语义保鲜影响(IR/类型语义是否变化)。 +4. 等待审查(≥1 审批,审批人限维护者)。 +5. 审批通过且 PR 层 CI 全绿后,维护者手动 **squash 合入 develop**(merge queue 因免费计划不可用,已降级;见 spec §3.3),源分支由 GitHub 自动删除。 ## 铁律 -- **全面使用 jj,禁止 `git` 命令**(仓库为 jj colocated 形态;维护者本地 Claude Code hook 会拦截 git) -- 长时间编译/测试任务限速运行(`cpulimit -l 10` 或 `nice -n 19`) -- 文件还原必须经维护者明确许可 +- **全面使用 jj,禁止 `git` 命令**(仓库为 jj colocated 形态;维护者本地 Claude Code hook 会拦截 git)。 +- 长时间编译或测试任务限速运行(`cpulimit -l 10` 或 `nice -n 19`)。 +- 文件还原必须经维护者明确许可。 ## 构建与测试 @@ -30,19 +30,19 @@ python3 tests/selfhost/test_compile.py # 自举编译器测试 # tests/suite/*.cr 为集成测试:./build/corec build FILE.cr -o OUT --static && ./OUT ``` -CI 与本地跑同一套命令(`src/ci/run.sh`,按 `CI_JOB_NAME` 分发)。 +CI 与本地运行同一套命令(`src/ci/run.sh`,按 `CI_JOB_NAME` 分发)。 ## 编码约定 -- 全部数组为动态字节缓冲(`string` + grow 函数),无 `MAX_*` 上限 -- 扁平 AST / 扁平 IR(每节点为 `{kind, a, b, c, ...}` 结构) -- 每个目录的 `_import.cr` 集中管理共享导入 -- 关键字以 `src/compiler/lexer.cr` 为准(唯一) -- 文档(`docs/`)更新与实现同步;伪代码文档(`docs/pseudocode/`)由源码生成,改源码后须重跑 `tools/pseudocode_check.py` +- 全部数组为动态字节缓冲(`string` + grow 函数),无 `MAX_*` 上限。 +- 扁平 AST / 扁平 IR(每节点为 `{kind, a, b, c, ...}` 结构)。 +- 每个目录的 `_import.cr` 集中管理共享导入。 +- 关键字以 `src/compiler/lexer.cr` 为准(唯一)。 +- 文档(`docs/`)更新与实现同步;伪代码文档(`docs/pseudocode/`)由源码生成,改动源码后须重跑 `tools/pseudocode_check.py`。 ## 审查标准 -- 不绕过问题(root cause 直修) -- 语义保鲜:IR 全程保留类型/语义信息 -- 惰性/数据流优化不改变程序输出 -- 测试随变更更新 +- 不绕过问题(root cause 直修)。 +- 语义保鲜:IR 全程保留类型/语义信息。 +- 惰性/数据流优化不改变程序输出。 +- 测试随变更更新。 diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 9ec0175a..e74a5f09 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -2,7 +2,7 @@ ## 报告漏洞 -请通过 GitHub 的 **私有漏洞报告**(仓库页 → Security → Report a vulnerability)提交, +请通过 GitHub 的**私有漏洞报告**(仓库页 → Security → Report a vulnerability)提交, 不要公开披露。 ## 响应 @@ -11,5 +11,5 @@ ## 范围 -编译器本身(`src/compiler/`)、运行时(`src/runtime/`)、生成代码的正确性。 -生成代码/编译器的安全问题按严重程度处理。 +范围为编译器本身(`src/compiler/`)、运行时(`src/runtime/`)与生成代码的正确性。 +生成代码与编译器的安全问题按严重程度处理。 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 267e8365..8ce7b3cb 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,17 +1,17 @@ ## 变更描述 - + ## 测试 - + - [ ] 本地测试通过 ## 语义保鲜影响 - + ## 已知限制 / 后续 - + diff --git a/CHANGELOG.md b/CHANGELOG.md index 4874ac95..92b701df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # 更新日志 > 说明:本文档记录里程碑级变更。近期每日开发流水、预存 bug 与架构规划以 `TODO.md` 为准。 -> 2026-06-21 至 2026-07-23 之间曾存在文档缺失期,以下条目按提交历史与 TODO.md 补齐。 +> 2026-06-21 至 2026-07-23 之间曾存在文档缺失期,以下条目按提交历史与 `TODO.md` 补齐。 ## 2026-09-17 ### [change] `@no_bounds_check` 更名为 `@NoBoundsCheck` @@ -22,7 +22,7 @@ - 函数地址支持:IR_FNADDR + `@addr` 内建(checker/ir_gen/ELF 后端全链路)。 - 并发集成:g_set_curg/g_get_curg 桥接 + M worker 线程池接线。 - 主线程注册为 G 0,可经 channel 阻塞/唤醒;sched_yield 不再重排 Gwaiting。 -- 多 M 线程完整验证仍待补(见 TODO.md 预存 bug 第 2 条)。 +- 多 M 线程完整验证仍待补(见 `TODO.md` 预存 bug 第 2 条)。 ## 2026-07-30 ### [fix] restore directory builds @@ -42,7 +42,7 @@ ## 2026-07-28 ### [feat] arena memory model, @ builtins, incremental cache, hotpatch, pointer-model passes - Arena 内存模型完整实现(`src/stdlib/arena.cr`):init/new/reset 生命周期、动态元数据、free list、嵌套;IR 子图绑定(函数/loop/for/unsafe 自动 arena);ELF 双路径 alloc(arena 感知 + 全局 bump 回退);IR_ARENA_NEW(32)/IR_ARENA_RESET(33) 编码;mmap 堆扩展(BSS 打满自动 mmap 1GB)。 -- `@` 内建原语 12 个全部完整:`@sizeOf/@alignOf/@fields/@hasField/@field/@typeInfo/@comptime/@inline/@no_bounds_check/@fast/@unroll/@section`(后增 `@addr`、`@hotpatch`,见 07-31/07-30)。 +- `@` 内建原语 12 个已全部实现:`@sizeOf/@alignOf/@fields/@hasField/@field/@typeInfo/@comptime/@inline/@no_bounds_check/@fast/@unroll/@section`(后增 `@addr`、`@hotpatch`,见 07-31/07-30)。 - 增量缓存(函数级 .cir,默认开启):`cir_cache.cr` save/load 每函数快照,`clean-cache` 子命令。 - `@hotpatch` 滚动更新:IR_HOTPATCH_ROUTE(39) + parser `@hotpatch(ver=N)` + checker 多版本签名校验 + ELF 编码 + SIGHUP 信号处理。 - 指针模型三 pass 实现(PointerAnalysis/RegionCheck/ProvenanceVerify):DEREF 后端 cmp+jae+ud2 边界检查(s3 编码 alloc_size)、运行时 prov_table 堆边界检查 patch、arena BSS 全局。 @@ -159,13 +159,13 @@ Known issue: name_idx in .ccr is off by 1 (first string index mismatch) ### [fix] use index comparison for main lookup - Replace str_get() comparison with direct index comparison in elf.cr -### [fix] pipeline from source to binary now works! +### [fix] pipeline from source to binary now works Root cause: g_str_count = 0 after tokenize() reset the string table, ### [feat] BSS global variable support in ELF backend - Add g_x86_is_global/g_x86_global_off arrays to track BSS vars ### [feat] dynamic linking - external call relocation recording - IR_CALL to unknown functions now records ext_rel entries instead of -### [feat] dynamic linking with PLT/GOT works! +### [feat] dynamic linking with PLT/GOT works Bug fix: PLT j loop missing 'break' caused infinite loop in emit(). ### [feat] standard library .so files - Build core_io.so and core_math.so from src/stdlib/*.cr @@ -237,13 +237,13 @@ ### [refactor] measure _start size via emit_start_size() instead of hardcoded 22 - Extract _start emission into emit_start() function ### [refactor] instruction sizes via _size() functions (Hexagon pessimistic) -### [fix] massive landmine cleanup — dynamic arrays, dynamic linking, instr fixes, va/offset bugs +### [fix] large-scale landmine cleanup — dynamic arrays, dynamic linking, instr fixes, va/offset bugs - Converted all [int; N]/[string; N] arrays to dynamic string buffers ### [docs] add hard rules — ban git, use jj, no bypassing, no reverting ## 2026-06-18 -### [fix] 扫清全部隐患 — CLI 子命令 + 6 个未初始化数组 + batch:= 解析 + 边界校验 - CLI 重构: +### [fix] 清理全部隐患 — CLI 子命令 + 6 个未初始化数组 + batch:= 解析 + 边界校验 + CLI 重构: ### [fix] 3 parser fixes — parse_primary advance_tok, local_stmts 256-limit, parse_for_expr C-style guard ### [fix] string interpolation parser infinite loop on unterminated { — cli.cr crash root cause ### [fix] string interpolation infinite loop when { without } diff --git a/CLAUDE.md b/CLAUDE.md index f246c875..77bb8754 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -56,7 +56,7 @@ jj git fetch && jj bookmark move main -r main@origin ```bash # Build self-hosted compiler (Python bootstrap → native binary) -python3 build_selfhost_native.py # Produces build/corec + build/corearch +python3 build_selfhost_native.py # 产出三个:build/corec · build/corearch · build/corelsp # Self-hosted frontend: .cr → .ccr/.cir ./build/corec build FILE.cr -o OUTPUT --static @@ -73,22 +73,70 @@ python3 build_selfhost_native.py # Produces build/corec + build/corearch # Dataflow graph dump ./build/corec cir FILE.cr -# 格形态 IR dump(v8 = 段表 8 段:STR/SYM/NOD/ENT/REG/EDG + TYPE(7)/IFACE(8)) +# 格形态 IR dump(v9 = 段表 8 段:STR/SYM/NOD/ENT/REG/EDG + TYPE(7)/IFACE(8); +# 版本真源 = src/compiler/ccr_io.cr::CCR_VERSION,load 校验 ==9 且拒收 v8 及更早) ./build/corec ccr FILE.cr + +# Project mode:目录(Core.toml + main.cr + _import.cr)整体构建 +./build/corec build src/targets/x86_64-linux -o OUT --static + +# 增量缓存 + 引擎自测通道(判定面自测,非构建) +./build/corec clean-cache +./build/corec selftest-types # 类型项引擎用例表(400+ 例) +./build/corec selftest-purity # 真纯度计算自测通道 ``` -### Test suites +**构建脚本的两个结构性事实**(读 `build_selfhost_native.py` 才看得到,勿凭文件名推断): + +1. **清单 = 单元归属真源**。脚本按 `common_files` / `hit_engine_files` / `kernel_files` / + `arch_x86_64_files` / `format_elf_files` / `os_linux_files` / `backend_support_files` / + `corec_files` / `corelsp_files` / `x86_linux_target_files` 逐条列出全路径后 concat 成 + **单一扁平编译单元**(逐文件剥 `import` 行)。**段内/段间的相对顺序 = 行为定义面** + (平铺单元的声明序/全局序),搬迁文件必须保序。→ 判断「某文件属谁、是否在编译」以本脚本为准, + 不是以目录位置或 `_import.cr` 为准。 +2. **两道构建守卫**(吸收 ld 单元静默缺陷教训):① `guard_manifest` 清单文件存在性断言; + ② `guard_build_log` 本阶段日志 `error[` 计数与未定义符号计数必须为 0。project-mode 面 + (`corec build
'");
- return 1;
- }
- g_source = cli_arg(0);
- g_source_dir = dirname(cli_arg(0));
+ if cli_eq(cmd, "run"):
+ if cli_arg_count() < 1:
+ println("error: run requires code to execute")
+ println("usage: corec run ''")
+ return 1
+ g_source = cli_arg(0)
+ g_source_dir = dirname(cli_arg(0))
// Check if source already has 'fn main'
- has_main : ., mut = 0;
- si2 : ., mut = 0;
- sl2 := str_len(g_source);
- loop {
- if si2 >= sl2 { break; }
- c0 := load8(g_source, si2);
- if c0 == 102 {
- if si2 + 6 < sl2 {
- if load8(g_source, si2) == 102 &&
- load8(g_source, si2 + 1) == 110 &&
- load8(g_source, si2 + 2) == 32 &&
- load8(g_source, si2 + 3) == 109 &&
- load8(g_source, si2 + 4) == 97 &&
- load8(g_source, si2 + 5) == 105 &&
- load8(g_source, si2 + 6) == 110 {
- has_main = 1;
- break;
- }
- }
- }
- si2 = si2 + 1;
- }
-
- if has_main == 0 {
- imports : ., mut = "";
- src2 : ., mut = "";
- ii : ., mut = 0;
- ilen := str_len(g_source);
- loop {
- if ii >= ilen { break; }
- if ii + 6 < ilen {
- c := load8(g_source, ii);
- c_prev : ., mut = 59;
- if ii > 0 { c_prev = load8(g_source, ii - 1); }
- if (ii == 0 || c_prev == 59 || c_prev == 10) &&
- load8(g_source, ii) == 105 &&
- load8(g_source, ii + 1) == 109 &&
- load8(g_source, ii + 2) == 112 &&
- load8(g_source, ii + 3) == 111 &&
- load8(g_source, ii + 4) == 114 &&
- load8(g_source, ii + 5) == 116 {
- ij : ., mut = ii;
- loop {
- if ij >= ilen { break; }
- if load8(g_source, ij) == 59 { ij = ij + 1; break; }
- ij = ij + 1;
- }
- imports = imports + str_sub(g_source, ii, ij - ii);
- ii = ij;
- continue;
- }
- }
- src2 = src2 + get_char(g_source, ii);
- ii = ii + 1;
- }
- g_source = src2;
-
- has_semi : ., mut = 0;
- si2 : ., mut = 0;
- loop {
- if si2 >= str_len(g_source) { break; }
- if get_char(g_source, si2) == ";" { has_semi = 1; break; }
- si2 = si2 + 1;
- }
- if has_semi != 0 {
- last_semi : ., mut = -1;
- ls : ., mut = 0;
- loop {
- if ls >= str_len(g_source) { break; }
- if get_char(g_source, ls) == ";" { last_semi = ls; }
- ls = ls + 1;
- }
- if last_semi >= 0 {
+ has_main : ., mut = 0
+ si2 : ., mut = 0
+ sl2 := str_len(g_source)
+ loop:
+ if si2 >= sl2:
+ break
+ c0 := load8(g_source, si2)
+ if c0 == 102:
+ if si2 + 6 < sl2:
+ if load8(g_source, si2) == 102 && load8(g_source, si2 + 1) == 110 && load8(g_source, si2 + 2) == 32 && load8(g_source, si2 + 3) == 109 && load8(g_source, si2 + 4) == 97 && load8(g_source, si2 + 5) == 105 && load8(g_source, si2 + 6) == 110:
+ has_main = 1
+ break
+ si2 = si2 + 1
+
+ if has_main == 0:
+ imports : ., mut = ""
+ src2 : ., mut = ""
+ ii : ., mut = 0
+ ilen := str_len(g_source)
+ loop:
+ if ii >= ilen:
+ break
+ if ii + 6 < ilen:
+ c := load8(g_source, ii)
+ c_prev : ., mut = 59
+ if ii > 0:
+ c_prev = load8(g_source, ii - 1)
+ if (ii == 0 || c_prev == 59 || c_prev == 10) && load8(g_source, ii) == 105 && load8(g_source, ii + 1) == 109 && load8(g_source, ii + 2) == 112 && load8(g_source, ii + 3) == 111 && load8(g_source, ii + 4) == 114 && load8(g_source, ii + 5) == 116:
+ ij : ., mut = ii
+ loop:
+ if ij >= ilen:
+ break
+ if load8(g_source, ij) == 59:
+ ij = ij + 1
+ break
+ ij = ij + 1
+ imports = imports + str_sub(g_source, ii, ij - ii)
+ ii = ij
+ continue
+ src2 = src2 + get_char(g_source, ii)
+ ii = ii + 1
+ g_source = src2
+
+ has_semi : ., mut = 0
+ si2 : ., mut = 0
+ loop:
+ if si2 >= str_len(g_source):
+ break
+ if get_char(g_source, si2) == ";":
+ has_semi = 1
+ break
+ si2 = si2 + 1
+ if has_semi != 0:
+ last_semi : ., mut = -1
+ ls : ., mut = 0
+ loop:
+ if ls >= str_len(g_source):
+ break
+ if get_char(g_source, ls) == ";":
+ last_semi = ls
+ ls = ls + 1
+ if last_semi >= 0:
last_expr := str_sub(g_source, last_semi + 1,
- str_len(g_source) - last_semi - 1);
- body := str_sub(g_source, 0, last_semi + 1);
- if is_decl_stmt(last_expr) != 0 {
- g_source = imports + "fn main() -> int {\n" + body + "\n" + last_expr + ";\nreturn 0;\n}\n";
- } else {
- has_lcall : ., mut = 0;
- lci : ., mut = 0;
- lclen := str_len(last_expr);
- loop {
- if lci >= lclen { break; }
- if load8(last_expr, lci) == 40 { has_lcall = 1; break; }
- lci = lci + 1;
- }
- if has_lcall != 0 {
- g_source = imports + "fn main() -> int {\n" + body + last_expr + ";\nreturn 0;\n}\n";
- } else {
- g_source = imports + "fn main() -> int {\n" + body + "\nreturn " + last_expr + ";\n}\n";
- }
- }
- } else {
- g_source = imports + "fn main() -> int {\n" + g_source + ";\nreturn 0;\n}\n";
- }
- } else {
- if is_decl_stmt(g_source) != 0 {
- g_source = imports + "fn main() -> int {\n" + g_source + ";\nreturn 0;\n}\n";
- } else {
- has_call : ., mut = 0;
- ci3 : ., mut = 0;
- clen := str_len(g_source);
- loop {
- if ci3 >= clen { break; }
- if load8(g_source, ci3) == 40 { has_call = 1; break; }
- ci3 = ci3 + 1;
- }
- if has_call != 0 {
- g_source = imports + "fn main() -> int {\n" + g_source + ";\nreturn 0;\n}\n";
- } else {
- g_source = imports + "fn main() -> int {\nreturn " + g_source + ";\n}\n";
- }
- }
- }
- }
-
- run_rc := run_frontend();
- if run_rc != 0 { return 1; }
- ir_gen_all();
- return ir_interpret();
- }
+ str_len(g_source) - last_semi - 1)
+ body := str_sub(g_source, 0, last_semi + 1)
+ if is_decl_stmt(last_expr) != 0:
+ g_source = imports + "fn main() -> int {\n" + body + "\n" + last_expr + ";\nreturn 0;\n}\n"
+ else:
+ has_lcall : ., mut = 0
+ lci : ., mut = 0
+ lclen := str_len(last_expr)
+ loop:
+ if lci >= lclen:
+ break
+ if load8(last_expr, lci) == 40:
+ has_lcall = 1
+ break
+ lci = lci + 1
+ if has_lcall != 0:
+ g_source = imports + "fn main() -> int {\n" + body + last_expr + ";\nreturn 0;\n}\n"
+ else:
+ g_source = imports + "fn main() -> int {\n" + body + "\nreturn " + last_expr + ";\n}\n"
+ else:
+ g_source = imports + "fn main() -> int {\n" + g_source + ";\nreturn 0;\n}\n"
+ else:
+ if is_decl_stmt(g_source) != 0:
+ g_source = imports + "fn main() -> int {\n" + g_source + ";\nreturn 0;\n}\n"
+ else:
+ has_call : ., mut = 0
+ ci3 : ., mut = 0
+ clen := str_len(g_source)
+ loop:
+ if ci3 >= clen:
+ break
+ if load8(g_source, ci3) == 40:
+ has_call = 1
+ break
+ ci3 = ci3 + 1
+ if has_call != 0:
+ g_source = imports + "fn main() -> int {\n" + g_source + ";\nreturn 0;\n}\n"
+ else:
+ g_source = imports + "fn main() -> int {\nreturn " + g_source + ";\n}\n"
+
+ run_rc := run_frontend()
+ if run_rc != 0:
+ return 1
+ ir_gen_all()
+ return ir_interpret()
// === clean-cache: delete incremental compilation cache ===
- if cli_eq(cmd, "clean-cache") {
- system("rm -rf .core/cache/cir/");
- print("cleaned ");
- println(".core/cache/cir/");
- return 0;
- }
+ if cli_eq(cmd, "clean-cache"):
+ system("rm -rf .core/cache/cir/")
+ print("cleaned ")
+ println(".core/cache/cir/")
+ return 0
// === selftest-types: 类型项引擎自测(R2 P0)——不读源文件、不产生产物 ===
- if cli_eq(cmd, "selftest-types") { return type_selftest_run(); }
+ if cli_eq(cmd, "selftest-types"):
+ return type_selftest_run()
// === selftest-purity: 效应纯度自测(Task 1)——自建内联源 + 完整前端/IR ===
- if cli_eq(cmd, "selftest-purity") { return purity_selftest_run(); }
+ if cli_eq(cmd, "selftest-purity"):
+ return purity_selftest_run()
// === File-based subcommands: build | check | cir | ccr ===
- if cli_arg_count() < 1 {
- print("error: ");
- print(cmd);
- println(" requires a source file or directory");
- return 1;
- }
- src_path := cli_arg(0);
+ if cli_arg_count() < 1:
+ print("error: ")
+ print(cmd)
+ println(" requires a source file or directory")
+ return 1
+ src_path := cli_arg(0)
- if read_source_or_project(src_path) != 0 { return 1; }
+ if read_source_or_project(src_path) != 0:
+ return 1
// --static: prepend rt.cr so * functions inline
- if cli_has("static") != 0 {
- rt_src := read_static_runtime_source();
- if str_len(rt_src) == 0 {
- println("error: cannot locate src/runtime/rt.cr");
- return 1;
- }
- g_source = rt_src + "\n" + g_source;
- }
+ if cli_has("static") != 0:
+ rt_src := read_static_runtime_source()
+ if str_len(rt_src) == 0:
+ println("error: cannot locate src/runtime/rt.cr")
+ return 1
+ g_source = rt_src + "\n" + g_source
- fe_rc := run_frontend();
- if fe_rc != 0 { return 1; }
+ fe_rc := run_frontend()
+ if fe_rc != 0:
+ return 1
// === check: type-check only ===
- if cli_eq(cmd, "check") {
+ if cli_eq(cmd, "check"):
// F19:type-check 诊断非致命(run_frontend 已打印,build 路径行为不变),
// 但 check 命令必须以非零退出码反映诊断——修复前诊断后仍无条件 return 0。
// 无诊断 → rc=0("ok")。
- if g_diag_count > 0 { return 1; }
- println("ok");
- return 0;
- }
+ if g_diag_count > 0:
+ return 1
+ println("ok")
+ return 0
// === build | cir | ccr all need IR gen ===
// Initialize IR state
- g_ir_var_count = 0;
- g_ir_instr_count = 0;
- g_ir_func_count = 0;
- g_ir_local_count = 0;
- g_ir_local_depth = 0;
- g_ir_global_count = 0;
- g_next_label = 1;
- g_ir_loop_depth = 0;
- g_ir_str_const_count = 0;
- g_ir_source_hash = 0;
- g_ir_source_hash_ready = 0;
- init_df();
+ g_ir_var_count = 0
+ g_ir_instr_count = 0
+ g_ir_func_count = 0
+ g_ir_local_count = 0
+ g_ir_local_depth = 0
+ g_ir_global_count = 0
+ g_next_label = 1
+ g_ir_loop_depth = 0
+ g_ir_str_const_count = 0
+ g_ir_source_hash = 0
+ g_ir_source_hash_ready = 0
+ init_df()
// 可选表示面(R2 P4 Task 5):本路径不经过 ir_gen_all ⇒ 必须自行初始化(侧表复位
// + 启用扫描),且**先于 ir_gen_globals**(隐藏信道的 var 行序依赖)。
- optrep_begin();
- ir_gen_globals();
+ optrep_begin()
+ ir_gen_globals()
// Incremental cache: ensure cache directory exists
- make_cir_cache_dir();
+ make_cir_cache_dir()
// A cached caller does not replay monomorphization, so its specialized
// callee FuncInfo entries would be missing on the next compile.
- cache_enabled : int, mut = 1;
- cache_scan : ., mut = 0;
- loop {
- if cache_scan >= g_func_count { break; }
- if fi_generic_count(cache_scan) > 0 { cache_enabled = 0; break; }
- cache_scan = cache_scan + 1;
- }
+ cache_enabled : int, mut = 1
+ cache_scan : ., mut = 0
+ loop:
+ if cache_scan >= g_func_count:
+ break
+ if fi_generic_count(cache_scan) > 0:
+ cache_enabled = 0
+ break
+ cache_scan = cache_scan + 1
// 可选表示面启用 ⇒ **关 .cir 快照缓存**(R2 P4 Task 5):表示位侧表是**编译期
// 进程内状态**(var → 表示位 var 映射),快照只存指令/节点不存侧表 ⇒ 命中恢复的
// 函数解包点会回落既有装箱路径,与冷路径**产物分歧**(冷/热分歧类,同 Task 4 的
// bad_term 教训)。关缓存 = 每次全量重建 = 正确性优先;非可选程序照常缓存。
- if g_optrep_on != 0 {
- cache_enabled = 0;
- }
+ if g_optrep_on != 0:
+ cache_enabled = 0
// 隐藏 debug(仅判据突变自证用;真构建路径永不注入):跳过装载期 intern 日志重放
// ⇒ v21 缺陷原样复现(判据用它证明「修法确实是被测对象」——突变必须打中目标)。
- if cli_has("inject-cir-skip-journal") != 0 { g_cir_skip_journal = 1; }
+ if cli_has("inject-cir-skip-journal") != 0:
+ g_cir_skip_journal = 1
// Generate IR for each function, checking cache first
- fi : ., mut = 0;
- loop {
- if fi >= g_func_count { break; }
+ fi : ., mut = 0
+ loop:
+ if fi >= g_func_count:
+ break
// Skip generic functions — they are monomorphized at call sites
- if fi_generic_count(fi) > 0 {
- fi = fi + 1;
- continue;
- }
+ if fi_generic_count(fi) > 0:
+ fi = fi + 1
+ continue
// DFG metadata uses the compact IR function index. Source FuncInfo
// indices diverge as soon as a generic function is skipped.
- ir_func_idx := g_ir_func_count;
- df_begin_func(ir_func_idx);
+ ir_func_idx := g_ir_func_count
+ df_begin_func(ir_func_idx)
// Build cache key from source path + function name
- fn_node := fi_ast_node(fi);
- name_ni := ast_a(fn_node);
- name := istr_get(name_ni);
- func_id := src_path + "::" + name;
+ fn_node := fi_ast_node(fi)
+ name_ni := ast_a(fn_node)
+ name := istr_get(name_ni)
+ func_id := src_path + "::" + name
// Sanitize func_id for filesystem: replace / with _
- cache_path : ., mut = ".core/cache/cir/";
- ci : ., mut = 0;
- loop {
- if ci >= str_len(func_id) { break; }
- c := load8(func_id, ci);
- if c == 47 { cache_path = cache_path + "_"; }
- else { cache_path = cache_path + chr(c); }
- ci = ci + 1;
- }
- cache_path = cache_path + ".cir";
+ cache_path : ., mut = ".core/cache/cir/"
+ ci : ., mut = 0
+ loop:
+ if ci >= str_len(func_id):
+ break
+ c := load8(func_id, ci)
+ if c == 47:
+ cache_path = cache_path + "_"
+ else:
+ cache_path = cache_path + chr(c)
+ ci = ci + 1
+ cache_path = cache_path + ".cir"
// Capture current state before cache load
- instr_start := g_ir_instr_count;
- var_start := g_ir_var_count;
+ instr_start := g_ir_instr_count
+ var_start := g_ir_var_count
// Try loading from cache (pass func_idx for signature verification)
- cached : int, mut = -1;
- if cache_enabled != 0 { cached = load_cir_cache(cache_path, fi); }
- if cached == 0 {
+ cached : int, mut = -1
+ if cache_enabled != 0:
+ cached = load_cir_cache(cache_path, fi)
+ if cached == 0:
// Cache hit: setup function metadata for restored data
- func_idx := g_ir_func_count;
- grow_ir_func_meta(func_idx + 1);
- w64(g_ir_func_name_idx, func_idx * 8, name_ni);
- w64(g_ir_func_ret_type, func_idx * 8, fi_return_type(fi));
- w64(g_ir_func_instr_start, func_idx * 8, instr_start);
- w64(g_ir_func_var_start, func_idx * 8, var_start);
- w64(g_ir_func_param_count, func_idx * 8, ast_c(fn_node));
- w64(g_ir_func_instr_count, func_idx * 8, g_ir_instr_count - instr_start);
- w64(g_ir_func_var_count, func_idx * 8, g_ir_var_count - var_start);
- g_ir_func_count = func_idx + 1;
-
- df_end_func(ir_func_idx);
- } else {
+ func_idx := g_ir_func_count
+ grow_ir_func_meta(func_idx + 1)
+ w64(g_ir_func_name_idx, func_idx * 8, name_ni)
+ w64(g_ir_func_ret_type, func_idx * 8, fi_return_type(fi))
+ w64(g_ir_func_instr_start, func_idx * 8, instr_start)
+ w64(g_ir_func_var_start, func_idx * 8, var_start)
+ w64(g_ir_func_param_count, func_idx * 8, ast_c(fn_node))
+ w64(g_ir_func_instr_count, func_idx * 8, g_ir_instr_count - instr_start)
+ w64(g_ir_func_var_count, func_idx * 8, g_ir_var_count - var_start)
+ g_ir_func_count = func_idx + 1
+
+ df_end_func(ir_func_idx)
+ else:
// Cache miss: do full frontend IR gen
// TODO #2026-09-15-5(裁-W1 = (b) 先行,**见证式**一般化):缓存命中会**跳过本函数的生成期
// 副作用**——凡该副作用落在「快照**不携带**的共享空间」上,命中后该空间与冷路径
@@ -582,201 +574,191 @@ fn corec_main() -> int {
// (写侧编号自洽、读侧编号也自洽)而不显形,直到把「同一源两次构建」的产物逐字节
// 对拍才暴露(VER 17/18/19/20 四代全复现,非本代引入)。⇒ **教训:本清单是
// 「已归位实例表」,不是「该类全表」——新增共享面时必须主动对照三条件,别等对拍。**
- tc0 := g_type_count;
+ tc0 := g_type_count
// v21 生成期 intern 日志窗口(见 cir_cache.cr 头注「21」段):本函数生成期间
// 每次新 intern 都记进日志 ⇒ 条目落盘时随之写入;命中装载时按序重放。
- if cache_enabled != 0 { cir_rec_begin(); }
- ir_gen_func(fi);
- if cache_enabled != 0 { cir_rec_end(); }
- df_end_func(ir_func_idx);
+ if cache_enabled != 0:
+ cir_rec_begin()
+ ir_gen_func(fi)
+ if cache_enabled != 0:
+ cir_rec_end()
+ df_end_func(ir_func_idx)
// Save cache only when no side effect on snapshot-uncarried shared faces.
- if cache_enabled != 0 {
- if g_type_count == tc0 { save_cir_cache(cache_path, fi, ir_func_idx); }
- }
- }
+ if cache_enabled != 0:
+ if g_type_count == tc0:
+ save_cir_cache(cache_path, fi, ir_func_idx)
- fi = fi + 1;
- }
+ fi = fi + 1
// === 纯度 + state 链最终化(IR 生成结束、任何链消费者之前)===
// 真纯度只能由全程序 IR 体算(checker.cr compute_all_purity 头注),链的连接
// 依赖真纯度 ⇒ 两者同点时后移(dataflow.cr df_replay_state_chain 头注)。
- df_state_finalize();
+ df_state_finalize()
// === cir: output dataflow graph ===
- if cli_eq(cmd, "cir") {
+ if cli_eq(cmd, "cir"):
// regalloc 判定/条目调试通道(--dump-entries/--dump-coexist/--check-regalloc/
// --inject-*)已随编码决策层迁 corearch(2026-09-07 regalloc 移后端)——
// corearch load .ccr 后自算自检(src/arch/x86_64/regalloc.cr),载体 =
// corearch 同名隐藏 flag。
- dot := df_graph_to_dot();
- out := cli_get("output");
- if str_len(out) == 0 {
- out = default_out_path(src_path, ".cir");
- }
- written := write_file(out, dot);
- if written < 0 {
- print("error: could not write ");
- println(out);
- return 1;
- }
+ dot := df_graph_to_dot()
+ out := cli_get("output")
+ if str_len(out) == 0:
+ out = default_out_path(src_path, ".cir")
+ written := write_file(out, dot)
+ if written < 0:
+ print("error: could not write ")
+ println(out)
+ return 1
// Text dump with region annotations (g_sgs fully populated by the
// df_begin_func/df_end_func + sg_push/sg_pop calls in the IR gen loop above)
- print(cir_text_dump());
- print(" -> ");
- println(out);
+ print(cir_text_dump())
+ print(" -> ")
+ println(out)
// R2 P4 Task 4 测试通道(hidden):逐节点 tk/项槽 dump——冷路径(emit 填槽)
// 与暖路径(.cir 快照读回)用同一通道对拍(test_ccr_types.py 的 T4 节)。
// 时点 = 全图构建完(含命中恢复);只读,不产产物。
- if cli_has("dump-tk-terms") != 0 { print(df_tk_term_dump()); }
- return 0;
- }
+ if cli_has("dump-tk-terms") != 0:
+ print(df_tk_term_dump())
+ return 0
// === Pointer analysis + safety passes (always run, even at opt_level 0) ===
- base_diags := g_diag_count;
- ptr_analysis_all();
- region_check_all();
- provenance_verify_all();
+ base_diags := g_diag_count
+ ptr_analysis_all()
+ region_check_all()
+ provenance_verify_all()
// 修复 5:编译期确定的越界(provenance 诊断)是硬错误——拦截编译。
// 修复前诊断只记录不拦截,越界程序照常生成。
- if g_diag_count > base_diags {
- print_diagnostics();
- return 1;
- }
+ if g_diag_count > base_diags:
+ print_diagnostics()
+ return 1
// === build | ccr need lower_to_ccr ===
// regalloc 移后端(2026-09-07):O2 分配 + 一致性判定已归位 corearch——
// corearch load .ccr 后自算自检(违反 = 编译错误);corec 只留语义层 CSE。
- if g_opt_level >= 1 {
- pass_cse();
- }
- println("lower to ccr...");
- lower_to_ccr();
- print("lower done: ");
- print(int_str(g_ir_func_count));
- print(" funcs, ");
- print(int_str(g_ir_instr_count));
- println(" instrs");
+ if g_opt_level >= 1:
+ pass_cse()
+ println("lower to ccr...")
+ lower_to_ccr()
+ print("lower done: ")
+ print(int_str(g_ir_func_count))
+ print(" funcs, ")
+ print(int_str(g_ir_instr_count))
+ println(" instrs")
// === ccr: output linear CFG ===
- if cli_eq(cmd, "ccr") {
- out := cli_get("output");
- if str_len(out) == 0 {
- out = default_out_path(src_path, ".ccr");
- }
+ if cli_eq(cmd, "ccr"):
+ out := cli_get("output")
+ if str_len(out) == 0:
+ out = default_out_path(src_path, ".ccr")
// Hidden debug (--inject-var-shift): GC-4 test hook — shift func0's var decl
// block start left by 1 (count-level guards can't see it; the position-level
// guard in save_ccr must reject). Real build paths never inject.
- if cli_has("inject-var-shift") != 0 {
- if inject_var_shift() != 0 {
- print("error: inject-var-shift: precondition failed (func0 block start < 1)");
- println("");
- return 1;
- }
- }
+ if cli_has("inject-var-shift") != 0:
+ if inject_var_shift() != 0:
+ print("error: inject-var-shift: precondition failed (func0 block start < 1)")
+ println("")
+ return 1
// R2 P4 Task 2/3(D13/D14):TYPE/IFACE 段内容构造 = 确定性装填(项层/引擎/
// 桥接复位 → 形状重注册 → 行序装填 → 接口签名项装填)+ 两段体缓冲;save_ccr
// 只按段表搬运缓冲(D18)。装填失败(不可译行/签名项)= 拒绝落盘(rc=1 +
// 诊断——不得产出缺项的类型/接口段)。
- if ccr_seg_prepare_save() != 0 {
- println("error: could not build TYPE/IFACE segments");
- return 1;
- }
+ if ccr_seg_prepare_save() != 0:
+ println("error: could not build TYPE/IFACE segments")
+ return 1
// 测试通道(hidden):载入前 dump 段内容面(行表/项 DAG/probe;接口表/形状/
// 签名项/跨段引用域探针)——与 corearch --dump-types/--dump-ifaces 同一条打印
// 路径(跨进程对拍),见 test_ccr_types.py。
- if cli_has("dump-types") != 0 { ccr_type_selftest_dump(); }
- if cli_has("dump-ifaces") != 0 { ccr_iface_selftest_dump(); }
- r := save_ccr(out);
- if r != 0 {
- print("error: could not write ");
- println(out);
- return 1;
- }
- print(" -> ");
- print(out);
- print(" (");
- print(int_str(g_ir_func_count));
- print(" funcs, ");
- print(int_str(g_ir_instr_count));
- println(" instrs)");
- return 0;
- }
+ if cli_has("dump-types") != 0:
+ ccr_type_selftest_dump()
+ if cli_has("dump-ifaces") != 0:
+ ccr_iface_selftest_dump()
+ r := save_ccr(out)
+ if r != 0:
+ print("error: could not write ")
+ println(out)
+ return 1
+ print(" -> ")
+ print(out)
+ print(" (")
+ print(int_str(g_ir_func_count))
+ print(" funcs, ")
+ print(int_str(g_ir_instr_count))
+ println(" instrs)")
+ return 0
// === build: compile + link to ELF ===
- out_path : ., mut = cli_get("output");
- if str_len(out_path) == 0 {
- out_path = default_out_path(src_path, "");
- }
+ out_path : ., mut = cli_get("output")
+ if str_len(out_path) == 0:
+ out_path = default_out_path(src_path, "")
// Save .ccr alongside output (real IR artifact)
- println("save .ccr...");
- ccr_path : ., mut = out_path + ".ccr";
+ println("save .ccr...")
+ ccr_path : ., mut = out_path + ".ccr"
// R2 P4 Task 2/3(D13/D14/D18):TYPE/IFACE 段装填 + 段体缓冲(同 ccr 分支;
// 前置核查 = 本点之后无类型项/接口消费者——其后仅拼 corearch 命令行并子进程执行)。
- if ccr_seg_prepare_save() != 0 {
- println("error: could not build TYPE/IFACE segments");
- return 1;
- }
- r := save_ccr(ccr_path);
- if r != 0 { println("error: could not write .ccr"); return 1; }
- println("generate ELF...");
+ if ccr_seg_prepare_save() != 0:
+ println("error: could not build TYPE/IFACE segments")
+ return 1
+ r := save_ccr(ccr_path)
+ if r != 0:
+ println("error: could not write .ccr")
+ return 1
+ println("generate ELF...")
// Call corearch to produce ELF
- cmd2 : ., mut = "corearch ";
- cmd2 = cmd2 + ccr_path + " --elf";
- if g_opt_level > 0 { cmd2 = cmd2 + " --opt-level " + int_str(g_opt_level); }
- if cli_has("static") != 0 {
- cmd2 = cmd2 + " --static";
- } else {
- cmd2 = cmd2 + " --link auto";
- }
- cmd2 = cmd2 + " -o " + out_path;
- self_path := get_arg(0);
- sl2 := str_len(self_path);
- if sl2 > 0 {
- last_slash : ., mut = -1;
- si : ., mut = 0; loop { if si >= sl2 { break; }
- if load8(self_path, si) == 47 { last_slash = si; } si = si + 1; }
- if last_slash >= 0 {
- dir2 := str_sub(self_path, 0, last_slash + 1);
- cmd2 = dir2 + cmd2;
- }
- }
- exit_code := system(cmd2);
- if exit_code != 0 {
+ cmd2 : ., mut = "corearch "
+ cmd2 = cmd2 + ccr_path + " --elf"
+ if g_opt_level > 0:
+ cmd2 = cmd2 + " --opt-level " + int_str(g_opt_level)
+ if cli_has("static") != 0:
+ cmd2 = cmd2 + " --static"
+ else:
+ cmd2 = cmd2 + " --link auto"
+ cmd2 = cmd2 + " -o " + out_path
+ self_path := get_arg(0)
+ sl2 := str_len(self_path)
+ if sl2 > 0:
+ last_slash : ., mut = -1
+ si : ., mut = 0
+ loop:
+ if si >= sl2:
+ break
+ if load8(self_path, si) == 47:
+ last_slash = si
+ si = si + 1
+ if last_slash >= 0:
+ dir2 := str_sub(self_path, 0, last_slash + 1)
+ cmd2 = dir2 + cmd2
+ exit_code := system(cmd2)
+ if exit_code != 0:
// fail-closed 零产物(裁-FC-6):corearch 失败 ⇒ 删除**本次** save_ccr 写下的 `.ccr`
// 半成品(`save_ccr` 已覆盖同名旧文件 ⇒ 删除不额外损失;**未创建者不删**——不删目标 ELF
// 的既有旧文件,见本批报告「零产物边界」)。
- system("rm -f \"" + ccr_path + "\"");
- }
- return exit_code;
-}
+ system("rm -f \"" + ccr_path + "\"")
+ return exit_code
// Full compilation: source -> assembly (used by tests and programmatic API)
-fn compile_source(source: string) -> string {
- g_source = source;
- tokenize(g_source);
- res_imports();
- parse_all();
- check_all();
- if g_diag_count > 0 {
- err_msg : ., mut = "check errors:";
- ei : ., mut = 0;
- loop {
- if ei >= g_diag_count { break; }
- diag_code := r64(g_diags, ei * DIAG_REC_SIZE);
- diag_msg := load_str_ptr(g_diags, ei * DIAG_REC_SIZE + 8);
- err_msg = err_msg + " [" + int_str(diag_code) + "] " + diag_msg;
- ei = ei + 1;
- }
- return err_msg;
- }
- ir_gen_all();
- lower_to_ccr();
- return "ok";
-}
+fn compile_source(source: string) -> string:
+ g_source = source
+ tokenize(g_source, 0)
+ res_imports()
+ parse_all()
+ check_all()
+ if g_diag_count > 0:
+ err_msg : ., mut = "check errors:"
+ ei : ., mut = 0
+ loop:
+ if ei >= g_diag_count:
+ break
+ diag_code := r64(g_diags, ei * DIAG_REC_SIZE)
+ diag_msg := load_str_ptr(g_diags, ei * DIAG_REC_SIZE + 8)
+ err_msg = err_msg + " [" + int_str(diag_code) + "] " + diag_msg
+ ei = ei + 1
+ return err_msg
+ ir_gen_all()
+ lower_to_ccr()
+ return "ok"
// Entry point
-fn compiler_main() -> int {
- return corec_main();
-}
+fn compiler_main() -> int:
+ return corec_main()
diff --git a/src/compiler/module.cr b/src/compiler/module.cr
index 1051b11f..fa07f45c 100644
--- a/src/compiler/module.cr
+++ b/src/compiler/module.cr
@@ -6,216 +6,212 @@
// didOpen/didChange 由 LSP 层把路径与源文本复制到稳定堆字符串后注册;
// module_get_source 先查打开文档、未打开才读盘——进程内重跑前端不再依赖磁盘。
-fn grow_open_docs(needed: int) {
- if needed < g_open_doc_cap { return; }
- ncap : ., mut = g_open_doc_cap * 2; if ncap < 8 { ncap = 8; } if ncap < needed { ncap = needed + 8; }
- nb := alloc(ncap * 24); _dyncpy(g_open_docs, g_open_doc_cap * 24, nb);
- g_open_docs = nb; g_open_doc_cap = ncap; }
-
-fn module_open_doc_set(path: string, src: string) {
- i : ., mut = 0;
- loop {
- if i >= g_open_doc_count { break; }
- if str_eq(load_str_ptr(g_open_docs, i * 24), path) != 0 {
- store_str_ptr(g_open_docs, i * 24 + 8, src);
- w64(g_open_docs, i * 24 + 16, str_len(src));
- return;
- }
- i = i + 1;
- }
- grow_open_docs(g_open_doc_count + 1);
- store_str_ptr(g_open_docs, g_open_doc_count * 24, path);
- store_str_ptr(g_open_docs, g_open_doc_count * 24 + 8, src);
- w64(g_open_docs, g_open_doc_count * 24 + 16, str_len(src));
- g_open_doc_count = g_open_doc_count + 1;
-}
-
-fn module_open_doc_remove(path: string) {
- i : ., mut = 0;
- loop {
- if i >= g_open_doc_count { break; }
- if str_eq(load_str_ptr(g_open_docs, i * 24), path) != 0 {
- j : ., mut = i + 1;
- loop {
- if j >= g_open_doc_count { break; }
- store_str_ptr(g_open_docs, (j - 1) * 24, load_str_ptr(g_open_docs, j * 24));
- store_str_ptr(g_open_docs, (j - 1) * 24 + 8, load_str_ptr(g_open_docs, j * 24 + 8));
- w64(g_open_docs, (j - 1) * 24 + 16, r64(g_open_docs, j * 24 + 16));
- j = j + 1;
- }
- g_open_doc_count = g_open_doc_count - 1;
- return;
- }
- i = i + 1;
- }
-}
+fn grow_open_docs(needed: int):
+ if needed < g_open_doc_cap:
+ return
+ ncap : ., mut = g_open_doc_cap * 2
+ if ncap < 8:
+ ncap = 8
+ if ncap < needed:
+ ncap = needed + 8
+ nb := alloc(ncap * 24)
+ _dyncpy(g_open_docs, g_open_doc_cap * 24, nb)
+ g_open_docs = nb
+ g_open_doc_cap = ncap
+
+fn module_open_doc_set(path: string, src: string):
+ i : ., mut = 0
+ loop:
+ if i >= g_open_doc_count:
+ break
+ if str_eq(load_str_ptr(g_open_docs, i * 24), path) != 0:
+ store_str_ptr(g_open_docs, i * 24 + 8, src)
+ w64(g_open_docs, i * 24 + 16, str_len(src))
+ return
+ i = i + 1
+ grow_open_docs(g_open_doc_count + 1)
+ store_str_ptr(g_open_docs, g_open_doc_count * 24, path)
+ store_str_ptr(g_open_docs, g_open_doc_count * 24 + 8, src)
+ w64(g_open_docs, g_open_doc_count * 24 + 16, str_len(src))
+ g_open_doc_count = g_open_doc_count + 1
+
+fn module_open_doc_remove(path: string):
+ i : ., mut = 0
+ loop:
+ if i >= g_open_doc_count:
+ break
+ if str_eq(load_str_ptr(g_open_docs, i * 24), path) != 0:
+ j : ., mut = i + 1
+ loop:
+ if j >= g_open_doc_count:
+ break
+ store_str_ptr(g_open_docs, (j - 1) * 24, load_str_ptr(g_open_docs, j * 24))
+ store_str_ptr(g_open_docs, (j - 1) * 24 + 8, load_str_ptr(g_open_docs, j * 24 + 8))
+ w64(g_open_docs, (j - 1) * 24 + 16, r64(g_open_docs, j * 24 + 16))
+ j = j + 1
+ g_open_doc_count = g_open_doc_count - 1
+ return
+ i = i + 1
// 先查打开文档(路径精确匹配),未打开读盘;两者皆无返回 ""
-fn module_get_source(path: string) -> string {
- i : ., mut = 0;
- loop {
- if i >= g_open_doc_count { break; }
- if str_eq(load_str_ptr(g_open_docs, i * 24), path) != 0 {
- return load_str_ptr(g_open_docs, i * 24 + 8);
- }
- i = i + 1;
- }
- return read_file(path);
-}
-
-fn count_newlines(s: string) -> int {
- slen := str_len(s);
- n : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= slen { break; }
- if str_eq(get_char(s, i), "\n") != 0 { n = n + 1; }
- i = i + 1;
- }
- return n;
-}
-
-fn get_fileid(s: string) -> string {
- slen := str_len(s);
- i : ., mut = 0;
- loop {
- if i + 6 >= slen { return ""; }
+fn module_get_source(path: string) -> string:
+ i : ., mut = 0
+ loop:
+ if i >= g_open_doc_count:
+ break
+ if str_eq(load_str_ptr(g_open_docs, i * 24), path) != 0:
+ return load_str_ptr(g_open_docs, i * 24 + 8)
+ i = i + 1
+ return read_file(path)
+
+fn count_newlines(s: string) -> int:
+ slen := str_len(s)
+ n : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= slen:
+ break
+ if str_eq(get_char(s, i), "\n") != 0:
+ n = n + 1
+ i = i + 1
+ return n
+
+fn get_fileid(s: string) -> string:
+ slen := str_len(s)
+ i : ., mut = 0
+ loop:
+ if i + 6 >= slen:
+ return ""
// Inline "fileid" check — int-based, no str_sub/str_eq
- if load8(s, i) == 102 && load8(s, i+1) == 105 && load8(s, i+2) == 108 &&
- load8(s, i+3) == 101 && load8(s, i+4) == 105 && load8(s, i+5) == 100 {
- j : ., mut = i + 6;
- loop {
- if j >= slen { return ""; }
- if load8(s, j) == 34 { // '"'
- start := j + 1;
- k : ., mut = start;
- loop {
- if k >= slen { return ""; }
- if load8(s, k) == 34 { // '"'
- return str_sub(s, start, k - start);
- }
- k = k + 1;
- }
- }
- j = j + 1;
- }
- }
- i = i + 1;
- }
- return "";
-}
-
-fn dirname(path: string) -> string {
- slen := str_len(path);
- last_slash : ., mut = -1;
- i : ., mut = 0;
- loop {
- if i >= slen { break; }
- if str_eq(get_char(path, i), "/") != 0 { last_slash = i; }
- i = i + 1;
- }
- if last_slash >= 0 {
- return str_sub(path, 0, last_slash + 1);
- }
- return "";
-}
-
-fn basename(path: string) -> string {
- slen := str_len(path);
- if slen == 0 { return ""; }
- end : ., mut = slen;
+ if load8(s, i) == 102 && load8(s, i+1) == 105 && load8(s, i+2) == 108 && load8(s, i+3) == 101 && load8(s, i+4) == 105 && load8(s, i+5) == 100:
+ j : ., mut = i + 6
+ loop:
+ if j >= slen:
+ return ""
+ if load8(s, j) == 34:
+ // '"'
+ start := j + 1
+ k : ., mut = start
+ loop:
+ if k >= slen:
+ return ""
+ if load8(s, k) == 34:
+ // '"'
+ return str_sub(s, start, k - start)
+ k = k + 1
+ j = j + 1
+ i = i + 1
+ return ""
+
+fn dirname(path: string) -> string:
+ slen := str_len(path)
+ last_slash : ., mut = -1
+ i : ., mut = 0
+ loop:
+ if i >= slen:
+ break
+ if str_eq(get_char(path, i), "/") != 0:
+ last_slash = i
+ i = i + 1
+ if last_slash >= 0:
+ return str_sub(path, 0, last_slash + 1)
+ return ""
+
+fn basename(path: string) -> string:
+ slen := str_len(path)
+ if slen == 0:
+ return ""
+ end : ., mut = slen
// strip trailing /
- loop {
- if end <= 0 { break; }
- if str_eq(get_char(path, end - 1), "/") != 0 { end = end - 1; }
- else { break; }
- }
- if end == 0 { return "/"; }
- last_slash : ., mut = -1;
- i : ., mut = 0;
- loop {
- if i >= end { break; }
- if str_eq(get_char(path, i), "/") != 0 { last_slash = i; }
- i = i + 1;
- }
- if last_slash >= 0 {
- return str_sub(path, last_slash + 1, end - last_slash - 1);
- }
- return str_sub(path, 0, end);
-}
-
-fn parent_dir(dir: string) -> string {
- slen := str_len(dir);
- if slen <= 1 { return ""; }
- trimmed : ., mut = dir;
- last_ch := get_char(dir, slen - 1);
- if str_eq(last_ch, "/") != 0 {
- trimmed = str_sub(dir, 0, slen - 1);
- }
- last_slash : ., mut = -1;
- i : ., mut = 0;
- tlen := str_len(trimmed);
- loop {
- if i >= tlen { break; }
- if str_eq(get_char(trimmed, i), "/") != 0 { last_slash = i; }
- i = i + 1;
- }
- if last_slash >= 0 {
- return str_sub(trimmed, 0, last_slash + 1);
- }
- return "";
-}
-
-fn load_imports(dir_path: string) -> string {
- imp_path : ., mut = dir_path + "_import.cr";
- content := module_get_source(imp_path);
- if str_len(content) > 0 {
- }
- return content;
-}
-
-fn reg_fileid(fileid_str: string, path: string) -> int {
- fni := str_intern(fileid_str);
- fi : ., mut = 0;
- loop {
- if fi >= g_file_count { break; }
- if r64(g_files, fi * 16) == fni {
- return fni;
- }
- fi = fi + 1;
- }
- grow_files(g_file_count + 1);
- w64(g_files, g_file_count * 16, fni);
- store_str_ptr(g_files, g_file_count * 16 + 8, path);
- g_file_count = g_file_count + 1;
- return fni;
-}
-
-fn build_line_fileid() {
- g_line_count = 0; g_line_cap = 0;
- slen := str_len(g_source);
- seg_idx : ., mut = 0;
- grow_line_file(g_line_count + 1); w64(g_line_fileid, g_line_count * 8, r64(g_seg_fileids, 0));
- g_line_count = g_line_count + 1;
- pos : ., mut = 0;
- loop {
- if pos >= slen { break; }
- if str_eq(get_char(g_source, pos), "\n") != 0 {
- next_start := 0;
- next_fileid := -1;
- if seg_idx + 1 < g_seg_count {
- next_start = r64(g_seg_starts, (seg_idx + 1) * 8);
- next_fileid = r64(g_seg_fileids, (seg_idx + 1) * 8);
- }
- if next_fileid >= 0 && pos + 1 >= next_start {
- seg_idx = seg_idx + 1;
- }
- grow_line_file(g_line_count + 1); w64(g_line_fileid, g_line_count * 8, r64(g_seg_fileids, seg_idx * 8));
- g_line_count = g_line_count + 1;
- }
- pos = pos + 1;
- }
-}
+ loop:
+ if end <= 0:
+ break
+ if str_eq(get_char(path, end - 1), "/") != 0:
+ end = end - 1
+ else:
+ break
+ if end == 0:
+ return "/"
+ last_slash : ., mut = -1
+ i : ., mut = 0
+ loop:
+ if i >= end:
+ break
+ if str_eq(get_char(path, i), "/") != 0:
+ last_slash = i
+ i = i + 1
+ if last_slash >= 0:
+ return str_sub(path, last_slash + 1, end - last_slash - 1)
+ return str_sub(path, 0, end)
+
+fn parent_dir(dir: string) -> string:
+ slen := str_len(dir)
+ if slen <= 1:
+ return ""
+ trimmed : ., mut = dir
+ last_ch := get_char(dir, slen - 1)
+ if str_eq(last_ch, "/") != 0:
+ trimmed = str_sub(dir, 0, slen - 1)
+ last_slash : ., mut = -1
+ i : ., mut = 0
+ tlen := str_len(trimmed)
+ loop:
+ if i >= tlen:
+ break
+ if str_eq(get_char(trimmed, i), "/") != 0:
+ last_slash = i
+ i = i + 1
+ if last_slash >= 0:
+ return str_sub(trimmed, 0, last_slash + 1)
+ return ""
+
+fn load_imports(dir_path: string) -> string:
+ imp_path : ., mut = dir_path + "_import.cr"
+ content := module_get_source(imp_path)
+ // 回流(2026-10-11):同 `main.cr::read_source_file` —— T4 按旧政策整条删除,
+ // **连带删掉一次内存读**;现政策(region 可为空)下回流成 `if …:` + 空 region。
+ if str_len(content) > 0:
+ return content
+
+fn reg_fileid(fileid_str: string, path: string) -> int:
+ fni := str_intern(fileid_str)
+ fi : ., mut = 0
+ loop:
+ if fi >= g_file_count:
+ break
+ if r64(g_files, fi * 16) == fni:
+ return fni
+ fi = fi + 1
+ grow_files(g_file_count + 1)
+ w64(g_files, g_file_count * 16, fni)
+ store_str_ptr(g_files, g_file_count * 16 + 8, path)
+ g_file_count = g_file_count + 1
+ return fni
+
+fn build_line_fileid():
+ g_line_count = 0
+ g_line_cap = 0
+ slen := str_len(g_source)
+ seg_idx : ., mut = 0
+ grow_line_file(g_line_count + 1)
+ w64(g_line_fileid, g_line_count * 8, r64(g_seg_fileids, 0))
+ g_line_count = g_line_count + 1
+ pos : ., mut = 0
+ loop:
+ if pos >= slen:
+ break
+ if str_eq(get_char(g_source, pos), "\n") != 0:
+ next_start := 0
+ next_fileid := -1
+ if seg_idx + 1 < g_seg_count:
+ next_start = r64(g_seg_starts, (seg_idx + 1) * 8)
+ next_fileid = r64(g_seg_fileids, (seg_idx + 1) * 8)
+ if next_fileid >= 0 && pos + 1 >= next_start:
+ seg_idx = seg_idx + 1
+ grow_line_file(g_line_count + 1)
+ w64(g_line_fileid, g_line_count * 8, r64(g_seg_fileids, seg_idx * 8))
+ g_line_count = g_line_count + 1
+ pos = pos + 1
// Register functions from a .so extension index file.
// Index format (one function per line):
@@ -223,163 +219,210 @@ fn build_line_fileid() {
// Examples:
// print: string, variadic, auto_str
// read_file: string -> string
-fn reg_so_funcs(index_content: string, so_name: string) {
- sl := str_len(index_content);
- line_start : ., mut = 0;
- loop {
- if line_start >= sl { break; }
+fn reg_so_funcs(index_content: string, so_name: string):
+ sl := str_len(index_content)
+ line_start : ., mut = 0
+ loop:
+ if line_start >= sl:
+ break
// Find end of line
- line_end : ., mut = line_start;
- loop {
- if line_end >= sl { break; }
- c := load8(index_content, line_end);
- if c == 10 { break; } // \n
- line_end = line_end + 1;
- }
- line := str_sub(index_content, line_start, line_end - line_start);
- line_start = line_end + 1;
+ line_end : ., mut = line_start
+ loop:
+ if line_end >= sl:
+ break
+ c := load8(index_content, line_end)
+ if c == 10:
+ break
+ // \n
+ line_end = line_end + 1
+ line := str_sub(index_content, line_start, line_end - line_start)
+ line_start = line_end + 1
// Skip empty lines and comments
- if str_len(line) == 0 { continue; }
- c0 := load8(line, 0);
- if c0 == 35 || c0 == 10 || c0 == 13 { continue; } // #, \n, \r
+ if str_len(line) == 0:
+ continue
+ c0 := load8(line, 0)
+ if c0 == 35 || c0 == 10 || c0 == 13:
+ continue
+ // #, \n, \r
// Parse: func_name: rest
- colon_pos : ., mut = -1;
- ci : ., mut = 0;
- loop {
- if ci >= str_len(line) { break; }
- if load8(line, ci) == 58 { colon_pos = ci; break; } // :
- ci = ci + 1;
- }
- if colon_pos < 0 { continue; }
- func_name := str_sub(line, 0, colon_pos);
- rest := str_sub(line, colon_pos + 1, str_len(line) - colon_pos - 1);
- if str_len(func_name) == 0 { continue; }
+ colon_pos : ., mut = -1
+ ci : ., mut = 0
+ loop:
+ if ci >= str_len(line):
+ break
+ if load8(line, ci) == 58:
+ colon_pos = ci
+ break
+ // :
+ ci = ci + 1
+ if colon_pos < 0:
+ continue
+ func_name := str_sub(line, 0, colon_pos)
+ rest := str_sub(line, colon_pos + 1, str_len(line) - colon_pos - 1)
+ if str_len(func_name) == 0:
+ continue
// Parse rest into params and tags (comma-separated)
- param_types : ., mut = "";
- ret_type : ., mut = "unit";
- tag_flags : ., mut = 0;
+ param_types : ., mut = ""
+ ret_type : ., mut = "unit"
+ tag_flags : ., mut = 0
// Split rest by -> to get ret type
- arrow_pos : ., mut = -1;
- ai : ., mut = 0; rl := str_len(rest);
- loop {
- if ai + 2 > rl { break; }
- if load8(rest, ai) == 45 && ai + 1 < rl && load8(rest, ai+1) == 62 { // ->
- arrow_pos = ai; break; }
- ai = ai + 1;
- }
-
- params_str : ., mut = "";
- tags_str : ., mut = "";
- if arrow_pos >= 0 {
- params_str = str_sub(rest, 0, arrow_pos);
- ret_str := str_sub(rest, arrow_pos + 2, rl - arrow_pos - 2);
+ arrow_pos : ., mut = -1
+ ai : ., mut = 0
+ rl := str_len(rest)
+ loop:
+ if ai + 2 > rl:
+ break
+ if load8(rest, ai) == 45 && ai + 1 < rl && load8(rest, ai+1) == 62:
+ // ->
+ arrow_pos = ai
+ break
+ ai = ai + 1
+
+ params_str : ., mut = ""
+ tags_str : ., mut = ""
+ if arrow_pos >= 0:
+ params_str = str_sub(rest, 0, arrow_pos)
+ ret_str := str_sub(rest, arrow_pos + 2, rl - arrow_pos - 2)
// ret_str might have tags too after comma
- ret_comma : ., mut = -1;
- rci : ., mut = 0;
- loop { if rci >= str_len(ret_str) { break; }
- if load8(ret_str, rci) == 44 { ret_comma = rci; break; }
- rci = rci + 1; }
- if ret_comma >= 0 {
- ret_type = str_sub(ret_str, 0, ret_comma);
- tags_str = str_sub(ret_str, ret_comma + 1, str_len(ret_str) - ret_comma - 1);
- } else {
- ret_type = ret_str;
+ ret_comma : ., mut = -1
+ rci : ., mut = 0
+ loop:
+ if rci >= str_len(ret_str):
+ break
+ if load8(ret_str, rci) == 44:
+ ret_comma = rci
+ break
+ rci = rci + 1
+ if ret_comma >= 0:
+ ret_type = str_sub(ret_str, 0, ret_comma)
+ tags_str = str_sub(ret_str, ret_comma + 1, str_len(ret_str) - ret_comma - 1)
+ else:
+ ret_type = ret_str
// trim whitespace
- trim_rt : ., mut = "";
- tri : ., mut = 0;
- loop { if tri >= str_len(ret_type) { break; }
- tc := load8(ret_type, tri);
- if tc != 32 { trim_rt = trim_rt + get_char(ret_type, tri); }
- tri = tri + 1; }
- ret_type = trim_rt;
- }
- } else {
- params_str = rest;
- }
+ trim_rt : ., mut = ""
+ tri : ., mut = 0
+ loop:
+ if tri >= str_len(ret_type):
+ break
+ tc := load8(ret_type, tri)
+ if tc != 32:
+ trim_rt = trim_rt + get_char(ret_type, tri)
+ tri = tri + 1
+ ret_type = trim_rt
+ else:
+ params_str = rest
// Split params_str and tags_str by comma
// Params are before the first recognized tag name
- pi : ., mut = 0; pl := str_len(params_str);
- loop {
- if pi >= pl { break; }
+ pi : ., mut = 0
+ pl := str_len(params_str)
+ loop:
+ if pi >= pl:
+ break
// Skip whitespace
- while pi < pl && load8(params_str, pi) == 32 { pi = pi + 1; }
- if pi >= pl { break; }
+ while pi < pl && load8(params_str, pi) == 32:
+ pi = pi + 1
+ if pi >= pl:
+ break
// Find comma or end
- item_end : ., mut = pi;
- while item_end < pl && load8(params_str, item_end) != 44 { item_end = item_end + 1; }
- item := str_sub(params_str, pi, item_end - pi);
+ item_end : ., mut = pi
+ while item_end < pl && load8(params_str, item_end) != 44:
+ item_end = item_end + 1
+ item := str_sub(params_str, pi, item_end - pi)
// Trim whitespace
- while str_len(item) > 0 && load8(item, 0) == 32 { item = str_sub(item, 1, str_len(item)-1); }
- while str_len(item) > 0 && load8(item, str_len(item)-1) == 32 { item = str_sub(item, 0, str_len(item)-1); }
-
- if str_len(item) > 0 {
- if item == "variadic" { tag_flags = tag_flags + TAG_VARIADIC; }
- else if item == "auto_str" { tag_flags = tag_flags + TAG_AUTO_STR; }
- else {
+ while str_len(item) > 0 && load8(item, 0) == 32:
+ item = str_sub(item, 1, str_len(item)-1)
+ while str_len(item) > 0 && load8(item, str_len(item)-1) == 32:
+ item = str_sub(item, 0, str_len(item)-1)
+
+ if str_len(item) > 0:
+ if item == "variadic":
+ tag_flags = tag_flags + TAG_VARIADIC
+ else if item == "auto_str":
+ tag_flags = tag_flags + TAG_AUTO_STR
+ else:
// It's a param type name
- if str_len(param_types) > 0 { param_types = param_types + ","; }
- param_types = param_types + item;
- }
- }
- pi = item_end + 1;
- }
+ if str_len(param_types) > 0:
+ param_types = param_types + ","
+ param_types = param_types + item
+ pi = item_end + 1
// Same for tags_str
- ti : ., mut = 0; tl := str_len(tags_str);
- loop {
- if ti >= tl { break; }
- while ti < tl && load8(tags_str, ti) == 32 { ti = ti + 1; }
- if ti >= tl { break; }
- item_end2 : ., mut = ti;
- while item_end2 < tl && load8(tags_str, item_end2) != 44 { item_end2 = item_end2 + 1; }
- item2 := str_sub(tags_str, ti, item_end2 - ti);
- while str_len(item2) > 0 && load8(item2, 0) == 32 { item2 = str_sub(item2, 1, str_len(item2)-1); }
- while str_len(item2) > 0 && load8(item2, str_len(item2)-1) == 32 { item2 = str_sub(item2, 0, str_len(item2)-1); }
- if item2 == "variadic" { tag_flags = tag_flags + TAG_VARIADIC; }
- else if item2 == "auto_str" { tag_flags = tag_flags + TAG_AUTO_STR; }
- ti = item_end2 + 1;
- }
+ ti : ., mut = 0
+ tl := str_len(tags_str)
+ loop:
+ if ti >= tl:
+ break
+ while ti < tl && load8(tags_str, ti) == 32:
+ ti = ti + 1
+ if ti >= tl:
+ break
+ item_end2 : ., mut = ti
+ while item_end2 < tl && load8(tags_str, item_end2) != 44:
+ item_end2 = item_end2 + 1
+ item2 := str_sub(tags_str, ti, item_end2 - ti)
+ while str_len(item2) > 0 && load8(item2, 0) == 32:
+ item2 = str_sub(item2, 1, str_len(item2)-1)
+ while str_len(item2) > 0 && load8(item2, str_len(item2)-1) == 32:
+ item2 = str_sub(item2, 0, str_len(item2)-1)
+ if item2 == "variadic":
+ tag_flags = tag_flags + TAG_VARIADIC
+ else if item2 == "auto_str":
+ tag_flags = tag_flags + TAG_AUTO_STR
+ ti = item_end2 + 1
// Build type encoding for sym_node: param_count + param_types (3 bits each) + ret_type (3 bits)
- param_count : ., mut = 0;
- param_type_bits : ., mut = 0;
- pti : ., mut = 0;
- loop {
- if pti >= str_len(param_types) { break; }
+ param_count : ., mut = 0
+ param_type_bits : ., mut = 0
+ pti : ., mut = 0
+ loop:
+ if pti >= str_len(param_types):
+ break
// Skip to next param (comma-separated)
- pn_start : ., mut = pti;
- while pti < str_len(param_types) && load8(param_types, pti) != 44 { pti = pti + 1; }
- pname := str_sub(param_types, pn_start, pti - pn_start);
- while str_len(pname) > 0 && load8(pname, 0) == 32 { pname = str_sub(pname, 1, str_len(pname)-1); }
- while str_len(pname) > 0 && load8(pname, str_len(pname)-1) == 32 { pname = str_sub(pname, 0, str_len(pname)-1); }
- if str_len(pname) > 0 && param_count < 8 {
+ pn_start : ., mut = pti
+ while pti < str_len(param_types) && load8(param_types, pti) != 44:
+ pti = pti + 1
+ pname := str_sub(param_types, pn_start, pti - pn_start)
+ while str_len(pname) > 0 && load8(pname, 0) == 32:
+ pname = str_sub(pname, 1, str_len(pname)-1)
+ while str_len(pname) > 0 && load8(pname, str_len(pname)-1) == 32:
+ pname = str_sub(pname, 0, str_len(pname)-1)
+ if str_len(pname) > 0 && param_count < 8:
// Encode type: int=0, string=1, unit=2, dex=3(binary64 跨 C 边界 = apx 授权), bool=4, other=5
- ptype_code : ., mut = 5;
- if pname == "int" { ptype_code = 0; }
- else if pname == "string" { ptype_code = 1; }
- else if pname == "unit" { ptype_code = 2; }
- else if pname == "dex" { ptype_code = 3; }
- else if pname == "bool" { ptype_code = 4; }
+ ptype_code : ., mut = 5
+ if pname == "int":
+ ptype_code = 0
+ else if pname == "string":
+ ptype_code = 1
+ else if pname == "unit":
+ ptype_code = 2
+ else if pname == "dex":
+ ptype_code = 3
+ else if pname == "bool":
+ ptype_code = 4
// Decimal encoding: packed positionally
- param_type_bits = param_type_bits * 100 + ptype_code;
- param_count = param_count + 1;
- }
- if pti < str_len(param_types) && load8(param_types, pti) == 44 { pti = pti + 1; }
- }
+ param_type_bits = param_type_bits * 100 + ptype_code
+ param_count = param_count + 1
+ if pti < str_len(param_types) && load8(param_types, pti) == 44:
+ pti = pti + 1
// Encode return type
- ret_code : ., mut = 5;
- if ret_type == "int" { ret_code = 0; }
- else if ret_type == "string" { ret_code = 1; }
- else if ret_type == "unit" || str_eq(ret_type, "") != 0 { ret_code = 2; }
- else if ret_type == "dex" { ret_code = 3; }
- else if ret_type == "bool" { ret_code = 4; }
- type_encoding : ., mut = param_count * 1000000000000 + param_type_bits * 100 + ret_code;
+ ret_code : ., mut = 5
+ if ret_type == "int":
+ ret_code = 0
+ else if ret_type == "string":
+ ret_code = 1
+ else if ret_type == "unit" || str_eq(ret_type, "") != 0:
+ ret_code = 2
+ else if ret_type == "dex":
+ ret_code = 3
+ else if ret_type == "bool":
+ ret_code = 4
+ type_encoding : ., mut = param_count * 1000000000000 + param_type_bits * 100 + ret_code
// 落**侧表**(第 4 批 #82/#83),**不**进串表/符号表:
// ① 本函数在 `import` 解析期被调用,而「该名字是否被程序引用」要到检查期才知道
@@ -390,168 +433,159 @@ fn reg_so_funcs(index_content: string, so_name: string) {
// ⇒ 承重面(`print_int` 等只在索引里存在的名字)不变。
// ③ 侧表**动态增长**(grow_so_side)⇒ 不再有 `check_all` 里那份 128 容量硬编码、
// 写入无界的保全缓冲(TODO #2026-09-17-1 的越界写堆面随本改动消失,见 checker.cr:check_all 注)。
- ssi : ., mut = g_so_side_count;
- grow_so_side(ssi + 1);
- store_str_ptr(g_so_side_name, ssi * 8, func_name);
- w64(g_so_side_tags, ssi * 8, tag_flags);
- w64(g_so_side_type, ssi * 8, type_encoding);
- g_so_side_count = ssi + 1;
- }
-}
+ ssi : ., mut = g_so_side_count
+ grow_so_side(ssi + 1)
+ store_str_ptr(g_so_side_name, ssi * 8, func_name)
+ w64(g_so_side_tags, ssi * 8, tag_flags)
+ w64(g_so_side_type, ssi * 8, type_encoding)
+ g_so_side_count = ssi + 1
// 侧表按名字查找(返回侧表下标;-1 = 未命中)。名字**尚未 intern**(存的是原始串),
// 故按串比较——这是「未引用不物化」的代价面,只在查找未命中主表时走一次。
-fn find_so_side(name_idx: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= g_so_side_count { return -1; }
- if str_eq(istr_get(name_idx), load_str_ptr(g_so_side_name, i * 8)) != 0 { return i; }
- i = i + 1;
- }
- return -1;
-}
+fn find_so_side(name_idx: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= g_so_side_count:
+ return -1
+ if str_eq(istr_get(name_idx), load_str_ptr(g_so_side_name, i * 8)) != 0:
+ return i
+ i = i + 1
+ return -1
// 把侧表条目**物化**进符号表(首次被查找时调用)。返回新落的符号索引。
// 调用点约定(裁-HR-2「.cr 声明优先」):只有主表**完全没有**该名字时才可调用
// —— 否则宿主家目录里的一个索引文件会**覆盖用户源码里的声明**。
-fn so_materialize(side_i: int) -> int {
- fni := str_intern(load_str_ptr(g_so_side_name, side_i * 8));
- si := g_sym_count;
- grow_syms(si + 1);
- sym_set_name(si, fni);
- sym_set_kind(si, SYM_SO_FN);
- sym_set_type(si, r64(g_so_side_tags, side_i * 8));
- sym_set_node(si, r64(g_so_side_type, side_i * 8));
- g_sym_count = si + 1;
- return si;
-}
-
-fn res_imports() {
- g_file_count = 0; g_file_cap = 0;
- g_mod_count = 0; g_mod_cap = 0;
- g_seg_count = 0; g_seg_cap = 0;
+fn so_materialize(side_i: int) -> int:
+ fni := str_intern(load_str_ptr(g_so_side_name, side_i * 8))
+ si := g_sym_count
+ grow_syms(si + 1)
+ sym_set_name(si, fni)
+ sym_set_kind(si, SYM_SO_FN)
+ sym_set_type(si, r64(g_so_side_tags, side_i * 8))
+ sym_set_node(si, r64(g_so_side_type, side_i * 8))
+ g_sym_count = si + 1
+ return si
+
+fn res_imports():
+ g_file_count = 0
+ g_file_cap = 0
+ g_mod_count = 0
+ g_mod_cap = 0
+ g_seg_count = 0
+ g_seg_cap = 0
// Step 1: collect _import.cr from source directory and ancestors
- import_core_acc : ., mut = "";
+ import_core_acc : ., mut = ""
// Also collect stdlib _import.cr (provides import fmt for stdlib files)
- sic := load_imports("src/stdlib/");
- if str_len(sic) > 0 { import_core_acc = sic + "\n"; }
- search_dir : ., mut = g_source_dir;
- loop {
- ic := load_imports(search_dir);
- if str_len(ic) > 0 {
- import_core_acc = ic + "\n" + import_core_acc;
- }
- pd := parent_dir(search_dir);
- if str_len(pd) == 0 { break; }
- if str_eq(pd, search_dir) != 0 { break; }
- search_dir = pd;
- }
+ sic := load_imports("src/stdlib/")
+ if str_len(sic) > 0:
+ import_core_acc = sic + "\n"
+ search_dir : ., mut = g_source_dir
+ loop:
+ ic := load_imports(search_dir)
+ if str_len(ic) > 0:
+ import_core_acc = ic + "\n" + import_core_acc
+ pd := parent_dir(search_dir)
+ if str_len(pd) == 0:
+ break
+ if str_eq(pd, search_dir) != 0:
+ break
+ search_dir = pd
// Record original source length before prepending _import.cr preamble.
// Used later for segment tracking when we strip the preamble.
- real_main_len : ., mut = str_len(g_source);
+ real_main_len : ., mut = str_len(g_source)
- if str_len(import_core_acc) > 0 {
- g_source = import_core_acc + "\n" + g_source;
- tokenize(g_source);
- }
+ if str_len(import_core_acc) > 0:
+ g_source = import_core_acc + "\n" + g_source
+ tokenize(g_source, 0)
// Determine main file's fileid
- main_fileid_str : ., mut = get_fileid(g_source);
- if str_len(main_fileid_str) == 0 { main_fileid_str = "main"; }
- main_fni := reg_fileid(main_fileid_str, "");
- main_len : ., mut = real_main_len; // original source length (without preamble)
+ main_fileid_str : ., mut = get_fileid(g_source)
+ if str_len(main_fileid_str) == 0:
+ main_fileid_str = "main"
+ main_fni := reg_fileid(main_fileid_str, "")
+ main_len : ., mut = real_main_len // original source length (without preamble)
// First segment: main source
- grow_segs(g_seg_count + 1); w64(g_seg_starts, g_seg_count * 8, 0);
- w64(g_seg_fileids, g_seg_count * 8, main_fni);
- g_seg_count = g_seg_count + 1;
+ grow_segs(g_seg_count + 1)
+ w64(g_seg_starts, g_seg_count * 8, 0)
+ w64(g_seg_fileids, g_seg_count * 8, main_fni)
+ g_seg_count = g_seg_count + 1
- total_accumulated : ., mut = 0;
+ total_accumulated : ., mut = 0
// Multi-pass import resolution: keep scanning until no new imports found.
// This enables imports from within imported files (recursive imports).
- loop {
- pass_src : ., mut = "";
- pass_bytes : ., mut = 0;
- any_new : ., mut = 0;
-
- i : ., mut = 0;
- loop {
- if i >= g_token_count { break; }
- tk := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_KIND);
-
- if tk == T_IMPORT {
- pos : ., mut = i + 1;
- is_project : ., mut = false;
- project_name : ., mut = "";
- if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_AT {
- is_project = true;
- pos = pos + 1;
- if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT {
- project_name = istr_get(r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_LEXEME));
- pos = pos + 1;
- }
- }
- import_fileid : ., mut = "";
- if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT {
- import_fileid = istr_get(r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_LEXEME));
- pos = pos + 1;
+ loop:
+ pass_src : ., mut = ""
+ pass_bytes : ., mut = 0
+ any_new : ., mut = 0
+
+ i : ., mut = 0
+ loop:
+ if i >= g_token_count:
+ break
+ tk := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_KIND)
+
+ if tk == T_IMPORT:
+ pos : ., mut = i + 1
+ is_project : ., mut = false
+ project_name : ., mut = ""
+ if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_AT:
+ is_project = true
+ pos = pos + 1
+ if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT:
+ project_name = istr_get(r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_LEXEME))
+ pos = pos + 1
+ import_fileid : ., mut = ""
+ if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT:
+ import_fileid = istr_get(r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_LEXEME))
+ pos = pos + 1
// Handle :: segments: backend::x86_64 -> backend::x86_64
- loop {
- if pos + 1 < g_token_count &&
- r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_PATHSEP &&
- r64(g_tokens, (pos + 1) * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT {
- import_fileid = import_fileid + "::" + istr_get(r64(g_tokens, (pos + 1) * ESZ_TOKEN + OFF_TK_LEXEME));
- pos = pos + 2;
- } else { break; }
- }
- }
- alias_str : ., mut = "";
- if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_COLON {
- pos = pos + 1;
- if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT {
- alias_str = istr_get(r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_LEXEME));
- pos = pos + 1;
- }
- }
- path : ., mut = "";
- content : ., mut = "";
+ loop:
+ if pos + 1 < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_PATHSEP && r64(g_tokens, (pos + 1) * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT:
+ import_fileid = import_fileid + "::" + istr_get(r64(g_tokens, (pos + 1) * ESZ_TOKEN + OFF_TK_LEXEME))
+ pos = pos + 2
+ else:
+ break
+ alias_str : ., mut = ""
+ if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_COLON_DECL:
+ pos = pos + 1
+ if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT:
+ alias_str = istr_get(r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_LEXEME))
+ pos = pos + 1
+ path : ., mut = ""
+ content : ., mut = ""
// Skip import if it references the same file as the main source
// (prevents duplicate definitions when _import.cr imports the entry file)
- if str_len(import_fileid) > 0 && str_eq(import_fileid, main_fileid_str) != 0 {
- i = pos;
- continue;
- }
- if str_len(import_fileid) > 0 {
- if is_project {
- proj_toml : ., mut = "src/" + project_name + "/Core.toml";
- ptc := read_file(proj_toml);
- if str_len(ptc) > 0 {
- pn := extract_toml_name(ptc);
- if str_len(pn) > 0 && str_eq(pn, project_name) == 0 {
- if g_silent_stdout == 0 {
- print(" warning: @");
- print(project_name);
- print(" toml name='");
- print(pn);
- println("' mismatch");
- }
- }
- }
- path = "src/" + project_name + "/" + import_fileid + ".cr";
- content = module_get_source(path);
- } else {
+ if str_len(import_fileid) > 0 && str_eq(import_fileid, main_fileid_str) != 0:
+ i = pos
+ continue
+ if str_len(import_fileid) > 0:
+ if is_project:
+ proj_toml : ., mut = "src/" + project_name + "/Core.toml"
+ ptc := read_file(proj_toml)
+ if str_len(ptc) > 0:
+ pn := extract_toml_name(ptc)
+ if str_len(pn) > 0 && str_eq(pn, project_name) == 0:
+ if g_silent_stdout == 0:
+ print(" warning: @")
+ print(project_name)
+ print(" toml name='")
+ print(pn)
+ println("' mismatch")
+ path = "src/" + project_name + "/" + import_fileid + ".cr"
+ content = module_get_source(path)
+ else:
// Convert :: to / for subdirectory paths (e.g. backend::x86_64::instr -> backend/x86_64/instr)
- fs_path : ., mut = import_fileid;
- pi : ., mut = 0;
- loop {
- if pi >= str_len(fs_path) { break; }
- if load8(fs_path, pi) == 58 && pi + 1 < str_len(fs_path) && load8(fs_path, pi+1) == 58 {
- fs_path = str_sub(fs_path, 0, pi) + "/" + str_sub(fs_path, pi+2, str_len(fs_path)-pi-2);
- }
- pi = pi + 1;
- }
+ fs_path : ., mut = import_fileid
+ pi : ., mut = 0
+ loop:
+ if pi >= str_len(fs_path):
+ break
+ if load8(fs_path, pi) == 58 && pi + 1 < str_len(fs_path) && load8(fs_path, pi+1) == 58:
+ fs_path = str_sub(fs_path, 0, pi) + "/" + str_sub(fs_path, pi+2, str_len(fs_path)-pi-2)
+ pi = pi + 1
// Try .so extension index: $HOME/.core/lib//index
// Loads metadata (tags). The .cr file still provides runtime implementation.
// 第 4 批 #83:**不再**兜底到硬编码家目录。原实现把空 HOME 兜底为
@@ -565,26 +599,22 @@ fn res_imports() {
// **不在此处放行**(放行会把响亮失败退化为静默错值 = 本批红线)。
// 注:嵌套 if 而非 `home_dir != "" && …`——bootstrap 构建的 corec 对
// `&&` 两侧**无条件求值**(仓内既有纪律)。
- home_dir : ., mut = get_env("HOME");
- if str_len(home_dir) > 0 {
- so_idx_path : ., mut = home_dir + "/.core/lib/" + fs_path + "/index";
- so_idx := read_file(so_idx_path);
- if str_len(so_idx) > 0 {
- reg_so_funcs(so_idx, fs_path);
- }
- }
+ home_dir : ., mut = get_env("HOME")
+ if str_len(home_dir) > 0:
+ so_idx_path : ., mut = home_dir + "/.core/lib/" + fs_path + "/index"
+ so_idx := read_file(so_idx_path)
+ if str_len(so_idx) > 0:
+ reg_so_funcs(so_idx, fs_path)
// Always load .cr for runtime implementation
// (module_get_source:打开文档优先,未打开读盘)
- path = g_source_dir + fs_path + ".cr";
- content = module_get_source(path);
- if str_len(content) == 0 {
- path = "src/stdlib/" + fs_path + ".cr";
- content = module_get_source(path);
- }
- if str_len(content) == 0 {
- path = "src/runtime/" + fs_path + ".cr";
- content = module_get_source(path);
- }
+ path = g_source_dir + fs_path + ".cr"
+ content = module_get_source(path)
+ if str_len(content) == 0:
+ path = "src/stdlib/" + fs_path + ".cr"
+ content = module_get_source(path)
+ if str_len(content) == 0:
+ path = "src/runtime/" + fs_path + ".cr"
+ content = module_get_source(path)
// ── 三轴实例目录(x86 实例化波 1 Task 1 搬迁落位)──
// 架构 × 格式 × OS 三轴目录 = 跨轴 import 的唯一通道(H5:
// elf→arch 6 处跨轴缝依赖此回退链)。**置于 src/compiler/
@@ -595,26 +625,21 @@ fn res_imports() {
// N06 静默未定义。既有条目命中不漂:本三条目录为新建,
// 其文件名(instr/sizes/regalloc/elf/resolve/ld)在
// g_source_dir / src/stdlib / src/runtime 三级均无同名文件。
- if str_len(content) == 0 {
- path = "src/format/elf/" + fs_path + ".cr";
- content = module_get_source(path);
- }
- if str_len(content) == 0 {
- path = "src/arch/x86_64/" + fs_path + ".cr";
- content = module_get_source(path);
- }
- if str_len(content) == 0 {
- path = "src/os/linux/" + fs_path + ".cr";
- content = module_get_source(path);
- }
- if str_len(content) == 0 {
- path = "src/compiler/" + fs_path + ".cr";
- content = module_get_source(path);
- }
- if str_len(content) == 0 {
- path = "src/arch/hit/" + fs_path + ".cr";
- content = module_get_source(path);
- }
+ if str_len(content) == 0:
+ path = "src/format/elf/" + fs_path + ".cr"
+ content = module_get_source(path)
+ if str_len(content) == 0:
+ path = "src/arch/x86_64/" + fs_path + ".cr"
+ content = module_get_source(path)
+ if str_len(content) == 0:
+ path = "src/os/linux/" + fs_path + ".cr"
+ content = module_get_source(path)
+ if str_len(content) == 0:
+ path = "src/compiler/" + fs_path + ".cr"
+ content = module_get_source(path)
+ if str_len(content) == 0:
+ path = "src/arch/hit/" + fs_path + ".cr"
+ content = module_get_source(path)
// ent_kernel.cr(语义内核,格层 src/lattice/——2026-09-10 自
// 旧实例目录迁出:实例目录不再承载语义内核;该目录于 x86
// 实例化波 1 Task 1 拆为三轴 src/arch/x86_64 + src/format/elf
@@ -623,86 +648,82 @@ fn res_imports() {
// grow_entries 等;镜像 src/compiler 跨树回退(同 concat 共享
// 文件可被任意编译单元 import——src/compiler 单元自身需经此路
// 径收编内核;实例单元与独立工程构建同经此路径命中)
- if str_len(content) == 0 {
- path = "src/lattice/" + fs_path + ".cr";
- content = module_get_source(path);
- }
+ if str_len(content) == 0:
+ path = "src/lattice/" + fs_path + ".cr"
+ content = module_get_source(path)
// 组合根(三轴组合 = target triple 命名):project-mode 入口
// = 该目录 main.cr(load_project 直读)+ _import.cr(load_imports
// 直读)——**后置于 compiler/lattice**:目录内 main.cr 非 import
// 目标,前置会遮蔽既有 main/entry 命中(src/compiler/_import.cr
// 的 import main/entry);此条目为跨轴/跨单元收编面而备。
- if str_len(content) == 0 {
- path = "src/targets/x86_64-linux/" + fs_path + ".cr";
- content = module_get_source(path);
- }
- if str_len(content) == 0 {
- path = fs_path + ".cr";
- content = module_get_source(path);
- }
- if str_len(content) == 0 {
- if g_silent_stdout == 0 { print("!! import fail: "); println(import_fileid); }
- }
- }
- }
- if str_len(content) > 0 {
- content_len := str_len(content);
- loaded_fid : ., mut = get_fileid(content);
- if str_len(loaded_fid) == 0 { loaded_fid = import_fileid; }
- loaded_fni := reg_fileid(loaded_fid, path);
+ if str_len(content) == 0:
+ path = "src/targets/x86_64-linux/" + fs_path + ".cr"
+ content = module_get_source(path)
+ if str_len(content) == 0:
+ path = fs_path + ".cr"
+ content = module_get_source(path)
+ if str_len(content) == 0:
+ if g_silent_stdout == 0:
+ print("!! import fail: ")
+ println(import_fileid)
+ if str_len(content) > 0:
+ content_len := str_len(content)
+ loaded_fid : ., mut = get_fileid(content)
+ if str_len(loaded_fid) == 0:
+ loaded_fid = import_fileid
+ loaded_fni := reg_fileid(loaded_fid, path)
// Check if this file was already loaded (prevent duplicates)
- already_loaded : ., mut = 0;
- mi : ., mut = 0;
- loop { if mi >= g_mod_count { break; }
- if r64(g_mods, mi * 24 + 8) == loaded_fni { already_loaded = 1; break; }
- mi = mi + 1; }
- if already_loaded != 0 {
- i = pos;
- continue;
- }
- if g_silent_stdout == 0 { print(" -> "); println(path); }
- any_new = 1;
- seg_byte := main_len + total_accumulated + pass_bytes + 1;
- grow_segs(g_seg_count + 1); w64(g_seg_starts, g_seg_count * 8, seg_byte);
- w64(g_seg_fileids, g_seg_count * 8, loaded_fni);
- g_seg_count = g_seg_count + 1;
- pass_bytes = pass_bytes + 1 + content_len;
- alias_ni : ., mut = -1;
- if str_len(alias_str) > 0 {
- alias_ni = str_intern(alias_str);
- } else {
- alias_ni = loaded_fni;
- }
- grow_mods(g_mod_count + 1);
- w64(g_mods, g_mod_count * 24, alias_ni);
- w64(g_mods, g_mod_count * 24 + 8, loaded_fni);
- store_str_ptr(g_mods, g_mod_count * 24 + 16, path);
- g_mod_count = g_mod_count + 1;
- pass_src = pass_src + "\n" + content;
- }
- i = pos;
- continue;
- }
- i = i + 1;
- }
-
- if any_new == 0 { break; }
-
- if str_len(pass_src) > 0 {
- g_source = g_source + pass_src;
- tokenize(g_source);
- total_accumulated = total_accumulated + pass_bytes;
- }
- }
+ already_loaded : ., mut = 0
+ mi : ., mut = 0
+ loop:
+ if mi >= g_mod_count:
+ break
+ if r64(g_mods, mi * 24 + 8) == loaded_fni:
+ already_loaded = 1
+ break
+ mi = mi + 1
+ if already_loaded != 0:
+ i = pos
+ continue
+ if g_silent_stdout == 0:
+ print(" -> ")
+ println(path)
+ any_new = 1
+ seg_byte := main_len + total_accumulated + pass_bytes + 1
+ grow_segs(g_seg_count + 1)
+ w64(g_seg_starts, g_seg_count * 8, seg_byte)
+ w64(g_seg_fileids, g_seg_count * 8, loaded_fni)
+ g_seg_count = g_seg_count + 1
+ pass_bytes = pass_bytes + 1 + content_len
+ alias_ni : ., mut = -1
+ if str_len(alias_str) > 0:
+ alias_ni = str_intern(alias_str)
+ else:
+ alias_ni = loaded_fni
+ grow_mods(g_mod_count + 1)
+ w64(g_mods, g_mod_count * 24, alias_ni)
+ w64(g_mods, g_mod_count * 24 + 8, loaded_fni)
+ store_str_ptr(g_mods, g_mod_count * 24 + 16, path)
+ g_mod_count = g_mod_count + 1
+ pass_src = pass_src + "\n" + content
+ i = pos
+ continue
+ i = i + 1
+
+ if any_new == 0:
+ break
+
+ if str_len(pass_src) > 0:
+ g_source = g_source + pass_src
+ tokenize(g_source, 0)
+ total_accumulated = total_accumulated + pass_bytes
// Strip _import.cr preamble to prevent re-parsing import tokens as code.
// Import resolution already completed above; leaving the preamble in
// g_source causes the checker to emit spurious errors and may crash IR gen.
- if str_len(import_core_acc) > 0 {
- skip := str_len(import_core_acc) + 1; // +1 for the "\n" separator
- g_source = str_sub(g_source, skip, str_len(g_source) - skip);
- tokenize(g_source);
- }
-
- build_line_fileid();
-}
+ if str_len(import_core_acc) > 0:
+ skip := str_len(import_core_acc) + 1 // +1 for the "\n" separator
+ g_source = str_sub(g_source, skip, str_len(g_source) - skip)
+ tokenize(g_source, 0)
+
+ build_line_fileid()
diff --git a/src/compiler/monomorph.cr b/src/compiler/monomorph.cr
index 52f2a2a1..b22920be 100644
--- a/src/compiler/monomorph.cr
+++ b/src/compiler/monomorph.cr
@@ -5,71 +5,110 @@
// ── Instance cache ──
// Each entry: 24 bytes = [original_func_ni, type_args_str_ni, specialized_fi]
-g_gen_instances : string, mut;
-g_gen_instance_count : int, mut;
-g_gen_instance_cap : int, mut;
+g_gen_instances : string, mut
+g_gen_instance_count : int, mut
+g_gen_instance_cap : int, mut
// ── Temporary substitution mapping (during clone) ──
// Parallel arrays: generic param name index → concrete type name index
-g_gen_subst_old : string, mut;
-g_gen_subst_new : string, mut;
-g_gen_subst_count : int, mut;
-g_gen_subst_cap : int, mut;
+g_gen_subst_old : string, mut
+g_gen_subst_new : string, mut
+g_gen_subst_count : int, mut
+g_gen_subst_cap : int, mut
// ── R2 P3 Task 5(Step 4):ti 型替换表(与上面的名字表**并行同键**:g_gen_subst_old 的
// 名字 ni → 实参**类型行 ti**)。来源 = checker 的调用点绑定段(g_gen_binds,globals.cr
// 表注);命中时替换产物 = `inst_type_node_of_ti` 造的**完整类型节点**(命名/复合/泛型
// 应用皆可表达),取代旧「拼名字串再 str_intern 查名字」的塌缩(非原生实参一律 "int")。
// -1/缺位 → 回落名字路径(旧行为逐字保持)。──
-g_gen_subst_tis : string, mut;
-g_gen_subst_tis_count : int, mut;
-g_gen_subst_tis_cap : int, mut;
+g_gen_subst_tis : string, mut
+g_gen_subst_tis_count : int, mut
+g_gen_subst_tis_cap : int, mut
// ── Temporary dedup map (old AST node → new AST node during clone) ──
-g_gen_dedup_old : string, mut;
-g_gen_dedup_new : string, mut;
-g_gen_dedup_count : int, mut;
-g_gen_dedup_cap : int, mut;
+g_gen_dedup_old : string, mut
+g_gen_dedup_new : string, mut
+g_gen_dedup_count : int, mut
+g_gen_dedup_cap : int, mut
// ============================================================
// Grow helpers
// ============================================================
-fn grow_gen_instances(needed: int) {
- if needed < g_gen_instance_cap { return; }
- nc : ., mut = g_gen_instance_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; }
- nb := alloc(nc * 24); _dyncpy(g_gen_instances, g_gen_instance_cap * 24, nb);
- g_gen_instances = nb; g_gen_instance_cap = nc; }
+fn grow_gen_instances(needed: int):
+ if needed < g_gen_instance_cap:
+ return
+ nc : ., mut = g_gen_instance_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ nb := alloc(nc * 24)
+ _dyncpy(g_gen_instances, g_gen_instance_cap * 24, nb)
+ g_gen_instances = nb
+ g_gen_instance_cap = nc
// 效应/纯度修正 Task 1:实例 → 源映射侧表(声明在 globals.cr——checker.cr 的
// compute_all_purity 要读它,bootstrap 名字解析按声明序)。
-fn grow_purity_inst(needed: int) {
- if needed < g_purity_inst_cap { return; }
- nc : ., mut = g_purity_inst_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; }
- nb := alloc(nc * 24); _dyncpy(g_purity_inst, g_purity_inst_cap * 24, nb);
- g_purity_inst = nb; g_purity_inst_cap = nc; }
-
-fn grow_gen_subst(needed: int) {
- if needed < g_gen_subst_cap { return; }
- nc : ., mut = g_gen_subst_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; }
- sz := nc * 8;
- n1 := alloc(sz); _dyncpy(g_gen_subst_old, g_gen_subst_cap * 8, n1); g_gen_subst_old = n1;
- n2 := alloc(sz); _dyncpy(g_gen_subst_new, g_gen_subst_cap * 8, n2); g_gen_subst_new = n2;
- g_gen_subst_cap = nc; }
-
-fn grow_gen_dedup(needed: int) {
- if needed < g_gen_dedup_cap { return; }
- nc : ., mut = g_gen_dedup_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; }
- sz := nc * 8;
- n1 := alloc(sz); _dyncpy(g_gen_dedup_old, g_gen_dedup_cap * 8, n1); g_gen_dedup_old = n1;
- n2 := alloc(sz); _dyncpy(g_gen_dedup_new, g_gen_dedup_cap * 8, n2); g_gen_dedup_new = n2;
- g_gen_dedup_cap = nc; }
+fn grow_purity_inst(needed: int):
+ if needed < g_purity_inst_cap:
+ return
+ nc : ., mut = g_purity_inst_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ nb := alloc(nc * 24)
+ _dyncpy(g_purity_inst, g_purity_inst_cap * 24, nb)
+ g_purity_inst = nb
+ g_purity_inst_cap = nc
+
+fn grow_gen_subst(needed: int):
+ if needed < g_gen_subst_cap:
+ return
+ nc : ., mut = g_gen_subst_cap * 2
+ if nc < 16:
+ nc = 16
+ if nc < needed:
+ nc = needed + 16
+ sz := nc * 8
+ n1 := alloc(sz)
+ _dyncpy(g_gen_subst_old, g_gen_subst_cap * 8, n1)
+ g_gen_subst_old = n1
+ n2 := alloc(sz)
+ _dyncpy(g_gen_subst_new, g_gen_subst_cap * 8, n2)
+ g_gen_subst_new = n2
+ g_gen_subst_cap = nc
+
+fn grow_gen_dedup(needed: int):
+ if needed < g_gen_dedup_cap:
+ return
+ nc : ., mut = g_gen_dedup_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ sz := nc * 8
+ n1 := alloc(sz)
+ _dyncpy(g_gen_dedup_old, g_gen_dedup_cap * 8, n1)
+ g_gen_dedup_old = n1
+ n2 := alloc(sz)
+ _dyncpy(g_gen_dedup_new, g_gen_dedup_cap * 8, n2)
+ g_gen_dedup_new = n2
+ g_gen_dedup_cap = nc
// R2 P3 Task 5(Step 4):ti 型替换表增长(与 g_gen_subst_old 同长——同一次实例化建立)
-fn grow_gen_subst_tis(needed: int) {
- if needed < g_gen_subst_tis_cap { return; }
- nc : ., mut = g_gen_subst_tis_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; }
- nb := alloc(nc * 8); _dyncpy(g_gen_subst_tis, g_gen_subst_tis_cap * 8, nb);
- g_gen_subst_tis = nb; g_gen_subst_tis_cap = nc; }
+fn grow_gen_subst_tis(needed: int):
+ if needed < g_gen_subst_tis_cap:
+ return
+ nc : ., mut = g_gen_subst_tis_cap * 2
+ if nc < 16:
+ nc = 16
+ if nc < needed:
+ nc = needed + 16
+ nb := alloc(nc * 8)
+ _dyncpy(g_gen_subst_tis, g_gen_subst_tis_cap * 8, nb)
+ g_gen_subst_tis = nb
+ g_gen_subst_tis_cap = nc
// ============================================================
// Substitution mapping
@@ -77,85 +116,103 @@ fn grow_gen_subst_tis(needed: int) {
// Parse comma-separated type_args and build substitution mapping
// from generic param names (from FuncInfo) to concrete type name indices.
-fn gen_build_subst(func_ni: int, type_args: string) {
- g_gen_subst_count = 0; g_gen_subst_cap = 0;
- gc := fi_generic_count(func_ni);
- if gc <= 0 { return; }
- pos : ., mut = 0;
- gi : ., mut = 0;
- loop {
- if gi >= gc { break; }
- if load8(type_args, pos) == 0 { break; }
- start := pos;
- loop {
- c := load8(type_args, pos);
- if c == 0 || c == 44 { break; } // null or comma
- pos = pos + 1;
- }
- type_name := str_sub(type_args, start, pos - start);
- if load8(type_args, pos) == 44 { pos = pos + 1; }
- gen_param_ni := fi_generic_name(func_ni, gi);
- concrete_ni := str_intern(type_name);
- grow_gen_subst(g_gen_subst_count + 1);
- w64(g_gen_subst_old, g_gen_subst_count * 8, gen_param_ni);
- w64(g_gen_subst_new, g_gen_subst_count * 8, concrete_ni);
- g_gen_subst_count = g_gen_subst_count + 1;
- gi = gi + 1;
- }
-}
+fn gen_build_subst(func_ni: int, type_args: string):
+ g_gen_subst_count = 0
+ g_gen_subst_cap = 0
+ gc := fi_generic_count(func_ni)
+ if gc <= 0:
+ return
+ pos : ., mut = 0
+ gi : ., mut = 0
+ loop:
+ if gi >= gc:
+ break
+ if load8(type_args, pos) == 0:
+ break
+ start := pos
+ loop:
+ c := load8(type_args, pos)
+ if c == 0 || c == 44:
+ break
+ // null or comma
+ pos = pos + 1
+ type_name := str_sub(type_args, start, pos - start)
+ if load8(type_args, pos) == 44:
+ pos = pos + 1
+ gen_param_ni := fi_generic_name(func_ni, gi)
+ concrete_ni := str_intern(type_name)
+ grow_gen_subst(g_gen_subst_count + 1)
+ w64(g_gen_subst_old, g_gen_subst_count * 8, gen_param_ni)
+ w64(g_gen_subst_new, g_gen_subst_count * 8, concrete_ni)
+ g_gen_subst_count = g_gen_subst_count + 1
+ gi = gi + 1
// R2 P3 Task 5(Step 4):把调用点绑定段(块 = [count, ti…],见 checker.cr 写入点)装进
// ti 型替换表——**名表与 ti 表同序同键**(第 i 项同为第 i 个泛型形参)。返回装填条数;
// 0 = 无绑定段/段非法(调用方回落名字路径)。
-fn gen_build_subst_tis(func_ni: int, bstart: int) -> int {
- g_gen_subst_tis_count = 0; g_gen_subst_tis_cap = 0;
- if bstart < 0 { return 0; }
- gc := fi_generic_count(func_ni);
- if gc <= 0 { return 0; }
- if bstart >= g_gen_binds_count { return 0; }
- cnt := r64(g_gen_binds, bstart * 8);
- if cnt != gc { return 0; } // 段长必须与形参数一致(不同 ⇒ 不信任)
- if bstart + 1 + cnt > g_gen_binds_count { return 0; }
- grow_gen_subst_tis(gc);
- i : ., mut = 0;
- loop {
- if i >= gc { break; }
- t := r64(g_gen_binds, (bstart + 1 + i) * 8);
- if t < 0 { return 0; } // 未绑定 ⇒ 全段放弃(不半解)
- if inst_ti_concrete(t) == 0 { return 0; } // 含泛型形参行 ⇒ 全段放弃(同上)
- w64(g_gen_subst_tis, i * 8, t);
- g_gen_subst_tis_count = i + 1;
- i = i + 1;
- }
- return g_gen_subst_tis_count;
-}
+fn gen_build_subst_tis(func_ni: int, bstart: int) -> int:
+ g_gen_subst_tis_count = 0
+ g_gen_subst_tis_cap = 0
+ if bstart < 0:
+ return 0
+ gc := fi_generic_count(func_ni)
+ if gc <= 0:
+ return 0
+ if bstart >= g_gen_binds_count:
+ return 0
+ cnt := r64(g_gen_binds, bstart * 8)
+ if cnt != gc:
+ return 0
+ // 段长必须与形参数一致(不同 ⇒ 不信任)
+ if bstart + 1 + cnt > g_gen_binds_count:
+ return 0
+ grow_gen_subst_tis(gc)
+ i : ., mut = 0
+ loop:
+ if i >= gc:
+ break
+ t := r64(g_gen_binds, (bstart + 1 + i) * 8)
+ if t < 0:
+ return 0
+ // 未绑定 ⇒ 全段放弃(不半解)
+ if inst_ti_concrete(t) == 0:
+ return 0
+ // 含泛型形参行 ⇒ 全段放弃(同上)
+ w64(g_gen_subst_tis, i * 8, t)
+ g_gen_subst_tis_count = i + 1
+ i = i + 1
+ return g_gen_subst_tis_count
// Look up substitution for a generic param name.
// Returns concrete type name index, or -1 if not a generic param.
-fn gen_lookup_subst(name_ni: int) -> int {
- mi : ., mut = 0;
- loop {
- if mi >= g_gen_subst_count { break; }
- if r64(g_gen_subst_old, mi * 8) == name_ni {
- return r64(g_gen_subst_new, mi * 8);
- }
- mi = mi + 1;
- }
- return -1;
-}
+fn gen_lookup_subst(name_ni: int) -> int:
+ mi : ., mut = 0
+ loop:
+ if mi >= g_gen_subst_count:
+ break
+ if r64(g_gen_subst_old, mi * 8) == name_ni:
+ return r64(g_gen_subst_new, mi * 8)
+ mi = mi + 1
+ return -1
// Check if a name is a base type. Returns the TY_* constant, or -1.
-fn gen_base_type_tv(name_ni: int) -> int {
- s := istr_get(name_ni);
- if s == "int" { return TY_INT; }
- if s == "dex" { return TY_DEX; }
- if s == "bool" { return TY_BOOL; }
- if s == "string" { return TY_STRING; }
- if s == "char" { return TY_CHAR; }
- if s == "unit" { return TY_UNIT; }
- if s == "never" { return TY_NEVER; }
- return -1;
-}
+fn gen_base_type_tv(name_ni: int) -> int:
+ s := istr_get(name_ni)
+ if s == "int":
+ return TY_INT
+ if s == "dex":
+ return TY_DEX
+ if s == "bool":
+ return TY_BOOL
+ if s == "string":
+ return TY_STRING
+ if s == "char":
+ return TY_CHAR
+ if s == "unit":
+ return TY_UNIT
+ if s == "never":
+ return TY_NEVER
+ return -1
// ═══════════════ R2 P3 Task 5(Step 4):ti ⇄ 节点/键 三件套 ═══════════════
// 背景(旧态,逐条实测):实例键由 ir_gen 从**实参 IR 变量的类型**拼名字串得到,非原生
@@ -174,600 +231,802 @@ fn gen_base_type_tv(name_ni: int) -> int {
// 子树节点会插在中间(parser 侧靠「子树的根恒为该子树最后分配的节点」自然成立)⇒ 复合实参
// 一律回 -1(调用方回落名字路径;登记为未覆盖面)。
-fn inst_key_of_ti(ti: int) -> string {
- k := get_type_kind(ti);
- if k < 0 { return "?"; }
- if k == TYP_BASE {
- d := get_type_data(ti);
- if d == TY_INT { return "int"; }
- if d == TY_DEX { return "dex"; }
- if d == TY_BOOL { return "bool"; }
- if d == TY_STRING { return "string"; }
- if d == TY_CHAR { return "char"; }
- if d == TY_UNIT { return "unit"; }
- if d == TY_NEVER { return "never"; }
- return "#" + int_str(d);
- }
- if k == TYP_NAMED || k == TYP_GENERIC_PARAM { return istr_get(get_type_data(ti)); }
- if k == TYP_GENERIC_APPLY {
- base := get_type_data(ti);
- s : ., mut = "?";
- if get_type_kind(base) == TYP_NAMED { s = istr_get(get_type_data(base)); }
- s = s + "[";
- start := get_type_extra(ti);
- cnt := r64(g_gen_apply_data, start * 8);
- i : ., mut = 0;
- loop {
- if i >= cnt { break; }
- if i > 0 { s = s + "|"; }
- s = s + inst_key_of_ti(r64(g_gen_apply_data, (start + 1 + i) * 8));
- i = i + 1;
- }
- return s + "]";
- }
- if k == TYP_ARRAY { return "[" + inst_key_of_ti(get_type_data(ti)) + "; " + int_str(get_type_extra(ti)) + "]"; }
- if k == TYP_SLICE { return "[" + inst_key_of_ti(get_type_data(ti)) + "]"; }
- if k == TYP_REF {
- if get_type_extra(ti) != 0 { return "&mut " + inst_key_of_ti(get_type_data(ti)); }
- return "&" + inst_key_of_ti(get_type_data(ti));
- }
- if k == TYP_PTR { return "*" + inst_key_of_ti(get_type_data(ti)); }
- if k == TYP_OPTIONAL { return inst_key_of_ti(get_type_data(ti)) + "?"; }
- if k == TYP_NULL { return "null"; }
- if k == TYP_DYN { return "dyn"; }
- if k == TYP_TUPLE {
- s : ., mut = "(";
- cnt2 := get_type_data(ti);
- start2 := get_type_extra(ti);
- i2 : ., mut = 0;
- loop {
- if i2 >= cnt2 { break; }
- if i2 > 0 { s = s + "|"; }
- s = s + inst_key_of_ti(r64(g_gen_apply_data, (start2 + i2) * 8));
- i2 = i2 + 1;
- }
- return s + ")";
- }
- return "#" + int_str(ti); // 未知 kind:行号兜底(同编译期内确定;跨行同型不去重,登记)
-}
+fn inst_key_of_ti(ti: int) -> string:
+ k := get_type_kind(ti)
+ if k < 0:
+ return "?"
+ if k == TYP_BASE:
+ d := get_type_data(ti)
+ if d == TY_INT:
+ return "int"
+ if d == TY_DEX:
+ return "dex"
+ if d == TY_BOOL:
+ return "bool"
+ if d == TY_STRING:
+ return "string"
+ if d == TY_CHAR:
+ return "char"
+ if d == TY_UNIT:
+ return "unit"
+ if d == TY_NEVER:
+ return "never"
+ return "#" + int_str(d)
+ if k == TYP_NAMED || k == TYP_GENERIC_PARAM:
+ return istr_get(get_type_data(ti))
+ if k == TYP_GENERIC_APPLY:
+ base := get_type_data(ti)
+ s : ., mut = "?"
+ if get_type_kind(base) == TYP_NAMED:
+ s = istr_get(get_type_data(base))
+ s = s + "["
+ start := get_type_extra(ti)
+ cnt := r64(g_gen_apply_data, start * 8)
+ i : ., mut = 0
+ loop:
+ if i >= cnt:
+ break
+ if i > 0:
+ s = s + "|"
+ s = s + inst_key_of_ti(r64(g_gen_apply_data, (start + 1 + i) * 8))
+ i = i + 1
+ return s + "]"
+ if k == TYP_ARRAY:
+ return "[" + inst_key_of_ti(get_type_data(ti)) + "; " + int_str(get_type_extra(ti)) + "]"
+ if k == TYP_SLICE:
+ return "[" + inst_key_of_ti(get_type_data(ti)) + "]"
+ if k == TYP_REF:
+ if get_type_extra(ti) != 0:
+ return "&mut " + inst_key_of_ti(get_type_data(ti))
+ return "&" + inst_key_of_ti(get_type_data(ti))
+ if k == TYP_PTR:
+ return "*" + inst_key_of_ti(get_type_data(ti))
+ if k == TYP_OPTIONAL:
+ return inst_key_of_ti(get_type_data(ti)) + "?"
+ if k == TYP_NULL:
+ return "null"
+ if k == TYP_DYN:
+ return "dyn"
+ if k == TYP_TUPLE:
+ s : ., mut = "("
+ cnt2 := get_type_data(ti)
+ start2 := get_type_extra(ti)
+ i2 : ., mut = 0
+ loop:
+ if i2 >= cnt2:
+ break
+ if i2 > 0:
+ s = s + "|"
+ s = s + inst_key_of_ti(r64(g_gen_apply_data, (start2 + i2) * 8))
+ i2 = i2 + 1
+ return s + ")"
+ return "#" + int_str(ti) // 未知 kind:行号兜底(同编译期内确定;跨行同型不去重,登记)
// 类型行 → 类型语法节点(**单槽根**约束见上注);-1 = 无对应形态(调用方回落名字路径)
-fn inst_type_node_of_ti(ti: int) -> int {
- k := get_type_kind(ti);
- if k < 0 { return -1; }
- if k == TYP_BASE { return alloc_node(0, 0, 0, 0, 0, get_type_data(ti), 0, 0, 0); }
- if k == TYP_NAMED || k == TYP_GENERIC_PARAM {
- return alloc_node(EXPR_IDENT, 0, 0, 0, get_type_data(ti), 0, 0, 0, 0);
- }
- if k == TYP_ARRAY {
- inner := inst_type_node_of_ti(get_type_data(ti));
- if inner < 0 { return -1; }
- return alloc_node(EXPR_ARRAY, inner, 0, 0, get_type_extra(ti), 0, 0, 0, 0);
- }
- if k == TYP_SLICE {
- inner := inst_type_node_of_ti(get_type_data(ti));
- if inner < 0 { return -1; }
- return alloc_node(EXPR_ARRAY, inner, 0, 0, 0, 0, 0, 0, 0);
- }
- if k == TYP_REF {
- inner := inst_type_node_of_ti(get_type_data(ti));
- if inner < 0 { return -1; }
- return alloc_node(EXPR_REFTYPE, inner, 0, 0, get_type_extra(ti), 0, 0, 0, 0);
- }
- if k == TYP_PTR {
- inner := inst_type_node_of_ti(get_type_data(ti));
- if inner < 0 { return -1; }
- return alloc_node(EXPR_PTRTYPE, inner, 0, 0, 0, 0, 0, 0, 0);
- }
- if k == TYP_OPTIONAL {
- inner := inst_type_node_of_ti(get_type_data(ti));
- if inner < 0 { return -1; }
- return alloc_node(EXPR_OPTIONAL, inner, 0, 0, 0, 0, 0, 0, 0);
- }
- if k == TYP_GENERIC_APPLY {
- base := get_type_data(ti);
- if get_type_kind(base) != TYP_NAMED { return -1; }
- start := get_type_extra(ti);
- cnt := r64(g_gen_apply_data, start * 8);
- if cnt <= 0 { return -1; }
- first_an : ., mut = -1;
- i : ., mut = 0;
- loop {
- if i >= cnt { break; }
- at := r64(g_gen_apply_data, (start + 1 + i) * 8);
- ak := get_type_kind(at);
+fn inst_type_node_of_ti(ti: int) -> int:
+ k := get_type_kind(ti)
+ if k < 0:
+ return -1
+ if k == TYP_BASE:
+ return alloc_node(0, 0, 0, 0, 0, get_type_data(ti), 0, 0, 0)
+ if k == TYP_NAMED || k == TYP_GENERIC_PARAM:
+ return alloc_node(EXPR_IDENT, 0, 0, 0, get_type_data(ti), 0, 0, 0, 0)
+ if k == TYP_ARRAY:
+ inner := inst_type_node_of_ti(get_type_data(ti))
+ if inner < 0:
+ return -1
+ return alloc_node(EXPR_ARRAY, inner, 0, 0, get_type_extra(ti), 0, 0, 0, 0)
+ if k == TYP_SLICE:
+ inner := inst_type_node_of_ti(get_type_data(ti))
+ if inner < 0:
+ return -1
+ return alloc_node(EXPR_ARRAY, inner, 0, 0, 0, 0, 0, 0, 0)
+ if k == TYP_REF:
+ inner := inst_type_node_of_ti(get_type_data(ti))
+ if inner < 0:
+ return -1
+ return alloc_node(EXPR_REFTYPE, inner, 0, 0, get_type_extra(ti), 0, 0, 0, 0)
+ if k == TYP_PTR:
+ inner := inst_type_node_of_ti(get_type_data(ti))
+ if inner < 0:
+ return -1
+ return alloc_node(EXPR_PTRTYPE, inner, 0, 0, 0, 0, 0, 0, 0)
+ if k == TYP_OPTIONAL:
+ inner := inst_type_node_of_ti(get_type_data(ti))
+ if inner < 0:
+ return -1
+ return alloc_node(EXPR_OPTIONAL, inner, 0, 0, 0, 0, 0, 0, 0)
+ if k == TYP_GENERIC_APPLY:
+ base := get_type_data(ti)
+ if get_type_kind(base) != TYP_NAMED:
+ return -1
+ start := get_type_extra(ti)
+ cnt := r64(g_gen_apply_data, start * 8)
+ if cnt <= 0:
+ return -1
+ first_an : ., mut = -1
+ i : ., mut = 0
+ loop:
+ if i >= cnt:
+ break
+ at := r64(g_gen_apply_data, (start + 1 + i) * 8)
+ ak := get_type_kind(at)
// 实参根节点连续契约:仅接受单槽根(原生/命名/形参)——复合实参见上注(登记)
- if ak != TYP_BASE && ak != TYP_NAMED && ak != TYP_GENERIC_PARAM { return -1; }
- an := inst_type_node_of_ti(at);
- if an < 0 { return -1; }
- if i == 0 { first_an = an; }
- i = i + 1;
- }
- return alloc_node(EXPR_GENERIC_APPLY, get_type_data(base), first_an, cnt, 0, 0, 0, 0, 0);
- }
- return -1; // TUPLE / NULL / DYN / 未知 kind:无语法形态(DYN 另见 res_type_node 的码 7 格)
-}
-
-fn gen_lookup_subst_ti(name_ni: int) -> int {
- mi : ., mut = 0;
- loop {
- if mi >= g_gen_subst_tis_count { break; }
- if r64(g_gen_subst_old, mi * 8) == name_ni { return r64(g_gen_subst_tis, mi * 8); }
- mi = mi + 1;
- }
- return -1;
-}
+ if ak != TYP_BASE && ak != TYP_NAMED && ak != TYP_GENERIC_PARAM:
+ return -1
+ an := inst_type_node_of_ti(at)
+ if an < 0:
+ return -1
+ if i == 0:
+ first_an = an
+ i = i + 1
+ return alloc_node(EXPR_GENERIC_APPLY, get_type_data(base), first_an, cnt, 0, 0, 0, 0, 0)
+ return -1 // TUPLE / NULL / DYN / 未知 kind:无语法形态(DYN 另见 res_type_node 的码 7 格)
+
+fn gen_lookup_subst_ti(name_ni: int) -> int:
+ mi : ., mut = 0
+ loop:
+ if mi >= g_gen_subst_tis_count:
+ break
+ if r64(g_gen_subst_old, mi * 8) == name_ni:
+ return r64(g_gen_subst_tis, mi * 8)
+ mi = mi + 1
+ return -1
// 类型行 → 按当前实例替换泛型形参行后的类型行(-1 保持原行;复合行结构性重建)
-fn gen_subst_ti(ti: int) -> int {
- k := get_type_kind(ti);
- if k < 0 { return ti; }
- if k == TYP_GENERIC_PARAM {
- s := gen_lookup_subst_ti(get_type_data(ti));
- if s >= 0 { return s; }
- return ti;
- }
- if k == TYP_ARRAY { return alloc_type(TYP_ARRAY, gen_subst_ti(get_type_data(ti)), get_type_extra(ti)); }
- if k == TYP_SLICE { return alloc_type(TYP_SLICE, gen_subst_ti(get_type_data(ti)), 0); }
- if k == TYP_REF { return alloc_type(TYP_REF, gen_subst_ti(get_type_data(ti)), get_type_extra(ti)); }
- if k == TYP_PTR { return alloc_type(TYP_PTR, gen_subst_ti(get_type_data(ti)), get_type_extra(ti)); }
- if k == TYP_OPTIONAL { return alloc_type(TYP_OPTIONAL, gen_subst_ti(get_type_data(ti)), 0); }
- if k == TYP_GENERIC_APPLY {
- start := get_type_extra(ti);
- cnt := r64(g_gen_apply_data, start * 8);
+fn gen_subst_ti(ti: int) -> int:
+ k := get_type_kind(ti)
+ if k < 0:
+ return ti
+ if k == TYP_GENERIC_PARAM:
+ s := gen_lookup_subst_ti(get_type_data(ti))
+ if s >= 0:
+ return s
+ return ti
+ if k == TYP_ARRAY:
+ return alloc_type(TYP_ARRAY, gen_subst_ti(get_type_data(ti)), get_type_extra(ti))
+ if k == TYP_SLICE:
+ return alloc_type(TYP_SLICE, gen_subst_ti(get_type_data(ti)), 0)
+ if k == TYP_REF:
+ return alloc_type(TYP_REF, gen_subst_ti(get_type_data(ti)), get_type_extra(ti))
+ if k == TYP_PTR:
+ return alloc_type(TYP_PTR, gen_subst_ti(get_type_data(ti)), get_type_extra(ti))
+ if k == TYP_OPTIONAL:
+ return alloc_type(TYP_OPTIONAL, gen_subst_ti(get_type_data(ti)), 0)
+ if k == TYP_GENERIC_APPLY:
+ start := get_type_extra(ti)
+ cnt := r64(g_gen_apply_data, start * 8)
// 两趟(照 res_type_node 同款:子项替换自身会追加 gen_apply 载荷)
- subs : string, mut;
- if cnt > 0 {
- subs = alloc(cnt * 8);
- i : ., mut = 0;
- loop {
- if i >= cnt { break; }
- w64(subs, i * 8, gen_subst_ti(r64(g_gen_apply_data, (start + 1 + i) * 8)));
- i = i + 1;
- }
- }
- ns := g_gen_apply_data_count;
- grow_gen_apply_data(ns + 1 + cnt);
- w64(g_gen_apply_data, ns * 8, cnt);
- i2 : ., mut = 0;
- loop {
- if i2 >= cnt { break; }
- w64(g_gen_apply_data, (ns + 1 + i2) * 8, r64(subs, i2 * 8));
- i2 = i2 + 1;
- }
- g_gen_apply_data_count = ns + 1 + cnt;
- return alloc_type(TYP_GENERIC_APPLY, get_type_data(ti), ns);
- }
- return ti;
-}
+ subs : string, mut
+ if cnt > 0:
+ subs = alloc(cnt * 8)
+ i : ., mut = 0
+ loop:
+ if i >= cnt:
+ break
+ w64(subs, i * 8, gen_subst_ti(r64(g_gen_apply_data, (start + 1 + i) * 8)))
+ i = i + 1
+ ns := g_gen_apply_data_count
+ grow_gen_apply_data(ns + 1 + cnt)
+ w64(g_gen_apply_data, ns * 8, cnt)
+ i2 : ., mut = 0
+ loop:
+ if i2 >= cnt:
+ break
+ w64(g_gen_apply_data, (ns + 1 + i2) * 8, r64(subs, i2 * 8))
+ i2 = i2 + 1
+ g_gen_apply_data_count = ns + 1 + cnt
+ return alloc_type(TYP_GENERIC_APPLY, get_type_data(ti), ns)
+ return ti
// 替换后是否**全具体**(无残留泛型形参行):克隆期嵌套调用点绑定重映射的前置条件
// (残留 = 该绑定在本实例上下文无解 ⇒ 整段放弃、回落旧名字路径,不发明半解实例)
-fn inst_ti_concrete(ti: int) -> int {
- k := get_type_kind(ti);
- if k < 0 { return 1; } // 越界行:非形参,按具体处理(判定面自会拒绝)
- if k == TYP_GENERIC_PARAM { return 0; }
- if k == TYP_ARRAY || k == TYP_SLICE || k == TYP_REF || k == TYP_PTR || k == TYP_OPTIONAL {
- return inst_ti_concrete(get_type_data(ti));
- }
- if k == TYP_GENERIC_APPLY {
- start := get_type_extra(ti);
- cnt := r64(g_gen_apply_data, start * 8);
- i : ., mut = 0;
- loop {
- if i >= cnt { return 1; }
- if inst_ti_concrete(r64(g_gen_apply_data, (start + 1 + i) * 8)) == 0 { return 0; }
- i = i + 1;
- }
- return 1;
- }
- if k == TYP_TUPLE {
- start2 := get_type_extra(ti);
- cnt2 := get_type_data(ti);
- i2 : ., mut = 0;
- loop {
- if i2 >= cnt2 { return 1; }
- if inst_ti_concrete(r64(g_gen_apply_data, (start2 + i2) * 8)) == 0 { return 0; }
- i2 = i2 + 1;
- }
- return 1;
- }
- return 1;
-}
+fn inst_ti_concrete(ti: int) -> int:
+ k := get_type_kind(ti)
+ if k < 0:
+ return 1
+ // 越界行:非形参,按具体处理(判定面自会拒绝)
+ if k == TYP_GENERIC_PARAM:
+ return 0
+ if k == TYP_ARRAY || k == TYP_SLICE || k == TYP_REF || k == TYP_PTR || k == TYP_OPTIONAL:
+ return inst_ti_concrete(get_type_data(ti))
+ if k == TYP_GENERIC_APPLY:
+ start := get_type_extra(ti)
+ cnt := r64(g_gen_apply_data, start * 8)
+ i : ., mut = 0
+ loop:
+ if i >= cnt:
+ return 1
+ if inst_ti_concrete(r64(g_gen_apply_data, (start + 1 + i) * 8)) == 0:
+ return 0
+ i = i + 1
+ return 1
+ if k == TYP_TUPLE:
+ start2 := get_type_extra(ti)
+ cnt2 := get_type_data(ti)
+ i2 : ., mut = 0
+ loop:
+ if i2 >= cnt2:
+ return 1
+ if inst_ti_concrete(r64(g_gen_apply_data, (start2 + i2) * 8)) == 0:
+ return 0
+ i2 = i2 + 1
+ return 1
+ return 1
// 克隆期:源调用点绑定段(iv = 段起始 + 1,见 checker.cr 写入点)→ 按当前实例重登记的段
// (返回新的 **iv**;0 = 无/不可重映射 ⇒ 克隆体回落旧名字路径)。
// 为何必须重映射:克隆体内的调用节点携带**源函数上下文**的绑定(如 T := gparam(U))——
// 直接沿用 = 用源上下文的形参行给实例建键(错实例);置 0 = 丢信息(旧行为)。
-fn gen_remap_binds(iv: int) -> int {
- if iv <= 0 { return 0; }
- start := iv - 1;
- if start >= g_gen_binds_count { return 0; }
- cnt := r64(g_gen_binds, start * 8);
- if cnt <= 0 { return 0; }
- if start + 1 + cnt > g_gen_binds_count { return 0; }
+fn gen_remap_binds(iv: int) -> int:
+ if iv <= 0:
+ return 0
+ start := iv - 1
+ if start >= g_gen_binds_count:
+ return 0
+ cnt := r64(g_gen_binds, start * 8)
+ if cnt <= 0:
+ return 0
+ if start + 1 + cnt > g_gen_binds_count:
+ return 0
// 前置:全部条目替换后须**全具体**(否则整段放弃——不发明半解实例)。替换结果先落暂存
// (gen_subst_ti 对复合行会追加类型行/载荷 ⇒ 逐条重算 = 双倍分配;且避免边写边读)。
- subs : string, mut = alloc(cnt * 8);
- i : ., mut = 0;
- loop {
- if i >= cnt { break; }
- t := gen_subst_ti(r64(g_gen_binds, (start + 1 + i) * 8));
- if inst_ti_concrete(t) == 0 { return 0; }
- w64(subs, i * 8, t);
- i = i + 1;
- }
- ns := g_gen_binds_count;
- grow_gen_binds(ns + 1 + cnt);
- w64(g_gen_binds, ns * 8, cnt);
- i2 : ., mut = 0;
- loop {
- if i2 >= cnt { break; }
- w64(g_gen_binds, (ns + 1 + i2) * 8, r64(subs, i2 * 8));
- i2 = i2 + 1;
- }
- g_gen_binds_count = ns + 1 + cnt;
- return ns + 1;
-}
+ subs : string, mut = alloc(cnt * 8)
+ i : ., mut = 0
+ loop:
+ if i >= cnt:
+ break
+ t := gen_subst_ti(r64(g_gen_binds, (start + 1 + i) * 8))
+ if inst_ti_concrete(t) == 0:
+ return 0
+ w64(subs, i * 8, t)
+ i = i + 1
+ ns := g_gen_binds_count
+ grow_gen_binds(ns + 1 + cnt)
+ w64(g_gen_binds, ns * 8, cnt)
+ i2 : ., mut = 0
+ loop:
+ if i2 >= cnt:
+ break
+ w64(g_gen_binds, (ns + 1 + i2) * 8, r64(subs, i2 * 8))
+ i2 = i2 + 1
+ g_gen_binds_count = ns + 1 + cnt
+ return ns + 1
// ============================================================
// Dedup mapping for tree clone
// ============================================================
-fn gen_dedup_find(old_node: int) -> int {
- mi : ., mut = 0;
- loop {
- if mi >= g_gen_dedup_count { break; }
- if r64(g_gen_dedup_old, mi * 8) == old_node {
- return r64(g_gen_dedup_new, mi * 8);
- }
- mi = mi + 1;
- }
- return -1;
-}
-
-fn gen_dedup_add(old_node: int, new_node: int) {
- grow_gen_dedup(g_gen_dedup_count + 1);
- w64(g_gen_dedup_old, g_gen_dedup_count * 8, old_node);
- w64(g_gen_dedup_new, g_gen_dedup_count * 8, new_node);
- g_gen_dedup_count = g_gen_dedup_count + 1;
-}
+fn gen_dedup_find(old_node: int) -> int:
+ mi : ., mut = 0
+ loop:
+ if mi >= g_gen_dedup_count:
+ break
+ if r64(g_gen_dedup_old, mi * 8) == old_node:
+ return r64(g_gen_dedup_new, mi * 8)
+ mi = mi + 1
+ return -1
+
+fn gen_dedup_add(old_node: int, new_node: int):
+ grow_gen_dedup(g_gen_dedup_count + 1)
+ w64(g_gen_dedup_old, g_gen_dedup_count * 8, old_node)
+ w64(g_gen_dedup_new, g_gen_dedup_count * 8, new_node)
+ g_gen_dedup_count = g_gen_dedup_count + 1
// ============================================================
// Deep AST clone with generic param substitution
// ============================================================
// Clone a sequence of g_block_stmts entries, substituting each one.
-fn gen_clone_block(start: int, count: int) -> int {
- if count <= 0 { return -1; }
- new_start := g_block_stmt_count;
- grow_block_stmts(new_start + count);
+fn gen_clone_block(start: int, count: int) -> int:
+ if count <= 0:
+ return -1
+ new_start := g_block_stmt_count
+ grow_block_stmts(new_start + count)
// Reserve the outer block range before cloning children. Nested blocks
// append after this range instead of reusing and overwriting new_start.
- g_block_stmt_count = new_start + count;
- i : ., mut = 0;
- loop {
- if i >= count { break; }
- old_stmt := r64(g_block_stmts, (start + i) * 8);
- new_stmt := gen_clone_tree(old_stmt);
- w64(g_block_stmts, (new_start + i) * 8, new_stmt);
- i = i + 1;
- }
- return new_start;
-}
+ g_block_stmt_count = new_start + count
+ i : ., mut = 0
+ loop:
+ if i >= count:
+ break
+ old_stmt := r64(g_block_stmts, (start + i) * 8)
+ new_stmt := gen_clone_tree(old_stmt)
+ w64(g_block_stmts, (new_start + i) * 8, new_stmt)
+ i = i + 1
+ return new_start
// Clone consecutive AST nodes (for struct fields, array elements, etc.)
-fn gen_clone_consecutive(start: int, count: int) -> int {
- if count <= 0 || start < 0 { return -1; }
+fn gen_clone_consecutive(start: int, count: int) -> int:
+ if count <= 0 || start < 0:
+ return -1
// Each cloned node is appended to g_ast by gen_clone_tree, so they end up consecutive.
- first_new := g_ast_count;
- i : ., mut = 0;
- loop {
- if i >= count { break; }
- gen_clone_tree(start + i);
- i = i + 1;
- }
- return first_new;
-}
+ first_new := g_ast_count
+ i : ., mut = 0
+ loop:
+ if i >= count:
+ break
+ gen_clone_tree(start + i)
+ i = i + 1
+ return first_new
// Deep-clone an AST subtree, substituting generic param references
// with concrete type name references.
-fn gen_clone_tree(node: int) -> int {
- if node < 0 { return -1; }
+fn gen_clone_tree(node: int) -> int:
+ if node < 0:
+ return -1
// Dedup: if this node was already cloned, return the existing clone.
- dup := gen_dedup_find(node);
- if dup >= 0 { return dup; }
-
- k := ast_kind(node);
- a := ast_a(node); b := ast_b(node); c := ast_c(node);
- iv := ast_int_val(node); tv := ast_type_val(node);
- d := ast_data(node); ln := ast_line(node); cl := ast_col(node);
+ dup := gen_dedup_find(node)
+ if dup >= 0:
+ return dup
+
+ k := ast_kind(node)
+ a := ast_a(node)
+ b := ast_b(node)
+ c := ast_c(node)
+ iv := ast_int_val(node)
+ tv := ast_type_val(node)
+ d := ast_data(node)
+ ln := ast_line(node)
+ cl := ast_col(node)
// ── EXPR_IDENT: might be a generic param reference ──
- if k == EXPR_IDENT {
- ni := iv;
+ if k == EXPR_IDENT:
+ ni := iv
// R2 P3 Task 5(Step 4):**ti 路径优先**——由类型行合成完整类型节点(命名/应用/序列/
// 引用/指针/可选皆可表达),治旧「名字文本替换」对非原生实参的塌缩。合成失败(-1:
// 元组/复合实参等无语法形态)→ 落名字路径(旧行为逐字保持)。
- sti := gen_lookup_subst_ti(ni);
- if sti >= 0 {
- sn := inst_type_node_of_ti(sti);
- if sn >= 0 { gen_dedup_add(node, sn); return sn; }
- }
- sub := gen_lookup_subst(ni);
- if sub >= 0 {
+ sti := gen_lookup_subst_ti(ni)
+ if sti >= 0:
+ sn := inst_type_node_of_ti(sti)
+ if sn >= 0:
+ gen_dedup_add(node, sn)
+ return sn
+ sub := gen_lookup_subst(ni)
+ if sub >= 0:
// Substitute generic param with concrete type
- base_tv := gen_base_type_tv(sub);
- if base_tv >= 0 {
+ base_tv := gen_base_type_tv(sub)
+ if base_tv >= 0:
// Base type reference (int, float, etc.) → kind=0 node with type_val
- n := ast_alloc(0, 0, 0, 0, 0, base_tv, 0, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ n := ast_alloc(0, 0, 0, 0, 0, base_tv, 0, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// Named type (struct name, etc.) → EXPR_IDENT with concrete name
- n := ast_alloc(k, a, b, c, sub, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ n := ast_alloc(k, a, b, c, sub, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// Not a generic param — clone as-is
- n := ast_alloc(k, a, b, c, ni, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ n := ast_alloc(k, a, b, c, ni, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_NONE (kind=0): base type node OR struct field wrapper ──
- if k == EXPR_NONE {
- if a >= 0 && a != node {
+ if k == EXPR_NONE:
+ if a >= 0 && a != node:
// Struct literal field or pattern wrapper: a = value expression
- a2 := gen_clone_tree(a);
- n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// Base type node or empty: no AST children
- n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── Leaf nodes (no AST children) ──
- if k == EXPR_INT { n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_DEX { n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_BOOL { n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_STRING { n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_CHAR { n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_WILDCARD { n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_BREAK { n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_CONTINUE { n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_INT:
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_DEX:
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_BOOL:
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_STRING:
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_CHAR:
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_WILDCARD:
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_BREAK:
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_CONTINUE:
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── Single child in `a` ──
- if k == EXPR_RETURN { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_YIELD { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_AWAIT { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_MOVE { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_UNSAFE { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_TRY { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_UNARY { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_FIELD { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_STMT { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_GO { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_RETURN:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_YIELD:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_AWAIT:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_MOVE:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_UNSAFE:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_TRY:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_UNARY:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_FIELD:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_STMT:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_GO:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── R2 P3 Task 4:`T?`(a = 内层类型节点,可能含泛型形参)——单子节点克隆,
// 形参代入由 EXPR_IDENT 分支承担(clone 时经 gen_lookup_subst),故此处只递归 a。
// **必配分支**:默认兜底会把 d(=0)当 AST 子节点克隆(读进节点 0)——显式分支消除该面。
- if k == EXPR_OPTIONAL { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_OPTIONAL:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── 插值洞(批 8 插值展开):**理论不可达**(checker 已把洞就地改写为转换调用,早于本阶段的
// 克隆面)——但**必须显式分支**:默认兜底会把 `d` 当 AST 子节点(读进节点 0)或静默丢子树,
// 两者都是静默类。本分支 = 递归唯一的真子节点 `a`(洞表达式),并保留 `data`(洞文本)。
- if k == EXPR_INTERP_HOLE { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, 0, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_INTERP_HOLE:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, 0, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── Two children: `a` and `b` ──
- if k == EXPR_BINARY { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_ASSIGN { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_INDEX { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_WHILE { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_LOOP { a2 := gen_clone_tree(a); n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_RANGE { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
- if k == EXPR_AS { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_BINARY:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_ASSIGN:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_INDEX:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_WHILE:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_LOOP:
+ a2 := gen_clone_tree(a)
+ n := ast_alloc(k, a2, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_RANGE:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ if k == EXPR_AS:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_CALL: a=func_node(YES), b=first_ARG(YES), c=arg_count(NOT) ──
- if k == EXPR_CALL {
- a2 := gen_clone_tree(a); b2 := gen_clone_tree(b);
+ if k == EXPR_CALL:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
// R2 P3 Task 5(Step 4):调用点绑定的**实例化重映射**——克隆体内的调用节点携带
// **源函数上下文**的绑定(如 T := gparam(U))⇒ 按当前实例替换重登记(gen_remap_binds);
// 不可完全落地 → 0(= 无绑定,回落旧名字路径)。**必须显式改写**:iv 经 ast_alloc
// 原样拷贝,沿用 = 用源上下文的形参行给实例建键(错实例)。
- n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl);
- ast_set_int_val(n, gen_remap_binds(iv));
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ ast_set_int_val(n, gen_remap_binds(iv))
// R2 P3b Task 6(Step 3,mangling 退役):接口方法调用(泛型形参接收者)的**实例化解析**。
// 源节点携带(data = 泛型形参名 ni,type_val = CALL_FLAG_IFACE_METHOD;检查见 checker 的
// 泛型约束方法路径注)⇒ 此处按当前实例的具体类型**查方法表**取真实函数名(`g_methods`
// 三元组 → 函数名 ni)。旧态 = 克隆期沿用合成的 "T.m" 串(文本替换只作用于 EXPR_IDENT)
// ⇒ 实例体内调用目标悬空(实测:产物运行 rc=139)。
// 解析失败(形参未绑定 / 具体类型无此方法 / 嵌套形参)⇒ 保持原状(登记面,不发明目标)。
- if tv == CALL_FLAG_IFACE_METHOD {
- cni := gen_lookup_subst(d);
- if cni >= 0 && a2 >= 0 {
- m_ni := ast_int_val(a2);
- f_ni := iface_find_method(cni, m_ni);
- if f_ni >= 0 {
- ast_set_data(n, f_ni);
- ast_set_type_val(n, 0);
- }
- }
- }
- gen_dedup_add(node, n); return n;
- }
+ if tv == CALL_FLAG_IFACE_METHOD:
+ cni := gen_lookup_subst(d)
+ if cni >= 0 && a2 >= 0:
+ m_ni := ast_int_val(a2)
+ f_ni := iface_find_method(cni, m_ni)
+ if f_ni >= 0:
+ ast_set_data(n, f_ni)
+ ast_set_type_val(n, 0)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_ARG: a=expr(YES), b=next_arg(YES or -1) ──
- if k == EXPR_ARG { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_ARG:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_IF: a=cond(YES), b=then(YES), c=else(YES or -1) ──
- if k == EXPR_IF { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); c2 := gen_clone_tree(c); n := ast_alloc(k, a2, b2, c2, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_IF:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ c2 := gen_clone_tree(c)
+ n := ast_alloc(k, a2, b2, c2, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_FN: a=name_ni(NOT), b=first_param(YES), c=param_count(NOT), d=body(YES) ──
- if k == EXPR_FN { d2 := gen_clone_tree(d); n := ast_alloc(k, a, b, c, iv, tv, d2, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_FN:
+ d2 := gen_clone_tree(d)
+ n := ast_alloc(k, a, b, c, iv, tv, d2, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_PARAM: a=name_ni(NOT), d=type_node(YES) ──
- if k == EXPR_PARAM { d2 := gen_clone_tree(d); n := ast_alloc(k, a, b, c, iv, tv, d2, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_PARAM:
+ d2 := gen_clone_tree(d)
+ n := ast_alloc(k, a, b, c, iv, tv, d2, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_BLOCK: children in g_block_stmts ──
- if k == EXPR_BLOCK { new_start := gen_clone_block(a, b); n := ast_alloc(k, new_start, b, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_BLOCK:
+ new_start := gen_clone_block(a, b)
+ n := ast_alloc(k, new_start, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_FOR: a=var_name_ni(NOT), b=iter(YES), c=body(YES) ──
- if k == EXPR_FOR { b2 := gen_clone_tree(b); c2 := gen_clone_tree(c); n := ast_alloc(k, a, b2, c2, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_FOR:
+ b2 := gen_clone_tree(b)
+ c2 := gen_clone_tree(c)
+ n := ast_alloc(k, a, b2, c2, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_LET: a=name_ni(NOT), b=type(YES or -1), c=value(YES or -1), d=is_mut(NOT) ──
- if k == EXPR_LET { b2 := gen_clone_tree(b); c2 := gen_clone_tree(c); n := ast_alloc(k, a, b2, c2, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_LET:
+ b2 := gen_clone_tree(b)
+ c2 := gen_clone_tree(c)
+ n := ast_alloc(k, a, b2, c2, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_STRUCT: a=type_name_ni(NOT), b=first wrapper(YES, consecutive), c=field_count(NOT);
// wrapper.a = field value node、wrapper.b = 字段名 idx(TODO #2026-09-11-11 ①;-1 = 无名字信息)
// (F5 契约,见 parser.cr struct 字面量分支)──
- if k == EXPR_STRUCT {
- if b >= 0 && c > 0 {
+ if k == EXPR_STRUCT:
+ if b >= 0 && c > 0:
// 字段值先逐个深克隆(各自子树自占槽位),再统建连续 wrapper——
// 不得「克隆值后随建 wrapper」逐元素交错:wrapper 将不连续(与 parser 同契约)。
// **名字随克隆保留**(#2026-09-11-11 ①):实例体里的字段绑定仍按名字(源序 ≠ 声明序时,
// 丢名字会让 ir_gen 回落位序 ⇒ 静默错值——正是 #2026-09-11-11 要消灭的类)。
- nvs : string, mut = alloc(c * 8);
- nms : string, mut = alloc(c * 8);
- i : ., mut = 0;
- loop {
- if i >= c { break; }
- vn : ., mut = -1;
- if b + i >= 0 { vn = ast_a(b + i); }
- w64(nvs, i * 8, gen_clone_tree(vn));
- w64(nms, i * 8, ast_b(b + i));
- i = i + 1;
- }
- new_first := g_ast_count;
- i = 0;
- loop {
- if i >= c { break; }
- ast_alloc(EXPR_NONE, r64(nvs, i * 8), r64(nms, i * 8), 0, 0, 0, 0, ln, cl);
- i = i + 1;
- }
- n := ast_alloc(k, a, new_first, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
- n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ nvs : string, mut = alloc(c * 8)
+ nms : string, mut = alloc(c * 8)
+ i : ., mut = 0
+ loop:
+ if i >= c:
+ break
+ vn : ., mut = -1
+ if b + i >= 0:
+ vn = ast_a(b + i)
+ w64(nvs, i * 8, gen_clone_tree(vn))
+ w64(nms, i * 8, ast_b(b + i))
+ i = i + 1
+ new_first := g_ast_count
+ i = 0
+ loop:
+ if i >= c:
+ break
+ ast_alloc(EXPR_NONE, r64(nvs, i * 8), r64(nms, i * 8), 0, 0, 0, 0, ln, cl)
+ i = i + 1
+ n := ast_alloc(k, a, new_first, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_ARRAY: a=first wrapper(YES, consecutive), b=elem_count(NOT);
// wrapper.a = element value node(F5 契约,见 parser.cr 下标分支)──
- if k == EXPR_ARRAY {
- if a >= 0 && b > 0 {
+ if k == EXPR_ARRAY:
+ if a >= 0 && b > 0:
// 元素值先逐个深克隆(各自子树自占槽位),再统建连续 wrapper(与 parser 同契约)。
- nvs : string, mut = alloc(b * 8);
- i : ., mut = 0;
- loop {
- if i >= b { break; }
- vn : ., mut = -1;
- if a + i >= 0 { vn = ast_a(a + i); }
- w64(nvs, i * 8, gen_clone_tree(vn));
- i = i + 1;
- }
- new_first := g_ast_count;
- i = 0;
- loop {
- if i >= b { break; }
- ast_alloc(EXPR_NONE, r64(nvs, i * 8), 0, 0, 0, 0, 0, ln, cl);
- i = i + 1;
- }
- n := ast_alloc(k, new_first, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
- n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ nvs : string, mut = alloc(b * 8)
+ i : ., mut = 0
+ loop:
+ if i >= b:
+ break
+ vn : ., mut = -1
+ if a + i >= 0:
+ vn = ast_a(a + i)
+ w64(nvs, i * 8, gen_clone_tree(vn))
+ i = i + 1
+ new_first := g_ast_count
+ i = 0
+ loop:
+ if i >= b:
+ break
+ ast_alloc(EXPR_NONE, r64(nvs, i * 8), 0, 0, 0, 0, 0, ln, cl)
+ i = i + 1
+ n := ast_alloc(k, new_first, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_TUPLE: a=first wrapper(YES, consecutive), b=elem_count(NOT);
// wrapper.a = element value node(F5 契约,见 parser.cr 元组分支)──
- if k == EXPR_TUPLE {
- if a >= 0 && b > 0 {
+ if k == EXPR_TUPLE:
+ if a >= 0 && b > 0:
// 元素值先逐个深克隆(各自子树自占槽位),再统建连续 wrapper——
// 不得「克隆值后随建 wrapper」逐元素交错:wrapper 将不连续(与 parser 同契约)。
- nvs : string, mut = alloc(b * 8);
- i : ., mut = 0;
- loop {
- if i >= b { break; }
- vn : ., mut = -1;
- if a + i >= 0 { vn = ast_a(a + i); }
- w64(nvs, i * 8, gen_clone_tree(vn));
- i = i + 1;
- }
- new_first := g_ast_count;
- i = 0;
- loop {
- if i >= b { break; }
- ast_alloc(EXPR_NONE, r64(nvs, i * 8), 0, 0, 0, 0, 0, ln, cl);
- i = i + 1;
- }
- n := ast_alloc(k, new_first, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
- n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ nvs : string, mut = alloc(b * 8)
+ i : ., mut = 0
+ loop:
+ if i >= b:
+ break
+ vn : ., mut = -1
+ if a + i >= 0:
+ vn = ast_a(a + i)
+ w64(nvs, i * 8, gen_clone_tree(vn))
+ i = i + 1
+ new_first := g_ast_count
+ i = 0
+ loop:
+ if i >= b:
+ break
+ ast_alloc(EXPR_NONE, r64(nvs, i * 8), 0, 0, 0, 0, 0, ln, cl)
+ i = i + 1
+ n := ast_alloc(k, new_first, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_GENERIC_APPLY: a=base_name_ni(NOT), b=first_arg(YES, consecutive), c=arg_count(NOT) ──
- if k == EXPR_GENERIC_APPLY {
- if b >= 0 && c > 0 {
- new_first := gen_clone_consecutive(b, c);
- n := ast_alloc(k, a, new_first, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
- n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ if k == EXPR_GENERIC_APPLY:
+ if b >= 0 && c > 0:
+ new_first := gen_clone_consecutive(b, c)
+ n := ast_alloc(k, a, new_first, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_MATCH: a=expr(YES), b=first_arm(YES), c=arm_count(NOT) ──
- if k == EXPR_MATCH { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_MATCH:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_ARM: a=pattern(YES), b=body(YES) ──
- if k == EXPR_ARM { a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_ARM:
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a2, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_ENUM_CONSTRUCTOR: a=name_ni(NOT), b=first_arg(YES), c=arg_count(NOT) ──
- if k == EXPR_ENUM_CONSTRUCTOR { b2 := gen_clone_tree(b); n := ast_alloc(k, a, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_ENUM_CONSTRUCTOR:
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_ENUMPAT: a=name_ni(NOT), b=first_subpat(YES, consecutive), c=subpat_count(NOT) ──
- if k == EXPR_ENUMPAT { b2 := gen_clone_consecutive(b, c); n := ast_alloc(k, a, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_ENUMPAT:
+ b2 := gen_clone_consecutive(b, c)
+ n := ast_alloc(k, a, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_STRUCTPAT: a=name_ni(NOT), b=first wrapper(YES, consecutive), c=field_count(NOT);
// wrapper.a = 子模式节点(F5 契约,见 parser.cr struct 模式分支)──
- if k == EXPR_STRUCTPAT {
- if b >= 0 && c > 0 {
- nvs : string, mut = alloc(c * 8);
- i : ., mut = 0;
- loop {
- if i >= c { break; }
- vn : ., mut = -1;
- if b + i >= 0 { vn = ast_a(b + i); }
- w64(nvs, i * 8, gen_clone_tree(vn));
- i = i + 1;
- }
- new_first := g_ast_count;
- i = 0;
- loop {
- if i >= c { break; }
- ast_alloc(EXPR_NONE, r64(nvs, i * 8), 0, 0, 0, 0, 0, ln, cl);
- i = i + 1;
- }
- n := ast_alloc(k, a, new_first, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
- n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl);
- gen_dedup_add(node, n); return n;
- }
+ if k == EXPR_STRUCTPAT:
+ if b >= 0 && c > 0:
+ nvs : string, mut = alloc(c * 8)
+ i : ., mut = 0
+ loop:
+ if i >= c:
+ break
+ vn : ., mut = -1
+ if b + i >= 0:
+ vn = ast_a(b + i)
+ w64(nvs, i * 8, gen_clone_tree(vn))
+ i = i + 1
+ new_first := g_ast_count
+ i = 0
+ loop:
+ if i >= c:
+ break
+ ast_alloc(EXPR_NONE, r64(nvs, i * 8), 0, 0, 0, 0, 0, ln, cl)
+ i = i + 1
+ n := ast_alloc(k, a, new_first, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
+ n := ast_alloc(k, a, b, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_AT: a=name_ni(NOT), b=args_node(YES or -1) ──
- if k == EXPR_AT { b2 := gen_clone_tree(b); n := ast_alloc(k, a, b2, c, iv, tv, d, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_AT:
+ b2 := gen_clone_tree(b)
+ n := ast_alloc(k, a, b2, c, iv, tv, d, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── EXPR_FLOW: a=name_ni(NOT), b=param_count(NOT), c=first_param(YES), d=body(YES) ──
- if k == EXPR_FLOW { c2 := gen_clone_tree(c); d2 := gen_clone_tree(d); n := ast_alloc(k, a, b, c2, iv, tv, d2, ln, cl); gen_dedup_add(node, n); return n; }
+ if k == EXPR_FLOW:
+ c2 := gen_clone_tree(c)
+ d2 := gen_clone_tree(d)
+ n := ast_alloc(k, a, b, c2, iv, tv, d2, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ── Fallback (shouldn't normally reach here) ──
// Conservatively clone all pointer-sized fields as AST children.
- a2 := gen_clone_tree(a); b2 := gen_clone_tree(b); c2 := gen_clone_tree(c); d2 := gen_clone_tree(d);
- n := ast_alloc(k, a2, b2, c2, iv, tv, d2, ln, cl);
- gen_dedup_add(node, n); return n;
-}
+ a2 := gen_clone_tree(a)
+ b2 := gen_clone_tree(b)
+ c2 := gen_clone_tree(c)
+ d2 := gen_clone_tree(d)
+ n := ast_alloc(k, a2, b2, c2, iv, tv, d2, ln, cl)
+ gen_dedup_add(node, n)
+ return n
// ============================================================
// Cache API: find or create specialized instance
@@ -777,38 +1036,35 @@ fn gen_clone_tree(node: int) -> int {
// func_ni: the original generic FuncInfo index
// type_args: comma-separated concrete type names (e.g. "int,string")
// Returns the specialized function index, or -1 if not found.
-fn gen_find_cached(func_ni: int, type_args: string) -> int {
- i : ., mut = 0;
- loop {
- if i >= g_gen_instance_count { break; }
- if r64(g_gen_instances, i * 24) == func_ni {
- cached_args_ni := r64(g_gen_instances, i * 24 + 8);
- if istr_eq(cached_args_ni, type_args) != 0 {
- return r64(g_gen_instances, i * 24 + 16);
- }
- }
- i = i + 1;
- }
- return -1;
-}
+fn gen_find_cached(func_ni: int, type_args: string) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= g_gen_instance_count:
+ break
+ if r64(g_gen_instances, i * 24) == func_ni:
+ cached_args_ni := r64(g_gen_instances, i * 24 + 8)
+ if istr_eq(cached_args_ni, type_args) != 0:
+ return r64(g_gen_instances, i * 24 + 16)
+ i = i + 1
+ return -1
// Find or create a specialized instance of a generic function.
// func_ni: the original generic FuncInfo index
// type_args: comma-separated concrete type names (e.g. "int,string")
// Returns the specialized function index.
-fn gen_find_or_create(func_ni: int, type_args: string) -> int {
- cached := gen_find_cached(func_ni, type_args);
- if cached >= 0 { return cached; }
- return gen_create_instance(func_ni, type_args, -1);
-}
+fn gen_find_or_create(func_ni: int, type_args: string) -> int:
+ cached := gen_find_cached(func_ni, type_args)
+ if cached >= 0:
+ return cached
+ return gen_create_instance(func_ni, type_args, -1)
// R2 P3 Task 5(Step 4):带**调用点绑定段**的查/建(ir_gen 提供规范键 + 段起始)。
// 缓存键 = type_args 串(规范结构名 join,含真身份)⇒ 同实例同键、异实例异键(不再折叠)。
-fn gen_find_or_create_bind(func_ni: int, type_args: string, bstart: int) -> int {
- cached := gen_find_cached(func_ni, type_args);
- if cached >= 0 { return cached; }
- return gen_create_instance(func_ni, type_args, bstart);
-}
+fn gen_find_or_create_bind(func_ni: int, type_args: string, bstart: int) -> int:
+ cached := gen_find_cached(func_ni, type_args)
+ if cached >= 0:
+ return cached
+ return gen_create_instance(func_ni, type_args, bstart)
// Create a specialized copy of a generic function.
// Steps:
@@ -817,18 +1073,19 @@ fn gen_find_or_create_bind(func_ni: int, type_args: string, bstart: int) -> int
// 3. Register the new function in g_funcs
// 4. Cache the new function index
// 5. Return the new function index
-fn gen_create_instance(func_ni: int, type_args: string, bstart: int) -> int {
+fn gen_create_instance(func_ni: int, type_args: string, bstart: int) -> int:
// 1. Build substitution mapping
// · 名表(g_gen_subst_old/new):键 = 键串按逗号切分——**回落路径**;规范键下其名字对
// 复合类型不是声明名 ⇒ 只在 ti 路径失效时才可能被用到(见 gen_clone_tree 的优先级)。
// · ti 表(g_gen_subst_tis):bstart ≥ 0 且段合法时装填(**优先路径**——完整类型节点)。
- gen_build_subst(func_ni, type_args);
- gen_build_subst_tis(func_ni, bstart);
+ gen_build_subst(func_ni, type_args)
+ gen_build_subst_tis(func_ni, bstart)
// 2. Clone the original function AST
- orig_fn_node := fi_ast_node(func_ni);
- g_gen_dedup_count = 0; g_gen_dedup_cap = 0;
- new_fn_node := gen_clone_tree(orig_fn_node);
+ orig_fn_node := fi_ast_node(func_ni)
+ g_gen_dedup_count = 0
+ g_gen_dedup_cap = 0
+ new_fn_node := gen_clone_tree(orig_fn_node)
// ── (乙) A1:实例形参链**具体化**(2026-09-18)──────────────────────────────
// 根因:上方 `gen_clone_tree` 的 EXPR_FN 分支只深克隆 `d`(函数体),`b/c`(首形参/
@@ -844,84 +1101,86 @@ fn gen_create_instance(func_ni: int, type_args: string, bstart: int) -> int {
// `T` 靠本行(`type_val`),`T?` 靠类型节点代入(序言走 `dex_opt_type_node` 分支)。
// 布局契约(与 parser 同形):每个形参的类型子树**先于**其形参节点分配 ⇒ 「从
// `pn+1` 向前扫到下一个 EXPR_PARAM」的游标语义(序言与对齐环共用)逐字保持。
- pc_src := ast_c(orig_fn_node);
- if pc_src > 0 {
- opn : ., mut = ast_b(orig_fn_node);
- first_np : ., mut = -1;
- pi_src : ., mut = 0;
- loop {
- if pi_src >= pc_src { break; }
- if opn < 0 { break; }
- if ast_kind(opn) == EXPR_PARAM {
- nd := ast_data(opn);
- nd2 : ., mut = -1;
- if nd >= 0 { nd2 = gen_clone_tree(nd); }
- ntv : ., mut = 0;
- if nd2 >= 0 && ast_kind(nd2) == 0 { ntv = ast_type_val(nd2); }
- np := ast_alloc(EXPR_PARAM, ast_a(opn), ast_b(opn), ast_c(opn), ast_int_val(opn), ntv, nd2, ast_line(opn), ast_col(opn));
- gen_dedup_add(opn, np);
- if first_np < 0 { first_np = np; }
- pi_src = pi_src + 1;
- }
- opn = opn + 1;
- }
- if first_np >= 0 { ast_set_b(new_fn_node, first_np); }
- }
+ pc_src := ast_c(orig_fn_node)
+ if pc_src > 0:
+ opn : ., mut = ast_b(orig_fn_node)
+ first_np : ., mut = -1
+ pi_src : ., mut = 0
+ loop:
+ if pi_src >= pc_src:
+ break
+ if opn < 0:
+ break
+ if ast_kind(opn) == EXPR_PARAM:
+ nd := ast_data(opn)
+ nd2 : ., mut = -1
+ if nd >= 0:
+ nd2 = gen_clone_tree(nd)
+ ntv : ., mut = 0
+ if nd2 >= 0 && ast_kind(nd2) == 0:
+ ntv = ast_type_val(nd2)
+ np := ast_alloc(EXPR_PARAM, ast_a(opn), ast_b(opn), ast_c(opn), ast_int_val(opn), ntv, nd2, ast_line(opn), ast_col(opn))
+ gen_dedup_add(opn, np)
+ if first_np < 0:
+ first_np = np
+ pi_src = pi_src + 1
+ opn = opn + 1
+ if first_np >= 0:
+ ast_set_b(new_fn_node, first_np)
// Compute mangled name: "orig_name[type_args]" for unique identification
- orig_name := istr_get(fi_name(func_ni));
- mangled_name : ., mut = orig_name + "[" + type_args + "]";
- mangled_ni := str_intern(mangled_name);
+ orig_name := istr_get(fi_name(func_ni))
+ mangled_name : ., mut = orig_name + "[" + type_args + "]"
+ mangled_ni := str_intern(mangled_name)
// Update the cloned AST node's name to the mangled name
- ast_set_a(new_fn_node, mangled_ni);
+ ast_set_a(new_fn_node, mangled_ni)
// 3. Register new function in g_funcs
- new_fi := g_func_count;
- grow_funcs(new_fi + 1);
+ new_fi := g_func_count
+ grow_funcs(new_fi + 1)
// Use mangled name for unique lookup
- fi_set_name(new_fi, mangled_ni);
+ fi_set_name(new_fi, mangled_ni)
// Clone params: param type info from FuncInfo
- pc := fi_param_count(func_ni);
- fi_set_param_count(new_fi, pc);
- pi : ., mut = 0;
- loop {
- if pi >= pc { break; }
- fi_set_param_type(new_fi, pi, fi_param_type(func_ni, pi));
- pi = pi + 1;
- }
+ pc := fi_param_count(func_ni)
+ fi_set_param_count(new_fi, pc)
+ pi : ., mut = 0
+ loop:
+ if pi >= pc:
+ break
+ fi_set_param_type(new_fi, pi, fi_param_type(func_ni, pi))
+ pi = pi + 1
// Return type (set from original; will be re-checked)
- fi_set_return_type(new_fi, fi_return_type(func_ni));
+ fi_set_return_type(new_fi, fi_return_type(func_ni))
// AST node reference
- fi_set_ast_node(new_fi, new_fn_node);
+ fi_set_ast_node(new_fi, new_fn_node)
// Specialized instance has zero generic params (they've been substituted)
- fi_set_generic_count(new_fi, 0);
+ fi_set_generic_count(new_fi, 0)
- g_func_count = new_fi + 1;
+ g_func_count = new_fi + 1
// 4. Cache the new function
- type_args_ni := str_intern(type_args);
- grow_gen_instances(g_gen_instance_count + 1);
- w64(g_gen_instances, g_gen_instance_count * 24, func_ni);
- w64(g_gen_instances, g_gen_instance_count * 24 + 8, type_args_ni);
- w64(g_gen_instances, g_gen_instance_count * 24 + 16, new_fi);
- g_gen_instance_count = g_gen_instance_count + 1;
+ type_args_ni := str_intern(type_args)
+ grow_gen_instances(g_gen_instance_count + 1)
+ w64(g_gen_instances, g_gen_instance_count * 24, func_ni)
+ w64(g_gen_instances, g_gen_instance_count * 24 + 8, type_args_ni)
+ w64(g_gen_instances, g_gen_instance_count * 24 + 16, new_fi)
+ g_gen_instance_count = g_gen_instance_count + 1
// 效应/纯度修正 Task 1:登记实例 → 源(纯度回填用,见 globals.cr 表注)。
// 注意:不在此处写 fi_set_ispure(new_fi, fi_ispure(func_ni))——本时点(IR 生成期)
// 源函数还没有真纯度(真纯度只能由全程序 IR 体算,见 checker.cr 头注),
// 抄过来的是乐观默认值,会把有效应泛型实例错标为纯。实例纯度由其自身体
// 在 df_state_finalize 算出;源函数纯度 = 实例合取(compute_all_purity 回填)。
- grow_purity_inst(g_purity_inst_count + 1);
- w64(g_purity_inst, g_purity_inst_count * 24, func_ni);
- w64(g_purity_inst, g_purity_inst_count * 24 + 8, type_args_ni);
- w64(g_purity_inst, g_purity_inst_count * 24 + 16, new_fi);
- g_purity_inst_count = g_purity_inst_count + 1;
+ grow_purity_inst(g_purity_inst_count + 1)
+ w64(g_purity_inst, g_purity_inst_count * 24, func_ni)
+ w64(g_purity_inst, g_purity_inst_count * 24 + 8, type_args_ni)
+ w64(g_purity_inst, g_purity_inst_count * 24 + 16, new_fi)
+ g_purity_inst_count = g_purity_inst_count + 1
// 5. Return new function index
- return new_fi;
-}
+ return new_fi
diff --git a/src/compiler/opt.cr b/src/compiler/opt.cr
index d39d52f2..a2d789f2 100644
--- a/src/compiler/opt.cr
+++ b/src/compiler/opt.cr
@@ -10,342 +10,410 @@
// AST constant folding: EXPR_BINARY(int, int) → EXPR_INT
// ------------------------------------------------------------------
-fn ast_is_const_int(node: int) -> int {
- if node < 0 { return 0; }
- if ast_kind(node) == EXPR_INT { return 1; }
- return 0;
-}
+fn ast_is_const_int(node: int) -> int:
+ if node < 0:
+ return 0
+ if ast_kind(node) == EXPR_INT:
+ return 1
+ return 0
-fn ast_const_val(node: int) -> int {
- return ast_int_val(node);
-}
+fn ast_const_val(node: int) -> int:
+ return ast_int_val(node)
-fn ast_bool_as_int(value: bool) -> int {
- if value { return 1; }
- return 0;
-}
+fn ast_bool_as_int(value: bool) -> int:
+ if value:
+ return 1
+ return 0
-fn ast_fold_binary(node: int) -> int {
- left := ast_a(node);
- right := ast_b(node);
- opc := ast_c(node);
- if !ast_is_const_int(left) || !ast_is_const_int(right) { return 0; }
- v1 := ast_const_val(left);
- v2 := ast_const_val(right);
- rv : ., mut = 0;
- known : ., mut = 1;
- if opc == OP_ADD { rv = v1 + v2; }
- else if opc == OP_SUB { rv = v1 - v2; }
- else if opc == OP_MUL { rv = v1 * v2; }
- else if opc == OP_DIV { if v2 == 0 { return 0; } rv = v1 / v2; }
- else if opc == OP_MOD { if v2 == 0 { return 0; } rv = v1 % v2; }
- else if opc == OP_EQ { rv = ast_bool_as_int(v1 == v2); }
- else if opc == OP_NE { rv = ast_bool_as_int(v1 != v2); }
- else if opc == OP_LT { rv = ast_bool_as_int(v1 < v2); }
- else if opc == OP_GT { rv = ast_bool_as_int(v1 > v2); }
- else if opc == OP_LE { rv = ast_bool_as_int(v1 <= v2); }
- else if opc == OP_GE { rv = ast_bool_as_int(v1 >= v2); }
- else if opc == OP_AND { rv = ast_bool_as_int(v1 != 0 && v2 != 0); }
- else if opc == OP_OR { rv = ast_bool_as_int(v1 != 0 || v2 != 0); }
- else { known = 0; }
- if known == 0 { return 0; }
+fn ast_fold_binary(node: int) -> int:
+ left := ast_a(node)
+ right := ast_b(node)
+ opc := ast_c(node)
+ if !ast_is_const_int(left) || !ast_is_const_int(right):
+ return 0
+ v1 := ast_const_val(left)
+ v2 := ast_const_val(right)
+ rv : ., mut = 0
+ known : ., mut = 1
+ if opc == OP_ADD:
+ rv = v1 + v2
+ else if opc == OP_SUB:
+ rv = v1 - v2
+ else if opc == OP_MUL:
+ rv = v1 * v2
+ else if opc == OP_DIV:
+ if v2 == 0:
+ return 0
+ rv = v1 / v2
+ else if opc == OP_MOD:
+ if v2 == 0:
+ return 0
+ rv = v1 % v2
+ else if opc == OP_EQ:
+ rv = ast_bool_as_int(v1 == v2)
+ else if opc == OP_NE:
+ rv = ast_bool_as_int(v1 != v2)
+ else if opc == OP_LT:
+ rv = ast_bool_as_int(v1 < v2)
+ else if opc == OP_GT:
+ rv = ast_bool_as_int(v1 > v2)
+ else if opc == OP_LE:
+ rv = ast_bool_as_int(v1 <= v2)
+ else if opc == OP_GE:
+ rv = ast_bool_as_int(v1 >= v2)
+ else if opc == OP_AND:
+ rv = ast_bool_as_int(v1 != 0 && v2 != 0)
+ else if opc == OP_OR:
+ rv = ast_bool_as_int(v1 != 0 || v2 != 0)
+ else:
+ known = 0
+ if known == 0:
+ return 0
// Fold: replace EXPR_BINARY with EXPR_INT
// Use ast_set_* to modify in-place
- ast_set_kind(node, EXPR_INT);
- ast_set_a(node, 0);
- ast_set_b(node, 0);
- ast_set_c(node, 0);
- ast_set_int_val(node, rv);
- ast_set_type_val(node, TY_INT);
- return 1;
-}
+ ast_set_kind(node, EXPR_INT)
+ ast_set_a(node, 0)
+ ast_set_b(node, 0)
+ ast_set_c(node, 0)
+ ast_set_int_val(node, rv)
+ ast_set_type_val(node, TY_INT)
+ return 1
// ------------------------------------------------------------------
// Walk a block's statements and fold expressions
// ------------------------------------------------------------------
-fn ast_optimize_body(body: int) {
- if body < 0 { return; }
- bk := ast_kind(body);
+fn ast_optimize_body(body: int):
+ if body < 0:
+ return
+ bk := ast_kind(body)
// EXPR_BLOCK: optimize each statement recursively
- if bk == EXPR_BLOCK {
- ss := ast_a(body); sc := ast_b(body);
- i : ., mut = 0;
- loop {
- if i >= sc { break; }
- sn := r64(g_block_stmts, (ss + i) * 8);
- ast_optimize_body(sn);
- i = i + 1;
- }
- return;
- }
+ if bk == EXPR_BLOCK:
+ ss := ast_a(body)
+ sc := ast_b(body)
+ i : ., mut = 0
+ loop:
+ if i >= sc:
+ break
+ sn := r64(g_block_stmts, (ss + i) * 8)
+ ast_optimize_body(sn)
+ i = i + 1
+ return
// EXPR_RETURN: optimize the return value expression
- if bk == EXPR_RETURN {
- if ast_a(body) >= 0 { ast_optimize_body(ast_a(body)); }
- return;
- }
+ if bk == EXPR_RETURN:
+ if ast_a(body) >= 0:
+ ast_optimize_body(ast_a(body))
+ return
// EXPR_IF: optimize condition, then, else
- if bk == EXPR_IF {
- ast_optimize_body(ast_a(body)); // cond
- ast_optimize_body(ast_b(body)); // then
- if ast_c(body) >= 0 { ast_optimize_body(ast_c(body)); } // else
+ if bk == EXPR_IF:
+ ast_optimize_body(ast_a(body)) // cond
+ ast_optimize_body(ast_b(body)) // then
+ if ast_c(body) >= 0:
+ ast_optimize_body(ast_c(body))
+ // else
// Fold: if const_int(0) → else, if const_int(≠0) → then
- cond := ast_a(body);
- if ast_is_const_int(cond) {
- cv := ast_const_val(cond);
- then_node := ast_b(body);
- else_node := ast_c(body);
- if cv != 0 && then_node >= 0 {
+ cond := ast_a(body)
+ if ast_is_const_int(cond):
+ cv := ast_const_val(cond)
+ then_node := ast_b(body)
+ else_node := ast_c(body)
+
// Replace if with then body
// We can't easily clone AST, so just mark as NONE
// (IR gen will skip)
- } else if cv == 0 && else_node >= 0 {
+
// Replace if with else body
- }
- }
- return;
- }
+
+ return
// EXPR_BINARY: fold constants
- if bk == EXPR_BINARY {
- ast_optimize_body(ast_a(body));
- ast_optimize_body(ast_b(body));
- ast_fold_binary(body);
- return;
- }
+ if bk == EXPR_BINARY:
+ ast_optimize_body(ast_a(body))
+ ast_optimize_body(ast_b(body))
+ ast_fold_binary(body)
+ return
// EXPR_UNARY
- if bk == EXPR_UNARY {
- if ast_a(body) >= 0 { ast_optimize_body(ast_a(body)); }
- return;
- }
+ if bk == EXPR_UNARY:
+ if ast_a(body) >= 0:
+ ast_optimize_body(ast_a(body))
+ return
// EXPR_CALL: optimize args
- if bk == EXPR_CALL {
- if ast_a(body) >= 0 { ast_optimize_body(ast_a(body)); }
- an := ast_b(body); ac := ast_c(body);
- ai : ., mut = 0;
- loop { if ai >= ac { break; } if an >= 0 { ast_optimize_body(an); an = an + 1; } ai = ai + 1; }
- return;
- }
+ if bk == EXPR_CALL:
+ if ast_a(body) >= 0:
+ ast_optimize_body(ast_a(body))
+ an := ast_b(body)
+ ac := ast_c(body)
+ ai : ., mut = 0
+ loop:
+ if ai >= ac:
+ break
+ if an >= 0:
+ ast_optimize_body(an)
+ an = an + 1
+ ai = ai + 1
+ return
// EXPR_STRUCT: a=type_name_ni, b=first wrapper(连续), c=field_count;wrapper.a=字段值节点
// (F5 契约,见 parser.cr struct 字面量分支)。旧代码直接对 wrapper 递归,而 wrapper 的
// kind=EXPR_NONE 在本函数无分支 ⇒ 常量折叠静默空转(字段值从不被优化)。
- if bk == EXPR_STRUCT {
- fn2 := ast_b(body); fc := ast_c(body);
- i : ., mut = 0;
- loop {
- if i >= fc { break; }
- if fn2 >= 0 {
- vn : ., mut = -1;
- if ast_kind(fn2) == EXPR_NONE { vn = ast_a(fn2); }
- if vn >= 0 { ast_optimize_body(vn); }
- fn2 = fn2 + 1;
- }
- i = i + 1;
- }
- return;
- }
+ if bk == EXPR_STRUCT:
+ fn2 := ast_b(body)
+ fc := ast_c(body)
+ i : ., mut = 0
+ loop:
+ if i >= fc:
+ break
+ if fn2 >= 0:
+ vn : ., mut = -1
+ if ast_kind(fn2) == EXPR_NONE:
+ vn = ast_a(fn2)
+ if vn >= 0:
+ ast_optimize_body(vn)
+ fn2 = fn2 + 1
+ i = i + 1
+ return
// EXPR_LET: optimize value expression
- if bk == EXPR_LET {
- if ast_c(body) >= 0 { ast_optimize_body(ast_c(body)); }
- return;
- }
+ if bk == EXPR_LET:
+ if ast_c(body) >= 0:
+ ast_optimize_body(ast_c(body))
+ return
// EXPR_GO: optimize spawned body
- if bk == EXPR_GO {
- if ast_b(body) >= 0 { ast_optimize_body(ast_b(body)); }
- return;
- }
- if bk == EXPR_YIELD {
- if ast_a(body) >= 0 { ast_optimize_body(ast_a(body)); }
- return;
- }
+ if bk == EXPR_GO:
+ if ast_b(body) >= 0:
+ ast_optimize_body(ast_b(body))
+ return
+ if bk == EXPR_YIELD:
+ if ast_a(body) >= 0:
+ ast_optimize_body(ast_a(body))
+ return
// EXPR_LOOP, EXPR_WHILE: optimize body
- if bk == EXPR_LOOP || bk == EXPR_WHILE {
- if ast_a(body) >= 0 { ast_optimize_body(ast_a(body)); }
- return;
- }
+ if bk == EXPR_LOOP || bk == EXPR_WHILE:
+ if ast_a(body) >= 0:
+ ast_optimize_body(ast_a(body))
+ return
// EXPR_FOR: optimize iter and body
- if bk == EXPR_FOR {
- if ast_b(body) >= 0 { ast_optimize_body(ast_b(body)); }
- if ast_c(body) >= 0 { ast_optimize_body(ast_c(body)); }
- return;
- }
+ if bk == EXPR_FOR:
+ if ast_b(body) >= 0:
+ ast_optimize_body(ast_b(body))
+ if ast_c(body) >= 0:
+ ast_optimize_body(ast_c(body))
+ return
// EXPR_MATCH: optimize match expr and arms
- if bk == EXPR_MATCH {
- if ast_a(body) >= 0 { ast_optimize_body(ast_a(body)); }
- an := ast_b(body);
- loop { if an < 0 { break; }
- if ast_a(an) >= 0 { ast_optimize_body(ast_a(an)); }
- if ast_b(an) >= 0 { ast_optimize_body(ast_b(an)); }
- an = ast_c(an); }
- return;
- }
+ if bk == EXPR_MATCH:
+ if ast_a(body) >= 0:
+ ast_optimize_body(ast_a(body))
+ an := ast_b(body)
+ loop:
+ if an < 0:
+ break
+ if ast_a(an) >= 0:
+ ast_optimize_body(ast_a(an))
+ if ast_b(an) >= 0:
+ ast_optimize_body(ast_b(an))
+ an = ast_c(an)
+ return
// EXPR_STMT: unwrap
- if bk == EXPR_STMT {
- if ast_a(body) >= 0 { ast_optimize_body(ast_a(body)); }
- return;
- }
+ if bk == EXPR_STMT:
+ if ast_a(body) >= 0:
+ ast_optimize_body(ast_a(body))
+ return
// EXPR_ARRAY: a=first wrapper(连续), b=elem_count;wrapper.a=元素值节点
// (F5 契约,见 parser.cr 下标分支);旧代码直接对 wrapper 递归 = 空转(EXPR_NONE 无分支)。
- if bk == EXPR_ARRAY {
- an := ast_a(body); ac := ast_b(body);
- i : ., mut = 0;
- loop {
- if i >= ac { break; }
- if an >= 0 {
- vn : ., mut = -1;
- if ast_kind(an) == EXPR_NONE { vn = ast_a(an); }
- if vn >= 0 { ast_optimize_body(vn); }
- an = an + 1;
- }
- i = i + 1;
- }
- return;
- }
+ if bk == EXPR_ARRAY:
+ an := ast_a(body)
+ ac := ast_b(body)
+ i : ., mut = 0
+ loop:
+ if i >= ac:
+ break
+ if an >= 0:
+ vn : ., mut = -1
+ if ast_kind(an) == EXPR_NONE:
+ vn = ast_a(an)
+ if vn >= 0:
+ ast_optimize_body(vn)
+ an = an + 1
+ i = i + 1
+ return
// EXPR_TUPLE: a=first wrapper(连续), b=elem_count;wrapper.a=元素值节点(F5 契约)
- if bk == EXPR_TUPLE {
- an := ast_a(body); ac := ast_b(body);
- i : ., mut = 0;
- loop {
- if i >= ac { break; }
- if an >= 0 {
- vn : ., mut = -1;
- if ast_kind(an) == EXPR_NONE { vn = ast_a(an); }
- if vn >= 0 { ast_optimize_body(vn); }
- an = an + 1;
- }
- i = i + 1;
- }
- return;
- }
+ if bk == EXPR_TUPLE:
+ an := ast_a(body)
+ ac := ast_b(body)
+ i : ., mut = 0
+ loop:
+ if i >= ac:
+ break
+ if an >= 0:
+ vn : ., mut = -1
+ if ast_kind(an) == EXPR_NONE:
+ vn = ast_a(an)
+ if vn >= 0:
+ ast_optimize_body(vn)
+ an = an + 1
+ i = i + 1
+ return
// EXPR_AS: optimize both sides
- if bk == EXPR_AS {
- if ast_a(body) >= 0 { ast_optimize_body(ast_a(body)); }
- return;
- }
+ if bk == EXPR_AS:
+ if ast_a(body) >= 0:
+ ast_optimize_body(ast_a(body))
+ return
// EXPR_BINARY already handled above; fallthrough for EXPR_INDEX etc.
-}
// ------------------------------------------------------------------
// Common subexpression elimination (CFIR)
// ------------------------------------------------------------------
-fn pass_cse() {
- if g_ir_func_count <= 0 { return; }
- fi : ., mut = 0;
- loop {
- if fi >= g_ir_func_count { break; }
- ic := r64(g_ir_func_instr_count, fi * 8);
- ist := r64(g_ir_func_instr_start, fi * 8);
- if ic <= 0 { fi = fi + 1; continue; }
+fn pass_cse():
+ if g_ir_func_count <= 0:
+ return
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ ic := r64(g_ir_func_instr_count, fi * 8)
+ ist := r64(g_ir_func_instr_start, fi * 8)
+ if ic <= 0:
+ fi = fi + 1
+ continue
// CSE: track seen (op, s1, s2) → dest_var mapping
// Simple linear scan — sufficient for O1
- seen_count : ., mut = 0;
+ seen_count : ., mut = 0
// Flat array: each entry = (op:8, s1:8, s2:8, dest:8) = 32 bytes
- seen : string, mut = alloc(ic * 32);
+ seen : string, mut = alloc(ic * 32)
// Replacement map: var → canonical var (8 bytes each)
- replace_map : string, mut = alloc(ic * 8);
- replace_count : ., mut = 0;
+ replace_map : string, mut = alloc(ic * 8)
+ replace_count : ., mut = 0
- ii : ., mut = 0;
- loop {
- if ii >= ic { break; }
- inst := ist + ii;
- op := iri_op(inst);
- d := iri_dest(inst);
- s1 := iri_s1(inst);
- s2 := iri_s2(inst);
+ ii : ., mut = 0
+ loop:
+ if ii >= ic:
+ break
+ inst := ist + ii
+ op := iri_op(inst)
+ d := iri_dest(inst)
+ s1 := iri_s1(inst)
+ s2 := iri_s2(inst)
// Skip arena opcodes — side-effecting, not optimizable
- if op == IR_ARENA_NEW { ii = ii + 1; continue; }
- if op == IR_ARENA_RESET { ii = ii + 1; continue; }
- if op == IR_INLINE { ii = ii + 1; continue; }
- if op == IR_NO_BOUNDS_CHECK { ii = ii + 1; continue; }
- if op == IR_FAST { ii = ii + 1; continue; }
- if op == IR_UNROLL { ii = ii + 1; continue; }
- if op == IR_APPROX { ii = ii + 1; continue; }
- if op == IR_SECTION { ii = ii + 1; continue; }
- if op == IR_HOTPATCH_ROUTE { ii = ii + 1; continue; }
- if op == IR_DYN_TAG { ii = ii + 1; continue; }
- if op == IR_DYN_VAL { ii = ii + 1; continue; }
- if op == IR_DYN_PACK { ii = ii + 1; continue; }
- if op == IR_DYN_DISPATCH { ii = ii + 1; continue; }
- if op == IR_CALL_EXTERN { ii = ii + 1; continue; }
- if op == IR_LAZY_THUNK { ii = ii + 1; continue; }
- if op == IR_LAZY_FORCE { ii = ii + 1; continue; }
- if op == IR_FNADDR { ii = ii + 1; continue; }
+ if op == IR_ARENA_NEW:
+ ii = ii + 1
+ continue
+ if op == IR_ARENA_RESET:
+ ii = ii + 1
+ continue
+ if op == IR_INLINE:
+ ii = ii + 1
+ continue
+ if op == IR_NO_BOUNDS_CHECK:
+ ii = ii + 1
+ continue
+ if op == IR_FAST:
+ ii = ii + 1
+ continue
+ if op == IR_UNROLL:
+ ii = ii + 1
+ continue
+ if op == IR_APPROX:
+ ii = ii + 1
+ continue
+ if op == IR_SECTION:
+ ii = ii + 1
+ continue
+ if op == IR_HOTPATCH_ROUTE:
+ ii = ii + 1
+ continue
+ if op == IR_DYN_TAG:
+ ii = ii + 1
+ continue
+ if op == IR_DYN_VAL:
+ ii = ii + 1
+ continue
+ if op == IR_DYN_PACK:
+ ii = ii + 1
+ continue
+ if op == IR_DYN_DISPATCH:
+ ii = ii + 1
+ continue
+ if op == IR_CALL_EXTERN:
+ ii = ii + 1
+ continue
+ if op == IR_LAZY_THUNK:
+ ii = ii + 1
+ continue
+ if op == IR_LAZY_FORCE:
+ ii = ii + 1
+ continue
+ if op == IR_FNADDR:
+ ii = ii + 1
+ continue
// Only CSE for pure computations: BINARY, UNARY
- if (op == IR_BINARY || op == IR_UNARY) && d >= 0 {
+ if (op == IR_BINARY || op == IR_UNARY) && d >= 0:
// Check if we've seen this expression
- found : ., mut = -1;
- sj : ., mut = 0;
- loop {
- if sj >= seen_count { break; }
- so := sj * 32;
- if r64(seen, so) == op && r64(seen, so+8) == s1 && r64(seen, so+16) == s2 {
- found = sj; break;
- }
- sj = sj + 1;
- }
- if found >= 0 {
+ found : ., mut = -1
+ sj : ., mut = 0
+ loop:
+ if sj >= seen_count:
+ break
+ so := sj * 32
+ if r64(seen, so) == op && r64(seen, so+8) == s1 && r64(seen, so+16) == s2:
+ found = sj
+ break
+ sj = sj + 1
+ if found >= 0:
// Duplicate — record replacement: d → canonical dest
- canonical := r64(seen, found * 32 + 24);
- w64(replace_map, replace_count * 8, d);
- w64(replace_map, replace_count * 8 + 8, canonical);
- replace_count = replace_count + 1;
+ canonical := r64(seen, found * 32 + 24)
+ w64(replace_map, replace_count * 8, d)
+ w64(replace_map, replace_count * 8 + 8, canonical)
+ replace_count = replace_count + 1
// NOP this instruction
- iri_set_op(inst, IR_NOP);
- } else {
+ iri_set_op(inst, IR_NOP)
+ else:
// New expression — record it
- so := seen_count * 32;
- w64(seen, so, op);
- w64(seen, so+8, s1);
- w64(seen, so+16, s2);
- w64(seen, so+24, d);
- seen_count = seen_count + 1;
- }
- }
+ so := seen_count * 32
+ w64(seen, so, op)
+ w64(seen, so+8, s1)
+ w64(seen, so+16, s2)
+ w64(seen, so+24, d)
+ seen_count = seen_count + 1
// Apply replacements to operands of ALL instructions
- if replace_count > 0 {
- rj : ., mut = 0;
- loop {
- if rj >= replace_count { break; }
- old_v := r64(replace_map, rj * 8);
- new_v := r64(replace_map, rj * 8 + 8);
- if iri_s1(inst) == old_v { iri_set_s1(inst, new_v); }
- if iri_s2(inst) == old_v { iri_set_s2(inst, new_v); }
- if iri_s3(inst) == old_v { iri_set_s3(inst, new_v); }
- rj = rj + 1;
- }
- }
+ if replace_count > 0:
+ rj : ., mut = 0
+ loop:
+ if rj >= replace_count:
+ break
+ old_v := r64(replace_map, rj * 8)
+ new_v := r64(replace_map, rj * 8 + 8)
+ if iri_s1(inst) == old_v:
+ iri_set_s1(inst, new_v)
+ if iri_s2(inst) == old_v:
+ iri_set_s2(inst, new_v)
+ if iri_s3(inst) == old_v:
+ iri_set_s3(inst, new_v)
+ rj = rj + 1
- ii = ii + 1;
- }
- fi = fi + 1;
- }
-}
+ ii = ii + 1
+ fi = fi + 1
-fn optimize_all() {
+fn optimize_all():
// Pointer analysis (always runs, even at opt_level 0)
- ptr_analysis_all();
+ ptr_analysis_all()
// RegionCheck: verify DEREF targets are in live subgraphs
- region_check_all();
+ region_check_all()
// ProvenanceVerify: check DEREF offsets against allocation sizes
- provenance_verify_all();
- if g_opt_level < 1 { return; }
- fi : ., mut = 0;
- loop {
- if fi >= g_func_count { break; }
- fn_node := fi_ast_node(fi);
- body := ast_data(fn_node); // function body
- ast_optimize_body(body);
- fi = fi + 1;
- }
+ provenance_verify_all()
+ if g_opt_level < 1:
+ return
+ fi : ., mut = 0
+ loop:
+ if fi >= g_func_count:
+ break
+ fn_node := fi_ast_node(fi)
+ body := ast_data(fn_node) // function body
+ ast_optimize_body(body)
+ fi = fi + 1
// 注(2026-09-07 regalloc 移后端):alloc_registers/pass_stack_share 已迁
// corearch(src/arch/x86_64/regalloc.cr——.ccr 不再传 REG_ASSIGN/ENT)。
// 本函数无调用者(main.cr 直调各 pass),保留为历史编排入口。
- if g_opt_level >= 2 {
- pass_cse();
- }
-}
+ if g_opt_level >= 2:
+ pass_cse()
diff --git a/src/compiler/parser.cr b/src/compiler/parser.cr
index 550fb7bc..e953212f 100644
--- a/src/compiler/parser.cr
+++ b/src/compiler/parser.cr
@@ -1,399 +1,506 @@
// Parser: recursive descent with flat AST output
// Global state for parser (shared globals in globals.cr)
-g_token_pos : int, mut;
+g_token_pos : int, mut
// Buffer for batch declaration overflow (a, b : int = 1, 2)
-g_extra_lets : string, mut; g_extra_lets_cap : int, mut;
-g_extra_let_count : int, mut;
-
-// Flag: when set, IDENT { is NOT parsed as struct literal
-g_parse_no_struct_literal : int, mut;
-
-fn alloc_node(kind: int, a: int, b: int, c: int, iv: int, tv: int, d: int, line: int, col: int) -> int {
- return ast_alloc(kind, a, b, c, iv, tv, d, line, col);
-}
-
-fn cur_tok() -> int { return g_token_pos; }
-fn tok_k(p: int) -> int { return r64(g_tokens, p * ESZ_TOKEN + OFF_TK_KIND); }
-fn tok_lx(p: int) -> string { return istr_get(r64(g_tokens, p * ESZ_TOKEN + OFF_TK_LEXEME)); }
-fn tok_iv(p: int) -> int { return r64(g_tokens, p * ESZ_TOKEN + OFF_TK_INTVAL); }
-fn tok_ln(p: int) -> int { return r64(g_tokens, p * ESZ_TOKEN + OFF_TK_LINE); }
-fn tok_cl(p: int) -> int { return r64(g_tokens, p * ESZ_TOKEN + OFF_TK_COL); }
-
-fn advance_tok() -> int {
- t := cur_tok();
- if tok_k(t) != T_EOF { g_token_pos = t + 1; }
- return t;
-}
-
-fn check(k: int) -> bool {
- if tok_k(cur_tok()) == k { return true; } else { return false; }
-}
-
-fn expect(k: int) -> int {
- t := cur_tok();
- if tok_k(t) == k { return advance_tok(); }
- return t;
-}
+g_extra_lets : string, mut
+g_extra_lets_cap : int, mut
+g_extra_let_count : int, mut
+
+// v4(T0 布局规格 §4.5):原 `g_parse_no_struct_literal` 旗标**已删除** —— 块花括号不存在
+// ⇒ `IDENT {` 之后**必**是结构体字面量,歧义(靠「深度 1 的 `;`」判块)随之消失。
+
+fn alloc_node(kind: int, a: int, b: int, c: int, iv: int, tv: int, d: int, line: int, col: int) -> int:
+ return ast_alloc(kind, a, b, c, iv, tv, d, line, col)
+
+fn cur_tok() -> int:
+ return g_token_pos
+fn tok_k(p: int) -> int:
+ return r64(g_tokens, p * ESZ_TOKEN + OFF_TK_KIND)
+fn tok_lx(p: int) -> string:
+ return istr_get(r64(g_tokens, p * ESZ_TOKEN + OFF_TK_LEXEME))
+fn tok_iv(p: int) -> int:
+ return r64(g_tokens, p * ESZ_TOKEN + OFF_TK_INTVAL)
+fn tok_ln(p: int) -> int:
+ return r64(g_tokens, p * ESZ_TOKEN + OFF_TK_LINE)
+fn tok_cl(p: int) -> int:
+ return r64(g_tokens, p * ESZ_TOKEN + OFF_TK_COL)
+
+fn advance_tok() -> int:
+ t := cur_tok()
+ if tok_k(t) != T_EOF:
+ g_token_pos = t + 1
+ return t
+
+fn check(k: int) -> bool:
+ if tok_k(cur_tok()) == k:
+ return true
+ else:
+ return false
+
+fn expect(k: int) -> int:
+ t := cur_tok()
+ if tok_k(t) == k:
+ return advance_tok()
+ return t
+
+// ── v4 位置语义(T5;逐条等价于 bootstrap/corec/frontend/parser.py 的 `want_value`)──────
+// 表达式位(声明/赋值右值、return 的值、实参、下标、括号内、元组/数组元素、字面量字段值)
+// ⇒ region 末项**保尾值**;语句位(语句、函数体、if/else 语句体、loop/while/for 体)
+// ⇒ 末项裸表达式**包 EXPR_STMT**(等价 v3 带 `;` 的表达式语句);**例外 = 块状末项**
+// (if/match/loop/while/for/unsafe)**保尾值** —— v3 的 `;` 只终止普通表达式语句,
+// 控制流语句本来就以 `}` 收尾(本来就是块的尾值)。判据 = v3 逐形等价。
+g_want_value : int, mut
+
+// 行边界(`;` 退场后的统一终止面,T0 布局规格 §2.5 + §6.2 的 A/B 两类逐点判定):
+// NEWLINE / DEDENT / EOF 三态;其中 **DEDENT 与 EOF 不消费** —— 它们是 region 收尾信号,
+// 由块产生式处理。
+// 第三态:**刚吃掉 DEDENT**(= region 收尾)也构成行边界。块产生式消费 DEDENT 后,
+// lexer 已把下一行的首 token 接在 DEDENT 之后(token 次序 NEWLINE → DEDENT → 下一行首 token)
+// ⇒ 「prev == DEDENT」等价于「站在新一行的行首」。少了这条,`x := unsafe: …` 这类
+// **以 region 收尾的声明/表达式**会在 end_decl 处被误判为「同行还有 token」。
+fn at_line_end() -> int:
+ if g_token_pos > 0 && tok_k(g_token_pos - 1) == T_DEDENT:
+ return 1
+ k := tok_k(cur_tok())
+ if k == T_NEWLINE || k == T_DEDENT || k == T_EOF:
+ return 1
+ return 0
+
+fn skip_newlines():
+ loop:
+ if tok_k(cur_tok()) != T_NEWLINE:
+ break
+ advance_tok()
+
+// 语句/声明的行边界收尾(取代原 `expect(T_SEMI)`):保留其**严格性** ——
+// 少了这条,「同行两条声明」会被静默接受。
+fn end_decl():
+ if at_line_end() == 0:
+ add_error("expected end of line, got '" + tok_lx(cur_tok()) + "'")
+ skip_newlines()
+
+// region 头:`T_COLON_BLOCK`(行尾冒号)+ 其后的 NEWLINE + `T_INDENT`。
+// token 次序由 lexer 的 layout_break 决定:NEWLINE 先于 INDENT/DEDENT。
+// **行内 `:`(T_COLON_DECL)在此被响亮拒绝** —— 正是 T0 布局规格 §2.2 要的
+// 「行尾类型标注不是合法文本」的兜住点;形参标注断行(`fn f(a:` + 续行 `int):`)
+// 在 lexer 层与头部终结不可区分,正是靠这里兜住。
+// 返回 1 = 吃到 `T_INDENT`(region 有 items);**0 = 空 region**(无 INDENT、无 items)。
+// v4 裁定(2026-10-11,**推翻** T0 布局规格 §10.2 的「空 region 无法表达 + 逐处改写」):
+// **region 可以为空** —— `:` 之后下一行**不更深** ⇒ 无 INDENT、无 items,region 值为「无值」。
+// 用途实证(T6b 报来、维护者采纳):`loop { }`(**永不返回**,与 `loop:` + 裸 `return`
+// **不等价**)与 `interface Empty { }`(**零方法接口**,合法且有意义)在「逐处改写」下无等价形。
+// ⚠ 只放宽「零项」这一格:**行内 `:`(T_COLON_DECL)在 region 头位仍响亮拒绝**(上面那支),
+// 非零项 region 的缩进规则一个字不动。
+fn expect_region_head() -> int:
+ if tok_k(cur_tok()) == T_COLON_BLOCK:
+ advance_tok()
+ else:
+ add_error("expected ':' to open a region, got '" + tok_lx(cur_tok()) + "'")
+ return 0
+ skip_newlines()
+ if tok_k(cur_tok()) == T_INDENT:
+ advance_tok()
+ return 1
+ return 0
+
+// region 收尾:消费 `T_DEDENT`;非 DEDENT(如 EOF)⇒ 响亮报错(不静默吞)。
+fn close_region():
+ if tok_k(cur_tok()) == T_DEDENT:
+ advance_tok()
+ else:
+ add_error("expected end of region (missing DEDENT)")
+
+// 语句位 region 的**控制流**末项:位置标志为语句位时,控制流类尾项保留为**块的尾值**;
+// 其余一律包 EXPR_STMT(等价 v3 带 `;` 的表达式语句)。
+//
+// ⚠ **本清单两套前端**本来就不一样**,判据锚在语义(v3 逐形等价),**不锚在 kind 名机械一致**
+// —— 见维护者裁定(2026-10-11):
+// · 自源侧 **`while` 有独立 kind `EXPR_WHILE`**(`parse_while_expr` 直接建它,`checker.cr`/
+// `ir_gen.cr` 都有该分支)⇒ **必须入列**。少了它,`while` 作 region 尾项会被包 `EXPR_STMT`
+// ⇒ `unit`,与 v3(`while c { … }` 不带 `;` ⇒ 本就是块的值)**漂移**。
+// · Python 侧 `while` **desugar 成 `Loop`** ⇒ 那边只需 `Loop`,**不要**去给它补一个 while 项。
+// · `Flow`:Python 侧是表达式节点(入列);自源侧 **`flow` 只是顶层声明修饰符、不是表达式
+// 节点**(`parse_primary` 无 `T_FLOW` 分支)⇒ **不入列**。
+// ⇒ **禁止**为「两边 kind 清单长得一样」而增删本行——那会把语义正确的差异抹平成错。
+fn is_block_like(n: int) -> int:
+ if n < 0:
+ return 0
+ k := ast_kind(n)
+ if k == EXPR_IF || k == EXPR_MATCH || k == EXPR_LOOP || k == EXPR_WHILE || k == EXPR_FOR || k == EXPR_UNSAFE:
+ return 1
+ return 0
+
+// 块内的「语句类」节点(Python 侧的 Stmt 族):let / return / break / continue。
+fn is_stmt_node(n: int) -> int:
+ if n < 0:
+ return 1
+ k := ast_kind(n)
+ if k == EXPR_LET || k == EXPR_RETURN || k == EXPR_BREAK || k == EXPR_CONTINUE:
+ return 1
+ return 0
// --- Type parsing ---
-fn parse_type() -> int {
- t := cur_tok();
- line := tok_ln(t);
- col := tok_cl(t);
- res : ., mut = 0;
+fn parse_type() -> int:
+ t := cur_tok()
+ line := tok_ln(t)
+ col := tok_cl(t)
+ res : ., mut = 0
// 表示层概念(2026-09-10 语言面收窄裁决 §1):`[T; N]` 的类型构造器身份已退役——
// 语义归处 = product(N 元聚合)/ 序列接口 + 长度 where(N 长序列)/ F11 图(长度事实,
// 可表达依赖长度)。本语法保留为「内联容量存储」表示提示(映射参数层,与 hw-map 同层;
// 随实例选择生效或退化,非经典范式映射可忽略)。见
// docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md §1
- if tok_k(t) == T_LBRACKET {
- advance_tok();
- inner := parse_type();
- if check(T_SEMI) {
- advance_tok();
- sz := advance_tok();
- advance_tok();
- res = alloc_node(EXPR_ARRAY, inner, 0, 0, tok_iv(sz), 0, 0, line, col);
- } else {
- advance_tok();
+ if tok_k(t) == T_LBRACKET:
+ advance_tok()
+ inner := parse_type()
+ if check(T_SEMI):
+ advance_tok()
+ sz := advance_tok()
+ advance_tok()
+ res = alloc_node(EXPR_ARRAY, inner, 0, 0, tok_iv(sz), 0, 0, line, col)
+ else:
+ advance_tok()
// Slice type [T]
- res = alloc_node(EXPR_ARRAY, inner, 0, 0, 0, 0, 0, line, col);
- }
- } else if tok_k(t) == T_LPAREN {
- advance_tok();
- typ := parse_type();
- advance_tok();
- res = typ;
- } else if tok_k(t) == T_AMPERSAND {
- advance_tok();
- is_mut : ., mut = 0;
- if tok_k(cur_tok()) == T_MUT {
- is_mut = 1;
- advance_tok();
- }
- inner := parse_type();
- res = alloc_node(EXPR_REFTYPE, inner, 0, 0, is_mut, 0, 0, line, col);
- } else if tok_k(t) == T_STAR {
- advance_tok();
- inner := parse_type();
- res = alloc_node(EXPR_PTRTYPE, inner, 0, 0, 0, 0, 0, line, col);
- } else if tok_k(t) == T_UNIT {
- advance_tok();
- res = alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, line, col);
- } else if tok_k(t) == T_IDENT || tok_k(t) == T_SELF || tok_k(t) == T_UNDERSCORE {
- lex := tok_lx(t);
- advance_tok();
- if lex == "int" { res = alloc_node(0, 0, 0, 0, 0, TY_INT, 0, line, col); }
+ res = alloc_node(EXPR_ARRAY, inner, 0, 0, 0, 0, 0, line, col)
+ else if tok_k(t) == T_LPAREN:
+ advance_tok()
+ typ := parse_type()
+ advance_tok()
+ res = typ
+ else if tok_k(t) == T_AMPERSAND:
+ advance_tok()
+ is_mut : ., mut = 0
+ if tok_k(cur_tok()) == T_MUT:
+ is_mut = 1
+ advance_tok()
+ inner := parse_type()
+ res = alloc_node(EXPR_REFTYPE, inner, 0, 0, is_mut, 0, 0, line, col)
+ else if tok_k(t) == T_STAR:
+ advance_tok()
+ inner := parse_type()
+ res = alloc_node(EXPR_PTRTYPE, inner, 0, 0, 0, 0, 0, line, col)
+ else if tok_k(t) == T_UNIT:
+ advance_tok()
+ res = alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, line, col)
+ else if tok_k(t) == T_NEVER:
+ // v4(施工计划 §四.1 项 8):`never` 由**词素比对提升进关键字表** ⇒ 走独立 token 分支
+ // (升格后它不再可能是标识符)。语义不变:TY_NEVER。
+ advance_tok()
+ res = alloc_node(0, 0, 0, 0, 0, TY_NEVER, 0, line, col)
+ else if tok_k(t) == T_DYN:
+ // 同上:`dyn` 升格为关键字(复用既有 token kind T_DYN=99)。语义不变:TI_DYN。
+ advance_tok()
+ res = alloc_node(0, 0, 0, 0, 0, TI_DYN, 0, line, col)
+ else if tok_k(t) == T_IDENT || tok_k(t) == T_SELF || tok_k(t) == T_UNDERSCORE:
+ lex := tok_lx(t)
+ advance_tok()
+ if lex == "int":
+ res = alloc_node(0, 0, 0, 0, 0, TY_INT, 0, line, col)
// dex = 精确小数(float 类型名已移除——数值迁移 Task 5)
- else if lex == "dex" { res = alloc_node(0, 0, 0, 0, 0, TY_DEX, 0, line, col); }
- else if lex == "bool" { res = alloc_node(0, 0, 0, 0, 0, TY_BOOL, 0, line, col); }
- else if lex == "string" { res = alloc_node(0, 0, 0, 0, 0, TY_STRING, 0, line, col); }
- else if lex == "char" { res = alloc_node(0, 0, 0, 0, 0, TY_CHAR, 0, line, col); }
- else if lex == "never" { res = alloc_node(0, 0, 0, 0, 0, TY_NEVER, 0, line, col); }
- else if lex == "dyn" { res = alloc_node(0, 0, 0, 0, 0, TI_DYN, 0, line, col); }
- else {
- ni := str_intern(lex);
+ else if lex == "dex":
+ res = alloc_node(0, 0, 0, 0, 0, TY_DEX, 0, line, col)
+ else if lex == "bool":
+ res = alloc_node(0, 0, 0, 0, 0, TY_BOOL, 0, line, col)
+ else if lex == "string":
+ res = alloc_node(0, 0, 0, 0, 0, TY_STRING, 0, line, col)
+ else if lex == "char":
+ res = alloc_node(0, 0, 0, 0, 0, TY_CHAR, 0, line, col)
+ else:
+ ni := str_intern(lex)
// Check for generic args: Box[int,...] or Box
- close_tok : ., mut = 0;
- if check(T_LBRACKET) { close_tok = T_RBRACKET; }
- else if check(T_LT) { close_tok = T_GT; }
- if close_tok > 0 {
- advance_tok();
- first_arg := parse_type();
- arg_count : ., mut = 1;
- loop {
- if check(close_tok) { break; }
- if !check(T_COMMA) { break; }
- advance_tok();
- parse_type();
- arg_count = arg_count + 1;
- }
- advance_tok();
- res = alloc_node(EXPR_GENERIC_APPLY, ni, first_arg, arg_count, 0, 0, 0, line, col);
- } else {
- res = alloc_node(EXPR_IDENT, 0, 0, 0, ni, 0, 0, line, col);
- }
- }
- } else if tok_k(t) == T_LBRACE {
- grow_diags(g_diag_count + 1);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_P_EXPECTED);
- store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "expected type after '->', got '{' — missing return type?");
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, line);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, col);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(line));
- g_diag_count = g_diag_count + 1;
- res = alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, line, col);
- } else {
- grow_diags(g_diag_count + 1);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_P_EXPECTED);
- store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "expected type after '->'");
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, line);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, col);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(line));
- g_diag_count = g_diag_count + 1;
- res = alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, line, col);
- }
+ close_tok : ., mut = 0
+ if check(T_LBRACKET):
+ close_tok = T_RBRACKET
+ else if check(T_LT):
+ close_tok = T_GT
+ if close_tok > 0:
+ advance_tok()
+ first_arg := parse_type()
+ arg_count : ., mut = 1
+ loop:
+ if check(close_tok):
+ break
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ parse_type()
+ arg_count = arg_count + 1
+ advance_tok()
+ res = alloc_node(EXPR_GENERIC_APPLY, ni, first_arg, arg_count, 0, 0, 0, line, col)
+ else:
+ res = alloc_node(EXPR_IDENT, 0, 0, 0, ni, 0, 0, line, col)
+ else if tok_k(t) == T_LBRACE:
+ grow_diags(g_diag_count + 1)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_P_EXPECTED)
+ store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "expected type after '->', got '{' — missing return type?")
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, line)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, col)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(line))
+ g_diag_count = g_diag_count + 1
+ res = alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, line, col)
+ else:
+ grow_diags(g_diag_count + 1)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_P_EXPECTED)
+ store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "expected type after '->'")
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, line)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, col)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(line))
+ g_diag_count = g_diag_count + 1
+ res = alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, line, col)
// R2 P3 Task 4:`T?` 的目标形态 = **EXPR_OPTIONAL**(内层类型节点入 a 槽)。
// 旧形态(T? → EXPR_GENERIC_APPLY(Option, T))要求「内建 Option 名」在符号表里被注册,
// 正是本任务退役的做法(spec §5.4);且旧形态无法表达 `T? = T ∪ null`(GenericApply 行
// 在桥接侧是不展开的 AK_NAMED 原子)。新形态**零名字依赖**(不再 str_intern("Option"),
// 见 test_optional.py 的行数对照用例)。
- if check(T_QUESTION) {
- advance_tok();
- res = alloc_node(EXPR_OPTIONAL, res, 0, 0, 0, 0, 0, line, col);
- }
- return res;
-}
-
-fn unpack_type(typ: int) -> int {
- if ast_kind(typ) == 0 { return ast_type_val(typ); }
- return 0;
-}
+ if check(T_QUESTION):
+ advance_tok()
+ res = alloc_node(EXPR_OPTIONAL, res, 0, 0, 0, 0, 0, line, col)
+ return res
+
+fn unpack_type(typ: int) -> int:
+ if ast_kind(typ) == 0:
+ return ast_type_val(typ)
+ return 0
// --- Expression parsing ---
-fn prec(k: int) -> int {
- if k == T_EQ { return 1; }
- if k == T_PLUS_EQ { return 1; }
- if k == T_MINUS_EQ { return 1; }
- if k == T_STAR_EQ { return 1; }
- if k == T_SLASH_EQ { return 1; }
- if k == T_PIPEPIPE { return 2; }
- if k == T_ANDAND { return 3; }
- if k == T_EQEQ || k == T_BANGEQ { return 4; }
- if k == T_LT || k == T_GT || k == T_LTEQ || k == T_GTEQ { return 5; }
- if k == T_PLUS || k == T_MINUS { return 6; }
- if k == T_STAR || k == T_SLASH || k == T_PERCENT { return 7; }
- return -1;
-}
-
-fn tok2op(k: int) -> int {
- if k == T_PLUS { return OP_ADD; }
- if k == T_MINUS { return OP_SUB; }
- if k == T_STAR { return OP_MUL; }
- if k == T_SLASH { return OP_DIV; }
- if k == T_PERCENT { return OP_MOD; }
- if k == T_EQEQ { return OP_EQ; }
- if k == T_BANGEQ { return OP_NE; }
- if k == T_LT { return OP_LT; }
- if k == T_GT { return OP_GT; }
- if k == T_LTEQ { return OP_LE; }
- if k == T_GTEQ { return OP_GE; }
- if k == T_ANDAND { return OP_AND; }
- if k == T_PIPEPIPE { return OP_OR; }
- return 0;
-}
-
-fn parse_expr() -> int {
- left := parse_binary(0);
- if check(T_DOTDOT) {
- t := advance_tok();
- right := parse_expr();
- return alloc_node(EXPR_RANGE, left, right, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- return left;
-}
-
-fn parse_binary(mp: int) -> int {
- left : ., mut = parse_unary();
+fn prec(k: int) -> int:
+ if k == T_EQ:
+ return 1
+ if k == T_PLUS_EQ:
+ return 1
+ if k == T_MINUS_EQ:
+ return 1
+ if k == T_STAR_EQ:
+ return 1
+ if k == T_SLASH_EQ:
+ return 1
+ if k == T_PIPEPIPE:
+ return 2
+ if k == T_ANDAND:
+ return 3
+ if k == T_EQEQ || k == T_BANGEQ:
+ return 4
+ if k == T_LT || k == T_GT || k == T_LTEQ || k == T_GTEQ:
+ return 5
+ if k == T_PLUS || k == T_MINUS:
+ return 6
+ if k == T_STAR || k == T_SLASH || k == T_PERCENT:
+ return 7
+ return -1
+
+fn tok2op(k: int) -> int:
+ if k == T_PLUS:
+ return OP_ADD
+ if k == T_MINUS:
+ return OP_SUB
+ if k == T_STAR:
+ return OP_MUL
+ if k == T_SLASH:
+ return OP_DIV
+ if k == T_PERCENT:
+ return OP_MOD
+ if k == T_EQEQ:
+ return OP_EQ
+ if k == T_BANGEQ:
+ return OP_NE
+ if k == T_LT:
+ return OP_LT
+ if k == T_GT:
+ return OP_GT
+ if k == T_LTEQ:
+ return OP_LE
+ if k == T_GTEQ:
+ return OP_GE
+ if k == T_ANDAND:
+ return OP_AND
+ if k == T_PIPEPIPE:
+ return OP_OR
+ return 0
+
+fn parse_expr() -> int:
+ left := parse_binary(0)
+ if check(T_DOTDOT):
+ t := advance_tok()
+ right := parse_expr()
+ return alloc_node(EXPR_RANGE, left, right, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ return left
+
+fn parse_binary(mp: int) -> int:
+ left : ., mut = parse_unary()
// If the left expression is a block-ending construct (IF, BLOCK, etc.),
// don't allow binary operators to extend past it. The next operator
// belongs to a new expression, not the current one.
// This prevents `if ... { } *p = 99` from parsing `*` as multiplication.
- lk := ast_kind(left);
- if lk == EXPR_IF || lk == EXPR_BLOCK || lk == EXPR_LOOP || lk == EXPR_WHILE || lk == EXPR_FOR {
- return left;
- }
- loop {
- t := cur_tok();
- k := tok_k(t);
- p := prec(k);
- if p < mp { break; }
- advance_tok();
- right := parse_binary(p + 1);
- op := tok2op(k);
+ lk := ast_kind(left)
+ if lk == EXPR_IF || lk == EXPR_BLOCK || lk == EXPR_LOOP || lk == EXPR_WHILE || lk == EXPR_FOR:
+ return left
+ loop:
+ t := cur_tok()
+ k := tok_k(t)
+ p := prec(k)
+ if p < mp:
+ break
+ advance_tok()
+ if p == 1:
+ // 赋值/复合赋值的右值 = 表达式位(bootstrap 侧 `parse_assignment` 同判:
+ // `x = ` 的尾值必须保留 —— 见 g_want_value 头注规则 ②)。
+ g_want_value = 1
+ right := parse_binary(p + 1)
+ op := tok2op(k)
// Compound assignment: += -= *= /= → a = a op b
- if k == T_PLUS_EQ {
- left = alloc_node(EXPR_ASSIGN, left, alloc_node(EXPR_BINARY, left, right, OP_ADD, 0, 0, 0, tok_ln(t), tok_cl(t)), 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- } else if k == T_MINUS_EQ {
- left = alloc_node(EXPR_ASSIGN, left, alloc_node(EXPR_BINARY, left, right, OP_SUB, 0, 0, 0, tok_ln(t), tok_cl(t)), 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- } else if k == T_STAR_EQ {
- left = alloc_node(EXPR_ASSIGN, left, alloc_node(EXPR_BINARY, left, right, OP_MUL, 0, 0, 0, tok_ln(t), tok_cl(t)), 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- } else if k == T_SLASH_EQ {
- left = alloc_node(EXPR_ASSIGN, left, alloc_node(EXPR_BINARY, left, right, OP_DIV, 0, 0, 0, tok_ln(t), tok_cl(t)), 0, 0, 0, 0, tok_ln(t), tok_cl(t));
+ if k == T_PLUS_EQ:
+ left = alloc_node(EXPR_ASSIGN, left, alloc_node(EXPR_BINARY, left, right, OP_ADD, 0, 0, 0, tok_ln(t), tok_cl(t)), 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ else if k == T_MINUS_EQ:
+ left = alloc_node(EXPR_ASSIGN, left, alloc_node(EXPR_BINARY, left, right, OP_SUB, 0, 0, 0, tok_ln(t), tok_cl(t)), 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ else if k == T_STAR_EQ:
+ left = alloc_node(EXPR_ASSIGN, left, alloc_node(EXPR_BINARY, left, right, OP_MUL, 0, 0, 0, tok_ln(t), tok_cl(t)), 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ else if k == T_SLASH_EQ:
+ left = alloc_node(EXPR_ASSIGN, left, alloc_node(EXPR_BINARY, left, right, OP_DIV, 0, 0, 0, tok_ln(t), tok_cl(t)), 0, 0, 0, 0, tok_ln(t), tok_cl(t))
// Convert assignment to EXPR_ASSIGN
- } else if k == T_EQ {
- left = alloc_node(EXPR_ASSIGN, left, right, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- } else {
- left = alloc_node(EXPR_BINARY, left, right, op, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- }
- return left;
-}
-
-fn parse_unary() -> int {
- t := cur_tok();
- if tok_k(t) == T_MINUS {
- advance_tok();
- op := parse_unary();
- return alloc_node(EXPR_UNARY, op, 0, UOP_NEG, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_AMPERSAND {
- advance_tok();
- is_mut : ., mut = 0;
- if tok_k(cur_tok()) == T_MUT {
- is_mut = 1;
- advance_tok();
- }
- op := parse_unary();
- return alloc_node(EXPR_UNARY, op, 0, UOP_REF, is_mut, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_BANG {
- advance_tok();
- op := parse_unary();
- return alloc_node(EXPR_UNARY, op, 0, UOP_NOT, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_MOVE {
- advance_tok();
- op := parse_unary();
- return alloc_node(EXPR_MOVE, op, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_STAR {
- advance_tok();
- op := parse_unary();
- return alloc_node(EXPR_UNARY, op, 0, UOP_DEREF, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- node := parse_postfix();
+ else if k == T_EQ:
+ left = alloc_node(EXPR_ASSIGN, left, right, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ else:
+ left = alloc_node(EXPR_BINARY, left, right, op, 0, 0, 0, tok_ln(t), tok_cl(t))
+ return left
+
+fn parse_unary() -> int:
+ t := cur_tok()
+ if tok_k(t) == T_MINUS:
+ advance_tok()
+ op := parse_unary()
+ return alloc_node(EXPR_UNARY, op, 0, UOP_NEG, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_AMPERSAND:
+ advance_tok()
+ is_mut : ., mut = 0
+ if tok_k(cur_tok()) == T_MUT:
+ is_mut = 1
+ advance_tok()
+ op := parse_unary()
+ return alloc_node(EXPR_UNARY, op, 0, UOP_REF, is_mut, 0, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_BANG:
+ advance_tok()
+ op := parse_unary()
+ return alloc_node(EXPR_UNARY, op, 0, UOP_NOT, 0, 0, 0, tok_ln(t), tok_cl(t))
+ // v4(§一.5):`move` 已从关键字表退场 ⇒ lexer 不再发射 T_MOVE,本分支一并删除
+ // (原 EXPR_MOVE 构造在 v4 下**不可达**;`move x` 现按普通标识符解析并响亮报错,不静默)。
+ if tok_k(t) == T_STAR:
+ advance_tok()
+ op := parse_unary()
+ return alloc_node(EXPR_UNARY, op, 0, UOP_DEREF, 0, 0, 0, tok_ln(t), tok_cl(t))
+ node := parse_postfix()
// Handle 'as' type cast: expr as Type
- if check(T_AS) {
- advance_tok();
- typ := parse_type();
- return alloc_node(EXPR_AS, node, typ, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- return node;
-}
-
-fn parse_postfix() -> int {
- node : ., mut = parse_primary();
+ if check(T_AS):
+ advance_tok()
+ typ := parse_type()
+ return alloc_node(EXPR_AS, node, typ, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ return node
+
+fn parse_postfix() -> int:
+ node : ., mut = parse_primary()
// Handle cast(expr) syntax — same as expr as T
- if ast_kind(node) == EXPR_IDENT {
- ni := ast_int_val(node);
- if str_eq(istr_get(ni), "cast") != 0 && tok_k(cur_tok()) == T_LT {
- advance_tok();
- typ := parse_type();
- advance_tok(); // skip T_GT
- if tok_k(cur_tok()) == T_LPAREN {
- advance_tok();
- inner := parse_expr(0);
- advance_tok(); // skip T_RPAREN
- return alloc_node(EXPR_AS, inner, typ, 0, 0, 0, 0, tok_ln(node), tok_cl(node));
- }
- }
- }
- loop {
- t := cur_tok();
- if tok_k(t) == T_LPAREN {
- advance_tok();
- af := -1;
- ac : ., mut = 0;
- if !check(T_RPAREN) {
+ if ast_kind(node) == EXPR_IDENT:
+ ni := ast_int_val(node)
+ if str_eq(istr_get(ni), "cast") != 0 && tok_k(cur_tok()) == T_LT:
+ advance_tok()
+ typ := parse_type()
+ advance_tok() // skip T_GT
+ if tok_k(cur_tok()) == T_LPAREN:
+ advance_tok()
+ inner := parse_expr(0)
+ advance_tok() // skip T_RPAREN
+ return alloc_node(EXPR_AS, inner, typ, 0, 0, 0, 0, tok_ln(node), tok_cl(node))
+ loop:
+ t := cur_tok()
+ if tok_k(t) == T_LPAREN:
+ advance_tok()
+ af := -1
+ ac : ., mut = 0
+ if !check(T_RPAREN):
// Wrap each argument in EXPR_ARG(a=expr, b=next_arg) linked list
- first_expr := parse_expr();
- af = alloc_node(EXPR_ARG, first_expr, -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- ac = 1;
- prev_arg := af;
- loop {
- if !check(T_COMMA) { break; }
- advance_tok();
- next_expr := parse_expr();
- new_arg := alloc_node(EXPR_ARG, next_expr, -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- ast_set_b(prev_arg, new_arg);
- prev_arg = new_arg;
- ac = ac + 1;
- }
- }
- advance_tok();
+ g_want_value = 1 // 实参 = 表达式位
+ first_expr := parse_expr()
+ af = alloc_node(EXPR_ARG, first_expr, -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ ac = 1
+ prev_arg := af
+ loop:
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ g_want_value = 1
+ next_expr := parse_expr()
+ new_arg := alloc_node(EXPR_ARG, next_expr, -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ ast_set_b(prev_arg, new_arg)
+ prev_arg = new_arg
+ ac = ac + 1
+ advance_tok()
// Check if this is an enum constructor
// Cases: Some(42) or Option::Some(42)
- is_enum_con : ., mut = 0;
- name_idx : ., mut = -1;
- if ast_kind(node) == EXPR_IDENT {
- name_idx = ast_int_val(node);
- } else if ast_kind(node) == EXPR_FIELD && ast_data(node) != 0 {
+ is_enum_con : ., mut = 0
+ name_idx : ., mut = -1
+ if ast_kind(node) == EXPR_IDENT:
+ name_idx = ast_int_val(node)
+ else if ast_kind(node) == EXPR_FIELD && ast_data(node) != 0:
// Path access: Option::Some → EXPR_FIELD(Option, Some, data=1)
- name_idx = ast_int_val(node);
- }
- if name_idx >= 0 {
- name := istr_get(name_idx);
- c := get_char(name, 0);
- if str_cmp(c, "A") >= 0 && str_cmp(c, "Z") <= 0 {
- is_enum_con = 1;
- }
- }
- if is_enum_con == 1 {
- node = alloc_node(EXPR_ENUM_CONSTRUCTOR, name_idx, af, ac, 0, 0, 0, tok_ln(t), tok_cl(t));
- } else {
- call_func := node;
- call_flags : ., mut = 0;
+ name_idx = ast_int_val(node)
+ if name_idx >= 0:
+ name := istr_get(name_idx)
+ c := get_char(name, 0)
+ if str_cmp(c, "A") >= 0 && str_cmp(c, "Z") <= 0:
+ is_enum_con = 1
+ if is_enum_con == 1:
+ node = alloc_node(EXPR_ENUM_CONSTRUCTOR, name_idx, af, ac, 0, 0, 0, tok_ln(t), tok_cl(t))
+ else:
+ call_func := node
+ call_flags : ., mut = 0
// @inline(fn)(args) is a hinted call, not a call through the
// value returned by @inline(fn).
- if ast_kind(node) == EXPR_CALL && ast_c(node) == 1 {
- wrapper := ast_a(node);
- wrapper_arg := ast_b(node);
- if ast_kind(wrapper) == EXPR_AT && wrapper_arg >= 0 {
- wrapper_name := istr_get(ast_a(wrapper));
- if str_eq(wrapper_name, "inline") != 0 {
- call_func = ast_a(wrapper_arg);
- call_flags = CALL_FLAG_INLINE;
- }
- }
- }
- node = alloc_node(EXPR_CALL, call_func, af, ac, 0, call_flags, 0, tok_ln(t), tok_cl(t));
- }
- continue;
- }
- if tok_k(t) == T_DOT {
- advance_tok();
- f := advance_tok();
- ni := str_intern(tok_lx(f));
+ if ast_kind(node) == EXPR_CALL && ast_c(node) == 1:
+ wrapper := ast_a(node)
+ wrapper_arg := ast_b(node)
+ if ast_kind(wrapper) == EXPR_AT && wrapper_arg >= 0:
+ wrapper_name := istr_get(ast_a(wrapper))
+ if str_eq(wrapper_name, "inline") != 0:
+ call_func = ast_a(wrapper_arg)
+ call_flags = CALL_FLAG_INLINE
+ node = alloc_node(EXPR_CALL, call_func, af, ac, 0, call_flags, 0, tok_ln(t), tok_cl(t))
+ continue
+ if tok_k(t) == T_DOT:
+ advance_tok()
+ f := advance_tok()
+ ni := str_intern(tok_lx(f))
// type_val: for numeric field names, stores index+1 (0 means struct field)
- tv : ., mut = 0;
- if tok_k(f) == T_INT {
- tv = tok_iv(f) + 1; // +1 so default 0 means struct field
- }
- node = alloc_node(EXPR_FIELD, node, 0, 0, ni, tv, 0, tok_ln(t), tok_cl(t));
- continue;
- }
- if tok_k(t) == T_PATHSEP {
- advance_tok();
- f := advance_tok();
- ni := str_intern(tok_lx(f));
- node = alloc_node(EXPR_FIELD, node, 0, 0, ni, 0, 1, tok_ln(t), tok_cl(t));
- continue;
- }
- if tok_k(t) == T_LBRACKET {
- advance_tok();
- idx := parse_expr();
- advance_tok();
- node = alloc_node(EXPR_INDEX, node, idx, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- continue;
- }
- if tok_k(t) == T_QUESTION {
- advance_tok();
- node = alloc_node(EXPR_TRY, node, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- continue;
- }
- break;
- }
- return node;
-}
-
-fn is_upper_first(s: string) -> bool {
- c := get_char(s, 0);
- if str_cmp(c, "A") >= 0 && str_cmp(c, "Z") <= 0 { return true; }
- return false;
-}
+ tv : ., mut = 0
+ if tok_k(f) == T_INT:
+ tv = tok_iv(f) + 1 // +1 so default 0 means struct field
+ node = alloc_node(EXPR_FIELD, node, 0, 0, ni, tv, 0, tok_ln(t), tok_cl(t))
+ continue
+ if tok_k(t) == T_PATHSEP:
+ advance_tok()
+ f := advance_tok()
+ ni := str_intern(tok_lx(f))
+ node = alloc_node(EXPR_FIELD, node, 0, 0, ni, 0, 1, tok_ln(t), tok_cl(t))
+ continue
+ if tok_k(t) == T_LBRACKET:
+ advance_tok()
+ g_want_value = 1 // 下标 = 表达式位
+ idx := parse_expr()
+ advance_tok()
+ node = alloc_node(EXPR_INDEX, node, idx, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ continue
+ if tok_k(t) == T_QUESTION:
+ advance_tok()
+ node = alloc_node(EXPR_TRY, node, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ continue
+ break
+ return node
+
+fn is_upper_first(s: string) -> bool:
+ c := get_char(s, 0)
+ if str_cmp(c, "A") >= 0 && str_cmp(c, "Z") <= 0:
+ return true
+ return false
// ── 字符串插值展开(批 8 裁定 (b)):词法已把含 `${...}` 的字面量拆成 part 序列 ─────────
// part = T_STRING(字面段)或 T_INTERP(洞;lexeme = 洞内原文)。
@@ -401,136 +508,114 @@ fn is_upper_first(s: string) -> bool {
// +1 = 属含插值的字面量 · +2 = 其后还有 part · 4(仅 T_INTERP)= 洞已闭合 ⇒ 判据 `iv >= 4` / `(iv % 4) >= 2`。⇒ parser 只把**同一字面量**的 part 串成链(`"${x}" "y"` 是两个字面量、
// 不连;裸邻接字符串仍照旧报错),**无洞字面量 iv=0 ⇒ 单 part、节点形态与旧实现逐字相同**(产物零足迹)。
// 洞表达式本体在 parse_all 末尾统一解析(那时 token 流已用毕);类型转换由 checker 就地改写。
-fn parse_interp_run() -> int {
- t := cur_tok();
- left : ., mut = -1;
- loop {
- k := tok_k(t);
- if k != T_STRING && k != T_INTERP { break; }
- iv := tok_iv(t);
- part : ., mut = -1;
- if k == T_INTERP {
- txt := tok_lx(t);
- if iv < 4 {
- check_error(EC_P_INTERP_UNCLOSED, "unclosed string interpolation: '\${' has no matching '}'", tok_ln(t), tok_cl(t));
- } else if str_len(txt) == 0 {
- check_error(EC_P_INTERP_UNCLOSED, "empty string interpolation: '\${}'", tok_ln(t), tok_cl(t));
- }
- part = alloc_node(EXPR_INTERP_HOLE, 0, 0, 0, 0, 0, str_intern(txt), tok_ln(t), tok_cl(t));
- } else {
- part = alloc_node(EXPR_STRING, 0, 0, 0, str_intern(tok_lx(t)), TY_STRING, 0, tok_ln(t), tok_cl(t));
- }
- if left < 0 { left = part; } else {
- left = alloc_node(EXPR_BINARY, left, part, OP_ADD, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- advance_tok();
- if (iv % 4) < 2 { break; }
- t = cur_tok();
- }
- return left;
-}
+fn parse_interp_run() -> int:
+ t := cur_tok()
+ left : ., mut = -1
+ loop:
+ k := tok_k(t)
+ if k != T_STRING && k != T_INTERP:
+ break
+ iv := tok_iv(t)
+ part : ., mut = -1
+ if k == T_INTERP:
+ txt := tok_lx(t)
+ if iv < 4:
+ check_error(EC_P_INTERP_UNCLOSED, "unclosed string interpolation: '\${' has no matching '}'", tok_ln(t), tok_cl(t))
+ else if str_len(txt) == 0:
+ check_error(EC_P_INTERP_UNCLOSED, "empty string interpolation: '\${}'", tok_ln(t), tok_cl(t))
+ part = alloc_node(EXPR_INTERP_HOLE, 0, 0, 0, 0, 0, str_intern(txt), tok_ln(t), tok_cl(t))
+ else:
+ part = alloc_node(EXPR_STRING, 0, 0, 0, str_intern(tok_lx(t)), TY_STRING, 0, tok_ln(t), tok_cl(t))
+ if left < 0:
+ left = part
+ else:
+ left = alloc_node(EXPR_BINARY, left, part, OP_ADD, 0, 0, 0, tok_ln(t), tok_cl(t))
+ advance_tok()
+ if (iv % 4) < 2:
+ break
+ t = cur_tok()
+ return left
// 洞表达式统一解析(parse_all 末尾调用):线性扫本文件新建 AST,遇 EXPR_INTERP_HOLE 即把
// data 槽的洞文本重新词法化 + parse_expr,结果写回 a 槽。**必须在 token 流用毕后调用**(会覆盖 g_tokens);
// 洞内嵌套插值产生的新 HOLE 节点由本循环自然覆盖(上界 g_ast_count 随扫描增长)。
-fn interp_parse_holes() {
- i : ., mut = 0;
- loop {
- if i >= g_ast_count { break; }
- if ast_kind(i) == EXPR_INTERP_HOLE {
- txt := istr_get(ast_data(i));
- if str_len(txt) > 0 {
- tokenize(txt);
- g_token_pos = 0;
- ast_set_a(i, parse_expr());
- tk2 := cur_tok(); // ⚠ 不写 `if tok_k(cur_tok()) != T_EOF {`——那会与 A₁ 顶层兜底的
- if tok_k(tk2) != T_EOF { // 突变锚点(tests/harness/test_criteria_mutations.py M9)撞形
- check_error(EC_P_INTERP_UNCLOSED, "trailing tokens in string interpolation hole", ast_line(i), ast_col(i));
- }
- }
- }
- i = i + 1;
- }
-}
-
-fn parse_primary() -> int {
- t := cur_tok();
- if tok_k(t) == T_INT {
- advance_tok();
- return alloc_node(EXPR_INT, 0, 0, 0, tok_iv(t), TY_INT, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_DEX {
- advance_tok();
+fn interp_parse_holes():
+ i : ., mut = 0
+ loop:
+ if i >= g_ast_count:
+ break
+ if ast_kind(i) == EXPR_INTERP_HOLE:
+ txt := istr_get(ast_data(i))
+ if str_len(txt) > 0:
+ // 洞内重入(**全仓唯一的重入点**,T0 布局规格 §5.2/§5.4):洞是从源里切出的
+ // 一小段表达式,**没有 layout 上下文** ⇒ 必须**显式旁路** layout 发射
+ // (否则会伪造缩进状态并改写外层缩进栈;嵌套插值还会递归重入)。
+ // 规则(规格 §5.2):调用后 token 流不由 parse_all/parse_expr 消费 ⇒ 必传旁路。
+ // 旁路以**显式实参**给出(形参 = `layout_bypass`),使调用点原文即判据载体
+ // (J-T0-5 零构建半逐字读本行的 `g_layout_bypass`)。
+ g_layout_bypass = 1
+ tokenize(txt, g_layout_bypass)
+ g_layout_bypass = 0
+ g_token_pos = 0
+ ast_set_a(i, parse_expr())
+ tk2 := cur_tok() // ⚠ 不写 `if tok_k(cur_tok()) != T_EOF {`——那会与 A₁ 顶层兜底的
+ if tok_k(tk2) != T_EOF:
+ // 突变锚点(tests/harness/test_criteria_mutations.py M9)撞形
+ check_error(EC_P_INTERP_UNCLOSED, "trailing tokens in string interpolation hole", ast_line(i), ast_col(i))
+ i = i + 1
+
+fn parse_primary() -> int:
+ t := cur_tok()
+ if tok_k(t) == T_INT:
+ advance_tok()
+ return alloc_node(EXPR_INT, 0, 0, 0, tok_iv(t), TY_INT, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_DEX:
+ advance_tok()
// 节点字段(数值迁移 Task 4):a = binary64 位模式(apx 快路径字面量表示,
// 由 lexer 存入 token 的 lexeme 槽的数字串还原);int_val = 定点缩放整数
// (精确表示,默认路径)。宽度后缀退役(2026-09-10 语言面收窄 §2):data 槽
// 不再承载宽度标注,恒 0。
- bits : int = 0;
- tl := r64(g_tokens, t * ESZ_TOKEN + OFF_TK_LEXEME); // 词素串下标(-1 = 无)
- if tl >= 0 { bits = str_to_f64_bits(istr_get(tl)); }
- return alloc_node(EXPR_DEX, bits, 0, 0, tok_iv(t), TY_DEX, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_STRING || tok_k(t) == T_INTERP {
- return parse_interp_run();
- }
- if tok_k(t) == T_TRUE { advance_tok(); return alloc_node(EXPR_BOOL, 0, 0, 0, 1, TY_BOOL, 0, tok_ln(t), tok_cl(t)); }
- if tok_k(t) == T_FALSE { advance_tok(); return alloc_node(EXPR_BOOL, 0, 0, 0, 0, TY_BOOL, 0, tok_ln(t), tok_cl(t)); }
- if tok_k(t) == T_NONE {
- advance_tok();
- return alloc_node(EXPR_ENUM_CONSTRUCTOR, str_intern("None"), -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_SOME {
- advance_tok();
- ni := str_intern("Some");
- if check(T_LPAREN) {
- // Parse Some(expr[, expr…]) —— R2 P3 Task 4 修复:**实参须照通用枚举构造器分支
- // (下方 parse_postfix 的路径)建 EXPR_ARG 链**。旧实现把值节点直接放 b 槽,
- // 而 checker/ir_gen 的 EXPR_ENUM_CONSTRUCTOR 消费点按 EXPR_ARG 链走
- // (`an := ast_b(node); ast_a(an); an = ast_b(an)`)⇒ 旧形态令该链读进值节点自身
- // 的 a/b 槽(节点 0 当实参、按 ast_b 前行)——实测(本任务开工前):
- // `enum Option[T] { None, Some(T) }` + `x: int? = Some(5)` **checker 死循环**
- // (`corec check` rc=124 超时)。链一修,消费点契约恢复(parser.cr:300-312 同款)。
- advance_tok();
- af : ., mut = -1;
- ac : ., mut = 0;
- if !check(T_RPAREN) {
- first_expr := parse_expr();
- af = alloc_node(EXPR_ARG, first_expr, -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- ac = 1;
- prev_arg : ., mut = af;
- loop {
- if !check(T_COMMA) { break; }
- advance_tok();
- next_expr := parse_expr();
- new_arg := alloc_node(EXPR_ARG, next_expr, -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- ast_set_b(prev_arg, new_arg);
- prev_arg = new_arg;
- ac = ac + 1;
- }
- }
- advance_tok(); // consume )
- return alloc_node(EXPR_ENUM_CONSTRUCTOR, ni, af, ac, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- // Some without parens → treat as identifier (will be resolved by uppercase → enum constructor)
- return alloc_node(EXPR_IDENT, 0, 0, 0, ni, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_AT {
- advance_tok();
- if tok_k(cur_tok()) == T_IDENT {
- name_ni := str_intern(tok_lx(cur_tok()));
- advance_tok();
+ bits : int = 0
+ tl := r64(g_tokens, t * ESZ_TOKEN + OFF_TK_LEXEME) // 词素串下标(-1 = 无)
+ if tl >= 0:
+ bits = str_to_f64_bits(istr_get(tl))
+ return alloc_node(EXPR_DEX, bits, 0, 0, tok_iv(t), TY_DEX, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_STRING || tok_k(t) == T_INTERP:
+ return parse_interp_run()
+ if tok_k(t) == T_TRUE:
+ advance_tok()
+ return alloc_node(EXPR_BOOL, 0, 0, 0, 1, TY_BOOL, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_FALSE:
+ advance_tok()
+ return alloc_node(EXPR_BOOL, 0, 0, 0, 0, TY_BOOL, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_NONE:
+ // v4(§一.5 + docs/core-language-syntax_v4.md:59/264):`none` 是**关键字**,
+ // 空可选值(`T?` 的无值形态)即此拼写。canonical 变体名仍是 `None`(desugar/checker/
+ // ty_shadow 按标签串 `None` 比较,见 ty_shadow.cr:1457)⇒ 此处映射到 canonical 名。
+ // ⚠ `None`(大写)已**退役为普通标识符** —— 作值用会走 EXPR_IDENT 的未定义名硬错(响亮),
+ // 与「拼写面重命名」的意图一致(不静默改判)。
+ advance_tok()
+ return alloc_node(EXPR_ENUM_CONSTRUCTOR, str_intern("None"), -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ // `Some` 已退场为关键字(T_SOME 不再由 lexer 发射):`Some(x)` 走 parse_postfix 的
+ // 「IDENT + `(` + 首字母大写 ⇒ EXPR_ENUM_CONSTRUCTOR」分支(与旧 T_SOME 分支同契约:
+ // 实参建 EXPR_ARG 链),裸 `Some` 走 EXPR_IDENT。
+ if tok_k(t) == T_AT:
+ advance_tok()
+ if tok_k(cur_tok()) == T_IDENT:
+ name_ni := str_intern(tok_lx(cur_tok()))
+ advance_tok()
// args_node = -1 means no args; parse_postfix will handle (args) as EXPR_CALL
- return alloc_node(EXPR_AT, name_ni, -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- add_error("expected identifier after @");
- return alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_IDENT || tok_k(t) == T_SELF || tok_k(t) == T_UNDERSCORE {
- advance_tok();
- name := tok_lx(t);
- ni := str_intern(name);
- if check(T_LBRACE) && g_parse_no_struct_literal == 0 {
- advance_tok();
+ return alloc_node(EXPR_AT, name_ni, -1, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ add_error("expected identifier after @")
+ return alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_IDENT || tok_k(t) == T_SELF || tok_k(t) == T_UNDERSCORE:
+ advance_tok()
+ name := tok_lx(t)
+ ni := str_intern(name)
+ // v4(T0 布局规格 §4.5):块花括号不存在 ⇒ `Name {` 之后**必**是字面量,
+ // 原 `_is_struct_lit` 消解器与 `g_parse_no_struct_literal` 旗标一并退场(无需前瞻)。
+ if check(T_LBRACE):
+ advance_tok()
// 契约(F5 修复,与元组分支同款):EXPR_STRUCT = a=类型名 idx、b=首 wrapper、c=字段数;
// wrapper 在 g_ast 中**连续**(kind=EXPR_NONE,wrapper.a=该字段的值节点)→ 消费者
// 经 EXPR_NONE 前向解引用取值。字段值节点自身对复合表达式(调用 / 字面量 / 嵌套聚合)
@@ -540,57 +625,65 @@ fn parse_primary() -> int {
// TODO #2026-09-11-11 ①:wrapper.b = 字段名 idx(**名字绑定**,-1 = 无名字信息)——旧代码取
// `fni` 后从未写入 ⇒ 值按声明位序绑定(P{b:11,a:22} 静默得 a=11)。名字随 wrapper
// 同行(与值并列的平行表,两趟结构不变,仍无交错分配)。
- cap : ., mut = 8;
- vals : string, mut = alloc(cap * 8);
- names : string, mut = alloc(cap * 8);
- fc : ., mut = 0;
- loop {
+ cap : ., mut = 8
+ vals : string, mut = alloc(cap * 8)
+ names : string, mut = alloc(cap * 8)
+ fc : ., mut = 0
+ loop:
// EOF 护栏(TODO #2026-09-10-12 根因面):本循环只认 `}`,而 advance_tok 在 EOF 是空操作
// ⇒ 解析失步至 EOF 后自旋,每轮分配 AST 节点直至 OOM(alloc 失败返回 NULL →
// grow_ast 向 NULL 拷贝 SIGSEGV)。同族 6 处循环统一补 EOF 退出。
- if check(T_RBRACE) || check(T_EOF) { break; }
- ft := advance_tok();
- fni := str_intern(tok_lx(ft));
- advance_tok();
- if fc >= cap {
- ncap := cap * 2;
- nv := alloc(ncap * 8);
- _dyncpy(vals, cap * 8, nv);
- vals = nv;
- nn := alloc(ncap * 8);
- _dyncpy(names, cap * 8, nn);
- names = nn;
- cap = ncap;
- }
- w64(vals, fc * 8, parse_expr()); // 字段值(子树自占若干槽)
- w64(names, fc * 8, fni); // 字段名 idx(① 名字绑定)
- fc = fc + 1;
- if check(T_COMMA) { advance_tok(); }
- }
- advance_tok();
- ff : ., mut = -1;
- fi2 : ., mut = 0;
- loop {
- if fi2 >= fc { break; }
- vn := r64(vals, fi2 * 8);
- ln : ., mut = tok_ln(t);
- cl : ., mut = tok_cl(t);
- if vn >= 0 { ln = ast_line(vn); cl = ast_col(vn); }
- wl := ast_alloc(EXPR_NONE, vn, r64(names, fi2 * 8), 0, 0, 0, 0, ln, cl);
- if fi2 == 0 { ff = wl; }
- fi2 = fi2 + 1;
- }
- return alloc_node(EXPR_STRUCT, ni, ff, fc, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- return alloc_node(EXPR_IDENT, 0, 0, 0, ni, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_LPAREN {
- advance_tok();
- saved_nsl := g_parse_no_struct_literal;
- g_parse_no_struct_literal = 0;
- e := parse_expr();
- g_parse_no_struct_literal = saved_nsl;
- if check(T_COMMA) {
+ if check(T_RBRACE) || check(T_EOF):
+ break
+ ft := advance_tok()
+ fni := str_intern(tok_lx(ft))
+ // T0 布局规格 §4.2 写死:**字段分隔符必须是 `=`**(v4 单形语言),未选定的
+ // `:` 形**响亮拒绝**(码 P030)。修复前是**盲跳一个 token**(返回值丢弃)⇒
+ // `=` 与 `:` 两形都收 = 判据无鉴别力,而 v4 是单形语言。
+ if check(T_EQ):
+ advance_tok()
+ else:
+ check_error(EC_P_STRUCT_LIT_SEP,
+ "struct literal field separator must be '=' (':' is not valid in v4)",
+ tok_ln(cur_tok()), tok_cl(cur_tok()))
+ if fc >= cap:
+ ncap := cap * 2
+ nv := alloc(ncap * 8)
+ _dyncpy(vals, cap * 8, nv)
+ vals = nv
+ nn := alloc(ncap * 8)
+ _dyncpy(names, cap * 8, nn)
+ names = nn
+ cap = ncap
+ g_want_value = 1 // 字段值 = 表达式位
+ w64(vals, fc * 8, parse_expr()) // 字段值(子树自占若干槽)
+ w64(names, fc * 8, fni) // 字段名 idx(① 名字绑定)
+ fc = fc + 1
+ if check(T_COMMA):
+ advance_tok()
+ advance_tok()
+ ff : ., mut = -1
+ fi2 : ., mut = 0
+ loop:
+ if fi2 >= fc:
+ break
+ vn := r64(vals, fi2 * 8)
+ ln : ., mut = tok_ln(t)
+ cl : ., mut = tok_cl(t)
+ if vn >= 0:
+ ln = ast_line(vn)
+ cl = ast_col(vn)
+ wl := ast_alloc(EXPR_NONE, vn, r64(names, fi2 * 8), 0, 0, 0, 0, ln, cl)
+ if fi2 == 0:
+ ff = wl
+ fi2 = fi2 + 1
+ return alloc_node(EXPR_STRUCT, ni, ff, fc, 0, 0, 0, tok_ln(t), tok_cl(t))
+ return alloc_node(EXPR_IDENT, 0, 0, 0, ni, 0, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_LPAREN:
+ advance_tok()
+ g_want_value = 1 // 括号内 = 表达式位
+ e := parse_expr()
+ if check(T_COMMA):
// Tuple: (e1, e2, ...)
// 契约(F5 修复):EXPR_TUPLE = a=首 wrapper、b=元素个数;wrapper 在 g_ast 中
// **连续**,每个 wrapper(kind=EXPR_NONE)的 a = 该元素的值节点 → 消费者经
@@ -598,102 +691,108 @@ fn parse_primary() -> int {
// (复合元素子树自占多槽),故必须分两趟:先解析全部元素值,再统建连续 wrapper。
// 注:不得照 struct 字面量分支(本文件 T_IDENT+T_LBRACE 段)的「逐值后随建
// wrapper」交错顺序——复合值会插在相邻 wrapper 之间致其不连续,同属本根因。
- cap : ., mut = 8;
- vals : string, mut = alloc(cap * 8);
- w64(vals, 0, e);
- ec : ., mut = 1;
- loop {
- advance_tok(); // consume comma
- if ec >= cap {
- ncap := cap * 2;
- nv := alloc(ncap * 8);
- _dyncpy(vals, cap * 8, nv);
- vals = nv;
- cap = ncap;
- }
- w64(vals, ec * 8, parse_expr()); // 元素值(子树自占若干槽)
- ec = ec + 1;
- if !check(T_COMMA) { break; }
- }
- advance_tok(); // consume )
- ef : ., mut = -1;
- ei : ., mut = 0;
- loop {
- if ei >= ec { break; }
- vn := r64(vals, ei * 8);
- ln : ., mut = tok_ln(t);
- cl : ., mut = tok_cl(t);
- if vn >= 0 { ln = ast_line(vn); cl = ast_col(vn); }
- wl := ast_alloc(EXPR_NONE, vn, 0, 0, 0, 0, 0, ln, cl);
- if ei == 0 { ef = wl; }
- ei = ei + 1;
- }
- return alloc_node(EXPR_TUPLE, ef, ec, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- advance_tok();
- return e;
- }
- if tok_k(t) == T_CHAR {
- advance_tok();
- return alloc_node(EXPR_CHAR, 0, 0, 0, str_intern(tok_lx(t)), TY_CHAR, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_LBRACE { return parse_block(); }
- if tok_k(t) == T_IF { return parse_if_expr(); }
- if tok_k(t) == T_WHILE { return parse_while_expr(); }
- if tok_k(t) == T_LOOP { return parse_loop_expr(); }
- if tok_k(t) == T_FOR { return parse_for_expr(); }
- if tok_k(t) == T_GO {
- t2 := advance_tok();
- if check(T_SEMI) || check(T_RBRACE) || check(T_EOF) {
- add_error("Expected expression after `go`");
- return 0;
- }
+ cap : ., mut = 8
+ vals : string, mut = alloc(cap * 8)
+ w64(vals, 0, e)
+ ec : ., mut = 1
+ loop:
+ advance_tok() // consume comma
+ if ec >= cap:
+ ncap := cap * 2
+ nv := alloc(ncap * 8)
+ _dyncpy(vals, cap * 8, nv)
+ vals = nv
+ cap = ncap
+ g_want_value = 1 // 元组元素 = 表达式位
+ w64(vals, ec * 8, parse_expr()) // 元素值(子树自占若干槽)
+ ec = ec + 1
+ if !check(T_COMMA):
+ break
+ advance_tok() // consume )
+ ef : ., mut = -1
+ ei : ., mut = 0
+ loop:
+ if ei >= ec:
+ break
+ vn := r64(vals, ei * 8)
+ ln : ., mut = tok_ln(t)
+ cl : ., mut = tok_cl(t)
+ if vn >= 0:
+ ln = ast_line(vn)
+ cl = ast_col(vn)
+ wl := ast_alloc(EXPR_NONE, vn, 0, 0, 0, 0, 0, ln, cl)
+ if ei == 0:
+ ef = wl
+ ei = ei + 1
+ return alloc_node(EXPR_TUPLE, ef, ec, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ advance_tok()
+ return e
+ if tok_k(t) == T_CHAR:
+ advance_tok()
+ return alloc_node(EXPR_CHAR, 0, 0, 0, str_intern(tok_lx(t)), TY_CHAR, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_LBRACE:
+ // v4(T0 布局规格 §4.3):`{ }` **只**作结构体字面量定界符(`{` 的唯一合法位置);
+ // 块结构由 `:` + 缩进取代 ⇒ 表达式位的裸 `{` 无产生式,**响亮报错**(不静默按块解)。
+ check_error(EC_P_EXPR,
+ "'{' is only valid as a struct literal delimiter in v4 (blocks use ':' + indent)",
+ tok_ln(t), tok_cl(t))
+ advance_tok()
+ return alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_IF:
+ return parse_if_expr()
+ if tok_k(t) == T_WHILE:
+ return parse_while_expr()
+ if tok_k(t) == T_LOOP:
+ return parse_loop_expr()
+ if tok_k(t) == T_FOR:
+ return parse_for_expr()
+ if tok_k(t) == T_GO:
+ t2 := advance_tok()
+ // A7(T0 布局规格 §6.2):`;`/`}` 的紧跟判定换成**行边界** —— `go` 之后
+ // **同一逻辑行内**无 token ⇒ 响亮报错。
+ if at_line_end() != 0:
+ add_error("Expected expression after `go`")
+ return 0
// go [N] expr or go var start end expr → desugared to for loop
- count : ., mut = -1;
- iter_var_ni : ., mut = -1;
- range_start : ., mut = -1;
- range_end : ., mut = -1;
+ count : ., mut = -1
+ iter_var_ni : ., mut = -1
+ range_start : ., mut = -1
+ range_end : ., mut = -1
// Check for range syntax: go var start..end expr
- saved_pos : ., mut = g_token_pos;
- if tok_k(cur_tok()) == T_IDENT {
- vn := str_intern(tok_lx(cur_tok()));
- advance_tok();
- if tok_k(cur_tok()) == T_INT {
- iter_var_ni = vn;
- range_start = tok_iv(cur_tok());
- advance_tok();
- if tok_k(cur_tok()) == T_DOTDOT {
- advance_tok();
- if tok_k(cur_tok()) == T_INT {
- range_end = tok_iv(cur_tok());
- advance_tok();
- }
- body := parse_expr();
+ saved_pos : ., mut = g_token_pos
+ if tok_k(cur_tok()) == T_IDENT:
+ vn := str_intern(tok_lx(cur_tok()))
+ advance_tok()
+ if tok_k(cur_tok()) == T_INT:
+ iter_var_ni = vn
+ range_start = tok_iv(cur_tok())
+ advance_tok()
+ if tok_k(cur_tok()) == T_DOTDOT:
+ advance_tok()
+ if tok_k(cur_tok()) == T_INT:
+ range_end = tok_iv(cur_tok())
+ advance_tok()
+ body := parse_expr()
// Range go: keep range info in EXPR_GO for IR gen result collection
- range_node := alloc_node(EXPR_RANGE, range_start, range_end, 0, 0, 0, 0, tok_ln(t2), tok_cl(t2));
- return alloc_node(EXPR_GO, -1, body, iter_var_ni, 0, 0, range_node, tok_ln(t2), tok_cl(t2));
- }
- }
+ range_node := alloc_node(EXPR_RANGE, range_start, range_end, 0, 0, 0, 0, tok_ln(t2), tok_cl(t2))
+ return alloc_node(EXPR_GO, -1, body, iter_var_ni, 0, 0, range_node, tok_ln(t2), tok_cl(t2))
// Not range mode — backtrack: regular go
- g_token_pos = saved_pos;
- }
+ g_token_pos = saved_pos
// Single: go expr (no count-based batch)
- body := parse_expr();
- return alloc_node(EXPR_GO, count, body, 0, 0, 0, 0, tok_ln(t2), tok_cl(t2));
- }
- if tok_k(t) == T_AWAIT {
- t2 := advance_tok();
- val := parse_expr();
- return alloc_node(EXPR_AWAIT, val, 0, 0, 0, 0, 0, tok_ln(t2), tok_cl(t2));
- }
- if tok_k(t) == T_MATCH { return parse_match_expr(); }
- if tok_k(t) == T_UNSAFE {
- t2 := advance_tok();
- body := parse_block();
- return alloc_node(EXPR_UNSAFE, body, 0, 0, 0, 0, 0, tok_ln(t2), tok_cl(t2));
- }
- if tok_k(t) == T_LBRACKET {
- advance_tok();
+ body := parse_expr()
+ return alloc_node(EXPR_GO, count, body, 0, 0, 0, 0, tok_ln(t2), tok_cl(t2))
+ if tok_k(t) == T_AWAIT:
+ t2 := advance_tok()
+ val := parse_expr()
+ return alloc_node(EXPR_AWAIT, val, 0, 0, 0, 0, 0, tok_ln(t2), tok_cl(t2))
+ if tok_k(t) == T_MATCH:
+ return parse_match_expr()
+ if tok_k(t) == T_UNSAFE:
+ t2 := advance_tok()
+ body := parse_block()
+ return alloc_node(EXPR_UNSAFE, body, 0, 0, 0, 0, 0, tok_ln(t2), tok_cl(t2))
+ if tok_k(t) == T_LBRACKET:
+ advance_tok()
// 契约(F5 修复,与元组/struct 字面量分支同款):**字面量形** EXPR_ARRAY =
// a=首 wrapper、b=元素个数;wrapper 在 g_ast 中**连续**(kind=EXPR_NONE,wrapper.a=元素值
// 节点)→ 消费者经 EXPR_NONE 前向解引用取值。元素值节点自身对复合表达式(嵌套字面量 /
@@ -702,224 +801,298 @@ fn parse_primary() -> int {
// a[1][0] SIGSEGV 139;且 [[1,2],[3,4]] 与 [5,6] 类型互赋静默通过 = soundness 漏放)。
// 区分:**类型形** [T; N] / [T] 由 parse_type 产出(a=内层类型节点、b=0、int_val=尺寸),
// 不经本分支,不受本契约影响。
- cap : ., mut = 8;
- vals : string, mut = alloc(cap * 8);
- ec : ., mut = 0;
- if !check(T_RBRACKET) {
- w64(vals, 0, parse_expr()); // 元素值(子树自占若干槽)
- ec = 1;
- if check(T_SEMI) {
+ cap : ., mut = 8
+ vals : string, mut = alloc(cap * 8)
+ ec : ., mut = 0
+ if !check(T_RBRACKET):
+ g_want_value = 1 // 数组元素 = 表达式位
+ w64(vals, 0, parse_expr()) // 元素值(子树自占若干槽)
+ ec = 1
+ if check(T_SEMI):
// Repeat array: [value; count] —— 值节点只解析一次,其后仅**共享**同一值节点
// 追加 wrapper(旧写法浅拷贝根节点 N-1 份;共享值节点语义等价,且不再复制多槽子树)。
- advance_tok();
- ct := advance_tok();
- cnt : ., mut = tok_iv(ct);
- if cnt > cap {
- nv := alloc(cnt * 8);
- _dyncpy(vals, cap * 8, nv);
- vals = nv;
- cap = cnt;
- }
- ri : ., mut = 1;
- loop {
- if ri >= cnt { break; }
- w64(vals, ri * 8, r64(vals, 0));
- ri = ri + 1;
- }
- ec = cnt;
- } else {
- loop {
- if !check(T_COMMA) { break; }
- advance_tok();
- if ec >= cap {
- ncap := cap * 2;
- nv := alloc(ncap * 8);
- _dyncpy(vals, cap * 8, nv);
- vals = nv;
- cap = ncap;
- }
- w64(vals, ec * 8, parse_expr()); // 元素值(子树自占若干槽)
- ec = ec + 1;
- }
- }
- }
- advance_tok();
- ef : ., mut = -1;
- ei2 : ., mut = 0;
- loop {
- if ei2 >= ec { break; }
- vn := r64(vals, ei2 * 8);
- ln : ., mut = tok_ln(t);
- cl : ., mut = tok_cl(t);
- if vn >= 0 { ln = ast_line(vn); cl = ast_col(vn); }
- wl := ast_alloc(EXPR_NONE, vn, 0, 0, 0, 0, 0, ln, cl);
- if ei2 == 0 { ef = wl; }
- ei2 = ei2 + 1;
- }
- return alloc_node(EXPR_ARRAY, ef, ec, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- add_error("Unexpected token in expression");
- advance_tok(); // consume the unexpected token to avoid infinite loop
- return 0;
-}
-
-fn parse_block() -> int {
- t := advance_tok();
- local_stmts : string, mut; local_stmts_cap : int, mut;
- local_stmts = alloc(256 * 8); local_stmts_cap = 256;
- sc : ., mut = 0;
- loop {
- if check(T_RBRACE) || check(T_EOF) { break; }
- st := parse_stmt();
- if sc >= local_stmts_cap {
- new_cap := local_stmts_cap * 2;
- new_stmts := alloc(new_cap * 8);
- _dyncpy(local_stmts, local_stmts_cap * 8, new_stmts);
- local_stmts = new_stmts;
- local_stmts_cap = new_cap;
- }
- w64(local_stmts, sc * 8, st);
- sc = sc + 1;
- }
- advance_tok();
+ advance_tok()
+ ct := advance_tok()
+ cnt : ., mut = tok_iv(ct)
+ if cnt > cap:
+ nv := alloc(cnt * 8)
+ _dyncpy(vals, cap * 8, nv)
+ vals = nv
+ cap = cnt
+ ri : ., mut = 1
+ loop:
+ if ri >= cnt:
+ break
+ w64(vals, ri * 8, r64(vals, 0))
+ ri = ri + 1
+ ec = cnt
+ else:
+ loop:
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ if ec >= cap:
+ ncap := cap * 2
+ nv := alloc(ncap * 8)
+ _dyncpy(vals, cap * 8, nv)
+ vals = nv
+ cap = ncap
+ g_want_value = 1 // 数组元素 = 表达式位
+ w64(vals, ec * 8, parse_expr()) // 元素值(子树自占若干槽)
+ ec = ec + 1
+ advance_tok()
+ ef : ., mut = -1
+ ei2 : ., mut = 0
+ loop:
+ if ei2 >= ec:
+ break
+ vn := r64(vals, ei2 * 8)
+ ln : ., mut = tok_ln(t)
+ cl : ., mut = tok_cl(t)
+ if vn >= 0:
+ ln = ast_line(vn)
+ cl = ast_col(vn)
+ wl := ast_alloc(EXPR_NONE, vn, 0, 0, 0, 0, 0, ln, cl)
+ if ei2 == 0:
+ ef = wl
+ ei2 = ei2 + 1
+ return alloc_node(EXPR_ARRAY, ef, ec, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ add_error("Unexpected token in expression")
+ advance_tok() // consume the unexpected token to avoid infinite loop
+ return 0
+
+// 块体收集缓冲(局部语句表;每层 region 一段,退出时整体并入 g_block_stmts)。
+g_pb_stmts : string, mut
+g_pb_cap : int, mut
+g_pb_count : int, mut
+
+fn block_push(n: int):
+ if g_pb_count >= g_pb_cap:
+ ncap : ., mut = g_pb_cap * 2
+ if ncap < 16:
+ ncap = 16
+ nv := alloc(ncap * 8)
+ if g_pb_cap > 0:
+ _dyncpy(g_pb_stmts, g_pb_cap * 8, nv)
+ g_pb_stmts = nv
+ g_pb_cap = ncap
+ w64(g_pb_stmts, g_pb_count * 8, n)
+ g_pb_count = g_pb_count + 1
+
+// region 头 + 体(**所有** region 的通用入口)。
+fn parse_block() -> int:
+ head := cur_tok()
+ if expect_region_head() == 0:
+ // 空 region:零 items、无 DEDENT 可吃 ⇒ 不进 parse_block_items(其 close_region 会要 DEDENT)。
+ return alloc_node(EXPR_BLOCK, g_block_stmt_count, 0, 0, 0, 0, 0, tok_ln(head), tok_cl(head))
+ return parse_block_items(head)
+
+// 体(**头已吃掉**)。拆出本函数只为「函数体 region 的开头若干项 = 规约注解」
+// (v4 文档 §10.1,见 parse_body 的调用点)——那里必须在 statements 之前先吃 `#check`/`#ensure`。
+// v4 region:`T_COLON_BLOCK` + NEWLINE + `T_INDENT` … `T_DEDENT`(取代原 `{` … `}`)。
+// 尾表达式判定(T0 布局规格 §6.2 A1):**region 的最后一项 = 该 region 的值**,
+// 其余各项按语句处理 —— 「还有下一项」的判据由「不是 `}`」变成「不是 DEDENT」。
+// 位置语义见 g_want_value 的头注:进入时读标志决定尾值去留,**体内嵌套 region 一律
+// 先复位为语句位**(parse_stmt / 各 region 产生式各自复位),退出时恢复为进入值。
+fn parse_block_items(head: int) -> int:
+ t := head
+ want := g_want_value
+ g_want_value = 0
+ g_pb_stmts = alloc(256 * 8)
+ g_pb_cap = 256
+ g_pb_count = 0
+ have_expr : ., mut = -1
+ loop:
+ skip_newlines()
+ if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF:
+ break
+ // 收集缓冲的 save/restore:`parse_stmt` 会递归进入嵌套 region(**每个 region 各自
+ // 重置本组全局**)⇒ 不复原本层已收集的语句会被内层覆盖(静默丢语句)。
+ // 保存/恢复的必须是**本层**的状态(不是外层)——否则语句会被推给外层缓冲。
+ my_stmts := g_pb_stmts
+ my_cap := g_pb_cap
+ my_count := g_pb_count
+ st := parse_stmt()
+ g_pb_stmts = my_stmts
+ g_pb_cap = my_cap
+ g_pb_count = my_count
+ if is_stmt_node(st) != 0:
+ // 语句类项:其前的裸表达式不是末项 ⇒ 包 EXPR_STMT(等价 v3 带 `;`)
+ if have_expr >= 0:
+ block_push(alloc_node(EXPR_STMT, have_expr, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t)))
+ have_expr = -1
+ block_push(st)
+ else:
+ // 裸表达式:**暂定**为 region 尾值(后面还有一项时再包成 EXPR_STMT)
+ if have_expr >= 0:
+ block_push(alloc_node(EXPR_STMT, have_expr, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t)))
+ have_expr = st
+ close_region()
+ g_want_value = want
+ if want == 0 && have_expr >= 0 && is_block_like(have_expr) == 0:
+ // 语句位 region + 末项是**普通**裸表达式(赋值/调用/二元/一元/字面量/标识符/下标…)
+ // ⇒ 包 EXPR_STMT(等价 v3 的 `expr;`),region 视为无值。
+ block_push(alloc_node(EXPR_STMT, have_expr, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t)))
+ have_expr = -1
+ if have_expr >= 0:
+ block_push(have_expr)
// Flush to global block_stmts array (isolated from nested blocks)
- si := g_block_stmt_count;
- i : ., mut = 0;
- loop {
- if i >= sc { break; }
- grow_block_stmts(g_block_stmt_count + 1);
- w64(g_block_stmts, g_block_stmt_count * 8, r64(local_stmts, i * 8));
- g_block_stmt_count = g_block_stmt_count + 1;
- i = i + 1;
- }
- return alloc_node(EXPR_BLOCK, si, sc, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
-}
-
-fn is_new_var_decl() -> bool {
- p := cur_tok();
- if tok_k(p) != T_IDENT { return false; }
+ si := g_block_stmt_count
+ i : ., mut = 0
+ loop:
+ if i >= g_pb_count:
+ break
+ grow_block_stmts(g_block_stmt_count + 1)
+ w64(g_block_stmts, g_block_stmt_count * 8, r64(g_pb_stmts, i * 8))
+ g_block_stmt_count = g_block_stmt_count + 1
+ i = i + 1
+ return alloc_node(EXPR_BLOCK, si, g_pb_count, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+
+fn is_new_var_decl() -> bool:
+ p := cur_tok()
+ if tok_k(p) != T_IDENT:
+ return false
// x := expr
- if tok_k(p + 1) == T_COLON_EQ { return true; }
- // x : type ...
- if tok_k(p + 1) == T_COLON { return true; }
+ if tok_k(p + 1) == T_COLON_EQ:
+ return true
+ // x : type ...(T0 布局规格 §6.2 A3:改判 T_COLON_DECL —— 裁定 (b) 使两种 `:` 互斥且
+ // 穷尽 ⇒ `T_COLON_BLOCK` 不进声明分支(进不去 ⇒ 在语句位由 expect_region_head 响亮报错)。
+ // `:=` 仍走 T_COLON_EQ,批量仍走 T_COMMA ⇒ 本消解器零前瞻、比 `;` 时代更简单)
+ if tok_k(p + 1) == T_COLON_DECL:
+ return true
// a, b, ... : type ... or a, b, ... := ... (batch, any count)
- if tok_k(p + 1) == T_COMMA {
- i : ., mut = 2;
- loop {
- if tok_k(p + i) == T_IDENT && tok_k(p + i + 1) == T_COMMA { i = i + 2; continue; }
- if tok_k(p + i) == T_IDENT && (tok_k(p + i + 1) == T_COLON || tok_k(p + i + 1) == T_COLON_EQ) { return true; }
- break;
- }
- }
- return false;
-}
-
-fn parse_new_var_decl() -> int {
- t := cur_tok();
- names : string, mut; names_cap : int, mut;
- names = alloc(64 * 8);
- names_cap = 64;
- nc : ., mut = 0;
+ if tok_k(p + 1) == T_COMMA:
+ i : ., mut = 2
+ loop:
+ if tok_k(p + i) == T_IDENT && tok_k(p + i + 1) == T_COMMA:
+ i = i + 2
+ continue
+ if tok_k(p + i) == T_IDENT && (tok_k(p + i + 1) == T_COLON_DECL || tok_k(p + i + 1) == T_COLON_EQ):
+ return true
+ break
+ return false
+
+fn parse_new_var_decl() -> int:
+ t := cur_tok()
+ names : string, mut
+ names_cap : int, mut
+ names = alloc(64 * 8)
+ names_cap = 64
+ nc : ., mut = 0
// Parse name list
- nt := advance_tok();
- unsafe { w64(names, nc * 8, @ptr_of(tok_lx(nt))); } // 2(a):串字入裸字表
- nc = nc + 1;
+ nt := advance_tok()
+ unsafe:
+ w64(names, nc * 8, @ptr_of(tok_lx(nt)))
+ // 2(a):串字入裸字表
+ nc = nc + 1
// Batch: a, b : type = ...
- if check(T_COMMA) {
- loop {
- if !check(T_COMMA) { break; }
- advance_tok(); // ,
- nt2 := advance_tok();
- unsafe { w64(names, nc * 8, @ptr_of(tok_lx(nt2))); }
- nc = nc + 1;
- }
- }
-
- typ : ., mut = -1;
- is_mut : ., mut = 0; is_pub : ., mut = 0; is_apx : ., mut = 0;
-
- values : string, mut; values_cap : int, mut;
- values = alloc(64 * 8); values_cap = 64;
- vc : ., mut = 0;
-
- if check(T_COLON_EQ) {
- advance_tok();
- w64(values, vc * 8, parse_expr());
- vc = vc + 1;
- loop {
- if !check(T_COMMA) { break; }
- advance_tok();
- w64(values, vc * 8, parse_expr());
- vc = vc + 1;
- }
- } else {
+ if check(T_COMMA):
+ loop:
+ if !check(T_COMMA):
+ break
+ advance_tok() // ,
+ nt2 := advance_tok()
+ unsafe:
+ w64(names, nc * 8, @ptr_of(tok_lx(nt2)))
+ nc = nc + 1
+
+ typ : ., mut = -1
+ is_mut : ., mut = 0
+ is_pub : ., mut = 0
+ is_apx : ., mut = 0
+
+ values : string, mut
+ values_cap : int, mut
+ values = alloc(64 * 8)
+ values_cap = 64
+ vc : ., mut = 0
+
+ if check(T_COLON_EQ):
+ advance_tok()
+ g_want_value = 1 // 声明右值 = 表达式位
+ w64(values, vc * 8, parse_expr())
+ vc = vc + 1
+ loop:
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ g_want_value = 1
+ w64(values, vc * 8, parse_expr())
+ vc = vc + 1
+ else:
// consume ':'
- advance_tok();
+ advance_tok()
- if tok_k(cur_tok()) == T_AUTO || tok_k(cur_tok()) == T_DOT {
- typ = -1;
- advance_tok();
- } else {
- typ = parse_type();
- }
+ if tok_k(cur_tok()) == T_AUTO || tok_k(cur_tok()) == T_DOT:
+ typ = -1
+ advance_tok()
+ else:
+ typ = parse_type()
// Optional tags (built-in + plugin-extensible)
- if check(T_COMMA) {
- advance_tok();
- loop {
- if check(T_EQ) || check(T_SEMI) || check(T_EOF) { break; }
- tag_t := advance_tok();
- tag := tok_lx(tag_t);
- if tag == "mut" { is_mut = 1; }
- else if tag == "pub" { is_pub = 1; }
- else if tag == "apx" { is_apx = 1; }
- else {
- tni := str_intern(tag);
- ei := find_plugin_entry(g_plugin_tags, g_plugin_tag_count, tni, -1);
- if ei >= 0 {
- pd := r64(g_plugin_tags, ei*24+16);
- if pd != 0 { is_mut = 1; }
- } else {
+ if check(T_COMMA):
+ advance_tok()
+ loop:
+ // 标签表终止面(T0 布局规格 §6.2 A8 + A9 的对齐目标):**行边界** + `EQ`
+ // (`x : int, mut, pub = e` 的 `=` 仍保留)。A9:与 bootstrap 侧取同一形。
+ if check(T_EQ) || at_line_end() != 0:
+ break
+ tag_t := advance_tok()
+ tag := tok_lx(tag_t)
+ if tag == "mut":
+ is_mut = 1
+ else if tag == "pub":
+ is_pub = 1
+ else if tag == "apx":
+ is_apx = 1
+ else:
+ tni := str_intern(tag)
+ ei := find_plugin_entry(g_plugin_tags, g_plugin_tag_count, tni, -1)
+ if ei >= 0:
+ pd := r64(g_plugin_tags, ei*24+16)
+ if pd != 0:
+ is_mut = 1
+ else:
// 未知标签:TA08(已知标签 = mut/pub/apx + 插件注册标签)
- grow_diags(g_diag_count + 1);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_TA_UNKNOWN_TAG);
- store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "unknown declaration tag '" + tag + "'");
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, tok_ln(tag_t));
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, tok_cl(tag_t));
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(tok_ln(tag_t)));
- g_diag_count = g_diag_count + 1;
- }
- }
- if !check(T_COMMA) { break; }
- advance_tok();
- }
- }
+ grow_diags(g_diag_count + 1)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_TA_UNKNOWN_TAG)
+ store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "unknown declaration tag '" + tag + "'")
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, tok_ln(tag_t))
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, tok_cl(tag_t))
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(tok_ln(tag_t)))
+ g_diag_count = g_diag_count + 1
+ if !check(T_COMMA):
+ break
+ advance_tok()
// Parse values
- w64(values, 0 * 8, -1);
- if check(T_EQ) {
- advance_tok();
- w64(values, vc * 8, parse_expr());
- vc = vc + 1;
- loop {
- if !check(T_COMMA) { break; }
- advance_tok();
- w64(values, vc * 8, parse_expr());
- vc = vc + 1;
- }
- }
- }
-
- if check(T_SEMI) { advance_tok(); } // optional ;
+ w64(values, 0 * 8, -1)
+ if check(T_EQ):
+ advance_tok()
+ g_want_value = 1 // 声明右值 = 表达式位
+ w64(values, vc * 8, parse_expr())
+ vc = vc + 1
+ loop:
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ g_want_value = 1
+ w64(values, vc * 8, parse_expr())
+ vc = vc + 1
+
+ // v4:语句末可选 `;` 退场(T0 布局规格 §6.2 B1)——收尾统一由 end_decl 的行边界完成。
// Emit LET nodes. First returned directly, extras go to g_extra_lets (dynamic grow).
- first_node : ., mut = -1;
- i : ., mut = 0;
- loop {
- if i >= nc { break; }
- ni := str_intern(unsafe { @str_of(r64(names, i * 8)) }); // 2(a):裸字读出按串用
- nv := r64(values, i * 8);
+ first_node : ., mut = -1
+ i : ., mut = 0
+ loop:
+ if i >= nc:
+ break
+ name_str := unsafe:
+ @str_of(r64(names, i * 8))
+ ni := str_intern(name_str) // 2(a):裸字读出按串用
+ nv := r64(values, i * 8)
// 批 8(静默面收口 · 条目 5;lead 2026-09-18 裁 **(B) 白名单**):`apx` 仅适用于
// **显式 `dex`**(有表示路径)与 **显式 `int`**(既有契约的纯注解:`tests/selfhost/test_apx_tag.py`
// 钉「语法合法 + 语义不变 + `.cir` 携 `approx`」,`tests/bootstrap/test_apx_tag.py` 同向 ApproxInstr
@@ -934,64 +1107,149 @@ fn parse_new_var_decl() -> int {
// 在 **bootstrap 侧仍被接受**、self-hosted 侧**拒**(`error[P26]`)⇒ **接受集分歧**(同族
// `TODO #2026-09-17-10` 的两前端分歧家族)。**形态为预存**(bootstrap 从未校验适用性),
// 但**分歧面因 (B) 而显性化**;收敛方向 = bootstrap 侧补同款白名单(另批,不在本 PR 范围)。
- if is_apx != 0 {
- apx_ok : ., mut = 0;
- if typ >= 0 && ast_kind(typ) == 0 {
- tv := ast_type_val(typ);
- if tv == TY_DEX || tv == TY_INT { apx_ok = 1; }
- }
- if apx_ok == 0 {
+ if is_apx != 0:
+ apx_ok : ., mut = 0
+ if typ >= 0 && ast_kind(typ) == 0:
+ tv := ast_type_val(typ)
+ if tv == TY_DEX || tv == TY_INT:
+ apx_ok = 1
+ if apx_ok == 0:
check_error(EC_P_APX_TAG,
"'apx' tag is only allowed on an explicit 'dex' or 'int' declaration",
- tok_ln(t), tok_cl(t));
- }
- }
- node := alloc_node(EXPR_LET, ni, typ, nv, is_apx, 0, is_mut, tok_ln(t), tok_cl(t));
- if i == 0 {
- first_node = node;
- } else {
- if g_extra_lets_cap == 0 { g_extra_lets = alloc(128); g_extra_lets_cap = 16; }
- if g_extra_let_count < g_extra_lets_cap {
- w64(g_extra_lets, g_extra_let_count * 8, node);
- g_extra_let_count = g_extra_let_count + 1;
- }
- }
- i = i + 1;
- }
-
- return first_node;
-}
+ tok_ln(t), tok_cl(t))
+ node := alloc_node(EXPR_LET, ni, typ, nv, is_apx, 0, is_mut, tok_ln(t), tok_cl(t))
+ if i == 0:
+ first_node = node
+ else:
+ if g_extra_lets_cap == 0:
+ g_extra_lets = alloc(128)
+ g_extra_lets_cap = 16
+ if g_extra_let_count < g_extra_lets_cap:
+ w64(g_extra_lets, g_extra_let_count * 8, node)
+ g_extra_let_count = g_extra_let_count + 1
+ i = i + 1
+
+ return first_node
// 跳过整段嵌套函数声明(P021 已报错,仅错误恢复路径):`fn name(params) -> T {body}`
// 按花括号配平跳过整段;`= expr;` 形式(含 extern 无体形式)遇分号收尾。起始 token 可为
// `pub`。花括号配平从函数体的 `{` 起算(depth 0→1),体内嵌套块/struct 字面量的花括号
// 成对计入,不会在 depth 归零前误判结束。
-fn skip_nested_fn() {
- depth : ., mut = 0;
- seen_brace : ., mut = 0;
- loop {
- k := tok_k(cur_tok());
- if k == T_EOF { return; }
- if k == T_LBRACE { depth = depth + 1; seen_brace = 1; advance_tok(); continue; }
- if k == T_RBRACE {
- advance_tok();
- depth = depth - 1;
- if depth <= 0 { return; }
- continue;
- }
- if k == T_SEMI && seen_brace == 0 { advance_tok(); return; }
- advance_tok();
- }
-}
-
-fn parse_stmt() -> int {
+fn skip_nested_fn():
+ // v4:体的两种形态都以**行边界**收尾 —— `:` + INDENT…DEDENT 的 region,或 `= expr` 行内体。
+ // 花括号配平换成缩进配平(T0 布局规格 §6.2 A5:原 `;` 收尾 ⇒ region 收尾)。
+ depth : ., mut = 0
+ loop:
+ k := tok_k(cur_tok())
+ if k == T_EOF:
+ return
+ if depth == 0:
+ if k == T_NEWLINE:
+ advance_tok()
+ return
+ if k == T_COLON_BLOCK:
+ advance_tok()
+ skip_newlines()
+ if tok_k(cur_tok()) == T_INDENT:
+ depth = 1
+ advance_tok()
+ else:
+ return
+ continue
+ advance_tok()
+ continue
+ if k == T_INDENT:
+ depth = depth + 1
+ else if k == T_DEDENT:
+ depth = depth - 1
+ advance_tok()
+ if depth == 0:
+ return
+
+// 语句前导位 `@` 注解的白名单(v4 §13 的**实证**清单 —— 文档或语料在**语句/region 前导位**
+// 实际出现过的名字):
+// §13.7 `@preferredDomain(gpu)` 前导 `loop:`(文档第三例,逐字)
+// §13.7 `@executionDomain(name)`(同族硬约束;其文档例的目标是顶层 `flow`,此处置同名同判)
+// §13.4 `@NoBoundsCheck`(文档:只用于「调用方承担边界安全责任的**低层区域**」;
+// 语料 `tests/suite/at_test.cr:46` 就是语句位用法)
+// §13.2 `@fast` / `@unroll(4)` / `@section("text.hot")`(语料 `tests/probes/p_annots.cr:5-7` 语句位)
+// **不收** §13.1 查询族 / §13.3 `@addr` / §13.2 `@inline` —— 文档里它们都在**表达式位**
+// (语料同证:`sz := @sizeOf(P3)`、`r := @inline(add)(3, 4)`)⇒ 走既有表达式路。
+// **未知名**不在此列 ⇒ 仍是表达式 ⇒ 由 checker 以 `EC_N_*` 响亮拒绝(不静默)。
+//
+// ⚠ **本清单的判据 = 「文档释文 + 语料实证」,不是「章号范围」**(维护者 2026-10-11 采纳)。
+// 二者会冲突,且本处**以后者为准**:`NoBoundsCheck`(§13.4)/ `fast`·`unroll`·`section`(§13.2)
+// 章号上属「§13.1–13.4」,但那四条的**释文/语料**都把它们用在**语句前导位**(见上逐条出处)
+// ⇒ 收。**禁止**后人按章号把它们再收窄回去——那会把有实证支持的名字重新判成非法。
+fn is_stmt_at_annotation(name: string) -> int:
+ if str_eq(name, "preferredDomain") != 0:
+ return 1
+ if str_eq(name, "executionDomain") != 0:
+ return 1
+ if str_eq(name, "NoBoundsCheck") != 0:
+ return 1
+ if str_eq(name, "fast") != 0:
+ return 1
+ if str_eq(name, "unroll") != 0:
+ return 1
+ if str_eq(name, "section") != 0:
+ return 1
+ return 0
+
+// 消费语句前导位的 `@` 注解链(一至多条,各占一行)。返回被消费的条数。
+fn skip_stmt_at_annotations() -> int:
+ cnt : ., mut = 0
+ loop:
+ if tok_k(cur_tok()) != T_AT:
+ break
+ nxt := cur_tok() + 1
+ if tok_k(nxt) != T_IDENT:
+ break
+ an := tok_lx(nxt)
+ if is_stmt_at_annotation(an) == 0:
+ break
+ at_line := tok_ln(cur_tok())
+ at_col := tok_cl(cur_tok())
+ advance_tok() // '@'
+ advance_tok() // 名字
+ if check(T_LPAREN):
+ depth : ., mut = 1
+ advance_tok()
+ loop:
+ if depth <= 0:
+ break
+ k := tok_k(cur_tok())
+ if k == T_EOF:
+ break
+ if k == T_LPAREN:
+ depth = depth + 1
+ else if k == T_RPAREN:
+ depth = depth - 1
+ advance_tok()
+ // 注解**独占一行**(与规约注解同口径)。带码(V03)—— 不带码的消息会被
+ // `run_frontend` 的 `g_diag_count > 0` 早退挡在 `print_parse_errors()` 之前(报不出来)。
+ if at_line_end() == 0:
+ check_error(EC_V_ANN_SYNTAX,
+ "Expected end of line after '@" + an + "' annotation", at_line, at_col)
+ return cnt
+ skip_newlines()
+ cnt = cnt + 1
+ return cnt
+
+fn parse_stmt() -> int:
+ // 语句位入口(位置语义规则 ①):本语句整体在语句位 ⇒ 先复位;语句内的表达式位由
+ // 各入口重置为 1(声明/赋值右值、return 值、实参、下标、括号内、字面量字段值…)。
+ g_want_value = 0
+ // v4 §13.7 第三例 / §13.4:**语句前导位**的 `@` 注解(如 `@preferredDomain(gpu)` 前导
+ // `loop:`)。必须在此消费 —— 否则 `@` 会落进表达式路,被 checker 当**未知名内建**报 N01
+ // (实测:`@preferredDomain(gpu)` + `loop:` ⇒ `error[N01]`)。
+ skip_stmt_at_annotations()
// Drain batch extras from previous call
- if g_extra_let_count > 0 {
- g_extra_let_count = g_extra_let_count - 1;
- return r64(g_extra_lets, g_extra_let_count * 8);
- }
+ if g_extra_let_count > 0:
+ g_extra_let_count = g_extra_let_count - 1
+ return r64(g_extra_lets, g_extra_let_count * 8)
- t := cur_tok();
+ t := cur_tok()
// 嵌套 `fn`/`flow` 声明不属语言面——grammar/core.ebnf 的 Statement 不含 FunctionDecl
// (函数声明仅顶层 TopLevelDecl),bootstrap 参考实现亦以 positioned error 拒绝。
// 修复前此处落回 parse_primary 的「Unexpected token in expression」通用兜底:只消费
@@ -999,334 +1257,394 @@ fn parse_stmt() -> int {
// 至 EOF 后因该循环只认 `}` 且 advance_tok 在 EOF 是空操作而自旋——每轮分配 AST 节点,
// 直到 bump allocator 耗尽返回 NULL、grow_ast 向 NULL 拷贝(rc=139 SIGSEGV,TODO #2026-09-10-12)。
// 现显式报 P021 并整段跳过该声明:错误定位到声明处,且后续语句恢复正常解析。
- if tok_k(t) == T_FN || tok_k(t) == T_FLOW
- || (tok_k(t) == T_PUB && (tok_k(t + 1) == T_FN || tok_k(t + 1) == T_FLOW)) {
- fnt : ., mut = t;
- if tok_k(fnt) == T_PUB { fnt = fnt + 1; }
- msg : ., mut = "Nested function declaration is not supported; declare it at top level";
- if tok_k(fnt + 1) == T_IDENT {
- msg = "Nested function declaration '" + tok_lx(fnt + 1) + "' is not supported; declare it at top level";
- }
- check_error(EC_P_NESTED_FN, msg, tok_ln(fnt), tok_cl(fnt));
- skip_nested_fn();
- return 0;
- }
+ if tok_k(t) == T_FN || tok_k(t) == T_FLOW || (tok_k(t) == T_PUB && (tok_k(t + 1) == T_FN || tok_k(t + 1) == T_FLOW)):
+ fnt : ., mut = t
+ if tok_k(fnt) == T_PUB:
+ fnt = fnt + 1
+ msg : ., mut = "Nested function declaration is not supported; declare it at top level"
+ if tok_k(fnt + 1) == T_IDENT:
+ msg = "Nested function declaration '" + tok_lx(fnt + 1) + "' is not supported; declare it at top level"
+ check_error(EC_P_NESTED_FN, msg, tok_ln(fnt), tok_cl(fnt))
+ skip_nested_fn()
+ return 0
// New variable declaration syntax
- if tok_k(t) == T_IDENT && is_new_var_decl() {
- return parse_new_var_decl();
- }
- if tok_k(t) == T_RETURN {
- advance_tok();
- val : ., mut = -1;
- if !check(T_SEMI) && !check(T_RBRACE) { val = parse_expr(); }
- if check(T_SEMI) { advance_tok(); }
- return alloc_node(EXPR_RETURN, val, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_YIELD {
- advance_tok();
- val : ., mut = -1;
- if !check(T_SEMI) && !check(T_RBRACE) { val = parse_expr(); }
- if check(T_SEMI) { advance_tok(); }
- return alloc_node(EXPR_YIELD, val, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_BREAK {
- advance_tok();
- if check(T_SEMI) { advance_tok(); }
- return alloc_node(EXPR_BREAK, 0, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_CONTINUE {
- advance_tok();
- if check(T_SEMI) { advance_tok(); }
- return alloc_node(EXPR_CONTINUE, 0, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- e := parse_expr();
- if check(T_SEMI) {
- advance_tok();
- return alloc_node(EXPR_STMT, e, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- return e;
-}
-
-fn parse_if_expr() -> int {
- t := advance_tok();
- // Disable struct literal parsing in condition context
- saved_nsl := g_parse_no_struct_literal;
- g_parse_no_struct_literal = 1;
- cond := parse_expr();
- g_parse_no_struct_literal = saved_nsl;
- tb := parse_block();
- eb : ., mut = -1;
- if check(T_ELSE) {
- advance_tok();
- if check(T_IF) { eb = parse_if_expr(); }
- else { eb = parse_block(); }
- }
- return alloc_node(EXPR_IF, cond, tb, eb, 0, 0, 0, tok_ln(t), tok_cl(t));
-}
-
-fn parse_loop_expr() -> int {
- t := advance_tok();
- body := parse_block();
- return alloc_node(EXPR_LOOP, body, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
-}
-
-fn parse_while_expr() -> int {
- t := advance_tok();
- cond := parse_expr();
- body := parse_block();
- return alloc_node(EXPR_WHILE, cond, body, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
-}
-
-fn parse_for_expr() -> int {
- t := advance_tok();
- vt := advance_tok();
- vn := str_intern(tok_lx(vt));
- advance_tok();
- iter := parse_expr();
- body : ., mut = -1;
- // Core supports: for var := range_expr { body }
- // C-style (for var := init ; cond ; post) is NOT supported;
- // skip to the first '{' to avoid consuming subsequent statements.
- if !check(T_LBRACE) {
- loop {
- if check(T_LBRACE) { break; }
- if check(T_EOF) { break; }
- advance_tok();
- }
- }
- if check(T_LBRACE) {
- body = parse_block();
- }
- return alloc_node(EXPR_FOR, vn, iter, body, 0, 0, 0, tok_ln(t), tok_cl(t));
-}
-
-fn parse_match_expr() -> int {
- t := advance_tok();
- g_parse_no_struct_literal = 1;
- expr := parse_expr();
- g_parse_no_struct_literal = 0;
- advance_tok();
- af := -1;
- al : ., mut = -1; // last arm index
- ac : ., mut = 0;
- loop {
- if check(T_RBRACE) || check(T_EOF) { break; }
- pat := parse_pattern();
- advance_tok();
- body := parse_expr();
- if check(T_COMMA) { advance_tok(); }
- n := alloc_node(EXPR_ARM, pat, body, -1, 0, 0, 0, tok_ln(t), tok_cl(t));
- if ac == 0 { af = n; }
- if al >= 0 { ast_set_c(al, n); } // link previous arm to this one
- al = n;
- ac = ac + 1;
- }
- advance_tok();
- return alloc_node(EXPR_MATCH, expr, af, ac, 0, 0, 0, tok_ln(t), tok_cl(t));
-}
-
-fn parse_pattern() -> int {
- t := cur_tok();
- if tok_k(t) == T_UNDERSCORE {
- advance_tok();
- return alloc_node(EXPR_WILDCARD, 0, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_INT {
- advance_tok();
- return alloc_node(EXPR_INT, 0, 0, 0, tok_iv(t), TY_INT, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_STRING || tok_k(t) == T_INTERP {
- return parse_interp_run();
- }
- if tok_k(t) == T_CHAR {
- advance_tok();
- return alloc_node(EXPR_CHAR, 0, 0, 0, str_intern(tok_lx(t)), TY_CHAR, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_TRUE {
- advance_tok();
- return alloc_node(EXPR_BOOL, 0, 0, 0, 1, TY_BOOL, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_FALSE {
- advance_tok();
- return alloc_node(EXPR_BOOL, 0, 0, 0, 0, TY_BOOL, 0, tok_ln(t), tok_cl(t));
- }
- if tok_k(t) == T_IDENT || tok_k(t) == T_NONE || tok_k(t) == T_SOME {
- advance_tok();
- name := tok_lx(t);
- ni := str_intern(name);
+ if tok_k(t) == T_IDENT && is_new_var_decl():
+ return parse_new_var_decl()
+ if tok_k(t) == T_RETURN:
+ advance_tok()
+ val : ., mut = -1
+ // A6(T0 布局规格 §6.2):关键字之后**同一逻辑行内**无 token ⇒ 无值(行边界取代 `;`)
+ if at_line_end() == 0:
+ g_want_value = 1 // return 的值 = 表达式位
+ val = parse_expr()
+ skip_newlines()
+ return alloc_node(EXPR_RETURN, val, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_YIELD:
+ advance_tok()
+ val : ., mut = -1
+ if at_line_end() == 0:
+ g_want_value = 1
+ val = parse_expr()
+ skip_newlines()
+ return alloc_node(EXPR_YIELD, val, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_BREAK:
+ advance_tok()
+ skip_newlines() // B5:语句末可选 `;` 退场
+ return alloc_node(EXPR_BREAK, 0, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_CONTINUE:
+ advance_tok()
+ skip_newlines()
+ return alloc_node(EXPR_CONTINUE, 0, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ // A1:裸表达式**暂定**为 region 尾值;块循环在「后面还有一项」时再包成 EXPR_STMT。
+ // v4 无 `;` ⇒ 不再有「显式语句」形态(原 `if check(T_SEMI): return EXPR_STMT(e)` 分支淘汰)。
+ return parse_expr()
+
+fn parse_if_expr() -> int:
+ t := advance_tok()
+ want := g_want_value
+ g_want_value = 1 // 条件恒为表达式位
+ cond := parse_expr()
+ g_want_value = want
+ tb := parse_block() // 两臂 region 的位置 = 本 if 表达式自身的位置
+ eb : ., mut = -1
+ if check(T_ELSE):
+ advance_tok()
+ g_want_value = want
+ if check(T_IF):
+ eb = parse_if_expr()
+ else:
+ eb = parse_block()
+ g_want_value = want
+ return alloc_node(EXPR_IF, cond, tb, eb, 0, 0, 0, tok_ln(t), tok_cl(t))
+
+fn parse_loop_expr() -> int:
+ // 规则 ①:loop 体恒为**语句位** region(v3 里体末语句必带 `;` ⇒ 块类型 unit)。
+ t := advance_tok()
+ want := g_want_value
+ g_want_value = 0
+ body := parse_block()
+ g_want_value = want
+ return alloc_node(EXPR_LOOP, body, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+
+fn parse_while_expr() -> int:
+ // 条件恒为表达式位;体恒为语句位 region。
+ t := advance_tok()
+ want := g_want_value
+ g_want_value = 1
+ cond := parse_expr()
+ g_want_value = 0
+ body := parse_block()
+ g_want_value = want
+ return alloc_node(EXPR_WHILE, cond, body, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+
+fn parse_for_expr() -> int:
+ // for var in iter: 。被迭代表达式恒为表达式位;体恒为语句位 region。
+ // C 风格 `for a; b; c` 不支持(`;` 在 v4 只活在 `[T; N]`)。
+ t := advance_tok()
+ vt := advance_tok()
+ vn := str_intern(tok_lx(vt))
+ advance_tok() // in
+ want := g_want_value
+ g_want_value = 1
+ iter := parse_expr()
+ g_want_value = 0
+ body := parse_block()
+ g_want_value = want
+ return alloc_node(EXPR_FOR, vn, iter, body, 0, 0, 0, tok_ln(t), tok_cl(t))
+
+fn parse_match_expr() -> int:
+ // 被匹配的值恒为表达式位;臂体 `=> Expr` 恒为表达式位(单行,不是 region)。
+ t := advance_tok()
+ want := g_want_value
+ g_want_value = 1
+ expr := parse_expr()
+ g_want_value = 0
+ // 空 region(§10.2 裁定推翻后合法):`match c:` 后无可达更深的行 ⇒ 零臂。
+ // `has_items == 0` 时下面的循环一次不进、也不吃 DEDENT(没有)。
+ has_items := expect_region_head()
+ af := -1
+ al : ., mut = -1 // last arm index
+ ac : ., mut = 0
+ loop:
+ if has_items == 0:
+ break
+ skip_newlines()
+ if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF:
+ break
+ // 臂前缀 `|`(v4 目标形)——与 bootstrap 侧同判:**有 `|` 与无 `|` 两形都收**。
+ // 改前 `|` 在臂首是解析错误 ⇒ 本放宽不改变任何既有可解析程序的含义(纯增量)。
+ if check(T_PIPE):
+ advance_tok()
+ pat := parse_pattern()
+ if check(T_FATARROW):
+ advance_tok()
+ else:
+ add_error("expected '=>' in match arm")
+ // v4 文档 §7.3(逐字):「需要多行 arm body 时,`=>` 后换行并进入更深 layout」
+ // match cmd:
+ // | "start" =>
+ // prepare()
+ // start_server()
+ // | _ => println("unknown command")
+ // ⇒ `=>` 后**行尾** ⟺ 臂体是一个 layout region;否则单表达式。
+ // ⚠ 该 region **没有 `:`**(`=>` 已充当开启符)⇒ **不能**走 expect_region_head。
+ body : ., mut = -1
+ // **兼容形 `=>:`**(`=>` 后紧跟 `:`):文档 §7.3 **没有**这一形(那里是 `=>` 后直接换行),
+ // 但 T6 的语料(`tests/selfhost/test_optional.py` 等 ~167 处)机械改写成了它
+ // ⇒ 按本批既有先例(`flow fn` 兼容形)**收为兼容**:与文档形**同判**(其后仍是
+ // 换行 + 更深 layout 的 region)。文档不写它、不为它新增用例;**不改变**文档形的判定。
+ // 「臂体是 region」的判据必须在**消费 `:` 之前**定下 —— 消费后再问 at_line_end()
+ // 会因为站在 INDENT 上而误判成「非行边界」(实测踩过)。
+ is_region : ., mut = 0
+ if check(T_COLON_BLOCK):
+ is_region = 1
+ advance_tok()
+ else if at_line_end() != 0:
+ is_region = 1
+ if is_region != 0:
+ head := cur_tok()
+ skip_newlines()
+ if tok_k(cur_tok()) == T_INDENT:
+ advance_tok()
+ g_want_value = 1 // 臂体 = 表达式位 ⇒ region 保尾值
+ body = parse_block_items(head)
+ else:
+ // 空 region(形态 D:`| _ =>` 后无更深行):值 = 无值
+ body = alloc_node(EXPR_BLOCK, g_block_stmt_count, 0, 0, 0, 0, 0, tok_ln(head), tok_cl(head))
+ else:
+ g_want_value = 1
+ body = parse_expr()
+ if check(T_COMMA):
+ advance_tok()
+ n := alloc_node(EXPR_ARM, pat, body, -1, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if ac == 0:
+ af = n
+ if al >= 0:
+ ast_set_c(al, n)
+ // link previous arm to this one
+ al = n
+ ac = ac + 1
+ if has_items != 0:
+ close_region()
+ g_want_value = want
+ return alloc_node(EXPR_MATCH, expr, af, ac, 0, 0, 0, tok_ln(t), tok_cl(t))
+
+fn parse_pattern() -> int:
+ t := cur_tok()
+ if tok_k(t) == T_UNDERSCORE:
+ advance_tok()
+ return alloc_node(EXPR_WILDCARD, 0, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_INT:
+ advance_tok()
+ return alloc_node(EXPR_INT, 0, 0, 0, tok_iv(t), TY_INT, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_STRING || tok_k(t) == T_INTERP:
+ return parse_interp_run()
+ if tok_k(t) == T_CHAR:
+ advance_tok()
+ return alloc_node(EXPR_CHAR, 0, 0, 0, str_intern(tok_lx(t)), TY_CHAR, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_TRUE:
+ advance_tok()
+ return alloc_node(EXPR_BOOL, 0, 0, 0, 1, TY_BOOL, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_FALSE:
+ advance_tok()
+ return alloc_node(EXPR_BOOL, 0, 0, 0, 0, TY_BOOL, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_NONE:
+ // v4(bootstrap parse_pattern 同判):小写 `none` 是关键字,映射到 **canonical 变体名
+ // `None`**(EnumPattern 的 path[-1] 会被当**标签串**比较,见 desugar/ty_shadow:1457)。
+ // **漏掉本格** ⇒ `none` 掉进下方 `is_upper_first` 为假的 EXPR_IDENT(那是**变量绑定**,
+ // 不是匹配)⇒ 模式永远命中 = 语义静默改变。`Some` 已退场为普通 IDENT,
+ // 走下方 IDENT 分支的「首字母大写 ⇒ EXPR_ENUMPAT」(与旧 T_SOME 同形)。
+ advance_tok()
+ return alloc_node(EXPR_ENUMPAT, str_intern("None"), 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if tok_k(t) == T_IDENT:
+ advance_tok()
+ name := tok_lx(t)
+ ni := str_intern(name)
// Handle Enum.Variant pattern
- if check(T_DOT) {
- advance_tok();
- vt := advance_tok();
- name = name + "." + tok_lx(vt);
- ni = str_intern(name);
- if check(T_LPAREN) {
+ if check(T_DOT):
+ advance_tok()
+ vt := advance_tok()
+ name = name + "." + tok_lx(vt)
+ ni = str_intern(name)
+ if check(T_LPAREN):
// Enum.Variant(subpat, ...)
- advance_tok();
- sub_first : ., mut = -1;
- ac : ., mut = 0;
- if !check(T_RPAREN) {
- sub_first = parse_pattern();
- ac = 1;
- loop {
- if !check(T_COMMA) { break; }
- advance_tok();
- parse_pattern();
- ac = ac + 1;
- }
- }
- advance_tok();
- return alloc_node(EXPR_ENUMPAT, ni, sub_first, ac, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- return alloc_node(EXPR_ENUMPAT, ni, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if check(T_LPAREN) {
- advance_tok();
- sub_first : ., mut = -1;
- ac : ., mut = 0;
- if !check(T_RPAREN) {
- sub_first = parse_pattern();
- ac = 1;
- loop {
- if !check(T_COMMA) { break; }
- advance_tok();
- parse_pattern();
- ac = ac + 1;
- }
- }
- advance_tok();
- return alloc_node(EXPR_ENUMPAT, ni, sub_first, ac, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if check(T_LBRACE) {
+ advance_tok()
+ sub_first : ., mut = -1
+ ac : ., mut = 0
+ if !check(T_RPAREN):
+ sub_first = parse_pattern()
+ ac = 1
+ loop:
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ parse_pattern()
+ ac = ac + 1
+ advance_tok()
+ return alloc_node(EXPR_ENUMPAT, ni, sub_first, ac, 0, 0, 0, tok_ln(t), tok_cl(t))
+ return alloc_node(EXPR_ENUMPAT, ni, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if check(T_LPAREN):
+ advance_tok()
+ sub_first : ., mut = -1
+ ac : ., mut = 0
+ if !check(T_RPAREN):
+ sub_first = parse_pattern()
+ ac = 1
+ loop:
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ parse_pattern()
+ ac = ac + 1
+ advance_tok()
+ return alloc_node(EXPR_ENUMPAT, ni, sub_first, ac, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if check(T_LBRACE):
// Struct pattern: Name { field = pat, ... }
// 契约(F5 修复,与 struct 字面量分支同款):EXPR_STRUCTPAT = a=名字 idx、b=首 wrapper、
// c=字段数;wrapper 在 g_ast 中**连续**(kind=EXPR_NONE,wrapper.a=子模式节点)。
// 复合子模式(嵌套 struct/enum/tuple 模式)子树占多槽,故两趟:先全部解析、后统建 wrapper。
- advance_tok();
- cap : ., mut = 8;
- vals : string, mut = alloc(cap * 8);
- fc : ., mut = 0;
- loop {
- if check(T_RBRACE) || check(T_EOF) { break; }
- ft := advance_tok();
- fni := str_intern(tok_lx(ft));
- advance_tok(); // =
- if fc >= cap {
- ncap := cap * 2;
- nv := alloc(ncap * 8);
- _dyncpy(vals, cap * 8, nv);
- vals = nv;
- cap = ncap;
- }
- w64(vals, fc * 8, parse_pattern());
- fc = fc + 1;
- if check(T_COMMA) { advance_tok(); }
- }
- advance_tok();
- ff : ., mut = -1;
- fi2 : ., mut = 0;
- loop {
- if fi2 >= fc { break; }
- vn := r64(vals, fi2 * 8);
- ln : ., mut = tok_ln(t);
- cl : ., mut = tok_cl(t);
- if vn >= 0 { ln = ast_line(vn); cl = ast_col(vn); }
- wl := ast_alloc(EXPR_NONE, vn, 0, 0, 0, 0, 0, ln, cl);
- if fi2 == 0 { ff = wl; }
- fi2 = fi2 + 1;
- }
- return alloc_node(EXPR_STRUCTPAT, ni, ff, fc, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- if is_upper_first(name) {
- return alloc_node(EXPR_ENUMPAT, ni, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t));
- }
- return alloc_node(EXPR_IDENT, 0, 0, 0, ni, 0, 0, tok_ln(t), tok_cl(t));
- }
- advance_tok();
- return 0;
-}
+ advance_tok()
+ cap : ., mut = 8
+ vals : string, mut = alloc(cap * 8)
+ fc : ., mut = 0
+ loop:
+ if check(T_RBRACE) || check(T_EOF):
+ break
+ ft := advance_tok()
+ fni := str_intern(tok_lx(ft))
+ // 同 struct 字面量的字段分隔符守卫(T0 布局规格 §4.2):struct **模式**取单形 `=`。
+ if check(T_EQ):
+ advance_tok()
+ else:
+ check_error(EC_P_STRUCT_LIT_SEP,
+ "struct pattern field separator must be '='",
+ tok_ln(cur_tok()), tok_cl(cur_tok()))
+ if fc >= cap:
+ ncap := cap * 2
+ nv := alloc(ncap * 8)
+ _dyncpy(vals, cap * 8, nv)
+ vals = nv
+ cap = ncap
+ w64(vals, fc * 8, parse_pattern())
+ fc = fc + 1
+ if check(T_COMMA):
+ advance_tok()
+ advance_tok()
+ ff : ., mut = -1
+ fi2 : ., mut = 0
+ loop:
+ if fi2 >= fc:
+ break
+ vn := r64(vals, fi2 * 8)
+ ln : ., mut = tok_ln(t)
+ cl : ., mut = tok_cl(t)
+ if vn >= 0:
+ ln = ast_line(vn)
+ cl = ast_col(vn)
+ wl := ast_alloc(EXPR_NONE, vn, 0, 0, 0, 0, 0, ln, cl)
+ if fi2 == 0:
+ ff = wl
+ fi2 = fi2 + 1
+ return alloc_node(EXPR_STRUCTPAT, ni, ff, fc, 0, 0, 0, tok_ln(t), tok_cl(t))
+ if is_upper_first(name):
+ return alloc_node(EXPR_ENUMPAT, ni, 0, 0, 0, 0, 0, tok_ln(t), tok_cl(t))
+ return alloc_node(EXPR_IDENT, 0, 0, 0, ni, 0, 0, tok_ln(t), tok_cl(t))
+ advance_tok()
+ return 0
// --- Top-level declarations ---
-fn parse_generics() -> int {
- open_tok : ., mut = 0;
- close_tok : ., mut = 0;
- if check(T_LBRACKET) { open_tok = T_LBRACKET; close_tok = T_RBRACKET; }
- else if check(T_LT) { open_tok = T_LT; close_tok = T_GT; }
- if open_tok > 0 {
- advance_tok(); // [ or <
- gc : ., mut = 0;
- loop {
- if check(close_tok) { break; }
- if gc >= MAX_GENERICS { break; }
- advance_tok();
- gc = gc + 1;
- if !check(T_COMMA) { break; }
- advance_tok();
- }
- advance_tok(); // ] or >
- return gc;
- }
- return 0;
-}
-
-fn parse_generics_into(names: string, constrs: string) -> int {
+fn parse_generics() -> int:
+ open_tok : ., mut = 0
+ close_tok : ., mut = 0
+ if check(T_LBRACKET):
+ open_tok = T_LBRACKET
+ close_tok = T_RBRACKET
+ else if check(T_LT):
+ open_tok = T_LT
+ close_tok = T_GT
+ if open_tok > 0:
+ advance_tok() // [ or <
+ gc : ., mut = 0
+ loop:
+ if check(close_tok):
+ break
+ if gc >= MAX_GENERICS:
+ break
+ advance_tok()
+ gc = gc + 1
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ advance_tok() // ] or >
+ return gc
+ return 0
+
+fn parse_generics_into(names: string, constrs: string) -> int:
// Initialize constraints to -1 (no constraint)
- ci : ., mut = 0;
- loop { if ci >= 4 { break; } w64(constrs, ci * 8, -1); ci = ci + 1; }
- open_tok : ., mut = 0;
- close_tok : ., mut = 0;
- if check(T_LBRACKET) { open_tok = T_LBRACKET; close_tok = T_RBRACKET; }
- else if check(T_LT) { open_tok = T_LT; close_tok = T_GT; }
- if open_tok > 0 {
- advance_tok(); // [ or <
- gc : ., mut = 0;
- loop {
- if check(close_tok) { break; }
- if gc >= MAX_GENERICS { break; }
- gt := advance_tok();
- unsafe { w64(names, gc * 8, @ptr_of(tok_lx(gt))); }
+ ci : ., mut = 0
+ loop:
+ if ci >= 4:
+ break
+ w64(constrs, ci * 8, -1)
+ ci = ci + 1
+ open_tok : ., mut = 0
+ close_tok : ., mut = 0
+ if check(T_LBRACKET):
+ open_tok = T_LBRACKET
+ close_tok = T_RBRACKET
+ else if check(T_LT):
+ open_tok = T_LT
+ close_tok = T_GT
+ if open_tok > 0:
+ advance_tok() // [ or <
+ gc : ., mut = 0
+ loop:
+ if check(close_tok):
+ break
+ if gc >= MAX_GENERICS:
+ break
+ gt := advance_tok()
+ unsafe:
+ w64(names, gc * 8, @ptr_of(tok_lx(gt)))
// Check for constraint: T: Interface
- w64(constrs, gc * 8, -1);
- if check(T_COLON) {
- advance_tok();
- ct := advance_tok();
- w64(constrs, gc * 8, str_intern(tok_lx(ct)));
- }
- gc = gc + 1;
- if !check(T_COMMA) { break; }
- advance_tok();
- }
- advance_tok(); // ] or >
- return gc;
- }
- return 0;
-}
-
-fn save_func_generics(fi: int, names: string, count: int) {
- fi_set_generic_count(fi, count);
- gi : ., mut = 0;
- loop {
- if gi >= count { break; }
- ni := str_intern(unsafe { @str_of(r64(names, gi * 8)) });
- fi_set_generic_name(fi, gi, ni);
- gi = gi + 1;
- }
-}
-
-fn save_func_gen_constrs(fi: int, constrs: string, count: int) {
- gi : ., mut = 0;
- loop {
- if gi >= count { break; }
- if r64(constrs, gi * 8) >= 0 {
- idx := fi * MAX_GENERICS + gi;
- grow_gen_constr(idx + 1);
- w64(g_generic_constr, idx * 8, r64(constrs, gi * 8));
- if idx + 1 > g_generic_constr_count { g_generic_constr_count = idx + 1; }
- }
- gi = gi + 1;
- }
-}
+ w64(constrs, gc * 8, -1)
+ if check(T_COLON_DECL):
+ advance_tok()
+ ct := advance_tok()
+ w64(constrs, gc * 8, str_intern(tok_lx(ct)))
+ gc = gc + 1
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ advance_tok() // ] or >
+ return gc
+ return 0
+
+fn save_func_generics(fi: int, names: string, count: int):
+ fi_set_generic_count(fi, count)
+ gi : ., mut = 0
+ loop:
+ if gi >= count:
+ break
+ name_str := unsafe:
+ @str_of(r64(names, gi * 8))
+ ni := str_intern(name_str)
+ fi_set_generic_name(fi, gi, ni)
+ gi = gi + 1
+
+fn save_func_gen_constrs(fi: int, constrs: string, count: int):
+ gi : ., mut = 0
+ loop:
+ if gi >= count:
+ break
+ if r64(constrs, gi * 8) >= 0:
+ idx := fi * MAX_GENERICS + gi
+ grow_gen_constr(idx + 1)
+ w64(g_generic_constr, idx * 8, r64(constrs, gi * 8))
+ if idx + 1 > g_generic_constr_count:
+ g_generic_constr_count = idx + 1
+ gi = gi + 1
// ─── R2 P3 Task 5(Step 2):结构/枚举泛型约束登记(**索引空间分家** —— 键 = row*MAX_GENERICS+gi,
// 与函数侧 g_generic_constr 不同缓冲;见 globals.cr 表注)───
@@ -1335,230 +1653,270 @@ fn save_func_gen_constrs(fi: int, constrs: string, count: int) {
// `c_ni >= 0` 会把空槽当有效约束名(把首个驻留串当接口/类型名查表)= 凭空约束。
// 故本三函数一律先整行(MAX_GENERICS 槽)写 -1 再覆盖有约束的槽——行的语义 = 「本行全部
// 形参位都有明确值」。读取器的越界闸(idx ≥ count)仍保留(整行未登记时的兜底)。
-fn save_struct_gen_constrs(si: int, constrs: string, count: int) {
- grow_sgen_constr(si * MAX_GENERICS + MAX_GENERICS);
- if si * MAX_GENERICS + MAX_GENERICS > g_sgen_constr_count { g_sgen_constr_count = si * MAX_GENERICS + MAX_GENERICS; }
- zi : ., mut = 0;
- loop {
- if zi >= MAX_GENERICS { break; }
- w64(g_sgen_constr, (si * MAX_GENERICS + zi) * 8, -1);
- zi = zi + 1;
- }
- gi : ., mut = 0;
- loop {
- if gi >= count { break; }
- if gi >= MAX_GENERICS { break; }
- if r64(constrs, gi * 8) >= 0 {
- w64(g_sgen_constr, (si * MAX_GENERICS + gi) * 8, r64(constrs, gi * 8));
- }
- gi = gi + 1;
- }
-}
-
-fn save_enum_gen_constrs(ei: int, constrs: string, count: int) {
- grow_egen_constr(ei * MAX_GENERICS + MAX_GENERICS);
- if ei * MAX_GENERICS + MAX_GENERICS > g_egen_constr_count { g_egen_constr_count = ei * MAX_GENERICS + MAX_GENERICS; }
- zi : ., mut = 0;
- loop {
- if zi >= MAX_GENERICS { break; }
- w64(g_egen_constr, (ei * MAX_GENERICS + zi) * 8, -1);
- zi = zi + 1;
- }
- gi : ., mut = 0;
- loop {
- if gi >= count { break; }
- if gi >= MAX_GENERICS { break; }
- if r64(constrs, gi * 8) >= 0 {
- w64(g_egen_constr, (ei * MAX_GENERICS + gi) * 8, r64(constrs, gi * 8));
- }
- gi = gi + 1;
- }
-}
-
-fn add_func(name: string, pc: int, rt: int, an: int) -> int {
- idx := g_func_count;
- grow_funcs(idx + 1);
- ni := str_intern(name);
- fi_set_name(idx, ni);
- fi_set_param_count(idx, pc);
- fi_set_return_type(idx, rt);
- fi_set_ast_node(idx, an);
- g_func_count = idx + 1;
- return idx;
-}
-
-fn add_struct(name: string) -> int {
- idx := g_struct_count;
- grow_structs(idx + 1);
- ni := str_intern(name);
- base := idx * ESZ_STRUCTINFO;
+fn save_struct_gen_constrs(si: int, constrs: string, count: int):
+ grow_sgen_constr(si * MAX_GENERICS + MAX_GENERICS)
+ if si * MAX_GENERICS + MAX_GENERICS > g_sgen_constr_count:
+ g_sgen_constr_count = si * MAX_GENERICS + MAX_GENERICS
+ zi : ., mut = 0
+ loop:
+ if zi >= MAX_GENERICS:
+ break
+ w64(g_sgen_constr, (si * MAX_GENERICS + zi) * 8, -1)
+ zi = zi + 1
+ gi : ., mut = 0
+ loop:
+ if gi >= count:
+ break
+ if gi >= MAX_GENERICS:
+ break
+ if r64(constrs, gi * 8) >= 0:
+ w64(g_sgen_constr, (si * MAX_GENERICS + gi) * 8, r64(constrs, gi * 8))
+ gi = gi + 1
+
+fn save_enum_gen_constrs(ei: int, constrs: string, count: int):
+ grow_egen_constr(ei * MAX_GENERICS + MAX_GENERICS)
+ if ei * MAX_GENERICS + MAX_GENERICS > g_egen_constr_count:
+ g_egen_constr_count = ei * MAX_GENERICS + MAX_GENERICS
+ zi : ., mut = 0
+ loop:
+ if zi >= MAX_GENERICS:
+ break
+ w64(g_egen_constr, (ei * MAX_GENERICS + zi) * 8, -1)
+ zi = zi + 1
+ gi : ., mut = 0
+ loop:
+ if gi >= count:
+ break
+ if gi >= MAX_GENERICS:
+ break
+ if r64(constrs, gi * 8) >= 0:
+ w64(g_egen_constr, (ei * MAX_GENERICS + gi) * 8, r64(constrs, gi * 8))
+ gi = gi + 1
+
+fn add_func(name: string, pc: int, rt: int, an: int) -> int:
+ idx := g_func_count
+ grow_funcs(idx + 1)
+ ni := str_intern(name)
+ fi_set_name(idx, ni)
+ fi_set_param_count(idx, pc)
+ fi_set_return_type(idx, rt)
+ fi_set_ast_node(idx, an)
+ g_func_count = idx + 1
+ return idx
+
+fn add_struct(name: string) -> int:
+ idx := g_struct_count
+ grow_structs(idx + 1)
+ ni := str_intern(name)
+ base := idx * ESZ_STRUCTINFO
// Zero the entire struct entry
- zi : ., mut = 0;
- loop {
- if zi >= ESZ_STRUCTINFO { break; }
- w8(g_structs, base + zi, 0);
- zi = zi + 1;
- }
- w64(g_structs, base + OFF_SI_NAME, ni);
+ zi : ., mut = 0
+ loop:
+ if zi >= ESZ_STRUCTINFO:
+ break
+ w8(g_structs, base + zi, 0)
+ zi = zi + 1
+ w64(g_structs, base + OFF_SI_NAME, ni)
// 容量批 T3:字段区基址 = 侧表高水位(字段写入点按 base + 下标寻址;体尾 si_commit_fields 提交)
- si_set_field_base(idx, g_si_f_used);
- g_struct_count = idx + 1;
- return idx;
-}
-
-fn add_enum(name: string) -> int {
- idx := g_enum_count;
- grow_enums(idx + 1);
- ni := str_intern(name);
- base := idx * ESZ_ENUMINFO;
+ si_set_field_base(idx, g_si_f_used)
+ g_struct_count = idx + 1
+ return idx
+
+fn add_enum(name: string) -> int:
+ idx := g_enum_count
+ grow_enums(idx + 1)
+ ni := str_intern(name)
+ base := idx * ESZ_ENUMINFO
// Zero the entire enum entry
- zi : ., mut = 0;
- loop {
- if zi >= ESZ_ENUMINFO { break; }
- w8(g_enums, base + zi, 0);
- zi = zi + 1;
- }
- w64(g_enums, base + OFF_EI_NAME, ni);
+ zi : ., mut = 0
+ loop:
+ if zi >= ESZ_ENUMINFO:
+ break
+ w8(g_enums, base + zi, 0)
+ zi = zi + 1
+ w64(g_enums, base + OFF_EI_NAME, ni)
// 容量批 T3:变体区基址 = 侧表高水位(体尾 ei_commit_variants 提交)
- ei_set_variant_base(idx, g_ei_v_used);
- g_enum_count = idx + 1;
- return idx;
-}
-
-fn extract_hotpatch_ver(args_node: int) -> int {
- if args_node < 0 { return -1; }
- arg := args_node;
- loop {
- if arg < 0 { break; }
- expr := ast_a(arg);
- k := ast_kind(expr);
- if k == EXPR_ASSIGN {
- name_ni := ast_a(expr);
- name := istr_get(name_ni);
- val_node := ast_b(expr);
- if str_eq(name, "ver") != 0 {
- return ast_int_val(val_node);
- }
- }
- arg = ast_b(arg);
- }
- return -1;
-}
-
-fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_ver: int) {
- gnames : string, mut; gnames_cap : int, mut;
- gnames = alloc(64 * 8); gnames_cap = 64;
- gconstrs : string, mut; gconstrs_cap : int, mut;
- gconstrs = alloc(64 * 8); gconstrs_cap = 64;
- gc := parse_generics_into(gnames, gconstrs);
-
- advance_tok(); // (
- pf : ., mut = -1;
- pc : ., mut = 0;
- if !check(T_RPAREN) {
- loop {
+ ei_set_variant_base(idx, g_ei_v_used)
+ g_enum_count = idx + 1
+ return idx
+
+fn extract_hotpatch_ver(args_node: int) -> int:
+ if args_node < 0:
+ return -1
+ arg := args_node
+ loop:
+ if arg < 0:
+ break
+ expr := ast_a(arg)
+ k := ast_kind(expr)
+ if k == EXPR_ASSIGN:
+ name_ni := ast_a(expr)
+ name := istr_get(name_ni)
+ val_node := ast_b(expr)
+ if str_eq(name, "ver") != 0:
+ return ast_int_val(val_node)
+ arg = ast_b(arg)
+ return -1
+
+fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_ver: int):
+ gnames : string, mut
+ gnames_cap : int, mut
+ gnames = alloc(64 * 8)
+ gnames_cap = 64
+ gconstrs : string, mut
+ gconstrs_cap : int, mut
+ gconstrs = alloc(64 * 8)
+ gconstrs_cap = 64
+ gc := parse_generics_into(gnames, gconstrs)
+
+ advance_tok() // (
+ pf : ., mut = -1
+ pc : ., mut = 0
+ if !check(T_RPAREN):
+ loop:
// Handle self/&self/&mut self params
- if tok_k(cur_tok()) == T_SELF {
- pt := advance_tok();
- if pf < 0 { pf = g_ast_count; }
- alloc_node(EXPR_PARAM, str_intern("self"), 0, 0, 1, 0, 0, tok_ln(pt), tok_cl(pt));
- pc = pc + 1;
- if check(T_COLON) { advance_tok(); parse_type(); }
- if !check(T_COMMA) { break; }
- advance_tok();
- continue;
- }
- if tok_k(cur_tok()) == T_AMPERSAND && tok_k(cur_tok()+1) == T_MUT && tok_k(cur_tok()+2) == T_SELF {
- pt := advance_tok();
- advance_tok();
- advance_tok();
- if pf < 0 { pf = g_ast_count; }
- alloc_node(EXPR_PARAM, str_intern("self"), 0, 0, 3, 0, 0, tok_ln(pt), tok_cl(pt));
- pc = pc + 1;
- if check(T_COLON) { advance_tok(); parse_type(); }
- if !check(T_COMMA) { break; }
- advance_tok();
- continue;
- }
- if tok_k(cur_tok()) == T_AMPERSAND && tok_k(cur_tok()+1) == T_SELF {
- pt := advance_tok();
- advance_tok();
- if pf < 0 { pf = g_ast_count; }
- alloc_node(EXPR_PARAM, str_intern("self"), 0, 0, 2, 0, 0, tok_ln(pt), tok_cl(pt));
- pc = pc + 1;
- if check(T_COLON) { advance_tok(); parse_type(); }
- if !check(T_COMMA) { break; }
- advance_tok();
- continue;
- }
+ if tok_k(cur_tok()) == T_SELF:
+ pt := advance_tok()
+ if pf < 0:
+ pf = g_ast_count
+ alloc_node(EXPR_PARAM, str_intern("self"), 0, 0, 1, 0, 0, tok_ln(pt), tok_cl(pt))
+ pc = pc + 1
+ if check(T_COLON_DECL):
+ advance_tok()
+ parse_type()
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ continue
+ if tok_k(cur_tok()) == T_AMPERSAND && tok_k(cur_tok()+1) == T_MUT && tok_k(cur_tok()+2) == T_SELF:
+ pt := advance_tok()
+ advance_tok()
+ advance_tok()
+ if pf < 0:
+ pf = g_ast_count
+ alloc_node(EXPR_PARAM, str_intern("self"), 0, 0, 3, 0, 0, tok_ln(pt), tok_cl(pt))
+ pc = pc + 1
+ if check(T_COLON_DECL):
+ advance_tok()
+ parse_type()
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ continue
+ if tok_k(cur_tok()) == T_AMPERSAND && tok_k(cur_tok()+1) == T_SELF:
+ pt := advance_tok()
+ advance_tok()
+ if pf < 0:
+ pf = g_ast_count
+ alloc_node(EXPR_PARAM, str_intern("self"), 0, 0, 2, 0, 0, tok_ln(pt), tok_cl(pt))
+ pc = pc + 1
+ if check(T_COLON_DECL):
+ advance_tok()
+ parse_type()
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ continue
// Variadic: ...name:type
- if check(T_DOTDOTDOT) {
- advance_tok(); vt := advance_tok();
- vn := str_intern(tok_lx(vt)); advance_tok();
- vty := parse_type();
- if pf < 0 { pf = g_ast_count; }
- alloc_node(EXPR_PARAM, vn, 0, 0, -1, 0, vty, tok_ln(vt), tok_cl(vt));
- pc = pc + 1;
- if !check(T_COMMA) { break; } advance_tok(); continue;
- }
- pt := advance_tok();
- pn := str_intern(tok_lx(pt));
- advance_tok();
- pty := parse_type();
- if pf < 0 { pf = g_ast_count; }
- alloc_node(EXPR_PARAM, pn, 0, 0, 0, unpack_type(pty), pty, tok_ln(pt), tok_cl(pt));
- pc = pc + 1;
- if !check(T_COMMA) { break; }
- advance_tok();
- }
- }
- advance_tok(); // )
- rt : ., mut = 0;
- rtv : ., mut = TY_UNIT;
- if check(T_ARROW) {
- advance_tok(); // ->
- rt = parse_type();
- rtv = unpack_type(rt);
- }
+ if check(T_DOTDOTDOT):
+ advance_tok()
+ vt := advance_tok()
+ vn := str_intern(tok_lx(vt))
+ advance_tok()
+ vty := parse_type()
+ if pf < 0:
+ pf = g_ast_count
+ alloc_node(EXPR_PARAM, vn, 0, 0, -1, 0, vty, tok_ln(vt), tok_cl(vt))
+ pc = pc + 1
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ continue
+ pt := advance_tok()
+ pn := str_intern(tok_lx(pt))
+ advance_tok()
+ pty := parse_type()
+ if pf < 0:
+ pf = g_ast_count
+ alloc_node(EXPR_PARAM, pn, 0, 0, 0, unpack_type(pty), pty, tok_ln(pt), tok_cl(pt))
+ pc = pc + 1
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ advance_tok() // )
+ rt : ., mut = 0
+ rtv : ., mut = TY_UNIT
+ if check(T_ARROW):
+ advance_tok() // ->
+ rt = parse_type()
+ rtv = unpack_type(rt)
// 批 6(T2,裁-S2):规约标注链——**签名之后、body 之前**(spec-design §四)。
// T3:记录起点,`alloc_node(EXPR_FN, …)` 之后把本函数的标注行回填为 **fn_node 索引**
//(唯一键——按函数名会串台:同名方法/多 impl)。
- spec_start := g_spec_count;
- parse_spec_annotations(fn_ni);
-
- body : ., mut = -1;
- if check(T_LBRACE) {
- body = parse_block();
- } else {
- advance_tok(); // =
- body = parse_expr();
- advance_tok(); // ;
- }
- fn_node := alloc_node(EXPR_FN, fn_ni, pf, pc, rtv + hotpatch_ver * 256, rt, body, fn_line, fn_col);
+ spec_start := g_spec_count
+ parse_spec_annotations(fn_ni, 0) // inline 形(兼容):注解后紧跟 `:`,不要求行尾
+
+ body : ., mut = -1
+ // D9/D10(T0 布局规格 §2.2):有体 ⇒ 行尾 `:`(T_COLON_BLOCK)开 region;
+ // 无体(`extern fn read(fd: int) -> int`)⇒ 行边界,无 `:`。
+ // 规则 ①:函数体 region **恒为语句位** ⇒ 末项裸表达式包 EXPR_STMT,块类型 unit
+ // ⇒ 返回值只经显式 `return`(v4 §7.4「函数没有 implicit tail return」)。
+ if at_line_end() != 0:
+ body = -1
+ else if check(T_EQ):
+ // `fn f() = expr`(表达式体)——声明右值 = 表达式位
+ advance_tok()
+ g_want_value = 1
+ body = parse_expr()
+ else:
+ g_want_value = 0
+ // v4 文档 §10.1(**文档形**):规约注解位于函数 layout region 的**开头**——
+ // 「在 statements 之前」的若干项。故此处**自己吃掉 region 头**,先把 `#check`/`#ensure`
+ // 收干净,再进 statements(`parse_block` 那条通用路做不到这一步)。
+ // inline 形(注解夹在签名与 `:` 之间,见上方 1737-1738 行)**保留为兼容**:
+ // 它不在文档里,但 `tests/spec` 的干净档有工具产出,删掉会牵动 T6 的修复路径。
+ head := cur_tok()
+ if expect_region_head() == 0:
+ // 空函数体(§10.2 裁定推翻后合法):零项 ⇒ 值 = 无值(块类型 unit)。
+ body = alloc_node(EXPR_BLOCK, g_block_stmt_count, 0, 0, 0, 0, 0, tok_ln(head), tok_cl(head))
+ else:
+ parse_spec_annotations(fn_ni, 1) // 文档形:注解独占一行
+ body = parse_block_items(head)
+ fn_node := alloc_node(EXPR_FN, fn_ni, pf, pc, rtv + hotpatch_ver * 256, rt, body, fn_line, fn_col)
// T3:标注行回填 fn_node(本函数新增的行 = [spec_start, g_spec_count))
- spec_patch : ., mut = spec_start;
- loop { if spec_patch >= g_spec_count { break; } spec_set_fnode(spec_patch, fn_node); spec_patch = spec_patch + 1; }
+ spec_patch : ., mut = spec_start
+ loop:
+ if spec_patch >= g_spec_count:
+ break
+ spec_set_fnode(spec_patch, fn_node)
+ spec_patch = spec_patch + 1
// 形参上限硬错(防御面,TODO #2026-09-10-4):FuncInfo.param_types 是定长内嵌槽区
// (MAX_FN_PARAMS 槽),超限签名无法表示 ⇒ 拒绝编译(rc=1)而非截断/越界写。
// 形参表容纳不下时**必须**在这条路径上停住:静默越界写曾踩 ast_node 致
// name_idx/param_count 归零 + TF01 误归 + rc=0 产物崩。
- if pc > MAX_FN_PARAMS {
+ if pc > MAX_FN_PARAMS:
check_error(EC_P_TOO_MANY_PARAMS,
"Function has too many parameters (" + int_str(pc) + " > " + int_str(MAX_FN_PARAMS) + ")",
- fn_line, fn_col);
- }
- fi := add_func(fn_name, pc, rtv, fn_node);
- if fi >= 0 && gc > 0 { save_func_generics(fi, gnames, gc); save_func_gen_constrs(fi, gconstrs, gc); }
+ fn_line, fn_col)
+ fi := add_func(fn_name, pc, rtv, fn_node)
+ if fi >= 0 && gc > 0:
+ save_func_generics(fi, gnames, gc)
+ save_func_gen_constrs(fi, gconstrs, gc)
// Store param types in FuncInfo(pc > MAX_FN_PARAMS 已被上方硬错拒绝;
// 此处再显式跳过 + fi_set_param_type 内槽区护栏 = 双保险,未来新调用点亦不越过界)
- if fi >= 0 && pc <= MAX_FN_PARAMS { pstore_i : ., mut = 0; pstore_n : ., mut = pf;
- loop { if pstore_i >= pc { break; } if pstore_n < 0 { break; }
- if ast_kind(pstore_n) == EXPR_PARAM {
- fi_set_param_type(fi, pstore_i, ast_type_val(pstore_n));
- pstore_i = pstore_i + 1; }
- pstore_n = pstore_n + 1; } }
-}
+ if fi >= 0 && pc <= MAX_FN_PARAMS:
+ pstore_i : ., mut = 0
+ pstore_n : ., mut = pf
+ loop:
+ if pstore_i >= pc:
+ break
+ if pstore_n < 0:
+ break
+ if ast_kind(pstore_n) == EXPR_PARAM:
+ fi_set_param_type(fi, pstore_i, ast_type_val(pstore_n))
+ pstore_i = pstore_i + 1
+ pstore_n = pstore_n + 1
// 批 6(T2,裁-S1/S2):规约标注链 `#check(expr)` / `#ensure(expr)` —— **签名与 body 之间**。
// 位置真源 = docs/maintainer/design/spec-design.md §四(`fn f(...) -> T` 之后、body 之前)。
@@ -1574,596 +1932,732 @@ fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_v
// 形态错一律**响亮**(EC_V_*:17xxx 家族,fail-closed 默认阻断 ⇒ rc=1 + 零产物;
// 照「未知字符不得静默」的既有口径)。错误后**不消费残余**、直接返回 ⇒ 由外层继续解析并
// 给出第二重信号(不静默、不猜)。
-fn parse_spec_annotations(fn_ni: int) {
- loop {
- if !check(T_HASH) { break; }
- at_line := tok_ln(cur_tok());
- at_col := tok_cl(cur_tok());
- advance_tok(); // '#'
- if tok_k(cur_tok()) != T_IDENT {
- check_error(EC_V_BAD_TAG, "Expected annotation name after '#'", at_line, at_col);
- return;
- }
- an_name := tok_lx(cur_tok());
- kind : ., mut = -1;
- if str_eq(an_name, "check") != 0 { kind = 0; }
- else if str_eq(an_name, "ensure") != 0 { kind = 1; }
- if kind < 0 {
+// 两个位置共用本函数;`need_eol` 区分二者:
+// ① **inline 形**(兼容,非文档)——签名与 `:` 之间,各条注解同行 ⇒ need_eol=0
+// (其后紧跟的是 `T_COLON_BLOCK`,不是行边界,故**不能**要行尾);
+// ② **文档形**(v4 §10.1)——函数 region 的**开头若干项**,每条注解**独占一行** ⇒ need_eol=1
+// (v4 的行语义 = 一条语句一行;`#check(1 > 0) return 1` 同行是**非法文本**)。
+// 循环尾 `skip_newlines()` 让注解链跨行成立(① 那侧无 NEWLINE,是 no-op)。
+fn parse_spec_annotations(fn_ni: int, need_eol: int):
+ loop:
+ if !check(T_HASH):
+ break
+ at_line := tok_ln(cur_tok())
+ at_col := tok_cl(cur_tok())
+ advance_tok() // '#'
+ if tok_k(cur_tok()) != T_IDENT:
+ check_error(EC_V_BAD_TAG, "Expected annotation name after '#'", at_line, at_col)
+ return
+ an_name := tok_lx(cur_tok())
+ kind : ., mut = -1
+ if str_eq(an_name, "check") != 0:
+ kind = 0
+ else if str_eq(an_name, "ensure") != 0:
+ kind = 1
+ if kind < 0:
check_error(EC_V_BAD_TAG,
- "Unknown annotation '#" + an_name + "' (expected '#check' or '#ensure')", at_line, at_col);
- return;
- }
- advance_tok(); // 标注名
- if !check(T_LPAREN) {
- check_error(EC_V_ANN_SYNTAX, "Expected '(' after '#" + an_name + "'", at_line, at_col);
- return;
- }
- advance_tok(); // '('
- expr := parse_expr();
- if !check(T_RPAREN) {
+ "Unknown annotation '#" + an_name + "' (expected '#check' or '#ensure')", at_line, at_col)
+ return
+ advance_tok() // 标注名
+ if !check(T_LPAREN):
+ check_error(EC_V_ANN_SYNTAX, "Expected '(' after '#" + an_name + "'", at_line, at_col)
+ return
+ advance_tok() // '('
+ expr := parse_expr()
+ if !check(T_RPAREN):
+ check_error(EC_V_ANN_SYNTAX,
+ "Expected ')' to close '#" + an_name + "' annotation", at_line, at_col)
+ return
+ advance_tok() // ')'
+ // 文档形:注解必须**独占一行**。**带码**(V03)而非 `add_error` —— 不带码的
+ // 消息会被 `run_frontend` 的 `g_diag_count > 0` 早退挡在 `print_parse_errors()`
+ // 之前(见 `main.cr:133-137`),也就是**报不出来**(同 `flow` 那处的先例)。
+ // 判据(负例档 `tests/spec/t2_neg_inbody.cr` 逐字 `#check(1 > 0) return 1`):
+ // 该档是**负例**,必须 rc=1;漏了本条会把它变成静默接受(实测确曾如此)。
+ if need_eol != 0 && at_line_end() == 0:
check_error(EC_V_ANN_SYNTAX,
- "Expected ')' to close '#" + an_name + "' annotation", at_line, at_col);
- return;
- }
- advance_tok(); // ')'
- spec_add(fn_ni, kind, expr, at_line, at_col);
- }
-}
-
-fn parse_ffi_annotation() -> int {
+ "Expected end of line after '#" + an_name + "' annotation", at_line, at_col)
+ return
+ spec_add(fn_ni, kind, expr, at_line, at_col)
+ // 注解之间的换行(文档形 §10.1:每条独占一行)。**只跳注解之间**——
+ // 首条之前若有 NEWLINE(无体声明的收尾),在此吞掉会让调用点的 at_line_end()
+ // 误判「非行边界」(回归面)。
+ skip_newlines()
+
+fn parse_ffi_annotation() -> int:
// Current token is T_AT; consume it and parse @ffi("lang")
- advance_tok(); // skip @
- if tok_k(cur_tok()) != T_IDENT { add_error("expected ffi"); return -1; }
- lex := tok_lx(cur_tok());
- if str_eq(lex, "ffi") == 0 { add_error("expected ffi"); return -1; }
- advance_tok();
+ advance_tok() // skip @
+ if tok_k(cur_tok()) != T_IDENT:
+ add_error("expected ffi")
+ return -1
+ lex := tok_lx(cur_tok())
+ if str_eq(lex, "ffi") == 0:
+ add_error("expected ffi")
+ return -1
+ advance_tok()
// Expect ( "lang_name" )
- if tok_k(cur_tok()) != T_LPAREN { add_error("expected ("); return -1; }
- advance_tok();
- if tok_k(cur_tok()) != T_STRING { add_error("expected string literal for FFI language"); return -1; }
- lang_ni := str_intern(tok_lx(cur_tok()));
- advance_tok();
- if tok_k(cur_tok()) != T_RPAREN { add_error("expected )"); return -1; }
- advance_tok();
- return lang_ni;
-}
-
-fn parse_declaration() {
- hotpatch_ver : ., mut = 0;
-
- // Handle @hotpatch(ver=N) annotation before function declarations
- if check(T_AT) {
- saved_ast := g_ast_count;
- annotation := parse_expr();
- if check(T_FN) || check(T_FLOW) || check(T_PUB) || check(T_EXTERN) {
- k := ast_kind(annotation);
- if k == EXPR_CALL {
- callee := ast_a(annotation);
- if ast_kind(callee) == EXPR_AT {
- name_ni := ast_a(callee);
- name := istr_get(name_ni);
- if str_eq(name, "hotpatch") != 0 {
- hv := extract_hotpatch_ver(ast_b(annotation));
- if hv >= 0 { hotpatch_ver = hv; } else { hotpatch_ver = 1; }
- }
- }
- } else if k == EXPR_AT {
- name_ni := ast_a(annotation);
- name := istr_get(name_ni);
- if str_eq(name, "hotpatch") != 0 {
- hotpatch_ver = 1;
- }
- }
- g_ast_count = saved_ast;
- }
- }
-
- ip : ., mut = 0;
- if check(T_PUB) { ip = 1; advance_tok(); }
+ if tok_k(cur_tok()) != T_LPAREN:
+ add_error("expected (")
+ return -1
+ advance_tok()
+ if tok_k(cur_tok()) != T_STRING:
+ add_error("expected string literal for FFI language")
+ return -1
+ lang_ni := str_intern(tok_lx(cur_tok()))
+ advance_tok()
+ if tok_k(cur_tok()) != T_RPAREN:
+ add_error("expected )")
+ return -1
+ advance_tok()
+ return lang_ni
+
+fn parse_declaration():
+ hotpatch_ver : ., mut = 0
+ lead_ffi_ni : ., mut = -1
+
+ // ── v4 文档 §13:顶层声明可带**前导 `@` 注解**(一至多条,各自独占一行)──
+ // 文档里**声明前导**的形共四个(§13 全量扫描,见本次交付的清单):
+ // §13.5 `@ffi("Python")` / `@ffi("Java")` ← 前导 `extern fn`
+ // §13.6 `@hotpatch(ver=1)` / `@hotpatch(ver=2)` ← 前导 `fn`
+ // §13.7 `@preferredDomain(gpu)` ← 前导 `fn`
+ // §13.7 `@executionDomain(fpgaA)` ← 前导 `flow`
+ // 本循环 = **一至多条**(`skip_newlines()` 使「注解独占一行」的文档形成立;
+ // 同行的旧形 `@hotpatch(ver=1) fn …`(`tests/suite/hotpatch_test.cr` 的用法)不受影响)。
+ // ⚠ 白名单**只收这四个**,其余名字在此位置**响亮报错**(V02)——「放宽 = 吞错」是静默面:
+ // `@hotpach(ver=1)` 这种笔误若不报,注解就被静默丢弃。§13.2/.3/.4 的
+ // `@inline`/`@section`/`@fast`/`@NoBoundsCheck`/`@addr`/`@sizeOf`… 在文档里
+ // **只作表达式/语句位**出现(语料同:`tests/suite/at_test.cr:46` 的 `@NoBoundsCheck`
+ // 是 region 内的语句,走 parse_stmt→parse_expr),**未**出现于声明前导位 ⇒ 不入白名单。
+ loop:
+ if !check(T_AT):
+ break
+ at_line := tok_ln(cur_tok())
+ at_col := tok_cl(cur_tok())
+ saved_ast := g_ast_count
+ annotation := parse_expr()
+ k := ast_kind(annotation)
+ an_name_ni : ., mut = -1
+ an_args : ., mut = -1
+ if k == EXPR_CALL:
+ callee := ast_a(annotation)
+ if ast_kind(callee) == EXPR_AT:
+ an_name_ni = ast_a(callee)
+ an_args = ast_b(annotation)
+ else if k == EXPR_AT:
+ an_name_ni = ast_a(annotation)
+ an_name : ., mut = ""
+ if an_name_ni >= 0:
+ an_name = istr_get(an_name_ni)
+ // 已知/未知用**标志位**汇合(不用「空 else-if 分支」——region 内无语句在 v4 不可表达,T0 §10.2)。
+ known : ., mut = 0
+ if str_eq(an_name, "hotpatch") != 0:
+ known = 1
+ hv := extract_hotpatch_ver(an_args)
+ if hv >= 0:
+ hotpatch_ver = hv
+ else:
+ hotpatch_ver = 1
+ else if str_eq(an_name, "ffi") != 0:
+ known = 1
+ // §13.5:`@ffi("lang")` 前导 `extern fn` —— 语言名从**位置实参**取(第一个字符串)
+ if an_args >= 0 && ast_kind(an_args) == EXPR_ARG:
+ s := ast_a(an_args)
+ if s >= 0 && ast_kind(s) == EXPR_STRING:
+ lead_ffi_ni = ast_int_val(s)
+ else if str_eq(an_name, "preferredDomain") != 0:
+ known = 1
+ else if str_eq(an_name, "executionDomain") != 0:
+ known = 1
+ if known == 0:
+ check_error(EC_V_BAD_TAG,
+ "Unknown top-level '@" + an_name + "' annotation (expected '@hotpatch' / '@ffi' / '@preferredDomain' / '@executionDomain')",
+ at_line, at_col)
+ g_ast_count = saved_ast
+ skip_newlines()
+
+ ip : ., mut = 0
+ if check(T_PUB):
+ ip = 1
+ advance_tok()
// extern fn declaration (FFI)
- if check(T_EXTERN) {
- t := cur_tok();
- advance_tok();
- ffi_lang_ni : ., mut = -1;
- // Check for @ffi("...")
- if check(T_AT) {
- ffi_lang_ni = parse_ffi_annotation();
- }
+ if check(T_EXTERN):
+ t := cur_tok()
+ advance_tok()
+ ffi_lang_ni : ., mut = lead_ffi_ni // 前导 `@ffi("…")`(§13.5 文档形)
+ // 兼容旧形(注解夹在 `extern` 与 `fn` 之间)
+ if check(T_AT):
+ ffi_lang_ni = parse_ffi_annotation()
// Expect fn keyword
- if tok_k(cur_tok()) != T_FN {
- add_error("expected 'fn' after extern");
- return;
- }
- advance_tok();
+ if tok_k(cur_tok()) != T_FN:
+ add_error("expected 'fn' after extern")
+ return
+ advance_tok()
// Parse function name
- nt := advance_tok();
- name := tok_lx(nt);
- fn_name_ni := str_intern(name);
+ nt := advance_tok()
+ name := tok_lx(nt)
+ fn_name_ni := str_intern(name)
// Parse param list: (name: type, ...)
- advance_tok(); // (
- first_param : ., mut = -1;
- param_count : ., mut = 0;
+ advance_tok() // (
+ first_param : ., mut = -1
+ param_count : ., mut = 0
// 批 8(静默面收口 · 条目 3):C ABI 无可选表示 ⇒ extern 声明的**形参/返回不得为可选**
// (修复前 checker 对 extern 声明整段早退(`checker.cr` EXPR_EXTERN 分支)⇒ `extern fn e(x: int?)`
// check=0/build=0、运行期垃圾值;两条早退路径都不报)。判据 = rc=1 + 定位 + 零产物(P024);
// **非可选 extern 不受影响**(判据 ②,守卫档 = test_iface_ops.py / ffi_test.cr / p_ffi2.cr)。
- extern_opt : ., mut = 0;
- if !check(T_RPAREN) {
- loop {
- pt := advance_tok();
- pn := str_intern(tok_lx(pt));
- advance_tok(); // :
- pty := parse_type();
- if pty >= 0 && ast_kind(pty) == EXPR_OPTIONAL { extern_opt = 1; }
- if first_param < 0 { first_param = g_ast_count; }
- alloc_node(EXPR_PARAM, pn, 0, 0, 0, unpack_type(pty), pty, tok_ln(pt), tok_cl(pt));
- param_count = param_count + 1;
- if !check(T_COMMA) { break; }
- advance_tok();
- }
- }
- advance_tok(); // )
+ extern_opt : ., mut = 0
+ if !check(T_RPAREN):
+ loop:
+ pt := advance_tok()
+ pn := str_intern(tok_lx(pt))
+ advance_tok() // :
+ pty := parse_type()
+ if pty >= 0 && ast_kind(pty) == EXPR_OPTIONAL:
+ extern_opt = 1
+ if first_param < 0:
+ first_param = g_ast_count
+ alloc_node(EXPR_PARAM, pn, 0, 0, 0, unpack_type(pty), pty, tok_ln(pt), tok_cl(pt))
+ param_count = param_count + 1
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ advance_tok() // )
// Parse return type (optional, defaults to unit)
- ret_type : ., mut = TY_UNIT;
- if check(T_ARROW) {
- advance_tok();
- ret_node := parse_type();
- if ret_node >= 0 && ast_kind(ret_node) == EXPR_OPTIONAL { extern_opt = 1; }
- ret_type = unpack_type(ret_node);
- }
- if extern_opt != 0 {
- check_error(EC_P_EXTERN_OPTIONAL, "extern declaration cannot use optional type ('?') - no C ABI representation", tok_ln(t), tok_cl(t));
- }
+ ret_type : ., mut = TY_UNIT
+ if check(T_ARROW):
+ advance_tok()
+ ret_node := parse_type()
+ if ret_node >= 0 && ast_kind(ret_node) == EXPR_OPTIONAL:
+ extern_opt = 1
+ ret_type = unpack_type(ret_node)
+ if extern_opt != 0:
+ check_error(EC_P_EXTERN_OPTIONAL, "extern declaration cannot use optional type ('?') - no C ABI representation", tok_ln(t), tok_cl(t))
// Create EXPR_EXTERN node (no body)
- node : ., mut = alloc_node(EXPR_EXTERN, fn_name_ni, first_param, param_count, 0, ret_type, ffi_lang_ni, tok_ln(t), tok_cl(t));
- // Consume semicolon
- if check(T_SEMI) { advance_tok(); }
- return;
- }
-
- // fn / flow fn
- if check(T_FN) || check(T_FLOW) {
- is_flow : ., mut = 0;
+ node : ., mut = alloc_node(EXPR_EXTERN, fn_name_ni, first_param, param_count, 0, ret_type, ffi_lang_ni, tok_ln(t), tok_cl(t))
+ // v4(T0 布局规格 §6.2 B2):extern 声明末的可选 `;` 退场 ⇒ 收尾 = 行边界。
+ end_decl()
+ return
+
+ // fn / flow
+ if check(T_FN) || check(T_FLOW):
+ is_flow : ., mut = 0
// F5c:`flow fn name()` 语法——修复前消费 T_FLOW 后直接 advance_tok()
// 把 T_FN 当函数名(name="fn"),flow 函数构造不可达(P01 乱报)。
- if check(T_FLOW) {
- is_flow = 1;
- advance_tok(); // 消费 'flow'
- if !check(T_FN) {
- add_error("expected 'fn' after flow");
- return;
- }
- }
- t := advance_tok();
- nt := advance_tok();
- name := tok_lx(nt);
- ni := str_intern(name);
- parse_body(name, ni, tok_ln(t), tok_cl(t), hotpatch_ver);
- if is_flow != 0 {
+ // v4 文档形(2026-10-11 裁:文档是目标语法 ⇒ 改实现):
+ // `docs/core-language-syntax_v4.md:1232` 逐字 `flow counter(start: int) -> int:`、
+ // `:1406` 逐字 `flow encode(input: Frame) -> Packet:` —— **无 `fn`**。
+ // ⇒ 两形都收:文档形 `flow name(...)`(主),旧形 `flow fn name(...)`(**兼容**,
+ // 语料 `purity_selftest.cr:231` 用它;文档不写它、也不为它新增用例)。
+ // ⚠ 修前此处是 `if !check(T_FN): add_error(...); return` —— 该 `add_error` **不带码**,
+ // 而 `run_frontend` 先在 `g_diag_count > 0` 处 `return 1`(main.cr:133-137),
+ // ⇒ 这条理由**永不落到用户眼前**,用户只看到后续的 P25 串(实测 grep 命中 0)。
+ // 改动后该分支不存在,问题随之消失(记录在案:那是一次「诊断没到眼前」)。
+ t : ., mut = cur_tok()
+ if check(T_FLOW):
+ is_flow = 1
+ advance_tok() // 消费 'flow'
+ if check(T_FN):
+ t = advance_tok() // 兼容形:定位令牌取 `fn`
+ else:
+ advance_tok() // 消费 'fn'
+ nt := advance_tok()
+ name := tok_lx(nt)
+ ni := str_intern(name)
+ parse_body(name, ni, tok_ln(t), tok_cl(t), hotpatch_ver)
+
// Flow function — checker detects yield statements in body
// to skip return type check (yield != return)
- }
- return;
- }
+
+ return
// struct
- if check(T_STRUCT) {
- t := advance_tok();
- nt := advance_tok();
- name := tok_lx(nt);
- sg_names : string, mut; sg_names_cap : int, mut;
- sg_names = alloc(64 * 8); sg_names_cap = 64;
- sg_constrs : string, mut; sg_constrs_cap : int, mut;
- sg_constrs = alloc(64 * 8); sg_constrs_cap = 64;
- sg_count := parse_generics_into(sg_names, sg_constrs);
- advance_tok(); // {
-
- si := add_struct(name);
- if si >= 0 {
- if sg_count > 0 {
- w64(g_structs, si * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT, sg_count);
- sgi : ., mut = 0;
- loop {
- if sgi >= sg_count { break; }
- unsafe { w64(g_structs, si * ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES + sgi * 8, str_intern(@str_of(r64(sg_names, sgi * 8)))); }
- sgi = sgi + 1;
- }
+ if check(T_STRUCT):
+ t := advance_tok()
+ nt := advance_tok()
+ name := tok_lx(nt)
+ sg_names : string, mut
+ sg_names_cap : int, mut
+ sg_names = alloc(64 * 8)
+ sg_names_cap = 64
+ sg_constrs : string, mut
+ sg_constrs_cap : int, mut
+ sg_constrs = alloc(64 * 8)
+ sg_constrs_cap = 64
+ sg_count := parse_generics_into(sg_names, sg_constrs)
+ has_items := expect_region_head() // 0 = 空 region(如 `struct S:` 后无可达更深的行)
+
+ si := add_struct(name)
+ if si >= 0:
+ if sg_count > 0:
+ w64(g_structs, si * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT, sg_count)
+ sgi : ., mut = 0
+ loop:
+ if sgi >= sg_count:
+ break
+ unsafe:
+ w64(g_structs, si * ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES + sgi * 8, str_intern(@str_of(r64(sg_names, sgi * 8))))
+ sgi = sgi + 1
// R2 P3 Task 5(Step 2):约束**不再丢弃**(旧态 = 写进 dummy 缓冲后随作用域
// 消失 ⇒ `struct Box[T: I]` 静默无约束)。登记到 struct 侧表,实例化点
// (res_type_node 的 EXPR_GENERIC_APPLY 分支)消费。
- save_struct_gen_constrs(si, sg_constrs, sg_count);
- }
- fc : ., mut = 0;
- loop {
- if check(T_RBRACE) || check(T_EOF) { break; }
- ft := advance_tok();
- fn2 := tok_lx(ft);
- fni := str_intern(fn2);
+ save_struct_gen_constrs(si, sg_constrs, sg_count)
+ fc : ., mut = 0
+ loop:
+ if has_items == 0:
+ break
+ skip_newlines()
+ if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF:
+ break
+ ft := advance_tok()
+ fn2 := tok_lx(ft)
+ fni := str_intern(fn2)
// 容量批 T3(裁-CAP-2 (a)):字段**无硬上限**(侧表;第 17 字段起照常写入)
// ⇒ 旧 P023 闸与槽上限分支一并删除(不再存在越界写对象)。
- si_set_field_name(si, fc, fni);
- advance_tok();
- fty := parse_type();
- si_set_field_type(si, fc, unpack_type(fty));
- si_set_field_type_node(si, fc, fty);
- fc = fc + 1;
- if check(T_COMMA) { advance_tok(); }
- }
- w64(g_structs, si * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, fc);
- si_commit_fields(si, fc); // 提交字段区(高水位 = base + fc)
- }
- advance_tok();
- return;
- }
+ si_set_field_name(si, fc, fni)
+ if check(T_COLON_DECL):
+ advance_tok()
+ else:
+ add_error("expected ':' after struct field name")
+ fty := parse_type()
+ si_set_field_type(si, fc, unpack_type(fty))
+ si_set_field_type_node(si, fc, fty)
+ fc = fc + 1
+ if check(T_COMMA):
+ advance_tok()
+ w64(g_structs, si * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, fc)
+ si_commit_fields(si, fc) // 提交字段区(高水位 = base + fc)
+ if has_items != 0:
+ close_region()
+ return
// enum
- if check(T_ENUM) {
- t := advance_tok();
- nt := advance_tok();
- name := tok_lx(nt);
- eg_names : string, mut; eg_names_cap : int, mut;
- eg_names = alloc(64 * 8); eg_names_cap = 64;
- eg_constrs : string, mut; eg_constrs_cap : int, mut;
- eg_constrs = alloc(64 * 8); eg_constrs_cap = 64;
- eg_count := parse_generics_into(eg_names, eg_constrs);
- advance_tok();
-
- ei := add_enum(name);
- if ei >= 0 {
- if eg_count > 0 {
- w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, eg_count);
- egi : ., mut = 0;
- loop {
- if egi >= eg_count { break; }
- unsafe { w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES + egi * 8, str_intern(@str_of(r64(eg_names, egi * 8)))); }
- egi = egi + 1;
- }
+ if check(T_ENUM):
+ t := advance_tok()
+ nt := advance_tok()
+ name := tok_lx(nt)
+ eg_names : string, mut
+ eg_names_cap : int, mut
+ eg_names = alloc(64 * 8)
+ eg_names_cap = 64
+ eg_constrs : string, mut
+ eg_constrs_cap : int, mut
+ eg_constrs = alloc(64 * 8)
+ eg_constrs_cap = 64
+ eg_count := parse_generics_into(eg_names, eg_constrs)
+ has_items := expect_region_head() // 0 = 空 region
+
+ ei := add_enum(name)
+ if ei >= 0:
+ if eg_count > 0:
+ w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, eg_count)
+ egi : ., mut = 0
+ loop:
+ if egi >= eg_count:
+ break
+ unsafe:
+ w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES + egi * 8, str_intern(@str_of(r64(eg_names, egi * 8))))
+ egi = egi + 1
// R2 P3 Task 5(Step 2):同 struct 分支——枚举泛型约束登记(旧态同款丢弃)
- save_enum_gen_constrs(ei, eg_constrs, eg_count);
- }
- vc : ., mut = 0;
- loop {
- if check(T_RBRACE) || check(T_EOF) { break; }
- vt := advance_tok();
- vname := tok_lx(vt);
- vni := str_intern(vname);
+ save_enum_gen_constrs(ei, eg_constrs, eg_count)
+ vc : ., mut = 0
+ loop:
+ if has_items == 0:
+ break
+ skip_newlines()
+ if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF:
+ break
+ vt := advance_tok()
+ vname := tok_lx(vt)
+ vni := str_intern(vname)
// 容量批 T3(裁-CAP-2 (a)):变体**无硬上限**(侧表)⇒ 旧 P022 闸与槽上限
// 分支一并删除(不再存在越界写对象)
- ei_set_variant_name(ei, vc, vni);
- tc : ., mut = 0;
- if check(T_LPAREN) {
- advance_tok();
- loop {
- if check(T_RPAREN) { break; }
- fty := parse_type();
- ei_set_variant_type(ei, vc, tc, unpack_type(fty));
+ ei_set_variant_name(ei, vc, vni)
+ tc : ., mut = 0
+ if check(T_LPAREN):
+ advance_tok()
+ loop:
+ if check(T_RPAREN):
+ break
+ fty := parse_type()
+ ei_set_variant_type(ei, vc, tc, unpack_type(fty))
// R2 P3 Task 4(T0 交接 ①):载荷类型**节点**随裸码同写(照 struct 的
// OFF_SI_FIELD_TYPE_NODES 先例)——裸码把非基型载荷塌缩成 0 = TY_INT,
// 节点是载荷面(泛型形参代入 / 满足判定)的唯一忠实来源。
- ei_set_variant_type_node(ei, vc, tc, fty);
- tc = tc + 1;
- if !check(T_COMMA) { break; }
- advance_tok();
- }
- advance_tok();
- }
- ei_set_variant_type_count(ei, vc, tc);
- vc = vc + 1;
- if check(T_COMMA) { advance_tok(); }
- }
- w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, vc);
- ei_commit_variants(ei, vc); // 提交变体区(高水位 = base + vc)
- }
- advance_tok();
- return;
- }
+ ei_set_variant_type_node(ei, vc, tc, fty)
+ tc = tc + 1
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ advance_tok()
+ ei_set_variant_type_count(ei, vc, tc)
+ vc = vc + 1
+ if check(T_COMMA):
+ advance_tok()
+ w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, vc)
+ ei_commit_variants(ei, vc) // 提交变体区(高水位 = base + vc)
+ if has_items != 0:
+ close_region()
+ return
// interface declaration
- if check(T_INTERFACE) {
- t := advance_tok();
- nt := advance_tok();
- iface_name := tok_lx(nt);
- iface_ni := str_intern(iface_name);
- ig_names : string, mut; ig_names_cap : int, mut;
- ig_names = alloc(64 * 8); ig_names_cap = 64;
- ig_dummy : string, mut; ig_dummy_cap : int, mut;
- ig_dummy = alloc(64 * 8); ig_dummy_cap = 64;
- ig_count := parse_generics_into(ig_names, ig_dummy);
- advance_tok(); // {
+ if check(T_INTERFACE):
+ t := advance_tok()
+ nt := advance_tok()
+ iface_name := tok_lx(nt)
+ iface_ni := str_intern(iface_name)
+ ig_names : string, mut
+ ig_names_cap : int, mut
+ ig_names = alloc(64 * 8)
+ ig_names_cap = 64
+ ig_dummy : string, mut
+ ig_dummy_cap : int, mut
+ ig_dummy = alloc(64 * 8)
+ ig_dummy_cap = 64
+ ig_count := parse_generics_into(ig_names, ig_dummy)
+ has_items := expect_region_head() // 0 = 空 region ⇒ **零方法接口**(合法且有意义)
// Allocate interface entry
- grow_ifaces(g_iface_count + 1);
- iface_base := g_iface_count * ESZ_IFACEINFO;
+ grow_ifaces(g_iface_count + 1)
+ iface_base := g_iface_count * ESZ_IFACEINFO
// Zero it out
- zi : ., mut = 0;
- loop { if zi >= ESZ_IFACEINFO { break; } w8(g_ifaces, iface_base + zi, 0); zi = zi + 1; }
- w64(g_ifaces, iface_base + OFF_IF_NAME, iface_ni);
- w64(g_ifaces, iface_base + OFF_IF_GENERIC_COUNT, ig_count);
- method_count : ., mut = 0;
-
- loop {
- if check(T_RBRACE) || check(T_EOF) { break; }
- if check(T_FN) {
- advance_tok(); // fn
- mt := advance_tok(); // method name
- method_ni := str_intern(tok_lx(mt));
- advance_tok(); // (
+ zi : ., mut = 0
+ loop:
+ if zi >= ESZ_IFACEINFO:
+ break
+ w8(g_ifaces, iface_base + zi, 0)
+ zi = zi + 1
+ w64(g_ifaces, iface_base + OFF_IF_NAME, iface_ni)
+ w64(g_ifaces, iface_base + OFF_IF_GENERIC_COUNT, ig_count)
+ method_count : ., mut = 0
+
+ loop:
+ if has_items == 0:
+ break
+ skip_newlines()
+ if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF:
+ break
+ if check(T_FN):
+ advance_tok() // fn
+ mt := advance_tok() // method name
+ method_ni := str_intern(tok_lx(mt))
+ advance_tok() // (
// Parse params with types (handle self, &self, &mut self, name: Type)
- pc : ., mut = 0;
- param_tis : string, mut; param_tis_cap : int, mut;
- param_tis = alloc(128 * 8); param_tis_cap = 128;
- pi2 : ., mut = 0;
- loop { if pi2 >= 8 { break; } w64(param_tis, pi2 * 8, TY_UNIT); pi2 = pi2 + 1; }
+ pc : ., mut = 0
+ param_tis : string, mut
+ param_tis_cap : int, mut
+ param_tis = alloc(128 * 8)
+ param_tis_cap = 128
+ pi2 : ., mut = 0
+ loop:
+ if pi2 >= 8:
+ break
+ w64(param_tis, pi2 * 8, TY_UNIT)
+ pi2 = pi2 + 1
// R2 P3b Task 6(Step 1):签名**类型节点**槽(与裸码槽并行写,照 struct/enum
// 的 code+node 双写先例)。self 接收者槽恒无节点(两侧同约定,见 OFF_IFM_SELF_MODE)。
- param_nodes : string, mut; param_nodes_cap : int, mut;
- param_nodes = alloc(128 * 8); param_nodes_cap = 128;
- pni2 : ., mut = 0;
- loop { if pni2 >= 8 { break; } w64(param_nodes, pni2 * 8, -1); pni2 = pni2 + 1; }
- self_mode : ., mut = 0;
- if !check(T_RPAREN) {
- loop {
- fst := cur_tok();
+ param_nodes : string, mut
+ param_nodes_cap : int, mut
+ param_nodes = alloc(128 * 8)
+ param_nodes_cap = 128
+ pni2 : ., mut = 0
+ loop:
+ if pni2 >= 8:
+ break
+ w64(param_nodes, pni2 * 8, -1)
+ pni2 = pni2 + 1
+ self_mode : ., mut = 0
+ if !check(T_RPAREN):
+ loop:
+ fst := cur_tok()
// Handle &self / &mut self / self
- if tok_k(fst) == T_AMPERSAND || tok_k(fst) == T_SELF {
- self_mode_t : ., mut = 1; // self
- if tok_k(fst) == T_AMPERSAND {
- advance_tok(); // &
- self_mode_t = 2; // &self
- if check(T_MUT) { advance_tok(); self_mode_t = 3; } // &mut self
- }
- nt2 := advance_tok(); // self
- if pc < 8 { w64(param_tis, pc * 8, 0); } // match function's default for &self
- if pc == 0 { self_mode = self_mode_t; } // 首参 = 接收者才记模式
- pc = pc + 1;
- } else {
- advance_tok(); // param name
- advance_tok(); // :
- ptype := parse_type();
- if pc < 8 {
- w64(param_tis, pc * 8, unpack_type(ptype));
- w64(param_nodes, pc * 8, ptype);
- }
- pc = pc + 1;
- }
- if !check(T_COMMA) { break; }
- advance_tok();
- }
- }
- advance_tok(); // )
+ if tok_k(fst) == T_AMPERSAND || tok_k(fst) == T_SELF:
+ self_mode_t : ., mut = 1 // self
+ if tok_k(fst) == T_AMPERSAND:
+ advance_tok() // &
+ self_mode_t = 2 // &self
+ if check(T_MUT):
+ advance_tok()
+ self_mode_t = 3
+ // &mut self
+ nt2 := advance_tok() // self
+ if pc < 8:
+ w64(param_tis, pc * 8, 0)
+ // match function's default for &self
+ if pc == 0:
+ self_mode = self_mode_t
+ // 首参 = 接收者才记模式
+ pc = pc + 1
+ else:
+ advance_tok() // param name
+ advance_tok() // :
+ ptype := parse_type()
+ if pc < 8:
+ w64(param_tis, pc * 8, unpack_type(ptype))
+ w64(param_nodes, pc * 8, ptype)
+ pc = pc + 1
+ if !check(T_COMMA):
+ break
+ advance_tok()
+ advance_tok() // )
// Parse return type
- ret_ti : ., mut = TY_UNIT;
- ret_node : ., mut = -1;
- if check(T_ARROW) {
- advance_tok();
- rn2 := parse_type();
- ret_node = rn2;
- ret_ti = unpack_type(rn2);
- }
- advance_tok(); // ;
+ ret_ti : ., mut = TY_UNIT
+ ret_node : ., mut = -1
+ if check(T_ARROW):
+ advance_tok()
+ rn2 := parse_type()
+ ret_node = rn2
+ ret_ti = unpack_type(rn2)
+ // D11(T0 布局规格 §2.2):接口方法**无体**、**无 `:`** ⇒ 收尾 = 行边界(原 `;`)。
+ end_decl()
// Store method in interface entry (with overflow checks)
// R2 P3b Task 6(Step 1):上限**显式登记保留**(单源常量 MAX_IFACE_METHODS)——
// 超限 = 硬错 rc=1(非静默截断),解除面(侧表迁移)见 dyn_arr.cr 常量注。
- if method_count >= MAX_IFACE_METHODS {
- grow_diags(g_diag_count + 1);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_P_FIELD_SYNTAX);
- store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "interface '" + iface_name + "' exceeds max 16 methods");
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, tok_ln(t)); w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, tok_cl(t));
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(tok_ln(t)));
- g_diag_count = g_diag_count + 1;
- } else {
- mbase := iface_base + OFF_IF_METHODS + method_count * ESZ_IFMETHOD;
- w64(g_ifaces, mbase + OFF_IFM_NAME, method_ni);
- w64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT, pc);
- w64(g_ifaces, mbase + OFF_IFM_RET_TI, ret_ti);
- w64(g_ifaces, mbase + OFF_IFM_RET_NODE, ret_node);
- w64(g_ifaces, mbase + OFF_IFM_SELF_MODE, self_mode);
- pj : ., mut = 0;
- loop { if pj >= 8 || pj >= pc { break; }
- w64(g_ifaces, mbase + OFF_IFM_PARAM_TYPES + pj * 8, r64(param_tis, pj * 8));
- w64(g_ifaces, mbase + OFF_IFM_PARAM_NODES + pj * 8, r64(param_nodes, pj * 8));
- pj = pj + 1; }
- if pc > 8 {
- grow_diags(g_diag_count + 1);
- w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_P_PARAM_TYPE);
- store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "method '" + istr_get(method_ni) + "' in interface exceeds max 8 params");
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, tok_ln(t)); w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, tok_cl(t));
- w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(tok_ln(t)));
- g_diag_count = g_diag_count + 1;
- }
- }
- method_count = method_count + 1;
- } else { advance_tok(); }
- }
- w64(g_ifaces, iface_base + OFF_IF_METHOD_COUNT, method_count);
- g_iface_count = g_iface_count + 1;
- advance_tok(); // }
- return;
- }
-
- // impl block (impl Type { ... } or impl Interface for Type { ... })
- if check(T_IMPL) {
- t := advance_tok();
- first_nt := advance_tok();
- first_name := tok_lx(first_nt);
- first_ni := str_intern(first_name);
- trait_ni : ., mut = -1;
- type_ni : ., mut = first_ni;
- type_name : ., mut = first_name;
- if check(T_FOR) {
- advance_tok();
- trait_ni = first_ni;
- type_nt := advance_tok();
- type_name = tok_lx(type_nt);
- type_ni = str_intern(type_name);
- }
- advance_tok(); // {
- loop {
- if check(T_RBRACE) || check(T_EOF) { break; }
- if check(T_FN) {
- ft := advance_tok();
- method_nt := advance_tok();
- method_name := tok_lx(method_nt);
- method_ni := str_intern(method_name);
- mangled := type_name + "." + method_name;
- mangled_ni := str_intern(mangled);
- parse_body(mangled, mangled_ni, tok_ln(ft), tok_cl(ft), 0);
+ if method_count >= MAX_IFACE_METHODS:
+ grow_diags(g_diag_count + 1)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_P_FIELD_SYNTAX)
+ store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "interface '" + iface_name + "' exceeds max 16 methods")
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, tok_ln(t))
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, tok_cl(t))
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(tok_ln(t)))
+ g_diag_count = g_diag_count + 1
+ else:
+ mbase := iface_base + OFF_IF_METHODS + method_count * ESZ_IFMETHOD
+ w64(g_ifaces, mbase + OFF_IFM_NAME, method_ni)
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT, pc)
+ w64(g_ifaces, mbase + OFF_IFM_RET_TI, ret_ti)
+ w64(g_ifaces, mbase + OFF_IFM_RET_NODE, ret_node)
+ w64(g_ifaces, mbase + OFF_IFM_SELF_MODE, self_mode)
+ pj : ., mut = 0
+ loop:
+ if pj >= 8 || pj >= pc:
+ break
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_TYPES + pj * 8, r64(param_tis, pj * 8))
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_NODES + pj * 8, r64(param_nodes, pj * 8))
+ pj = pj + 1
+ if pc > 8:
+ grow_diags(g_diag_count + 1)
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE, EC_P_PARAM_TYPE)
+ store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, "method '" + istr_get(method_ni) + "' in interface exceeds max 8 params")
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 16, tok_ln(t))
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 24, tok_cl(t))
+ w64(g_diags, g_diag_count * DIAG_REC_SIZE + 32, diag_fileid_for_line(tok_ln(t)))
+ g_diag_count = g_diag_count + 1
+ method_count = method_count + 1
+ else:
+ advance_tok()
+ w64(g_ifaces, iface_base + OFF_IF_METHOD_COUNT, method_count)
+ g_iface_count = g_iface_count + 1
+ if has_items != 0:
+ close_region()
+ return
+
+ // impl block (impl Type: ... or impl Interface for Type: ...)
+ if check(T_IMPL):
+ t := advance_tok()
+ first_nt := advance_tok()
+ first_name := tok_lx(first_nt)
+ first_ni := str_intern(first_name)
+ trait_ni : ., mut = -1
+ type_ni : ., mut = first_ni
+ type_name : ., mut = first_name
+ if check(T_FOR):
+ advance_tok()
+ trait_ni = first_ni
+ type_nt := advance_tok()
+ type_name = tok_lx(type_nt)
+ type_ni = str_intern(type_name)
+ has_items := expect_region_head() // 0 = 空 region
+ loop:
+ if has_items == 0:
+ break
+ skip_newlines()
+ if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF:
+ break
+ if check(T_FN):
+ ft := advance_tok()
+ method_nt := advance_tok()
+ method_name := tok_lx(method_nt)
+ method_ni := str_intern(method_name)
+ mangled := type_name + "." + method_name
+ mangled_ni := str_intern(mangled)
+ parse_body(mangled, mangled_ni, tok_ln(ft), tok_cl(ft), 0)
// Register in method lookup table
- grow_methods(g_method_count + 1);
- w64(g_methods, g_method_count * 24, type_ni);
- w64(g_methods, g_method_count * 24 + 8, method_ni);
- w64(g_methods, g_method_count * 24 + 16, mangled_ni);
- g_method_count = g_method_count + 1;
- } else {
- advance_tok();
- }
- }
- advance_tok(); // }
+ grow_methods(g_method_count + 1)
+ w64(g_methods, g_method_count * 24, type_ni)
+ w64(g_methods, g_method_count * 24 + 8, method_ni)
+ w64(g_methods, g_method_count * 24 + 16, mangled_ni)
+ g_method_count = g_method_count + 1
+ else:
+ advance_tok()
+ if has_items != 0:
+ close_region()
// Store impl-for relationship after processing all methods
- if trait_ni >= 0 {
- grow_impl_for(g_impl_for_count + 1);
- w64(g_impl_for, g_impl_for_count * 16, trait_ni);
- w64(g_impl_for, g_impl_for_count * 16 + 8, type_ni);
- g_impl_for_count = g_impl_for_count + 1;
- }
- return;
- }
+ if trait_ni >= 0:
+ grow_impl_for(g_impl_for_count + 1)
+ w64(g_impl_for, g_impl_for_count * 16, trait_ni)
+ w64(g_impl_for, g_impl_for_count * 16 + 8, type_ni)
+ g_impl_for_count = g_impl_for_count + 1
+ return
// type alias
- if check(T_TYPE) {
- advance_tok();
- nt := advance_tok();
- name_idx := str_intern(tok_lx(nt));
- advance_tok();
- type_node := parse_type();
- advance_tok(); // ;
- grow_type_aliases(g_type_alias_count + 1);
- w64(g_type_aliases, g_type_alias_count * 16, name_idx);
- w64(g_type_aliases, g_type_alias_count * 16 + 8, type_node);
- g_type_alias_count = g_type_alias_count + 1;
- return;
- }
+ if check(T_TYPE):
+ advance_tok()
+ nt := advance_tok()
+ name_idx := str_intern(tok_lx(nt))
+ if check(T_EQ):
+ advance_tok()
+ else:
+ add_error("expected '=' in type alias")
+ type_node := parse_type()
+ end_decl()
+ grow_type_aliases(g_type_alias_count + 1)
+ w64(g_type_aliases, g_type_alias_count * 16, name_idx)
+ w64(g_type_aliases, g_type_alias_count * 16 + 8, type_node)
+ g_type_alias_count = g_type_alias_count + 1
+ return
// mod declaration: mod name; or mod path::name; or mod name { ... }
- if check(T_MOD) {
- t := advance_tok();
- nt := advance_tok();
- path_name := tok_lx(nt);
+ if check(T_MOD):
+ t := advance_tok()
+ nt := advance_tok()
+ path_name := tok_lx(nt)
// Collect full path: mod a::b::c;
- loop {
- if check(T_PATHSEP) {
- advance_tok();
- nt2 := advance_tok();
- path_name = path_name + "::" + tok_lx(nt2);
- } else { break; }
- }
- mod_ni := str_intern(path_name);
+ loop:
+ if check(T_PATHSEP):
+ advance_tok()
+ nt2 := advance_tok()
+ path_name = path_name + "::" + tok_lx(nt2)
+ else:
+ break
+ mod_ni := str_intern(path_name)
// Store mod path for checker registration
- grow_mod_paths(g_mod_path_count + 1);
- w64(g_mod_path_names, g_mod_path_count * 8, mod_ni);
- g_mod_path_count = g_mod_path_count + 1;
- if check(T_LBRACE) {
- // mod name { ... } — consume block contents
- push_scope();
- advance_tok();
- depth : ., mut = 1;
- loop {
- if depth <= 0 { break; }
- tk := advance_tok();
- if tok_k(tk) == T_RBRACE { depth = depth - 1; }
- else if tok_k(tk) == T_LBRACE { depth = depth + 1; }
- else if tok_k(tk) == T_EOF { break; }
- }
- } else {
- if check(T_SEMI) { advance_tok(); }
- }
- return;
- }
+ grow_mod_paths(g_mod_path_count + 1)
+ w64(g_mod_path_names, g_mod_path_count * 8, mod_ni)
+ g_mod_path_count = g_mod_path_count + 1
+ // v4:`mod path` 以行边界收尾;`mod path:` + region 形式**跳过**整段 region 内容。
+ if tok_k(cur_tok()) == T_COLON_BLOCK:
+ advance_tok()
+ skip_newlines()
+ else:
+ end_decl()
+ if tok_k(cur_tok()) == T_INDENT:
+ push_scope()
+ depth : ., mut = 1
+ advance_tok()
+ loop:
+ if depth <= 0:
+ break
+ tk := tok_k(cur_tok())
+ if tk == T_EOF:
+ break
+ if tk == T_DEDENT:
+ depth = depth - 1
+ else if tk == T_INDENT:
+ depth = depth + 1
+ advance_tok()
+ return
// import/fileid declarations are already skipped in parse_all() loop.
// If we reach here, the token was NOT T_IMPORT/T_FILEID.
// New syntax global variable declaration
- if check(T_IDENT) && is_new_var_decl() {
- node := parse_new_var_decl();
- grow_global_lets(g_global_let_count + 1);
- w64(g_global_lets, g_global_let_count * 8, node);
- g_global_let_count = g_global_let_count + 1;
+ if check(T_IDENT) && is_new_var_decl():
+ node := parse_new_var_decl()
+ grow_global_lets(g_global_let_count + 1)
+ w64(g_global_lets, g_global_let_count * 8, node)
+ g_global_let_count = g_global_let_count + 1
// Drain batch extras to globals
- _drained : ., mut = 0;
- loop {
- if g_extra_let_count <= 0 { break; }
- g_extra_let_count = g_extra_let_count - 1;
- grow_global_lets(g_global_let_count + 1);
- w64(g_global_lets, g_global_let_count * 8, r64(g_extra_lets, g_extra_let_count * 8));
- g_global_let_count = g_global_let_count + 1;
- _drained = _drained + 1;
- }
- return;
- }
+ _drained : ., mut = 0
+ loop:
+ if g_extra_let_count <= 0:
+ break
+ g_extra_let_count = g_extra_let_count - 1
+ grow_global_lets(g_global_let_count + 1)
+ w64(g_global_lets, g_global_let_count * 8, r64(g_extra_lets, g_extra_let_count * 8))
+ g_global_let_count = g_global_let_count + 1
+ _drained = _drained + 1
+ end_decl() // v4:全局声明以行边界收尾(原可选 `;` 退场)
+ return
// 批 6(T2):`#` 出现在**非标注位置**(声明之前 / body 之后 / 顶层任意处)⇒ **响亮拒绝**。
// 本仓的顶层兜底 = 下方 `advance_tok()`(**静默丢弃一个 token、不报错**)——`#` 走它
// 就会被逐 token 吞净(T2 首轮实测:`#check(1>0) fn f()…` 与 `… } #check(1>0)` 均 rc=0 +
// 产物照出)。这与 T0 §10.2 的静默误编译**同源**(`#` 被静默丢弃),必须此点转响亮。
// 合法位置**唯一** = 签名与 body 之间(parse_spec_annotations,spec-design §四)。
- if check(T_HASH) {
+ if check(T_HASH):
check_error(EC_V_BAD_TAG,
"'#' annotation is only allowed between the function signature and its body",
- tok_ln(cur_tok()), tok_cl(cur_tok()));
- advance_tok(); // 吞掉 `#` 本身,避免 parse_all 空转;残余由后续解析按既有规则处理
- return;
- }
+ tok_ln(cur_tok()), tok_cl(cur_tok()))
+ advance_tok() // 吞掉 `#` 本身,避免 parse_all 空转;残余由后续解析按既有规则处理
+ return
// 批 8(静默面收口 · 条目 4):**顶层兜底不再静默吞 token**——修复前此处为裸 `advance_tok()`:
// 无法识别的顶层 token(typo 的 `stuct` / 多余 `}` / 游离 token)被**无声消费**,既不诊断也不定位;
// 紧随其后的声明会被误归(计划 §1 条目 4 现象③「静默丢弃 ⇒ 后续 TF01 误报」与条目 6 同族)。
// 全语料实核(批 8 预备扫描;括号深度感知):179 档 `.cr` 顶层非法首 token = **0** ⇒ 零语料代价。
// 先例 = 批 6 T2 的 `#` 非标注位在同一兜底点转响亮(上方 `EC_V_BAD_TAG`)。
// EOF 不报(`parse_all` 已先判;此处仅为防御),且**必定推进**一个 token(错误恢复)。
- if tok_k(cur_tok()) != T_EOF {
+ if tok_k(cur_tok()) != T_EOF:
check_error(EC_P_TOPLEVEL_TOKEN,
"unexpected top-level token '" + tok_lx(cur_tok()) + "'",
- tok_ln(cur_tok()), tok_cl(cur_tok()));
- advance_tok();
- }
-}
-
-fn parse_all() {
- g_ast_count = 0;
- g_token_pos = 0;
- g_global_let_count = 0;
- g_global_lets_cap = 0;
- g_func_count = 0;
- g_struct_count = 0;
- g_enum_count = 0;
- g_type_alias_count = 0; g_type_alias_cap = 0;
- g_method_count = 0; g_method_cap = 0;
- g_loop_depth = 0; g_loop_stack_cap = 0;
- g_extra_let_count = 0;
- g_block_stmt_count = 0;
+ tok_ln(cur_tok()), tok_cl(cur_tok()))
+ advance_tok()
+
+fn parse_all():
+ g_ast_count = 0
+ g_token_pos = 0
+ g_global_let_count = 0
+ g_global_lets_cap = 0
+ g_func_count = 0
+ g_struct_count = 0
+ g_enum_count = 0
+ g_type_alias_count = 0
+ g_type_alias_cap = 0
+ g_method_count = 0
+ g_method_cap = 0
+ g_loop_depth = 0
+ g_loop_stack_cap = 0
+ g_extra_let_count = 0
+ g_block_stmt_count = 0
// 注意:不再清零 g_error_count——tokenize 阶段(词法守卫,如整数字面量
// 溢出)已用 add_error 累积错误;parse_all 清零会把它们一并吞掉,
// 造成「静默越界/静默环绕」类错误永远不报(run_frontend 在 parse_all
// 之后才检查 g_error_count)。parse 自身的语法错误继续 add_error 追加。
- g_mod_path_count = 0; g_mod_path_cap = 0;
- g_iface_count = 0; g_iface_cap = 0;
- g_impl_for_count = 0; g_impl_for_cap = 0;
- g_generic_constr_count = 0; g_generic_constr_cap = 0;
- g_gen_param_count = 0; g_gen_param_cap = 0;
-
- ci : ., mut = 0;
- loop {
- // Skip import/fileid tokens
- loop {
- tk := tok_k(cur_tok());
- if tk == T_EOF { return; }
- if tk != T_IMPORT && tk != T_FILEID { break; }
- is_fileid := tk == T_FILEID;
- advance_tok();
+ g_mod_path_count = 0
+ g_mod_path_cap = 0
+ g_iface_count = 0
+ g_iface_cap = 0
+ g_impl_for_count = 0
+ g_impl_for_cap = 0
+ g_generic_constr_count = 0
+ g_generic_constr_cap = 0
+ g_gen_param_count = 0
+ g_gen_param_cap = 0
+
+ g_want_value = 0
+ ci : ., mut = 0
+ loop:
+ // 顶层行边界(v4,T0 布局规格 §1):NEWLINE 是 no-op;DEDENT 出现在顶层 = 缩进失衡
+ // (lexer 的 layout_break 已报错),此处再给一重带位置的响亮信号,**不静默吞**。
+ // ⚠ 本跳过必须出现在**每次** import 消费之后(v4 的 import 声明以行边界收尾,`;` 已退场)
+ // ⇒ 故它同时是下面 import 循环的循环头(否则 import 之后残留的 NEWLINE 会直达
+ // `parse_declaration` 的顶层兜底 = 假 P25 硬错)。
+ loop:
+ skip_newlines()
+ tk := tok_k(cur_tok())
+ if tk == T_EOF:
+ return
+ if tk == T_DEDENT:
+ check_error(EC_P_TOPLEVEL, "unexpected dedent at top level",
+ tok_ln(cur_tok()), tok_cl(cur_tok()))
+ advance_tok()
+ continue
+ if tk != T_IMPORT && tk != T_FILEID:
+ break
+ is_fileid := tk == T_FILEID
+ advance_tok()
// 批 8(静默面收口 · 条目 4 前置):**消费整条 import 语句**。
// 修复前只吞 `import` 关键字本身,其后的路径/别名 token 落进 `parse_declaration` 尾部兜底被
// **静默吞**——全语料(含 `_import.cr` 与注入的运行时源)普遍如此 ⇒ 条目 4 的顶层硬错若
@@ -2171,30 +2665,35 @@ fn parse_all() {
// 形状与 `module.cr` res_imports 的扫描**逐字一致**:`[@proj] [a(::b)*] [: alias] [;]`。
// ⚠ **不得**放宽成「吞到分号」或「吞任意 IDENT」:那会把紧随其后的下一条声明头也吃掉
// (本轮实测:`import arena_globals` 后无分号 ⇒ 误吞 `g_rt_argc : int` ⇒ 余下 `mut` 触发 P25)。
- if check(T_AT) { advance_tok(); if check(T_IDENT) { advance_tok(); } }
- if check(T_IDENT) {
- advance_tok();
- loop {
- if check(T_PATHSEP) {
- advance_tok();
- if check(T_IDENT) { advance_tok(); }
- continue;
- }
- break;
- }
- }
- if check(T_COLON) { advance_tok(); if check(T_IDENT) { advance_tok(); } }
- if is_fileid && check(T_INT) { advance_tok(); }
- if check(T_SEMI) { advance_tok(); }
- }
- t_cur := cur_tok();
- t_kind := tok_k(t_cur);
- if t_kind == T_EOF { break; }
- if ci > 5 { ci = 0; }
- parse_declaration();
- if tok_k(cur_tok()) == T_EOF { break; }
- ci = ci + 1;
- }
+ if check(T_AT):
+ advance_tok()
+ if check(T_IDENT):
+ advance_tok()
+ if check(T_IDENT):
+ advance_tok()
+ loop:
+ if check(T_PATHSEP):
+ advance_tok()
+ if check(T_IDENT):
+ advance_tok()
+ continue
+ break
+ if check(T_COLON_DECL):
+ advance_tok()
+ if check(T_IDENT):
+ advance_tok()
+ if is_fileid && check(T_INT):
+ advance_tok()
+ // v4:import/fileid 声明末的可选 `;` 退场(T0 布局规格 §6.2 B4)⇒ 收尾 = 行边界。
+ t_cur := cur_tok()
+ t_kind := tok_k(t_cur)
+ if t_kind == T_EOF:
+ break
+ if ci > 5:
+ ci = 0
+ parse_declaration()
+ if tok_k(cur_tok()) == T_EOF:
+ break
+ ci = ci + 1
// 插值洞表达式统一解析(token 流已用毕 ⇒ 可安全重新 tokenize;见 interp_parse_holes)
- interp_parse_holes();
-}
+ interp_parse_holes()
diff --git a/src/compiler/pass.cr b/src/compiler/pass.cr
index d8941493..d514ce98 100644
--- a/src/compiler/pass.cr
+++ b/src/compiler/pass.cr
@@ -9,16 +9,13 @@
// 数组访问前 — 由 ir_gen 在每次 IR_LOAD/STORE_INDEX 前调用
// 返回: 0=正常, 1=跳过此次访问
-fn pass_before_array_access(arr_var: int, idx_var: int, idx_lit: int, arr_len_lit: int) -> int {
- return ext_dispatch_array_access(arr_var, idx_var, idx_lit, arr_len_lit);
-}
+fn pass_before_array_access(arr_var: int, idx_var: int, idx_lit: int, arr_len_lit: int) -> int:
+ return ext_dispatch_array_access(arr_var, idx_var, idx_lit, arr_len_lit)
// 二元运算后 — 用于溢出检查
-fn pass_after_binary(op: int, lv: int, rv: int, result_var: int) -> int {
- return ext_dispatch_binary_op(op, lv, rv, result_var);
-}
+fn pass_after_binary(op: int, lv: int, rv: int, result_var: int) -> int:
+ return ext_dispatch_binary_op(op, lv, rv, result_var)
// 内置函数展开 — 由 .so/stdlib 插件注册
-fn dispatch_call(fn_ni: int, ac: int, arg_vars: string) -> int {
- return -1;
-}
+fn dispatch_call(fn_ni: int, ac: int, arg_vars: string) -> int:
+ return -1
diff --git a/src/compiler/project.cr b/src/compiler/project.cr
index 3f11598b..4026163f 100644
--- a/src/compiler/project.cr
+++ b/src/compiler/project.cr
@@ -4,53 +4,45 @@
// Depends on toml.cr for low-level key-value parsing.
// Set by load_project() — used by read_project_dir in main.cr
-g_project_source_dir : string, mut;
-g_project_name : string, mut;
+g_project_source_dir : string, mut
+g_project_name : string, mut
// Load project config. Returns main_source, sets g_project_source_dir as side effect.
-fn load_project(dir: string) -> string {
- sd : ., mut = "";
- toml_path : ., mut = dir;
- if str_eq(get_char(dir, str_len(dir) - 1), "/") != 0 {
- sd = dir;
- toml_path = dir + "Core.toml";
- } else {
- sd = dir + "/";
- toml_path = dir + "/Core.toml";
- }
+fn load_project(dir: string) -> string:
+ sd : ., mut = ""
+ toml_path : ., mut = dir
+ if str_eq(get_char(dir, str_len(dir) - 1), "/") != 0:
+ sd = dir
+ toml_path = dir + "Core.toml"
+ else:
+ sd = dir + "/"
+ toml_path = dir + "/Core.toml"
- tc := read_file(toml_path);
- pname : ., mut = "";
- if str_len(tc) > 0 {
- pname = extract_toml_name(tc);
- }
+ tc := read_file(toml_path)
+ pname : ., mut = ""
+ if str_len(tc) > 0:
+ pname = extract_toml_name(tc)
- g_project_name = pname;
- if str_len(g_project_name) == 0 {
- fallback_name : ., mut = basename(dir);
- if str_eq(fallback_name, ".") != 0 {
- cwd := get_cwd();
- if str_len(cwd) > 0 { fallback_name = basename(cwd); }
- }
- if str_len(fallback_name) == 0 || str_eq(fallback_name, ".") != 0 ||
- str_eq(fallback_name, "..") != 0 || str_eq(fallback_name, "/") != 0 {
- fallback_name = "a.out";
- }
- g_project_name = fallback_name;
- }
+ g_project_name = pname
+ if str_len(g_project_name) == 0:
+ fallback_name : ., mut = basename(dir)
+ if str_eq(fallback_name, ".") != 0:
+ cwd := get_cwd()
+ if str_len(cwd) > 0:
+ fallback_name = basename(cwd)
+ if str_len(fallback_name) == 0 || str_eq(fallback_name, ".") != 0 || str_eq(fallback_name, "..") != 0 || str_eq(fallback_name, "/") != 0:
+ fallback_name = "a.out"
+ g_project_name = fallback_name
- main_path : ., mut = sd + "main.cr";
- source := read_file(main_path);
+ main_path : ., mut = sd + "main.cr"
+ source := read_file(main_path)
- g_project_source_dir = sd;
- if str_len(pname) > 0 {
- print(" project: ");
- println(pname);
- }
- if str_len(source) > 0 {
- print(" main.cr: ");
- println(main_path);
- }
+ g_project_source_dir = sd
+ if str_len(pname) > 0:
+ print(" project: ")
+ println(pname)
+ if str_len(source) > 0:
+ print(" main.cr: ")
+ println(main_path)
- return source;
-}
+ return source
diff --git a/src/compiler/provenance_verify.cr b/src/compiler/provenance_verify.cr
index ab099aeb..e1bfdd28 100644
--- a/src/compiler/provenance_verify.cr
+++ b/src/compiler/provenance_verify.cr
@@ -3,67 +3,76 @@
// Runs after PointerAnalysis (ptr_analysis.cr) and RegionCheck (region_check.cr).
// Detects out-of-bounds pointer accesses at compile time.
-fn get_alloc_size(alloc_seq: int) -> int {
+fn get_alloc_size(alloc_seq: int) -> int:
// 修复 3:alloc_seq 是 pts 位号(第几个 alloc),经映射表查 DF 节点序号再算大小。
// 修复前直接当节点序号用 → 查到节点 0 → 恒返回 -1 → 运行时检查永不生成。
- if alloc_seq < 0 || alloc_seq >= g_pa_alloc_count { return -1; }
- an := r64(g_pa_alloc_nodes, alloc_seq * 8);
- op := r64(g_df_nodes, an * ESZ_DFNODE + OFF_DF_OPCODE);
- s1 := r64(g_df_nodes, an * ESZ_DFNODE + OFF_DF_S1);
- s3 := r64(g_df_nodes, an * ESZ_DFNODE + OFF_DF_S3);
+ if alloc_seq < 0 || alloc_seq >= g_pa_alloc_count:
+ return -1
+ an := r64(g_pa_alloc_nodes, alloc_seq * 8)
+ op := r64(g_df_nodes, an * ESZ_DFNODE + OFF_DF_OPCODE)
+ s1 := r64(g_df_nodes, an * ESZ_DFNODE + OFF_DF_S1)
+ s3 := r64(g_df_nodes, an * ESZ_DFNODE + OFF_DF_S3)
// 修复 12:IR_ALLOC(标量变量槽标记)不是堆分配——不返回 8(修复前把
// 变量槽当 8 字节堆块,误报/误取 size)
- if op == IR_ALLOC_ARRAY { return s1 * 8; } // count * 8(元素恒 8 字节,见 instr.cr IR_ALLOC_ARRAY)
- if op == IR_ALLOC_STRUCT {
+ if op == IR_ALLOC_ARRAY:
+ return s1 * 8
+ // count * 8(元素恒 8 字节,见 instr.cr IR_ALLOC_ARRAY)
+ if op == IR_ALLOC_STRUCT:
// 与 instr.cr IR_ALLOC_STRUCT 一致:fc * 8(field count × 8)
- fi : int = -1; si2 : ., mut = 0;
- loop { if si2 >= g_struct_count { break; }
- if si_name(si2) == s3 { fi = si2; break; }
- si2 = si2 + 1; }
- if fi >= 0 { return si_field_count(fi) * 8; }
- return 8;
- }
- return -1; // unknown (defer to runtime check)
-}
+ fi : int = -1
+ si2 : ., mut = 0
+ loop:
+ if si2 >= g_struct_count:
+ break
+ if si_name(si2) == s3:
+ fi = si2
+ break
+ si2 = si2 + 1
+ if fi >= 0:
+ return si_field_count(fi) * 8
+ return 8
+ return -1 // unknown (defer to runtime check)
-fn get_alloc_var(alloc_seq: int) -> int {
- if alloc_seq < 0 || alloc_seq >= g_pa_alloc_count { return -1; }
- an := r64(g_pa_alloc_nodes, alloc_seq * 8);
- return r64(g_df_nodes, an * ESZ_DFNODE + OFF_DF_DEST);
-}
+fn get_alloc_var(alloc_seq: int) -> int:
+ if alloc_seq < 0 || alloc_seq >= g_pa_alloc_count:
+ return -1
+ an := r64(g_pa_alloc_nodes, alloc_seq * 8)
+ return r64(g_df_nodes, an * ESZ_DFNODE + OFF_DF_DEST)
-fn pv_is_in_unsafe(node_seq: int) -> int {
- si : ., mut = 0;
- loop { if si >= g_sg_count { break; }
- kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND);
- if kind == SG_UNSAFE {
- nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART);
- ncount := r64(g_sgs, si * ESZ_SG + OFF_SG_NCOUNT);
- if node_seq >= nstart && node_seq < nstart + ncount {
- return 1;
- }
- }
- si = si + 1;
- }
- return 0;
-}
+fn pv_is_in_unsafe(node_seq: int) -> int:
+ si : ., mut = 0
+ loop:
+ if si >= g_sg_count:
+ break
+ kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND)
+ if kind == SG_UNSAFE:
+ nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART)
+ ncount := r64(g_sgs, si * ESZ_SG + OFF_SG_NCOUNT)
+ if node_seq >= nstart && node_seq < nstart + ncount:
+ return 1
+ si = si + 1
+ return 0
-fn provenance_verify_func(nstart: int, ncount: int) {
- ni : ., mut = nstart;
- loop { if ni >= nstart + ncount { break; }
- op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE);
- s1 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S1);
+fn provenance_verify_func(nstart: int, ncount: int):
+ ni : ., mut = nstart
+ loop:
+ if ni >= nstart + ncount:
+ break
+ op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE)
+ s1 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S1)
// R2 P5 Task 2(D19):本处读的是**访问宽度**(字节数)——单槽化前它住在混用
// tk 槽,现居**辅码**槽(OFF_DF_AUX)。值域/语义零变化(仅 IR_DEREF/IR_STORE_PTR
// 消费;两 op 均属辅码面)。读 40 槽(类型项引用)会把项行号当宽度 = 静默错值。
- width : ., mut = r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_AUX);
+ width : ., mut = r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_AUX)
- if (op == IR_DEREF || op == IR_STORE_PTR) && s1 >= 0 {
+ if (op == IR_DEREF || op == IR_STORE_PTR) && s1 >= 0:
// Skip checks in unsafe blocks
- if pv_is_in_unsafe(ni) != 0 { ni = ni + 1; continue; }
+ if pv_is_in_unsafe(ni) != 0:
+ ni = ni + 1
+ continue
- ptr_ti := irv_type(s1);
+ ptr_ti := irv_type(s1)
// ── S6 (b′) **登记「本处不适用」**(2026-09-20 维护者裁)——**不给它写 REF 谓词** ──
// **为什么不用改**:本门是**条件触发硬错**(`kind == TYP_PTR && extra != 0` ⇒ 报 EC_TU_DEREF),
// 而 `&x` 的型在改判前由 `checker.cr` 写死 `extra = 0` ⇒ **该门对 `&x` 从来就没生效过**,
@@ -77,81 +86,73 @@ fn provenance_verify_func(nstart: int, ncount: int) {
// `tests/selfhost/test_pointer_safety.py`(`:132`/`:142`/`:153`/`:165`),**全部是
// `as *T` 转换形,无一处用 `&x`** ⇒ 该门活覆盖 100% 在 cast 面。
// **反向钉**:naive 扩 ⇒ `&mut` 解引用假阳(见上,两处现成载体)。
- if ptr_ti >= 0 && get_type_kind(ptr_ti) == TYP_PTR && get_type_extra(ptr_ti) != 0 {
+ if ptr_ti >= 0 && get_type_kind(ptr_ti) == TYP_PTR && get_type_extra(ptr_ti) != 0:
check_error(EC_TU_DEREF,
"external pointer dereference requires unsafe",
- 0, 0);
- ni = ni + 1;
- continue;
- }
+ 0, 0)
+ ni = ni + 1
+ continue
- if width <= 0 { width = 8; }
+ if width <= 0:
+ width = 8
- pts := r64(g_pts, s1 * 8);
- off := r64(g_offsets, s1 * 8);
- runtime_targets : ., mut = 0;
- runtime_size : ., mut = 0;
- runtime_base : ., mut = -1;
+ pts := r64(g_pts, s1 * 8)
+ off := r64(g_offsets, s1 * 8)
+ runtime_targets : ., mut = 0
+ runtime_size : ., mut = 0
+ runtime_base : ., mut = -1
// Check each potential allocation target in the points-to set
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= 64 { break; }
- if (pts / mask) % 2 != 0 {
- alloc_size := get_alloc_size(bi);
- if alloc_size >= 0 && off >= 0 {
- if width > alloc_size || off > alloc_size - width {
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= 64:
+ break
+ if (pts / mask) % 2 != 0:
+ alloc_size := get_alloc_size(bi)
+ if alloc_size >= 0 && off >= 0:
+ if width > alloc_size || off > alloc_size - width:
check_error(EC_TK_INDEX,
"pointer out of bounds: offset " + int_str(off) +
" + width " + int_str(width) +
" > size " + int_str(alloc_size),
- 0, 0);
- }
- } else if alloc_size >= 0 {
- if width > alloc_size {
+ 0, 0)
+ else if alloc_size >= 0:
+ if width > alloc_size:
check_error(EC_TK_INDEX,
"pointer access width " + int_str(width) +
" exceeds allocation size " + int_str(alloc_size),
- 0, 0);
- } else {
- runtime_targets = runtime_targets + 1;
- runtime_size = alloc_size;
- runtime_base = get_alloc_var(bi);
- }
- } else {
+ 0, 0)
+ else:
+ runtime_targets = runtime_targets + 1
+ runtime_size = alloc_size
+ runtime_base = get_alloc_var(bi)
// 分配信息未知 → 不填充 s2/s3;编码器(instr.cr)对 s3=0
// 保留 null 陷阱(F6 修复——此前 s3=0 连 null 陷阱都没有)
- }
- }
- mask = mask * 2;
- bi = bi + 1;
- }
- if off < 0 && runtime_targets == 1 && runtime_base >= 0 {
- w64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3, runtime_size);
- if op == IR_DEREF {
- w64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S2, runtime_base);
- } else {
+ mask = mask * 2
+ bi = bi + 1
+
+ if off < 0 && runtime_targets == 1 && runtime_base >= 0:
+ w64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3, runtime_size)
+ if op == IR_DEREF:
+ w64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S2, runtime_base)
+ else:
// IR_STORE_PTR has no result, so dest carries the runtime base.
- w64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST, runtime_base);
- }
- } else if off < 0 && runtime_targets > 1 {
+ w64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST, runtime_base)
+ else if off < 0 && runtime_targets > 1:
check_error(EC_TK_INDEX,
"runtime pointer bounds check has multiple allocation targets",
- 0, 0);
- }
- }
- ni = ni + 1;
- }
-}
+ 0, 0)
+ ni = ni + 1
-fn provenance_verify_all() {
+fn provenance_verify_all():
// Safety pass — always runs
- fi : ., mut = 0;
- loop { if fi >= g_ir_func_count { break; }
- nstart := r64(g_df_func_node_start, fi * 8);
- ncount := r64(g_df_func_node_count, fi * 8);
- provenance_verify_func(nstart, ncount);
- fi = fi + 1;
- }
-}
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ nstart := r64(g_df_func_node_start, fi * 8)
+ ncount := r64(g_df_func_node_count, fi * 8)
+ provenance_verify_func(nstart, ncount)
+ fi = fi + 1
diff --git a/src/compiler/ptr_analysis.cr b/src/compiler/ptr_analysis.cr
index 6af6fd73..e5b36ab9 100644
--- a/src/compiler/ptr_analysis.cr
+++ b/src/compiler/ptr_analysis.cr
@@ -12,345 +12,362 @@
// Load: DEREF → propagate alloc content to dest (∀alloc∈pts(ptr))
// Call: function summary propagation + arg conservatism
-fn pa_in_unsafe(node_seq: int) -> int {
- si : ., mut = 0;
- loop { if si >= g_sg_count { break; }
- kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND);
- if kind == SG_UNSAFE {
- nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART);
- ncount := r64(g_sgs, si * ESZ_SG + OFF_SG_NCOUNT);
- if node_seq >= nstart && node_seq < nstart + ncount { return 1; }
- }
- si = si + 1;
- }
- return 0;
-}
+fn pa_in_unsafe(node_seq: int) -> int:
+ si : ., mut = 0
+ loop:
+ if si >= g_sg_count:
+ break
+ kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND)
+ if kind == SG_UNSAFE:
+ nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART)
+ ncount := r64(g_sgs, si * ESZ_SG + OFF_SG_NCOUNT)
+ if node_seq >= nstart && node_seq < nstart + ncount:
+ return 1
+ si = si + 1
+ return 0
// ── Alloc content tracking (Andersen Store/Load rules) ──
// g_alloc_pts[alloc_id]: pts set of values stored INTO this allocation
// via IR_STORE_PTR. Read via IR_DEREF.
-fn grow_alloc_pts(n: int) {
- if n < g_alloc_pts_cap { return; }
- nc := g_alloc_pts_cap;
- if nc == 0 { nc = 16; }
- loop { if nc > n { break; } nc = nc * 2; }
- nb := alloc(nc * 8);
- if g_alloc_pts_cap > 0 { _dyncpy(g_alloc_pts, g_alloc_pts_cap * 8, nb); }
- g_alloc_pts = nb; g_alloc_pts_cap = nc;
-}
+fn grow_alloc_pts(n: int):
+ if n < g_alloc_pts_cap:
+ return
+ nc := g_alloc_pts_cap
+ if nc == 0:
+ nc = 16
+ loop:
+ if nc > n:
+ break
+ nc = nc * 2
+ nb := alloc(nc * 8)
+ if g_alloc_pts_cap > 0:
+ _dyncpy(g_alloc_pts, g_alloc_pts_cap * 8, nb)
+ g_alloc_pts = nb
+ g_alloc_pts_cap = nc
-fn grow_pa_alloc_nodes(n: int) {
- if n < g_pa_alloc_nodes_cap { return; }
- nc := g_pa_alloc_nodes_cap;
- if nc == 0 { nc = 16; }
- loop { if nc > n { break; } nc = nc * 2; }
- nb := alloc(nc * 8);
- if g_pa_alloc_nodes_cap > 0 { _dyncpy(g_pa_alloc_nodes, g_pa_alloc_nodes_cap * 8, nb); }
- g_pa_alloc_nodes = nb; g_pa_alloc_nodes_cap = nc;
-}
+fn grow_pa_alloc_nodes(n: int):
+ if n < g_pa_alloc_nodes_cap:
+ return
+ nc := g_pa_alloc_nodes_cap
+ if nc == 0:
+ nc = 16
+ loop:
+ if nc > n:
+ break
+ nc = nc * 2
+ nb := alloc(nc * 8)
+ if g_pa_alloc_nodes_cap > 0:
+ _dyncpy(g_pa_alloc_nodes, g_pa_alloc_nodes_cap * 8, nb)
+ g_pa_alloc_nodes = nb
+ g_pa_alloc_nodes_cap = nc
// Set a bit in a pts bitmap at given index
-fn pa_set_bit(bitmap: int, bitpos: int) -> int {
+fn pa_set_bit(bitmap: int, bitpos: int) -> int:
// bitpos: which bit to set (0-63)
// Use multiplication to create the mask: 2^bitpos = 1 << bitpos
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= bitpos { break; } mask = mask * 2; bi = bi + 1; }
- return bitmap + mask; // set the bit via addition (OR)
-}
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= bitpos:
+ break
+ mask = mask * 2
+ bi = bi + 1
+ return bitmap + mask // set the bit via addition (OR)
// Check if a bit is set in a pts bitmap
-fn pa_has_bit(bitmap: int, bitpos: int) -> int {
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= bitpos { break; } mask = mask * 2; bi = bi + 1; }
- return (bitmap / mask) % 2;
-}
+fn pa_has_bit(bitmap: int, bitpos: int) -> int:
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= bitpos:
+ break
+ mask = mask * 2
+ bi = bi + 1
+ return (bitmap / mask) % 2
// Merge src bits into dst bitmap, return 1 if dst changed
-fn pa_merge_pts(dst_var: int, src_var: int) -> int {
- if dst_var < 0 || src_var < 0 { return 0; }
- if g_pts_cap <= dst_var { grow_pts(dst_var + 1); }
- if g_pts_cap <= src_var { grow_pts(src_var + 1); }
- dst := r64(g_pts, dst_var * 8);
- src := r64(g_pts, src_var * 8);
- if src == 0 { return 0; }
+fn pa_merge_pts(dst_var: int, src_var: int) -> int:
+ if dst_var < 0 || src_var < 0:
+ return 0
+ if g_pts_cap <= dst_var:
+ grow_pts(dst_var + 1)
+ if g_pts_cap <= src_var:
+ grow_pts(src_var + 1)
+ dst := r64(g_pts, dst_var * 8)
+ src := r64(g_pts, src_var * 8)
+ if src == 0:
+ return 0
// Bitwise OR: start from dst, add any src bits not already set
- out_val : int, mut = dst;
- changed : int, mut = 0;
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= 64 { break; }
- if (src / mask) % 2 == 1 && (out_val / mask) % 2 == 0 {
- out_val = out_val + mask;
- changed = 1;
- }
- mask = mask * 2;
- bi = bi + 1;
- }
- if changed != 0 { w64(g_pts, dst_var * 8, out_val); }
- return changed;
-}
+ out_val : int, mut = dst
+ changed : int, mut = 0
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= 64:
+ break
+ if (src / mask) % 2 == 1 && (out_val / mask) % 2 == 0:
+ out_val = out_val + mask
+ changed = 1
+ mask = mask * 2
+ bi = bi + 1
+ if changed != 0:
+ w64(g_pts, dst_var * 8, out_val)
+ return changed
// Merge alloc_pts[alloc_seq] into pts[dst_var], return 1 if changed
-fn pa_merge_alloc_pts(dst_var: int, alloc_seq: int) -> int {
- if dst_var < 0 || alloc_seq < 0 { return 0; }
- if g_pts_cap <= dst_var { grow_pts(dst_var + 1); }
- if g_alloc_pts_cap <= alloc_seq { grow_alloc_pts(alloc_seq + 1); }
- src := r64(g_alloc_pts, alloc_seq * 8);
- if src == 0 { return 0; }
- prev := r64(g_pts, dst_var * 8);
- changed : int, mut = 0;
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= 64 { break; }
- if (src / mask) % 2 == 1 && (prev / mask) % 2 == 0 {
- prev = pa_set_bit(prev, bi);
- changed = 1;
- }
- mask = mask * 2;
- bi = bi + 1;
- }
- if changed != 0 { w64(g_pts, dst_var * 8, prev); }
- return changed;
-}
+fn pa_merge_alloc_pts(dst_var: int, alloc_seq: int) -> int:
+ if dst_var < 0 || alloc_seq < 0:
+ return 0
+ if g_pts_cap <= dst_var:
+ grow_pts(dst_var + 1)
+ if g_alloc_pts_cap <= alloc_seq:
+ grow_alloc_pts(alloc_seq + 1)
+ src := r64(g_alloc_pts, alloc_seq * 8)
+ if src == 0:
+ return 0
+ prev := r64(g_pts, dst_var * 8)
+ changed : int, mut = 0
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= 64:
+ break
+ if (src / mask) % 2 == 1 && (prev / mask) % 2 == 0:
+ prev = pa_set_bit(prev, bi)
+ changed = 1
+ mask = mask * 2
+ bi = bi + 1
+ if changed != 0:
+ w64(g_pts, dst_var * 8, prev)
+ return changed
// Propagate pts[src_var] into alloc_pts[alloc_seq], return 1 if changed
-fn pa_store_to_alloc(alloc_seq: int, src_var: int) -> int {
- src := r64(g_pts, src_var * 8);
- if src == 0 { return 0; }
- grow_alloc_pts(alloc_seq + 1);
- prev := r64(g_alloc_pts, alloc_seq * 8);
- changed : int, mut = 0;
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= 64 { break; }
- if (src / mask) % 2 == 1 && (prev / mask) % 2 == 0 {
- prev = pa_set_bit(prev, bi);
- changed = 1;
- }
- mask = mask * 2;
- bi = bi + 1;
- }
- if changed != 0 { w64(g_alloc_pts, alloc_seq * 8, prev); }
- return changed;
-}
+fn pa_store_to_alloc(alloc_seq: int, src_var: int) -> int:
+ src := r64(g_pts, src_var * 8)
+ if src == 0:
+ return 0
+ grow_alloc_pts(alloc_seq + 1)
+ prev := r64(g_alloc_pts, alloc_seq * 8)
+ changed : int, mut = 0
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= 64:
+ break
+ if (src / mask) % 2 == 1 && (prev / mask) % 2 == 0:
+ prev = pa_set_bit(prev, bi)
+ changed = 1
+ mask = mask * 2
+ bi = bi + 1
+ if changed != 0:
+ w64(g_alloc_pts, alloc_seq * 8, prev)
+ return changed
// Andersen-style Load: r = *p → for each alloc in pts(p): pts(r) ∪= alloc_pts[alloc]
-fn pa_load(deref_node: int, dst_var: int, ptr_var: int) -> int {
- changed : int, mut = 0;
- pts_ptr := r64(g_pts, ptr_var * 8);
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= 64 { break; }
- if (pts_ptr / mask) % 2 == 1 {
- if pa_merge_alloc_pts(dst_var, bi) != 0 { changed = 1; }
- }
- mask = mask * 2;
- bi = bi + 1;
- }
- return changed;
-}
+fn pa_load(deref_node: int, dst_var: int, ptr_var: int) -> int:
+ changed : int, mut = 0
+ pts_ptr := r64(g_pts, ptr_var * 8)
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= 64:
+ break
+ if (pts_ptr / mask) % 2 == 1:
+ if pa_merge_alloc_pts(dst_var, bi) != 0:
+ changed = 1
+ mask = mask * 2
+ bi = bi + 1
+ return changed
// Andersen-style Store: *p = v → for each alloc in pts(p): alloc_pts[alloc] ∪= pts(v)
-fn pa_store(ptr_var: int, val_var: int) -> int {
- changed : int, mut = 0;
- pts_ptr := r64(g_pts, ptr_var * 8);
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= 64 { break; }
- if (pts_ptr / mask) % 2 == 1 {
- if pa_store_to_alloc(bi, val_var) != 0 { changed = 1; }
- }
- mask = mask * 2;
- bi = bi + 1;
- }
- return changed;
-}
+fn pa_store(ptr_var: int, val_var: int) -> int:
+ changed : int, mut = 0
+ pts_ptr := r64(g_pts, ptr_var * 8)
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= 64:
+ break
+ if (pts_ptr / mask) % 2 == 1:
+ if pa_store_to_alloc(bi, val_var) != 0:
+ changed = 1
+ mask = mask * 2
+ bi = bi + 1
+ return changed
-fn ptr_analysis_func(nstart: int, ncount: int, vstart: int, vcount: int) {
+fn ptr_analysis_func(nstart: int, ncount: int, vstart: int, vcount: int):
// Initialize pts/offset for this function's variables
- vi : ., mut = 0;
- loop { if vi >= vcount { break; }
- var_idx := vstart + vi;
- grow_pts(var_idx + 1);
- w64(g_pts, var_idx * 8, 0);
- grow_offsets(var_idx + 1);
- w64(g_offsets, var_idx * 8, 0);
- vi = vi + 1;
- }
+ vi : ., mut = 0
+ loop:
+ if vi >= vcount:
+ break
+ var_idx := vstart + vi
+ grow_pts(var_idx + 1)
+ w64(g_pts, var_idx * 8, 0)
+ grow_offsets(var_idx + 1)
+ w64(g_offsets, var_idx * 8, 0)
+ vi = vi + 1
- changed : int, mut = 1;
- iter : ., mut = 0;
- loop {
- if changed == 0 { break; }
- if iter >= 10 { break; } // safety limit
- changed = 0;
- iter = iter + 1;
+ changed : int, mut = 1
+ iter : ., mut = 0
+ loop:
+ if changed == 0:
+ break
+ if iter >= 10:
+ break
+ // safety limit
+ changed = 0
+ iter = iter + 1
- ni : ., mut = nstart;
- loop { if ni >= nstart + ncount { break; }
- op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE);
- d := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST);
- s1 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S1);
- s2 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S2);
- s3 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3);
+ ni : ., mut = nstart
+ loop:
+ if ni >= nstart + ncount:
+ break
+ op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE)
+ d := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST)
+ s1 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S1)
+ s2 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S2)
+ s3 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3)
// In unsafe blocks: suppress pointer tracking
- if pa_in_unsafe(ni) != 0 { ni = ni + 1; continue; }
+ if pa_in_unsafe(ni) != 0:
+ ni = ni + 1
+ continue
- if d >= 0 {
+ if d >= 0:
// Addr: ALLOC/REF/ADDR_INDEX → self-pointer
- if op == IR_ALLOC_STRUCT || op == IR_ALLOC_ARRAY {
+ if op == IR_ALLOC_STRUCT || op == IR_ALLOC_ARRAY:
// 修复 12:IR_ALLOC(标量变量槽标记,不发射代码)不是堆分配,
// 不参与 pts 追踪——修复前它被分配 pts 位,导致 p = &arr[i]
// 的 pts 含变量槽的位(多个 alloc 位污染)→ s3 取错 alloc。
- if r64(g_pts, d * 8) == 0 {
+ if r64(g_pts, d * 8) == 0:
// 修复 3:每个 alloc 分配递增位号(bit = alloc_seq),并登记
// alloc_seq → DF 节点序号。修复前恒设 bit 0——所有 alloc 别名
// 串扰,provenance 的 get_alloc_size(0) 查到节点 0 → 检查永远不生成。
- if g_pa_alloc_count < 64 {
- grow_pa_alloc_nodes(g_pa_alloc_count + 1);
- w64(g_pa_alloc_nodes, g_pa_alloc_count * 8, ni);
- w64(g_pts, d * 8, pa_set_bit(0, g_pa_alloc_count));
- g_pa_alloc_count = g_pa_alloc_count + 1;
- changed = 1;
- }
- }
- w64(g_offsets, d * 8, 0);
- }
+ if g_pa_alloc_count < 64:
+ grow_pa_alloc_nodes(g_pa_alloc_count + 1)
+ w64(g_pa_alloc_nodes, g_pa_alloc_count * 8, ni)
+ w64(g_pts, d * 8, pa_set_bit(0, g_pa_alloc_count))
+ g_pa_alloc_count = g_pa_alloc_count + 1
+ changed = 1
+ w64(g_offsets, d * 8, 0)
- if op == IR_REF && s1 >= 0 {
- if pa_merge_pts(d, s1) != 0 { changed = 1; }
+ if op == IR_REF && s1 >= 0:
+ if pa_merge_pts(d, s1) != 0:
+ changed = 1
// offset propagates
- w64(g_offsets, d * 8, r64(g_offsets, s1 * 8));
- }
+ w64(g_offsets, d * 8, r64(g_offsets, s1 * 8))
- if op == IR_ADDR_INDEX && s1 >= 0 {
- if pa_merge_pts(d, s1) != 0 { changed = 1; }
+ if op == IR_ADDR_INDEX && s1 >= 0:
+ if pa_merge_pts(d, s1) != 0:
+ changed = 1
// offset 由索引 s2 决定:常量索引可精确计算(idx*8),
// 运行时索引 → 未知(-1),迫使 provenance_verify 生成运行时检查。
// 修复前:无条件传播 s1 的 offset(数组=0),运行时越界被误判为
// 编译期安全 → 越界裸读(见 docs/archive/compcert-reference.md 审查记录)。
- base_off := r64(g_offsets, s1 * 8);
- idx_val : int = -1;
- if s2 >= 0 {
- prod := r64(g_df_var_producer, s2 * 8);
- if prod >= 0 {
- prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE);
- if prod_op == IR_CONST {
- idx_val = r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S1);
- }
- }
- }
- if idx_val >= 0 && base_off >= 0 {
- w64(g_offsets, d * 8, base_off + idx_val * 8);
- } else {
- w64(g_offsets, d * 8, -1);
- }
- }
+ base_off := r64(g_offsets, s1 * 8)
+ idx_val : int = -1
+ if s2 >= 0:
+ prod := r64(g_df_var_producer, s2 * 8)
+ if prod >= 0:
+ prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE)
+ if prod_op == IR_CONST:
+ idx_val = r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S1)
+ if idx_val >= 0 && base_off >= 0:
+ w64(g_offsets, d * 8, base_off + idx_val * 8)
+ else:
+ w64(g_offsets, d * 8, -1)
// F11①:IR_SLICE 传播底层数组 provenance(d = &arr[low])。
// 使经切片的 DEREF 能被分配长度检查捕获;offset = low*8(常量时)。
- if op == IR_SLICE && s1 >= 0 {
- if pa_merge_pts(d, s1) != 0 { changed = 1; }
- base_off := r64(g_offsets, s1 * 8);
- low_val : int = -1;
- if s2 >= 0 {
- prod := r64(g_df_var_producer, s2 * 8);
- if prod >= 0 {
- prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE);
- if prod_op == IR_CONST {
- low_val = r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S1);
- }
- }
- }
- if low_val >= 0 && base_off >= 0 {
- w64(g_offsets, d * 8, base_off + low_val * 8);
- } else {
- w64(g_offsets, d * 8, -1);
- }
- }
+ if op == IR_SLICE && s1 >= 0:
+ if pa_merge_pts(d, s1) != 0:
+ changed = 1
+ base_off := r64(g_offsets, s1 * 8)
+ low_val : int = -1
+ if s2 >= 0:
+ prod := r64(g_df_var_producer, s2 * 8)
+ if prod >= 0:
+ prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE)
+ if prod_op == IR_CONST:
+ low_val = r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S1)
+ if low_val >= 0 && base_off >= 0:
+ w64(g_offsets, d * 8, base_off + low_val * 8)
+ else:
+ w64(g_offsets, d * 8, -1)
// BINARY with PTR ops: propagate with offset
- if op == IR_BINARY && (s3 == OP_PTR_ADD || s3 == OP_PTR_SUB) && s1 >= 0 {
- if pa_merge_pts(d, s1) != 0 { changed = 1; }
+ if op == IR_BINARY && (s3 == OP_PTR_ADD || s3 == OP_PTR_SUB) && s1 >= 0:
+ if pa_merge_pts(d, s1) != 0:
+ changed = 1
// Prov-GC: evaluate constant offsets precisely
- base_off := r64(g_offsets, s1 * 8);
- off_val : ., mut = 0;
+ base_off := r64(g_offsets, s1 * 8)
+ off_val : ., mut = 0
// Check if s2 comes from a CONST instruction
- if s2 >= 0 {
- prod := r64(g_df_var_producer, s2 * 8);
- if prod >= 0 {
- prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE);
- if prod_op == IR_CONST {
- off_val = r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S1);
- }
- }
- }
- if s3 == OP_PTR_ADD {
- w64(g_offsets, d * 8, base_off + off_val * 8);
- } else {
- w64(g_offsets, d * 8, base_off - off_val * 8);
- }
- }
+ if s2 >= 0:
+ prod := r64(g_df_var_producer, s2 * 8)
+ if prod >= 0:
+ prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE)
+ if prod_op == IR_CONST:
+ off_val = r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S1)
+ if s3 == OP_PTR_ADD:
+ w64(g_offsets, d * 8, base_off + off_val * 8)
+ else:
+ w64(g_offsets, d * 8, base_off - off_val * 8)
// LOAD: d ← s1 拷贝传播
- if op == IR_LOAD && s1 >= 0 {
- if pa_merge_pts(d, s1) != 0 { changed = 1; }
- w64(g_offsets, d * 8, r64(g_offsets, s1 * 8));
- }
+ if op == IR_LOAD && s1 >= 0:
+ if pa_merge_pts(d, s1) != 0:
+ changed = 1
+ w64(g_offsets, d * 8, r64(g_offsets, s1 * 8))
// STORE: s1 ← s2 拷贝传播。修复 4:IR_STORE 的 dest 恒为 -1,
// 原代码把 STORE 混进 LOAD 分支(用 d 传播)→ 永不执行 →
// p = &arr[i] 的 offset 丢失 → 越界检查被跳过。
// 注意:此分支必须在 if d >= 0 块外(d 恒为 -1)。
// PHI: merge pts from both predecessors (implicit flow)
- if op == IR_PHI {
- if s1 >= 0 && pa_merge_pts(d, s1) != 0 { changed = 1; }
- if s2 >= 0 && pa_merge_pts(d, s2) != 0 { changed = 1; }
- w64(g_offsets, d * 8, 0); // approximate offset after merge
- }
+ if op == IR_PHI:
+ if s1 >= 0 && pa_merge_pts(d, s1) != 0:
+ changed = 1
+ if s2 >= 0 && pa_merge_pts(d, s2) != 0:
+ changed = 1
+ w64(g_offsets, d * 8, 0) // approximate offset after merge
// CALL: leave pts=0 for now (conservative)
- if op == IR_CALL {
- w64(g_offsets, d * 8, 0);
- }
- }
+ if op == IR_CALL:
+ w64(g_offsets, d * 8, 0)
// Store: s1 ← s2 拷贝传播(IR_STORE 的 d 恒为 -1,必须在 if d >= 0 块外)
- if op == IR_STORE && s1 >= 0 && s2 >= 0 {
- if pa_merge_pts(s1, s2) != 0 { changed = 1; }
- w64(g_offsets, s1 * 8, r64(g_offsets, s2 * 8));
- }
+ if op == IR_STORE && s1 >= 0 && s2 >= 0:
+ if pa_merge_pts(s1, s2) != 0:
+ changed = 1
+ w64(g_offsets, s1 * 8, r64(g_offsets, s2 * 8))
// Store: *p = v (Andersen store rule) — s1=ptr, s2=val
- if op == IR_STORE_PTR && s1 >= 0 && s2 >= 0 {
- if pa_store(s1, s2) != 0 { changed = 1; }
- }
+ if op == IR_STORE_PTR && s1 >= 0 && s2 >= 0:
+ if pa_store(s1, s2) != 0:
+ changed = 1
// Load: r = *p (Andersen load rule) — d=dest, s1=ptr
- if op == IR_DEREF && d >= 0 && s1 >= 0 {
+ if op == IR_DEREF && d >= 0 && s1 >= 0:
// Also propagate pts(ptr) as conservative base
- if pa_merge_pts(d, s1) != 0 { changed = 1; }
+ if pa_merge_pts(d, s1) != 0:
+ changed = 1
// Merge alloc content from each pointee
- if pa_load(ni, d, s1) != 0 { changed = 1; }
- }
+ if pa_load(ni, d, s1) != 0:
+ changed = 1
- ni = ni + 1;
- }
- }
-}
+ ni = ni + 1
-fn ptr_analysis_all() {
- fi : ., mut = 0;
- loop { if fi >= g_ir_func_count { break; }
- nstart := r64(g_df_func_node_start, fi * 8);
- ncount := r64(g_df_func_node_count, fi * 8);
- vstart := r64(g_ir_func_var_start, fi * 8);
- vcount := r64(g_ir_func_var_count, fi * 8);
- ptr_analysis_func(nstart, ncount, vstart, vcount);
- fi = fi + 1;
- }
-}
+fn ptr_analysis_all():
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ nstart := r64(g_df_func_node_start, fi * 8)
+ ncount := r64(g_df_func_node_count, fi * 8)
+ vstart := r64(g_ir_func_var_start, fi * 8)
+ vcount := r64(g_ir_func_var_count, fi * 8)
+ ptr_analysis_func(nstart, ncount, vstart, vcount)
+ fi = fi + 1
diff --git a/src/compiler/purity_selftest.cr b/src/compiler/purity_selftest.cr
index b7f93a87..adf7d6d9 100644
--- a/src/compiler/purity_selftest.cr
+++ b/src/compiler/purity_selftest.cr
@@ -8,50 +8,58 @@
// 的是 IR 生成后由 compute_all_purity 写回的值(时点见 checker.cr 头注)。
// 语言面注意:本语言无三元运算符。
-fn ps_check(name: string, got: int, want: int) -> int {
- if got == want {
- print("PASS "); println(name);
- return 0;
- }
- print("FAIL "); print(name);
- print(": got "); print(int_str(got));
- print(" want "); println(int_str(want));
- return 1;
-}
+fn ps_check(name: string, got: int, want: int) -> int:
+ if got == want:
+ print("PASS ")
+ println(name)
+ return 0
+ print("FAIL ")
+ print(name)
+ print(": got ")
+ print(int_str(got))
+ print(" want ")
+ println(int_str(want))
+ return 1
// bool 版(批 8 S2 · bool 类;同 `ts_check_b`,纯度自测表用)。
-fn ps_check_b(name: string, got: bool, want: bool) -> int {
- if got == want {
- print("PASS "); println(name);
- return 0;
- }
- print("FAIL "); print(name);
- print(": got "); print(bool_str(got));
- print(" want "); println(bool_str(want));
- return 1;
-}
+fn ps_check_b(name: string, got: bool, want: bool) -> int:
+ if got == want:
+ print("PASS ")
+ println(name)
+ return 0
+ print("FAIL ")
+ print(name)
+ print(": got ")
+ print(bool_str(got))
+ print(" want ")
+ println(bool_str(want))
+ return 1
// 单次完整前端 + IR 生成(自测用;与 main.cr 的 run 路径同序,无文件缓存)。
-fn ps_compile(src: string) -> int {
- reset_frontend_state();
- g_source = src;
- g_error_count = 0;
- g_source_dir = "";
- tokenize(g_source);
- res_imports();
- parse_all();
- if g_error_count > 0 { print_parse_errors(); return 1; }
- if g_diag_count > 0 { print_diagnostics(); return 1; }
- check_all();
- if g_diag_count > 0 { print_diagnostics(); return 1; }
- ir_gen_all();
- return 0;
-}
+fn ps_compile(src: string) -> int:
+ reset_frontend_state()
+ g_source = src
+ g_error_count = 0
+ g_source_dir = ""
+ tokenize(g_source, 0)
+ res_imports()
+ parse_all()
+ if g_error_count > 0:
+ print_parse_errors()
+ return 1
+ if g_diag_count > 0:
+ print_diagnostics()
+ return 1
+ check_all()
+ if g_diag_count > 0:
+ print_diagnostics()
+ return 1
+ ir_gen_all()
+ return 0
// 按名查纯度(-1 = 无此函数——与 0/1 区分,防「查不到」被当「不纯」混过)
-fn ps_purity(name: string) -> int {
- return fi_ispure_of(str_intern(name));
-}
+fn ps_purity(name: string) -> int:
+ return fi_ispure_of(str_intern(name))
// ── state 链面(Task 1 的落点:纯度是手段,「调用进链」才是目的)──────────
// 链 = kind=1 的 DF 边(dataflow.cr df_replay_state_chain 重放产出)。以下三条
@@ -62,250 +70,277 @@ fn ps_purity(name: string) -> int {
// 源函数名 → IR 函数序号(-1 = 无)。IR 表名 = 源函数名(monomorph 实例为
// 改写名,本通道只用非泛型函数名)。
-fn ps_ir_index_of(name: string) -> int {
- ni := str_intern(name);
- irf : ., mut = 0;
- loop {
- if irf >= g_ir_func_count { return -1; }
- if r64(g_ir_func_name_idx, irf * 8) == ni { return irf; }
- irf = irf + 1;
- }
- return -1;
-}
+fn ps_ir_index_of(name: string) -> int:
+ ni := str_intern(name)
+ irf : ., mut = 0
+ loop:
+ if irf >= g_ir_func_count:
+ return -1
+ if r64(g_ir_func_name_idx, irf * 8) == ni:
+ return irf
+ irf = irf + 1
+ return -1
// 函数 irf 体内「调 callee」的 DF 节点序号(-1 = 无)
-fn ps_call_node(irf: int, callee: string) -> int {
- cni := str_intern(callee);
- start := r64(g_df_func_node_start, irf * 8);
- cnt := r64(g_df_func_node_count, irf * 8);
- n : ., mut = start;
- loop {
- if n >= start + cnt { return -1; }
- if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) == IR_CALL {
- if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3) == cni { return n; }
- }
- n = n + 1;
- }
- return -1;
-}
+fn ps_call_node(irf: int, callee: string) -> int:
+ cni := str_intern(callee)
+ start := r64(g_df_func_node_start, irf * 8)
+ cnt := r64(g_df_func_node_count, irf * 8)
+ n : ., mut = start
+ loop:
+ if n >= start + cnt:
+ return -1
+ if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) == IR_CALL:
+ if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3) == cni:
+ return n
+ n = n + 1
+ return -1
// 函数 irf 体内「调 callee」的 DF 节点总数(非空断言用:防「查不到 ⇒ 恒 0」
// 把「零入链」退化断言混过)
-fn ps_count_call_nodes(irf: int, callee: string) -> int {
- if irf < 0 { return -1; }
- cni := str_intern(callee);
- start := r64(g_df_func_node_start, irf * 8);
- cnt := r64(g_df_func_node_count, irf * 8);
- r : ., mut = 0;
- n : ., mut = start;
- loop {
- if n >= start + cnt { return r; }
- if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) == IR_CALL {
- if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3) == cni { r = r + 1; }
- }
- n = n + 1;
- }
- return r;
-}
+fn ps_count_call_nodes(irf: int, callee: string) -> int:
+ if irf < 0:
+ return -1
+ cni := str_intern(callee)
+ start := r64(g_df_func_node_start, irf * 8)
+ cnt := r64(g_df_func_node_count, irf * 8)
+ r : ., mut = 0
+ n : ., mut = start
+ loop:
+ if n >= start + cnt:
+ return r
+ if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) == IR_CALL:
+ if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3) == cni:
+ r = r + 1
+ n = n + 1
+ return r
// 函数 irf 体内首个 opcode 节点(-1 = 无)
-fn ps_op_node(irf: int, opcode: int) -> int {
- if irf < 0 { return -1; }
- start := r64(g_df_func_node_start, irf * 8);
- cnt := r64(g_df_func_node_count, irf * 8);
- n : ., mut = start;
- loop {
- if n >= start + cnt { return -1; }
- if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) == opcode { return n; }
- n = n + 1;
- }
- return -1;
-}
+fn ps_op_node(irf: int, opcode: int) -> int:
+ if irf < 0:
+ return -1
+ start := r64(g_df_func_node_start, irf * 8)
+ cnt := r64(g_df_func_node_count, irf * 8)
+ n : ., mut = start
+ loop:
+ if n >= start + cnt:
+ return -1
+ if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) == opcode:
+ return n
+ n = n + 1
+ return -1
// 节点 nid 是否被 kind=1 边指入(1 = 有入边,0 = 无,-1 = 无此节点)
-fn ps_has_state_in(nid: int) -> int {
- if nid < 0 { return -1; }
- t := ps_state_touch(nid);
- return t - (t / 2) * 2; // t 的入边位(无按位与;t >= 0 ⇒ 取模非负)
-}
+fn ps_has_state_in(nid: int) -> int:
+ if nid < 0:
+ return -1
+ t := ps_state_touch(nid)
+ return t - (t / 2) * 2 // t 的入边位(无按位与;t >= 0 ⇒ 取模非负)
// 节点 nid 是否以 kind=1 边指出(1 = 有出边,0 = 无,-1 = 无此节点)
-fn ps_has_state_out(nid: int) -> int {
- if nid < 0 { return -1; }
- t := ps_state_touch(nid);
- return t / 2 - (t / 4) * 2;
-}
+fn ps_has_state_out(nid: int) -> int:
+ if nid < 0:
+ return -1
+ t := ps_state_touch(nid)
+ return t / 2 - (t / 4) * 2
// 函数 irf 体内「调 callee 且被链指入」的节点数(Task 2 验收例:同一被调者
// 被调两次 ⇒ 必须两个都在链上;纯调用同形 ⇒ 0)
-fn ps_calls_in_chain(irf: int, callee: string) -> int {
- if irf < 0 { return -1; }
- cni := str_intern(callee);
- start := r64(g_df_func_node_start, irf * 8);
- cnt := r64(g_df_func_node_count, irf * 8);
- r : ., mut = 0;
- n : ., mut = start;
- loop {
- if n >= start + cnt { return r; }
- if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) == IR_CALL {
- if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3) == cni {
- if ps_has_state_in(n) == 1 { r = r + 1; }
- }
- }
- n = n + 1;
- }
- return r;
-}
+fn ps_calls_in_chain(irf: int, callee: string) -> int:
+ if irf < 0:
+ return -1
+ cni := str_intern(callee)
+ start := r64(g_df_func_node_start, irf * 8)
+ cnt := r64(g_df_func_node_count, irf * 8)
+ r : ., mut = 0
+ n : ., mut = start
+ loop:
+ if n >= start + cnt:
+ return r
+ if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) == IR_CALL:
+ if r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3) == cni:
+ if ps_has_state_in(n) == 1:
+ r = r + 1
+ n = n + 1
+ return r
// 节点 nid 被 kind=1 边触及的面:+1 = 有入边,+2 = 有出边(返回 0..3)
-fn ps_state_touch(nid: int) -> int {
- if nid < 0 { return -1; }
- r : ., mut = 0;
- e : ., mut = 0;
- loop {
- if e >= g_df_edge_count { break; }
- if r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_KIND) == 1 {
- if r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_TO) == nid { r = r + 1; }
- if r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_FROM) == nid { r = r + 2; }
- }
- e = e + 1;
- }
- return r;
-}
+fn ps_state_touch(nid: int) -> int:
+ if nid < 0:
+ return -1
+ r : ., mut = 0
+ e : ., mut = 0
+ loop:
+ if e >= g_df_edge_count:
+ break
+ if r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_KIND) == 1:
+ if r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_TO) == nid:
+ r = r + 1
+ if r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_FROM) == nid:
+ r = r + 2
+ e = e + 1
+ return r
// 函数 irf 区间内是否存在「指向 label 节点的 kind=1 边」(循环终止依赖:
// 循环退出节点必须依赖循环体内最后一个副作用——spec region-cfg §4.2)
-fn ps_has_label_state_target(irf: int) -> int {
- start := r64(g_df_func_node_start, irf * 8);
- cnt := r64(g_df_func_node_count, irf * 8);
- e : ., mut = 0;
- loop {
- if e >= g_df_edge_count { break; }
- if r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_KIND) == 1 {
- tgt := r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_TO);
- if tgt >= start && tgt < start + cnt {
- if r64(g_df_nodes, tgt * ESZ_DFNODE + OFF_DF_OPCODE) == IR_LABEL { return 1; }
- }
- }
- e = e + 1;
- }
- return 0;
-}
+fn ps_has_label_state_target(irf: int) -> int:
+ start := r64(g_df_func_node_start, irf * 8)
+ cnt := r64(g_df_func_node_count, irf * 8)
+ e : ., mut = 0
+ loop:
+ if e >= g_df_edge_count:
+ break
+ if r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_KIND) == 1:
+ tgt := r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_TO)
+ if tgt >= start && tgt < start + cnt:
+ if r64(g_df_nodes, tgt * ESZ_DFNODE + OFF_DF_OPCODE) == IR_LABEL:
+ return 1
+ e = e + 1
+ return 0
-fn purity_selftest_run() -> int {
- fails : ., mut = 0;
- total : ., mut = 0;
+fn purity_selftest_run() -> int:
+ fails : ., mut = 0
+ total : ., mut = 0
// 用例程序:正控(含传递正控)+ 负控①-⑥(含 SCC 互递归 + 有效应泛型)
- src := "fn pure_add(a: int, b: int) -> int { return a + b; }\n";
- src = src + "fn pure_caller(a: int, b: int) -> int { return pure_add(a, b); }\n";
- src = src + "fn effect() { st : ., mut = 0; st = 1; }\n";
- src = src + "fn call_effect() { effect(); }\n";
- src = src + "extern fn ext_probe(x: int) -> int;\n";
- src = src + "fn call_extern(x: int) -> int { return ext_probe(x); }\n";
- src = src + "fn call_builtin(x: int) -> int { return load64(x); }\n";
- src = src + "fn self_rec(n: int) -> int { if n <= 0 { return 0; } return self_rec(n - 1); }\n";
- src = src + "fn mut_rec_a(n: int) -> int { if n <= 0 { return 0; } return mut_rec_b(n - 1); }\n";
- src = src + "fn mut_rec_b(n: int) -> int { if n <= 0 { return 0; } return mut_rec_a(n - 1); }\n";
- src = src + "fn id[T](x: T) -> T { return x; }\n";
- src = src + "fn use_id(x: int) -> int { return id(x); }\n";
- src = src + "fn gid[T](x: T) -> T { gst : ., mut = 0; gst = 1; return x; }\n";
- src = src + "fn use_gid(x: int) -> int { return gid(x); }\n";
+ src := "fn pure_add(a: int, b: int) -> int:\n return a + b\n"
+ src = src + "fn pure_caller(a: int, b: int) -> int:\n return pure_add(a, b)\n"
+ src = src + "fn effect():\n st : ., mut = 0\n st = 1\n"
+ src = src + "fn call_effect():\n effect()\n"
+ src = src + "extern fn ext_probe(x: int) -> int\n"
+ src = src + "fn call_extern(x: int) -> int:\n return ext_probe(x)\n"
+ src = src + "fn call_builtin(x: int) -> int:\n return load64(x)\n"
+ src = src + "fn self_rec(n: int) -> int:\n if n <= 0:\n return 0\n return self_rec(n - 1)\n"
+ src = src + "fn mut_rec_a(n: int) -> int:\n if n <= 0:\n return 0\n return mut_rec_b(n - 1)\n"
+ src = src + "fn mut_rec_b(n: int) -> int:\n if n <= 0:\n return 0\n return mut_rec_a(n - 1)\n"
+ src = src + "fn id[T](x: T) -> T:\n return x\n"
+ src = src + "fn use_id(x: int) -> int:\n return id(x)\n"
+ src = src + "fn gid[T](x: T) -> T:\n gst : ., mut = 0\n gst = 1\n return x\n"
+ src = src + "fn use_gid(x: int) -> int:\n return gid(x)\n"
// state 链面用例(行为级):效应调用夹在两 store 之间 / 纯调用同形 / 循环
- src = src + "fn chain_effect() -> int { a : ., mut = 0; a = 1; effect(); a = 2; return a; }\n";
- src = src + "fn chain_pure() -> int { a : ., mut = 0; a = 1; b := pure_add(a, 1); a = 2; return a + b; }\n";
- src = src + "fn chain_loop() -> int { acc : ., mut = 0; i : ., mut = 0; loop { if i >= 3 { break; } acc = acc + 1; i = i + 1; } return acc; }\n";
+ src = src + "fn chain_effect() -> int:\n a : ., mut = 0\n a = 1\n effect()\n a = 2\n return a\n"
+ src = src + "fn chain_pure() -> int:\n a : ., mut = 0\n a = 1\n b := pure_add(a, 1)\n a = 2\n return a + b\n"
+ src = src + "fn chain_loop() -> int:\n acc : ., mut = 0\n i : ., mut = 0\n loop:\n if i >= 3:\n break\n acc = acc + 1\n i = i + 1\n return acc\n"
// Task 2 用例:① 效应调用双调(验收例:两个 CALL 都必须进链)+ 同形纯调用
// 负控;② IR_CALL_EXTERN / IR_SPAWN / IR_YIELD 三类 Task 2 新入链 opcode
// ——每例都带前 store(链头播种)与后 store(出边),故期望 touch == 3。
- src = src + "fn chain_two() -> int { a : ., mut = 0; a = 1; effect(); effect(); b := pure_add(a, 1); a = 2; return a + b; }\n";
- src = src + "fn chain_extern_op(x: int) -> int { a : ., mut = 0; a = 1; r := ext_probe(a); a = 2; return a + r; }\n";
- src = src + "fn spawnee(x: int) -> int { return x + 1; }\n";
- src = src + "fn chain_spawn_op() -> int { a : ., mut = 0; a = 1; r := go i 0..2 spawnee(i); a = 2; return a; }\n";
- src = src + "flow fn chain_yield_op(n: int) -> int { a : ., mut = 0; a = 1; yield n; a = 2; return a; }\n";
- src = src + "fn main() -> int { return 0; }\n";
+ src = src + "fn chain_two() -> int:\n a : ., mut = 0\n a = 1\n effect()\n effect()\n b := pure_add(a, 1)\n a = 2\n return a + b\n"
+ src = src + "fn chain_extern_op(x: int) -> int:\n a : ., mut = 0\n a = 1\n r := ext_probe(a)\n a = 2\n return a + r\n"
+ src = src + "fn spawnee(x: int) -> int:\n return x + 1\n"
+ src = src + "fn chain_spawn_op() -> int:\n a : ., mut = 0\n a = 1\n r := go i 0..2 spawnee(i)\n a = 2\n return a\n"
+ src = src + "flow fn chain_yield_op(n: int) -> int:\n a : ., mut = 0\n a = 1\n yield n\n a = 2\n return a\n"
+ src = src + "fn main() -> int:\n return 0\n"
- if ps_compile(src) != 0 {
- print("FAIL "); println("purity.selftest_compile");
- return 1;
- }
+ if ps_compile(src) != 0:
+ print("FAIL ")
+ println("purity.selftest_compile")
+ return 1
// ── 正控:无 store、无调用(及经纯函数的传递调用)⇒ 1 ──
- total = total + 1; fails = fails + ps_check("purity.pure_add", ps_purity("pure_add"), 1);
- total = total + 1; fails = fails + ps_check("purity.pure_caller", ps_purity("pure_caller"), 1);
+ total = total + 1
+ fails = fails + ps_check("purity.pure_add", ps_purity("pure_add"), 1)
+ total = total + 1
+ fails = fails + ps_check("purity.pure_caller", ps_purity("pure_caller"), 1)
// ── 负控① store ──
- total = total + 1; fails = fails + ps_check("purity.effect_store", ps_purity("effect"), 0);
+ total = total + 1
+ fails = fails + ps_check("purity.effect_store", ps_purity("effect"), 0)
// ── 负控② 传递:被调者不纯 ⇒ 调用者不纯 ──
- total = total + 1; fails = fails + ps_check("purity.call_effect", ps_purity("call_effect"), 0);
+ total = total + 1
+ fails = fails + ps_check("purity.call_effect", ps_purity("call_effect"), 0)
// ── 负控③ extern 调用(IR_CALL_EXTERN 出现即不纯)──
- total = total + 1; fails = fails + ps_check("purity.call_extern", ps_purity("call_extern"), 0);
+ total = total + 1
+ fails = fails + ps_check("purity.call_extern", ps_purity("call_extern"), 0)
// ── 负控④ 不可解析调用(runtime builtin:load64 无 FuncInfo)──
- total = total + 1; fails = fails + ps_check("purity.call_builtin", ps_purity("call_builtin"), 0);
+ total = total + 1
+ fails = fails + ps_check("purity.call_builtin", ps_purity("call_builtin"), 0)
// ── 负控⑤ 自递归(保守不纯:不动点永等不到自己被证明纯)──
- total = total + 1; fails = fails + ps_check("purity.self_rec", ps_purity("self_rec"), 0);
+ total = total + 1
+ fails = fails + ps_check("purity.self_rec", ps_purity("self_rec"), 0)
// ── 负控⑤b 互递归(SCC 保守;两成员都要钉)──
- total = total + 1; fails = fails + ps_check("purity.mut_rec_a", ps_purity("mut_rec_a"), 0);
- total = total + 1; fails = fails + ps_check("purity.mut_rec_b", ps_purity("mut_rec_b"), 0);
+ total = total + 1
+ fails = fails + ps_check("purity.mut_rec_a", ps_purity("mut_rec_a"), 0)
+ total = total + 1
+ fails = fails + ps_check("purity.mut_rec_b", ps_purity("mut_rec_b"), 0)
// ── 负控⑥ 泛型实例:与源函数同值。纯源:**两断**(同值 + 实例值 = 1)——
// 只断同值会被「两侧同为不纯」的退化实现假绿;只断实例值则漏掉源值。
- inst_p := ps_purity("id[int]");
- src_p := ps_purity("id");
- total = total + 1; fails = fails + ps_check("purity.generic_instance_pure", inst_p, 1);
- total = total + 1; fails = fails + ps_check_b("purity.generic_instance_eq_source", (inst_p == src_p), true);
+ inst_p := ps_purity("id[int]")
+ src_p := ps_purity("id")
+ total = total + 1
+ fails = fails + ps_check("purity.generic_instance_pure", inst_p, 1)
+ total = total + 1
+ fails = fails + ps_check_b("purity.generic_instance_eq_source", (inst_p == src_p), true)
// 负控⑥b 有效应泛型(体内有 store):实例与源同为 0(反向:防「实例恒纯」)
- g_inst := ps_purity("gid[int]");
- total = total + 1; fails = fails + ps_check("purity.generic_effect_instance", g_inst, 0);
- total = total + 1; fails = fails + ps_check_b("purity.generic_effect_eq_source", (g_inst == ps_purity("gid")), true);
+ g_inst := ps_purity("gid[int]")
+ total = total + 1
+ fails = fails + ps_check("purity.generic_effect_instance", g_inst, 0)
+ total = total + 1
+ fails = fails + ps_check_b("purity.generic_effect_eq_source", (g_inst == ps_purity("gid")), true)
// ── state 链面(Task 1 目的:效应调用重新进链;纯调用不入链;循环终止依赖)──
// ① 效应调用被链穿过:调用节点既要有入边(前 store → call)又要有出边
// (call → 后 store)——touch == 3。
- irf_ce := ps_ir_index_of("chain_effect");
- n_ce := ps_call_node(irf_ce, "effect");
- total = total + 1; fails = fails + ps_check("chain.impure_call_pierced", ps_state_touch(n_ce), 3);
+ irf_ce := ps_ir_index_of("chain_effect")
+ n_ce := ps_call_node(irf_ce, "effect")
+ total = total + 1
+ fails = fails + ps_check("chain.impure_call_pierced", ps_state_touch(n_ce), 3)
// ② 可证纯调用不被链触及:同形(store / call / store)下 touch == 0——
// 与 ① 只差被调者纯度 ⇒ 两条合起来把「按真纯度入链」钉死(退化实现
// 「全入链」挂②、「全不入链」挂①)。
- irf_cp := ps_ir_index_of("chain_pure");
- n_cp := ps_call_node(irf_cp, "pure_add");
- total = total + 1; fails = fails + ps_check("chain.pure_call_untouched", ps_state_touch(n_cp), 0);
+ irf_cp := ps_ir_index_of("chain_pure")
+ n_cp := ps_call_node(irf_cp, "pure_add")
+ total = total + 1
+ fails = fails + ps_check("chain.pure_call_untouched", ps_state_touch(n_cp), 0)
// ③ 循环终止依赖:链重放复刻 sg_pop 规则(regcfg §4.2)——循环体内的最后
// 副作用必须有边指向循环退出节点(label)。该规则随本次迁移从生成期移到
// 重放,缺判据则回归无感。
- irf_cl := ps_ir_index_of("chain_loop");
- total = total + 1; fails = fails + ps_check("chain.loop_exit_termination", ps_has_label_state_target(irf_cl), 1);
+ irf_cl := ps_ir_index_of("chain_loop")
+ total = total + 1
+ fails = fails + ps_check("chain.loop_exit_termination", ps_has_label_state_target(irf_cl), 1)
// ③' 负控:无循环的函数区间内不得出现指向 label 的链边(防「恒真」实现)
- total = total + 1; fails = fails + ps_check("chain.no_label_edge_without_loop",
- ps_has_label_state_target(irf_cp), 0);
+ total = total + 1
+ fails = fails + ps_check("chain.no_label_edge_without_loop",
+ ps_has_label_state_target(irf_cp), 0)
// ── Task 2:分类表补全(效应 opcode 全族入链;单一真源 = purity_op_effect)──
// ④ 验收例:effect 被调两次 ⇒ **两个** CALL 都在链上;同形纯调用 ⇒ 0。
- irf_tw := ps_ir_index_of("chain_two");
- total = total + 1; fails = fails + ps_check("chain.two_calls_exist",
- ps_count_call_nodes(irf_tw, "effect"), 2); // 非空断言(防「零入链」退化假绿)
- total = total + 1; fails = fails + ps_check("chain.two_impure_calls_in_chain",
- ps_calls_in_chain(irf_tw, "effect"), 2);
- total = total + 1; fails = fails + ps_check("chain.two_pure_call_untouched",
- ps_calls_in_chain(irf_tw, "pure_add"), 0);
+ irf_tw := ps_ir_index_of("chain_two")
+ total = total + 1
+ fails = fails + ps_check("chain.two_calls_exist",
+ ps_count_call_nodes(irf_tw, "effect"), 2) // 非空断言(防「零入链」退化假绿)
+ total = total + 1
+ fails = fails + ps_check("chain.two_impure_calls_in_chain",
+ ps_calls_in_chain(irf_tw, "effect"), 2)
+ total = total + 1
+ fails = fails + ps_check("chain.two_pure_call_untouched",
+ ps_calls_in_chain(irf_tw, "pure_add"), 0)
// ⑤ IR_CALL_EXTERN:extern 调用入链(前后 store 夹逼 ⇒ touch == 3)
- irf_ex := ps_ir_index_of("chain_extern_op");
- n_ex := ps_op_node(irf_ex, IR_CALL_EXTERN);
- total = total + 1; fails = fails + ps_check_b("chain.extern_op_exists", (n_ex >= 0), true);
- total = total + 1; fails = fails + ps_check("chain.extern_op_pierced", ps_state_touch(n_ex), 3);
+ irf_ex := ps_ir_index_of("chain_extern_op")
+ n_ex := ps_op_node(irf_ex, IR_CALL_EXTERN)
+ total = total + 1
+ fails = fails + ps_check_b("chain.extern_op_exists", (n_ex >= 0), true)
+ total = total + 1
+ fails = fails + ps_check("chain.extern_op_pierced", ps_state_touch(n_ex), 3)
// ⑥ IR_SPAWN(range-go 每迭代发射):入链
- irf_sp := ps_ir_index_of("chain_spawn_op");
- n_sp := ps_op_node(irf_sp, IR_SPAWN);
- total = total + 1; fails = fails + ps_check_b("chain.spawn_op_exists", (n_sp >= 0), true);
- total = total + 1; fails = fails + ps_check("chain.spawn_op_in_chain", ps_has_state_in(n_sp), 1);
+ irf_sp := ps_ir_index_of("chain_spawn_op")
+ n_sp := ps_op_node(irf_sp, IR_SPAWN)
+ total = total + 1
+ fails = fails + ps_check_b("chain.spawn_op_exists", (n_sp >= 0), true)
+ total = total + 1
+ fails = fails + ps_check("chain.spawn_op_in_chain", ps_has_state_in(n_sp), 1)
// ⑦ IR_YIELD(flow 函数体):入链
- irf_yl := ps_ir_index_of("chain_yield_op");
- n_yl := ps_op_node(irf_yl, IR_YIELD);
- total = total + 1; fails = fails + ps_check_b("chain.yield_op_exists", (n_yl >= 0), true);
- total = total + 1; fails = fails + ps_check("chain.yield_op_pierced", ps_state_touch(n_yl), 3);
+ irf_yl := ps_ir_index_of("chain_yield_op")
+ n_yl := ps_op_node(irf_yl, IR_YIELD)
+ total = total + 1
+ fails = fails + ps_check_b("chain.yield_op_exists", (n_yl >= 0), true)
+ total = total + 1
+ fails = fails + ps_check("chain.yield_op_pierced", ps_state_touch(n_yl), 3)
- print(int_str(total - fails)); print("/"); print(int_str(total)); println(" purity cases passed");
- if fails != 0 { return 1; }
- return 0;
-}
+ print(int_str(total - fails))
+ print("/")
+ print(int_str(total))
+ println(" purity cases passed")
+ if fails != 0:
+ return 1
+ return 0
diff --git a/src/compiler/region_check.cr b/src/compiler/region_check.cr
index 54c7bcbd..ef368441 100644
--- a/src/compiler/region_check.cr
+++ b/src/compiler/region_check.cr
@@ -2,29 +2,25 @@
// RegionCheck pass — verifies DEREF targets are in live subgraphs.
// Runs after PointerAnalysis (ptr_analysis.cr) which builds g_pts table.
-fn subgraph_containing(node_seq: int) -> int {
+fn subgraph_containing(node_seq: int) -> int:
// 显式映射:O(1) 归属查询(g_df_node_region 由 df_create_node 写入)
- if node_seq >= 0 && node_seq < g_df_node_count {
- return r64(g_df_node_region, node_seq * 8);
- }
- return -1;
-}
-
-fn is_in_unsafe(node_seq: int) -> int {
- si : ., mut = 0;
- loop { if si >= g_sg_count { break; }
- kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND);
- if kind == SG_UNSAFE {
- nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART);
- ncount := r64(g_sgs, si * ESZ_SG + OFF_SG_NCOUNT);
- if node_seq >= nstart && node_seq < nstart + ncount {
- return 1;
- }
- }
- si = si + 1;
- }
- return 0;
-}
+ if node_seq >= 0 && node_seq < g_df_node_count:
+ return r64(g_df_node_region, node_seq * 8)
+ return -1
+
+fn is_in_unsafe(node_seq: int) -> int:
+ si : ., mut = 0
+ loop:
+ if si >= g_sg_count:
+ break
+ kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND)
+ if kind == SG_UNSAFE:
+ nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART)
+ ncount := r64(g_sgs, si * ESZ_SG + OFF_SG_NCOUNT)
+ if node_seq >= nstart && node_seq < nstart + ncount:
+ return 1
+ si = si + 1
+ return 0
// ─── 逃逸判定的单源(#2026-09-20-1)───────────────────────────────────────
// 「某分配在节点 ni 已死」⟺ 它在某个**出口真的归还内存**的区域里分配,且 ni 落在该
@@ -58,53 +54,55 @@ fn is_in_unsafe(node_seq: int) -> int {
// 是 `TYP_REF`,且 `&局部 as *T`(REF→PTR cast)**本身即 TF01** ⇒ 由 `&局部` **构造不出**
// `TYP_PTR` 的区域局部形状。即:**本判定的 PTR 半边在当前基上对这一面是惰性的**,
// 实际活的是 REF 半边;并集保留(PTR 侧对 alloc()/FFI 派生值仍有效)。
-fn rc_sg_releases(sg: int) -> int {
- if sg < 0 { return 0; }
- k := r64(g_sgs, sg * ESZ_SG + OFF_SG_KIND);
- if k == SG_LOOP || k == SG_FOR || k == SG_UNSAFE { return 1; }
- return 0;
-}
+fn rc_sg_releases(sg: int) -> int:
+ if sg < 0:
+ return 0
+ k := r64(g_sgs, sg * ESZ_SG + OFF_SG_KIND)
+ if k == SG_LOOP || k == SG_FOR || k == SG_UNSAFE:
+ return 1
+ return 0
// 分配点 → 最近一个「出口归还内存」的区域(含自身;沿 OFF_SG_PARENT 上溯)。
// -1 = 无此祖先(函数级/无区域)⇒ 该分配在函数内不会死 ⇒ 不构成逃逸。
-fn rc_releasing_region(alloc_node: int) -> int {
- sg := subgraph_containing(alloc_node);
- loop {
- if sg < 0 { return -1; }
- if rc_sg_releases(sg) != 0 { return sg; }
- sg = r64(g_sgs, sg * ESZ_SG + OFF_SG_PARENT);
- }
-}
+fn rc_releasing_region(alloc_node: int) -> int:
+ sg := subgraph_containing(alloc_node)
+ loop:
+ if sg < 0:
+ return -1
+ if rc_sg_releases(sg) != 0:
+ return sg
+ sg = r64(g_sgs, sg * ESZ_SG + OFF_SG_PARENT)
// 第 bi 位(= 全局 alloc 序号,经 g_pa_alloc_nodes 映射到 DF 节点)的释放点。
// 返回 EXIT 序数;-1 = 该分配不被任何区域归还(或区域未关闭 = 仍存活)。
-fn rc_bit_exit(bi: int) -> int {
- alloc_node := r64(g_pa_alloc_nodes, bi * 8);
- sg := rc_releasing_region(alloc_node);
- if sg < 0 { return -1; }
- return r64(g_sgs, sg * ESZ_SG + OFF_SG_EXIT);
-}
-
-fn rc_bit_dead(bi: int, ni: int) -> int {
- ex := rc_bit_exit(bi);
- if ex < 0 { return 0; }
- if ni < ex { return 0; }
- return 1;
-}
+fn rc_bit_exit(bi: int) -> int:
+ alloc_node := r64(g_pa_alloc_nodes, bi * 8)
+ sg := rc_releasing_region(alloc_node)
+ if sg < 0:
+ return -1
+ return r64(g_sgs, sg * ESZ_SG + OFF_SG_EXIT)
+
+fn rc_bit_dead(bi: int, ni: int) -> int:
+ ex := rc_bit_exit(bi)
+ if ex < 0:
+ return 0
+ if ni < ex:
+ return 0
+ return 1
// pts 中是否已有分配在节点 ni 死亡(纯判定,不含重赋值清除规则)
-fn rc_pts_dead(pts: int, ni: int) -> int {
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= 64 { break; }
- if (pts / mask) % 2 == 1 {
- if rc_bit_dead(bi, ni) != 0 { return 1; }
- }
- mask = mask * 2;
- bi = bi + 1;
- }
- return 0;
-}
+fn rc_pts_dead(pts: int, ni: int) -> int:
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= 64:
+ break
+ if (pts / mask) % 2 == 1:
+ if rc_bit_dead(bi, ni) != 0:
+ return 1
+ mask = mask * 2
+ bi = bi + 1
+ return 0
// 重赋值清除:pts 是**流不敏感并集**,[lo, hi) 内一旦对该变量重赋值,并集就不再描述
// 它此刻持有什么 —— 拿失效的并集当事实用会误报(实测:循环里取 &arr[0]、循环后
@@ -115,65 +113,68 @@ fn rc_pts_dead(pts: int, ni: int) -> int {
// 已知不完整(登记):值为**跨调用结果**时 pts 为空(ptr_analysis.cr 的 CALL 分支
// 不做摘要传播,头注声称的 summary propagation 未实现)⇒ 会被当作「明确不逃逸」而
// 清除;该类真阳性转漏检,根因 = pts 流不敏感,非本批引入。
-fn rc_reassign_clears(ptr_var: int, lo: int, hi: int) -> int {
- saw_safe : int, mut = 0;
- i : ., mut = lo;
- loop { if i >= hi { break; }
- op := r64(g_df_nodes, i * ESZ_DFNODE + OFF_DF_OPCODE);
- d := r64(g_df_nodes, i * ESZ_DFNODE + OFF_DF_DEST);
- s1 := r64(g_df_nodes, i * ESZ_DFNODE + OFF_DF_S1);
- s2 := r64(g_df_nodes, i * ESZ_DFNODE + OFF_DF_S2);
- if op == IR_STORE && s1 == ptr_var {
- if s2 < 0 { return 0; }
- if rc_pts_dead(r64(g_pts, s2 * 8), i) != 0 { return 0; }
- saw_safe = 1;
- }
- if op == IR_PHI && d == ptr_var {
- if s1 < 0 || s2 < 0 { return 0; }
- if rc_pts_dead(r64(g_pts, s1 * 8), i) != 0 { return 0; }
- if rc_pts_dead(r64(g_pts, s2 * 8), i) != 0 { return 0; }
- saw_safe = 1;
- }
- i = i + 1;
- }
- return saw_safe;
-}
+fn rc_reassign_clears(ptr_var: int, lo: int, hi: int) -> int:
+ saw_safe : int, mut = 0
+ i : ., mut = lo
+ loop:
+ if i >= hi:
+ break
+ op := r64(g_df_nodes, i * ESZ_DFNODE + OFF_DF_OPCODE)
+ d := r64(g_df_nodes, i * ESZ_DFNODE + OFF_DF_DEST)
+ s1 := r64(g_df_nodes, i * ESZ_DFNODE + OFF_DF_S1)
+ s2 := r64(g_df_nodes, i * ESZ_DFNODE + OFF_DF_S2)
+ if op == IR_STORE && s1 == ptr_var:
+ if s2 < 0:
+ return 0
+ if rc_pts_dead(r64(g_pts, s2 * 8), i) != 0:
+ return 0
+ saw_safe = 1
+ if op == IR_PHI && d == ptr_var:
+ if s1 < 0 || s2 < 0:
+ return 0
+ if rc_pts_dead(r64(g_pts, s1 * 8), i) != 0:
+ return 0
+ if rc_pts_dead(r64(g_pts, s2 * 8), i) != 0:
+ return 0
+ saw_safe = 1
+ i = i + 1
+ return saw_safe
// 变量级判定:ptr_var 在节点 ni 是否持有已死指针。
// 类型门(S6):地址型 = TYP_PTR ∪ TYP_REF(只判 kind、不读 extra)。解引用读出的
// int 是普通数据、不是又一个指针 ⇒ 非地址型直接放行。
-fn rc_var_dead(ptr_var: int, ni: int) -> int {
- if ptr_var < 0 { return 0; }
- ti := irv_type(ptr_var);
- if ti < 0 || (get_type_kind(ti) != TYP_PTR && get_type_kind(ti) != TYP_REF) { return 0; }
- pts := r64(g_pts, ptr_var * 8);
- if pts == 0 { return 0; }
- mask : int, mut = 1;
- bi : ., mut = 0;
- loop { if bi >= 64 { break; }
- if (pts / mask) % 2 == 1 {
- ex := rc_bit_exit(bi);
- if ex >= 0 && ni >= ex {
- if rc_reassign_clears(ptr_var, ex, ni) == 0 { return 1; }
- }
- }
- mask = mask * 2;
- bi = bi + 1;
- }
- return 0;
-}
+fn rc_var_dead(ptr_var: int, ni: int) -> int:
+ if ptr_var < 0:
+ return 0
+ ti := irv_type(ptr_var)
+ if ti < 0 || (get_type_kind(ti) != TYP_PTR && get_type_kind(ti) != TYP_REF):
+ return 0
+ pts := r64(g_pts, ptr_var * 8)
+ if pts == 0:
+ return 0
+ mask : int, mut = 1
+ bi : ., mut = 0
+ loop:
+ if bi >= 64:
+ break
+ if (pts / mask) % 2 == 1:
+ ex := rc_bit_exit(bi)
+ if ex >= 0 && ni >= ex:
+ if rc_reassign_clears(ptr_var, ex, ni) == 0:
+ return 1
+ mask = mask * 2
+ bi = bi + 1
+ return 0
// 返回逃逸:返回的指针指向已退出的子图分配。
// 错误码 = B010 EC_B_ESCAPE(errors.md:245「Reference to local escapes the
// function」,例子即 `return &x`);修前误用 B011(码位错配)。
// 函数级(SG_FUNC)分配由 rc_releasing_region 自然放行 —— 无需特例。
-fn rc_return_escape(ni: int, s1: int) {
- if rc_var_dead(s1, ni) != 0 {
+fn rc_return_escape(ni: int, s1: int):
+ if rc_var_dead(s1, ni) != 0:
check_error(EC_B_ESCAPE,
"region escape: returning pointer to exited subgraph allocation",
- 0, 0);
- }
-}
+ 0, 0)
// 存储逃逸:*ptr = val 存入的指针指向已退出的子图分配 ⇒ 写出的引用悬垂。
// 修前本函数体的判定值被整行丢弃(`rc_pts_has_escaped(val_pts, ni, 0);` 同行注
@@ -181,53 +182,49 @@ fn rc_return_escape(ni: int, s1: int) {
// 触发(引入提交 92eec5a7 起即如此)。此处接回 check_error,范式同 DEREF/返回两处。
// ptr_var(存储目标)本批未用:其双边 outlives 比较(注释所述「val 的目标分配寿命
// ≥ ptr 的」)需要目标侧区域比较,属未实现设计,另登记(勿当作已实现)。
-fn rc_store_escape(ni: int, ptr_var: int, val_var: int) {
- if rc_var_dead(val_var, ni) != 0 {
+fn rc_store_escape(ni: int, ptr_var: int, val_var: int):
+ if rc_var_dead(val_var, ni) != 0:
check_error(EC_B_LIFETIME,
"store escape: storing pointer to exited subgraph allocation",
- 0, 0);
- }
-}
-
-fn region_check_func(nstart: int, ncount: int) {
- ni : ., mut = nstart;
- loop { if ni >= nstart + ncount { break; }
- op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE);
- d := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST);
- s1 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S1);
- s2 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S2);
-
- if is_in_unsafe(ni) != 0 { ni = ni + 1; continue; }
-
- if op == IR_DEREF && d >= 0 && s1 >= 0 {
- if rc_var_dead(s1, ni) != 0 {
+ 0, 0)
+
+fn region_check_func(nstart: int, ncount: int):
+ ni : ., mut = nstart
+ loop:
+ if ni >= nstart + ncount:
+ break
+ op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE)
+ d := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST)
+ s1 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S1)
+ s2 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S2)
+
+ if is_in_unsafe(ni) != 0:
+ ni = ni + 1
+ continue
+
+ if op == IR_DEREF && d >= 0 && s1 >= 0:
+ if rc_var_dead(s1, ni) != 0:
check_error(EC_B_LIFETIME,
"dangling pointer: allocation subgraph exited before deref",
- 0, 0);
- }
- }
+ 0, 0)
// Siebert: interprocedural escape via return
- if op == IR_RETURN && s1 >= 0 {
- rc_return_escape(ni, s1);
- }
+ if op == IR_RETURN && s1 >= 0:
+ rc_return_escape(ni, s1)
// Siebert: interprocedural escape via store
- if op == IR_STORE_PTR {
- rc_store_escape(ni, s1, s2);
- }
+ if op == IR_STORE_PTR:
+ rc_store_escape(ni, s1, s2)
- ni = ni + 1;
- }
-}
+ ni = ni + 1
-fn region_check_all() {
+fn region_check_all():
// Safety pass — always runs
- fi : ., mut = 0;
- loop { if fi >= g_ir_func_count { break; }
- nstart := r64(g_df_func_node_start, fi * 8);
- ncount := r64(g_df_func_node_count, fi * 8);
- region_check_func(nstart, ncount);
- fi = fi + 1;
- }
-}
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ nstart := r64(g_df_func_node_start, fi * 8)
+ ncount := r64(g_df_func_node_count, fi * 8)
+ region_check_func(nstart, ncount)
+ fi = fi + 1
diff --git a/src/compiler/ty_shadow.cr b/src/compiler/ty_shadow.cr
index 136d627e..36c413f1 100644
--- a/src/compiler/ty_shadow.cr
+++ b/src/compiler/ty_shadow.cr
@@ -75,7 +75,7 @@
// 本实现:翻译完成后**重探**再写;重探必落空槽(ti 图无环——子项 ti 恒小于父项,
// 父项此刻未入表),命中分支仅为防未来改动的兜底。
-TERM_MAP_INIT_CAP : int = 1024;
+TERM_MAP_INIT_CAP : int = 1024
// ─── 原生清单 → AK_*(**按语义逐项对应,不得按下标直通**;下标互换事实见文件头注)───
// 计划注释「AK_* 与 TI_* 前 7 项 1:1」与 spec §11 实测**不一致**:照抄骨架的
@@ -86,24 +86,24 @@ TERM_MAP_INIT_CAP : int = 1024;
// 注:TYP_DYN 行(TI_DYN=7)kind ≠ TYP_BASE → 不在此路,走 sh_term_of_ti 的 TYP_DYN 分支;
// TY_DEX_S 占位行(TI_DEX_S=8)经 sh_base_ak 归 AK_DEX(同值域不同表示)
// ——旧实现按行号白名单把它留给通用路径,两条路产出的项完全一致(仅缓存占用差异)。
-fn sh_native_ak(ti: int) -> int {
- if ti < 0 { return -1; }
+fn sh_native_ak(ti: int) -> int:
+ if ti < 0:
+ return -1
// **原门保留**(P2b Task 2 的关键点):本快路径只认「类型表本体 = TYP_BASE」的行;
// TYP_DYN 行与全部结构/命名行一律 -1(TI_DYN 走 sh_term_of_ti 的 TYP_DYN 分支,见文件头注)。
// ⚠ **不得**把本函数直接换成 iface_kind_of:后者对 TYP_DYN 行回 AK_DYN、对结构行回
// AK_SEQUENCE/…(= 注册表的分派面),与本层的「原生快路径」契约不同——两函数只用
// 同一个 TY_* 逐项分派表(iface_by_ty_code),门各自保留。
- if get_type_kind(ti) != TYP_BASE { return -1; }
- return iface_by_ty_code(get_type_data(ti));
-}
+ if get_type_kind(ti) != TYP_BASE:
+ return -1
+ return iface_by_ty_code(get_type_data(ti))
// TYP_BASE 的 data(TY_*)→ AK_*:同款语义对应(TY 序与 TI 序一致,故与 AK 下标同样
// 不可混用)。-1 = 无对应(调用方回退 AK_NAMED)。
// R2 P2b Task 2:实现已**单源化**到 iface_registry.cr 的 `iface_by_ty_code`(唯一实现;
// 逐项语义分派,含 TY_DEX_S→AK_DEX / TY_GENERIC_PARAM→AK_NAMED 两条已裁决灰格)。
-fn sh_base_ak(ty: int) -> int {
- return iface_by_ty_code(ty);
-}
+fn sh_base_ak(ty: int) -> int:
+ return iface_by_ty_code(ty)
// ─── 对照物(R2 P2b Task 2 的改动前实现字面拷贝)**R2 P5 Task 4 删除**───
// 用途曾是 `iface.by_ty_code_all_codes` / `iface.native_ak_all_rows`(逐 TY 码 × 逐 ti 行,
@@ -120,21 +120,22 @@ fn sh_base_ak(ty: int) -> int {
// 数组元素型 int→bool,第二次 diagnostics=0(应 1 条 Assignment type mismatch)。
// cap = 0 → 下次 sh_map_find 惰性重建(空槽全 -1);entries 归零(否则装填因子守卫按陈旧
// 计数提前扩容)。**R2 P5 Task 5**:影子期的 hits 复位已删(计数本体随影子层下线)。
-fn sh_map_reset() {
- g_term_map_cap = 0;
- g_term_map_entries = 0;
-}
-
-fn sh_map_cap_init() {
- if g_term_map_cap <= 0 {
- nc : ., mut = TERM_MAP_INIT_CAP;
- nb := alloc(nc * 16);
- i : ., mut = 0;
- loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; }
- g_term_map = nb;
- g_term_map_cap = nc;
- }
-}
+fn sh_map_reset():
+ g_term_map_cap = 0
+ g_term_map_entries = 0
+
+fn sh_map_cap_init():
+ if g_term_map_cap <= 0:
+ nc : ., mut = TERM_MAP_INIT_CAP
+ nb := alloc(nc * 16)
+ i : ., mut = 0
+ loop:
+ if i >= nc:
+ break
+ w64(nb, i * 16, -1)
+ i = i + 1
+ g_term_map = nb
+ g_term_map_cap = nc
// 无守卫探测(**只可在扩容守卫之后调用**;sh_map_rehash 重放时借道这里):
// 命中返回槽位,未命中返回空槽位(不插入)。
@@ -144,54 +145,61 @@ fn sh_map_cap_init() {
// (TF01 收口:checker.cr 的 `stmt_cannot_fall_through`/`loop_body_has_break` 落空分析 +
// type_engine.cr 的 `lits_copy` 返回型改 string),此处形态保留仅为 typed 探测的旧写法,
// 不再有「不许这么写」的合规约束(不过改写无益,故不动)。
-fn sh_map_find_nogrow(ti: int) -> int {
- cap := g_term_map_cap;
+fn sh_map_find_nogrow(ti: int) -> int:
+ cap := g_term_map_cap
// 非负槽位(负数取模 = 负下标 → 探针越界;与引擎 tt_mod 同式同因——直接复用引擎
// 该函数,避免本仓库第三份取模式各自漂移)
- p : ., mut = tt_mod(ti, cap);
- ret : ., mut = -1;
- loop {
- k := r64(g_term_map, p * 16);
- if k < 0 { ret = p; break; }
- if k == ti { ret = p; break; }
- p = p + 1; if p >= cap { p = 0; }
- }
- return ret;
-}
-
-fn sh_map_find(ti: int) -> int {
- sh_map_cap_init();
+ p : ., mut = tt_mod(ti, cap)
+ ret : ., mut = -1
+ loop:
+ k := r64(g_term_map, p * 16)
+ if k < 0:
+ ret = p
+ break
+ if k == ti:
+ ret = p
+ break
+ p = p + 1
+ if p >= cap:
+ p = 0
+ return ret
+
+fn sh_map_find(ti: int) -> int:
+ sh_map_cap_init()
// 装填因子守卫(**必须在探测前**):表满且键不存在时开放寻址永不退出(死循环)
- if (g_term_map_entries + 1) * 2 >= g_term_map_cap { sh_map_rehash(); }
- return sh_map_find_nogrow(ti);
-}
+ if (g_term_map_entries + 1) * 2 >= g_term_map_cap:
+ sh_map_rehash()
+ return sh_map_find_nogrow(ti)
// 扩容 = 重建 + **重放既有条目**(引擎 grow_tt_index/tt_reindex 同式);计数随重放重算
// (装填因子守卫读的就是它,不得沿用旧值)。
-fn sh_map_rehash() {
- old := g_term_map;
- old_cap := g_term_map_cap;
- nc : ., mut = old_cap * 2;
- if nc < TERM_MAP_INIT_CAP { nc = TERM_MAP_INIT_CAP; }
- nb := alloc(nc * 16);
- i : ., mut = 0;
- loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; }
- g_term_map = nb;
- g_term_map_cap = nc;
- g_term_map_entries = 0;
- j : ., mut = 0;
- loop {
- if j >= old_cap { break; }
- k := r64(old, j * 16);
- if k >= 0 {
- s := sh_map_find_nogrow(k);
- w64(g_term_map, s * 16, k);
- w64(g_term_map, s * 16 + 8, r64(old, j * 16 + 8));
- g_term_map_entries = g_term_map_entries + 1;
- }
- j = j + 1;
- }
-}
+fn sh_map_rehash():
+ old := g_term_map
+ old_cap := g_term_map_cap
+ nc : ., mut = old_cap * 2
+ if nc < TERM_MAP_INIT_CAP:
+ nc = TERM_MAP_INIT_CAP
+ nb := alloc(nc * 16)
+ i : ., mut = 0
+ loop:
+ if i >= nc:
+ break
+ w64(nb, i * 16, -1)
+ i = i + 1
+ g_term_map = nb
+ g_term_map_cap = nc
+ g_term_map_entries = 0
+ j : ., mut = 0
+ loop:
+ if j >= old_cap:
+ break
+ k := r64(old, j * 16)
+ if k >= 0:
+ s := sh_map_find_nogrow(k)
+ w64(g_term_map, s * 16, k)
+ w64(g_term_map, s * 16 + 8, r64(old, j * 16 + 8))
+ g_term_map_entries = g_term_map_entries + 1
+ j = j + 1
// TYP_TUPLE → AK_PRODUCT(参数链 = 逐字段项,顺序 = 声明顺序)。
// **实读布局**(checker.cr:118-131 type_equal 的 TUPLE 分支 + :2041-2050 字段访问 t.N):
@@ -209,11 +217,11 @@ fn sh_map_rehash() {
// `ty_sub == 1`,拒绝一律由 checker 的常量档约束承担。固定性位的消费者 = checker.cr
// `array_len_constraint_ok` 的**方向规则**(视图→固定拒绝)与后续横切形状(P3 Task 2)。
// -1 = 元素项译不成(调用方回 -1,不缓存)。
-fn sh_seq_term(elem_ti: int, fixed_len: int) -> int {
- el := sh_term_of_ti(elem_ti);
- if el < 0 { return -1; }
- return tt_atom(AK_SEQUENCE, fixed_len, tt_cons(el, tt_nil()));
-}
+fn sh_seq_term(elem_ti: int, fixed_len: int) -> int:
+ el := sh_term_of_ti(elem_ti)
+ if el < 0:
+ return -1
+ return tt_atom(AK_SEQUENCE, fixed_len, tt_cons(el, tt_nil()))
// AK_REF 链槽 0 = mut 标记(R2 P3 Task 1 起 mut **成为判定维度**,替代旧约定的「不入链」——
// 旧约定下 `&T` 与 `&mut T` 的项逐位相同 ⇒ 引擎判等价,而 legacy 比 extra(mut) 判不等 ⇒
@@ -221,9 +229,8 @@ fn sh_seq_term(elem_ti: int, fixed_len: int) -> int {
// 标记项 = tt_atom(AK_UNIT, mut, -1):**语法令牌**(b 槽 = 标记值,照 AK_NAMED 的 b = 行号
// 同约定),非类型集——引擎侧按**节点同一性**比较(type_engine.cr 的 tt_list_variance_at
// 槽 0 分支;不同标记 = 确定不匹配 ⇒ 0,不回 -1)。
-fn sh_ref_mut_marker(mutv: int) -> int {
- return tt_atom(AK_UNIT, mutv, -1);
-}
+fn sh_ref_mut_marker(mutv: int) -> int:
+ return tt_atom(AK_UNIT, mutv, -1)
// 名字令牌(P3 Task 1 起:变体身份链的 name **索引入链**升级为**令牌原子上链**)。
// 旧约定(Task 0)= `tt_cons(ei_name(ea), tt_cons(name_ni, tt_nil()))` 直接把 **name 索引**
@@ -234,24 +241,24 @@ fn sh_ref_mut_marker(mutv: int) -> int {
// (tt_type_elem_same)会读链元素的 class。⇒ 令牌改为**原子节点**
// `tt_atom(AK_UNIT, ni, -1)`(与 mut 标记同式;b = 值),只按**节点同一性**比较,
// 结构比较再也不可能把它当术语解释。语义等价(不同名字 → 不同节点;同名字 → 同节点)。
-fn sh_name_token(ni: int) -> int {
- return tt_atom(AK_UNIT, ni, -1);
-}
-
-fn sh_tuple_to_product(ti: int) -> int {
- cnt := get_type_data(ti);
- start := get_type_extra(ti);
- tail : ., mut = tt_nil();
- i : ., mut = cnt - 1;
- loop {
- if i < 0 { break; }
- et := sh_term_of_ti(r64(g_gen_apply_data, (start + i) * 8));
- if et < 0 { return -1; } // 任一字段无法翻译 → 整项无法翻译(不缓存)
- tail = tt_cons(et, tail);
- i = i - 1;
- }
- return tt_atom(AK_PRODUCT, -1, tail);
-}
+fn sh_name_token(ni: int) -> int:
+ return tt_atom(AK_UNIT, ni, -1)
+
+fn sh_tuple_to_product(ti: int) -> int:
+ cnt := get_type_data(ti)
+ start := get_type_extra(ti)
+ tail : ., mut = tt_nil()
+ i : ., mut = cnt - 1
+ loop:
+ if i < 0:
+ break
+ et := sh_term_of_ti(r64(g_gen_apply_data, (start + i) * 8))
+ if et < 0:
+ return -1
+ // 任一字段无法翻译 → 整项无法翻译(不缓存)
+ tail = tt_cons(et, tail)
+ i = i - 1
+ return tt_atom(AK_PRODUCT, -1, tail)
// ─── R2 P3 Task 4:null 项(`T? = T ∪ null` 的右支;`None` 类型的项)───
// 规范形态 = tt_atom(AK_NULL, -1, -1):**行号不入项**(b 槽是标注;此处刻意连标注都空)。
@@ -259,9 +266,8 @@ fn sh_tuple_to_product(ti: int) -> int {
// 会有 N 个「不同节点」——虽然引擎比较只看 a/c 两槽(b 是标注)⇒ 语义不受影响,但节点同一
// 性快路径(ty_sub 的 `a == b`、tt_norm 的哈希去重)会失去同项合并,读数与缓存都变差。
// 单点语义 ⇒ 项恒定,构造去重(tt_term 的哈希合表)保证全仓只有**一个** null 节点。
-fn sh_null_term() -> int {
- return tt_atom(AK_NULL, -1, -1);
-}
+fn sh_null_term() -> int:
+ return tt_atom(AK_NULL, -1, -1)
// ─── R2 P5 Task 3:命名面**身份链**(两构造点共用;取代「空链 + b 槽当身份」)───
// 语义:命名型(TYP_NAMED / TYP_GENERIC_PARAM / TYP_GENERIC_APPLY)的**身份** = 身份链:
@@ -278,119 +284,134 @@ fn sh_null_term() -> int {
// 命名面**不展开**(P1 裁决 + P3a 反证:展开项接进等价面 ⇒ 同形不同名 struct 判等)——
// 链里只有身份令牌与实参类型项,没有任何结构定义。
// -1 = 不可构造(行越界 / 基型非命名行 / 实参不可译)——调用方按桥接缺口上抛。
-fn sh_named_identity_term(ti: int) -> int {
- if ti < 0 { return -1; }
- ni := get_type_data(ti);
- if ni < 0 { return -1; }
- return tt_atom(AK_NAMED, ti, tt_cons(sh_name_token(ni), tt_nil()));
-}
+fn sh_named_identity_term(ti: int) -> int:
+ if ti < 0:
+ return -1
+ ni := get_type_data(ti)
+ if ni < 0:
+ return -1
+ return tt_atom(AK_NAMED, ti, tt_cons(sh_name_token(ni), tt_nil()))
// 泛型应用实参链(两构造点共用骨架;variant:0 = 桥接面递归 sh_term_of_ti /
// 1 = 签名面递归 sh_sig_term_of_ti)。
-fn sh_apply_args_chain(ti: int, variant: int) -> int {
- start := get_type_extra(ti);
- cnt := r64(g_gen_apply_data, start * 8);
- if cnt < 0 { return -1; }
- tail : ., mut = tt_nil();
- j : ., mut = cnt - 1;
- loop {
- if j < 0 { break; }
- ai := r64(g_gen_apply_data, (start + 1 + j) * 8);
- at : ., mut = -1;
- if variant == 0 { at = sh_term_of_ti(ai); } else { at = sh_sig_term_of_ti(ai); }
- if at < 0 { return -1; } // 任一实参不可译 ⇒ 整项不可译(不缓存)
- tail = tt_cons(at, tail);
- j = j - 1;
- }
- return tail;
-}
+fn sh_apply_args_chain(ti: int, variant: int) -> int:
+ start := get_type_extra(ti)
+ cnt := r64(g_gen_apply_data, start * 8)
+ if cnt < 0:
+ return -1
+ tail : ., mut = tt_nil()
+ j : ., mut = cnt - 1
+ loop:
+ if j < 0:
+ break
+ ai := r64(g_gen_apply_data, (start + 1 + j) * 8)
+ at : ., mut = -1
+ if variant == 0:
+ at = sh_term_of_ti(ai)
+ else:
+ at = sh_sig_term_of_ti(ai)
+ if at < 0:
+ return -1
+ // 任一实参不可译 ⇒ 整项不可译(不缓存)
+ tail = tt_cons(at, tail)
+ j = j - 1
+ return tail
// 泛型应用行 → 命名原子(身份 = 基名令牌 + 实参项链;b = 基型行 = 规范形)。-1 = 不可构造。
-fn sh_apply_identity_term(ti: int, variant: int) -> int {
- if ti < 0 { return -1; }
- base := get_type_data(ti);
- if get_type_kind(base) != TYP_NAMED { return -1; }
- bni := get_type_data(base);
- if bni < 0 { return -1; }
- tail := sh_apply_args_chain(ti, variant);
- if tail < 0 { return -1; }
- return tt_atom(AK_NAMED, base, tt_cons(sh_name_token(bni), tail));
-}
+fn sh_apply_identity_term(ti: int, variant: int) -> int:
+ if ti < 0:
+ return -1
+ base := get_type_data(ti)
+ if get_type_kind(base) != TYP_NAMED:
+ return -1
+ bni := get_type_data(base)
+ if bni < 0:
+ return -1
+ tail := sh_apply_args_chain(ti, variant)
+ if tail < 0:
+ return -1
+ return tt_atom(AK_NAMED, base, tt_cons(sh_name_token(bni), tail))
// ti → 类型项(带 per-ti 缓存;-1 = 无法翻译)
-fn sh_term_of_ti(ti: int) -> int {
- if ti < 0 { return -1; }
+fn sh_term_of_ti(ti: int) -> int:
+ if ti < 0:
+ return -1
// 原生快路径:无表读、不占缓存条目
- nak := sh_native_ak(ti);
- if nak >= 0 { return tt_atom(nak, ti, -1); }
- slot := sh_map_find(ti);
- if r64(g_term_map, slot * 16) == ti {
- return r64(g_term_map, slot * 16 + 8);
- }
+ nak := sh_native_ak(ti)
+ if nak >= 0:
+ return tt_atom(nak, ti, -1)
+ slot := sh_map_find(ti)
+ if r64(g_term_map, slot * 16) == ti:
+ return r64(g_term_map, slot * 16 + 8)
// 未命中:按 kind 翻译(递归子项)
- term : ., mut = -1;
- k1 := get_type_kind(ti);
- d1 := get_type_data(ti);
- if k1 < 0 { return -1; } // 行号越界(ti >= g_type_count)= 无法翻译
- if k1 == TYP_BASE {
- bak := sh_base_ak(d1);
- if bak >= 0 { term = tt_atom(bak, ti, -1); }
- } else if k1 == TYP_DYN {
+ term : ., mut = -1
+ k1 := get_type_kind(ti)
+ d1 := get_type_data(ti)
+ if k1 < 0:
+ return -1
+ // 行号越界(ti >= g_type_count)= 无法翻译
+ if k1 == TYP_BASE:
+ bak := sh_base_ak(d1)
+ if bak >= 0:
+ term = tt_atom(bak, ti, -1)
+ else if k1 == TYP_DYN:
// data = 类型集位图(0 = 单一已知类型)——计划表定 TYP_DYN → AK_DYN。位图是
// dyn 的**收窄**,AK_DYN 在引擎侧 = ⊤(与一切相容)→ 该项过宽(可致 Task 3
// 里同源 dyn 集被判「等价」的假信号);P1 不改引擎,先按表落 + 报告注记。
- term = tt_atom(AK_DYN, ti, -1);
- } else if k1 == TYP_ARRAY || k1 == TYP_SLICE {
+ term = tt_atom(AK_DYN, ti, -1)
+ else if k1 == TYP_ARRAY || k1 == TYP_SLICE:
// TYP_ARRAY 的 extra = N(长度),**不入身份**(R1 裁决)→ 参数链只含元素项,
// N 落 b 槽 = 固定性位(P3 Task 1;构造点单源化到 sh_seq_term)
- fl : ., mut = -1;
- if k1 == TYP_ARRAY { fl = get_type_extra(ti); }
- term = sh_seq_term(d1, fl);
- } else if k1 == TYP_PTR {
+ fl : ., mut = -1
+ if k1 == TYP_ARRAY:
+ fl = get_type_extra(ti)
+ term = sh_seq_term(d1, fl)
+ else if k1 == TYP_PTR:
// 同 PTR:元素入链(AK_PTR 槽 0 变型 = 不变,见 type_engine.cr 变型表);
// extra(asp 地址空间位)不入链——与 legacy 的 PTR 分支(只比 data)同语义
- in1 := sh_term_of_ti(d1);
- if in1 >= 0 { term = tt_atom(AK_PTR, -1, tt_cons(in1, tt_nil())); }
- } else if k1 == TYP_REF {
+ in1 := sh_term_of_ti(d1)
+ if in1 >= 0:
+ term = tt_atom(AK_PTR, -1, tt_cons(in1, tt_nil()))
+ else if k1 == TYP_REF:
// extra = mut 标记:**入链**(P3 Task 1)——链 = [mut 标记项, 元素项],标记与元素
// 各占一槽(槽 0 不变 / 槽 1 只读协变、可写不变,见 type_engine.cr 变型表)
- in2 := sh_term_of_ti(d1);
- if in2 >= 0 { term = tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(get_type_extra(ti)), tt_cons(in2, tt_nil()))); }
- } else if k1 == TYP_OPTIONAL {
+ in2 := sh_term_of_ti(d1)
+ if in2 >= 0:
+ term = tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(get_type_extra(ti)), tt_cons(in2, tt_nil())))
+ else if k1 == TYP_OPTIONAL:
// R2 P3 Task 4:`T?` = `T ∪ null`(spec §5.4)。这是桥接层**唯一**译作非原子项的行
// (其余行 → 单原子);依据 = 定义式本身(不是名义展开——T? 无名字可展开)。语义落点:
// 引擎对 union 的一切判定(包含/等价/不相交/穷尽性)零新规则。
- in3 := sh_term_of_ti(d1);
- if in3 >= 0 { term = tt_union(in3, sh_null_term()); }
- } else if k1 == TYP_NULL {
+ in3 := sh_term_of_ti(d1)
+ if in3 >= 0:
+ term = tt_union(in3, sh_null_term())
+ else if k1 == TYP_NULL:
// null 单点类型(`None` 值的类型):规范项 = null 原子(无参数、无 b 槽行号——同一
// 类型的不同出现点(每处 `None` 各一行)必须译成**同一**项,否则 `ty_sub(null, null)`
// 会走结构比较而非节点同一/规范化快路径(语义仍对,但多绕一圈且不可读)。
- term = sh_null_term();
- } else if k1 == TYP_TUPLE {
- term = sh_tuple_to_product(ti);
- } else if k1 == TYP_NAMED || k1 == TYP_GENERIC_PARAM {
+ term = sh_null_term()
+ else if k1 == TYP_TUPLE:
+ term = sh_tuple_to_product(ti)
+ else if k1 == TYP_NAMED || k1 == TYP_GENERIC_PARAM:
// R2 P5 Task 3:身份链(名字令牌)——取代原「空链 + b 槽当身份」(见
// sh_named_identity_term 文件头注)
- term = sh_named_identity_term(ti);
- } else if k1 == TYP_GENERIC_APPLY {
- term = sh_apply_identity_term(ti, 0);
- } else {
+ term = sh_named_identity_term(ti)
+ else if k1 == TYP_GENERIC_APPLY:
+ term = sh_apply_identity_term(ti, 0)
+ else:
// 未知 kind 保守归入命名类:**无链** ⇒ 引擎命名面域外(-1,见 te_named_pair 守卫)。
// 全部 kind 已在上面逐项分派 ⇒ 本分支不可达(防御面,非未覆盖面)。
- term = tt_atom(AK_NAMED, ti, -1);
- }
- if term < 0 { return -1; }
+ term = tt_atom(AK_NAMED, ti, -1)
+ if term < 0:
+ return -1
// 写回前**重探**(递归翻译期间可能已扩容——见文件头注记②)
- slot2 := sh_map_find(ti);
- if r64(g_term_map, slot2 * 16) == ti {
- return r64(g_term_map, slot2 * 16 + 8); // 兜底:递归期间同 ti 已入表
- }
- w64(g_term_map, slot2 * 16, ti);
- w64(g_term_map, slot2 * 16 + 8, term);
- g_term_map_entries = g_term_map_entries + 1;
- return term;
-}
+ slot2 := sh_map_find(ti)
+ if r64(g_term_map, slot2 * 16) == ti:
+ return r64(g_term_map, slot2 * 16 + 8) // 兜底:递归期间同 ti 已入表
+ w64(g_term_map, slot2 * 16, ti)
+ w64(g_term_map, slot2 * 16 + 8, term)
+ g_term_map_entries = g_term_map_entries + 1
+ return term
// ─── R2 P5 Task 2(D19/D21/D22/D23):DFNode 类型面单槽化 = 唯一分类表 + 拆分器 ───
// 单槽化(α,内存面):`OFF_DF_TK` = **类型项引用**(类型面唯一真源),
@@ -421,41 +442,36 @@ fn sh_term_of_ti(ti: int) -> int {
// 三态纪律(D23):类型面 op 的行**越出类型表**或**在域内但译不出项**(桥接缺口)
// ⇒ **建项失败**(`g_tk_face_fail` 置位)⇒ save 侧拒绝落盘(rc=1 + 诊断),绝不静默
// 留空项。`tk < 0` = 「无类型」(IR_LOAD/CALL 的未定型路径)不是行码,不算失败。
-fn sh_tk_is_type_face(opcode: int) -> int {
- if opcode == IR_CONST || opcode == IR_BINARY || opcode == IR_ALLOC ||
- opcode == IR_CALL || opcode == IR_LOAD || opcode == IR_I2F || opcode == IR_F2I {
- return 1;
- }
- return 0;
-}
+fn sh_tk_is_type_face(opcode: int) -> int:
+ if opcode == IR_CONST || opcode == IR_BINARY || opcode == IR_ALLOC || opcode == IR_CALL || opcode == IR_LOAD || opcode == IR_I2F || opcode == IR_F2I:
+ return 1
+ return 0
// 行三态(D23 判据面):-1 = 非行码(tk < 0 = 无类型,合法);0 = **不可译**(越界 /
// 桥接缺口 ⇒ 建项失败);1 = 可译(原子行 ⇒ 项;复合行 ⇒ 辅码保真)。
-fn sh_tk_row_state(tk: int) -> int {
- if tk < 0 { return -1; }
- if tk >= g_type_count { return 0; }
- if sh_term_of_ti(tk) < 0 { return 0; }
- return 1;
-}
+fn sh_tk_row_state(tk: int) -> int:
+ if tk < 0:
+ return -1
+ if tk >= g_type_count:
+ return 0
+ if sh_term_of_ti(tk) < 0:
+ return 0
+ return 1
// D21 契约的实现在 **type_terms.cr:tt_atom_of_term**(R2 P6 Task 3 整函数迁出:
// corearch 清单不含本文件,而 `load_ccr` 的项索引一致性校验 + corearch 回读通道
// 需要它)——本层及上层调用点一律用该单源入口,**不再**在此留第二定义。
// 分类(纯函数):0 = 类型行面(**项可逆**才归此面)/ 1 = 辅码面 / 2 = 无面。
-fn sh_tk_face_of_code(opcode: int, tk: int) -> int {
- if sh_tk_is_type_face(opcode) != 0 {
- if sh_tk_row_state(tk) == 1 {
- if tt_atom_of_term(sh_term_of_ti(tk)) == tk { return 0; }
- }
- return 1; // 复合行 / 越界 / 桥接缺口 / 负值 —— 一律辅码(码保真)
- }
- if opcode == IR_BOUNDS_CHECK || opcode == IR_DEREF || opcode == IR_STORE_PTR ||
- opcode == IR_SPAWN || opcode == IR_HOTPATCH_ROUTE {
- return 1;
- }
- return 2;
-}
+fn sh_tk_face_of_code(opcode: int, tk: int) -> int:
+ if sh_tk_is_type_face(opcode) != 0:
+ if sh_tk_row_state(tk) == 1:
+ if tt_atom_of_term(sh_term_of_ti(tk)) == tk:
+ return 0
+ return 1 // 复合行 / 越界 / 桥接缺口 / 负值 —— 一律辅码(码保真)
+ if opcode == IR_BOUNDS_CHECK || opcode == IR_DEREF || opcode == IR_STORE_PTR || opcode == IR_SPAWN || opcode == IR_HOTPATCH_ROUTE:
+ return 1
+ return 2
// 拆分器(**单源**;emit 与 `.cir` 装载侧共用):(opcode, tk) → (项槽, 辅码槽)。
// 出参经两个全局返回(Core 无多返回值)——**读前必先调用**(函数入口先置默认值,
@@ -466,9 +482,8 @@ fn sh_tk_face_of_code(opcode: int, tk: int) -> int {
// 该调用**不进**影子对账计数(hits/entries 只统计判定站点;本函数是载体面派生,
// 冷/暖两态与判定历史无关)——故 sh_term_of_ti 的命中计数先存后复原。
// entries(装填因子输入 = 真实占用槽数)**不复原**——复原即欺骗扩容守卫。
-fn sh_tk_split(opcode: int, tk: int) {
- sh_tk_split_impl(opcode, tk, 1);
-}
+fn sh_tk_split(opcode: int, tk: int):
+ sh_tk_split_impl(opcode, tk, 1)
// 装载侧变体(`.cir` 快照重派生):**不置 D23 失败位**。理由 = 判据面不同:
// · emit 路径(count_fail=1):类型面行的可译性是**真不变量**——行刚由前端/IR 生成
@@ -479,51 +494,50 @@ fn sh_tk_split(opcode: int, tk: int) {
// 在暖进程可能不存在。这是**预存的缓存面局限**(登记:报告 §5-④;β 盘面项索引
// 承接面 = P6),不是本进程的编译器 bug。代码由辅码槽保真 ⇒ 派生码仍逐字节正确,
// 只有该项在本进程不可重建(term = -1)。缓存命中**绝不**因此让编译失败。
-fn sh_tk_split_load(opcode: int, tk: int) {
- sh_tk_split_impl(opcode, tk, 0);
-}
-
-fn sh_tk_split_impl(opcode: int, tk: int, count_fail: int) {
- fac := sh_tk_face_of_code(opcode, tk);
- g_sh_slot_term = -1;
- g_sh_slot_aux = 0;
- if fac == 0 {
- g_sh_slot_term = sh_term_of_ti(tk);
- } else {
+fn sh_tk_split_load(opcode: int, tk: int):
+ sh_tk_split_impl(opcode, tk, 0)
+
+fn sh_tk_split_impl(opcode: int, tk: int, count_fail: int):
+ fac := sh_tk_face_of_code(opcode, tk)
+ g_sh_slot_term = -1
+ g_sh_slot_aux = 0
+ if fac == 0:
+ g_sh_slot_term = sh_term_of_ti(tk)
+ else:
// 码保真:旗标/宽度/计数/复合行码/无面 op 的非零码一律原样承载(含负码——
// IR_SPAWN 的 tk = -1 = 「动态 spawn 计数」,是合法辅码,**不得**钳成 0)。
// 辅码哨兵:0 = 无;非零(含负)= 该码本身。
- g_sh_slot_aux = tk;
+ g_sh_slot_aux = tk
// D23:类型面 op 的行**不可译**(越界/桥接缺口)⇒ 建项失败——复合行是
// 域内可译 ⇒ 正常路径,不置位。
- if count_fail != 0 {
- if sh_tk_is_type_face(opcode) != 0 && sh_tk_row_state(tk) == 0 { g_tk_face_fail = g_tk_face_fail + 1; }
- }
- }
-}
+ if count_fail != 0:
+ if sh_tk_is_type_face(opcode) != 0 && sh_tk_row_state(tk) == 0:
+ g_tk_face_fail = g_tk_face_fail + 1
// 槽 → 派生码(**唯一**派生点;dataflow.cr 的 lower_to_ccr / ir_gen.cr 的 emit /
// cir_cache.cr 的装载侧共用):辅码 ≠ 0 ⇒ 辅码;无项 ⇒ 0;否则 `atom_of(项)`
// (不可逆 ⇒ -1:显式、响亮,绝不近似成 0/1)。
-fn sh_dfn_code_of_slots(tk_term: int, tk_aux: int) -> int {
- if tk_aux != 0 { return tk_aux; }
- if tk_term < 0 { return 0; }
- return tt_atom_of_term(tk_term);
-}
+fn sh_dfn_code_of_slots(tk_term: int, tk_aux: int) -> int:
+ if tk_aux != 0:
+ return tk_aux
+ if tk_term < 0:
+ return 0
+ return tt_atom_of_term(tk_term)
// 兼容入口(自测/诊断面):单槽化前 `sh_tk_term_of_code(opcode, tk)` 的语义 =
// 「类型面派生出的项;其余 -1」——即拆分器的**项槽**输出,但**纯查询**:不写槽出参、
// 不计 D23 失败位(诊断调用不得污染落盘闸;有副作用的生产路径一律走 sh_tk_split)。
// 与 split 共用同一个分类函数 sh_tk_face_of_code ⇒ 规则单源,无第二份判定。
-fn sh_tk_term_of_code(opcode: int, tk: int) -> int {
- t : ., mut = -1;
- if sh_tk_face_of_code(opcode, tk) == 0 { t = sh_term_of_ti(tk); }
- return t;
-}
+fn sh_tk_term_of_code(opcode: int, tk: int) -> int:
+ t : ., mut = -1
+ if sh_tk_face_of_code(opcode, tk) == 0:
+ t = sh_term_of_ti(tk)
+ return t
// ─── 桥接统计(自测断言用;**R2 P5 Task 5**:影子期的 hits 通道已删——桥接缓存现有
// 唯一可观测面 = 占用槽数 entries(装填因子守卫的输入,恒等于真实占用))───
-fn sh_map_entries() -> int { return g_term_map_entries; }
+fn sh_map_entries() -> int:
+ return g_term_map_entries
// ─── R2 P3 Task 5:类型项文本化(诊断反例用)───
// 用途 = `tt_witness` 的反例项 → 人可读文本(P3 计划 Task 5 Step 3「诊断含反例值」)。
@@ -531,76 +545,108 @@ fn sh_map_entries() -> int { return g_term_map_entries; }
// 不得驻留新串(诊断文本一律用 dyn 串拼接;istr_get 读既有串)。
// 形态 = 结构化 JSON 风格(`int`/`string`/`sequence`/`{int, string}`/`A ∪ B`/`¬A`…);
// 未识别 tag → "?"(**不谎报**形态)。深度上限 = 避免病态项上的栈爆(超限 → "…")。
-fn tt_display_at(t: int, depth: int) -> string {
- if t < 0 { return "?"; }
- if depth > 24 { return "…"; }
- if t >= tt_count() { return "?"; }
- tg := tt_tag(t);
- if tg == TT_BOT { return "⊥"; }
- if tg == TT_TOP { return "⊤"; }
- if tg == TT_TOP_K { return "⊤" + int_str(tt_a(t)); }
- if tg == TT_UNION { return tt_display_at(tt_a(t), depth + 1) + " ∪ " + tt_display_at(tt_b(t), depth + 1); }
- if tg == TT_INTER { return tt_display_at(tt_a(t), depth + 1) + " ∩ " + tt_display_at(tt_b(t), depth + 1); }
- if tg == TT_NOT { return "¬" + tt_display_at(tt_a(t), depth + 1); }
- if tg == TT_MU { return "μ" + int_str(tt_a(t)) + "." + tt_display_at(tt_b(t), depth + 1); }
- if tg == TT_VAR { return "X" + int_str(tt_a(t)); }
- if tg == TT_NIL { return "nil"; }
- if tg == TT_CONS { return "cons(" + tt_display_at(tt_a(t), depth + 1) + ", " + tt_display_at(tt_b(t), depth + 1) + ")"; }
- if tg == TT_ATOM {
- ak := tt_a(t);
+fn tt_display_at(t: int, depth: int) -> string:
+ if t < 0:
+ return "?"
+ if depth > 24:
+ return "…"
+ if t >= tt_count():
+ return "?"
+ tg := tt_tag(t)
+ if tg == TT_BOT:
+ return "⊥"
+ if tg == TT_TOP:
+ return "⊤"
+ if tg == TT_TOP_K:
+ return "⊤" + int_str(tt_a(t))
+ if tg == TT_UNION:
+ return tt_display_at(tt_a(t), depth + 1) + " ∪ " + tt_display_at(tt_b(t), depth + 1)
+ if tg == TT_INTER:
+ return tt_display_at(tt_a(t), depth + 1) + " ∩ " + tt_display_at(tt_b(t), depth + 1)
+ if tg == TT_NOT:
+ return "¬" + tt_display_at(tt_a(t), depth + 1)
+ if tg == TT_MU:
+ return "μ" + int_str(tt_a(t)) + "." + tt_display_at(tt_b(t), depth + 1)
+ if tg == TT_VAR:
+ return "X" + int_str(tt_a(t))
+ if tg == TT_NIL:
+ return "nil"
+ if tg == TT_CONS:
+ return "cons(" + tt_display_at(tt_a(t), depth + 1) + ", " + tt_display_at(tt_b(t), depth + 1) + ")"
+ if tg == TT_ATOM:
+ ak := tt_a(t)
// AK_NAMED 单列提前返回(**不是**风格偏好):若并入下方 if-else 链,链内既有赋值分支
// 又有 return 分支 ⇒ 自托管 checker 报 `error[TC02]: If branches have different types`
// (本文件属 `check src/compiler` 语料 ⇒ 会给 CI 的 check 作业加一条**新**诊断——
// 实测 build10 前版本命中:`tt_display_at` 的 AK_FN/AK_NAMED 分支)。
- if ak == AK_NAMED {
- nb := tt_b(t);
- if nb >= 0 { return "named#" + int_str(nb); }
- return "named";
- }
- head : ., mut = "";
- if ak == AK_INT { head = "int"; }
- else if ak == AK_DEX { head = "dex"; }
- else if ak == AK_STRING { head = "string"; }
- else if ak == AK_BOOL { head = "bool"; }
- else if ak == AK_UNIT { head = "unit"; }
- else if ak == AK_NEVER { head = "never"; }
- else if ak == AK_CHAR { head = "char"; }
- else if ak == AK_DYN { head = "dyn"; }
- else if ak == AK_NULL { head = "null"; }
- else if ak == AK_PRODUCT { head = "product"; }
- else if ak == AK_SUM { head = "sum"; }
- else if ak == AK_SEQUENCE { head = "sequence"; }
- else if ak == AK_REF { head = "ref"; }
- else if ak == AK_PTR { head = "ptr"; }
- else if ak == AK_FN { head = "fn"; }
- else { head = "atom#" + int_str(ak); }
+ if ak == AK_NAMED:
+ nb := tt_b(t)
+ if nb >= 0:
+ return "named#" + int_str(nb)
+ return "named"
+ head : ., mut = ""
+ if ak == AK_INT:
+ head = "int"
+ else if ak == AK_DEX:
+ head = "dex"
+ else if ak == AK_STRING:
+ head = "string"
+ else if ak == AK_BOOL:
+ head = "bool"
+ else if ak == AK_UNIT:
+ head = "unit"
+ else if ak == AK_NEVER:
+ head = "never"
+ else if ak == AK_CHAR:
+ head = "char"
+ else if ak == AK_DYN:
+ head = "dyn"
+ else if ak == AK_NULL:
+ head = "null"
+ else if ak == AK_PRODUCT:
+ head = "product"
+ else if ak == AK_SUM:
+ head = "sum"
+ else if ak == AK_SEQUENCE:
+ head = "sequence"
+ else if ak == AK_REF:
+ head = "ref"
+ else if ak == AK_PTR:
+ head = "ptr"
+ else if ak == AK_FN:
+ head = "fn"
+ else:
+ head = "atom#" + int_str(ak)
// 参数链(AK_REF 的槽 0 是 mut 标记:语义为 &/&mut,照桥接约定还原)
- if ak == AK_REF && tt_c(t) >= 0 && tt_tag(tt_c(t)) == TT_CONS {
- m := tt_a(tt_c(t));
- mut_s : ., mut = "&";
- if tt_tag(m) == TT_ATOM && tt_a(m) == AK_UNIT && tt_b(m) == 1 { mut_s = "&mut "; }
- rest := tt_b(tt_c(t));
- if rest >= 0 && tt_tag(rest) == TT_CONS { return mut_s + tt_display_at(tt_a(rest), depth + 1); }
- return mut_s;
- }
- p := tt_c(t);
- if p < 0 || tt_tag(p) != TT_CONS { return head; }
- s : ., mut = head + "<";
- k : ., mut = 0;
- loop {
- if p < 0 { break; }
- if tt_tag(p) != TT_CONS { break; }
- if k > 0 { s = s + ", "; }
- s = s + tt_display_at(tt_a(p), depth + 1);
- p = tt_b(p);
- k = k + 1;
- }
- return s + ">";
- }
- return "?";
-}
-
-fn tt_display(t: int) -> string { return tt_display_at(t, 0); }
+ if ak == AK_REF && tt_c(t) >= 0 && tt_tag(tt_c(t)) == TT_CONS:
+ m := tt_a(tt_c(t))
+ mut_s : ., mut = "&"
+ if tt_tag(m) == TT_ATOM && tt_a(m) == AK_UNIT && tt_b(m) == 1:
+ mut_s = "&mut "
+ rest := tt_b(tt_c(t))
+ if rest >= 0 && tt_tag(rest) == TT_CONS:
+ return mut_s + tt_display_at(tt_a(rest), depth + 1)
+ return mut_s
+ p := tt_c(t)
+ if p < 0 || tt_tag(p) != TT_CONS:
+ return head
+ s : ., mut = head + "<"
+ k : ., mut = 0
+ loop:
+ if p < 0:
+ break
+ if tt_tag(p) != TT_CONS:
+ break
+ if k > 0:
+ s = s + ", "
+ s = s + tt_display_at(tt_a(p), depth + 1)
+ p = tt_b(p)
+ k = k + 1
+ return s + ">"
+ return "?"
+
+fn tt_display(t: int) -> string:
+ return tt_display_at(t, 0)
// ═══════════════ R2 P1 影子判定挂点 + 分类计数 + 摘要/转储:**R2 P5 Task 5 已删除** ═══════════════
// 本段原为影子通道本体——站点挂点(`sh_site_begin`,checker 的判定点各调一次)+ 站点 id↔语义表
@@ -652,90 +698,101 @@ fn tt_display(t: int) -> string { return tt_display_at(t, 0); }
// 类型节点,照 struct 的 OFF_SI_FIELD_TYPE_NODES 先例)。穷尽性按变体身份判定不受影响
// (现状模式面亦不按 payload 分解——EXPR_ENUMPAT 的子模式是另一条路径)。
-UNF_MAP_INIT_CAP : int = 256;
+UNF_MAP_INIT_CAP : int = 256
// 展开缓存随类型表作废(同 sh_map_reset 同因同式:init_types 行号空间复用 ⇒ 陈旧 ti→展开项
// 命中 = 把上一个请求的类型结构安到当前行上;长驻 corelsp 每请求一次 init_types)。
-fn sh_unf_map_reset() {
- g_unf_map_cap = 0;
- g_unf_entries = 0;
- g_unf_hits = 0;
-}
-
-fn sh_unf_cap_init() {
- if g_unf_map_cap <= 0 {
- nc : ., mut = UNF_MAP_INIT_CAP;
- nb := alloc(nc * 16);
- i : ., mut = 0;
- loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; }
- g_unf_map = nb;
- g_unf_map_cap = nc;
- }
-}
+fn sh_unf_map_reset():
+ g_unf_map_cap = 0
+ g_unf_entries = 0
+ g_unf_hits = 0
+
+fn sh_unf_cap_init():
+ if g_unf_map_cap <= 0:
+ nc : ., mut = UNF_MAP_INIT_CAP
+ nb := alloc(nc * 16)
+ i : ., mut = 0
+ loop:
+ if i >= nc:
+ break
+ w64(nb, i * 16, -1)
+ i = i + 1
+ g_unf_map = nb
+ g_unf_map_cap = nc
// 无守卫探测(**只可在扩容守卫之后调用**;重建重放借道)——形态照 sh_map_find_nogrow
// (typed 探测用 ret + break + 尾 return;函数体不以无 break 的 loop 收尾——自托管 checker
// 对该形态有 TF01 误报面,见该函数注记)。
-fn sh_unf_find_nogrow(ti: int) -> int {
- cap := g_unf_map_cap;
- p : ., mut = tt_mod(ti, cap);
- ret : ., mut = -1;
- loop {
- k := r64(g_unf_map, p * 16);
- if k < 0 { ret = p; break; }
- if k == ti { ret = p; break; }
- p = p + 1; if p >= cap { p = 0; }
- }
- return ret;
-}
-
-fn sh_unf_find(ti: int) -> int {
- sh_unf_cap_init();
+fn sh_unf_find_nogrow(ti: int) -> int:
+ cap := g_unf_map_cap
+ p : ., mut = tt_mod(ti, cap)
+ ret : ., mut = -1
+ loop:
+ k := r64(g_unf_map, p * 16)
+ if k < 0:
+ ret = p
+ break
+ if k == ti:
+ ret = p
+ break
+ p = p + 1
+ if p >= cap:
+ p = 0
+ return ret
+
+fn sh_unf_find(ti: int) -> int:
+ sh_unf_cap_init()
// 装填因子守卫(**必须在探测前**):表满且键不存在时开放寻址永不退出(死循环)
- if (g_unf_entries + 1) * 2 >= g_unf_map_cap { sh_unf_rehash(); }
- return sh_unf_find_nogrow(ti);
-}
+ if (g_unf_entries + 1) * 2 >= g_unf_map_cap:
+ sh_unf_rehash()
+ return sh_unf_find_nogrow(ti)
// 扩容 = 重建 + **重放既有条目**(引擎 grow_tt_index / 桥接 sh_map_rehash 同式);计数随重放重算
-fn sh_unf_rehash() {
- old := g_unf_map;
- old_cap := g_unf_map_cap;
- nc : ., mut = old_cap * 2;
- if nc < UNF_MAP_INIT_CAP { nc = UNF_MAP_INIT_CAP; }
- nb := alloc(nc * 16);
- i : ., mut = 0;
- loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; }
- g_unf_map = nb;
- g_unf_map_cap = nc;
- g_unf_entries = 0;
- j : ., mut = 0;
- loop {
- if j >= old_cap { break; }
- k := r64(old, j * 16);
- if k >= 0 {
- s := sh_unf_find_nogrow(k);
- w64(g_unf_map, s * 16, k);
- w64(g_unf_map, s * 16 + 8, r64(old, j * 16 + 8));
- g_unf_entries = g_unf_entries + 1;
- }
- j = j + 1;
- }
-}
-
-fn sh_unf_hits() -> int { return g_unf_hits; }
-fn sh_unf_entries() -> int { return g_unf_entries; }
+fn sh_unf_rehash():
+ old := g_unf_map
+ old_cap := g_unf_map_cap
+ nc : ., mut = old_cap * 2
+ if nc < UNF_MAP_INIT_CAP:
+ nc = UNF_MAP_INIT_CAP
+ nb := alloc(nc * 16)
+ i : ., mut = 0
+ loop:
+ if i >= nc:
+ break
+ w64(nb, i * 16, -1)
+ i = i + 1
+ g_unf_map = nb
+ g_unf_map_cap = nc
+ g_unf_entries = 0
+ j : ., mut = 0
+ loop:
+ if j >= old_cap:
+ break
+ k := r64(old, j * 16)
+ if k >= 0:
+ s := sh_unf_find_nogrow(k)
+ w64(g_unf_map, s * 16, k)
+ w64(g_unf_map, s * 16 + 8, r64(old, j * 16 + 8))
+ g_unf_entries = g_unf_entries + 1
+ j = j + 1
+
+fn sh_unf_hits() -> int:
+ return g_unf_hits
+fn sh_unf_entries() -> int:
+ return g_unf_entries
// 枚举变体名 → 变体下标(-1 = 该枚举无此变体名)。线性扫(容量批 T3 起无变体上限)。
-fn sh_enum_variant_index(ea: int, name_ni: int) -> int {
- i : ., mut = 0;
- ret : ., mut = -1;
- loop {
- if i >= ei_variant_count(ea) { break; }
- if ei_variant_name(ea, i) == name_ni { ret = i; break; }
- i = i + 1;
- }
- return ret;
-}
+fn sh_enum_variant_index(ea: int, name_ni: int) -> int:
+ i : ., mut = 0
+ ret : ., mut = -1
+ loop:
+ if i >= ei_variant_count(ea):
+ break
+ if ei_variant_name(ea, i) == name_ni:
+ ret = i
+ break
+ i = i + 1
+ return ret
// struct 第 fi 字段 → 项(-1 = 不可展开)。泛型形参代入照 checker.cr EXPR_FIELD 的路径
// (那里返回 ti、消费方是 checker;此处返回项):字段节点为 EXPR_IDENT 且名字 ∈ 该 struct 的
@@ -744,118 +801,125 @@ fn sh_enum_variant_index(ea: int, name_ni: int) -> int {
// 注:非应用形态下泛型形参保持**名义**(res_type_node 取该形参的类型行 ⇒ AK_NAMED 原子)——
// 不假装知道实参是什么(EXPR_FIELD 的落空路径同款)。嵌套代入(`Box[Box[T]]`)现状不可达:
// 形参只做**一层**代入(与 checker 现状一致;F4 同族缺陷,TODO #2026-09-11-4 / Task 5 收口)。
-fn sh_struct_field_term(sa: int, fi: int, ga: int) -> int {
- fnode := si_field_type_node(sa, fi);
- if fnode < 0 { return -1; }
- if ast_kind(fnode) == EXPR_IDENT {
- fni := ast_int_val(fnode);
- if is_struct_generic(sa, fni) {
- if ga >= 0 && get_type_kind(ga) == TYP_GENERIC_APPLY {
- gstart := get_type_extra(ga);
- gcnt := r64(g_gen_apply_data, gstart * 8);
- gpi : ., mut = 0;
- loop {
- if gpi >= si_generic_count(sa) { break; }
- if si_generic_name(sa, gpi) == fni {
- if gpi < gcnt { return sh_term_of_ti(r64(g_gen_apply_data, (gstart + 1 + gpi) * 8)); }
- break; // 实参缺位 → 落空到名义项(下方 res_type_node),不得取越界槽
- }
- gpi = gpi + 1;
- }
- }
- }
- }
- fti := res_type_node(fnode);
- if fti < 0 { return -1; }
- return sh_term_of_ti(fti);
-}
+fn sh_struct_field_term(sa: int, fi: int, ga: int) -> int:
+ fnode := si_field_type_node(sa, fi)
+ if fnode < 0:
+ return -1
+ if ast_kind(fnode) == EXPR_IDENT:
+ fni := ast_int_val(fnode)
+ if is_struct_generic(sa, fni):
+ if ga >= 0 && get_type_kind(ga) == TYP_GENERIC_APPLY:
+ gstart := get_type_extra(ga)
+ gcnt := r64(g_gen_apply_data, gstart * 8)
+ gpi : ., mut = 0
+ loop:
+ if gpi >= si_generic_count(sa):
+ break
+ if si_generic_name(sa, gpi) == fni:
+ if gpi < gcnt:
+ return sh_term_of_ti(r64(g_gen_apply_data, (gstart + 1 + gpi) * 8))
+ break // 实参缺位 → 落空到名义项(下方 res_type_node),不得取越界槽
+ gpi = gpi + 1
+ fti := res_type_node(fnode)
+ if fti < 0:
+ return -1
+ return sh_term_of_ti(fti)
// struct 命名行 / 泛型应用行 → AK_PRODUCT(参数链 = 逐字段项,**声明序**)。
// -1 = 不可展开(既非命名行也非泛型应用行 / 名字未声明为 struct / 任一字段不可展开 / 预算耗尽)。
-fn sh_struct_term(ti: int) -> int {
- if ti < 0 { return -1; }
- if get_type_kind(ti) < 0 { return -1; } // 行号越界(ti ≥ g_type_count)
- sa := find_struct_row_of(ti);
- if sa < 0 { return -1; }
- slot := sh_unf_find(ti);
- if r64(g_unf_map, slot * 16) == ti {
- g_unf_hits = g_unf_hits + 1;
- return r64(g_unf_map, slot * 16 + 8);
- }
- ga : ., mut = -1;
- if get_type_kind(ti) == TYP_GENERIC_APPLY { ga = ti; }
+fn sh_struct_term(ti: int) -> int:
+ if ti < 0:
+ return -1
+ if get_type_kind(ti) < 0:
+ return -1
+ // 行号越界(ti ≥ g_type_count)
+ sa := find_struct_row_of(ti)
+ if sa < 0:
+ return -1
+ slot := sh_unf_find(ti)
+ if r64(g_unf_map, slot * 16) == ti:
+ g_unf_hits = g_unf_hits + 1
+ return r64(g_unf_map, slot * 16 + 8)
+ ga : ., mut = -1
+ if get_type_kind(ti) == TYP_GENERIC_APPLY:
+ ga = ti
// CONS 链**逆序构造**(i 自末尾向前):DAG 项不可变,正向追加需改写已建项;逆序构造的
// 结果顺序仍 = 声明序(照 sh_tuple_to_product 同款同因)。
- tail : ., mut = tt_nil();
- i : ., mut = si_field_count(sa) - 1;
- loop {
- if i < 0 { break; }
- if tt_step() == -1 { return -1; } // 预算耗尽 → 上抛(不得当「空 product」)
- ft := sh_struct_field_term(sa, i, ga);
- if ft < 0 { return -1; } // 任一字段不可展开 ⇒ 整项不可展开(不缓存)
- tail = tt_cons(ft, tail);
- i = i - 1;
- }
- term := tt_atom(AK_PRODUCT, ti, tail);
+ tail : ., mut = tt_nil()
+ i : ., mut = si_field_count(sa) - 1
+ loop:
+ if i < 0:
+ break
+ if tt_step() == -1:
+ return -1
+ // 预算耗尽 → 上抛(不得当「空 product」)
+ ft := sh_struct_field_term(sa, i, ga)
+ if ft < 0:
+ return -1
+ // 任一字段不可展开 ⇒ 整项不可展开(不缓存)
+ tail = tt_cons(ft, tail)
+ i = i - 1
+ term := tt_atom(AK_PRODUCT, ti, tail)
// 写回前**重探**(字段解析期间可能已扩容——照 sh_term_of_ti 注记②同款)
- slot2 := sh_unf_find(ti);
- if r64(g_unf_map, slot2 * 16) == ti {
- g_unf_hits = g_unf_hits + 1;
- return r64(g_unf_map, slot2 * 16 + 8);
- }
- w64(g_unf_map, slot2 * 16, ti);
- w64(g_unf_map, slot2 * 16 + 8, term);
- g_unf_entries = g_unf_entries + 1;
- return term;
-}
+ slot2 := sh_unf_find(ti)
+ if r64(g_unf_map, slot2 * 16) == ti:
+ g_unf_hits = g_unf_hits + 1
+ return r64(g_unf_map, slot2 * 16 + 8)
+ w64(g_unf_map, slot2 * 16, ti)
+ w64(g_unf_map, slot2 * 16 + 8, term)
+ g_unf_entries = g_unf_entries + 1
+ return term
// 变体名 → 变体项(穷尽性**模式项**用;与域中的对应变体项**同一构造**——两者必须逐位相同,
// 否则补集判定失真)。name_ni 必须是该枚举**声明过的**变体名(否则 -1:不得为未声明变体臆造项)。
// ti 接受命名行与泛型应用行(变体身份与实参无关——payload 不入项时 Option[int]/Option[str]
// 的变体集相同,正是穷尽性所需)。
-fn sh_variant_term(ti: int, name_ni: int) -> int {
- ea := find_enum_row_of(ti);
- if ea < 0 { return -1; }
- if sh_enum_variant_index(ea, name_ni) < 0 { return -1; }
+fn sh_variant_term(ti: int, name_ni: int) -> int:
+ ea := find_enum_row_of(ti)
+ if ea < 0:
+ return -1
+ if sh_enum_variant_index(ea, name_ni) < 0:
+ return -1
// P3 Task 1:身份两名经 **sh_name_token** 上链(旧约定 = 裸 name 索引入链——索引用作
// 链元素时会被结构比较当术语下标解释,见 sh_name_token 注记);两构造点(域/模式项)
// 仍逐位同一 ✓
- return tt_atom(AK_SUM, ti, tt_cons(sh_name_token(ei_name(ea)), tt_cons(sh_name_token(name_ni), tt_nil())));
-}
+ return tt_atom(AK_SUM, ti, tt_cons(sh_name_token(ei_name(ea)), tt_cons(sh_name_token(name_ni), tt_nil())))
// enum 命名行 / 泛型应用行 → **域** = 各变体项之并(左深 union)。
// -1 = 不可展开(非枚举行 / 预算耗尽)。空枚举(0 变体)→ ⊥ = 无值可取(**唯一**的
// 「展开成功但域为空」形态;Task 3 判穷尽时对该形态须显式裁决——空域在补集语义下恒穷尽)。
-fn sh_enum_domain_term(ti: int) -> int {
- if ti < 0 { return -1; }
- if get_type_kind(ti) < 0 { return -1; }
- ea := find_enum_row_of(ti);
- if ea < 0 { return -1; }
- slot := sh_unf_find(ti);
- if r64(g_unf_map, slot * 16) == ti {
- g_unf_hits = g_unf_hits + 1;
- return r64(g_unf_map, slot * 16 + 8);
- }
- acc : ., mut = tt_bot();
- i : ., mut = 0;
- loop {
- if i >= ei_variant_count(ea) { break; }
- if tt_step() == -1 { return -1; }
- v := sh_variant_term(ti, ei_variant_name(ea, i));
- if v < 0 { return -1; }
- acc = tt_union(acc, v);
- i = i + 1;
- }
- slot2 := sh_unf_find(ti);
- if r64(g_unf_map, slot2 * 16) == ti {
- g_unf_hits = g_unf_hits + 1;
- return r64(g_unf_map, slot2 * 16 + 8);
- }
- w64(g_unf_map, slot2 * 16, ti);
- w64(g_unf_map, slot2 * 16 + 8, acc);
- g_unf_entries = g_unf_entries + 1;
- return acc;
-}
+fn sh_enum_domain_term(ti: int) -> int:
+ if ti < 0:
+ return -1
+ if get_type_kind(ti) < 0:
+ return -1
+ ea := find_enum_row_of(ti)
+ if ea < 0:
+ return -1
+ slot := sh_unf_find(ti)
+ if r64(g_unf_map, slot * 16) == ti:
+ g_unf_hits = g_unf_hits + 1
+ return r64(g_unf_map, slot * 16 + 8)
+ acc : ., mut = tt_bot()
+ i : ., mut = 0
+ loop:
+ if i >= ei_variant_count(ea):
+ break
+ if tt_step() == -1:
+ return -1
+ v := sh_variant_term(ti, ei_variant_name(ea, i))
+ if v < 0:
+ return -1
+ acc = tt_union(acc, v)
+ i = i + 1
+ slot2 := sh_unf_find(ti)
+ if r64(g_unf_map, slot2 * 16) == ti:
+ g_unf_hits = g_unf_hits + 1
+ return r64(g_unf_map, slot2 * 16 + 8)
+ w64(g_unf_map, slot2 * 16, ti)
+ w64(g_unf_map, slot2 * 16 + 8, acc)
+ g_unf_entries = g_unf_entries + 1
+ return acc
// 接口 → 形状项(方法集 = product of fn)——**仍为占位,恒 -1**(阻塞精确定位见下):
// 现状接口方法签名存**裸 TY_***(parser.cr:1671/1685 的 `unpack_type` ⇒ 非原生类型节点一律
@@ -877,185 +941,202 @@ fn sh_enum_domain_term(ti: int) -> int {
// 不变槽链比较)即给出签名相等判定(1/0;-1 面只剩建项失败)。
// dyn(位图行不参与规范形)与未知 kind ⇒ -1(未覆盖面,**不得**当 0/1)。
// 零 str_intern:全部走既有 ni/行(.ccr STR 段守)。
-fn sh_sig_term_of_ti(ti: int) -> int {
- if ti < 0 { return -1; }
- k := get_type_kind(ti);
- if k < 0 { return -1; }
- if k == TYP_BASE {
- d := get_type_data(ti);
- ak := sh_base_ak(d);
- if ak < 0 { return -1; }
- return tt_atom(ak, ti, -1);
- }
- if k == TYP_NAMED || k == TYP_GENERIC_PARAM {
+fn sh_sig_term_of_ti(ti: int) -> int:
+ if ti < 0:
+ return -1
+ k := get_type_kind(ti)
+ if k < 0:
+ return -1
+ if k == TYP_BASE:
+ d := get_type_data(ti)
+ ak := sh_base_ak(d)
+ if ak < 0:
+ return -1
+ return tt_atom(ak, ti, -1)
+ if k == TYP_NAMED || k == TYP_GENERIC_PARAM:
// 命名行:named_dedup 按名规范(同名恒同行);泛型形参行 = 声明点行(跨声明不同行 =
// 已登记面:签名内含泛型形参的匹配只在同一声明内成立)
// R2 P5 Task 3:身份链与 sh_term_of_ti 的命名分支**逐位同构**(同一 sh_name_token
// 链形态)——双构造点契约(计划停条件③;改动必须两点同时)。
- return sh_named_identity_term(ti);
- }
- if k == TYP_NULL { return sh_null_term(); }
- if k == TYP_ARRAY || k == TYP_SLICE {
- el := sh_sig_term_of_ti(get_type_data(ti));
- if el < 0 { return -1; }
- return tt_atom(AK_SEQUENCE, -1, tt_cons(el, tt_nil()));
- }
- if k == TYP_PTR {
- el2 := sh_sig_term_of_ti(get_type_data(ti));
- if el2 < 0 { return -1; }
- return tt_atom(AK_PTR, -1, tt_cons(el2, tt_nil()));
- }
- if k == TYP_REF {
- el3 := sh_sig_term_of_ti(get_type_data(ti));
- if el3 < 0 { return -1; }
- return tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(get_type_extra(ti)), tt_cons(el3, tt_nil())));
- }
- if k == TYP_OPTIONAL {
- el4 := sh_sig_term_of_ti(get_type_data(ti));
- if el4 < 0 { return -1; }
- return tt_union(el4, sh_null_term());
- }
- if k == TYP_TUPLE {
- cnt := get_type_data(ti);
- start := get_type_extra(ti);
- tail : ., mut = tt_nil();
- i : ., mut = cnt - 1;
- loop {
- if i < 0 { break; }
- et := sh_sig_term_of_ti(r64(g_gen_apply_data, (start + i) * 8));
- if et < 0 { return -1; }
- tail = tt_cons(et, tail);
- i = i - 1;
- }
- return tt_atom(AK_PRODUCT, -1, tail);
- }
- if k == TYP_GENERIC_APPLY {
+ return sh_named_identity_term(ti)
+ if k == TYP_NULL:
+ return sh_null_term()
+ if k == TYP_ARRAY || k == TYP_SLICE:
+ el := sh_sig_term_of_ti(get_type_data(ti))
+ if el < 0:
+ return -1
+ return tt_atom(AK_SEQUENCE, -1, tt_cons(el, tt_nil()))
+ if k == TYP_PTR:
+ el2 := sh_sig_term_of_ti(get_type_data(ti))
+ if el2 < 0:
+ return -1
+ return tt_atom(AK_PTR, -1, tt_cons(el2, tt_nil()))
+ if k == TYP_REF:
+ el3 := sh_sig_term_of_ti(get_type_data(ti))
+ if el3 < 0:
+ return -1
+ return tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(get_type_extra(ti)), tt_cons(el3, tt_nil())))
+ if k == TYP_OPTIONAL:
+ el4 := sh_sig_term_of_ti(get_type_data(ti))
+ if el4 < 0:
+ return -1
+ return tt_union(el4, sh_null_term())
+ if k == TYP_TUPLE:
+ cnt := get_type_data(ti)
+ start := get_type_extra(ti)
+ tail : ., mut = tt_nil()
+ i : ., mut = cnt - 1
+ loop:
+ if i < 0:
+ break
+ et := sh_sig_term_of_ti(r64(g_gen_apply_data, (start + i) * 8))
+ if et < 0:
+ return -1
+ tail = tt_cons(et, tail)
+ i = i - 1
+ return tt_atom(AK_PRODUCT, -1, tail)
+ if k == TYP_GENERIC_APPLY:
// R2 P5 Task 3:形态与 sh_term_of_ti 的 APPLY 分支**同构**(基型行 + [基名令牌,
// 实参项…])——不再只挂裸实参链(那是「基型行当身份」的旧形态:与桥接侧命名分支
// 失同步 ⇒ 两构造点对同型给出不同节点)。差别只剩实参项递归走**本构造点**
// (variant=1:签名面 N 不入项,见 sh_apply_args_chain 注)。
- return sh_apply_identity_term(ti, 1);
- }
- return -1; // TYP_DYN(位图行)/ 未知 kind:未覆盖面
-}
+ return sh_apply_identity_term(ti, 1)
+ return -1 // TYP_DYN(位图行)/ 未知 kind:未覆盖面
// 类型**节点** → 签名项(节点契约:<0 = 无节点 ⇒ unit;照 checker 的 `type_node > 0` 约定,
// 但用 -1 哨兵以免与「节点 0」混同)。res_type_node 的解析面 = 与其它消费点同一入口。
-fn sh_sig_term_of_node(node: int) -> int {
- if node < 0 { return sh_sig_term_of_ti(TI_UNIT); }
- ti := res_type_node(node);
- return sh_sig_term_of_ti(ti);
-}
+fn sh_sig_term_of_node(node: int) -> int:
+ if node < 0:
+ return sh_sig_term_of_ti(TI_UNIT)
+ ti := res_type_node(node)
+ return sh_sig_term_of_ti(ti)
// 接口方法签名的**参数项**(idx 自 0 起)。接收者槽(self_mode ≠ 0 且 idx == 0)= unit
// **占位**——接收者模式(self/&self/&mut self)是调用约定而非类型集维度,由消费方**显式比较**
//(`sh_iface_self_mode` / `sh_func_self_mode`);不为它造令牌原子的理由:令牌的 b 槽在引擎
// 的类级比较(只看 a/c 两槽)下不可见 ⇒ 模式 1/2/3 会互相判等(静默)。
-fn sh_iface_sig_param_term(ii: int, mi: int, idx: int) -> int {
- if ii < 0 || mi < 0 || idx < 0 { return -1; }
- if idx >= MAX_IFACE_METHOD_PARAMS { return -1; }
- mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD;
- if r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT) <= idx { return -1; }
- smode := r64(g_ifaces, mbase + OFF_IFM_SELF_MODE);
- if idx == 0 && smode != 0 { return sh_sig_term_of_ti(TI_UNIT); }
- return sh_sig_term_of_node(r64(g_ifaces, mbase + OFF_IFM_PARAM_NODES + idx * 8));
-}
-
-fn sh_iface_sig_ret_term(ii: int, mi: int) -> int {
- if ii < 0 || mi < 0 { return -1; }
- mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD;
- return sh_sig_term_of_node(r64(g_ifaces, mbase + OFF_IFM_RET_NODE));
-}
-
-fn sh_iface_self_mode(ii: int, mi: int) -> int {
- if ii < 0 || mi < 0 { return -1; }
- return r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD + OFF_IFM_SELF_MODE);
-}
+fn sh_iface_sig_param_term(ii: int, mi: int, idx: int) -> int:
+ if ii < 0 || mi < 0 || idx < 0:
+ return -1
+ if idx >= MAX_IFACE_METHOD_PARAMS:
+ return -1
+ mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD
+ if r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT) <= idx:
+ return -1
+ smode := r64(g_ifaces, mbase + OFF_IFM_SELF_MODE)
+ if idx == 0 && smode != 0:
+ return sh_sig_term_of_ti(TI_UNIT)
+ return sh_sig_term_of_node(r64(g_ifaces, mbase + OFF_IFM_PARAM_NODES + idx * 8))
+
+fn sh_iface_sig_ret_term(ii: int, mi: int) -> int:
+ if ii < 0 || mi < 0:
+ return -1
+ mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD
+ return sh_sig_term_of_node(r64(g_ifaces, mbase + OFF_IFM_RET_NODE))
+
+fn sh_iface_self_mode(ii: int, mi: int) -> int:
+ if ii < 0 || mi < 0:
+ return -1
+ return r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD + OFF_IFM_SELF_MODE)
// impl 侧(函数行)签名的**参数项**(idx 自 0 起;从 AST 形参链前扫解析——形参节点不连续,
// 每参的类型节点插在其后,照 ir_gen/checker 同款扫描约定)。接收者槽同占位约定。
-fn sh_func_sig_param_term(fi: int, idx: int) -> int {
- if fi < 0 || idx < 0 { return -1; }
- fn_node := fi_ast_node(fi);
- if fn_node < 0 { return -1; }
- if ast_kind(fn_node) != EXPR_FN { return -1; }
- if idx >= fi_param_count(fi) { return -1; }
- pn := ast_b(fn_node); // EXPR_FN: b = first param node(a = 函数名 ni——不是形参入口)
- pi : ., mut = 0;
- loop {
- if pn < 0 { return -1; }
- if pn >= g_ast_count { return -1; }
- if ast_kind(pn) == EXPR_PARAM {
- if pi == idx {
- mode := ast_int_val(pn);
- if mode == -1 { return -1; } // 变参:签名项不可表达(登记)
- if mode != 0 { return sh_sig_term_of_ti(TI_UNIT); }
- return sh_sig_term_of_node(ast_data(pn));
- }
- pi = pi + 1;
- }
- pn = pn + 1;
- }
- return -1;
-}
-
-fn sh_func_self_mode(fi: int) -> int {
- if fi < 0 { return -1; }
- fn_node := fi_ast_node(fi);
- if fn_node < 0 { return -1; }
- if ast_kind(fn_node) != EXPR_FN { return -1; }
- if fi_param_count(fi) <= 0 { return 0; }
- pn := ast_b(fn_node); // EXPR_FN: b = first param node
- loop {
- if pn < 0 { return -1; }
- if pn >= g_ast_count { return -1; }
- if ast_kind(pn) == EXPR_PARAM {
- m := ast_int_val(pn);
- if m == -1 { return -1; }
- return m;
- }
- pn = pn + 1;
- }
- return -1;
-}
+fn sh_func_sig_param_term(fi: int, idx: int) -> int:
+ if fi < 0 || idx < 0:
+ return -1
+ fn_node := fi_ast_node(fi)
+ if fn_node < 0:
+ return -1
+ if ast_kind(fn_node) != EXPR_FN:
+ return -1
+ if idx >= fi_param_count(fi):
+ return -1
+ pn := ast_b(fn_node) // EXPR_FN: b = first param node(a = 函数名 ni——不是形参入口)
+ pi : ., mut = 0
+ loop:
+ if pn < 0:
+ return -1
+ if pn >= g_ast_count:
+ return -1
+ if ast_kind(pn) == EXPR_PARAM:
+ if pi == idx:
+ mode := ast_int_val(pn)
+ if mode == -1:
+ return -1
+ // 变参:签名项不可表达(登记)
+ if mode != 0:
+ return sh_sig_term_of_ti(TI_UNIT)
+ return sh_sig_term_of_node(ast_data(pn))
+ pi = pi + 1
+ pn = pn + 1
+ return -1
+
+fn sh_func_self_mode(fi: int) -> int:
+ if fi < 0:
+ return -1
+ fn_node := fi_ast_node(fi)
+ if fn_node < 0:
+ return -1
+ if ast_kind(fn_node) != EXPR_FN:
+ return -1
+ if fi_param_count(fi) <= 0:
+ return 0
+ pn := ast_b(fn_node) // EXPR_FN: b = first param node
+ loop:
+ if pn < 0:
+ return -1
+ if pn >= g_ast_count:
+ return -1
+ if ast_kind(pn) == EXPR_PARAM:
+ m := ast_int_val(pn)
+ if m == -1:
+ return -1
+ return m
+ pn = pn + 1
+ return -1
// impl 侧函数行的返回项(解析规则 = check_func 的返回位逐字同款:非基型节点走
// res_type_node;基型/无节点走码表(域含 NEVER、缺 7 ⇒ unit 兜底))。
-fn sh_func_sig_ret_term(fi: int) -> int {
- if fi < 0 { return -1; }
- fn_node := fi_ast_node(fi);
- if fn_node < 0 { return -1; }
- if ast_kind(fn_node) != EXPR_FN { return -1; }
- rnode := ast_type_val(fn_node);
- ret_ti : ., mut = TI_UNIT;
- if rnode > 0 && ast_kind(rnode) != 0 {
- ret_ti = res_type_node(rnode);
- } else {
- rm := ty_code_to_ti(fi_return_type(fi));
- if rm >= 0 && rm != TI_DYN { ret_ti = rm; }
- }
- return sh_sig_term_of_ti(ret_ti);
-}
+fn sh_func_sig_ret_term(fi: int) -> int:
+ if fi < 0:
+ return -1
+ fn_node := fi_ast_node(fi)
+ if fn_node < 0:
+ return -1
+ if ast_kind(fn_node) != EXPR_FN:
+ return -1
+ rnode := ast_type_val(fn_node)
+ ret_ti : ., mut = TI_UNIT
+ if rnode > 0 && ast_kind(rnode) != 0:
+ ret_ti = res_type_node(rnode)
+ else:
+ rm := ty_code_to_ti(fi_return_type(fi))
+ if rm >= 0 && rm != TI_DYN:
+ ret_ti = rm
+ return sh_sig_term_of_ti(ret_ti)
// 函数行 → **fn 项**:`tt_atom(AK_FN, -1, [返回项, 参数项…])`(链序 = 返回在首,参数按声明序;
// 逆序构造,照 sh_tuple_to_product 同因)。b 槽留空(引擎比较只看 a/c ⇒ 方法名不参与判定)。
-fn sh_func_sig_term(fi: int) -> int {
- if fi < 0 { return -1; }
- pc := fi_param_count(fi);
- if pc < 0 || pc > MAX_FN_PARAMS { return -1; }
- rt := sh_func_sig_ret_term(fi);
- if rt < 0 { return -1; }
- tail : ., mut = tt_cons(rt, tt_nil());
- i : ., mut = pc - 1;
- loop {
- if i < 0 { break; }
- pt := sh_func_sig_param_term(fi, i);
- if pt < 0 { return -1; }
- tail = tt_cons(pt, tail);
- i = i - 1;
- }
- return tt_atom(AK_FN, -1, tail);
-}
+fn sh_func_sig_term(fi: int) -> int:
+ if fi < 0:
+ return -1
+ pc := fi_param_count(fi)
+ if pc < 0 || pc > MAX_FN_PARAMS:
+ return -1
+ rt := sh_func_sig_ret_term(fi)
+ if rt < 0:
+ return -1
+ tail : ., mut = tt_cons(rt, tt_nil())
+ i : ., mut = pc - 1
+ loop:
+ if i < 0:
+ break
+ pt := sh_func_sig_param_term(fi, i)
+ if pt < 0:
+ return -1
+ tail = tt_cons(pt, tail)
+ i = i - 1
+ return tt_atom(AK_FN, -1, tail)
// 接口 → 形状类型项(spec §2.3):`tt_atom(AK_PRODUCT, -1, [fn 项…])`,链序 = 方法声明序
// (与 `g_ifaces` 方法表同序——消费方按表索引取成员,见 type_engine 的轴 C)。成员 fn 项的
@@ -1063,55 +1144,66 @@ fn sh_func_sig_term(fi: int) -> int {
// -1 = 不可建(接口名未声明 / 方法数越界(>16)/ 任一签名项不可建 / 参数数越界(>8))。
// 零方法接口 ⇒ 空 product(`tt_nil()` 链)——空洞满足的载体(判定面见轴 C)。
// 三态纪律:-1 = 未覆盖面,**不得**被消费方当 0(不满足)或 1(满足)用。
-fn sh_iface_shape_term(iface_ni: int) -> int {
- if iface_ni < 0 { return -1; }
- ii := find_iface(iface_ni);
- if ii < 0 { return -1; }
- mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT);
- if mc < 0 { return -1; }
- if mc > MAX_IFACE_METHODS { return -1; }
- tail : ., mut = tt_nil();
- i : ., mut = mc - 1;
- loop {
- if i < 0 { break; }
- mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + i * ESZ_IFMETHOD;
- m_ni := r64(g_ifaces, mbase + OFF_IFM_NAME);
- pc := r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT);
- if pc < 0 || pc > MAX_IFACE_METHOD_PARAMS { return -1; }
- rt2 := sh_iface_sig_ret_term(ii, i);
- if rt2 < 0 { return -1; }
- ptail : ., mut = tt_cons(rt2, tt_nil());
- pj : ., mut = pc - 1;
- loop {
- if pj < 0 { break; }
- pterm := sh_iface_sig_param_term(ii, i, pj);
- if pterm < 0 { return -1; }
- ptail = tt_cons(pterm, ptail);
- pj = pj - 1;
- }
- tail = tt_cons(tt_atom(AK_FN, m_ni, ptail), tail);
- i = i - 1;
- }
- return tt_atom(AK_PRODUCT, -1, tail);
-}
+fn sh_iface_shape_term(iface_ni: int) -> int:
+ if iface_ni < 0:
+ return -1
+ ii := find_iface(iface_ni)
+ if ii < 0:
+ return -1
+ mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT)
+ if mc < 0:
+ return -1
+ if mc > MAX_IFACE_METHODS:
+ return -1
+ tail : ., mut = tt_nil()
+ i : ., mut = mc - 1
+ loop:
+ if i < 0:
+ break
+ mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + i * ESZ_IFMETHOD
+ m_ni := r64(g_ifaces, mbase + OFF_IFM_NAME)
+ pc := r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT)
+ if pc < 0 || pc > MAX_IFACE_METHOD_PARAMS:
+ return -1
+ rt2 := sh_iface_sig_ret_term(ii, i)
+ if rt2 < 0:
+ return -1
+ ptail : ., mut = tt_cons(rt2, tt_nil())
+ pj : ., mut = pc - 1
+ loop:
+ if pj < 0:
+ break
+ pterm := sh_iface_sig_param_term(ii, i, pj)
+ if pterm < 0:
+ return -1
+ ptail = tt_cons(pterm, ptail)
+ pj = pj - 1
+ tail = tt_cons(tt_atom(AK_FN, m_ni, ptail), tail)
+ i = i - 1
+ return tt_atom(AK_PRODUCT, -1, tail)
// 形状项的第 idx 个成员(fn 项;-1 = 越界/非形状项)。消费方(轴 C)按方法表索引取用。
-fn sh_shape_member_at(shp: int, idx: int) -> int {
- if shp < 0 || idx < 0 { return -1; }
- if tt_tag(shp) != TT_ATOM { return -1; }
- if tt_a(shp) != AK_PRODUCT { return -1; }
- c := tt_c(shp);
- i : ., mut = 0;
- loop {
- if i > idx { return -1; }
- if c < 0 { return -1; }
- if tt_tag(c) != TT_CONS { return -1; }
- if i == idx { return tt_a(c); }
- c = tt_b(c);
- i = i + 1;
- }
- return -1;
-}
+fn sh_shape_member_at(shp: int, idx: int) -> int:
+ if shp < 0 || idx < 0:
+ return -1
+ if tt_tag(shp) != TT_ATOM:
+ return -1
+ if tt_a(shp) != AK_PRODUCT:
+ return -1
+ c := tt_c(shp)
+ i : ., mut = 0
+ loop:
+ if i > idx:
+ return -1
+ if c < 0:
+ return -1
+ if tt_tag(c) != TT_CONS:
+ return -1
+ if i == idx:
+ return tt_a(c)
+ c = tt_b(c)
+ i = i + 1
+ return -1
// ─── R2 P3b Task 2:序列行的**固定性**读取(range 消费点的表示层维度)───
// 返回:固定长序列的 N(数组,≥0)/ -1(视图(切片)/ 非序列行 / 不可译行)。
@@ -1121,13 +1213,15 @@ fn sh_shape_member_at(shp: int, idx: int) -> int {
// 用途 = checker 的 range 索引分支(`arr[lo..hi]`):固定长 ⇒ 产视图(`[T]`);视图 ⇒ 现状
// `TI_UNIT`(IP_INDEX_RANGE 未接线,登记面)。**不得**把它读作身份/子类型维度(那是常量档的
// 职责;本站只决定「range 在本行上产不产视图」的结果形态,行为与改动前逐行相同)。
-fn sh_seq_fixed_len_of_ti(ti: int) -> int {
- t := sh_term_of_ti(ti);
- if t < 0 { return -1; }
- if tt_tag(t) != TT_ATOM { return -1; }
- if tt_a(t) != AK_SEQUENCE { return -1; }
- return tt_b(t);
-}
+fn sh_seq_fixed_len_of_ti(ti: int) -> int:
+ t := sh_term_of_ti(ti)
+ if t < 0:
+ return -1
+ if tt_tag(t) != TT_ATOM:
+ return -1
+ if tt_a(t) != AK_SEQUENCE:
+ return -1
+ return tt_b(t)
// ═══════════════ R2 P3 Task 3:match 穷尽性消费点(补集空性 + 具体变体反例)═══════════════
// 判据本体 = 引擎的**补集空性**(`ty_exhaustive`:domain \ ⋃patterns 的可满足性;P0 已落)。
@@ -1147,14 +1241,18 @@ fn sh_seq_fixed_len_of_ti(ti: int) -> int {
// (两个构造点不同 ⇒ 补集判定失真)。
// 臂模式 → 类别:1 = ⊤(通配 `_` / 绑定 ident)/ 2 = 枚举变体模式(须再判归属)/ 0 = 不可映射。
-fn sh_match_pat_kind(pat_node: int) -> int {
- if pat_node < 0 { return 0; }
- k := ast_kind(pat_node);
- if k == EXPR_WILDCARD { return 1; }
- if k == EXPR_IDENT { return 1; } // 绑定 = 通配(值域不绑;与 ir_gen 的按值比较臂不同层)
- if k == EXPR_ENUMPAT { return 2; }
- return 0; // 字面量 / struct 模式 / EXPR_NONE ⇒ 不可映射(登记)
-}
+fn sh_match_pat_kind(pat_node: int) -> int:
+ if pat_node < 0:
+ return 0
+ k := ast_kind(pat_node)
+ if k == EXPR_WILDCARD:
+ return 1
+ if k == EXPR_IDENT:
+ return 1
+ // 绑定 = 通配(值域不绑;与 ir_gen 的按值比较臂不同层)
+ if k == EXPR_ENUMPAT:
+ return 2
+ return 0 // 字面量 / struct 模式 / EXPR_NONE ⇒ 不可映射(登记)
// 变体模式 → **本枚举**变体下标(-1 = 不属本枚举 / 名字不可解析 / scrutinee 不可展开)。
// 名字两形态(parser.cr parse_pattern 的产物):裸变体名(`Red`)/ 限定名(`Color.Red`
@@ -1162,133 +1260,166 @@ fn sh_match_pat_kind(pat_node: int) -> int {
// get_variant_name_idx 一致;此处**不调 str_intern**——`.ccr` STR 段 = g_strs 全量,
// 见 P2b 附录 A.3-② 的硬判据约束)。前缀不是本枚举名 ⇒ -1(该模式对本域无覆盖,但按②取
// **不可判**而非 ∅)。变体名比较用 str_eq 逐项(不驻留新串)。
-fn sh_match_pat_variant(scrut_ti: int, pat_node: int) -> int {
- ea := find_enum_row_of(scrut_ti);
- if ea < 0 { return -1; }
- if pat_node < 0 { return -1; }
+fn sh_match_pat_variant(scrut_ti: int, pat_node: int) -> int:
+ ea := find_enum_row_of(scrut_ti)
+ if ea < 0:
+ return -1
+ if pat_node < 0:
+ return -1
// 名字槽 = **a**(parser.cr parse_pattern:`alloc_node(EXPR_ENUMPAT, ni, …)`;ir_gen 的
// 消费点同用 ast_a 取之。**不是** int_val——EXPR_IDENT 才把名字放 int_val)。
- pname := istr_get(ast_a(pat_node));
- slen := str_len(pname);
- dot : ., mut = -1;
- i : ., mut = 0;
- loop {
- if i >= slen { break; }
- c := get_char(pname, i);
- if str_eq(c, ".") != 0 { dot = i; }
- i = i + 1;
- }
- vname : ., mut = pname;
- if dot >= 0 {
- head := str_sub(pname, 0, dot);
- if str_eq(head, istr_get(ei_name(ea))) == 0 { return -1; }
- vname = str_sub(pname, dot + 1, slen - dot - 1);
- }
- vi : ., mut = 0;
- loop {
- if vi >= ei_variant_count(ea) { return -1; }
- if str_eq(istr_get(ei_variant_name(ea, vi)), vname) != 0 { return vi; }
- vi = vi + 1;
- }
- return -1;
-}
+ pname := istr_get(ast_a(pat_node))
+ slen := str_len(pname)
+ dot : ., mut = -1
+ i : ., mut = 0
+ loop:
+ if i >= slen:
+ break
+ c := get_char(pname, i)
+ if str_eq(c, ".") != 0:
+ dot = i
+ i = i + 1
+ vname : ., mut = pname
+ if dot >= 0:
+ head := str_sub(pname, 0, dot)
+ if str_eq(head, istr_get(ei_name(ea))) == 0:
+ return -1
+ vname = str_sub(pname, dot + 1, slen - dot - 1)
+ vi : ., mut = 0
+ loop:
+ if vi >= ei_variant_count(ea):
+ return -1
+ if str_eq(istr_get(ei_variant_name(ea, vi)), vname) != 0:
+ return vi
+ vi = vi + 1
+ return -1
// 变体下标 → 变体项(-1 = 越界/scrutinee 不可展开);与 sh_variant_term 的唯一入口关系
-fn sh_match_variant_term(scrut_ti: int, vi: int) -> int {
- ea := find_enum_row_of(scrut_ti);
- if ea < 0 { return -1; }
- if vi < 0 || vi >= ei_variant_count(ea) { return -1; }
- return sh_variant_term(scrut_ti, ei_variant_name(ea, vi));
-}
+fn sh_match_variant_term(scrut_ti: int, vi: int) -> int:
+ ea := find_enum_row_of(scrut_ti)
+ if ea < 0:
+ return -1
+ if vi < 0 || vi >= ei_variant_count(ea):
+ return -1
+ return sh_variant_term(scrut_ti, ei_variant_name(ea, vi))
// ─── 容量批 T3(裁-CAP-2 (a)):match 覆盖位**无界位图**(替换 2^vi 单 int)───
// 动机:变体上限解除后 `2^vi` 在 vi ≥ 63 溢出 ⇒ 覆盖判定失真(e70 实测 SIGFPE 136)。
// 位图 = 字节缓冲(每字节 8 位)+ 位下标寻址(本语言无按位与 ⇒ 除法/取模,照 iface_permits
// 惯例);**栈纪律**:`mc_begin` 记长度、`mc_end` 清零回退 ⇒ 嵌套 match 互不污染。
-fn grow_cov_bits(needed: int) {
- if needed <= g_cov_cap { return; }
- nc := g_cov_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; }
- nb := alloc(nc); _dyncpy(g_cov_bits, g_cov_cap, nb);
- z : ., mut = g_cov_cap;
- loop { if z >= nc { break; } store8(nb, z, 0); z = z + 1; }
- g_cov_bits = nb; g_cov_cap = nc;
-}
+fn grow_cov_bits(needed: int):
+ if needed <= g_cov_cap:
+ return
+ nc := g_cov_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ nb := alloc(nc)
+ _dyncpy(g_cov_bits, g_cov_cap, nb)
+ z : ., mut = g_cov_cap
+ loop:
+ if z >= nc:
+ break
+ store8(nb, z, 0)
+ z = z + 1
+ g_cov_bits = nb
+ g_cov_cap = nc
// 进入一次 match 覆盖收集:返回当前长度(供 mc_end 回退)
-fn mc_begin() -> int { return g_cov_len; }
-fn mc_add(vi: int) {
- if vi < 0 { return; }
- grow_cov_bits(vi / 8 + 1);
- if vi + 1 > g_cov_len { g_cov_len = vi + 1; }
- b := bu8(g_cov_bits, vi / 8);
- pw : ., mut = 1;
- k : ., mut = vi % 8;
- loop { if k <= 0 { break; } pw = pw * 2; k = k - 1; }
- if (b / pw) % 2 == 0 { store8(g_cov_bits, vi / 8, b + pw); }
-}
-fn mc_has(vi: int) -> int {
- if vi < 0 { return 0; }
- if vi >= g_cov_len { return 0; }
- if vi / 8 >= g_cov_cap { return 0; }
- b := bu8(g_cov_bits, vi / 8);
- pw : ., mut = 1;
- k : ., mut = vi % 8;
- loop { if k <= 0 { break; } pw = pw * 2; k = k - 1; }
- return (b / pw) % 2;
-}
+fn mc_begin() -> int:
+ return g_cov_len
+fn mc_add(vi: int):
+ if vi < 0:
+ return
+ grow_cov_bits(vi / 8 + 1)
+ if vi + 1 > g_cov_len:
+ g_cov_len = vi + 1
+ b := bu8(g_cov_bits, vi / 8)
+ pw : ., mut = 1
+ k : ., mut = vi % 8
+ loop:
+ if k <= 0:
+ break
+ pw = pw * 2
+ k = k - 1
+ if (b / pw) % 2 == 0:
+ store8(g_cov_bits, vi / 8, b + pw)
+fn mc_has(vi: int) -> int:
+ if vi < 0:
+ return 0
+ if vi >= g_cov_len:
+ return 0
+ if vi / 8 >= g_cov_cap:
+ return 0
+ b := bu8(g_cov_bits, vi / 8)
+ pw : ., mut = 1
+ k : ., mut = vi % 8
+ loop:
+ if k <= 0:
+ break
+ pw = pw * 2
+ k = k - 1
+ return (b / pw) % 2
// 首个未覆盖位(-1 = 全覆盖);三态口径与 sh_match_first_missing 同
-fn mc_first_missing(count: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= count { return -1; }
- if mc_has(i) == 0 { return i; }
- i = i + 1;
- }
- return -1;
-}
+fn mc_first_missing(count: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= count:
+ return -1
+ if mc_has(i) == 0:
+ return i
+ i = i + 1
+ return -1
// 退出:清零本层用过的位并回退长度(嵌套安全)
-fn mc_end(saved: int) {
- i : ., mut = saved;
- loop {
- if i >= g_cov_len { break; }
- if i / 8 < g_cov_cap { store8(g_cov_bits, i / 8, 0); }
- i = i + 1;
- }
- g_cov_len = saved;
-}
+fn mc_end(saved: int):
+ i : ., mut = saved
+ loop:
+ if i >= g_cov_len:
+ break
+ if i / 8 < g_cov_cap:
+ store8(g_cov_bits, i / 8, 0)
+ i = i + 1
+ g_cov_len = saved
// 覆盖位(**遗留 API,仅供 selftest 的 ≤62 域使用**):bit(vi) = 2^vi(本语言无移位 ⇒
// 循环乘 2)。**生产路径自容量批 T3 起改用无界位图 `mc_*`**(本函数在 vi ≥ 63 溢出——
// 旧前提「MAX_ENUM_VARIANTS = 16 保证不溢出」已随变体上限解除而失效)。
-fn sh_match_bit(vi: int) -> int {
- if vi < 0 { return 0; }
- b : ., mut = 1;
- k : ., mut = vi;
- loop { if k <= 0 { break; } b = b * 2; k = k - 1; }
- return b;
-}
+fn sh_match_bit(vi: int) -> int:
+ if vi < 0:
+ return 0
+ b : ., mut = 1
+ k : ., mut = vi
+ loop:
+ if k <= 0:
+ break
+ b = b * 2
+ k = k - 1
+ return b
// 首个**未覆盖**变体下标(-1 = 全覆盖 = 反例面为空)。反例命名 = 本函数(头注③);位测试照
// iface_permits 的 (bits / bit) % 2 惯例(**无按位与运算符**;bits ≥ 0、bit > 0 ⇒ 取模非负)。
-fn sh_match_first_missing(cover_bits: int, count: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= count { return -1; }
- b := sh_match_bit(i); // i ≥ 0 ⇒ b ≥ 1(除零不可达)
- if (cover_bits / b) % 2 == 0 { return i; }
- i = i + 1;
- }
- return -1;
-}
+fn sh_match_first_missing(cover_bits: int, count: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= count:
+ return -1
+ b := sh_match_bit(i) // i ≥ 0 ⇒ b ≥ 1(除零不可达)
+ if (cover_bits / b) % 2 == 0:
+ return i
+ i = i + 1
+ return -1
// 穷尽性三态:1 = 穷尽(补集空)/ 0 = 不穷尽(有反例变体)/ -1 = **不判**(域不可展开 /
// 模式不可映射 / 引擎未知=预算耗尽)。消费方:0 → 诊断 + 反例命名;1/-1 → 零动作。
// R2 P3 Task 4:域面扩一条 —— `T?`(TYP_OPTIONAL)的域 = `T ∪ null`(sh_match_domain_term)。
-fn sh_match_exhaustive(scrut_ti: int, pat_terms: int, unmappable: int) -> int {
- if unmappable != 0 { return -1; }
- dom := sh_match_domain_term(scrut_ti);
- if dom < 0 { return -1; } // 非枚举/非可选域 ⇒ 不判(域限定的显式登记)
- return ty_exhaustive(dom, pat_terms);
-}
+fn sh_match_exhaustive(scrut_ti: int, pat_terms: int, unmappable: int) -> int:
+ if unmappable != 0:
+ return -1
+ dom := sh_match_domain_term(scrut_ti)
+ if dom < 0:
+ return -1
+ // 非枚举/非可选域 ⇒ 不判(域限定的显式登记)
+ return ty_exhaustive(dom, pat_terms)
// ═══════════════ R2 P3 Task 4:联合/可选(`T?` = `T ∪ null`)的 match 域面 ═══════════════
// 域:枚举行 → 变体集之并(Task 0/3 的 sh_enum_domain_term);**TYP_OPTIONAL 行 → T ∪ null**。
@@ -1299,33 +1430,39 @@ fn sh_match_exhaustive(scrut_ti: int, pat_terms: int, unmappable: int) -> int {
// ⇒ -1(不可映射,同 Task 3 的②:不得当 ∅ 或 ⊤)。
// 名字形态:仅裸名 `Some`/`None`(**限定名不接受**——可选无类型名可作前缀;用户声明
// `enum Option` 时那走枚举域那条路,与本路互不干扰)。
-fn sh_match_domain_term(ti: int) -> int {
- if ti < 0 { return -1; }
- if get_type_kind(ti) == TYP_OPTIONAL {
- in5 := sh_term_of_ti(get_type_data(ti));
- if in5 < 0 { return -1; } // 内层不可译 ⇒ 域不可展开(不判)
- return tt_union(in5, sh_null_term());
- }
- return sh_enum_domain_term(ti);
-}
+fn sh_match_domain_term(ti: int) -> int:
+ if ti < 0:
+ return -1
+ if get_type_kind(ti) == TYP_OPTIONAL:
+ in5 := sh_term_of_ti(get_type_data(ti))
+ if in5 < 0:
+ return -1
+ // 内层不可译 ⇒ 域不可展开(不判)
+ return tt_union(in5, sh_null_term())
+ return sh_enum_domain_term(ti)
// 可选模式 → 分支下标(0 = 有值 / 1 = null;-1 = 不可映射或非可选 scrutinee)。
// 名字槽 = ast_a(EXPR_ENUMPAT 契约,Task 3 §6-②);`Some`/`None` 是关键字名。
-fn sh_match_opt_pat(scrut_ti: int, pat_node: int) -> int {
- if scrut_ti < 0 { return -1; }
- if get_type_kind(scrut_ti) != TYP_OPTIONAL { return -1; }
- if pat_node < 0 { return -1; }
- pname := istr_get(ast_a(pat_node));
- if str_eq(pname, "Some") != 0 { return 0; } // `Some(…)` 与裸 `Some` 同判(载荷绑定不参与)
- if str_eq(pname, "None") != 0 { return 1; }
- return -1;
-}
+fn sh_match_opt_pat(scrut_ti: int, pat_node: int) -> int:
+ if scrut_ti < 0:
+ return -1
+ if get_type_kind(scrut_ti) != TYP_OPTIONAL:
+ return -1
+ if pat_node < 0:
+ return -1
+ pname := istr_get(ast_a(pat_node))
+ if str_eq(pname, "Some") != 0:
+ return 0
+ // `Some(…)` 与裸 `Some` 同判(载荷绑定不参与)
+ if str_eq(pname, "None") != 0:
+ return 1
+ return -1
// 分支下标 → 覆盖项(与 sh_match_domain_term 的析取支**同一构造**——两个构造点不同 ⇒ 补集失真)。
-fn sh_match_opt_term(scrut_ti: int, part: int) -> int {
- if part == 0 { return sh_term_of_ti(get_type_data(scrut_ti)); }
- return sh_null_term();
-}
+fn sh_match_opt_term(scrut_ti: int, part: int) -> int:
+ if part == 0:
+ return sh_term_of_ti(get_type_data(scrut_ti))
+ return sh_null_term()
// ─── R2 P3 Task 4:枚举变体**载荷项**(T0 交接 ① 的消费面;载荷类型节点列的唯一读取点)───
// 背景(Task 0 §5-①):枚举表旧布局只存载荷**裸 TY 码**(OFF_EV_TYPES),非基型一律塌缩为
@@ -1336,53 +1473,59 @@ fn sh_match_opt_term(scrut_ti: int, part: int) -> int {
// 返回:单载荷 = 该载荷项;多载荷 = AK_PRODUCT 链(**声明序**,逆序构造);**0 载荷(tag 变体)→ -1**
// (语义域外登记:载荷为空 ≠ 载荷 unit——不发明「tag 变体 = 单点」的项,Task 5/6 若需要另裁)。
// -1 = 不可展开(非枚举行 / 无此变体名 / 无载荷 / 载荷节点缺失 / 任一载荷不可译 / 预算耗尽)。
-fn sh_variant_payload_at(ea: int, vi: int, i: int, ga: int) -> int {
- pn := ei_variant_type_node(ea, vi, i);
- if pn < 0 { return -1; }
- if ast_kind(pn) == EXPR_IDENT {
- pni := ast_int_val(pn);
- gi2 : ., mut = 0;
- loop {
- if gi2 >= ei_generic_count(ea) { break; }
- if ei_generic_name(ea, gi2) == pni {
+fn sh_variant_payload_at(ea: int, vi: int, i: int, ga: int) -> int:
+ pn := ei_variant_type_node(ea, vi, i)
+ if pn < 0:
+ return -1
+ if ast_kind(pn) == EXPR_IDENT:
+ pni := ast_int_val(pn)
+ gi2 : ., mut = 0
+ loop:
+ if gi2 >= ei_generic_count(ea):
+ break
+ if ei_generic_name(ea, gi2) == pni:
// 泛型形参:泛型应用行的对应实参(缺位 → 落空到名义,照 sh_struct_field_term)
- if ga >= 0 && get_type_kind(ga) == TYP_GENERIC_APPLY {
- gstart2 := get_type_extra(ga);
- gcnt2 := r64(g_gen_apply_data, gstart2 * 8);
- if gi2 < gcnt2 { return sh_term_of_ti(r64(g_gen_apply_data, (gstart2 + 1 + gi2) * 8)); }
- }
- break;
- }
- gi2 = gi2 + 1;
- }
- }
- pti := res_type_node(pn);
- if pti < 0 { return -1; }
- return sh_term_of_ti(pti);
-}
-
-fn sh_variant_payload_term(ti: int, name_ni: int) -> int {
- ea := find_enum_row_of(ti);
- if ea < 0 { return -1; }
- vi := sh_enum_variant_index(ea, name_ni);
- if vi < 0 { return -1; }
- tc := ei_variant_type_count(ea, vi);
- if tc <= 0 { return -1; }
- ga : ., mut = -1;
- if get_type_kind(ti) == TYP_GENERIC_APPLY { ga = ti; }
- tail : ., mut = tt_nil();
- i : ., mut = tc - 1;
- loop {
- if i < 0 { break; }
- if tt_step() == -1 { return -1; }
- pt := sh_variant_payload_at(ea, vi, i, ga);
- if pt < 0 { return -1; }
- tail = tt_cons(pt, tail);
- i = i - 1;
- }
- if tc == 1 { return tt_a(tail); } // 单载荷:链首即载荷项(不套空实义 product)
- return tt_atom(AK_PRODUCT, ti, tail);
-}
+ if ga >= 0 && get_type_kind(ga) == TYP_GENERIC_APPLY:
+ gstart2 := get_type_extra(ga)
+ gcnt2 := r64(g_gen_apply_data, gstart2 * 8)
+ if gi2 < gcnt2:
+ return sh_term_of_ti(r64(g_gen_apply_data, (gstart2 + 1 + gi2) * 8))
+ break
+ gi2 = gi2 + 1
+ pti := res_type_node(pn)
+ if pti < 0:
+ return -1
+ return sh_term_of_ti(pti)
+
+fn sh_variant_payload_term(ti: int, name_ni: int) -> int:
+ ea := find_enum_row_of(ti)
+ if ea < 0:
+ return -1
+ vi := sh_enum_variant_index(ea, name_ni)
+ if vi < 0:
+ return -1
+ tc := ei_variant_type_count(ea, vi)
+ if tc <= 0:
+ return -1
+ ga : ., mut = -1
+ if get_type_kind(ti) == TYP_GENERIC_APPLY:
+ ga = ti
+ tail : ., mut = tt_nil()
+ i : ., mut = tc - 1
+ loop:
+ if i < 0:
+ break
+ if tt_step() == -1:
+ return -1
+ pt := sh_variant_payload_at(ea, vi, i, ga)
+ if pt < 0:
+ return -1
+ tail = tt_cons(pt, tail)
+ i = i - 1
+ if tc == 1:
+ return tt_a(tail)
+ // 单载荷:链首即载荷项(不套空实义 product)
+ return tt_atom(AK_PRODUCT, ti, tail)
// ─── R2 P3 Task 4:枚举载荷列入库断言(调试通道 `--verify-evp-nodes`,默认关)───
// 报文 = `[enum-payload-verify] enums=E variants=V slots=S collapses=C bad=B`,返回 bad
@@ -1390,45 +1533,44 @@ fn sh_variant_payload_term(ti: int, name_ni: int) -> int {
// 缺口复发)。`collapses` = 裸码列说 int(TY_INT=0)而**节点列不是 int 基型节点**的槽数——
// 即「裸码丢失了真实载荷类型」的可数证据(T0 §5-① 的仓库级量化);它是**信息量**(≥ 0 正常),
// 不是失败(bad 才算失败)。只读、只计数、不写任何表。
-fn sh_evp_verify() -> int {
- bad : ., mut = 0;
- slots : ., mut = 0;
- collapsed : ., mut = 0;
- variants : ., mut = 0;
- ei : ., mut = 0;
- loop {
- if ei >= g_enum_count { break; }
- vi : ., mut = 0;
- loop {
- if vi >= ei_variant_count(ei) { break; }
- variants = variants + 1;
- tc2 := ei_variant_type_count(ei, vi);
- ti2 : ., mut = 0;
- loop {
- if ti2 >= tc2 { break; }
- slots = slots + 1;
- code := ei_variant_type(ei, vi, ti2);
- pn2 := ei_variant_type_node(ei, vi, ti2);
- if pn2 < 0 {
- bad = bad + 1;
- } else if code == TY_INT {
- if ast_kind(pn2) != 0 || ast_type_val(pn2) != TY_INT { collapsed = collapsed + 1; }
- }
- ti2 = ti2 + 1;
- }
- vi = vi + 1;
- }
- ei = ei + 1;
- }
- print("[enum-payload-verify] enums=");
- print(int_str(g_enum_count));
- print(" variants=");
- print(int_str(variants));
- print(" slots=");
- print(int_str(slots));
- print(" collapses=");
- print(int_str(collapsed));
- print(" bad=");
- println(int_str(bad));
- return bad;
-}
+fn sh_evp_verify() -> int:
+ bad : ., mut = 0
+ slots : ., mut = 0
+ collapsed : ., mut = 0
+ variants : ., mut = 0
+ ei : ., mut = 0
+ loop:
+ if ei >= g_enum_count:
+ break
+ vi : ., mut = 0
+ loop:
+ if vi >= ei_variant_count(ei):
+ break
+ variants = variants + 1
+ tc2 := ei_variant_type_count(ei, vi)
+ ti2 : ., mut = 0
+ loop:
+ if ti2 >= tc2:
+ break
+ slots = slots + 1
+ code := ei_variant_type(ei, vi, ti2)
+ pn2 := ei_variant_type_node(ei, vi, ti2)
+ if pn2 < 0:
+ bad = bad + 1
+ else if code == TY_INT:
+ if ast_kind(pn2) != 0 || ast_type_val(pn2) != TY_INT:
+ collapsed = collapsed + 1
+ ti2 = ti2 + 1
+ vi = vi + 1
+ ei = ei + 1
+ print("[enum-payload-verify] enums=")
+ print(int_str(g_enum_count))
+ print(" variants=")
+ print(int_str(variants))
+ print(" slots=")
+ print(int_str(slots))
+ print(" collapses=")
+ print(int_str(collapsed))
+ print(" bad=")
+ println(int_str(bad))
+ return bad
diff --git a/src/compiler/type_engine.cr b/src/compiler/type_engine.cr
index 7f6b0d0c..b9213f03 100644
--- a/src/compiler/type_engine.cr
+++ b/src/compiler/type_engine.cr
@@ -23,10 +23,21 @@
// (ti = -1 = 类级)。
// ─── 原子类 id(AK_*)───
-AK_INT : int = 0; AK_DEX : int = 1; AK_STRING : int = 2; AK_BOOL : int = 3;
-AK_UNIT : int = 4; AK_NEVER : int = 5; AK_CHAR : int = 6; AK_DYN : int = 7;
-AK_PRODUCT : int = 8; AK_SUM : int = 9; AK_SEQUENCE : int = 10;
-AK_REF : int = 11; AK_PTR : int = 12; AK_FN : int = 13; AK_NAMED : int = 14;
+AK_INT : int = 0
+AK_DEX : int = 1
+AK_STRING : int = 2
+AK_BOOL : int = 3
+AK_UNIT : int = 4
+AK_NEVER : int = 5
+AK_CHAR : int = 6
+AK_DYN : int = 7
+AK_PRODUCT : int = 8
+AK_SUM : int = 9
+AK_SEQUENCE : int = 10
+AK_REF : int = 11
+AK_PTR : int = 12
+AK_FN : int = 13
+AK_NAMED : int = 14
// R2 P3 Task 4(联合/可选):`null`(`None` 值的类型)——**原生第九员**,值域 = 单点。
// 语义(spec §5.4):`T?` = `T ∪ null`(桥接侧把 TYP_OPTIONAL 行译作该原子与内层项之并)。
// 公理(ak_disjoint):与一切异类原子**不相交**(含 AK_UNIT / AK_NEVER / AK_NAMED——null 不是
@@ -35,133 +46,155 @@ AK_REF : int = 11; AK_PTR : int = 12; AK_FN : int = 13; AK_NAMED : i
// 无需特例)。无类型参数(ty_variance_of 落表外默认不变,链恒空)。
// 注册表:**不入 iface_registry 条目表**(IFACE_ENTRY_COUNT = 13 为 P2b 判据硬值;且本原子
// 无操作许可 —— 算术/逻辑/条件门对其全拒,正是期望行为)⇒ `iface_kind_of` 对承载行回 -1。
-AK_NULL : int = 15;
+AK_NULL : int = 15
// ─── 字面收集侧缓冲(product 的字面集)───
-fn grow_ty_lits(needed: int) {
- if needed < g_ty_lits_cap { return; }
- nc : ., mut = g_ty_lits_cap * 2;
- if nc < 64 { nc = 64; }
- if nc < needed { nc = needed + 64; }
- nb := alloc(nc * 8);
- _dyncpy(g_ty_lits, g_ty_lits_cap * 8, nb);
- g_ty_lits = nb;
- g_ty_lits_cap = nc;
-}
-
-fn ty_lits_reset() { g_ty_lits_count = 0; }
-
-fn ty_lits_push(t: int) {
- if g_ty_lits_count + 1 > g_ty_lits_cap { grow_ty_lits(g_ty_lits_count + 1); }
- w64(g_ty_lits, g_ty_lits_count * 8, t);
- g_ty_lits_count = g_ty_lits_count + 1;
-}
-
-fn ty_lit_at(k: int) -> int { return r64(g_ty_lits, k * 8); }
+fn grow_ty_lits(needed: int):
+ if needed < g_ty_lits_cap:
+ return
+ nc : ., mut = g_ty_lits_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ nb := alloc(nc * 8)
+ _dyncpy(g_ty_lits, g_ty_lits_cap * 8, nb)
+ g_ty_lits = nb
+ g_ty_lits_cap = nc
+
+fn ty_lits_reset():
+ g_ty_lits_count = 0
+
+fn ty_lits_push(t: int):
+ if g_ty_lits_count + 1 > g_ty_lits_cap:
+ grow_ty_lits(g_ty_lits_count + 1)
+ w64(g_ty_lits, g_ty_lits_count * 8, t)
+ g_ty_lits_count = g_ty_lits_count + 1
+
+fn ty_lit_at(k: int) -> int:
+ return r64(g_ty_lits, k * 8)
// product(∩-链)或单字面 → 字面集(写 g_ty_lits)
-fn lit_collect(i: int) {
- if tt_tag(i) == TT_INTER { lit_collect(tt_a(i)); lit_collect(tt_b(i)); return; }
- ty_lits_push(i);
-}
+fn lit_collect(i: int):
+ if tt_tag(i) == TT_INTER:
+ lit_collect(tt_a(i))
+ lit_collect(tt_b(i))
+ return
+ ty_lits_push(i)
// ─── 原子类互斥公理(P0 表:不同原子类两两不相交;AK_DYN = ⊤ 与一切相容)───
-fn ak_disjoint(x: int, y: int) -> int {
- if x == y { return 0; }
- if x == AK_DYN || y == AK_DYN { return 0; }
+fn ak_disjoint(x: int, y: int) -> int:
+ if x == y:
+ return 0
+ if x == AK_DYN || y == AK_DYN:
+ return 0
// R2 P3 Task 4:null 是**它自己的**单点原子类——与其余一切类不相交。位置在 AK_NEVER/
// AK_NAMED 两条之前:与 NEVER 相交(两者都无公共值);与 NAMED 的「不得断言互斥」无关
// (NAMED 保守律针对的是「命名类型可能是任何结构类型」——null 不是结构类型,任何用户
// 声明类型的值集里都不含 None 这个值 ⇒ 断互斥是**可断言**的,不违 P0 终审 Important B)。
- if x == AK_NULL || y == AK_NULL { return 1; }
- if x == AK_NEVER || y == AK_NEVER { return 1; }
+ if x == AK_NULL || y == AK_NULL:
+ return 1
+ if x == AK_NEVER || y == AK_NEVER:
+ return 1
// AK_NAMED 的具体行不展开(未覆盖面②)→ **不得断言互斥**(P0 终审 Important B 实证:
// named 可能是任何结构类型的别名,断言互斥即不可能断言)
- if x == AK_NAMED || y == AK_NAMED { return 0; }
- return 1;
-}
+ if x == AK_NAMED || y == AK_NAMED:
+ return 0
+ return 1
// 字面的原子类(⊥/⊤/VAR 无类 → -1)
-fn ty_ak_of(i: int) -> int {
- t := tt_tag(i);
- if t == TT_ATOM { return tt_a(i); }
- if t == TT_NOT && tt_tag(tt_a(i)) == TT_ATOM { return tt_a(tt_a(i)); }
- if t == TT_TOP_K { return tt_a(i); }
- return -1;
-}
+fn ty_ak_of(i: int) -> int:
+ t := tt_tag(i)
+ if t == TT_ATOM:
+ return tt_a(i)
+ if t == TT_NOT && tt_tag(tt_a(i)) == TT_ATOM:
+ return tt_a(tt_a(i))
+ if t == TT_TOP_K:
+ return tt_a(i)
+ return -1
// ─── 字面矛盾判定(product 是否为空集的一阶判据)───
// 字面所属原子类(ATOM/⊤ₖ 正位置,及其否定)——-1 = 无类(VAR/复合/⊥/⊤)
-fn lit_class_of(i: int) -> int {
- t := tt_tag(i);
- if t == TT_ATOM || t == TT_TOP_K { return tt_a(i); }
- if t == TT_NOT {
- it := tt_tag(tt_a(i));
- if it == TT_ATOM || it == TT_TOP_K { return tt_a(tt_a(i)); }
- }
- return -1;
-}
-
-fn lit_is_neg(i: int) -> int { if tt_tag(i) == TT_NOT { return 1; } return 0; }
+fn lit_class_of(i: int) -> int:
+ t := tt_tag(i)
+ if t == TT_ATOM || t == TT_TOP_K:
+ return tt_a(i)
+ if t == TT_NOT:
+ it := tt_tag(tt_a(i))
+ if it == TT_ATOM || it == TT_TOP_K:
+ return tt_a(tt_a(i))
+ return -1
+
+fn lit_is_neg(i: int) -> int:
+ if tt_tag(i) == TT_NOT:
+ return 1
+ return 0
// 单对字面是否互斥(⟦p⟧ ∩ ⟦q⟧ = ∅)——**规则要窄**:
// 正×正 异类 → ∅ ✓;正×负 **异类不空**(int ∩ ¬string = int ≠ ∅——P0 Task 4 自测实证
// 早期版本把这条写错,导致 witness 恒 -1);正׬⊤ₖ 同类 → ∅;负×负 永不空。
-fn lit_empty_pair(p: int, q: int) -> int {
- if tt_tag(p) == TT_BOT || tt_tag(q) == TT_BOT { return 1; }
- if tt_not(q) == p { return 1; } // X ∧ ¬X
- pc := lit_class_of(p);
- qc := lit_class_of(q);
- if pc < 0 || qc < 0 { return 0; }
- pneg := lit_is_neg(p);
- qneg := lit_is_neg(q);
- if pneg == 0 && qneg == 0 { return ak_disjoint(pc, qc); } // 正 × 正
- if pneg == 0 && qneg != 0 {
- if tt_tag(q) == TT_NOT && tt_tag(tt_a(q)) == TT_TOP_K && pc == qc { return 1; }
- return 0;
- }
- if pneg != 0 && qneg == 0 {
- if tt_tag(p) == TT_NOT && tt_tag(tt_a(p)) == TT_TOP_K && pc == qc { return 1; }
- return 0;
- }
- return 0; // 负 × 负
-}
+fn lit_empty_pair(p: int, q: int) -> int:
+ if tt_tag(p) == TT_BOT || tt_tag(q) == TT_BOT:
+ return 1
+ if tt_not(q) == p:
+ return 1
+ // X ∧ ¬X
+ pc := lit_class_of(p)
+ qc := lit_class_of(q)
+ if pc < 0 || qc < 0:
+ return 0
+ pneg := lit_is_neg(p)
+ qneg := lit_is_neg(q)
+ if pneg == 0 && qneg == 0:
+ return ak_disjoint(pc, qc)
+ // 正 × 正
+ if pneg == 0 && qneg != 0:
+ if tt_tag(q) == TT_NOT && tt_tag(tt_a(q)) == TT_TOP_K && pc == qc:
+ return 1
+ return 0
+ if pneg != 0 && qneg == 0:
+ if tt_tag(p) == TT_NOT && tt_tag(tt_a(p)) == TT_TOP_K && pc == qc:
+ return 1
+ return 0
+ return 0 // 负 × 负
// 独立缓冲版(避免侧缓冲互踩:sub_cover 需同时持有 p/q 两侧字面集)
-fn lits_contradictory_buf(buf: string, n: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- p := r64(buf, i * 8);
- j : ., mut = i + 1;
- loop {
- if j >= n { break; }
- q := r64(buf, j * 8);
- if lit_empty_pair(p, q) == 1 { return 1; }
- j = j + 1;
- }
- i = i + 1;
- }
- return 0;
-}
+fn lits_contradictory_buf(buf: string, n: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ p := r64(buf, i * 8)
+ j : ., mut = i + 1
+ loop:
+ if j >= n:
+ break
+ q := r64(buf, j * 8)
+ if lit_empty_pair(p, q) == 1:
+ return 1
+ j = j + 1
+ i = i + 1
+ return 0
// 收集 product 的字面到独立缓冲,返回缓冲(元素数 = g_ty_lits_count)
// 返回型 = `string`:`alloc` 在类型模型里就是 `() -> string`(checker.cr 的 bi_add("alloc",
// TI_STR)),本值流转面也全按字节缓冲走(`r64`/`w64`/`lits_contradictory_buf` 皆收 string)
// ——旧声明 `-> int` 是真·类型洗白(TF01;check 作业 rc=1 划界之一,本批修)。
-fn lits_copy(p: int) -> string {
- ty_lits_reset();
- lit_collect(p);
- n := g_ty_lits_count;
- buf := alloc((n + 1) * 8);
- i : ., mut = 0;
- loop { if i >= n { break; } w64(buf, i * 8, ty_lit_at(i)); i = i + 1; }
- return buf;
-}
-
-fn lits_contradictory() -> int {
- return lits_contradictory_buf(g_ty_lits, g_ty_lits_count);
-}
+fn lits_copy(p: int) -> string:
+ ty_lits_reset()
+ lit_collect(p)
+ n := g_ty_lits_count
+ buf := alloc((n + 1) * 8)
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ w64(buf, i * 8, ty_lit_at(i))
+ i = i + 1
+ return buf
+
+fn lits_contradictory() -> int:
+ return lits_contradictory_buf(g_ty_lits, g_ty_lits_count)
// ═══════════ R2 P5 Task 3:命名面可判定域(身份链判定)═══════════
// 背景:AK_NAMED 原子原为**一律 -1**(未覆盖面②「命名行不展开」)⇒ 任何两个命名型比较都
@@ -187,58 +220,68 @@ fn lits_contradictory() -> int {
// kind 相同 + data 递归(命名行 data = 名字索引;named_dedup 使「同名 ⇔ 同行」⇒ 与令牌
// 同一性一致)。**已登记未编码角落**:本链不区分 kind(TYP_NAMED vs TYP_GENERIC_PARAM
// 同名 ⇒ 判等,legacy 按 kind 判否)——需同名跨类比较才可达,可达性未证实(P5 T3 报告 §)。
-fn te_is_name_token(e: int) -> int {
- if e < 0 || e >= tt_count() { return 0; }
- if tt_tag(e) != TT_ATOM { return 0; }
- if tt_a(e) != AK_UNIT { return 0; }
- if tt_b(e) < 0 { return 0; }
- return 1;
-}
+fn te_is_name_token(e: int) -> int:
+ if e < 0 || e >= tt_count():
+ return 0
+ if tt_tag(e) != TT_ATOM:
+ return 0
+ if tt_a(e) != AK_UNIT:
+ return 0
+ if tt_b(e) < 0:
+ return 0
+ return 1
// 实参位允许的项:类型项(原子/并/交/链/空链)。μ 变元/¬/裸值一律域外。
// 注:AK_UNIT 原子(原生 unit 类型项)**在**域内——它与令牌同形(b ≥ 0),本层不按键区分:
// 实参位比较走 ty_equiv(unit vs int ⇒ 类不同 ⇒ 0,与 legacy 同结论;令牌不会出现在实参位,
// 令牌位的比较另有 te_token_cmp)。
-fn te_is_arg_term(e: int) -> int {
- if e < 0 || e >= tt_count() { return 0; }
- t := tt_tag(e);
- if t == TT_ATOM || t == TT_UNION || t == TT_INTER || t == TT_CONS || t == TT_NIL { return 1; }
- return 0;
-}
+fn te_is_arg_term(e: int) -> int:
+ if e < 0 || e >= tt_count():
+ return 0
+ t := tt_tag(e)
+ if t == TT_ATOM || t == TT_UNION || t == TT_INTER || t == TT_CONS || t == TT_NIL:
+ return 1
+ return 0
// 位置 0(身份令牌)比较;调用方已保证 e1 != e2。差异 ⇒ 确定不同(名字令牌的身份 = 节点)。
-fn te_token_cmp(e1: int, e2: int) -> int {
- if te_is_name_token(e1) != 0 && te_is_name_token(e2) != 0 { return 0; }
- return -1; // 位置错位(非令牌)⇒ 域外,不猜
-}
+fn te_token_cmp(e1: int, e2: int) -> int:
+ if te_is_name_token(e1) != 0 && te_is_name_token(e2) != 0:
+ return 0
+ return -1 // 位置错位(非令牌)⇒ 域外,不猜
// 位置 ≥ 1(泛型实参类型项)比较:引擎等价(0/1/-1 直传)。
-fn te_arg_cmp(e1: int, e2: int) -> int {
- if te_is_arg_term(e1) == 0 || te_is_arg_term(e2) == 0 { return -1; }
- return ty_equiv(e1, e2);
-}
+fn te_arg_cmp(e1: int, e2: int) -> int:
+ if te_is_arg_term(e1) == 0 || te_is_arg_term(e2) == 0:
+ return -1
+ return ty_equiv(e1, e2)
// 身份链比较(三态):slot = 当前位置(0 = 令牌位)。链形不同 = 结构不同(proper list 前提:
// nil vs cons ⇒ 0;任一侧非链形(非 nil/cons)⇒ 域外 ⇒ -1)。
-fn te_chain_cmp(slot: int, p: int, q: int) -> int {
- if p == q { return 1; }
- if p < 0 || q < 0 { return 0; } // 空链 vs 非空链
- tp := tt_tag(p);
- tq := tt_tag(q);
- if tp != TT_CONS || tq != TT_CONS {
- if tp == TT_NIL || tq == TT_NIL { return 0; }
- return -1;
- }
- e1 := tt_a(p);
- e2 := tt_a(q);
- d : ., mut = 1;
- if e1 != e2 {
- if slot == 0 { d = te_token_cmp(e1, e2); } else { d = te_arg_cmp(e1, e2); }
- }
- if d == -1 { return -1; }
- if d == 0 { return 0; }
- return te_chain_cmp(slot + 1, tt_b(p), tt_b(q));
-}
+fn te_chain_cmp(slot: int, p: int, q: int) -> int:
+ if p == q:
+ return 1
+ if p < 0 || q < 0:
+ return 0
+ // 空链 vs 非空链
+ tp := tt_tag(p)
+ tq := tt_tag(q)
+ if tp != TT_CONS || tq != TT_CONS:
+ if tp == TT_NIL || tq == TT_NIL:
+ return 0
+ return -1
+ e1 := tt_a(p)
+ e2 := tt_a(q)
+ d : ., mut = 1
+ if e1 != e2:
+ if slot == 0:
+ d = te_token_cmp(e1, e2)
+ else:
+ d = te_arg_cmp(e1, e2)
+ if d == -1:
+ return -1
+ if d == 0:
+ return 0
+ return te_chain_cmp(slot + 1, tt_b(p), tt_b(q))
// ═══════════ R2 P5 Task 3b:不变槽元素比较(三态)═══════════
// 背景(P5 Task 3 §6 残留面,本步收口):不变槽元素原为「结构同形(tt_type_elem_same)
@@ -266,34 +309,39 @@ fn te_chain_cmp(slot: int, p: int, q: int) -> int {
// 绝不产生假等。可达性:唯一原生 unit 项在 DAG 里**只有一个节点**(单行 + 去重)⇒ unit
// × unit 恒同节点(快路径);token × unit 需构造点在同一槽混排两排序——全构造点无此形态
// (负控见 type_selftest.cr 的 t3b.* 段)。
-fn te_elem_cmp(p: int, q: int) -> int {
- if p == q { return 1; }
- if te_is_name_token(p) != 0 && te_is_name_token(q) != 0 { return 0; }
- if te_is_arg_term(p) != 0 && te_is_arg_term(q) != 0 { return ty_equiv(p, q); }
- g_ty_uncovered = 1;
- return -1;
-}
+fn te_elem_cmp(p: int, q: int) -> int:
+ if p == q:
+ return 1
+ if te_is_name_token(p) != 0 && te_is_name_token(q) != 0:
+ return 0
+ if te_is_arg_term(p) != 0 && te_is_arg_term(q) != 0:
+ return ty_equiv(p, q)
+ g_ty_uncovered = 1
+ return -1
// 命名面成对判定(三态):p/q 皆 TT_ATOM 且至少一侧 AK_NAMED(调用方保证)。
-fn te_named_pair(pk: int, p: int, qk: int, q: int) -> int {
- if pk == qk {
+fn te_named_pair(pk: int, p: int, qk: int, q: int) -> int:
+ if pk == qk:
// 双方皆 AK_NAMED(同类 ∧ 至少一侧 NAMED)
- cp := tt_c(p);
- cq := tt_c(q);
- if cp < 0 || cq < 0 { return -1; } // 空链 = 无身份(未覆盖面②原形态)⇒ 域外
- return te_chain_cmp(0, cp, cq);
- }
+ cp := tt_c(p)
+ cq := tt_c(q)
+ if cp < 0 || cq < 0:
+ return -1
+ // 空链 = 无身份(未覆盖面②原形态)⇒ 域外
+ return te_chain_cmp(0, cp, cq)
// 名义型 × 异类原子:确定不同(legacy 跨 kind 同结论)。守卫:命名侧必须带身份链;
// 异类侧不得是 AK_NEVER/AK_DYN(⊥/⊤ 语义未建模 ⇒ 域外,保持 -1)。
- if pk == AK_NAMED {
- if tt_c(p) < 0 { return -1; }
- if qk == AK_NEVER || qk == AK_DYN { return -1; }
- return 0;
- }
- if tt_c(q) < 0 { return -1; }
- if pk == AK_NEVER || pk == AK_DYN { return -1; }
- return 0;
-}
+ if pk == AK_NAMED:
+ if tt_c(p) < 0:
+ return -1
+ if qk == AK_NEVER || qk == AK_DYN:
+ return -1
+ return 0
+ if tt_c(q) < 0:
+ return -1
+ if pk == AK_NEVER || pk == AK_DYN:
+ return -1
+ return 0
// ─── R2 P6 Task 2(E-10):同类原子的「确定不交」判定(¬ 面专用)───
// 用途:`lit_implies` 的 ¬ 面判 `lp ⊆ ¬x ⟺ lp ∩ x = ∅`;两侧**同类**原子时,类目互斥公理
@@ -316,17 +364,26 @@ fn te_named_pair(pk: int, p: int, qk: int, q: int) -> int {
// ⑤ AK_SUM 链元素非令牌(手造畸形项)⇒ 不可判 ⇒ 同 P1-a ⇒ 0。
// 三态说明:本函数**只回 0/1**,不置 `g_ty_uncovered`(域外面由调用点既有守卫承担)。
// 生产可达性:`sh_variant_term`(ty_shadow.cr:823)恒造双令牌链 ⇒ ④/⑤ 生产不可达。
-fn atom_same_class_disjoint(p: int, q: int) -> int {
- if tt_tag(p) == TT_TOP_K || tt_tag(q) == TT_TOP_K { return 0; } // ② 类顶
- if tt_a(p) != AK_SUM { return 0; } // ③ 非身份型原子(含原生/参数化)
- cp := tt_c(p);
- cq := tt_c(q);
- if cp < 0 || cq < 0 { return 0; } // ④ 空链 = 无身份
- d := sum_chain_same(cp, cq); // 三态(见下)
- if d == 1 { return 0; } // 同身份 ⇒ 相交
- if d == 0 { return 1; } // 异身份 ⇒ 确定不交
- return 0; // ⑤ 不可判(同 P1-a)
-}
+fn atom_same_class_disjoint(p: int, q: int) -> int:
+ if tt_tag(p) == TT_TOP_K || tt_tag(q) == TT_TOP_K:
+ return 0
+ // ② 类顶
+ if tt_a(p) != AK_SUM:
+ return 0
+ // ③ 非身份型原子(含原生/参数化)
+ cp := tt_c(p)
+ cq := tt_c(q)
+ if cp < 0 || cq < 0:
+ return 0
+ // ④ 空链 = 无身份
+ d := sum_chain_same(cp, cq) // 三态(见下)
+ if d == 1:
+ return 0
+ // 同身份 ⇒ 相交
+ if d == 0:
+ return 1
+ // 异身份 ⇒ 确定不交
+ return 0 // ⑤ 不可判(同 P1-a)
// AK_SUM 变体项身份链的「同链」判定(三态:1 = 同链 / 0 = 确定异链 / -1 = 不可判)。
// 链 = [枚举名令牌, 变体名令牌](唯一生产构造点 `sh_variant_term`,ty_shadow.cr:823)⇒
@@ -337,85 +394,104 @@ fn atom_same_class_disjoint(p: int, q: int) -> int {
// 实测(本批):首版用 `te_chain_cmp` 时三例 `t3.*_over_claim` 仍判 0,而 9 例负控全过
// (N5 跨枚举在**槽 0** 被令牌规则救回)⇒ 补 N10「同枚举异变体」后才暴露。
// 不可判面(空链 / 形状异常 / 非令牌元素)= 手造畸形项,生产不可达;调用方按 P1-a 归 0。
-fn sum_chain_same(p: int, q: int) -> int {
- if p == q { return 1; }
- if p < 0 || q < 0 { return -1; }
- if tt_tag(p) != TT_CONS || tt_tag(q) != TT_CONS { return -1; }
- e1 := tt_a(p);
- e2 := tt_a(q);
- if e1 != e2 {
- if te_is_name_token(e1) == 0 || te_is_name_token(e2) == 0 { return -1; }
- return 0; // 两侧皆令牌且异节点 ⇒ 确定异链
- }
- return sum_chain_same(tt_b(p), tt_b(q));
-}
+fn sum_chain_same(p: int, q: int) -> int:
+ if p == q:
+ return 1
+ if p < 0 || q < 0:
+ return -1
+ if tt_tag(p) != TT_CONS || tt_tag(q) != TT_CONS:
+ return -1
+ e1 := tt_a(p)
+ e2 := tt_a(q)
+ if e1 != e2:
+ if te_is_name_token(e1) == 0 || te_is_name_token(e2) == 0:
+ return -1
+ return 0 // 两侧皆令牌且异节点 ⇒ 确定异链
+ return sum_chain_same(tt_b(p), tt_b(q))
// ─── 字面蕴含(⟦lp⟧ ⊆ ⟦lq⟧)───
-fn lit_implies(lp: int, lq: int) -> int {
- if lp == lq { return 1; }
- if tt_tag(lq) == TT_TOP { return 1; }
- if tt_tag(lp) == TT_BOT { return 1; }
- if tt_tag(lp) == TT_TOP { return tt_tag(lq) == TT_TOP; }
+fn lit_implies(lp: int, lq: int) -> int:
+ if lp == lq:
+ return 1
+ if tt_tag(lq) == TT_TOP:
+ return 1
+ if tt_tag(lp) == TT_BOT:
+ return 1
+ if tt_tag(lp) == TT_TOP:
+ return tt_tag(lq) == TT_TOP
// lq = ⊤ₖ
- if tt_tag(lq) == TT_TOP_K {
- k := tt_a(lq);
- if tt_tag(lp) == TT_TOP_K { return tt_a(lp) == k; }
- if tt_tag(lp) == TT_ATOM { return tt_a(lp) == k; }
- return 0;
- }
+ if tt_tag(lq) == TT_TOP_K:
+ k := tt_a(lq)
+ if tt_tag(lp) == TT_TOP_K:
+ return tt_a(lp) == k
+ if tt_tag(lp) == TT_ATOM:
+ return tt_a(lp) == k
+ return 0
// lq = ¬x:lp ⊆ ¬x ⟺ lp ∩ x = ∅
- if tt_tag(lq) == TT_NOT {
- x := tt_a(lq);
+ if tt_tag(lq) == TT_NOT:
+ x := tt_a(lq)
// ¬P ⊆ ¬X ⟺ **X ⊆ P**(逆否)——P0 终审 Critical 1:早期写成 ty_sub(P, X)(方向反),
// 使 ¬A ⊆ ¬B 与 A ⊊ B 同时成立(自相矛盾)。
- if tt_tag(lp) == TT_NOT { return ty_sub(x, tt_a(lp)); }
+ if tt_tag(lp) == TT_NOT:
+ return ty_sub(x, tt_a(lp))
// ¬(μ…) 等无类字面:未知(登记,保守不覆盖)
- if lit_class_of(lp) < 0 || lit_class_of(x) < 0 {
- if tt_tag(x) == TT_BOT { return 1; }
- if tt_tag(lp) == TT_BOT { return 1; }
- g_ty_uncovered = 1;
- return -1;
- }
- pk := lit_class_of(lp);
- xk := lit_class_of(x);
- if pk == AK_NAMED || xk == AK_NAMED { g_ty_uncovered = 1; return -1; } // 不展开 → 未知
+ if lit_class_of(lp) < 0 || lit_class_of(x) < 0:
+ if tt_tag(x) == TT_BOT:
+ return 1
+ if tt_tag(lp) == TT_BOT:
+ return 1
+ g_ty_uncovered = 1
+ return -1
+ pk := lit_class_of(lp)
+ xk := lit_class_of(x)
+ if pk == AK_NAMED || xk == AK_NAMED:
+ g_ty_uncovered = 1
+ return -1
+ // 不展开 → 未知
// R2 P6 Task 2(E-10):同类 ⇒ 身份判据(异身份 ⇒ 确定不交 ⇒ lp ⊆ ¬x 成立)。
// 异类面照旧走 ak_disjoint 的公理表——identity 只存在于**项**里,而 ak_disjoint 只见
// 类 id(故本加强不得落在 ak_disjoint 本体:那会退化成「同类一律不交」= 假不交)。
- if pk == xk { return atom_same_class_disjoint(lp, x); }
- if ak_disjoint(pk, xk) == 1 { return 1; }
- return 0;
- }
+ if pk == xk:
+ return atom_same_class_disjoint(lp, x)
+ if ak_disjoint(pk, xk) == 1:
+ return 1
+ return 0
// 双方皆正原子:同类 + 参数链按**变型**比较(R2 P3 Task 1 取代 P0「仅同形判等」)
- if tt_tag(lp) == TT_ATOM && tt_tag(lq) == TT_ATOM {
- pk := tt_a(lp);
- qk := tt_a(lq);
+ if tt_tag(lp) == TT_ATOM && tt_tag(lq) == TT_ATOM:
+ pk := tt_a(lp)
+ qk := tt_a(lq)
// R2 P5 Task 3:命名面(身份链)——取代原「AK_NAMED ⇒ 一律 -1」守卫。
// 可判定域/域外三态见 te_named_pair 头注(P5 前此面 = unknown 清零对象)
- if pk == AK_NAMED || qk == AK_NAMED {
- d := te_named_pair(pk, lp, qk, lq);
- if d == -1 { g_ty_uncovered = 1; return -1; }
- return d;
- }
- if pk != qk { return 0; }
- lv := tt_list_variance(pk, tt_c(lp), tt_c(lq));
- if lv == 1 { return 1; }
- if lv == -1 { return -1; } // 未知(不定槽的 ty_equiv 三态负值):**上抛**,不得当 0
+ if pk == AK_NAMED || qk == AK_NAMED:
+ d := te_named_pair(pk, lp, qk, lq)
+ if d == -1:
+ g_ty_uncovered = 1
+ return -1
+ return d
+ if pk != qk:
+ return 0
+ lv := tt_list_variance(pk, tt_c(lp), tt_c(lq))
+ if lv == 1:
+ return 1
+ if lv == -1:
+ return -1
+ // 未知(不定槽的 ty_equiv 三态负值):**上抛**,不得当 0
// 确定不蕴含(不变槽查到确定不等价 / 协变槽 ty_sub 确定不成立 / 链形不同):
// P0 此处一律回 -1 + 未覆盖面(登记「参数仅同形判等」)——变型落地后它是**已判**面
- return 0;
- }
- return 0;
-}
+ return 0
+ return 0
// 参数链同形(结构相等;R2 P3 Task 1 起为**变型表的默认槽比较**——不变槽即此恒等)
-fn tt_list_same(p: int, q: int) -> int {
- if p == q { return 1; }
- if p < 0 || q < 0 { return 0; }
- if tt_tag(p) != TT_CONS || tt_tag(q) != TT_CONS { return 0; }
- if tt_list_same(tt_a(p), tt_a(q)) == 0 { return 0; }
- return tt_list_same(tt_b(p), tt_b(q));
-}
+fn tt_list_same(p: int, q: int) -> int:
+ if p == q:
+ return 1
+ if p < 0 || q < 0:
+ return 0
+ if tt_tag(p) != TT_CONS || tt_tag(q) != TT_CONS:
+ return 0
+ if tt_list_same(tt_a(p), tt_a(q)) == 0:
+ return 0
+ return tt_list_same(tt_b(p), tt_b(q))
// ─── R2 P3 Task 1:不变槽的「类型项相等」——序列项**固定性位(b)不入** ───
// 背景(本任务实测):序列项的 b 槽是表示提示(N / 固定性,见 ty_shadow.cr 的 sh_seq_term),
@@ -429,25 +505,30 @@ fn tt_list_same(p: int, q: int) -> int {
// ([S] 与 [T] 必须不同)、令牌原子(AK_SUM 的 name 令牌 / AK_REF 的 mut 标记)的 b 也是身份。
// 守卫「皆 AK_SEQUENCE」使本函数**永不**解释令牌(令牌恒为 AK_UNIT 原子,见 sh_name_token /
// sh_ref_mut_marker)——旧约定(裸 name 索引入链)下的别名风险已随之消除。
-fn tt_type_elem_same(p: int, q: int) -> int {
- if p == q { return 1; }
- if p < 0 || q < 0 { return 0; }
- if tt_tag(p) == TT_ATOM && tt_a(p) == AK_SEQUENCE &&
- tt_tag(q) == TT_ATOM && tt_a(q) == AK_SEQUENCE { return tt_seq_same(p, q); }
- return tt_list_same(p, q);
-}
+fn tt_type_elem_same(p: int, q: int) -> int:
+ if p == q:
+ return 1
+ if p < 0 || q < 0:
+ return 0
+ if tt_tag(p) == TT_ATOM && tt_a(p) == AK_SEQUENCE && tt_tag(q) == TT_ATOM && tt_a(q) == AK_SEQUENCE:
+ return tt_seq_same(p, q)
+ return tt_list_same(p, q)
// 序列项相等(忽略 b):class 相同 + 参数链逐元素递归(元素位经 tt_type_elem_same 再判定)。
-fn tt_seq_same(p: int, q: int) -> int {
- if p == q { return 1; }
- cp := tt_c(p);
- cq := tt_c(q);
- if cp == cq { return 1; }
- if cp < 0 || cq < 0 { return 0; }
- if tt_tag(cp) != TT_CONS || tt_tag(cq) != TT_CONS { return 0; }
- if tt_type_elem_same(tt_a(cp), tt_a(cq)) != 1 { return 0; }
- return tt_type_elem_same(tt_b(cp), tt_b(cq));
-}
+fn tt_seq_same(p: int, q: int) -> int:
+ if p == q:
+ return 1
+ cp := tt_c(p)
+ cq := tt_c(q)
+ if cp == cq:
+ return 1
+ if cp < 0 || cq < 0:
+ return 0
+ if tt_tag(cp) != TT_CONS || tt_tag(cq) != TT_CONS:
+ return 0
+ if tt_type_elem_same(tt_a(cp), tt_a(cq)) != 1:
+ return 0
+ return tt_type_elem_same(tt_b(cp), tt_b(cq))
// ═══════════════ R2 P3 Task 1:变型表(slot 单调性)+ 参数链按变型比较 ═══════════════
// 语义(spec §5.1):只读视图**协变**(⟦槽a⟧ ⊆ ⟦槽b⟧ ⇒ 蕴含),可写视图**不变**(槽须等价)。
@@ -462,16 +543,18 @@ fn tt_seq_same(p: int, q: int) -> int {
// tt_list_variance_at);槽 1(元素)= **只读协变 / 可写不变**:变型依赖槽 0 的值 ⇒ 静态
// 二元表表达不了该条件,故本表给只读侧(mut = 0)的默认值 1,可写侧由 tt_list_variance_at
// 依链首标记降为 0(**条件单点收敛在比较函数内**,本表不重复表达)。
-fn ty_variance_of(ak: int, slot: int) -> int {
- if ak == AK_REF {
- if slot == 0 { return 0; }
- if slot == 1 { return 1; }
- return 0;
- }
- if ak == AK_SEQUENCE { return 0; }
- if ak == AK_PTR { return 0; }
- return 0; // 表外构造子(含原生八员/命名类):不变 = 现状结构相等
-}
+fn ty_variance_of(ak: int, slot: int) -> int:
+ if ak == AK_REF:
+ if slot == 0:
+ return 0
+ if slot == 1:
+ return 1
+ return 0
+ if ak == AK_SEQUENCE:
+ return 0
+ if ak == AK_PTR:
+ return 0
+ return 0 // 表外构造子(含原生八员/命名类):不变 = 现状结构相等
// 参数链按变型比较(lit_implies 的正原子同形面入口)。返回 1 / 0 / **-1 = 未知**(上抛)。
// 槽位语义(逐槽成对推进):
@@ -489,335 +572,411 @@ fn ty_variance_of(ak: int, slot: int) -> int {
// 碰撞类;M 改法红例 = 异枚举同名变体被判等),故加强面现在可安全落地。
// 同形快路径:p == q → 1(DAG 去重使「同形同项」恒为同一节点 ⇒ 主流路径零额外开销,且
// **改动前后逐位一致**)。链形不同(非 CONS / 负)→ 0(结构不同 = 现状语义)。
-fn tt_list_variance_at(ak: int, slot: int, mutv: int, p: int, q: int) -> int {
- if p == q { return 1; }
- if p < 0 || q < 0 { return 0; }
- if tt_tag(p) != TT_CONS || tt_tag(q) != TT_CONS { return 0; }
- ha := tt_a(p);
- hb := tt_a(q);
- if ak == AK_REF && slot == 0 {
- if tt_list_same(ha, hb) != 1 { return 0; } // 标记槽:可判定(见上)
- } else {
- v : ., mut = ty_variance_of(ak, slot);
- if ak == AK_REF && slot == 1 && mutv == 1 { v = 0; } // 可写 ref:元素降为不变
- if v == 1 {
- s := ty_sub(ha, hb);
- if s != 1 { return s; }
- } else {
- if tt_type_elem_same(ha, hb) != 1 {
+fn tt_list_variance_at(ak: int, slot: int, mutv: int, p: int, q: int) -> int:
+ if p == q:
+ return 1
+ if p < 0 || q < 0:
+ return 0
+ if tt_tag(p) != TT_CONS || tt_tag(q) != TT_CONS:
+ return 0
+ ha := tt_a(p)
+ hb := tt_a(q)
+ if ak == AK_REF && slot == 0:
+ if tt_list_same(ha, hb) != 1:
+ return 0
+ // 标记槽:可判定(见上)
+ else:
+ v : ., mut = ty_variance_of(ak, slot)
+ if ak == AK_REF && slot == 1 && mutv == 1:
+ v = 0
+ // 可写 ref:元素降为不变
+ if v == 1:
+ s := ty_sub(ha, hb)
+ if s != 1:
+ return s
+ else:
+ if tt_type_elem_same(ha, hb) != 1:
// R2 P5 Task 3b:非同形 ⇒ 三态加强(确定不同 ⇒ 0;域外/内层未知 ⇒ -1 上抛,
// 位由 te_elem_cmp / 内层置起——本层不吞、不改标)
- d := te_elem_cmp(ha, hb);
- if d == -1 { return -1; }
- if d == 0 { return 0; }
- }
- }
- }
- return tt_list_variance_at(ak, slot + 1, mutv, tt_b(p), tt_b(q));
-}
-
-fn tt_list_variance(ak: int, p: int, q: int) -> int {
- mutv : ., mut = 0;
- if ak == AK_REF {
+ d := te_elem_cmp(ha, hb)
+ if d == -1:
+ return -1
+ if d == 0:
+ return 0
+ return tt_list_variance_at(ak, slot + 1, mutv, tt_b(p), tt_b(q))
+
+fn tt_list_variance(ak: int, p: int, q: int) -> int:
+ mutv : ., mut = 0
+ if ak == AK_REF:
// 槽 0 已在调用前判定同形(p == q 快路径或由本函数逐槽比较)——此处只取标记值:
// 链首 = 标记项(链形约定见 sh_ref_mut_marker;非标记形态保守取 0 = 只读)
- if p >= 0 && tt_tag(p) == TT_CONS {
- m := tt_a(p);
- if tt_tag(m) == TT_ATOM && tt_a(m) == AK_UNIT { mutv = tt_b(m); }
- }
- }
- return tt_list_variance_at(ak, 0, mutv, p, q);
-}
+ if p >= 0 && tt_tag(p) == TT_CONS:
+ m := tt_a(p)
+ if tt_tag(m) == TT_ATOM && tt_a(m) == AK_UNIT:
+ mutv = tt_b(m)
+ return tt_list_variance_at(ak, 0, mutv, p, q)
// ─── memo(假设-判定;0 = 假 / 1 = 真 / 2 = 进行中即假设真)───
-fn grow_ty_memo(needed: int) {
- if needed < g_ty_memo_cap { return; }
- nc : ., mut = 1024;
- loop { if nc >= needed { break; } nc = nc * 2; }
- nb := alloc(nc * 16);
- i : ., mut = 0;
- loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; }
- nv := alloc(nc * 8);
- i2 : ., mut = 0;
- loop { if i2 >= nc { break; } w64(nv, i2 * 8, 0); i2 = i2 + 1; }
- g_ty_memo_keys = nb;
- g_ty_memo_vals = nv;
- g_ty_memo_cap = nc;
- g_ty_memo_count = 0;
-}
+fn grow_ty_memo(needed: int):
+ if needed < g_ty_memo_cap:
+ return
+ nc : ., mut = 1024
+ loop:
+ if nc >= needed:
+ break
+ nc = nc * 2
+ nb := alloc(nc * 16)
+ i : ., mut = 0
+ loop:
+ if i >= nc:
+ break
+ w64(nb, i * 16, -1)
+ i = i + 1
+ nv := alloc(nc * 8)
+ i2 : ., mut = 0
+ loop:
+ if i2 >= nc:
+ break
+ w64(nv, i2 * 8, 0)
+ i2 = i2 + 1
+ g_ty_memo_keys = nb
+ g_ty_memo_vals = nv
+ g_ty_memo_cap = nc
+ g_ty_memo_count = 0
// 扩容 = 重建 + **重放既有条目**(保留「进行中」状态:清表会丢余归纳假设 → 可能不终止)
-fn ty_memo_rehash() {
- old_keys := g_ty_memo_keys;
- old_vals := g_ty_memo_vals;
- old_cap := g_ty_memo_cap;
- nc : ., mut = old_cap * 2;
- if nc < 1024 { nc = 1024; }
- nb := alloc(nc * 16);
- nv := alloc(nc * 8);
- i : ., mut = 0;
- loop { if i >= nc { break; } w64(nb, i * 16, -1); w64(nv, i * 8, 0); i = i + 1; }
- g_ty_memo_keys = nb;
- g_ty_memo_vals = nv;
- g_ty_memo_cap = nc;
- g_ty_memo_count = 0;
- j : ., mut = 0;
- loop {
- if j >= old_cap { break; }
- k := r64(old_keys, j * 16);
- if k >= 0 {
- b2 := r64(old_keys, j * 16 + 8);
- s := ty_memo_slot_no_grow(k, b2);
- w64(g_ty_memo_keys, s * 16, k);
- w64(g_ty_memo_keys, s * 16 + 8, b2);
- w64(g_ty_memo_vals, s * 8, r64(old_vals, j * 8));
- g_ty_memo_count = g_ty_memo_count + 1;
- }
- j = j + 1;
- }
-}
-
-fn ty_memo_slot_no_grow(a: int, b: int) -> int {
- h : ., mut = (a * 31 + b) % g_ty_memo_cap;
- if h < 0 { h = 0 - h; }
- p : ., mut = h;
- loop {
- k := r64(g_ty_memo_keys, p * 16);
- if k < 0 { return p; }
- if k == a && r64(g_ty_memo_keys, p * 16 + 8) == b { return p; }
- p = p + 1; if p >= g_ty_memo_cap { p = 0; }
- }
-}
-
-fn ty_memo_slot(a: int, b: int) -> int {
- if g_ty_memo_ok == 0 { grow_ty_memo(1024); g_ty_memo_ok = 1; }
+fn ty_memo_rehash():
+ old_keys := g_ty_memo_keys
+ old_vals := g_ty_memo_vals
+ old_cap := g_ty_memo_cap
+ nc : ., mut = old_cap * 2
+ if nc < 1024:
+ nc = 1024
+ nb := alloc(nc * 16)
+ nv := alloc(nc * 8)
+ i : ., mut = 0
+ loop:
+ if i >= nc:
+ break
+ w64(nb, i * 16, -1)
+ w64(nv, i * 8, 0)
+ i = i + 1
+ g_ty_memo_keys = nb
+ g_ty_memo_vals = nv
+ g_ty_memo_cap = nc
+ g_ty_memo_count = 0
+ j : ., mut = 0
+ loop:
+ if j >= old_cap:
+ break
+ k := r64(old_keys, j * 16)
+ if k >= 0:
+ b2 := r64(old_keys, j * 16 + 8)
+ s := ty_memo_slot_no_grow(k, b2)
+ w64(g_ty_memo_keys, s * 16, k)
+ w64(g_ty_memo_keys, s * 16 + 8, b2)
+ w64(g_ty_memo_vals, s * 8, r64(old_vals, j * 8))
+ g_ty_memo_count = g_ty_memo_count + 1
+ j = j + 1
+
+fn ty_memo_slot_no_grow(a: int, b: int) -> int:
+ h : ., mut = (a * 31 + b) % g_ty_memo_cap
+ if h < 0:
+ h = 0 - h
+ p : ., mut = h
+ loop:
+ k := r64(g_ty_memo_keys, p * 16)
+ if k < 0:
+ return p
+ if k == a && r64(g_ty_memo_keys, p * 16 + 8) == b:
+ return p
+ p = p + 1
+ if p >= g_ty_memo_cap:
+ p = 0
+
+fn ty_memo_slot(a: int, b: int) -> int:
+ if g_ty_memo_ok == 0:
+ grow_ty_memo(1024)
+ g_ty_memo_ok = 1
// 装填因子守卫(**必须在探测前**):表满且键不存在时开放寻址永不退出
// (P0 终审 Critical 2 实证:1200 互异对 → 98% CPU 空转)→ 先扩容(重建 + 重放)
- if (g_ty_memo_count + 1) * 2 >= g_ty_memo_cap { ty_memo_rehash(); }
+ if (g_ty_memo_count + 1) * 2 >= g_ty_memo_cap:
+ ty_memo_rehash()
// memo 查找计入预算(防备忘录自身成为无界成本);耗尽 → -1 上抛(调用方处理)
- if tt_step() == -1 { return -1; }
- return ty_memo_slot_no_grow(a, b);
-}
-
-fn ty_memo_state(slot: int) -> int {
- if r64(g_ty_memo_keys, slot * 16) < 0 { return -2; } // 空槽(未占用)
- return r64(g_ty_memo_vals, slot * 8);
-}
-
-fn ty_memo_set(slot: int, a: int, b: int, v: int) {
- if r64(g_ty_memo_keys, slot * 16) < 0 {
- w64(g_ty_memo_keys, slot * 16, a);
- w64(g_ty_memo_keys, slot * 16 + 8, b);
- g_ty_memo_count = g_ty_memo_count + 1;
- }
- w64(g_ty_memo_vals, slot * 8, v);
-}
+ if tt_step() == -1:
+ return -1
+ return ty_memo_slot_no_grow(a, b)
+
+fn ty_memo_state(slot: int) -> int:
+ if r64(g_ty_memo_keys, slot * 16) < 0:
+ return -2
+ // 空槽(未占用)
+ return r64(g_ty_memo_vals, slot * 8)
+
+fn ty_memo_set(slot: int, a: int, b: int, v: int):
+ if r64(g_ty_memo_keys, slot * 16) < 0:
+ w64(g_ty_memo_keys, slot * 16, a)
+ w64(g_ty_memo_keys, slot * 16 + 8, b)
+ g_ty_memo_count = g_ty_memo_count + 1
+ w64(g_ty_memo_vals, slot * 8, v)
// ─── μ 展开(代入)───
-fn tt_subst_list(p: int, v: int, r: int) -> int {
- if p < 0 { return -1; }
- if tt_tag(p) != TT_CONS { return tt_subst(p, v, r); }
- return tt_cons(tt_subst(tt_a(p), v, r), tt_subst_list(tt_b(p), v, r));
-}
-
-fn tt_subst(i: int, v: int, r: int) -> int {
- t := tt_tag(i);
- if t == TT_VAR { if tt_a(i) == v { return r; } return i; }
- if t == TT_UNION { return tt_union(tt_subst(tt_a(i), v, r), tt_subst(tt_b(i), v, r)); }
- if t == TT_INTER { return tt_inter(tt_subst(tt_a(i), v, r), tt_subst(tt_b(i), v, r)); }
- if t == TT_NOT { return tt_not(tt_subst(tt_a(i), v, r)); }
- if t == TT_MU {
- if tt_a(i) == v { return i; } // 内层同名 μ 遮蔽(避免捕获)
- return tt_mu(tt_a(i), tt_subst(tt_b(i), v, r));
- }
- if t == TT_ATOM { return tt_atom(tt_a(i), tt_b(i), tt_subst_list(tt_c(i), v, r)); }
- return i;
-}
+fn tt_subst_list(p: int, v: int, r: int) -> int:
+ if p < 0:
+ return -1
+ if tt_tag(p) != TT_CONS:
+ return tt_subst(p, v, r)
+ return tt_cons(tt_subst(tt_a(p), v, r), tt_subst_list(tt_b(p), v, r))
+
+fn tt_subst(i: int, v: int, r: int) -> int:
+ t := tt_tag(i)
+ if t == TT_VAR:
+ if tt_a(i) == v:
+ return r
+ return i
+ if t == TT_UNION:
+ return tt_union(tt_subst(tt_a(i), v, r), tt_subst(tt_b(i), v, r))
+ if t == TT_INTER:
+ return tt_inter(tt_subst(tt_a(i), v, r), tt_subst(tt_b(i), v, r))
+ if t == TT_NOT:
+ return tt_not(tt_subst(tt_a(i), v, r))
+ if t == TT_MU:
+ if tt_a(i) == v:
+ return i
+ // 内层同名 μ 遮蔽(避免捕获)
+ return tt_mu(tt_a(i), tt_subst(tt_b(i), v, r))
+ if t == TT_ATOM:
+ return tt_atom(tt_a(i), tt_b(i), tt_subst_list(tt_c(i), v, r))
+ return i
// ─── 预算守卫 ───
-fn ty_budget_reset(limit: int) {
- g_ty_steps = 0;
- g_ty_budget_max = limit;
- g_ty_exhausted = 0;
- g_ty_uncovered = 0;
+fn ty_budget_reset(limit: int):
+ g_ty_steps = 0
+ g_ty_budget_max = limit
+ g_ty_exhausted = 0
+ g_ty_uncovered = 0
// memo 随之清空(下次 ty_memo_slot 重建):**每个顶层查询独立**——否则跨查询的
// 缓存命中会让结果依赖预算历史而非输入项(P0 终审 Critical 3 实证)
// 注意还要清 cap:grow_ty_memo 有 `needed < cap → return` 早退,若 cap 已涨过
// (经 rehash),只清 ok 位会复用旧表 → 隔离承诺落空(修复复审 N1)
- g_ty_memo_ok = 0;
- g_ty_memo_cap = 0;
-}
+ g_ty_memo_ok = 0
+ g_ty_memo_cap = 0
-fn ty_exhausted() -> int { return g_ty_exhausted; }
-fn ty_uncovered() -> int { return g_ty_uncovered; }
+fn ty_exhausted() -> int:
+ return g_ty_exhausted
+fn ty_uncovered() -> int:
+ return g_ty_uncovered
// ─── 覆盖判定:⟦p⟧ ⊆ ⟦q⟧(p/q 已规范化;q 可为 union)───
-fn sub_cover(p: int, q: int) -> int {
- g_ty_steps = g_ty_steps + 1;
- if g_ty_steps > g_ty_budget_max { g_ty_exhausted = 1; return -1; }
+fn sub_cover(p: int, q: int) -> int:
+ g_ty_steps = g_ty_steps + 1
+ if g_ty_steps > g_ty_budget_max:
+ g_ty_exhausted = 1
+ return -1
// μ 展开(左右各自)——**必须走 ty_sub_core(memo 入口)**:展开后的项对会重复出现,
// 靠「进行中 = 假设成立」的余归纳终止(直接递归 sub_cover 会不收敛——Task 4 自测
// rec.absorb 实证:μX.(int ∪ X) ≤ int 需要假设-判定才成立)。
- if tt_tag(p) == TT_MU { return ty_sub_core(tt_subst(tt_b(p), tt_a(p), p), q); }
- if tt_tag(q) == TT_MU { return ty_sub_core(p, tt_subst(tt_b(q), tt_a(q), q)); }
- if tt_tag(p) == TT_UNION {
- x := sub_cover(tt_a(p), q);
- if x != 1 { return x; }
- return sub_cover(tt_b(p), q);
- }
- if tt_tag(q) == TT_UNION {
+ if tt_tag(p) == TT_MU:
+ return ty_sub_core(tt_subst(tt_b(p), tt_a(p), p), q)
+ if tt_tag(q) == TT_MU:
+ return ty_sub_core(p, tt_subst(tt_b(q), tt_a(q), q))
+ if tt_tag(p) == TT_UNION:
+ x := sub_cover(tt_a(p), q)
+ if x != 1:
+ return x
+ return sub_cover(tt_b(p), q)
+ if tt_tag(q) == TT_UNION:
// p 被某个析取支覆盖即可;三态:任一为 1 → 1;全 0 → 0;含 -1 → -1
- x := sub_cover(p, tt_a(q));
- if x == 1 { return 1; }
- y := sub_cover(p, tt_b(q));
- if y == 1 { return 1; }
- if x == -1 || y == -1 { return -1; }
- return 0;
- }
- if tt_tag(q) == TT_TOP { return 1; }
- if tt_tag(p) == TT_BOT { return 1; }
+ x := sub_cover(p, tt_a(q))
+ if x == 1:
+ return 1
+ y := sub_cover(p, tt_b(q))
+ if y == 1:
+ return 1
+ if x == -1 || y == -1:
+ return -1
+ return 0
+ if tt_tag(q) == TT_TOP:
+ return 1
+ if tt_tag(p) == TT_BOT:
+ return 1
// p、q 皆 product(∩-链)或单字面:p 的字面集须覆盖 q 的每个字面
- bufp := lits_copy(p);
- pn := g_ty_lits_count;
- if lits_contradictory_buf(bufp, pn) == 1 { return 1; } // p = ∅ ⊆ 一切
- bufq := lits_copy(q);
- qn := g_ty_lits_count;
- qi : ., mut = 0;
- loop {
- if qi >= qn { break; }
- lq := r64(bufq, qi * 8);
- covered : ., mut = 0;
- pi : ., mut = 0;
- loop {
- if pi >= pn { break; }
- lp := r64(bufp, pi * 8);
- li := lit_implies(lp, lq);
- if li == 1 { covered = 1; break; }
+ bufp := lits_copy(p)
+ pn := g_ty_lits_count
+ if lits_contradictory_buf(bufp, pn) == 1:
+ return 1
+ // p = ∅ ⊆ 一切
+ bufq := lits_copy(q)
+ qn := g_ty_lits_count
+ qi : ., mut = 0
+ loop:
+ if qi >= qn:
+ break
+ lq := r64(bufq, qi * 8)
+ covered : ., mut = 0
+ pi : ., mut = 0
+ loop:
+ if pi >= pn:
+ break
+ lp := r64(bufp, pi * 8)
+ li := lit_implies(lp, lq)
+ if li == 1:
+ covered = 1
+ break
// 预算耗尽/未覆盖面必须**上抛**(P0 终审 Critical 3:早期 `== 1` 把 -1 当「未覆盖」
// → 判定结果被吞成 0 并缓存,违反 spec §3.3「禁止当 0 用」)
- if li == -1 { return -1; }
- pi = pi + 1;
- }
- if covered == 0 { return 0; }
- qi = qi + 1;
- }
- return 1;
-}
+ if li == -1:
+ return -1
+ pi = pi + 1
+ if covered == 0:
+ return 0
+ qi = qi + 1
+ return 1
// ─── 顶层:包含(假设-判定 + memo + 预算)───
-fn ty_sub_core(a: int, b: int) -> int {
- slot := ty_memo_slot(a, b);
- if slot < 0 { return -1; } // 预算耗尽(memo 查找本身计数)
- st := ty_memo_state(slot);
- if st == 2 { return 1; } // 进行中 = 假设成立(余归纳)
- if st == 1 { return 1; }
- if st == 0 { return 0; }
- ty_memo_set(slot, a, b, 2);
- r := sub_cover(a, b);
- if r == -1 {
+fn ty_sub_core(a: int, b: int) -> int:
+ slot := ty_memo_slot(a, b)
+ if slot < 0:
+ return -1
+ // 预算耗尽(memo 查找本身计数)
+ st := ty_memo_state(slot)
+ if st == 2:
+ return 1
+ // 进行中 = 假设成立(余归纳)
+ if st == 1:
+ return 1
+ if st == 0:
+ return 0
+ ty_memo_set(slot, a, b, 2)
+ r := sub_cover(a, b)
+ if r == -1:
// 预算耗尽的结果**不可缓存**(否则后续更大预算的调用会读到假 -1)——清槽
- w64(g_ty_memo_keys, slot * 16, -1);
- w64(g_ty_memo_vals, slot * 8, 0);
- } else {
- ty_memo_set(slot, a, b, r);
- }
- return r;
-}
-
-fn ty_sub(a: int, b: int) -> int {
+ w64(g_ty_memo_keys, slot * 16, -1)
+ w64(g_ty_memo_vals, slot * 8, 0)
+ else:
+ ty_memo_set(slot, a, b, r)
+ return r
+
+fn ty_sub(a: int, b: int) -> int:
// 默认预算(未显式 ty_budget_reset 时可用;零初值下 g_ty_budget_max = 0 会让每次
// 判定都「预算耗尽」→ 满屏 -1——P0 Task 3 自测实证)
- if g_ty_budget_max <= 0 { ty_budget_reset(200000); }
- if a == b { return 1; }
- n1 := tt_norm(a);
- if n1 < 0 { return -1; } // 规范化预算耗尽(P0 终审 Important C)
- n2 := tt_norm(b);
- if n2 < 0 { return -1; }
- if n1 == n2 { return 1; }
- if tt_tag(n2) == TT_TOP { return 1; }
- if tt_tag(n1) == TT_BOT { return 1; }
- return ty_sub_core(n1, n2);
-}
-
-fn ty_equiv(a: int, b: int) -> int {
- x := ty_sub(a, b);
- if x != 1 { return x; }
- y := ty_sub(b, a);
- if y != 1 { return y; }
- return 1;
-}
+ if g_ty_budget_max <= 0:
+ ty_budget_reset(200000)
+ if a == b:
+ return 1
+ n1 := tt_norm(a)
+ if n1 < 0:
+ return -1
+ // 规范化预算耗尽(P0 终审 Important C)
+ n2 := tt_norm(b)
+ if n2 < 0:
+ return -1
+ if n1 == n2:
+ return 1
+ if tt_tag(n2) == TT_TOP:
+ return 1
+ if tt_tag(n1) == TT_BOT:
+ return 1
+ return ty_sub_core(n1, n2)
+
+fn ty_equiv(a: int, b: int) -> int:
+ x := ty_sub(a, b)
+ if x != 1:
+ return x
+ y := ty_sub(b, a)
+ if y != 1:
+ return y
+ return 1
// 可空性:DNF 下存在一个不矛盾 product
-fn ty_inhabited(a: int) -> int {
- if g_ty_budget_max <= 0 { ty_budget_reset(200000); }
- n := tt_norm(a);
- if n < 0 { return -1; } // 规范化预算耗尽
- return inh_any_at(n, 0);
-}
+fn ty_inhabited(a: int) -> int:
+ if g_ty_budget_max <= 0:
+ ty_budget_reset(200000)
+ n := tt_norm(a)
+ if n < 0:
+ return -1
+ // 规范化预算耗尽
+ return inh_any_at(n, 0)
// 深度守卫:μ 展开的**空递归**(如 μX.X)无可终止判据——超深即 -1 + 未覆盖面
// (登记:空递归保守判为不可判,不静默当 0/1)
-fn inh_any(i: int) -> int { return inh_any_at(i, 0); }
-
-fn inh_any_at(i: int, depth: int) -> int {
- if depth > 512 { g_ty_exhausted = 1; return -1; }
- if tt_tag(i) == TT_UNION {
- x := inh_any_at(tt_a(i), depth);
- if x == 1 { return 1; }
- y := inh_any_at(tt_b(i), depth);
- if y == 1 { return 1; }
- if x == -1 || y == -1 { return -1; }
- return 0;
- }
- if tt_tag(i) == TT_MU { return inh_any_at(tt_subst(tt_b(i), tt_a(i), i), depth + 1); }
- if tt_tag(i) == TT_BOT { return 0; }
- ty_lits_reset();
- lit_collect(i);
+fn inh_any(i: int) -> int:
+ return inh_any_at(i, 0)
+
+fn inh_any_at(i: int, depth: int) -> int:
+ if depth > 512:
+ g_ty_exhausted = 1
+ return -1
+ if tt_tag(i) == TT_UNION:
+ x := inh_any_at(tt_a(i), depth)
+ if x == 1:
+ return 1
+ y := inh_any_at(tt_b(i), depth)
+ if y == 1:
+ return 1
+ if x == -1 || y == -1:
+ return -1
+ return 0
+ if tt_tag(i) == TT_MU:
+ return inh_any_at(tt_subst(tt_b(i), tt_a(i), i), depth + 1)
+ if tt_tag(i) == TT_BOT:
+ return 0
+ ty_lits_reset()
+ lit_collect(i)
// 本语言无三元运算符(`?:` 不合法——P0 Task 3 构建期实证)→ 显式分支
- if lits_contradictory() == 1 { return 0; }
- return 1;
-}
+ if lits_contradictory() == 1:
+ return 0
+ return 1
// ─── 反例(witness)与穷尽性(Task 4)───
// witness = A\B 的规范化类型项;**不可满足 → -1**(无遗漏/无反例值);
// **-2 = 未知**(预算耗尽/未覆盖面——与「不可满足」严格区分:P0 终审 Minor 指出早期
// 二者共用 -1 会让「证明不了」被当成「确实穷尽」)
-fn tt_witness(a: int, b: int) -> int {
- r := tt_norm(tt_inter(a, tt_not(b)));
- if r < 0 { return -2; }
- if tt_tag(r) == TT_BOT { return -1; }
- x := ty_inhabited(r);
- if x == -1 { return -2; }
- if x != 1 { return -1; }
- return r;
-}
+fn tt_witness(a: int, b: int) -> int:
+ r := tt_norm(tt_inter(a, tt_not(b)))
+ if r < 0:
+ return -2
+ if tt_tag(r) == TT_BOT:
+ return -1
+ x := ty_inhabited(r)
+ if x == -1:
+ return -2
+ if x != 1:
+ return -1
+ return r
// 穷尽 witness = domain \ ⋃patterns(patterns = CONS 链)
-fn ty_exhaust_witness(domain: int, patterns: int) -> int {
- acc : ., mut = tt_bot();
- p : ., mut = patterns;
- loop {
- if p < 0 { break; }
- if tt_tag(p) != TT_CONS { break; }
- acc = tt_union(acc, tt_a(p));
- p = tt_b(p);
- }
- return tt_witness(domain, acc);
-}
-
-fn ty_exhaustive(domain: int, patterns: int) -> int {
- w := ty_exhaust_witness(domain, patterns);
- if w == -2 { return -1; } // 未知(预算耗尽/未覆盖面)——不得当「穷尽」
- if g_ty_exhausted != 0 { return -1; }
- if w < 0 { return 1; } // 补集空 = 穷尽
- return 0;
-}
-
-fn ty_disjoint(a: int, b: int) -> int {
- x := ty_inhabited(tt_inter(a, b));
- if x == -1 { return -1; } // 三态传播:未知不得降级为 0
- if x == 0 { return 1; }
- return 0;
-}
+fn ty_exhaust_witness(domain: int, patterns: int) -> int:
+ acc : ., mut = tt_bot()
+ p : ., mut = patterns
+ loop:
+ if p < 0:
+ break
+ if tt_tag(p) != TT_CONS:
+ break
+ acc = tt_union(acc, tt_a(p))
+ p = tt_b(p)
+ return tt_witness(domain, acc)
+
+fn ty_exhaustive(domain: int, patterns: int) -> int:
+ w := ty_exhaust_witness(domain, patterns)
+ if w == -2:
+ return -1
+ // 未知(预算耗尽/未覆盖面)——不得当「穷尽」
+ if g_ty_exhausted != 0:
+ return -1
+ if w < 0:
+ return 1
+ // 补集空 = 穷尽
+ return 0
+
+fn ty_disjoint(a: int, b: int) -> int:
+ x := ty_inhabited(tt_inter(a, b))
+ if x == -1:
+ return -1
+ // 三态传播:未知不得降级为 0
+ if x == 0:
+ return 1
+ return 0
// iface 簇已移至 iface_axis.cr(R2 P4 Task 0,链接面纯化)
diff --git a/src/compiler/type_selftest.cr b/src/compiler/type_selftest.cr
index 7a87a29e..c101aa38 100644
--- a/src/compiler/type_selftest.cr
+++ b/src/compiler/type_selftest.cr
@@ -7,157 +7,171 @@
// (否定在超类型侧 / memo 扩容不挂 / 预算不吞 -1 / n 元析取 / 命名原子未知 /
// ¬μ 不下推 / 未覆盖面未知)。tests/selfhost/test_type_engine.py 的 MIN_CASES = 32。
-fn ts_check(name: string, got: int, want: int) -> int {
- if got == want {
- print("PASS "); println(name);
- return 0;
- }
- print("FAIL "); print(name);
- print(": got "); print(int_str(got));
- print(" want "); println(int_str(want));
- return 1;
-}
+fn ts_check(name: string, got: int, want: int) -> int:
+ if got == want:
+ print("PASS ")
+ println(name)
+ return 0
+ print("FAIL ")
+ print(name)
+ print(": got ")
+ print(int_str(got))
+ print(" want ")
+ println(int_str(want))
+ return 1
// bool 版(批 8 S2 · bool 类;维护者裁定「bool 不隐式转 int」⇒ 计数惯用式改**类型化 helper**):
// 语义与 `ts_check` 逐字一致,只把 `got`/`want` 换成 **bool** ⇒ 调用点无需 bool→int 隐式转换;
// FAIL 分支打印 `bool_str`(与 int 版的 `int_str` 对应)。
-fn ts_check_b(name: string, got: bool, want: bool) -> int {
- if got == want {
- print("PASS "); println(name);
- return 0;
- }
- print("FAIL "); print(name);
- print(": got "); print(bool_str(got));
- print(" want "); println(bool_str(want));
- return 1;
-}
+fn ts_check_b(name: string, got: bool, want: bool) -> int:
+ if got == want:
+ print("PASS ")
+ println(name)
+ return 0
+ print("FAIL ")
+ print(name)
+ print(": got ")
+ print(bool_str(got))
+ print(" want ")
+ println(bool_str(want))
+ return 1
// Task 4 端到端用例的诊断探针:check_error 只追加 g_diags(不打印),故「门是否报错」可由
// 增量计数 + 首条新诊断码直接读——这是「接线后门真的在判」的行为证据(表侧用例只能证明表对)。
-fn ts_diag_code_at(idx: int) -> int {
- if idx < 0 { return -1; }
- if idx >= g_diag_count { return -1; }
- return r64(g_diags, idx * DIAG_REC_SIZE);
-}
+fn ts_diag_code_at(idx: int) -> int:
+ if idx < 0:
+ return -1
+ if idx >= g_diag_count:
+ return -1
+ return r64(g_diags, idx * DIAG_REC_SIZE)
// 诊断消息探针(R2 P5 Task 4):读第 idx 条诊断的消息指针(check_error 存的就是该指针)。
-fn ts_diag_msg_at(idx: int) -> string {
- if idx < 0 { return ""; }
- if idx >= g_diag_count { return ""; }
- return load_str_ptr(g_diags, idx * DIAG_REC_SIZE + 8);
-}
+fn ts_diag_msg_at(idx: int) -> string:
+ if idx < 0:
+ return ""
+ if idx >= g_diag_count:
+ return ""
+ return load_str_ptr(g_diags, idx * DIAG_REC_SIZE + 8)
// ─── R2 P5 Task 4:AK 映射的**冻结期望表**(替代已删的 legacy 副本对照物)───
// 与 iface_registry.cr 的 `iface_by_ty_code`(唯一生产实现)逐格对照用:本表 = 数据形态的期望,
// 不再是生产文件里的第二份实现(单源化的判据由此从「两份实现互比」变「实现 vs 冻结期望」)。
// 依据 = P2b Task 2 已裁决的映射(含两条灰格:TY_DEX_S → AK_DEX(同值域不同表示)、
// TY_GENERIC_PARAM → AK_NAMED(泛型参数哨兵 → 命名类,不展开));未映射码 ⇒ -1。
-fn ts_t4_ak_expected(ty: int) -> int {
- if ty == TY_INT { return AK_INT; }
- if ty == TY_DEX { return AK_DEX; }
- if ty == TY_DEX_S { return AK_DEX; }
- if ty == TY_BOOL { return AK_BOOL; }
- if ty == TY_STRING { return AK_STRING; }
- if ty == TY_UNIT { return AK_UNIT; }
- if ty == TY_NEVER { return AK_NEVER; }
- if ty == TY_CHAR { return AK_CHAR; }
- if ty == TY_GENERIC_PARAM { return AK_NAMED; }
- return -1;
-}
+fn ts_t4_ak_expected(ty: int) -> int:
+ if ty == TY_INT:
+ return AK_INT
+ if ty == TY_DEX:
+ return AK_DEX
+ if ty == TY_DEX_S:
+ return AK_DEX
+ if ty == TY_BOOL:
+ return AK_BOOL
+ if ty == TY_STRING:
+ return AK_STRING
+ if ty == TY_UNIT:
+ return AK_UNIT
+ if ty == TY_NEVER:
+ return AK_NEVER
+ if ty == TY_CHAR:
+ return AK_CHAR
+ if ty == TY_GENERIC_PARAM:
+ return AK_NAMED
+ return -1
// 行号面期望:**门**(kind 非 TYP_BASE ⇒ -1,含 TYP_DYN/结构/命名行与负 ti)+ 表内分派。
-fn ts_t4_native_ak_expected(ti: int) -> int {
- if ti < 0 { return -1; }
- if get_type_kind(ti) != TYP_BASE { return -1; }
- return ts_t4_ak_expected(get_type_data(ti));
-}
+fn ts_t4_native_ak_expected(ti: int) -> int:
+ if ti < 0:
+ return -1
+ if get_type_kind(ti) != TYP_BASE:
+ return -1
+ return ts_t4_ak_expected(get_type_data(ti))
// 宽联合探针(预算守卫用):N 层左深 union —— sub_cover 逐支递归,每支 1 步,
// N > 预算即耗尽(深 μ 链不行:参数位置的字面蕴含不递归展开,会在参数比较处短路)。
-fn tt_probe_wide_union(depth: int) -> int {
- acc : ., mut = tt_atom(AK_INT, TI_INT, -1);
- d : ., mut = 0;
- loop {
- if d >= depth { break; }
- acc = tt_union(acc, tt_atom(AK_STRING, TI_STR, -1));
- d = d + 1;
- }
- return acc;
-}
+fn tt_probe_wide_union(depth: int) -> int:
+ acc : ., mut = tt_atom(AK_INT, TI_INT, -1)
+ d : ., mut = 0
+ loop:
+ if d >= depth:
+ break
+ acc = tt_union(acc, tt_atom(AK_STRING, TI_STR, -1))
+ d = d + 1
+ return acc
// R2 P3 Task 0 夹具:声明单 `int` 字段 struct(a: int),返回其命名行。本通道不经
// parser/check_all ⇒ struct 声明表照 parser.cr:1539-1560 的写槽序人工落(字段名 /
// 裸码槽 / 类型节点 / 字段数),类型节点照 parse_type 的产物形态构造。
-fn ts_unf_mk_int_struct(name: string) -> int {
- sa := add_struct(name);
- si_set_field_name(sa, 0, str_intern("a"));
- si_set_field_type(sa, 0, TY_INT);
- si_set_field_type_node(sa, 0, alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0));
- w64(g_structs, sa * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, 1);
- return alloc_named_type(str_intern(name));
-}
+fn ts_unf_mk_int_struct(name: string) -> int:
+ sa := add_struct(name)
+ si_set_field_name(sa, 0, str_intern("a"))
+ si_set_field_type(sa, 0, TY_INT)
+ si_set_field_type_node(sa, 0, alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0))
+ w64(g_structs, sa * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, 1)
+ return alloc_named_type(str_intern(name))
// 域项的析取支计数(「变体数」判据用):只按引擎项形态走 union 树,**不与实现共享计数逻辑**
// (独立重算——否则同源同错自洽假绿)。⊥/单支 → 1。
-fn ts_unf_union_leaves(t: int) -> int {
- if tt_tag(t) == TT_UNION { return ts_unf_union_leaves(tt_a(t)) + ts_unf_union_leaves(tt_b(t)); }
- return 1;
-}
+fn ts_unf_union_leaves(t: int) -> int:
+ if tt_tag(t) == TT_UNION:
+ return ts_unf_union_leaves(tt_a(t)) + ts_unf_union_leaves(tt_b(t))
+ return 1
// ─── R2 P3 Task 5 夹具(生产函数入口,见 t5.* 段注)───
// g_gen_map 按名字查绑定(-1 = 未绑定)——t5.f4 用(独立读取,不复用 checker 内部循环)
-fn ts_gen_map_ti(name_ni: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= g_gen_map_count { return -1; }
- if r64(g_gen_map_names, i * 8) == name_ni { return r64(g_gen_map_types, i * 8); }
- i = i + 1;
- }
- return -1;
-}
+fn ts_gen_map_ti(name_ni: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= g_gen_map_count:
+ return -1
+ if r64(g_gen_map_names, i * 8) == name_ni:
+ return r64(g_gen_map_types, i * 8)
+ i = i + 1
+ return -1
// 单泛型形参 + 单约束名的 struct 声明行夹具(约束经 **parser 的生产登记函数**
// save_struct_gen_constrs 落侧表——测真实路径,不手写侧表)
-fn ts_t5_mk_constr_struct(name: string, cname: string) -> int {
- sa := add_struct(name);
- w64(g_structs, sa * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT, 1);
- w64(g_structs, sa * ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES, str_intern("T5_CS_T"));
- cb := alloc(8);
- w64(cb, 0, str_intern(cname));
- save_struct_gen_constrs(sa, cb, 1);
- return sa;
-}
-
-fn ts_t5_mk_constr_enum(name: string, cname: string) -> int {
- ea := add_enum(name);
- w64(g_enums, ea * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 1);
- w64(g_enums, ea * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES, str_intern("T5_CE_T"));
- cb := alloc(8);
- w64(cb, 0, str_intern(cname));
- save_enum_gen_constrs(ea, cb, 1);
- return ea;
-}
+fn ts_t5_mk_constr_struct(name: string, cname: string) -> int:
+ sa := add_struct(name)
+ w64(g_structs, sa * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT, 1)
+ w64(g_structs, sa * ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES, str_intern("T5_CS_T"))
+ cb := alloc(8)
+ w64(cb, 0, str_intern(cname))
+ save_struct_gen_constrs(sa, cb, 1)
+ return sa
+
+fn ts_t5_mk_constr_enum(name: string, cname: string) -> int:
+ ea := add_enum(name)
+ w64(g_enums, ea * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 1)
+ w64(g_enums, ea * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES, str_intern("T5_CE_T"))
+ cb := alloc(8)
+ w64(cb, 0, str_intern(cname))
+ save_enum_gen_constrs(ea, cb, 1)
+ return ea
// 接口表行夹具(零方法):t5.constr_iface_is_unknown_p3b 用(谓词 = find_iface 命中 ⇒
// gen_constr_satisfied 必须回 -1——P3b 交接边界)
-fn ts_t5_mk_iface(name: string) -> int {
- grow_ifaces(g_iface_count + 1);
- base := g_iface_count * ESZ_IFACEINFO;
- zi : ., mut = 0;
- loop { if zi >= ESZ_IFACEINFO { break; } w8(g_ifaces, base + zi, 0); zi = zi + 1; }
- w64(g_ifaces, base + OFF_IF_NAME, str_intern(name));
- w64(g_ifaces, base + OFF_IF_GENERIC_COUNT, 0);
- g_iface_count = g_iface_count + 1;
- return g_iface_count - 1;
-}
+fn ts_t5_mk_iface(name: string) -> int:
+ grow_ifaces(g_iface_count + 1)
+ base := g_iface_count * ESZ_IFACEINFO
+ zi : ., mut = 0
+ loop:
+ if zi >= ESZ_IFACEINFO:
+ break
+ w8(g_ifaces, base + zi, 0)
+ zi = zi + 1
+ w64(g_ifaces, base + OFF_IF_NAME, str_intern(name))
+ w64(g_ifaces, base + OFF_IF_GENERIC_COUNT, 0)
+ g_iface_count = g_iface_count + 1
+ return g_iface_count - 1
// ─── R2 P3 Task 5 用例体(独立函数:**不得**内联进 type_selftest_run ——
/// 该函数已是巨型函数,本段 40+ 局部变量的加入会使其在 Python bootstrap 的
/// 栈式代码生成下越界(实测:内联版 SIGSEGV rc=139;拆出后正常)。返回 = 失败数。
/// 用例数 = 9(调用方 `total = total + 9` 须同步——增删用例两处一起改)。
-fn ts_t5_run() -> int {
- fails : ., mut = 0;
+fn ts_t5_run() -> int:
+ fails : ., mut = 0
// ═══ R2 P3 Task 5:泛型约束(保留 / 实例化判定 / 反例 / 实例键类型项化)═══
// 判据面 = ① F4 形参链导航(形参节点**不连续**布局下的正/负控——旧 `pn+1` 导航的牙);
// ② 约束名解析 + 本质轴三态判定(1/0/-1);③ 用户接口约束 = **-1 不判**(P3b 交接边界:
@@ -166,162 +180,159 @@ fn ts_t5_run() -> int {
// ⑦ 实例键结构忠实(异型异键 = 反折叠)+ ti 型替换在**克隆体**上的落点(形参类型节点)。
// 夹具说明:本组不经 parser/check_all(照 t3/t4 口径人工落表),但**走生产函数**——
// save_struct_gen_constrs / gen_inst_constr_check / infer_gen_call / gen_find_or_create_bind。
- init_types();
- ty_budget_reset(200000);
+ init_types()
+ ty_budget_reset(200000)
// ① F4:夹具 = 「文件首类型节点恰是另一泛型形参的 ident」+ 形参 (n: int, a: T)(类型节点
// 插在形参节点之前 ⇒ 形参在节点表不连续)。旧导航把 param1 的 pattern 读成节点 0 ⇒
// 凭空绑定 U(phanton)且 T 永不绑定;修复后 param1 的 pattern = 声明类型 gparam(T)。
- init_types(); // 夹具前再清一次(上面 alloc 的行使节点下标可预期:本组不依赖具体下标)
- t5_u_ni := str_intern("T5_U");
- t5_u_row := alloc_type(TYP_GENERIC_PARAM, t5_u_ni, 0);
- def_sym(t5_u_ni, SYM_TYPE, t5_u_row, -1);
- alloc_node(EXPR_IDENT, 0, 0, 0, t5_u_ni, 0, 0, 0, 0); // 「文件首类型节点」
- t5_int_n := alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0);
- t5_p0 := alloc_node(EXPR_PARAM, str_intern("n"), 0, 0, 0, TY_INT, t5_int_n, 0, 0);
- t5_t_ni := str_intern("T5_T");
- t5_t_row := alloc_type(TYP_GENERIC_PARAM, t5_t_ni, 0);
- def_sym(t5_t_ni, SYM_TYPE, t5_t_row, -1);
- t5_t_n1 := alloc_node(EXPR_IDENT, 0, 0, 0, t5_t_ni, 0, 0, 0, 0);
- t5_p1 := alloc_node(EXPR_PARAM, str_intern("a"), 0, 0, 0, 0, t5_t_n1, 0, 0);
- t5_rt := alloc_node(EXPR_IDENT, 0, 0, 0, t5_t_ni, 0, 0, 0, 0);
- t5_fn := alloc_node(EXPR_FN, str_intern("t5_f4_take"), t5_p0, 2, 0, t5_rt, -1, 0, 0);
- t5_fi := add_func("t5_f4_take", 2, 0, t5_fn); // add_func 收**字符串**(parser 同款:tok_lx 结果),不是 ni
- fi_set_generic_count(t5_fi, 1);
- println("M5b");
- fi_set_generic_name(t5_fi, 0, t5_t_ni);
- println("M5c");
- def_sym(str_intern("t5_f4_take"), SYM_FN, TI_UNIT, -1);
- t5_arg2 := alloc_node(EXPR_ARG, alloc_node(EXPR_STRING, 0, 0, 0, str_intern("s"), 0, 0, 0, 0), 0, 0, 0, 0, 0, 0, 0);
+ init_types() // 夹具前再清一次(上面 alloc 的行使节点下标可预期:本组不依赖具体下标)
+ t5_u_ni := str_intern("T5_U")
+ t5_u_row := alloc_type(TYP_GENERIC_PARAM, t5_u_ni, 0)
+ def_sym(t5_u_ni, SYM_TYPE, t5_u_row, -1)
+ alloc_node(EXPR_IDENT, 0, 0, 0, t5_u_ni, 0, 0, 0, 0) // 「文件首类型节点」
+ t5_int_n := alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0)
+ t5_p0 := alloc_node(EXPR_PARAM, str_intern("n"), 0, 0, 0, TY_INT, t5_int_n, 0, 0)
+ t5_t_ni := str_intern("T5_T")
+ t5_t_row := alloc_type(TYP_GENERIC_PARAM, t5_t_ni, 0)
+ def_sym(t5_t_ni, SYM_TYPE, t5_t_row, -1)
+ t5_t_n1 := alloc_node(EXPR_IDENT, 0, 0, 0, t5_t_ni, 0, 0, 0, 0)
+ t5_p1 := alloc_node(EXPR_PARAM, str_intern("a"), 0, 0, 0, 0, t5_t_n1, 0, 0)
+ t5_rt := alloc_node(EXPR_IDENT, 0, 0, 0, t5_t_ni, 0, 0, 0, 0)
+ t5_fn := alloc_node(EXPR_FN, str_intern("t5_f4_take"), t5_p0, 2, 0, t5_rt, -1, 0, 0)
+ t5_fi := add_func("t5_f4_take", 2, 0, t5_fn) // add_func 收**字符串**(parser 同款:tok_lx 结果),不是 ni
+ fi_set_generic_count(t5_fi, 1)
+ println("M5b")
+ fi_set_generic_name(t5_fi, 0, t5_t_ni)
+ println("M5c")
+ def_sym(str_intern("t5_f4_take"), SYM_FN, TI_UNIT, -1)
+ t5_arg2 := alloc_node(EXPR_ARG, alloc_node(EXPR_STRING, 0, 0, 0, str_intern("s"), 0, 0, 0, 0), 0, 0, 0, 0, 0, 0, 0)
// EXPR_ARG: a = expr, b = next(末项 b = 0 即终止符——链遍历按 `an < 0` 停,见 infer_gen_call)
- ast_set_b(t5_arg2, -1);
- t5_arg1 := alloc_node(EXPR_ARG, alloc_node(EXPR_INT, 0, 0, 0, 1, 0, 0, 0, 0), t5_arg2, 0, 0, 0, 0, 0, 0);
- t5_calln := alloc_node(EXPR_CALL, 0, t5_arg1, 2, 0, 0, 0, 0, 0);
- infer_gen_call(t5_fi, t5_calln, t5_arg1, 2);
- t5_ti_bound := ts_gen_map_ti(t5_t_ni);
+ ast_set_b(t5_arg2, -1)
+ t5_arg1 := alloc_node(EXPR_ARG, alloc_node(EXPR_INT, 0, 0, 0, 1, 0, 0, 0, 0), t5_arg2, 0, 0, 0, 0, 0, 0)
+ t5_calln := alloc_node(EXPR_CALL, 0, t5_arg1, 2, 0, 0, 0, 0, 0)
+ infer_gen_call(t5_fi, t5_calln, t5_arg1, 2)
+ t5_ti_bound := ts_gen_map_ti(t5_t_ni)
fails = fails + ts_check_b("t5.f4_later_param_declared_type",
- (t5_ti_bound == TI_STR && ts_gen_map_ti(t5_u_ni) == -1), true);
+ (t5_ti_bound == TI_STR && ts_gen_map_ti(t5_u_ni) == -1), true)
fails = fails + ts_check_b("t5.f4_bind_seg_recorded",
(g_gen_binds_count == 2 && r64(g_gen_binds, 0 * 8) == 1 &&
- r64(g_gen_binds, 1 * 8) == TI_STR && ast_int_val(t5_calln) == 1), true);
+ r64(g_gen_binds, 1 * 8) == TI_STR && ast_int_val(t5_calln) == 1), true)
// ② 约束名解析 + 本质轴三态
- t5_ni_int := str_intern("int");
- t5_ni_str := str_intern("string");
- t5_ni_nope := str_intern("T5_NoSuchTypeName");
+ t5_ni_int := str_intern("int")
+ t5_ni_str := str_intern("string")
+ t5_ni_nope := str_intern("T5_NoSuchTypeName")
fails = fails + ts_check_b("t5.constr_name_resolve",
(gen_constr_type_ti(t5_ni_int) == TI_INT && gen_constr_type_ti(t5_ni_str) == TI_STR &&
- gen_constr_type_ti(str_intern("never")) == TI_NEVER && gen_constr_type_ti(t5_ni_nope) == -1 &&
- gen_constr_type_ti(-1) == -1), true);
+ gen_constr_type_ti(str_intern("never")) == TI_NEVER && gen_constr_type_ti(t5_ni_nope) == -1 &&
+ gen_constr_type_ti(-1) == -1), true)
fails = fails + ts_check_b("t5.constr_essence_three_state",
(gen_constr_satisfied(t5_ni_int, TI_INT) == 1 &&
// `never` **不**满足原生约束(引擎现状:AK_NEVER 是与 AK_INT 互斥的**原子**,不是 ⊥
// ——P0 既有语义「never 行在引擎侧不是真 ⊥」(T4 报告 §7-⑨),本批如实钉住、不动)
- gen_constr_satisfied(t5_ni_int, TI_NEVER) == 0 &&
- gen_constr_satisfied(t5_ni_int, TI_STR) == 0 &&
- gen_constr_satisfied(t5_ni_str, TI_INT) == 0 &&
- gen_constr_satisfied(t5_ni_nope, TI_INT) == -1), true);
+ gen_constr_satisfied(t5_ni_int, TI_NEVER) == 0 &&
+ gen_constr_satisfied(t5_ni_int, TI_STR) == 0 &&
+ gen_constr_satisfied(t5_ni_str, TI_INT) == 0 &&
+ gen_constr_satisfied(t5_ni_nope, TI_INT) == -1), true)
// ③ 用户接口约束 + **非命名实参** ⇒ -1(P3b Task 0 后仍 -1:域限定——接口方法表只对命名行
// 可查,故 `int` 实参不判;**不是**「未交付」。命名实参的判定面见 isat.* 段与
// tests/selfhost/test_iface_satisfies.py)
- t5_if_ii := ts_t5_mk_iface("T5_Show");
+ t5_if_ii := ts_t5_mk_iface("T5_Show")
fails = fails + ts_check_b("t5.constr_iface_non_named_unjudged",
(find_iface(str_intern("T5_Show")) == t5_if_ii &&
- gen_constr_satisfied(str_intern("T5_Show"), TI_INT) == -1), true);
+ gen_constr_satisfied(str_intern("T5_Show"), TI_INT) == -1), true)
// ④ 反例文本:失败非空、通过为空(**不谎报**)
fails = fails + ts_check_b("t5.constr_witness_text",
(str_len(gen_constr_witness_str(TI_STR, t5_ni_int)) > 0 &&
- str_len(gen_constr_witness_str(TI_INT, t5_ni_int)) == 0 &&
- str_len(gen_constr_witness_str(TI_INT, t5_ni_nope)) == 0), true);
+ str_len(gen_constr_witness_str(TI_INT, t5_ni_int)) == 0 &&
+ str_len(gen_constr_witness_str(TI_INT, t5_ni_nope)) == 0), true)
// ⑤⑥ 实例化点检查:结构/枚举约束经 parser 登记函数落侧表 + 判定 + 去重 + 正负控 + 接口面零动作
- t5_si := ts_t5_mk_constr_struct("T5BoxInt", "int");
- t5_ei := ts_t5_mk_constr_enum("T5EBoxInt", "int");
- t5_si2 := ts_t5_mk_constr_struct("T5BoxShow", "T5_Show");
+ t5_si := ts_t5_mk_constr_struct("T5BoxInt", "int")
+ t5_ei := ts_t5_mk_constr_enum("T5EBoxInt", "int")
+ t5_si2 := ts_t5_mk_constr_struct("T5BoxShow", "T5_Show")
fails = fails + ts_check_b("t5.constr_side_table_readback",
(si_generic_count(t5_si) == 1 && si_gen_constr(t5_si, 0) == t5_ni_int &&
- si_gen_constr(t5_si, 1) == -1 && si_gen_constr(-1, 0) == -1 &&
- ei_generic_count(t5_ei) == 1 && ei_gen_constr(t5_ei, 0) == t5_ni_int &&
- ei_gen_constr(t5_ei, 4) == -1), true);
- t5_args := alloc(8);
- w64(t5_args, 0 * 8, TI_STR);
- t5_gnode := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5BoxInt"), -1, 1, 0, 0, 0, 41, 3);
- t5_d0 := g_diag_count;
- gen_inst_constr_check(t5_gnode, t5_si, -1, t5_args, 1);
- t5_d1 := g_diag_count;
- gen_inst_constr_check(t5_gnode, t5_si, -1, t5_args, 1); // 同节点同形参 → 去重
- t5_d2 := g_diag_count;
- t5_gnode2 := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5BoxInt"), -1, 1, 0, 0, 0, 42, 3);
- gen_inst_constr_check(t5_gnode2, t5_si, -1, t5_args, 1); // 新节点 → 再报(去重不跨节点)
- t5_d3 := g_diag_count;
- w64(t5_args, 0 * 8, TI_INT);
- t5_gnode3 := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5BoxInt"), -1, 1, 0, 0, 0, 43, 3);
- gen_inst_constr_check(t5_gnode3, t5_si, -1, t5_args, 1); // 正控:满足 → 零诊断
- gen_inst_constr_check(t5_gnode3, t5_ei, -1, t5_args, 1); // 枚举侧同(满足)
- t5_d4 := g_diag_count;
- w64(t5_args, 0 * 8, TI_STR);
- t5_gnode4 := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5EBoxInt"), -1, 1, 0, 0, 0, 44, 3);
- gen_inst_constr_check(t5_gnode4, -1, t5_ei, t5_args, 1); // 枚举侧违反 → 诊断
- t5_d5 := g_diag_count;
- t5_gnode5 := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5BoxShow"), -1, 1, 0, 0, 0, 45, 3);
- gen_inst_constr_check(t5_gnode5, t5_si2, -1, t5_args, 1); // 接口约束 = 不判 → 零诊断
- t5_d6 := g_diag_count;
+ si_gen_constr(t5_si, 1) == -1 && si_gen_constr(-1, 0) == -1 &&
+ ei_generic_count(t5_ei) == 1 && ei_gen_constr(t5_ei, 0) == t5_ni_int &&
+ ei_gen_constr(t5_ei, 4) == -1), true)
+ t5_args := alloc(8)
+ w64(t5_args, 0 * 8, TI_STR)
+ t5_gnode := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5BoxInt"), -1, 1, 0, 0, 0, 41, 3)
+ t5_d0 := g_diag_count
+ gen_inst_constr_check(t5_gnode, t5_si, -1, t5_args, 1)
+ t5_d1 := g_diag_count
+ gen_inst_constr_check(t5_gnode, t5_si, -1, t5_args, 1) // 同节点同形参 → 去重
+ t5_d2 := g_diag_count
+ t5_gnode2 := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5BoxInt"), -1, 1, 0, 0, 0, 42, 3)
+ gen_inst_constr_check(t5_gnode2, t5_si, -1, t5_args, 1) // 新节点 → 再报(去重不跨节点)
+ t5_d3 := g_diag_count
+ w64(t5_args, 0 * 8, TI_INT)
+ t5_gnode3 := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5BoxInt"), -1, 1, 0, 0, 0, 43, 3)
+ gen_inst_constr_check(t5_gnode3, t5_si, -1, t5_args, 1) // 正控:满足 → 零诊断
+ gen_inst_constr_check(t5_gnode3, t5_ei, -1, t5_args, 1) // 枚举侧同(满足)
+ t5_d4 := g_diag_count
+ w64(t5_args, 0 * 8, TI_STR)
+ t5_gnode4 := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5EBoxInt"), -1, 1, 0, 0, 0, 44, 3)
+ gen_inst_constr_check(t5_gnode4, -1, t5_ei, t5_args, 1) // 枚举侧违反 → 诊断
+ t5_d5 := g_diag_count
+ t5_gnode5 := alloc_node(EXPR_GENERIC_APPLY, str_intern("T5BoxShow"), -1, 1, 0, 0, 0, 45, 3)
+ gen_inst_constr_check(t5_gnode5, t5_si2, -1, t5_args, 1) // 接口约束 = 不判 → 零诊断
+ t5_d6 := g_diag_count
fails = fails + ts_check_b("t5.inst_check_dedup_and_controls",
(t5_d1 - t5_d0 == 1 && t5_d2 - t5_d1 == 0 && t5_d3 - t5_d2 == 1 &&
- t5_d4 - t5_d3 == 0 && t5_d5 - t5_d4 == 1 && t5_d6 - t5_d5 == 0 &&
- ts_diag_code_at(t5_d0) == EC_TG_BOUND &&
+ t5_d4 - t5_d3 == 0 && t5_d5 - t5_d4 == 1 && t5_d6 - t5_d5 == 0 &&
+ ts_diag_code_at(t5_d0) == EC_TG_BOUND &&
// 末条记录下标 = **调用后计数 - 1**(d5 是调用后的 g_diag_count)
- ts_diag_code_at(t5_d5 - 1) == EC_TG_BOUND), true);
+ ts_diag_code_at(t5_d5 - 1) == EC_TG_BOUND), true)
// ⑦ 实例键:异型异键(反折叠)+ 同名义同行同键 + 结构忠实(复合键含结构)
- t5_a_ti := alloc_named_type(str_intern("T5_A"));
- t5_b_ti := alloc_named_type(str_intern("T5_B"));
- t5_a2_ti := alloc_type(TYP_NAMED, str_intern("T5_A"), 0);
- t5_arr_ti := alloc_type(TYP_ARRAY, TI_INT, 3);
- t5_ptr_ti := alloc_type(TYP_PTR, t5_a_ti, 0);
- t5_slice_ti := alloc_type(TYP_SLICE, TI_INT, 0);
+ t5_a_ti := alloc_named_type(str_intern("T5_A"))
+ t5_b_ti := alloc_named_type(str_intern("T5_B"))
+ t5_a2_ti := alloc_type(TYP_NAMED, str_intern("T5_A"), 0)
+ t5_arr_ti := alloc_type(TYP_ARRAY, TI_INT, 3)
+ t5_ptr_ti := alloc_type(TYP_PTR, t5_a_ti, 0)
+ t5_slice_ti := alloc_type(TYP_SLICE, TI_INT, 0)
fails = fails + ts_check_b("t5.inst_key_structural_faithful",
(str_eq(inst_key_of_ti(t5_a_ti), inst_key_of_ti(t5_b_ti)) == 0 &&
- str_eq(inst_key_of_ti(t5_a_ti), inst_key_of_ti(t5_a2_ti)) != 0 &&
- str_eq(inst_key_of_ti(TI_INT), "int") != 0 &&
- str_eq(inst_key_of_ti(t5_arr_ti), "[int; 3]") != 0 &&
- str_eq(inst_key_of_ti(t5_ptr_ti), "*T5_A") != 0), true);
+ str_eq(inst_key_of_ti(t5_a_ti), inst_key_of_ti(t5_a2_ti)) != 0 &&
+ str_eq(inst_key_of_ti(TI_INT), "int") != 0 &&
+ str_eq(inst_key_of_ti(t5_arr_ti), "[int; 3]") != 0 &&
+ str_eq(inst_key_of_ti(t5_ptr_ti), "*T5_A") != 0), true)
// ⑧ ti 型替换端到端:克隆体内**泛型形参位**换成实参类型节点;异键异实例、同键缓存命中。
// 夹具形参实参 = **切片** `[int]`(键 "[int]"):ti 路径产出 EXPR_ARRAY 类型节点,名字路径
// 只会产出 EXPR_IDENT("[int]")(非法声明名)⇒ 本判据对「ti 路径是否生效」有牙。
// ⚠ **范围登记**:替换只覆盖**函数体内**节点——EXPR_FN 分支不克隆形参(形参类型由
// fi_param_type 的裸码承担),故克隆体形参仍指向源节点(与实例化的既有语义一致)。
- t5_m_ni := str_intern("T5_M");
- t5_m_tynode := alloc_node(EXPR_IDENT, 0, 0, 0, t5_m_ni, 0, 0, 0, 0);
- t5_m_body := alloc_node(EXPR_RETURN, t5_m_tynode, 0, 0, 0, 0, 0, 0, 0); // 体内形参位
- t5_m_p := alloc_node(EXPR_PARAM, str_intern("x"), 0, 0, 0, 0, t5_m_tynode, 0, 0);
- t5_m_rt := alloc_node(EXPR_IDENT, 0, 0, 0, t5_m_ni, 0, 0, 0, 0);
- t5_m_fn := alloc_node(EXPR_FN, t5_m_ni, t5_m_p, 1, 0, t5_m_rt, t5_m_body, 0, 0);
- t5_m_fi := add_func("T5_M", 1, 0, t5_m_fn);
- fi_set_generic_count(t5_m_fi, 1);
- fi_set_generic_name(t5_m_fi, 0, t5_m_ni);
+ t5_m_ni := str_intern("T5_M")
+ t5_m_tynode := alloc_node(EXPR_IDENT, 0, 0, 0, t5_m_ni, 0, 0, 0, 0)
+ t5_m_body := alloc_node(EXPR_RETURN, t5_m_tynode, 0, 0, 0, 0, 0, 0, 0) // 体内形参位
+ t5_m_p := alloc_node(EXPR_PARAM, str_intern("x"), 0, 0, 0, 0, t5_m_tynode, 0, 0)
+ t5_m_rt := alloc_node(EXPR_IDENT, 0, 0, 0, t5_m_ni, 0, 0, 0, 0)
+ t5_m_fn := alloc_node(EXPR_FN, t5_m_ni, t5_m_p, 1, 0, t5_m_rt, t5_m_body, 0, 0)
+ t5_m_fi := add_func("T5_M", 1, 0, t5_m_fn)
+ fi_set_generic_count(t5_m_fi, 1)
+ fi_set_generic_name(t5_m_fi, 0, t5_m_ni)
// 绑定段(人工按 checker 写入形态落:块 = [count, ti…],节点 int_val = 起始 + 1)
- grow_gen_binds(g_gen_binds_count + 2);
- t5_bstart := g_gen_binds_count;
- w64(g_gen_binds, t5_bstart * 8, 1);
- w64(g_gen_binds, (t5_bstart + 1) * 8, t5_slice_ti);
- g_gen_binds_count = t5_bstart + 2;
- t5_key_s := inst_key_of_ti(t5_slice_ti);
- t5_f1 := gen_find_or_create_bind(t5_m_fi, t5_key_s, t5_bstart);
- t5_f2 := gen_find_or_create_bind(t5_m_fi, t5_key_s, t5_bstart); // 同键 → 缓存命中
- t5_f3 := gen_find_or_create_bind(t5_m_fi, inst_key_of_ti(t5_b_ti), t5_bstart); // 异键 → 新实例
- t5_cp_ok : ., mut = 0;
- if t5_f1 >= 0 {
- t5_cb := ast_data(fi_ast_node(t5_f1)); // 克隆体(EXPR_FN)的 body
- if t5_cb >= 0 && ast_kind(t5_cb) == EXPR_RETURN {
- t5_cn := ast_a(t5_cb); // 体内形参位(源 = EXPR_IDENT(T5_M))
- if t5_cn >= 0 && ast_kind(t5_cn) == EXPR_ARRAY {
- t5_cn_e := ast_a(t5_cn); // 切片元素位(源实参 = int)
- if t5_cn_e >= 0 && ast_kind(t5_cn_e) == 0 && ast_type_val(t5_cn_e) == TY_INT { t5_cp_ok = 1; }
- }
- }
- }
+ grow_gen_binds(g_gen_binds_count + 2)
+ t5_bstart := g_gen_binds_count
+ w64(g_gen_binds, t5_bstart * 8, 1)
+ w64(g_gen_binds, (t5_bstart + 1) * 8, t5_slice_ti)
+ g_gen_binds_count = t5_bstart + 2
+ t5_key_s := inst_key_of_ti(t5_slice_ti)
+ t5_f1 := gen_find_or_create_bind(t5_m_fi, t5_key_s, t5_bstart)
+ t5_f2 := gen_find_or_create_bind(t5_m_fi, t5_key_s, t5_bstart) // 同键 → 缓存命中
+ t5_f3 := gen_find_or_create_bind(t5_m_fi, inst_key_of_ti(t5_b_ti), t5_bstart) // 异键 → 新实例
+ t5_cp_ok : ., mut = 0
+ if t5_f1 >= 0:
+ t5_cb := ast_data(fi_ast_node(t5_f1)) // 克隆体(EXPR_FN)的 body
+ if t5_cb >= 0 && ast_kind(t5_cb) == EXPR_RETURN:
+ t5_cn := ast_a(t5_cb) // 体内形参位(源 = EXPR_IDENT(T5_M))
+ if t5_cn >= 0 && ast_kind(t5_cn) == EXPR_ARRAY:
+ t5_cn_e := ast_a(t5_cn) // 切片元素位(源实参 = int)
+ if t5_cn_e >= 0 && ast_kind(t5_cn_e) == 0 && ast_type_val(t5_cn_e) == TY_INT:
+ t5_cp_ok = 1
fails = fails + ts_check_b("t5.inst_ti_subst_in_clone",
- (t5_f1 >= 0 && t5_f2 == t5_f1 && t5_f3 >= 0 && t5_f3 != t5_f1 && t5_cp_ok == 1), true);
+ (t5_f1 >= 0 && t5_f2 == t5_f1 && t5_f3 >= 0 && t5_f3 != t5_f1 && t5_cp_ok == 1), true)
- return fails;
-}
+ return fails
// ═══════════════ R2 P3b Task 0:`iface_satisfies` 契约用例(isat.*)═══════════════
// 面(详见 type_engine.cr 的契约头注):轴分派 A 形状 → C 用户接口 → B 本质轴;三态纪律
@@ -330,190 +341,187 @@ fn ts_t5_run() -> int {
// ③ 判定路径零 str_intern(.ccr STR 段守卫)④ 形状表注册/覆盖/复位语义。**
// 接口方法条目追加(照 parser 的 interface 分支写点:mbase + name/param_count/ret_ti)
-fn ts_isat_add_method(ii: int, mname: string, pc: int, rt: int) -> int {
- n := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT);
- mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + n * ESZ_IFMETHOD;
- w64(g_ifaces, mbase + OFF_IFM_NAME, str_intern(mname));
- w64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT, pc);
- w64(g_ifaces, mbase + OFF_IFM_RET_TI, rt);
+fn ts_isat_add_method(ii: int, mname: string, pc: int, rt: int) -> int:
+ n := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT)
+ mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + n * ESZ_IFMETHOD
+ w64(g_ifaces, mbase + OFF_IFM_NAME, str_intern(mname))
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT, pc)
+ w64(g_ifaces, mbase + OFF_IFM_RET_TI, rt)
// R2 P3b Task 6(Step 1 签名类型项化):**类型节点**槽(与生产 parser 同形:基类型节点 =
// kind 0 + type_val = TY_* 码)+ 接收者模式(0 = 无接收者,本组夹具形态)。
- w64(g_ifaces, mbase + OFF_IFM_RET_NODE, ts_ifc_base_node(rt));
- w64(g_ifaces, mbase + OFF_IFM_SELF_MODE, 0);
- pj : ., mut = 0;
- loop {
- if pj >= pc || pj >= MAX_IFACE_METHOD_PARAMS { break; }
- w64(g_ifaces, mbase + OFF_IFM_PARAM_TYPES + pj * 8, TY_INT);
- w64(g_ifaces, mbase + OFF_IFM_PARAM_NODES + pj * 8, ts_ifc_base_node(TY_INT));
- pj = pj + 1;
- }
- w64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT, n + 1);
- return mbase;
-}
+ w64(g_ifaces, mbase + OFF_IFM_RET_NODE, ts_ifc_base_node(rt))
+ w64(g_ifaces, mbase + OFF_IFM_SELF_MODE, 0)
+ pj : ., mut = 0
+ loop:
+ if pj >= pc || pj >= MAX_IFACE_METHOD_PARAMS:
+ break
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_TYPES + pj * 8, TY_INT)
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_NODES + pj * 8, ts_ifc_base_node(TY_INT))
+ pj = pj + 1
+ w64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT, n + 1)
+ return mbase
// 基类型节点(= parser `parse_type` 的基类型产物同形:kind 0、type_val = TY_* 码;
// 签名面消费点(`sh_sig_term_of_node` → `res_type_node`)按同一分派表解析)。
-fn ts_ifc_base_node(ty: int) -> int {
- return alloc_node(0, 0, 0, 0, 0, ty, 0, 0, 0);
-}
+fn ts_ifc_base_node(ty: int) -> int:
+ return alloc_node(0, 0, 0, 0, 0, ty, 0, 0, 0)
// impl 方法登记(**照 parser 的 impl 分支写点**:mangled 函数名 + g_methods 三元组
// {type_ni, method_ni, mangled_ni})——夹具须与生产写点同形,否则对拍在两种登记面上空转。
// R2 P3b Task 6:函数行带**真 EXPR_FN 节点**(形参链 + 类型节点;形参节点**不连续**——类型
// 节点插在其后,照 parse_body 的分配布局)——签名面(`sh_func_sig_term`)从 AST 读参数/返回型。
-fn ts_isat_add_impl_method(tname_ni: int, mname: string, pc: int, rt: int) -> int {
- mn := istr_get(tname_ni) + "." + mname;
- mangled_ni := str_intern(mn);
- pf : ., mut = -1;
- pj : ., mut = 0;
- loop {
- if pj >= pc { break; }
- tn := ts_ifc_base_node(TY_INT);
- if pf < 0 { pf = g_ast_count; }
- alloc_node(EXPR_PARAM, str_intern("p"), 0, 0, 0, TY_INT, tn, 0, 0);
- pj = pj + 1;
- }
- rtn := ts_ifc_base_node(rt);
- fn_node := alloc_node(EXPR_FN, mangled_ni, pf, pc, rt, rtn, -1, 0, 0);
- fi := add_func(mn, pc, rt, fn_node);
- grow_methods(g_method_count + 1);
- w64(g_methods, g_method_count * 24, tname_ni);
- w64(g_methods, g_method_count * 24 + 8, str_intern(mname));
- w64(g_methods, g_method_count * 24 + 16, mangled_ni);
- g_method_count = g_method_count + 1;
- return fi;
-}
-
-fn ts_isat_b2i(b: bool) -> int { if b { return 1; } return 0; }
+fn ts_isat_add_impl_method(tname_ni: int, mname: string, pc: int, rt: int) -> int:
+ mn := istr_get(tname_ni) + "." + mname
+ mangled_ni := str_intern(mn)
+ pf : ., mut = -1
+ pj : ., mut = 0
+ loop:
+ if pj >= pc:
+ break
+ tn := ts_ifc_base_node(TY_INT)
+ if pf < 0:
+ pf = g_ast_count
+ alloc_node(EXPR_PARAM, str_intern("p"), 0, 0, 0, TY_INT, tn, 0, 0)
+ pj = pj + 1
+ rtn := ts_ifc_base_node(rt)
+ fn_node := alloc_node(EXPR_FN, mangled_ni, pf, pc, rt, rtn, -1, 0, 0)
+ fi := add_func(mn, pc, rt, fn_node)
+ grow_methods(g_method_count + 1)
+ w64(g_methods, g_method_count * 24, tname_ni)
+ w64(g_methods, g_method_count * 24 + 8, str_intern(mname))
+ w64(g_methods, g_method_count * 24 + 16, mangled_ni)
+ g_method_count = g_method_count + 1
+ return fi
+
+fn ts_isat_b2i(b: bool) -> int:
+ if b:
+ return 1
+ return 0
// 用例数 = 16(调用方 `total = total + 16` 须同步——增删用例两处一起改)。
-fn ts_isat_run() -> int {
- fails : ., mut = 0;
+fn ts_isat_run() -> int:
+ fails : ., mut = 0
// ── 夹具:接口 `T0bShow { fn show(pc=1, rt=0) }`;命名行 T0bS(有 show)/ T0bT(无方法)──
// rt 码语义 = 映射层编码(0 = TY_INT,见 type_engine.cr 轴 C 注)。
- isat_ii := ts_t5_mk_iface("T0bShow");
- ts_isat_add_method(isat_ii, "show", 1, 0);
- isat_show_ni := str_intern("show");
- isat_s_ti := alloc_named_type(str_intern("T0bS"));
- isat_t_ti := alloc_named_type(str_intern("T0bT"));
- ts_isat_add_impl_method(str_intern("T0bS"), "show", 1, 0);
+ isat_ii := ts_t5_mk_iface("T0bShow")
+ ts_isat_add_method(isat_ii, "show", 1, 0)
+ isat_show_ni := str_intern("show")
+ isat_s_ti := alloc_named_type(str_intern("T0bS"))
+ isat_t_ti := alloc_named_type(str_intern("T0bT"))
+ ts_isat_add_impl_method(str_intern("T0bS"), "show", 1, 0)
// ① 轴 C 正例:方法在位 + 计数/返回码相符 ⇒ 1(命名行的空洞满足另见 ⑫)
fails = fails + ts_check("isat.axis_c_satisfied",
- iface_satisfies(isat_s_ti, str_intern("T0bShow")), 1);
+ iface_satisfies(isat_s_ti, str_intern("T0bShow")), 1)
// ② 轴 C 反例:方法名不在位 ⇒ **0**(可证违反——名字面忠实;不是 -1)
fails = fails + ts_check("isat.axis_c_missing_method",
- iface_satisfies(isat_t_ti, str_intern("T0bShow")), 0);
+ iface_satisfies(isat_t_ti, str_intern("T0bShow")), 0)
// ③ 轴 C 反例:参数计数不符 ⇒ 0
- isat_c_ti := alloc_named_type(str_intern("T0bC"));
- ts_isat_add_impl_method(str_intern("T0bC"), "show", 2, 0);
+ isat_c_ti := alloc_named_type(str_intern("T0bC"))
+ ts_isat_add_impl_method(str_intern("T0bC"), "show", 2, 0)
fails = fails + ts_check("isat.axis_c_param_count",
- iface_satisfies(isat_c_ti, str_intern("T0bShow")), 0);
+ iface_satisfies(isat_c_ti, str_intern("T0bShow")), 0)
// ④ 轴 C 反例:返回码不符(3 = TY_STRING)⇒ 0
- isat_r_ti := alloc_named_type(str_intern("T0bR"));
- ts_isat_add_impl_method(str_intern("T0bR"), "show", 1, 3);
+ isat_r_ti := alloc_named_type(str_intern("T0bR"))
+ ts_isat_add_impl_method(str_intern("T0bR"), "show", 1, 3)
fails = fails + ts_check("isat.axis_c_ret_code",
- iface_satisfies(isat_r_ti, str_intern("T0bShow")), 0);
+ iface_satisfies(isat_r_ti, str_intern("T0bShow")), 0)
// ⑤ 域限定:非命名行(原生 / dyn / 泛型形参)⇒ **不判**(无方法表身份;绝不因「查不到」报 0)
- isat_dyn_ti := alloc_type(TYP_DYN, 0, 0);
- isat_gp_ti := alloc_type(TYP_GENERIC_PARAM, str_intern("T0bU"), 0);
+ isat_dyn_ti := alloc_type(TYP_DYN, 0, 0)
+ isat_gp_ti := alloc_type(TYP_GENERIC_PARAM, str_intern("T0bU"), 0)
fails = fails + ts_check("isat.axis_c_non_named_unjudged",
ts_isat_b2i(iface_satisfies(TI_INT, str_intern("T0bShow")) == -1 &&
- iface_satisfies(isat_dyn_ti, str_intern("T0bShow")) == -1 &&
- iface_satisfies(isat_gp_ti, str_intern("T0bShow")) == -1), 1);
+ iface_satisfies(isat_dyn_ti, str_intern("T0bShow")) == -1 &&
+ iface_satisfies(isat_gp_ti, str_intern("T0bShow")) == -1), 1)
// ⑥ 轴 B(本质轴):= gen_constr_satisfied 引擎面(迁移到统一入口后逐例同结论)
fails = fails + ts_check("isat.axis_b_essence",
ts_isat_b2i(iface_satisfies(TI_INT, str_intern("int")) == 1 &&
- iface_satisfies(TI_INT, str_intern("string")) == 0 &&
- iface_satisfies(TI_INT, str_intern("T0bNoSuchName")) == -1), 1);
+ iface_satisfies(TI_INT, str_intern("string")) == 0 &&
+ iface_satisfies(TI_INT, str_intern("T0bNoSuchName")) == -1), 1)
// ⑦ 轴 A(横切形状):注册 ⊤_SEQUENCE 名 ⇒ 切片行 1 / 原生行 0;**复位后同键 ⇒ -1**
// (复位断言防「条目泄漏成全局态」;lookup 负键守卫)
// R2 P4 Task 3 重定:形状表在 init_types 尾部已有**生产注册面**(6 条 D17 名)
// ——本行 = 第 7 条(slot 6),计数基数由 0 改 6;注册/查询/判定语义零变化。
- isat_seq_ti := alloc_type(TYP_SLICE, TI_INT, 0);
- isat_shape_name := str_intern("T0bShapeSeq");
- isat_n_pre := iface_shape_count();
- isat_slot := iface_shape_register(isat_shape_name, tt_top_k(AK_SEQUENCE));
+ isat_seq_ti := alloc_type(TYP_SLICE, TI_INT, 0)
+ isat_shape_name := str_intern("T0bShapeSeq")
+ isat_n_pre := iface_shape_count()
+ isat_slot := iface_shape_register(isat_shape_name, tt_top_k(AK_SEQUENCE))
fails = fails + ts_check("isat.axis_a_shape",
ts_isat_b2i(isat_slot == isat_n_pre && iface_shape_count() == isat_n_pre + 1 &&
- iface_shape_lookup(isat_shape_name) >= 0 &&
- iface_satisfies(isat_seq_ti, isat_shape_name) == 1 &&
- iface_satisfies(TI_INT, isat_shape_name) == 0), 1);
+ iface_shape_lookup(isat_shape_name) >= 0 &&
+ iface_satisfies(isat_seq_ti, isat_shape_name) == 1 &&
+ iface_satisfies(TI_INT, isat_shape_name) == 0), 1)
// ⑧ 轴优先级:同名既是形状又是接口 ⇒ **形状优先**(TI_INT 在形状面可判 0,在用户轴恒 -1
// ⇒ 结果 0 即证明走了轴 A;零方法接口在用户轴本会走 1 的路径也一并在 ⑫ 覆盖)
- isat_dup_ii := ts_t5_mk_iface("T0bDup");
+ isat_dup_ii := ts_t5_mk_iface("T0bDup")
fails = fails + ts_check("isat.axis_order_shape_first",
ts_isat_b2i(find_iface(str_intern("T0bDup")) == isat_dup_ii &&
- iface_shape_register(str_intern("T0bDup"), tt_top_k(AK_SEQUENCE)) >= 0 &&
- iface_satisfies(TI_INT, str_intern("T0bDup")) == 0), 1);
+ iface_shape_register(str_intern("T0bDup"), tt_top_k(AK_SEQUENCE)) >= 0 &&
+ iface_satisfies(TI_INT, str_intern("T0bDup")) == 0), 1)
// ⑨ 轴优先级:同名既是接口又是原生类型名 ⇒ **接口优先**(= 现状 gen_constr_satisfied 的
// find_iface 先行;非命名实参 ⇒ -1,**不做**本质轴判定)——P3a 零行为变化面
- ts_t5_mk_iface("int");
+ ts_t5_mk_iface("int")
fails = fails + ts_check("isat.axis_order_iface_over_essence",
- ts_isat_b2i(iface_satisfies(TI_INT, str_intern("int")) == -1), 1);
+ ts_isat_b2i(iface_satisfies(TI_INT, str_intern("int")) == -1), 1)
// ⑩ 与 check_iface **逐例对拍**(谓词同源的最强守门:三形态 = 满足/计数不符/返回码
// 不符;缺方法形态在 ② 与 ⑪ 分别钉住 0 与零驻留表增长)
- isat_eq := -1;
- if ts_isat_b2i(check_iface(str_intern("T0bS"), isat_ii)) == iface_satisfies(isat_s_ti, str_intern("T0bShow")) {
- if ts_isat_b2i(check_iface(str_intern("T0bC"), isat_ii)) == iface_satisfies(isat_c_ti, str_intern("T0bShow")) {
- if ts_isat_b2i(check_iface(str_intern("T0bR"), isat_ii)) == iface_satisfies(isat_r_ti, str_intern("T0bShow")) {
- isat_eq = 1;
- }
- }
- }
- fails = fails + ts_check("isat.predicate_same_as_check_iface", isat_eq, 1);
+ isat_eq := -1
+ if ts_isat_b2i(check_iface(str_intern("T0bS"), isat_ii)) == iface_satisfies(isat_s_ti, str_intern("T0bShow")):
+ if ts_isat_b2i(check_iface(str_intern("T0bC"), isat_ii)) == iface_satisfies(isat_c_ti, str_intern("T0bShow")):
+ if ts_isat_b2i(check_iface(str_intern("T0bR"), isat_ii)) == iface_satisfies(isat_r_ti, str_intern("T0bShow")):
+ isat_eq = 1
+ fails = fails + ts_check("isat.predicate_same_as_check_iface", isat_eq, 1)
// ⑪ 判定路径**零 str_intern**(.ccr STR 段守卫):缺失方法名(= 判定 0 的路径)不得把
// 新串追加进驻留表——`type_has_method` 的 `str_intern("T.m")` 形态在此会增长表。
- isat_zz_ti := alloc_named_type(str_intern("T0bZz"));
- isat_before := g_str_count;
- iface_satisfies(isat_zz_ti, str_intern("T0bShow"));
+ isat_zz_ti := alloc_named_type(str_intern("T0bZz"))
+ isat_before := g_str_count
+ iface_satisfies(isat_zz_ti, str_intern("T0bShow"))
fails = fails + ts_check("isat.no_str_intern_on_missing",
- ts_isat_b2i(g_str_count == isat_before), 1);
+ ts_isat_b2i(g_str_count == isat_before), 1)
// ⑫ 空洞满足:零方法接口 + 命名行 ⇒ 1;非命名行 ⇒ -1(域限定先于空循环)
- isat_empty_ii := ts_t5_mk_iface("T0bEmpty");
+ isat_empty_ii := ts_t5_mk_iface("T0bEmpty")
fails = fails + ts_check("isat.empty_iface_vacuous",
ts_isat_b2i(find_iface(str_intern("T0bEmpty")) == isat_empty_ii &&
- iface_satisfies(isat_t_ti, str_intern("T0bEmpty")) == 1 &&
- iface_satisfies(TI_INT, str_intern("T0bEmpty")) == -1), 1);
+ iface_satisfies(isat_t_ti, str_intern("T0bEmpty")) == 1 &&
+ iface_satisfies(TI_INT, str_intern("T0bEmpty")) == -1), 1)
// ⑬ 泛型应用行:查方法走**基名**(decl_name_of_ti 的 TYP_GENERIC_APPLY 分支)
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- isat_ga_s := g_gen_apply_data_count;
- w64(g_gen_apply_data, isat_ga_s * 8, 1);
- w64(g_gen_apply_data, (isat_ga_s + 1) * 8, TI_INT);
- g_gen_apply_data_count = isat_ga_s + 2;
- isat_ga_ti := alloc_type(TYP_GENERIC_APPLY, isat_s_ti, isat_ga_s);
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ isat_ga_s := g_gen_apply_data_count
+ w64(g_gen_apply_data, isat_ga_s * 8, 1)
+ w64(g_gen_apply_data, (isat_ga_s + 1) * 8, TI_INT)
+ g_gen_apply_data_count = isat_ga_s + 2
+ isat_ga_ti := alloc_type(TYP_GENERIC_APPLY, isat_s_ti, isat_ga_s)
fails = fails + ts_check("isat.generic_apply_base_name",
- iface_satisfies(isat_ga_ti, str_intern("T0bShow")), 1);
+ iface_satisfies(isat_ga_ti, str_intern("T0bShow")), 1)
// ⑭ 三态 + 预算隔离:不可译行(越界 ti)/负键 ⇒ -1(**不得**当 0/1);且**成功判定后**
// 预算窗口必须干净(g_ty_steps 归零 + 上限 = 本层窗口常量;memo 不复用跨查询历史——
// P0 终审 Critical 3 的口径,同 type_equal_engine/gen_constr_satisfied)
- ty_budget_reset(200000);
- isat_bad_ti := g_type_count + 7;
+ ty_budget_reset(200000)
+ isat_bad_ti := g_type_count + 7
// 两条引擎路径:**节点同一快路径**(0 步)+ **非同一比较**(sub_cover 计步 ⇒ 出口复位可观测:
// 缺出口复位时 g_ty_steps > 0 即红——MUT4 实证过「只用快路径 = 该断言空转」)
- isat_ok := iface_satisfies(TI_STR, str_intern("string")); // 轴 B 快路径(勿用 int——⑨ 已声明同名接口)
- isat_no := iface_satisfies(TI_INT, str_intern("string")); // 轴 B 非同一 ⇒ 计步
+ isat_ok := iface_satisfies(TI_STR, str_intern("string")) // 轴 B 快路径(勿用 int——⑨ 已声明同名接口)
+ isat_no := iface_satisfies(TI_INT, str_intern("string")) // 轴 B 非同一 ⇒ 计步
fails = fails + ts_check("isat.three_state_budget_isolated",
ts_isat_b2i(isat_ok == 1 && isat_no == 0 && g_ty_steps == 0 && g_ty_budget_max == IFACE_SAT_BUDGET &&
- iface_satisfies(isat_bad_ti, str_intern("int")) == -1 &&
- iface_satisfies(TI_INT, isat_bad_ti) == -1 &&
- iface_satisfies(-1, 0) == -1 && iface_satisfies(TI_INT, -1) == -1 &&
- iface_satisfies_term(-1, tt_top()) == -1 && iface_satisfies_term(TI_INT, -1) == -1 &&
- g_ty_exhausted == 0), 1);
+ iface_satisfies(isat_bad_ti, str_intern("int")) == -1 &&
+ iface_satisfies(TI_INT, isat_bad_ti) == -1 &&
+ iface_satisfies(-1, 0) == -1 && iface_satisfies(TI_INT, -1) == -1 &&
+ iface_satisfies_term(-1, tt_top()) == -1 && iface_satisfies_term(TI_INT, -1) == -1 &&
+ g_ty_exhausted == 0), 1)
// ⑮ 形状表语义:覆盖(同名重注册不增长)+ 负键守卫 + 复位(count=0 ⇒ 同键未命中)
- isat_n := iface_shape_count();
+ isat_n := iface_shape_count()
fails = fails + ts_check("isat.shape_registry_semantics",
ts_isat_b2i(iface_shape_register(isat_shape_name, tt_top_k(AK_SEQUENCE)) == isat_slot &&
- iface_shape_count() == isat_n &&
- iface_shape_register(-1, tt_top()) == -1 &&
- iface_shape_register(isat_shape_name, -1) == -1 &&
- iface_shape_lookup(-1) == -1 &&
- iface_shape_lookup(str_intern("T0bNoShape")) == -1), 1);
- iface_shape_reset();
+ iface_shape_count() == isat_n &&
+ iface_shape_register(-1, tt_top()) == -1 &&
+ iface_shape_register(isat_shape_name, -1) == -1 &&
+ iface_shape_lookup(-1) == -1 &&
+ iface_shape_lookup(str_intern("T0bNoShape")) == -1), 1)
+ iface_shape_reset()
fails = fails + ts_check("isat.shape_registry_reset",
ts_isat_b2i(iface_shape_count() == 0 && iface_shape_lookup(isat_shape_name) == -1 &&
- iface_satisfies(isat_seq_ti, isat_shape_name) == -1), 1);
- return fails;
-}
+ iface_satisfies(isat_seq_ti, isat_shape_name) == -1), 1)
+ return fails
// ─── R2 P3b Task 2 用例体(独立函数:**不得**内联进 type_selftest_run——同 ts_t5_run 的
// 栈式代码生成上限理由;用例数 = **15**,调用方 `total = total + 15` 须同步)。
@@ -523,166 +531,171 @@ fn ts_isat_run() -> int {
// **两路纪律**(Task 0 M4 教训:只走节点同一快路径的断言 = 空转):每例除「判定值」外加一条
// 「非同一比较」断言(实参项 != 形状项 ⇒ 结果不可能由 ty_sub 的 `a == b` 快路径给出);
// 两条枚举例的枚举规模单独断言(防零行遍历/真空通过)。
-fn ts_x2_b(b: bool) -> int { if b { return 1; } return 0; }
+fn ts_x2_b(b: bool) -> int:
+ if b:
+ return 1
+ return 0
-fn ts_x2_run() -> int {
- fails : ., mut = 0;
+fn ts_x2_run() -> int:
+ fails : ., mut = 0
// ── 夹具(行面)──
- x2_arr := alloc_type(TYP_ARRAY, TI_INT, 3); // 固定长序列(固定性位 = N = 3)
- x2_slice := alloc_type(TYP_SLICE, TI_INT, 0); // 视图(固定性位 = -1)
- x2_ro_view := alloc_type(TYP_REF, x2_slice, 0); // &[int](只读视图)
- x2_rw_view := alloc_type(TYP_REF, x2_slice, 1); // &mut [int](可写视图)
- grow_gen_apply_data(g_gen_apply_data_count + 1); // 元组行:字段列(product 面的行)
- x2_tup_start := g_gen_apply_data_count;
- w64(g_gen_apply_data, x2_tup_start * 8, TI_INT);
- g_gen_apply_data_count = x2_tup_start + 1;
- x2_tup := alloc_type(TYP_TUPLE, 1, x2_tup_start);
- x2_named := alloc_named_type(str_intern("X2ShapeN"));
+ x2_arr := alloc_type(TYP_ARRAY, TI_INT, 3) // 固定长序列(固定性位 = N = 3)
+ x2_slice := alloc_type(TYP_SLICE, TI_INT, 0) // 视图(固定性位 = -1)
+ x2_ro_view := alloc_type(TYP_REF, x2_slice, 0) // &[int](只读视图)
+ x2_rw_view := alloc_type(TYP_REF, x2_slice, 1) // &mut [int](可写视图)
+ grow_gen_apply_data(g_gen_apply_data_count + 1) // 元组行:字段列(product 面的行)
+ x2_tup_start := g_gen_apply_data_count
+ w64(g_gen_apply_data, x2_tup_start * 8, TI_INT)
+ g_gen_apply_data_count = x2_tup_start + 1
+ x2_tup := alloc_type(TYP_TUPLE, 1, x2_tup_start)
+ x2_named := alloc_named_type(str_intern("X2ShapeN"))
// ① 序列接口:数组 + 切片(皆 AK_SEQUENCE)满足;原生/只读视图/命名行不满足;**非同一**断言
fails = fails + ts_check("x2.seq_accepts_body",
ts_x2_b(iface_satisfies_term(x2_arr, sh_shape_seq()) == 1 &&
- iface_satisfies_term(x2_slice, sh_shape_seq()) == 1 &&
- sh_term_of_ti(x2_arr) != sh_shape_seq() && sh_term_of_ti(x2_slice) != sh_shape_seq()), 1);
+ iface_satisfies_term(x2_slice, sh_shape_seq()) == 1 &&
+ sh_term_of_ti(x2_arr) != sh_shape_seq() && sh_term_of_ti(x2_slice) != sh_shape_seq()), 1)
fails = fails + ts_check("x2.seq_rejects_non_body",
ts_x2_b(iface_satisfies_term(TI_INT, sh_shape_seq()) == 0 &&
- iface_satisfies_term(x2_ro_view, sh_shape_seq()) == 0 &&
- iface_satisfies_term(x2_named, sh_shape_seq()) == 0), 1);
+ iface_satisfies_term(x2_ro_view, sh_shape_seq()) == 0 &&
+ iface_satisfies_term(x2_named, sh_shape_seq()) == 0), 1)
// ② 只读序列:本体(数组/切片)+ 只读视图满足(视图面由 AK_REF **协变槽**判定 = 元素非 ⊤
// 也成立,即「只读 = 协变」的兑现);可写视图**不**满足(mut 标记等式语义 = Task 1 裁决)
fails = fails + ts_check("x2.ro_accepts_body_and_ro_view",
ts_x2_b(iface_satisfies_term(x2_arr, sh_shape_seq_ro()) == 1 &&
- iface_satisfies_term(x2_slice, sh_shape_seq_ro()) == 1 &&
- iface_satisfies_term(x2_ro_view, sh_shape_seq_ro()) == 1 &&
- iface_satisfies_term(x2_rw_view, sh_shape_seq_ro()) == 0 &&
- sh_term_of_ti(x2_ro_view) != sh_shape_seq_ro()), 1);
+ iface_satisfies_term(x2_slice, sh_shape_seq_ro()) == 1 &&
+ iface_satisfies_term(x2_ro_view, sh_shape_seq_ro()) == 1 &&
+ iface_satisfies_term(x2_rw_view, sh_shape_seq_ro()) == 0 &&
+ sh_term_of_ti(x2_ro_view) != sh_shape_seq_ro()), 1)
// ③ 可写序列:本体满足(切片可写 = T1 探针 pSliceW `s[0] = 9` rc=0 实证);**拒绝只读视图**
fails = fails + ts_check("x2.rw_accepts_body_rejects_ro_view",
ts_x2_b(iface_satisfies_term(x2_arr, sh_shape_seq_rw()) == 1 &&
- iface_satisfies_term(x2_slice, sh_shape_seq_rw()) == 1 &&
- iface_satisfies_term(x2_ro_view, sh_shape_seq_rw()) == 0 &&
- iface_satisfies_term(TI_INT, sh_shape_seq_rw()) == 0), 1);
+ iface_satisfies_term(x2_slice, sh_shape_seq_rw()) == 1 &&
+ iface_satisfies_term(x2_ro_view, sh_shape_seq_rw()) == 0 &&
+ iface_satisfies_term(TI_INT, sh_shape_seq_rw()) == 0), 1)
// ④ 可写**视图**形状不可表达(登记面,三态纪律):ref(mut=1, ⊤ₖ(SEQ)) ⇒ **-1**(不变槽遇 ⊤ =
// 未覆盖面),**不得**当 0/1(改成 0/1 的突变即红)。uncovered 位须**直调引擎**读
// (`iface_satisfies_term` 出口做预算复位 = 清该位——本层读不到,非「未置位」)。
- ty_budget_reset(200000);
- x2_rw_shape := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(tt_top_k(AK_SEQUENCE), tt_nil())));
- x2_rw_s := iface_satisfies_term(x2_rw_view, x2_rw_shape);
- ty_budget_reset(200000);
- x2_rw_direct := ty_sub(sh_term_of_ti(x2_rw_view), x2_rw_shape);
- x2_rw_unc := ty_uncovered();
+ ty_budget_reset(200000)
+ x2_rw_shape := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(tt_top_k(AK_SEQUENCE), tt_nil())))
+ x2_rw_s := iface_satisfies_term(x2_rw_view, x2_rw_shape)
+ ty_budget_reset(200000)
+ x2_rw_direct := ty_sub(sh_term_of_ti(x2_rw_view), x2_rw_shape)
+ x2_rw_unc := ty_uncovered()
fails = fails + ts_check("x2.rw_view_unexpressible",
- ts_x2_b(x2_rw_s == -1 && x2_rw_direct == -1 && x2_rw_unc == 1), 1);
- ty_budget_reset(200000);
+ ts_x2_b(x2_rw_s == -1 && x2_rw_direct == -1 && x2_rw_unc == 1), 1)
+ ty_budget_reset(200000)
// ⑤ 可索引:字符串正控(checker 既有串下标结果分支)+ 序列;原生负控
fails = fails + ts_check("x2.indexable_str_and_seq",
ts_x2_b(iface_satisfies_term(TI_STR, sh_shape_indexable()) == 1 &&
- iface_satisfies_term(x2_arr, sh_shape_indexable()) == 1 &&
- iface_satisfies_term(x2_slice, sh_shape_indexable()) == 1 &&
- iface_satisfies_term(TI_INT, sh_shape_indexable()) == 0), 1);
+ iface_satisfies_term(x2_arr, sh_shape_indexable()) == 1 &&
+ iface_satisfies_term(x2_slice, sh_shape_indexable()) == 1 &&
+ iface_satisfies_term(TI_INT, sh_shape_indexable()) == 0), 1)
// ⑥ 可迭代(首版)+ product:序列满足迭代;元组行满足 product;原生/命名行皆否
fails = fails + ts_check("x2.iterable_and_product",
ts_x2_b(iface_satisfies_term(x2_arr, sh_shape_iterable()) == 1 &&
- iface_satisfies_term(x2_slice, sh_shape_iterable()) == 1 &&
- iface_satisfies_term(TI_INT, sh_shape_iterable()) == 0 &&
- iface_satisfies_term(x2_tup, sh_shape_product()) == 1 &&
- iface_satisfies_term(TI_INT, sh_shape_product()) == 0 &&
- iface_satisfies_term(x2_named, sh_shape_product()) == 0), 1);
+ iface_satisfies_term(x2_slice, sh_shape_iterable()) == 1 &&
+ iface_satisfies_term(TI_INT, sh_shape_iterable()) == 0 &&
+ iface_satisfies_term(x2_tup, sh_shape_product()) == 1 &&
+ iface_satisfies_term(TI_INT, sh_shape_product()) == 0 &&
+ iface_satisfies_term(x2_named, sh_shape_product()) == 0), 1)
// ⑦ **消费点换位等价(索引门)**:可索引形状满足集 == IP_INDEX 许可集——全类型行枚举。
// checker 索引兜底门换位后行为保持的判据;枚举规模单独断言(反真空:行数/许可行数下界)
- x2_n_rows : ., mut = 0;
- x2_bad : ., mut = 0;
- x2_n_perm : ., mut = 0;
- x2_n_undec : ., mut = 0;
- x2_i : ., mut = 0;
- loop {
- if x2_i >= g_type_count { break; }
- x2_n_rows = x2_n_rows + 1;
- x2_s := iface_satisfies_term(x2_i, sh_shape_indexable());
- x2_o := iface_permits(iface_kind_of(x2_i), IP_INDEX);
- if x2_s == -1 {
- x2_n_undec = x2_n_undec + 1;
- } else {
- if x2_s == 1 { x2_n_perm = x2_n_perm + 1; }
- if (x2_s == 1) != (x2_o == 1) { x2_bad = x2_bad + 1; }
- }
- x2_i = x2_i + 1;
- }
+ x2_n_rows : ., mut = 0
+ x2_bad : ., mut = 0
+ x2_n_perm : ., mut = 0
+ x2_n_undec : ., mut = 0
+ x2_i : ., mut = 0
+ loop:
+ if x2_i >= g_type_count:
+ break
+ x2_n_rows = x2_n_rows + 1
+ x2_s := iface_satisfies_term(x2_i, sh_shape_indexable())
+ x2_o := iface_permits(iface_kind_of(x2_i), IP_INDEX)
+ if x2_s == -1:
+ x2_n_undec = x2_n_undec + 1
+ else:
+ if x2_s == 1:
+ x2_n_perm = x2_n_perm + 1
+ if (x2_s == 1) != (x2_o == 1):
+ x2_bad = x2_bad + 1
+ x2_i = x2_i + 1
fails = fails + ts_check("x2.indexable_matches_ops",
ts_x2_b(x2_n_rows == g_type_count && x2_n_rows >= 15 && x2_bad == 0 &&
- x2_n_perm >= 3 && x2_n_undec == 0 && get_type_kind(TI_STR) == TYP_BASE), 1);
+ x2_n_perm >= 3 && x2_n_undec == 0 && get_type_kind(TI_STR) == TYP_BASE), 1)
// ⑧ **消费点换位等价(range 分支)**:`形状满足 ∧ 固定性位 ≥ 0` == `kind == TYP_ARRAY`——
// 全类型行枚举(固定长行与视图行**两类皆须出现**,否则枚举面真空)
- x2_bad2 : ., mut = 0;
- x2_n_fixed : ., mut = 0;
- x2_n_view : ., mut = 0;
- x2_j : ., mut = 0;
- loop {
- if x2_j >= g_type_count { break; }
- x2_s2 := iface_satisfies_term(x2_j, sh_shape_seq());
- if x2_s2 != -1 {
- x2_fixed : ., mut = 0;
- if x2_s2 == 1 {
- if sh_seq_fixed_len_of_ti(x2_j) >= 0 { x2_fixed = 1; }
- }
- x2_k : ., mut = 0;
- if get_type_kind(x2_j) == TYP_ARRAY { x2_k = 1; }
- if x2_fixed != x2_k { x2_bad2 = x2_bad2 + 1; }
- if x2_s2 == 1 {
- if x2_fixed == 1 { x2_n_fixed = x2_n_fixed + 1; } else { x2_n_view = x2_n_view + 1; }
- }
- }
- x2_j = x2_j + 1;
- }
+ x2_bad2 : ., mut = 0
+ x2_n_fixed : ., mut = 0
+ x2_n_view : ., mut = 0
+ x2_j : ., mut = 0
+ loop:
+ if x2_j >= g_type_count:
+ break
+ x2_s2 := iface_satisfies_term(x2_j, sh_shape_seq())
+ if x2_s2 != -1:
+ x2_fixed : ., mut = 0
+ if x2_s2 == 1:
+ if sh_seq_fixed_len_of_ti(x2_j) >= 0:
+ x2_fixed = 1
+ x2_k : ., mut = 0
+ if get_type_kind(x2_j) == TYP_ARRAY:
+ x2_k = 1
+ if x2_fixed != x2_k:
+ x2_bad2 = x2_bad2 + 1
+ if x2_s2 == 1:
+ if x2_fixed == 1:
+ x2_n_fixed = x2_n_fixed + 1
+ else:
+ x2_n_view = x2_n_view + 1
+ x2_j = x2_j + 1
fails = fails + ts_check("x2.range_fixedness_matches_kind",
- ts_x2_b(x2_bad2 == 0 && x2_n_fixed >= 1 && x2_n_view >= 1), 1);
+ ts_x2_b(x2_bad2 == 0 && x2_n_fixed >= 1 && x2_n_view >= 1), 1)
// ⑨ 形状项的**名字面**(轴 A 生产入口):六条规范项经注册表可按名判定(= Step 1「条目」的
// 注册面兑现);复位后同键 ⇒ -1(无泄漏)。
// R2 P4 Task 3 重钉(裁决 1 + D17):**生产注册面**同例断言——`iface_shape_builtin_init()`
// 显式重跑(幂等)后,六个 D17 名可按名查询且与 sh_shape_*() 构造点**同项**;
// 随后照旧注册六个自测名(同名覆盖语义不受影响,计数 = 6 + 6)。
- iface_shape_builtin_init();
- x2_p1 := iface_shape_lookup(str_intern("sequence"));
- x2_p2 := iface_shape_lookup(str_intern("sequence_ro"));
- x2_p3 := iface_shape_lookup(str_intern("sequence_rw"));
- x2_p4 := iface_shape_lookup(str_intern("indexable"));
- x2_p5 := iface_shape_lookup(str_intern("iterable"));
- x2_p6 := iface_shape_lookup(str_intern("product"));
+ iface_shape_builtin_init()
+ x2_p1 := iface_shape_lookup(str_intern("sequence"))
+ x2_p2 := iface_shape_lookup(str_intern("sequence_ro"))
+ x2_p3 := iface_shape_lookup(str_intern("sequence_rw"))
+ x2_p4 := iface_shape_lookup(str_intern("indexable"))
+ x2_p5 := iface_shape_lookup(str_intern("iterable"))
+ x2_p6 := iface_shape_lookup(str_intern("product"))
fails = fails + ts_check("x2.shape_builtin_names", ts_x2_b(
- iface_shape_count() == 6 && x2_p1 == sh_shape_seq() && x2_p2 == sh_shape_seq_ro() &&
- x2_p3 == sh_shape_seq_rw() && x2_p4 == sh_shape_indexable() &&
- x2_p5 == sh_shape_iterable() && x2_p6 == sh_shape_product() &&
- iface_satisfies(x2_arr, str_intern("sequence")) == 1 &&
- iface_satisfies(TI_INT, str_intern("sequence")) == 0), 1);
- x2_n0 := iface_shape_count();
- x2_r1 := iface_shape_register(str_intern("X2NameSeq"), sh_shape_seq());
- x2_r2 := iface_shape_register(str_intern("X2NameIdx"), sh_shape_indexable());
- x2_r3 := iface_shape_register(str_intern("X2NameRo"), sh_shape_seq_ro());
- x2_r4 := iface_shape_register(str_intern("X2NameRw"), sh_shape_seq_rw());
- x2_r5 := iface_shape_register(str_intern("X2NameItr"), sh_shape_iterable());
- x2_r6 := iface_shape_register(str_intern("X2NameProd"), sh_shape_product());
+ iface_shape_count() == 6 && x2_p1 == sh_shape_seq() && x2_p2 == sh_shape_seq_ro() &&
+ x2_p3 == sh_shape_seq_rw() && x2_p4 == sh_shape_indexable() &&
+ x2_p5 == sh_shape_iterable() && x2_p6 == sh_shape_product() &&
+ iface_satisfies(x2_arr, str_intern("sequence")) == 1 &&
+ iface_satisfies(TI_INT, str_intern("sequence")) == 0), 1)
+ x2_n0 := iface_shape_count()
+ x2_r1 := iface_shape_register(str_intern("X2NameSeq"), sh_shape_seq())
+ x2_r2 := iface_shape_register(str_intern("X2NameIdx"), sh_shape_indexable())
+ x2_r3 := iface_shape_register(str_intern("X2NameRo"), sh_shape_seq_ro())
+ x2_r4 := iface_shape_register(str_intern("X2NameRw"), sh_shape_seq_rw())
+ x2_r5 := iface_shape_register(str_intern("X2NameItr"), sh_shape_iterable())
+ x2_r6 := iface_shape_register(str_intern("X2NameProd"), sh_shape_product())
fails = fails + ts_check("x2.axis_a_registered",
ts_x2_b(x2_r1 >= 0 && x2_r2 >= 0 && x2_r3 >= 0 && x2_r4 >= 0 && x2_r5 >= 0 && x2_r6 >= 0 &&
- iface_shape_count() == x2_n0 + 6 &&
- iface_satisfies(x2_arr, str_intern("X2NameSeq")) == 1 &&
- iface_satisfies(x2_arr, str_intern("X2NameIdx")) == 1 &&
- iface_satisfies(x2_ro_view, str_intern("X2NameRo")) == 1 &&
- iface_satisfies(x2_ro_view, str_intern("X2NameRw")) == 0 &&
- iface_satisfies(x2_tup, str_intern("X2NameProd")) == 1 &&
- iface_satisfies(TI_INT, str_intern("X2NameSeq")) == 0), 1);
- iface_shape_reset();
+ iface_shape_count() == x2_n0 + 6 &&
+ iface_satisfies(x2_arr, str_intern("X2NameSeq")) == 1 &&
+ iface_satisfies(x2_arr, str_intern("X2NameIdx")) == 1 &&
+ iface_satisfies(x2_ro_view, str_intern("X2NameRo")) == 1 &&
+ iface_satisfies(x2_ro_view, str_intern("X2NameRw")) == 0 &&
+ iface_satisfies(x2_tup, str_intern("X2NameProd")) == 1 &&
+ iface_satisfies(TI_INT, str_intern("X2NameSeq")) == 0), 1)
+ iface_shape_reset()
// R2 P4 Task 3 重钉:复位守门口径不变(count = 0 + 旧键 -1);**新增**生产注册面的
// 「复位后可重建」断言(生产重置点 = reset_frontend_state 清 count,随 init_types 尾部
// 的 iface_shape_builtin_init 重建 ⇒ 长驻进程每请求一致)。
- x2_restored : ., mut = 0;
- if iface_shape_count() == 0 && iface_satisfies(x2_arr, str_intern("X2NameSeq")) == -1 {
- iface_shape_builtin_init();
- if iface_shape_count() == 6 && iface_shape_lookup(str_intern("sequence")) == sh_shape_seq() {
- x2_restored = 1;
- }
- }
+ x2_restored : ., mut = 0
+ if iface_shape_count() == 0 && iface_satisfies(x2_arr, str_intern("X2NameSeq")) == -1:
+ iface_shape_builtin_init()
+ if iface_shape_count() == 6 && iface_shape_lookup(str_intern("sequence")) == sh_shape_seq():
+ x2_restored = 1
fails = fails + ts_check("x2.shape_no_leak_after_reset",
- ts_x2_b(x2_restored == 1), 1);
+ ts_x2_b(x2_restored == 1), 1)
// ⑩ 零 str_intern(.ccr STR 段守卫)——R2 P4 Task 3 重定(裁决 1):
// (a) **判定/查询路径零新增驻留**:形状项构造(六构造点)+ 按名查询 + 注册幂等重跑
// (iface_shape_builtin_init 重复调用)皆不得增长 g_strs;
@@ -691,58 +704,57 @@ fn ts_x2_run() -> int {
// 六名可查(= 名字已驻留且 ni 解析正确)」两式联立钉住。
// 注:T1..T2 期的绝对口径「构造路径恒零驻留」在初始化面已不成立(原文保留于
// iface_registry.cr 头注),本重定即该翻转的落地面。
- x2_strs := g_str_count;
- x2_t1 := sh_shape_seq();
- x2_t2 := sh_shape_seq_ro();
- x2_t3 := sh_shape_seq_rw();
- x2_t4 := sh_shape_indexable();
- x2_t5 := sh_shape_iterable();
- x2_t6 := sh_shape_product();
- x2_p1b := iface_shape_lookup(str_intern("sequence"));
- x2_p2b := iface_shape_lookup(str_intern("sequence_ro"));
- x2_p3b := iface_shape_lookup(str_intern("sequence_rw"));
- x2_p4b := iface_shape_lookup(str_intern("indexable"));
- x2_p5b := iface_shape_lookup(str_intern("iterable"));
- x2_p6b := iface_shape_lookup(str_intern("product"));
- iface_shape_builtin_init(); // 幂等重跑(不得再增长驻留表)
+ x2_strs := g_str_count
+ x2_t1 := sh_shape_seq()
+ x2_t2 := sh_shape_seq_ro()
+ x2_t3 := sh_shape_seq_rw()
+ x2_t4 := sh_shape_indexable()
+ x2_t5 := sh_shape_iterable()
+ x2_t6 := sh_shape_product()
+ x2_p1b := iface_shape_lookup(str_intern("sequence"))
+ x2_p2b := iface_shape_lookup(str_intern("sequence_ro"))
+ x2_p3b := iface_shape_lookup(str_intern("sequence_rw"))
+ x2_p4b := iface_shape_lookup(str_intern("indexable"))
+ x2_p5b := iface_shape_lookup(str_intern("iterable"))
+ x2_p6b := iface_shape_lookup(str_intern("product"))
+ iface_shape_builtin_init() // 幂等重跑(不得再增长驻留表)
fails = fails + ts_check("x2.no_str_intern",
ts_x2_b(g_str_count == x2_strs && x2_t1 >= 0 && x2_t2 >= 0 && x2_t3 >= 0 &&
- x2_t4 >= 0 && x2_t5 >= 0 && x2_t6 >= 0 &&
- x2_p1b == x2_t1 && x2_p2b == x2_t2 && x2_p3b == x2_t3 &&
- x2_p4b == x2_t4 && x2_p5b == x2_t5 && x2_p6b == x2_t6), 1);
+ x2_t4 >= 0 && x2_t5 >= 0 && x2_t6 >= 0 &&
+ x2_p1b == x2_t1 && x2_p2b == x2_t2 && x2_p3b == x2_t3 &&
+ x2_p4b == x2_t4 && x2_p5b == x2_t5 && x2_p6b == x2_t6), 1)
// ⑪ 三态纪律(形状面):越界行/负键/不可译行 ⇒ **-1**(不得当 0/1);成功判定后预算窗口干净
- ty_budget_reset(200000);
- x2_ok := iface_satisfies_term(x2_arr, sh_shape_seq()); // 非同一 ⇒ 计步(非快路径)
+ ty_budget_reset(200000)
+ x2_ok := iface_satisfies_term(x2_arr, sh_shape_seq()) // 非同一 ⇒ 计步(非快路径)
fails = fails + ts_check("x2.uncovered_not_folded",
ts_x2_b(x2_ok == 1 && g_ty_steps == 0 && g_ty_budget_max == IFACE_SAT_BUDGET &&
- iface_satisfies_term(-1, sh_shape_seq()) == -1 &&
- iface_satisfies_term(g_type_count + 7, sh_shape_seq()) == -1 &&
- iface_satisfies_term(TI_INT, -1) == -1 &&
- iface_satisfies(x2_arr, -1) == -1 && iface_satisfies(-1, 0) == -1 &&
- g_ty_exhausted == 0), 1);
+ iface_satisfies_term(-1, sh_shape_seq()) == -1 &&
+ iface_satisfies_term(g_type_count + 7, sh_shape_seq()) == -1 &&
+ iface_satisfies_term(TI_INT, -1) == -1 &&
+ iface_satisfies(x2_arr, -1) == -1 && iface_satisfies(-1, 0) == -1 &&
+ g_ty_exhausted == 0), 1)
// ⑫ 用户接口形状项(R2 P3b Task 6 Step 1 起**可建**):零方法接口 ⇒ **空 product**(≥0,
// 空洞满足的载体);未声明的接口名 ⇒ -1(不得当 0/1)。判断面:命名行 + 零方法 = 满足 1
// (空洞);原生行 = 域限定 -1。
- x2_ii := ts_t5_mk_iface("X2ShapeIface");
+ x2_ii := ts_t5_mk_iface("X2ShapeIface")
fails = fails + ts_check("x2.iface_shape_term_built",
ts_x2_b(find_iface(str_intern("X2ShapeIface")) == x2_ii &&
- sh_iface_shape_term(str_intern("X2ShapeIface")) >= 0 &&
- sh_iface_shape_term(str_intern("X2NoSuchIface")) == -1 &&
- iface_satisfies(x2_named, str_intern("X2ShapeIface")) == 1 &&
- iface_satisfies(TI_INT, str_intern("X2ShapeIface")) == -1), 1);
+ sh_iface_shape_term(str_intern("X2ShapeIface")) >= 0 &&
+ sh_iface_shape_term(str_intern("X2NoSuchIface")) == -1 &&
+ iface_satisfies(x2_named, str_intern("X2ShapeIface")) == 1 &&
+ iface_satisfies(TI_INT, str_intern("X2ShapeIface")) == -1), 1)
// ⑬ 形状项与**行**的桥接关系(形状判定 = 行桥接 + 引擎包含,两层都不可少):切片的项
// 除固定性位外与数组项同形 ⇒ 两者同判(固定性**不**入形状判定——语义判定不看 N)
- x2_same : ., mut = 0;
- x2_ta := sh_term_of_ti(x2_arr);
- x2_ts := sh_term_of_ti(x2_slice);
- if x2_ta >= 0 && x2_ts >= 0 && x2_ta != x2_ts {
- if ty_sub(x2_ta, x2_ts) == 1 && ty_sub(x2_ts, x2_ta) == 1 { x2_same = 1; }
- }
+ x2_same : ., mut = 0
+ x2_ta := sh_term_of_ti(x2_arr)
+ x2_ts := sh_term_of_ti(x2_slice)
+ if x2_ta >= 0 && x2_ts >= 0 && x2_ta != x2_ts:
+ if ty_sub(x2_ta, x2_ts) == 1 && ty_sub(x2_ts, x2_ta) == 1:
+ x2_same = 1
fails = fails + ts_check("x2.fixedness_not_in_shape_judgment",
ts_x2_b(x2_same == 1 && sh_seq_fixed_len_of_ti(x2_arr) == 3 &&
- sh_seq_fixed_len_of_ti(x2_slice) == -1 && sh_seq_fixed_len_of_ti(TI_INT) == -1), 1);
- return fails;
-}
+ sh_seq_fixed_len_of_ti(x2_slice) == -1 && sh_seq_fixed_len_of_ti(TI_INT) == -1), 1)
+ return fails
// ═══════════════ R2 P3b Task 6:impl 契约用例(ifc.*)═══════════════
// 面(详见 ty_shadow.cr 的 sh_sig_term_of_ti / sh_iface_shape_term 注 + type_engine.cr 的
@@ -756,242 +768,237 @@ fn ts_x2_run() -> int {
// 命名类型夹具(结构声明 + SYM_TYPE 登记 + 命名行——供 res_type_node 的 EXPR_IDENT /
// EXPR_GENERIC_APPLY 两分支解析)。
-fn ts_ifc_mk_named(name: string) -> int {
- ni := str_intern(name);
- add_struct(name);
- ti := alloc_named_type(ni);
- def_sym(ni, SYM_TYPE, ti, -1);
- return ti;
-}
+fn ts_ifc_mk_named(name: string) -> int:
+ ni := str_intern(name)
+ add_struct(name)
+ ti := alloc_named_type(ni)
+ def_sym(ni, SYM_TYPE, ti, -1)
+ return ti
// 签名类型**节点**夹具:命名型(EXPR_IDENT,int_val = 名字 ni)
-fn ts_ifc_named_node(name: string) -> int {
- return alloc_node(EXPR_IDENT, 0, 0, 0, str_intern(name), 0, 0, 0, 0);
-}
+fn ts_ifc_named_node(name: string) -> int:
+ return alloc_node(EXPR_IDENT, 0, 0, 0, str_intern(name), 0, 0, 0, 0)
// 签名类型节点:序列(EXPR_ARRAY;n = 长度,0 = 视图)——实参根单槽契约照 parser 产物
-fn ts_ifc_seq_node(elem_node: int, n: int) -> int {
- return alloc_node(EXPR_ARRAY, elem_node, 0, 0, n, 0, 0, 0, 0);
-}
+fn ts_ifc_seq_node(elem_node: int, n: int) -> int:
+ return alloc_node(EXPR_ARRAY, elem_node, 0, 0, n, 0, 0, 0, 0)
// 签名类型节点:泛型应用(EXPR_GENERIC_APPLY;a = 基名 ni、b = 首实参节点(**连续**)、c = 个数)
-fn ts_ifc_apply_node(base_name: string, arg_node: int) -> int {
- return alloc_node(EXPR_GENERIC_APPLY, str_intern(base_name), arg_node, 1, 0, 0, 0, 0, 0);
-}
+fn ts_ifc_apply_node(base_name: string, arg_node: int) -> int:
+ return alloc_node(EXPR_GENERIC_APPLY, str_intern(base_name), arg_node, 1, 0, 0, 0, 0, 0)
// 接口方法条目(节点面可控:pnodes = 参数节点缓冲(可 -1 = 全无节点);rnode = 返回型节点;
// smode = 接收者模式(0 = 无接收者,1/2/3 = self/&self/&mut self))
-fn ts_ifc_add_method_n(ii: int, mname: string, pc: int, smode: int, n0: int, n1: int, n2: int, n3: int, rnode: int) -> int {
- n := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT);
- mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + n * ESZ_IFMETHOD;
- w64(g_ifaces, mbase + OFF_IFM_NAME, str_intern(mname));
- w64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT, pc);
- w64(g_ifaces, mbase + OFF_IFM_RET_TI, 0);
- w64(g_ifaces, mbase + OFF_IFM_RET_NODE, rnode);
- w64(g_ifaces, mbase + OFF_IFM_SELF_MODE, smode);
- pj : ., mut = 0;
- loop {
- if pj >= pc || pj >= MAX_IFACE_METHOD_PARAMS { break; }
- pn : ., mut = -1;
- if pj == 0 { pn = n0; }
- if pj == 1 { pn = n1; }
- if pj == 2 { pn = n2; }
- if pj == 3 { pn = n3; }
- w64(g_ifaces, mbase + OFF_IFM_PARAM_TYPES + pj * 8, TY_INT);
- w64(g_ifaces, mbase + OFF_IFM_PARAM_NODES + pj * 8, pn);
- pj = pj + 1;
- }
- w64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT, n + 1);
- return mbase;
-}
+fn ts_ifc_add_method_n(ii: int, mname: string, pc: int, smode: int, n0: int, n1: int, n2: int, n3: int, rnode: int) -> int:
+ n := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT)
+ mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + n * ESZ_IFMETHOD
+ w64(g_ifaces, mbase + OFF_IFM_NAME, str_intern(mname))
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT, pc)
+ w64(g_ifaces, mbase + OFF_IFM_RET_TI, 0)
+ w64(g_ifaces, mbase + OFF_IFM_RET_NODE, rnode)
+ w64(g_ifaces, mbase + OFF_IFM_SELF_MODE, smode)
+ pj : ., mut = 0
+ loop:
+ if pj >= pc || pj >= MAX_IFACE_METHOD_PARAMS:
+ break
+ pn : ., mut = -1
+ if pj == 0:
+ pn = n0
+ if pj == 1:
+ pn = n1
+ if pj == 2:
+ pn = n2
+ if pj == 3:
+ pn = n3
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_TYPES + pj * 8, TY_INT)
+ w64(g_ifaces, mbase + OFF_IFM_PARAM_NODES + pj * 8, pn)
+ pj = pj + 1
+ w64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT, n + 1)
+ return mbase
// impl 侧函数行(节点面可控;mode0 = 首参接收者模式(≠0 时该参无节点——接收者槽约定))。
// 返回 = 函数行号。
-fn ts_ifc_add_impl(tname_ni: int, mname: string, pc: int, mode0: int, n0: int, n1: int, rnode: int) -> int {
- mn := istr_get(tname_ni) + "." + mname;
- mangled_ni := str_intern(mn);
- pf : ., mut = -1;
- pj : ., mut = 0;
- loop {
- if pj >= pc { break; }
- pn2 : ., mut = -1;
- m : ., mut = 0;
- if pj == 0 { m = mode0; }
- if m == 0 {
- if pj == 0 { pn2 = n0; }
- if pj == 1 { pn2 = n1; }
- }
- if pf < 0 { pf = g_ast_count; }
- alloc_node(EXPR_PARAM, str_intern("p"), 0, 0, m, TY_INT, pn2, 0, 0);
- pj = pj + 1;
- }
- fn_node := alloc_node(EXPR_FN, mangled_ni, pf, pc, 0, rnode, -1, 0, 0);
- fi := add_func(mn, pc, 0, fn_node);
- grow_methods(g_method_count + 1);
- w64(g_methods, g_method_count * 24, tname_ni);
- w64(g_methods, g_method_count * 24 + 8, str_intern(mname));
- w64(g_methods, g_method_count * 24 + 16, mangled_ni);
- g_method_count = g_method_count + 1;
- return fi;
-}
-
-fn ts_ifc_run() -> int {
- fails : ., mut = 0;
+fn ts_ifc_add_impl(tname_ni: int, mname: string, pc: int, mode0: int, n0: int, n1: int, rnode: int) -> int:
+ mn := istr_get(tname_ni) + "." + mname
+ mangled_ni := str_intern(mn)
+ pf : ., mut = -1
+ pj : ., mut = 0
+ loop:
+ if pj >= pc:
+ break
+ pn2 : ., mut = -1
+ m : ., mut = 0
+ if pj == 0:
+ m = mode0
+ if m == 0:
+ if pj == 0:
+ pn2 = n0
+ if pj == 1:
+ pn2 = n1
+ if pf < 0:
+ pf = g_ast_count
+ alloc_node(EXPR_PARAM, str_intern("p"), 0, 0, m, TY_INT, pn2, 0, 0)
+ pj = pj + 1
+ fn_node := alloc_node(EXPR_FN, mangled_ni, pf, pc, 0, rnode, -1, 0, 0)
+ fi := add_func(mn, pc, 0, fn_node)
+ grow_methods(g_method_count + 1)
+ w64(g_methods, g_method_count * 24, tname_ni)
+ w64(g_methods, g_method_count * 24 + 8, str_intern(mname))
+ w64(g_methods, g_method_count * 24 + 16, mangled_ni)
+ g_method_count = g_method_count + 1
+ return fi
+
+fn ts_ifc_run() -> int:
+ fails : ., mut = 0
// ── 夹具:4 个命名类型(A/B 同构异名——名义 vs 结构面)+ 3 个 impl 宿主 ──
- ifc_a_ti := ts_ifc_mk_named("IfcA");
- ts_ifc_mk_named("IfcB");
- ts_ifc_mk_named("IfcBox");
- ifc_a_n := ts_ifc_named_node("IfcA");
- ifc_b_n := ts_ifc_named_node("IfcB");
- ifc_int_n := ts_ifc_base_node(TY_INT);
+ ifc_a_ti := ts_ifc_mk_named("IfcA")
+ ts_ifc_mk_named("IfcB")
+ ts_ifc_mk_named("IfcBox")
+ ifc_a_n := ts_ifc_named_node("IfcA")
+ ifc_b_n := ts_ifc_named_node("IfcB")
+ ifc_int_n := ts_ifc_base_node(TY_INT)
// 泛型应用节点:`IfcBox[IfcA]` / `IfcBox[IfcB]`(实参根单槽连续)
- ifc_ap_a := ts_ifc_apply_node("IfcBox", ifc_a_n);
- ifc_ap_b := ts_ifc_apply_node("IfcBox", ifc_b_n);
+ ifc_ap_a := ts_ifc_apply_node("IfcBox", ifc_a_n)
+ ifc_ap_b := ts_ifc_apply_node("IfcBox", ifc_b_n)
// 序列节点:`[int; 3]` / `[int; 4]`
- ifc_seq3 := ts_ifc_seq_node(ifc_int_n, 3);
- ifc_seq4 := ts_ifc_seq_node(ifc_int_n, 4);
+ ifc_seq3 := ts_ifc_seq_node(ifc_int_n, 3)
+ ifc_seq4 := ts_ifc_seq_node(ifc_int_n, 4)
// 接口:IfcI0 { m(x: IfcA) -> IfcB }(无接收者;参数/返回皆命名型)
- ifc_ii0 := ts_t5_mk_iface("IfcI0");
- ts_ifc_add_method_n(ifc_ii0, "m", 1, 0, ifc_a_n, -1, -1, -1, ifc_b_n);
+ ifc_ii0 := ts_t5_mk_iface("IfcI0")
+ ts_ifc_add_method_n(ifc_ii0, "m", 1, 0, ifc_a_n, -1, -1, -1, ifc_b_n)
// 命中:同签名
- ifc_h_ti := ts_ifc_mk_named("IfcH");
- ts_ifc_add_impl(str_intern("IfcH"), "m", 1, 0, ifc_a_n, -1, ifc_b_n);
+ ifc_h_ti := ts_ifc_mk_named("IfcH")
+ ts_ifc_add_impl(str_intern("IfcH"), "m", 1, 0, ifc_a_n, -1, ifc_b_n)
// 参数类型不符(IfcB ← IfcA)
- ifc_p_ti := ts_ifc_mk_named("IfcP");
- ts_ifc_add_impl(str_intern("IfcP"), "m", 1, 0, ifc_b_n, -1, ifc_b_n);
+ ifc_p_ti := ts_ifc_mk_named("IfcP")
+ ts_ifc_add_impl(str_intern("IfcP"), "m", 1, 0, ifc_b_n, -1, ifc_b_n)
// 返回类型不符(int ← IfcB)
- ifc_r_ti := ts_ifc_mk_named("IfcR");
- ts_ifc_add_impl(str_intern("IfcR"), "m", 1, 0, ifc_a_n, -1, ifc_int_n);
+ ifc_r_ti := ts_ifc_mk_named("IfcR")
+ ts_ifc_add_impl(str_intern("IfcR"), "m", 1, 0, ifc_a_n, -1, ifc_int_n)
// ① 签名类型项化(参数面):命名参数型按**类型**判定——同型 1 / 异型 0(旧态两侧皆码 0 ⇒ 恒等)
fails = fails + ts_check("ifc.sig_named_param_bound",
ts_isat_b2i(iface_satisfies(ifc_h_ti, str_intern("IfcI0")) == 1 &&
- iface_satisfies(ifc_p_ti, str_intern("IfcI0")) == 0), 1);
+ iface_satisfies(ifc_p_ti, str_intern("IfcI0")) == 0), 1)
// ② 签名类型项化(返回面):命名返回型 vs 原生返回型 ⇒ 0;同命名型 ⇒ 1(编码面闭合的直接判据)
fails = fails + ts_check("ifc.sig_named_ret_bound",
ts_isat_b2i(iface_satisfies(ifc_r_ti, str_intern("IfcI0")) == 0 &&
- iface_satisfies(ifc_h_ti, str_intern("IfcI0")) == 1), 1);
+ iface_satisfies(ifc_h_ti, str_intern("IfcI0")) == 1), 1)
// ③ 泛型应用实参面:`IfcBox[IfcA]` vs `IfcBox[IfcB]` ⇒ 0;同实参 ⇒ 1
// (旧态:应用行裸码塌缩为 0 ⇒ 静默判等;规范形展开基名 + 实参链 ⇒ 异实参异节点)
- ifc_ii1 := ts_t5_mk_iface("IfcI1");
- ts_ifc_add_method_n(ifc_ii1, "m", 1, 0, ifc_ap_a, -1, -1, -1, ifc_int_n);
- ifc_g_ti := ts_ifc_mk_named("IfcG");
- ts_ifc_add_impl(str_intern("IfcG"), "m", 1, 0, ifc_ap_a, -1, ifc_int_n);
- ifc_g2_ti := ts_ifc_mk_named("IfcG2");
- ts_ifc_add_impl(str_intern("IfcG2"), "m", 1, 0, ifc_ap_b, -1, ifc_int_n);
+ ifc_ii1 := ts_t5_mk_iface("IfcI1")
+ ts_ifc_add_method_n(ifc_ii1, "m", 1, 0, ifc_ap_a, -1, -1, -1, ifc_int_n)
+ ifc_g_ti := ts_ifc_mk_named("IfcG")
+ ts_ifc_add_impl(str_intern("IfcG"), "m", 1, 0, ifc_ap_a, -1, ifc_int_n)
+ ifc_g2_ti := ts_ifc_mk_named("IfcG2")
+ ts_ifc_add_impl(str_intern("IfcG2"), "m", 1, 0, ifc_ap_b, -1, ifc_int_n)
fails = fails + ts_check("ifc.sig_apply_arg_bound",
ts_isat_b2i(iface_satisfies(ifc_g_ti, str_intern("IfcI1")) == 1 &&
- iface_satisfies(ifc_g2_ti, str_intern("IfcI1")) == 0), 1);
+ iface_satisfies(ifc_g2_ti, str_intern("IfcI1")) == 0), 1)
// ④ 接收者模式是判定维度:iface `&self`(2)vs impl `self`(1)/`&mut self`(3)⇒ 0;同模式 ⇒ 1
- ifc_ii2 := ts_t5_mk_iface("IfcI2");
- ts_ifc_add_method_n(ifc_ii2, "m", 1, 2, -1, -1, -1, -1, ifc_int_n);
- ifc_m1_ti := ts_ifc_mk_named("IfcM1");
- ts_ifc_add_impl(str_intern("IfcM1"), "m", 1, 1, -1, -1, ifc_int_n);
- ifc_m2_ti := ts_ifc_mk_named("IfcM2");
- ts_ifc_add_impl(str_intern("IfcM2"), "m", 1, 2, -1, -1, ifc_int_n);
- ifc_m3_ti := ts_ifc_mk_named("IfcM3");
- ts_ifc_add_impl(str_intern("IfcM3"), "m", 1, 3, -1, -1, ifc_int_n);
+ ifc_ii2 := ts_t5_mk_iface("IfcI2")
+ ts_ifc_add_method_n(ifc_ii2, "m", 1, 2, -1, -1, -1, -1, ifc_int_n)
+ ifc_m1_ti := ts_ifc_mk_named("IfcM1")
+ ts_ifc_add_impl(str_intern("IfcM1"), "m", 1, 1, -1, -1, ifc_int_n)
+ ifc_m2_ti := ts_ifc_mk_named("IfcM2")
+ ts_ifc_add_impl(str_intern("IfcM2"), "m", 1, 2, -1, -1, ifc_int_n)
+ ifc_m3_ti := ts_ifc_mk_named("IfcM3")
+ ts_ifc_add_impl(str_intern("IfcM3"), "m", 1, 3, -1, -1, ifc_int_n)
fails = fails + ts_check("ifc.sig_receiver_mode",
ts_isat_b2i(iface_satisfies(ifc_m2_ti, str_intern("IfcI2")) == 1 &&
- iface_satisfies(ifc_m1_ti, str_intern("IfcI2")) == 0 &&
- iface_satisfies(ifc_m3_ti, str_intern("IfcI2")) == 0), 1);
+ iface_satisfies(ifc_m1_ti, str_intern("IfcI2")) == 0 &&
+ iface_satisfies(ifc_m3_ti, str_intern("IfcI2")) == 0), 1)
// ⑤ 元数(链长):iface 1 参 vs impl 2 参 ⇒ 0(链形不同);impl 0 参 ⇒ 0
- ifc_w_ti := ts_ifc_mk_named("IfcW");
- ts_ifc_add_impl(str_intern("IfcW"), "m", 2, 0, ifc_a_n, ifc_int_n, ifc_b_n);
- ifc_w0_ti := ts_ifc_mk_named("IfcW0");
- ts_ifc_add_impl(str_intern("IfcW0"), "m", 0, 0, -1, -1, ifc_b_n);
+ ifc_w_ti := ts_ifc_mk_named("IfcW")
+ ts_ifc_add_impl(str_intern("IfcW"), "m", 2, 0, ifc_a_n, ifc_int_n, ifc_b_n)
+ ifc_w0_ti := ts_ifc_mk_named("IfcW0")
+ ts_ifc_add_impl(str_intern("IfcW0"), "m", 0, 0, -1, -1, ifc_b_n)
fails = fails + ts_check("ifc.sig_arity_chain",
ts_isat_b2i(iface_satisfies(ifc_w_ti, str_intern("IfcI0")) == 0 &&
- iface_satisfies(ifc_w0_ti, str_intern("IfcI0")) == 0), 1);
+ iface_satisfies(ifc_w0_ti, str_intern("IfcI0")) == 0), 1)
// ⑥ N **不入**签名身份(P3a 不变量):`[int;3]` vs `[int;4]` ⇒ 1(长度面由常量档承担)
- ifc_ii3 := ts_t5_mk_iface("IfcI3");
- ts_ifc_add_method_n(ifc_ii3, "m", 1, 0, ifc_seq3, -1, -1, -1, ifc_int_n);
- ifc_n_ti := ts_ifc_mk_named("IfcN");
- ts_ifc_add_impl(str_intern("IfcN"), "m", 1, 0, ifc_seq4, -1, ifc_int_n);
+ ifc_ii3 := ts_t5_mk_iface("IfcI3")
+ ts_ifc_add_method_n(ifc_ii3, "m", 1, 0, ifc_seq3, -1, -1, -1, ifc_int_n)
+ ifc_n_ti := ts_ifc_mk_named("IfcN")
+ ts_ifc_add_impl(str_intern("IfcN"), "m", 1, 0, ifc_seq4, -1, ifc_int_n)
fails = fails + ts_check("ifc.sig_len_not_in_identity",
- ts_isat_b2i(iface_satisfies(ifc_n_ti, str_intern("IfcI3")) == 1), 1);
+ ts_isat_b2i(iface_satisfies(ifc_n_ti, str_intern("IfcI3")) == 1), 1)
// ⑦ 命名行**名义**(不展开):IfcA 与 IfcB 结构同构(皆零字段)但不可互换 ⇒ 0
// (判定不落引擎的 AK_NAMED 展开面——签名身份按**行**(同名字同行))
fails = fails + ts_check("ifc.sig_named_nominal_not_structural",
ts_isat_b2i(iface_satisfies(ifc_p_ti, str_intern("IfcI1")) == 0 &&
- iface_satisfies(ifc_g_ti, str_intern("IfcI1")) == 1), 1);
+ iface_satisfies(ifc_g_ti, str_intern("IfcI1")) == 1), 1)
// ⑧ 接口形状项 = 方法集(product of fn):成员数 = 方法数、成员 b 槽 = 方法名、
// 链长 = 1 + 参数数;越界成员 ⇒ -1
- ifc_ii4 := ts_t5_mk_iface("IfcI4");
- ts_ifc_add_method_n(ifc_ii4, "m", 1, 0, ifc_a_n, -1, -1, -1, ifc_b_n);
- ts_ifc_add_method_n(ifc_ii4, "n", 2, 0, ifc_a_n, ifc_int_n, -1, -1, ifc_int_n);
- ifc_shp := sh_iface_shape_term(str_intern("IfcI4"));
- ifc_m0 := sh_shape_member_at(ifc_shp, 0);
- ifc_m1 := sh_shape_member_at(ifc_shp, 1);
- ifc_chain_ok : ., mut = 0;
- if ifc_m0 >= 0 && ifc_m1 >= 0 {
- c0 := tt_c(ifc_m0);
- c1 := tt_c(ifc_m1);
+ ifc_ii4 := ts_t5_mk_iface("IfcI4")
+ ts_ifc_add_method_n(ifc_ii4, "m", 1, 0, ifc_a_n, -1, -1, -1, ifc_b_n)
+ ts_ifc_add_method_n(ifc_ii4, "n", 2, 0, ifc_a_n, ifc_int_n, -1, -1, ifc_int_n)
+ ifc_shp := sh_iface_shape_term(str_intern("IfcI4"))
+ ifc_m0 := sh_shape_member_at(ifc_shp, 0)
+ ifc_m1 := sh_shape_member_at(ifc_shp, 1)
+ ifc_chain_ok : ., mut = 0
+ if ifc_m0 >= 0 && ifc_m1 >= 0:
+ c0 := tt_c(ifc_m0)
+ c1 := tt_c(ifc_m1)
// 链长(1 + pc):cons(ret, cons(p…)) ⇒ 2 元链(pc=1)/ 3 元链(pc=2)
- if tt_tag(c0) == TT_CONS && tt_tag(tt_b(c0)) == TT_CONS && tt_tag(tt_b(tt_b(c0))) == TT_NIL {
- if tt_tag(c1) == TT_CONS && tt_tag(tt_b(c1)) == TT_CONS {
- if tt_tag(tt_b(tt_b(c1))) == TT_CONS && tt_tag(tt_b(tt_b(tt_b(c1)))) == TT_NIL { ifc_chain_ok = 1; }
- }
- }
- }
+ if tt_tag(c0) == TT_CONS && tt_tag(tt_b(c0)) == TT_CONS && tt_tag(tt_b(tt_b(c0))) == TT_NIL:
+ if tt_tag(c1) == TT_CONS && tt_tag(tt_b(c1)) == TT_CONS:
+ if tt_tag(tt_b(tt_b(c1))) == TT_CONS && tt_tag(tt_b(tt_b(tt_b(c1)))) == TT_NIL:
+ ifc_chain_ok = 1
fails = fails + ts_check("ifc.shape_product_of_fn",
ts_isat_b2i(ifc_shp >= 0 && tt_tag(ifc_shp) == TT_ATOM && tt_a(ifc_shp) == AK_PRODUCT &&
- ifc_m0 >= 0 && tt_tag(ifc_m0) == TT_ATOM && tt_a(ifc_m0) == AK_FN &&
- tt_b(ifc_m0) == str_intern("m") && tt_b(ifc_m1) == str_intern("n") &&
- ifc_chain_ok == 1 && sh_shape_member_at(ifc_shp, 2) == -1 &&
- sh_shape_member_at(ifc_shp, -1) == -1), 1);
+ ifc_m0 >= 0 && tt_tag(ifc_m0) == TT_ATOM && tt_a(ifc_m0) == AK_FN &&
+ tt_b(ifc_m0) == str_intern("m") && tt_b(ifc_m1) == str_intern("n") &&
+ ifc_chain_ok == 1 && sh_shape_member_at(ifc_shp, 2) == -1 &&
+ sh_shape_member_at(ifc_shp, -1) == -1), 1)
// ⑨ 形状项不可建面:参数数越界(9 > MAX_IFACE_METHOD_PARAMS)⇒ -1(未覆盖面,不得当 0/1);
// 未声明接口名 ⇒ -1
- ifc_ii5 := ts_t5_mk_iface("IfcI5");
- ts_ifc_add_method_n(ifc_ii5, "m", 9, 0, -1, -1, -1, -1, ifc_int_n);
+ ifc_ii5 := ts_t5_mk_iface("IfcI5")
+ ts_ifc_add_method_n(ifc_ii5, "m", 9, 0, -1, -1, -1, -1, ifc_int_n)
fails = fails + ts_check("ifc.shape_build_unjudged",
ts_isat_b2i(sh_iface_shape_term(str_intern("IfcI5")) == -1 &&
- sh_iface_shape_term(str_intern("IfcNope")) == -1 &&
- iface_satisfies(ifc_h_ti, str_intern("IfcI5")) == -1), 1);
+ sh_iface_shape_term(str_intern("IfcNope")) == -1 &&
+ iface_satisfies(ifc_h_ti, str_intern("IfcI5")) == -1), 1)
// ⑩ mangling 退役:判定/查表路径**零 str_intern**(缺失方法 = 判定 0 的路径也不得驻留新串
// ——旧 `type_has_method` 的 `str_intern("T.m")` 形态在此会增长表)
- ifc_zz_ti := ts_ifc_mk_named("IfcZz");
- ifc_strs := g_str_count;
- ifc_p1 := iface_satisfies(ifc_zz_ti, str_intern("IfcI0"));
- ifc_p2 := type_has_method(str_intern("IfcZz"), str_intern("m"));
+ ifc_zz_ti := ts_ifc_mk_named("IfcZz")
+ ifc_strs := g_str_count
+ ifc_p1 := iface_satisfies(ifc_zz_ti, str_intern("IfcI0"))
+ ifc_p2 := type_has_method(str_intern("IfcZz"), str_intern("m"))
fails = fails + ts_check("ifc.mangling_zero_str_intern",
- ts_isat_b2i(ifc_p1 == 0 && ifc_p2 == false && g_str_count == ifc_strs), 1);
+ ts_isat_b2i(ifc_p1 == 0 && ifc_p2 == false && g_str_count == ifc_strs), 1)
// ⑪ 方法解析 = 表查询(`type_has_method` ⇔ `iface_find_method >= 0`):在位 true / 缺失 false
fails = fails + ts_check("ifc.type_has_method_table",
ts_isat_b2i(type_has_method(str_intern("IfcH"), str_intern("m")) == true &&
- type_has_method(str_intern("IfcZz"), str_intern("m")) == false &&
- iface_find_method(str_intern("IfcH"), str_intern("m")) >= 0 &&
- iface_find_method(str_intern("IfcZz"), str_intern("m")) < 0), 1);
+ type_has_method(str_intern("IfcZz"), str_intern("m")) == false &&
+ iface_find_method(str_intern("IfcH"), str_intern("m")) >= 0 &&
+ iface_find_method(str_intern("IfcZz"), str_intern("m")) < 0), 1)
// ⑫ 同源对拍(check_iface bool 面 ⇔ iface_satisfies 三态面 的 1 侧):三形态逐例相等
- ifc_eq : ., mut = 0;
- if ts_isat_b2i(check_iface(str_intern("IfcH"), ifc_ii0)) == iface_satisfies(ifc_h_ti, str_intern("IfcI0")) {
- if ts_isat_b2i(check_iface(str_intern("IfcP"), ifc_ii0)) == iface_satisfies(ifc_p_ti, str_intern("IfcI0")) {
- if ts_isat_b2i(check_iface(str_intern("IfcR"), ifc_ii0)) == iface_satisfies(ifc_r_ti, str_intern("IfcI0")) {
- ifc_eq = 1;
- }
- }
- }
- fails = fails + ts_check("ifc.check_iface_same_source", ifc_eq, 1);
+ ifc_eq : ., mut = 0
+ if ts_isat_b2i(check_iface(str_intern("IfcH"), ifc_ii0)) == iface_satisfies(ifc_h_ti, str_intern("IfcI0")):
+ if ts_isat_b2i(check_iface(str_intern("IfcP"), ifc_ii0)) == iface_satisfies(ifc_p_ti, str_intern("IfcI0")):
+ if ts_isat_b2i(check_iface(str_intern("IfcR"), ifc_ii0)) == iface_satisfies(ifc_r_ti, str_intern("IfcI0")):
+ ifc_eq = 1
+ fails = fails + ts_check("ifc.check_iface_same_source", ifc_eq, 1)
// ⑬ 三态(域限定与不可判):非命名行(原生/泛型形参/dyn)⇒ -1;零方法接口 + 命名行 ⇒ 1
// (空洞满足);未知接口名 ⇒ -1
- ifc_gp_ti := alloc_type(TYP_GENERIC_PARAM, str_intern("IfcU"), 0);
- ifc_dyn_ti := alloc_type(TYP_DYN, 0, 0);
- ifc_ii6 := ts_t5_mk_iface("IfcI6");
+ ifc_gp_ti := alloc_type(TYP_GENERIC_PARAM, str_intern("IfcU"), 0)
+ ifc_dyn_ti := alloc_type(TYP_DYN, 0, 0)
+ ifc_ii6 := ts_t5_mk_iface("IfcI6")
fails = fails + ts_check("ifc.three_state_unjudged",
ts_isat_b2i(iface_satisfies(TI_INT, str_intern("IfcI0")) == -1 &&
- iface_satisfies(ifc_gp_ti, str_intern("IfcI0")) == -1 &&
- iface_satisfies(ifc_dyn_ti, str_intern("IfcI0")) == -1 &&
- iface_satisfies(ifc_h_ti, str_intern("IfcI6")) == 1 &&
- iface_satisfies(ifc_h_ti, str_intern("IfcNope")) == -1 &&
- iface_satisfies(-1, str_intern("IfcI0")) == -1), 1);
+ iface_satisfies(ifc_gp_ti, str_intern("IfcI0")) == -1 &&
+ iface_satisfies(ifc_dyn_ti, str_intern("IfcI0")) == -1 &&
+ iface_satisfies(ifc_h_ti, str_intern("IfcI6")) == 1 &&
+ iface_satisfies(ifc_h_ti, str_intern("IfcNope")) == -1 &&
+ iface_satisfies(-1, str_intern("IfcI0")) == -1), 1)
// ⑭ 空 product 的形状面:零方法接口的形状项链为空(tt_nil)——成员/链形判据
- ifc_shp6 := sh_iface_shape_term(str_intern("IfcI6"));
+ ifc_shp6 := sh_iface_shape_term(str_intern("IfcI6"))
fails = fails + ts_check("ifc.shape_empty_product",
ts_isat_b2i(ifc_shp6 >= 0 && tt_tag(ifc_shp6) == TT_ATOM && tt_a(ifc_shp6) == AK_PRODUCT &&
- tt_c(ifc_shp6) >= 0 && tt_tag(tt_c(ifc_shp6)) == TT_NIL &&
- sh_shape_member_at(ifc_shp6, 0) == -1 && ifc_a_ti >= 0), 1);
- return fails;
-}
+ tt_c(ifc_shp6) >= 0 && tt_tag(tt_c(ifc_shp6)) == TT_NIL &&
+ sh_shape_member_at(ifc_shp6, 0) == -1 && ifc_a_ti >= 0), 1)
+ return fails
// ═══════════ R2 P5 Task 3:命名面判定化(身份链 + 可判定面加强)用例段 ═══════════
// 判据面(行为/结构断言,**不依赖 legacy 存活**——影子层下线后本段仍是回归网组件;
@@ -1007,129 +1014,128 @@ fn ts_ifc_run() -> int {
// T3 时未动(可判定但属 `tt_list_variance_at` 不变槽,须单独裁决)⇒ **T3b 已关闭**
// (`te_elem_cmp` 三态;断言迁往 `ts_t3b_run` 段——本段只剩同元素对照)。
// 夹具 = 人造行(alloc_named_type/alloc_type),不进生产侧表语义面,只服务本段断言。
-fn ts_t3n_run() -> int {
- fails : ., mut = 0;
- ty_budget_reset(200000);
- n_a := alloc_named_type(str_intern("T3NA"));
- n_b := alloc_named_type(str_intern("T3NB"));
- na_ni := get_type_data(n_a);
- ta := sh_term_of_ti(n_a);
- tb := sh_term_of_ti(n_b);
+fn ts_t3n_run() -> int:
+ fails : ., mut = 0
+ ty_budget_reset(200000)
+ n_a := alloc_named_type(str_intern("T3NA"))
+ n_b := alloc_named_type(str_intern("T3NB"))
+ na_ni := get_type_data(n_a)
+ ta := sh_term_of_ti(n_a)
+ tb := sh_term_of_ti(n_b)
// ① 链形态:b 槽 = 行号(标注;D21 的 atom_of 消费者),c = [令牌(name_ni)]
fails = fails + ts_check_b("t3n.chain_shape",
(ta >= 0 && tt_a(ta) == AK_NAMED && tt_b(ta) == n_a &&
- tt_c(ta) >= 0 && tt_tag(tt_c(ta)) == TT_CONS &&
- tt_a(tt_c(ta)) == sh_name_token(na_ni) &&
- tt_b(tt_c(ta)) >= 0 && tt_tag(tt_b(tt_c(ta))) == TT_NIL), true);
+ tt_c(ta) >= 0 && tt_tag(tt_c(ta)) == TT_CONS &&
+ tt_a(tt_c(ta)) == sh_name_token(na_ni) &&
+ tt_b(tt_c(ta)) >= 0 && tt_tag(tt_b(tt_c(ta))) == TT_NIL), true)
// ① D21 契约不回退:atom_of 仍读 b(命名行 = 本行;应用行 = 基型行,规范形)
// ② 同名 ⇒ 同行(named_dedup)⇒ 同节点 ⇒ 等价 1;异名 ⇒ 0(双向)
- n_a2 := alloc_named_type(str_intern("T3NA"));
+ n_a2 := alloc_named_type(str_intern("T3NA"))
fails = fails + ts_check_b("t3n.same_name_same_row",
- (n_a2 == n_a && sh_term_of_ti(n_a2) == ta && ty_equiv(ta, sh_term_of_ti(n_a2)) == 1), true);
+ (n_a2 == n_a && sh_term_of_ti(n_a2) == ta && ty_equiv(ta, sh_term_of_ti(n_a2)) == 1), true)
fails = fails + ts_check_b("t3n.diff_name_diff",
- (ty_sub(ta, tb) == 0 && ty_sub(tb, ta) == 0 && ty_equiv(ta, tb) == 0), true);
+ (ty_sub(ta, tb) == 0 && ty_sub(tb, ta) == 0 && ty_equiv(ta, tb) == 0), true)
// ③ 混类:命名 × 原生 ⇒ 0(名义型与异类原子不交)
fails = fails + ts_check_b("t3n.named_vs_base_zero",
(ty_equiv(ta, sh_term_of_ti(TI_INT)) == 0 && ty_equiv(ta, sh_term_of_ti(TI_STR)) == 0 &&
- ty_equiv(sh_term_of_ti(TI_STR), ta) == 0), true);
+ ty_equiv(sh_term_of_ti(TI_STR), ta) == 0), true)
// ④ 域外:NEVER/DYN 混类 ⇒ -1 + 未覆盖面位置位(⊥/⊤ 语义未建模,登记)
- ty_budget_reset(200000);
- dn := ty_equiv(ta, sh_term_of_ti(TI_NEVER));
- unc1 := ty_uncovered();
- ty_budget_reset(200000);
- dd := ty_equiv(ta, sh_term_of_ti(TI_DYN));
- unc2 := ty_uncovered();
+ ty_budget_reset(200000)
+ dn := ty_equiv(ta, sh_term_of_ti(TI_NEVER))
+ unc1 := ty_uncovered()
+ ty_budget_reset(200000)
+ dd := ty_equiv(ta, sh_term_of_ti(TI_DYN))
+ unc2 := ty_uncovered()
fails = fails + ts_check_b("t3n.never_dyn_out_of_domain",
- (dn == -1 && dd == -1 && unc1 == 1 && unc2 == 1), true);
+ (dn == -1 && dd == -1 && unc1 == 1 && unc2 == 1), true)
// ④ 域外:空链(无身份 = 未覆盖面②原形态)⇒ -1
- ty_budget_reset(200000);
- dnc := ty_equiv(tt_atom(AK_NAMED, -1, -1), ta);
- fails = fails + ts_check_b("t3n.no_chain_out_of_domain", (dnc == -1 && ty_uncovered() == 1), true);
+ ty_budget_reset(200000)
+ dnc := ty_equiv(tt_atom(AK_NAMED, -1, -1), ta)
+ fails = fails + ts_check_b("t3n.no_chain_out_of_domain", (dnc == -1 && ty_uncovered() == 1), true)
// ④ 域外:令牌位放类型项 ⇒ -1(位置错位不猜)
- ty_budget_reset(200000);
- mis1 := ty_equiv(tt_atom(AK_NAMED, -1, tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())), ta);
- fails = fails + ts_check_b("t3n.token_pos_mismatch_out", (mis1 == -1 && ty_uncovered() == 1), true);
+ ty_budget_reset(200000)
+ mis1 := ty_equiv(tt_atom(AK_NAMED, -1, tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())), ta)
+ fails = fails + ts_check_b("t3n.token_pos_mismatch_out", (mis1 == -1 && ty_uncovered() == 1), true)
// ④ 域外:实参位 μ 变元 ⇒ -1(实参位只收类型项;令牌位同节点 ⇒ 比较推进到实参位)
- bad_arg := tt_atom(AK_NAMED, n_a, tt_cons(sh_name_token(na_ni), tt_cons(tt_var(0), tt_nil())));
- good_arg := tt_atom(AK_NAMED, n_a, tt_cons(sh_name_token(na_ni), tt_cons(sh_term_of_ti(TI_INT), tt_nil())));
- ty_budget_reset(200000);
- mis2 := ty_equiv(bad_arg, good_arg);
- fails = fails + ts_check_b("t3n.arg_var_out_of_domain", (mis2 == -1 && ty_uncovered() == 1), true);
+ bad_arg := tt_atom(AK_NAMED, n_a, tt_cons(sh_name_token(na_ni), tt_cons(tt_var(0), tt_nil())))
+ good_arg := tt_atom(AK_NAMED, n_a, tt_cons(sh_name_token(na_ni), tt_cons(sh_term_of_ti(TI_INT), tt_nil())))
+ ty_budget_reset(200000)
+ mis2 := ty_equiv(bad_arg, good_arg)
+ fails = fails + ts_check_b("t3n.arg_var_out_of_domain", (mis2 == -1 && ty_uncovered() == 1), true)
// ⑤ 清零判据(二进制内):命名面经 type_equal = **引擎自决**——R2 P5 Task 4 后回落计数
// 本体已删(legacy 一并删除)⇒ 断言升级为「自决 + **零 ICE04 诊断**」:诊断缺席 = 引擎
// 真判(0/1),而不是「未知被静默当 false」(P-A 的牙齿 = t4.ice04_* 三例)。
- t3n_d0 := g_diag_count;
- eqf : ., mut = 0;
- if !type_equal(n_a, n_b) {
- if g_diag_count == t3n_d0 { eqf = 1; }
- }
- fails = fails + ts_check_b("t3n.decided_no_indeterminate", (eqf == 1 && ty_sub(ta, tb) == 0), true);
+ t3n_d0 := g_diag_count
+ eqf : ., mut = 0
+ if !type_equal(n_a, n_b):
+ if g_diag_count == t3n_d0:
+ eqf = 1
+ fails = fails + ts_check_b("t3n.decided_no_indeterminate", (eqf == 1 && ty_sub(ta, tb) == 0), true)
// ② 泛型应用:规范形 b = 基型行 + 链 [基名令牌, 实参项…]
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- gs1 := g_gen_apply_data_count;
- w64(g_gen_apply_data, gs1 * 8, 1);
- w64(g_gen_apply_data, (gs1 + 1) * 8, TI_INT);
- g_gen_apply_data_count = gs1 + 2;
- ga1 := alloc_type(TYP_GENERIC_APPLY, n_a, gs1);
- ga2 := alloc_type(TYP_GENERIC_APPLY, n_a, gs1); // **另一行**,同基型同实参
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- gs2 := g_gen_apply_data_count;
- w64(g_gen_apply_data, gs2 * 8, 1);
- w64(g_gen_apply_data, (gs2 + 1) * 8, TI_STR);
- g_gen_apply_data_count = gs2 + 2;
- ga3 := alloc_type(TYP_GENERIC_APPLY, n_a, gs2); // 同基型**异实参**
- t_ga1 := sh_term_of_ti(ga1);
- t_ga2 := sh_term_of_ti(ga2);
- t_ga3 := sh_term_of_ti(ga3);
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ gs1 := g_gen_apply_data_count
+ w64(g_gen_apply_data, gs1 * 8, 1)
+ w64(g_gen_apply_data, (gs1 + 1) * 8, TI_INT)
+ g_gen_apply_data_count = gs1 + 2
+ ga1 := alloc_type(TYP_GENERIC_APPLY, n_a, gs1)
+ ga2 := alloc_type(TYP_GENERIC_APPLY, n_a, gs1) // **另一行**,同基型同实参
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ gs2 := g_gen_apply_data_count
+ w64(g_gen_apply_data, gs2 * 8, 1)
+ w64(g_gen_apply_data, (gs2 + 1) * 8, TI_STR)
+ g_gen_apply_data_count = gs2 + 2
+ ga3 := alloc_type(TYP_GENERIC_APPLY, n_a, gs2) // 同基型**异实参**
+ t_ga1 := sh_term_of_ti(ga1)
+ t_ga2 := sh_term_of_ti(ga2)
+ t_ga3 := sh_term_of_ti(ga3)
fails = fails + ts_check_b("t3n.apply_canonical_b",
(t_ga1 >= 0 && tt_a(t_ga1) == AK_NAMED && tt_b(t_ga1) == n_a &&
- tt_atom_of_term(t_ga1) == n_a &&
- tt_c(t_ga1) >= 0 && tt_tag(tt_c(t_ga1)) == TT_CONS &&
- tt_a(tt_c(t_ga1)) == sh_name_token(na_ni) &&
- tt_a(tt_b(tt_c(t_ga1))) == sh_term_of_ti(TI_INT)), true);
+ tt_atom_of_term(t_ga1) == n_a &&
+ tt_c(t_ga1) >= 0 && tt_tag(tt_c(t_ga1)) == TT_CONS &&
+ tt_a(tt_c(t_ga1)) == sh_name_token(na_ni) &&
+ tt_a(tt_b(tt_c(t_ga1))) == sh_term_of_ti(TI_INT)), true)
fails = fails + ts_check_b("t3n.apply_two_rows_same_args",
- (ga1 != ga2 && t_ga1 == t_ga2 && ty_equiv(t_ga1, t_ga2) == 1), true);
+ (ga1 != ga2 && t_ga1 == t_ga2 && ty_equiv(t_ga1, t_ga2) == 1), true)
fails = fails + ts_check_b("t3n.apply_diff_args_zero",
- (ty_sub(t_ga1, t_ga3) == 0 && ty_sub(t_ga3, t_ga1) == 0), true);
+ (ty_sub(t_ga1, t_ga3) == 0 && ty_sub(t_ga3, t_ga1) == 0), true)
fails = fails + ts_check_b("t3n.apply_vs_bare_diff",
- (ty_sub(t_ga1, ta) == 0 && ty_sub(ta, t_ga1) == 0), true);
+ (ty_sub(t_ga1, ta) == 0 && ty_sub(ta, t_ga1) == 0), true)
// ② 双构造点逐位同构(计划停条件③守门):同型两构造 ⇒ **同节点**
fails = fails + ts_check_b("t3n.two_points_isomorphic",
- (sh_sig_term_of_ti(n_a) == ta && sh_sig_term_of_ti(ga1) == t_ga1), true);
+ (sh_sig_term_of_ti(n_a) == ta && sh_sig_term_of_ti(ga1) == t_ga1), true)
// ② 嵌套应用:Box[Box[int]] 两处(外层实参分别指向同实参的**不同行**)⇒ 同节点
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- gs3 := g_gen_apply_data_count;
- w64(g_gen_apply_data, gs3 * 8, 1);
- w64(g_gen_apply_data, (gs3 + 1) * 8, ga1);
- g_gen_apply_data_count = gs3 + 2;
- ga4 := alloc_type(TYP_GENERIC_APPLY, n_a, gs3);
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- gs4 := g_gen_apply_data_count;
- w64(g_gen_apply_data, gs4 * 8, 1);
- w64(g_gen_apply_data, (gs4 + 1) * 8, ga2);
- g_gen_apply_data_count = gs4 + 2;
- ga5 := alloc_type(TYP_GENERIC_APPLY, n_a, gs4);
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ gs3 := g_gen_apply_data_count
+ w64(g_gen_apply_data, gs3 * 8, 1)
+ w64(g_gen_apply_data, (gs3 + 1) * 8, ga1)
+ g_gen_apply_data_count = gs3 + 2
+ ga4 := alloc_type(TYP_GENERIC_APPLY, n_a, gs3)
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ gs4 := g_gen_apply_data_count
+ w64(g_gen_apply_data, gs4 * 8, 1)
+ w64(g_gen_apply_data, (gs4 + 1) * 8, ga2)
+ g_gen_apply_data_count = gs4 + 2
+ ga5 := alloc_type(TYP_GENERIC_APPLY, n_a, gs4)
fails = fails + ts_check_b("t3n.nested_apply_same",
- (ga4 != ga5 && sh_term_of_ti(ga4) == sh_term_of_ti(ga5)), true);
+ (ga4 != ga5 && sh_term_of_ti(ga4) == sh_term_of_ti(ga5)), true)
// ② 可选面(union):NA ⊂ NA?(注入面)⇒ 1;NA? vs NB?(内层异名)⇒ 0
- opt_a := tt_union(ta, sh_null_term());
- opt_b := tt_union(tb, sh_null_term());
+ opt_a := tt_union(ta, sh_null_term())
+ opt_b := tt_union(tb, sh_null_term())
fails = fails + ts_check_b("t3n.optional_named",
- (ty_sub(ta, opt_a) == 1 && ty_sub(opt_a, opt_b) == 0), true);
+ (ty_sub(ta, opt_a) == 1 && ty_sub(opt_a, opt_b) == 0), true)
// ④ 域外:union 面含**无链**命名原子(未覆盖面②原形态)⇒ 仍 -1(加强不得把
// 未范化/域外并集面误判成 0——计划 Step 1 的 union 负控)
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
u_out := ty_equiv(tt_union(tt_atom(AK_NAMED, -1, -1), sh_null_term()),
- tt_union(tt_atom(AK_NAMED, -2, -1), sh_null_term()));
- fails = fails + ts_check_b("t3n.union_out_of_domain", (u_out == -1 && ty_uncovered() == 1), true);
+ tt_union(tt_atom(AK_NAMED, -2, -1), sh_null_term()))
+ fails = fails + ts_check_b("t3n.union_out_of_domain", (u_out == -1 && ty_uncovered() == 1), true)
// ⑥ 残留面**已关闭**(R2 P5 Task 3b:不变槽元素三态 te_elem_cmp)——断言迁移到
// `t3b.inv_slot_seq_named_diff_zero`(本段不再钉「-1」;翻转向量见 p5-task3b 报告)
// ⑥ 对照:同元素(不同行)⇒ 1(N 不入身份 + 同链 ⇒ 快路径)
- arr_a := sh_seq_term(n_a, 2);
- arr_a2 := sh_seq_term(n_a, 2);
- fails = fails + ts_check("t3n.same_elem_seq_equiv", ty_equiv(arr_a, arr_a2), 1);
- return fails;
-}
+ arr_a := sh_seq_term(n_a, 2)
+ arr_a2 := sh_seq_term(n_a, 2)
+ fails = fails + ts_check("t3n.same_elem_seq_equiv", ty_equiv(arr_a, arr_a2), 1)
+ return fails
// ═══════════ R2 P5 Task 3b:不变槽元素三态(te_elem_cmp)用例段 ═══════════
// 关闭 P5 Task 3 §6 登记的残留面(交接条目即本段 RED 面)。判据六面:
@@ -1145,109 +1151,108 @@ fn ts_t3n_run() -> int {
// ⑥ 二进制面清零判据:数组行经 `type_equal` = **引擎自决 + 零 ICE04 诊断**(T4 重钉:
// 回落计数随 legacy 删除,断言形态改为「未知诊断缺席」)。
// 夹具 = 人造行(alloc_named_type/alloc_type,同名 ⇒ 同名去重行);不进生产侧表语义面。
-fn ts_t3b_run() -> int {
- fails : ., mut = 0;
- ty_budget_reset(200000);
- n_a := alloc_named_type(str_intern("T3NA"));
- n_b := alloc_named_type(str_intern("T3NB"));
- t_a := sh_term_of_ti(n_a);
- t_b := sh_term_of_ti(n_b);
- t_int := sh_term_of_ti(TI_INT);
+fn ts_t3b_run() -> int:
+ fails : ., mut = 0
+ ty_budget_reset(200000)
+ n_a := alloc_named_type(str_intern("T3NA"))
+ n_b := alloc_named_type(str_intern("T3NB"))
+ t_a := sh_term_of_ti(n_a)
+ t_b := sh_term_of_ti(n_b)
+ t_int := sh_term_of_ti(TI_INT)
// ① 序列元素(AK_SEQUENCE 链槽 0):异名 ⇒ 0 双向 + 零未覆盖面
- arr_a := alloc_type(TYP_ARRAY, n_a, 2);
- arr_b := alloc_type(TYP_ARRAY, n_b, 2);
- ty_budget_reset(200000);
- ab := ty_sub(sh_term_of_ti(arr_a), sh_term_of_ti(arr_b));
- ba := ty_sub(sh_term_of_ti(arr_b), sh_term_of_ti(arr_a));
+ arr_a := alloc_type(TYP_ARRAY, n_a, 2)
+ arr_b := alloc_type(TYP_ARRAY, n_b, 2)
+ ty_budget_reset(200000)
+ ab := ty_sub(sh_term_of_ti(arr_a), sh_term_of_ti(arr_b))
+ ba := ty_sub(sh_term_of_ti(arr_b), sh_term_of_ti(arr_a))
fails = fails + ts_check("t3b.inv_slot_seq_named_diff_zero",
- ts_isat_b2i(ab == 0 && ba == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(ab == 0 && ba == 0 && ty_uncovered() == 0), 1)
// ① 指针元素(AK_PTR 链槽 0)⇒ 0
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
pb := ty_sub(tt_atom(AK_PTR, -1, tt_cons(t_a, tt_nil())),
- tt_atom(AK_PTR, -1, tt_cons(t_b, tt_nil())));
+ tt_atom(AK_PTR, -1, tt_cons(t_b, tt_nil())))
fails = fails + ts_check("t3b.inv_slot_ptr_named_diff_zero",
- ts_isat_b2i(pb == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(pb == 0 && ty_uncovered() == 0), 1)
// ① 元组字段位(AK_PRODUCT 链;第 2 字段同项 = 对照组)⇒ 0
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
pr := ty_sub(tt_atom(AK_PRODUCT, -1, tt_cons(t_a, tt_cons(t_int, tt_nil()))),
- tt_atom(AK_PRODUCT, -1, tt_cons(t_b, tt_cons(t_int, tt_nil()))));
+ tt_atom(AK_PRODUCT, -1, tt_cons(t_b, tt_cons(t_int, tt_nil()))))
fails = fails + ts_check("t3b.inv_slot_prod_named_diff_zero",
- ts_isat_b2i(pr == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(pr == 0 && ty_uncovered() == 0), 1)
// ① 嵌套(元素 = 序列项 ⇒ 经 te_elem_cmp 的类型项面递归):[[NA;2];2] vs [[NB;2];2] ⇒ 0
- nest_a := alloc_type(TYP_ARRAY, alloc_type(TYP_ARRAY, n_a, 2), 2);
- nest_b := alloc_type(TYP_ARRAY, alloc_type(TYP_ARRAY, n_b, 2), 2);
- ty_budget_reset(200000);
- ns := ty_sub(sh_term_of_ti(nest_a), sh_term_of_ti(nest_b));
+ nest_a := alloc_type(TYP_ARRAY, alloc_type(TYP_ARRAY, n_a, 2), 2)
+ nest_b := alloc_type(TYP_ARRAY, alloc_type(TYP_ARRAY, n_b, 2), 2)
+ ty_budget_reset(200000)
+ ns := ty_sub(sh_term_of_ti(nest_a), sh_term_of_ti(nest_b))
fails = fails + ts_check("t3b.inv_slot_nested_seq_diff_zero",
- ts_isat_b2i(ns == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(ns == 0 && ty_uncovered() == 0), 1)
// ② 等价面不被压成 0:N 面([NA;2] vs [NA;3] ⇒ 1)+ 同元素**另一行** ⇒ 1
- ty_budget_reset(200000);
- n_eq := ty_equiv(sh_term_of_ti(arr_a), sh_term_of_ti(alloc_type(TYP_ARRAY, n_a, 3)));
- r_eq := ty_equiv(sh_term_of_ti(arr_a), sh_term_of_ti(alloc_type(TYP_ARRAY, n_a, 2)));
+ ty_budget_reset(200000)
+ n_eq := ty_equiv(sh_term_of_ti(arr_a), sh_term_of_ti(alloc_type(TYP_ARRAY, n_a, 3)))
+ r_eq := ty_equiv(sh_term_of_ti(arr_a), sh_term_of_ti(alloc_type(TYP_ARRAY, n_a, 2)))
fails = fails + ts_check("t3b.equiv_face_not_crushed",
- ts_isat_b2i(n_eq == 1 && r_eq == 1 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(n_eq == 1 && r_eq == 1 && ty_uncovered() == 0), 1)
// ③ 令牌位:AK_SUM 链 = [枚举名令牌, 变体名令牌](皆不变槽)——异变体名 ⇒ 0
- e1 := str_intern("T3bE1");
- v1 := str_intern("T3bV1");
- v2 := str_intern("T3bV2");
- sum_v1 := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v1), tt_nil())));
- sum_v2 := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v2), tt_nil())));
- ty_budget_reset(200000);
- sv := ty_sub(sum_v1, sum_v2);
+ e1 := str_intern("T3bE1")
+ v1 := str_intern("T3bV1")
+ v2 := str_intern("T3bV2")
+ sum_v1 := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v1), tt_nil())))
+ sum_v2 := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v2), tt_nil())))
+ ty_budget_reset(200000)
+ sv := ty_sub(sum_v1, sum_v2)
fails = fails + ts_check("t3b.token_slot_variant_diff_zero",
- ts_isat_b2i(sv == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(sv == 0 && ty_uncovered() == 0), 1)
// ③ 同令牌 ⇒ 同节点 ⇒ 1(同枚举同变体两处构造)
- sum_v1x := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v1), tt_nil())));
+ sum_v1x := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v1), tt_nil())))
fails = fails + ts_check("t3b.token_slot_same_one",
- ts_isat_b2i(sum_v1 == sum_v1x && ty_equiv(sum_v1, sum_v1x) == 1), 1);
+ ts_isat_b2i(sum_v1 == sum_v1x && ty_equiv(sum_v1, sum_v1x) == 1), 1)
// ⑤(a) 负控:同名令牌 ⇒ 同一节点(DAG 去重)——「同名不同节点」结构上不可达;
// mut 标记同式(同值同节点、异值异节点)
fails = fails + ts_check("t3b.token_same_name_same_node",
ts_isat_b2i(sh_name_token(e1) == sh_name_token(e1) &&
- sh_name_token(e1) != sh_name_token(v1) &&
- sh_ref_mut_marker(0) == sh_ref_mut_marker(0) &&
- sh_ref_mut_marker(0) != sh_ref_mut_marker(1)), 1);
+ sh_name_token(e1) != sh_name_token(v1) &&
+ sh_ref_mut_marker(0) == sh_ref_mut_marker(0) &&
+ sh_ref_mut_marker(0) != sh_ref_mut_marker(1)), 1)
// ⑤(b) 负控:令牌 × 原生 unit 项同形 ⇒ ty_equiv 判**等**(碰撞实证);
// te_elem_cmp 令牌先判 ⇒ 0(无假等);unit × unit ⇒ 同节点 ⇒ 1
- u_item := sh_term_of_ti(TI_UNIT);
- tok_e1 := sh_name_token(e1);
- ty_budget_reset(200000);
- coll := ty_equiv(u_item, tok_e1);
+ u_item := sh_term_of_ti(TI_UNIT)
+ tok_e1 := sh_name_token(e1)
+ ty_budget_reset(200000)
+ coll := ty_equiv(u_item, tok_e1)
fails = fails + ts_check("t3b.unit_token_shape_collision_guard",
ts_isat_b2i(coll == 1 && te_elem_cmp(u_item, tok_e1) == 0 &&
- te_elem_cmp(u_item, u_item) == 1), 1);
+ te_elem_cmp(u_item, u_item) == 1), 1)
// ⑤(b) 补:unit 项在**非令牌型**元素位上按类型项比较 ⇒ [unit] vs [int] = 0;
// [unit] vs [unit](N 不同)⇒ 1
- ty_budget_reset(200000);
- u_i := ty_sub(sh_seq_term(TI_UNIT, 2), sh_seq_term(TI_INT, 2));
- u_u := ty_equiv(sh_seq_term(TI_UNIT, 2), sh_seq_term(TI_UNIT, 3));
+ ty_budget_reset(200000)
+ u_i := ty_sub(sh_seq_term(TI_UNIT, 2), sh_seq_term(TI_INT, 2))
+ u_u := ty_equiv(sh_seq_term(TI_UNIT, 2), sh_seq_term(TI_UNIT, 3))
fails = fails + ts_check("t3b.unit_elem_type_item_face",
- ts_isat_b2i(u_i == 0 && u_u == 1 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(u_i == 0 && u_u == 1 && ty_uncovered() == 0), 1)
// ④ 域外守卫的牙:链元素既非令牌也非类型项(μ 变元)⇒ -1 + 未覆盖面
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
dom := ty_sub(tt_atom(AK_SEQUENCE, -1, tt_cons(tt_var(0), tt_nil())),
- tt_atom(AK_SEQUENCE, -1, tt_cons(t_int, tt_nil())));
+ tt_atom(AK_SEQUENCE, -1, tt_cons(t_int, tt_nil())))
fails = fails + ts_check("t3b.elem_out_of_domain_stays_minus1",
- ts_isat_b2i(dom == -1 && ty_uncovered() == 1), 1);
+ ts_isat_b2i(dom == -1 && ty_uncovered() == 1), 1)
// ② 只读 ref 元素(协变槽)+ mut 标记槽回归钉:&NA vs &NB ⇒ 0;& 与 &mut ⇒ 0
- ref_a := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(t_a, tt_nil())));
- ref_b := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(t_b, tt_nil())));
- ref_m := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(t_a, tt_nil())));
- ty_budget_reset(200000);
- rb := ty_sub(ref_a, ref_b);
- rm := ty_sub(ref_a, ref_m);
+ ref_a := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(t_a, tt_nil())))
+ ref_b := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(t_b, tt_nil())))
+ ref_m := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(t_a, tt_nil())))
+ ty_budget_reset(200000)
+ rb := ty_sub(ref_a, ref_b)
+ rm := ty_sub(ref_a, ref_m)
fails = fails + ts_check("t3b.ref_elem_and_marker",
- ts_isat_b2i(rb == 0 && rm == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(rb == 0 && rm == 0 && ty_uncovered() == 0), 1)
// ⑥ 清零判据(二进制内):数组行经 type_equal = 引擎自决 + 零 ICE04 诊断(T4 重钉:
// 回落计数已随 legacy 删除 ⇒ 断言形态 = 「未知诊断缺席」)
- t3b_d0 := g_diag_count;
- dec : ., mut = 0;
- if !type_equal(arr_a, arr_b) {
- if g_diag_count == t3b_d0 { dec = 1; }
- }
- fails = fails + ts_check("t3b.decided_no_indeterminate_arr", dec, 1);
- return fails;
-}
+ t3b_d0 := g_diag_count
+ dec : ., mut = 0
+ if !type_equal(arr_a, arr_b):
+ if g_diag_count == t3b_d0:
+ dec = 1
+ fails = fails + ts_check("t3b.decided_no_indeterminate_arr", dec, 1)
+ return fails
// ═══════════ R2 P5 Task 4:残留 -1 政策 P-A(ICE04 硬错)用例段 ═══════════
// 判据面(**不依赖 legacy 存活**——它就是 legacy 删除后的替身证据;影子层下线后照常):
@@ -1259,42 +1264,44 @@ fn ts_t3b_run() -> int {
// 「未知 ⇒ 诊断」而「确定 ⇒ 无诊断」(P-A 若被改回「静默 false」= ①②转红;若被改成
// 「全报」= ③转红)。
// 诊断是**故意**触发的:本段结束时复位 g_diag_count(不留进后续用例的增量基线)。
-fn ts_t4_run() -> int {
- fails : ., mut = 0;
+fn ts_t4_run() -> int:
+ fails : ., mut = 0
// ① 桥接缺口(ti 越界 = 无项)
- t4_d0 := g_diag_count;
- t4_b1 : ., mut = 0;
- if !type_equal(g_type_count + 100, TI_INT) { t4_b1 = 1; }
- t4_d1 := g_diag_count;
- t4_m_bridge := ts_diag_msg_at(t4_d0);
+ t4_d0 := g_diag_count
+ t4_b1 : ., mut = 0
+ if !type_equal(g_type_count + 100, TI_INT):
+ t4_b1 = 1
+ t4_d1 := g_diag_count
+ t4_m_bridge := ts_diag_msg_at(t4_d0)
fails = fails + ts_check_b("t4.ice04_bridge_gap_hard_error",
(t4_b1 == 1 && t4_d1 == t4_d0 + 1 && ts_diag_code_at(t4_d0) == EC_ICE_TY_INDET &&
- str_len(t4_m_bridge) > 0), true);
+ str_len(t4_m_bridge) > 0), true)
// ② 引擎 -1(未覆盖面):命名原子(T3 身份链)× NEVER 原子 = **域外**(`te_named_pair`
// 的 NEVER/DYN 守卫 ⇒ -1 + g_ty_uncovered,见 t3n.never_dyn_out_of_domain)——这是
// 桥接**能译**(两条目皆 ≥ 0)但引擎判不了的形态:与 ① 的桥接缺口是**两个不同出口**。
// (反例形态记:AK_NEVER × AK_DYN 是**已判**面(⊥ ⊆ ⊤ 不反向 ⇒ 0),不产 -1。)
- t4_na := alloc_named_type(str_intern("T4IndetNamed"));
- t4_d2 := g_diag_count;
- t4_b2 : ., mut = 0;
- if !type_equal(t4_na, TI_NEVER) { t4_b2 = 1; }
- t4_d3 := g_diag_count;
- t4_m_engine := ts_diag_msg_at(t4_d2);
+ t4_na := alloc_named_type(str_intern("T4IndetNamed"))
+ t4_d2 := g_diag_count
+ t4_b2 : ., mut = 0
+ if !type_equal(t4_na, TI_NEVER):
+ t4_b2 = 1
+ t4_d3 := g_diag_count
+ t4_m_engine := ts_diag_msg_at(t4_d2)
fails = fails + ts_check_b("t4.ice04_engine_uncovered_hard_error",
(t4_b2 == 1 && t4_d3 == t4_d2 + 1 && ts_diag_code_at(t4_d2) == EC_ICE_TY_INDET &&
- str_len(t4_m_engine) > 0 && str_eq(t4_m_bridge, t4_m_engine) == 0), true);
+ str_len(t4_m_engine) > 0 && str_eq(t4_m_bridge, t4_m_engine) == 0), true)
// ③ 决定面零误报(引擎自决 0 与同一行快路径各自零诊断)
- t4_d4 := g_diag_count;
- t4_ok : ., mut = 0;
- if !type_equal(TI_INT, TI_STR) { // 引擎自决 0
- if type_equal(TI_INT, TI_INT) { // 同一行快路径(自反)
- if g_diag_count == t4_d4 { t4_ok = 1; }
- }
- }
- fails = fails + ts_check("t4.ice04_decided_no_false_positive", t4_ok, 1);
- g_diag_count = t4_d4; // 复位(本段的 ICE04 是故意触发的)
- return fails;
-}
+ t4_d4 := g_diag_count
+ t4_ok : ., mut = 0
+ if !type_equal(TI_INT, TI_STR):
+ // 引擎自决 0
+ if type_equal(TI_INT, TI_INT):
+ // 同一行快路径(自反)
+ if g_diag_count == t4_d4:
+ t4_ok = 1
+ fails = fails + ts_check("t4.ice04_decided_no_false_positive", t4_ok, 1)
+ g_diag_count = t4_d4 // 复位(本段的 ICE04 是故意触发的)
+ return fails
// ═══════════ R2 P4 Task 2:TYPE 段内容面(装填 / 序列化 / dedup / 确定性)═══════════
// 用例面:① 段体缓冲 ↔ 内存表逐字段 roundtrip(行表 24B/条 + 项表 40B/条 + 长度公式);
@@ -1304,146 +1311,165 @@ fn ts_t4_run() -> int {
// ④ 不可译行 ⇒ 装填拒绝(save 侧拒落盘,三态纪律)。
// 夹具说明:本组自建干净类型表(init_types 9 原生行 + 4 行可选/定长数组),不经
// parser/check_all;**必须最后运行**(populate 复位项层/引擎/桥接三面缓存)。
-fn ts_ccr_roundtrip_ok() -> int {
- rc := g_type_count;
- tc := tt_count();
- if g_ccr_type_seg_len != 4 + rc * ESZ_TYPE_ROW + 4 + tc * ESZ_TYPE_TERM_DISK { return 0; }
- if buf_read_u32(g_ccr_type_seg, 0) != rc { return 0; }
- pos : ., mut = 4;
- i : ., mut = 0;
- loop {
- if i >= rc { break; }
- if buf_read_i64(g_ccr_type_seg, pos) != r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_KIND) { return 0; }
- if buf_read_i64(g_ccr_type_seg, pos + 8) != r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_DATA) { return 0; }
- if buf_read_i64(g_ccr_type_seg, pos + 16) != r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_EXTRA) { return 0; }
- pos = pos + ESZ_TYPE_ROW;
- i = i + 1;
- }
- if buf_read_u32(g_ccr_type_seg, pos) != tc { return 0; }
- pos = pos + 4;
- j : ., mut = 0;
- loop {
- if j >= tc { break; }
- if buf_read_i64(g_ccr_type_seg, pos) != tt_tag(j) { return 0; }
- if buf_read_i64(g_ccr_type_seg, pos + 8) != tt_a(j) { return 0; }
- if buf_read_i64(g_ccr_type_seg, pos + 16) != tt_b(j) { return 0; }
- if buf_read_i64(g_ccr_type_seg, pos + 24) != tt_c(j) { return 0; }
- if buf_read_i64(g_ccr_type_seg, pos + 32) != tt_d(j) { return 0; }
- pos = pos + ESZ_TYPE_TERM_DISK;
- j = j + 1;
- }
- if pos != g_ccr_type_seg_len { return 0; }
- return 1;
-}
-
-fn ts_ccr_dedup_ok(opt_a: int, opt_b: int, arr3: int, arr4: int) -> int {
+fn ts_ccr_roundtrip_ok() -> int:
+ rc := g_type_count
+ tc := tt_count()
+ if g_ccr_type_seg_len != 4 + rc * ESZ_TYPE_ROW + 4 + tc * ESZ_TYPE_TERM_DISK:
+ return 0
+ if buf_read_u32(g_ccr_type_seg, 0) != rc:
+ return 0
+ pos : ., mut = 4
+ i : ., mut = 0
+ loop:
+ if i >= rc:
+ break
+ if buf_read_i64(g_ccr_type_seg, pos) != r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_KIND):
+ return 0
+ if buf_read_i64(g_ccr_type_seg, pos + 8) != r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_DATA):
+ return 0
+ if buf_read_i64(g_ccr_type_seg, pos + 16) != r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_EXTRA):
+ return 0
+ pos = pos + ESZ_TYPE_ROW
+ i = i + 1
+ if buf_read_u32(g_ccr_type_seg, pos) != tc:
+ return 0
+ pos = pos + 4
+ j : ., mut = 0
+ loop:
+ if j >= tc:
+ break
+ if buf_read_i64(g_ccr_type_seg, pos) != tt_tag(j):
+ return 0
+ if buf_read_i64(g_ccr_type_seg, pos + 8) != tt_a(j):
+ return 0
+ if buf_read_i64(g_ccr_type_seg, pos + 16) != tt_b(j):
+ return 0
+ if buf_read_i64(g_ccr_type_seg, pos + 24) != tt_c(j):
+ return 0
+ if buf_read_i64(g_ccr_type_seg, pos + 32) != tt_d(j):
+ return 0
+ pos = pos + ESZ_TYPE_TERM_DISK
+ j = j + 1
+ if pos != g_ccr_type_seg_len:
+ return 0
+ return 1
+
+fn ts_ccr_dedup_ok(opt_a: int, opt_b: int, arr3: int, arr4: int) -> int:
// 同构 ⇒ 同节点(两个 `int?` 行 → 同一 union 项);b 标注(固定长度)区分 ⇒ 异节点
- if sh_term_of_ti(opt_a) != sh_term_of_ti(opt_b) { return 0; }
- if sh_term_of_ti(arr3) == sh_term_of_ti(arr4) { return 0; }
+ if sh_term_of_ti(opt_a) != sh_term_of_ti(opt_b):
+ return 0
+ if sh_term_of_ti(arr3) == sh_term_of_ti(arr4):
+ return 0
// DAG 不变量:表内无两个同 (tag,a..d) 的行(tt_term 去重——重建路径的牙)
- n := tt_count();
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- j : ., mut = i + 1;
- loop {
- if j >= n { break; }
- if tt_tag(i) == tt_tag(j) && tt_a(i) == tt_a(j) && tt_b(i) == tt_b(j) &&
- tt_c(i) == tt_c(j) && tt_d(i) == tt_d(j) { return 0; }
- j = j + 1;
- }
- i = i + 1;
- }
- return 1;
-}
-
-fn ts_ccr_purity_ok() -> int {
- n0 := g_ccr_type_seg_len;
- cp := alloc(n0 + 8);
- _dyncpy(g_ccr_type_seg, n0, cp);
+ n := tt_count()
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ j : ., mut = i + 1
+ loop:
+ if j >= n:
+ break
+ if tt_tag(i) == tt_tag(j) && tt_a(i) == tt_a(j) && tt_b(i) == tt_b(j) && tt_c(i) == tt_c(j) && tt_d(i) == tt_d(j):
+ return 0
+ j = j + 1
+ i = i + 1
+ return 1
+
+fn ts_ccr_purity_ok() -> int:
+ n0 := g_ccr_type_seg_len
+ cp := alloc(n0 + 8)
+ _dyncpy(g_ccr_type_seg, n0, cp)
// R2 P4 Task 3:IFACE 段同批纳入(D13 的承诺面 = **两段**皆类型表/接口表的纯函数)
- i0 := g_ccr_iface_seg_len;
- ip := alloc(i0 + 8);
- _dyncpy(g_ccr_iface_seg, i0, ip);
+ i0 := g_ccr_iface_seg_len
+ ip := alloc(i0 + 8)
+ _dyncpy(g_ccr_iface_seg, i0, ip)
// 判定历史扰动:跨项判定 + 规范化(向项表追加新项——旧「直接序列化活表」必在此变)
- pa := tt_atom(AK_INT, TI_INT, -1);
- pb := tt_atom(AK_STRING, TI_STR, -1);
- if ty_sub(tt_union(pa, pb), pa) != 0 { println("ct.seg_determinism: perturbation ty_sub != 0"); return 0; }
- if ty_disjoint(pa, pb) != 1 { println("ct.seg_determinism: perturbation ty_disjoint != 1"); return 0; }
- if ty_equiv(tt_union(pa, tt_union(pb, pa)), tt_union(pa, pb)) != 1 {
- println("ct.seg_determinism: perturbation ty_equiv != 1"); return 0;
- }
+ pa := tt_atom(AK_INT, TI_INT, -1)
+ pb := tt_atom(AK_STRING, TI_STR, -1)
+ if ty_sub(tt_union(pa, pb), pa) != 0:
+ println("ct.seg_determinism: perturbation ty_sub != 0")
+ return 0
+ if ty_disjoint(pa, pb) != 1:
+ println("ct.seg_determinism: perturbation ty_disjoint != 1")
+ return 0
+ if ty_equiv(tt_union(pa, tt_union(pb, pa)), tt_union(pa, pb)) != 1:
+ println("ct.seg_determinism: perturbation ty_equiv != 1")
+ return 0
// 唯一标注项(**保证**向项表追加新项——判定扰动可能与既有项同构而零新增,
// 突变控制实证:仅判定扰动的版本对「跳过装填」突变不转红,本项补上该牙)
- uq := tt_atom(AK_DEX, 900001, tt_cons(pa, tt_nil()));
- if tt_tag(uq) != TT_ATOM || tt_b(uq) != 900001 {
- println("ct.seg_determinism: unique-term fixture failed"); return 0;
- }
+ uq := tt_atom(AK_DEX, 900001, tt_cons(pa, tt_nil()))
+ if tt_tag(uq) != TT_ATOM || tt_b(uq) != 900001:
+ println("ct.seg_determinism: unique-term fixture failed")
+ return 0
// 重装填(项层/引擎/桥接复位 → 行序重建)⇒ 段体逐字节同
- if ccr_seg_prepare_save() != 0 { println("ct.seg_determinism: rebuild prepare failed"); return 0; }
- if g_ccr_type_seg_len != n0 {
- print("ct.seg_determinism: buffer length changed "); print(int_str(n0));
- print(" -> "); println(int_str(g_ccr_type_seg_len));
- return 0;
- }
- k : ., mut = 0;
- loop {
- if k >= n0 { break; }
- if load8(g_ccr_type_seg, k) != load8(cp, k) {
- print("ct.seg_determinism: buffer byte mismatch at "); println(int_str(k));
- return 0;
- }
- k = k + 1;
- }
+ if ccr_seg_prepare_save() != 0:
+ println("ct.seg_determinism: rebuild prepare failed")
+ return 0
+ if g_ccr_type_seg_len != n0:
+ print("ct.seg_determinism: buffer length changed ")
+ print(int_str(n0))
+ print(" -> ")
+ println(int_str(g_ccr_type_seg_len))
+ return 0
+ k : ., mut = 0
+ loop:
+ if k >= n0:
+ break
+ if load8(g_ccr_type_seg, k) != load8(cp, k):
+ print("ct.seg_determinism: buffer byte mismatch at ")
+ println(int_str(k))
+ return 0
+ k = k + 1
// IFACE 段同判(R2 P4 Task 3):重装填后逐字节同(形状重注册/签名装填皆纯函数)
- if g_ccr_iface_seg_len != i0 {
- print("ct.seg_determinism: iface buffer length changed "); print(int_str(i0));
- print(" -> "); println(int_str(g_ccr_iface_seg_len));
- return 0;
- }
- k2 : ., mut = 0;
- loop {
- if k2 >= i0 { break; }
- if load8(g_ccr_iface_seg, k2) != load8(ip, k2) {
- print("ct.seg_determinism: iface buffer byte mismatch at "); println(int_str(k2));
- return 0;
- }
- k2 = k2 + 1;
- }
- return 1;
-}
-
-fn ts_ccr_run() -> int {
- fails : ., mut = 0;
- init_types(); // 干净表(9 原生行——不受前段夹具影响)
+ if g_ccr_iface_seg_len != i0:
+ print("ct.seg_determinism: iface buffer length changed ")
+ print(int_str(i0))
+ print(" -> ")
+ println(int_str(g_ccr_iface_seg_len))
+ return 0
+ k2 : ., mut = 0
+ loop:
+ if k2 >= i0:
+ break
+ if load8(g_ccr_iface_seg, k2) != load8(ip, k2):
+ print("ct.seg_determinism: iface buffer byte mismatch at ")
+ println(int_str(k2))
+ return 0
+ k2 = k2 + 1
+ return 1
+
+fn ts_ccr_run() -> int:
+ fails : ., mut = 0
+ init_types() // 干净表(9 原生行——不受前段夹具影响)
// R2 P4 Task 3:接口表同批清零(段体含 IFACE 五小节 ⇒ 上游 ifc/isat 夹具的**死节点**
// (EXPR_IDENT 指向已被 init_types 作废的命名行 ⇒ res_type_node 落 dyn 行)会令签名项
// 不可建 ⇒ 装填拒绝。本组语义 = 「干净类型表 + 干净接口表」的段体往返夹具。
- g_iface_count = 0;
- g_impl_for_count = 0;
- g_method_count = 0;
- iface_shape_reset();
- iface_shape_builtin_init();
- opt_a := alloc_type(TYP_OPTIONAL, TI_INT, 0);
- opt_b := alloc_type(TYP_OPTIONAL, TI_INT, 0);
- arr3 := alloc_type(TYP_ARRAY, TI_INT, 3);
- arr4 := alloc_type(TYP_ARRAY, TI_INT, 4);
- prep := ccr_seg_prepare_save();
- fails = fails + ts_check("ct.seg_prepare", prep, 0);
- if prep == 0 {
- fails = fails + ts_check("ct.seg_roundtrip", ts_ccr_roundtrip_ok(), 1);
- fails = fails + ts_check("ct.seg_dedup_identity", ts_ccr_dedup_ok(opt_a, opt_b, arr3, arr4), 1);
- fails = fails + ts_check("ct.seg_determinism", ts_ccr_purity_ok(), 1);
- } else {
- fails = fails + 3; // 后续三例无法运行 ⇒ 计失败(不得静默少算)
- }
+ g_iface_count = 0
+ g_impl_for_count = 0
+ g_method_count = 0
+ iface_shape_reset()
+ iface_shape_builtin_init()
+ opt_a := alloc_type(TYP_OPTIONAL, TI_INT, 0)
+ opt_b := alloc_type(TYP_OPTIONAL, TI_INT, 0)
+ arr3 := alloc_type(TYP_ARRAY, TI_INT, 3)
+ arr4 := alloc_type(TYP_ARRAY, TI_INT, 4)
+ prep := ccr_seg_prepare_save()
+ fails = fails + ts_check("ct.seg_prepare", prep, 0)
+ if prep == 0:
+ fails = fails + ts_check("ct.seg_roundtrip", ts_ccr_roundtrip_ok(), 1)
+ fails = fails + ts_check("ct.seg_dedup_identity", ts_ccr_dedup_ok(opt_a, opt_b, arr3, arr4), 1)
+ fails = fails + ts_check("ct.seg_determinism", ts_ccr_purity_ok(), 1)
+ else:
+ fails = fails + 3 // 后续三例无法运行 ⇒ 计失败(不得静默少算)
// ④ 不可译行(子行越界)⇒ 装填拒绝(save 拒落盘)——**最后**(污染类型表)
- bad_row := alloc_type(TYP_ARRAY, 999999, 0);
- rej := ccr_type_populate();
- if bad_row < 0 { rej = 1; } // 夹具未建成 ⇒ 不算通过(防假绿)
- fails = fails + ts_check("ct.seg_reject_untranslatable", rej, -1);
- return fails;
-}
+ bad_row := alloc_type(TYP_ARRAY, 999999, 0)
+ rej := ccr_type_populate()
+ if bad_row < 0:
+ rej = 1
+ // 夹具未建成 ⇒ 不算通过(防假绿)
+ fails = fails + ts_check("ct.seg_reject_untranslatable", rej, -1)
+ return fails
// ═══════════ R2 P4 Task 3:IFACE 段内容面(扩列 / 命名化 / 签名项化 / 段体往返)═══════════
// 用例面(7 例):① 段体五小节与内存表逐字段一致 + 行走完 == 缓冲长度(无尾随);
@@ -1455,251 +1481,315 @@ fn ts_ccr_run() -> int {
// 夹具/边界:本组自建**干净接口表**(g_iface_count/g_impl_for_count/g_method_count 清零 +
// 形状表 reset + 生产注册面重跑)——上游 ts_ifc_run 的夹具含 9 形参接口(不可建面),
// 不清零会令装填拒绝(设计如此:populate 不静默跳过)。**必须最后运行**(populate 复位三面缓存)。
-fn ts_ccr2_row_ok(b: string, p: int, i: int) -> int {
- eo := i * ESZ_IFACE_ENTRY;
- if buf_read_i32(b, p) != r64(g_iface_entries, eo + OFF_IE_AK) { return 0; }
- if buf_read_i32(b, p + 4) != r64(g_iface_entries, eo + OFF_IE_TI) { return 0; }
- if buf_read_i32(b, p + 8) != r64(g_iface_entries, eo + OFF_IE_NAME) { return 0; }
- if buf_read_i32(b, p + 12) != r64(g_iface_entries, eo + OFF_IE_LIT) { return 0; }
- if buf_read_i64(b, p + 16) != r64(g_iface_entries, eo + OFF_IE_OPS) { return 0; }
- return 1;
-}
-
-fn ts_ccr2_seg_walk_ok() -> int {
- b := g_ccr_iface_seg;
- n := g_ccr_iface_seg_len;
- if n <= 0 { return 0; }
+fn ts_ccr2_row_ok(b: string, p: int, i: int) -> int:
+ eo := i * ESZ_IFACE_ENTRY
+ if buf_read_i32(b, p) != r64(g_iface_entries, eo + OFF_IE_AK):
+ return 0
+ if buf_read_i32(b, p + 4) != r64(g_iface_entries, eo + OFF_IE_TI):
+ return 0
+ if buf_read_i32(b, p + 8) != r64(g_iface_entries, eo + OFF_IE_NAME):
+ return 0
+ if buf_read_i32(b, p + 12) != r64(g_iface_entries, eo + OFF_IE_LIT):
+ return 0
+ if buf_read_i64(b, p + 16) != r64(g_iface_entries, eo + OFF_IE_OPS):
+ return 0
+ return 1
+
+fn ts_ccr2_seg_walk_ok() -> int:
+ b := g_ccr_iface_seg
+ n := g_ccr_iface_seg_len
+ if n <= 0:
+ return 0
// ① 原生条目(计数 == 常量 == 表计数;逐行 5 字段 == g_iface_entries)
- if buf_read_u32(b, 0) != IFACE_ENTRY_COUNT { return 0; }
- if buf_read_u32(b, 0) != g_iface_entry_count { return 0; }
- p : ., mut = 4;
- ei : ., mut = 0;
- loop {
- if ei >= IFACE_ENTRY_COUNT { break; }
- if ts_ccr2_row_ok(b, p, ei) != 1 { return 0; }
- p = p + 24;
- ei = ei + 1;
- }
+ if buf_read_u32(b, 0) != IFACE_ENTRY_COUNT:
+ return 0
+ if buf_read_u32(b, 0) != g_iface_entry_count:
+ return 0
+ p : ., mut = 4
+ ei : ., mut = 0
+ loop:
+ if ei >= IFACE_ENTRY_COUNT:
+ break
+ if ts_ccr2_row_ok(b, p, ei) != 1:
+ return 0
+ p = p + 24
+ ei = ei + 1
// ② 横切形状
- if buf_read_u32(b, p) != g_iface_shape_count { return 0; }
- p = p + 4;
- si : ., mut = 0;
- loop {
- if si >= g_iface_shape_count { break; }
- if buf_read_i32(b, p) != r64(g_iface_shape_names, si * 8) { return 0; }
- if buf_read_i32(b, p + 4) != r64(g_iface_shape_terms, si * 8) { return 0; }
- p = p + 8;
- si = si + 1;
- }
+ if buf_read_u32(b, p) != g_iface_shape_count:
+ return 0
+ p = p + 4
+ si : ., mut = 0
+ loop:
+ if si >= g_iface_shape_count:
+ break
+ if buf_read_i32(b, p) != r64(g_iface_shape_names, si * 8):
+ return 0
+ if buf_read_i32(b, p + 4) != r64(g_iface_shape_terms, si * 8):
+ return 0
+ p = p + 8
+ si = si + 1
// ③ 用户接口(头 16B + 方法 80B:项槽先于裸码槽——实施取声明行序,见 ccr_types.cr 头注)
- if buf_read_u32(b, p) != g_iface_count { return 0; }
- p = p + 4;
- fi : ., mut = 0;
- loop {
- if fi >= g_iface_count { break; }
- fo := fi * ESZ_IFACEINFO;
- mc := r64(g_ifaces, fo + OFF_IF_METHOD_COUNT);
- if buf_read_i32(b, p) != r64(g_ifaces, fo + OFF_IF_NAME) { return 0; }
- if buf_read_i32(b, p + 4) != mc { return 0; }
- if buf_read_i32(b, p + 8) != r64(g_ifaces, fo + OFF_IF_GENERIC_COUNT) { return 0; }
- p = p + 16;
- mj : ., mut = 0;
- loop {
- if mj >= mc { break; }
- mo := fo + OFF_IF_METHODS + mj * ESZ_IFMETHOD;
- if buf_read_i32(b, p) != r64(g_ifaces, mo + OFF_IFM_NAME) { return 0; }
- if buf_read_i32(b, p + 4) != r64(g_ifaces, mo + OFF_IFM_PARAM_COUNT) { return 0; }
- if buf_read_i32(b, p + 8) != r64(g_ifaces, mo + OFF_IFM_SELF_MODE) { return 0; }
- if buf_read_i32(b, p + 12) != r64(g_ifaces, mo + OFF_IFM_RET_TERM) { return 0; }
- p = p + 16;
- kq : ., mut = 0;
- loop {
- if kq >= MAX_IFACE_METHOD_PARAMS { break; }
- if buf_read_i32(b, p) != r64(g_ifaces, mo + OFF_IFM_PARAM_TERMS + kq * 8) { return 0; }
- p = p + 4;
- kq = kq + 1;
- }
- qq : ., mut = 0;
- loop {
- if qq >= MAX_IFACE_METHOD_PARAMS { break; }
- if buf_read_i32(b, p) != r64(g_ifaces, mo + OFF_IFM_PARAM_TYPES + qq * 8) { return 0; }
- p = p + 4;
- qq = qq + 1;
- }
- mj = mj + 1;
- }
- fi = fi + 1;
- }
+ if buf_read_u32(b, p) != g_iface_count:
+ return 0
+ p = p + 4
+ fi : ., mut = 0
+ loop:
+ if fi >= g_iface_count:
+ break
+ fo := fi * ESZ_IFACEINFO
+ mc := r64(g_ifaces, fo + OFF_IF_METHOD_COUNT)
+ if buf_read_i32(b, p) != r64(g_ifaces, fo + OFF_IF_NAME):
+ return 0
+ if buf_read_i32(b, p + 4) != mc:
+ return 0
+ if buf_read_i32(b, p + 8) != r64(g_ifaces, fo + OFF_IF_GENERIC_COUNT):
+ return 0
+ p = p + 16
+ mj : ., mut = 0
+ loop:
+ if mj >= mc:
+ break
+ mo := fo + OFF_IF_METHODS + mj * ESZ_IFMETHOD
+ if buf_read_i32(b, p) != r64(g_ifaces, mo + OFF_IFM_NAME):
+ return 0
+ if buf_read_i32(b, p + 4) != r64(g_ifaces, mo + OFF_IFM_PARAM_COUNT):
+ return 0
+ if buf_read_i32(b, p + 8) != r64(g_ifaces, mo + OFF_IFM_SELF_MODE):
+ return 0
+ if buf_read_i32(b, p + 12) != r64(g_ifaces, mo + OFF_IFM_RET_TERM):
+ return 0
+ p = p + 16
+ kq : ., mut = 0
+ loop:
+ if kq >= MAX_IFACE_METHOD_PARAMS:
+ break
+ if buf_read_i32(b, p) != r64(g_ifaces, mo + OFF_IFM_PARAM_TERMS + kq * 8):
+ return 0
+ p = p + 4
+ kq = kq + 1
+ qq : ., mut = 0
+ loop:
+ if qq >= MAX_IFACE_METHOD_PARAMS:
+ break
+ if buf_read_i32(b, p) != r64(g_ifaces, mo + OFF_IFM_PARAM_TYPES + qq * 8):
+ return 0
+ p = p + 4
+ qq = qq + 1
+ mj = mj + 1
+ fi = fi + 1
// ④ impl 边
- if buf_read_u32(b, p) != g_impl_for_count { return 0; }
- p = p + 4;
- gi : ., mut = 0;
- loop {
- if gi >= g_impl_for_count { break; }
- if buf_read_i32(b, p) != r64(g_impl_for, gi * 16) { return 0; }
- if buf_read_i32(b, p + 4) != r64(g_impl_for, gi * 16 + 8) { return 0; }
- p = p + 8;
- gi = gi + 1;
- }
+ if buf_read_u32(b, p) != g_impl_for_count:
+ return 0
+ p = p + 4
+ gi : ., mut = 0
+ loop:
+ if gi >= g_impl_for_count:
+ break
+ if buf_read_i32(b, p) != r64(g_impl_for, gi * 16):
+ return 0
+ if buf_read_i32(b, p + 4) != r64(g_impl_for, gi * 16 + 8):
+ return 0
+ p = p + 8
+ gi = gi + 1
// ⑤ 方法表
- if buf_read_u32(b, p) != g_method_count { return 0; }
- p = p + 4;
- mi : ., mut = 0;
- loop {
- if mi >= g_method_count { break; }
- if buf_read_i32(b, p) != r64(g_methods, mi * 24) { return 0; }
- if buf_read_i32(b, p + 4) != r64(g_methods, mi * 24 + 8) { return 0; }
- if buf_read_i32(b, p + 8) != r64(g_methods, mi * 24 + 16) { return 0; }
- p = p + 12;
- mi = mi + 1;
- }
- if p != n { return 0; } // 行走完 == 缓冲长度(五小节自洽 + 无尾随字节)
- return 1;
-}
-
-fn ts_ccr2_sig_slots_ok() -> int {
- ii : ., mut = 0;
- loop {
- if ii >= g_iface_count { break; }
- mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT);
- mi : ., mut = 0;
- loop {
- if mi >= mc { break; }
- mo := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD;
+ if buf_read_u32(b, p) != g_method_count:
+ return 0
+ p = p + 4
+ mi : ., mut = 0
+ loop:
+ if mi >= g_method_count:
+ break
+ if buf_read_i32(b, p) != r64(g_methods, mi * 24):
+ return 0
+ if buf_read_i32(b, p + 4) != r64(g_methods, mi * 24 + 8):
+ return 0
+ if buf_read_i32(b, p + 8) != r64(g_methods, mi * 24 + 16):
+ return 0
+ p = p + 12
+ mi = mi + 1
+ if p != n:
+ return 0
+ // 行走完 == 缓冲长度(五小节自洽 + 无尾随字节)
+ return 1
+
+fn ts_ccr2_sig_slots_ok() -> int:
+ ii : ., mut = 0
+ loop:
+ if ii >= g_iface_count:
+ break
+ mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT)
+ mi : ., mut = 0
+ loop:
+ if mi >= mc:
+ break
+ mo := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD
// 返回槽 == 活算(签名的唯一来源 = sh_iface_sig_ret_term)
- if r64(g_ifaces, mo + OFF_IFM_RET_TERM) != sh_iface_sig_ret_term(ii, mi) { return 0; }
- pc := r64(g_ifaces, mo + OFF_IFM_PARAM_COUNT);
- pj : ., mut = 0;
- loop {
- if pj >= MAX_IFACE_METHOD_PARAMS { break; }
- if pj < pc {
- if r64(g_ifaces, mo + OFF_IFM_PARAM_TERMS + pj * 8) != sh_iface_sig_param_term(ii, mi, pj) { return 0; }
- } else {
- if r64(g_ifaces, mo + OFF_IFM_PARAM_TERMS + pj * 8) != -1 { return 0; } // 未用槽 = -1
- }
- pj = pj + 1;
- }
- mi = mi + 1;
- }
- ii = ii + 1;
- }
- return 1;
-}
-
-fn ts_ccr2_shape_names_ok() -> int {
+ if r64(g_ifaces, mo + OFF_IFM_RET_TERM) != sh_iface_sig_ret_term(ii, mi):
+ return 0
+ pc := r64(g_ifaces, mo + OFF_IFM_PARAM_COUNT)
+ pj : ., mut = 0
+ loop:
+ if pj >= MAX_IFACE_METHOD_PARAMS:
+ break
+ if pj < pc:
+ if r64(g_ifaces, mo + OFF_IFM_PARAM_TERMS + pj * 8) != sh_iface_sig_param_term(ii, mi, pj):
+ return 0
+ else:
+ if r64(g_ifaces, mo + OFF_IFM_PARAM_TERMS + pj * 8) != -1:
+ return 0
+ // 未用槽 = -1
+ pj = pj + 1
+ mi = mi + 1
+ ii = ii + 1
+ return 1
+
+fn ts_ccr2_shape_names_ok() -> int:
// 六生产名可查 + 与构造点**同项**(节点同一——形状项 = 唯一数据面)
- if iface_shape_count() < 6 { return 0; }
- if iface_shape_lookup(str_intern("sequence")) != sh_shape_seq() { return 0; }
- if iface_shape_lookup(str_intern("sequence_ro")) != sh_shape_seq_ro() { return 0; }
- if iface_shape_lookup(str_intern("sequence_rw")) != sh_shape_seq_rw() { return 0; }
- if iface_shape_lookup(str_intern("indexable")) != sh_shape_indexable() { return 0; }
- if iface_shape_lookup(str_intern("iterable")) != sh_shape_iterable() { return 0; }
- if iface_shape_lookup(str_intern("product")) != sh_shape_product() { return 0; }
- return 1;
-}
-
-fn ts_ccr2_entries_ok() -> int {
+ if iface_shape_count() < 6:
+ return 0
+ if iface_shape_lookup(str_intern("sequence")) != sh_shape_seq():
+ return 0
+ if iface_shape_lookup(str_intern("sequence_ro")) != sh_shape_seq_ro():
+ return 0
+ if iface_shape_lookup(str_intern("sequence_rw")) != sh_shape_seq_rw():
+ return 0
+ if iface_shape_lookup(str_intern("indexable")) != sh_shape_indexable():
+ return 0
+ if iface_shape_lookup(str_intern("iterable")) != sh_shape_iterable():
+ return 0
+ if iface_shape_lookup(str_intern("product")) != sh_shape_product():
+ return 0
+ return 1
+
+fn ts_ccr2_entries_ok() -> int:
// 扩列 13 → 16:三新行可查 + ops = 0(纯信息面)+ 16 行逐名(注册面固定增量)
- if iface_count() != 16 { return 0; }
- if iface_entry(AK_NULL) < 0 { return 0; }
- if iface_entry(AK_SUM) < 0 { return 0; }
- if iface_entry(AK_FN) < 0 { return 0; }
- if iface_ops(AK_NULL) != 0 { return 0; }
- if iface_ops(AK_SUM) != 0 { return 0; }
- if iface_ops(AK_FN) != 0 { return 0; }
- if iface_ti_of(AK_NULL) != -1 { return 0; } // 无规范行(类级)
- if iface_ti_of(AK_SUM) != -1 { return 0; }
- if iface_ti_of(AK_FN) != -1 { return 0; }
+ if iface_count() != 16:
+ return 0
+ if iface_entry(AK_NULL) < 0:
+ return 0
+ if iface_entry(AK_SUM) < 0:
+ return 0
+ if iface_entry(AK_FN) < 0:
+ return 0
+ if iface_ops(AK_NULL) != 0:
+ return 0
+ if iface_ops(AK_SUM) != 0:
+ return 0
+ if iface_ops(AK_FN) != 0:
+ return 0
+ if iface_ti_of(AK_NULL) != -1:
+ return 0
+ // 无规范行(类级)
+ if iface_ti_of(AK_SUM) != -1:
+ return 0
+ if iface_ti_of(AK_FN) != -1:
+ return 0
// 逐名(16 行:8 原生 + 5 结构/命名 + 3 新行)
- if iface_name_of(AK_INT) != str_intern("int") { return 0; }
- if iface_name_of(AK_DEX) != str_intern("dex") { return 0; }
- if iface_name_of(AK_STRING) != str_intern("string") { return 0; }
- if iface_name_of(AK_BOOL) != str_intern("bool") { return 0; }
- if iface_name_of(AK_UNIT) != str_intern("unit") { return 0; }
- if iface_name_of(AK_NEVER) != str_intern("never") { return 0; }
- if iface_name_of(AK_CHAR) != str_intern("char") { return 0; }
- if iface_name_of(AK_DYN) != str_intern("dyn") { return 0; }
- if iface_name_of(AK_PRODUCT) != str_intern("product") { return 0; }
- if iface_name_of(AK_SEQUENCE) != str_intern("sequence") { return 0; }
- if iface_name_of(AK_REF) != str_intern("ref") { return 0; }
- if iface_name_of(AK_PTR) != str_intern("ptr") { return 0; }
- if iface_name_of(AK_NAMED) != str_intern("named") { return 0; }
- if iface_name_of(AK_NULL) != str_intern("null") { return 0; }
- if iface_name_of(AK_SUM) != str_intern("sum") { return 0; }
- if iface_name_of(AK_FN) != str_intern("fn") { return 0; }
- if iface_name_of(-1) != -1 { return 0; } // 负键守卫(不得与行 0 混同)
- if iface_name_of(9999) != -1 { return 0; }
- return 1;
-}
-
-fn ts_ccr2_kind_domain_ok() -> int {
+ if iface_name_of(AK_INT) != str_intern("int"):
+ return 0
+ if iface_name_of(AK_DEX) != str_intern("dex"):
+ return 0
+ if iface_name_of(AK_STRING) != str_intern("string"):
+ return 0
+ if iface_name_of(AK_BOOL) != str_intern("bool"):
+ return 0
+ if iface_name_of(AK_UNIT) != str_intern("unit"):
+ return 0
+ if iface_name_of(AK_NEVER) != str_intern("never"):
+ return 0
+ if iface_name_of(AK_CHAR) != str_intern("char"):
+ return 0
+ if iface_name_of(AK_DYN) != str_intern("dyn"):
+ return 0
+ if iface_name_of(AK_PRODUCT) != str_intern("product"):
+ return 0
+ if iface_name_of(AK_SEQUENCE) != str_intern("sequence"):
+ return 0
+ if iface_name_of(AK_REF) != str_intern("ref"):
+ return 0
+ if iface_name_of(AK_PTR) != str_intern("ptr"):
+ return 0
+ if iface_name_of(AK_NAMED) != str_intern("named"):
+ return 0
+ if iface_name_of(AK_NULL) != str_intern("null"):
+ return 0
+ if iface_name_of(AK_SUM) != str_intern("sum"):
+ return 0
+ if iface_name_of(AK_FN) != str_intern("fn"):
+ return 0
+ if iface_name_of(-1) != -1:
+ return 0
+ // 负键守卫(不得与行 0 混同)
+ if iface_name_of(9999) != -1:
+ return 0
+ return 1
+
+fn ts_ccr2_kind_domain_ok() -> int:
// 判定面零变化(扩列只加「可查询性」):全类型行枚举——三新原子不得被任何行命中
// (若未来给某行新映射到 AK_NULL/AK_SUM/AK_FN,本用例转红 = 有意的闸)
- i : ., mut = 0;
- loop {
- if i >= g_type_count { break; }
- k := iface_kind_of(i);
- if k == AK_NULL || k == AK_SUM || k == AK_FN { return 0; }
- i = i + 1;
- }
- return 1;
-}
-
-fn ts_ccr2_run() -> int {
- fails : ., mut = 0;
+ i : ., mut = 0
+ loop:
+ if i >= g_type_count:
+ break
+ k := iface_kind_of(i)
+ if k == AK_NULL || k == AK_SUM || k == AK_FN:
+ return 0
+ i = i + 1
+ return 1
+
+fn ts_ccr2_run() -> int:
+ fails : ., mut = 0
// 生产重置路径的接线钉(先于夹具):`reset_frontend_state` 清形状表 count +
// `check_all` 首行的 init_types ⇒ 六名重建——**不经**显式 iface_shape_builtin_init
// (本断言 = 「init_types 尾部调用」的牙;若该调用缺失/被挪走 ⇒ 本条转红)。
- iface_shape_reset();
- init_types(); // 干净类型表(9 原生行)+ 生产形状注册面
+ iface_shape_reset()
+ init_types() // 干净类型表(9 原生行)+ 生产形状注册面
fails = fails + ts_check_b("ct2.shape_face_from_init_types",
(iface_shape_count() == 6 &&
- iface_shape_lookup(str_intern("sequence")) == sh_shape_seq() &&
- iface_shape_lookup(str_intern("product")) == sh_shape_product()), true);
- g_iface_count = 0; // 干净接口表(上游 ts_ifc_run 夹具含不可建面——不清零即拒装填)
- g_impl_for_count = 0;
- g_method_count = 0;
- iface_shape_reset();
- iface_shape_builtin_init(); // 生产注册面(6 名)——populate 会重跑(幂等)
+ iface_shape_lookup(str_intern("sequence")) == sh_shape_seq() &&
+ iface_shape_lookup(str_intern("product")) == sh_shape_product()), true)
+ g_iface_count = 0 // 干净接口表(上游 ts_ifc_run 夹具含不可建面——不清零即拒装填)
+ g_impl_for_count = 0
+ g_method_count = 0
+ iface_shape_reset()
+ iface_shape_builtin_init() // 生产注册面(6 名)——populate 会重跑(幂等)
// 夹具:命名行 + null/可选行(判定面显式钉)+ 1 接口(self 接收者 + 命名型形参)
// + impl 边 + 方法表(生产写点同形:parser 的 interface/impl 分支)
- ts_ifc_mk_named("Ct2Named");
- ct2_null := alloc_type(TYP_NULL, 0, 0);
- ct2_opt := alloc_type(TYP_OPTIONAL, TI_INT, 0);
- ct2_n := ts_ifc_named_node("Ct2Named");
- ct2_int_n := ts_ifc_base_node(TY_INT);
- ct2_ii := ts_t5_mk_iface("Ct2Iface");
- ts_ifc_add_method_n(ct2_ii, "a", 1, 1, -1, -1, -1, -1, ct2_int_n); // fn a(self) -> int
- ts_ifc_add_method_n(ct2_ii, "b", 1, 0, ct2_n, -1, -1, -1, ct2_int_n); // fn b(x: Ct2Named) -> int
- grow_impl_for(1);
- w64(g_impl_for, 0, str_intern("Ct2Iface"));
- w64(g_impl_for, 8, str_intern("Ct2Named"));
- g_impl_for_count = 1;
- grow_methods(1);
- w64(g_methods, 0, str_intern("Ct2Named"));
- w64(g_methods, 8, str_intern("b"));
- w64(g_methods, 16, str_intern("Ct2Named.b"));
- g_method_count = 1;
- prep := ccr_seg_prepare_save();
- fails = fails + ts_check("ct2.seg_prepare", prep, 0);
- if prep == 0 {
- fails = fails + ts_check("ct2.iface_seg_walk", ts_ccr2_seg_walk_ok(), 1);
- fails = fails + ts_check("ct2.iface_sig_slots", ts_ccr2_sig_slots_ok(), 1);
- fails = fails + ts_check("ct2.shape_names_production", ts_ccr2_shape_names_ok(), 1);
- } else {
- fails = fails + 3; // 后续三例无法运行 ⇒ 计失败(不得静默少算)
- }
- fails = fails + ts_check("ct2.entry_table_16_named", ts_ccr2_entries_ok(), 1);
+ ts_ifc_mk_named("Ct2Named")
+ ct2_null := alloc_type(TYP_NULL, 0, 0)
+ ct2_opt := alloc_type(TYP_OPTIONAL, TI_INT, 0)
+ ct2_n := ts_ifc_named_node("Ct2Named")
+ ct2_int_n := ts_ifc_base_node(TY_INT)
+ ct2_ii := ts_t5_mk_iface("Ct2Iface")
+ ts_ifc_add_method_n(ct2_ii, "a", 1, 1, -1, -1, -1, -1, ct2_int_n) // fn a(self) -> int
+ ts_ifc_add_method_n(ct2_ii, "b", 1, 0, ct2_n, -1, -1, -1, ct2_int_n) // fn b(x: Ct2Named) -> int
+ grow_impl_for(1)
+ w64(g_impl_for, 0, str_intern("Ct2Iface"))
+ w64(g_impl_for, 8, str_intern("Ct2Named"))
+ g_impl_for_count = 1
+ grow_methods(1)
+ w64(g_methods, 0, str_intern("Ct2Named"))
+ w64(g_methods, 8, str_intern("b"))
+ w64(g_methods, 16, str_intern("Ct2Named.b"))
+ g_method_count = 1
+ prep := ccr_seg_prepare_save()
+ fails = fails + ts_check("ct2.seg_prepare", prep, 0)
+ if prep == 0:
+ fails = fails + ts_check("ct2.iface_seg_walk", ts_ccr2_seg_walk_ok(), 1)
+ fails = fails + ts_check("ct2.iface_sig_slots", ts_ccr2_sig_slots_ok(), 1)
+ fails = fails + ts_check("ct2.shape_names_production", ts_ccr2_shape_names_ok(), 1)
+ else:
+ fails = fails + 3 // 后续三例无法运行 ⇒ 计失败(不得静默少算)
+ fails = fails + ts_check("ct2.entry_table_16_named", ts_ccr2_entries_ok(), 1)
fails = fails + ts_check_b("ct2.kind_of_no_new_mapping",
- (ts_ccr2_kind_domain_ok() == 1 && iface_kind_of(ct2_null) == -1 && iface_kind_of(ct2_opt) == -1), true);
+ (ts_ccr2_kind_domain_ok() == 1 && iface_kind_of(ct2_null) == -1 && iface_kind_of(ct2_opt) == -1), true)
// ⑥ 不可建签名(dyn 位图行入签名:sh_sig_term_of_ti 对 TYP_DYN 回 -1)⇒ 装填拒绝
// (save 拒落盘——三态纪律:不得把缺项签名静默写成 -1 落盘)——**最后**(污染接口表)
- ct2_dyn_n := ts_ifc_base_node(TI_DYN); // parser 对 `dyn` 正产 type_val = TI_DYN
- ts_ifc_add_method_n(ct2_ii, "c", 0, 0, -1, -1, -1, -1, ct2_dyn_n);
- rej2 := ccr_iface_populate();
- fails = fails + ts_check("ct2.reject_unbuildable_sig", rej2, -1);
- return fails;
-}
+ ct2_dyn_n := ts_ifc_base_node(TI_DYN) // parser 对 `dyn` 正产 type_val = TI_DYN
+ ts_ifc_add_method_n(ct2_ii, "c", 0, 0, -1, -1, -1, -1, ct2_dyn_n)
+ rej2 := ccr_iface_populate()
+ fails = fails + ts_check("ct2.reject_unbuildable_sig", rej2, -1)
+ return fails
// ═══════════ R2 P6 Task 2(E-10):¬ 面同类原子身份判据的邻域覆盖(9 例)═══════════
// 牙齿分工(计划 Task 2 Step 4 的四向 + 本批补钉):
@@ -1717,266 +1807,323 @@ fn ts_ccr2_run() -> int {
// 夹具 = 纯合成(`str_intern` + `sh_name_token` + `tt_atom/tt_cons/tt_nil/tt_union`)⇒ 不依赖
// g_types / `sh_term_of_ti` / `init_types()`(与调用序列中其它段解耦)。
// 用例数 = **11**(调用方 `total = total + 11` 须同步——增删用例两处一起改)。
-fn ts_t2_neg_run() -> int {
- fails : ., mut = 0;
- e1 := str_intern("T2NegE1");
- v1 := str_intern("T2NegV1");
- v2 := str_intern("T2NegV2");
- e2 := str_intern("T2NegE2");
- sum_11 := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v1), tt_nil())));
- sum_21 := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e2), tt_cons(sh_name_token(v1), tt_nil())));
- i_atom := tt_atom(AK_INT, TI_INT, -1);
- s_atom := tt_atom(AK_STRING, TI_STR, -1);
+fn ts_t2_neg_run() -> int:
+ fails : ., mut = 0
+ e1 := str_intern("T2NegE1")
+ v1 := str_intern("T2NegV1")
+ v2 := str_intern("T2NegV2")
+ e2 := str_intern("T2NegE2")
+ sum_11 := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v1), tt_nil())))
+ sum_21 := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e2), tt_cons(sh_name_token(v1), tt_nil())))
+ i_atom := tt_atom(AK_INT, TI_INT, -1)
+ s_atom := tt_atom(AK_STRING, TI_STR, -1)
// ① 同身份(同枚举同变体,两处构造 ⇒ DAG 去重同节点)⇒ lp ⊆ ¬x 不成立 ⇒ 0
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_same_identity_not_disjoint",
- ts_isat_b2i(ty_sub(sum_11, tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(ty_sub(sum_11, tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1)
// ② μ 变元作字面(无原子类)⇒ -1 + 未覆盖面(既有域外路径,不受本批改动影响)
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_var_literal_stays_minus1",
- ts_isat_b2i(ty_sub(tt_var(0), tt_not(sum_11)) == -1 && ty_uncovered() == 1), 1);
+ ts_isat_b2i(ty_sub(tt_var(0), tt_not(sum_11)) == -1 && ty_uncovered() == 1), 1)
// ③ ⊤ₖ 在左:类顶 ⊆ ¬原子 ⇒ 假(类顶含该类全部值)⇒ 0
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_topk_left_unchanged",
- ts_isat_b2i(ty_sub(tt_top_k(AK_SUM), tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(ty_sub(tt_top_k(AK_SUM), tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1)
// ④ ⊤ₖ 在右:原子 ⊆ ¬类顶 ⇒ 假 ⇒ 0
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_topk_right_unchanged",
- ts_isat_b2i(ty_sub(sum_11, tt_not(tt_top_k(AK_SUM))) == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(ty_sub(sum_11, tt_not(tt_top_k(AK_SUM))) == 0 && ty_uncovered() == 0), 1)
// ⑤ 跨枚举同名变体:链首令牌(枚举名)不同 ⇒ 异身份 ⇒ 1;同项 ⇒ 0(不得混同)
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_cross_enum_same_name",
ts_isat_b2i(ty_sub(sum_21, tt_not(sum_11)) == 1 && ty_sub(sum_11, tt_not(sum_21)) == 1 &&
- ty_sub(sum_11, tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1);
+ ty_sub(sum_11, tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1)
// ⑩ **同枚举异变体**(本批暴露首版实现缺陷的那条):AK_SUM 槽 1 = **变体令牌**,而
// `te_chain_cmp` 的槽 ≥1 走**实参位规则**(`te_arg_cmp → ty_equiv`)⇒ 两个不同令牌
// 结构判等(b 槽只是标注)⇒ 误判「同链」。本判据走**逐元素令牌同一性** ⇒ 1。
// (三例 `t3.*_over_claim` 与该例同族:同枚举 T3Color 的 T3Blue vs T3Red。)
- sum_12b := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v2), tt_nil())));
- ty_budget_reset(200000);
+ sum_12b := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(sh_name_token(v2), tt_nil())))
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_same_enum_diff_variant",
ts_isat_b2i(ty_sub(sum_12b, tt_not(sum_11)) == 1 && ty_sub(sum_11, tt_not(sum_12b)) == 1 &&
- ty_sub(sum_11, tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1);
+ ty_sub(sum_11, tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1)
// ⑥ AK_UNIT 类令牌字面(非 AK_SUM)⇒ 类域外 ⇒ 维持 0
- ty_budget_reset(200000);
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_token_literal_not_identity_face",
- ts_isat_b2i(ty_sub(sh_name_token(v1), tt_not(sh_name_token(v2))) == 0 && ty_uncovered() == 0), 1);
+ ts_isat_b2i(ty_sub(sh_name_token(v1), tt_not(sh_name_token(v2))) == 0 && ty_uncovered() == 0), 1)
// ⑦ AK_NAMED ⇒ 维持 -1 + 未覆盖面(P0 Important B / named.not_disjoint 在册;本批不动)
- ty_budget_reset(200000);
- named_nc := tt_atom(AK_NAMED, 7, -1);
+ ty_budget_reset(200000)
+ named_nc := tt_atom(AK_NAMED, 7, -1)
fails = fails + ts_check("t2.neg_named_stays_minus1",
- ts_isat_b2i(ty_sub(named_nc, tt_not(sum_11)) == -1 && ty_uncovered() == 1), 1);
+ ts_isat_b2i(ty_sub(named_nc, tt_not(sum_11)) == -1 && ty_uncovered() == 1), 1)
// ⑧ 身份链不可判的手造畸形项 ⇒ 维持 0(P1-a 钉;两条断言分别钉两个守卫:
// 空链(无身份)与链元素域外(非令牌)——无守卫时都会落成 d == 0 ⇒ 误判「异身份」⇒ 1)
- ty_budget_reset(200000);
- mu_chain := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(tt_var(0), tt_nil())));
- empty_chain := tt_atom(AK_SUM, -1, -1);
+ ty_budget_reset(200000)
+ mu_chain := tt_atom(AK_SUM, -1, tt_cons(sh_name_token(e1), tt_cons(tt_var(0), tt_nil())))
+ empty_chain := tt_atom(AK_SUM, -1, -1)
fails = fails + ts_check("t2.neg_chain_elem_out_of_domain_pin",
ts_isat_b2i(ty_sub(empty_chain, tt_not(sum_11)) == 0 &&
- ty_sub(mu_chain, tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1);
+ ty_sub(mu_chain, tt_not(sum_11)) == 0 && ty_uncovered() == 0), 1)
// ⑪ AK_REF 的 **mut 标记位是令牌**(`sh_ref_mut_marker`)⇒ 链形与 AK_SUM 同族(元素皆令牌)
// ⇒ **类域守卫的稳定牙齿**:无守卫时 `&int` vs `&mut int` 在槽 0 令牌异节点 ⇒ 误判
// 「异身份」⇒ 1 = **假不交**(D4 的 REF 面;语义上两者值集关系未建模,保守回 0)。
- ref_r := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(i_atom, tt_nil())));
- ref_m := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(i_atom, tt_nil())));
- ty_budget_reset(200000);
+ ref_r := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(i_atom, tt_nil())))
+ ref_m := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(i_atom, tt_nil())))
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_ref_mut_marker_face_stays_zero",
ts_isat_b2i(ty_sub(ref_r, tt_not(ref_m)) == 0 && ty_sub(ref_m, tt_not(ref_r)) == 0 &&
- ty_uncovered() == 0), 1);
+ ty_uncovered() == 0), 1)
// ⑨ 参数化构造子(D4):`[int]` vs ¬`[int ∪ string]` 双向 ⇒ 0 —— 类域守卫的稳定牙齿
// (无守卫时元素项不同 ⇒ te_chain_cmp 回 0 ⇒ 误判 1 = 假不交;语义上 `[int] ⊆ [int∪string]`)
- seq_i := tt_atom(AK_SEQUENCE, -1, tt_cons(i_atom, tt_nil()));
- seq_u := tt_atom(AK_SEQUENCE, -1, tt_cons(tt_union(i_atom, s_atom), tt_nil()));
- ty_budget_reset(200000);
+ seq_i := tt_atom(AK_SEQUENCE, -1, tt_cons(i_atom, tt_nil()))
+ seq_u := tt_atom(AK_SEQUENCE, -1, tt_cons(tt_union(i_atom, s_atom), tt_nil()))
+ ty_budget_reset(200000)
fails = fails + ts_check("t2.neg_param_face_stays_zero",
ts_isat_b2i(ty_sub(seq_i, tt_not(seq_u)) == 0 && ty_sub(seq_u, tt_not(seq_i)) == 0 &&
- ty_uncovered() == 0), 1);
- return fails;
-}
+ ty_uncovered() == 0), 1)
+ return fails
-fn type_selftest_run() -> int {
- fails : ., mut = 0;
- total : ., mut = 0;
+fn type_selftest_run() -> int:
+ fails : ., mut = 0
+ total : ., mut = 0
// --- P0 最小用例 ---
- a_int := tt_atom(AK_INT, TI_INT, -1);
- a_str := tt_atom(AK_STRING, TI_STR, -1);
- a_bool := tt_atom(AK_BOOL, TI_BOOL, -1);
+ a_int := tt_atom(AK_INT, TI_INT, -1)
+ a_str := tt_atom(AK_STRING, TI_STR, -1)
+ a_bool := tt_atom(AK_BOOL, TI_BOOL, -1)
- total = total + 1; fails = fails + ts_check("unit.bot_sub_int", ty_sub(tt_bot(), a_int), 1);
- total = total + 1; fails = fails + ts_check("unit.int_sub_str", ty_sub(a_int, a_str), 0);
- total = total + 1; fails = fails + ts_check("unit.int_sub_int", ty_sub(a_int, a_int), 1);
- total = total + 1; fails = fails + ts_check_b("unit.dedup", (tt_union(a_int, a_str) == tt_union(a_int, a_str)), true);
- total = total + 1; fails = fails + ts_check_b("unit.notnot", (tt_not(tt_not(a_int)) == a_int), true);
+ total = total + 1
+ fails = fails + ts_check("unit.bot_sub_int", ty_sub(tt_bot(), a_int), 1)
+ total = total + 1
+ fails = fails + ts_check("unit.int_sub_str", ty_sub(a_int, a_str), 0)
+ total = total + 1
+ fails = fails + ts_check("unit.int_sub_int", ty_sub(a_int, a_int), 1)
+ total = total + 1
+ fails = fails + ts_check_b("unit.dedup", (tt_union(a_int, a_str) == tt_union(a_int, a_str)), true)
+ total = total + 1
+ fails = fails + ts_check_b("unit.notnot", (tt_not(tt_not(a_int)) == a_int), true)
// --- 规范化(Task 2):De Morgan / 否定下推 / 分配律 / 幂等 ---
// 探针:(int ∪ string) ∩ bool —— 分配律必须把它展成 union(两层分配)
- probe := tt_inter(tt_union(a_int, a_str), a_bool);
- total = total + 1; fails = fails + ts_check_b("norm.demorgan",
- (tt_norm(tt_not(tt_union(a_int, a_str))) == tt_norm(tt_inter(tt_not(a_int), tt_not(a_str)))), true);
- total = total + 1; fails = fails + ts_check("norm.nnf_neg_push",
- tt_tag(tt_norm(tt_not(tt_union(a_int, a_str)))), TT_INTER);
- total = total + 1; fails = fails + ts_check("norm.dnf_shape", tt_is_dnf(tt_norm(probe)), 1);
- total = total + 1; fails = fails + ts_check("norm.distributed", tt_tag(tt_norm(probe)), TT_UNION);
- total = total + 1; fails = fails + ts_check_b("norm.idempotent",
- (tt_norm(tt_norm(probe)) == tt_norm(probe)), true);
+ probe := tt_inter(tt_union(a_int, a_str), a_bool)
+ total = total + 1
+ fails = fails + ts_check_b("norm.demorgan",
+ (tt_norm(tt_not(tt_union(a_int, a_str))) == tt_norm(tt_inter(tt_not(a_int), tt_not(a_str)))), true)
+ total = total + 1
+ fails = fails + ts_check("norm.nnf_neg_push",
+ tt_tag(tt_norm(tt_not(tt_union(a_int, a_str)))), TT_INTER)
+ total = total + 1
+ fails = fails + ts_check("norm.dnf_shape", tt_is_dnf(tt_norm(probe)), 1)
+ total = total + 1
+ fails = fails + ts_check("norm.distributed", tt_tag(tt_norm(probe)), TT_UNION)
+ total = total + 1
+ fails = fails + ts_check_b("norm.idempotent",
+ (tt_norm(tt_norm(probe)) == tt_norm(probe)), true)
// --- 判定(Task 3):子类型 / 等价 / 不相交 / 可空 / ⊤ₖ / 预算三态 ---
- u_is := tt_union(a_int, a_str);
- total = total + 1; fails = fails + ts_check("sub.union_right", ty_sub(a_int, u_is), 1);
- total = total + 1; fails = fails + ts_check("sub.union_left_neg", ty_sub(u_is, a_int), 0);
- total = total + 1; fails = fails + ts_check("sub.inter", ty_sub(tt_inter(a_int, a_str), a_int), 1);
+ u_is := tt_union(a_int, a_str)
+ total = total + 1
+ fails = fails + ts_check("sub.union_right", ty_sub(a_int, u_is), 1)
+ total = total + 1
+ fails = fails + ts_check("sub.union_left_neg", ty_sub(u_is, a_int), 0)
+ total = total + 1
+ fails = fails + ts_check("sub.inter", ty_sub(tt_inter(a_int, a_str), a_int), 1)
// 非平凡吸收:int ∪ (str ∪ int) ≡ int ∪ str(需引擎判定,非构造律)
- total = total + 1; fails = fails + ts_check("equiv.absorb",
- ty_equiv(tt_union(a_int, tt_union(a_str, a_int)), tt_union(a_int, a_str)), 1);
- total = total + 1; fails = fails + ts_check("disjoint.atoms", ty_disjoint(a_int, a_str), 1);
- total = total + 1; fails = fails + ts_check("disjoint.same", ty_disjoint(a_int, a_int), 0);
- total = total + 1; fails = fails + ts_check("inh.atom", ty_inhabited(a_int), 1);
- total = total + 1; fails = fails + ts_check("inh.contra", ty_inhabited(tt_inter(a_int, tt_not(a_int))), 0);
- total = total + 1; fails = fails + ts_check("inh.mixed_atoms",
- ty_inhabited(tt_inter(a_int, tt_atom(AK_SEQUENCE, -1, -1))), 0);
- total = total + 1; fails = fails + ts_check("topk.sub", ty_sub(a_int, tt_top_k(AK_INT)), 1);
- total = total + 1; fails = fails + ts_check("topk.neg", ty_sub(a_str, tt_top_k(AK_INT)), 0);
+ total = total + 1
+ fails = fails + ts_check("equiv.absorb",
+ ty_equiv(tt_union(a_int, tt_union(a_str, a_int)), tt_union(a_int, a_str)), 1)
+ total = total + 1
+ fails = fails + ts_check("disjoint.atoms", ty_disjoint(a_int, a_str), 1)
+ total = total + 1
+ fails = fails + ts_check("disjoint.same", ty_disjoint(a_int, a_int), 0)
+ total = total + 1
+ fails = fails + ts_check("inh.atom", ty_inhabited(a_int), 1)
+ total = total + 1
+ fails = fails + ts_check("inh.contra", ty_inhabited(tt_inter(a_int, tt_not(a_int))), 0)
+ total = total + 1
+ fails = fails + ts_check("inh.mixed_atoms",
+ ty_inhabited(tt_inter(a_int, tt_atom(AK_SEQUENCE, -1, -1))), 0)
+ total = total + 1
+ fails = fails + ts_check("topk.sub", ty_sub(a_int, tt_top_k(AK_INT)), 1)
+ total = total + 1
+ fails = fails + ts_check("topk.neg", ty_sub(a_str, tt_top_k(AK_INT)), 0)
// 预算守卫:深递归项 + 极小预算 → 三态 -1(禁止与「不成立」混淆)
- ty_budget_reset(64);
- total = total + 1; fails = fails + ts_check("budget.unknown", ty_sub(tt_probe_wide_union(300), a_int), -1);
- total = total + 1; fails = fails + ts_check("budget.flag", ty_exhausted(), 1);
- ty_budget_reset(200000);
+ ty_budget_reset(64)
+ total = total + 1
+ fails = fails + ts_check("budget.unknown", ty_sub(tt_probe_wide_union(300), a_int), -1)
+ total = total + 1
+ fails = fails + ts_check("budget.flag", ty_exhausted(), 1)
+ ty_budget_reset(200000)
// --- 反例(witness)+ 穷尽性(Task 4)---
- w := tt_witness(a_int, a_str);
- total = total + 1; fails = fails + ts_check_b("witness.nonempty", (w >= 0), true);
- total = total + 1; fails = fails + ts_check("witness.sub_of_a", ty_sub(w, a_int), 1);
- total = total + 1; fails = fails + ts_check("witness.not_sub_of_b", ty_sub(w, a_str), 0);
- total = total + 1; fails = fails + ts_check("witness.empty", tt_witness(a_int, a_int), -1);
-
- dom := tt_union(tt_union(a_int, a_str), a_bool);
- pats := tt_cons(a_int, tt_cons(a_str, tt_nil()));
- total = total + 1; fails = fails + ts_check("exhaust.incomplete", ty_exhaustive(dom, pats), 0);
- miss := ty_exhaust_witness(dom, pats);
- total = total + 1; fails = fails + ts_check("exhaust.witness_bool", ty_equiv(miss, a_bool), 1);
- total = total + 1; fails = fails + ts_check("exhaust.complete",
- ty_exhaustive(dom, tt_cons(a_int, tt_cons(a_str, tt_cons(a_bool, tt_nil())))), 1);
+ w := tt_witness(a_int, a_str)
+ total = total + 1
+ fails = fails + ts_check_b("witness.nonempty", (w >= 0), true)
+ total = total + 1
+ fails = fails + ts_check("witness.sub_of_a", ty_sub(w, a_int), 1)
+ total = total + 1
+ fails = fails + ts_check("witness.not_sub_of_b", ty_sub(w, a_str), 0)
+ total = total + 1
+ fails = fails + ts_check("witness.empty", tt_witness(a_int, a_int), -1)
+
+ dom := tt_union(tt_union(a_int, a_str), a_bool)
+ pats := tt_cons(a_int, tt_cons(a_str, tt_nil()))
+ total = total + 1
+ fails = fails + ts_check("exhaust.incomplete", ty_exhaustive(dom, pats), 0)
+ miss := ty_exhaust_witness(dom, pats)
+ total = total + 1
+ fails = fails + ts_check("exhaust.witness_bool", ty_equiv(miss, a_bool), 1)
+ total = total + 1
+ fails = fails + ts_check("exhaust.complete",
+ ty_exhaustive(dom, tt_cons(a_int, tt_cons(a_str, tt_cons(a_bool, tt_nil())))), 1)
// --- 递归 + 参数化(Task 4)---
- rec_abs := tt_mu(0, tt_union(a_int, tt_var(0)));
- total = total + 1; fails = fails + ts_check("rec.absorb", ty_equiv(rec_abs, a_int), 1);
- rec_list := tt_mu(0, tt_union(a_int, tt_atom(AK_PRODUCT, -1, tt_cons(tt_var(0), tt_nil()))));
- total = total + 1; fails = fails + ts_check("rec.inh", ty_inhabited(rec_list), 1);
- total = total + 1; fails = fails + ts_check("rec.sub_self", ty_sub(rec_list, rec_list), 1);
- seq_i := tt_atom(AK_SEQUENCE, -1, tt_cons(a_int, tt_nil()));
- seq_s := tt_atom(AK_SEQUENCE, -1, tt_cons(a_str, tt_nil()));
- total = total + 1; fails = fails + ts_check("param.same", ty_sub(seq_i, seq_i), 1);
+ rec_abs := tt_mu(0, tt_union(a_int, tt_var(0)))
+ total = total + 1
+ fails = fails + ts_check("rec.absorb", ty_equiv(rec_abs, a_int), 1)
+ rec_list := tt_mu(0, tt_union(a_int, tt_atom(AK_PRODUCT, -1, tt_cons(tt_var(0), tt_nil()))))
+ total = total + 1
+ fails = fails + ts_check("rec.inh", ty_inhabited(rec_list), 1)
+ total = total + 1
+ fails = fails + ts_check("rec.sub_self", ty_sub(rec_list, rec_list), 1)
+ seq_i := tt_atom(AK_SEQUENCE, -1, tt_cons(a_int, tt_nil()))
+ seq_s := tt_atom(AK_SEQUENCE, -1, tt_cons(a_str, tt_nil()))
+ total = total + 1
+ fails = fails + ts_check("param.same", ty_sub(seq_i, seq_i), 1)
// **R2 P5 Task 3b 翻转钉**(原 `param.unknown_p0`,期望 -1):不变槽元素三态落地后
// 同类异参(`[int]` vs `[str]`,元素 = 异原生类)由「未知 -1」变「确定不同 **0**」。
// 语义正确性:不变元素槽下 `[int] ⊄ [str]`(元素类不同 ⇒ 确定);与 spec §2.2 的
// `sequence<⊤>` 正向面**无冲突**——后者由 `tt_top_k(AK_SEQUENCE)` 的 TOP_K 分支判
// (`[T] <: sequence<⊤>` 恒 1,与元素比较无关;守门例见 x2.shape_* 段)。
// 对齐面:legacy `type_equal([int],[str]) = false` = 0(替换门同结论,影子 old_* = 0)。
- total = total + 1; fails = fails + ts_check("param.elem_class_diff_zero", ty_sub(seq_i, seq_s), 0);
+ total = total + 1
+ fails = fails + ts_check("param.elem_class_diff_zero", ty_sub(seq_i, seq_s), 0)
// 未覆盖面位断言前**显式重置**(全局粘滞位,前面案例碰过 ¬μ 会误过——修复复审 N5);
// T3b 后本触发器改用**仍属域外**的面(μ 变元作序列元素 ⇒ te_elem_cmp 域外守卫)
- ty_budget_reset(200000);
- seq_mu := tt_atom(AK_SEQUENCE, -1, tt_cons(tt_var(0), tt_nil()));
- d_dummy := ty_sub(seq_i, seq_mu); // 重置后重新触发一次未覆盖面(域外元素)
- total = total + 1; fails = fails + ts_check("param.uncovered_flag", ty_uncovered(), 1);
+ ty_budget_reset(200000)
+ seq_mu := tt_atom(AK_SEQUENCE, -1, tt_cons(tt_var(0), tt_nil()))
+ d_dummy := ty_sub(seq_i, seq_mu) // 重置后重新触发一次未覆盖面(域外元素)
+ total = total + 1
+ fails = fails + ts_check("param.uncovered_flag", ty_uncovered(), 1)
// --- P0 终审补例(三个 Critical + 两条 Important 各配一例回归)---
// C1:否定在超类型侧 —— ¬A ⊆ ¬B ⟺ B ⊆ A(方向反会让两侧同时成立)
- total = total + 1; fails = fails + ts_check("neg.supertype",
- ty_sub(tt_not(seq_i), tt_not(tt_top_k(AK_SEQUENCE))), 0);
- total = total + 1; fails = fails + ts_check("neg.supertype_rev",
- ty_sub(tt_not(tt_top_k(AK_SEQUENCE)), tt_not(seq_i)), 1);
+ total = total + 1
+ fails = fails + ts_check("neg.supertype",
+ ty_sub(tt_not(seq_i), tt_not(tt_top_k(AK_SEQUENCE))), 0)
+ total = total + 1
+ fails = fails + ts_check("neg.supertype_rev",
+ ty_sub(tt_not(tt_top_k(AK_SEQUENCE)), tt_not(seq_i)), 1)
// C3:预算耗尽不得被吞成 0(三态必须上抛)——**预算窗口扫描**守「exhausted ⇒ -1」
// 不变量(单点预算 1 会被规范化预算满足,守不住 lit_implies 吞并面——修复复审 N2)
- ok_sw : ., mut = 1;
- bi : ., mut = 1;
- loop {
- if bi > 12 { break; }
- ty_budget_reset(bi);
- r_sw := ty_sub(tt_not(seq_i), tt_not(tt_top_k(AK_SEQUENCE)));
- if ty_exhausted() == 1 && r_sw != -1 { ok_sw = 0; }
- bi = bi + 1;
- }
- ty_budget_reset(200000);
- total = total + 1; fails = fails + ts_check("budget.no_swallow_sweep", ok_sw, 1);
+ ok_sw : ., mut = 1
+ bi : ., mut = 1
+ loop:
+ if bi > 12:
+ break
+ ty_budget_reset(bi)
+ r_sw := ty_sub(tt_not(seq_i), tt_not(tt_top_k(AK_SEQUENCE)))
+ if ty_exhausted() == 1 && r_sw != -1:
+ ok_sw = 0
+ bi = bi + 1
+ ty_budget_reset(200000)
+ total = total + 1
+ fails = fails + ts_check("budget.no_swallow_sweep", ok_sw, 1)
// witness 的三态:-1 = 不可满足 / -2 = 未知(预算耗尽),ty_exhaustive 对 -2 → -1
// (dom/pats 在此处重新构造:本块位于「反例+穷尽性」节之前)
- dom_u := tt_union(tt_union(a_int, a_str), a_bool);
- pats_u := tt_cons(a_int, tt_cons(a_str, tt_nil()));
- ty_budget_reset(1);
- total = total + 1; fails = fails + ts_check("witness.unknown_budget", tt_witness(a_int, a_str), -2);
- total = total + 1; fails = fails + ts_check("exhaust.unknown_budget", ty_exhaustive(dom_u, pats_u), -1);
- ty_budget_reset(200000);
+ dom_u := tt_union(tt_union(a_int, a_str), a_bool)
+ pats_u := tt_cons(a_int, tt_cons(a_str, tt_nil()))
+ ty_budget_reset(1)
+ total = total + 1
+ fails = fails + ts_check("witness.unknown_budget", tt_witness(a_int, a_str), -2)
+ total = total + 1
+ fails = fails + ts_check("exhaust.unknown_budget", ty_exhaustive(dom_u, pats_u), -1)
+ ty_budget_reset(200000)
// C2:memo 表扩容不挂(1200 互异对逼出装填因子守卫 + 重建重放;到得了下一行 = 未死循环)
- d2 : ., mut = 0;
- last := 0;
- loop {
- if d2 >= 1200 { break; }
- last = ty_sub(tt_mu(d2, a_int), a_int);
- d2 = d2 + 1;
- }
- total = total + 1; fails = fails + ts_check("memo.overflow_survived", last, 1);
+ d2 : ., mut = 0
+ last := 0
+ loop:
+ if d2 >= 1200:
+ break
+ last = ty_sub(tt_mu(d2, a_int), a_int)
+ d2 = d2 + 1
+ total = total + 1
+ fails = fails + ts_check("memo.overflow_survived", last, 1)
// A:n 元析取(≥3)是合法 DNF(左深嵌套 union)
- total = total + 1; fails = fails + ts_check("dnf.n_ary",
- tt_is_dnf(tt_norm(tt_inter(tt_union(a_int, a_str), tt_union(a_bool, a_int)))), 1);
+ total = total + 1
+ fails = fails + ts_check("dnf.n_ary",
+ tt_is_dnf(tt_norm(tt_inter(tt_union(a_int, a_str), tt_union(a_bool, a_int)))), 1)
// B:命名原子不展开 → 未知;且不得断言与它互斥
- named_t := tt_atom(AK_NAMED, 7, -1);
- a_prod := tt_atom(AK_PRODUCT, -1, -1);
- total = total + 1; fails = fails + ts_check("named.unknown", ty_sub(named_t, a_prod), -1);
- total = total + 1; fails = fails + ts_check("named.not_disjoint", ty_disjoint(named_t, a_prod), 0);
+ named_t := tt_atom(AK_NAMED, 7, -1)
+ a_prod := tt_atom(AK_PRODUCT, -1, -1)
+ total = total + 1
+ fails = fails + ts_check("named.unknown", ty_sub(named_t, a_prod), -1)
+ total = total + 1
+ fails = fails + ts_check("named.not_disjoint", ty_disjoint(named_t, a_prod), 0)
// D:¬μ 不静默改写为 μ¬(保留为字面 + 未覆盖面)
- total = total + 1; fails = fails + ts_check("neg.mu_kept",
- tt_tag(tt_norm(tt_not(tt_mu(0, a_int)))), TT_NOT);
+ total = total + 1
+ fails = fails + ts_check("neg.mu_kept",
+ tt_tag(tt_norm(tt_not(tt_mu(0, a_int)))), TT_NOT)
// --- 索引扩容守门(Task 1 遗留:判据规模 << 初始容量 → 扩容/重建路径无常规覆盖)---
- ref := tt_atom(AK_SEQUENCE, -1, tt_cons(a_int, tt_nil()));
- before := tt_count();
- g_tt_index_cap = 0; // 直接逼出 grow_tt_index → 重建索引(tt_reindex)+ 重放插入
- grow_tt_index(2);
- after := tt_atom(AK_SEQUENCE, -1, tt_cons(a_int, tt_nil()));
- total = total + 1; fails = fails + ts_check_b("grow.index_rebuilt", (after == ref), true);
- d : ., mut = 0;
- loop {
- if d >= 40 { break; }
- item := tt_atom(AK_PRODUCT, -1, tt_cons(tt_mu(d, a_int), tt_nil()));
- d = d + 1;
- }
+ ref := tt_atom(AK_SEQUENCE, -1, tt_cons(a_int, tt_nil()))
+ before := tt_count()
+ g_tt_index_cap = 0 // 直接逼出 grow_tt_index → 重建索引(tt_reindex)+ 重放插入
+ grow_tt_index(2)
+ after := tt_atom(AK_SEQUENCE, -1, tt_cons(a_int, tt_nil()))
+ total = total + 1
+ fails = fails + ts_check_b("grow.index_rebuilt", (after == ref), true)
+ d : ., mut = 0
+ loop:
+ if d >= 40:
+ break
+ item := tt_atom(AK_PRODUCT, -1, tt_cons(tt_mu(d, a_int), tt_nil()))
+ d = d + 1
// 40 个互异项建两遍:第二遍必须**全部命中**已有项(DAG 去重幂等)——精确断言
// (早期版本用 `>= before+40`,既弱又不精确;P0 终审 Minor 指出)
- c_after_first := tt_count();
- d4 : ., mut = 0;
- loop {
- if d4 >= 40 { break; }
- item2 := tt_atom(AK_PRODUCT, -1, tt_cons(tt_mu(d4, a_int), tt_nil()));
- d4 = d4 + 1;
- }
- total = total + 1; fails = fails + ts_check("grow.dedup_40_idempotent", (tt_count() - c_after_first), 0);
- total = total + 1; fails = fails + ts_check_b("grow.dedup_after_rebuild",
+ c_after_first := tt_count()
+ d4 : ., mut = 0
+ loop:
+ if d4 >= 40:
+ break
+ item2 := tt_atom(AK_PRODUCT, -1, tt_cons(tt_mu(d4, a_int), tt_nil()))
+ d4 = d4 + 1
+ total = total + 1
+ fails = fails + ts_check("grow.dedup_40_idempotent", (tt_count() - c_after_first), 0)
+ total = total + 1
+ fails = fails + ts_check_b("grow.dedup_after_rebuild",
(tt_atom(AK_PRODUCT, -1, tt_cons(tt_mu(0, a_int), tt_nil())) ==
- tt_atom(AK_PRODUCT, -1, tt_cons(tt_mu(0, a_int), tt_nil()))), true);
+ tt_atom(AK_PRODUCT, -1, tt_cons(tt_mu(0, a_int), tt_nil()))), true)
// --- P1 桥接(checker ti → 引擎项,R2 P1 Task 1;映射表 = 计划 Task 1 表)---
// 前置:本通道不经 check_all(),g_types 未初始化 → 显式 init_types()(原生 9 项
// 占下标 0..8,用户类型自 9 起——桥接用例的 alloc_type 依赖该布局)。
// 预算:前段用例累积 g_ty_steps(仅显式 ty_budget_reset 归零),重置到干净窗口
// (P0 修复复审 N5 同款卫生)。
- init_types();
- ty_budget_reset(200000);
- t_int := sh_term_of_ti(TI_INT);
- total = total + 1; fails = fails + ts_check("bridge.int_atom", tt_tag(t_int), TT_ATOM);
- total = total + 1; fails = fails + ts_check("bridge.int_ak", tt_a(t_int), AK_INT);
- t_arr := sh_term_of_ti(alloc_type(TYP_ARRAY, TI_INT, 3));
- total = total + 1; fails = fails + ts_check("bridge.arr_seq", tt_a(t_arr), AK_SEQUENCE);
- t_arr3 := sh_term_of_ti(alloc_type(TYP_ARRAY, TI_INT, 4));
- total = total + 1; fails = fails + ts_check("bridge.len_not_identity",
- ty_equiv(t_arr, t_arr3), 1); // N 不入身份(R1 裁决)——3 与 4 等价
- total = total + 1; fails = fails + ts_check_b("bridge.cache_hit", (sh_term_of_ti(TI_INT) == t_int), true);
+ init_types()
+ ty_budget_reset(200000)
+ t_int := sh_term_of_ti(TI_INT)
+ total = total + 1
+ fails = fails + ts_check("bridge.int_atom", tt_tag(t_int), TT_ATOM)
+ total = total + 1
+ fails = fails + ts_check("bridge.int_ak", tt_a(t_int), AK_INT)
+ t_arr := sh_term_of_ti(alloc_type(TYP_ARRAY, TI_INT, 3))
+ total = total + 1
+ fails = fails + ts_check("bridge.arr_seq", tt_a(t_arr), AK_SEQUENCE)
+ t_arr3 := sh_term_of_ti(alloc_type(TYP_ARRAY, TI_INT, 4))
+ total = total + 1
+ fails = fails + ts_check("bridge.len_not_identity",
+ ty_equiv(t_arr, t_arr3), 1) // N 不入身份(R1 裁决)——3 与 4 等价
+ total = total + 1
+ fails = fails + ts_check_b("bridge.cache_hit", (sh_term_of_ti(TI_INT) == t_int), true)
// 原生序守门:checker 下标序 ≠ 引擎 AK 序——TI_BOOL=2/TI_STR=3 vs AK_STRING=2/AK_BOOL=3
// (计划注释「AK_* 与 TI_* 前 7 项 1:1」**不成立**,按下标直通会 bool↔string 静默错标)
- total = total + 1; fails = fails + ts_check("bridge.str_ak", tt_a(sh_term_of_ti(TI_STR)), AK_STRING);
- total = total + 1; fails = fails + ts_check("bridge.bool_ak", tt_a(sh_term_of_ti(TI_BOOL)), AK_BOOL);
- total = total + 1; fails = fails + ts_check("bridge.dyn_ak", tt_a(sh_term_of_ti(TI_DYN)), AK_DYN);
+ total = total + 1
+ fails = fails + ts_check("bridge.str_ak", tt_a(sh_term_of_ti(TI_STR)), AK_STRING)
+ total = total + 1
+ fails = fails + ts_check("bridge.bool_ak", tt_a(sh_term_of_ti(TI_BOOL)), AK_BOOL)
+ total = total + 1
+ fails = fails + ts_check("bridge.dyn_ak", tt_a(sh_term_of_ti(TI_DYN)), AK_DYN)
// M3(Task 1 评审):native 分派 = 读表本体(kind == TYP_BASE 且 data == TY_*)——**全表覆盖**
// (M1 后它成为主路径,此前只有 row 8 可达且无用例)。行 0..7 逐行对照,不抽样:
// 任一行错位(含 bool↔str 互换回归)即红。
@@ -1984,296 +2131,376 @@ fn type_selftest_run() -> int {
// data 再判 kind,dyn 会静默译成 AK_INT。故 ① 断言 sh_native_ak(TI_DYN) == -1(dyn 必走
// kind 分支,绝不进 native 路径),② 项本身仍 = AK_DYN。两断言合起来把「先 data 后 kind」
// 的写法钉死在红。
- acc_nat : ., mut = 1;
- ri : ., mut = 0;
- loop {
- if ri >= 8 { break; }
- want_ak : ., mut = -1;
- if ri == TI_INT { want_ak = AK_INT; }
- else if ri == TI_DEX { want_ak = AK_DEX; }
- else if ri == TI_BOOL { want_ak = AK_BOOL; }
- else if ri == TI_STR { want_ak = AK_STRING; }
- else if ri == TI_UNIT { want_ak = AK_UNIT; }
- else if ri == TI_NEVER { want_ak = AK_NEVER; }
- else if ri == TI_CHAR { want_ak = AK_CHAR; }
- got_ak := sh_native_ak(ri);
- if ri == TI_DYN {
- if got_ak != -1 { acc_nat = 0; } // dyn:kind 分支,native 必 -1
- } else if got_ak != want_ak { acc_nat = 0; }
- ri = ri + 1;
- }
- total = total + 1; fails = fails + ts_check("bridge.native_row_table", acc_nat, 1);
- total = total + 1; fails = fails + ts_check_b("bridge.native_dyn_kind_branch",
- (sh_native_ak(TI_DYN) == -1 && tt_a(sh_term_of_ti(TI_DYN)) == AK_DYN), true);
+ acc_nat : ., mut = 1
+ ri : ., mut = 0
+ loop:
+ if ri >= 8:
+ break
+ want_ak : ., mut = -1
+ if ri == TI_INT:
+ want_ak = AK_INT
+ else if ri == TI_DEX:
+ want_ak = AK_DEX
+ else if ri == TI_BOOL:
+ want_ak = AK_BOOL
+ else if ri == TI_STR:
+ want_ak = AK_STRING
+ else if ri == TI_UNIT:
+ want_ak = AK_UNIT
+ else if ri == TI_NEVER:
+ want_ak = AK_NEVER
+ else if ri == TI_CHAR:
+ want_ak = AK_CHAR
+ got_ak := sh_native_ak(ri)
+ if ri == TI_DYN:
+ if got_ak != -1:
+ acc_nat = 0
+ // dyn:kind 分支,native 必 -1
+ else if got_ak != want_ak:
+ acc_nat = 0
+ ri = ri + 1
+ total = total + 1
+ fails = fails + ts_check("bridge.native_row_table", acc_nat, 1)
+ total = total + 1
+ fails = fails + ts_check_b("bridge.native_dyn_kind_branch",
+ (sh_native_ak(TI_DYN) == -1 && tt_a(sh_term_of_ti(TI_DYN)) == AK_DYN), true)
// TY_DEX_S 占位行(row 8):M1 后走 native 路径(旧实现走通用路径),两侧同 = AK_DEX
- total = total + 1; fails = fails + ts_check_b("bridge.native_dex_s",
- (sh_native_ak(TI_DEX_S) == AK_DEX && tt_a(sh_term_of_ti(TI_DEX_S)) == AK_DEX), true);
+ total = total + 1
+ fails = fails + ts_check_b("bridge.native_dex_s",
+ (sh_native_ak(TI_DEX_S) == AK_DEX && tt_a(sh_term_of_ti(TI_DEX_S)) == AK_DEX), true)
// 参数链(内层项)+ 两份同类分支不得互串(PTR/REF 是两条独立分支)
- t_ptr := sh_term_of_ti(alloc_type(TYP_PTR, TI_INT, 0));
+ t_ptr := sh_term_of_ti(alloc_type(TYP_PTR, TI_INT, 0))
// M2(Task 1 评审):class 断言与参数链**并列**——原用例只断参数链,整支误译成
// SEQUENCE/REF 也会绿(对照 ref_inner 已断 class)
- total = total + 1; fails = fails + ts_check("bridge.ptr_ak", tt_a(t_ptr), AK_PTR);
- total = total + 1; fails = fails + ts_check("bridge.ptr_inner",
- tt_c(t_ptr), tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil()));
+ total = total + 1
+ fails = fails + ts_check("bridge.ptr_ak", tt_a(t_ptr), AK_PTR)
+ total = total + 1
+ fails = fails + ts_check("bridge.ptr_inner",
+ tt_c(t_ptr), tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil()))
// P3 Task 1(断言更新,用例数不变):AK_REF 链 = [mut 标记项, 元素项](mut 入链 = 判定
// 维度)⇒ 本用例守的「REF 链含元素项」改断链**第二项**(标记项由 t1.var_mut_* 单列)。
// 旧断言(链首即元素)随 mut 入链的布局裁决更新——原因见 ty_shadow.cr 的 sh_ref_mut_marker。
- t_ref := sh_term_of_ti(alloc_type(TYP_REF, TI_STR, 0));
- total = total + 1; fails = fails + ts_check_b("bridge.ref_inner",
- (tt_a(t_ref) == AK_REF && tt_b(tt_c(t_ref)) == tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil())), true);
- t_slice := sh_term_of_ti(alloc_type(TYP_SLICE, TI_STR, 0));
- total = total + 1; fails = fails + ts_check_b("bridge.slice_seq",
- (tt_a(t_slice) == AK_SEQUENCE && tt_c(t_slice) == tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil())), true);
+ t_ref := sh_term_of_ti(alloc_type(TYP_REF, TI_STR, 0))
+ total = total + 1
+ fails = fails + ts_check_b("bridge.ref_inner",
+ (tt_a(t_ref) == AK_REF && tt_b(tt_c(t_ref)) == tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil())), true)
+ t_slice := sh_term_of_ti(alloc_type(TYP_SLICE, TI_STR, 0))
+ total = total + 1
+ fails = fails + ts_check_b("bridge.slice_seq",
+ (tt_a(t_slice) == AK_SEQUENCE && tt_c(t_slice) == tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil())), true)
// --- R2 P5 Task 2(D19/D21/D22/D23):DFNode 类型面**单槽化** ---
// 形态 = 两槽(OFF_DF_TK 项引用 + OFF_DF_AUX 辅码)+ 派生码(sh_dfn_code_of_slots);
// P4 的 `t4.tk_*` 用例保留(语义未变者原地;清单扩大/复合行走辅码者重钉)。
// 负控的牙齿 = 每个「本该 -1」的用例都同时断言**直译路径非 -1**(证明拒绝出自
// 分类门而非「该行不可译」——否则门形同虚设也能绿)。
- total = total + 1; fails = fails + ts_check_b("t4.tk_const_int",
+ total = total + 1
+ fails = fails + ts_check_b("t4.tk_const_int",
(sh_tk_term_of_code(IR_CONST, TI_INT) == sh_term_of_ti(TI_INT) &&
- tt_a(sh_tk_term_of_code(IR_CONST, TI_INT)) == AK_INT), true);
- total = total + 1; fails = fails + ts_check_b("t4.tk_binary_dex",
+ tt_a(sh_tk_term_of_code(IR_CONST, TI_INT)) == AK_INT), true)
+ total = total + 1
+ fails = fails + ts_check_b("t4.tk_binary_dex",
(sh_tk_term_of_code(IR_BINARY, TI_DEX) == sh_term_of_ti(TI_DEX) &&
- tt_a(sh_tk_term_of_code(IR_BINARY, TI_DEX)) == AK_DEX), true);
- total = total + 1; fails = fails + ts_check_b("t4.tk_const_dex_s_row8",
+ tt_a(sh_tk_term_of_code(IR_BINARY, TI_DEX)) == AK_DEX), true)
+ total = total + 1
+ fails = fails + ts_check_b("t4.tk_const_dex_s_row8",
(sh_tk_term_of_code(IR_CONST, TI_DEX_S) == sh_term_of_ti(TI_DEX_S) &&
- tt_a(sh_tk_term_of_code(IR_CONST, TI_DEX_S)) == AK_DEX), true);
+ tt_a(sh_tk_term_of_code(IR_CONST, TI_DEX_S)) == AK_DEX), true)
// 负控 ①:IR_BOUNDS_CHECK 的 tk 是旗标(1 = 动态上限),而 1 数值上 = TI_DEX 行
// ——直译有值 ⇒ 只能靠分类门挡住(凭空安 dex 项 = 本用例钉死的形态)。
- total = total + 1; fails = fails + ts_check_b("t4.tk_bounds_flag1_rejected",
- (sh_tk_term_of_code(IR_BOUNDS_CHECK, 1) == -1 && sh_term_of_ti(1) >= 0), true);
+ total = total + 1
+ fails = fails + ts_check_b("t4.tk_bounds_flag1_rejected",
+ (sh_tk_term_of_code(IR_BOUNDS_CHECK, 1) == -1 && sh_term_of_ti(1) >= 0), true)
// 负控 ②:IR_DEREF 的 tk 是访问宽度(8B),8 数值上 = TI_DEX_S 行(同款陷阱)。
- total = total + 1; fails = fails + ts_check_b("t4.tk_deref_width8_rejected",
- (sh_tk_term_of_code(IR_DEREF, 8) == -1 && sh_term_of_ti(TI_DEX_S) >= 0), true);
+ total = total + 1
+ fails = fails + ts_check_b("t4.tk_deref_width8_rejected",
+ (sh_tk_term_of_code(IR_DEREF, 8) == -1 && sh_term_of_ti(TI_DEX_S) >= 0), true)
// 负控 ③(重钉:P5 T2 起 IR_CALL/IR_ALLOC 入类型行面 ⇒ 换成「面外」op):
// 「行合法(0 = TI_INT)但 op 不在任何类型/辅码面」——面外 op 不得因 tk 恰好合法而放行。
- total = total + 1; fails = fails + ts_check_b("t4.tk_unlisted_op_valid_row_rejected",
+ total = total + 1
+ fails = fails + ts_check_b("t4.tk_unlisted_op_valid_row_rejected",
(sh_tk_term_of_code(IR_STORE, TI_INT) == -1 &&
- sh_tk_term_of_code(IR_RETURN, TI_INT) == -1 &&
- sh_tk_term_of_code(IR_MAKE_ENUM, TI_INT) == -1 &&
- sh_term_of_ti(TI_INT) >= 0), true);
+ sh_tk_term_of_code(IR_RETURN, TI_INT) == -1 &&
+ sh_tk_term_of_code(IR_MAKE_ENUM, TI_INT) == -1 &&
+ sh_term_of_ti(TI_INT) >= 0), true)
// 负控 ④:行号越界 / 负值 ⇒ -1(不得当 0/1 用;不得读越界项表)。
- total = total + 1; fails = fails + ts_check_b("t4.tk_row_range_rejected",
+ total = total + 1
+ fails = fails + ts_check_b("t4.tk_row_range_rejected",
(sh_tk_term_of_code(IR_CONST, g_type_count) == -1 &&
- sh_tk_term_of_code(IR_BINARY, g_type_count + 7) == -1 &&
- sh_tk_term_of_code(IR_CONST, -1) == -1), true);
+ sh_tk_term_of_code(IR_BINARY, g_type_count + 7) == -1 &&
+ sh_tk_term_of_code(IR_CONST, -1) == -1), true)
// 查询纯度(P5 T2 引入 / **P5 T5 重钉**:原断言 = 「本函数不扰动影子对账的 hits 计数」,
// 影子通道下线后该计数已不存在 ⇒ 改钉**查询纯度**这一同源性质):`sh_tk_term_of_code`
// 是**纯查询**——不写槽出参、不置 D23 失败位(诊断调用不得污染落盘闸;有副作用的生产
// 路径一律走 sh_tk_split);且对同一行返回**同一项**(缓存语义)。
// 牙齿:必须取**非原生行**(原生行走 sh_native_ak 快路径,本就不进缓存 ⇒ 拿 TI_INT 测
// 等于恒真断言)。TYP_DYN 行首次直译建项入缓存、二次直译命中同项。
- t4_dyn_row := alloc_type(TYP_DYN, 0, 0);
- t4_dyn_term := sh_term_of_ti(t4_dyn_row); // 预热:首次(miss)入桥接缓存
- t4_fail_0 := g_tk_face_fail;
- sh_tk_split(IR_CONST, g_type_count); // 槽出参置哨兵(越界行 ⇒ term=-1/aux=越界行号)
- t4_sent_t := g_sh_slot_term;
- t4_sent_a := g_sh_slot_aux;
- t4_fail_before := g_tk_face_fail;
- sk4 := sh_tk_term_of_code(IR_CONST, t4_dyn_row); // 查询路径(缓存命中)
- total = total + 1; fails = fails + ts_check_b("t4.tk_query_purity_and_cache_hit",
+ t4_dyn_row := alloc_type(TYP_DYN, 0, 0)
+ t4_dyn_term := sh_term_of_ti(t4_dyn_row) // 预热:首次(miss)入桥接缓存
+ t4_fail_0 := g_tk_face_fail
+ sh_tk_split(IR_CONST, g_type_count) // 槽出参置哨兵(越界行 ⇒ term=-1/aux=越界行号)
+ t4_sent_t := g_sh_slot_term
+ t4_sent_a := g_sh_slot_aux
+ t4_fail_before := g_tk_face_fail
+ sk4 := sh_tk_term_of_code(IR_CONST, t4_dyn_row) // 查询路径(缓存命中)
+ total = total + 1
+ fails = fails + ts_check_b("t4.tk_query_purity_and_cache_hit",
((t4_dyn_term >= 0 && sk4 == t4_dyn_term &&
- g_sh_slot_term == t4_sent_t && g_sh_slot_aux == t4_sent_a &&
- g_tk_face_fail == t4_fail_before)), true);
- g_tk_face_fail = t4_fail_0; // 复位(哨兵行的 D23 位 = 本用例产物,不留给后续)
+ g_sh_slot_term == t4_sent_t && g_sh_slot_aux == t4_sent_a &&
+ g_tk_face_fail == t4_fail_before)), true)
+ g_tk_face_fail = t4_fail_0 // 复位(哨兵行的 D23 位 = 本用例产物,不留给后续)
// ── R2 P5 Task 2 新例 ①:原子行契约(D21)──
// TT_ATOM ∧ b ≥ 0 ⇒ b;union / cons / nil / 负 / 越界 ⇒ **-1**(显式,不得近似)。
- t5s_ptr_row := alloc_type(TYP_PTR, TI_INT, 0);
- t5s_ptr_term := sh_term_of_ti(t5s_ptr_row);
- total = total + 1; fails = fails + ts_check_b("p5t2.atom_of_contract",
+ t5s_ptr_row := alloc_type(TYP_PTR, TI_INT, 0)
+ t5s_ptr_term := sh_term_of_ti(t5s_ptr_row)
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.atom_of_contract",
(tt_atom_of_term(sh_term_of_ti(TI_INT)) == TI_INT &&
- tt_atom_of_term(t5s_ptr_term) == -1 && // 复合项:AK_PTR 的 b = -1
- tt_atom_of_term(tt_nil()) == -1 &&
- tt_atom_of_term(tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())) == -1 &&
- tt_atom_of_term(-1) == -1 &&
- tt_atom_of_term(tt_count() + 9) == -1), true);
+ tt_atom_of_term(t5s_ptr_term) == -1 && // 复合项:AK_PTR 的 b = -1
+ tt_atom_of_term(tt_nil()) == -1 &&
+ tt_atom_of_term(tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())) == -1 &&
+ tt_atom_of_term(-1) == -1 &&
+ tt_atom_of_term(tt_count() + 9) == -1), true)
// ── 新例 ②:类型行面 —— 改走 split,断言**两槽**(项 + 空辅码)+ 互斥 ──
- sh_tk_split(IR_BINARY, TI_STR);
- t5s_bin_str_term := g_sh_slot_term;
- t5s_bin_str_aux := g_sh_slot_aux;
- total = total + 1; fails = fails + ts_check_b("p5t2.slot_type_face_atomic",
+ sh_tk_split(IR_BINARY, TI_STR)
+ t5s_bin_str_term := g_sh_slot_term
+ t5s_bin_str_aux := g_sh_slot_aux
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.slot_type_face_atomic",
(t5s_bin_str_term == sh_term_of_ti(TI_STR) && t5s_bin_str_aux == 0 &&
- sh_dfn_code_of_slots(t5s_bin_str_term, t5s_bin_str_aux) == TI_STR), true);
+ sh_dfn_code_of_slots(t5s_bin_str_term, t5s_bin_str_aux) == TI_STR), true)
// ── 新例 ③:类型行面扩面(Task 0 再裁的 5 个 op 正控)──
- sh_tk_split(IR_ALLOC, TI_UNIT); t5s_a1 := g_sh_slot_term; t5s_a1x := g_sh_slot_aux;
- sh_tk_split(IR_CALL, TI_INT); t5s_a2 := g_sh_slot_term; t5s_a2x := g_sh_slot_aux;
- sh_tk_split(IR_LOAD, TI_INT); t5s_a3 := g_sh_slot_term; t5s_a3x := g_sh_slot_aux;
- sh_tk_split(IR_I2F, TI_DEX); t5s_a4 := g_sh_slot_term; t5s_a4x := g_sh_slot_aux;
- sh_tk_split(IR_F2I, TI_DEX); t5s_a5 := g_sh_slot_term; t5s_a5x := g_sh_slot_aux;
- total = total + 1; fails = fails + ts_check_b("p5t2.slot_type_face_extended",
+ sh_tk_split(IR_ALLOC, TI_UNIT)
+ t5s_a1 := g_sh_slot_term
+ t5s_a1x := g_sh_slot_aux
+ sh_tk_split(IR_CALL, TI_INT)
+ t5s_a2 := g_sh_slot_term
+ t5s_a2x := g_sh_slot_aux
+ sh_tk_split(IR_LOAD, TI_INT)
+ t5s_a3 := g_sh_slot_term
+ t5s_a3x := g_sh_slot_aux
+ sh_tk_split(IR_I2F, TI_DEX)
+ t5s_a4 := g_sh_slot_term
+ t5s_a4x := g_sh_slot_aux
+ sh_tk_split(IR_F2I, TI_DEX)
+ t5s_a5 := g_sh_slot_term
+ t5s_a5x := g_sh_slot_aux
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.slot_type_face_extended",
(t5s_a1 == sh_term_of_ti(TI_UNIT) && t5s_a1x == 0 && tt_a(t5s_a1) == AK_UNIT &&
- t5s_a2 == sh_term_of_ti(TI_INT) && t5s_a2x == 0 &&
- t5s_a3 == sh_term_of_ti(TI_INT) && t5s_a3x == 0 &&
- t5s_a4 == sh_term_of_ti(TI_DEX) && t5s_a4x == 0 && tt_a(t5s_a4) == AK_DEX &&
- t5s_a5 == sh_term_of_ti(TI_DEX) && t5s_a5x == 0 && tt_a(t5s_a5) == AK_DEX), true);
+ t5s_a2 == sh_term_of_ti(TI_INT) && t5s_a2x == 0 &&
+ t5s_a3 == sh_term_of_ti(TI_INT) && t5s_a3x == 0 &&
+ t5s_a4 == sh_term_of_ti(TI_DEX) && t5s_a4x == 0 && tt_a(t5s_a4) == AK_DEX &&
+ t5s_a5 == sh_term_of_ti(TI_DEX) && t5s_a5x == 0 && tt_a(t5s_a5) == AK_DEX), true)
// ── 新例 ④:复合行 ⇒ 走辅码(F2 裁决;码保真,派生码 ≡ 旧混用码)──
// 牙齿:先证该行**可译**(sh_term_of_ti ≥ 0)——否则「term = -1」可能出自不可译,
// 门形同虚设也能绿。
- sh_tk_split(IR_BINARY, t5s_ptr_row);
- total = total + 1; fails = fails + ts_check_b("p5t2.slot_composite_row_to_aux",
+ sh_tk_split(IR_BINARY, t5s_ptr_row)
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.slot_composite_row_to_aux",
(t5s_ptr_term >= 0 && g_sh_slot_term == -1 && g_sh_slot_aux == t5s_ptr_row &&
- sh_dfn_code_of_slots(g_sh_slot_term, g_sh_slot_aux) == t5s_ptr_row), true);
+ sh_dfn_code_of_slots(g_sh_slot_term, g_sh_slot_aux) == t5s_ptr_row), true)
// 同款:数组行(AK_SEQUENCE 的 b = 长度或 -1 ⇒ 复合)。
- t5s_arr_row := alloc_type(TYP_ARRAY, TI_INT, 3);
- sh_tk_split(IR_CONST, t5s_arr_row);
- total = total + 1; fails = fails + ts_check_b("p5t2.slot_array_row_to_aux",
+ t5s_arr_row := alloc_type(TYP_ARRAY, TI_INT, 3)
+ sh_tk_split(IR_CONST, t5s_arr_row)
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.slot_array_row_to_aux",
(sh_term_of_ti(t5s_arr_row) >= 0 && g_sh_slot_term == -1 &&
- g_sh_slot_aux == t5s_arr_row &&
- sh_dfn_code_of_slots(g_sh_slot_term, g_sh_slot_aux) == t5s_arr_row), true);
+ g_sh_slot_aux == t5s_arr_row &&
+ sh_dfn_code_of_slots(g_sh_slot_term, g_sh_slot_aux) == t5s_arr_row), true)
// ── 新例 ⑤:辅码面 —— 旗标 / 宽度 / 计数(含负码)原码保真 ──
- sh_tk_split(IR_BOUNDS_CHECK, 1); t5s_f1t := g_sh_slot_term; t5s_f1a := g_sh_slot_aux;
- sh_tk_split(IR_BOUNDS_CHECK, 0); t5s_f0t := g_sh_slot_term; t5s_f0a := g_sh_slot_aux;
- sh_tk_split(IR_DEREF, 8); t5s_d8t := g_sh_slot_term; t5s_d8a := g_sh_slot_aux;
- sh_tk_split(IR_STORE_PTR, 4); t5s_d4t := g_sh_slot_term; t5s_d4a := g_sh_slot_aux;
- sh_tk_split(IR_SPAWN, -1); t5s_spt := g_sh_slot_term; t5s_spa := g_sh_slot_aux;
- total = total + 1; fails = fails + ts_check_b("p5t2.slot_aux_face_codes",
+ sh_tk_split(IR_BOUNDS_CHECK, 1)
+ t5s_f1t := g_sh_slot_term
+ t5s_f1a := g_sh_slot_aux
+ sh_tk_split(IR_BOUNDS_CHECK, 0)
+ t5s_f0t := g_sh_slot_term
+ t5s_f0a := g_sh_slot_aux
+ sh_tk_split(IR_DEREF, 8)
+ t5s_d8t := g_sh_slot_term
+ t5s_d8a := g_sh_slot_aux
+ sh_tk_split(IR_STORE_PTR, 4)
+ t5s_d4t := g_sh_slot_term
+ t5s_d4a := g_sh_slot_aux
+ sh_tk_split(IR_SPAWN, -1)
+ t5s_spt := g_sh_slot_term
+ t5s_spa := g_sh_slot_aux
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.slot_aux_face_codes",
(t5s_f1t == -1 && t5s_f1a == 1 && sh_dfn_code_of_slots(t5s_f1t, t5s_f1a) == 1 &&
- t5s_f0t == -1 && t5s_f0a == 0 && sh_dfn_code_of_slots(t5s_f0t, t5s_f0a) == 0 &&
- t5s_d8t == -1 && t5s_d8a == 8 && sh_dfn_code_of_slots(t5s_d8t, t5s_d8a) == 8 &&
- t5s_d4t == -1 && t5s_d4a == 4 &&
- t5s_spt == -1 && t5s_spa == -1 && sh_dfn_code_of_slots(t5s_spt, t5s_spa) == -1), true);
+ t5s_f0t == -1 && t5s_f0a == 0 && sh_dfn_code_of_slots(t5s_f0t, t5s_f0a) == 0 &&
+ t5s_d8t == -1 && t5s_d8a == 8 && sh_dfn_code_of_slots(t5s_d8t, t5s_d8a) == 8 &&
+ t5s_d4t == -1 && t5s_d4a == 4 &&
+ t5s_spt == -1 && t5s_spa == -1 && sh_dfn_code_of_slots(t5s_spt, t5s_spa) == -1), true)
// 数值陷阱复证:辅码 1 / 8 直译确有其项(TI_DEX / TI_DEX_S 行)——分类门才是拦阻者。
- total = total + 1; fails = fails + ts_check_b("p5t2.aux_trap_rows_translatable",
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.aux_trap_rows_translatable",
(sh_term_of_ti(1) >= 0 && tt_a(sh_term_of_ti(1)) == AK_DEX &&
- sh_term_of_ti(TI_DEX_S) >= 0 && tt_a(sh_term_of_ti(TI_DEX_S)) == AK_DEX &&
- sh_tk_term_of_code(IR_STORE_PTR, TI_DEX_S) == -1), true);
+ sh_term_of_ti(TI_DEX_S) >= 0 && tt_a(sh_term_of_ti(TI_DEX_S)) == AK_DEX &&
+ sh_tk_term_of_code(IR_STORE_PTR, TI_DEX_S) == -1), true)
// ── 新例 ⑥:面外 op ⇒ 两槽皆空、派生码 0(含 LOAD_ENUM_TAG = Task 0 再裁「无」)──
- sh_tk_split(IR_STORE, 0); t5s_n1t := g_sh_slot_term; t5s_n1a := g_sh_slot_aux;
- sh_tk_split(IR_LOAD_ENUM_TAG, 0); t5s_n2t := g_sh_slot_term; t5s_n2a := g_sh_slot_aux;
- sh_tk_split(IR_LABEL, 0); t5s_n3t := g_sh_slot_term; t5s_n3a := g_sh_slot_aux;
- total = total + 1; fails = fails + ts_check_b("p5t2.slot_none_face_empty",
+ sh_tk_split(IR_STORE, 0)
+ t5s_n1t := g_sh_slot_term
+ t5s_n1a := g_sh_slot_aux
+ sh_tk_split(IR_LOAD_ENUM_TAG, 0)
+ t5s_n2t := g_sh_slot_term
+ t5s_n2a := g_sh_slot_aux
+ sh_tk_split(IR_LABEL, 0)
+ t5s_n3t := g_sh_slot_term
+ t5s_n3a := g_sh_slot_aux
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.slot_none_face_empty",
(t5s_n1t == -1 && t5s_n1a == 0 && sh_dfn_code_of_slots(t5s_n1t, t5s_n1a) == 0 &&
- t5s_n2t == -1 && t5s_n2a == 0 && t5s_n3t == -1 && t5s_n3a == 0), true);
+ t5s_n2t == -1 && t5s_n2a == 0 && t5s_n3t == -1 && t5s_n3a == 0), true)
// ── 新例 ⑦:派生码契约(辅码优先 / 无项⇒0 / 不可逆⇒-1 显式)──
- total = total + 1; fails = fails + ts_check_b("p5t2.code_derivation_contract",
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.code_derivation_contract",
(sh_dfn_code_of_slots(sh_term_of_ti(TI_STR), 0) == TI_STR &&
- sh_dfn_code_of_slots(-1, 0) == 0 &&
- sh_dfn_code_of_slots(-1, 7) == 7 &&
- sh_dfn_code_of_slots(t5s_ptr_term, 0) == -1 && // 复合项入项槽 = 无法派生(显式响亮)
- sh_dfn_code_of_slots(sh_term_of_ti(TI_INT), 9) == 9), true); // 辅码优先(互斥由拆分器保证)
+ sh_dfn_code_of_slots(-1, 0) == 0 &&
+ sh_dfn_code_of_slots(-1, 7) == 7 &&
+ sh_dfn_code_of_slots(t5s_ptr_term, 0) == -1 && // 复合项入项槽 = 无法派生(显式响亮)
+ sh_dfn_code_of_slots(sh_term_of_ti(TI_INT), 9) == 9), true) // 辅码优先(互斥由拆分器保证)
// ── 新例 ⑧:互斥不变量(D22-②)逐 op 复核(面 0 / 面 1 / 面 2 各取代表)──
- sh_tk_split(IR_CONST, TI_STR); t5s_m1 := (g_sh_slot_term >= 0 && g_sh_slot_aux == 0);
- sh_tk_split(IR_DEREF, 8); t5s_m2 := (g_sh_slot_term == -1 && g_sh_slot_aux != 0);
- sh_tk_split(IR_STORE, 0); t5s_m3 := (g_sh_slot_term == -1 && g_sh_slot_aux == 0);
- t5s_m_ok := 1;
- if t5s_m1 == 0 || t5s_m2 == 0 || t5s_m3 == 0 { t5s_m_ok = 0; }
- total = total + 1; fails = fails + ts_check("p5t2.slot_mutual_exclusion", t5s_m_ok, 1);
+ sh_tk_split(IR_CONST, TI_STR)
+ t5s_m1 := (g_sh_slot_term >= 0 && g_sh_slot_aux == 0)
+ sh_tk_split(IR_DEREF, 8)
+ t5s_m2 := (g_sh_slot_term == -1 && g_sh_slot_aux != 0)
+ sh_tk_split(IR_STORE, 0)
+ t5s_m3 := (g_sh_slot_term == -1 && g_sh_slot_aux == 0)
+ t5s_m_ok := 1
+ if t5s_m1 == 0 || t5s_m2 == 0 || t5s_m3 == 0:
+ t5s_m_ok = 0
+ total = total + 1
+ fails = fails + ts_check("p5t2.slot_mutual_exclusion", t5s_m_ok, 1)
// ── 新例 ⑨:F1 修正(IR_HOTPATCH_ROUTE 的类型面 = 无;显式 0 实参 ⇒ 两槽皆空)──
- sh_tk_split(IR_HOTPATCH_ROUTE, 0);
- total = total + 1; fails = fails + ts_check_b("p5t2.hotpatch_route_no_face",
+ sh_tk_split(IR_HOTPATCH_ROUTE, 0)
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.hotpatch_route_no_face",
(g_sh_slot_term == -1 && g_sh_slot_aux == 0 &&
- sh_dfn_code_of_slots(g_sh_slot_term, g_sh_slot_aux) == 0), true);
+ sh_dfn_code_of_slots(g_sh_slot_term, g_sh_slot_aux) == 0), true)
// ── 新例 ⑩:D23 建项失败位(越界类型面行 ⇒ 计数 +1;复合行**不**置位)──
- t5s_fail_before := g_tk_face_fail;
- sh_tk_split(IR_CONST, g_type_count);
- t5s_fail_after := g_tk_face_fail;
- t5s_out_t := g_sh_slot_term; // 出参须**即时**取(下一次 split 会覆写)
- t5s_out_a := g_sh_slot_aux;
- sh_tk_split(IR_BINARY, t5s_ptr_row); // 复合行 = 域内可译 ⇒ 不得置位
- t5s_fail_final := g_tk_face_fail;
- g_tk_face_fail = 0; // 复位(不污染后续落盘闸用例)
- total = total + 1; fails = fails + ts_check_b("p5t2.d23_build_fail_bit",
+ t5s_fail_before := g_tk_face_fail
+ sh_tk_split(IR_CONST, g_type_count)
+ t5s_fail_after := g_tk_face_fail
+ t5s_out_t := g_sh_slot_term // 出参须**即时**取(下一次 split 会覆写)
+ t5s_out_a := g_sh_slot_aux
+ sh_tk_split(IR_BINARY, t5s_ptr_row) // 复合行 = 域内可译 ⇒ 不得置位
+ t5s_fail_final := g_tk_face_fail
+ g_tk_face_fail = 0 // 复位(不污染后续落盘闸用例)
+ total = total + 1
+ fails = fails + ts_check_b("p5t2.d23_build_fail_bit",
(t5s_fail_after == t5s_fail_before + 1 && t5s_fail_final == t5s_fail_after &&
- t5s_out_t == -1 && t5s_out_a == g_type_count), true);
+ t5s_out_t == -1 && t5s_out_a == g_type_count), true)
// TYP_NAMED:AK_NAMED + 行号存 b 槽(引擎不展开 → 判定 UNKNOWN = P1 预期未覆盖面)
// ⚠️ 本行**刻意走裸分配**(P2a Task 1 后 8 个生产分配点已收敛到 alloc_named_type):
// 它构造的是人造 TYP_NAMED 行(键 1201 不对应任何真名),登记进生产侧表会用假键污染
// name→ti 映射(自测将来若被并入编译路径即静默错型)。裸分配 = 不登记 = 不污染。
- named_ti := alloc_type(TYP_NAMED, 1201, 0);
- t_named := sh_term_of_ti(named_ti);
- total = total + 1; fails = fails + ts_check_b("bridge.named_ak_b",
- (tt_a(t_named) == AK_NAMED && tt_b(t_named) == named_ti), true);
+ named_ti := alloc_type(TYP_NAMED, 1201, 0)
+ t_named := sh_term_of_ti(named_ti)
+ total = total + 1
+ fails = fails + ts_check_b("bridge.named_ak_b",
+ (tt_a(t_named) == AK_NAMED && tt_b(t_named) == named_ti), true)
// TYP_TUPLE 实读布局(checker.cr:118 type_equal 分支 + :2041+ 字段访问 t.N):
// data = 字段数,extra = 字段 ti 在 g_gen_apply_data 的起始下标(8B/元素)
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- tup_start := g_gen_apply_data_count;
- w64(g_gen_apply_data, tup_start * 8, TI_INT);
- w64(g_gen_apply_data, (tup_start + 1) * 8, TI_STR);
- g_gen_apply_data_count = g_gen_apply_data_count + 2;
- t_tup := sh_term_of_ti(alloc_type(TYP_TUPLE, 2, tup_start));
- total = total + 1; fails = fails + ts_check("bridge.tuple_product", tt_a(t_tup), AK_PRODUCT);
- total = total + 1; fails = fails + ts_check("bridge.tuple_fields",
- tt_c(t_tup), tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil())));
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ tup_start := g_gen_apply_data_count
+ w64(g_gen_apply_data, tup_start * 8, TI_INT)
+ w64(g_gen_apply_data, (tup_start + 1) * 8, TI_STR)
+ g_gen_apply_data_count = g_gen_apply_data_count + 2
+ t_tup := sh_term_of_ti(alloc_type(TYP_TUPLE, 2, tup_start))
+ total = total + 1
+ fails = fails + ts_check("bridge.tuple_product", tt_a(t_tup), AK_PRODUCT)
+ total = total + 1
+ fails = fails + ts_check("bridge.tuple_fields",
+ tt_c(t_tup), tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil())))
// 缓存语义:新 ti 恰入表 1 条(其元素 = 原生快路径,不入表);同 ti 二次调用 = 命中
// (**P5 T5 重钉**:原断言 = hits 计数恰 +1;影子 hits 通道已随影子层下线 ⇒ 改钉
// 「命中 ⇒ 同项 + 不新增条目」——同一语义的占用面证据,不再依赖计数器)。
- e_before := sh_map_entries();
- arr_ti2 := alloc_type(TYP_ARRAY, TI_STR, 9);
- t_arr2 := sh_term_of_ti(arr_ti2);
- total = total + 1; fails = fails + ts_check("bridge.entries_delta", (sh_map_entries() - e_before), 1);
- e_hit_before := sh_map_entries();
- t_arr2b := sh_term_of_ti(arr_ti2);
- total = total + 1; fails = fails + ts_check_b("bridge.cache_hit_same_term_no_new_entry",
- (t_arr2b == t_arr2 && sh_map_entries() == e_hit_before), true);
+ e_before := sh_map_entries()
+ arr_ti2 := alloc_type(TYP_ARRAY, TI_STR, 9)
+ t_arr2 := sh_term_of_ti(arr_ti2)
+ total = total + 1
+ fails = fails + ts_check("bridge.entries_delta", (sh_map_entries() - e_before), 1)
+ e_hit_before := sh_map_entries()
+ t_arr2b := sh_term_of_ti(arr_ti2)
+ total = total + 1
+ fails = fails + ts_check_b("bridge.cache_hit_same_term_no_new_entry",
+ (t_arr2b == t_arr2 && sh_map_entries() == e_hit_before), true)
// 缓存扩容/重建守门(P0「扩容路径判据不可达」教训同款):上面仅 8 条 << 初始容量
// 1024 → 装填因子守卫/重建路径**不可达**。用 600 个互异 ti(extra=N 各不同 = 互异
// 类型表行,正是「N 不入身份」下 600 行同项的典型规模)逼出一次扩容重建(守卫
// (entries+1)*2 >= cap 在 entries=511 时触发);再验两件事:①重放守恒(条目数恰
// +600,不多不少)②重建**前**已入表的条目仍命中(重放把旧表条目全搬过去了)。
- g_before := sh_map_entries();
- gi : ., mut = 0;
- loop {
- if gi >= 600 { break; }
- sh_term_of_ti(alloc_type(TYP_ARRAY, TI_INT, 1000 + gi));
- gi = gi + 1;
- }
- total = total + 1; fails = fails + ts_check_b("bridge.grow_rehash",
- (sh_map_entries() == g_before + 600 && sh_term_of_ti(arr_ti2) == t_arr2), true);
- total = total + 1; fails = fails + ts_check_b("bridge.grow_cap_doubled", (g_term_map_cap >= 2048), true);
+ g_before := sh_map_entries()
+ gi : ., mut = 0
+ loop:
+ if gi >= 600:
+ break
+ sh_term_of_ti(alloc_type(TYP_ARRAY, TI_INT, 1000 + gi))
+ gi = gi + 1
+ total = total + 1
+ fails = fails + ts_check_b("bridge.grow_rehash",
+ (sh_map_entries() == g_before + 600 && sh_term_of_ti(arr_ti2) == t_arr2), true)
+ total = total + 1
+ fails = fails + ts_check_b("bridge.grow_cap_doubled", (g_term_map_cap >= 2048), true)
// 第二次重建守门(Step 4b ②,Task 1 评审挂账:「>1024 条目第二次重建无实测」):
// 上一例只推过第一条守卫线(entries=511 → cap 1024→2048);本例再入 1100 条互异 ti
// 把条目推过第二条守卫线(entries=1023 → cap 2048→4096)——断三件事:①重放守恒(恰
// +1100,不多不少)②cap ≥ 4096(**证明**第二次重建真的发生,不是「读码判安全」)
// ③首批(第一次重建前入表)条目仍命中(两次重放都把它搬过去了)。
- g2_before := sh_map_entries();
- gj : ., mut = 0;
- loop {
- if gj >= 1100 { break; }
- sh_term_of_ti(alloc_type(TYP_ARRAY, TI_INT, 5000 + gj));
- gj = gj + 1;
- }
- total = total + 1; fails = fails + ts_check_b("bridge.grow_rehash2",
- (sh_map_entries() == g2_before + 1100 && g_term_map_cap >= 4096 && sh_term_of_ti(arr_ti2) == t_arr2), true);
+ g2_before := sh_map_entries()
+ gj : ., mut = 0
+ loop:
+ if gj >= 1100:
+ break
+ sh_term_of_ti(alloc_type(TYP_ARRAY, TI_INT, 5000 + gj))
+ gj = gj + 1
+ total = total + 1
+ fails = fails + ts_check_b("bridge.grow_rehash2",
+ (sh_map_entries() == g2_before + 1100 && g_term_map_cap >= 4096 && sh_term_of_ti(arr_ti2) == t_arr2), true)
// --- F1(R2 P2a Task 1):同名 TYP_NAMED 归一行 —— P1 影子对拍 9/9 差异根因消除 ---
// 根因:同一类型名(struct 字面量 / 泛型应用基型在不同**出现点**)各建一行 → 桥接按行
// 建原子(AK_NAMED 的 b 槽 = 行号)→ 引擎视两行为互异命名类型 → 判不了(9 条 unknown)。
// 修法(用户裁决 = 根治):建表去重,唯一分配点收敛到 alloc_named_type。
- n1 := alloc_named_type(str_intern("DedupProbe"));
- n2 := alloc_named_type(str_intern("DedupProbe"));
- total = total + 1; fails = fails + ts_check_b("f1.same_name_one_row", (n1 == n2), true);
- total = total + 1; fails = fails + ts_check("f1.row_count", named_dedup_rows(str_intern("DedupProbe")), 1);
- n3 := alloc_named_type(str_intern("DedupProbe2"));
- total = total + 1; fails = fails + ts_check_b("f1.diff_name_diff_row", (n3 != n1), true);
+ n1 := alloc_named_type(str_intern("DedupProbe"))
+ n2 := alloc_named_type(str_intern("DedupProbe"))
+ total = total + 1
+ fails = fails + ts_check_b("f1.same_name_one_row", (n1 == n2), true)
+ total = total + 1
+ fails = fails + ts_check("f1.row_count", named_dedup_rows(str_intern("DedupProbe")), 1)
+ n3 := alloc_named_type(str_intern("DedupProbe2"))
+ total = total + 1
+ fails = fails + ts_check_b("f1.diff_name_diff_row", (n3 != n1), true)
// 引擎侧:同名两行归一后,桥接的同一性成立(P1 的 9 unknown 根因消除)
- total = total + 1; fails = fails + ts_check_b("f1.bridge_same_term",
- (sh_term_of_ti(n1) == sh_term_of_ti(n2)), true);
+ total = total + 1
+ fails = fails + ts_check_b("f1.bridge_same_term",
+ (sh_term_of_ti(n1) == sh_term_of_ti(n2)), true)
// 扩容/重建覆盖(P0/P1 血泪教训:装填守卫/重建重放路径判据不可达 = 挂死风险只靠读码):
// 入 1700 个互异**真名**(键域 = str_intern 分配的名字下标,与生产同域)推过**两道**
// 守卫线——count=511 → cap 1024→2048,count=1023 → 2048→4096。断四件事:①两次重建都
// 真的发生(cap≥4096,非「读码判安全」)②重放守恒(条目计数恰 +1700,不多不少——
// 重放漏条目/重复计数即红)③首条(重建前入表)仍归**原行**(重放把旧条目全搬过去了)
// ④该名字行数仍为 1(重建不产生重复行 = 去重不因扩容失效)。
- c_before := g_named_dedup_count;
- f1i : ., mut = 0;
- loop {
- if f1i >= 1700 { break; }
- alloc_named_type(str_intern("DedupGrow" + int_str(f1i)));
- f1i = f1i + 1;
- }
- total = total + 1; fails = fails + ts_check_b("f1.dedup_rehash_survived",
- (g_named_dedup_cap >= 4096 && g_named_dedup_count == c_before + 1700 && alloc_named_type(str_intern("DedupProbe")) == n1 && named_dedup_rows(str_intern("DedupProbe")) == 1), true);
+ c_before := g_named_dedup_count
+ f1i : ., mut = 0
+ loop:
+ if f1i >= 1700:
+ break
+ alloc_named_type(str_intern("DedupGrow" + int_str(f1i)))
+ f1i = f1i + 1
+ total = total + 1
+ fails = fails + ts_check_b("f1.dedup_rehash_survived",
+ (g_named_dedup_cap >= 4096 && g_named_dedup_count == c_before + 1700 && alloc_named_type(str_intern("DedupProbe")) == n1 && named_dedup_rows(str_intern("DedupProbe")) == 1), true)
// --- F2(R2 P2a Task 2):数组长度 N 迁为「常量档长度约束」 ---
// 背景(P1 findings §6.F2):身份判等曾把 N 与元素判等绑在一起(N 属身份);引擎侧按
@@ -2281,80 +2508,93 @@ fn type_selftest_run() -> int {
// 修法(用户裁决 = 落常量档长度约束):N 迁出身份 → 具名约束 array_len_constraint_ok
// (判定点显式补检);拒绝语义保持(异长仍拒、同长仍过)。本组即该约束的守门用例。
// 默认预算窗口(ty_equiv 用例计数)——本组之前的用例只碰过裸分配/侧表,未跑判定。
- ty_budget_reset(200000);
- f2_arr3 := alloc_type(TYP_ARRAY, TI_INT, 3);
- f2_arr3b := alloc_type(TYP_ARRAY, TI_INT, 3); // **另一行**同长:约束不可是 ti 同一性
- f2_arr4 := alloc_type(TYP_ARRAY, TI_INT, 4);
- total = total + 1; fails = fails + ts_check("f2.same_len_ok",
- array_len_constraint_ok(f2_arr3, f2_arr3b), 1);
- total = total + 1; fails = fails + ts_check("f2.diff_len_reject",
- array_len_constraint_ok(f2_arr4, f2_arr3), 0);
+ ty_budget_reset(200000)
+ f2_arr3 := alloc_type(TYP_ARRAY, TI_INT, 3)
+ f2_arr3b := alloc_type(TYP_ARRAY, TI_INT, 3) // **另一行**同长:约束不可是 ti 同一性
+ f2_arr4 := alloc_type(TYP_ARRAY, TI_INT, 4)
+ total = total + 1
+ fails = fails + ts_check("f2.same_len_ok",
+ array_len_constraint_ok(f2_arr3, f2_arr3b), 1)
+ total = total + 1
+ fails = fails + ts_check("f2.diff_len_reject",
+ array_len_constraint_ok(f2_arr4, f2_arr3), 0)
// 引擎侧:N 不入身份(spec §5.1;与 bridge.len_not_identity 同义,此处另立一行)
- total = total + 1; fails = fails + ts_check("f2.engine_len_agnostic",
- ty_equiv(sh_term_of_ti(f2_arr4), sh_term_of_ti(f2_arr3)), 1);
+ total = total + 1
+ fails = fails + ts_check("f2.engine_len_agnostic",
+ ty_equiv(sh_term_of_ti(f2_arr4), sh_term_of_ti(f2_arr3)), 1)
// 结构下钻(N 不在顶层数组位也要拦住——否则身份去 N 后这些位置静默放宽):
// ① 数组元素位 `[[int;3];2]`;② 泛型应用实参位 `G<[int;3]>`;③ 指针元素位 `*[int;3]`;
// ④ 元组字段位 `(int, [int;3])`。每例双断:同结构同长 → 1 / 同结构异长 → 0(防误拒)。
- f2_outer3 := alloc_type(TYP_ARRAY, f2_arr3, 2);
- f2_outer4 := alloc_type(TYP_ARRAY, f2_arr4, 2);
- total = total + 1; fails = fails + ts_check_b("f2.nested_elem_reject",
- (array_len_constraint_ok(f2_outer3, f2_outer3) == 1 && array_len_constraint_ok(f2_outer4, f2_outer3) == 0), true);
- grow_gen_apply_data(g_gen_apply_data_count + 4);
- f2_ga_s1 := g_gen_apply_data_count;
- w64(g_gen_apply_data, f2_ga_s1 * 8, 1);
- w64(g_gen_apply_data, (f2_ga_s1 + 1) * 8, f2_arr3);
- f2_ga_s2 := f2_ga_s1 + 2;
- w64(g_gen_apply_data, f2_ga_s2 * 8, 1);
- w64(g_gen_apply_data, (f2_ga_s2 + 1) * 8, f2_arr4);
- g_gen_apply_data_count = f2_ga_s2 + 2;
+ f2_outer3 := alloc_type(TYP_ARRAY, f2_arr3, 2)
+ f2_outer4 := alloc_type(TYP_ARRAY, f2_arr4, 2)
+ total = total + 1
+ fails = fails + ts_check_b("f2.nested_elem_reject",
+ (array_len_constraint_ok(f2_outer3, f2_outer3) == 1 && array_len_constraint_ok(f2_outer4, f2_outer3) == 0), true)
+ grow_gen_apply_data(g_gen_apply_data_count + 4)
+ f2_ga_s1 := g_gen_apply_data_count
+ w64(g_gen_apply_data, f2_ga_s1 * 8, 1)
+ w64(g_gen_apply_data, (f2_ga_s1 + 1) * 8, f2_arr3)
+ f2_ga_s2 := f2_ga_s1 + 2
+ w64(g_gen_apply_data, f2_ga_s2 * 8, 1)
+ w64(g_gen_apply_data, (f2_ga_s2 + 1) * 8, f2_arr4)
+ g_gen_apply_data_count = f2_ga_s2 + 2
// base 走**裸分配**(人造行不入侧表——P1 桥接夹具同款约定,防假键污染 name→ti)
- f2_base := alloc_type(TYP_NAMED, 1202, 0);
- f2_ga3 := alloc_type(TYP_GENERIC_APPLY, f2_base, f2_ga_s1);
- f2_ga4 := alloc_type(TYP_GENERIC_APPLY, f2_base, f2_ga_s2);
- total = total + 1; fails = fails + ts_check_b("f2.genapply_arg_reject",
- (array_len_constraint_ok(f2_ga3, f2_ga3) == 1 && array_len_constraint_ok(f2_ga4, f2_ga3) == 0), true);
- f2_pt3 := alloc_type(TYP_PTR, f2_arr3, 0);
- f2_pt4 := alloc_type(TYP_PTR, f2_arr4, 0);
- total = total + 1; fails = fails + ts_check_b("f2.ptr_elem_reject",
- (array_len_constraint_ok(f2_pt3, f2_pt3) == 1 && array_len_constraint_ok(f2_pt4, f2_pt3) == 0), true);
- grow_gen_apply_data(g_gen_apply_data_count + 4);
- f2_tp_s1 := g_gen_apply_data_count;
- w64(g_gen_apply_data, f2_tp_s1 * 8, TI_INT);
- w64(g_gen_apply_data, (f2_tp_s1 + 1) * 8, f2_arr3);
- f2_tp_s2 := f2_tp_s1 + 2;
- w64(g_gen_apply_data, f2_tp_s2 * 8, TI_INT);
- w64(g_gen_apply_data, (f2_tp_s2 + 1) * 8, f2_arr4);
- g_gen_apply_data_count = f2_tp_s2 + 2;
- f2_tup3 := alloc_type(TYP_TUPLE, 2, f2_tp_s1);
- f2_tup4 := alloc_type(TYP_TUPLE, 2, f2_tp_s2);
- total = total + 1; fails = fails + ts_check_b("f2.tuple_field_reject",
- (array_len_constraint_ok(f2_tup3, f2_tup3) == 1 && array_len_constraint_ok(f2_tup4, f2_tup3) == 0), true);
+ f2_base := alloc_type(TYP_NAMED, 1202, 0)
+ f2_ga3 := alloc_type(TYP_GENERIC_APPLY, f2_base, f2_ga_s1)
+ f2_ga4 := alloc_type(TYP_GENERIC_APPLY, f2_base, f2_ga_s2)
+ total = total + 1
+ fails = fails + ts_check_b("f2.genapply_arg_reject",
+ (array_len_constraint_ok(f2_ga3, f2_ga3) == 1 && array_len_constraint_ok(f2_ga4, f2_ga3) == 0), true)
+ f2_pt3 := alloc_type(TYP_PTR, f2_arr3, 0)
+ f2_pt4 := alloc_type(TYP_PTR, f2_arr4, 0)
+ total = total + 1
+ fails = fails + ts_check_b("f2.ptr_elem_reject",
+ (array_len_constraint_ok(f2_pt3, f2_pt3) == 1 && array_len_constraint_ok(f2_pt4, f2_pt3) == 0), true)
+ grow_gen_apply_data(g_gen_apply_data_count + 4)
+ f2_tp_s1 := g_gen_apply_data_count
+ w64(g_gen_apply_data, f2_tp_s1 * 8, TI_INT)
+ w64(g_gen_apply_data, (f2_tp_s1 + 1) * 8, f2_arr3)
+ f2_tp_s2 := f2_tp_s1 + 2
+ w64(g_gen_apply_data, f2_tp_s2 * 8, TI_INT)
+ w64(g_gen_apply_data, (f2_tp_s2 + 1) * 8, f2_arr4)
+ g_gen_apply_data_count = f2_tp_s2 + 2
+ f2_tup3 := alloc_type(TYP_TUPLE, 2, f2_tp_s1)
+ f2_tup4 := alloc_type(TYP_TUPLE, 2, f2_tp_s2)
+ total = total + 1
+ fails = fails + ts_check_b("f2.tuple_field_reject",
+ (array_len_constraint_ok(f2_tup3, f2_tup3) == 1 && array_len_constraint_ok(f2_tup4, f2_tup3) == 0), true)
// 负控:非数组对(含单侧数组)长度面无约束 → 恒满足(防「一律拒绝」的退化实现)
- total = total + 1; fails = fails + ts_check_b("f2.nonarray_no_constraint",
- (array_len_constraint_ok(f2_arr3, TI_INT) == 1 && array_len_constraint_ok(TI_INT, f2_arr3) == 1), true);
+ total = total + 1
+ fails = fails + ts_check_b("f2.nonarray_no_constraint",
+ (array_len_constraint_ok(f2_arr3, TI_INT) == 1 && array_len_constraint_ok(TI_INT, f2_arr3) == 1), true)
// Task 4 Step 5c(Task 2 评审 M2 收口):① 补齐约束的 REF / SLICE 两个递归位(此前已钉
// 数组元素 / 泛型实参 / 指针元素 / 元组字段四位,下钻面 6 位里缺这两位);② 把**站点接线**
// 纳入自测面——站点的措辞由 type_compat_strict 的**三态**分派(1 = 兼容 / 0 = 身份不匹配
// → 原措辞 / -1 = 身份通过但长度约束违反 → 专属措辞),故 0 与 -1 的**区分**本身就是判据
// (把两路并成一路 = 措辞面回归,且会把「长度不满足」误报成普通类型不匹配)。
// REF 位注:约束只看 data(元素),**不**比 extra(mut)——mut 归身份判定(头注「同形」限定)。
- f2_rf3 := alloc_type(TYP_REF, f2_arr3, 0);
- f2_rf4 := alloc_type(TYP_REF, f2_arr4, 0);
- total = total + 1; fails = fails + ts_check_b("f2.ref_elem_reject",
- (array_len_constraint_ok(f2_rf3, f2_rf3) == 1 && array_len_constraint_ok(f2_rf4, f2_rf3) == 0), true);
- f2_sl3 := alloc_type(TYP_SLICE, f2_arr3, 0);
- f2_sl4 := alloc_type(TYP_SLICE, f2_arr4, 0);
- total = total + 1; fails = fails + ts_check_b("f2.slice_elem_reject",
- (array_len_constraint_ok(f2_sl3, f2_sl3) == 1 && array_len_constraint_ok(f2_sl4, f2_sl3) == 0), true);
+ f2_rf3 := alloc_type(TYP_REF, f2_arr3, 0)
+ f2_rf4 := alloc_type(TYP_REF, f2_arr4, 0)
+ total = total + 1
+ fails = fails + ts_check_b("f2.ref_elem_reject",
+ (array_len_constraint_ok(f2_rf3, f2_rf3) == 1 && array_len_constraint_ok(f2_rf4, f2_rf3) == 0), true)
+ f2_sl3 := alloc_type(TYP_SLICE, f2_arr3, 0)
+ f2_sl4 := alloc_type(TYP_SLICE, f2_arr4, 0)
+ total = total + 1
+ fails = fails + ts_check_b("f2.slice_elem_reject",
+ (array_len_constraint_ok(f2_sl3, f2_sl3) == 1 && array_len_constraint_ok(f2_sl4, f2_sl3) == 0), true)
// 站点三态(type_compat_strict 恒「先 type_equal 再约束」,站点调用面不变):
// ① 同结构同长 → 1;② 异结构(数组 vs 基类型)→ 0(身份面否决,原措辞);③ 同结构异长
// → -1(**只有**这一路走长度措辞;且它证明 type_equal 已放行 = 引擎身份确实 N-free)。
- total = total + 1; fails = fails + ts_check("t3.strict_dispatch_ok",
- type_compat_strict(f2_arr3, f2_arr3b), 1);
- total = total + 1; fails = fails + ts_check("t3.strict_dispatch_identity",
- type_compat_strict(f2_arr3, TI_INT), 0);
- total = total + 1; fails = fails + ts_check("t3.strict_dispatch_len",
- type_compat_strict(f2_arr4, f2_arr3), -1);
+ total = total + 1
+ fails = fails + ts_check("t3.strict_dispatch_ok",
+ type_compat_strict(f2_arr3, f2_arr3b), 1)
+ total = total + 1
+ fails = fails + ts_check("t3.strict_dispatch_identity",
+ type_compat_strict(f2_arr3, TI_INT), 0)
+ total = total + 1
+ fails = fails + ts_check("t3.strict_dispatch_len",
+ type_compat_strict(f2_arr4, f2_arr3), -1)
// --- R2 P2a Task 3:判定替换(引擎为判定权威 + unknown 政策 + N 不回身份)---
// ① N 面(Task 2/3 评审裁决「N 不得回身份」):`type_equal`(引擎判定)对**同结构异长**
@@ -2364,40 +2604,42 @@ fn type_selftest_run() -> int {
// 引擎**自决 0**(不再未知 ⇒ 零回落);T4 后回落本体已删 ⇒ 断言 = 「自决 + 零未知
// 诊断(ICE04 缺席)」。**不得静默当 0/1** 的牙齿在 t4.ice04_* 三例(真未知面)。
// ③ 同一行快路径:不触发引擎/回落(同型自反恒 true)。
- ty_budget_reset(200000);
- t3_arr3 := alloc_type(TYP_ARRAY, TI_INT, 3);
- t3_arr4 := alloc_type(TYP_ARRAY, TI_INT, 4);
- t3_ok : ., mut = 0;
- if type_equal(t3_arr3, t3_arr4) {
- if array_len_constraint_ok(t3_arr4, t3_arr3) == 0 { t3_ok = 1; }
- }
- total = total + 1; fails = fails + ts_check("t3.engine_len_not_identity", t3_ok, 1);
+ ty_budget_reset(200000)
+ t3_arr3 := alloc_type(TYP_ARRAY, TI_INT, 3)
+ t3_arr4 := alloc_type(TYP_ARRAY, TI_INT, 4)
+ t3_ok : ., mut = 0
+ if type_equal(t3_arr3, t3_arr4):
+ if array_len_constraint_ok(t3_arr4, t3_arr3) == 0:
+ t3_ok = 1
+ total = total + 1
+ fails = fails + ts_check("t3.engine_len_not_identity", t3_ok, 1)
// 行 1203/1204 = 人造行(不进生产侧表语义面;alloc_named_type 仅为取得互异 named 行)
- t3_na := alloc_named_type(str_intern("T3NamedA"));
- t3_nb := alloc_named_type(str_intern("T3NamedB"));
+ t3_na := alloc_named_type(str_intern("T3NamedA"))
+ t3_nb := alloc_named_type(str_intern("T3NamedB"))
// **R2 P5 Task 3 重钉 / T4 终态**:命名面接引擎(身份链)后本形态 = 引擎**自决 0**
// (= legacy 同值),不再回落——T4 后回落计数本体亦删 ⇒ 断言形态 = 「行为(false)+
// 引擎直判 0 + **零未知诊断**(ICE04 缺席 = 引擎真判而非未知被静默当 false)」。
- t3_d0 := g_diag_count;
- t3_ub : ., mut = 0;
- if !type_equal(t3_na, t3_nb) {
- if g_diag_count == t3_d0 { t3_ub = 1; }
- }
- total = total + 1; fails = fails + ts_check_b("t3.named_face_decided_no_indeterminate",
- (t3_ub == 1 && ty_equiv(sh_term_of_ti(t3_na), sh_term_of_ti(t3_nb)) == 0), true);
+ t3_d0 := g_diag_count
+ t3_ub : ., mut = 0
+ if !type_equal(t3_na, t3_nb):
+ if g_diag_count == t3_d0:
+ t3_ub = 1
+ total = total + 1
+ fails = fails + ts_check_b("t3.named_face_decided_no_indeterminate",
+ (t3_ub == 1 && ty_equiv(sh_term_of_ti(t3_na), sh_term_of_ti(t3_nb)) == 0), true)
// 桥接缺口(sh_term_of_ti 译不成项:行号越界)→ **P-A 硬错**(T4 重钉:旧行为 = 回落
// legacy + g_replace_bridge 计数;现行为 = 判 false + ICE04 诊断恰 1 条)。措辞/成因面
// 由 t4.ice04_* 段复核(本例只钉「行为 + 码」)。
- t3_bf_d0 := g_diag_count;
- t3_bf : ., mut = 0;
- if !type_equal(g_type_count + 100, TI_INT) {
- if g_diag_count == t3_bf_d0 + 1 {
- if ts_diag_code_at(t3_bf_d0) == EC_ICE_TY_INDET { t3_bf = 1; }
- }
- }
- total = total + 1; fails = fails + ts_check("t3.bridge_gap_ice04_hard_error", t3_bf, 1);
- g_diag_count = t3_bf_d0; // 本诊断是**故意**触发的(复位:不留进后续用例的增量基线)
- ty_budget_reset(200000);
+ t3_bf_d0 := g_diag_count
+ t3_bf : ., mut = 0
+ if !type_equal(g_type_count + 100, TI_INT):
+ if g_diag_count == t3_bf_d0 + 1:
+ if ts_diag_code_at(t3_bf_d0) == EC_ICE_TY_INDET:
+ t3_bf = 1
+ total = total + 1
+ fails = fails + ts_check("t3.bridge_gap_ice04_hard_error", t3_bf, 1)
+ g_diag_count = t3_bf_d0 // 本诊断是**故意**触发的(复位:不留进后续用例的增量基线)
+ ty_budget_reset(200000)
// --- R2 P2a Task 3 评审 Critical:桥接缓存**随类型表重置失效**(sh_map_reset)---
// 机制:判定路径**无条件**调 sh_term_of_ti(R2 P2a Task 3 起;此前仅 --type-shadow 下译项,
@@ -2407,25 +2649,27 @@ fn type_selftest_run() -> int {
// 用例 ① 重置后缓存确实清空(entries 0 + cap 0 = 惰性重建);② 行号复用场景下**不得**返回
// 陈旧项——返回的必须是新类型的项(元素 AK 由 int 变 bool)。② 是 ① 的行为级对偶:
// 只查计数不查返回值的断言在「清了计数但表还活着」的错法下会假绿。
- init_types(); // 干净起点(同时建立缓存基线)
- t3c_tiA := alloc_type(TYP_ARRAY, TI_INT, 2); // 行号 T
- t3c_termA := sh_term_of_ti(t3c_tiA); // 缓存 {T → seq(int)}
- t3c_entries_mid := sh_map_entries();
- init_types(); // 类型表 + 桥接缓存一并失效
- t3c_entries_after := sh_map_entries();
- total = total + 1; fails = fails + ts_check_b("t3c.map_reset_clears_bridge",
- (t3c_entries_mid >= 1 && t3c_entries_after == 0 && g_term_map_cap == 0), true);
- t3c_tiB := alloc_type(TYP_ARRAY, TI_BOOL, 2); // 同一行号 T(复用)
- t3c_termB := sh_term_of_ti(t3c_tiB);
- t3c_ok : ., mut = 0;
- if t3c_tiB == t3c_tiA { // 场景成立:行号确实复用
- if t3c_termB != t3c_termA { // 未返回陈旧项
- if tt_a(tt_a(tt_c(t3c_termA))) == AK_INT {
- if tt_a(tt_a(tt_c(t3c_termB))) == AK_BOOL { t3c_ok = 1; }
- }
- }
- }
- total = total + 1; fails = fails + ts_check("t3c.no_stale_term_after_reset", t3c_ok, 1);
+ init_types() // 干净起点(同时建立缓存基线)
+ t3c_tiA := alloc_type(TYP_ARRAY, TI_INT, 2) // 行号 T
+ t3c_termA := sh_term_of_ti(t3c_tiA) // 缓存 {T → seq(int)}
+ t3c_entries_mid := sh_map_entries()
+ init_types() // 类型表 + 桥接缓存一并失效
+ t3c_entries_after := sh_map_entries()
+ total = total + 1
+ fails = fails + ts_check_b("t3c.map_reset_clears_bridge",
+ (t3c_entries_mid >= 1 && t3c_entries_after == 0 && g_term_map_cap == 0), true)
+ t3c_tiB := alloc_type(TYP_ARRAY, TI_BOOL, 2) // 同一行号 T(复用)
+ t3c_termB := sh_term_of_ti(t3c_tiB)
+ t3c_ok : ., mut = 0
+ if t3c_tiB == t3c_tiA:
+ // 场景成立:行号确实复用
+ if t3c_termB != t3c_termA:
+ // 未返回陈旧项
+ if tt_a(tt_a(tt_c(t3c_termA))) == AK_INT:
+ if tt_a(tt_a(tt_c(t3c_termB))) == AK_BOOL:
+ t3c_ok = 1
+ total = total + 1
+ fails = fails + ts_check("t3c.no_stale_term_after_reset", t3c_ok, 1)
// --- R2 P2b Task 1:本质条目表 + `iface_*` 查询 API(零消费者建层;表 = 静态数据)---
// 前置:表由 init_types() 尾部建立(本通道不经 check_all → 与 P1 桥接段同款显式调用);
@@ -2434,88 +2678,131 @@ fn type_selftest_run() -> int {
// (ak→ti 行 / 行→ak 类)+ 12 个 API 逐签名;8 原生逐条目不抽样。扩列 = 纯信息面
// (三新行 ops = 0、ti_row = -1)——判定面零变化由 `ct2.kind_of_no_new_mapping`(全类型
// 行枚举)承担,本行只钉「可查询性」面。
- init_types();
- total = total + 1; fails = fails + ts_check("iface.count", iface_count(), 16);
+ init_types()
+ total = total + 1
+ fails = fails + ts_check("iface.count", iface_count(), 16)
// 逐原生条目:ak → 规范行 + **AK↔TI 下标不 1:1** 的显式守卫(bool/string 互换即红)
- total = total + 1; fails = fails + ts_check("iface.int_ti", iface_ti_of(AK_INT), TI_INT);
- total = total + 1; fails = fails + ts_check("iface.dex_ti", iface_ti_of(AK_DEX), TI_DEX);
- total = total + 1; fails = fails + ts_check("iface.str_ti", iface_ti_of(AK_STRING), TI_STR);
- total = total + 1; fails = fails + ts_check("iface.bool_ti", iface_ti_of(AK_BOOL), TI_BOOL);
- total = total + 1; fails = fails + ts_check("iface.unit_ti", iface_ti_of(AK_UNIT), TI_UNIT);
- total = total + 1; fails = fails + ts_check("iface.never_ti", iface_ti_of(AK_NEVER), TI_NEVER);
- total = total + 1; fails = fails + ts_check("iface.char_ti", iface_ti_of(AK_CHAR), TI_CHAR);
- total = total + 1; fails = fails + ts_check("iface.dyn_ti", iface_ti_of(AK_DYN), TI_DYN);
+ total = total + 1
+ fails = fails + ts_check("iface.int_ti", iface_ti_of(AK_INT), TI_INT)
+ total = total + 1
+ fails = fails + ts_check("iface.dex_ti", iface_ti_of(AK_DEX), TI_DEX)
+ total = total + 1
+ fails = fails + ts_check("iface.str_ti", iface_ti_of(AK_STRING), TI_STR)
+ total = total + 1
+ fails = fails + ts_check("iface.bool_ti", iface_ti_of(AK_BOOL), TI_BOOL)
+ total = total + 1
+ fails = fails + ts_check("iface.unit_ti", iface_ti_of(AK_UNIT), TI_UNIT)
+ total = total + 1
+ fails = fails + ts_check("iface.never_ti", iface_ti_of(AK_NEVER), TI_NEVER)
+ total = total + 1
+ fails = fails + ts_check("iface.char_ti", iface_ti_of(AK_CHAR), TI_CHAR)
+ total = total + 1
+ fails = fails + ts_check("iface.dyn_ti", iface_ti_of(AK_DYN), TI_DYN)
// 反向:结构/命名条目无「规范行」(类级)→ 恒 -1(若哪天被填成某行 = 类级/行级混同)
- total = total + 1; fails = fails + ts_check_b("iface.struct_ti_none",
+ total = total + 1
+ fails = fails + ts_check_b("iface.struct_ti_none",
(iface_ti_of(AK_PRODUCT) == -1 && iface_ti_of(AK_SEQUENCE) == -1 && iface_ti_of(AK_REF) == -1 &&
- iface_ti_of(AK_PTR) == -1 && iface_ti_of(AK_NAMED) == -1), true);
+ iface_ti_of(AK_PTR) == -1 && iface_ti_of(AK_NAMED) == -1), true)
// 行号 → 原子类:8 原生经**类型表本体**(kind == TYP_BASE && data == TY_*)判,不按行号猜
- total = total + 1; fails = fails + ts_check("iface.kind_int", iface_kind_of(TI_INT), AK_INT);
- total = total + 1; fails = fails + ts_check("iface.kind_dex", iface_kind_of(TI_DEX), AK_DEX);
- total = total + 1; fails = fails + ts_check("iface.kind_str", iface_kind_of(TI_STR), AK_STRING);
- total = total + 1; fails = fails + ts_check("iface.kind_bool", iface_kind_of(TI_BOOL), AK_BOOL);
- total = total + 1; fails = fails + ts_check("iface.kind_unit", iface_kind_of(TI_UNIT), AK_UNIT);
- total = total + 1; fails = fails + ts_check("iface.kind_never", iface_kind_of(TI_NEVER), AK_NEVER);
- total = total + 1; fails = fails + ts_check("iface.kind_char", iface_kind_of(TI_CHAR), AK_CHAR);
- total = total + 1; fails = fails + ts_check("iface.kind_dyn", iface_kind_of(TI_DYN), AK_DYN);
- total = total + 1; fails = fails + ts_check("iface.kind_oob", iface_kind_of(g_type_count + 7), -1);
- total = total + 1; fails = fails + ts_check("iface.kind_neg", iface_kind_of(-1), -1);
+ total = total + 1
+ fails = fails + ts_check("iface.kind_int", iface_kind_of(TI_INT), AK_INT)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_dex", iface_kind_of(TI_DEX), AK_DEX)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_str", iface_kind_of(TI_STR), AK_STRING)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_bool", iface_kind_of(TI_BOOL), AK_BOOL)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_unit", iface_kind_of(TI_UNIT), AK_UNIT)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_never", iface_kind_of(TI_NEVER), AK_NEVER)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_char", iface_kind_of(TI_CHAR), AK_CHAR)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_dyn", iface_kind_of(TI_DYN), AK_DYN)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_oob", iface_kind_of(g_type_count + 7), -1)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_neg", iface_kind_of(-1), -1)
// 结构/命名行 → 类(逐 kind 一条构造子;配对着写以钉死「非同类混判」)
- ifc_ptr := alloc_type(TYP_PTR, TI_INT, 0);
- ifc_ref := alloc_type(TYP_REF, TI_STR, 0);
- total = total + 1; fails = fails + ts_check_b("iface.kind_ptr_ref",
- (iface_kind_of(ifc_ptr) == AK_PTR && iface_kind_of(ifc_ref) == AK_REF), true);
- ifc_arr := alloc_type(TYP_ARRAY, TI_INT, 3);
- ifc_slice := alloc_type(TYP_SLICE, TI_INT, 0);
- total = total + 1; fails = fails + ts_check_b("iface.kind_seq",
- (iface_kind_of(ifc_arr) == AK_SEQUENCE && iface_kind_of(ifc_slice) == AK_SEQUENCE), true);
- ifc_tup := alloc_type(TYP_TUPLE, 0, 0);
- total = total + 1; fails = fails + ts_check("iface.kind_product", iface_kind_of(ifc_tup), AK_PRODUCT);
- ifc_named := alloc_named_type(str_intern("IfaceNamedProbe"));
- ifc_gp := alloc_type(TYP_GENERIC_PARAM, str_intern("IfaceGP"), 0);
- ifc_ga := alloc_type(TYP_GENERIC_APPLY, ifc_named, 0);
- total = total + 1; fails = fails + ts_check_b("iface.kind_named",
+ ifc_ptr := alloc_type(TYP_PTR, TI_INT, 0)
+ ifc_ref := alloc_type(TYP_REF, TI_STR, 0)
+ total = total + 1
+ fails = fails + ts_check_b("iface.kind_ptr_ref",
+ (iface_kind_of(ifc_ptr) == AK_PTR && iface_kind_of(ifc_ref) == AK_REF), true)
+ ifc_arr := alloc_type(TYP_ARRAY, TI_INT, 3)
+ ifc_slice := alloc_type(TYP_SLICE, TI_INT, 0)
+ total = total + 1
+ fails = fails + ts_check_b("iface.kind_seq",
+ (iface_kind_of(ifc_arr) == AK_SEQUENCE && iface_kind_of(ifc_slice) == AK_SEQUENCE), true)
+ ifc_tup := alloc_type(TYP_TUPLE, 0, 0)
+ total = total + 1
+ fails = fails + ts_check("iface.kind_product", iface_kind_of(ifc_tup), AK_PRODUCT)
+ ifc_named := alloc_named_type(str_intern("IfaceNamedProbe"))
+ ifc_gp := alloc_type(TYP_GENERIC_PARAM, str_intern("IfaceGP"), 0)
+ ifc_ga := alloc_type(TYP_GENERIC_APPLY, ifc_named, 0)
+ total = total + 1
+ fails = fails + ts_check_b("iface.kind_named",
(iface_kind_of(ifc_named) == AK_NAMED && iface_kind_of(ifc_gp) == AK_NAMED &&
- iface_kind_of(ifc_ga) == AK_NAMED), true);
+ iface_kind_of(ifc_ga) == AK_NAMED), true)
// 条目定位(含越界/负键:不得把「无此原子」与行 0 混同)
- total = total + 1; fails = fails + ts_check_b("iface.entry_lookup",
+ total = total + 1
+ fails = fails + ts_check_b("iface.entry_lookup",
(iface_entry(AK_INT) >= 0 && iface_entry(AK_INT) < iface_count() && iface_entry(AK_NAMED) >= 0 &&
- iface_entry(-1) == -1 && iface_entry(9999) == -1), true);
+ iface_entry(-1) == -1 && iface_entry(9999) == -1), true)
// TY_* 码 → 原子类(逐项语义分派;含两条已裁决灰格:DEX_S 同值域不同表示、GENERIC_PARAM 哨兵)
- total = total + 1; fails = fails + ts_check_b("iface.ty_code_natives",
+ total = total + 1
+ fails = fails + ts_check_b("iface.ty_code_natives",
(iface_by_ty_code(TY_INT) == AK_INT && iface_by_ty_code(TY_DEX) == AK_DEX &&
- iface_by_ty_code(TY_BOOL) == AK_BOOL && iface_by_ty_code(TY_STRING) == AK_STRING &&
- iface_by_ty_code(TY_UNIT) == AK_UNIT && iface_by_ty_code(TY_NEVER) == AK_NEVER &&
- iface_by_ty_code(TY_CHAR) == AK_CHAR), true);
- total = total + 1; fails = fails + ts_check_b("iface.ty_code_gray",
- (iface_by_ty_code(TY_DEX_S) == AK_DEX && iface_by_ty_code(TY_GENERIC_PARAM) == AK_NAMED), true);
- total = total + 1; fails = fails + ts_check("iface.ty_code_unknown", iface_by_ty_code(999), -1);
+ iface_by_ty_code(TY_BOOL) == AK_BOOL && iface_by_ty_code(TY_STRING) == AK_STRING &&
+ iface_by_ty_code(TY_UNIT) == AK_UNIT && iface_by_ty_code(TY_NEVER) == AK_NEVER &&
+ iface_by_ty_code(TY_CHAR) == AK_CHAR), true)
+ total = total + 1
+ fails = fails + ts_check_b("iface.ty_code_gray",
+ (iface_by_ty_code(TY_DEX_S) == AK_DEX && iface_by_ty_code(TY_GENERIC_PARAM) == AK_NAMED), true)
+ total = total + 1
+ fails = fails + ts_check("iface.ty_code_unknown", iface_by_ty_code(999), -1)
// 字面量定型(查表入口 = 条目 lit_code 列;接线后 = infer_expr 的 5 处唯一真源,
// 端到端对拍见本文件末段 `lit.infer_*`)
- total = total + 1; fails = fails + ts_check("iface.lit_int", iface_lit_ti(EXPR_INT), TI_INT);
- total = total + 1; fails = fails + ts_check("iface.lit_dex", iface_lit_ti(EXPR_DEX), TI_DEX);
- total = total + 1; fails = fails + ts_check("iface.lit_str", iface_lit_ti(EXPR_STRING), TI_STR);
- total = total + 1; fails = fails + ts_check("iface.lit_bool", iface_lit_ti(EXPR_BOOL), TI_BOOL);
- total = total + 1; fails = fails + ts_check("iface.lit_char", iface_lit_ti(EXPR_CHAR), TI_CHAR);
- total = total + 1; fails = fails + ts_check("iface.lit_none", iface_lit_ti(EXPR_IDENT), -1);
- total = total + 1; fails = fails + ts_check_b("iface.lit_ak",
+ total = total + 1
+ fails = fails + ts_check("iface.lit_int", iface_lit_ti(EXPR_INT), TI_INT)
+ total = total + 1
+ fails = fails + ts_check("iface.lit_dex", iface_lit_ti(EXPR_DEX), TI_DEX)
+ total = total + 1
+ fails = fails + ts_check("iface.lit_str", iface_lit_ti(EXPR_STRING), TI_STR)
+ total = total + 1
+ fails = fails + ts_check("iface.lit_bool", iface_lit_ti(EXPR_BOOL), TI_BOOL)
+ total = total + 1
+ fails = fails + ts_check("iface.lit_char", iface_lit_ti(EXPR_CHAR), TI_CHAR)
+ total = total + 1
+ fails = fails + ts_check("iface.lit_none", iface_lit_ti(EXPR_IDENT), -1)
+ total = total + 1
+ fails = fails + ts_check_b("iface.lit_ak",
(iface_lit_ak(EXPR_INT) == AK_INT && iface_lit_ak(EXPR_DEX) == AK_DEX &&
- iface_lit_ak(EXPR_STRING) == AK_STRING && iface_lit_ak(EXPR_BOOL) == AK_BOOL &&
- iface_lit_ak(EXPR_CHAR) == AK_CHAR), true);
+ iface_lit_ak(EXPR_STRING) == AK_STRING && iface_lit_ak(EXPR_BOOL) == AK_BOOL &&
+ iface_lit_ak(EXPR_CHAR) == AK_CHAR), true)
// 负键 = 条目的「无字面量」哨兵 ⇒ 必须先行拒绝(否则 -1 命中无字面量条目)
- total = total + 1; fails = fails + ts_check("iface.lit_neg", iface_lit_ak(-1), -1);
+ total = total + 1
+ fails = fails + ts_check("iface.lit_neg", iface_lit_ak(-1), -1)
// 类型项 → 原子类(单一原子 / ⊤ₖ;复合与越界 → -1)
- ifc_term_atom := tt_atom(AK_INT, TI_INT, -1);
- total = total + 1; fails = fails + ts_check("iface.of_term_atom", iface_of_term(ifc_term_atom), AK_INT);
- total = total + 1; fails = fails + ts_check("iface.of_term_topk", iface_of_term(tt_top_k(AK_SEQUENCE)), AK_SEQUENCE);
- total = total + 1; fails = fails + ts_check("iface.of_term_compound", iface_of_term(tt_union(a_int, a_str)), -1);
- total = total + 1; fails = fails + ts_check_b("iface.of_term_oob",
- (iface_of_term(-1) == -1 && iface_of_term(tt_count() + 9) == -1), true);
+ ifc_term_atom := tt_atom(AK_INT, TI_INT, -1)
+ total = total + 1
+ fails = fails + ts_check("iface.of_term_atom", iface_of_term(ifc_term_atom), AK_INT)
+ total = total + 1
+ fails = fails + ts_check("iface.of_term_topk", iface_of_term(tt_top_k(AK_SEQUENCE)), AK_SEQUENCE)
+ total = total + 1
+ fails = fails + ts_check("iface.of_term_compound", iface_of_term(tt_union(a_int, a_str)), -1)
+ total = total + 1
+ fails = fails + ts_check_b("iface.of_term_oob",
+ (iface_of_term(-1) == -1 && iface_of_term(tt_count() + 9) == -1), true)
// 未知原子 → 空许可集(不得给「看起来有许可」的位);位下标越界 → 0(不得回绕成全位命中)
- total = total + 1; fails = fails + ts_check("iface.ops_unknown", iface_ops(-1), 0);
- total = total + 1; fails = fails + ts_check("iface.ops_unknown_ak", iface_ops(9999), 0);
- total = total + 1; fails = fails + ts_check_b("iface.permits_bad_op",
- (iface_permits(AK_INT, -1) == 0 && iface_permits(AK_INT, 63) == 0 && iface_permits(9999, OP_ADD) == 0), true);
+ total = total + 1
+ fails = fails + ts_check("iface.ops_unknown", iface_ops(-1), 0)
+ total = total + 1
+ fails = fails + ts_check("iface.ops_unknown_ak", iface_ops(9999), 0)
+ total = total + 1
+ fails = fails + ts_check_b("iface.permits_bad_op",
+ (iface_permits(AK_INT, -1) == 0 && iface_permits(AK_INT, 63) == 0 && iface_permits(9999, OP_ADD) == 0), true)
// --- R2 P2b Task 2:`iface_kind_of` 单源化——桥接分派(sh_native_ak/sh_base_ak)与注册表合一 ---
// 判据 = **全表逐格**(非抽样):生产入口对**冻结期望表**逐格相同。**R2 P5 Task 4 重定**:
@@ -2524,51 +2811,65 @@ fn type_selftest_run() -> int {
// 的第二份实现——单源化的收益自此由数据钉住)。只比「两版相等」会漏两类错——入口被换成
// 第三个实现、两版一起错 ⇒ 另加③~⑥的**显式**断言(反真空/灰格/门/下标不 1:1)。
// ① TY 码面:全部 9 个 TY_* 码(含 TY_DEX_S / TY_GENERIC_PARAM 两条已裁决灰格)+ 未映射码
- t2_codes := alloc(10 * 8);
- w64(t2_codes, 0, TY_INT); w64(t2_codes, 8, TY_DEX);
- w64(t2_codes, 16, TY_BOOL); w64(t2_codes, 24, TY_STRING);
- w64(t2_codes, 32, TY_UNIT); w64(t2_codes, 40, TY_NEVER);
- w64(t2_codes, 48, TY_CHAR); w64(t2_codes, 56, TY_GENERIC_PARAM);
- w64(t2_codes, 64, TY_DEX_S); w64(t2_codes, 72, 999);
- t2_ty_bad : ., mut = 0;
- t2_i : ., mut = 0;
- loop {
- if t2_i >= 10 { break; }
- t2_code := r64(t2_codes, t2_i * 8);
- if iface_by_ty_code(t2_code) != ts_t4_ak_expected(t2_code) { t2_ty_bad = t2_ty_bad + 1; }
- t2_i = t2_i + 1;
- }
- total = total + 1; fails = fails + ts_check("iface.by_ty_code_all_codes", t2_ty_bad, 0);
+ t2_codes := alloc(10 * 8)
+ w64(t2_codes, 0, TY_INT)
+ w64(t2_codes, 8, TY_DEX)
+ w64(t2_codes, 16, TY_BOOL)
+ w64(t2_codes, 24, TY_STRING)
+ w64(t2_codes, 32, TY_UNIT)
+ w64(t2_codes, 40, TY_NEVER)
+ w64(t2_codes, 48, TY_CHAR)
+ w64(t2_codes, 56, TY_GENERIC_PARAM)
+ w64(t2_codes, 64, TY_DEX_S)
+ w64(t2_codes, 72, 999)
+ t2_ty_bad : ., mut = 0
+ t2_i : ., mut = 0
+ loop:
+ if t2_i >= 10:
+ break
+ t2_code := r64(t2_codes, t2_i * 8)
+ if iface_by_ty_code(t2_code) != ts_t4_ak_expected(t2_code):
+ t2_ty_bad = t2_ty_bad + 1
+ t2_i = t2_i + 1
+ total = total + 1
+ fails = fails + ts_check("iface.by_ty_code_all_codes", t2_ty_bad, 0)
// ② 行号面全表:逐 ti ∈ [0, g_type_count)(含 TI_DYN 行、TI_DEX_S 占位行与上方结构/命名行)
- t2_ti_bad : ., mut = 0;
- t2_j : ., mut = 0;
- loop {
- if t2_j >= g_type_count { break; }
- if sh_native_ak(t2_j) != ts_t4_native_ak_expected(t2_j) { t2_ti_bad = t2_ti_bad + 1; }
- t2_j = t2_j + 1;
- }
- total = total + 1; fails = fails + ts_check("iface.native_ak_all_rows", t2_ti_bad, 0);
+ t2_ti_bad : ., mut = 0
+ t2_j : ., mut = 0
+ loop:
+ if t2_j >= g_type_count:
+ break
+ if sh_native_ak(t2_j) != ts_t4_native_ak_expected(t2_j):
+ t2_ti_bad = t2_ti_bad + 1
+ t2_j = t2_j + 1
+ total = total + 1
+ fails = fails + ts_check("iface.native_ak_all_rows", t2_ti_bad, 0)
// ③ **反真空哨兵**(两处 loop 是本 Task 的判据本体,不得空转假绿):
// ⓐ 扫描计数:码面 10 个键全扫过(且解码真读回写入值);行面恰为 g_type_count 行且 ≥ 9;
// ⓑ 比较是活的:两个**已知互补**的格必须给出**不同**结果(未映射码 → -1 而 TY_INT → AK_INT)。
- total = total + 1; fails = fails + ts_check_b("iface.scan_coverage",
+ total = total + 1
+ fails = fails + ts_check_b("iface.scan_coverage",
(t2_i == 10 && r64(t2_codes, 56) == TY_GENERIC_PARAM && r64(t2_codes, 64) == TY_DEX_S &&
- t2_j == g_type_count && t2_j >= 9), true);
- total = total + 1; fails = fails + ts_check_b("iface.compare_is_live",
- (iface_by_ty_code(999) == ts_t4_ak_expected(TY_INT)), false);
+ t2_j == g_type_count && t2_j >= 9), true)
+ total = total + 1
+ fails = fails + ts_check_b("iface.compare_is_live",
+ (iface_by_ty_code(999) == ts_t4_ak_expected(TY_INT)), false)
// ④ 生产入口**确实在委托**(逐项钉死;含两条灰格与未映射码)
- total = total + 1; fails = fails + ts_check_b("iface.bridge_delegates",
+ total = total + 1
+ fails = fails + ts_check_b("iface.bridge_delegates",
(sh_base_ak(TY_INT) == AK_INT && sh_base_ak(TY_STRING) == AK_STRING && sh_base_ak(TY_BOOL) == AK_BOOL &&
- sh_base_ak(TY_DEX_S) == AK_DEX && sh_base_ak(TY_GENERIC_PARAM) == AK_NAMED && sh_base_ak(999) == -1 &&
- sh_native_ak(TI_INT) == AK_INT && sh_native_ak(TI_STR) == AK_STRING), true);
+ sh_base_ak(TY_DEX_S) == AK_DEX && sh_base_ak(TY_GENERIC_PARAM) == AK_NAMED && sh_base_ak(999) == -1 &&
+ sh_native_ak(TI_INT) == AK_INT && sh_native_ak(TI_STR) == AK_STRING), true)
// ⑤ **原门保留**(委托不得把 sh_native_ak 变成 iface_kind_of):DYN 行/结构行/负号 → -1,
// 而同时注册表侧对 DYN 行回 AK_DYN——两函数契约不同,各自钉一条。
- total = total + 1; fails = fails + ts_check_b("iface.bridge_gate_kept",
+ total = total + 1
+ fails = fails + ts_check_b("iface.bridge_gate_kept",
(sh_native_ak(TI_DYN) == -1 && sh_native_ak(ifc_arr) == -1 && sh_native_ak(ifc_named) == -1 &&
- sh_native_ak(-1) == -1 && iface_kind_of(TI_DYN) == AK_DYN), true);
+ sh_native_ak(-1) == -1 && iface_kind_of(TI_DYN) == AK_DYN), true)
// ⑥ 语义分派守卫(P1 血泪:AK/TI 下标不 1:1)——若哪天有人「按下标直传」,本行必红
- total = total + 1; fails = fails + ts_check_b("iface.dispatch_no_index_shortcut",
- (iface_ti_of(AK_STRING) != AK_STRING && iface_ti_of(AK_BOOL) != AK_BOOL && TI_STR != TI_BOOL), true);
+ total = total + 1
+ fails = fails + ts_check_b("iface.dispatch_no_index_shortcut",
+ (iface_ti_of(AK_STRING) != AK_STRING && iface_ti_of(AK_BOOL) != AK_BOOL && TI_STR != TI_BOOL), true)
// --- R2 P2b Task 3:字面量定型查表接线(infer_expr 的 5 个字面量分支 → iface_lit_ti)---
// 判据 = **接线端到端**:用与 parser 同族的 `alloc_node` 构造 5 个字面量 AST 节点,逐 kind 比
@@ -2577,36 +2878,46 @@ fn type_selftest_run() -> int {
// `iface_lit_ti(EXPR_DEX)`)在表侧用例下**全绿**——只有经 infer_expr 真跑才暴露。
// 本段为**本 Task 的判据本体**,其非真空性由实施报告记录的**突变控制**(翻转表格 ⇒ 本段
// `lit.infer_int` 必红 ⇒ 复位)实证,非仅「跑过一遍」。
- li_int := alloc_node(EXPR_INT, -1, -1, -1, 42, TY_INT, -1, 0, 0);
- li_dex := alloc_node(EXPR_DEX, -1, -1, -1, 314, TY_DEX, -1, 0, 0);
- li_str := alloc_node(EXPR_STRING, -1, -1, -1, str_intern("iface_lit_probe"), TY_STRING, -1, 0, 0);
- li_bool := alloc_node(EXPR_BOOL, -1, -1, -1, 1, TY_BOOL, -1, 0, 0);
- li_char := alloc_node(EXPR_CHAR, -1, -1, -1, 65, TY_CHAR, -1, 0, 0);
+ li_int := alloc_node(EXPR_INT, -1, -1, -1, 42, TY_INT, -1, 0, 0)
+ li_dex := alloc_node(EXPR_DEX, -1, -1, -1, 314, TY_DEX, -1, 0, 0)
+ li_str := alloc_node(EXPR_STRING, -1, -1, -1, str_intern("iface_lit_probe"), TY_STRING, -1, 0, 0)
+ li_bool := alloc_node(EXPR_BOOL, -1, -1, -1, 1, TY_BOOL, -1, 0, 0)
+ li_char := alloc_node(EXPR_CHAR, -1, -1, -1, 65, TY_CHAR, -1, 0, 0)
// 反真空哨兵:构造出的节点确实带预期 kind(防 alloc_node 参数错位 ⇒ 「拿错节点比错值」假绿)
- total = total + 1; fails = fails + ts_check_b("lit.node_kinds",
+ total = total + 1
+ fails = fails + ts_check_b("lit.node_kinds",
(ast_kind(li_int) == EXPR_INT && ast_kind(li_dex) == EXPR_DEX && ast_kind(li_str) == EXPR_STRING &&
- ast_kind(li_bool) == EXPR_BOOL && ast_kind(li_char) == EXPR_CHAR), true);
- total = total + 1; fails = fails + ts_check("lit.infer_int", infer_expr(li_int), TI_INT);
- total = total + 1; fails = fails + ts_check("lit.infer_dex", infer_expr(li_dex), TI_DEX);
- total = total + 1; fails = fails + ts_check("lit.infer_str", infer_expr(li_str), TI_STR);
- total = total + 1; fails = fails + ts_check("lit.infer_bool", infer_expr(li_bool), TI_BOOL);
- total = total + 1; fails = fails + ts_check("lit.infer_char", infer_expr(li_char), TI_CHAR);
+ ast_kind(li_bool) == EXPR_BOOL && ast_kind(li_char) == EXPR_CHAR), true)
+ total = total + 1
+ fails = fails + ts_check("lit.infer_int", infer_expr(li_int), TI_INT)
+ total = total + 1
+ fails = fails + ts_check("lit.infer_dex", infer_expr(li_dex), TI_DEX)
+ total = total + 1
+ fails = fails + ts_check("lit.infer_str", infer_expr(li_str), TI_STR)
+ total = total + 1
+ fails = fails + ts_check("lit.infer_bool", infer_expr(li_bool), TI_BOOL)
+ total = total + 1
+ fails = fails + ts_check("lit.infer_char", infer_expr(li_char), TI_CHAR)
// 端到端 ↔ 表 对拍:接线后 infer_expr 的结果必须**逐 kind 等于表查表结果**(表 = 唯一真源;
// 若哪天有人把某行改回硬编码常量,本行仍绿但 `lit.infer_*` 亦绿——真正的守门是实施报告的
// 突变控制:改表格 ⇒ infer_* 红 ⇒ 该行确在读表)
- total = total + 1; fails = fails + ts_check_b("lit.infer_is_table",
+ total = total + 1
+ fails = fails + ts_check_b("lit.infer_is_table",
(infer_expr(li_int) == iface_lit_ti(EXPR_INT) && infer_expr(li_dex) == iface_lit_ti(EXPR_DEX) &&
- infer_expr(li_str) == iface_lit_ti(EXPR_STRING) && infer_expr(li_bool) == iface_lit_ti(EXPR_BOOL) &&
- infer_expr(li_char) == iface_lit_ti(EXPR_CHAR)), true);
+ infer_expr(li_str) == iface_lit_ti(EXPR_STRING) && infer_expr(li_bool) == iface_lit_ti(EXPR_BOOL) &&
+ infer_expr(li_char) == iface_lit_ti(EXPR_CHAR)), true)
// 短路顺序(接线硬口径:**逐字保持**)——EXPR_NONE 转发行夹在 EXPR_INT 与 EXPR_DEX 之间:
// ① 带内层值的 wrapper:在 EXPR_INT 行不命中(kind=0)⇒ 走转发行 → 内层类型;
// ② 空 wrapper(a = -1):转发行不命中 ⇒ 落函数中部的 EXPR_NONE 分支 → TI_UNIT。
- li_wrap := alloc_node(EXPR_NONE, li_int, -1, -1, 0, 0, -1, 0, 0);
- li_wrap_empty := alloc_node(EXPR_NONE, -1, -1, -1, 0, 0, -1, 0, 0);
- total = total + 1; fails = fails + ts_check("lit.none_forwards", infer_expr(li_wrap), TI_INT);
- total = total + 1; fails = fails + ts_check("lit.none_empty_unit", infer_expr(li_wrap_empty), TI_UNIT);
+ li_wrap := alloc_node(EXPR_NONE, li_int, -1, -1, 0, 0, -1, 0, 0)
+ li_wrap_empty := alloc_node(EXPR_NONE, -1, -1, -1, 0, 0, -1, 0, 0)
+ total = total + 1
+ fails = fails + ts_check("lit.none_forwards", infer_expr(li_wrap), TI_INT)
+ total = total + 1
+ fails = fails + ts_check("lit.none_empty_unit", infer_expr(li_wrap_empty), TI_UNIT)
// 负节点先行拒绝(infer_expr 头行;接线不得把它挤掉)
- total = total + 1; fails = fails + ts_check("lit.neg_node_unit", infer_expr(-1), TI_UNIT);
+ total = total + 1
+ fails = fails + ts_check("lit.neg_node_unit", infer_expr(-1), TI_UNIT)
// --- R2 P2b Task 4:操作许可位集接线(ops 列逐格;消费者 = checker.cr 的三个门)---
// 判据口径 = **与改动前的判定一字等价**(逐格全表对拍,非抽样):把「改动前的谓词」内联进
@@ -2617,161 +2928,208 @@ fn type_selftest_run() -> int {
// ② OP_AND/OP_OR 许可 ⟺ ak ∈ {AK_INT, AK_BOOL}(dex 拒——`1.5 && true` 现状 TC01)
// ③ IP_COND ⟺ ak ∈ {AK_INT, AK_BOOL};IP_COND_BOOL ⟺ ak == AK_BOOL(`while 1` 现状 TC04)
// 反真空:另立「许可为 1 的格数」哨兵(全 0 表 ⇒ 计数 0 必红)+ 条目面一致性 + 端到端段。
- o4_aks := alloc(13 * 8); // 13 类枚举(顺序 = 条目表声明序)
- w64(o4_aks, 0, AK_INT); w64(o4_aks, 8, AK_DEX); w64(o4_aks, 16, AK_STRING);
- w64(o4_aks, 24, AK_BOOL); w64(o4_aks, 32, AK_UNIT); w64(o4_aks, 40, AK_NEVER);
- w64(o4_aks, 48, AK_CHAR); w64(o4_aks, 56, AK_DYN); w64(o4_aks, 64, AK_PRODUCT);
- w64(o4_aks, 72, AK_SEQUENCE); w64(o4_aks, 80, AK_REF); w64(o4_aks, 88, AK_PTR);
- w64(o4_aks, 96, AK_NAMED);
- o4_ops := alloc(5 * 8); // 算术族 5 op(门消费面:OP_ADD..OP_MOD)
- w64(o4_ops, 0, OP_ADD); w64(o4_ops, 8, OP_SUB); w64(o4_ops, 16, OP_MUL);
- w64(o4_ops, 24, OP_DIV); w64(o4_ops, 32, OP_MOD);
+ o4_aks := alloc(13 * 8) // 13 类枚举(顺序 = 条目表声明序)
+ w64(o4_aks, 0, AK_INT)
+ w64(o4_aks, 8, AK_DEX)
+ w64(o4_aks, 16, AK_STRING)
+ w64(o4_aks, 24, AK_BOOL)
+ w64(o4_aks, 32, AK_UNIT)
+ w64(o4_aks, 40, AK_NEVER)
+ w64(o4_aks, 48, AK_CHAR)
+ w64(o4_aks, 56, AK_DYN)
+ w64(o4_aks, 64, AK_PRODUCT)
+ w64(o4_aks, 72, AK_SEQUENCE)
+ w64(o4_aks, 80, AK_REF)
+ w64(o4_aks, 88, AK_PTR)
+ w64(o4_aks, 96, AK_NAMED)
+ o4_ops := alloc(5 * 8) // 算术族 5 op(门消费面:OP_ADD..OP_MOD)
+ w64(o4_ops, 0, OP_ADD)
+ w64(o4_ops, 8, OP_SUB)
+ w64(o4_ops, 16, OP_MUL)
+ w64(o4_ops, 24, OP_DIV)
+ w64(o4_ops, 32, OP_MOD)
// ① 算术门:逐 ak × 逐 op 对拍「许可 ⟺ int|dex」
- o4_arith_bad : ., mut = 0;
- o4_arith_yes : ., mut = 0;
- o4_i : ., mut = 0;
- loop {
- if o4_i >= 13 { break; }
- o4_ak := r64(o4_aks, o4_i * 8);
- o4_j : ., mut = 0;
- loop {
- if o4_j >= 5 { break; }
- o4_op := r64(o4_ops, o4_j * 8);
- o4_want : ., mut = 0;
- if o4_ak == AK_INT || o4_ak == AK_DEX { o4_want = 1; }
- if iface_permits(o4_ak, o4_op) != o4_want { o4_arith_bad = o4_arith_bad + 1; }
- if iface_permits(o4_ak, o4_op) == 1 { o4_arith_yes = o4_arith_yes + 1; }
- o4_j = o4_j + 1;
- }
- o4_i = o4_i + 1;
- }
- total = total + 1; fails = fails + ts_check("ops.arith_gate_eq_legacy", o4_arith_bad, 0);
- total = total + 1; fails = fails + ts_check("ops.arith_permit_count", o4_arith_yes, 10); // = 2 ak × 5 op
+ o4_arith_bad : ., mut = 0
+ o4_arith_yes : ., mut = 0
+ o4_i : ., mut = 0
+ loop:
+ if o4_i >= 13:
+ break
+ o4_ak := r64(o4_aks, o4_i * 8)
+ o4_j : ., mut = 0
+ loop:
+ if o4_j >= 5:
+ break
+ o4_op := r64(o4_ops, o4_j * 8)
+ o4_want : ., mut = 0
+ if o4_ak == AK_INT || o4_ak == AK_DEX:
+ o4_want = 1
+ if iface_permits(o4_ak, o4_op) != o4_want:
+ o4_arith_bad = o4_arith_bad + 1
+ if iface_permits(o4_ak, o4_op) == 1:
+ o4_arith_yes = o4_arith_yes + 1
+ o4_j = o4_j + 1
+ o4_i = o4_i + 1
+ total = total + 1
+ fails = fails + ts_check("ops.arith_gate_eq_legacy", o4_arith_bad, 0)
+ total = total + 1
+ fails = fails + ts_check("ops.arith_permit_count", o4_arith_yes, 10) // = 2 ak × 5 op
// ② 逻辑族:逐 ak × 逐 op(OP_AND/OP_OR)对拍「许可 ⟺ int|bool」——谓词取 OP_AND(不另设 IP_LOGIC)
- o4_logic_bad : ., mut = 0;
- o4_logic_yes : ., mut = 0;
- o4_k : ., mut = 0;
- loop {
- if o4_k >= 13 { break; }
- o4_ak2 := r64(o4_aks, o4_k * 8);
- o4_want2 : ., mut = 0;
- if o4_ak2 == AK_INT || o4_ak2 == AK_BOOL { o4_want2 = 1; }
- if iface_permits(o4_ak2, OP_AND) != o4_want2 { o4_logic_bad = o4_logic_bad + 1; }
- if iface_permits(o4_ak2, OP_OR) != o4_want2 { o4_logic_bad = o4_logic_bad + 1; }
- if iface_permits(o4_ak2, OP_AND) == 1 { o4_logic_yes = o4_logic_yes + 1; }
- o4_k = o4_k + 1;
- }
- total = total + 1; fails = fails + ts_check("ops.logic_gate_eq_legacy", o4_logic_bad, 0);
- total = total + 1; fails = fails + ts_check("ops.logic_permit_count", o4_logic_yes, 2); // int + bool
+ o4_logic_bad : ., mut = 0
+ o4_logic_yes : ., mut = 0
+ o4_k : ., mut = 0
+ loop:
+ if o4_k >= 13:
+ break
+ o4_ak2 := r64(o4_aks, o4_k * 8)
+ o4_want2 : ., mut = 0
+ if o4_ak2 == AK_INT || o4_ak2 == AK_BOOL:
+ o4_want2 = 1
+ if iface_permits(o4_ak2, OP_AND) != o4_want2:
+ o4_logic_bad = o4_logic_bad + 1
+ if iface_permits(o4_ak2, OP_OR) != o4_want2:
+ o4_logic_bad = o4_logic_bad + 1
+ if iface_permits(o4_ak2, OP_AND) == 1:
+ o4_logic_yes = o4_logic_yes + 1
+ o4_k = o4_k + 1
+ total = total + 1
+ fails = fails + ts_check("ops.logic_gate_eq_legacy", o4_logic_bad, 0)
+ total = total + 1
+ fails = fails + ts_check("ops.logic_permit_count", o4_logic_yes, 2) // int + bool
// ③ 条件族:IP_COND = {int, bool};IP_COND_BOOL = {bool}(**两条规则现状不同,不得合并**)
- o4_cond_bad : ., mut = 0;
- o4_cond_yes : ., mut = 0;
- o4_condb_yes : ., mut = 0;
- o4_m : ., mut = 0;
- loop {
- if o4_m >= 13 { break; }
- o4_ak3 := r64(o4_aks, o4_m * 8);
- o4_want3 : ., mut = 0;
- if o4_ak3 == AK_INT || o4_ak3 == AK_BOOL { o4_want3 = 1; }
- o4_want4 : ., mut = 0;
- if o4_ak3 == AK_BOOL { o4_want4 = 1; }
- if iface_permits(o4_ak3, IP_COND) != o4_want3 { o4_cond_bad = o4_cond_bad + 1; }
- if iface_permits(o4_ak3, IP_COND_BOOL) != o4_want4 { o4_cond_bad = o4_cond_bad + 1; }
- if iface_permits(o4_ak3, IP_COND) == 1 { o4_cond_yes = o4_cond_yes + 1; }
- if iface_permits(o4_ak3, IP_COND_BOOL) == 1 { o4_condb_yes = o4_condb_yes + 1; }
- o4_m = o4_m + 1;
- }
- total = total + 1; fails = fails + ts_check("ops.cond_gate_eq_legacy", o4_cond_bad, 0);
- total = total + 1; fails = fails + ts_check("ops.cond_permit_count", o4_cond_yes * 10 + o4_condb_yes, 21); // 2 与 1
+ o4_cond_bad : ., mut = 0
+ o4_cond_yes : ., mut = 0
+ o4_condb_yes : ., mut = 0
+ o4_m : ., mut = 0
+ loop:
+ if o4_m >= 13:
+ break
+ o4_ak3 := r64(o4_aks, o4_m * 8)
+ o4_want3 : ., mut = 0
+ if o4_ak3 == AK_INT || o4_ak3 == AK_BOOL:
+ o4_want3 = 1
+ o4_want4 : ., mut = 0
+ if o4_ak3 == AK_BOOL:
+ o4_want4 = 1
+ if iface_permits(o4_ak3, IP_COND) != o4_want3:
+ o4_cond_bad = o4_cond_bad + 1
+ if iface_permits(o4_ak3, IP_COND_BOOL) != o4_want4:
+ o4_cond_bad = o4_cond_bad + 1
+ if iface_permits(o4_ak3, IP_COND) == 1:
+ o4_cond_yes = o4_cond_yes + 1
+ if iface_permits(o4_ak3, IP_COND_BOOL) == 1:
+ o4_condb_yes = o4_condb_yes + 1
+ o4_m = o4_m + 1
+ total = total + 1
+ fails = fails + ts_check("ops.cond_gate_eq_legacy", o4_cond_bad, 0)
+ total = total + 1
+ fails = fails + ts_check("ops.cond_permit_count", o4_cond_yes * 10 + o4_condb_yes, 21) // 2 与 1
// ④ 全许可面(现状**无拒绝路径** ⇒ 本批不接线、只登记为 P3 旋钮):比较 6 op / 一元 4 op / AS
// 对全部 13 类置 1——逐格对拍(计数 = 13 × 11 = 143)
- o4_all_bad : ., mut = 0;
- o4_all_yes : ., mut = 0;
- o4_n : ., mut = 0;
- loop {
- if o4_n >= 13 { break; }
- o4_ak4 := r64(o4_aks, o4_n * 8);
- o4_n2 : ., mut = 0;
- loop {
- if o4_n2 >= 6 { break; }
- o4_cop := OP_EQ + o4_n2; // OP_EQ..OP_GE 连续取值(6..11)
- if iface_permits(o4_ak4, o4_cop) != 1 { o4_all_bad = o4_all_bad + 1; }
- if iface_permits(o4_ak4, o4_cop) == 1 { o4_all_yes = o4_all_yes + 1; }
- o4_n2 = o4_n2 + 1;
- }
- o4_n3 : ., mut = 0;
- loop {
- if o4_n3 >= 4 { break; }
- o4_uop := IP_UOP_BIAS + 1 + o4_n3; // UOP_NEG..UOP_DEREF → 21..24
- if iface_permits(o4_ak4, o4_uop) != 1 { o4_all_bad = o4_all_bad + 1; }
- if iface_permits(o4_ak4, o4_uop) == 1 { o4_all_yes = o4_all_yes + 1; }
- o4_n3 = o4_n3 + 1;
- }
- if iface_permits(o4_ak4, IP_AS) != 1 { o4_all_bad = o4_all_bad + 1; }
- if iface_permits(o4_ak4, IP_AS) == 1 { o4_all_yes = o4_all_yes + 1; }
- o4_n = o4_n + 1;
- }
- total = total + 1; fails = fails + ts_check("ops.all_permit_eq_legacy", o4_all_bad, 0);
- total = total + 1; fails = fails + ts_check("ops.all_permit_count", o4_all_yes, 143); // 13 × 11
+ o4_all_bad : ., mut = 0
+ o4_all_yes : ., mut = 0
+ o4_n : ., mut = 0
+ loop:
+ if o4_n >= 13:
+ break
+ o4_ak4 := r64(o4_aks, o4_n * 8)
+ o4_n2 : ., mut = 0
+ loop:
+ if o4_n2 >= 6:
+ break
+ o4_cop := OP_EQ + o4_n2 // OP_EQ..OP_GE 连续取值(6..11)
+ if iface_permits(o4_ak4, o4_cop) != 1:
+ o4_all_bad = o4_all_bad + 1
+ if iface_permits(o4_ak4, o4_cop) == 1:
+ o4_all_yes = o4_all_yes + 1
+ o4_n2 = o4_n2 + 1
+ o4_n3 : ., mut = 0
+ loop:
+ if o4_n3 >= 4:
+ break
+ o4_uop := IP_UOP_BIAS + 1 + o4_n3 // UOP_NEG..UOP_DEREF → 21..24
+ if iface_permits(o4_ak4, o4_uop) != 1:
+ o4_all_bad = o4_all_bad + 1
+ if iface_permits(o4_ak4, o4_uop) == 1:
+ o4_all_yes = o4_all_yes + 1
+ o4_n3 = o4_n3 + 1
+ if iface_permits(o4_ak4, IP_AS) != 1:
+ o4_all_bad = o4_all_bad + 1
+ if iface_permits(o4_ak4, IP_AS) == 1:
+ o4_all_yes = o4_all_yes + 1
+ o4_n = o4_n + 1
+ total = total + 1
+ fails = fails + ts_check("ops.all_permit_eq_legacy", o4_all_bad, 0)
+ total = total + 1
+ fails = fails + ts_check("ops.all_permit_count", o4_all_yes, 143) // 13 × 11
// ⑤ 容器/方法面(Task 5 的消费格;本批登记):索引/字段/方法各恰两类
- total = total + 1; fails = fails + ts_check_b("ops.index_permit_set",
+ total = total + 1
+ fails = fails + ts_check_b("ops.index_permit_set",
(iface_permits(AK_SEQUENCE, IP_INDEX) == 1 && iface_permits(AK_STRING, IP_INDEX) == 1 &&
- iface_permits(AK_INT, IP_INDEX) == 0 && iface_permits(AK_REF, IP_INDEX) == 0 &&
- iface_permits(AK_SEQUENCE, IP_INDEX_RANGE) == 1 && iface_permits(AK_STRING, IP_INDEX_RANGE) == 0), true);
- total = total + 1; fails = fails + ts_check_b("ops.field_permit_set",
+ iface_permits(AK_INT, IP_INDEX) == 0 && iface_permits(AK_REF, IP_INDEX) == 0 &&
+ iface_permits(AK_SEQUENCE, IP_INDEX_RANGE) == 1 && iface_permits(AK_STRING, IP_INDEX_RANGE) == 0), true)
+ total = total + 1
+ fails = fails + ts_check_b("ops.field_permit_set",
(iface_permits(AK_NAMED, IP_FIELD) == 1 && iface_permits(AK_PRODUCT, IP_FIELD) == 1 &&
- iface_permits(AK_INT, IP_FIELD) == 0 && iface_permits(AK_SEQUENCE, IP_FIELD) == 0), true);
- total = total + 1; fails = fails + ts_check_b("ops.method_permit_set",
+ iface_permits(AK_INT, IP_FIELD) == 0 && iface_permits(AK_SEQUENCE, IP_FIELD) == 0), true)
+ total = total + 1
+ fails = fails + ts_check_b("ops.method_permit_set",
(iface_permits(AK_DYN, IP_METHOD) == 1 && iface_permits(AK_NAMED, IP_METHOD) == 1 &&
- iface_permits(AK_INT, IP_METHOD) == 0 && iface_permits(AK_PTR, IP_METHOD) == 0), true);
+ iface_permits(AK_INT, IP_METHOD) == 0 && iface_permits(AK_PTR, IP_METHOD) == 0), true)
// ⑥ 条目面一致性(逐条目:`iface_ops(ak)` 必须回读该行的 ops 列;防「列未填/查错行」)。
// R2 P4 Task 3 重定:扩列三行(AK_NULL/AK_SUM/AK_FN)= **纯信息面**(ops = 0 是设计值,
// 非「空集残留」)⇒ 零 ops 行 = **恰三行且逐名可指**(允许集显式列举,其余行仍须非 0
// ——T1..T2 口径保持)。
- o4_row_bad : ., mut = 0;
- o4_zero : ., mut = 0;
- o4_r : ., mut = 0;
- loop {
- if o4_r >= g_iface_entry_count { break; }
- o4_akr := r64(g_iface_entries, o4_r * ESZ_IFACE_ENTRY + OFF_IE_AK);
- if iface_ops(o4_akr) != r64(g_iface_entries, o4_r * ESZ_IFACE_ENTRY + OFF_IE_OPS) { o4_row_bad = o4_row_bad + 1; }
- if iface_ops(o4_akr) == 0 {
- if o4_akr == AK_NULL || o4_akr == AK_SUM || o4_akr == AK_FN { o4_zero = o4_zero + 1; }
- else { o4_row_bad = o4_row_bad + 1; }
- }
- o4_r = o4_r + 1;
- }
- total = total + 1; fails = fails + ts_check_b("ops.entry_row_consistent",
- (o4_row_bad == 0 && o4_zero == 3), true);
+ o4_row_bad : ., mut = 0
+ o4_zero : ., mut = 0
+ o4_r : ., mut = 0
+ loop:
+ if o4_r >= g_iface_entry_count:
+ break
+ o4_akr := r64(g_iface_entries, o4_r * ESZ_IFACE_ENTRY + OFF_IE_AK)
+ if iface_ops(o4_akr) != r64(g_iface_entries, o4_r * ESZ_IFACE_ENTRY + OFF_IE_OPS):
+ o4_row_bad = o4_row_bad + 1
+ if iface_ops(o4_akr) == 0:
+ if o4_akr == AK_NULL || o4_akr == AK_SUM || o4_akr == AK_FN:
+ o4_zero = o4_zero + 1
+ else:
+ o4_row_bad = o4_row_bad + 1
+ o4_r = o4_r + 1
+ total = total + 1
+ fails = fails + ts_check_b("ops.entry_row_consistent",
+ (o4_row_bad == 0 && o4_zero == 3), true)
// ⑦ 端到端(经真 infer_expr 走三个门;**行为证据**——表侧用例证明不了「线对」):
// ptr 操作数 = `&int 字面量` 的构造节点(EXPR_UNARY/UOP_REF,非 ident 分支 ⇒ 不触借用检查)
- o4_ref := alloc_node(EXPR_UNARY, li_int, -1, UOP_REF, 0, 0, -1, 0, 0);
- o4_ref2 := alloc_node(EXPR_UNARY, li_int, -1, UOP_REF, 0, 0, -1, 0, 0);
- o4_b_add_int := alloc_node(EXPR_BINARY, li_int, li_int, OP_ADD, 0, 0, -1, 0, 0);
- o4_b_sub_str := alloc_node(EXPR_BINARY, li_str, li_str, OP_SUB, 0, 0, -1, 0, 0);
- o4_b_add_str := alloc_node(EXPR_BINARY, li_str, li_str, OP_ADD, 0, 0, -1, 0, 0);
- o4_b_ptrptr := alloc_node(EXPR_BINARY, o4_ref, o4_ref2, OP_ADD, 0, 0, -1, 0, 0);
- o4_b_ptrdiff := alloc_node(EXPR_BINARY, o4_ref, o4_ref2, OP_SUB, 0, 0, -1, 0, 0);
- o4_b_ptradd := alloc_node(EXPR_BINARY, o4_ref, li_int, OP_ADD, 0, 0, -1, 0, 0);
- o4_b_dex := alloc_node(EXPR_BINARY, li_dex, li_int, OP_ADD, 0, 0, -1, 0, 0);
- o4_b_logic := alloc_node(EXPR_BINARY, li_bool, li_int, OP_AND, 0, 0, -1, 0, 0);
- o4_b_logic_bad := alloc_node(EXPR_BINARY, li_dex, li_bool, OP_AND, 0, 0, -1, 0, 0);
- o4_b_eq := alloc_node(EXPR_BINARY, li_str, li_int, OP_EQ, 0, 0, -1, 0, 0);
+ o4_ref := alloc_node(EXPR_UNARY, li_int, -1, UOP_REF, 0, 0, -1, 0, 0)
+ o4_ref2 := alloc_node(EXPR_UNARY, li_int, -1, UOP_REF, 0, 0, -1, 0, 0)
+ o4_b_add_int := alloc_node(EXPR_BINARY, li_int, li_int, OP_ADD, 0, 0, -1, 0, 0)
+ o4_b_sub_str := alloc_node(EXPR_BINARY, li_str, li_str, OP_SUB, 0, 0, -1, 0, 0)
+ o4_b_add_str := alloc_node(EXPR_BINARY, li_str, li_str, OP_ADD, 0, 0, -1, 0, 0)
+ o4_b_ptrptr := alloc_node(EXPR_BINARY, o4_ref, o4_ref2, OP_ADD, 0, 0, -1, 0, 0)
+ o4_b_ptrdiff := alloc_node(EXPR_BINARY, o4_ref, o4_ref2, OP_SUB, 0, 0, -1, 0, 0)
+ o4_b_ptradd := alloc_node(EXPR_BINARY, o4_ref, li_int, OP_ADD, 0, 0, -1, 0, 0)
+ o4_b_dex := alloc_node(EXPR_BINARY, li_dex, li_int, OP_ADD, 0, 0, -1, 0, 0)
+ o4_b_logic := alloc_node(EXPR_BINARY, li_bool, li_int, OP_AND, 0, 0, -1, 0, 0)
+ o4_b_logic_bad := alloc_node(EXPR_BINARY, li_dex, li_bool, OP_AND, 0, 0, -1, 0, 0)
+ o4_b_eq := alloc_node(EXPR_BINARY, li_str, li_int, OP_EQ, 0, 0, -1, 0, 0)
// 反真空哨兵:构造节点确实带预期 kind/op(防 alloc_node 参数错位 ⇒ 假绿)
- total = total + 1; fails = fails + ts_check_b("ops.node_kinds",
+ total = total + 1
+ fails = fails + ts_check_b("ops.node_kinds",
(ast_kind(o4_b_add_int) == EXPR_BINARY && ast_c(o4_b_add_int) == OP_ADD &&
- ast_kind(o4_ref) == EXPR_UNARY && ast_c(o4_ref) == UOP_REF), true);
+ ast_kind(o4_ref) == EXPR_UNARY && ast_c(o4_ref) == UOP_REF), true)
// 正控:int 算术 / 串拼接(早退规则)/ 指针算术 + int / dex 支配 / 逻辑 int 侧 / 比较不校验
- o4_m0 := g_diag_count;
- o4_r_add := infer_expr(o4_b_add_int);
- total = total + 1; fails = fails + ts_check("ops.infer_add_int",
- o4_r_add * 100 + (g_diag_count - o4_m0), TI_INT * 100);
- o4_m1 := g_diag_count;
- o4_r_cat := infer_expr(o4_b_add_str);
- total = total + 1; fails = fails + ts_check("ops.infer_add_str_concat",
- o4_r_cat * 100 + (g_diag_count - o4_m1), TI_STR * 100);
- o4_m2 := g_diag_count;
- o4_r_pa := infer_expr(o4_b_ptradd);
+ o4_m0 := g_diag_count
+ o4_r_add := infer_expr(o4_b_add_int)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_add_int",
+ o4_r_add * 100 + (g_diag_count - o4_m0), TI_INT * 100)
+ o4_m1 := g_diag_count
+ o4_r_cat := infer_expr(o4_b_add_str)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_add_str_concat",
+ o4_r_cat * 100 + (g_diag_count - o4_m1), TI_STR * 100)
+ o4_m2 := g_diag_count
+ o4_r_pa := infer_expr(o4_b_ptradd)
// 结果 = 地址型行本身(T = int):**不**与另一次 `infer_expr(o4_ref)` 的行号比——alloc_type
// 是裸分配器(不去重,每次调用追加新行)⇒ 两次推断的行号必然不同(比行号 = 永久红)。
// ⚠ **前提已改(2026-09-20,随 S3 裁定;改前提、不删断言)**:
@@ -2779,59 +3137,73 @@ fn type_selftest_run() -> int {
// · **新契约** = **结果保持操作数 kind** ⇒ `o4_ref`(现为 REF)进 ⇒ **结果 `TYP_REF`**。
// ⇒ 本行同时充任**正钉**:证明门**真的接受 REF**(不是「算术整条被关掉」——门若被关,
// 这里会因 `g_diag_count` 变化而红)。
- o4_pa_ok : ., mut = 0;
- if get_type_kind(o4_r_pa) == TYP_REF && get_type_data(o4_r_pa) == TI_INT {
- if g_diag_count - o4_m2 == 0 { o4_pa_ok = 1; }
- }
- total = total + 1; fails = fails + ts_check("ops.infer_ptr_add_int", o4_pa_ok, 1);
+ o4_pa_ok : ., mut = 0
+ if get_type_kind(o4_r_pa) == TYP_REF && get_type_data(o4_r_pa) == TI_INT:
+ if g_diag_count - o4_m2 == 0:
+ o4_pa_ok = 1
+ total = total + 1
+ fails = fails + ts_check("ops.infer_ptr_add_int", o4_pa_ok, 1)
// S3 附加钉(2026-09-20):**`int + 地址型` 方向**——覆盖本门**第 2 个谓词**
// (`lt == TI_INT && rt 为地址型`);上一例只覆盖第 1 个谓词(地址型在左)。
// **同时是「门真的接受 REF」的独立第二例**:`li_int + o4_ref2` ⇒ 结果 = `o4_ref2` 的 kind(REF)。
// **反面对照**由既有 `ops.infer_add_int`(`int + int` ⇒ `TI_INT` 且 **0 错误**,F0 已写死)承担
// ⇒ 两例合起来满足「**放得对**(门没被一律关掉)+ **没一律放**(非地址型照旧)」。
- o4_b_intaddr := alloc_node(EXPR_BINARY, li_int, o4_ref2, OP_ADD, 0, 0, -1, 0, 0);
- o4_m2b := g_diag_count;
- o4_r_ia := infer_expr(o4_b_intaddr);
- o4_ia_ok : ., mut = 0;
- if get_type_kind(o4_r_ia) == TYP_REF && get_type_data(o4_r_ia) == TI_INT {
- if g_diag_count - o4_m2b == 0 { o4_ia_ok = 1; }
- }
- total = total + 1; fails = fails + ts_check("ops.infer_int_add_addr", o4_ia_ok, 1);
- o4_m3 := g_diag_count;
- o4_r_dx := infer_expr(o4_b_dex);
- total = total + 1; fails = fails + ts_check("ops.infer_dex_add",
- o4_r_dx * 100 + (g_diag_count - o4_m3), TI_DEX * 100);
- o4_m4 := g_diag_count;
- o4_r_lg := infer_expr(o4_b_logic);
- total = total + 1; fails = fails + ts_check("ops.infer_logic_int_ok",
- o4_r_lg * 100 + (g_diag_count - o4_m4), TI_BOOL * 100);
- o4_m5 := g_diag_count;
- o4_r_eq := infer_expr(o4_b_eq);
- total = total + 1; fails = fails + ts_check("ops.infer_cmp_unchecked",
- o4_r_eq * 100 + (g_diag_count - o4_m5), TI_BOOL * 100); // 现状宽松面:比较不校验(登记)
+ o4_b_intaddr := alloc_node(EXPR_BINARY, li_int, o4_ref2, OP_ADD, 0, 0, -1, 0, 0)
+ o4_m2b := g_diag_count
+ o4_r_ia := infer_expr(o4_b_intaddr)
+ o4_ia_ok : ., mut = 0
+ if get_type_kind(o4_r_ia) == TYP_REF && get_type_data(o4_r_ia) == TI_INT:
+ if g_diag_count - o4_m2b == 0:
+ o4_ia_ok = 1
+ total = total + 1
+ fails = fails + ts_check("ops.infer_int_add_addr", o4_ia_ok, 1)
+ o4_m3 := g_diag_count
+ o4_r_dx := infer_expr(o4_b_dex)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_dex_add",
+ o4_r_dx * 100 + (g_diag_count - o4_m3), TI_DEX * 100)
+ o4_m4 := g_diag_count
+ o4_r_lg := infer_expr(o4_b_logic)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_logic_int_ok",
+ o4_r_lg * 100 + (g_diag_count - o4_m4), TI_BOOL * 100)
+ o4_m5 := g_diag_count
+ o4_r_eq := infer_expr(o4_b_eq)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_cmp_unchecked",
+ o4_r_eq * 100 + (g_diag_count - o4_m5), TI_BOOL * 100) // 现状宽松面:比较不校验(登记)
// 负控(**本批最易放宽的三条**):string 算术 / ptr+ptr / dex 逻辑 → 必须仍报错(码不变)
- o4_m6 := g_diag_count;
- o4_r_bad1 := infer_expr(o4_b_sub_str);
- total = total + 1; fails = fails + ts_check("ops.infer_sub_str_diag", g_diag_count - o4_m6, 1);
- total = total + 1; fails = fails + ts_check("ops.infer_sub_str_code", ts_diag_code_at(o4_m6), EC_TB_ADD);
- total = total + 1; fails = fails + ts_check("ops.infer_sub_str_result", o4_r_bad1, TI_INT);
- o4_m7 := g_diag_count;
- o4_r_bad2 := infer_expr(o4_b_ptrptr);
- total = total + 1; fails = fails + ts_check("ops.infer_ptr_add_ptr_diag", g_diag_count - o4_m7, 1);
- total = total + 1; fails = fails + ts_check("ops.infer_ptr_add_ptr_code", ts_diag_code_at(o4_m7), EC_TB_ADD);
- total = total + 1; fails = fails + ts_check("ops.infer_ptr_add_ptr_result", o4_r_bad2, TI_INT);
- o4_m8 := g_diag_count;
- o4_r_bad3 := infer_expr(o4_b_logic_bad);
- total = total + 1; fails = fails + ts_check("ops.infer_logic_dex_diag", g_diag_count - o4_m8, 1);
- total = total + 1; fails = fails + ts_check("ops.infer_logic_dex_code", ts_diag_code_at(o4_m8), EC_TC_IF_COND);
+ o4_m6 := g_diag_count
+ o4_r_bad1 := infer_expr(o4_b_sub_str)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_sub_str_diag", g_diag_count - o4_m6, 1)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_sub_str_code", ts_diag_code_at(o4_m6), EC_TB_ADD)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_sub_str_result", o4_r_bad1, TI_INT)
+ o4_m7 := g_diag_count
+ o4_r_bad2 := infer_expr(o4_b_ptrptr)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_ptr_add_ptr_diag", g_diag_count - o4_m7, 1)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_ptr_add_ptr_code", ts_diag_code_at(o4_m7), EC_TB_ADD)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_ptr_add_ptr_result", o4_r_bad2, TI_INT)
+ o4_m8 := g_diag_count
+ o4_r_bad3 := infer_expr(o4_b_logic_bad)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_logic_dex_diag", g_diag_count - o4_m8, 1)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_logic_dex_code", ts_diag_code_at(o4_m8), EC_TC_IF_COND)
// 早退规则保留(结果规则):指针差 = 地址型 − 地址型 → int(不经门、不报错)
// ⚠ **前提随 S3 恢复成立(2026-09-20)**:`o4_ref` 现为 REF ⇒ 改判后一度**落空算术门而报诊断**
// (这正是 S1 落地后本档转红的原因);S3 把 REF 纳入本门后,**「结果 = `TI_INT` 且 0 诊断」
// 在新契约下同样成立** ⇒ **期望值不变,只是它重新成立**(不是改断言)。
- o4_m9 := g_diag_count;
- o4_r_pd := infer_expr(o4_b_ptrdiff);
- total = total + 1; fails = fails + ts_check("ops.infer_ptr_diff",
- o4_r_pd * 100 + (g_diag_count - o4_m9), TI_INT * 100);
+ o4_m9 := g_diag_count
+ o4_r_pd := infer_expr(o4_b_ptrdiff)
+ total = total + 1
+ fails = fails + ts_check("ops.infer_ptr_diff",
+ o4_r_pd * 100 + (g_diag_count - o4_m9), TI_INT * 100)
// --- R2 P2b Task 5:容器面接线(**唯一接线点** = 索引兜底拒绝 → IP_INDEX 查表)---
// 三层判据:
@@ -2842,106 +3214,134 @@ fn type_selftest_run() -> int {
// ② **端到端经真 infer_expr**(三个结果分支保留 + 兜底门在判):诊断增量 + 码 + 结果类型。
// ③ 反真空哨兵:枚举覆盖行类直方图非退化 + 构造节点 kind/op 正确。
// 覆盖行类自备(不依赖前序段落的残余行):PTR/REF/TUPLE 各一行,供 ③ 的直方图计数
- ix_row_ptr := alloc_type(TYP_PTR, TI_INT, 0);
- ix_row_ref := alloc_type(TYP_REF, TI_INT, 0);
- ix_row_tup := alloc_type(TYP_TUPLE, 0, 0);
- ix_li0 := alloc_node(EXPR_INT, -1, -1, -1, 0, TY_INT, -1, 0, 0); // 索引值 0(串下标须在界内,避免 F 面诊断)
- ix_arr3 := alloc_node(EXPR_ARRAY, -1, 3, -1, 0, 0, -1, 0, 0); // 数组字面量 len=3(无元素)
- ix_arr0 := alloc_node(EXPR_ARRAY, -1, 0, -1, 0, 0, -1, 0, 0); // 空数组字面量 len=0
- ix_idx_arr := alloc_node(EXPR_INDEX, ix_arr0, li_int, -1, 0, 0, -1, 0, 0);
- ix_idx_str := alloc_node(EXPR_INDEX, li_str, ix_li0, -1, 0, 0, -1, 0, 0);
- ix_idx_int := alloc_node(EXPR_INDEX, li_int, li_int, -1, 0, 0, -1, 0, 0);
- ix_idx_bool := alloc_node(EXPR_INDEX, li_bool, li_int, -1, 0, 0, -1, 0, 0);
- ix_ref := alloc_node(EXPR_UNARY, li_int, -1, UOP_REF, 0, 0, -1, 0, 0);
- ix_idx_ptr := alloc_node(EXPR_INDEX, ix_ref, li_int, -1, 0, 0, -1, 0, 0);
- ix_range := alloc_node(EXPR_RANGE, li_int, li_int, -1, 0, 0, -1, 0, 0);
- ix_idx_arr_range := alloc_node(EXPR_INDEX, ix_arr0, ix_range, -1, 0, 0, -1, 0, 0);
- ix_idx_str_range := alloc_node(EXPR_INDEX, li_str, ix_range, -1, 0, 0, -1, 0, 0);
- ix_idx_arr_oob := alloc_node(EXPR_INDEX, ix_arr3, li_int, -1, 0, 0, -1, 0, 0);
- ix_idx_range_oob := alloc_node(EXPR_INDEX, ix_arr3, ix_range, -1, 0, 0, -1, 0, 0);
- total = total + 1; fails = fails + ts_check_b("idx.node_kinds",
+ ix_row_ptr := alloc_type(TYP_PTR, TI_INT, 0)
+ ix_row_ref := alloc_type(TYP_REF, TI_INT, 0)
+ ix_row_tup := alloc_type(TYP_TUPLE, 0, 0)
+ ix_li0 := alloc_node(EXPR_INT, -1, -1, -1, 0, TY_INT, -1, 0, 0) // 索引值 0(串下标须在界内,避免 F 面诊断)
+ ix_arr3 := alloc_node(EXPR_ARRAY, -1, 3, -1, 0, 0, -1, 0, 0) // 数组字面量 len=3(无元素)
+ ix_arr0 := alloc_node(EXPR_ARRAY, -1, 0, -1, 0, 0, -1, 0, 0) // 空数组字面量 len=0
+ ix_idx_arr := alloc_node(EXPR_INDEX, ix_arr0, li_int, -1, 0, 0, -1, 0, 0)
+ ix_idx_str := alloc_node(EXPR_INDEX, li_str, ix_li0, -1, 0, 0, -1, 0, 0)
+ ix_idx_int := alloc_node(EXPR_INDEX, li_int, li_int, -1, 0, 0, -1, 0, 0)
+ ix_idx_bool := alloc_node(EXPR_INDEX, li_bool, li_int, -1, 0, 0, -1, 0, 0)
+ ix_ref := alloc_node(EXPR_UNARY, li_int, -1, UOP_REF, 0, 0, -1, 0, 0)
+ ix_idx_ptr := alloc_node(EXPR_INDEX, ix_ref, li_int, -1, 0, 0, -1, 0, 0)
+ ix_range := alloc_node(EXPR_RANGE, li_int, li_int, -1, 0, 0, -1, 0, 0)
+ ix_idx_arr_range := alloc_node(EXPR_INDEX, ix_arr0, ix_range, -1, 0, 0, -1, 0, 0)
+ ix_idx_str_range := alloc_node(EXPR_INDEX, li_str, ix_range, -1, 0, 0, -1, 0, 0)
+ ix_idx_arr_oob := alloc_node(EXPR_INDEX, ix_arr3, li_int, -1, 0, 0, -1, 0, 0)
+ ix_idx_range_oob := alloc_node(EXPR_INDEX, ix_arr3, ix_range, -1, 0, 0, -1, 0, 0)
+ total = total + 1
+ fails = fails + ts_check_b("idx.node_kinds",
(ast_kind(ix_idx_arr) == EXPR_INDEX && ast_kind(ix_arr3) == EXPR_ARRAY && ast_b(ix_idx_arr) == li_int &&
- ast_kind(ix_range) == EXPR_RANGE && ast_kind(ix_idx_ptr) == EXPR_INDEX && ast_c(ix_ref) == UOP_REF), true);
+ ast_kind(ix_range) == EXPR_RANGE && ast_kind(ix_idx_ptr) == EXPR_INDEX && ast_c(ix_ref) == UOP_REF), true)
// ① 集等价(逐行):perm == 1 ⟺ 该行**不**属于「结果分支已处理集」{kind ARRAY, kind SLICE, ti == TI_STR}
- ix_bad : ., mut = 0;
- ix_n_rows : ., mut = 0;
- ix_n_seq : ., mut = 0;
- ix_n_str : ., mut = 0;
- ix_n_named : ., mut = 0;
- ix_n_prod : ., mut = 0;
- ix_n_ref : ., mut = 0;
- ix_n_ptr : ., mut = 0;
- ix_n_dyn : ., mut = 0;
- ix_i : ., mut = 0;
- loop {
- if ix_i >= g_type_count { break; }
- ix_k := get_type_kind(ix_i);
- ix_ak := iface_kind_of(ix_i);
- ix_reach : ., mut = 1; // 1 = 到达兜底门(结果分支都不命中)
- if ix_k == TYP_ARRAY || ix_k == TYP_SLICE || ix_i == TI_STR { ix_reach = 0; }
- ix_perm := iface_permits(ix_ak, IP_INDEX);
- ix_want : ., mut = 1;
- if ix_reach == 1 { ix_want = 0; }
- if ix_perm != ix_want { ix_bad = ix_bad + 1; }
- if ix_k == TYP_ARRAY || ix_k == TYP_SLICE { ix_n_seq = ix_n_seq + 1; }
- if ix_i == TI_STR { ix_n_str = ix_n_str + 1; }
- if ix_ak == AK_NAMED { ix_n_named = ix_n_named + 1; }
- if ix_ak == AK_PRODUCT { ix_n_prod = ix_n_prod + 1; }
- if ix_ak == AK_REF { ix_n_ref = ix_n_ref + 1; }
- if ix_ak == AK_PTR { ix_n_ptr = ix_n_ptr + 1; }
- if ix_ak == AK_DYN { ix_n_dyn = ix_n_dyn + 1; }
- ix_n_rows = ix_n_rows + 1;
- ix_i = ix_i + 1;
- }
- total = total + 1; fails = fails + ts_check("idx.gate_deny_covers_fallback", ix_bad, 0);
+ ix_bad : ., mut = 0
+ ix_n_rows : ., mut = 0
+ ix_n_seq : ., mut = 0
+ ix_n_str : ., mut = 0
+ ix_n_named : ., mut = 0
+ ix_n_prod : ., mut = 0
+ ix_n_ref : ., mut = 0
+ ix_n_ptr : ., mut = 0
+ ix_n_dyn : ., mut = 0
+ ix_i : ., mut = 0
+ loop:
+ if ix_i >= g_type_count:
+ break
+ ix_k := get_type_kind(ix_i)
+ ix_ak := iface_kind_of(ix_i)
+ ix_reach : ., mut = 1 // 1 = 到达兜底门(结果分支都不命中)
+ if ix_k == TYP_ARRAY || ix_k == TYP_SLICE || ix_i == TI_STR:
+ ix_reach = 0
+ ix_perm := iface_permits(ix_ak, IP_INDEX)
+ ix_want : ., mut = 1
+ if ix_reach == 1:
+ ix_want = 0
+ if ix_perm != ix_want:
+ ix_bad = ix_bad + 1
+ if ix_k == TYP_ARRAY || ix_k == TYP_SLICE:
+ ix_n_seq = ix_n_seq + 1
+ if ix_i == TI_STR:
+ ix_n_str = ix_n_str + 1
+ if ix_ak == AK_NAMED:
+ ix_n_named = ix_n_named + 1
+ if ix_ak == AK_PRODUCT:
+ ix_n_prod = ix_n_prod + 1
+ if ix_ak == AK_REF:
+ ix_n_ref = ix_n_ref + 1
+ if ix_ak == AK_PTR:
+ ix_n_ptr = ix_n_ptr + 1
+ if ix_ak == AK_DYN:
+ ix_n_dyn = ix_n_dyn + 1
+ ix_n_rows = ix_n_rows + 1
+ ix_i = ix_i + 1
+ total = total + 1
+ fails = fails + ts_check("idx.gate_deny_covers_fallback", ix_bad, 0)
// ③ 反真空:扫满全表 + 每类至少一行 + **STR 行恰 1 行**(`ti == TI_STR` ⇔ AK_STRING 的等价性
// 依赖「TYP_BASE 行唯一分配点 = init_types」——该行数若变,本例先红)
- total = total + 1; fails = fails + ts_check_b("idx.scan_coverage",
+ total = total + 1
+ fails = fails + ts_check_b("idx.scan_coverage",
(ix_n_rows == g_type_count && ix_n_rows >= 15 && ix_n_seq >= 2 && ix_n_str == 1 &&
- ix_n_named >= 1 && ix_n_prod >= 1 && ix_n_ref >= 1 && ix_n_ptr >= 1 && ix_n_dyn >= 1 &&
- get_type_kind(ix_row_ptr) == TYP_PTR && get_type_kind(ix_row_ref) == TYP_REF &&
- get_type_kind(ix_row_tup) == TYP_TUPLE), true);
+ ix_n_named >= 1 && ix_n_prod >= 1 && ix_n_ref >= 1 && ix_n_ptr >= 1 && ix_n_dyn >= 1 &&
+ get_type_kind(ix_row_ptr) == TYP_PTR && get_type_kind(ix_row_ref) == TYP_REF &&
+ get_type_kind(ix_row_tup) == TYP_TUPLE), true)
// ② 端到端:结果分支保留(数组 → int、串 → int;含 OOB/F11 两个既有诊断仍发)
- ix_m0 := g_diag_count;
- ix_r_arr := infer_expr(ix_idx_arr);
- total = total + 1; fails = fails + ts_check("idx.infer_arr_ok", ix_r_arr * 100 + (g_diag_count - ix_m0), TI_INT * 100);
- ix_m1 := g_diag_count;
- ix_r_str := infer_expr(ix_idx_str);
- total = total + 1; fails = fails + ts_check("idx.infer_str_ok", ix_r_str * 100 + (g_diag_count - ix_m1), TI_INT * 100);
- ix_m2 := g_diag_count;
- ix_r_asc := infer_expr(ix_idx_arr_range);
- ix_asc_ok : ., mut = 0;
- if get_type_kind(ix_r_asc) == TYP_SLICE && get_type_data(ix_r_asc) == TI_INT {
- if g_diag_count - ix_m2 == 0 { ix_asc_ok = 1; }
- }
- total = total + 1; fails = fails + ts_check("idx.infer_range_slice", ix_asc_ok, 1);
+ ix_m0 := g_diag_count
+ ix_r_arr := infer_expr(ix_idx_arr)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_arr_ok", ix_r_arr * 100 + (g_diag_count - ix_m0), TI_INT * 100)
+ ix_m1 := g_diag_count
+ ix_r_str := infer_expr(ix_idx_str)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_str_ok", ix_r_str * 100 + (g_diag_count - ix_m1), TI_INT * 100)
+ ix_m2 := g_diag_count
+ ix_r_asc := infer_expr(ix_idx_arr_range)
+ ix_asc_ok : ., mut = 0
+ if get_type_kind(ix_r_asc) == TYP_SLICE && get_type_data(ix_r_asc) == TI_INT:
+ if g_diag_count - ix_m2 == 0:
+ ix_asc_ok = 1
+ total = total + 1
+ fails = fails + ts_check("idx.infer_range_slice", ix_asc_ok, 1)
// 兜底门在判:非容器行 → TK01(码/结果逐字不变)
- ix_m3 := g_diag_count;
- ix_r_int := infer_expr(ix_idx_int);
- total = total + 1; fails = fails + ts_check("idx.infer_int_denied_diag", g_diag_count - ix_m3, 1);
- total = total + 1; fails = fails + ts_check("idx.infer_int_denied_code", ts_diag_code_at(ix_m3), EC_TK_INDEX);
- total = total + 1; fails = fails + ts_check("idx.infer_int_denied_result", ix_r_int, TI_INT);
- ix_m4 := g_diag_count;
- infer_expr(ix_idx_bool);
- total = total + 1; fails = fails + ts_check("idx.infer_bool_denied_diag", g_diag_count - ix_m4, 1);
- total = total + 1; fails = fails + ts_check("idx.infer_bool_denied_code", ts_diag_code_at(ix_m4), EC_TK_INDEX);
- ix_m5 := g_diag_count;
- infer_expr(ix_idx_ptr);
- total = total + 1; fails = fails + ts_check("idx.infer_ptr_denied_diag", g_diag_count - ix_m5, 1);
- total = total + 1; fails = fails + ts_check("idx.infer_ptr_denied_code", ts_diag_code_at(ix_m5), EC_TK_INDEX);
+ ix_m3 := g_diag_count
+ ix_r_int := infer_expr(ix_idx_int)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_int_denied_diag", g_diag_count - ix_m3, 1)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_int_denied_code", ts_diag_code_at(ix_m3), EC_TK_INDEX)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_int_denied_result", ix_r_int, TI_INT)
+ ix_m4 := g_diag_count
+ infer_expr(ix_idx_bool)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_bool_denied_diag", g_diag_count - ix_m4, 1)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_bool_denied_code", ts_diag_code_at(ix_m4), EC_TK_INDEX)
+ ix_m5 := g_diag_count
+ infer_expr(ix_idx_ptr)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_ptr_denied_diag", g_diag_count - ix_m5, 1)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_ptr_denied_code", ts_diag_code_at(ix_m5), EC_TK_INDEX)
// 登记面(现状宽松,本 Task 断言「不动」):串 range 索引静默 → unit(range 分支的非数组落空)
- ix_m6 := g_diag_count;
- ix_r_sr := infer_expr(ix_idx_str_range);
- total = total + 1; fails = fails + ts_check("idx.infer_str_range_unit", ix_r_sr * 100 + (g_diag_count - ix_m6), TI_UNIT * 100);
+ ix_m6 := g_diag_count
+ ix_r_sr := infer_expr(ix_idx_str_range)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_str_range_unit", ix_r_sr * 100 + (g_diag_count - ix_m6), TI_UNIT * 100)
// 结果规则原地保留的**正证据**(防「接线把分支合并掉」):F2 越界 + F11 切片界仍发
- ix_m7 := g_diag_count;
- infer_expr(ix_idx_arr_oob);
- total = total + 1; fails = fails + ts_check("idx.infer_arr_oob_diag", g_diag_count - ix_m7, 1);
- total = total + 1; fails = fails + ts_check("idx.infer_arr_oob_code", ts_diag_code_at(ix_m7), EC_R_OOB);
- ix_m8 := g_diag_count;
- infer_expr(ix_idx_range_oob);
- total = total + 1; fails = fails + ts_check("idx.infer_range_oob_diag", g_diag_count - ix_m8, 1);
- total = total + 1; fails = fails + ts_check("idx.infer_range_oob_code", ts_diag_code_at(ix_m8), EC_TK_SLICE_BOUNDS);
+ ix_m7 := g_diag_count
+ infer_expr(ix_idx_arr_oob)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_arr_oob_diag", g_diag_count - ix_m7, 1)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_arr_oob_code", ts_diag_code_at(ix_m7), EC_R_OOB)
+ ix_m8 := g_diag_count
+ infer_expr(ix_idx_range_oob)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_range_oob_diag", g_diag_count - ix_m8, 1)
+ total = total + 1
+ fails = fails + ts_check("idx.infer_range_oob_code", ts_diag_code_at(ix_m8), EC_TK_SLICE_BOUNDS)
// --- R2 P2b Task 6:`res_type_node`/`res_call_type` 双份 TY→TI 映射合一(单表 ty_code_to_ti)---
// 三层判据:
@@ -2951,53 +3351,64 @@ fn type_selftest_run() -> int {
// ③ 反真空哨兵(构造节点 kind/tv 回读正确;负节点先行拒绝)+ **两表唯一差异格** NEVER 的双向断言
// (A → TI_NEVER、B → TI_UNIT——探针实测该格在调用位点**可达**,差异显式保留不静默合一)。
// 非真空性(表变 ⇒ ②段必变)由实施报告的突变控制承担:表侧用例只能证明表对,证明不了线对。
- total = total + 1; fails = fails + ts_check_b("t6.ty_code_head",
+ total = total + 1
+ fails = fails + ts_check_b("t6.ty_code_head",
(ty_code_to_ti(TY_INT) == TI_INT && ty_code_to_ti(TY_DEX) == TI_DEX &&
- ty_code_to_ti(TY_BOOL) == TI_BOOL && ty_code_to_ti(TY_STRING) == TI_STR &&
- ty_code_to_ti(TY_UNIT) == TI_UNIT), true);
- total = total + 1; fails = fails + ts_check_b("t6.ty_code_tail",
- (ty_code_to_ti(TY_NEVER) == TI_NEVER && ty_code_to_ti(TY_CHAR) == TI_CHAR), true);
+ ty_code_to_ti(TY_BOOL) == TI_BOOL && ty_code_to_ti(TY_STRING) == TI_STR &&
+ ty_code_to_ti(TY_UNIT) == TI_UNIT), true)
+ total = total + 1
+ fails = fails + ts_check_b("t6.ty_code_tail",
+ (ty_code_to_ti(TY_NEVER) == TI_NEVER && ty_code_to_ti(TY_CHAR) == TI_CHAR), true)
// 码 7 = TY_GENERIC_PARAM 与 TI_DYN 的数值撞车格(spec §2.4 现场):现状两表原文原样保留
- total = total + 1; fails = fails + ts_check_b("t6.ty_code_dyn7",
- (ty_code_to_ti(TI_DYN) == TI_DYN && ty_code_to_ti(TY_GENERIC_PARAM) == TI_DYN), true);
+ total = total + 1
+ fails = fails + ts_check_b("t6.ty_code_dyn7",
+ (ty_code_to_ti(TI_DYN) == TI_DYN && ty_code_to_ti(TY_GENERIC_PARAM) == TI_DYN), true)
// **表内不兜底**:TY_DEX_S(8) 不入表(计划注「不属两表并集」)+ 未知/负码 → -1
- total = total + 1; fails = fails + ts_check_b("t6.ty_code_domain",
- (ty_code_to_ti(TY_DEX_S) == -1 && ty_code_to_ti(-1) == -1 && ty_code_to_ti(999) == -1), true);
+ total = total + 1
+ fails = fails + ts_check_b("t6.ty_code_domain",
+ (ty_code_to_ti(TY_DEX_S) == -1 && ty_code_to_ti(-1) == -1 && ty_code_to_ti(999) == -1), true)
// ② 端到端:基型节点逐码(含 7 = dyn 码位——parser.cr:98 对 `dyn` 类型名正产此码)
- t6_int := alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0);
- t6_dex := alloc_node(0, 0, 0, 0, 0, TY_DEX, 0, 0, 0);
- t6_bool := alloc_node(0, 0, 0, 0, 0, TY_BOOL, 0, 0, 0);
- t6_str := alloc_node(0, 0, 0, 0, 0, TY_STRING, 0, 0, 0);
- t6_unit := alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, 0, 0);
- t6_never := alloc_node(0, 0, 0, 0, 0, TY_NEVER, 0, 0, 0);
- t6_char := alloc_node(0, 0, 0, 0, 0, TY_CHAR, 0, 0, 0);
- t6_dyn := alloc_node(0, 0, 0, 0, 0, TI_DYN, 0, 0, 0);
- t6_dex_s := alloc_node(0, 0, 0, 0, 0, TY_DEX_S, 0, 0, 0);
- t6_oob := alloc_node(0, 0, 0, 0, 0, 999, 0, 0, 0);
- total = total + 1; fails = fails + ts_check_b("t6.node_kinds",
+ t6_int := alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0)
+ t6_dex := alloc_node(0, 0, 0, 0, 0, TY_DEX, 0, 0, 0)
+ t6_bool := alloc_node(0, 0, 0, 0, 0, TY_BOOL, 0, 0, 0)
+ t6_str := alloc_node(0, 0, 0, 0, 0, TY_STRING, 0, 0, 0)
+ t6_unit := alloc_node(0, 0, 0, 0, 0, TY_UNIT, 0, 0, 0)
+ t6_never := alloc_node(0, 0, 0, 0, 0, TY_NEVER, 0, 0, 0)
+ t6_char := alloc_node(0, 0, 0, 0, 0, TY_CHAR, 0, 0, 0)
+ t6_dyn := alloc_node(0, 0, 0, 0, 0, TI_DYN, 0, 0, 0)
+ t6_dex_s := alloc_node(0, 0, 0, 0, 0, TY_DEX_S, 0, 0, 0)
+ t6_oob := alloc_node(0, 0, 0, 0, 0, 999, 0, 0, 0)
+ total = total + 1
+ fails = fails + ts_check_b("t6.node_kinds",
(ast_kind(t6_never) == 0 && ast_type_val(t6_never) == TY_NEVER &&
- ast_type_val(t6_dyn) == TI_DYN && ast_type_val(t6_dex_s) == TY_DEX_S), true);
- total = total + 1; fails = fails + ts_check_b("t6.R_codes",
+ ast_type_val(t6_dyn) == TI_DYN && ast_type_val(t6_dex_s) == TY_DEX_S), true)
+ total = total + 1
+ fails = fails + ts_check_b("t6.R_codes",
(res_type_node(t6_int) == TI_INT && res_type_node(t6_dex) == TI_DEX &&
- res_type_node(t6_bool) == TI_BOOL && res_type_node(t6_str) == TI_STR &&
- res_type_node(t6_unit) == TI_UNIT && res_type_node(t6_never) == TI_NEVER &&
- res_type_node(t6_char) == TI_CHAR), true);
- total = total + 1; fails = fails + ts_check_b("t6.C_codes",
+ res_type_node(t6_bool) == TI_BOOL && res_type_node(t6_str) == TI_STR &&
+ res_type_node(t6_unit) == TI_UNIT && res_type_node(t6_never) == TI_NEVER &&
+ res_type_node(t6_char) == TI_CHAR), true)
+ total = total + 1
+ fails = fails + ts_check_b("t6.C_codes",
(res_call_type(t6_int, -1) == TI_INT && res_call_type(t6_dex, -1) == TI_DEX &&
- res_call_type(t6_bool, -1) == TI_BOOL && res_call_type(t6_str, -1) == TI_STR &&
- res_call_type(t6_unit, -1) == TI_UNIT && res_call_type(t6_char, -1) == TI_CHAR), true);
+ res_call_type(t6_bool, -1) == TI_BOOL && res_call_type(t6_str, -1) == TI_STR &&
+ res_call_type(t6_unit, -1) == TI_UNIT && res_call_type(t6_char, -1) == TI_CHAR), true)
// **两表唯一语义差**:NEVER 格(A 有 / B 无 ⇒ B 落 TI_UNIT)——差异不得被合一抹平
- total = total + 1; fails = fails + ts_check_b("t6.never_cell_diff",
- (res_type_node(t6_never) == TI_NEVER && res_call_type(t6_never, -1) == TI_UNIT), true);
+ total = total + 1
+ fails = fails + ts_check_b("t6.never_cell_diff",
+ (res_type_node(t6_never) == TI_NEVER && res_call_type(t6_never, -1) == TI_UNIT), true)
// 两表**共有**的 7 码格(dyn):均 → TI_DYN(B2 探针:`x : dyn = 5; x.nosuch()` 的 N08 依赖本格)
- total = total + 1; fails = fails + ts_check_b("t6.dyn_cell_both",
- (res_type_node(t6_dyn) == TI_DYN && res_call_type(t6_dyn, -1) == TI_DYN), true);
+ total = total + 1
+ fails = fails + ts_check_b("t6.dyn_cell_both",
+ (res_type_node(t6_dyn) == TI_DYN && res_call_type(t6_dyn, -1) == TI_DYN), true)
// 域外码(TY_DEX_S/未知)两表均落 TI_UNIT(= 改动前的尾回落;表内无兜底)
- total = total + 1; fails = fails + ts_check_b("t6.dex_s_oob_unit",
+ total = total + 1
+ fails = fails + ts_check_b("t6.dex_s_oob_unit",
(res_type_node(t6_dex_s) == TI_UNIT && res_call_type(t6_dex_s, -1) == TI_UNIT &&
- res_type_node(t6_oob) == TI_UNIT && res_call_type(t6_oob, -1) == TI_UNIT), true);
- total = total + 1; fails = fails + ts_check_b("t6.neg_node_unit",
- (res_type_node(-1) == TI_UNIT && res_call_type(-1, -1) == TI_UNIT), true);
+ res_type_node(t6_oob) == TI_UNIT && res_call_type(t6_oob, -1) == TI_UNIT), true)
+ total = total + 1
+ fails = fails + ts_check_b("t6.neg_node_unit",
+ (res_type_node(-1) == TI_UNIT && res_call_type(-1, -1) == TI_UNIT), true)
// ═══ R2 P3 Task 0:引擎展开层(named/struct/enum/generic-apply → 结构项)═══
// 判据面 = ① 正向形态:字段**声明序** / 变体数 / 泛型实参代入;② **名义不变量双钉**
@@ -3007,180 +3418,197 @@ fn type_selftest_run() -> int {
// 夹具全部人造行(本通道不经 parser/check_all):声明表照 parser 的写槽序落,类型节点照
// parse_type 的产物形态构造(基型节点 kind=0 + type_val=TY_*;EXPR_IDENT = 泛型形参/
// 命名类型;EXPR_ARRAY = `[T;N]`)。
- init_types(); // 干净起点(类型行号空间复位;原生 9 行在前)
- ty_budget_reset(200000);
+ init_types() // 干净起点(类型行号空间复位;原生 9 行在前)
+ ty_budget_reset(200000)
// 夹具 ①:struct UnfBoxU[T] { val: T }(泛型字段 = 形参 ⇒ 实参代入判据)+ 两个应用行
// 形参照 collect_decls(checker.cr:941-950)登记为符号——**生产路径 struct 泛型形参必在
// 符号表**(res_type_node 经 find_gsym 解析形参名),本通道照此登记 = 走真实解析路径。
- unf_gp := str_intern("UnfTGparamU");
- def_sym(unf_gp, SYM_TYPE, alloc_type(TYP_GENERIC_PARAM, unf_gp, 0), -1);
- unf_box_sa := add_struct("UnfBoxU");
- w64(g_structs, unf_box_sa * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT, 1);
- w64(g_structs, unf_box_sa * ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES, unf_gp);
- si_set_field_name(unf_box_sa, 0, str_intern("val"));
- si_set_field_type(unf_box_sa, 0, 0); // 裸码槽 = parser 对非基型的塌缩值(0 = TY_INT;本层不读)
+ unf_gp := str_intern("UnfTGparamU")
+ def_sym(unf_gp, SYM_TYPE, alloc_type(TYP_GENERIC_PARAM, unf_gp, 0), -1)
+ unf_box_sa := add_struct("UnfBoxU")
+ w64(g_structs, unf_box_sa * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT, 1)
+ w64(g_structs, unf_box_sa * ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES, unf_gp)
+ si_set_field_name(unf_box_sa, 0, str_intern("val"))
+ si_set_field_type(unf_box_sa, 0, 0) // 裸码槽 = parser 对非基型的塌缩值(0 = TY_INT;本层不读)
si_set_field_type_node(unf_box_sa, 0,
- alloc_node(EXPR_IDENT, -1, -1, -1, unf_gp, 0, -1, 0, 0));
- w64(g_structs, unf_box_sa * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, 1);
- unf_box_ti := alloc_named_type(str_intern("UnfBoxU"));
+ alloc_node(EXPR_IDENT, -1, -1, -1, unf_gp, 0, -1, 0, 0))
+ w64(g_structs, unf_box_sa * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, 1)
+ unf_box_ti := alloc_named_type(str_intern("UnfBoxU"))
// 应用行 `UnfBoxU[int]` / `UnfBoxU[string]`(g_gen_apply_data: [count, arg])
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- unf_gas1 := g_gen_apply_data_count;
- w64(g_gen_apply_data, unf_gas1 * 8, 1);
- w64(g_gen_apply_data, (unf_gas1 + 1) * 8, TI_INT);
- g_gen_apply_data_count = unf_gas1 + 2;
- unf_ga_int := alloc_type(TYP_GENERIC_APPLY, unf_box_ti, unf_gas1);
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- unf_gas2 := g_gen_apply_data_count;
- w64(g_gen_apply_data, unf_gas2 * 8, 1);
- w64(g_gen_apply_data, (unf_gas2 + 1) * 8, TI_STR);
- g_gen_apply_data_count = unf_gas2 + 2;
- unf_ga_str := alloc_type(TYP_GENERIC_APPLY, unf_box_ti, unf_gas2);
- unf_ta := sh_struct_term(unf_ga_int);
- unf_tb := sh_struct_term(unf_ga_str);
- total = total + 1; fails = fails + ts_check_b("unf.ga_arg_subst",
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ unf_gas1 := g_gen_apply_data_count
+ w64(g_gen_apply_data, unf_gas1 * 8, 1)
+ w64(g_gen_apply_data, (unf_gas1 + 1) * 8, TI_INT)
+ g_gen_apply_data_count = unf_gas1 + 2
+ unf_ga_int := alloc_type(TYP_GENERIC_APPLY, unf_box_ti, unf_gas1)
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ unf_gas2 := g_gen_apply_data_count
+ w64(g_gen_apply_data, unf_gas2 * 8, 1)
+ w64(g_gen_apply_data, (unf_gas2 + 1) * 8, TI_STR)
+ g_gen_apply_data_count = unf_gas2 + 2
+ unf_ga_str := alloc_type(TYP_GENERIC_APPLY, unf_box_ti, unf_gas2)
+ unf_ta := sh_struct_term(unf_ga_int)
+ unf_tb := sh_struct_term(unf_ga_str)
+ total = total + 1
+ fails = fails + ts_check_b("unf.ga_arg_subst",
(tt_a(unf_ta) == AK_PRODUCT && tt_c(unf_ta) == tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil()) &&
- tt_c(unf_tb) == tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil()) && unf_ta != unf_tb), true);
+ tt_c(unf_tb) == tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil()) && unf_ta != unf_tb), true)
// 未应用形态:泛型形参保持**名义**(res_type_node 取形参行 ⇒ AK_NAMED)——不得凭空代入 int
- unf_tbare := sh_struct_term(unf_box_ti);
- total = total + 1; fails = fails + ts_check_b("unf.ga_unapplied_nominal",
- (unf_tbare >= 0 && tt_a(unf_tbare) == AK_PRODUCT && tt_a(tt_a(tt_c(unf_tbare))) != AK_INT), true);
+ unf_tbare := sh_struct_term(unf_box_ti)
+ total = total + 1
+ fails = fails + ts_check_b("unf.ga_unapplied_nominal",
+ (unf_tbare >= 0 && tt_a(unf_tbare) == AK_PRODUCT && tt_a(tt_a(tt_c(unf_tbare))) != AK_INT), true)
// 夹具 ②:struct UnfP1U { a: int, b: string }(字段**声明序**;含基型两种)
- unf_p1_sa := add_struct("UnfP1U");
- si_set_field_name(unf_p1_sa, 0, str_intern("a"));
- si_set_field_type(unf_p1_sa, 0, TY_INT);
- si_set_field_type_node(unf_p1_sa, 0, alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0));
- si_set_field_name(unf_p1_sa, 1, str_intern("b"));
- si_set_field_type(unf_p1_sa, 1, TY_STRING);
- si_set_field_type_node(unf_p1_sa, 1, alloc_node(0, 0, 0, 0, 0, TY_STRING, 0, 0, 0));
- w64(g_structs, unf_p1_sa * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, 2);
- unf_p1_ti := alloc_named_type(str_intern("UnfP1U"));
- unf_tp1 := sh_struct_term(unf_p1_ti);
- total = total + 1; fails = fails + ts_check_b("unf.struct_field_order",
+ unf_p1_sa := add_struct("UnfP1U")
+ si_set_field_name(unf_p1_sa, 0, str_intern("a"))
+ si_set_field_type(unf_p1_sa, 0, TY_INT)
+ si_set_field_type_node(unf_p1_sa, 0, alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0))
+ si_set_field_name(unf_p1_sa, 1, str_intern("b"))
+ si_set_field_type(unf_p1_sa, 1, TY_STRING)
+ si_set_field_type_node(unf_p1_sa, 1, alloc_node(0, 0, 0, 0, 0, TY_STRING, 0, 0, 0))
+ w64(g_structs, unf_p1_sa * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, 2)
+ unf_p1_ti := alloc_named_type(str_intern("UnfP1U"))
+ unf_tp1 := sh_struct_term(unf_p1_ti)
+ total = total + 1
+ fails = fails + ts_check_b("unf.struct_field_order",
(tt_a(unf_tp1) == AK_PRODUCT &&
- tt_c(unf_tp1) == tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil()))), true);
+ tt_c(unf_tp1) == tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_cons(tt_atom(AK_STRING, TI_STR, -1), tt_nil()))), true)
// 夹具 ③:struct UnfP2U { x: [int;2] }——字段**裸码槽 = 0(= TY_INT)而类型节点 = 数组**:
// 「只读裸码槽」的实现会把该字段静默误判为 int(本用例即其守门;裸码塌缩 = parser 事实)
- unf_p2_sa := add_struct("UnfP2U");
- unf_arrn := alloc_node(EXPR_ARRAY, alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0), -1, -1, 2, 0, -1, 0, 0);
- si_set_field_name(unf_p2_sa, 0, str_intern("x"));
- si_set_field_type(unf_p2_sa, 0, 0);
- si_set_field_type_node(unf_p2_sa, 0, unf_arrn);
- w64(g_structs, unf_p2_sa * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, 1);
- unf_p2_ti := alloc_named_type(str_intern("UnfP2U"));
- unf_tp2 := sh_struct_term(unf_p2_ti);
- total = total + 1; fails = fails + ts_check_b("unf.struct_field_node_not_code",
- (tt_a(unf_tp2) == AK_PRODUCT && tt_a(tt_a(tt_c(unf_tp2))) == AK_SEQUENCE), true);
+ unf_p2_sa := add_struct("UnfP2U")
+ unf_arrn := alloc_node(EXPR_ARRAY, alloc_node(0, 0, 0, 0, 0, TY_INT, 0, 0, 0), -1, -1, 2, 0, -1, 0, 0)
+ si_set_field_name(unf_p2_sa, 0, str_intern("x"))
+ si_set_field_type(unf_p2_sa, 0, 0)
+ si_set_field_type_node(unf_p2_sa, 0, unf_arrn)
+ w64(g_structs, unf_p2_sa * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, 1)
+ unf_p2_ti := alloc_named_type(str_intern("UnfP2U"))
+ unf_tp2 := sh_struct_term(unf_p2_ti)
+ total = total + 1
+ fails = fails + ts_check_b("unf.struct_field_node_not_code",
+ (tt_a(unf_tp2) == AK_PRODUCT && tt_a(tt_a(tt_c(unf_tp2))) == AK_SEQUENCE), true)
// 夹具 ④:两个**同形不同名** struct(UnfS1U{a:int} / UnfS2U{a:int})——本 Task 的风险边界,
// 三断 = 双钉:① 展开项(满足面)**结构相等**(同形 ⇒ 同项 = 满足判定的设计意图);
// ② 桥接项(等价面)仍 -1(AK_NAMED 原子不展开,**不得**当 0/1);③ type_equal 仍 false
// 且回落 legacy 恰 +1(不静默)。
- unf_s1_ti := ts_unf_mk_int_struct("UnfS1U");
- unf_s2_ti := ts_unf_mk_int_struct("UnfS2U");
- unf_e1 := sh_struct_term(unf_s1_ti);
- unf_e2 := sh_struct_term(unf_s2_ti);
- total = total + 1; fails = fails + ts_check_b("unf.nominal_structural_equal",
- (unf_e1 >= 0 && unf_e2 >= 0 && ty_equiv(unf_e1, unf_e2) == 1), true);
+ unf_s1_ti := ts_unf_mk_int_struct("UnfS1U")
+ unf_s2_ti := ts_unf_mk_int_struct("UnfS2U")
+ unf_e1 := sh_struct_term(unf_s1_ti)
+ unf_e2 := sh_struct_term(unf_s2_ti)
+ total = total + 1
+ fails = fails + ts_check_b("unf.nominal_structural_equal",
+ (unf_e1 >= 0 && unf_e2 >= 0 && ty_equiv(unf_e1, unf_e2) == 1), true)
// **R2 P5 Task 3 重钉**(翻转向量表:`unf.nominal_equiv_atomic_unknown` →
// `unf.nominal_equiv_atomic_decided`):命名面接引擎身份链后,**异名同形**两个命名型的
// 桥接项判 **0 = 确定不同**(旧断 -1 = 未覆盖面;legacy 同结论 = false ⇒ 行为同值,
// 差异 = 引擎自决而非回落)。展开项(满足面)结构相等断(上一例)逐字未动——「等价面
// 不展开」的边界仍由该例把住(同形不同名 ⇒ 桥接项 0,展开项 1)。
- total = total + 1; fails = fails + ts_check("unf.nominal_equiv_atomic_decided",
- ty_equiv(sh_term_of_ti(unf_s1_ti), sh_term_of_ti(unf_s2_ti)), 0);
+ total = total + 1
+ fails = fails + ts_check("unf.nominal_equiv_atomic_decided",
+ ty_equiv(sh_term_of_ti(unf_s1_ti), sh_term_of_ti(unf_s2_ti)), 0)
// T3 重钉(零回落)→ **T4 终态**:回落计数已随 legacy 删除 ⇒ 断言 = 「判 false + 零
// 未知诊断(ICE04 缺席 = 引擎真判 0,而非未知被静默当 false)」。
- unf_d0 := g_diag_count;
- unf_eqf : ., mut = 0;
- if !type_equal(unf_s1_ti, unf_s2_ti) {
- if g_diag_count == unf_d0 { unf_eqf = 1; }
- }
- total = total + 1; fails = fails + ts_check("unf.nominal_type_equal_false", unf_eqf, 1);
+ unf_d0 := g_diag_count
+ unf_eqf : ., mut = 0
+ if !type_equal(unf_s1_ti, unf_s2_ti):
+ if g_diag_count == unf_d0:
+ unf_eqf = 1
+ total = total + 1
+ fails = fails + ts_check("unf.nominal_type_equal_false", unf_eqf, 1)
// 夹具 ⑤:enum UnfColorU { UnfRedU, UnfGreenU, UnfBlueU }(tag-only,3 变体)
- unf_col_ei := add_enum("UnfColorU");
- ei_set_variant_name(unf_col_ei, 0, str_intern("UnfRedU"));
- ei_set_variant_name(unf_col_ei, 1, str_intern("UnfGreenU"));
- ei_set_variant_name(unf_col_ei, 2, str_intern("UnfBlueU"));
- w64(g_enums, unf_col_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 3);
- unf_col_ti := alloc_named_type(str_intern("UnfColorU"));
- unf_dom := sh_enum_domain_term(unf_col_ti);
- total = total + 1; fails = fails + ts_check_b("unf.enum_domain_count",
- (unf_dom >= 0 && ts_unf_union_leaves(unf_dom) == 3), true);
- unf_vr := sh_variant_term(unf_col_ti, str_intern("UnfRedU"));
- unf_vg := sh_variant_term(unf_col_ti, str_intern("UnfGreenU"));
- unf_vb := sh_variant_term(unf_col_ti, str_intern("UnfBlueU"));
- total = total + 1; fails = fails + ts_check_b("unf.enum_variant_in_domain",
+ unf_col_ei := add_enum("UnfColorU")
+ ei_set_variant_name(unf_col_ei, 0, str_intern("UnfRedU"))
+ ei_set_variant_name(unf_col_ei, 1, str_intern("UnfGreenU"))
+ ei_set_variant_name(unf_col_ei, 2, str_intern("UnfBlueU"))
+ w64(g_enums, unf_col_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 3)
+ unf_col_ti := alloc_named_type(str_intern("UnfColorU"))
+ unf_dom := sh_enum_domain_term(unf_col_ti)
+ total = total + 1
+ fails = fails + ts_check_b("unf.enum_domain_count",
+ (unf_dom >= 0 && ts_unf_union_leaves(unf_dom) == 3), true)
+ unf_vr := sh_variant_term(unf_col_ti, str_intern("UnfRedU"))
+ unf_vg := sh_variant_term(unf_col_ti, str_intern("UnfGreenU"))
+ unf_vb := sh_variant_term(unf_col_ti, str_intern("UnfBlueU"))
+ total = total + 1
+ fails = fails + ts_check_b("unf.enum_variant_in_domain",
(ty_sub(unf_vr, unf_dom) == 1 && ty_sub(unf_vg, unf_dom) == 1 && ty_sub(unf_vb, unf_dom) == 1 &&
- sh_variant_term(unf_col_ti, str_intern("UnfNoSuchVariantU")) == -1), true);
+ sh_variant_term(unf_col_ti, str_intern("UnfNoSuchVariantU")) == -1), true)
// 变体身份**含枚举名**(引擎只比 a/c 两槽 ⇒ 身份必须入参数链):异枚举**同名变体**不得被判等价
- unf_dup_ei := add_enum("UnfDupU");
- ei_set_variant_name(unf_dup_ei, 0, str_intern("UnfRedU"));
- w64(g_enums, unf_dup_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 1);
- unf_dup_ti := alloc_named_type(str_intern("UnfDupU"));
- unf_vdup := sh_variant_term(unf_dup_ti, str_intern("UnfRedU"));
- total = total + 1; fails = fails + ts_check_b("unf.enum_variant_identity_scoped",
- (unf_vdup >= 0 && ty_sub(unf_vdup, unf_vr) != 1 && ty_sub(unf_vr, unf_vdup) != 1), true);
+ unf_dup_ei := add_enum("UnfDupU")
+ ei_set_variant_name(unf_dup_ei, 0, str_intern("UnfRedU"))
+ w64(g_enums, unf_dup_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 1)
+ unf_dup_ti := alloc_named_type(str_intern("UnfDupU"))
+ unf_vdup := sh_variant_term(unf_dup_ti, str_intern("UnfRedU"))
+ total = total + 1
+ fails = fails + ts_check_b("unf.enum_variant_identity_scoped",
+ (unf_vdup >= 0 && ty_sub(unf_vdup, unf_vr) != 1 && ty_sub(unf_vr, unf_vdup) != 1), true)
// 空枚举:域 = ⊥(无值可取——**登记语义**:空域在补集语义下恒穷尽,Task 3 须显式裁决)
- unf_emp_ei := add_enum("UnfEmptyU");
- w64(g_enums, unf_emp_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 0);
- unf_emp_ti := alloc_named_type(str_intern("UnfEmptyU"));
- total = total + 1; fails = fails + ts_check("unf.enum_empty_domain_bot", tt_tag(sh_enum_domain_term(unf_emp_ti)), TT_BOT);
+ unf_emp_ei := add_enum("UnfEmptyU")
+ w64(g_enums, unf_emp_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 0)
+ unf_emp_ti := alloc_named_type(str_intern("UnfEmptyU"))
+ total = total + 1
+ fails = fails + ts_check("unf.enum_empty_domain_bot", tt_tag(sh_enum_domain_term(unf_emp_ti)), TT_BOT)
// 夹具 ⑥:enum UnfOptU[T] { UnfNoneU, UnfSomeU(T) }(tag + payload 混合)——域/模式项在
// 引擎穷尽性上的**端到端**前哨(Task 3 判据的种子)。payload 槽照 parser 落裸码(非基型
// 塌缩为 0 ⇒ 本层**不读**它:payload 不入变体项,见 ty_shadow.cr 展开段未覆盖面注记)。
- unf_opt_ei := add_enum("UnfOptU");
- w64(g_enums, unf_opt_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 1);
- w64(g_enums, unf_opt_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES, str_intern("UnfTOptU"));
- ei_set_variant_name(unf_opt_ei, 0, str_intern("UnfNoneU"));
- ei_set_variant_name(unf_opt_ei, 1, str_intern("UnfSomeU"));
- ei_set_variant_type_count(unf_opt_ei, 1, 1);
- ei_set_variant_type(unf_opt_ei, 1, 0, TY_INT); // 裸码槽(parser 事实;本层不读)
- w64(g_enums, unf_opt_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 2);
- unf_opt_ti := alloc_named_type(str_intern("UnfOptU"));
- unf_odom := sh_enum_domain_term(unf_opt_ti);
- unf_onone := sh_variant_term(unf_opt_ti, str_intern("UnfNoneU"));
- unf_osome := sh_variant_term(unf_opt_ti, str_intern("UnfSomeU"));
- total = total + 1; fails = fails + ts_check("unf.exhaust_cover_all",
- ty_exhaustive(unf_odom, tt_cons(unf_onone, tt_cons(unf_osome, tt_nil()))), 1);
- total = total + 1; fails = fails + ts_check("unf.exhaust_missing_one",
- ty_exhaustive(unf_odom, tt_cons(unf_onone, tt_nil())), 0);
+ unf_opt_ei := add_enum("UnfOptU")
+ w64(g_enums, unf_opt_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 1)
+ w64(g_enums, unf_opt_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES, str_intern("UnfTOptU"))
+ ei_set_variant_name(unf_opt_ei, 0, str_intern("UnfNoneU"))
+ ei_set_variant_name(unf_opt_ei, 1, str_intern("UnfSomeU"))
+ ei_set_variant_type_count(unf_opt_ei, 1, 1)
+ ei_set_variant_type(unf_opt_ei, 1, 0, TY_INT) // 裸码槽(parser 事实;本层不读)
+ w64(g_enums, unf_opt_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 2)
+ unf_opt_ti := alloc_named_type(str_intern("UnfOptU"))
+ unf_odom := sh_enum_domain_term(unf_opt_ti)
+ unf_onone := sh_variant_term(unf_opt_ti, str_intern("UnfNoneU"))
+ unf_osome := sh_variant_term(unf_opt_ti, str_intern("UnfSomeU"))
+ total = total + 1
+ fails = fails + ts_check("unf.exhaust_cover_all",
+ ty_exhaustive(unf_odom, tt_cons(unf_onone, tt_cons(unf_osome, tt_nil()))), 1)
+ total = total + 1
+ fails = fails + ts_check("unf.exhaust_missing_one",
+ ty_exhaustive(unf_odom, tt_cons(unf_onone, tt_nil())), 0)
// 缺变体 witness:不可空且 ⊆ 缺失变体。**登记**:原始 witness = 各析取支之并(**含空析取支**
// ——norm 不做空支净化)⇒ Task 3 若当「具体反例值」用,须先取有住户的支(或引擎加净化)。
- unf_w2 := ty_exhaust_witness(unf_odom, tt_cons(unf_onone, tt_nil()));
- total = total + 1; fails = fails + ts_check_b("unf.exhaust_witness_subset",
- (unf_w2 >= 0 && ty_inhabited(unf_w2) == 1 && ty_sub(unf_w2, unf_osome) == 1), true);
+ unf_w2 := ty_exhaust_witness(unf_odom, tt_cons(unf_onone, tt_nil()))
+ total = total + 1
+ fails = fails + ts_check_b("unf.exhaust_witness_subset",
+ (unf_w2 >= 0 && ty_inhabited(unf_w2) == 1 && ty_sub(unf_w2, unf_osome) == 1), true)
// 展开缓存:新 ti 恰入表 1 条;二次调用恰命中 1 次且返回**同项**;**失败不缓存**(-1 不入表)
- unf_fresh := ts_unf_mk_int_struct("UnfCacheU");
- unf_ce0 := sh_unf_entries();
- unf_ch0 := sh_unf_hits();
- unf_ct1 := sh_struct_term(unf_fresh);
- unf_ce1 := sh_unf_entries();
- unf_ct2 := sh_struct_term(unf_fresh);
- unf_fail_e0 := sh_unf_entries();
- sh_struct_term(g_type_count + 7);
- total = total + 1; fails = fails + ts_check_b("unf.cache_hit_and_no_neg_cache",
+ unf_fresh := ts_unf_mk_int_struct("UnfCacheU")
+ unf_ce0 := sh_unf_entries()
+ unf_ch0 := sh_unf_hits()
+ unf_ct1 := sh_struct_term(unf_fresh)
+ unf_ce1 := sh_unf_entries()
+ unf_ct2 := sh_struct_term(unf_fresh)
+ unf_fail_e0 := sh_unf_entries()
+ sh_struct_term(g_type_count + 7)
+ total = total + 1
+ fails = fails + ts_check_b("unf.cache_hit_and_no_neg_cache",
((unf_ce1 - unf_ce0) == 1 && (sh_unf_hits() - unf_ch0) == 1 && unf_ct2 == unf_ct1 &&
- (sh_unf_entries() - unf_fail_e0) == 0), true);
+ (sh_unf_entries() - unf_fail_e0) == 0), true)
// 缺口上抛(**不得静默判否**):行号越界 / 未声明的名字行 / 裸泛型形参行 / 非枚举变体名 → -1
- unf_plain_ti := alloc_named_type(str_intern("UnfNoDeclU"));
- unf_loose_gp := alloc_type(TYP_GENERIC_PARAM, str_intern("UnfLooseTU"), 0);
- total = total + 1; fails = fails + ts_check_b("unf.neg_paths",
+ unf_plain_ti := alloc_named_type(str_intern("UnfNoDeclU"))
+ unf_loose_gp := alloc_type(TYP_GENERIC_PARAM, str_intern("UnfLooseTU"), 0)
+ total = total + 1
+ fails = fails + ts_check_b("unf.neg_paths",
(sh_struct_term(g_type_count + 7) == -1 && sh_enum_domain_term(g_type_count + 7) == -1 &&
- sh_struct_term(-1) == -1 && sh_variant_term(-1, 0) == -1 && sh_variant_term(unf_col_ti, -1) == -1 &&
- sh_struct_term(unf_plain_ti) == -1 && sh_enum_domain_term(unf_plain_ti) == -1 &&
- sh_struct_term(unf_loose_gp) == -1), true);
+ sh_struct_term(-1) == -1 && sh_variant_term(-1, 0) == -1 && sh_variant_term(unf_col_ti, -1) == -1 &&
+ sh_struct_term(unf_plain_ti) == -1 && sh_enum_domain_term(unf_plain_ti) == -1 &&
+ sh_struct_term(unf_loose_gp) == -1), true)
// 接口面负键守门(P3b Task 0 后:`iface_satisfies` 已交付,本用例 = **域外输入守卫**——
// 形状项构造仍为 Task 6 占位(-1),负键/未知名键一律三态 -1,**不得**被消费方当 0/1 用)
- total = total + 1; fails = fails + ts_check_b("unf.iface_stub_three_state",
- (sh_iface_shape_term(-1) == -1 && iface_satisfies(-1, 0) == -1 && iface_satisfies(TI_INT, 9999) == -1), true);
+ total = total + 1
+ fails = fails + ts_check_b("unf.iface_stub_three_state",
+ (sh_iface_shape_term(-1) == -1 && iface_satisfies(-1, 0) == -1 && iface_satisfies(TI_INT, 9999) == -1), true)
// ═══ R2 P3 Task 1:定长退役收口(array/slice 方向 + 变型表 + N 读取面守门)═══
// 判据面 = ① 方向:`[T;N] <: [T]`(固定 → 视图 = 拓宽,放行)/ `[T] ⊄ [T;N]`(视图 → 固定,
@@ -3193,99 +3621,116 @@ fn type_selftest_run() -> int {
// ⇒ 方向**不在**引擎 ty_sub 面,而在 checker 的 array_len_constraint_ok(参序 =(源,目标))
// ——与 P2a「N 迁出身份、拒绝由常量档承担」同一构造;故本组的方向断言直接打该函数与站点
// 三态包装 type_compat_strict(引擎侧只保留「N 不入身份/子类型」的守门)。
- ty_budget_reset(200000);
- t1_arr3 := alloc_type(TYP_ARRAY, TI_INT, 3);
- t1_arr4 := alloc_type(TYP_ARRAY, TI_INT, 4);
- t1_sl := alloc_type(TYP_SLICE, TI_INT, 0);
- t1_sl2 := alloc_type(TYP_SLICE, TI_INT, 0); // 另一行同形切片:方向面不得靠 ti 同一性
+ ty_budget_reset(200000)
+ t1_arr3 := alloc_type(TYP_ARRAY, TI_INT, 3)
+ t1_arr4 := alloc_type(TYP_ARRAY, TI_INT, 4)
+ t1_sl := alloc_type(TYP_SLICE, TI_INT, 0)
+ t1_sl2 := alloc_type(TYP_SLICE, TI_INT, 0) // 另一行同形切片:方向面不得靠 ti 同一性
// ① 方向(顶层):固定→视图 放行;视图→固定 拒(0 = 决定,非 -1);视图→视图 同元素放行
- total = total + 1; fails = fails + ts_check("t1.dir_arr_to_slice_ok",
- array_len_constraint_ok(t1_arr3, t1_sl), 1);
- total = total + 1; fails = fails + ts_check("t1.dir_slice_to_arr_reject",
- array_len_constraint_ok(t1_sl, t1_arr3), 0);
- total = total + 1; fails = fails + ts_check("t1.dir_slice_slice_ok",
- array_len_constraint_ok(t1_sl, t1_sl2), 1);
+ total = total + 1
+ fails = fails + ts_check("t1.dir_arr_to_slice_ok",
+ array_len_constraint_ok(t1_arr3, t1_sl), 1)
+ total = total + 1
+ fails = fails + ts_check("t1.dir_slice_to_arr_reject",
+ array_len_constraint_ok(t1_sl, t1_arr3), 0)
+ total = total + 1
+ fails = fails + ts_check("t1.dir_slice_slice_ok",
+ array_len_constraint_ok(t1_sl, t1_sl2), 1)
// ② N 不入身份(同固定性异 N):引擎等价 1 ∧ 常量档拒 0(双钉 = 「N 迁移」不变量)
- total = total + 1; fails = fails + ts_check_b("t1.dir_fixed_two_lengths_identity",
+ total = total + 1
+ fails = fails + ts_check_b("t1.dir_fixed_two_lengths_identity",
(ty_equiv(sh_term_of_ti(t1_arr3), sh_term_of_ti(t1_arr4)) == 1 &&
- array_len_constraint_ok(t1_arr4, t1_arr3) == 0), true);
+ array_len_constraint_ok(t1_arr4, t1_arr3) == 0), true)
// ③ 嵌套位逐位同律(负控:反向拓宽必须仍放行——防「一律拒绝」的退化实现)
- t1_pt_sl := alloc_type(TYP_PTR, t1_sl, 0);
- t1_pt_arr := alloc_type(TYP_PTR, t1_arr3, 0);
- total = total + 1; fails = fails + ts_check_b("t1.dir_nested_ptr",
- (array_len_constraint_ok(t1_pt_sl, t1_pt_arr) == 0 && array_len_constraint_ok(t1_pt_arr, t1_pt_sl) == 1), true);
- t1_out_sl := alloc_type(TYP_ARRAY, t1_sl, 2); // [[int];2]
- t1_out_arr := alloc_type(TYP_ARRAY, t1_arr3, 2); // [[int;3];2]
- total = total + 1; fails = fails + ts_check_b("t1.dir_nested_elem",
- (array_len_constraint_ok(t1_out_sl, t1_out_arr) == 0 && array_len_constraint_ok(t1_out_arr, t1_out_sl) == 1), true);
- grow_gen_apply_data(g_gen_apply_data_count + 4);
- t1_tp_s1 := g_gen_apply_data_count;
- w64(g_gen_apply_data, t1_tp_s1 * 8, TI_INT);
- w64(g_gen_apply_data, (t1_tp_s1 + 1) * 8, t1_sl);
- t1_tp_s2 := t1_tp_s1 + 2;
- w64(g_gen_apply_data, t1_tp_s2 * 8, TI_INT);
- w64(g_gen_apply_data, (t1_tp_s2 + 1) * 8, t1_arr3);
- g_gen_apply_data_count = t1_tp_s2 + 2;
- t1_tup_sl := alloc_type(TYP_TUPLE, 2, t1_tp_s1); // (int, [int])
- t1_tup_arr := alloc_type(TYP_TUPLE, 2, t1_tp_s2); // (int, [int;3])
- total = total + 1; fails = fails + ts_check_b("t1.dir_nested_tuple",
- (array_len_constraint_ok(t1_tup_sl, t1_tup_arr) == 0 && array_len_constraint_ok(t1_tup_arr, t1_tup_sl) == 1), true);
- grow_gen_apply_data(g_gen_apply_data_count + 4);
- t1_ga_s1 := g_gen_apply_data_count;
- w64(g_gen_apply_data, t1_ga_s1 * 8, 1);
- w64(g_gen_apply_data, (t1_ga_s1 + 1) * 8, t1_sl);
- t1_ga_s2 := t1_ga_s1 + 2;
- w64(g_gen_apply_data, t1_ga_s2 * 8, 1);
- w64(g_gen_apply_data, (t1_ga_s2 + 1) * 8, t1_arr3);
- g_gen_apply_data_count = t1_ga_s2 + 2;
- t1_base := alloc_type(TYP_NAMED, 1203, 0); // 人造基型行(裸分配,防假键污染)
- t1_ga_sl := alloc_type(TYP_GENERIC_APPLY, t1_base, t1_ga_s1);
- t1_ga_arr := alloc_type(TYP_GENERIC_APPLY, t1_base, t1_ga_s2);
- total = total + 1; fails = fails + ts_check_b("t1.dir_nested_genapply",
- (array_len_constraint_ok(t1_ga_sl, t1_ga_arr) == 0 && array_len_constraint_ok(t1_ga_arr, t1_ga_sl) == 1), true);
+ t1_pt_sl := alloc_type(TYP_PTR, t1_sl, 0)
+ t1_pt_arr := alloc_type(TYP_PTR, t1_arr3, 0)
+ total = total + 1
+ fails = fails + ts_check_b("t1.dir_nested_ptr",
+ (array_len_constraint_ok(t1_pt_sl, t1_pt_arr) == 0 && array_len_constraint_ok(t1_pt_arr, t1_pt_sl) == 1), true)
+ t1_out_sl := alloc_type(TYP_ARRAY, t1_sl, 2) // [[int];2]
+ t1_out_arr := alloc_type(TYP_ARRAY, t1_arr3, 2) // [[int;3];2]
+ total = total + 1
+ fails = fails + ts_check_b("t1.dir_nested_elem",
+ (array_len_constraint_ok(t1_out_sl, t1_out_arr) == 0 && array_len_constraint_ok(t1_out_arr, t1_out_sl) == 1), true)
+ grow_gen_apply_data(g_gen_apply_data_count + 4)
+ t1_tp_s1 := g_gen_apply_data_count
+ w64(g_gen_apply_data, t1_tp_s1 * 8, TI_INT)
+ w64(g_gen_apply_data, (t1_tp_s1 + 1) * 8, t1_sl)
+ t1_tp_s2 := t1_tp_s1 + 2
+ w64(g_gen_apply_data, t1_tp_s2 * 8, TI_INT)
+ w64(g_gen_apply_data, (t1_tp_s2 + 1) * 8, t1_arr3)
+ g_gen_apply_data_count = t1_tp_s2 + 2
+ t1_tup_sl := alloc_type(TYP_TUPLE, 2, t1_tp_s1) // (int, [int])
+ t1_tup_arr := alloc_type(TYP_TUPLE, 2, t1_tp_s2) // (int, [int;3])
+ total = total + 1
+ fails = fails + ts_check_b("t1.dir_nested_tuple",
+ (array_len_constraint_ok(t1_tup_sl, t1_tup_arr) == 0 && array_len_constraint_ok(t1_tup_arr, t1_tup_sl) == 1), true)
+ grow_gen_apply_data(g_gen_apply_data_count + 4)
+ t1_ga_s1 := g_gen_apply_data_count
+ w64(g_gen_apply_data, t1_ga_s1 * 8, 1)
+ w64(g_gen_apply_data, (t1_ga_s1 + 1) * 8, t1_sl)
+ t1_ga_s2 := t1_ga_s1 + 2
+ w64(g_gen_apply_data, t1_ga_s2 * 8, 1)
+ w64(g_gen_apply_data, (t1_ga_s2 + 1) * 8, t1_arr3)
+ g_gen_apply_data_count = t1_ga_s2 + 2
+ t1_base := alloc_type(TYP_NAMED, 1203, 0) // 人造基型行(裸分配,防假键污染)
+ t1_ga_sl := alloc_type(TYP_GENERIC_APPLY, t1_base, t1_ga_s1)
+ t1_ga_arr := alloc_type(TYP_GENERIC_APPLY, t1_base, t1_ga_s2)
+ total = total + 1
+ fails = fails + ts_check_b("t1.dir_nested_genapply",
+ (array_len_constraint_ok(t1_ga_sl, t1_ga_arr) == 0 && array_len_constraint_ok(t1_ga_arr, t1_ga_sl) == 1), true)
// ④ 站点三态(专属措辞 = -1 路):拓宽 1;视图→固定 -1(身份放行、方向拒);对称核 = 现状
- total = total + 1; fails = fails + ts_check("t1.strict_widen_ok",
- type_compat_strict(t1_arr3, t1_sl), 1);
- total = total + 1; fails = fails + ts_check("t1.strict_view_to_fixed",
- type_compat_strict(t1_sl, t1_arr3), -1);
- total = total + 1; fails = fails + ts_check_b("t1.strict_sym_no_direction",
- (type_compat_sym(t1_sl, t1_arr3) == 1 && type_compat_sym(t1_arr3, t1_sl) == 1), true);
+ total = total + 1
+ fails = fails + ts_check("t1.strict_widen_ok",
+ type_compat_strict(t1_arr3, t1_sl), 1)
+ total = total + 1
+ fails = fails + ts_check("t1.strict_view_to_fixed",
+ type_compat_strict(t1_sl, t1_arr3), -1)
+ total = total + 1
+ fails = fails + ts_check_b("t1.strict_sym_no_direction",
+ (type_compat_sym(t1_sl, t1_arr3) == 1 && type_compat_sym(t1_arr3, t1_sl) == 1), true)
// ⑤ 变型:只读协变通过 / 可写不变拒绝(AK_REF 槽 1 条件变型);表外构造子默认不变
- t1_u := tt_union(tt_atom(AK_INT, TI_INT, -1), tt_atom(AK_STRING, TI_STR, -1)); // int ∪ string
- t1_rv_ro := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())));
- t1_rv_ro_w := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(t1_u, tt_nil())));
- t1_rv_mut := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())));
- t1_rv_mut_w := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(t1_u, tt_nil())));
- total = total + 1; fails = fails + ts_check_b("t1.var_readonly_covariant",
- (ty_sub(t1_rv_ro, t1_rv_ro_w) == 1 && ty_sub(t1_rv_ro_w, t1_rv_ro) == 0), true);
+ t1_u := tt_union(tt_atom(AK_INT, TI_INT, -1), tt_atom(AK_STRING, TI_STR, -1)) // int ∪ string
+ t1_rv_ro := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())))
+ t1_rv_ro_w := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(t1_u, tt_nil())))
+ t1_rv_mut := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())))
+ t1_rv_mut_w := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(1), tt_cons(t1_u, tt_nil())))
+ total = total + 1
+ fails = fails + ts_check_b("t1.var_readonly_covariant",
+ (ty_sub(t1_rv_ro, t1_rv_ro_w) == 1 && ty_sub(t1_rv_ro_w, t1_rv_ro) == 0), true)
// 不变槽非同形的判定**语义** = 「不是子类型」;引擎回 **-1**(未覆盖面登记——不变槽的
// 「确定不等价 ⇒ 0」加强需先有「链元素皆类型项」不变量,见 type_engine.cr 注记)⇒ 断
// 「两向皆不得判 1」= 不变性的可执行内容;生产面(checker type_equal)在此回落 legacy
// 得 false = 实拒(pE 探针实测 rc=1)。
- total = total + 1; fails = fails + ts_check_b("t1.var_mut_invariant_reject",
- (ty_sub(t1_rv_mut, t1_rv_mut_w) != 1 && ty_sub(t1_rv_mut_w, t1_rv_mut) != 1), true);
- total = total + 1; fails = fails + ts_check_b("t1.var_seq_elem_invariant",
+ total = total + 1
+ fails = fails + ts_check_b("t1.var_mut_invariant_reject",
+ (ty_sub(t1_rv_mut, t1_rv_mut_w) != 1 && ty_sub(t1_rv_mut_w, t1_rv_mut) != 1), true)
+ total = total + 1
+ fails = fails + ts_check_b("t1.var_seq_elem_invariant",
(ty_sub(tt_atom(AK_SEQUENCE, -1, tt_cons(tt_atom(AK_INT, TI_INT, -1), tt_nil())),
- tt_atom(AK_SEQUENCE, -1, tt_cons(t1_u, tt_nil()))) != 1), true);
+ tt_atom(AK_SEQUENCE, -1, tt_cons(t1_u, tt_nil()))) != 1), true)
// ⑥ mut 标记入链 = 判定维度(走真实桥接):`&T` ≢ `&mut T` 双向;同 mut 同元素仍等价
- t1_ref_ro := alloc_type(TYP_REF, TI_INT, 0);
- t1_ref_ro2 := alloc_type(TYP_REF, TI_INT, 0);
- t1_ref_mut := alloc_type(TYP_REF, TI_INT, 1);
- total = total + 1; fails = fails + ts_check_b("t1.var_mut_marker_dimension",
+ t1_ref_ro := alloc_type(TYP_REF, TI_INT, 0)
+ t1_ref_ro2 := alloc_type(TYP_REF, TI_INT, 0)
+ t1_ref_mut := alloc_type(TYP_REF, TI_INT, 1)
+ total = total + 1
+ fails = fails + ts_check_b("t1.var_mut_marker_dimension",
(ty_equiv(sh_term_of_ti(t1_ref_ro), sh_term_of_ti(t1_ref_mut)) == 0 &&
- ty_equiv(sh_term_of_ti(t1_ref_mut), sh_term_of_ti(t1_ref_ro)) == 0 &&
- ty_equiv(sh_term_of_ti(t1_ref_ro), sh_term_of_ti(t1_ref_ro2)) == 1 &&
- tt_b(tt_a(tt_c(sh_term_of_ti(t1_ref_mut)))) == 1), true);
+ ty_equiv(sh_term_of_ti(t1_ref_mut), sh_term_of_ti(t1_ref_ro)) == 0 &&
+ ty_equiv(sh_term_of_ti(t1_ref_ro), sh_term_of_ti(t1_ref_ro2)) == 1 &&
+ tt_b(tt_a(tt_c(sh_term_of_ti(t1_ref_mut)))) == 1), true)
// ⑦ N 读取面守门:身份路径(ty_equiv)+ **子类型路径(ty_sub)**零 N;唯一拒绝来源 = 常量档
- total = total + 1; fails = fails + ts_check_b("t1.n_face_gate",
+ total = total + 1
+ fails = fails + ts_check_b("t1.n_face_gate",
(type_equal(t1_arr3, t1_arr4) &&
- ty_sub(sh_term_of_ti(t1_arr3), sh_term_of_ti(t1_arr4)) == 1 &&
- array_len_constraint_ok(t1_arr4, t1_arr3) == 0), true);
+ ty_sub(sh_term_of_ti(t1_arr3), sh_term_of_ti(t1_arr4)) == 1 &&
+ array_len_constraint_ok(t1_arr4, t1_arr3) == 0), true)
// ⑧ 动态档登记:切片运行期长度不可证 ⇒ 视图→固定是**决定**(0),不得回 -1 冒充未知;
// 异长固定档同理(常量档拒绝也在决定面)。
- total = total + 1; fails = fails + ts_check_b("t1.dyn_tier_decided",
+ total = total + 1
+ fails = fails + ts_check_b("t1.dyn_tier_decided",
(array_len_constraint_ok(t1_sl, t1_arr3) == 0 && array_len_constraint_ok(t1_sl2, t1_arr4) == 0 &&
- array_len_constraint_ok(t1_arr3, t1_arr4) == 0), true);
+ array_len_constraint_ok(t1_arr3, t1_arr4) == 0), true)
// ⑨ **嵌套位**的身份不变量 + 站点三态(本批实测发现的回归面:序列项的固定性位 b 会经
// 嵌套元素位的**节点同一性**泄进身份 ⇒ 必须由引擎的「忽略 b 的序列项相等」挡住——
// type_engine.cr 的 tt_type_elem_same/tt_seq_same)。断三件事:
@@ -3293,17 +3738,22 @@ fn type_selftest_run() -> int {
// (引擎自决 = 身份路径零 N 的强式;旧实现靠 legacy 回落兜底,措辞随之退化);
// ② 嵌套固定性同样**不入身份**(`ty_equiv` 两向 1);
// ③ 站点层:嵌套 视图→固定 = -1(专属措辞路)、嵌套 固定→视图 = 1(拓宽保持)。
- t1_out_arr4 := alloc_type(TYP_ARRAY, t1_arr4, 2); // [[int;4];2]
+ t1_out_arr4 := alloc_type(TYP_ARRAY, t1_arr4, 2) // [[int;4];2]
// T4 终态:断言从「零回落计数」改为「零未知诊断」(ICE04 缺席 = 引擎真判身份路径)
- t1_d0 := g_diag_count;
- t1_nest_ok : ., mut = 0;
- if type_equal(t1_out_arr, t1_out_arr4) { if g_diag_count == t1_d0 { t1_nest_ok = 1; } }
- total = total + 1; fails = fails + ts_check_b("t1.n_face_gate_nested",
- (t1_nest_ok == 1 && array_len_constraint_ok(t1_out_arr4, t1_out_arr) == 0), true);
- total = total + 1; fails = fails + ts_check("t1.fixedness_not_identity_nested",
- ty_equiv(sh_term_of_ti(t1_out_sl), sh_term_of_ti(t1_out_arr)), 1);
- total = total + 1; fails = fails + ts_check_b("t1.dir_nested_strict",
- (type_compat_strict(t1_out_sl, t1_out_arr) == -1 && type_compat_strict(t1_out_arr, t1_out_sl) == 1), true);
+ t1_d0 := g_diag_count
+ t1_nest_ok : ., mut = 0
+ if type_equal(t1_out_arr, t1_out_arr4):
+ if g_diag_count == t1_d0:
+ t1_nest_ok = 1
+ total = total + 1
+ fails = fails + ts_check_b("t1.n_face_gate_nested",
+ (t1_nest_ok == 1 && array_len_constraint_ok(t1_out_arr4, t1_out_arr) == 0), true)
+ total = total + 1
+ fails = fails + ts_check("t1.fixedness_not_identity_nested",
+ ty_equiv(sh_term_of_ti(t1_out_sl), sh_term_of_ti(t1_out_arr)), 1)
+ total = total + 1
+ fails = fails + ts_check_b("t1.dir_nested_strict",
+ (type_compat_strict(t1_out_sl, t1_out_arr) == -1 && type_compat_strict(t1_out_arr, t1_out_sl) == 1), true)
// ═══ R2 P3 Task 3:match 穷尽性真判定(补集空性 + 具体变体反例)═══
// 判据面 = ① 引擎三态:全覆盖 / 缺一 / 无臂 / 通配吸收 / 单变体;② **反例的具体值** =
@@ -3312,37 +3762,40 @@ fn type_selftest_run() -> int {
// (-1 = 不判,不得当 0/1);④ 空枚举域 = 空洞穷尽(登记语义,与计划原文「= 0」的偏差
// 见任务报告);⑤ payload 变体混合 / 限定名解析 / 重复臂 / 泛型应用行。
// 夹具照 Task 0 先例人工落行(写槽序 = parser 的;payload 裸码槽照 parser 事实落)。
- init_types();
- ty_budget_reset(200000);
- t3_col_ei := add_enum("T3Color");
- ei_set_variant_name(t3_col_ei, 0, str_intern("T3Red"));
- ei_set_variant_name(t3_col_ei, 1, str_intern("T3Green"));
- ei_set_variant_name(t3_col_ei, 2, str_intern("T3Blue"));
- w64(g_enums, t3_col_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 3);
- t3_col_ti := alloc_named_type(str_intern("T3Color"));
- t3_r := sh_match_variant_term(t3_col_ti, 0);
- t3_g := sh_match_variant_term(t3_col_ti, 1);
- t3_b := sh_match_variant_term(t3_col_ti, 2);
+ init_types()
+ ty_budget_reset(200000)
+ t3_col_ei := add_enum("T3Color")
+ ei_set_variant_name(t3_col_ei, 0, str_intern("T3Red"))
+ ei_set_variant_name(t3_col_ei, 1, str_intern("T3Green"))
+ ei_set_variant_name(t3_col_ei, 2, str_intern("T3Blue"))
+ w64(g_enums, t3_col_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 3)
+ t3_col_ti := alloc_named_type(str_intern("T3Color"))
+ t3_r := sh_match_variant_term(t3_col_ti, 0)
+ t3_g := sh_match_variant_term(t3_col_ti, 1)
+ t3_b := sh_match_variant_term(t3_col_ti, 2)
// ① 全覆盖 = 1(模式项与域项同一构造 ⇒ 补集空)
- total = total + 1; fails = fails + ts_check("t3.cover_all",
- sh_match_exhaustive(t3_col_ti, tt_cons(t3_r, tt_cons(t3_g, tt_cons(t3_b, tt_nil()))), 0), 1);
+ total = total + 1
+ fails = fails + ts_check("t3.cover_all",
+ sh_match_exhaustive(t3_col_ti, tt_cons(t3_r, tt_cons(t3_g, tt_cons(t3_b, tt_nil()))), 0), 1)
// ② 缺一变体 = 0;反例 = **缺失变体名**(引擎判据 + 覆盖位命名两路并用)
- t3_ab := tt_cons(t3_r, tt_cons(t3_g, tt_nil()));
- total = total + 1; fails = fails + ts_check("t3.missing_one_verdict",
- sh_match_exhaustive(t3_col_ti, t3_ab, 0), 0);
- t3_w := ty_exhaust_witness(sh_enum_domain_term(t3_col_ti), t3_ab);
- t3_cx := sh_match_first_missing(sh_match_bit(0) + sh_match_bit(1), ei_variant_count(t3_col_ei));
- t3_cx_named : ., mut = 0;
- if t3_cx == 2 {
- if str_eq(istr_get(ei_variant_name(t3_col_ei, t3_cx)), "T3Blue") != 0 { t3_cx_named = 1; }
- }
+ t3_ab := tt_cons(t3_r, tt_cons(t3_g, tt_nil()))
+ total = total + 1
+ fails = fails + ts_check("t3.missing_one_verdict",
+ sh_match_exhaustive(t3_col_ti, t3_ab, 0), 0)
+ t3_w := ty_exhaust_witness(sh_enum_domain_term(t3_col_ti), t3_ab)
+ t3_cx := sh_match_first_missing(sh_match_bit(0) + sh_match_bit(1), ei_variant_count(t3_col_ei))
+ t3_cx_named : ., mut = 0
+ if t3_cx == 2:
+ if str_eq(istr_get(ei_variant_name(t3_col_ei, t3_cx)), "T3Blue") != 0:
+ t3_cx_named = 1
// 引擎 witness 原始形态 = 含空析取支的并(Task 0 §5-②):本批**实测**(三态)=
// ty_sub(w, 缺失变体) = 1(w ⊆ b)∧ ty_sub(反方向) = **-1**(未覆盖面——空析取支让反向
// 结构比较落空)∧ ty_equiv = **-1**(**不是 0**:Task 0 报告记「不等」为 `== 0`,实测为
// -1 = 未覆盖面,此处按实测钉死;-1 不得当 0 用的三态纪律在此具体化)∧ 可空 = 1。
// 故「反例给具体值」由**覆盖位命名**承担(引擎 witness 项在其上不可作显示名)。
- total = total + 1; fails = fails + ts_check_b("t3.counterexample_named_variant",
- (t3_w >= 0 && ty_inhabited(t3_w) == 1 && ty_sub(t3_w, t3_b) == 1 && t3_cx_named), true);
+ total = total + 1
+ fails = fails + ts_check_b("t3.counterexample_named_variant",
+ (t3_w >= 0 && ty_inhabited(t3_w) == 1 && ty_sub(t3_w, t3_b) == 1 && t3_cx_named), true)
// ─── R2 P5 Task 3b 翻转钉(原合取式 `... && ty_equiv(t3_w, t3_b) == -1` 的拆解)───
// 变体项 = AK_SUM 链 [枚举名令牌, 变体名令牌](两枚**身份令牌**)⇒ 不变槽三态落地后,
// 令牌按节点同一性判**确定不同 0**(改前 = -1 + 未覆盖面)。t3_w = 含两枚**空析取支**
@@ -3357,96 +3810,110 @@ fn type_selftest_run() -> int {
// 在 `lit_implies` 的 ¬ 面加「同类 ⇒ 身份判据」**(`atom_same_class_disjoint`,域 = AK_SUM
// 变体项)⇒ `B ⊆ ¬R`/`B ⊆ ¬G` 转 1 ⇒ 下两例 + 单点最小复现**转 1 并重钉**(本批唯一的
// 行为方向变化;域外面与 `AK_NAMED` 维持原语义,见 type_engine.cr 该函数头注)。
- total = total + 1; fails = fails + ts_check("t3.witness_reverse_over_claim", ty_sub(t3_b, t3_w), 1);
- total = total + 1; fails = fails + ts_check("t3.witness_equiv_over_claim", ty_equiv(t3_w, t3_b), 1);
+ total = total + 1
+ fails = fails + ts_check("t3.witness_reverse_over_claim", ty_sub(t3_b, t3_w), 1)
+ total = total + 1
+ fails = fails + ts_check("t3.witness_equiv_over_claim", ty_equiv(t3_w, t3_b), 1)
// 同一收口面的**最小复现**(单点断言:`B ⊆ B ∩ ¬R` ⟺ `B ⊆ ¬R`)
- total = total + 1; fails = fails + ts_check("t3.product_neg_over_claim",
- ty_sub(t3_b, tt_inter(t3_b, tt_not(t3_r))), 1);
+ total = total + 1
+ fails = fails + ts_check("t3.product_neg_over_claim",
+ ty_sub(t3_b, tt_inter(t3_b, tt_not(t3_r))), 1)
// ③ 通配/绑定 = ⊤:吸收一切(引擎侧 ⊤ 语义;checker 侧映射见 EXPR_MATCH)
- total = total + 1; fails = fails + ts_check("t3.wildcard_absorbs",
- sh_match_exhaustive(t3_col_ti, tt_cons(tt_top(), tt_nil()), 0), 1);
+ total = total + 1
+ fails = fails + ts_check("t3.wildcard_absorbs",
+ sh_match_exhaustive(t3_col_ti, tt_cons(tt_top(), tt_nil()), 0), 1)
// ④ 单变体枚举:有臂 = 1 / 无臂 = 0(空链 ⇒ 补集 = 全域)
- t3_only_ei := add_enum("T3Only");
- ei_set_variant_name(t3_only_ei, 0, str_intern("T3One"));
- w64(g_enums, t3_only_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 1);
- t3_only_ti := alloc_named_type(str_intern("T3Only"));
- t3_one := sh_match_variant_term(t3_only_ti, 0);
- total = total + 1; fails = fails + ts_check("t3.single_variant_covered",
- sh_match_exhaustive(t3_only_ti, tt_cons(t3_one, tt_nil()), 0), 1);
- total = total + 1; fails = fails + ts_check_b("t3.no_arms_not_exhaustive",
- (sh_match_exhaustive(t3_only_ti, tt_nil(), 0) == 0 && sh_match_first_missing(0, 1) == 0), true);
+ t3_only_ei := add_enum("T3Only")
+ ei_set_variant_name(t3_only_ei, 0, str_intern("T3One"))
+ w64(g_enums, t3_only_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 1)
+ t3_only_ti := alloc_named_type(str_intern("T3Only"))
+ t3_one := sh_match_variant_term(t3_only_ti, 0)
+ total = total + 1
+ fails = fails + ts_check("t3.single_variant_covered",
+ sh_match_exhaustive(t3_only_ti, tt_cons(t3_one, tt_nil()), 0), 1)
+ total = total + 1
+ fails = fails + ts_check_b("t3.no_arms_not_exhaustive",
+ (sh_match_exhaustive(t3_only_ti, tt_nil(), 0) == 0 && sh_match_first_missing(0, 1) == 0), true)
// ⑤ 域守卫与不可映射守卫:非枚举 scrutinee / 不可映射模式 ⇒ -1(**不判**,不得当 0/1)
- t3_s_ti := ts_unf_mk_int_struct("T3StrU");
- total = total + 1; fails = fails + ts_check_b("t3.domain_guard_unknown",
+ t3_s_ti := ts_unf_mk_int_struct("T3StrU")
+ total = total + 1
+ fails = fails + ts_check_b("t3.domain_guard_unknown",
(sh_match_exhaustive(TI_INT, tt_nil(), 0) == -1 && sh_match_exhaustive(t3_s_ti, tt_nil(), 0) == -1 &&
- sh_match_exhaustive(-1, tt_nil(), 0) == -1 && sh_enum_domain_term(t3_s_ti) == -1), true);
- total = total + 1; fails = fails + ts_check("t3.unmappable_guard_unknown",
- sh_match_exhaustive(t3_col_ti, tt_cons(t3_r, tt_cons(t3_g, tt_cons(t3_b, tt_nil()))), 1), -1);
+ sh_match_exhaustive(-1, tt_nil(), 0) == -1 && sh_enum_domain_term(t3_s_ti) == -1), true)
+ total = total + 1
+ fails = fails + ts_check("t3.unmappable_guard_unknown",
+ sh_match_exhaustive(t3_col_ti, tt_cons(t3_r, tt_cons(t3_g, tt_cons(t3_b, tt_nil()))), 1), -1)
// ⑥ 空枚举域 = ⊥:补集语义下**空洞穷尽**(无值可漏 ⇒ 无反例;计划原文「= 0」的偏差登记)
- t3_emp_ei := add_enum("T3Empty");
- w64(g_enums, t3_emp_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 0);
- t3_emp_ti := alloc_named_type(str_intern("T3Empty"));
- total = total + 1; fails = fails + ts_check_b("t3.empty_domain_vacuous",
- (sh_match_exhaustive(t3_emp_ti, tt_nil(), 0) == 1 && sh_match_first_missing(0, 0) == -1), true);
+ t3_emp_ei := add_enum("T3Empty")
+ w64(g_enums, t3_emp_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 0)
+ t3_emp_ti := alloc_named_type(str_intern("T3Empty"))
+ total = total + 1
+ fails = fails + ts_check_b("t3.empty_domain_vacuous",
+ (sh_match_exhaustive(t3_emp_ti, tt_nil(), 0) == 1 && sh_match_first_missing(0, 0) == -1), true)
// ⑦ payload 变体与 tag 变体混合(payload 不入项 = 变体身份粒度;覆盖语义不受影响)
- t3_mix_ei := add_enum("T3Mix");
- ei_set_variant_name(t3_mix_ei, 0, str_intern("T3None"));
- ei_set_variant_name(t3_mix_ei, 1, str_intern("T3Some"));
- ei_set_variant_type_count(t3_mix_ei, 1, 1);
- ei_set_variant_type(t3_mix_ei, 1, 0, TY_INT);
- w64(g_enums, t3_mix_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 2);
- t3_mix_ti := alloc_named_type(str_intern("T3Mix"));
- t3_none := sh_match_variant_term(t3_mix_ti, 0);
- t3_some := sh_match_variant_term(t3_mix_ti, 1);
- total = total + 1; fails = fails + ts_check_b("t3.payload_mixed_cover",
+ t3_mix_ei := add_enum("T3Mix")
+ ei_set_variant_name(t3_mix_ei, 0, str_intern("T3None"))
+ ei_set_variant_name(t3_mix_ei, 1, str_intern("T3Some"))
+ ei_set_variant_type_count(t3_mix_ei, 1, 1)
+ ei_set_variant_type(t3_mix_ei, 1, 0, TY_INT)
+ w64(g_enums, t3_mix_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 2)
+ t3_mix_ti := alloc_named_type(str_intern("T3Mix"))
+ t3_none := sh_match_variant_term(t3_mix_ti, 0)
+ t3_some := sh_match_variant_term(t3_mix_ti, 1)
+ total = total + 1
+ fails = fails + ts_check_b("t3.payload_mixed_cover",
(t3_none >= 0 && t3_some >= 0 && t3_none != t3_some &&
- sh_match_exhaustive(t3_mix_ti, tt_cons(t3_some, tt_cons(t3_none, tt_nil())), 0) == 1 &&
- sh_match_exhaustive(t3_mix_ti, tt_cons(t3_none, tt_nil()), 0) == 0 &&
- sh_match_first_missing(sh_match_bit(0), 2) == 1), true);
+ sh_match_exhaustive(t3_mix_ti, tt_cons(t3_some, tt_cons(t3_none, tt_nil())), 0) == 1 &&
+ sh_match_exhaustive(t3_mix_ti, tt_cons(t3_none, tt_nil()), 0) == 0 &&
+ sh_match_first_missing(sh_match_bit(0), 2) == 1), true)
// ⑧ 模式名字解析:限定名 `Enum.Variant` 与裸名同判;异枚举前缀 / 未声明名 ⇒ -1(不可映射);
// 类别分类:通配/绑定 = ⊤、枚举模式 = 变体、字面量/负节点 = 不可映射
- t3_pat_q := alloc_node(EXPR_ENUMPAT, str_intern("T3Color.T3Blue"), 0, 0, 0, 0, 0, 0, 0);
- t3_pat_b := alloc_node(EXPR_ENUMPAT, str_intern("T3Blue"), 0, 0, 0, 0, 0, 0, 0);
- t3_pat_f := alloc_node(EXPR_ENUMPAT, str_intern("T3Mix.T3Blue"), 0, 0, 0, 0, 0, 0, 0);
- t3_pat_n := alloc_node(EXPR_ENUMPAT, str_intern("T3Nope"), 0, 0, 0, 0, 0, 0, 0);
- t3_pat_w := alloc_node(EXPR_WILDCARD, 0, 0, 0, 0, 0, 0, 0, 0);
- t3_pat_l := alloc_node(EXPR_INT, 0, 0, 0, 5, TY_INT, 0, 0, 0);
- t3_pat_i := alloc_node(EXPR_IDENT, 0, 0, 0, str_intern("t3bind"), 0, 0, 0, 0);
- total = total + 1; fails = fails + ts_check_b("t3.pat_name_resolution",
+ t3_pat_q := alloc_node(EXPR_ENUMPAT, str_intern("T3Color.T3Blue"), 0, 0, 0, 0, 0, 0, 0)
+ t3_pat_b := alloc_node(EXPR_ENUMPAT, str_intern("T3Blue"), 0, 0, 0, 0, 0, 0, 0)
+ t3_pat_f := alloc_node(EXPR_ENUMPAT, str_intern("T3Mix.T3Blue"), 0, 0, 0, 0, 0, 0, 0)
+ t3_pat_n := alloc_node(EXPR_ENUMPAT, str_intern("T3Nope"), 0, 0, 0, 0, 0, 0, 0)
+ t3_pat_w := alloc_node(EXPR_WILDCARD, 0, 0, 0, 0, 0, 0, 0, 0)
+ t3_pat_l := alloc_node(EXPR_INT, 0, 0, 0, 5, TY_INT, 0, 0, 0)
+ t3_pat_i := alloc_node(EXPR_IDENT, 0, 0, 0, str_intern("t3bind"), 0, 0, 0, 0)
+ total = total + 1
+ fails = fails + ts_check_b("t3.pat_name_resolution",
(sh_match_pat_variant(t3_col_ti, t3_pat_q) == 2 && sh_match_pat_variant(t3_col_ti, t3_pat_b) == 2 &&
- sh_match_pat_variant(t3_col_ti, t3_pat_f) == -1 && sh_match_pat_variant(t3_col_ti, t3_pat_n) == -1 &&
- sh_match_pat_variant(t3_col_ti, t3_pat_w) == -1 && sh_match_pat_variant(t3_s_ti, t3_pat_b) == -1), true);
- total = total + 1; fails = fails + ts_check_b("t3.pat_kind_classification",
+ sh_match_pat_variant(t3_col_ti, t3_pat_f) == -1 && sh_match_pat_variant(t3_col_ti, t3_pat_n) == -1 &&
+ sh_match_pat_variant(t3_col_ti, t3_pat_w) == -1 && sh_match_pat_variant(t3_s_ti, t3_pat_b) == -1), true)
+ total = total + 1
+ fails = fails + ts_check_b("t3.pat_kind_classification",
(sh_match_pat_kind(t3_pat_w) == 1 && sh_match_pat_kind(t3_pat_i) == 1 &&
- sh_match_pat_kind(t3_pat_q) == 2 && sh_match_pat_kind(t3_pat_l) == 0 &&
- sh_match_pat_kind(-1) == 0), true);
+ sh_match_pat_kind(t3_pat_q) == 2 && sh_match_pat_kind(t3_pat_l) == 0 &&
+ sh_match_pat_kind(-1) == 0), true)
// ⑨ 重复臂:覆盖面无贡献(补集仍空 = 穷尽;覆盖位去重在 checker 侧收集时做——
// 「位已置 ⇒ 该臂冗余」由行为集钉死)
- total = total + 1; fails = fails + ts_check_b("t3.dup_arm_complement",
+ total = total + 1
+ fails = fails + ts_check_b("t3.dup_arm_complement",
(sh_match_exhaustive(t3_only_ti, tt_cons(t3_one, tt_cons(t3_one, tt_nil())), 0) == 1 &&
- sh_match_first_missing(sh_match_bit(0), 3) == 1), true);
+ sh_match_first_missing(sh_match_bit(0), 3) == 1), true)
// ⑩ 泛型应用行(`T3GOpt[int]`):域可展开 + 全覆盖 = 1(变体身份与实参无关)
- t3_go_ei := add_enum("T3GOpt");
- w64(g_enums, t3_go_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 1);
- w64(g_enums, t3_go_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES, str_intern("T3GT"));
- ei_set_variant_name(t3_go_ei, 0, str_intern("T3GN"));
- ei_set_variant_name(t3_go_ei, 1, str_intern("T3GS"));
- ei_set_variant_type_count(t3_go_ei, 1, 1);
- ei_set_variant_type(t3_go_ei, 1, 0, 0);
- w64(g_enums, t3_go_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 2);
- t3_go_ti := alloc_named_type(str_intern("T3GOpt"));
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- t3_gas := g_gen_apply_data_count;
- w64(g_gen_apply_data, t3_gas * 8, 1);
- w64(g_gen_apply_data, (t3_gas + 1) * 8, TI_INT);
- g_gen_apply_data_count = t3_gas + 2;
- t3_go_ga := alloc_type(TYP_GENERIC_APPLY, t3_go_ti, t3_gas);
- t3_gn := sh_match_variant_term(t3_go_ga, 0);
- t3_gs := sh_match_variant_term(t3_go_ga, 1);
- total = total + 1; fails = fails + ts_check_b("t3.generic_apply_domain",
+ t3_go_ei := add_enum("T3GOpt")
+ w64(g_enums, t3_go_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 1)
+ w64(g_enums, t3_go_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES, str_intern("T3GT"))
+ ei_set_variant_name(t3_go_ei, 0, str_intern("T3GN"))
+ ei_set_variant_name(t3_go_ei, 1, str_intern("T3GS"))
+ ei_set_variant_type_count(t3_go_ei, 1, 1)
+ ei_set_variant_type(t3_go_ei, 1, 0, 0)
+ w64(g_enums, t3_go_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 2)
+ t3_go_ti := alloc_named_type(str_intern("T3GOpt"))
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ t3_gas := g_gen_apply_data_count
+ w64(g_gen_apply_data, t3_gas * 8, 1)
+ w64(g_gen_apply_data, (t3_gas + 1) * 8, TI_INT)
+ g_gen_apply_data_count = t3_gas + 2
+ t3_go_ga := alloc_type(TYP_GENERIC_APPLY, t3_go_ti, t3_gas)
+ t3_gn := sh_match_variant_term(t3_go_ga, 0)
+ t3_gs := sh_match_variant_term(t3_go_ga, 1)
+ total = total + 1
+ fails = fails + ts_check_b("t3.generic_apply_domain",
(t3_gn >= 0 && t3_gs >= 0 &&
- sh_match_exhaustive(t3_go_ga, tt_cons(t3_gn, tt_cons(t3_gs, tt_nil())), 0) == 1 &&
- sh_match_exhaustive(t3_go_ga, tt_cons(t3_gn, tt_nil()), 0) == 0), true);
+ sh_match_exhaustive(t3_go_ga, tt_cons(t3_gn, tt_cons(t3_gs, tt_nil())), 0) == 1 &&
+ sh_match_exhaustive(t3_go_ga, tt_cons(t3_gn, tt_nil()), 0) == 0), true)
// ═══ R2 P3 Task 4:联合/可选(`T?` = `T ∪ null`;退役内建 Option 注册)═══
// 判据面 = ① 项层:`T?` 行译作 union(内层项, null 原子项)——与**独立构造**的并项等价;
@@ -3457,174 +3924,214 @@ fn type_selftest_run() -> int {
// 裸码塌缩为 0 = TY_INT,节点列才是载荷真值——本组以「码说是 int、节点说是 string」的
// 反向夹具把节点列的读取钉死);⑦ 退役面(Option 无命名行、AK_NULL 无注册表条目)。
// 夹具:行 = alloc_type/alloc_named_type;枚举表照 parser 写槽序人工落(两列都写)。
- init_types();
- ty_budget_reset(200000);
- t4_null := alloc_type(TYP_NULL, 0, 0); // None 的类型行(每出现点一行)
- t4_null2 := alloc_type(TYP_NULL, 0, 0); // 第二个出现点(规范化判据用)
- t4_int_opt := alloc_type(TYP_OPTIONAL, TI_INT, 0);
- t4_str_opt := alloc_type(TYP_OPTIONAL, TI_STR, 0);
- t4_intt := sh_term_of_ti(TI_INT);
- t4_nullt := sh_null_term();
- t4_optt := sh_term_of_ti(t4_int_opt);
+ init_types()
+ ty_budget_reset(200000)
+ t4_null := alloc_type(TYP_NULL, 0, 0) // None 的类型行(每出现点一行)
+ t4_null2 := alloc_type(TYP_NULL, 0, 0) // 第二个出现点(规范化判据用)
+ t4_int_opt := alloc_type(TYP_OPTIONAL, TI_INT, 0)
+ t4_str_opt := alloc_type(TYP_OPTIONAL, TI_STR, 0)
+ t4_intt := sh_term_of_ti(TI_INT)
+ t4_nullt := sh_null_term()
+ t4_optt := sh_term_of_ti(t4_int_opt)
// ① 项层:`int?` 项 = int ∪ null(与独立构造的并项等价),且 **不等于** 裸 int
- total = total + 1; fails = fails + ts_check_b("t4.opt_term_is_union",
+ total = total + 1
+ fails = fails + ts_check_b("t4.opt_term_is_union",
(ty_equiv(t4_optt, tt_union(t4_intt, t4_nullt)) == 1 &&
- ty_equiv(t4_optt, t4_intt) == 0 && ty_sub(t4_intt, t4_optt) == 1), true);
+ ty_equiv(t4_optt, t4_intt) == 0 && ty_sub(t4_intt, t4_optt) == 1), true)
// ② 子类型/不相交/可空
- total = total + 1; fails = fails + ts_check_b("t4.none_sub_optional",
+ total = total + 1
+ fails = fails + ts_check_b("t4.none_sub_optional",
(ty_sub(t4_nullt, t4_optt) == 1 && ty_sub(t4_nullt, sh_term_of_ti(t4_str_opt)) == 1 &&
- ty_sub(t4_optt, t4_nullt) == 0 && ty_sub(t4_optt, t4_intt) == 0), true);
- total = total + 1; fails = fails + ts_check_b("t4.some_sub_optional",
- (ty_equiv(sh_term_of_ti(alloc_type(TYP_OPTIONAL, TI_INT, 0)), t4_optt) == 1), true);
- total = total + 1; fails = fails + ts_check_b("t4.null_disjoint_and_inhabited",
+ ty_sub(t4_optt, t4_nullt) == 0 && ty_sub(t4_optt, t4_intt) == 0), true)
+ total = total + 1
+ fails = fails + ts_check_b("t4.some_sub_optional",
+ (ty_equiv(sh_term_of_ti(alloc_type(TYP_OPTIONAL, TI_INT, 0)), t4_optt) == 1), true)
+ total = total + 1
+ fails = fails + ts_check_b("t4.null_disjoint_and_inhabited",
(ty_disjoint(t4_nullt, t4_intt) == 1 && ty_disjoint(t4_nullt, sh_term_of_ti(TI_UNIT)) == 1 &&
- ty_disjoint(t4_nullt, sh_term_of_ti(TI_NEVER)) == 1 && ty_disjoint(t4_nullt, t4_nullt) == 0 &&
- ty_inhabited(t4_nullt) == 1), true);
+ ty_disjoint(t4_nullt, sh_term_of_ti(TI_NEVER)) == 1 && ty_disjoint(t4_nullt, t4_nullt) == 0 &&
+ ty_inhabited(t4_nullt) == 1), true)
// ③ null 行规范化:两个出现点译成**同一项**(节点同一),且互判包含
- total = total + 1; fails = fails + ts_check_b("t4.null_row_canonical",
+ total = total + 1
+ fails = fails + ts_check_b("t4.null_row_canonical",
(sh_term_of_ti(t4_null) == sh_term_of_ti(t4_null2) &&
- ty_sub(sh_term_of_ti(t4_null), sh_term_of_ti(t4_null2)) == 1), true);
+ ty_sub(sh_term_of_ti(t4_null), sh_term_of_ti(t4_null2)) == 1), true)
// ④ 判定点注入(type_compat_strict):T ⊆ T? 放行、反向拒绝、异型拒绝;同型走身份路径
- total = total + 1; fails = fails + ts_check_b("t4.sub_injection_asymmetry",
+ total = total + 1
+ fails = fails + ts_check_b("t4.sub_injection_asymmetry",
(type_compat_strict(TI_INT, t4_int_opt) == 1 && type_compat_strict(t4_int_opt, TI_INT) == 0 &&
- type_compat_strict(TI_STR, t4_int_opt) == 0 && type_compat_strict(t4_null, t4_int_opt) == 1 &&
- type_compat_strict(t4_int_opt, t4_int_opt) == 1 && type_compat_strict(TI_INT, t4_str_opt) == 0), true);
+ type_compat_strict(TI_STR, t4_int_opt) == 0 && type_compat_strict(t4_null, t4_int_opt) == 1 &&
+ type_compat_strict(t4_int_opt, t4_int_opt) == 1 && type_compat_strict(TI_INT, t4_str_opt) == 0), true)
// ⑤ 注册表/许可:null 与可选行都**不是**单一原子类 ⇒ -1(门全拒)。
// R2 P4 Task 3 重定(原判据「AK_NULL 无条目」随扩列翻转):AK_NULL **有条目**
// (第 14 行,可查询性面)但 ops = 0 ⇒ 操作门仍全拒——保守面由「无条目」换位到
// 「条目 + 零许可位」(同一行为、更可查询);条目数 13 → 16(扩列硬值)。
- total = total + 1; fails = fails + ts_check_b("t4.null_no_ops_no_entry",
+ total = total + 1
+ fails = fails + ts_check_b("t4.null_no_ops_no_entry",
(iface_kind_of(t4_null) == -1 && iface_kind_of(t4_int_opt) == -1 &&
- iface_permits(-1, OP_ADD) == 0 && iface_entry(AK_NULL) >= 0 &&
- iface_ops(AK_NULL) == 0 && iface_permits(AK_NULL, OP_ADD) == 0 && iface_count() == 16), true);
+ iface_permits(-1, OP_ADD) == 0 && iface_entry(AK_NULL) >= 0 &&
+ iface_ops(AK_NULL) == 0 && iface_permits(AK_NULL, OP_ADD) == 0 && iface_count() == 16), true)
// ⑥ AK_NULL 互斥公理全表(13 类逐类):除 AK_DYN(⊤ 相容规则)与自身外皆不相交
- t4_dj : ., mut = 0;
- t4_k : ., mut = 0;
- t4_aks := alloc(13 * 8);
- w64(t4_aks, 0 * 8, AK_INT); w64(t4_aks, 1 * 8, AK_DEX); w64(t4_aks, 2 * 8, AK_STRING);
- w64(t4_aks, 3 * 8, AK_BOOL); w64(t4_aks, 4 * 8, AK_UNIT); w64(t4_aks, 5 * 8, AK_NEVER);
- w64(t4_aks, 6 * 8, AK_CHAR); w64(t4_aks, 7 * 8, AK_DYN); w64(t4_aks, 8 * 8, AK_PRODUCT);
- w64(t4_aks, 9 * 8, AK_SUM); w64(t4_aks, 10 * 8, AK_SEQUENCE); w64(t4_aks, 11 * 8, AK_REF);
- w64(t4_aks, 12 * 8, AK_PTR);
- loop {
- if t4_k >= 13 { break; }
- ka := r64(t4_aks, t4_k * 8);
- want : ., mut = 1;
- if ka == AK_DYN { want = 0; } // AK_DYN = ⊤:与一切相容(含 null)——登记
- if ak_disjoint(AK_NULL, ka) != want { t4_dj = t4_dj + 1; }
- t4_k = t4_k + 1;
- }
- total = total + 1; fails = fails + ts_check_b("t4.ak_null_disjoint_table",
- (t4_dj == 0 && ak_disjoint(AK_NULL, AK_NULL) == 0 && ak_disjoint(AK_NULL, AK_NAMED) == 1), true);
+ t4_dj : ., mut = 0
+ t4_k : ., mut = 0
+ t4_aks := alloc(13 * 8)
+ w64(t4_aks, 0 * 8, AK_INT)
+ w64(t4_aks, 1 * 8, AK_DEX)
+ w64(t4_aks, 2 * 8, AK_STRING)
+ w64(t4_aks, 3 * 8, AK_BOOL)
+ w64(t4_aks, 4 * 8, AK_UNIT)
+ w64(t4_aks, 5 * 8, AK_NEVER)
+ w64(t4_aks, 6 * 8, AK_CHAR)
+ w64(t4_aks, 7 * 8, AK_DYN)
+ w64(t4_aks, 8 * 8, AK_PRODUCT)
+ w64(t4_aks, 9 * 8, AK_SUM)
+ w64(t4_aks, 10 * 8, AK_SEQUENCE)
+ w64(t4_aks, 11 * 8, AK_REF)
+ w64(t4_aks, 12 * 8, AK_PTR)
+ loop:
+ if t4_k >= 13:
+ break
+ ka := r64(t4_aks, t4_k * 8)
+ want : ., mut = 1
+ if ka == AK_DYN:
+ want = 0
+ // AK_DYN = ⊤:与一切相容(含 null)——登记
+ if ak_disjoint(AK_NULL, ka) != want:
+ t4_dj = t4_dj + 1
+ t4_k = t4_k + 1
+ total = total + 1
+ fails = fails + ts_check_b("t4.ak_null_disjoint_table",
+ (t4_dj == 0 && ak_disjoint(AK_NULL, AK_NULL) == 0 && ak_disjoint(AK_NULL, AK_NAMED) == 1), true)
// ⑦ match 域面:可选域 = 两分支(有值 = Some 模式 / null = None 模式)
- t4_some_pat := alloc_node(EXPR_ENUMPAT, str_intern("Some"), 0, 0, 0, 0, 0, 0, 0);
- t4_none_pat := alloc_node(EXPR_ENUMPAT, str_intern("None"), 0, 0, 0, 0, 0, 0, 0);
- t4_other_pat := alloc_node(EXPR_ENUMPAT, str_intern("Red"), 0, 0, 0, 0, 0, 0, 0);
- t4_qual_pat := alloc_node(EXPR_ENUMPAT, str_intern("Option.Some"), 0, 0, 0, 0, 0, 0, 0);
- t4_some_t := sh_match_opt_term(t4_int_opt, sh_match_opt_pat(t4_int_opt, t4_some_pat));
- t4_none_t := sh_match_opt_term(t4_int_opt, sh_match_opt_pat(t4_int_opt, t4_none_pat));
- t4_full := tt_cons(t4_some_t, tt_cons(t4_none_t, tt_nil()));
- total = total + 1; fails = fails + ts_check_b("t4.match_opt_two_branch_cover",
+ t4_some_pat := alloc_node(EXPR_ENUMPAT, str_intern("Some"), 0, 0, 0, 0, 0, 0, 0)
+ t4_none_pat := alloc_node(EXPR_ENUMPAT, str_intern("None"), 0, 0, 0, 0, 0, 0, 0)
+ t4_other_pat := alloc_node(EXPR_ENUMPAT, str_intern("Red"), 0, 0, 0, 0, 0, 0, 0)
+ t4_qual_pat := alloc_node(EXPR_ENUMPAT, str_intern("Option.Some"), 0, 0, 0, 0, 0, 0, 0)
+ t4_some_t := sh_match_opt_term(t4_int_opt, sh_match_opt_pat(t4_int_opt, t4_some_pat))
+ t4_none_t := sh_match_opt_term(t4_int_opt, sh_match_opt_pat(t4_int_opt, t4_none_pat))
+ t4_full := tt_cons(t4_some_t, tt_cons(t4_none_t, tt_nil()))
+ total = total + 1
+ fails = fails + ts_check_b("t4.match_opt_two_branch_cover",
(t4_some_t == t4_intt && t4_none_t == t4_nullt &&
- sh_match_exhaustive(t4_int_opt, t4_full, 0) == 1 &&
- sh_match_exhaustive(t4_int_opt, tt_cons(t4_some_t, tt_nil()), 0) == 0 &&
- sh_match_exhaustive(t4_int_opt, tt_cons(t4_none_t, tt_nil()), 0) == 0), true);
- total = total + 1; fails = fails + ts_check_b("t4.match_opt_counterexample_naming",
+ sh_match_exhaustive(t4_int_opt, t4_full, 0) == 1 &&
+ sh_match_exhaustive(t4_int_opt, tt_cons(t4_some_t, tt_nil()), 0) == 0 &&
+ sh_match_exhaustive(t4_int_opt, tt_cons(t4_none_t, tt_nil()), 0) == 0), true)
+ total = total + 1
+ fails = fails + ts_check_b("t4.match_opt_counterexample_naming",
(sh_match_first_missing(sh_match_bit(0), 2) == 1 &&
- sh_match_first_missing(sh_match_bit(1), 2) == 0 &&
- sh_match_first_missing(0, 2) == 0), true);
- total = total + 1; fails = fails + ts_check_b("t4.match_opt_wildcard_and_guards",
+ sh_match_first_missing(sh_match_bit(1), 2) == 0 &&
+ sh_match_first_missing(0, 2) == 0), true)
+ total = total + 1
+ fails = fails + ts_check_b("t4.match_opt_wildcard_and_guards",
(sh_match_exhaustive(t4_int_opt, tt_cons(tt_top(), tt_nil()), 0) == 1 &&
- sh_match_exhaustive(t4_int_opt, t4_full, 1) == -1 &&
- sh_match_exhaustive(TI_INT, t4_full, 0) == -1 &&
- sh_match_domain_term(TI_INT) == -1 && sh_match_domain_term(t4_str_opt) >= 0), true);
- total = total + 1; fails = fails + ts_check_b("t4.opt_pat_mapping",
+ sh_match_exhaustive(t4_int_opt, t4_full, 1) == -1 &&
+ sh_match_exhaustive(TI_INT, t4_full, 0) == -1 &&
+ sh_match_domain_term(TI_INT) == -1 && sh_match_domain_term(t4_str_opt) >= 0), true)
+ total = total + 1
+ fails = fails + ts_check_b("t4.opt_pat_mapping",
(sh_match_opt_pat(t4_int_opt, t4_some_pat) == 0 && sh_match_opt_pat(t4_int_opt, t4_none_pat) == 1 &&
- sh_match_opt_pat(t4_int_opt, t4_other_pat) == -1 && sh_match_opt_pat(t4_int_opt, t4_qual_pat) == -1 &&
- sh_match_opt_pat(TI_INT, t4_none_pat) == -1), true);
- total = total + 1; fails = fails + ts_check_b("t4.opt_domain_leaf_count",
+ sh_match_opt_pat(t4_int_opt, t4_other_pat) == -1 && sh_match_opt_pat(t4_int_opt, t4_qual_pat) == -1 &&
+ sh_match_opt_pat(TI_INT, t4_none_pat) == -1), true)
+ total = total + 1
+ fails = fails + ts_check_b("t4.opt_domain_leaf_count",
(ts_unf_union_leaves(sh_match_domain_term(t4_int_opt)) == 2 &&
- ts_unf_union_leaves(sh_match_domain_term(t4_str_opt)) == 2), true);
+ ts_unf_union_leaves(sh_match_domain_term(t4_str_opt)) == 2), true)
// ⑧ 枚举载荷类型节点列(T0 交接 ① 的消费面:sh_variant_payload_term)
- t4_p_ei := add_enum("T4Payload");
- ei_set_variant_name(t4_p_ei, 0, str_intern("T4Tag"));
+ t4_p_ei := add_enum("T4Payload")
+ ei_set_variant_name(t4_p_ei, 0, str_intern("T4Tag"))
// 变体 1:**裸码槽 = 0(= TY_INT,旧布局的全部信息)而节点列 = string** —— 节点列才是真值
- ei_set_variant_name(t4_p_ei, 1, str_intern("T4Str"));
- ei_set_variant_type_count(t4_p_ei, 1, 1);
- ei_set_variant_type(t4_p_ei, 1, 0, TY_INT);
- ei_set_variant_type_node(t4_p_ei, 1, 0, alloc_node(0, 0, 0, 0, 0, TY_STRING, 0, 0, 0));
- w64(g_enums, t4_p_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 2);
- t4_p_ti := alloc_named_type(str_intern("T4Payload"));
- total = total + 1; fails = fails + ts_check_b("t4.payload_node_beats_bare_code",
+ ei_set_variant_name(t4_p_ei, 1, str_intern("T4Str"))
+ ei_set_variant_type_count(t4_p_ei, 1, 1)
+ ei_set_variant_type(t4_p_ei, 1, 0, TY_INT)
+ ei_set_variant_type_node(t4_p_ei, 1, 0, alloc_node(0, 0, 0, 0, 0, TY_STRING, 0, 0, 0))
+ w64(g_enums, t4_p_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 2)
+ t4_p_ti := alloc_named_type(str_intern("T4Payload"))
+ total = total + 1
+ fails = fails + ts_check_b("t4.payload_node_beats_bare_code",
(sh_variant_payload_term(t4_p_ti, str_intern("T4Str")) == sh_term_of_ti(TI_STR) &&
- ty_disjoint(sh_variant_payload_term(t4_p_ti, str_intern("T4Str")), t4_intt) == 1 &&
- sh_variant_payload_term(t4_p_ti, str_intern("T4Tag")) == -1 &&
- sh_variant_payload_term(t4_p_ti, str_intern("T4Nope")) == -1), true);
+ ty_disjoint(sh_variant_payload_term(t4_p_ti, str_intern("T4Str")), t4_intt) == 1 &&
+ sh_variant_payload_term(t4_p_ti, str_intern("T4Tag")) == -1 &&
+ sh_variant_payload_term(t4_p_ti, str_intern("T4Nope")) == -1), true)
// ⑨ 载荷泛型代入:`enum T4GP[T] { T4S(T) }` 的 apply 行取实参项;两实例不同
- t4_g_ei := add_enum("T4GP");
- w64(g_enums, t4_g_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 1);
- w64(g_enums, t4_g_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES, str_intern("T4GT"));
- ei_set_variant_name(t4_g_ei, 0, str_intern("T4GS"));
- ei_set_variant_type_count(t4_g_ei, 0, 1);
- ei_set_variant_type(t4_g_ei, 0, 0, TY_INT);
- ei_set_variant_type_node(t4_g_ei, 0, 0, alloc_node(EXPR_IDENT, 0, 0, 0, str_intern("T4GT"), 0, 0, 0, 0));
- w64(g_enums, t4_g_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 1);
- t4_g_ti := alloc_named_type(str_intern("T4GP"));
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- t4_gs := g_gen_apply_data_count;
- w64(g_gen_apply_data, t4_gs * 8, 1);
- w64(g_gen_apply_data, (t4_gs + 1) * 8, TI_INT);
- g_gen_apply_data_count = t4_gs + 2;
- t4_g_ga := alloc_type(TYP_GENERIC_APPLY, t4_g_ti, t4_gs);
- grow_gen_apply_data(g_gen_apply_data_count + 2);
- t4_gs2 := g_gen_apply_data_count;
- w64(g_gen_apply_data, t4_gs2 * 8, 1);
- w64(g_gen_apply_data, (t4_gs2 + 1) * 8, TI_STR);
- g_gen_apply_data_count = t4_gs2 + 2;
- t4_g_ga2 := alloc_type(TYP_GENERIC_APPLY, t4_g_ti, t4_gs2);
- total = total + 1; fails = fails + ts_check_b("t4.payload_generic_subst",
+ t4_g_ei := add_enum("T4GP")
+ w64(g_enums, t4_g_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 1)
+ w64(g_enums, t4_g_ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES, str_intern("T4GT"))
+ ei_set_variant_name(t4_g_ei, 0, str_intern("T4GS"))
+ ei_set_variant_type_count(t4_g_ei, 0, 1)
+ ei_set_variant_type(t4_g_ei, 0, 0, TY_INT)
+ ei_set_variant_type_node(t4_g_ei, 0, 0, alloc_node(EXPR_IDENT, 0, 0, 0, str_intern("T4GT"), 0, 0, 0, 0))
+ w64(g_enums, t4_g_ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, 1)
+ t4_g_ti := alloc_named_type(str_intern("T4GP"))
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ t4_gs := g_gen_apply_data_count
+ w64(g_gen_apply_data, t4_gs * 8, 1)
+ w64(g_gen_apply_data, (t4_gs + 1) * 8, TI_INT)
+ g_gen_apply_data_count = t4_gs + 2
+ t4_g_ga := alloc_type(TYP_GENERIC_APPLY, t4_g_ti, t4_gs)
+ grow_gen_apply_data(g_gen_apply_data_count + 2)
+ t4_gs2 := g_gen_apply_data_count
+ w64(g_gen_apply_data, t4_gs2 * 8, 1)
+ w64(g_gen_apply_data, (t4_gs2 + 1) * 8, TI_STR)
+ g_gen_apply_data_count = t4_gs2 + 2
+ t4_g_ga2 := alloc_type(TYP_GENERIC_APPLY, t4_g_ti, t4_gs2)
+ total = total + 1
+ fails = fails + ts_check_b("t4.payload_generic_subst",
(sh_variant_payload_term(t4_g_ga, str_intern("T4GS")) == sh_term_of_ti(TI_INT) &&
- sh_variant_payload_term(t4_g_ga2, str_intern("T4GS")) == sh_term_of_ti(TI_STR) &&
- sh_variant_payload_term(t4_g_ga, str_intern("T4GS")) != sh_variant_payload_term(t4_g_ga2, str_intern("T4GS"))), true);
+ sh_variant_payload_term(t4_g_ga2, str_intern("T4GS")) == sh_term_of_ti(TI_STR) &&
+ sh_variant_payload_term(t4_g_ga, str_intern("T4GS")) != sh_variant_payload_term(t4_g_ga2, str_intern("T4GS"))), true)
// ⑩ 退役面:`Option` 名在类型表**零行**(内建注册已退役;用户声明才建行)
- total = total + 1; fails = fails + ts_check_b("t4.option_not_registered",
- (named_dedup_rows(str_intern("Option")) == 0 && find_gsym(str_intern("Option")) < 0), true);
+ total = total + 1
+ fails = fails + ts_check_b("t4.option_not_registered",
+ (named_dedup_rows(str_intern("Option")) == 0 && find_gsym(str_intern("Option")) < 0), true)
// R2 P3 Task 5 段(用例体在 ts_t5_run——见该函数头注「不得内联」)
- total = total + 9; fails = fails + ts_t5_run();
+ total = total + 9
+ fails = fails + ts_t5_run()
// R2 P3b Task 0 段(用例体在 ts_isat_run——同上,不得内联)
- total = total + 16; fails = fails + ts_isat_run();
+ total = total + 16
+ fails = fails + ts_isat_run()
// R2 P3b Task 2 段(用例体在 ts_x2_run——同上,不得内联;16 例 = 原 15 + R2 P4
// Task 3 新增 x2.shape_builtin_names)
- total = total + 16; fails = fails + ts_x2_run();
+ total = total + 16
+ fails = fails + ts_x2_run()
// R2 P3b Task 6:impl 契约(签名类型项化 / 形状项 / mangling 退役 / 三态)——见 ts_ifc_run
- total = total + 14; fails = fails + ts_ifc_run();
+ total = total + 14
+ fails = fails + ts_ifc_run()
// R2 P5 Task 3:命名面判定化(身份链 + 可判定面加强 + 域外守卫)——见 ts_t3n_run
// (残留面 1 例已迁至 t3b 段 ⇒ 本段 19 → 18)
- total = total + 18; fails = fails + ts_t3n_run();
+ total = total + 18
+ fails = fails + ts_t3n_run()
// R2 P5 Task 3b:不变槽元素三态(te_elem_cmp)——见 ts_t3b_run(13 例)
- total = total + 13; fails = fails + ts_t3b_run();
+ total = total + 13
+ fails = fails + ts_t3b_run()
// R2 P5 Task 4:残留 -1 政策 P-A(ICE04 硬错;桥接缺口 / 引擎未覆盖面 / 决定面零误报)
// ——见 ts_t4_run(3 例)
- total = total + 3; fails = fails + ts_t4_run();
+ total = total + 3
+ fails = fails + ts_t4_run()
// R2 P6 Task 2(E-10):¬ 面同类原子身份判据邻域覆盖——见 ts_t2_neg_run(9 例)
- total = total + 11; fails = fails + ts_t2_neg_run();
+ total = total + 11
+ fails = fails + ts_t2_neg_run()
// R2 P4 Task 2:TYPE 段内容面(装填/roundtrip/dedup/确定性/拒绝面)——见 ts_ccr_run
// R2 P4 Task 3:IFACE 段内容面(五小节往返/签名项槽/形状名注册面/条目扩列/判定面
// 零变化/不可建签名拒绝)——见 ts_ccr2_run(**必须最后**:populate 复位项层/引擎/
// 桥接三面缓存;两段共用同一装填入口)
// (R2 P4 Task 4 的 7 例已在前段 bridge 节内联——见 t4.tk_* 注释。)
- total = total + 5; fails = fails + ts_ccr_run();
- total = total + 8; fails = fails + ts_ccr2_run();
+ total = total + 5
+ fails = fails + ts_ccr_run()
+ total = total + 8
+ fails = fails + ts_ccr2_run()
- print(int_str(total - fails)); print("/"); print(int_str(total)); println(" type-engine cases passed");
- if fails != 0 { return 1; }
- return 0;
-}
+ print(int_str(total - fails))
+ print("/")
+ print(int_str(total))
+ println(" type-engine cases passed")
+ if fails != 0:
+ return 1
+ return 0
diff --git a/src/compiler/type_terms.cr b/src/compiler/type_terms.cr
index 525e55ba..da0e7c77 100644
--- a/src/compiler/type_terms.cr
+++ b/src/compiler/type_terms.cr
@@ -13,75 +13,100 @@
// ③ 键 = 五字段全比,哈希不入键(只定位槽位)——见 tt_term 内注记。
// ─── 标签常量(TT_*;与 ast.cr 的 TI_* 类型 kind 无关——本层是类型项语言)───
-TT_BOT : int = 0; TT_TOP : int = 1; TT_TOP_K : int = 2;
-TT_UNION : int = 3; TT_INTER : int = 4; TT_NOT : int = 5;
-TT_MU : int = 6; TT_ATOM : int = 7; TT_VAR : int = 8;
-TT_NIL : int = 9; TT_CONS : int = 10;
+TT_BOT : int = 0
+TT_TOP : int = 1
+TT_TOP_K : int = 2
+TT_UNION : int = 3
+TT_INTER : int = 4
+TT_NOT : int = 5
+TT_MU : int = 6
+TT_ATOM : int = 7
+TT_VAR : int = 8
+TT_NIL : int = 9
+TT_CONS : int = 10
// 条目 = 48B,六字段各 8B(与 g_ir_entries 同风格:字节缓冲 + 偏移常量)
-ESZ_TYPE_TERM : int = 48;
-OFF_TT_TAG : int = 0; OFF_TT_A : int = 8; OFF_TT_B : int = 16;
-OFF_TT_C : int = 24; OFF_TT_D : int = 32; OFF_TT_HASH : int = 40;
+ESZ_TYPE_TERM : int = 48
+OFF_TT_TAG : int = 0
+OFF_TT_A : int = 8
+OFF_TT_B : int = 16
+OFF_TT_C : int = 24
+OFF_TT_D : int = 32
+OFF_TT_HASH : int = 40
// 盘上项记录(TYPE 段,R2 P4 Task 2 / D12):5 × i64 = 40B {tag,a,b,c,d}——
// 内存 48B 记录**去掉 hash 槽**(哈希 = 五字段的纯函数,落盘 = 冗余 + 第二真源;
// 加载侧由 tt_hash5 重算)。字段宽度 8B = 与内存槽逐位同源(无截断面;D12 的
// 「40B/条」= 5×8B,不是 5×i32)。
-ESZ_TYPE_TERM_DISK : int = 40;
+ESZ_TYPE_TERM_DISK : int = 40
// ─── 访问器(i = 类型项行号;调用方保证 0 ≤ i < tt_count())───
-fn tt_tag(i: int) -> int { return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_TAG); }
-fn tt_a(i: int) -> int { return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_A); }
-fn tt_b(i: int) -> int { return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_B); }
-fn tt_c(i: int) -> int { return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_C); }
-fn tt_d(i: int) -> int { return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_D); }
-fn tt_count() -> int { return g_type_term_count; }
+fn tt_tag(i: int) -> int:
+ return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_TAG)
+fn tt_a(i: int) -> int:
+ return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_A)
+fn tt_b(i: int) -> int:
+ return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_B)
+fn tt_c(i: int) -> int:
+ return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_C)
+fn tt_d(i: int) -> int:
+ return r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_D)
+fn tt_count() -> int:
+ return g_type_term_count
// ─── D21 契约:`TT_ATOM ∧ b ≥ 0 ⇒ b`(b 槽即该原子的类型行);其余(union/product/μ/
// 空链/负)⇒ **-1 = 非单一原子**(不得近似、不得回 0)。R2 P6 Task 3 自
// `ty_shadow.cr:sh_atom_of_term` **整函数迁入**(单一真源;原位置 = 桥接层,而
// corearch 清单不含 ty_shadow.cr ⇒ `load_ccr` 的项索引一致性校验与 corearch 回读
// 通道无此函数可用)。语义/返回域与迁移前逐字同(唯一改点 = 函数名,调用点同步)。
-fn tt_atom_of_term(term: int) -> int {
- if term < 0 || term >= tt_count() { return -1; }
- if tt_tag(term) != TT_ATOM { return -1; }
- if tt_b(term) < 0 { return -1; }
- return tt_b(term);
-}
+fn tt_atom_of_term(term: int) -> int:
+ if term < 0 || term >= tt_count():
+ return -1
+ if tt_tag(term) != TT_ATOM:
+ return -1
+ if tt_b(term) < 0:
+ return -1
+ return tt_b(term)
// ─── 结构哈希(DAG 去重的键:五字段 fold,与插入顺序无关)───
-fn tt_hash5(tag: int, a: int, b: int, c: int, d: int) -> int {
- h : ., mut = 1469598103934665603;
- slot : ., mut = 0;
- loop {
- if slot >= 5 { break; }
- v : ., mut = tag;
- if slot == 1 { v = a; } else if slot == 2 { v = b; }
- else if slot == 3 { v = c; } else if slot == 4 { v = d; }
- k : ., mut = 0;
- loop {
- if k >= 8 { break; }
- byte : ., mut = v % 256;
- if byte < 0 { byte = -byte; }
- h = h * 1099511628211 + byte;
- v = v / 256;
- k = k + 1;
- }
- slot = slot + 1;
- }
- return h;
-}
+fn tt_hash5(tag: int, a: int, b: int, c: int, d: int) -> int:
+ h : ., mut = 1469598103934665603
+ slot : ., mut = 0
+ loop:
+ if slot >= 5:
+ break
+ v : ., mut = tag
+ if slot == 1:
+ v = a
+ else if slot == 2:
+ v = b
+ else if slot == 3:
+ v = c
+ else if slot == 4:
+ v = d
+ k : ., mut = 0
+ loop:
+ if k >= 8:
+ break
+ byte : ., mut = v % 256
+ if byte < 0:
+ byte = -byte
+ h = h * 1099511628211 + byte
+ v = v / 256
+ k = k + 1
+ slot = slot + 1
+ return h
// 非负槽位(**不要写 h - (h/cap)*cap**:i64 除法向零截断,h 为负时该式得负下标 →
// 探针越界 → 去重静默失效;2026-09-10 P0 Task 1 原生压力测试实证扩容后 dedup 全灭,
// 计划同日同款修正 = 本函数)。
// 先取余再取绝对值:|h % cap| < cap ≤ 2^63,取负不溢出(cap 恒为 2 的幂,见
// grow_tt_index);本仓库先例 = str_intern 的 `pos := h % cap; if pos < 0 { pos = -pos; }`。
-fn tt_mod(h: int, cap: int) -> int {
- m : ., mut = h % cap;
- if m < 0 { m = 0 - m; }
- return m;
-}
+fn tt_mod(h: int, cap: int) -> int:
+ m : ., mut = h % cap
+ if m < 0:
+ m = 0 - m
+ return m
// ─── 扩容(本文件自持,**不置 dyn_arr.cr**)───
// 计划 Step 4 把两函数放在 dyn_arr.cr(照 grow_types 先例),实测该位置破坏
@@ -92,53 +117,64 @@ fn tt_mod(h: int, cap: int) -> int {
// **corelsp 更正(R2 P1 Task 2 评审 M3)**:自 Task 2 起 checker 的判定入口引用
// 桥接层(ty_shadow.cr)→ corelsp 清单必须链接 引擎 + 桥接层,本文件已在其中
// (build_selfhost_native.py 的 corelsp_files);「corelsp 不受影响」的旧半句已不成立。
-fn grow_type_terms(needed: int) {
- if needed < g_type_term_cap { return; }
- nc : ., mut = g_type_term_cap * 2;
- if nc < 256 { nc = 256; }
- if nc < needed { nc = needed + 64; }
- nb := alloc(nc * ESZ_TYPE_TERM);
- _dyncpy(g_type_terms, g_type_term_cap * ESZ_TYPE_TERM, nb);
- g_type_terms = nb;
- g_type_term_cap = nc;
-}
-
-fn grow_tt_index(needed: int) {
+fn grow_type_terms(needed: int):
+ if needed < g_type_term_cap:
+ return
+ nc : ., mut = g_type_term_cap * 2
+ if nc < 256:
+ nc = 256
+ if nc < needed:
+ nc = needed + 64
+ nb := alloc(nc * ESZ_TYPE_TERM)
+ _dyncpy(g_type_terms, g_type_term_cap * ESZ_TYPE_TERM, nb)
+ g_type_terms = nb
+ g_type_term_cap = nc
+
+fn grow_tt_index(needed: int):
// 开放寻址索引:容量取 2 的幂、**≥ 2×现有项数**(重建式扩容,见 tt_reindex)。
// 「≥ 2×项数」不是可选项:tt_reindex 的重放插入**没有**装填因子守卫,若新表按
// needed 定得过小(如调用方传 2、而现有项已 >512),重放时探测永不落空 = 死循环
// (P0 自测守门用例实证:`g_tt_index_cap = 0; grow_tt_index(2)` 直接挂死)。
- if needed < g_tt_index_cap { return; }
- nc : ., mut = 1024;
- need2 : ., mut = needed;
- if (g_type_term_count + 1) * 2 > need2 { need2 = (g_type_term_count + 1) * 2; }
- loop { if nc >= need2 { break; } nc = nc * 2; }
- nb := alloc(nc * 8);
- i : ., mut = 0;
- loop { if i >= nc { break; } w64(nb, i * 8, -1); i = i + 1; }
- g_tt_index = nb;
- g_tt_index_cap = nc;
- g_tt_index_count = 0;
- tt_reindex();
-}
+ if needed < g_tt_index_cap:
+ return
+ nc : ., mut = 1024
+ need2 : ., mut = needed
+ if (g_type_term_count + 1) * 2 > need2:
+ need2 = (g_type_term_count + 1) * 2
+ loop:
+ if nc >= need2:
+ break
+ nc = nc * 2
+ nb := alloc(nc * 8)
+ i : ., mut = 0
+ loop:
+ if i >= nc:
+ break
+ w64(nb, i * 8, -1)
+ i = i + 1
+ g_tt_index = nb
+ g_tt_index_cap = nc
+ g_tt_index_count = 0
+ tt_reindex()
// ─── 索引重建(grow_tt_index 扩容后调用:清表 + 重放全部项的开放寻址插入)───
-fn tt_reindex() {
- i : ., mut = 0;
- loop {
- if i >= g_type_term_count { break; }
- h := r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_HASH);
- cap := g_tt_index_cap;
- p : ., mut = tt_mod(h, cap);
- loop {
- if r64(g_tt_index, p * 8) < 0 { break; }
- p = p + 1; if p >= cap { p = 0; }
- }
- w64(g_tt_index, p * 8, i);
- g_tt_index_count = g_tt_index_count + 1;
- i = i + 1;
- }
-}
+fn tt_reindex():
+ i : ., mut = 0
+ loop:
+ if i >= g_type_term_count:
+ break
+ h := r64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_HASH)
+ cap := g_tt_index_cap
+ p : ., mut = tt_mod(h, cap)
+ loop:
+ if r64(g_tt_index, p * 8) < 0:
+ break
+ p = p + 1
+ if p >= cap:
+ p = 0
+ w64(g_tt_index, p * 8, i)
+ g_tt_index_count = g_tt_index_count + 1
+ i = i + 1
// ─── 项层复位(R2 P4 Task 2:D13 确定性装填 与 loader 重建 的共点)───
// 计数/索引/惰性 memo 全清:g_tt_index_cap = 0 ⇒ 下一次 tt_term 触发
@@ -153,270 +189,311 @@ fn tt_reindex() {
// → return` 早退,只清 ok 位会复用旧表,照该函数 N1 修复注记)+ 字面缓冲计数)。
// 调用方(ccr_types.cr 装填 / ccr_io.cr loader)另须复位桥接面
// (sh_map_reset/sh_unf_map_reset,corec 侧)——陈旧 ti→term 缓存持有旧行号语义。
-fn tt_layer_reset() {
- g_type_term_count = 0;
- g_tt_index_cap = 0;
- g_tt_index_count = 0;
- g_tt_top_ok = 0;
- g_tt_nil_ok = 0;
- tt_budget_state_reset();
- g_ty_memo_ok = 0;
- g_ty_memo_cap = 0;
- g_ty_lits_count = 0;
-}
+fn tt_layer_reset():
+ g_type_term_count = 0
+ g_tt_index_cap = 0
+ g_tt_index_count = 0
+ g_tt_top_ok = 0
+ g_tt_nil_ok = 0
+ tt_budget_state_reset()
+ g_ty_memo_ok = 0
+ g_ty_memo_cap = 0
+ g_ty_lits_count = 0
// 预算/未覆盖位复位(**不动项表**):--dump-types 的 probe 在表已载入后跑项层
// 原语(tt_norm——规范化计步),两侧(写侧进程/读侧进程)须从同一计数起点出发
// 才能对拍消耗与结果。
-fn tt_budget_state_reset() {
- g_ty_steps = 0;
- g_ty_budget_max = 200000;
- g_ty_exhausted = 0;
- g_ty_uncovered = 0;
-}
+fn tt_budget_state_reset():
+ g_ty_steps = 0
+ g_ty_budget_max = 200000
+ g_ty_exhausted = 0
+ g_ty_uncovered = 0
// 同构比较(五字段全比——DAG 键;哈希相同与否不参与,见 tt_term 内注记)
-fn tt_same(i: int, j: int) -> int {
- if tt_tag(i) != tt_tag(j) { return 0; }
- if tt_a(i) != tt_a(j) { return 0; }
- if tt_b(i) != tt_b(j) { return 0; }
- if tt_c(i) != tt_c(j) { return 0; }
- if tt_d(i) != tt_d(j) { return 0; }
- return 1;
-}
+fn tt_same(i: int, j: int) -> int:
+ if tt_tag(i) != tt_tag(j):
+ return 0
+ if tt_a(i) != tt_a(j):
+ return 0
+ if tt_b(i) != tt_b(j):
+ return 0
+ if tt_c(i) != tt_c(j):
+ return 0
+ if tt_d(i) != tt_d(j):
+ return 0
+ return 1
// ─── 构造/复用(DAG 去重的唯一入口)───
-fn tt_term(tag: int, a: int, b: int, c: int, d: int) -> int {
- if g_tt_index_cap <= 0 { grow_tt_index(2); }
- h := tt_hash5(tag, a, b, c, d);
- ret : ., mut = -1;
- loop {
+fn tt_term(tag: int, a: int, b: int, c: int, d: int) -> int:
+ if g_tt_index_cap <= 0:
+ grow_tt_index(2)
+ h := tt_hash5(tag, a, b, c, d)
+ ret : ., mut = -1
+ loop:
// 装填因子守卫:探测前扩容(扩容 = 重建索引,故探测位置不会中途失配);
// 扩容后重试同一轮(loop 而非递归——避免深递归与重复增长)。
- if (g_type_term_count + 1) * 2 >= g_tt_index_cap { grow_tt_index((g_type_term_count + 1) * 2); }
- cap := g_tt_index_cap;
- p : ., mut = tt_mod(h, cap);
- loop {
- idx := r64(g_tt_index, p * 8);
- if idx < 0 { break; }
+ if (g_type_term_count + 1) * 2 >= g_tt_index_cap:
+ grow_tt_index((g_type_term_count + 1) * 2)
+ cap := g_tt_index_cap
+ p : ., mut = tt_mod(h, cap)
+ loop:
+ idx := r64(g_tt_index, p * 8)
+ if idx < 0:
+ break
// 键比较 = 五字段全比(DAG 键);**不**把「存储哈希 == 重算哈希」并入键:
// 该等式只在 i64 回绕语义下恒真(x86-64 后端成立),而 bootstrap 解释器
// 为任意精度整数(interpreter.py 二元运算无回绕)——重算 h 不回绕、落盘
// 哈希经 w64/r64 截断到 i64,等式恒假 → 去重静默退化为「只插不查」。
// 哈希在本层的唯一职责 = 槽位定位(插入与 tt_reindex 重放同用),
// 故键只认五字段;碰撞(含上述截断差)仅令探测链变长,不改变结果。
- if tt_tag(idx) == tag && tt_a(idx) == a && tt_b(idx) == b &&
- tt_c(idx) == c && tt_d(idx) == d { ret = idx; break; }
- p = p + 1; if p >= cap { p = 0; }
- }
- if ret >= 0 { break; }
+ if tt_tag(idx) == tag && tt_a(idx) == a && tt_b(idx) == b && tt_c(idx) == c && tt_d(idx) == d:
+ ret = idx
+ break
+ p = p + 1
+ if p >= cap:
+ p = 0
+ if ret >= 0:
+ break
// 未命中:追加新项,写入本轮探测到的空槽(轮内索引未被改动)
- grow_type_terms(g_type_term_count + 1);
- i := g_type_term_count;
- w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_TAG, tag);
- w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_A, a);
- w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_B, b);
- w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_C, c);
- w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_D, d);
- w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_HASH, h);
- g_type_term_count = i + 1;
- w64(g_tt_index, p * 8, i);
- g_tt_index_count = g_tt_index_count + 1;
- ret = i;
- break;
- }
- return ret;
-}
+ grow_type_terms(g_type_term_count + 1)
+ i := g_type_term_count
+ w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_TAG, tag)
+ w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_A, a)
+ w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_B, b)
+ w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_C, c)
+ w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_D, d)
+ w64(g_type_terms, i * ESZ_TYPE_TERM + OFF_TT_HASH, h)
+ g_type_term_count = i + 1
+ w64(g_tt_index, p * 8, i)
+ g_tt_index_count = g_tt_index_count + 1
+ ret = i
+ break
+ return ret
// ─── 构造 API ───
// 惰性 memo:0 = 未建 + ready 位(零初值惯例——全局 `= -1` 初值在 bootstrap
// 后端会被降级为 0,见 globals.cr 声明段注记)
-fn tt_bot() -> int { return tt_term(TT_BOT, 0, 0, 0, 0); }
-
-fn tt_top() -> int {
- if g_tt_top_ok == 0 { g_tt_top = tt_term(TT_TOP, 0, 0, 0, 0); g_tt_top_ok = 1; }
- return g_tt_top;
-}
-
-fn tt_top_k(k: int) -> int { return tt_term(TT_TOP_K, k, 0, 0, 0); }
-
-fn tt_union(a: int, b: int) -> int {
- if a == b { return a; }
- if tt_tag(a) == TT_BOT { return b; }
- if tt_tag(b) == TT_BOT { return a; }
- if tt_tag(a) == TT_TOP || tt_tag(b) == TT_TOP { return tt_top(); }
- return tt_term(TT_UNION, a, b, 0, 0);
-}
-
-fn tt_inter(a: int, b: int) -> int {
- if a == b { return a; }
- if tt_tag(a) == TT_TOP { return b; }
- if tt_tag(b) == TT_TOP { return a; }
- if tt_tag(a) == TT_BOT || tt_tag(b) == TT_BOT { return tt_bot(); }
- return tt_term(TT_INTER, a, b, 0, 0);
-}
-
-fn tt_not(a: int) -> int {
- if tt_tag(a) == TT_BOT { return tt_top(); }
- if tt_tag(a) == TT_TOP { return tt_bot(); }
- if tt_tag(a) == TT_NOT { return tt_a(a); } // 双重否定免费(构造面代数律)
- return tt_term(TT_NOT, a, 0, 0, 0);
-}
-
-fn tt_mu(v: int, body: int) -> int { return tt_term(TT_MU, v, body, 0, 0); }
-fn tt_var(v: int) -> int { return tt_term(TT_VAR, v, 0, 0, 0); }
-
-fn tt_nil() -> int {
- if g_tt_nil_ok == 0 { g_tt_nil = tt_term(TT_NIL, 0, 0, 0, 0); g_tt_nil_ok = 1; }
- return g_tt_nil;
-}
-
-fn tt_cons(head: int, tail: int) -> int { return tt_term(TT_CONS, head, tail, 0, 0); }
-fn tt_atom(ak: int, ti: int, params: int) -> int { return tt_term(TT_ATOM, ak, ti, params, 0); }
+fn tt_bot() -> int:
+ return tt_term(TT_BOT, 0, 0, 0, 0)
+
+fn tt_top() -> int:
+ if g_tt_top_ok == 0:
+ g_tt_top = tt_term(TT_TOP, 0, 0, 0, 0)
+ g_tt_top_ok = 1
+ return g_tt_top
+
+fn tt_top_k(k: int) -> int:
+ return tt_term(TT_TOP_K, k, 0, 0, 0)
+
+fn tt_union(a: int, b: int) -> int:
+ if a == b:
+ return a
+ if tt_tag(a) == TT_BOT:
+ return b
+ if tt_tag(b) == TT_BOT:
+ return a
+ if tt_tag(a) == TT_TOP || tt_tag(b) == TT_TOP:
+ return tt_top()
+ return tt_term(TT_UNION, a, b, 0, 0)
+
+fn tt_inter(a: int, b: int) -> int:
+ if a == b:
+ return a
+ if tt_tag(a) == TT_TOP:
+ return b
+ if tt_tag(b) == TT_TOP:
+ return a
+ if tt_tag(a) == TT_BOT || tt_tag(b) == TT_BOT:
+ return tt_bot()
+ return tt_term(TT_INTER, a, b, 0, 0)
+
+fn tt_not(a: int) -> int:
+ if tt_tag(a) == TT_BOT:
+ return tt_top()
+ if tt_tag(a) == TT_TOP:
+ return tt_bot()
+ if tt_tag(a) == TT_NOT:
+ return tt_a(a)
+ // 双重否定免费(构造面代数律)
+ return tt_term(TT_NOT, a, 0, 0, 0)
+
+fn tt_mu(v: int, body: int) -> int:
+ return tt_term(TT_MU, v, body, 0, 0)
+fn tt_var(v: int) -> int:
+ return tt_term(TT_VAR, v, 0, 0, 0)
+
+fn tt_nil() -> int:
+ if g_tt_nil_ok == 0:
+ g_tt_nil = tt_term(TT_NIL, 0, 0, 0, 0)
+ g_tt_nil_ok = 1
+ return g_tt_nil
+
+fn tt_cons(head: int, tail: int) -> int:
+ return tt_term(TT_CONS, head, tail, 0, 0)
+fn tt_atom(ak: int, ti: int, params: int) -> int:
+ return tt_term(TT_ATOM, ak, ti, params, 0)
// ─── NNF(否定下推)与 DNF 规范化(R2 P0 Task 2)───
// 语义(spec §1.3):规范化输出 = DNF(union of products;product = 字面集合)。
// 本层只做「形态规整」——语义判定(覆盖/等价/可空/反例)在 type_engine.cr。
// 参数链逐元素 NNF(ATOM 的 params = CONS 链;-1 = 无参)
-fn tt_nnf_list(p: int) -> int {
- if p < 0 { return -1; }
- if tt_tag(p) != TT_CONS { return tt_nnf(p); }
- return tt_cons(tt_nnf(tt_a(p)), tt_nnf_list(tt_b(p)));
-}
+fn tt_nnf_list(p: int) -> int:
+ if p < 0:
+ return -1
+ if tt_tag(p) != TT_CONS:
+ return tt_nnf(p)
+ return tt_cons(tt_nnf(tt_a(p)), tt_nnf_list(tt_b(p)))
// 正位置 NNF:结构不变,否定下推(¬(∪) → ∩(¬)、¬(∩) → ∪(¬)、¬¬ 消,均在负位置函数里)
-fn tt_nnf(i: int) -> int {
- t := tt_tag(i);
- if t == TT_NOT { return tt_nnf_neg(tt_a(i)); }
- if t == TT_UNION { return tt_union(tt_nnf(tt_a(i)), tt_nnf(tt_b(i))); }
- if t == TT_INTER { return tt_inter(tt_nnf(tt_a(i)), tt_nnf(tt_b(i))); }
- if t == TT_MU { return tt_mu(tt_a(i), tt_nnf(tt_b(i))); }
- if t == TT_ATOM { return tt_atom(tt_a(i), tt_b(i), tt_nnf_list(tt_c(i))); }
- if t == TT_CONS { return tt_nnf_list(i); }
- return i; // ⊥ / ⊤ / ⊤ₖ / VAR / NIL:字面,原样
-}
+fn tt_nnf(i: int) -> int:
+ t := tt_tag(i)
+ if t == TT_NOT:
+ return tt_nnf_neg(tt_a(i))
+ if t == TT_UNION:
+ return tt_union(tt_nnf(tt_a(i)), tt_nnf(tt_b(i)))
+ if t == TT_INTER:
+ return tt_inter(tt_nnf(tt_a(i)), tt_nnf(tt_b(i)))
+ if t == TT_MU:
+ return tt_mu(tt_a(i), tt_nnf(tt_b(i)))
+ if t == TT_ATOM:
+ return tt_atom(tt_a(i), tt_b(i), tt_nnf_list(tt_c(i)))
+ if t == TT_CONS:
+ return tt_nnf_list(i)
+ return i // ⊥ / ⊤ / ⊤ₖ / VAR / NIL:字面,原样
// 负位置 NNF:计算 ¬i 的 NNF
-fn tt_nnf_neg(i: int) -> int {
- t := tt_tag(i);
- if t == TT_BOT { return tt_top(); }
- if t == TT_TOP { return tt_bot(); }
- if t == TT_NOT { return tt_nnf(tt_a(i)); } // ¬¬i = i
- if t == TT_UNION { return tt_inter(tt_nnf_neg(tt_a(i)), tt_nnf_neg(tt_b(i))); }
- if t == TT_INTER { return tt_union(tt_nnf_neg(tt_a(i)), tt_nnf_neg(tt_b(i))); }
- if t == TT_MU {
+fn tt_nnf_neg(i: int) -> int:
+ t := tt_tag(i)
+ if t == TT_BOT:
+ return tt_top()
+ if t == TT_TOP:
+ return tt_bot()
+ if t == TT_NOT:
+ return tt_nnf(tt_a(i))
+ // ¬¬i = i
+ if t == TT_UNION:
+ return tt_inter(tt_nnf_neg(tt_a(i)), tt_nnf_neg(tt_b(i)))
+ if t == TT_INTER:
+ return tt_union(tt_nnf_neg(tt_a(i)), tt_nnf_neg(tt_b(i)))
+ if t == TT_MU:
// ¬μX.F ≠ μX.¬F(后者需要 ν 绑定)——**不静默做非等价改写**(P0 终审 Important D):
// 保留 ¬(μ…) 为字面(tt_is_literal 接受)+ 登记未覆盖面;判定侧走保守路径(不覆盖)
- g_ty_uncovered = 1;
- return tt_not(i);
- }
- return tt_not(i); // 字面取反:¬ATOM / ¬VAR / ¬⊤ₖ
-}
+ g_ty_uncovered = 1
+ return tt_not(i)
+ return tt_not(i) // 字面取反:¬ATOM / ¬VAR / ¬⊤ₖ
// 参数链逐元素 DNF(参数内的分配律同样要做)
-fn tt_dnf_list(p: int) -> int {
- if p < 0 { return -1; }
- if tt_tag(p) != TT_CONS { return tt_dnf(p); }
- return tt_cons(tt_dnf(tt_a(p)), tt_dnf_list(tt_b(p)));
-}
+fn tt_dnf_list(p: int) -> int:
+ if p < 0:
+ return -1
+ if tt_tag(p) != TT_CONS:
+ return tt_dnf(p)
+ return tt_cons(tt_dnf(tt_a(p)), tt_dnf_list(tt_b(p)))
// DNF:∩ 分配到 ∪ 上((A∪B)∩C → (A∩C)∪(B∩C));叶子 = product(∩-链)或字面
// 全程计预算;-1 = 预算耗尽(上抛,不得当 0/形态用)
-fn tt_dnf(i: int) -> int {
- if tt_step() == -1 { return -1; }
- t := tt_tag(i);
- if t == TT_UNION {
- a1 := tt_dnf(tt_a(i));
- if a1 < 0 { return -1; }
- b1 := tt_dnf(tt_b(i));
- if b1 < 0 { return -1; }
- return tt_union(a1, b1);
- }
- if t == TT_INTER {
- l := tt_dnf(tt_a(i));
- if l < 0 { return -1; }
- r := tt_dnf(tt_b(i));
- if r < 0 { return -1; }
+fn tt_dnf(i: int) -> int:
+ if tt_step() == -1:
+ return -1
+ t := tt_tag(i)
+ if t == TT_UNION:
+ a1 := tt_dnf(tt_a(i))
+ if a1 < 0:
+ return -1
+ b1 := tt_dnf(tt_b(i))
+ if b1 < 0:
+ return -1
+ return tt_union(a1, b1)
+ if t == TT_INTER:
+ l := tt_dnf(tt_a(i))
+ if l < 0:
+ return -1
+ r := tt_dnf(tt_b(i))
+ if r < 0:
+ return -1
// 分配律必须**两支都展开**:(A∪B)∩C → (A∩C) ∪ (B∩C)。
// 只展开一支 = 静默丢项(P0 Task 2 自测实证:norm.distributed got INTER want UNION
// ——计划骨架同样写错,本实现已修)。
- if tt_tag(l) == TT_UNION {
- x := tt_dnf(tt_inter(tt_a(l), r));
- if x < 0 { return -1; }
- y := tt_dnf(tt_inter(tt_b(l), r));
- if y < 0 { return -1; }
- return tt_union(x, y);
- }
- if tt_tag(r) == TT_UNION {
- x := tt_dnf(tt_inter(l, tt_a(r)));
- if x < 0 { return -1; }
- y := tt_dnf(tt_inter(l, tt_b(r)));
- if y < 0 { return -1; }
- return tt_union(x, y);
- }
- return tt_inter(l, r);
- }
- if t == TT_MU {
- b1 := tt_dnf(tt_b(i));
- if b1 < 0 { return -1; }
- return tt_mu(tt_a(i), b1);
- }
- if t == TT_ATOM { return tt_atom(tt_a(i), tt_b(i), tt_dnf_list(tt_c(i))); }
- return i;
-}
+ if tt_tag(l) == TT_UNION:
+ x := tt_dnf(tt_inter(tt_a(l), r))
+ if x < 0:
+ return -1
+ y := tt_dnf(tt_inter(tt_b(l), r))
+ if y < 0:
+ return -1
+ return tt_union(x, y)
+ if tt_tag(r) == TT_UNION:
+ x := tt_dnf(tt_inter(l, tt_a(r)))
+ if x < 0:
+ return -1
+ y := tt_dnf(tt_inter(l, tt_b(r)))
+ if y < 0:
+ return -1
+ return tt_union(x, y)
+ return tt_inter(l, r)
+ if t == TT_MU:
+ b1 := tt_dnf(tt_b(i))
+ if b1 < 0:
+ return -1
+ return tt_mu(tt_a(i), b1)
+ if t == TT_ATOM:
+ return tt_atom(tt_a(i), tt_b(i), tt_dnf_list(tt_c(i)))
+ return i
// 预算步进(**规范化也计入**——P0 终审 Important C 实证:∩ 分配律在 n 元联合下
// 词项数 2^n 爆炸(n=16 → 29 万项)而 exhausted 恒 0,预算形同虚设)。
-fn tt_step() -> int {
- if g_ty_budget_max <= 0 { g_ty_budget_max = 200000; }
- g_ty_steps = g_ty_steps + 1;
- if g_ty_steps > g_ty_budget_max { g_ty_exhausted = 1; return -1; }
- return 0;
-}
+fn tt_step() -> int:
+ if g_ty_budget_max <= 0:
+ g_ty_budget_max = 200000
+ g_ty_steps = g_ty_steps + 1
+ if g_ty_steps > g_ty_budget_max:
+ g_ty_exhausted = 1
+ return -1
+ return 0
// 规范化入口(NNF → DNF;DAG 去重使「同形同项」免费)——-1 = 预算耗尽(调用方必须上抛)
-fn tt_norm(i: int) -> int {
- n := tt_nnf(i);
- if n < 0 { return -1; }
- return tt_dnf(n);
-}
+fn tt_norm(i: int) -> int:
+ n := tt_nnf(i)
+ if n < 0:
+ return -1
+ return tt_dnf(n)
// ─── 形态判定(自测断言与引擎前置检查共用)───
-fn tt_is_literal(i: int) -> int {
- t := tt_tag(i);
- if t == TT_ATOM || t == TT_VAR || t == TT_TOP_K || t == TT_BOT || t == TT_TOP { return 1; }
- if t == TT_NOT {
- it := tt_tag(tt_a(i));
+fn tt_is_literal(i: int) -> int:
+ t := tt_tag(i)
+ if t == TT_ATOM || t == TT_VAR || t == TT_TOP_K || t == TT_BOT || t == TT_TOP:
+ return 1
+ if t == TT_NOT:
+ it := tt_tag(tt_a(i))
// NOT(MU) 亦为字面:¬μ 不下推动(见 tt_nnf_neg 的 MU 分支)
- if it == TT_ATOM || it == TT_VAR || it == TT_TOP_K || it == TT_MU { return 1; }
- }
- return 0;
-}
-
-fn tt_is_product_chain(i: int) -> int {
- if tt_tag(i) == TT_INTER {
- if tt_tag(tt_a(i)) == TT_UNION || tt_tag(tt_b(i)) == TT_UNION { return 0; }
- if tt_is_product_chain(tt_a(i)) == 0 { return 0; }
- return tt_is_product_chain(tt_b(i));
- }
- return tt_is_literal(i);
-}
+ if it == TT_ATOM || it == TT_VAR || it == TT_TOP_K || it == TT_MU:
+ return 1
+ return 0
+
+fn tt_is_product_chain(i: int) -> int:
+ if tt_tag(i) == TT_INTER:
+ if tt_tag(tt_a(i)) == TT_UNION || tt_tag(tt_b(i)) == TT_UNION:
+ return 0
+ if tt_is_product_chain(tt_a(i)) == 0:
+ return 0
+ return tt_is_product_chain(tt_b(i))
+ return tt_is_literal(i)
// DNF 成员:union 的子项 = product 或字面(不得再嵌 union)
-fn tt_is_dnf_member(i: int) -> int {
- if tt_tag(i) == TT_UNION { return 0; }
- if tt_tag(i) == TT_INTER { return tt_is_product_chain(i); }
- return tt_is_literal(i);
-}
-
-fn tt_is_dnf(i: int) -> int {
+fn tt_is_dnf_member(i: int) -> int:
+ if tt_tag(i) == TT_UNION:
+ return 0
+ if tt_tag(i) == TT_INTER:
+ return tt_is_product_chain(i)
+ return tt_is_literal(i)
+
+fn tt_is_dnf(i: int) -> int:
// union 是**左深嵌套**(tt_union 不扁平化)→ 必须递归接受 n 元析取:
// 早期版本对子项调 tt_is_dnf_member(要求子项非 union)→ ≥3 析取的合法 DNF 被误判 0
// (P0 终审 Important A 实证:(A|B)∩(C|D) 规范化为 4 析取 → 判 0)。
- if tt_tag(i) == TT_UNION {
- if tt_is_dnf(tt_a(i)) == 0 { return 0; }
- return tt_is_dnf(tt_b(i));
- }
- return tt_is_dnf_member(i);
-}
+ if tt_tag(i) == TT_UNION:
+ if tt_is_dnf(tt_a(i)) == 0:
+ return 0
+ return tt_is_dnf(tt_b(i))
+ return tt_is_dnf_member(i)
diff --git a/src/format/elf/elf.cr b/src/format/elf/elf.cr
index 5c16da85..44353580 100644
--- a/src/format/elf/elf.cr
+++ b/src/format/elf/elf.cr
@@ -9,523 +9,934 @@
// Depends on: backend/resolve.cr (res_labels)
// ── ELF constants (x86-64) ──
-ET_EXEC : int = 2;
-EM_X86_64 : int = 62;
-PT_LOAD : int = 1;
-PF_RX : int = 5;
-PF_RW : int = 6;
+ET_EXEC : int = 2
+EM_X86_64 : int = 62
+PT_LOAD : int = 1
+PF_RX : int = 5
+PF_RW : int = 6
// Avoid the name r16: Intel syntax parses `call r16` as a register operand.
-fn read_u16(buf: string, pos: int) -> int { return bu8(buf,pos) + bu8(buf,pos+1)*256; }
+fn read_u16(buf: string, pos: int) -> int:
+ return bu8(buf,pos) + bu8(buf,pos+1)*256
-TEXT_BASE : int = 4194304; // 0x400000 - base address of code segment
+TEXT_BASE : int = 4194304 // 0x400000 - base address of code segment
-fn w8_signed(buf: string, pos: int, val: int) {
- w32(buf, pos, val);
-}
+fn w8_signed(buf: string, pos: int, val: int):
+ w32(buf, pos, val)
// Emit arena-aware dual-path allocator function body
// Checks g_current_arena: if >=0 uses arena bump, otherwise global bump.
// Returns bytes written.
-fn emit_alloc_body(buf: string, pos: int, bss_va: int, globals_size: int) -> int {
+fn emit_alloc_body(buf: string, pos: int, bss_va: int, globals_size: int) -> int:
// When arena globals aren't registered (e.g. non-static builds), emit the
// original simple bump allocator to avoid relying on unpatched rip-relatives.
- if gv_current_arena < 0 { return emit_alloc_body_simple(buf, pos, bss_va, globals_size); }
+ if gv_current_arena < 0:
+ return emit_alloc_body_simple(buf, pos, bss_va, globals_size)
- cp := 0;
- fva := TEXT_BASE + pos;
+ cp := 0
+ fva := TEXT_BASE + pos
// ── Part 0: 64MB sanity check (12 bytes) ──
// cmp rdi, 67108864
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 129); w8(buf, pos+cp+2, 255);
- e2_w32(buf, pos+cp+3, 67108864); cp = cp + 7;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 129)
+ w8(buf, pos+cp+2, 255)
+ e2_w32(buf, pos+cp+3, 67108864)
+ cp = cp + 7
// jbe +3
- w8(buf, pos+cp, 118); w8(buf, pos+cp+1, 3); cp = cp + 2;
+ w8(buf, pos+cp, 118)
+ w8(buf, pos+cp+1, 3)
+ cp = cp + 2
// xor eax, eax; ret
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 192); cp = cp + 2;
- w8(buf, pos+cp, 195); cp = cp + 1;
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 192)
+ cp = cp + 2
+ w8(buf, pos+cp, 195)
+ cp = cp + 1
// ── Part 1: Save original size + check arena (53 bytes) ──
// mov r9, rdi — 49 89 F9
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 249); cp = cp + 3;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 249)
+ cp = cp + 3
// lea r10, [rip + g_current_arena] — 4C 8D 15 (dest r10, not r8!)
- rip_pos_ca := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 21);
- e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos_ca);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_current_arena);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos_ca := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 21)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos_ca)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_current_arena)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov r10, [r10] — 4D 8B 12 (modrm 0x12: reg=010+R -> r10, rm=010+B -> [r10];
// old 0x10 had rm=100 which consumed a SIB byte and desynced the stream)
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 18); cp = cp + 3;
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 18)
+ cp = cp + 3
// test r10, r10 — 4D 85 D2
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 133); w8(buf, pos+cp+2, 210); cp = cp + 3;
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 133)
+ w8(buf, pos+cp+2, 210)
+ cp = cp + 3
// jl .Lglobal (no active arena → global bump path) — 0F 8C rel32, patched at Part 8
- g_alloc_gl_jmp_pos = pos + cp;
- w8(buf, pos+cp, 15); w8(buf, pos+cp+1, 140); e2_w32(buf, pos+cp+2, 0); cp = cp + 6;
+ g_alloc_gl_jmp_pos = pos + cp
+ w8(buf, pos+cp, 15)
+ w8(buf, pos+cp+1, 140)
+ e2_w32(buf, pos+cp+2, 0)
+ cp = cp + 6
// ── Compute chunk_start BEFORE loading the cursors pointer ──
// mul r10 clobbers rdx:rax — if rdx already held the cursors pointer
// (loaded below), the commit at Part 5 would write to garbage. Order matters.
// lea r11, [rip + g_arena_pool_data] — e2_lrb, rip_patch
- rip_pos3 := pos + cp + 3;
- cp = cp + e2_lrb(buf, pos + cp, 0);
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos3);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_pool_data);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos3 := pos + cp + 3
+ cp = cp + e2_lrb(buf, pos + cp, 0)
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos3)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_pool_data)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov r11, [r11] — 4D 8B 1B
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 27); cp = cp + 3;
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 27)
+ cp = cp + 3
// lea rax, [rip + g_arena_max_size] — 48 8D 05 xx xx xx xx, rip_patch
- rip_pos4 := pos + cp + 3;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 5);
- e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos4);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_max_size);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos4 := pos + cp + 3
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 5)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos4)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_max_size)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov rax, [rax] — 48 8B 00 (load g_arena_max_size value)
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 0); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 0)
+ cp = cp + 3
// mul r10 — 49 F7 E2 (rax = g_arena_max_size * ai)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 247); w8(buf, pos+cp+2, 226); cp = cp + 3;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 247)
+ w8(buf, pos+cp+2, 226)
+ cp = cp + 3
// add r11, rax — 49 01 C3 (r11 = pool_base + offset = chunk_start)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 1); w8(buf, pos+cp+2, 195); cp = cp + 3;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 1)
+ w8(buf, pos+cp+2, 195)
+ cp = cp + 3
// ── Load cursors + sizes (rdx must not be clobbered after this) ──
// NB: r11 MUST keep chunk_start (pool_data + max_size*ai) — Part 5b/6
// depend on it. Load the cursors array into rdx directly.
// lea rdx, [rip + g_arena_cursors] — 48 8D 15, rip_patch
- rip_pos1 := pos + cp + 3;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 21); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos1);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_cursors);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos1 := pos + cp + 3
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 21)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos1)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_cursors)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov rdx, [rdx] — 48 8B 12
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 18); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 18)
+ cp = cp + 3
// mov rcx, [rdx + r10*8] — 4A 8B 0C D2 (SIB: scale=3, index=r10, base=rdx)
- w8(buf, pos+cp, 74); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 12); w8(buf, pos+cp+3, 210); cp = cp + 4;
+ w8(buf, pos+cp, 74)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 12)
+ w8(buf, pos+cp+3, 210)
+ cp = cp + 4
// lea rsi, [rip + g_arena_sizes] — preserve r11 as chunk_start
- rip_pos2 := pos + cp + 3;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 53); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos2);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_sizes);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos2 := pos + cp + 3
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 53)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos2)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_sizes)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov rsi, [rsi] — 48 8B 36
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 54); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 54)
+ cp = cp + 3
// mov r8, [rsi + r10*8] — 4E 8B 04 D6
- w8(buf, pos+cp, 78); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 4); w8(buf, pos+cp+3, 214); cp = cp + 4;
+ w8(buf, pos+cp, 78)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 4)
+ w8(buf, pos+cp+3, 214)
+ cp = cp + 4
// ── Part 4: Align size + bump check (22 bytes) ──
// mov rdi, r9 — 49 8B F9 (restore original size for alignment)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 249); cp = cp + 3;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 249)
+ cp = cp + 3
// add rdi, 15 — 48 83 C7 0F
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 131); w8(buf, pos+cp+2, 199); w8(buf, pos+cp+3, 15); cp = cp + 4;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 131)
+ w8(buf, pos+cp+2, 199)
+ w8(buf, pos+cp+3, 15)
+ cp = cp + 4
// and rdi, -8 — 48 83 E7 F8
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 131); w8(buf, pos+cp+2, 231); w8(buf, pos+cp+3, 248); cp = cp + 4;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 131)
+ w8(buf, pos+cp+2, 231)
+ w8(buf, pos+cp+3, 248)
+ cp = cp + 4
// mov rax, rcx — 48 89 C8 (rax = old_cursor)
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 200); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 200)
+ cp = cp + 3
// add rcx, rdi — 48 01 F9 (rcx = new_cursor)
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 1); w8(buf, pos+cp+2, 249); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 1)
+ w8(buf, pos+cp+2, 249)
+ cp = cp + 3
// cmp rcx, r8 — 4C 39 C1
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 57); w8(buf, pos+cp+2, 193); cp = cp + 3;
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 57)
+ w8(buf, pos+cp+2, 193)
+ cp = cp + 3
// ja .Lchain — 77 22 (rel8=34)
- w8(buf, pos+cp, 119); w8(buf, pos+cp+1, 34); cp = cp + 2;
+ w8(buf, pos+cp, 119)
+ w8(buf, pos+cp+1, 34)
+ cp = cp + 2
// ── Part 5: Commit cursor update (4 bytes) ──
// mov [rdx + r10*8], rcx — 4A 89 0C D2
- w8(buf, pos+cp, 74); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 12); w8(buf, pos+cp+3, 210); cp = cp + 4;
+ w8(buf, pos+cp, 74)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 12)
+ w8(buf, pos+cp+3, 210)
+ cp = cp + 4
// ── Part 5b: Zero-init newly allocated arena block (18 bytes) ──
// Zero only the newly allocated data bytes.
// rax=old_cursor, r11=chunk_start, rdx=cursors_ptr (no longer needed)
// mov rdx, rax (save old_cursor) — 48 89 C2
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 194); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 194)
+ cp = cp + 3
// lea rdi, [r11 + rax + 8] — allocation data after its header
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 124); w8(buf, pos+cp+3, 3); w8(buf, pos+cp+4, 8); cp = cp + 5;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 124)
+ w8(buf, pos+cp+3, 3)
+ w8(buf, pos+cp+4, 8)
+ cp = cp + 5
// mov rcx, r9 (requested data size) — 4C 89 C9
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 201); cp = cp + 3;
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 201)
+ cp = cp + 3
// xor eax, eax — 31 C0
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 192); cp = cp + 2;
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 192)
+ cp = cp + 2
// cld — FC
- w8(buf, pos+cp, 252); cp = cp + 1;
+ w8(buf, pos+cp, 252)
+ cp = cp + 1
// rep stosb — F3 AA
- w8(buf, pos+cp, 243); w8(buf, pos+cp+1, 170); cp = cp + 2;
+ w8(buf, pos+cp, 243)
+ w8(buf, pos+cp+1, 170)
+ cp = cp + 2
// mov rax, rdx (restore old_cursor) — 48 89 D0
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 208); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 208)
+ cp = cp + 3
// ── Part 6: Return arena pointer (11 bytes) ──
// add rax, r11 — 4C 01 D8 (rax = chunk_start + old_cursor = data ptr before header)
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 1); w8(buf, pos+cp+2, 216); cp = cp + 3;
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 1)
+ w8(buf, pos+cp+2, 216)
+ cp = cp + 3
// mov [rax], r9 — 4C 89 08 (store hidden length header)
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 8); cp = cp + 3;
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 8)
+ cp = cp + 3
// lea rax, [rax + 8] — 48 8D 40 08
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 64); w8(buf, pos+cp+3, 8); cp = cp + 4;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 64)
+ w8(buf, pos+cp+3, 8)
+ cp = cp + 4
// ret
- w8(buf, pos+cp, 195); cp = cp + 1;
+ w8(buf, pos+cp, 195)
+ cp = cp + 1
// ── Part 7: .Lchain — arena OOM → chain expand + mark full (41 bytes) ──
// lea r8, [rip + g_current_arena] — 4C 8D 05 xx xx xx xx, rip_patch #6
- rip_pos5 := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 5);
- e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos5);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_current_arena);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos5 := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 5)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos5)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_current_arena)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov qword [r8], -1 — 49 C7 00 FF FF FF FF (set g_current_arena = -1;
// REX.W+B — a 32-bit store would leave the slot = 0x00000000ffffffff,
// which is positive and re-enters the arena path with a garbage index)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 199); w8(buf, pos+cp+2, 0);
- e2_w32(buf, pos+cp+3, -1); cp = cp + 7;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 199)
+ w8(buf, pos+cp+2, 0)
+ e2_w32(buf, pos+cp+3, -1)
+ cp = cp + 7
// ── Bug 2 fix: Advance arena cursor to limit (mark full) ──
// rdx = cursors array pointer (from Part 2), r10 = arena index (from Part 1)
// Load sizes[ai] again (r8 was overwritten by g_current_arena LEA above)
// lea rsi, [rip + g_arena_sizes] — 48 8D 35 xx xx xx xx, rip_patch #8
- rip_pos_sizes := pos + cp + 3;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 53);
- e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos_sizes);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_sizes);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos_sizes := pos + cp + 3
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 53)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos_sizes)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_arena_sizes)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov rsi, [rsi] — 48 8B 36 (deref to get sizes array pointer)
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 54); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 54)
+ cp = cp + 3
// mov r8, [rsi + r10*8] — 4E 8B 04 D6 (r8 = sizes[ai] = limit)
- w8(buf, pos+cp, 78); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 4); w8(buf, pos+cp+3, 214); cp = cp + 4;
+ w8(buf, pos+cp, 78)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 4)
+ w8(buf, pos+cp+3, 214)
+ cp = cp + 4
// mov [rdx + r10*8], r8 — 4E 89 04 D2 (cursors[ai] = limit, mark full)
- w8(buf, pos+cp, 78); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 4); w8(buf, pos+cp+3, 210); cp = cp + 4;
+ w8(buf, pos+cp, 78)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 4)
+ w8(buf, pos+cp+3, 210)
+ cp = cp + 4
// Set r10d = -1 to skip arena restore at .Lglobal's end — 41 BA FF FF FF FF
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 186); e2_w32(buf, pos+cp+2, -1); cp = cp + 6;
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 186)
+ e2_w32(buf, pos+cp+2, -1)
+ cp = cp + 6
// mov rdi, r9 — 49 8B F9 (restore original size for global path alignment)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 249); cp = cp + 3;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 249)
+ cp = cp + 3
// ── Part 8: .Lglobal — global bump alloc path + arena restore (84 bytes) ──
// Patch Part 1's jl .Lglobal to here
- if g_alloc_gl_jmp_pos >= 0 {
- rel_gl := (pos + cp) - (g_alloc_gl_jmp_pos + 6);
- w32(buf, g_alloc_gl_jmp_pos + 2, rel_gl);
- g_alloc_gl_jmp_pos = -1;
- }
+ if g_alloc_gl_jmp_pos >= 0:
+ rel_gl := (pos + cp) - (g_alloc_gl_jmp_pos + 6)
+ w32(buf, g_alloc_gl_jmp_pos + 2, rel_gl)
+ g_alloc_gl_jmp_pos = -1
// add rdi, 15 — 48 83 C7 0F (align)
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 131); w8(buf, pos+cp+2, 199); w8(buf, pos+cp+3, 15); cp = cp + 4;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 131)
+ w8(buf, pos+cp+2, 199)
+ w8(buf, pos+cp+3, 15)
+ cp = cp + 4
// and rdi, -8 — 48 83 E7 F8
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 131); w8(buf, pos+cp+2, 231); w8(buf, pos+cp+3, 248); cp = cp + 4;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 131)
+ w8(buf, pos+cp+2, 231)
+ w8(buf, pos+cp+3, 248)
+ cp = cp + 4
// mov r11, [rip + g_heap_ptr] — load via rip_patch
- if gv_heap_ptr >= 0 {
- rip_hp0 := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 29); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp0);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel0 := bss_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel0); cp = cp + 7;
- }
+ if gv_heap_ptr >= 0:
+ rip_hp0 := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 29)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp0)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel0 := bss_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel0)
+ cp = cp + 7
// test r11, r11 — 4D 85 DB
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 133); w8(buf, pos+cp+2, 219); cp = cp + 3;
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 133)
+ w8(buf, pos+cp+2, 219)
+ cp = cp + 3
// jne +14 (skip init if already set) — 75 0E
- w8(buf, pos+cp, 117); w8(buf, pos+cp+1, 14); cp = cp + 2;
+ w8(buf, pos+cp, 117)
+ w8(buf, pos+cp+1, 14)
+ cp = cp + 2
// lea r11, [rip + heap_start] (after globals)
// BSS globals area: starts at rip_patch bss_va+16; globals_size covers all slots
- heap_start_va : ., mut = bss_va + 16 + globals_size;
- rel1 := heap_start_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel1); cp = cp + 7;
+ heap_start_va : ., mut = bss_va + 16 + globals_size
+ rel1 := heap_start_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel1)
+ cp = cp + 7
// mov [rip + g_heap_ptr], r11 — store via rip_patch
- if gv_heap_ptr >= 0 {
- rip_hp_s1 := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_s1);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel2 := bss_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel2); cp = cp + 7;
- }
+ if gv_heap_ptr >= 0:
+ rip_hp_s1 := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_s1)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel2 := bss_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel2)
+ cp = cp + 7
// ── OOM bounds check: .Lretry block ──
// Save original heap_ptr, check against heap_end, call heap_expand if OOM.
// retry_cp must start BEFORE mov r8, r11: heap_expand clobbers r8
// (r8d = fd = -1), so the retry has to re-save the (possibly new) heap_ptr.
// mov r8, r11 -- 4D 89 D8 (save original heap_ptr)
- retry_cp := cp;
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 216); cp = cp + 3;
+ retry_cp := cp
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 216)
+ cp = cp + 3
// lea rdx, [r11 + rdi] -- 4A 8D 14 1F (compute new end = r11 + rdi)
// REX 0x4A = W=1, X=1 (index 011 -> r11), B=0 (base 111 -> rdi); modrm reg=010 (rdx).
- w8(buf, pos+cp, 74); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 20); w8(buf, pos+cp+3, 31); cp = cp + 4;
+ w8(buf, pos+cp, 74)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 20)
+ w8(buf, pos+cp+3, 31)
+ cp = cp + 4
// lea rcx, [rip + g_heap_end] — rip_patch for gv_heap_end
- if gv_heap_end >= 0 {
- rip_he := pos + cp + 3;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 13); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_he);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_end);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- heap_end_va : ., mut = bss_va + 8;
- rel_he := heap_end_va - (fva + cp + 7);
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 13); w8_signed(buf, pos+cp+3, rel_he); cp = cp + 7;
- }
+ if gv_heap_end >= 0:
+ rip_he := pos + cp + 3
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 13)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_he)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_end)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ heap_end_va : ., mut = bss_va + 8
+ rel_he := heap_end_va - (fva + cp + 7)
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 13)
+ w8_signed(buf, pos+cp+3, rel_he)
+ cp = cp + 7
// cmp rdx, [rcx] -- 48 3B 11
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 59); w8(buf, pos+cp+2, 17); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 59)
+ w8(buf, pos+cp+2, 17)
+ cp = cp + 3
// jbe +14 (skip call+reload+jmp if within bounds)
- w8(buf, pos+cp, 118); w8(buf, pos+cp+1, 14); cp = cp + 2;
+ w8(buf, pos+cp, 118)
+ w8(buf, pos+cp+1, 14)
+ cp = cp + 2
// call heap_expand -- E8 xx xx xx xx (patched in elf_gen after heap_expand emitted)
- g_heap_expand_call_pos = pos + cp;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5;
+ g_heap_expand_call_pos = pos + cp
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5
// mov r11, [rip + g_heap_ptr] — reload via rip_patch after heap_expand
- if gv_heap_ptr >= 0 {
- rip_hp_rl := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 29); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_rl);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel_hr := bss_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel_hr); cp = cp + 7;
- }
+ if gv_heap_ptr >= 0:
+ rip_hp_rl := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 29)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_rl)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel_hr := bss_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel_hr)
+ cp = cp + 7
// jmp .Lretry -- EB xx (short backwards jump to mov r8, r11)
- jmp_off_val := retry_cp - (cp + 2);
- w8(buf, pos+cp, 235); w8(buf, pos+cp+1, jmp_off_val % 256); cp = cp + 2;
+ jmp_off_val := retry_cp - (cp + 2)
+ w8(buf, pos+cp, 235)
+ w8(buf, pos+cp+1, jmp_off_val % 256)
+ cp = cp + 2
// add r11, rdi -- 49 01 FB (bump r11, only reached when within bounds)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 1); w8(buf, pos+cp+2, 251); cp = cp + 3;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 1)
+ w8(buf, pos+cp+2, 251)
+ cp = cp + 3
// mov [rip + g_heap_ptr], r11 — store via rip_patch
- if gv_heap_ptr >= 0 {
- rip_hp_s2 := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_s2);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel3 := bss_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel3); cp = cp + 7;
- }
+ if gv_heap_ptr >= 0:
+ rip_hp_s2 := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_s2)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel3 := bss_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel3)
+ cp = cp + 7
// mov rdi, r8 — 4C 89 C7
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 199); cp = cp + 3;
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 199)
+ cp = cp + 3
// mov rcx, r11 — 4C 89 D9
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 217); cp = cp + 3;
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 217)
+ cp = cp + 3
// sub rcx, rdi — 48 29 F9
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 41); w8(buf, pos+cp+2, 249); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 41)
+ w8(buf, pos+cp+2, 249)
+ cp = cp + 3
// xor eax, eax — 31 C0
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 192); cp = cp + 2;
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 192)
+ cp = cp + 2
// cld — FC
- w8(buf, pos+cp, 252); cp = cp + 1;
+ w8(buf, pos+cp, 252)
+ cp = cp + 1
// rep stosb — F3 AA
- w8(buf, pos+cp, 243); w8(buf, pos+cp+1, 170); cp = cp + 2;
+ w8(buf, pos+cp, 243)
+ w8(buf, pos+cp+1, 170)
+ cp = cp + 2
// mov [r8], r9 — 4D 89 08 (store header)
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 8); cp = cp + 3;
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 8)
+ cp = cp + 3
// lea rax, [r8+8] — 49 8D 40 08
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 64); w8(buf, pos+cp+3, 8); cp = cp + 4;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 64)
+ w8(buf, pos+cp+3, 8)
+ cp = cp + 4
// ── Arena restore (before ret) ──
// test r10d, r10d — 45 85 D2 (was arena active? r10d ≥ 0 at entry)
- w8(buf, pos+cp, 69); w8(buf, pos+cp+1, 133); w8(buf, pos+cp+2, 210); cp = cp + 3;
+ w8(buf, pos+cp, 69)
+ w8(buf, pos+cp+1, 133)
+ w8(buf, pos+cp+2, 210)
+ cp = cp + 3
// js .Lret (skip restore if r10d < 0, i.e. normal global alloc) — 78 0A
- w8(buf, pos+cp, 120); w8(buf, pos+cp+1, 10); cp = cp + 2;
+ w8(buf, pos+cp, 120)
+ w8(buf, pos+cp+1, 10)
+ cp = cp + 2
// lea r8, [rip + g_current_arena] — 4C 8D 05 xx xx xx xx, rip_patch #7
- rip_pos6 := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 5);
- e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos6);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_current_arena);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos6 := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 5)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos6)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_current_arena)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov [r8], r10d — 45 89 10 (restore arena index: r8 = g_current_arena addr)
// objdump 验证:45 89 10 = mov %r10d,(%r8) ✓;44 89 00 = mov %r8d,(%rax) ✗
- w8(buf, pos+cp, 69); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 16); cp = cp + 3;
+ w8(buf, pos+cp, 69)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 16)
+ cp = cp + 3
// ret
- w8(buf, pos+cp, 195); cp = cp + 1;
+ w8(buf, pos+cp, 195)
+ cp = cp + 1
- return cp;
-}
+ return cp
// ── Simple bump allocator (no arena) — used when gv_current_arena < 0 ──
// Original 84-byte alloc body: no arena check, no rip_patches for arena globals.
// This avoids relying on unpatched RIP-relative addresses for g_current_arena
// when the variable isn't registered in the output binary (non-static builds).
-fn emit_alloc_body_simple(buf: string, pos: int, bss_va: int, globals_size: int) -> int {
- cp := 0;
- fva := TEXT_BASE + pos;
+fn emit_alloc_body_simple(buf: string, pos: int, bss_va: int, globals_size: int) -> int:
+ cp := 0
+ fva := TEXT_BASE + pos
// 64MB sanity check
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 129); w8(buf, pos+cp+2, 255);
- e2_w32(buf, pos+cp+3, 67108864); cp = cp + 7;
- w8(buf, pos+cp, 118); w8(buf, pos+cp+1, 3); cp = cp + 2;
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 192); cp = cp + 2;
- w8(buf, pos+cp, 195); cp = cp + 1;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 129)
+ w8(buf, pos+cp+2, 255)
+ e2_w32(buf, pos+cp+3, 67108864)
+ cp = cp + 7
+ w8(buf, pos+cp, 118)
+ w8(buf, pos+cp+1, 3)
+ cp = cp + 2
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 192)
+ cp = cp + 2
+ w8(buf, pos+cp, 195)
+ cp = cp + 1
// mov r9, rdi (save size for header)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 249); cp = cp + 3;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 249)
+ cp = cp + 3
// add rdi, 15; and rdi, -8
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 131); w8(buf, pos+cp+2, 199); w8(buf, pos+cp+3, 15); cp = cp + 4;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 131); w8(buf, pos+cp+2, 231); w8(buf, pos+cp+3, 248); cp = cp + 4;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 131)
+ w8(buf, pos+cp+2, 199)
+ w8(buf, pos+cp+3, 15)
+ cp = cp + 4
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 131)
+ w8(buf, pos+cp+2, 231)
+ w8(buf, pos+cp+3, 248)
+ cp = cp + 4
// mov r11, [rip + g_heap_ptr] — load via rip_patch
- if gv_heap_ptr >= 0 {
- rip_hp_l := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 29); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_l);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel0 := bss_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel0); cp = cp + 7;
- }
+ if gv_heap_ptr >= 0:
+ rip_hp_l := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 29)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_l)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel0 := bss_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel0)
+ cp = cp + 7
// test r11, r11; jne +14 (skip lazy init)
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 133); w8(buf, pos+cp+2, 219); cp = cp + 3;
- w8(buf, pos+cp, 117); w8(buf, pos+cp+1, 14); cp = cp + 2;
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 133)
+ w8(buf, pos+cp+2, 219)
+ cp = cp + 3
+ w8(buf, pos+cp, 117)
+ w8(buf, pos+cp+1, 14)
+ cp = cp + 2
// lea r11, [rip + heap_start]
- heap_start_va : ., mut = bss_va + 16 + globals_size;
- rel1 := heap_start_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel1); cp = cp + 7;
+ heap_start_va : ., mut = bss_va + 16 + globals_size
+ rel1 := heap_start_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel1)
+ cp = cp + 7
// mov [rip + g_heap_ptr], r11 — store via rip_patch
- if gv_heap_ptr >= 0 {
- rip_hp_s1 := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_s1);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel2 := bss_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel2); cp = cp + 7;
- }
+ if gv_heap_ptr >= 0:
+ rip_hp_s1 := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_s1)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel2 := bss_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel2)
+ cp = cp + 7
// mov r8, r11 (old ptr); add r11, rdi (bump); mov [rip + g_heap_ptr], r11
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 216); cp = cp + 3;
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 1); w8(buf, pos+cp+2, 251); cp = cp + 3;
- if gv_heap_ptr >= 0 {
- rip_hp_s2 := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_s2);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel3 := bss_va - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel3); cp = cp + 7;
- }
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 216)
+ cp = cp + 3
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 1)
+ w8(buf, pos+cp+2, 251)
+ cp = cp + 3
+ if gv_heap_ptr >= 0:
+ rip_hp_s2 := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_s2)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel3 := bss_va - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel3)
+ cp = cp + 7
// Zero-init: mov rdi, r8; mov rcx, r11; sub rcx, rdi; xor eax, eax; cld; rep stosb
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 199); cp = cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 217); cp = cp + 3;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 41); w8(buf, pos+cp+2, 249); cp = cp + 3;
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 192); cp = cp + 2;
- w8(buf, pos+cp, 252); cp = cp + 1;
- w8(buf, pos+cp, 243); w8(buf, pos+cp+1, 170); cp = cp + 2;
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 199)
+ cp = cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 217)
+ cp = cp + 3
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 41)
+ w8(buf, pos+cp+2, 249)
+ cp = cp + 3
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 192)
+ cp = cp + 2
+ w8(buf, pos+cp, 252)
+ cp = cp + 1
+ w8(buf, pos+cp, 243)
+ w8(buf, pos+cp+1, 170)
+ cp = cp + 2
// Store header: mov [r8], r9; lea rax, [r8+8]; ret
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 8); cp = cp + 3;
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 64); w8(buf, pos+cp+3, 8); cp = cp + 4;
- w8(buf, pos+cp, 195); cp = cp + 1;
-
- return cp;
-}
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 8)
+ cp = cp + 3
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 64)
+ w8(buf, pos+cp+3, 8)
+ cp = cp + 4
+ w8(buf, pos+cp, 195)
+ cp = cp + 1
+
+ return cp
// ── heap_expand: mmap(0, 1GB, 3, 0x22, -1, 0) for OOM recovery ──
// Called when global bump heap reaches heap_end. Uses mmap syscall to
// allocate a new 1GiB region, then updates heap_ptr and heap_end.
-fn emit_heap_expand(buf: string, pos: int, bss_va: int) -> int {
- cp := 0;
- fva := TEXT_BASE + pos;
+fn emit_heap_expand(buf: string, pos: int, bss_va: int) -> int:
+ cp := 0
+ fva := TEXT_BASE + pos
// Private allocator helper: preserve the live allocation span, original
// request size, and current arena index across mmap argument setup.
- w8(buf, pos+cp, 87); cp = cp + 1; // push rdi
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 81); cp = cp + 2; // push r9
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 82); cp = cp + 2; // push r10
+ w8(buf, pos+cp, 87)
+ cp = cp + 1 // push rdi
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 81)
+ cp = cp + 2 // push r9
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 82)
+ cp = cp + 2 // push r10
// xor edi, edi -- 31 FF (addr = NULL, let kernel choose)
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 255); cp = cp + 2;
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 255)
+ cp = cp + 2
// mov esi, 1073741824 -- BE xx xx xx xx (length = 1 GiB)
- e2_w8(buf, pos+cp, 190); e2_w32(buf, pos+cp+1, 1073741824); cp = cp + 5;
+ e2_w8(buf, pos+cp, 190)
+ e2_w32(buf, pos+cp+1, 1073741824)
+ cp = cp + 5
// mov edx, 3 -- BA 03 00 00 00 (prot = PROT_READ|PROT_WRITE)
- w8(buf, pos+cp, 186); e2_w32(buf, pos+cp+1, 3); cp = cp + 5;
+ w8(buf, pos+cp, 186)
+ e2_w32(buf, pos+cp+1, 3)
+ cp = cp + 5
// mov r10d, 0x22 -- 41 BA 22 00 00 00 (flags = MAP_PRIVATE|MAP_ANONYMOUS)
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 186); e2_w32(buf, pos+cp+2, 34); cp = cp + 6;
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 186)
+ e2_w32(buf, pos+cp+2, 34)
+ cp = cp + 6
// mov r8d, -1 -- 41 B8 FF FF FF FF (fd = -1)
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 184); e2_w32(buf, pos+cp+2, -1); cp = cp + 6;
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 184)
+ e2_w32(buf, pos+cp+2, -1)
+ cp = cp + 6
// xor r9d, r9d -- 45 31 C9 (offset = 0)
- w8(buf, pos+cp, 69); w8(buf, pos+cp+1, 49); w8(buf, pos+cp+2, 201); cp = cp + 3;
+ w8(buf, pos+cp, 69)
+ w8(buf, pos+cp+1, 49)
+ w8(buf, pos+cp+2, 201)
+ cp = cp + 3
// mov eax, 9 -- B8 09 00 00 00 (sys_mmap)
- w8(buf, pos+cp, 184); e2_w32(buf, pos+cp+1, 9); cp = cp + 5;
+ w8(buf, pos+cp, 184)
+ e2_w32(buf, pos+cp+1, 9)
+ cp = cp + 5
// syscall -- 0F 05
- w8(buf, pos+cp, 15); w8(buf, pos+cp+1, 5); cp = cp + 2;
+ w8(buf, pos+cp, 15)
+ w8(buf, pos+cp+1, 5)
+ cp = cp + 2
// test rax, rax -- 48 85 C0 (check if mmap returned negative error)
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 133); w8(buf, pos+cp+2, 192); cp = cp + 3;
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 133)
+ w8(buf, pos+cp+2, 192)
+ cp = cp + 3
// js .Lhf -- 78 XX (skip success path if mmap failed, rax has -errno)
// Success path: 7+7+7+2+5+1 = 29 bytes
- w8(buf, pos+cp, 120); w8(buf, pos+cp+1, 29); cp = cp + 2;
+ w8(buf, pos+cp, 120)
+ w8(buf, pos+cp+1, 29)
+ cp = cp + 2
// mov [rip + g_heap_ptr], rax — store via rip_patch
- if gv_heap_ptr >= 0 {
- rip_hp_ex := pos + cp + 3;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 5); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_ex);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel_hp_s := bss_va - (fva + cp + 7);
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 5); w8_signed(buf, pos+cp+3, rel_hp_s); cp = cp + 7;
- }
+ if gv_heap_ptr >= 0:
+ rip_hp_ex := pos + cp + 3
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 5)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_hp_ex)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_ptr)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel_hp_s := bss_va - (fva + cp + 7)
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 5)
+ w8_signed(buf, pos+cp+3, rel_hp_s)
+ cp = cp + 7
// lea r11, [rax + 1073741824] -- 4C 8D 98 xx xx xx xx (heap_end = new base + 1GB)
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 152); e2_w32(buf, pos+cp+3, 1073741824); cp = cp + 7;
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 152)
+ e2_w32(buf, pos+cp+3, 1073741824)
+ cp = cp + 7
// mov [rip + g_heap_end], r11 — store via rip_patch
- if gv_heap_end >= 0 {
- rip_he_ex := pos + cp + 3;
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); e2_w32(buf, pos+cp+3, 0); cp = cp + 7;
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_he_ex);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_end);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- } else {
- rel_hp_e := (bss_va + 8) - (fva + cp + 7);
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 29); w8_signed(buf, pos+cp+3, rel_hp_e); cp = cp + 7;
- }
+ if gv_heap_end >= 0:
+ rip_he_ex := pos + cp + 3
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ e2_w32(buf, pos+cp+3, 0)
+ cp = cp + 7
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_he_ex)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_heap_end)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ else:
+ rel_hp_e := (bss_va + 8) - (fva + cp + 7)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 29)
+ w8_signed(buf, pos+cp+3, rel_hp_e)
+ cp = cp + 7
// xor eax, eax -- 31 C0 (return 0 for success)
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 192); cp = cp + 2;
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 192)
+ cp = cp + 2
// Restore allocator state.
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 90); cp = cp + 2; // pop r10
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 89); cp = cp + 2; // pop r9
- w8(buf, pos+cp, 95); cp = cp + 1; // pop rdi
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 90)
+ cp = cp + 2 // pop r10
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 89)
+ cp = cp + 2 // pop r9
+ w8(buf, pos+cp, 95)
+ cp = cp + 1 // pop rdi
// ret -- C3
- w8(buf, pos+cp, 195); cp = cp + 1;
+ w8(buf, pos+cp, 195)
+ cp = cp + 1
// .Lhf: mmap failed, return -1
// mov rax, -1 -- 48 C7 C0 FF FF FF FF
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 199); w8(buf, pos+cp+2, 192); e2_w32(buf, pos+cp+3, -1); cp = cp + 7;
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 90); cp = cp + 2; // pop r10
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 89); cp = cp + 2; // pop r9
- w8(buf, pos+cp, 95); cp = cp + 1; // pop rdi
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 199)
+ w8(buf, pos+cp+2, 192)
+ e2_w32(buf, pos+cp+3, -1)
+ cp = cp + 7
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 90)
+ cp = cp + 2 // pop r10
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 89)
+ cp = cp + 2 // pop r9
+ w8(buf, pos+cp, 95)
+ cp = cp + 1 // pop rdi
// ret -- C3
- w8(buf, pos+cp, 195); cp = cp + 1;
- return cp;
-}
+ w8(buf, pos+cp, 195)
+ cp = cp + 1
+ return cp
// ── Scheduler call trampolines ──
// Emit sched_call_N(buf, p, n): mov rax,[rdi+rsi*8]; shift N args; jmp rax
// Returns bytes written.
-fn emit_sched_call(buf: string, p: int, n: int) -> int {
- w8(buf, p, 72); w8(buf, p+1, 139); w8(buf, p+2, 4); w8(buf, p+3, 240); off : ., mut = 4;
- if n >= 1 { w8(buf, p+off, 72); w8(buf, p+off+1, 137); w8(buf, p+off+2, 215); off = off + 3; }
- if n >= 2 { w8(buf, p+off, 72); w8(buf, p+off+1, 137); w8(buf, p+off+2, 206); off = off + 3; }
- if n >= 3 { w8(buf, p+off, 76); w8(buf, p+off+1, 137); w8(buf, p+off+2, 194); off = off + 3; }
- if n >= 4 { w8(buf, p+off, 76); w8(buf, p+off+1, 137); w8(buf, p+off+2, 201); off = off + 3; }
- w8(buf, p+off, 255); w8(buf, p+off+1, 224); off = off + 2;
- return off;
-}
-fn sched_tramp_sz(n: int) -> int {
- sz : ., mut = 6;
- if n >= 1 { sz = sz + 3; } if n >= 2 { sz = sz + 3; }
- if n >= 3 { sz = sz + 3; } if n >= 4 { sz = sz + 3; }
- return sz;
-}
+fn emit_sched_call(buf: string, p: int, n: int) -> int:
+ w8(buf, p, 72)
+ w8(buf, p+1, 139)
+ w8(buf, p+2, 4)
+ w8(buf, p+3, 240)
+ off : ., mut = 4
+ if n >= 1:
+ w8(buf, p+off, 72)
+ w8(buf, p+off+1, 137)
+ w8(buf, p+off+2, 215)
+ off = off + 3
+ if n >= 2:
+ w8(buf, p+off, 72)
+ w8(buf, p+off+1, 137)
+ w8(buf, p+off+2, 206)
+ off = off + 3
+ if n >= 3:
+ w8(buf, p+off, 76)
+ w8(buf, p+off+1, 137)
+ w8(buf, p+off+2, 194)
+ off = off + 3
+ if n >= 4:
+ w8(buf, p+off, 76)
+ w8(buf, p+off+1, 137)
+ w8(buf, p+off+2, 201)
+ off = off + 3
+ w8(buf, p+off, 255)
+ w8(buf, p+off+1, 224)
+ off = off + 2
+ return off
+fn sched_tramp_sz(n: int) -> int:
+ sz : ., mut = 6
+ if n >= 1:
+ sz = sz + 3
+ if n >= 2:
+ sz = sz + 3
+ if n >= 3:
+ sz = sz + 3
+ if n >= 4:
+ sz = sz + 3
+ return sz
// ── g_set_curg / g_get_curg bridge stubs ──
// Pure-static ELFs don't link rt.s, so the backend emits equivalent
@@ -533,22 +944,35 @@ fn sched_tramp_sz(n: int) -> int {
// In .so-linked builds (g_x86_emit_rt_stubs == 0) these stay external
// relocations resolved from rt.s at link time.
// Size: 11 bytes each — must match Phase 2 estimate.
-fn emit_curg_stubs(buf: string, pos: int, curg_va: int) -> int {
- cp : ., mut = 0;
+fn emit_curg_stubs(buf: string, pos: int, curg_va: int) -> int:
+ cp : ., mut = 0
// g_set_curg: lea rax, [rip + curg_va]; mov [rax], rdi; ret
- fva := TEXT_BASE + pos + cp;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 5); // lea rax, [rip+disp32]
- e2_w32(buf, pos+cp+3, curg_va - (fva + 7)); cp = cp + 7;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 56); cp = cp + 3; // mov [rax], rdi
- w8(buf, pos+cp, 195); cp = cp + 1; // ret
+ fva := TEXT_BASE + pos + cp
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 5) // lea rax, [rip+disp32]
+ e2_w32(buf, pos+cp+3, curg_va - (fva + 7))
+ cp = cp + 7
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 56)
+ cp = cp + 3 // mov [rax], rdi
+ w8(buf, pos+cp, 195)
+ cp = cp + 1 // ret
// g_get_curg: lea rax, [rip + curg_va]; mov rax, [rax]; ret
- fva2 := TEXT_BASE + pos + cp;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 5); // lea rax, [rip+disp32]
- e2_w32(buf, pos+cp+3, curg_va - (fva2 + 7)); cp = cp + 7;
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 0); cp = cp + 3; // mov rax, [rax]
- w8(buf, pos+cp, 195); cp = cp + 1; // ret
- return cp;
-}
+ fva2 := TEXT_BASE + pos + cp
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 5) // lea rax, [rip+disp32]
+ e2_w32(buf, pos+cp+3, curg_va - (fva2 + 7))
+ cp = cp + 7
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 0)
+ cp = cp + 3 // mov rax, [rax]
+ w8(buf, pos+cp, 195)
+ cp = cp + 1 // ret
+ return cp
// ── Goroutine runtime stubs (pure-static self-contained runtime) ──
// rt.s equivalents emitted into the binary so `go f()` works without
// linking rt.s: fiber_init, fiber_switch, goroutine_entry_wrapper.
@@ -557,40 +981,87 @@ fn emit_curg_stubs(buf: string, pos: int, curg_va: int) -> int {
// saved_fn(saved_arg), sends the result to result_ch (G+40), then yields
// forever. chan_send/sched_yield are Core functions — recorded as call
// patches resolved by the Phase 3 patch loop (user function names).
-fn emit_goroutine_stubs(buf: string, pos: int) -> int {
- cp : ., mut = 0;
+fn emit_goroutine_stubs(buf: string, pos: int) -> int:
+ cp : ., mut = 0
// fiber_init(stack_bottom, entry_fn) -> int — fake frame on the new stack.
// Layout: fiber_switch pops 6 regs (48 bytes) then ret reads
// [stack_bottom-8] — entry_fn MUST be at [stack_bottom-8]:
// mov rax, rdi; sub rax, 8; mov [rax], rsi; sub rax, 48;
// xor ecx, ecx; mov [rax], rcx; ret
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 248); cp = cp + 3; // mov rax, rdi
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 131); w8(buf, pos+cp+2, 232); w8(buf, pos+cp+3, 8); cp = cp + 4; // sub rax, 8
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 48); cp = cp + 3; // mov [rax], rsi
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 131); w8(buf, pos+cp+2, 232); w8(buf, pos+cp+3, 48); cp = cp + 4; // sub rax, 48
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 201); cp = cp + 2; // xor ecx, ecx
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 8); cp = cp + 3; // mov [rax], rcx
- w8(buf, pos+cp, 195); cp = cp + 1; // ret
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 248)
+ cp = cp + 3 // mov rax, rdi
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 131)
+ w8(buf, pos+cp+2, 232)
+ w8(buf, pos+cp+3, 8)
+ cp = cp + 4 // sub rax, 8
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 48)
+ cp = cp + 3 // mov [rax], rsi
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 131)
+ w8(buf, pos+cp+2, 232)
+ w8(buf, pos+cp+3, 48)
+ cp = cp + 4 // sub rax, 48
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 201)
+ cp = cp + 2 // xor ecx, ecx
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 8)
+ cp = cp + 3 // mov [rax], rcx
+ w8(buf, pos+cp, 195)
+ cp = cp + 1 // ret
// 20 bytes
// fiber_switch(current_sp_addr, next_sp) -> int — save/restore context:
// push rbx,r12-r15,rbp; mov [rdi], rsp; mov rsp, rsi; pop rbp,r15-r12,rbx; ret
- w8(buf, pos+cp, 83); cp = cp + 1; // push rbx
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 84); cp = cp + 2; // push r12
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 85); cp = cp + 2; // push r13
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 86); cp = cp + 2; // push r14
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 87); cp = cp + 2; // push r15
- w8(buf, pos+cp, 85); cp = cp + 1; // push rbp
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 39); cp = cp + 3; // mov [rdi], rsp
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 244); cp = cp + 3; // mov rsp, rsi
- w8(buf, pos+cp, 93); cp = cp + 1; // pop rbp
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 95); cp = cp + 2; // pop r15
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 94); cp = cp + 2; // pop r14
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 93); cp = cp + 2; // pop r13
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 92); cp = cp + 2; // pop r12
- w8(buf, pos+cp, 91); cp = cp + 1; // pop rbx
- w8(buf, pos+cp, 195); cp = cp + 1; // ret
+ w8(buf, pos+cp, 83)
+ cp = cp + 1 // push rbx
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 84)
+ cp = cp + 2 // push r12
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 85)
+ cp = cp + 2 // push r13
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 86)
+ cp = cp + 2 // push r14
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 87)
+ cp = cp + 2 // push r15
+ w8(buf, pos+cp, 85)
+ cp = cp + 1 // push rbp
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 39)
+ cp = cp + 3 // mov [rdi], rsp
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 244)
+ cp = cp + 3 // mov rsp, rsi
+ w8(buf, pos+cp, 93)
+ cp = cp + 1 // pop rbp
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 95)
+ cp = cp + 2 // pop r15
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 94)
+ cp = cp + 2 // pop r14
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 93)
+ cp = cp + 2 // pop r13
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 92)
+ cp = cp + 2 // pop r12
+ w8(buf, pos+cp, 91)
+ cp = cp + 1 // pop rbx
+ w8(buf, pos+cp, 195)
+ cp = cp + 1 // ret
// 27 bytes
// goroutine_entry_wrapper — fiber entry, no prologue (runs on the G's stack):
@@ -600,54 +1071,85 @@ fn emit_goroutine_stubs(buf: string, pos: int) -> int {
// then exit: call g_get_curg; mov rdi, rax; call g_free (arena_reset +
// mark _Gdead); call sched_schedule (switch to next, no re-enqueue);
// ret (fiber dead if no work)
- call_pos0 := pos + cp;
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos0);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("g_get_curg"));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call g_get_curg
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 120); w8(buf, pos+cp+3, 64); cp = cp + 4; // mov rdi, [rax+64]
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 64); w8(buf, pos+cp+3, 56); cp = cp + 4; // mov rax, [rax+56] (modrm 01 000 000 = 0x40 + disp8)
- w8(buf, pos+cp, 255); w8(buf, pos+cp+1, 208); cp = cp + 2; // call rax
- w8(buf, pos+cp, 80); cp = cp + 1; // push rax
- call_pos1 := pos + cp;
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos1);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("g_get_curg"));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call g_get_curg
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 120); w8(buf, pos+cp+3, 40); cp = cp + 4; // mov rdi, [rax+40]
- w8(buf, pos+cp, 94); cp = cp + 1; // pop rsi
- call_pos2 := pos + cp;
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos2);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("chan_send"));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call chan_send
+ call_pos0 := pos + cp
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos0)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("g_get_curg"))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5 // call g_get_curg
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 120)
+ w8(buf, pos+cp+3, 64)
+ cp = cp + 4 // mov rdi, [rax+64]
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 64)
+ w8(buf, pos+cp+3, 56)
+ cp = cp + 4 // mov rax, [rax+56] (modrm 01 000 000 = 0x40 + disp8)
+ w8(buf, pos+cp, 255)
+ w8(buf, pos+cp+1, 208)
+ cp = cp + 2 // call rax
+ w8(buf, pos+cp, 80)
+ cp = cp + 1 // push rax
+ call_pos1 := pos + cp
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos1)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("g_get_curg"))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5 // call g_get_curg
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 120)
+ w8(buf, pos+cp+3, 40)
+ cp = cp + 4 // mov rdi, [rax+40]
+ w8(buf, pos+cp, 94)
+ cp = cp + 1 // pop rsi
+ call_pos2 := pos + cp
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos2)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("chan_send"))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5 // call chan_send
// exit: call g_get_curg; mov rdi, rax; call g_free; call sched_schedule; ret
- call_pos3 := pos + cp;
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos3);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("g_get_curg"));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call g_get_curg
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 248); cp = cp + 3; // mov rdi, rax
- call_pos4 := pos + cp;
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos4);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("g_free"));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call g_free
- call_pos5 := pos + cp;
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos5);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("sched_schedule"));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call sched_schedule
- w8(buf, pos+cp, 195); cp = cp + 1; // ret
-
- return cp;
-}
+ call_pos3 := pos + cp
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos3)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("g_get_curg"))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5 // call g_get_curg
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 248)
+ cp = cp + 3 // mov rdi, rax
+ call_pos4 := pos + cp
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos4)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("g_free"))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5 // call g_free
+ call_pos5 := pos + cp
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos5)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("sched_schedule"))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5 // call sched_schedule
+ w8(buf, pos+cp, 195)
+ cp = cp + 1 // ret
+
+ return cp
// ── m_start_workers runtime stub (pure-static self-contained runtime) ──
// rt.s equivalent: launches n-1 worker threads via clone; each worker runs
@@ -664,163 +1166,286 @@ fn emit_goroutine_stubs(buf: string, pos: int) -> int {
// .Lnext: inc r12; jmp .Lloop
// .Lchild: xor ebp,ebp; ret
// .Ldone: pop r15,r13,r12,rbx; ret
-fn emit_m_start_workers(buf: string, pos: int) -> int {
- cp : ., mut = 0;
+fn emit_m_start_workers(buf: string, pos: int) -> int:
+ cp : ., mut = 0
// worker_entry (15 bytes):
- w8(buf, pos+cp, 95); cp = cp + 1; // pop rdi
- call_pos_we := pos + cp;
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos_we);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("sched_worker_run"));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call sched_worker_run
- w8(buf, pos+cp, 184); w8(buf, pos+cp+1, 60); w8(buf, pos+cp+2, 0); w8(buf, pos+cp+3, 0); w8(buf, pos+cp+4, 0); cp = cp + 5; // mov eax, 60
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 255); cp = cp + 2; // xor edi, edi
- w8(buf, pos+cp, 15); w8(buf, pos+cp+1, 5); cp = cp + 2; // syscall
+ w8(buf, pos+cp, 95)
+ cp = cp + 1 // pop rdi
+ call_pos_we := pos + cp
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos_we)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("sched_worker_run"))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5 // call sched_worker_run
+ w8(buf, pos+cp, 184)
+ w8(buf, pos+cp+1, 60)
+ w8(buf, pos+cp+2, 0)
+ w8(buf, pos+cp+3, 0)
+ w8(buf, pos+cp+4, 0)
+ cp = cp + 5 // mov eax, 60
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 255)
+ cp = cp + 2 // xor edi, edi
+ w8(buf, pos+cp, 15)
+ w8(buf, pos+cp+1, 5)
+ cp = cp + 2 // syscall
// m_start_workers (111 bytes, starts at pos+15)
- w8(buf, pos+cp, 83); cp = cp + 1; // push rbx
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 84); cp = cp + 2; // push r12
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 85); cp = cp + 2; // push r13
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 87); cp = cp + 2; // push r15
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 251); cp = cp + 3; // mov rbx, rdi
- w8(buf, pos+cp, 69); w8(buf, pos+cp+1, 49); w8(buf, pos+cp+2, 228); cp = cp + 3; // xor r12d, r12d
+ w8(buf, pos+cp, 83)
+ cp = cp + 1 // push rbx
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 84)
+ cp = cp + 2 // push r12
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 85)
+ cp = cp + 2 // push r13
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 87)
+ cp = cp + 2 // push r15
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 251)
+ cp = cp + 3 // mov rbx, rdi
+ w8(buf, pos+cp, 69)
+ w8(buf, pos+cp+1, 49)
+ w8(buf, pos+cp+2, 228)
+ cp = cp + 3 // xor r12d, r12d
// .Lworker_loop (offset 13)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 255); w8(buf, pos+cp+2, 196); cp = cp + 3; // inc r12
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 57); w8(buf, pos+cp+2, 220); cp = cp + 3; // cmp r12, rbx
- w8(buf, pos+cp, 125); w8(buf, pos+cp+1, 83); cp = cp + 2; // jge .Ldone (+83)
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 84); cp = cp + 2; // push r12
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 199); w8(buf, pos+cp+2, 199); cp = cp + 3; // mov rdi, 65536
- w8(buf, pos+cp, 0); w8(buf, pos+cp+1, 0); w8(buf, pos+cp+2, 1); w8(buf, pos+cp+3, 0); cp = cp + 4;
- call_pos_al := pos + cp;
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos_al);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("alloc"));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call alloc
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 92); cp = cp + 2; // pop r12
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 133); w8(buf, pos+cp+2, 192); cp = cp + 3; // test rax, rax
- w8(buf, pos+cp, 116); w8(buf, pos+cp+1, 54); cp = cp + 2; // jz .Lnext_worker (+54)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 199); cp = cp + 3; // mov r15, rax
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 129); w8(buf, pos+cp+2, 199); cp = cp + 3; // add r15, 65536
- w8(buf, pos+cp, 0); w8(buf, pos+cp+1, 0); w8(buf, pos+cp+2, 1); w8(buf, pos+cp+3, 0); cp = cp + 4;
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 255)
+ w8(buf, pos+cp+2, 196)
+ cp = cp + 3 // inc r12
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 57)
+ w8(buf, pos+cp+2, 220)
+ cp = cp + 3 // cmp r12, rbx
+ w8(buf, pos+cp, 125)
+ w8(buf, pos+cp+1, 83)
+ cp = cp + 2 // jge .Ldone (+83)
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 84)
+ cp = cp + 2 // push r12
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 199)
+ w8(buf, pos+cp+2, 199)
+ cp = cp + 3 // mov rdi, 65536
+ w8(buf, pos+cp, 0)
+ w8(buf, pos+cp+1, 0)
+ w8(buf, pos+cp+2, 1)
+ w8(buf, pos+cp+3, 0)
+ cp = cp + 4
+ call_pos_al := pos + cp
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, call_pos_al)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern("alloc"))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ e2_w8(buf, pos+cp, 232)
+ e2_w32(buf, pos+cp+1, 0)
+ cp = cp + 5 // call alloc
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 92)
+ cp = cp + 2 // pop r12
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 133)
+ w8(buf, pos+cp+2, 192)
+ cp = cp + 3 // test rax, rax
+ w8(buf, pos+cp, 116)
+ w8(buf, pos+cp+1, 54)
+ cp = cp + 2 // jz .Lnext_worker (+54)
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 199)
+ cp = cp + 3 // mov r15, rax
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 129)
+ w8(buf, pos+cp+2, 199)
+ cp = cp + 3 // add r15, 65536
+ w8(buf, pos+cp, 0)
+ w8(buf, pos+cp+1, 0)
+ w8(buf, pos+cp+2, 1)
+ w8(buf, pos+cp+3, 0)
+ cp = cp + 4
// lea r13, [rip + worker_entry] — worker_entry at stub base (pos+0), this lea
// is 7 bytes ending at (pos+58): disp = (pos+0) - (pos+58) = -58
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 45); cp = cp + 3;
- e2_w32(buf, pos+cp, -58); cp = cp + 4;
- w8(buf, pos+cp, 77); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 111); w8(buf, pos+cp+3, 240); cp = cp + 4; // mov [r15-16], r13
- w8(buf, pos+cp, 76); w8(buf, pos+cp+1, 137); w8(buf, pos+cp+2, 71); w8(buf, pos+cp+3, 248); cp = cp + 4; // mov [r15-8], r12
- w8(buf, pos+cp, 191); w8(buf, pos+cp+1, 0); w8(buf, pos+cp+2, 15); w8(buf, pos+cp+3, 1); w8(buf, pos+cp+4, 0); cp = cp + 5; // mov edi, 0x10F00
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 141); w8(buf, pos+cp+2, 119); w8(buf, pos+cp+3, 240); cp = cp + 4; // lea rsi, [r15-16]
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 210); cp = cp + 2; // xor edx, edx
- w8(buf, pos+cp, 69); w8(buf, pos+cp+1, 49); w8(buf, pos+cp+2, 210); cp = cp + 3; // xor r10d, r10d
- w8(buf, pos+cp, 69); w8(buf, pos+cp+1, 49); w8(buf, pos+cp+2, 192); cp = cp + 3; // xor r8d, r8d
- w8(buf, pos+cp, 184); w8(buf, pos+cp+1, 56); w8(buf, pos+cp+2, 0); w8(buf, pos+cp+3, 0); w8(buf, pos+cp+4, 0); cp = cp + 5; // mov eax, 56
- w8(buf, pos+cp, 15); w8(buf, pos+cp+1, 5); cp = cp + 2; // syscall
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 133); w8(buf, pos+cp+2, 192); cp = cp + 3; // test rax, rax
- w8(buf, pos+cp, 116); w8(buf, pos+cp+1, 5); cp = cp + 2; // jz .Lchild (+5)
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 45)
+ cp = cp + 3
+ e2_w32(buf, pos+cp, -58)
+ cp = cp + 4
+ w8(buf, pos+cp, 77)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 111)
+ w8(buf, pos+cp+3, 240)
+ cp = cp + 4 // mov [r15-16], r13
+ w8(buf, pos+cp, 76)
+ w8(buf, pos+cp+1, 137)
+ w8(buf, pos+cp+2, 71)
+ w8(buf, pos+cp+3, 248)
+ cp = cp + 4 // mov [r15-8], r12
+ w8(buf, pos+cp, 191)
+ w8(buf, pos+cp+1, 0)
+ w8(buf, pos+cp+2, 15)
+ w8(buf, pos+cp+3, 1)
+ w8(buf, pos+cp+4, 0)
+ cp = cp + 5 // mov edi, 0x10F00
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 141)
+ w8(buf, pos+cp+2, 119)
+ w8(buf, pos+cp+3, 240)
+ cp = cp + 4 // lea rsi, [r15-16]
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 210)
+ cp = cp + 2 // xor edx, edx
+ w8(buf, pos+cp, 69)
+ w8(buf, pos+cp+1, 49)
+ w8(buf, pos+cp+2, 210)
+ cp = cp + 3 // xor r10d, r10d
+ w8(buf, pos+cp, 69)
+ w8(buf, pos+cp+1, 49)
+ w8(buf, pos+cp+2, 192)
+ cp = cp + 3 // xor r8d, r8d
+ w8(buf, pos+cp, 184)
+ w8(buf, pos+cp+1, 56)
+ w8(buf, pos+cp+2, 0)
+ w8(buf, pos+cp+3, 0)
+ w8(buf, pos+cp+4, 0)
+ cp = cp + 5 // mov eax, 56
+ w8(buf, pos+cp, 15)
+ w8(buf, pos+cp+1, 5)
+ cp = cp + 2 // syscall
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 133)
+ w8(buf, pos+cp+2, 192)
+ cp = cp + 3 // test rax, rax
+ w8(buf, pos+cp, 116)
+ w8(buf, pos+cp+1, 5)
+ cp = cp + 2 // jz .Lchild (+5)
// .Lnext_worker (offset 95)
- w8(buf, pos+cp, 73); w8(buf, pos+cp+1, 255); w8(buf, pos+cp+2, 196); cp = cp + 3; // inc r12
- w8(buf, pos+cp, 235); w8(buf, pos+cp+1, 169); cp = cp + 2; // jmp .Lworker_loop (-87)
+ w8(buf, pos+cp, 73)
+ w8(buf, pos+cp+1, 255)
+ w8(buf, pos+cp+2, 196)
+ cp = cp + 3 // inc r12
+ w8(buf, pos+cp, 235)
+ w8(buf, pos+cp+1, 169)
+ cp = cp + 2 // jmp .Lworker_loop (-87)
// .Lchild (offset 100)
- w8(buf, pos+cp, 49); w8(buf, pos+cp+1, 237); cp = cp + 2; // xor ebp, ebp
- w8(buf, pos+cp, 195); cp = cp + 1; // ret
+ w8(buf, pos+cp, 49)
+ w8(buf, pos+cp+1, 237)
+ cp = cp + 2 // xor ebp, ebp
+ w8(buf, pos+cp, 195)
+ cp = cp + 1 // ret
// .Ldone (offset 103)
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 95); cp = cp + 2; // pop r15
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 93); cp = cp + 2; // pop r13
- w8(buf, pos+cp, 65); w8(buf, pos+cp+1, 92); cp = cp + 2; // pop r12
- w8(buf, pos+cp, 91); cp = cp + 1; // pop rbx
- w8(buf, pos+cp, 195); cp = cp + 1; // ret
-
- return cp;
-}
-
-fn sched_reg_one(name: string, offset: int, cp: int) {
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern(name));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, cp - 176);
- g_x86_func_off_count = g_x86_func_off_count + 1;
-}
-
-fn w16(buf: string, off: int, val: int) {
- store8(buf, off, val % 256); store8(buf, off+1, (val/256) % 256);
-}
-
-fn align_up(val: int, align: int) -> int { return (val + align - 1) / align * align; }
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 95)
+ cp = cp + 2 // pop r15
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 93)
+ cp = cp + 2 // pop r13
+ w8(buf, pos+cp, 65)
+ w8(buf, pos+cp+1, 92)
+ cp = cp + 2 // pop r12
+ w8(buf, pos+cp, 91)
+ cp = cp + 1 // pop rbx
+ w8(buf, pos+cp, 195)
+ cp = cp + 1 // ret
+
+ return cp
+
+fn sched_reg_one(name: string, offset: int, cp: int):
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern(name))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, cp - 176)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+
+fn w16(buf: string, off: int, val: int):
+ store8(buf, off, val % 256)
+ store8(buf, off+1, (val/256) % 256)
+
+fn align_up(val: int, align: int) -> int:
+ return (val + align - 1) / align * align
// ── Global ──
-g_asm_code_size : int, mut;
-g_elf_buf : string, mut;
+g_asm_code_size : int, mut
+g_elf_buf : string, mut
// ── ELF64 struct layout offsets (used by elf2_hdr) ──
// ELF64 Ehdr
-E_EHDR_MAGIC : int = 0; // 4B: \x7fELF
-E_CLASS : int = 4; // 1B: 2=64-bit
-E_DATA : int = 5; // 1B: 1=LE
-E_VER : int = 6; // 1B: 1=current
-E_OSABI : int = 7; // 1B: 0=UNIX System V
-E_PAD : int = 8; // 8B padding
-E_TYPE : int = 16; // 2B: 2=ET_EXEC
-E_MACH : int = 18; // 2B: 62=EM_X86_64
-E_VERSION : int = 20; // 4B: 1
-E_ENTRY : int = 24; // 8B: entry point VA
-E_PHOFF : int = 32; // 8B: program header offset
-E_SHOFF : int = 40; // 8B: section header offset
-E_FLAGS : int = 48; // 4B
-E_EHSIZE : int = 52; // 2B: sizeof(Elf64_Ehdr)=64
-E_PHENTSIZE : int = 54; // 2B: sizeof(Elf64_Phdr)=56
-E_PHNUM : int = 56; // 2B: number of phdrs
-E_SHENTSIZE : int = 58; // 2B
-E_SHNUM : int = 60; // 2B
-E_SHSTRNDX : int = 62; // 2B
-EHDR_SIZE : int = 64; // sizeof(Elf64_Ehdr)
+E_EHDR_MAGIC : int = 0 // 4B: \x7fELF
+E_CLASS : int = 4 // 1B: 2=64-bit
+E_DATA : int = 5 // 1B: 1=LE
+E_VER : int = 6 // 1B: 1=current
+E_OSABI : int = 7 // 1B: 0=UNIX System V
+E_PAD : int = 8 // 8B padding
+E_TYPE : int = 16 // 2B: 2=ET_EXEC
+E_MACH : int = 18 // 2B: 62=EM_X86_64
+E_VERSION : int = 20 // 4B: 1
+E_ENTRY : int = 24 // 8B: entry point VA
+E_PHOFF : int = 32 // 8B: program header offset
+E_SHOFF : int = 40 // 8B: section header offset
+E_FLAGS : int = 48 // 4B
+E_EHSIZE : int = 52 // 2B: sizeof(Elf64_Ehdr)=64
+E_PHENTSIZE : int = 54 // 2B: sizeof(Elf64_Phdr)=56
+E_PHNUM : int = 56 // 2B: number of phdrs
+E_SHENTSIZE : int = 58 // 2B
+E_SHNUM : int = 60 // 2B
+E_SHSTRNDX : int = 62 // 2B
+EHDR_SIZE : int = 64 // sizeof(Elf64_Ehdr)
// ELF64 Phdr (per-entry offsets, base = 64 + entry_idx * 56)
-P_TYPE : int = 0; // 4B: 1=PT_LOAD
-P_FLAGS : int = 4; // 4B: PF_{R,W,X}
-P_OFFSET : int = 8; // 8B: file offset
-P_VADDR : int = 16; // 8B: virtual address
-P_PADDR : int = 24; // 8B: physical address
-P_FILESZ : int = 32; // 8B: size in file
-P_MEMSZ : int = 40; // 8B: size in memory
-P_ALIGN : int = 48; // 8B: alignment
-PHDR_SIZE : int = 56; // sizeof(Elf64_Phdr)
+P_TYPE : int = 0 // 4B: 1=PT_LOAD
+P_FLAGS : int = 4 // 4B: PF_{R,W,X}
+P_OFFSET : int = 8 // 8B: file offset
+P_VADDR : int = 16 // 8B: virtual address
+P_PADDR : int = 24 // 8B: physical address
+P_FILESZ : int = 32 // 8B: size in file
+P_MEMSZ : int = 40 // 8B: size in memory
+P_ALIGN : int = 48 // 8B: alignment
+PHDR_SIZE : int = 56 // sizeof(Elf64_Phdr)
// Write one ELF64 program header entry
fn write_phdr(buf: string, idx: int, p_type: int, p_flags: int,
p_offset: int, p_vaddr: int, p_paddr: int,
- p_filesz: int, p_memsz: int, p_align: int) {
- base : ., mut = EHDR_SIZE + idx * PHDR_SIZE;
- w32(buf, base + P_TYPE, p_type);
- w32(buf, base + P_FLAGS, p_flags);
- w64(buf, base + P_OFFSET, p_offset);
- w64(buf, base + P_VADDR, p_vaddr);
- w64(buf, base + P_PADDR, p_paddr);
- w64(buf, base + P_FILESZ, p_filesz);
- w64(buf, base + P_MEMSZ, p_memsz);
- w64(buf, base + P_ALIGN, p_align);
-}
+ p_filesz: int, p_memsz: int, p_align: int):
+ base : ., mut = EHDR_SIZE + idx * PHDR_SIZE
+ w32(buf, base + P_TYPE, p_type)
+ w32(buf, base + P_FLAGS, p_flags)
+ w64(buf, base + P_OFFSET, p_offset)
+ w64(buf, base + P_VADDR, p_vaddr)
+ w64(buf, base + P_PADDR, p_paddr)
+ w64(buf, base + P_FILESZ, p_filesz)
+ w64(buf, base + P_MEMSZ, p_memsz)
+ w64(buf, base + P_ALIGN, p_align)
// ── ELF header writer (x86-64) ──
-fn elf2_hdr(buf: string, code_end: int, total_sz: int) {
- hdr_sz : ., mut = EHDR_SIZE + 2 * PHDR_SIZE; // 64+112=176
- i := 0; loop { if i >= hdr_sz { break; } store8(buf, i, 0); i = i + 1; }
+fn elf2_hdr(buf: string, code_end: int, total_sz: int):
+ hdr_sz : ., mut = EHDR_SIZE + 2 * PHDR_SIZE // 64+112=176
+ i := 0
+ loop:
+ if i >= hdr_sz:
+ break
+ store8(buf, i, 0)
+ i = i + 1
// e_ident
- w8(buf, E_EHDR_MAGIC, 127); w8(buf, E_EHDR_MAGIC+1, 69);
- w8(buf, E_EHDR_MAGIC+2, 76); w8(buf, E_EHDR_MAGIC+3, 70); // \x7fELF
- w8(buf, E_CLASS, 2); // EI_CLASS = ELFCLASS64
- w8(buf, E_DATA, 1); // EI_DATA = ELFDATA2LSB
- w8(buf, E_VER, 1); // EI_VERSION = EV_CURRENT
+ w8(buf, E_EHDR_MAGIC, 127)
+ w8(buf, E_EHDR_MAGIC+1, 69)
+ w8(buf, E_EHDR_MAGIC+2, 76)
+ w8(buf, E_EHDR_MAGIC+3, 70) // \x7fELF
+ w8(buf, E_CLASS, 2) // EI_CLASS = ELFCLASS64
+ w8(buf, E_DATA, 1) // EI_DATA = ELFDATA2LSB
+ w8(buf, E_VER, 1) // EI_VERSION = EV_CURRENT
// e_type, e_machine, e_version
- w16(buf, E_TYPE, 2); // ET_EXEC
- w16(buf, E_MACH, 62); // EM_X86_64
- w32(buf, E_VERSION, 1); // EV_CURRENT
- w64(buf, E_ENTRY, 0x400000 + EHDR_SIZE + 2 * PHDR_SIZE); // entry = text_base + 176
- w64(buf, E_PHOFF, EHDR_SIZE); // phdrs start right after ehdr
- w16(buf, E_EHSIZE, EHDR_SIZE); // sizeof(Elf64_Ehdr) = 64
- w16(buf, E_PHENTSIZE, PHDR_SIZE); // sizeof(Elf64_Phdr) = 56
- w16(buf, E_PHNUM, 2); // 2 program headers
+ w16(buf, E_TYPE, 2) // ET_EXEC
+ w16(buf, E_MACH, 62) // EM_X86_64
+ w32(buf, E_VERSION, 1) // EV_CURRENT
+ w64(buf, E_ENTRY, 0x400000 + EHDR_SIZE + 2 * PHDR_SIZE) // entry = text_base + 176
+ w64(buf, E_PHOFF, EHDR_SIZE) // phdrs start right after ehdr
+ w16(buf, E_EHSIZE, EHDR_SIZE) // sizeof(Elf64_Ehdr) = 64
+ w16(buf, E_PHENTSIZE, PHDR_SIZE) // sizeof(Elf64_Phdr) = 56
+ w16(buf, E_PHNUM, 2) // 2 program headers
// PHDR[0]: code segment (RX, file offset 0, VA = TEXT_BASE)
write_phdr(buf, 0,
@@ -829,36 +1454,35 @@ fn elf2_hdr(buf: string, code_end: int, total_sz: int) {
0, // file offset
4194304, // TEXT_BASE
4194304, // phys addr = TEXT_BASE
- code_end, code_end, 4096);
+ code_end, code_end, 4096)
// PHDR[1]: rodata+BSS (RW, starts at page after code)
- rodata_va : ., mut = 4194304 + code_end;
- data_sz : ., mut = total_sz - code_end;
+ rodata_va : ., mut = 4194304 + code_end
+ data_sz : ., mut = total_sz - code_end
write_phdr(buf, 1,
1, // PT_LOAD
6, // PF_R | PF_W
code_end,
rodata_va, rodata_va,
- data_sz, 1073741824, 4096); // memsz = 1 GiB virtual bump heap
-}
+ data_sz, 1073741824, 4096) // memsz = 1 GiB virtual bump heap
// ── _start 面共享状态(发射序本体 = OS 轴 src/os/linux/entry.cr)──
-g_call_main_pos : int, mut; // set by emit_start (OS 轴 entry.cr), used for patching call main
-gv_argc : int, mut; // IR var index for g_rt_argc (or -1)
-gv_argv : int, mut; // IR var index for g_rt_argv_ptr (or -1)
+g_call_main_pos : int, mut // set by emit_start (OS 轴 entry.cr), used for patching call main
+gv_argc : int, mut // IR var index for g_rt_argc (or -1)
+gv_argv : int, mut // IR var index for g_rt_argv_ptr (or -1)
// Arena global variable indices (set by elf_gen before emit_alloc_body calls)
-gv_current_arena : int, mut = -1;
-gv_arena_cursors : int, mut = -1;
-gv_arena_sizes : int, mut = -1;
-gv_arena_pool_data : int, mut = -1;
-gv_arena_max_size : int, mut = -1;
-gv_heap_ptr : int, mut = -1;
-gv_heap_end : int, mut = -1;
-gv_hp_config : int, mut = -1;
-gv_hp_inflight : int, mut = -1;
-g_heap_expand_call_pos : int, mut = -1;
-g_alloc_gl_jmp_pos : int, mut = -1; // Part 1 jl .Lglobal displacement position (patched at Part 8)
+gv_current_arena : int, mut = -1
+gv_arena_cursors : int, mut = -1
+gv_arena_sizes : int, mut = -1
+gv_arena_pool_data : int, mut = -1
+gv_arena_max_size : int, mut = -1
+gv_heap_ptr : int, mut = -1
+gv_heap_end : int, mut = -1
+gv_hp_config : int, mut = -1
+gv_hp_inflight : int, mut = -1
+g_heap_expand_call_pos : int, mut = -1
+g_alloc_gl_jmp_pos : int, mut = -1 // Part 1 jl .Lglobal displacement position (patched at Part 8)
// ── _start 发射序(emit_start/emit_start_size)已整函数迁 OS 轴
// src/os/linux/entry.cr(x86 实例化波 1 Task 2——跨轴调用经 module.cr 三轴回退
@@ -866,13 +1490,18 @@ g_alloc_gl_jmp_pos : int, mut = -1; // Part 1 jl .Lglobal displacement position
// 全局声明——单扁平编译单元内解析,无重复声明)──
// ── Main ELF generation ──
-fn elf_gen(buf: string) -> int {
+fn elf_gen(buf: string) -> int:
// Mark global variables for RIP-relative addressing
- gi := 0; loop { if gi >= g_ir_global_count { break; }
- gv := r64(g_ir_globals, gi * 24 + 8);
- if gv >= 0 { grow_is_global(gv + 1); w64(g_x86_is_global, gv * 8, 1); }
- gi = gi + 1; }
- grow_is_global(g_ir_var_count);
+ gi := 0
+ loop:
+ if gi >= g_ir_global_count:
+ break
+ gv := r64(g_ir_globals, gi * 24 + 8)
+ if gv >= 0:
+ grow_is_global(gv + 1)
+ w64(g_x86_is_global, gv * 8, 1)
+ gi = gi + 1
+ grow_is_global(g_ir_var_count)
// 内置体名索引扫描段(g_ni_* 赋值):**保留原位**——本段整体参数化 =
// 波 2 面(x86 实例化设计 §5 波 2)。syscall3/syscall4 二项消费方 =
@@ -884,285 +1513,391 @@ fn elf_gen(buf: string) -> int {
// exit / clone,syscall1/5/6 形,非内置体径)= OS 轴收编面,见 TODO #2026-09-10-6
// (波 2 / 实例 B 前必办——实例 B 承诺"换轴零改动"要求 Linux ABI 字节
// 不留在格式轴)。
- g_ni_syscall3 = -1; g_ni_syscall4 = -1; g_ni_load8 = -1; g_ni_store8 = -1; g_ni_load64 = -1;
- g_ni_load_str_ptr = -1; g_ni_store_str_ptr = -1; g_ni_get_arg = -1;
- g_ni_w64 = -1; g_ni_dyncpy = -1; g_ni_r64 = -1;
- g_ni_goroutine_wrapper_addr = -1;
- ni_i : ., mut = 0;
- loop { if ni_i >= g_str_count { break; }
- ns := istr_get(ni_i);
- if str_eq(ns, "syscall3") != 0 { g_ni_syscall3 = ni_i; }
- if str_eq(ns, "syscall4") != 0 { g_ni_syscall4 = ni_i; }
- if str_eq(ns, "load8") != 0 { g_ni_load8 = ni_i; }
- if str_eq(ns, "store8") != 0 { g_ni_store8 = ni_i; }
- if str_eq(ns, "load64") != 0 { g_ni_load64 = ni_i; }
- if str_eq(ns, "r64") != 0 { g_ni_r64 = ni_i; }
- if str_eq(ns, "load_str_ptr") != 0 { g_ni_load_str_ptr = ni_i; }
- if str_eq(ns, "store_str_ptr") != 0 { g_ni_store_str_ptr = ni_i; }
- if str_eq(ns, "get_arg") != 0 { g_ni_get_arg = ni_i; }
- if str_eq(ns, "w64") != 0 { g_ni_w64 = ni_i; }
- if str_eq(ns, "_dyncpy") != 0 { g_ni_dyncpy = ni_i; }
- if str_eq(ns, "goroutine_wrapper_addr") != 0 { g_ni_goroutine_wrapper_addr = ni_i; }
- ni_i = ni_i + 1; }
-
- print(" ni: syscall3="); print(int_str(g_ni_syscall3));
- print(" load8="); print(int_str(g_ni_load8));
- print(" w64="); print(int_str(g_ni_w64));
- print(" dyncpy="); println(int_str(g_ni_dyncpy));
+ g_ni_syscall3 = -1
+ g_ni_syscall4 = -1
+ g_ni_load8 = -1
+ g_ni_store8 = -1
+ g_ni_load64 = -1
+ g_ni_load_str_ptr = -1
+ g_ni_store_str_ptr = -1
+ g_ni_get_arg = -1
+ g_ni_w64 = -1
+ g_ni_dyncpy = -1
+ g_ni_r64 = -1
+ g_ni_goroutine_wrapper_addr = -1
+ ni_i : ., mut = 0
+ loop:
+ if ni_i >= g_str_count:
+ break
+ ns := istr_get(ni_i)
+ if str_eq(ns, "syscall3") != 0:
+ g_ni_syscall3 = ni_i
+ if str_eq(ns, "syscall4") != 0:
+ g_ni_syscall4 = ni_i
+ if str_eq(ns, "load8") != 0:
+ g_ni_load8 = ni_i
+ if str_eq(ns, "store8") != 0:
+ g_ni_store8 = ni_i
+ if str_eq(ns, "load64") != 0:
+ g_ni_load64 = ni_i
+ if str_eq(ns, "r64") != 0:
+ g_ni_r64 = ni_i
+ if str_eq(ns, "load_str_ptr") != 0:
+ g_ni_load_str_ptr = ni_i
+ if str_eq(ns, "store_str_ptr") != 0:
+ g_ni_store_str_ptr = ni_i
+ if str_eq(ns, "get_arg") != 0:
+ g_ni_get_arg = ni_i
+ if str_eq(ns, "w64") != 0:
+ g_ni_w64 = ni_i
+ if str_eq(ns, "_dyncpy") != 0:
+ g_ni_dyncpy = ni_i
+ if str_eq(ns, "goroutine_wrapper_addr") != 0:
+ g_ni_goroutine_wrapper_addr = ni_i
+ ni_i = ni_i + 1
+
+ print(" ni: syscall3=")
+ print(int_str(g_ni_syscall3))
+ print(" load8=")
+ print(int_str(g_ni_load8))
+ print(" w64=")
+ print(int_str(g_ni_w64))
+ print(" dyncpy=")
+ println(int_str(g_ni_dyncpy))
// Reset scratch-emission garbage (res_labels -> emit_instr -> pollutes rip_patch arrays)
- g_x86_rip_patch_count = 0;
- g_x86_rodataref_count = 0;
- g_x86_alloc_patch_count = 0;
- g_x86_fnaddr_patch_count = 0;
+ g_x86_rip_patch_count = 0
+ g_x86_rodataref_count = 0
+ g_x86_alloc_patch_count = 0
+ g_x86_fnaddr_patch_count = 0
- println(" elf: Phase 1 (rodata layout)...");
+ println(" elf: Phase 1 (rodata layout)...")
// Phase 1: rodata layout — collect string constants
- g_x86_str_count = 0;
- si := 0; loop { if si >= g_ir_str_const_count { break; } g2_str_off(r64(g_ir_str_consts, si * 8)); si = si + 1; }
+ g_x86_str_count = 0
+ si := 0
+ loop:
+ if si >= g_ir_str_const_count:
+ break
+ g2_str_off(r64(g_ir_str_consts, si * 8))
+ si = si + 1
// Find g_rt_argc/g_rt_argv_ptr via name_idx (no str_eq loop)
- gv_argc = -1; gv_argv = -1;
- argc_ni := str_intern("g_rt_argc"); argv_ni := str_intern("g_rt_argv_ptr");
+ gv_argc = -1
+ gv_argv = -1
+ argc_ni := str_intern("g_rt_argc")
+ argv_ni := str_intern("g_rt_argv_ptr")
// Arena global variable indices
- gv_current_arena = -1; gv_arena_cursors = -1; gv_arena_sizes = -1;
- gv_arena_pool_data = -1; gv_arena_max_size = -1;
- cur_ni := str_intern("g_current_arena"); cur_ni2 := str_intern("g_arena_cursors");
- cur_ni3 := str_intern("g_arena_sizes"); cur_ni4 := str_intern("g_arena_pool_data");
- cur_ni5 := str_intern("g_arena_max_size");
- cur_ni6 := str_intern("g_heap_ptr"); cur_ni7 := str_intern("g_heap_end");
- cur_ni8 := str_intern("g_hp_config"); cur_ni9 := str_intern("g_hp_inflight");
- gvsi : ., mut = 0;
- loop { if gvsi >= g_ir_global_count { break; }
- ni := r64(g_ir_globals, gvsi * 24);
- if ni == argc_ni { gv_argc = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == argv_ni { gv_argv = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni { gv_current_arena = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni2 { gv_arena_cursors = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni3 { gv_arena_sizes = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni4 { gv_arena_pool_data = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni5 { gv_arena_max_size = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni6 { gv_heap_ptr = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni7 { gv_heap_end = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni8 { gv_hp_config = r64(g_ir_globals, gvsi * 24 + 8); }
- if ni == cur_ni9 { gv_hp_inflight = r64(g_ir_globals, gvsi * 24 + 8); }
- gvsi = gvsi + 1; }
+ gv_current_arena = -1
+ gv_arena_cursors = -1
+ gv_arena_sizes = -1
+ gv_arena_pool_data = -1
+ gv_arena_max_size = -1
+ cur_ni := str_intern("g_current_arena")
+ cur_ni2 := str_intern("g_arena_cursors")
+ cur_ni3 := str_intern("g_arena_sizes")
+ cur_ni4 := str_intern("g_arena_pool_data")
+ cur_ni5 := str_intern("g_arena_max_size")
+ cur_ni6 := str_intern("g_heap_ptr")
+ cur_ni7 := str_intern("g_heap_end")
+ cur_ni8 := str_intern("g_hp_config")
+ cur_ni9 := str_intern("g_hp_inflight")
+ gvsi : ., mut = 0
+ loop:
+ if gvsi >= g_ir_global_count:
+ break
+ ni := r64(g_ir_globals, gvsi * 24)
+ if ni == argc_ni:
+ gv_argc = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == argv_ni:
+ gv_argv = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni:
+ gv_current_arena = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni2:
+ gv_arena_cursors = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni3:
+ gv_arena_sizes = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni4:
+ gv_arena_pool_data = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni5:
+ gv_arena_max_size = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni6:
+ gv_heap_ptr = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni7:
+ gv_heap_end = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni8:
+ gv_hp_config = r64(g_ir_globals, gvsi * 24 + 8)
+ if ni == cur_ni9:
+ gv_hp_inflight = r64(g_ir_globals, gvsi * 24 + 8)
+ gvsi = gvsi + 1
// Phase 2: compute sizes for all functions
- println(" elf: Phase 2 (size calc)...");
+ println(" elf: Phase 2 (size calc)...")
// Estimate function code sizes (~8B/inst average). Correct BSS position
// computed after Phase 3 emit (see rip_patch fixup below).
- max_labels : ., mut = 0;
- sfi : ., mut = 0;
- loop { if sfi >= g_ir_func_count { break; }
- ist2 := r64(g_ir_func_instr_start, sfi * 8);
- ic2 := r64(g_ir_func_instr_count, sfi * 8);
+ max_labels : ., mut = 0
+ sfi : ., mut = 0
+ loop:
+ if sfi >= g_ir_func_count:
+ break
+ ist2 := r64(g_ir_func_instr_start, sfi * 8)
+ ic2 := r64(g_ir_func_instr_count, sfi * 8)
// Count label indices for g_label_poses allocation
- cur_labels : ., mut = 0;
- ii2 : ., mut = 0;
- loop { if ii2 >= ic2 { break; }
- op := iri_op(ist2 + ii2);
- if op == IR_LABEL { lx := iri_s1(ist2 + ii2); if lx >= 0 && lx + 1 > cur_labels { cur_labels = lx + 1; } }
- if op == IR_BRANCH { lx := iri_s2(ist2 + ii2); if lx + 1 > cur_labels { cur_labels = lx + 1; }
- ly := iri_s3(ist2 + ii2); if ly + 1 > cur_labels { cur_labels = ly + 1; } }
- if op == IR_JUMP { lz := iri_s1(ist2 + ii2); if lz + 1 > cur_labels { cur_labels = lz + 1; } }
- ii2 = ii2 + 1; }
- if cur_labels > max_labels { max_labels = cur_labels; }
- grow_func_code_sz(sfi + 1); w64(g_x86_func_code_sz, sfi * 8, ic2 * 5);
- sfi = sfi + 1; }
- g_label_count = max_labels;
-
- total_code : ., mut = emit_start_size();
- fi := 0; g2_init(); loop { if fi >= g_ir_func_count { break; }
- if fi % 50 == 0 { print(" func "); print(int_str(fi)); print("/"); println(int_str(g_ir_func_count)); }
- ni := r64(g_ir_func_name_idx, fi * 8);
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, ni);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
-
- vc2 := r64(g_ir_func_var_count, fi * 8);
- vs2 := r64(g_ir_func_var_start, fi * 8);
- pc2 := r64(g_ir_func_param_count, fi * 8);
+ cur_labels : ., mut = 0
+ ii2 : ., mut = 0
+ loop:
+ if ii2 >= ic2:
+ break
+ op := iri_op(ist2 + ii2)
+ if op == IR_LABEL:
+ lx := iri_s1(ist2 + ii2)
+ if lx >= 0 && lx + 1 > cur_labels:
+ cur_labels = lx + 1
+ if op == IR_BRANCH:
+ lx := iri_s2(ist2 + ii2)
+ if lx + 1 > cur_labels:
+ cur_labels = lx + 1
+ ly := iri_s3(ist2 + ii2)
+ if ly + 1 > cur_labels:
+ cur_labels = ly + 1
+ if op == IR_JUMP:
+ lz := iri_s1(ist2 + ii2)
+ if lz + 1 > cur_labels:
+ cur_labels = lz + 1
+ ii2 = ii2 + 1
+ if cur_labels > max_labels:
+ max_labels = cur_labels
+ grow_func_code_sz(sfi + 1)
+ w64(g_x86_func_code_sz, sfi * 8, ic2 * 5)
+ sfi = sfi + 1
+ g_label_count = max_labels
+
+ total_code : ., mut = emit_start_size()
+ fi := 0
+ g2_init()
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ if fi % 50 == 0:
+ print(" func ")
+ print(int_str(fi))
+ print("/")
+ println(int_str(g_ir_func_count))
+ ni := r64(g_ir_func_name_idx, fi * 8)
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, ni)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+
+ vc2 := r64(g_ir_func_var_count, fi * 8)
+ vs2 := r64(g_ir_func_var_start, fi * 8)
+ pc2 := r64(g_ir_func_param_count, fi * 8)
// int 多字 M1(Task 1):识别潜在多字变量并计入帧尺寸(tag 区)。
// tag 数为 0 → pf_frame_size 与旧公式逐字节一致(快路径零变化)。
- mw_setup_tags(fi, vs2, vc2);
- fsz := r64(g_x86_func_code_sz, fi * 8);
+ mw_setup_tags(fi, vs2, vc2)
+ fsz := r64(g_x86_func_code_sz, fi * 8)
// 帧尺寸/帧相关字节 = frame.cr 单源(H2):SysV 16 字节对齐(发现 11)
// ——call 后 rsp%16=8;opt≥1 有 6 个 push(rbx,r12-15,rbp)→ rsp%16=8
// → size 需 ≡8 (mod 16);opt<1 有 1 个 push(rbp)→ rsp%16=0 → ≡0。
// 本 dry-run 与 Phase 3 的 sub rsp 立即数**调用同一函数**(pf_frame_size
// ——双源合流);帧相关字节总数 = pf_frame_overhead(须与 pf_prologue/
// pf_epilogue 实际发射一致)。本文件零帧尺寸计算(H2 纪律)。
- g_x86_emit_stack_size = pf_frame_size(vc2);
- ss_dry := g_x86_emit_stack_size;
- total_code = total_code + pf_frame_overhead(ss_dry);
- reg_pc2 : ., mut = pc2;
- if reg_pc2 > 6 { reg_pc2 = 6; }
- stack_pc2 : ., mut = pc2 - 6;
- if stack_pc2 < 0 { stack_pc2 = 0; }
- total_code = total_code + reg_pc2 * sz_save_param();
- total_code = total_code + stack_pc2 * sz_save_stack_param();
- total_code = total_code + fsz;
- fi = fi + 1; }
-
- rd_sz := g2_rodata_sz();
- total_code = total_code + 6; // _init_globals
+ g_x86_emit_stack_size = pf_frame_size(vc2)
+ ss_dry := g_x86_emit_stack_size
+ total_code = total_code + pf_frame_overhead(ss_dry)
+ reg_pc2 : ., mut = pc2
+ if reg_pc2 > 6:
+ reg_pc2 = 6
+ stack_pc2 : ., mut = pc2 - 6
+ if stack_pc2 < 0:
+ stack_pc2 = 0
+ total_code = total_code + reg_pc2 * sz_save_param()
+ total_code = total_code + stack_pc2 * sz_save_stack_param()
+ total_code = total_code + fsz
+ fi = fi + 1
+
+ rd_sz := g2_rodata_sz()
+ total_code = total_code + 6 // _init_globals
// alloc: bump allocator for heap allocation in ELF output
// Find alloc's name index in .ccr string table (not runtime str_intern)
- alloc_ni : ., mut = -1;
- asi : ., mut = 0;
- loop { if asi >= g_str_count { break; }
- if str_eq(istr_get(asi), "alloc") != 0 { alloc_ni = asi; break; }
- asi = asi + 1; }
- if alloc_ni < 0 { alloc_ni = str_intern("alloc"); }
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, alloc_ni);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + 330; // arena-aware dual-path alloc body (~323 bytes with OOM check + zero-init + chain-expand + current-arena check)
+ alloc_ni : ., mut = -1
+ asi : ., mut = 0
+ loop:
+ if asi >= g_str_count:
+ break
+ if str_eq(istr_get(asi), "alloc") != 0:
+ alloc_ni = asi
+ break
+ asi = asi + 1
+ if alloc_ni < 0:
+ alloc_ni = str_intern("alloc")
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, alloc_ni)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + 330 // arena-aware dual-path alloc body (~323 bytes with OOM check + zero-init + chain-expand + current-arena check)
// heap_expand
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("heap_expand"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + 86; // heap_expand with allocator-state save/restore
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("heap_expand"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + 86 // heap_expand with allocator-state save/restore
// sched_call trampolines (0..4)
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_0"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + sched_tramp_sz(0);
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_1"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + sched_tramp_sz(1);
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_2"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + sched_tramp_sz(2);
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_3"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + sched_tramp_sz(3);
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_4"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + sched_tramp_sz(4);
- if g_x86_emit_rt_stubs != 0 {
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_0"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + sched_tramp_sz(0)
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_1"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + sched_tramp_sz(1)
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_2"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + sched_tramp_sz(2)
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_3"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + sched_tramp_sz(3)
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("sched_call_4"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + sched_tramp_sz(4)
+ if g_x86_emit_rt_stubs != 0:
// g_set_curg / g_get_curg bridges (11 bytes each) — pure-static self-containment
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("g_set_curg"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + 11;
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("g_get_curg"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- total_code = total_code + 11;
- }
-
- hdr_total : ., mut = EHDR_SIZE + 2 * PHDR_SIZE;
- rodata_base := total_code;
- g_x86_rodata_base = hdr_total + rodata_base;
-
- println(" elf: Phase 3 (emit)...");
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("g_set_curg"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + 11
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("g_get_curg"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, total_code)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ total_code = total_code + 11
+
+ hdr_total : ., mut = EHDR_SIZE + 2 * PHDR_SIZE
+ rodata_base := total_code
+ g_x86_rodata_base = hdr_total + rodata_base
+
+ println(" elf: Phase 3 (emit)...")
// Phase 3: emit to buffer
- cp := hdr_total; // skip ELF header + program headers
+ cp := hdr_total // skip ELF header + program headers
// NB: g_x86_is_global already marked before Phase 0 — no need to redo
// ── _start (measured size from Phase 2) ──
- cp = cp + emit_start(buf, cp);
+ cp = cp + emit_start(buf, cp)
// ── All functions ──
- g_x86_ret_patch_count = 0;
- g_x86_call_patch_count = 0;
- g_x86_fnaddr_patch_count = 0;
- g_x86_rodataref_count = 0;
- g_x86_alloc_patch_count = 0;
- g_x86_ext_rel_count = 0;
-fi = 0; loop { if fi >= g_ir_func_count { break; }
- if fi % 50 == 0 { print(" emit func "); print(int_str(fi)); print("/"); println(int_str(g_ir_func_count)); }
- ni := r64(g_ir_func_name_idx, fi * 8);
- grow_func_cp(fi + 1); w64(g_x86_func_cp, fi * 8, cp);
+ g_x86_ret_patch_count = 0
+ g_x86_call_patch_count = 0
+ g_x86_fnaddr_patch_count = 0
+ g_x86_rodataref_count = 0
+ g_x86_alloc_patch_count = 0
+ g_x86_ext_rel_count = 0
+ fi = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ if fi % 50 == 0:
+ print(" emit func ")
+ print(int_str(fi))
+ print("/")
+ println(int_str(g_ir_func_count))
+ ni := r64(g_ir_func_name_idx, fi * 8)
+ grow_func_cp(fi + 1)
+ w64(g_x86_func_cp, fi * 8, cp)
// Override with actual position for backward calls
- fi3 := 0; loop { if fi3 >= g_x86_func_off_count { break; }
- if str_eq(istr_get(r64(g_x86_func_offsets, fi3*16)), istr_get(ni)) != 0 {
- w64(g_x86_func_offsets, fi3*16+8, cp - 176);
- break; }
- fi3 = fi3 + 1; }
- ist := r64(g_ir_func_instr_start, fi * 8);
- ic := r64(g_ir_func_instr_count, fi * 8);
- vc := r64(g_ir_func_var_count, fi * 8);
- vs := r64(g_ir_func_var_start, fi * 8);
- pc := r64(g_ir_func_param_count, fi * 8);
-
- g2_init();
- g_current_func_var_start = vs;
- vi := 0; loop { if vi >= vc { break; } g2_slot(vs + vi); vi = vi + 1; }
+ fi3 := 0
+ loop:
+ if fi3 >= g_x86_func_off_count:
+ break
+ if str_eq(istr_get(r64(g_x86_func_offsets, fi3*16)), istr_get(ni)) != 0:
+ w64(g_x86_func_offsets, fi3*16+8, cp - 176)
+ break
+ fi3 = fi3 + 1
+ ist := r64(g_ir_func_instr_start, fi * 8)
+ ic := r64(g_ir_func_instr_count, fi * 8)
+ vc := r64(g_ir_func_var_count, fi * 8)
+ vs := r64(g_ir_func_var_start, fi * 8)
+ pc := r64(g_ir_func_param_count, fi * 8)
+
+ g2_init()
+ g_current_func_var_start = vs
+ vi := 0
+ loop:
+ if vi >= vc:
+ break
+ g2_slot(vs + vi)
+ vi = vi + 1
// int 多字 M1(Task 1):潜在多字变量识别 + tag 字节偏移表(g2_tag_off)。
// 帧尺寸 = pf_frame_size(vc)(含 tag 区,16 对齐规则与 Phase 2 dry run
// 同源);tag 数为 0 → 与旧布局逐字节一致。
- mw_setup_tags(fi, vs, vc);
+ mw_setup_tags(fi, vs, vc)
// SysV 16 字节对齐(发现 11):与 dry run 相同的对齐规则
- g_x86_emit_stack_size = pf_frame_size(vc);
+ g_x86_emit_stack_size = pf_frame_size(vc)
// Init label state for single-pass backpatching (-1 = not yet seen)
- li2 : ., mut = 0;
- loop { if li2 >= g_label_count { break; } grow_label_poses(li2 + 1); w64(g_label_poses, li2*8, -1); li2 = li2 + 1; }
- g_pending_count = 0;
+ li2 : ., mut = 0
+ loop:
+ if li2 >= g_label_count:
+ break
+ grow_label_poses(li2 + 1)
+ w64(g_label_poses, li2*8, -1)
+ li2 = li2 + 1
+ g_pending_count = 0
// ── 序言 + 形参落槽 + 寄存器参数装载(frame.cr pf_prologue)──
// 帧 setup(opt≥1 六寄存器保存 → push rbp/mov rbp,rsp → sub rsp 占位
// 立即数)+ 形参落槽(XMM/int/栈参 + tag 卫生③参数行清 tag)+ 寄存器
// 分配参数装载。帧序唯一发射器(H2 ③);ss = pf_frame_size 结果。
- cp = pf_prologue(vs, pc, g_x86_emit_stack_size, buf, cp);
+ cp = pf_prologue(vs, pc, g_x86_emit_stack_size, buf, cp)
// function body — emit instructions
- g_x86_func_frame_start = cp; // absolute buffer pos of body start
- save_ss := g_x86_emit_stack_size; // save frame size before emission
-
- ii := 0; loop { if ii >= ic { break; }
- inst_idx := ist + ii;
+ g_x86_func_frame_start = cp // absolute buffer pos of body start
+ save_ss := g_x86_emit_stack_size // save frame size before emission
+
+ ii := 0
+ loop:
+ if ii >= ic:
+ break
+ inst_idx := ist + ii
// HIT 表模式(M1 Task 2):表映射 op 走 emit_instr_tabled;
// -1(未映射/形态不支持/无表)落旧路径 emit_instr——混合模式。
// int 多字 M1(Task 2):tagged int add/sub 需溢出跳(jo)——
// 表路径(hit_ev 降低不知 tag/无 jo 事件)整条排除落旧路径。
- jo_before := g_x86_mw_jo_count; // Task 3:站点回跳点记录
- oc_before := g_x86_mw_oc_count; // Task 4:2L 操作数站点回跳点记录
- sz : ., mut = -1;
- if hit_table_active() != 0 && mw_int_arith_jo_needed(inst_idx) == 0 {
- sz = emit_instr_tabled(inst_idx, buf, cp);
- }
- if sz < 0 { sz = emit_instr(inst_idx, buf, cp); }
+ jo_before := g_x86_mw_jo_count // Task 3:站点回跳点记录
+ oc_before := g_x86_mw_oc_count // Task 4:2L 操作数站点回跳点记录
+ sz : ., mut = -1
+ if hit_table_active() != 0 && mw_int_arith_jo_needed(inst_idx) == 0:
+ sz = emit_instr_tabled(inst_idx, buf, cp)
+ if sz < 0:
+ sz = emit_instr(inst_idx, buf, cp)
// Task 3:本指令若发射了 jo(至多 1 站点/指令——add/sub 单点),
// 其回跳点 = 快路径 e2_st 之后的指令尾(绝对位置 cp+sz)——慢路径
// 块跳回后从此继续(跳走即跳过该 store;dest 由块自行回存)。
- if g_x86_mw_jo_count > jo_before {
- w64(g_x86_mw_jo_resume, (g_x86_mw_jo_count - 1) * 8, cp + sz);
- }
+ if g_x86_mw_jo_count > jo_before:
+ w64(g_x86_mw_jo_resume, (g_x86_mw_jo_count - 1) * 8, cp + sz)
// Task 4:本指令若新建了 2L 操作数站点(至多 1/指令),其块回跳点
// 同样 = 指令尾(tag 清 0 之后——2L 块自写 tag 不受影响)。
- if g_x86_mw_oc_count > oc_before {
- w64(g_x86_mw_oc_resume, (g_x86_mw_oc_count - 1) * 8, cp + sz);
- }
- cp = cp + sz;
- ii = ii + 1; }
+ if g_x86_mw_oc_count > oc_before:
+ w64(g_x86_mw_oc_resume, (g_x86_mw_oc_count - 1) * 8, cp + sz)
+ cp = cp + sz
+ ii = ii + 1
// ── 尾声 + 函数尾附加块(frame.cr pf_epilogue)──
// RETURN patch → sub rsp 立即数回填(save_ss = 本函数帧字节)→
// epilogue(add rsp/opt≥1 逆序 pop/pop rbp/ret)→ jo 慢路径块 +
// 2L 操作数块(函数尾冷区)。帧序唯一发射器(H2 ③)。
- cp = pf_epilogue(save_ss, buf, cp);
- fi = fi + 1; }
+ cp = pf_epilogue(save_ss, buf, cp)
+ fi = fi + 1
// ── M2a Task 2:事件流 rel32 回填(回填表 kind 0 = 事件流位置)──
// jump 事件于事件字节发射期登记(instr.cr hit_rel_add);目标 = 事件序 →
@@ -1176,378 +1911,474 @@ fi = 0; loop { if fi >= g_ir_func_count { break; }
// 函数尾控制流下经自举编译器生成的边界读 = 未初始化栈槽(dir 目录构建
// corearch 的 stage1 场景 segv;concat 构建因陈旧栈值恰为 0 而潜伏),
// 重构后边界读落已写局部。语义零变化;缺陷 = 编译器层潜在面(待核注记)。
- hri2 : ., mut = g_hit_rel_count;
- if hri2 > 0 {
- hri : ., mut = 0;
- loop {
- if hri >= hri2 { break; }
- rk := r64(g_hit_rel, hri * 24);
- rp := r64(g_hit_rel, hri * 24 + 8);
- rt := r64(g_hit_rel, hri * 24 + 16);
- if rk == 0 {
- if rt >= 0 && rt < g_hit_ev_pos_count {
- tp := r64(g_hit_ev_pos, rt * 8);
- w32(buf, rp, tp - (rp + 4));
- } else {
- print(" MISSING event position for rel target ordinal ");
- println(int_str(rt));
- }
- } else {
- print(" BAD rel kind ");
- print(int_str(rk));
- println(" (func/extern backfill = Task 4/5)");
- }
- hri = hri + 1; }
- }
- g_hit_rel_count = 0;
+ hri2 : ., mut = g_hit_rel_count
+ if hri2 > 0:
+ hri : ., mut = 0
+ loop:
+ if hri >= hri2:
+ break
+ rk := r64(g_hit_rel, hri * 24)
+ rp := r64(g_hit_rel, hri * 24 + 8)
+ rt := r64(g_hit_rel, hri * 24 + 16)
+ if rk == 0:
+ if rt >= 0 && rt < g_hit_ev_pos_count:
+ tp := r64(g_hit_ev_pos, rt * 8)
+ w32(buf, rp, tp - (rp + 4))
+ else:
+ print(" MISSING event position for rel target ordinal ")
+ println(int_str(rt))
+ else:
+ print(" BAD rel kind ")
+ print(int_str(rk))
+ println(" (func/extern backfill = Task 4/5)")
+ hri = hri + 1
+ g_hit_rel_count = 0
// ── _init_globals ──
- w8(buf, cp, 85); cp = cp + 1;
- w8(buf, cp, 72); w8(buf, cp+1, 137); w8(buf, cp+2, 229); cp = cp + 3;
- w8(buf, cp, 93); cp = cp + 1;
- w8(buf, cp, 195); cp = cp + 1;
+ w8(buf, cp, 85)
+ cp = cp + 1
+ w8(buf, cp, 72)
+ w8(buf, cp+1, 137)
+ w8(buf, cp+2, 229)
+ cp = cp + 3
+ w8(buf, cp, 93)
+ cp = cp + 1
+ w8(buf, cp, 195)
+ cp = cp + 1
// ── alloc (bump allocator) ──
// BSS VA will be computed after all code emitted — placeholder for now
- bss_va := ((TEXT_BASE + cp + 4096 + 4095) / 4096) * 4096;
-
- max_gv : ., mut = 0;
- gsi : ., mut = 0;
- loop { if gsi >= g_ir_global_count { break; }
- gvv := r64(g_ir_globals, gsi * 24 + 8);
- if gvv >= 0 && gvv > max_gv { max_gv = gvv; }
- gsi = gsi + 1; }
+ bss_va := ((TEXT_BASE + cp + 4096 + 4095) / 4096) * 4096
+
+ max_gv : ., mut = 0
+ gsi : ., mut = 0
+ loop:
+ if gsi >= g_ir_global_count:
+ break
+ gvv := r64(g_ir_globals, gsi * 24 + 8)
+ if gvv >= 0 && gvv > max_gv:
+ max_gv = gvv
+ gsi = gsi + 1
// globals_size = (max_var_idx + 1) * 8 ensures BSS covers all globals
- globals_size : ., mut = (max_gv + 1) * 8;
- if globals_size < 256 { globals_size = 256; }
- if g_x86_emit_rt_stubs != 0 { globals_size = globals_size + 8; } // + current_g slot
- alloc_sz := emit_alloc_body(buf, cp, bss_va, globals_size);
- alloc_start := cp;
- g_curg_stub_start : ., mut = -1;
- cp = cp + alloc_sz;
+ globals_size : ., mut = (max_gv + 1) * 8
+ if globals_size < 256:
+ globals_size = 256
+ if g_x86_emit_rt_stubs != 0:
+ globals_size = globals_size + 8
+ // + current_g slot
+ alloc_sz := emit_alloc_body(buf, cp, bss_va, globals_size)
+ alloc_start := cp
+ g_curg_stub_start : ., mut = -1
+ cp = cp + alloc_sz
// ── heap_expand ──
- heap_expand_start : ., mut = cp;
- cp = cp + emit_heap_expand(buf, cp, bss_va);
+ heap_expand_start : ., mut = cp
+ cp = cp + emit_heap_expand(buf, cp, bss_va)
// Update heap_expand's offset in func_offsets to real position (Phase 3 value)
- hefi := 0;
- loop { if hefi >= g_x86_func_off_count { break; }
- if str_eq(istr_get(r64(g_x86_func_offsets, hefi*16)), "heap_expand") != 0 {
- w64(g_x86_func_offsets, hefi*16+8, heap_expand_start - 176);
- break; }
- hefi = hefi + 1; }
+ hefi := 0
+ loop:
+ if hefi >= g_x86_func_off_count:
+ break
+ if str_eq(istr_get(r64(g_x86_func_offsets, hefi*16)), "heap_expand") != 0:
+ w64(g_x86_func_offsets, hefi*16+8, heap_expand_start - 176)
+ break
+ hefi = hefi + 1
// Update alloc's offset in func_offsets to real position (Phase 3 value)
- afi2 := 0;
- loop { if afi2 >= g_x86_func_off_count { break; }
- if str_eq(istr_get(r64(g_x86_func_offsets, afi2*16)), istr_get(alloc_ni)) != 0 {
- w64(g_x86_func_offsets, afi2*16+8, alloc_start - 176);
- break; }
- afi2 = afi2 + 1; }
+ afi2 := 0
+ loop:
+ if afi2 >= g_x86_func_off_count:
+ break
+ if str_eq(istr_get(r64(g_x86_func_offsets, afi2*16)), istr_get(alloc_ni)) != 0:
+ w64(g_x86_func_offsets, afi2*16+8, alloc_start - 176)
+ break
+ afi2 = afi2 + 1
// Patch all IR_ALLOC_STRUCT/ARRAY/MAKE_ENUM call sites to point to alloc
// alloc_patch_pos entries are buffer positions of the 5-byte call instruction
// alloc offset = alloc_start - 176 (relative to code section start)
- alloc_code_off := alloc_start - 176;
- api := 0;
- loop { if api >= g_x86_alloc_patch_count { break; }
- call_pos := r64(g_x86_alloc_patch_pos, api * 8);
- rel := (176 + alloc_code_off) - (call_pos + 5);
- w32(buf, call_pos + 1, rel);
- api = api + 1; }
- g_x86_alloc_patch_count = 0;
+ alloc_code_off := alloc_start - 176
+ api := 0
+ loop:
+ if api >= g_x86_alloc_patch_count:
+ break
+ call_pos := r64(g_x86_alloc_patch_pos, api * 8)
+ rel := (176 + alloc_code_off) - (call_pos + 5)
+ w32(buf, call_pos + 1, rel)
+ api = api + 1
+ g_x86_alloc_patch_count = 0
// ── arena_new/arena_reset stubs (fallback when arena.cr not imported) ──
// These are only used when the functions aren't compiled from user code.
// If the user imports arena, the compiled versions in g_ir_func_name_idx take priority.
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("arena_new"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, cp - 176);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- w8(buf, cp, 195); cp = cp + 1; // ret
-
- grow_func_offsets(g_x86_func_off_count * 2 + 2);
- w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("arena_reset"));
- w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, cp - 176);
- g_x86_func_off_count = g_x86_func_off_count + 1;
- w8(buf, cp, 195); cp = cp + 1; // ret
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("arena_new"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, cp - 176)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ w8(buf, cp, 195)
+ cp = cp + 1 // ret
+
+ grow_func_offsets(g_x86_func_off_count * 2 + 2)
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16, str_intern("arena_reset"))
+ w64(g_x86_func_offsets, g_x86_func_off_count * 16 + 8, cp - 176)
+ g_x86_func_off_count = g_x86_func_off_count + 1
+ w8(buf, cp, 195)
+ cp = cp + 1 // ret
// ── scheduler call trampolines ──
- sched_reg_one("sched_call_0", 0, cp);
- cp = cp + emit_sched_call(buf, cp, 0);
- sched_reg_one("sched_call_1", 1, cp);
- cp = cp + emit_sched_call(buf, cp, 1);
- sched_reg_one("sched_call_2", 2, cp);
- cp = cp + emit_sched_call(buf, cp, 2);
- sched_reg_one("sched_call_3", 3, cp);
- cp = cp + emit_sched_call(buf, cp, 3);
- sched_reg_one("sched_call_4", 4, cp);
- cp = cp + emit_sched_call(buf, cp, 4);
+ sched_reg_one("sched_call_0", 0, cp)
+ cp = cp + emit_sched_call(buf, cp, 0)
+ sched_reg_one("sched_call_1", 1, cp)
+ cp = cp + emit_sched_call(buf, cp, 1)
+ sched_reg_one("sched_call_2", 2, cp)
+ cp = cp + emit_sched_call(buf, cp, 2)
+ sched_reg_one("sched_call_3", 3, cp)
+ cp = cp + emit_sched_call(buf, cp, 3)
+ sched_reg_one("sched_call_4", 4, cp)
+ cp = cp + emit_sched_call(buf, cp, 4)
// ── g_set_curg / g_get_curg bridge stubs (pure-static self-contained runtime) ──
// Provisional BSS VA (0); re-emitted in place after final bss_va is known.
- if g_x86_emit_rt_stubs != 0 {
- g_curg_stub_start = cp;
- cp = cp + emit_curg_stubs(buf, cp, 0);
+ if g_x86_emit_rt_stubs != 0:
+ g_curg_stub_start = cp
+ cp = cp + emit_curg_stubs(buf, cp, 0)
// Update func_offsets entries to real positions (call_patch fallback uses these)
- gsi2 : ., mut = 0;
- loop { if gsi2 >= g_x86_func_off_count { break; }
- nm2 := istr_get(r64(g_x86_func_offsets, gsi2*16));
- if str_eq(nm2, "g_set_curg") != 0 { w64(g_x86_func_offsets, gsi2*16+8, g_curg_stub_start - 176); }
- if str_eq(nm2, "g_get_curg") != 0 { w64(g_x86_func_offsets, gsi2*16+8, g_curg_stub_start - 176 + 11); }
- gsi2 = gsi2 + 1; }
- }
+ gsi2 : ., mut = 0
+ loop:
+ if gsi2 >= g_x86_func_off_count:
+ break
+ nm2 := istr_get(r64(g_x86_func_offsets, gsi2*16))
+ if str_eq(nm2, "g_set_curg") != 0:
+ w64(g_x86_func_offsets, gsi2*16+8, g_curg_stub_start - 176)
+ if str_eq(nm2, "g_get_curg") != 0:
+ w64(g_x86_func_offsets, gsi2*16+8, g_curg_stub_start - 176 + 11)
+ gsi2 = gsi2 + 1
// ── Goroutine runtime stubs (fiber_init / fiber_switch / goroutine_entry_wrapper) ──
// Required by g_new → go f(): the wrapper is the fiber entry, fiber_init
// builds the fake frame, fiber_switch performs the context switch.
// Registered in func_offsets so IR_CALL (fiber_init/fiber_switch from
// Core) and IR_FNADDR (@addr(goroutine_entry_wrapper)) resolve here.
- if g_x86_emit_rt_stubs != 0 {
- sched_reg_one("fiber_init", 0, cp);
- sched_reg_one("fiber_switch", 0, cp + 20);
- sched_reg_one("goroutine_entry_wrapper", 0, cp + 47);
- cp = cp + emit_goroutine_stubs(buf, cp);
+ if g_x86_emit_rt_stubs != 0:
+ sched_reg_one("fiber_init", 0, cp)
+ sched_reg_one("fiber_switch", 0, cp + 20)
+ sched_reg_one("goroutine_entry_wrapper", 0, cp + 47)
+ cp = cp + emit_goroutine_stubs(buf, cp)
// m_start_workers — worker thread launcher (clone). worker_entry
// (15 bytes) precedes the public entry so its RIP-relative LEA stays
// backward; register the public symbol at cp + 15.
- sched_reg_one("m_start_workers", 0, cp + 15);
- cp = cp + emit_m_start_workers(buf, cp);
- }
+ sched_reg_one("m_start_workers", 0, cp + 15)
+ cp = cp + emit_m_start_workers(buf, cp)
// ── Patch forward calls using actual cp positions ──
// Phase 3 stored cp at start of each function in g_x86_func_cp
// Must run after ALL code emitted (incl alloc + sched_call) so func_offsets are final
- cpi := 0; loop { if cpi >= g_x86_call_patch_count { break; }
- call_pos := r64(g_x86_call_patch_pos, cpi * 8);
- fn_ni := r64(g_x86_call_patch_name, cpi * 8);
- cfi2 : ., mut = 0;
- loop { if cfi2 >= g_ir_func_count { break; }
- name_at := r64(g_ir_func_name_idx, cfi2 * 8);
- if str_eq(istr_get(name_at), istr_get(fn_ni)) != 0 {
- func_cp := r64(g_x86_func_cp, cfi2 * 8);
- if func_cp > 0 {
- rel := func_cp - (call_pos + 5);
- w32(buf, call_pos + 1, rel);
- }
- break; }
- cfi2 = cfi2 + 1; }
+ cpi := 0
+ loop:
+ if cpi >= g_x86_call_patch_count:
+ break
+ call_pos := r64(g_x86_call_patch_pos, cpi * 8)
+ fn_ni := r64(g_x86_call_patch_name, cpi * 8)
+ cfi2 : ., mut = 0
+ loop:
+ if cfi2 >= g_ir_func_count:
+ break
+ name_at := r64(g_ir_func_name_idx, cfi2 * 8)
+ if str_eq(istr_get(name_at), istr_get(fn_ni)) != 0:
+ func_cp := r64(g_x86_func_cp, cfi2 * 8)
+ if func_cp > 0:
+ rel := func_cp - (call_pos + 5)
+ w32(buf, call_pos + 1, rel)
+ break
+ cfi2 = cfi2 + 1
// Fallback: search g_x86_func_offsets for builtins
- if cfi2 >= g_ir_func_count {
- bfi2 : ., mut = 0;
- loop { if bfi2 >= g_x86_func_off_count { break; }
- if str_eq(istr_get(r64(g_x86_func_offsets, bfi2*16)), istr_get(fn_ni)) != 0 {
- func_off := r64(g_x86_func_offsets, bfi2*16+8);
+ if cfi2 >= g_ir_func_count:
+ bfi2 : ., mut = 0
+ loop:
+ if bfi2 >= g_x86_func_off_count:
+ break
+ if str_eq(istr_get(r64(g_x86_func_offsets, bfi2*16)), istr_get(fn_ni)) != 0:
+ func_off := r64(g_x86_func_offsets, bfi2*16+8)
// Safety check: target must be within emitted code
- target_pos := 176 + func_off;
- if target_pos > 0 && target_pos < cp {
- rel := target_pos - (call_pos + 5);
- w32(buf, call_pos + 1, rel);
- }
- break; }
- bfi2 = bfi2 + 1; }
- }
- cpi = cpi + 1; }
- g_x86_call_patch_count = 0;
+ target_pos := 176 + func_off
+ if target_pos > 0 && target_pos < cp:
+ rel := target_pos - (call_pos + 5)
+ w32(buf, call_pos + 1, rel)
+ break
+ bfi2 = bfi2 + 1
+ cpi = cpi + 1
+ g_x86_call_patch_count = 0
// ── Patch function addresses (IR_FNADDR movabs placeholders) ──
// Each placeholder is a movabs r10, imm64 at an absolute buffer position.
// Resolve the same way as call patches: user functions by name in
// g_ir_func_name_idx/g_x86_func_cp, builtins via g_x86_func_offsets.
- fpi := 0; loop { if fpi >= g_x86_fnaddr_patch_count { break; }
- fp_pos := r64(g_x86_fnaddr_patch_pos, fpi * 8);
- fn_ni := r64(g_x86_fnaddr_patch_name, fpi * 8);
- fn_va : ., mut = 0;
- fcfi : ., mut = 0;
- loop { if fcfi >= g_ir_func_count { break; }
- name_at := r64(g_ir_func_name_idx, fcfi * 8);
- if str_eq(istr_get(name_at), istr_get(fn_ni)) != 0 {
- func_cp := r64(g_x86_func_cp, fcfi * 8);
- if func_cp > 0 { fn_va = TEXT_BASE + func_cp; }
- break; }
- fcfi = fcfi + 1; }
+ fpi := 0
+ loop:
+ if fpi >= g_x86_fnaddr_patch_count:
+ break
+ fp_pos := r64(g_x86_fnaddr_patch_pos, fpi * 8)
+ fn_ni := r64(g_x86_fnaddr_patch_name, fpi * 8)
+ fn_va : ., mut = 0
+ fcfi : ., mut = 0
+ loop:
+ if fcfi >= g_ir_func_count:
+ break
+ name_at := r64(g_ir_func_name_idx, fcfi * 8)
+ if str_eq(istr_get(name_at), istr_get(fn_ni)) != 0:
+ func_cp := r64(g_x86_func_cp, fcfi * 8)
+ if func_cp > 0:
+ fn_va = TEXT_BASE + func_cp
+ break
+ fcfi = fcfi + 1
// Fallback: search g_x86_func_offsets for builtins
- if fn_va == 0 {
- bfi3 : ., mut = 0;
- loop { if bfi3 >= g_x86_func_off_count { break; }
- if str_eq(istr_get(r64(g_x86_func_offsets, bfi3*16)), istr_get(fn_ni)) != 0 {
- func_off := r64(g_x86_func_offsets, bfi3*16+8);
- target_pos := 176 + func_off;
- if target_pos > 0 && target_pos < cp { fn_va = TEXT_BASE + target_pos; }
- break; }
- bfi3 = bfi3 + 1; }
- }
- if fn_va > 0 { w64(buf, fp_pos + 2, fn_va); } // imm64 placeholder starts after the 49 BB opcode
- fpi = fpi + 1; }
- g_x86_fnaddr_patch_count = 0;
+ if fn_va == 0:
+ bfi3 : ., mut = 0
+ loop:
+ if bfi3 >= g_x86_func_off_count:
+ break
+ if str_eq(istr_get(r64(g_x86_func_offsets, bfi3*16)), istr_get(fn_ni)) != 0:
+ func_off := r64(g_x86_func_offsets, bfi3*16+8)
+ target_pos := 176 + func_off
+ if target_pos > 0 && target_pos < cp:
+ fn_va = TEXT_BASE + target_pos
+ break
+ bfi3 = bfi3 + 1
+ if fn_va > 0:
+ w64(buf, fp_pos + 2, fn_va)
+ // imm64 placeholder starts after the 49 BB opcode
+ fpi = fpi + 1
+ g_x86_fnaddr_patch_count = 0
// Pad code to page boundary so RW segment doesn't share a page with RX
// (kernel maps shared page with RW permissions → code becomes non-executable)
- code_pad_end := (cp + 4095) / 4096 * 4096;
- loop { if cp >= code_pad_end { break; } w8(buf, cp, 0); cp = cp + 1; }
+ code_pad_end := (cp + 4095) / 4096 * 4096
+ loop:
+ if cp >= code_pad_end:
+ break
+ w8(buf, cp, 0)
+ cp = cp + 1
// Set rodata base from actual emission position
- g_x86_rodata_base = cp;
+ g_x86_rodata_base = cp
// Patch LEA rodata references (recorded during instr emission)
- rri : ., mut = 0;
- loop { if rri >= g_x86_rodataref_count { break; }
- lea_pos := r64(g_x86_rodataref_pos, rri * 8);
- ro_off := r64(g_x86_rodataref_ro, rri * 8);
- rel := g_x86_rodata_base + ro_off - (lea_pos + 7);
- w32(buf, lea_pos + 3, rel);
- rri = rri + 1; }
- g_x86_rodataref_count = 0;
+ rri : ., mut = 0
+ loop:
+ if rri >= g_x86_rodataref_count:
+ break
+ lea_pos := r64(g_x86_rodataref_pos, rri * 8)
+ ro_off := r64(g_x86_rodataref_ro, rri * 8)
+ rel := g_x86_rodata_base + ro_off - (lea_pos + 7)
+ w32(buf, lea_pos + 3, rel)
+ rri = rri + 1
+ g_x86_rodataref_count = 0
// ── .rodata ──
- si = 0; loop { if si >= g_x86_str_count { break; }
- s := istr_get(r64(g_x86_str_offs, si * 8));
- sl := str_len(s);
+ si = 0
+ loop:
+ if si >= g_x86_str_count:
+ break
+ s := istr_get(r64(g_x86_str_offs, si * 8))
+ sl := str_len(s)
// Write 8-byte length header (sl + null) so str_len via load64(s,-8) works
- w64(buf, cp, sl + 1); cp = cp + 8;
- ci := 0; loop { if ci >= sl { break; } w8(buf, cp, load8(s, ci)); ci = ci + 1; cp = cp + 1; }
- w8(buf, cp, 0); cp = cp + 1;
- loop { if cp % 8 == 0 { break; } w8(buf, cp, 0); cp = cp + 1; }
- si = si + 1; }
+ w64(buf, cp, sl + 1)
+ cp = cp + 8
+ ci := 0
+ loop:
+ if ci >= sl:
+ break
+ w8(buf, cp, load8(s, ci))
+ ci = ci + 1
+ cp = cp + 1
+ w8(buf, cp, 0)
+ cp = cp + 1
+ loop:
+ if cp % 8 == 0:
+ break
+ w8(buf, cp, 0)
+ cp = cp + 1
+ si = si + 1
// ── HIT const pool(M1 Task 3 合成层:lower 常量池 → rodata)──
// 池引用(mov r64, [rip+disp32] 占位)在函数发射期间记录(instr.cr 编码器);
// 字符串区定稿后回填 disp(池区紧随字符串,8B/槽、8 对齐不破)。
- hpr : ., mut = 0;
- loop { if hpr >= g_hit_pool_patch_count { break; }
- pp := r64(g_hit_pool_patch, hpr * 16);
- pk := r64(g_hit_pool_patch, hpr * 16 + 8);
- rel := cp + pk * 8 - (pp + 7);
- w32(buf, pp + 3, rel);
- hpr = hpr + 1; }
- g_hit_pool_patch_count = 0;
- hpk : ., mut = 0;
- loop { if hpk >= g_hit_pool_count { break; }
- w64(buf, cp + hpk * 8, r64(g_hit_pool, hpk * 8));
- hpk = hpk + 1; }
- cp = cp + g_hit_pool_count * 8;
+ hpr : ., mut = 0
+ loop:
+ if hpr >= g_hit_pool_patch_count:
+ break
+ pp := r64(g_hit_pool_patch, hpr * 16)
+ pk := r64(g_hit_pool_patch, hpr * 16 + 8)
+ rel := cp + pk * 8 - (pp + 7)
+ w32(buf, pp + 3, rel)
+ hpr = hpr + 1
+ g_hit_pool_patch_count = 0
+ hpk : ., mut = 0
+ loop:
+ if hpk >= g_hit_pool_count:
+ break
+ w64(buf, cp + hpk * 8, r64(g_hit_pool, hpk * 8))
+ hpk = hpk + 1
+ cp = cp + g_hit_pool_count * 8
// ── Recompute bss_va after all code emitted ──
// total_code from Phase 2 underestimates; use actual cp for precise calculation.
// +1 ensures BSS is on a different page from code.
- bss_va = ((TEXT_BASE + cp + 4096 + 4095) / 4096) * 4096;
+ bss_va = ((TEXT_BASE + cp + 4096 + 4095) / 4096) * 4096
// The allocator was emitted earlier with a provisional BSS address.
// Re-emit it in place now that the final data-segment VA is known.
- emit_alloc_body(buf, alloc_start, bss_va, globals_size);
+ emit_alloc_body(buf, alloc_start, bss_va, globals_size)
// Re-emit heap_expand with correct BSS VA
- emit_heap_expand(buf, heap_expand_start, bss_va);
+ emit_heap_expand(buf, heap_expand_start, bss_va)
// Re-emit g_set_curg/g_get_curg stubs with the final current_g BSS VA.
// Slot sits at the end of the globals region (globals_size includes +8).
- if g_x86_emit_rt_stubs != 0 && g_curg_stub_start >= 0 {
- curg_va := bss_va + 16 + globals_size - 8;
- emit_curg_stubs(buf, g_curg_stub_start, curg_va);
- }
+ if g_x86_emit_rt_stubs != 0 && g_curg_stub_start >= 0:
+ curg_va := bss_va + 16 + globals_size - 8
+ emit_curg_stubs(buf, g_curg_stub_start, curg_va)
// Patch call to heap_expand inside alloc body (re-emit wrote placeholder offset 0)
- if g_heap_expand_call_pos >= 0 {
- rel_he_call := heap_expand_start - (g_heap_expand_call_pos + 5);
- w32(buf, g_heap_expand_call_pos + 1, rel_he_call);
- g_heap_expand_call_pos = -1;
- }
+ if g_heap_expand_call_pos >= 0:
+ rel_he_call := heap_expand_start - (g_heap_expand_call_pos + 5)
+ w32(buf, g_heap_expand_call_pos + 1, rel_he_call)
+ g_heap_expand_call_pos = -1
// ── Allocate BSS for globals ──
- gi2 := 0; goff : ., mut = 0;
- loop { if gi2 >= g_ir_global_count { break; }
- gv2 := r64(g_ir_globals, gi2 * 24 + 8);
- if gv2 >= 0 { grow_global_off(gv2 + 1); w64(g_x86_global_off, gv2 * 8, goff); goff = goff + 8; }
- gi2 = gi2 + 1; }
+ gi2 := 0
+ goff : ., mut = 0
+ loop:
+ if gi2 >= g_ir_global_count:
+ break
+ gv2 := r64(g_ir_globals, gi2 * 24 + 8)
+ if gv2 >= 0:
+ grow_global_off(gv2 + 1)
+ w64(g_x86_global_off, gv2 * 8, goff)
+ goff = goff + 8
+ gi2 = gi2 + 1
// ── Patch global variable RIP-relative references ──
- rpi2 := 0;
- loop { if rpi2 >= g_x86_rip_patch_count { break; }
- ppos := r64(g_x86_rip_patch_pos, rpi2 * 8);
- gvi := r64(g_x86_rip_patch_globals, rpi2 * 8);
+ rpi2 := 0
+ loop:
+ if rpi2 >= g_x86_rip_patch_count:
+ break
+ ppos := r64(g_x86_rip_patch_pos, rpi2 * 8)
+ gvi := r64(g_x86_rip_patch_globals, rpi2 * 8)
// Verify: buffer at ppos-3 should contain LEA prefix (0x4C or 0x4D for REX.WR/WRB)
- lea_check := bu8(buf, ppos - 3);
- if lea_check != 72 && lea_check != 73 && lea_check != 76 && lea_check != 77 && lea_check != 74 && lea_check != 78 && lea_check != 79 && lea_check != 75 {
- print(" BAD rip["); print(int_str(rpi2)); print("] ppos="); print(int_str(ppos));
- print(" gvi="); print(int_str(gvi));
- print(" byte="); println(int_str(lea_check));
- }
- if gvi >= 0 {
- lea_end_va := TEXT_BASE + ppos + 4;
- off := r64(g_x86_global_off, gvi * 8);
- target_va := bss_va + 16 + off;
- rel := target_va - lea_end_va;
- w32(buf, ppos, rel);
+ lea_check := bu8(buf, ppos - 3)
+ if lea_check != 72 && lea_check != 73 && lea_check != 76 && lea_check != 77 && lea_check != 74 && lea_check != 78 && lea_check != 79 && lea_check != 75:
+ print(" BAD rip[")
+ print(int_str(rpi2))
+ print("] ppos=")
+ print(int_str(ppos))
+ print(" gvi=")
+ print(int_str(gvi))
+ print(" byte=")
+ println(int_str(lea_check))
+ if gvi >= 0:
+ lea_end_va := TEXT_BASE + ppos + 4
+ off := r64(g_x86_global_off, gvi * 8)
+ target_va := bss_va + 16 + off
+ rel := target_va - lea_end_va
+ w32(buf, ppos, rel)
// Verify write: read back and check
- rb0 := bu8(buf, ppos); rb1 := bu8(buf, ppos + 1);
- rb2 := bu8(buf, ppos + 2); rb3 := bu8(buf, ppos + 3);
- rbv : ., mut = rb0 + rb1 * 256 + rb2 * 65536;
- if rb3 >= 128 { rbv = rbv + (rb3 - 256) * 16777216; }
- else { rbv = rbv + rb3 * 16777216; }
- if rbv != rel && gvi >= 0 && gvi < 10 {
- print(" MISMATCH ppos="); print(int_str(ppos));
- print(" rel="); print(int_str(rel));
- print(" rbv="); println(int_str(rbv));
- }
- }
- rpi2 = rpi2 + 1; }
- g_x86_rip_patch_count = 0;
+ rb0 := bu8(buf, ppos)
+ rb1 := bu8(buf, ppos + 1)
+ rb2 := bu8(buf, ppos + 2)
+ rb3 := bu8(buf, ppos + 3)
+ rbv : ., mut = rb0 + rb1 * 256 + rb2 * 65536
+ if rb3 >= 128:
+ rbv = rbv + (rb3 - 256) * 16777216
+ else:
+ rbv = rbv + rb3 * 16777216
+ if rbv != rel && gvi >= 0 && gvi < 10:
+ print(" MISMATCH ppos=")
+ print(int_str(ppos))
+ print(" rel=")
+ print(int_str(rel))
+ print(" rbv=")
+ println(int_str(rbv))
+ rpi2 = rpi2 + 1
+ g_x86_rip_patch_count = 0
// ── Patch _start's call to main ──
// Search g_x86_func_offsets by name (indices differ from g_ir_func_name_idx)
- mo := -1; bfi3 := 0; loop { if bfi3 >= g_x86_func_off_count { break; }
- if str_eq(istr_get(r64(g_x86_func_offsets, bfi3*16)), "main") != 0 {
- mo = r64(g_x86_func_offsets, bfi3*16+8); break; }
- bfi3 = bfi3 + 1; }
+ mo := -1
+ bfi3 := 0
+ loop:
+ if bfi3 >= g_x86_func_off_count:
+ break
+ if str_eq(istr_get(r64(g_x86_func_offsets, bfi3*16)), "main") != 0:
+ mo = r64(g_x86_func_offsets, bfi3*16+8)
+ break
+ bfi3 = bfi3 + 1
// Debug: find ALL entries named "main"
- bfi4 := 0; loop { if bfi4 >= g_x86_func_off_count { break; }
- nm := istr_get(r64(g_x86_func_offsets, bfi4*16));
- if str_eq(nm, "main") != 0 {
- off := r64(g_x86_func_offsets, bfi4*16+8);
- print(" main at ["); print(int_str(bfi4)); print("] off="); print(int_str(off)); print(" cp="); println(int_str(off + 176));
- }
- bfi4 = bfi4 + 1; }
- if mo >= 0 {
- rel := mo + 176 - g_call_main_pos - 5;
- w32(buf, g_call_main_pos + 1, rel);
- }
+ bfi4 := 0
+ loop:
+ if bfi4 >= g_x86_func_off_count:
+ break
+ nm := istr_get(r64(g_x86_func_offsets, bfi4*16))
+ if str_eq(nm, "main") != 0:
+ off := r64(g_x86_func_offsets, bfi4*16+8)
+ print(" main at [")
+ print(int_str(bfi4))
+ print("] off=")
+ print(int_str(off))
+ print(" cp=")
+ println(int_str(off + 176))
+ bfi4 = bfi4 + 1
+ if mo >= 0:
+ rel := mo + 176 - g_call_main_pos - 5
+ w32(buf, g_call_main_pos + 1, rel)
// ── bss_init: zero BSS globals area before _start ──
// WSL2 (and possibly other kernels) do not reliably zero BSS,
// so we explicitly clear the first BSS_ZERO_SIZE bytes with
// rep stosb. This stub becomes the new entry point; after
// zeroing it jumps to the real _start.
- bss_init_cp := cp;
- BSS_ZERO_SIZE : int = 131072; // 128 KB — covers all globals
+ bss_init_cp := cp
+ BSS_ZERO_SIZE : int = 131072 // 128 KB — covers all globals
// lea rdi, [rip + rel] → rdi = bss_va
- rel_di := bss_va - (TEXT_BASE + cp + 7);
- w8(buf, cp, 72); w8(buf, cp+1, 141); w8(buf, cp+2, 61);
- w8_signed(buf, cp+3, rel_di); cp = cp + 7;
+ rel_di := bss_va - (TEXT_BASE + cp + 7)
+ w8(buf, cp, 72)
+ w8(buf, cp+1, 141)
+ w8(buf, cp+2, 61)
+ w8_signed(buf, cp+3, rel_di)
+ cp = cp + 7
// mov ecx, BSS_ZERO_SIZE
- w8(buf, cp, 185); e2_w32(buf, cp+1, BSS_ZERO_SIZE); cp = cp + 5;
+ w8(buf, cp, 185)
+ e2_w32(buf, cp+1, BSS_ZERO_SIZE)
+ cp = cp + 5
// xor eax, eax; cld; rep stosb
- w8(buf, cp, 49); w8(buf, cp+1, 192); cp = cp + 2;
- w8(buf, cp, 252); cp = cp + 1;
- w8(buf, cp, 243); w8(buf, cp+1, 170); cp = cp + 2;
+ w8(buf, cp, 49)
+ w8(buf, cp+1, 192)
+ cp = cp + 2
+ w8(buf, cp, 252)
+ cp = cp + 1
+ w8(buf, cp, 243)
+ w8(buf, cp+1, 170)
+ cp = cp + 2
// jmp _start (TEXT_BASE + 176)
- jmp_rel := TEXT_BASE + 176 - (TEXT_BASE + cp + 5);
- w8(buf, cp, 233); e2_w32(buf, cp+1, jmp_rel); cp = cp + 5;
+ jmp_rel := TEXT_BASE + 176 - (TEXT_BASE + cp + 5)
+ w8(buf, cp, 233)
+ e2_w32(buf, cp+1, jmp_rel)
+ cp = cp + 5
// ── Write ELF header ──
- total_sz := cp;
+ total_sz := cp
// Use actual total_sz as code_end so code segment covers all emitted content
- elf2_hdr(buf, total_sz, total_sz);
+ elf2_hdr(buf, total_sz, total_sz)
// Override entry point to bss_init (which zeroes heap then jumps to _start)
- w64(buf, E_ENTRY, TEXT_BASE + bss_init_cp);
+ w64(buf, E_ENTRY, TEXT_BASE + bss_init_cp)
// Patch data segment VA to match bss_va (page after code+rodata)
- data_phdr_base := EHDR_SIZE + PHDR_SIZE;
- w64(buf, data_phdr_base + P_OFFSET, bss_va - TEXT_BASE);
- w64(buf, data_phdr_base + P_VADDR, bss_va);
- w64(buf, data_phdr_base + P_PADDR, bss_va);
- g_asm_code_size = total_sz;
- return total_sz;
-}
+ data_phdr_base := EHDR_SIZE + PHDR_SIZE
+ w64(buf, data_phdr_base + P_OFFSET, bss_va - TEXT_BASE)
+ w64(buf, data_phdr_base + P_VADDR, bss_va)
+ w64(buf, data_phdr_base + P_PADDR, bss_va)
+ g_asm_code_size = total_sz
+ return total_sz
diff --git a/src/format/elf/ld.cr b/src/format/elf/ld.cr
index 7522a617..1cfd3ade 100644
--- a/src/format/elf/ld.cr
+++ b/src/format/elf/ld.cr
@@ -24,372 +24,672 @@
// ============================================================
-SHT_DYNAMIC : int = 6;
-SHT_DYNSYM : int = 11;
-STB_GLOBAL : int = 1;
-STT_FUNC : int = 2;
-SHN_UNDEF : int = 0;
-DT_NULL : int = 0;
-DT_NEEDED : int = 1;
-DT_PLTGOT : int = 3;
-DT_STRTAB : int = 5;
-DT_SYMTAB : int = 6;
-DT_STRSZ : int = 10;
-DT_SYMENT : int = 11;
-DT_PLTRELSZ : int = 2;
-DT_PLTREL : int = 20;
-DT_JMPREL : int = 23;
+SHT_DYNAMIC : int = 6
+SHT_DYNSYM : int = 11
+STB_GLOBAL : int = 1
+STT_FUNC : int = 2
+SHN_UNDEF : int = 0
+DT_NULL : int = 0
+DT_NEEDED : int = 1
+DT_PLTGOT : int = 3
+DT_STRTAB : int = 5
+DT_SYMTAB : int = 6
+DT_STRSZ : int = 10
+DT_SYMENT : int = 11
+DT_PLTRELSZ : int = 2
+DT_PLTREL : int = 20
+DT_JMPREL : int = 23
// ============================================================
// .so tracking
// ============================================================
-g_so_paths : string, mut; g_so_count : int, mut; g_so_cap : int, mut;
-
-fn dyn_grow_so(needed: int) {
- if needed < g_so_cap { return; }
- nc : ., mut = g_so_cap * 2; if nc < 4 { nc = 4; } if nc < needed { nc = needed + 4; }
- nb := alloc(nc * 8); _dyncpy(g_so_paths, g_so_cap * 8, nb); g_so_paths = nb; g_so_cap = nc; }
-
-struct PltEntry { name: string, so_idx: int }
-g_plts : string, mut; g_plt_count : int, mut; g_plt_cap : int, mut;
-
-fn dyn_grow_plts(needed: int) {
- if needed < g_plt_cap { return; }
- nc : ., mut = g_plt_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; }
- nb := alloc(nc * 16); _dyncpy(g_plts, g_plt_cap * 16, nb); g_plts = nb; g_plt_cap = nc; }
+g_so_paths : string, mut
+g_so_count : int, mut
+g_so_cap : int, mut
+
+fn dyn_grow_so(needed: int):
+ if needed < g_so_cap:
+ return
+ nc : ., mut = g_so_cap * 2
+ if nc < 4:
+ nc = 4
+ if nc < needed:
+ nc = needed + 4
+ nb := alloc(nc * 8)
+ _dyncpy(g_so_paths, g_so_cap * 8, nb)
+ g_so_paths = nb
+ g_so_cap = nc
+
+struct PltEntry:
+ name: string, so_idx: int
+g_plts : string, mut
+g_plt_count : int, mut
+g_plt_cap : int, mut
+
+fn dyn_grow_plts(needed: int):
+ if needed < g_plt_cap:
+ return
+ nc : ., mut = g_plt_cap * 2
+ if nc < 16:
+ nc = 16
+ if nc < needed:
+ nc = needed + 16
+ nb := alloc(nc * 16)
+ _dyncpy(g_plts, g_plt_cap * 16, nb)
+ g_plts = nb
+ g_plt_cap = nc
// ============================================================
// Linker state
// ============================================================
-g_user_code : string, mut;
-g_user_size : int, mut;
-g_text_base : int, mut;
+g_user_code : string, mut
+g_user_size : int, mut
+g_text_base : int, mut
// Flat chunk arrays (avoid struct array compiler limitation)
-g_ch_kind : string, mut; g_ch_kind_cap : int, mut;
-g_ch_vaddr : string, mut; g_ch_vaddr_cap : int, mut;
-g_ch_foff : string, mut; g_ch_foff_cap : int, mut;
-g_ch_size : string, mut; g_ch_size_cap : int, mut;
-g_ch_count : int, mut;
+g_ch_kind : string, mut
+g_ch_kind_cap : int, mut
+g_ch_vaddr : string, mut
+g_ch_vaddr_cap : int, mut
+g_ch_foff : string, mut
+g_ch_foff_cap : int, mut
+g_ch_size : string, mut
+g_ch_size_cap : int, mut
+g_ch_count : int, mut
// ============================================================
// Chunk helpers
// ============================================================
-fn grow_chunks(needed: int) {
- nc : ., mut = g_ch_kind_cap * 2; if nc < 8 { nc = 8; } if nc < needed { nc = needed + 8; }
- nb := alloc(nc * 8); zi : ., mut = 0; loop { if zi >= nc * 8 { break; } store8(nb, zi, 0); zi = zi + 1; } _dyncpy(g_ch_kind, g_ch_kind_cap * 8, nb); g_ch_kind = nb; g_ch_kind_cap = nc;
- nb2 := alloc(nc * 8); zi = 0; loop { if zi >= nc * 8 { break; } store8(nb2, zi, 0); zi = zi + 1; } _dyncpy(g_ch_vaddr, g_ch_vaddr_cap * 8, nb2); g_ch_vaddr = nb2; g_ch_vaddr_cap = nc;
- nb3 := alloc(nc * 8); zi = 0; loop { if zi >= nc * 8 { break; } store8(nb3, zi, 0); zi = zi + 1; } _dyncpy(g_ch_foff, g_ch_foff_cap * 8, nb3); g_ch_foff = nb3; g_ch_foff_cap = nc;
- nb4 := alloc(nc * 8); zi = 0; loop { if zi >= nc * 8 { break; } store8(nb4, zi, 0); zi = zi + 1; } _dyncpy(g_ch_size, g_ch_size_cap * 8, nb4); g_ch_size = nb4; g_ch_size_cap = nc; }
-
-fn cnew(k: int) {
- grow_chunks(g_ch_count + 1);
- w64(g_ch_kind, g_ch_count * 8, k);
- w64(g_ch_vaddr, g_ch_count * 8, 0);
- w64(g_ch_foff, g_ch_count * 8, 0);
- w64(g_ch_size, g_ch_count * 8, 0);
- g_ch_count = g_ch_count + 1; }
-
-fn cby(k: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= g_ch_count { break; }
- if r64(g_ch_kind, i * 8) == k { return i; }
- i = i + 1; }
- return -1; } // -1 = not found (callers must guard)
+fn grow_chunks(needed: int):
+ nc : ., mut = g_ch_kind_cap * 2
+ if nc < 8:
+ nc = 8
+ if nc < needed:
+ nc = needed + 8
+ nb := alloc(nc * 8)
+ zi : ., mut = 0
+ loop:
+ if zi >= nc * 8:
+ break
+ store8(nb, zi, 0)
+ zi = zi + 1
+ _dyncpy(g_ch_kind, g_ch_kind_cap * 8, nb)
+ g_ch_kind = nb
+ g_ch_kind_cap = nc
+ nb2 := alloc(nc * 8)
+ zi = 0
+ loop:
+ if zi >= nc * 8:
+ break
+ store8(nb2, zi, 0)
+ zi = zi + 1
+ _dyncpy(g_ch_vaddr, g_ch_vaddr_cap * 8, nb2)
+ g_ch_vaddr = nb2
+ g_ch_vaddr_cap = nc
+ nb3 := alloc(nc * 8)
+ zi = 0
+ loop:
+ if zi >= nc * 8:
+ break
+ store8(nb3, zi, 0)
+ zi = zi + 1
+ _dyncpy(g_ch_foff, g_ch_foff_cap * 8, nb3)
+ g_ch_foff = nb3
+ g_ch_foff_cap = nc
+ nb4 := alloc(nc * 8)
+ zi = 0
+ loop:
+ if zi >= nc * 8:
+ break
+ store8(nb4, zi, 0)
+ zi = zi + 1
+ _dyncpy(g_ch_size, g_ch_size_cap * 8, nb4)
+ g_ch_size = nb4
+ g_ch_size_cap = nc
+
+fn cnew(k: int):
+ grow_chunks(g_ch_count + 1)
+ w64(g_ch_kind, g_ch_count * 8, k)
+ w64(g_ch_vaddr, g_ch_count * 8, 0)
+ w64(g_ch_foff, g_ch_count * 8, 0)
+ w64(g_ch_size, g_ch_count * 8, 0)
+ g_ch_count = g_ch_count + 1
+
+fn cby(k: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= g_ch_count:
+ break
+ if r64(g_ch_kind, i * 8) == k:
+ return i
+ i = i + 1
+ return -1
+// -1 = not found (callers must guard)
// ============================================================
// .so symbol lookup
// ============================================================
-fn so_find(buf: string, name: string) -> int {
- if str_len(buf) < 64 { return -1; }
- if read_u16(buf, 16) != 3 { return -1; }
- e_shoff := r64(buf, 40); e_shnum := read_u16(buf, 60);
- do : ., mut = 0; ds : ., mut = 0; so : ., mut = 0; ss : ., mut = 0;
- i : ., mut = 0; loop { if i >= e_shnum { break; }
- t := r32(buf, e_shoff+i*64+4); a := r64(buf, e_shoff+i*64+16);
- o := r64(buf, e_shoff+i*64+24); s := r64(buf, e_shoff+i*64+32);
- if t == 11 { do = o; ds = s; }
- if t == 3 && a != 0 { so = o; ss = s; }
- i = i + 1; }
- if ds == 0 || ss == 0 { return -1; }
- sc := ds / 24;
- i = 0; loop { if i >= sc { break; }
- sn := r32(buf, do+i*24); sv := r64(buf, do+i*24+8);
- si := bu8(buf, do+i*24+4); sx := read_u16(buf, do+i*24+6);
- if si/16 == 1 && si%16 == 2 && sx != 0 {
- nm : ., mut = ""; k : ., mut = sn;
- loop { if k >= ss { break; }
- c := bu8(buf, so+k); if c == 0 { break; }
- sc2 := get_char(" ",0); store8(sc2,0,c);
- nm = nm + sc2; k = k + 1; }
- if str_len(nm) > 0 && str_eq(nm, name) != 0 { return sv; }
- }
- i = i + 1; }
- return -1; }
-
-fn so_find_any(name: string) -> int {
- si : ., mut = 0; loop { if si >= g_so_count { break; }
- if istr_len(r64(g_so_paths, si * 8)) > 0 {
+fn so_find(buf: string, name: string) -> int:
+ if str_len(buf) < 64:
+ return -1
+ if read_u16(buf, 16) != 3:
+ return -1
+ e_shoff := r64(buf, 40)
+ e_shnum := read_u16(buf, 60)
+ do : ., mut = 0
+ ds : ., mut = 0
+ so : ., mut = 0
+ ss : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= e_shnum:
+ break
+ t := r32(buf, e_shoff+i*64+4)
+ a := r64(buf, e_shoff+i*64+16)
+ o := r64(buf, e_shoff+i*64+24)
+ s := r64(buf, e_shoff+i*64+32)
+ if t == 11:
+ do = o
+ ds = s
+ if t == 3 && a != 0:
+ so = o
+ ss = s
+ i = i + 1
+ if ds == 0 || ss == 0:
+ return -1
+ sc := ds / 24
+ i = 0
+ loop:
+ if i >= sc:
+ break
+ sn := r32(buf, do+i*24)
+ sv := r64(buf, do+i*24+8)
+ si := bu8(buf, do+i*24+4)
+ sx := read_u16(buf, do+i*24+6)
+ if si/16 == 1 && si%16 == 2 && sx != 0:
+ nm : ., mut = ""
+ k : ., mut = sn
+ loop:
+ if k >= ss:
+ break
+ c := bu8(buf, so+k)
+ if c == 0:
+ break
+ sc2 := get_char(" ",0)
+ store8(sc2,0,c)
+ nm = nm + sc2
+ k = k + 1
+ if str_len(nm) > 0 && str_eq(nm, name) != 0:
+ return sv
+ i = i + 1
+ return -1
+
+fn so_find_any(name: string) -> int:
+ si : ., mut = 0
+ loop:
+ if si >= g_so_count:
+ break
+ if istr_len(r64(g_so_paths, si * 8)) > 0:
// 裸字 → string 视图:表里存的是**串指针**(`ctx_add_so` 的 `@ptr_of` 写入面),
// 读回时必须显式还原视图(2(a) 范式;`@str_of` 必须在 `unsafe` 内)。
- b := read_file(unsafe { @str_of(r64(g_so_paths, si * 8)) });
- if str_len(b) > 0 {
- a := so_find(b, name);
- if a >= 0 { return a; } }
- }
- si = si + 1; }
- return -1; }
+ so_path_str := unsafe:
+ @str_of(r64(g_so_paths, si * 8))
+ b := read_file(so_path_str)
+ if str_len(b) > 0:
+ a := so_find(b, name)
+ if a >= 0:
+ return a
+ si = si + 1
+ return -1
// ============================================================
// Layout — assign VA and file offsets to all chunks
// ============================================================
-fn layout() {
- va : ., mut = g_text_base;
- i : ., mut = 0; loop { if i >= g_ch_count { break; }
- sz : ., mut = 0;
- k := r64(g_ch_kind, i * 8);
- if k == 0 { sz = 344; }
- if k == 1 { sz = 29; }
- if k == 2 { sz = g_user_size; }
- if k == 3 { sz = 32 + g_plt_count * 16; }
- if k == 4 { sz = (3 + g_plt_count) * 8; }
- if k == 5 { sz = 10 * 16; }
- if k == 6 { sz = (1 + g_plt_count) * 24; }
- if k == 7 {
- sz = 1 + str_len("core_rt.so") + 1;
- j : ., mut = 0; loop { if j >= g_plt_count { break; }
- sz = sz + istr_len(r64(g_plts, j * 16)) + 1; j = j + 1; } }
- if k == 8 { sz = g_plt_count * 24; }
- w64(g_ch_vaddr, i * 8, va);
- w64(g_ch_foff, i * 8, va - g_text_base);
- w64(g_ch_size, i * 8, sz);
- va = va + sz;
- i = i + 1; }
- }
+fn layout():
+ va : ., mut = g_text_base
+ i : ., mut = 0
+ loop:
+ if i >= g_ch_count:
+ break
+ sz : ., mut = 0
+ k := r64(g_ch_kind, i * 8)
+ if k == 0:
+ sz = 344
+ if k == 1:
+ sz = 29
+ if k == 2:
+ sz = g_user_size
+ if k == 3:
+ sz = 32 + g_plt_count * 16
+ if k == 4:
+ sz = (3 + g_plt_count) * 8
+ if k == 5:
+ sz = 10 * 16
+ if k == 6:
+ sz = (1 + g_plt_count) * 24
+ if k == 7:
+ sz = 1 + str_len("core_rt.so") + 1
+ j : ., mut = 0
+ loop:
+ if j >= g_plt_count:
+ break
+ sz = sz + istr_len(r64(g_plts, j * 16)) + 1
+ j = j + 1
+ if k == 8:
+ sz = g_plt_count * 24
+ w64(g_ch_vaddr, i * 8, va)
+ w64(g_ch_foff, i * 8, va - g_text_base)
+ w64(g_ch_size, i * 8, sz)
+ va = va + sz
+ i = i + 1
// ============================================================
// Emit — write chunk data to output buffer
// ============================================================
-fn w32s(buf: string, pos: int, v: int) { w32(buf, pos, v); }
+fn w32s(buf: string, pos: int, v: int):
+ w32(buf, pos, v)
-fn emit(buf: string, total: int, is_so: int) {
+fn emit(buf: string, total: int, is_so: int):
// Zero buffer
- zi : ., mut = 0; loop { if zi >= total { break; } w8(buf, zi, 0); zi = zi + 1; }
- tb := g_text_base;
- i : ., mut = 0; loop { if i >= g_ch_count { break; }
- p : ., mut = r64(g_ch_foff, i * 8); k := r64(g_ch_kind, i * 8);
+ zi : ., mut = 0
+ loop:
+ if zi >= total:
+ break
+ w8(buf, zi, 0)
+ zi = zi + 1
+ tb := g_text_base
+ i : ., mut = 0
+ loop:
+ if i >= g_ch_count:
+ break
+ p : ., mut = r64(g_ch_foff, i * 8)
+ k := r64(g_ch_kind, i * 8)
// Ehdr: ELF header + 4 program headers
- if k == 0 {
- w8(buf,0,127);w8(buf,1,69);w8(buf,2,76);w8(buf,3,70);
- w8(buf,4,2);w8(buf,5,1);w8(buf,6,1);
- etype : ., mut = 2; if is_so != 0 { etype = 3; }
- w16(buf,16,etype);w16(buf,18,62);w32(buf,20,1);
- uv := cby(2); ev := r64(g_ch_vaddr, uv * 8);
- w64(buf,24,ev); w64(buf,32,64); w64(buf,40,0);
- w16(buf,52,64);w16(buf,54,56);w16(buf,56,5);w16(buf,58,64);
- pe := r64(g_ch_size, i * 8); // size of this chunk (EHDR+PHDRs)
+ if k == 0:
+ w8(buf,0,127)
+ w8(buf,1,69)
+ w8(buf,2,76)
+ w8(buf,3,70)
+ w8(buf,4,2)
+ w8(buf,5,1)
+ w8(buf,6,1)
+ etype : ., mut = 2
+ if is_so != 0:
+ etype = 3
+ w16(buf,16,etype)
+ w16(buf,18,62)
+ w32(buf,20,1)
+ uv := cby(2)
+ ev := r64(g_ch_vaddr, uv * 8)
+ w64(buf,24,ev)
+ w64(buf,32,64)
+ w64(buf,40,0)
+ w16(buf,52,64)
+ w16(buf,54,56)
+ w16(buf,56,5)
+ w16(buf,58,64)
+ pe := r64(g_ch_size, i * 8) // size of this chunk (EHDR+PHDRs)
// PT_PHDR
- w32(buf,64,6);w32(buf,68,4);w64(buf,72,64);w64(buf,80,tb+64);
- w64(buf,88,tb+64);w64(buf,96,pe-64);w64(buf,104,pe-64);w64(buf,112,8);
+ w32(buf,64,6)
+ w32(buf,68,4)
+ w64(buf,72,64)
+ w64(buf,80,tb+64)
+ w64(buf,88,tb+64)
+ w64(buf,96,pe-64)
+ w64(buf,104,pe-64)
+ w64(buf,112,8)
// PT_INTERP
- ic := cby(1);
- w32(buf,120,3);w32(buf,124,4);w64(buf,128,r64(g_ch_foff, ic * 8));
- w64(buf,136,r64(g_ch_vaddr, ic * 8));w64(buf,144,r64(g_ch_vaddr, ic * 8));
- w64(buf,152,r64(g_ch_size, ic * 8));w64(buf,160,r64(g_ch_size, ic * 8));w64(buf,168,1);
+ ic := cby(1)
+ w32(buf,120,3)
+ w32(buf,124,4)
+ w64(buf,128,r64(g_ch_foff, ic * 8))
+ w64(buf,136,r64(g_ch_vaddr, ic * 8))
+ w64(buf,144,r64(g_ch_vaddr, ic * 8))
+ w64(buf,152,r64(g_ch_size, ic * 8))
+ w64(buf,160,r64(g_ch_size, ic * 8))
+ w64(buf,168,1)
// PT_LOAD (RX)
- fs := r64(g_ch_vaddr, (g_ch_count - 1) * 8) + r64(g_ch_size, (g_ch_count - 1) * 8) - tb;
- w32(buf,176,1);w32(buf,180,7);w64(buf,184,0);
- w64(buf,192,tb);w64(buf,200,tb);w64(buf,208,fs);w64(buf,216,fs);w64(buf,224,4096);
+ fs := r64(g_ch_vaddr, (g_ch_count - 1) * 8) + r64(g_ch_size, (g_ch_count - 1) * 8) - tb
+ w32(buf,176,1)
+ w32(buf,180,7)
+ w64(buf,184,0)
+ w64(buf,192,tb)
+ w64(buf,200,tb)
+ w64(buf,208,fs)
+ w64(buf,216,fs)
+ w64(buf,224,4096)
// PT_GNU_STACK
- w32(buf,232,1685382481);w32(buf,236,6);w64(buf,240,0);
- w64(buf,248,0);w64(buf,256,0);w64(buf,264,0);w64(buf,272,0);w64(buf,280,8);
+ w32(buf,232,1685382481)
+ w32(buf,236,6)
+ w64(buf,240,0)
+ w64(buf,248,0)
+ w64(buf,256,0)
+ w64(buf,264,0)
+ w64(buf,272,0)
+ w64(buf,280,8)
// PT_DYNAMIC
- dc := cby(5);
- w32(buf,288,2);w32(buf,292,4);
- w64(buf,296,r64(g_ch_foff, dc * 8));w64(buf,304,r64(g_ch_vaddr, dc * 8));
- w64(buf,312,r64(g_ch_vaddr, dc * 8));
- w64(buf,320,r64(g_ch_size, dc * 8));w64(buf,328,r64(g_ch_size, dc * 8));w64(buf,336,8); }
+ dc := cby(5)
+ w32(buf,288,2)
+ w32(buf,292,4)
+ w64(buf,296,r64(g_ch_foff, dc * 8))
+ w64(buf,304,r64(g_ch_vaddr, dc * 8))
+ w64(buf,312,r64(g_ch_vaddr, dc * 8))
+ w64(buf,320,r64(g_ch_size, dc * 8))
+ w64(buf,328,r64(g_ch_size, dc * 8))
+ w64(buf,336,8)
// Interp
- if k == 1 {
- is := "/lib64/ld-linux-x86-64.so.2";
- j : ., mut = 0; loop { if j >= str_len(is) { break; }
- w8(buf,p+j, load8(is,j)); j = j + 1; }
- w8(buf,p+str_len(is),0); }
+ if k == 1:
+ is := "/lib64/ld-linux-x86-64.so.2"
+ j : ., mut = 0
+ loop:
+ if j >= str_len(is):
+ break
+ w8(buf,p+j, load8(is,j))
+ j = j + 1
+ w8(buf,p+str_len(is),0)
// User code
- if k == 2 {
- j : ., mut = 0; loop { if j >= g_user_size { break; }
- w8(buf,p+j,bu8(g_user_code,j)); j = j + 1; } }
+ if k == 2:
+ j : ., mut = 0
+ loop:
+ if j >= g_user_size:
+ break
+ w8(buf,p+j,bu8(g_user_code,j))
+ j = j + 1
// PLT
- if k == 3 {
- gv := r64(g_ch_vaddr, cby(4) * 8); pv := r64(g_ch_vaddr, i * 8);
- r1 := (gv+8)-(pv+6); w8(buf,p,255);w8(buf,p+1,53);w32s(buf,p+2,r1);
- r2 := (gv+16)-(pv+12); w8(buf,p+6,255);w8(buf,p+7,37);w32s(buf,p+8,r2);
+ if k == 3:
+ gv := r64(g_ch_vaddr, cby(4) * 8)
+ pv := r64(g_ch_vaddr, i * 8)
+ r1 := (gv+8)-(pv+6)
+ w8(buf,p,255)
+ w8(buf,p+1,53)
+ w32s(buf,p+2,r1)
+ r2 := (gv+16)-(pv+12)
+ w8(buf,p+6,255)
+ w8(buf,p+7,37)
+ w32s(buf,p+8,r2)
// 4-byte nop (not INT3)
- w8(buf,p+12,15);w8(buf,p+13,31);w8(buf,p+14,64);w8(buf,p+15,0);
- pi : ., mut = 0; loop { if pi >= g_plt_count { break; }
- eo := p+16+pi*16;
- ev := pv + 16 + pi*16;
+ w8(buf,p+12,15)
+ w8(buf,p+13,31)
+ w8(buf,p+14,64)
+ w8(buf,p+15,0)
+ pi : ., mut = 0
+ loop:
+ if pi >= g_plt_count:
+ break
+ eo := p+16+pi*16
+ ev := pv + 16 + pi*16
// jmp [GOT[3+pi]]
- rg := (gv+24+pi*8)-(ev+6); w8(buf,eo,255);w8(buf,eo+1,37);w32s(buf,eo+2,rg);
+ rg := (gv+24+pi*8)-(ev+6)
+ w8(buf,eo,255)
+ w8(buf,eo+1,37)
+ w32s(buf,eo+2,rg)
// push $pi (5 bytes)
- w8(buf,eo+6,104); w32(buf,eo+7,pi);
+ w8(buf,eo+6,104)
+ w32(buf,eo+7,pi)
// jmp PLT[0]
- rp := pv - (ev + 16); w8(buf,eo+11,233); w32s(buf,eo+12,rp);
- pi=pi+1; } }
+ rp := pv - (ev + 16)
+ w8(buf,eo+11,233)
+ w32s(buf,eo+12,rp)
+ pi=pi+1
// GOT.PLT
- if k == 4 {
- dv := r64(g_ch_vaddr, cby(5) * 8);
- w64(buf,p,dv);w64(buf,p+8,0);w64(buf,p+16,0);
- pi : ., mut = 0; loop { if pi >= g_plt_count { break; }
- pv2 := r64(g_ch_vaddr, cby(3) * 8);
- w64(buf,p+24+pi*8,pv2+16+pi*16+6);
- pi=pi+1; } }
+ if k == 4:
+ dv := r64(g_ch_vaddr, cby(5) * 8)
+ w64(buf,p,dv)
+ w64(buf,p+8,0)
+ w64(buf,p+16,0)
+ pi : ., mut = 0
+ loop:
+ if pi >= g_plt_count:
+ break
+ pv2 := r64(g_ch_vaddr, cby(3) * 8)
+ w64(buf,p+24+pi*8,pv2+16+pi*16+6)
+ pi=pi+1
// .dynamic (also writes .dynstr)
- if k == 5 {
+ if k == 5:
// Compute dynstr size: null + "core_rt.so\0" + all plt names
- dn : ., mut = 1 + str_len("core_rt.so") + 1;
- dnp : ., mut = 0; loop { if dnp >= g_plt_count { break; }
- dn = dn + istr_len(r64(g_plts, dnp * 16)) + 1; dnp = dnp + 1; }
+ dn : ., mut = 1 + str_len("core_rt.so") + 1
+ dnp : ., mut = 0
+ loop:
+ if dnp >= g_plt_count:
+ break
+ dn = dn + istr_len(r64(g_plts, dnp * 16)) + 1
+ dnp = dnp + 1
// Build dynstr
- db : ., mut = alloc(dn); w8(db,0,0); so_off : ., mut = 1;
- j : ., mut = 0; loop { if j >= str_len("core_rt.so") { break; }
- w8(db,so_off+j, load8("core_rt.so",j)); j=j+1; }
- w8(db,so_off+str_len("core_rt.so"),0);
- nxt : ., mut = so_off+str_len("core_rt.so")+1;
- pi : ., mut = 0; loop { if pi >= g_plt_count { break; }
- j=0; loop { if j >= istr_len(r64(g_plts, pi * 16)) { break; }
- w8(db,nxt+j, load8(r64(g_plts, pi * 16),j)); j=j+1; }
- w8(db,nxt+istr_len(r64(g_plts, pi * 16)),0);
- nxt=nxt+istr_len(r64(g_plts, pi * 16))+1; pi=pi+1; }
+ db : ., mut = alloc(dn)
+ w8(db,0,0)
+ so_off : ., mut = 1
+ j : ., mut = 0
+ loop:
+ if j >= str_len("core_rt.so"):
+ break
+ w8(db,so_off+j, load8("core_rt.so",j))
+ j=j+1
+ w8(db,so_off+str_len("core_rt.so"),0)
+ nxt : ., mut = so_off+str_len("core_rt.so")+1
+ pi : ., mut = 0
+ loop:
+ if pi >= g_plt_count:
+ break
+ j=0
+ loop:
+ if j >= istr_len(r64(g_plts, pi * 16)):
+ break
+ w8(db,nxt+j, load8(r64(g_plts, pi * 16),j))
+ j=j+1
+ w8(db,nxt+istr_len(r64(g_plts, pi * 16)),0)
+ nxt=nxt+istr_len(r64(g_plts, pi * 16))+1
+ pi=pi+1
// Write dynstr to its chunk
- dsc := cby(7);
- di2 : ., mut = 0; loop { if di2 >= nxt { break; }
- w8(buf,r64(g_ch_foff, dsc * 8)+di2,bu8(db,di2)); di2=di2+1; }
+ dsc := cby(7)
+ di2 : ., mut = 0
+ loop:
+ if di2 >= nxt:
+ break
+ w8(buf,r64(g_ch_foff, dsc * 8)+di2,bu8(db,di2))
+ di2=di2+1
// Write dynamic entries
- sv := r64(g_ch_vaddr, cby(6) * 8); dv2 := r64(g_ch_vaddr, dsc * 8);
- gv2 := r64(g_ch_vaddr, cby(4) * 8); rv := r64(g_ch_vaddr, cby(8) * 8);
- rs := r64(g_ch_size, cby(8) * 8);
- de : ., mut = 0;
- w64(buf,p+de*16,5);w64(buf,p+de*16+8,dv2);de=de+1; // DT_STRTAB
- w64(buf,p+de*16,11);w64(buf,p+de*16+8,24);de=de+1;
- w64(buf,p+de*16,6);w64(buf,p+de*16+8,sv);de=de+1; // DT_SYMTAB
- w64(buf,p+de*16,10);w64(buf,p+de*16+8,r64(g_ch_size, dsc * 8));de=de+1;
- w64(buf,p+de*16,3);w64(buf,p+de*16+8,gv2);de=de+1; // DT_PLTGOT
- w64(buf,p+de*16,2);w64(buf,p+de*16+8,rs);de=de+1;
- w64(buf,p+de*16,20);w64(buf,p+de*16+8,7);de=de+1; // DT_PLTREL=RELA
- w64(buf,p+de*16,23);w64(buf,p+de*16+8,rv);de=de+1; // DT_JMPREL
- w64(buf,p+de*16,1);w64(buf,p+de*16+8,so_off);de=de+1; // DT_NEEDED
- w64(buf,p+de*16,0);w64(buf,p+de*16+8,0); }
-
+ sv := r64(g_ch_vaddr, cby(6) * 8)
+ dv2 := r64(g_ch_vaddr, dsc * 8)
+ gv2 := r64(g_ch_vaddr, cby(4) * 8)
+ rv := r64(g_ch_vaddr, cby(8) * 8)
+ rs := r64(g_ch_size, cby(8) * 8)
+ de : ., mut = 0
+ w64(buf,p+de*16,5)
+ w64(buf,p+de*16+8,dv2)
+ de=de+1 // DT_STRTAB
+ w64(buf,p+de*16,11)
+ w64(buf,p+de*16+8,24)
+ de=de+1
+ w64(buf,p+de*16,6)
+ w64(buf,p+de*16+8,sv)
+ de=de+1 // DT_SYMTAB
+ w64(buf,p+de*16,10)
+ w64(buf,p+de*16+8,r64(g_ch_size, dsc * 8))
+ de=de+1
+ w64(buf,p+de*16,3)
+ w64(buf,p+de*16+8,gv2)
+ de=de+1 // DT_PLTGOT
+ w64(buf,p+de*16,2)
+ w64(buf,p+de*16+8,rs)
+ de=de+1
+ w64(buf,p+de*16,20)
+ w64(buf,p+de*16+8,7)
+ de=de+1 // DT_PLTREL=RELA
+ w64(buf,p+de*16,23)
+ w64(buf,p+de*16+8,rv)
+ de=de+1 // DT_JMPREL
+ w64(buf,p+de*16,1)
+ w64(buf,p+de*16+8,so_off)
+ de=de+1 // DT_NEEDED
+ w64(buf,p+de*16,0)
+ w64(buf,p+de*16+8,0)
+
// .dynsym
- if k == 6 {
- w32(buf,p,0);w8(buf,p+4,0);w8(buf,p+5,0);w16(buf,p+6,0);
- w64(buf,p+8,0);w64(buf,p+16,0);
- so_off2 : ., mut = 1;
- nxt2 : ., mut = 12;
- pi : ., mut = 0; loop { if pi >= g_plt_count { break; }
- so2 := p+(pi+1)*24;
- w32(buf,so2,nxt2);
- w8(buf,so2+4,18); w8(buf,so2+5,0);
- w16(buf,so2+6,0); w64(buf,so2+8,0); w64(buf,so2+16,0);
- nxt2 = nxt2 + istr_len(r64(g_plts, pi * 16)) + 1;
- pi=pi+1; } }
+ if k == 6:
+ w32(buf,p,0)
+ w8(buf,p+4,0)
+ w8(buf,p+5,0)
+ w16(buf,p+6,0)
+ w64(buf,p+8,0)
+ w64(buf,p+16,0)
+ so_off2 : ., mut = 1
+ nxt2 : ., mut = 12
+ pi : ., mut = 0
+ loop:
+ if pi >= g_plt_count:
+ break
+ so2 := p+(pi+1)*24
+ w32(buf,so2,nxt2)
+ w8(buf,so2+4,18)
+ w8(buf,so2+5,0)
+ w16(buf,so2+6,0)
+ w64(buf,so2+8,0)
+ w64(buf,so2+16,0)
+ nxt2 = nxt2 + istr_len(r64(g_plts, pi * 16)) + 1
+ pi=pi+1
// .rela.plt
- if k == 8 {
- gv3 := r64(g_ch_vaddr, cby(4) * 8);
- pi : ., mut = 0; loop { if pi >= g_plt_count { break; }
- ro := p+pi*24;
- w64(buf,ro,gv3+24+pi*8);
- rinfo := pi + 1;
- rinfo = rinfo * 65536;
- rinfo = rinfo * 65536 + 7;
- w64(buf,ro+8,rinfo);
- w64(buf,ro+16,0);
- pi=pi+1; } }
- i = i + 1; } }
+ if k == 8:
+ gv3 := r64(g_ch_vaddr, cby(4) * 8)
+ pi : ., mut = 0
+ loop:
+ if pi >= g_plt_count:
+ break
+ ro := p+pi*24
+ w64(buf,ro,gv3+24+pi*8)
+ rinfo := pi + 1
+ rinfo = rinfo * 65536
+ rinfo = rinfo * 65536 + 7
+ w64(buf,ro+8,rinfo)
+ w64(buf,ro+16,0)
+ pi=pi+1
+ i = i + 1
// ============================================================
// Relocation patching — fix up call offsets to PLT entries
// ============================================================
-fn patch_relocs() {
- if g_x86_ext_rel_count == 0 { return; }
- uc := cby(2); uv := r64(g_ch_vaddr, uc * 8);
- pv := r64(g_ch_vaddr, cby(3) * 8);
- ri : ., mut = 0; loop { if ri >= g_x86_ext_rel_count { break; }
- abs_pos := r64(g_x86_ext_rel_pos, ri * 8);
- code_off : ., mut = abs_pos - 176;
- if code_off < 0 || code_off >= g_user_size { ri=ri+1; continue; }
- fn_name_ni := r64(g_x86_ext_rel_name, ri * 8); fn_name : ., mut = "";
- if fn_name_ni >= 0 { fn_name = istr_get(fn_name_ni); }
- plt_idx : ., mut = -1;
- si : ., mut = 0; loop { if si >= g_plt_count { break; }
+fn patch_relocs():
+ if g_x86_ext_rel_count == 0:
+ return
+ uc := cby(2)
+ uv := r64(g_ch_vaddr, uc * 8)
+ pv := r64(g_ch_vaddr, cby(3) * 8)
+ ri : ., mut = 0
+ loop:
+ if ri >= g_x86_ext_rel_count:
+ break
+ abs_pos := r64(g_x86_ext_rel_pos, ri * 8)
+ code_off : ., mut = abs_pos - 176
+ if code_off < 0 || code_off >= g_user_size:
+ ri=ri+1
+ continue
+ fn_name_ni := r64(g_x86_ext_rel_name, ri * 8)
+ fn_name : ., mut = ""
+ if fn_name_ni >= 0:
+ fn_name = istr_get(fn_name_ni)
+ plt_idx : ., mut = -1
+ si : ., mut = 0
+ loop:
+ if si >= g_plt_count:
+ break
// 同上:`g_plts` 第 0 列存的是 PLT 名**串指针**(`ctx_add_plt` 的 `@ptr_of` 写入面)
- if str_eq(unsafe { @str_of(r64(g_plts, si * 16)) }, fn_name) != 0 { plt_idx = si; break; }
- si = si + 1; }
- if plt_idx >= 0 {
- call_va := uv + code_off;
- plt_va2 := pv + 16 + plt_idx * 16;
- rel := plt_va2 - call_va - 5;
- w32s(g_user_code, code_off, rel); }
- ri = ri + 1; } }
+ plt_name_str := unsafe:
+ @str_of(r64(g_plts, si * 16))
+ if str_eq(plt_name_str, fn_name) != 0:
+ plt_idx = si
+ break
+ si = si + 1
+ if plt_idx >= 0:
+ call_va := uv + code_off
+ plt_va2 := pv + 16 + plt_idx * 16
+ rel := plt_va2 - call_va - 5
+ w32s(g_user_code, code_off, rel)
+ ri = ri + 1
// ============================================================
// Public API
// ============================================================
-fn ctx_init() {
- g_ch_count = 0; g_so_count = 0; g_plt_count = 0; g_so_cap = 0; g_plt_cap = 0;
- g_text_base = 4194304; g_user_code = ""; g_user_size = 0; }
-
-fn ctx_set_user_code(data: string, sz: int) { g_user_code = data; g_user_size = sz; }
+fn ctx_init():
+ g_ch_count = 0
+ g_so_count = 0
+ g_plt_count = 0
+ g_so_cap = 0
+ g_plt_cap = 0
+ g_text_base = 4194304
+ g_user_code = ""
+ g_user_size = 0
+
+fn ctx_set_user_code(data: string, sz: int):
+ g_user_code = data
+ g_user_size = sz
// 表里存的是**串指针**(裸字表):写入面必须显式取指针(2(a) 范式;`@ptr_of` 必须在 `unsafe` 内)。
// 读回面对称地还原视图(见 `so_find_any` / `ctx_emit_static` / 上面的 `g_plts` 查找)。
-fn ctx_add_so(path: string) { dyn_grow_so(g_so_count + 1); w64(g_so_paths, g_so_count * 8, unsafe { @ptr_of(path) }); g_so_count = g_so_count + 1; }
-fn ctx_add_plt(name: string, so_idx: int) {
- dyn_grow_plts(g_plt_count + 1); w64(g_plts, g_plt_count * 16, unsafe { @ptr_of(name) }); w64(g_plts, g_plt_count * 16 + 8, so_idx); g_plt_count = g_plt_count + 1; }
+fn ctx_add_so(path: string):
+ dyn_grow_so(g_so_count + 1)
+ path_ptr := unsafe:
+ @ptr_of(path)
+ w64(g_so_paths, g_so_count * 8, path_ptr)
+ g_so_count = g_so_count + 1
+fn ctx_add_plt(name: string, so_idx: int):
+ dyn_grow_plts(g_plt_count + 1)
+ name_ptr := unsafe:
+ @ptr_of(name)
+ w64(g_plts, g_plt_count * 16, name_ptr)
+ w64(g_plts, g_plt_count * 16 + 8, so_idx)
+ g_plt_count = g_plt_count + 1
// Produce dynamically-linked ELF executable
-fn ctx_emit_dyn(buf: string, path: string) -> int {
- cnew(0); cnew(1); cnew(2); cnew(3); cnew(4); cnew(5); cnew(6); cnew(7); cnew(8);
- layout();
- patch_relocs();
- total := r64(g_ch_vaddr, (g_ch_count - 1) * 8) + r64(g_ch_size, (g_ch_count - 1) * 8) - g_text_base;
- println(int_str(total));
- emit(buf, total, 0);
- fd := syscall3(2, path, 577, 493); // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
- if fd < 0 { return -1; }
- nw := syscall3(1, fd, buf, total);
- syscall3(3, fd, 0, 0);
- return total; }
+fn ctx_emit_dyn(buf: string, path: string) -> int:
+ cnew(0)
+ cnew(1)
+ cnew(2)
+ cnew(3)
+ cnew(4)
+ cnew(5)
+ cnew(6)
+ cnew(7)
+ cnew(8)
+ layout()
+ patch_relocs()
+ total := r64(g_ch_vaddr, (g_ch_count - 1) * 8) + r64(g_ch_size, (g_ch_count - 1) * 8) - g_text_base
+ println(int_str(total))
+ emit(buf, total, 0)
+ fd := syscall3(2, path, 577, 493) // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
+ if fd < 0:
+ return -1
+ nw := syscall3(1, fd, buf, total)
+ syscall3(3, fd, 0, 0)
+ return total
// Produce shared library (--shared)
-fn ctx_emit_so(buf: string, path: string) -> int {
- cnew(0); cnew(2);
- g_ch_count = 2;
- layout();
- total := r64(g_ch_vaddr, (g_ch_count - 1) * 8) + r64(g_ch_size, (g_ch_count - 1) * 8) - g_text_base;
- emit(buf, total, 1);
- fd := syscall3(2, path, 577, 493); // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
- if fd < 0 { return -1; }
- nw := syscall3(1, fd, buf, total);
- syscall3(3, fd, 0, 0);
- return total; }
+fn ctx_emit_so(buf: string, path: string) -> int:
+ cnew(0)
+ cnew(2)
+ g_ch_count = 2
+ layout()
+ total := r64(g_ch_vaddr, (g_ch_count - 1) * 8) + r64(g_ch_size, (g_ch_count - 1) * 8) - g_text_base
+ emit(buf, total, 1)
+ fd := syscall3(2, path, 577, 493) // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
+ if fd < 0:
+ return -1
+ nw := syscall3(1, fd, buf, total)
+ syscall3(3, fd, 0, 0)
+ return total
// ============================================================
// Static linking — embed .so text into ELF, resolve relocations
@@ -398,138 +698,201 @@ fn ctx_emit_so(buf: string, path: string) -> int {
// referenced by user code, looks it up in the .so symbol table
// and copies the needed section into the output.
-g_so_off : int, mut; // .so .text file offset
-g_so_sz : int, mut; // .so .text size
-g_so_addr : int, mut; // .so .text base address
+g_so_off : int, mut // .so .text file offset
+g_so_sz : int, mut // .so .text size
+g_so_addr : int, mut // .so .text base address
-fn so_parse_text(buf: string) -> int {
+fn so_parse_text(buf: string) -> int:
// Find the executable PROGBITS section (.text) in the .so
- if str_len(buf) < 64 { return -1; }
- e_shoff := r64(buf, 40); e_shnum := read_u16(buf, 60);
+ if str_len(buf) < 64:
+ return -1
+ e_shoff := r64(buf, 40)
+ e_shnum := read_u16(buf, 60)
// A normal linker may place .init/.plt before .text. The old first-match
// scan copied one of those stubs and then resolved symbols against the
// wrong address range. Prefer the exact .text name from shstrtab.
- e_shstrndx := read_u16(buf, 62);
- shstr_off : ., mut = 0;
- shstr_sz : ., mut = 0;
- if e_shstrndx < e_shnum {
- sh := e_shoff + e_shstrndx * 64;
- shstr_off = r64(buf, sh + 24);
- shstr_sz = r64(buf, sh + 32);
- }
- i : ., mut = 0;
- fallback_off : ., mut = -1;
- fallback_sz : ., mut = 0;
- fallback_addr : ., mut = 0;
- loop { if i >= e_shnum { break; }
- t := r32(buf, e_shoff+i*64+4); fl := r64(buf, e_shoff+i*64+8);
- a := r64(buf, e_shoff+i*64+16); o := r64(buf, e_shoff+i*64+24); s := r64(buf, e_shoff+i*64+32);
+ e_shstrndx := read_u16(buf, 62)
+ shstr_off : ., mut = 0
+ shstr_sz : ., mut = 0
+ if e_shstrndx < e_shnum:
+ sh := e_shoff + e_shstrndx * 64
+ shstr_off = r64(buf, sh + 24)
+ shstr_sz = r64(buf, sh + 32)
+ i : ., mut = 0
+ fallback_off : ., mut = -1
+ fallback_sz : ., mut = 0
+ fallback_addr : ., mut = 0
+ loop:
+ if i >= e_shnum:
+ break
+ t := r32(buf, e_shoff+i*64+4)
+ fl := r64(buf, e_shoff+i*64+8)
+ a := r64(buf, e_shoff+i*64+16)
+ o := r64(buf, e_shoff+i*64+24)
+ s := r64(buf, e_shoff+i*64+32)
// SHT_PROGBITS(1) + SHF_ALLOC|SHF_EXECINSTR(6) = .text
- if t == 1 && fl == 6 && s > 0 {
- if fallback_off < 0 { fallback_off = o; fallback_sz = s; fallback_addr = a; }
- if shstr_off > 0 && shstr_sz > 0 {
- nm : ., mut = ""; p := e_shoff + i * 64;
- no := r32(buf, p);
- if no < shstr_sz {
- k : ., mut = no;
- loop { if k >= shstr_sz { break; }
- c := bu8(buf, shstr_off + k); if c == 0 { break; }
- one := get_char(" ", 0); store8(one, 0, c); nm = nm + one; k = k + 1; }
- if str_eq(nm, ".text") != 0 {
- g_so_off = o; g_so_sz = s; g_so_addr = a; return 0;
- }
- }
- }
- }
- i = i + 1; }
- if fallback_off >= 0 { g_so_off = fallback_off; g_so_sz = fallback_sz; g_so_addr = fallback_addr; return 0; }
- return -1; }
-
-fn ctx_emit_static(buf: string, path: string) -> int {
- so_buf : ., mut = "";
- si : ., mut = 0;
- loop { if si >= g_so_count { break; }
- sp := r64(g_so_paths, si * 8);
+ if t == 1 && fl == 6 && s > 0:
+ if fallback_off < 0:
+ fallback_off = o
+ fallback_sz = s
+ fallback_addr = a
+ if shstr_off > 0 && shstr_sz > 0:
+ nm : ., mut = ""
+ p := e_shoff + i * 64
+ no := r32(buf, p)
+ if no < shstr_sz:
+ k : ., mut = no
+ loop:
+ if k >= shstr_sz:
+ break
+ c := bu8(buf, shstr_off + k)
+ if c == 0:
+ break
+ one := get_char(" ", 0)
+ store8(one, 0, c)
+ nm = nm + one
+ k = k + 1
+ if str_eq(nm, ".text") != 0:
+ g_so_off = o
+ g_so_sz = s
+ g_so_addr = a
+ return 0
+ i = i + 1
+ if fallback_off >= 0:
+ g_so_off = fallback_off
+ g_so_sz = fallback_sz
+ g_so_addr = fallback_addr
+ return 0
+ return -1
+
+fn ctx_emit_static(buf: string, path: string) -> int:
+ so_buf : ., mut = ""
+ si : ., mut = 0
+ loop:
+ if si >= g_so_count:
+ break
+ sp := r64(g_so_paths, si * 8)
// `sp` 是表里的**串指针**(裸字)⇒ 用前显式还原视图(2(a) 范式;两处用法各自在 `unsafe` 内还原)
- if str_len(unsafe { @str_of(sp) }) > 0 {
- b := read_file(unsafe { @str_of(sp) });
- if str_len(b) > 0 && so_parse_text(b) == 0 { so_buf = b; break; }
- }
- si = si + 1; }
- if str_len(so_buf) == 0 { return -1; }
- if g_so_sz <= 0 { return -1; }
+ sp_str := unsafe:
+ @str_of(sp)
+ if str_len(sp_str) > 0:
+ sp_str_2 := unsafe:
+ @str_of(sp)
+ b := read_file(sp_str_2)
+ if str_len(b) > 0 && so_parse_text(b) == 0:
+ so_buf = b
+ break
+ si = si + 1
+ if str_len(so_buf) == 0:
+ return -1
+ if g_so_sz <= 0:
+ return -1
// Layout: 176 header + .so code + user code
- hdr_sz : ., mut = 176;
- so_out := hdr_sz; // .so .text starts right after header
- user_out := so_out + g_so_sz; // user code after .so
- total := user_out + g_user_size;
-
- zi : ., mut = 0; loop { if zi >= total { break; } w8(buf, zi, 0); zi = zi + 1; }
+ hdr_sz : ., mut = 176
+ so_out := hdr_sz // .so .text starts right after header
+ user_out := so_out + g_so_sz // user code after .so
+ total := user_out + g_user_size
+
+ zi : ., mut = 0
+ loop:
+ if zi >= total:
+ break
+ w8(buf, zi, 0)
+ zi = zi + 1
// Copy .so .text
- ci : ., mut = 0; loop { if ci >= g_so_sz { break; }
- w8(buf, so_out + ci, bu8(so_buf, g_so_off + ci)); ci = ci + 1; }
+ ci : ., mut = 0
+ loop:
+ if ci >= g_so_sz:
+ break
+ w8(buf, so_out + ci, bu8(so_buf, g_so_off + ci))
+ ci = ci + 1
// Copy user code (includes _start + all functions)
- cj : ., mut = 0; loop { if cj >= g_user_size { break; }
- w8(buf, user_out + cj, bu8(g_user_code, cj)); cj = cj + 1; }
+ cj : ., mut = 0
+ loop:
+ if cj >= g_user_size:
+ break
+ w8(buf, user_out + cj, bu8(g_user_code, cj))
+ cj = cj + 1
// Patch external relocations: user code calls → .so functions
// F16②:解析失败的外部符号是硬错误——修复前静默保留 rel32=0 → 跳入 ELF 头崩溃。
- unresolved : ., mut = 0;
- rpi : ., mut = 0;
- loop { if rpi >= g_x86_ext_rel_count { break; }
- abs_pos := r64(g_x86_ext_rel_pos, rpi * 8);
- fn_ni := r64(g_x86_ext_rel_name, rpi * 8);
- fn_name := istr_get(fn_ni);
- if str_len(fn_name) > 0 {
- sym_addr := so_find(so_buf, fn_name);
- if sym_addr >= g_so_addr && sym_addr < g_so_addr + g_so_sz {
- func_off := sym_addr - g_so_addr;
+ unresolved : ., mut = 0
+ rpi : ., mut = 0
+ loop:
+ if rpi >= g_x86_ext_rel_count:
+ break
+ abs_pos := r64(g_x86_ext_rel_pos, rpi * 8)
+ fn_ni := r64(g_x86_ext_rel_name, rpi * 8)
+ fn_name := istr_get(fn_ni)
+ if str_len(fn_name) > 0:
+ sym_addr := so_find(so_buf, fn_name)
+ if sym_addr >= g_so_addr && sym_addr < g_so_addr + g_so_sz:
+ func_off := sym_addr - g_so_addr
// Relocations are recorded against the full ELF buffer
// (the user code starts at offset 176), but ctx_emit_static
// copies that code to user_out after the embedded .so text.
// Convert the absolute emission position to a user-code
// relative offset before applying the new placement.
- code_off := abs_pos - 176;
- if code_off < 0 || code_off >= g_user_size { unresolved = unresolved + 1; rpi = rpi + 1; continue; }
+ code_off := abs_pos - 176
+ if code_off < 0 || code_off >= g_user_size:
+ unresolved = unresolved + 1
+ rpi = rpi + 1
+ continue
// IR_CALL_EXTERN records the call opcode, while the regular
// unknown-call path records its displacement byte. Normalize
// both forms to the opcode before writing rel32.
- call_pos : ., mut = user_out + code_off;
- if bu8(g_user_code, code_off) != 232 { call_pos = call_pos - 1; }
- target_va := 0x400000 + so_out + func_off;
- rel := target_va - (0x400000 + call_pos + 5);
- w32(buf, call_pos + 1, rel);
- } else {
- println("error: 无法解析外部符号(静态链接):" + fn_name);
- unresolved = unresolved + 1;
- }
- }
- rpi = rpi + 1; }
- if unresolved > 0 { return -2; }
+ call_pos : ., mut = user_out + code_off
+ if bu8(g_user_code, code_off) != 232:
+ call_pos = call_pos - 1
+ target_va := 0x400000 + so_out + func_off
+ rel := target_va - (0x400000 + call_pos + 5)
+ w32(buf, call_pos + 1, rel)
+ else:
+ println("error: 无法解析外部符号(静态链接):" + fn_name)
+ unresolved = unresolved + 1
+ rpi = rpi + 1
+ if unresolved > 0:
+ return -2
// ELF header: single PT_LOAD
- w8(buf,0,127);w8(buf,1,69);w8(buf,2,76);w8(buf,3,70);
- w8(buf,4,2);w8(buf,5,1);w8(buf,6,1);
- w16(buf,16,2);w16(buf,18,62);w32(buf,20,1);
- w64(buf,24,0x400000 + user_out); // entry = user code's _start
- w64(buf,32,64);w64(buf,40,0);
- w16(buf,52,64);w16(buf,54,56);w16(buf,56,2);w16(buf,58,64);
- w32(buf,64,1);w32(buf,68,5);w64(buf,72,0);
- w64(buf,80,0x400000);w64(buf,88,0x400000);
- w64(buf,96,total);w64(buf,104,total);
- w64(buf,112,4096);
+ w8(buf,0,127)
+ w8(buf,1,69)
+ w8(buf,2,76)
+ w8(buf,3,70)
+ w8(buf,4,2)
+ w8(buf,5,1)
+ w8(buf,6,1)
+ w16(buf,16,2)
+ w16(buf,18,62)
+ w32(buf,20,1)
+ w64(buf,24,0x400000 + user_out) // entry = user code's _start
+ w64(buf,32,64)
+ w64(buf,40,0)
+ w16(buf,52,64)
+ w16(buf,54,56)
+ w16(buf,56,2)
+ w16(buf,58,64)
+ w32(buf,64,1)
+ w32(buf,68,5)
+ w64(buf,72,0)
+ w64(buf,80,0x400000)
+ w64(buf,88,0x400000)
+ w64(buf,96,total)
+ w64(buf,104,total)
+ w64(buf,112,4096)
// The embedded user code still contains RIP-relative references to the
// original frontend BSS page, shifted by the copied .so text. Map a
// writable anonymous load at the next page so allocator/global slots do
// not fault when the linked executable starts.
- bss_page := 0x400000 + ((total + 4095) / 4096) * 4096 + 4096;
- write_phdr(buf, 1, 1, 6, 0, bss_page, bss_page, 0, 1073741824, 4096);
-
- fd := syscall3(2, path, 577, 493); // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
- if fd < 0 { return -1; }
- nw := syscall3(1, fd, buf, total);
- syscall3(3, fd, 0, 0);
- return total; }
+ bss_page := 0x400000 + ((total + 4095) / 4096) * 4096 + 4096
+ write_phdr(buf, 1, 1, 6, 0, bss_page, bss_page, 0, 1073741824, 4096)
+
+ fd := syscall3(2, path, 577, 493) // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
+ if fd < 0:
+ return -1
+ nw := syscall3(1, fd, buf, total)
+ syscall3(3, fd, 0, 0)
+ return total
diff --git a/src/format/elf/resolve.cr b/src/format/elf/resolve.cr
index bd353312..d322abf0 100644
--- a/src/format/elf/resolve.cr
+++ b/src/format/elf/resolve.cr
@@ -14,78 +14,89 @@
// The backend's emit_instr() can then write branch instructions using
// the pre-computed offsets, no label table lookup needed.
-fn res_labels() {
- print(" res_labels: ");
- print(int_str(g_ir_func_count));
- print(" funcs, ");
- print(int_str(g_ir_instr_count));
- println(" instrs");
- fi : ., mut = 0;
- loop {
- if fi >= g_ir_func_count { break; }
+fn res_labels():
+ print(" res_labels: ")
+ print(int_str(g_ir_func_count))
+ print(" funcs, ")
+ print(int_str(g_ir_instr_count))
+ println(" instrs")
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
- ist := r64(g_ir_func_instr_start, fi * 8);
- ic := r64(g_ir_func_instr_count, fi * 8);
- vs_r := r64(g_ir_func_var_start, fi * 8);
- vc_r := r64(g_ir_func_var_count, fi * 8);
- pc_r := r64(g_ir_func_param_count, fi * 8);
+ ist := r64(g_ir_func_instr_start, fi * 8)
+ ic := r64(g_ir_func_instr_count, fi * 8)
+ vs_r := r64(g_ir_func_var_start, fi * 8)
+ vc_r := r64(g_ir_func_var_count, fi * 8)
+ pc_r := r64(g_ir_func_param_count, fi * 8)
// Init slot state for accurate sizing
- g2_init();
- g_current_func_var_start = vs_r;
- vi4 := 0; loop { if vi4 >= vc_r { break; } g2_slot(vs_r + vi4); vi4 = vi4 + 1; }
- pi4 := 0; loop { if pi4 >= pc_r || pi4 >= 6 { break; } g2_slot(vs_r + pi4); pi4 = pi4 + 1; }
+ g2_init()
+ g_current_func_var_start = vs_r
+ vi4 := 0
+ loop:
+ if vi4 >= vc_r:
+ break
+ g2_slot(vs_r + vi4)
+ vi4 = vi4 + 1
+ pi4 := 0
+ loop:
+ if pi4 >= pc_r || pi4 >= 6:
+ break
+ g2_slot(vs_r + pi4)
+ pi4 = pi4 + 1
// ── Pass 1: measure instruction sizes via emit_instr (real encoder) ──
- g_label_count = 0;
- off : ., mut = 0;
- ii : ., mut = 0;
- scratch := alloc(64);
- loop {
- if ii >= ic { break; }
- inst_idx := ist + ii;
- if iri_op(inst_idx) == IR_LABEL {
- ln := iri_s1(inst_idx);
- if ln >= 0 {
- grow_label_poses(ln + 1);
- w64(g_label_poses, ln * 8, off);
- if ln + 1 > g_label_count { g_label_count = ln + 1; }
- }
- } else {
- off = off + emit_instr(inst_idx, scratch, 0);
- }
- ii = ii + 1;
- }
+ g_label_count = 0
+ off : ., mut = 0
+ ii : ., mut = 0
+ scratch := alloc(64)
+ loop:
+ if ii >= ic:
+ break
+ inst_idx := ist + ii
+ if iri_op(inst_idx) == IR_LABEL:
+ ln := iri_s1(inst_idx)
+ if ln >= 0:
+ grow_label_poses(ln + 1)
+ w64(g_label_poses, ln * 8, off)
+ if ln + 1 > g_label_count:
+ g_label_count = ln + 1
+ else:
+ off = off + emit_instr(inst_idx, scratch, 0)
+ ii = ii + 1
// Save per-function code size for Phase 2 reuse
- grow_func_code_sz(fi + 1); w64(g_x86_func_code_sz, fi * 8, off);
+ grow_func_code_sz(fi + 1)
+ w64(g_x86_func_code_sz, fi * 8, off)
// ── Pass 2: patch BRANCH/JUMP with resolved offsets ──
- ii = 0;
- loop {
- if ii >= ic { break; }
- inst_idx := ist + ii;
- if iri_op(inst_idx) == IR_BRANCH {
- true_off := r64(g_label_poses, iri_s2(inst_idx) * 8);
- false_off := r64(g_label_poses, iri_s3(inst_idx) * 8);
- iri_set_op(inst_idx, IR_BRANCH); iri_set_s2(inst_idx, true_off); iri_set_s3(inst_idx, false_off); iri_set_tk(inst_idx, IR_RESOLVED);
- }
- if iri_op(inst_idx) == IR_JUMP {
- tgt_off := r64(g_label_poses, iri_s1(inst_idx) * 8);
- iri_set_op(inst_idx, IR_JUMP); iri_set_s1(inst_idx, tgt_off); iri_set_tk(inst_idx, IR_RESOLVED);
- }
- ii = ii + 1;
- }
+ ii = 0
+ loop:
+ if ii >= ic:
+ break
+ inst_idx := ist + ii
+ if iri_op(inst_idx) == IR_BRANCH:
+ true_off := r64(g_label_poses, iri_s2(inst_idx) * 8)
+ false_off := r64(g_label_poses, iri_s3(inst_idx) * 8)
+ iri_set_op(inst_idx, IR_BRANCH)
+ iri_set_s2(inst_idx, true_off)
+ iri_set_s3(inst_idx, false_off)
+ iri_set_tk(inst_idx, IR_RESOLVED)
+ if iri_op(inst_idx) == IR_JUMP:
+ tgt_off := r64(g_label_poses, iri_s1(inst_idx) * 8)
+ iri_set_op(inst_idx, IR_JUMP)
+ iri_set_s1(inst_idx, tgt_off)
+ iri_set_tk(inst_idx, IR_RESOLVED)
+ ii = ii + 1
// ── Pass 3: turn LABEL into NOP (emit skips NOP) ──
- ii = 0;
- loop {
- if ii >= ic { break; }
- if iri_op(ist + ii) == IR_LABEL {
- iri_set_op(ist + ii, IR_NOP);
- }
- ii = ii + 1;
- }
+ ii = 0
+ loop:
+ if ii >= ic:
+ break
+ if iri_op(ist + ii) == IR_LABEL:
+ iri_set_op(ist + ii, IR_NOP)
+ ii = ii + 1
- fi = fi + 1;
- }
-}
+ fi = fi + 1
diff --git a/src/kernel/bytes.cr b/src/kernel/bytes.cr
index 10b33be1..5c8a33aa 100644
--- a/src/kernel/bytes.cr
+++ b/src/kernel/bytes.cr
@@ -3,47 +3,70 @@
// 不引入编译器全局(grow 函数引用全部 g_* 数组——内核不需要)。
// 来源对照:dyn_arr.cr L5-46, L144-146;语义逐字节一致。
-fn w8(buf: string, pos: int, val: int) { store8(buf, pos, val % 256); }
-fn bu8(buf: string, pos: int) -> int { return load8(buf, pos) % 256; }
-fn w32(buf: string, pos: int, val: int) {
- b0 : ., mut = val % 256; t1 : ., mut = val / 256;
- b1 : ., mut = t1 % 256; t2 : ., mut = t1 / 256;
- b2 : ., mut = t2 % 256; t3 : ., mut = t2 / 256;
- b3 : ., mut = t3 % 256;
+fn w8(buf: string, pos: int, val: int):
+ store8(buf, pos, val % 256)
+fn bu8(buf: string, pos: int) -> int:
+ return load8(buf, pos) % 256
+fn w32(buf: string, pos: int, val: int):
+ b0 : ., mut = val % 256
+ t1 : ., mut = val / 256
+ b1 : ., mut = t1 % 256
+ t2 : ., mut = t1 / 256
+ b2 : ., mut = t2 % 256
+ t3 : ., mut = t2 / 256
+ b3 : ., mut = t3 % 256
// Borrow chain for two's complement of negative val (no 4294967296 constant)
- if b0 < 0 { b0 = b0 + 256; b1 = b1 - 1; }
- if b1 < 0 { b1 = b1 + 256; b2 = b2 - 1; }
- if b2 < 0 { b2 = b2 + 256; b3 = b3 - 1; }
- if b3 < 0 { b3 = b3 + 256; }
- store8(buf,pos,b0); store8(buf,pos+1,b1);
- store8(buf,pos+2,b2); store8(buf,pos+3,b3); }
-fn r32(buf: string, pos: int) -> int {
- b0 := bu8(buf,pos); b1 := bu8(buf,pos+1);
- b2 := bu8(buf,pos+2); b3 := bu8(buf,pos+3);
- v := b0 + b1*256 + b2*65536;
- if b3 >= 128 { v = v + (b3 - 256) * 16777216; }
- else { v = v + b3 * 16777216; }
- return v; }
-fn w64(buf: string, pos: int, val: int) {
- cur : ., mut = val;
- i : ., mut = 0;
- loop {
- if i >= 8 { break; }
- byte : ., mut = cur % 256;
- if byte < 0 { byte = byte + 256; }
- store8(buf, pos + i, byte);
- cur = (cur - byte) / 256;
- i = i + 1;
- }
-}
-fn r64(buf: string, pos: int) -> int {
+ if b0 < 0:
+ b0 = b0 + 256
+ b1 = b1 - 1
+ if b1 < 0:
+ b1 = b1 + 256
+ b2 = b2 - 1
+ if b2 < 0:
+ b2 = b2 + 256
+ b3 = b3 - 1
+ if b3 < 0:
+ b3 = b3 + 256
+ store8(buf,pos,b0)
+ store8(buf,pos+1,b1)
+ store8(buf,pos+2,b2)
+ store8(buf,pos+3,b3)
+fn r32(buf: string, pos: int) -> int:
+ b0 := bu8(buf,pos)
+ b1 := bu8(buf,pos+1)
+ b2 := bu8(buf,pos+2)
+ b3 := bu8(buf,pos+3)
+ v := b0 + b1*256 + b2*65536
+ if b3 >= 128:
+ v = v + (b3 - 256) * 16777216
+ else:
+ v = v + b3 * 16777216
+ return v
+fn w64(buf: string, pos: int, val: int):
+ cur : ., mut = val
+ i : ., mut = 0
+ loop:
+ if i >= 8:
+ break
+ byte : ., mut = cur % 256
+ if byte < 0:
+ byte = byte + 256
+ store8(buf, pos + i, byte)
+ cur = (cur - byte) / 256
+ i = i + 1
+fn r64(buf: string, pos: int) -> int:
// The low dword is unsigned. Reading it through r32 double-subtracts
// 2^32 for negative values, e.g. -1 becomes -1 + (-1 * 2^32).
- lo := bu8(buf,pos) + bu8(buf,pos+1)*256 + bu8(buf,pos+2)*65536 + bu8(buf,pos+3)*16777216;
- hi := r32(buf,pos+4);
- hi_part := hi * 65536; hi_part = hi_part * 65536;
- return lo + hi_part; }
+ lo := bu8(buf,pos) + bu8(buf,pos+1)*256 + bu8(buf,pos+2)*65536 + bu8(buf,pos+3)*16777216
+ hi := r32(buf,pos+4)
+ hi_part := hi * 65536
+ hi_part = hi_part * 65536
+ return lo + hi_part
-fn _dyncpy(src: string, nbytes: int, dst: string) {
- ci : ., mut = 0;
- loop { if ci >= nbytes { break; } w8(dst, ci, bu8(src, ci)); ci = ci + 1; } }
+fn _dyncpy(src: string, nbytes: int, dst: string):
+ ci : ., mut = 0
+ loop:
+ if ci >= nbytes:
+ break
+ w8(dst, ci, bu8(src, ci))
+ ci = ci + 1
diff --git a/src/kernel/check.cr b/src/kernel/check.cr
index 17a277ed..6f7f6cc7 100644
--- a/src/kernel/check.cr
+++ b/src/kernel/check.cr
@@ -6,95 +6,122 @@
// type_infer(m) -> int(返回推断类型 nf 节点;-1=拒绝)
// 总化(protocol §5):任何前提失败 → -1(reject);推断结果一律 nf(spec §3 要点)
-fn ctx_pop() { if g_ctx_len > 0 { g_ctx_len = g_ctx_len - 1; } }
+fn ctx_pop():
+ if g_ctx_len > 0:
+ g_ctx_len = g_ctx_len - 1
// Γ ⊢a M ⟸ A:唯一检查规则 atc_ati——推断 + 子类型(AlgTyp/Definitions.v:11-14)
-fn type_check(a: int, m: int) -> int {
- ta := type_infer(m);
- if ta < 0 { return 0; }
- return subtyping(ta, a);
-}
+fn type_check(a: int, m: int) -> int:
+ ta := type_infer(m)
+ if ta < 0:
+ return 0
+ return subtyping(ta, a)
// Γ ⊢a M ⟹ A:9 条推断规则(AlgTyp/Definitions.v:17-51)
-fn type_infer(m: int) -> int {
- k := kern_kind(m);
- if k == K_TYP { return mk_typ(kern_get(m, 1) + 1); } // ati_typ:Type@i ⟹ Type@(S i)
- if k == K_NAT { return mk_typ(0); } // ati_nat:ℕ ⟹ Type@0
- if k == K_ZERO { return mk_nat(); } // ati_zero:zero ⟹ ℕ
- if k == K_SUCC {
+fn type_infer(m: int) -> int:
+ k := kern_kind(m)
+ if k == K_TYP:
+ return mk_typ(kern_get(m, 1) + 1)
+ // ati_typ:Type@i ⟹ Type@(S i)
+ if k == K_NAT:
+ return mk_typ(0)
+ // ati_nat:ℕ ⟹ Type@0
+ if k == K_ZERO:
+ return mk_nat()
+ // ati_zero:zero ⟹ ℕ
+ if k == K_SUCC:
// ati_succ:Γ ⊢a M ⟸ ℕ
- if type_check(mk_nat(), kern_get(m, 1)) <= 0 { return -1; }
- return mk_nat();
- }
- if k == K_VAR {
+ if type_check(mk_nat(), kern_get(m, 1)) <= 0:
+ return -1
+ return mk_nat()
+ if k == K_VAR:
// ati_vlookup:#x : A ∈ Γ;nbe_ty Γ (A[Wk^(x+1)])——提取 lookup 每层
// 递归包一次 Wk(TypeCheck.ml lookup),索引 x 弱化 x+1 次;
// 差分对拍 2026-08-28 实测确认(探针:1 次 Wk → var 1,2 次 → var 2)
- x := kern_get(m, 1);
- a := ctx_get(x);
- if a < 0 { return -1; } // 越界(自由变量)→ reject
- return kern_nbe_ty(mk_sub(a, subst_wk_n(x + 1)));
- }
- if k == K_PI {
+ x := kern_get(m, 1)
+ a := ctx_get(x)
+ if a < 0:
+ return -1
+ // 越界(自由变量)→ reject
+ return kern_nbe_ty(mk_sub(a, subst_wk_n(x + 1)))
+ if k == K_PI:
// ati_pi:Γ ⊢ A ⟹ Type@i;Γ,A ⊢ B ⟹ Type@j → Type@(max i j)
- a := kern_get(m, 1); b := kern_get(m, 2);
- ta := type_infer(a);
- if ta < 0 || kern_kind(ta) != K_TYP { return -1; }
- i := kern_get(ta, 1);
- ctx_extend(a);
- tb := type_infer(b);
- ctx_pop();
- if tb < 0 || kern_kind(tb) != K_TYP { return -1; }
- j := kern_get(tb, 1);
- if j > i { return mk_typ(j); }
- return mk_typ(i);
- }
- if k == K_FN {
+ a := kern_get(m, 1)
+ b := kern_get(m, 2)
+ ta := type_infer(a)
+ if ta < 0 || kern_kind(ta) != K_TYP:
+ return -1
+ i := kern_get(ta, 1)
+ ctx_extend(a)
+ tb := type_infer(b)
+ ctx_pop()
+ if tb < 0 || kern_kind(tb) != K_TYP:
+ return -1
+ j := kern_get(tb, 1)
+ if j > i:
+ return mk_typ(j)
+ return mk_typ(i)
+ if k == K_FN:
// ati_fn:Γ ⊢ A ⟹ Type@i;Γ,A ⊢ M ⟹ B;nbe_ty Γ A C → Π C B
- a := kern_get(m, 1); mm := kern_get(m, 2);
- ta := type_infer(a);
- if ta < 0 || kern_kind(ta) != K_TYP { return -1; }
- ctx_extend(a);
- tb := type_infer(mm);
- ctx_pop();
- if tb < 0 { return -1; }
- c := kern_nbe_ty(a); // nbe_ty Γ A(原始 ctx)
- if c < 0 { return -1; }
- return mk_pi(c, tb);
- }
- if k == K_APP {
+ a := kern_get(m, 1)
+ mm := kern_get(m, 2)
+ ta := type_infer(a)
+ if ta < 0 || kern_kind(ta) != K_TYP:
+ return -1
+ ctx_extend(a)
+ tb := type_infer(mm)
+ ctx_pop()
+ if tb < 0:
+ return -1
+ c := kern_nbe_ty(a) // nbe_ty Γ A(原始 ctx)
+ if c < 0:
+ return -1
+ return mk_pi(c, tb)
+ if k == K_APP:
// ati_app:Γ ⊢ M ⟹ Π A B;Γ ⊢ N ⟸ A;nbe_ty Γ B[Id,,N] C
- mm := kern_get(m, 1); nn := kern_get(m, 2);
- tm := type_infer(mm);
- if tm < 0 || kern_kind(tm) != K_PI { return -1; }
- a := kern_get(tm, 1); b := kern_get(tm, 2);
- if type_check(a, nn) <= 0 { return -1; }
- c := kern_nbe_ty(mk_sub(b, subst_id_of(nn))); // B[Id,,N]
- if c < 0 { return -1; }
- return c;
- }
- if k == K_NATREC {
+ mm := kern_get(m, 1)
+ nn := kern_get(m, 2)
+ tm := type_infer(mm)
+ if tm < 0 || kern_kind(tm) != K_PI:
+ return -1
+ a := kern_get(tm, 1)
+ b := kern_get(tm, 2)
+ if type_check(a, nn) <= 0:
+ return -1
+ c := kern_nbe_ty(mk_sub(b, subst_id_of(nn))) // B[Id,,N]
+ if c < 0:
+ return -1
+ return c
+ if k == K_NATREC:
// ati_natrec:Γ,ℕ ⊢ A ⟹ Type@i;Γ ⊢ MZ ⟸ A[Id,,zero];
// Γ,ℕ,A ⊢ MS ⟸ A[Wk∘Wk,,succ #1];Γ ⊢ M ⟸ ℕ;
// nbe_ty Γ A[Id,,M] B(AlgTyp/Definitions.v:26-32)
- a := kern_get(m, 1); mz := kern_get(m, 2); ms := kern_get(m, 3); mm := kern_get(m, 4);
- ctx_extend(mk_nat()); // Γ,ℕ
- ta := type_infer(a);
- if ta < 0 || kern_kind(ta) != K_TYP { ctx_pop(); return -1; }
- ctx_pop(); // 回 Γ
- if type_check(mk_sub(a, subst_id_zero()), mz) <= 0 { return -1; } // MZ ⟸ A[Id,,zero](Γ 下)
- ctx_extend(mk_nat()); // Γ,ℕ
- ctx_extend(a); // Γ,ℕ,A
- if type_check(mk_sub(a, subst_wk_wk_succ1()), ms) <= 0 {
- ctx_pop(); ctx_pop();
- return -1;
- }
- ctx_pop(); // 回 Γ,ℕ
- ctx_pop(); // 回 Γ
- if type_check(mk_nat(), mm) <= 0 { return -1; } // M ⟸ ℕ(Γ 下)
- b := kern_nbe_ty(mk_sub(a, subst_id_of(mm))); // nbe_ty Γ A[Id,,M]
- if b < 0 { return -1; }
- return b;
- }
- return -1; // 其他形态(含顶层 sub)→ reject
-}
+ a := kern_get(m, 1)
+ mz := kern_get(m, 2)
+ ms := kern_get(m, 3)
+ mm := kern_get(m, 4)
+ ctx_extend(mk_nat()) // Γ,ℕ
+ ta := type_infer(a)
+ if ta < 0 || kern_kind(ta) != K_TYP:
+ ctx_pop()
+ return -1
+ ctx_pop() // 回 Γ
+ if type_check(mk_sub(a, subst_id_zero()), mz) <= 0:
+ return -1
+ // MZ ⟸ A[Id,,zero](Γ 下)
+ ctx_extend(mk_nat()) // Γ,ℕ
+ ctx_extend(a) // Γ,ℕ,A
+ if type_check(mk_sub(a, subst_wk_wk_succ1()), ms) <= 0:
+ ctx_pop()
+ ctx_pop()
+ return -1
+ ctx_pop() // 回 Γ,ℕ
+ ctx_pop() // 回 Γ
+ if type_check(mk_nat(), mm) <= 0:
+ return -1
+ // M ⟸ ℕ(Γ 下)
+ b := kern_nbe_ty(mk_sub(a, subst_id_of(mm))) // nbe_ty Γ A[Id,,M]
+ if b < 0:
+ return -1
+ return b
+ return -1 // 其他形态(含顶层 sub)→ reject
diff --git a/src/kernel/kernel_main.cr b/src/kernel/kernel_main.cr
index 3a7dca58..339710b7 100644
--- a/src/kernel/kernel_main.cr
+++ b/src/kernel/kernel_main.cr
@@ -18,175 +18,212 @@
// fmt.cr(str_len/str_sub/load8)、io.cr(println/read_file)、rt.cr(argv)。
// ── nf 相等(Syntax.v nf_eq_dec,convert 用):nf/ne 结构相等 ──
-fn nf_sub_eq(a: int, b: int) -> int {
- if a < 0 || b < 0 { return 0; }
- ka := kern_get(a, 0); kb := kern_get(b, 0);
- if ka != K_SUB || kb != K_SUB { return 0; }
- sa := kern_get(a, 4); sb := kern_get(b, 4);
- if sa != sb { return 0; }
- if sa == S_ID || sa == S_WEAKEN { return 1; }
- if sa == S_COMPOSE {
- return nf_sub_eq(kern_get(a, 1), kern_get(b, 1)) != 0
- && nf_sub_eq(kern_get(a, 2), kern_get(b, 2)) != 0;
- }
- if sa == S_EXTEND {
- return nf_sub_eq(kern_get(a, 1), kern_get(b, 1)) != 0
- && nf_eq(kern_get(a, 2), kern_get(b, 2)) != 0;
- }
- return 0;
-}
+fn nf_sub_eq(a: int, b: int) -> int:
+ if a < 0 || b < 0:
+ return 0
+ ka := kern_get(a, 0)
+ kb := kern_get(b, 0)
+ if ka != K_SUB || kb != K_SUB:
+ return 0
+ sa := kern_get(a, 4)
+ sb := kern_get(b, 4)
+ if sa != sb:
+ return 0
+ if sa == S_ID || sa == S_WEAKEN:
+ return 1
+ if sa == S_COMPOSE:
+ return nf_sub_eq(kern_get(a, 1), kern_get(b, 1)) != 0 && nf_sub_eq(kern_get(a, 2), kern_get(b, 2)) != 0
+ if sa == S_EXTEND:
+ return nf_sub_eq(kern_get(a, 1), kern_get(b, 1)) != 0 && nf_eq(kern_get(a, 2), kern_get(b, 2)) != 0
+ return 0
-fn nf_eq(a: int, b: int) -> int {
- if a < 0 || b < 0 { return 0; }
- ka := kern_get(a, 0); kb := kern_get(b, 0);
- if ka != kb { return 0; }
- if ka == K_TYP { return kern_get(a, 1) == kern_get(b, 1); }
- if ka == K_NAT || ka == K_ZERO { return 1; }
- if ka == K_SUCC { return nf_eq(kern_get(a, 1), kern_get(b, 1)); }
- if ka == K_VAR { return kern_get(a, 1) == kern_get(b, 1); }
- if ka == K_NATREC {
- return nf_eq(kern_get(a, 1), kern_get(b, 1)) != 0
- && nf_eq(kern_get(a, 2), kern_get(b, 2)) != 0
- && nf_eq(kern_get(a, 3), kern_get(b, 3)) != 0
- && nf_eq(kern_get(a, 4), kern_get(b, 4)) != 0;
- }
- if ka == K_PI || ka == K_FN || ka == K_APP {
- return nf_eq(kern_get(a, 1), kern_get(b, 1)) != 0
- && nf_eq(kern_get(a, 2), kern_get(b, 2)) != 0;
- }
- if ka == K_SUB {
- return nf_eq(kern_get(a, 1), kern_get(b, 1)) != 0
- && nf_sub_eq(kern_get(a, 2), kern_get(b, 2)) != 0;
- }
- return 0;
-}
+fn nf_eq(a: int, b: int) -> int:
+ if a < 0 || b < 0:
+ return 0
+ ka := kern_get(a, 0)
+ kb := kern_get(b, 0)
+ if ka != kb:
+ return 0
+ if ka == K_TYP:
+ return kern_get(a, 1) == kern_get(b, 1)
+ if ka == K_NAT || ka == K_ZERO:
+ return 1
+ if ka == K_SUCC:
+ return nf_eq(kern_get(a, 1), kern_get(b, 1))
+ if ka == K_VAR:
+ return kern_get(a, 1) == kern_get(b, 1)
+ if ka == K_NATREC:
+ return nf_eq(kern_get(a, 1), kern_get(b, 1)) != 0 && nf_eq(kern_get(a, 2), kern_get(b, 2)) != 0 && nf_eq(kern_get(a, 3), kern_get(b, 3)) != 0 && nf_eq(kern_get(a, 4), kern_get(b, 4)) != 0
+ if ka == K_PI || ka == K_FN || ka == K_APP:
+ return nf_eq(kern_get(a, 1), kern_get(b, 1)) != 0 && nf_eq(kern_get(a, 2), kern_get(b, 2)) != 0
+ if ka == K_SUB:
+ return nf_eq(kern_get(a, 1), kern_get(b, 1)) != 0 && nf_sub_eq(kern_get(a, 2), kern_get(b, 2)) != 0
+ return 0
// ── 行处理 ──
-g_kernel_malformed : int, mut = 0;
+g_kernel_malformed : int, mut = 0
// (ctx exp*):按出现顺序压入 ctx(协议 §3:e1 = 头部 = 最近绑定,与
// ctx_extend 的压头语义一致)。失败返回 -1。
-fn kern_parse_ctx() -> int {
- kp_skip_ws();
- if kp_expect(40) == 0 { return -1; }
- kp_skip_ws();
- if kp_take_name("ctx") == 0 { return -1; }
- loop {
- kp_skip_ws();
- if g_kernel_parse_pos < kp_len() && load8(g_kernel_parse_text, g_kernel_parse_pos) == 41 {
- kp_expect(41);
- return 1;
- }
- e := parse_exp();
- if e < 0 { return -1; }
- ctx_extend(e);
- }
- return 1;
-}
+fn kern_parse_ctx() -> int:
+ kp_skip_ws()
+ if kp_expect(40) == 0:
+ return -1
+ kp_skip_ws()
+ if kp_take_name("ctx") == 0:
+ return -1
+ loop:
+ kp_skip_ws()
+ if g_kernel_parse_pos < kp_len() && load8(g_kernel_parse_text, g_kernel_parse_pos) == 41:
+ kp_expect(41)
+ return 1
+ e := parse_exp()
+ if e < 0:
+ return -1
+ ctx_extend(e)
+ return 1
// 校验行尾无残留;有残留 → malformed
-fn kern_line_end_ok() -> int {
- kp_skip_ws();
- if g_kernel_parse_pos < kp_len() { return 0; }
- return 1;
-}
+fn kern_line_end_ok() -> int:
+ kp_skip_ws()
+ if g_kernel_parse_pos < kp_len():
+ return 0
+ return 1
// 处理一行查询;返回 0=正常(已输出)、1=malformed(无输出、计数)
-fn kern_process_line(line: string) -> int {
+fn kern_process_line(line: string) -> int:
// 前导空白 + 空行 / # 注释 → 跳过(无输出)
- pos : ., mut = 0;
- loop {
- if pos >= str_len(line) { break; }
- c := load8(line, pos);
- if c == 32 || c == 9 || c == 13 { pos = pos + 1; }
- else { break; }
- }
- if pos >= str_len(line) { return 0; }
- if load8(line, pos) == 35 { return 0; } // '#'
+ pos : ., mut = 0
+ loop:
+ if pos >= str_len(line):
+ break
+ c := load8(line, pos)
+ if c == 32 || c == 9 || c == 13:
+ pos = pos + 1
+ else:
+ break
+ if pos >= str_len(line):
+ return 0
+ if load8(line, pos) == 35:
+ return 0
+ // '#'
// 每行三复位(arena / ctx / env)——直接调 parse_exp/parse_sub,勿用
// kernel_parse(它每次复位 arena 且要求整行单 exp)
- g_kernel_count = 0;
- g_ctx_len = 0;
- g_kernel_parse_text = line;
- g_kernel_parse_pos = pos;
+ g_kernel_count = 0
+ g_ctx_len = 0
+ g_kernel_parse_text = line
+ g_kernel_parse_pos = pos
- if kp_take_name("check") != 0 {
- if kern_parse_ctx() < 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- m := parse_exp();
- a := parse_exp();
- if m < 0 || a < 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- if kern_line_end_ok() == 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- r := type_check(a, m); // 协议:项在前类型在后 → 交换
- if r > 0 { println("check: accept"); } else { println("check: reject"); }
- return 0;
- }
- if kp_take_name("infer") != 0 {
- if kern_parse_ctx() < 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- m := parse_exp();
- if m < 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- if kern_line_end_ok() == 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- r := type_infer(m);
- if r >= 0 { println("infer: type: " + kernel_print(r)); }
- else { println("infer: reject"); }
- return 0;
- }
- if kp_take_name("convert") != 0 {
- if kern_parse_ctx() < 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- t1 := parse_exp();
- t2 := parse_exp();
- tv := parse_exp();
- if t1 < 0 || t2 < 0 || tv < 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- if kern_line_end_ok() == 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- n1 := kern_nbe(t1, tv);
- n2 := kern_nbe(t2, tv);
- if n1 >= 0 && n2 >= 0 && nf_eq(n1, n2) != 0 { println("convert: yes"); }
- else { println("convert: no"); }
- return 0;
- }
- if kp_take_name("subtype") != 0 {
- if kern_parse_ctx() < 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- a := parse_exp();
- b := parse_exp();
- if a < 0 || b < 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- if kern_line_end_ok() == 0 { g_kernel_malformed = g_kernel_malformed + 1; return 1; }
- r := subtyping(a, b);
- if r > 0 { println("subtype: yes"); } else { println("subtype: no"); }
- return 0;
- }
- g_kernel_malformed = g_kernel_malformed + 1;
- return 1;
-}
+ if kp_take_name("check") != 0:
+ if kern_parse_ctx() < 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ m := parse_exp()
+ a := parse_exp()
+ if m < 0 || a < 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ if kern_line_end_ok() == 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ r := type_check(a, m) // 协议:项在前类型在后 → 交换
+ if r > 0:
+ println("check: accept")
+ else:
+ println("check: reject")
+ return 0
+ if kp_take_name("infer") != 0:
+ if kern_parse_ctx() < 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ m := parse_exp()
+ if m < 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ if kern_line_end_ok() == 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ r := type_infer(m)
+ if r >= 0:
+ println("infer: type: " + kernel_print(r))
+ else:
+ println("infer: reject")
+ return 0
+ if kp_take_name("convert") != 0:
+ if kern_parse_ctx() < 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ t1 := parse_exp()
+ t2 := parse_exp()
+ tv := parse_exp()
+ if t1 < 0 || t2 < 0 || tv < 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ if kern_line_end_ok() == 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ n1 := kern_nbe(t1, tv)
+ n2 := kern_nbe(t2, tv)
+ if n1 >= 0 && n2 >= 0 && nf_eq(n1, n2) != 0:
+ println("convert: yes")
+ else:
+ println("convert: no")
+ return 0
+ if kp_take_name("subtype") != 0:
+ if kern_parse_ctx() < 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ a := parse_exp()
+ b := parse_exp()
+ if a < 0 || b < 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ if kern_line_end_ok() == 0:
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
+ r := subtyping(a, b)
+ if r > 0:
+ println("subtype: yes")
+ else:
+ println("subtype: no")
+ return 0
+ g_kernel_malformed = g_kernel_malformed + 1
+ return 1
// ── 入口 ──
-fn kernel_main() -> int {
+fn kernel_main() -> int:
// get_arg 是内建(instr.cr:701,corec 同款):get_arg(0)=argc(字符串),
// get_arg(i) = 第 i 个参数(i ≥ 1);到空串结束
- n : ., mut = 1;
- files : ., mut = 0;
- loop {
- a := get_arg(n);
- if str_len(a) == 0 { break; }
- txt := read_file(a);
- tl := str_len(txt);
- pos : ., mut = 0;
- loop {
- if pos >= tl { break; }
- end := pos;
- loop {
- if end >= tl { break; }
- if load8(txt, end) == 10 { break; }
- end = end + 1;
- }
- line := str_sub(txt, pos, end - pos);
- kern_process_line(line);
- if end >= tl { break; }
- pos = end + 1;
- }
- files = files + 1;
- n = n + 1;
- }
- if files <= 0 { return 1; } // usage:无文件参数
- if g_kernel_malformed > 0 { return 1; }
- return 0;
-}
+ n : ., mut = 1
+ files : ., mut = 0
+ loop:
+ a := get_arg(n)
+ if str_len(a) == 0:
+ break
+ txt := read_file(a)
+ tl := str_len(txt)
+ pos : ., mut = 0
+ loop:
+ if pos >= tl:
+ break
+ end := pos
+ loop:
+ if end >= tl:
+ break
+ if load8(txt, end) == 10:
+ break
+ end = end + 1
+ line := str_sub(txt, pos, end - pos)
+ kern_process_line(line)
+ if end >= tl:
+ break
+ pos = end + 1
+ files = files + 1
+ n = n + 1
+ if files <= 0:
+ return 1
+ // usage:无文件参数
+ if g_kernel_malformed > 0:
+ return 1
+ return 0
diff --git a/src/kernel/mctt.cr b/src/kernel/mctt.cr
index 5e7e13f4..7b83165f 100644
--- a/src/kernel/mctt.cr
+++ b/src/kernel/mctt.cr
@@ -1,114 +1,108 @@
-fn mk_typ(i : int) -> int {
- n := kern_new(K_TYP);
- kern_set(n , 1 , i);
- return n;
-}
-
-fn mk_pi(a : int , b : int) -> int {
- n := kern_new(K_PI);
- kern_set(n , 1 , a);
- kern_set(n , 2 , b);
- return n;
-}
-
-fn mk_natrec(a : int , mz : int , ms : int , m : int) -> int {
- n := kern_new(K_NATREC);
- kern_set(n , 1 , a);
- kern_set(n , 2 , mz);
- kern_set(n , 3 , ms);
- kern_set(n , 4 , m);
- return n;
-}
-
-fn mk_nat() -> int { return kern_new(K_NAT); }
-fn mk_zero() -> int { return kern_new(K_ZERO); }
-
-fn mk_succ(e : int) -> int {
- n := kern_new(K_SUCC);
- kern_set(n , 1 , e);
- return n;
-}
-
-fn mk_fn(a : int, m : int) -> int {
- n := kern_new(K_FN);
- kern_set(n , 1 , a);
- kern_set(n , 2 , m);
- return n;
-}
-
-fn mk_app(m : int, n : int) -> int {
- n := kern_new(K_APP);
- kern_set(n , 1 , m);
- kern_set(n , 2 , n);
- return n;
-}
-
-fn mk_var(x : int) -> int {
- n := kern_new(K_VAR);
- kern_set(n , 1 , x);
- return n;
-}
-
-fn mk_sub(e : int, s : int) -> int {
- n := kern_new(K_SUB);
- kern_set(n , 1 , e);
- kern_set(n , 2 , s);
- return n;
-}
-
-fn mk_id() -> int {
- n := kern_new(K_SUB);
- kern_set(n , 4 , S_ID);
- return n;
-}
-
-fn mk_weaken() -> int {
- n := kern_new(K_SUB);
- kern_set(n , 4 , S_WEAKEN);
- return n;
-}
-
-fn mk_compose(s1 : int, s2 : int) -> int {
- n := kern_new(K_SUB);
- kern_set(n , 1 , s1);
- kern_set(n , 2 , s2);
- kern_set(n , 4 , S_COMPOSE);
- return n;
-}
-
-fn mk_extend(s : int, e : int) -> int {
- n := kern_new(K_SUB);
- kern_set(n , 1 , s);
- kern_set(n , 2 , e);
- kern_set(n , 4 , S_EXTEND);
- return n;
-}
-
-fn kern_kind(e : int) -> int { return kern_get(e , 0); }
-fn exp_a(e : int) -> int { return kern_get(e , 1); }
-fn exp_b(e : int) -> int { return kern_get(e , 2); }
-
-g_ctx_buf : string , mut;
-g_ctx_len : int , mut = 0;
-g_ctx_cap : int , mut = 0;
-
-fn ctx_extend(a : int) {
- if g_ctx_len >= g_ctx_cap {
- nc := g_ctx_cap * 2;
- if nc == 0 { nc = 16; }
- nb := alloc( nc * 8 );
- i : . , mut = 0;
- loop { if i >= g_ctx_len { break; }
- w64(nb , i * 8 , r64(g_ctx_buf , i * 8));
- i = i + 1;}
- g_ctx_buf = nb;
- g_ctx_cap = nc;
- }
- w64(g_ctx_buf , g_ctx_len * 8 , a);
- g_ctx_len = g_ctx_len + 1;
-}
-
-fn ctx_get(x : int) -> int {
- if x < 0 || x >= g_ctx_len { return -1; }
- return r64(g_ctx_buf , (g_ctx_len - 1 -x) * 8);
-}
+fn mk_typ(i : int) -> int:
+ n := kern_new(K_TYP)
+ kern_set(n , 1 , i)
+ return n
+
+fn mk_pi(a : int , b : int) -> int:
+ n := kern_new(K_PI)
+ kern_set(n , 1 , a)
+ kern_set(n , 2 , b)
+ return n
+
+fn mk_natrec(a : int , mz : int , ms : int , m : int) -> int:
+ n := kern_new(K_NATREC)
+ kern_set(n , 1 , a)
+ kern_set(n , 2 , mz)
+ kern_set(n , 3 , ms)
+ kern_set(n , 4 , m)
+ return n
+
+fn mk_nat() -> int:
+ return kern_new(K_NAT)
+fn mk_zero() -> int:
+ return kern_new(K_ZERO)
+
+fn mk_succ(e : int) -> int:
+ n := kern_new(K_SUCC)
+ kern_set(n , 1 , e)
+ return n
+
+fn mk_fn(a : int, m : int) -> int:
+ n := kern_new(K_FN)
+ kern_set(n , 1 , a)
+ kern_set(n , 2 , m)
+ return n
+
+fn mk_app(m : int, n : int) -> int:
+ n := kern_new(K_APP)
+ kern_set(n , 1 , m)
+ kern_set(n , 2 , n)
+ return n
+
+fn mk_var(x : int) -> int:
+ n := kern_new(K_VAR)
+ kern_set(n , 1 , x)
+ return n
+
+fn mk_sub(e : int, s : int) -> int:
+ n := kern_new(K_SUB)
+ kern_set(n , 1 , e)
+ kern_set(n , 2 , s)
+ return n
+
+fn mk_id() -> int:
+ n := kern_new(K_SUB)
+ kern_set(n , 4 , S_ID)
+ return n
+
+fn mk_weaken() -> int:
+ n := kern_new(K_SUB)
+ kern_set(n , 4 , S_WEAKEN)
+ return n
+
+fn mk_compose(s1 : int, s2 : int) -> int:
+ n := kern_new(K_SUB)
+ kern_set(n , 1 , s1)
+ kern_set(n , 2 , s2)
+ kern_set(n , 4 , S_COMPOSE)
+ return n
+
+fn mk_extend(s : int, e : int) -> int:
+ n := kern_new(K_SUB)
+ kern_set(n , 1 , s)
+ kern_set(n , 2 , e)
+ kern_set(n , 4 , S_EXTEND)
+ return n
+
+fn kern_kind(e : int) -> int:
+ return kern_get(e , 0)
+fn exp_a(e : int) -> int:
+ return kern_get(e , 1)
+fn exp_b(e : int) -> int:
+ return kern_get(e , 2)
+
+g_ctx_buf : string , mut
+g_ctx_len : int , mut = 0
+g_ctx_cap : int , mut = 0
+
+fn ctx_extend(a : int):
+ if g_ctx_len >= g_ctx_cap:
+ nc := g_ctx_cap * 2
+ if nc == 0:
+ nc = 16
+ nb := alloc( nc * 8 )
+ i : . , mut = 0
+ loop:
+ if i >= g_ctx_len:
+ break
+ w64(nb , i * 8 , r64(g_ctx_buf , i * 8))
+ i = i + 1
+ g_ctx_buf = nb
+ g_ctx_cap = nc
+ w64(g_ctx_buf , g_ctx_len * 8 , a)
+ g_ctx_len = g_ctx_len + 1
+
+fn ctx_get(x : int) -> int:
+ if x < 0 || x >= g_ctx_len:
+ return -1
+ return r64(g_ctx_buf , (g_ctx_len - 1 -x) * 8)
diff --git a/src/kernel/nbe.cr b/src/kernel/nbe.cr
index f0fe9b2d..0f9f601b 100644
--- a/src/kernel/nbe.cr
+++ b/src/kernel/nbe.cr
@@ -9,253 +9,327 @@
// ── ① 语义域(§5.1 Domain.v)──
// 与 K_*(0-9)不冲突:D_* = 10+
-D_NAT : int = 10; // ℕ 的语义值
-D_PI : int = 11; // Π a ρ B(B 不求值,闭包存 ρ)
-D_UNIV : int = 12; // 𝕌@i
-D_ZERO : int = 13;
-D_SUCC : int = 14;
-D_FN : int = 15; // λ ρ M(A 不参与求值)
-D_NEUT : int = 16; // ⇑ a m(类型标注 a + neutral m)
-D_VAR : int = 17; // !x —— 绝对名
-D_APP : int = 18; // m n(neutral 应用)
-D_NATREC : int = 19;// rec m under ρ return P | zero -> mz | succ -> MS end
-D_NATREC2 : int = 20;// D_NATREC 的载荷组标记(MS 存槽 6,永不分发)
-D_DOM : int = 21; // ⇓ a m(类型+值配对,domain_nf)
+D_NAT : int = 10 // ℕ 的语义值
+D_PI : int = 11 // Π a ρ B(B 不求值,闭包存 ρ)
+D_UNIV : int = 12 // 𝕌@i
+D_ZERO : int = 13
+D_SUCC : int = 14
+D_FN : int = 15 // λ ρ M(A 不参与求值)
+D_NEUT : int = 16 // ⇑ a m(类型标注 a + neutral m)
+D_VAR : int = 17 // !x —— 绝对名
+D_APP : int = 18 // m n(neutral 应用)
+D_NATREC : int = 19// rec m under ρ return P | zero -> mz | succ -> MS end
+D_NATREC2 : int = 20// D_NATREC 的载荷组标记(MS 存槽 6,永不分发)
+D_DOM : int = 21 // ⇓ a m(类型+值配对,domain_nf)
// 环境节点(§5.1 env 的函数式表示——与提取的 extend_env/drop_env 同构;
// 差分对拍 2026-08-28 发现 count 式 env 在闭包快照被后续追加穿插时索引错位,
// 改链式节点:extend/drop 都是 O(1) 节点,查找沿链走)
-D_ENV_BASE : int = 22; // 空基环境(extend 链的底)
-D_ENV_EXT : int = 23; // {D_ENV_EXT, parent, d, 0, 0}:x=0 → d,否则 parent(x-1)
-D_ENV_DROP : int = 24; // {D_ENV_DROP, parent, 0, 0, 0}:x → parent(x+1)
+D_ENV_BASE : int = 22 // 空基环境(extend 链的底)
+D_ENV_EXT : int = 23 // {D_ENV_EXT, parent, d, 0, 0}:x=0 → d,否则 parent(x-1)
+D_ENV_DROP : int = 24 // {D_ENV_DROP, parent, 0, 0, 0}:x → parent(x+1)
-fn mk_d_nat() -> int { return kern_new(D_NAT); }
-fn mk_d_univ(i: int) -> int { n := kern_new(D_UNIV); kern_set(n, 1, i); return n; }
-fn mk_d_zero() -> int { return kern_new(D_ZERO); }
-fn mk_d_succ(m: int) -> int { n := kern_new(D_SUCC); kern_set(n, 1, m); return n; }
-fn mk_d_pi(a: int, rho: int, b: int) -> int { n := kern_new(D_PI); kern_set(n, 1, a); kern_set(n, 2, rho); kern_set(n, 3, b); return n; }
-fn mk_d_fn(rho: int, m: int) -> int { n := kern_new(D_FN); kern_set(n, 1, rho); kern_set(n, 2, m); return n; }
-fn mk_d_neut(a: int, ne: int) -> int { n := kern_new(D_NEUT); kern_set(n, 1, a); kern_set(n, 2, ne); return n; }
-fn mk_d_var(x: int) -> int { n := kern_new(D_VAR); kern_set(n, 1, x); return n; }
-fn mk_d_app(ne: int, nf: int) -> int { n := kern_new(D_APP); kern_set(n, 1, ne); kern_set(n, 2, nf); return n; }
+fn mk_d_nat() -> int:
+ return kern_new(D_NAT)
+fn mk_d_univ(i: int) -> int:
+ n := kern_new(D_UNIV)
+ kern_set(n, 1, i)
+ return n
+fn mk_d_zero() -> int:
+ return kern_new(D_ZERO)
+fn mk_d_succ(m: int) -> int:
+ n := kern_new(D_SUCC)
+ kern_set(n, 1, m)
+ return n
+fn mk_d_pi(a: int, rho: int, b: int) -> int:
+ n := kern_new(D_PI)
+ kern_set(n, 1, a)
+ kern_set(n, 2, rho)
+ kern_set(n, 3, b)
+ return n
+fn mk_d_fn(rho: int, m: int) -> int:
+ n := kern_new(D_FN)
+ kern_set(n, 1, rho)
+ kern_set(n, 2, m)
+ return n
+fn mk_d_neut(a: int, ne: int) -> int:
+ n := kern_new(D_NEUT)
+ kern_set(n, 1, a)
+ kern_set(n, 2, ne)
+ return n
+fn mk_d_var(x: int) -> int:
+ n := kern_new(D_VAR)
+ kern_set(n, 1, x)
+ return n
+fn mk_d_app(ne: int, nf: int) -> int:
+ n := kern_new(D_APP)
+ kern_set(n, 1, ne)
+ kern_set(n, 2, nf)
+ return n
// D_NATREC 有 5 个成分(m ρ P mz MS),五槽装不下——MS 存下一组的槽 1(= 槽 6)
-fn mk_d_natrec(m: int, rho: int, p: int, mz: int, ms: int) -> int {
- n := kern_new(D_NATREC);
- if n < 0 { return -1; }
- kern_set(n, 1, m); kern_set(n, 2, rho); kern_set(n, 3, p); kern_set(n, 4, mz);
- n2 := kern_new(D_NATREC2);
- if n2 < 0 { return -1; } // 载荷组分配失败:整组放弃(arena 追加式,无回滚必要)
- kern_set(n, 6, ms);
- return n;
-}
-fn d_natrec_ms(n: int) -> int { return kern_get(n, 6); }
-fn mk_d_dom(a: int, m: int) -> int { n := kern_new(D_DOM); kern_set(n, 1, a); kern_set(n, 2, m); return n; }
+fn mk_d_natrec(m: int, rho: int, p: int, mz: int, ms: int) -> int:
+ n := kern_new(D_NATREC)
+ if n < 0:
+ return -1
+ kern_set(n, 1, m)
+ kern_set(n, 2, rho)
+ kern_set(n, 3, p)
+ kern_set(n, 4, mz)
+ n2 := kern_new(D_NATREC2)
+ if n2 < 0:
+ return -1
+ // 载荷组分配失败:整组放弃(arena 追加式,无回滚必要)
+ kern_set(n, 6, ms)
+ return n
+fn d_natrec_ms(n: int) -> int:
+ return kern_get(n, 6)
+fn mk_d_dom(a: int, m: int) -> int:
+ n := kern_new(D_DOM)
+ kern_set(n, 1, a)
+ kern_set(n, 2, m)
+ return n
// ── ② 环境(§5.1 env/empty_env/extend_env/drop_env)──
// env = arena 节点链(函数式,同提取的 extend_env/drop_env):
// env_get(ρ, x) = de Bruijn x(0 = 最新);EXT: x=0 → d,否则 parent(x-1);
// DROP: parent(x+1);BASE: 越界 → -1
-fn mk_env_base() -> int { return kern_new(D_ENV_BASE); }
+fn mk_env_base() -> int:
+ return kern_new(D_ENV_BASE)
-fn env_extend(rho: int, d: int) -> int {
- n := kern_new(D_ENV_EXT);
- if n < 0 { return -1; }
- kern_set(n, 1, rho);
- kern_set(n, 2, d);
- return n;
-}
+fn env_extend(rho: int, d: int) -> int:
+ n := kern_new(D_ENV_EXT)
+ if n < 0:
+ return -1
+ kern_set(n, 1, rho)
+ kern_set(n, 2, d)
+ return n
-fn env_drop(rho: int) -> int {
- n := kern_new(D_ENV_DROP);
- if n < 0 { return -1; }
- kern_set(n, 1, rho);
- return n;
-}
+fn env_drop(rho: int) -> int:
+ n := kern_new(D_ENV_DROP)
+ if n < 0:
+ return -1
+ kern_set(n, 1, rho)
+ return n
-fn env_get(rho: int, x: int) -> int {
- if rho < 0 { return -1; }
- k := kern_kind(rho);
- if k == D_ENV_EXT {
- if x == 0 { return kern_get(rho, 2); }
- return env_get(kern_get(rho, 1), x - 1);
- }
- if k == D_ENV_DROP { return env_get(kern_get(rho, 1), x + 1); }
- if k == D_ENV_BASE { return mk_d_zero(); } // 空基:d_zero——env 全函数(提取 empty_env _ = d_zero,
+fn env_get(rho: int, x: int) -> int:
+ if rho < 0:
+ return -1
+ k := kern_kind(rho)
+ if k == D_ENV_EXT:
+ if x == 0:
+ return kern_get(rho, 2)
+ return env_get(kern_get(rho, 1), x - 1)
+ if k == D_ENV_DROP:
+ return env_get(kern_get(rho, 1), x + 1)
+ if k == D_ENV_BASE:
+ return mk_d_zero()
+ // 空基:d_zero——env 全函数(提取 empty_env _ = d_zero,
// Domain.ml;越界求值 = d_zero,差分对拍 2026-08-28 实测)
- return -1;
-}
+ return -1
// ── ③ 求值(§5.2 Eval/Definitions.v,19 条规则)──
// eval_exp(10 条):exp + env → domain
-fn kern_eval(e: int, rho: int) -> int {
- k := kern_kind(e);
- if k == K_TYP { return mk_d_univ(kern_get(e, 1)); } // ⟦Type@i⟧ = 𝕌@i
- if k == K_NAT { return mk_d_nat(); } // ⟦ℕ⟧ = ℕ
- if k == K_ZERO { return mk_d_zero(); } // ⟦zero⟧ = zero
- if k == K_SUCC { return mk_d_succ(kern_eval(kern_get(e, 1), rho)); } // ⟦succ M⟧
- if k == K_VAR { return env_get(rho, kern_get(e, 1)); } // ⟦#x⟧ρ = ρ x
- if k == K_PI { return mk_d_pi(kern_eval(kern_get(e, 1), rho), rho, kern_get(e, 2)); } // B 不求值
- if k == K_FN { return mk_d_fn(rho, kern_get(e, 2)); } // A 不参与求值
- if k == K_APP { return kern_eval_app(kern_eval(kern_get(e, 1), rho), kern_eval(kern_get(e, 2), rho)); }
- if k == K_NATREC { return kern_eval_natrec(kern_eval(kern_get(e, 4), rho), kern_get(e, 1), kern_get(e, 2), kern_get(e, 3), rho); }
- if k == K_SUB { return kern_eval(kern_get(e, 1), kern_eval_sub(kern_get(e, 2), rho)); } // 替换→环境→求值
- return -1;
-}
+fn kern_eval(e: int, rho: int) -> int:
+ k := kern_kind(e)
+ if k == K_TYP:
+ return mk_d_univ(kern_get(e, 1))
+ // ⟦Type@i⟧ = 𝕌@i
+ if k == K_NAT:
+ return mk_d_nat()
+ // ⟦ℕ⟧ = ℕ
+ if k == K_ZERO:
+ return mk_d_zero()
+ // ⟦zero⟧ = zero
+ if k == K_SUCC:
+ return mk_d_succ(kern_eval(kern_get(e, 1), rho))
+ // ⟦succ M⟧
+ if k == K_VAR:
+ return env_get(rho, kern_get(e, 1))
+ // ⟦#x⟧ρ = ρ x
+ if k == K_PI:
+ return mk_d_pi(kern_eval(kern_get(e, 1), rho), rho, kern_get(e, 2))
+ // B 不求值
+ if k == K_FN:
+ return mk_d_fn(rho, kern_get(e, 2))
+ // A 不参与求值
+ if k == K_APP:
+ return kern_eval_app(kern_eval(kern_get(e, 1), rho), kern_eval(kern_get(e, 2), rho))
+ if k == K_NATREC:
+ return kern_eval_natrec(kern_eval(kern_get(e, 4), rho), kern_get(e, 1), kern_get(e, 2), kern_get(e, 3), rho)
+ if k == K_SUB:
+ return kern_eval(kern_get(e, 1), kern_eval_sub(kern_get(e, 2), rho))
+ // 替换→环境→求值
+ return -1
// eval_natrec(3 条):domain 上的递归
-fn kern_eval_natrec(m: int, a: int, mz: int, ms: int, rho: int) -> int {
- k := kern_kind(m);
- if k == D_ZERO { return kern_eval(mz, rho); } // rec zero ↘ ⟦MZ⟧ρ
- if k == D_SUCC {
- b := kern_get(m, 1);
- r := kern_eval_natrec(b, a, mz, ms, rho); // 递归 r
- return kern_eval(ms, env_extend(env_extend(rho, b), r)); // ⟦MS⟧ ρ↦b↦r
- }
- if k == D_NEUT {
- ne := kern_get(m, 2);
- a2 := kern_eval(a, env_extend(rho, m)); // ⟦A⟧ ρ↦⇑b m
- return mk_d_neut(a2, mk_d_natrec(ne, rho, a, kern_eval(mz, rho), ms)); // 保持 neutral
- }
- return -1;
-}
+fn kern_eval_natrec(m: int, a: int, mz: int, ms: int, rho: int) -> int:
+ k := kern_kind(m)
+ if k == D_ZERO:
+ return kern_eval(mz, rho)
+ // rec zero ↘ ⟦MZ⟧ρ
+ if k == D_SUCC:
+ b := kern_get(m, 1)
+ r := kern_eval_natrec(b, a, mz, ms, rho) // 递归 r
+ return kern_eval(ms, env_extend(env_extend(rho, b), r)) // ⟦MS⟧ ρ↦b↦r
+ if k == D_NEUT:
+ ne := kern_get(m, 2)
+ a2 := kern_eval(a, env_extend(rho, m)) // ⟦A⟧ ρ↦⇑b m
+ return mk_d_neut(a2, mk_d_natrec(ne, rho, a, kern_eval(mz, rho), ms)) // 保持 neutral
+ return -1
// eval_app(2 条):$|m & n|↘ r
-fn kern_eval_app(m: int, n: int) -> int {
- k := kern_kind(m);
- if k == D_FN { return kern_eval(kern_get(m, 2), env_extend(kern_get(m, 1), n)); } // λρM 展开
- if k == D_NEUT {
- a := kern_get(m, 1);
- if kern_kind(a) == D_PI {
- ap := kern_get(a, 1); rp := kern_get(a, 2); bp := kern_get(a, 3);
- b := kern_eval(bp, env_extend(rp, n)); // ⟦B⟧ ρ↦n
- return mk_d_neut(b, mk_d_app(kern_get(m, 2), mk_d_dom(ap, n))); // ⇑b (m (⇓a n))
- }
- }
- return -1;
-}
+fn kern_eval_app(m: int, n: int) -> int:
+ k := kern_kind(m)
+ if k == D_FN:
+ return kern_eval(kern_get(m, 2), env_extend(kern_get(m, 1), n))
+ // λρM 展开
+ if k == D_NEUT:
+ a := kern_get(m, 1)
+ if kern_kind(a) == D_PI:
+ ap := kern_get(a, 1)
+ rp := kern_get(a, 2)
+ bp := kern_get(a, 3)
+ b := kern_eval(bp, env_extend(rp, n)) // ⟦B⟧ ρ↦n
+ return mk_d_neut(b, mk_d_app(kern_get(m, 2), mk_d_dom(ap, n))) // ⇑b (m (⇓a n))
+ return -1
// eval_sub(4 条):替换 → 环境(⟦σ⟧s ρ ↘ ρσ)
-fn kern_eval_sub(s: int, rho: int) -> int {
- k := kern_kind(s);
- if k == K_SUB {
- sk := kern_get(s, 4);
- if sk == S_ID { return rho; } // ⟦Id⟧ ρ = ρ
- if sk == S_WEAKEN { return env_drop(rho); } // ⟦Wk⟧ ρ = ρ↯
- if sk == S_EXTEND {
- rs := kern_eval_sub(kern_get(s, 1), rho); // ρσ
- return env_extend(rs, kern_eval(kern_get(s, 2), rho)); // ρσ ↦ m
- }
- if sk == S_COMPOSE {
- rt := kern_eval_sub(kern_get(s, 2), rho); // ⟦τ⟧ ρ(τ 先作用)
- return kern_eval_sub(kern_get(s, 1), rt); // ⟦σ⟧ ρτ
- }
- }
- return -1;
-}
+fn kern_eval_sub(s: int, rho: int) -> int:
+ k := kern_kind(s)
+ if k == K_SUB:
+ sk := kern_get(s, 4)
+ if sk == S_ID:
+ return rho
+ // ⟦Id⟧ ρ = ρ
+ if sk == S_WEAKEN:
+ return env_drop(rho)
+ // ⟦Wk⟧ ρ = ρ↯
+ if sk == S_EXTEND:
+ rs := kern_eval_sub(kern_get(s, 1), rho) // ρσ
+ return env_extend(rs, kern_eval(kern_get(s, 2), rho)) // ρσ ↦ m
+ if sk == S_COMPOSE:
+ rt := kern_eval_sub(kern_get(s, 2), rho) // ⟦τ⟧ ρ(τ 先作用)
+ return kern_eval_sub(kern_get(s, 1), rt) // ⟦σ⟧ ρτ
+ return -1
// ── ④ 读出(§5.3 Readback/Definitions.v,12 条规则)──
// domain + 深度 s → nf/ne(exp 节点!);绝对名 → de Bruijn:!x → #(s-x-1)
// read_nf(6 条)
-fn kern_read_nf(d: int, s: int) -> int {
- a := kern_get(d, 1); m := kern_get(d, 2); // ⇓ a m
- ak := kern_kind(a);
- if ak == D_UNIV { return kern_read_typ(m, s); } // ⇓𝕌@i a
- if ak == D_NAT {
- mk := kern_kind(m);
- if mk == D_ZERO { return mk_zero(); } // ⇓ℕ zero
- if mk == D_SUCC { return mk_succ(kern_read_nf(mk_d_dom(a, kern_get(m, 1)), s)); }
- if mk == D_NEUT { return kern_read_ne(kern_get(m, 2), s); } // ⇓ℕ (⇑a' m)
- return -1;
- }
- if ak == D_PI {
+fn kern_read_nf(d: int, s: int) -> int:
+ a := kern_get(d, 1)
+ m := kern_get(d, 2) // ⇓ a m
+ ak := kern_kind(a)
+ if ak == D_UNIV:
+ return kern_read_typ(m, s)
+ // ⇓𝕌@i a
+ if ak == D_NAT:
+ mk := kern_kind(m)
+ if mk == D_ZERO:
+ return mk_zero()
+ // ⇓ℕ zero
+ if mk == D_SUCC:
+ return mk_succ(kern_read_nf(mk_d_dom(a, kern_get(m, 1)), s))
+ if mk == D_NEUT:
+ return kern_read_ne(kern_get(m, 2), s)
+ // ⇓ℕ (⇑a' m)
+ return -1
+ if ak == D_PI:
// η 展开(read_nf_fn):应用到新鲜绝对名 s,深度 +1
- ap := kern_get(a, 1); rp := kern_get(a, 2); bp := kern_get(a, 3);
- a_out := kern_read_typ(ap, s); // A = Rtyp a in s
- fresh := mk_d_neut(ap, mk_d_var(s)); // ⇑! a s
- m1 := kern_eval_app(m, fresh); // $|m & ⇑!a s|
- b := kern_eval(bp, env_extend(rp, fresh)); // ⟦B⟧ ρ↦⇑!a s
- m_out := kern_read_nf(mk_d_dom(b, m1), s + 1); // Rnf ⇓b m' in S s
- return mk_fn(a_out, m_out); // λ A M
- }
- if ak == D_NEUT {
- mk := kern_kind(m);
- if mk == D_NEUT { return kern_read_ne(kern_get(m, 2), s); } // ⇓(⇑a b)(⇑c m)
- }
- return -1;
-}
+ ap := kern_get(a, 1)
+ rp := kern_get(a, 2)
+ bp := kern_get(a, 3)
+ a_out := kern_read_typ(ap, s) // A = Rtyp a in s
+ fresh := mk_d_neut(ap, mk_d_var(s)) // ⇑! a s
+ m1 := kern_eval_app(m, fresh) // $|m & ⇑!a s|
+ b := kern_eval(bp, env_extend(rp, fresh)) // ⟦B⟧ ρ↦⇑!a s
+ m_out := kern_read_nf(mk_d_dom(b, m1), s + 1) // Rnf ⇓b m' in S s
+ return mk_fn(a_out, m_out) // λ A M
+ if ak == D_NEUT:
+ mk := kern_kind(m)
+ if mk == D_NEUT:
+ return kern_read_ne(kern_get(m, 2), s)
+ // ⇓(⇑a b)(⇑c m)
+ return -1
// read_ne(3 条)
-fn kern_read_ne(ne: int, s: int) -> int {
- k := kern_kind(ne);
- if k == D_VAR { return mk_var(s - kern_get(ne, 1) - 1); } // !x → #(s-x-1)
- if k == D_APP { return mk_app(kern_read_ne(kern_get(ne, 1), s), kern_read_nf(kern_get(ne, 2), s)); }
- if k == D_NATREC {
- m := kern_get(ne, 1); rho := kern_get(ne, 2); b := kern_get(ne, 3);
- mz := kern_get(ne, 4); ms := d_natrec_ms(ne);
+fn kern_read_ne(ne: int, s: int) -> int:
+ k := kern_kind(ne)
+ if k == D_VAR:
+ return mk_var(s - kern_get(ne, 1) - 1)
+ // !x → #(s-x-1)
+ if k == D_APP:
+ return mk_app(kern_read_ne(kern_get(ne, 1), s), kern_read_nf(kern_get(ne, 2), s))
+ if k == D_NATREC:
+ m := kern_get(ne, 1)
+ rho := kern_get(ne, 2)
+ b := kern_get(ne, 3)
+ mz := kern_get(ne, 4)
+ ms := d_natrec_ms(ne)
// ⟦B⟧ ρ↦⇑!ℕs ↘ b1;Rtyp b1 in S s ↘ B'
- b1 := kern_eval(b, env_extend(rho, mk_d_neut(mk_d_nat(), mk_d_var(s))));
- b_out := kern_read_typ(b1, s + 1);
+ b1 := kern_eval(b, env_extend(rho, mk_d_neut(mk_d_nat(), mk_d_var(s))))
+ b_out := kern_read_typ(b1, s + 1)
// ⟦B⟧ ρ↦zero ↘ bz;Rnf ⇓bz mz in s ↘ MZ
- bz := kern_eval(b, env_extend(rho, mk_d_zero()));
- mz_out := kern_read_nf(mk_d_dom(bz, mz), s);
+ bz := kern_eval(b, env_extend(rho, mk_d_zero()))
+ mz_out := kern_read_nf(mk_d_dom(bz, mz), s)
// ⟦B⟧ ρ↦succ(⇑!ℕs) ↘ bs;⟦MS⟧ ρ↦⇑!ℕs↦⇑!b(Ss) ↘ ms';Rnf ⇓bs ms' in S(S s) ↘ MS'
- bs := kern_eval(b, env_extend(rho, mk_d_succ(mk_d_neut(mk_d_nat(), mk_d_var(s)))));
- ms1 := kern_eval(ms, env_extend(env_extend(rho, mk_d_neut(mk_d_nat(), mk_d_var(s))), mk_d_neut(b1, mk_d_var(s + 1))));
- ms_out := kern_read_nf(mk_d_dom(bs, ms1), s + 2);
+ bs := kern_eval(b, env_extend(rho, mk_d_succ(mk_d_neut(mk_d_nat(), mk_d_var(s)))))
+ ms1 := kern_eval(ms, env_extend(env_extend(rho, mk_d_neut(mk_d_nat(), mk_d_var(s))), mk_d_neut(b1, mk_d_var(s + 1))))
+ ms_out := kern_read_nf(mk_d_dom(bs, ms1), s + 2)
// Rne m in s ↘ M
- m_out := kern_read_ne(m, s);
- return mk_natrec(b_out, mz_out, ms_out, m_out); // rec M return B' | zero -> MZ | succ -> MS' end
- }
- return -1;
-}
+ m_out := kern_read_ne(m, s)
+ return mk_natrec(b_out, mz_out, ms_out, m_out) // rec M return B' | zero -> MZ | succ -> MS' end
+ return -1
// read_typ(4 条)
-fn kern_read_typ(a: int, s: int) -> int {
- k := kern_kind(a);
- if k == D_UNIV { return mk_typ(kern_get(a, 1)); } // 𝕌@i → Type@i
- if k == D_NAT { return mk_nat(); } // ℕ → ℕ
- if k == D_PI {
- ap := kern_get(a, 1); rp := kern_get(a, 2); bp := kern_get(a, 3);
- a_out := kern_read_typ(ap, s); // Rtyp a in s
- fresh := mk_d_neut(ap, mk_d_var(s)); // ⇑! a s
- b := kern_eval(bp, env_extend(rp, fresh)); // ⟦B⟧ ρ↦⇑!a s
- b_out := kern_read_typ(b, s + 1); // Rtyp b in S s
- return mk_pi(a_out, b_out); // Π A B'
- }
- if k == D_NEUT { return kern_read_ne(kern_get(a, 2), s); } // ⇑ a b → ⇑ B
- return -1;
-}
+fn kern_read_typ(a: int, s: int) -> int:
+ k := kern_kind(a)
+ if k == D_UNIV:
+ return mk_typ(kern_get(a, 1))
+ // 𝕌@i → Type@i
+ if k == D_NAT:
+ return mk_nat()
+ // ℕ → ℕ
+ if k == D_PI:
+ ap := kern_get(a, 1)
+ rp := kern_get(a, 2)
+ bp := kern_get(a, 3)
+ a_out := kern_read_typ(ap, s) // Rtyp a in s
+ fresh := mk_d_neut(ap, mk_d_var(s)) // ⇑! a s
+ b := kern_eval(bp, env_extend(rp, fresh)) // ⟦B⟧ ρ↦⇑!a s
+ b_out := kern_read_typ(b, s + 1) // Rtyp b in S s
+ return mk_pi(a_out, b_out) // Π A B'
+ if k == D_NEUT:
+ return kern_read_ne(kern_get(a, 2), s)
+ // ⇑ a b → ⇑ B
+ return -1
// ── ⑤ 规范化入口(§5.4 initial_env + §5.5 nbe/nbe_ty)──
// initial_env Γ ρ:从最旧到最新绑定,第 x 个 de Bruijn 变量 → 绝对名 (len-1-x)
-fn kern_initial_env() -> int {
- rho : ., mut = mk_env_base();
- name : ., mut = 0;
- i : ., mut = g_ctx_len - 1;
- loop {
- if i < 0 { break; }
- a := ctx_get(i);
- va := kern_eval(a, rho);
- rho = env_extend(rho, mk_d_neut(va, mk_d_var(name)));
- name = name + 1;
- i = i - 1;
- }
- return rho;
-}
+fn kern_initial_env() -> int:
+ rho : ., mut = mk_env_base()
+ name : ., mut = 0
+ i : ., mut = g_ctx_len - 1
+ loop:
+ if i < 0:
+ break
+ a := ctx_get(i)
+ va := kern_eval(a, rho)
+ rho = env_extend(rho, mk_d_neut(va, mk_d_var(name)))
+ name = name + 1
+ i = i - 1
+ return rho
// nbe Γ M A:M : A 规范化为 nf(读入深度 = length Γ)
-fn kern_nbe(m: int, a: int) -> int {
- rho := kern_initial_env();
- da := kern_eval(a, rho);
- dm := kern_eval(m, rho);
- return kern_read_nf(mk_d_dom(da, dm), g_ctx_len);
-}
+fn kern_nbe(m: int, a: int) -> int:
+ rho := kern_initial_env()
+ da := kern_eval(a, rho)
+ dm := kern_eval(m, rho)
+ return kern_read_nf(mk_d_dom(da, dm), g_ctx_len)
// nbe_ty Γ M:类型 M 规范化为 nf
-fn kern_nbe_ty(m: int) -> int {
- rho := kern_initial_env();
- dm := kern_eval(m, rho);
- return kern_read_typ(dm, g_ctx_len);
-}
+fn kern_nbe_ty(m: int) -> int:
+ rho := kern_initial_env()
+ dm := kern_eval(m, rho)
+ return kern_read_typ(dm, g_ctx_len)
diff --git a/src/kernel/subst.cr b/src/kernel/subst.cr
index 1e9f6294..e82a36e3 100644
--- a/src/kernel/subst.cr
+++ b/src/kernel/subst.cr
@@ -1,28 +1,23 @@
-fn subst_q(s : int) -> int {
- return mk_extend(mk_compose(s , mk_weaken()) , mk_var(0));
-}
+fn subst_q(s : int) -> int:
+ return mk_extend(mk_compose(s , mk_weaken()) , mk_var(0))
-fn subst_id_zero() -> int {
- return mk_extend(mk_id() , mk_zero());
-}
+fn subst_id_zero() -> int:
+ return mk_extend(mk_id() , mk_zero())
-fn subst_wk_wk_succ1() -> int {
- return mk_extend(mk_compose(mk_weaken() , mk_weaken()) , mk_succ(mk_var(1)));
-}
+fn subst_wk_wk_succ1() -> int:
+ return mk_extend(mk_compose(mk_weaken() , mk_weaken()) , mk_succ(mk_var(1)))
-fn subst_id_of(e : int) -> int {
- return mk_extend(mk_id() , e);
-}
+fn subst_id_of(e : int) -> int:
+ return mk_extend(mk_id() , e)
// Wk∘…∘Wk(n 次)——lookup 的弱化计数(TypeCheck.ml lookup 每层递归包一次 Wk,
// 索引 x 的查找结果被弱化 x+1 次;差分对拍 2026-08-28 实测确认)
-fn subst_wk_n(n : int) -> int {
- s : ., mut = mk_weaken();
- i : ., mut = 1;
- loop {
- if i >= n { break; }
- s = mk_compose(s , mk_weaken());
- i = i + 1;
- }
- return s;
-}
+fn subst_wk_n(n : int) -> int:
+ s : ., mut = mk_weaken()
+ i : ., mut = 1
+ loop:
+ if i >= n:
+ break
+ s = mk_compose(s , mk_weaken())
+ i = i + 1
+ return s
diff --git a/src/kernel/subtype.cr b/src/kernel/subtype.cr
index bc8e5c75..e18910b0 100644
--- a/src/kernel/subtype.cr
+++ b/src/kernel/subtype.cr
@@ -6,27 +6,29 @@
// 总化(protocol §5):两侧非类型形态 → no(kern_nbe_ty 失败 → -1 → 0)
// ⊢anf A ⊆ A':正规形子类型(AlgSub/Definitions.v:15-27,3 条)
-fn kern_sub_nf(a: int, b: int) -> int {
- ka := kern_get(a, 0); kb := kern_get(b, 0);
- if ka == K_TYP && kb == K_TYP {
+fn kern_sub_nf(a: int, b: int) -> int:
+ ka := kern_get(a, 0)
+ kb := kern_get(b, 0)
+ if ka == K_TYP && kb == K_TYP:
// asnf_univ:i <= j(AlgSub/Definitions.v:20-22)
- return kern_get(a, 1) <= kern_get(b, 1);
- }
- if ka == K_PI && kb == K_PI {
+ return kern_get(a, 1) <= kern_get(b, 1)
+ if ka == K_PI && kb == K_PI:
// asnf_pi:域语法相等 + 余域协变(AlgSub/Definitions.v:23-26)
// 注意:无逆变前提(McTT 没有 Π 逆变子类型——移植时不得添加)
- if nf_eq(kern_get(a, 1), kern_get(b, 1)) == 0 { return 0; }
- return kern_sub_nf(kern_get(a, 2), kern_get(b, 2));
- }
+ if nf_eq(kern_get(a, 1), kern_get(b, 1)) == 0:
+ return 0
+ return kern_sub_nf(kern_get(a, 2), kern_get(b, 2))
// asnf_refl:not_univ_pi A ∧ A = A'(AlgSub/Definitions.v:16-19)
- if ka == K_TYP || ka == K_PI { return 0; } // not_univ_pi 前置
- return nf_eq(a, b);
-}
+ if ka == K_TYP || ka == K_PI:
+ return 0
+ // not_univ_pi 前置
+ return nf_eq(a, b)
// Γ ⊢a A ⊆ B:先规范化两侧到 nf,再在 nf 上比较(AlgSub/Definitions.v:29-35)
-fn subtyping(a: int, b: int) -> int {
- a1 := kern_nbe_ty(a);
- b1 := kern_nbe_ty(b);
- if a1 < 0 || b1 < 0 { return 0; } // 非类型形态 → no(总化)
- return kern_sub_nf(a1, b1);
-}
+fn subtyping(a: int, b: int) -> int:
+ a1 := kern_nbe_ty(a)
+ b1 := kern_nbe_ty(b)
+ if a1 < 0 || b1 < 0:
+ return 0
+ // 非类型形态 → no(总化)
+ return kern_sub_nf(a1, b1)
diff --git a/src/kernel/term_io.cr b/src/kernel/term_io.cr
index 42dd325a..d03bb448 100644
--- a/src/kernel/term_io.cr
+++ b/src/kernel/term_io.cr
@@ -34,268 +34,321 @@
// S_COMPOSE/S_EXTEND 的 a/b 槽)出发的子指针指向 sub 节点——按位置区分,无歧义。
// ── 常量 ──
-K_TYP : int = 0; K_NAT : int = 1; K_ZERO : int = 2; K_SUCC : int = 3;
-K_NATREC : int = 4; K_PI : int = 5; K_FN : int = 6; K_APP : int = 7;
-K_VAR : int = 8; K_SUB : int = 9;
-S_ID : int = 0; S_WEAKEN : int = 1; S_COMPOSE : int = 2; S_EXTEND : int = 3;
+K_TYP : int = 0
+K_NAT : int = 1
+K_ZERO : int = 2
+K_SUCC : int = 3
+K_NATREC : int = 4
+K_PI : int = 5
+K_FN : int = 6
+K_APP : int = 7
+K_VAR : int = 8
+K_SUB : int = 9
+S_ID : int = 0
+S_WEAKEN : int = 1
+S_COMPOSE : int = 2
+S_EXTEND : int = 3
-KERNEL_SLOTS : int = 8192;
+KERNEL_SLOTS : int = 8192
// 注意:全局常量初始化必须是字面量——表达式(如 8192*8)的 init_val 为 0,
// BSS 槽保持 0(ELF 后端已知限制,曾导致 alloc(0))。
-KERNEL_SLOT_BYTES : int = 65536;
+KERNEL_SLOT_BYTES : int = 65536
// ── 扁平 arena ──
-g_kernel_nodes : string, mut; // 64KB 字节缓冲(8192 个 int 槽),惰性分配
-g_kernel_buf_ready : int, mut = 0; // 缓冲是否已分配(不能用 str_len 探测 NULL)
-g_kernel_count : int, mut = 0; // 已分配节点数(节点 = 五槽一组)
+g_kernel_nodes : string, mut // 64KB 字节缓冲(8192 个 int 槽),惰性分配
+g_kernel_buf_ready : int, mut = 0 // 缓冲是否已分配(不能用 str_len 探测 NULL)
+g_kernel_count : int, mut = 0 // 已分配节点数(节点 = 五槽一组)
-fn kern_ensure_buf() {
- if g_kernel_buf_ready == 0 {
- g_kernel_nodes = alloc(KERNEL_SLOT_BYTES);
- g_kernel_buf_ready = 1;
- }
-}
+fn kern_ensure_buf():
+ if g_kernel_buf_ready == 0:
+ g_kernel_nodes = alloc(KERNEL_SLOT_BYTES)
+ g_kernel_buf_ready = 1
// 新建节点,返回节点索引(起始槽);arena 满时返回 -1
-fn kern_new(k: int) -> int {
- kern_ensure_buf();
- if g_kernel_count * 5 + 5 > KERNEL_SLOTS { return -1; }
- i := g_kernel_count * 5;
- w64(g_kernel_nodes, i * 8, k);
- w64(g_kernel_nodes, (i + 1) * 8, 0);
- w64(g_kernel_nodes, (i + 2) * 8, 0);
- w64(g_kernel_nodes, (i + 3) * 8, 0);
- w64(g_kernel_nodes, (i + 4) * 8, 0);
- g_kernel_count = g_kernel_count + 1;
- return i;
-}
+fn kern_new(k: int) -> int:
+ kern_ensure_buf()
+ if g_kernel_count * 5 + 5 > KERNEL_SLOTS:
+ return -1
+ i := g_kernel_count * 5
+ w64(g_kernel_nodes, i * 8, k)
+ w64(g_kernel_nodes, (i + 1) * 8, 0)
+ w64(g_kernel_nodes, (i + 2) * 8, 0)
+ w64(g_kernel_nodes, (i + 3) * 8, 0)
+ w64(g_kernel_nodes, (i + 4) * 8, 0)
+ g_kernel_count = g_kernel_count + 1
+ return i
-fn kern_set(n: int, slot: int, v: int) {
- if n < 0 { return; } // arena 满(kern_new = -1)时防静默覆盖节点 0
- w64(g_kernel_nodes, (n + slot) * 8, v);
-}
+fn kern_set(n: int, slot: int, v: int):
+ if n < 0:
+ return
+ // arena 满(kern_new = -1)时防静默覆盖节点 0
+ w64(g_kernel_nodes, (n + slot) * 8, v)
-fn kern_get(n: int, slot: int) -> int {
- if n < 0 { return -1; }
- return r64(g_kernel_nodes, (n + slot) * 8);
-}
+fn kern_get(n: int, slot: int) -> int:
+ if n < 0:
+ return -1
+ return r64(g_kernel_nodes, (n + slot) * 8)
// ── 解析状态 ──
-g_kernel_parse_pos : int, mut = 0;
-g_kernel_parse_text : string, mut;
+g_kernel_parse_pos : int, mut = 0
+g_kernel_parse_text : string, mut
-fn kp_len() -> int { return str_len(g_kernel_parse_text); }
+fn kp_len() -> int:
+ return str_len(g_kernel_parse_text)
-fn kp_skip_ws() {
- loop {
- if g_kernel_parse_pos >= kp_len() { break; }
- c := load8(g_kernel_parse_text, g_kernel_parse_pos);
- if c == 32 || c == 9 || c == 10 || c == 13 { g_kernel_parse_pos = g_kernel_parse_pos + 1; }
- else { break; }
- }
-}
+fn kp_skip_ws():
+ loop:
+ if g_kernel_parse_pos >= kp_len():
+ break
+ c := load8(g_kernel_parse_text, g_kernel_parse_pos)
+ if c == 32 || c == 9 || c == 10 || c == 13:
+ g_kernel_parse_pos = g_kernel_parse_pos + 1
+ else:
+ break
// 当前位置的记号名与 name 逐字节比较(不移动位置)
-fn kp_name_is(name: string) -> int {
- nl := str_len(name);
- if g_kernel_parse_pos + nl > kp_len() { return 0; }
- i : int, mut = 0;
- loop {
- if i >= nl { break; }
- if load8(g_kernel_parse_text, g_kernel_parse_pos + i) != load8(name, i) { return 0; }
- i = i + 1;
- }
+fn kp_name_is(name: string) -> int:
+ nl := str_len(name)
+ if g_kernel_parse_pos + nl > kp_len():
+ return 0
+ i : int, mut = 0
+ loop:
+ if i >= nl:
+ break
+ if load8(g_kernel_parse_text, g_kernel_parse_pos + i) != load8(name, i):
+ return 0
+ i = i + 1
// 名字后必须是分隔符(空白 / ( / ) / 结束),防止 (natx) 误匹配 (nat)
- if g_kernel_parse_pos + nl >= kp_len() { return 1; }
- c := load8(g_kernel_parse_text, g_kernel_parse_pos + nl);
- if c == 32 || c == 9 || c == 10 || c == 13 || c == 40 || c == 41 { return 1; }
- return 0;
-}
+ if g_kernel_parse_pos + nl >= kp_len():
+ return 1
+ c := load8(g_kernel_parse_text, g_kernel_parse_pos + nl)
+ if c == 32 || c == 9 || c == 10 || c == 13 || c == 40 || c == 41:
+ return 1
+ return 0
// 解析非负十进制整数;无数字返回 -1
-fn kp_num() -> int {
- start := g_kernel_parse_pos;
- loop {
- if g_kernel_parse_pos >= kp_len() { break; }
- c := load8(g_kernel_parse_text, g_kernel_parse_pos);
- if c >= 48 && c <= 57 { g_kernel_parse_pos = g_kernel_parse_pos + 1; }
- else { break; }
- }
- if g_kernel_parse_pos == start { return -1; }
- v : int, mut = 0;
- i : int, mut = start;
- loop {
- if i >= g_kernel_parse_pos { break; }
- v = v * 10 + (load8(g_kernel_parse_text, i) - 48);
- i = i + 1;
- }
- return v;
-}
+fn kp_num() -> int:
+ start := g_kernel_parse_pos
+ loop:
+ if g_kernel_parse_pos >= kp_len():
+ break
+ c := load8(g_kernel_parse_text, g_kernel_parse_pos)
+ if c >= 48 && c <= 57:
+ g_kernel_parse_pos = g_kernel_parse_pos + 1
+ else:
+ break
+ if g_kernel_parse_pos == start:
+ return -1
+ v : int, mut = 0
+ i : int, mut = start
+ loop:
+ if i >= g_kernel_parse_pos:
+ break
+ v = v * 10 + (load8(g_kernel_parse_text, i) - 48)
+ i = i + 1
+ return v
// 期望当前位置是 'c'(消费它);否则返回 0
-fn kp_expect(c: int) -> int {
- if g_kernel_parse_pos < kp_len() && load8(g_kernel_parse_text, g_kernel_parse_pos) == c {
- g_kernel_parse_pos = g_kernel_parse_pos + 1;
- return 1;
- }
- return 0;
-}
+fn kp_expect(c: int) -> int:
+ if g_kernel_parse_pos < kp_len() && load8(g_kernel_parse_text, g_kernel_parse_pos) == c:
+ g_kernel_parse_pos = g_kernel_parse_pos + 1
+ return 1
+ return 0
// 名字匹配并前进:当前位置的记号名 == name 则消费并返回 1
-fn kp_take_name(name: string) -> int {
- if kp_name_is(name) == 0 { return 0; }
- g_kernel_parse_pos = g_kernel_parse_pos + str_len(name);
- return 1;
-}
+fn kp_take_name(name: string) -> int:
+ if kp_name_is(name) == 0:
+ return 0
+ g_kernel_parse_pos = g_kernel_parse_pos + str_len(name)
+ return 1
// ::= (typ N) | (nat) | (zero) | (succ ) | (natrec )
// | (pi ) | (fn ) | (app )
// | (var N) | (sub )
// 注意:if-else 链各分支必须以同类型语句收尾(赋值),统一在链后检查 n < 0。
-fn parse_exp() -> int {
- kp_skip_ws();
- if kp_expect(40) == 0 { return -1; } // '('
- kp_skip_ws();
- n : int, mut = -1;
- if kp_take_name("typ") != 0 {
- kp_skip_ws();
- v := kp_num();
- if v >= 0 { n = kern_new(K_TYP); }
- if n >= 0 { kern_set(n, 1, v); }
- } else if kp_take_name("natrec") != 0 {
- e1 := parse_exp();
- e2 := parse_exp();
- e3 := parse_exp();
- e4 := parse_exp();
- if e1 >= 0 && e2 >= 0 && e3 >= 0 && e4 >= 0 { n = kern_new(K_NATREC); }
- if n >= 0 {
- kern_set(n, 1, e1); kern_set(n, 2, e2); kern_set(n, 3, e3); kern_set(n, 4, e4);
- }
- } else if kp_take_name("nat") != 0 {
- n = kern_new(K_NAT);
- } else if kp_take_name("zero") != 0 {
- n = kern_new(K_ZERO);
- } else if kp_take_name("succ") != 0 {
- e := parse_exp();
- if e >= 0 { n = kern_new(K_SUCC); }
- if n >= 0 { kern_set(n, 1, e); }
- } else if kp_take_name("pi") != 0 {
- e1 := parse_exp();
- e2 := parse_exp();
- if e1 >= 0 && e2 >= 0 { n = kern_new(K_PI); }
- if n >= 0 { kern_set(n, 1, e1); kern_set(n, 2, e2); }
- } else if kp_take_name("fn") != 0 {
- e1 := parse_exp();
- e2 := parse_exp();
- if e1 >= 0 && e2 >= 0 { n = kern_new(K_FN); }
- if n >= 0 { kern_set(n, 1, e1); kern_set(n, 2, e2); }
- } else if kp_take_name("app") != 0 {
- e1 := parse_exp();
- e2 := parse_exp();
- if e1 >= 0 && e2 >= 0 { n = kern_new(K_APP); }
- if n >= 0 { kern_set(n, 1, e1); kern_set(n, 2, e2); }
- } else if kp_take_name("var") != 0 {
- kp_skip_ws();
- v := kp_num();
- if v >= 0 { n = kern_new(K_VAR); }
- if n >= 0 { kern_set(n, 1, v); }
- } else if kp_take_name("sub") != 0 {
- e := parse_exp();
- s := parse_sub();
- if e >= 0 && s >= 0 { n = kern_new(K_SUB); }
- if n >= 0 { kern_set(n, 1, e); kern_set(n, 2, s); }
- } else {
- n = -1;
- }
- if n < 0 { return -1; }
- kp_skip_ws();
- if kp_expect(41) == 0 { return -1; } // ')'
- return n;
-}
+fn parse_exp() -> int:
+ kp_skip_ws()
+ if kp_expect(40) == 0:
+ return -1
+ // '('
+ kp_skip_ws()
+ n : int, mut = -1
+ if kp_take_name("typ") != 0:
+ kp_skip_ws()
+ v := kp_num()
+ if v >= 0:
+ n = kern_new(K_TYP)
+ if n >= 0:
+ kern_set(n, 1, v)
+ else if kp_take_name("natrec") != 0:
+ e1 := parse_exp()
+ e2 := parse_exp()
+ e3 := parse_exp()
+ e4 := parse_exp()
+ if e1 >= 0 && e2 >= 0 && e3 >= 0 && e4 >= 0:
+ n = kern_new(K_NATREC)
+ if n >= 0:
+ kern_set(n, 1, e1)
+ kern_set(n, 2, e2)
+ kern_set(n, 3, e3)
+ kern_set(n, 4, e4)
+ else if kp_take_name("nat") != 0:
+ n = kern_new(K_NAT)
+ else if kp_take_name("zero") != 0:
+ n = kern_new(K_ZERO)
+ else if kp_take_name("succ") != 0:
+ e := parse_exp()
+ if e >= 0:
+ n = kern_new(K_SUCC)
+ if n >= 0:
+ kern_set(n, 1, e)
+ else if kp_take_name("pi") != 0:
+ e1 := parse_exp()
+ e2 := parse_exp()
+ if e1 >= 0 && e2 >= 0:
+ n = kern_new(K_PI)
+ if n >= 0:
+ kern_set(n, 1, e1)
+ kern_set(n, 2, e2)
+ else if kp_take_name("fn") != 0:
+ e1 := parse_exp()
+ e2 := parse_exp()
+ if e1 >= 0 && e2 >= 0:
+ n = kern_new(K_FN)
+ if n >= 0:
+ kern_set(n, 1, e1)
+ kern_set(n, 2, e2)
+ else if kp_take_name("app") != 0:
+ e1 := parse_exp()
+ e2 := parse_exp()
+ if e1 >= 0 && e2 >= 0:
+ n = kern_new(K_APP)
+ if n >= 0:
+ kern_set(n, 1, e1)
+ kern_set(n, 2, e2)
+ else if kp_take_name("var") != 0:
+ kp_skip_ws()
+ v := kp_num()
+ if v >= 0:
+ n = kern_new(K_VAR)
+ if n >= 0:
+ kern_set(n, 1, v)
+ else if kp_take_name("sub") != 0:
+ e := parse_exp()
+ s := parse_sub()
+ if e >= 0 && s >= 0:
+ n = kern_new(K_SUB)
+ if n >= 0:
+ kern_set(n, 1, e)
+ kern_set(n, 2, s)
+ else:
+ n = -1
+ if n < 0:
+ return -1
+ kp_skip_ws()
+ if kp_expect(41) == 0:
+ return -1
+ // ')'
+ return n
// ::= (id) | (weaken) | (compose ) | (extend )
-fn parse_sub() -> int {
- kp_skip_ws();
- if kp_expect(40) == 0 { return -1; }
- kp_skip_ws();
- n : int, mut = -1;
- if kp_take_name("id") != 0 {
- n = kern_new(K_SUB);
- if n >= 0 { kern_set(n, 4, S_ID); }
- } else if kp_take_name("weaken") != 0 {
- n = kern_new(K_SUB);
- if n >= 0 { kern_set(n, 4, S_WEAKEN); }
- } else if kp_take_name("compose") != 0 {
- s1 := parse_sub();
- s2 := parse_sub();
- if s1 >= 0 && s2 >= 0 { n = kern_new(K_SUB); }
- if n >= 0 { kern_set(n, 1, s1); kern_set(n, 2, s2); kern_set(n, 4, S_COMPOSE); }
- } else if kp_take_name("extend") != 0 {
- s := parse_sub();
- e := parse_exp();
- if s >= 0 && e >= 0 { n = kern_new(K_SUB); }
- if n >= 0 { kern_set(n, 1, s); kern_set(n, 2, e); kern_set(n, 4, S_EXTEND); }
- } else {
- n = -1;
- }
- if n < 0 { return -1; }
- kp_skip_ws();
- if kp_expect(41) == 0 { return -1; }
- return n;
-}
+fn parse_sub() -> int:
+ kp_skip_ws()
+ if kp_expect(40) == 0:
+ return -1
+ kp_skip_ws()
+ n : int, mut = -1
+ if kp_take_name("id") != 0:
+ n = kern_new(K_SUB)
+ if n >= 0:
+ kern_set(n, 4, S_ID)
+ else if kp_take_name("weaken") != 0:
+ n = kern_new(K_SUB)
+ if n >= 0:
+ kern_set(n, 4, S_WEAKEN)
+ else if kp_take_name("compose") != 0:
+ s1 := parse_sub()
+ s2 := parse_sub()
+ if s1 >= 0 && s2 >= 0:
+ n = kern_new(K_SUB)
+ if n >= 0:
+ kern_set(n, 1, s1)
+ kern_set(n, 2, s2)
+ kern_set(n, 4, S_COMPOSE)
+ else if kp_take_name("extend") != 0:
+ s := parse_sub()
+ e := parse_exp()
+ if s >= 0 && e >= 0:
+ n = kern_new(K_SUB)
+ if n >= 0:
+ kern_set(n, 1, s)
+ kern_set(n, 2, e)
+ kern_set(n, 4, S_EXTEND)
+ else:
+ n = -1
+ if n < 0:
+ return -1
+ kp_skip_ws()
+ if kp_expect(41) == 0:
+ return -1
+ return n
// ── 公开接口 ──
// kernel_parse(text) -> int:解析单个 的 S-表达式文本,返回根节点索引;
// 失败返回 -1。每次调用重置 arena(g_kernel_count = 0)。
-fn kernel_parse(text: string) -> int {
- g_kernel_count = 0;
- g_kernel_parse_text = text;
- g_kernel_parse_pos = 0;
- idx := parse_exp();
- if idx < 0 { return -1; }
- kp_skip_ws();
- if g_kernel_parse_pos < kp_len() { return -1; } // 尾部多余内容
- return idx;
-}
+fn kernel_parse(text: string) -> int:
+ g_kernel_count = 0
+ g_kernel_parse_text = text
+ g_kernel_parse_pos = 0
+ idx := parse_exp()
+ if idx < 0:
+ return -1
+ kp_skip_ws()
+ if g_kernel_parse_pos < kp_len():
+ return -1
+ // 尾部多余内容
+ return idx
// 按协议打印 sub 节点
-fn print_sub(n: int) -> string {
- sk := kern_get(n, 4);
- if sk == S_ID { return "(id)"; }
- if sk == S_WEAKEN { return "(weaken)"; }
- if sk == S_COMPOSE {
- return "(compose " + print_sub(kern_get(n, 1)) + " " + print_sub(kern_get(n, 2)) + ")";
- }
- if sk == S_EXTEND {
- return "(extend " + print_sub(kern_get(n, 1)) + " " + kern_print_rec(kern_get(n, 2)) + ")";
- }
- return "(?)";
-}
+fn print_sub(n: int) -> string:
+ sk := kern_get(n, 4)
+ if sk == S_ID:
+ return "(id)"
+ if sk == S_WEAKEN:
+ return "(weaken)"
+ if sk == S_COMPOSE:
+ return "(compose " + print_sub(kern_get(n, 1)) + " " + print_sub(kern_get(n, 2)) + ")"
+ if sk == S_EXTEND:
+ return "(extend " + print_sub(kern_get(n, 1)) + " " + kern_print_rec(kern_get(n, 2)) + ")"
+ return "(?)"
// 按协议打印 exp 节点
-fn kern_print_rec(idx: int) -> string {
- k := kern_get(idx, 0);
- if k == K_TYP { return "(typ " + int_str(kern_get(idx, 1)) + ")"; }
- if k == K_NAT { return "(nat)"; }
- if k == K_ZERO { return "(zero)"; }
- if k == K_SUCC { return "(succ " + kern_print_rec(kern_get(idx, 1)) + ")"; }
- if k == K_NATREC {
- return "(natrec " + kern_print_rec(kern_get(idx, 1)) + " "
- + kern_print_rec(kern_get(idx, 2)) + " "
- + kern_print_rec(kern_get(idx, 3)) + " "
- + kern_print_rec(kern_get(idx, 4)) + ")";
- }
- if k == K_PI { return "(pi " + kern_print_rec(kern_get(idx, 1)) + " " + kern_print_rec(kern_get(idx, 2)) + ")"; }
- if k == K_FN { return "(fn " + kern_print_rec(kern_get(idx, 1)) + " " + kern_print_rec(kern_get(idx, 2)) + ")"; }
- if k == K_APP { return "(app " + kern_print_rec(kern_get(idx, 1)) + " " + kern_print_rec(kern_get(idx, 2)) + ")"; }
- if k == K_VAR { return "(var " + int_str(kern_get(idx, 1)) + ")"; }
- if k == K_SUB { return "(sub " + kern_print_rec(kern_get(idx, 1)) + " " + print_sub(kern_get(idx, 2)) + ")"; }
- return "(?)";
-}
+fn kern_print_rec(idx: int) -> string:
+ k := kern_get(idx, 0)
+ if k == K_TYP:
+ return "(typ " + int_str(kern_get(idx, 1)) + ")"
+ if k == K_NAT:
+ return "(nat)"
+ if k == K_ZERO:
+ return "(zero)"
+ if k == K_SUCC:
+ return "(succ " + kern_print_rec(kern_get(idx, 1)) + ")"
+ if k == K_NATREC:
+ return "(natrec " + kern_print_rec(kern_get(idx, 1)) + " " + kern_print_rec(kern_get(idx, 2)) + " " + kern_print_rec(kern_get(idx, 3)) + " " + kern_print_rec(kern_get(idx, 4)) + ")"
+ if k == K_PI:
+ return "(pi " + kern_print_rec(kern_get(idx, 1)) + " " + kern_print_rec(kern_get(idx, 2)) + ")"
+ if k == K_FN:
+ return "(fn " + kern_print_rec(kern_get(idx, 1)) + " " + kern_print_rec(kern_get(idx, 2)) + ")"
+ if k == K_APP:
+ return "(app " + kern_print_rec(kern_get(idx, 1)) + " " + kern_print_rec(kern_get(idx, 2)) + ")"
+ if k == K_VAR:
+ return "(var " + int_str(kern_get(idx, 1)) + ")"
+ if k == K_SUB:
+ return "(sub " + kern_print_rec(kern_get(idx, 1)) + " " + print_sub(kern_get(idx, 2)) + ")"
+ return "(?)"
// kernel_print(idx) -> string:节点 → 协议 S-表达式文本
-fn kernel_print(idx: int) -> string {
- return kern_print_rec(idx);
-}
+fn kernel_print(idx: int) -> string:
+ return kern_print_rec(idx)
diff --git a/src/kernel/test_term_io.cr b/src/kernel/test_term_io.cr
index 73932d86..a366b51b 100644
--- a/src/kernel/test_term_io.cr
+++ b/src/kernel/test_term_io.cr
@@ -10,201 +10,235 @@
import io
import term_io
-g_fail_count : int, mut = 0;
+g_fail_count : int, mut = 0
-fn check_roundtrip(s: string) -> int {
- idx := kernel_parse(s);
- if idx < 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL parse(-1): " + s);
- return 1;
- }
- out := kernel_print(idx);
- if str_eq(out, s) == 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL roundtrip: [" + s + "] -> [" + out + "]");
- return 1;
- }
- return 0;
-}
+fn check_roundtrip(s: string) -> int:
+ idx := kernel_parse(s)
+ if idx < 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL parse(-1): " + s)
+ return 1
+ out := kernel_print(idx)
+ if str_eq(out, s) == 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL roundtrip: [" + s + "] -> [" + out + "]")
+ return 1
+ return 0
// 空白容忍:输入可含任意空白,打印结果须等于规范紧凑形式
-fn check_roundtrip_compact(s: string, canonical: string) -> int {
- idx := kernel_parse(s);
- if idx < 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL parse(-1): " + s);
- return 1;
- }
- out := kernel_print(idx);
- if str_eq(out, canonical) == 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL compact: [" + s + "] -> [" + out + "]");
- return 1;
- }
- return 0;
-}
+fn check_roundtrip_compact(s: string, canonical: string) -> int:
+ idx := kernel_parse(s)
+ if idx < 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL parse(-1): " + s)
+ return 1
+ out := kernel_print(idx)
+ if str_eq(out, canonical) == 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL compact: [" + s + "] -> [" + out + "]")
+ return 1
+ return 0
-fn check_parse_fail(s: string) -> int {
- idx := kernel_parse(s);
- if idx >= 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL expect -1: " + s);
- return 1;
- }
- return 0;
-}
+fn check_parse_fail(s: string) -> int:
+ idx := kernel_parse(s)
+ if idx >= 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL expect -1: " + s)
+ return 1
+ return 0
// 给定一行查询文本与 '(' 起始位置,返回匹配 ')' 之后的位置(深度计数)
-fn exp_end_at(text: string, start: int) -> int {
- depth : int, mut = 0;
- i : int, mut = start;
- len := str_len(text);
- loop {
- if i >= len { break; }
- c := load8(text, i);
- if c == 40 { depth = depth + 1; }
- else if c == 41 {
- depth = depth - 1;
- if depth == 0 { return i + 1; }
- }
- i = i + 1;
- }
- return -1;
-}
+fn exp_end_at(text: string, start: int) -> int:
+ depth : int, mut = 0
+ i : int, mut = start
+ len := str_len(text)
+ loop:
+ if i >= len:
+ break
+ c := load8(text, i)
+ if c == 40:
+ depth = depth + 1
+ else if c == 41:
+ depth = depth - 1
+ if depth == 0:
+ return i + 1
+ i = i + 1
+ return -1
// 解析一行查询中的全部 (跳过 与 ),逐个 kernel_parse
-fn check_line_exps(line: string) -> int {
+fn check_line_exps(line: string) -> int:
// 跳过 # 注释行
- l0 : int, mut = 0;
- ln := str_len(line);
- loop { if l0 >= ln { break; } if load8(line, l0) != 32 { break; } l0 = l0 + 1; }
- if l0 < ln && load8(line, l0) == 35 { return 0; } // '#'
+ l0 : int, mut = 0
+ ln := str_len(line)
+ loop:
+ if l0 >= ln:
+ break
+ if load8(line, l0) != 32:
+ break
+ l0 = l0 + 1
+ if l0 < ln && load8(line, l0) == 35:
+ return 0
+ // '#'
// 找 ctx 起点(第一个 '(')与其结束位置
- p : int, mut = 0;
- ctx_start : int, mut = -1;
- loop {
- if p >= ln { break; }
- if load8(line, p) == 40 { ctx_start = p; break; }
- p = p + 1;
- }
- if ctx_start < 0 { return 0; } // 无 exp,跳过
- rest := exp_end_at(line, ctx_start);
- if rest < 0 { return 0; }
+ p : int, mut = 0
+ ctx_start : int, mut = -1
+ loop:
+ if p >= ln:
+ break
+ if load8(line, p) == 40:
+ ctx_start = p
+ break
+ p = p + 1
+ if ctx_start < 0:
+ return 0
+ // 无 exp,跳过
+ rest := exp_end_at(line, ctx_start)
+ if rest < 0:
+ return 0
// 逐个解析剩余 exp
- loop {
- if rest >= ln { break; }
+ loop:
+ if rest >= ln:
+ break
// 跳过空白
- loop {
- if rest >= ln { break; }
- c := load8(line, rest);
- if c == 32 || c == 9 || c == 10 || c == 13 { rest = rest + 1; }
- else { break; }
- }
- if rest >= ln { break; }
- if load8(line, rest) != 40 { break; }
- e_end := exp_end_at(line, rest);
- if e_end < 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL unclosed exp in line: " + line);
- return 1;
- }
- exp_text := str_sub(line, rest, e_end - rest);
- idx := kernel_parse(exp_text);
- if idx < 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL corpus exp: " + exp_text);
- return 1;
- }
- out := kernel_print(idx);
- if str_eq(out, exp_text) == 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL corpus roundtrip: [" + exp_text + "] -> [" + out + "]");
- return 1;
- }
- rest = e_end;
- }
- return 0;
-}
+ loop:
+ if rest >= ln:
+ break
+ c := load8(line, rest)
+ if c == 32 || c == 9 || c == 10 || c == 13:
+ rest = rest + 1
+ else:
+ break
+ if rest >= ln:
+ break
+ if load8(line, rest) != 40:
+ break
+ e_end := exp_end_at(line, rest)
+ if e_end < 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL unclosed exp in line: " + line)
+ return 1
+ exp_text := str_sub(line, rest, e_end - rest)
+ idx := kernel_parse(exp_text)
+ if idx < 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL corpus exp: " + exp_text)
+ return 1
+ out := kernel_print(idx)
+ if str_eq(out, exp_text) == 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL corpus roundtrip: [" + exp_text + "] -> [" + out + "]")
+ return 1
+ rest = e_end
+ return 0
-fn main() -> int {
+fn main() -> int:
// ── Step 3:三个固定字符串往返 ──
// 注:brief 原例 2 的 λ 为 3 元 `(fn (nat) (nat) M)`,与协议 `(fn A M)`(2 元)不符
// (tests/kernel/README.md 已披露此 brief 错误并修正案卷);此处按协议用 2 元,
// 3 元形式列入负例(应解析失败)。
- if check_roundtrip("(succ (succ (zero)))") != 0 { println(" ^ case 1"); }
- if check_roundtrip("(natrec (nat) (zero) (fn (nat) (succ (var 0))) (succ (zero)))") != 0 { println(" ^ case 2"); }
- if check_roundtrip("(sub (var 0) (compose (weaken) (id)))") != 0 { println(" ^ case 3"); }
- if check_parse_fail("(natrec (nat) (zero) (fn (nat) (nat) (succ (var 0))) (succ (zero)))") != 0 { println(" ^ brief 3-ary fn (protocol violation)"); }
+ if check_roundtrip("(succ (succ (zero)))") != 0:
+ println(" ^ case 1")
+ if check_roundtrip("(natrec (nat) (zero) (fn (nat) (succ (var 0))) (succ (zero)))") != 0:
+ println(" ^ case 2")
+ if check_roundtrip("(sub (var 0) (compose (weaken) (id)))") != 0:
+ println(" ^ case 3")
+ if check_parse_fail("(natrec (nat) (zero) (fn (nat) (nat) (succ (var 0))) (succ (zero)))") != 0:
+ println(" ^ brief 3-ary fn (protocol violation)")
// ── 协议全 kind 覆盖 ──
- if check_roundtrip("(typ 0)") != 0 { println(" ^ typ"); }
- if check_roundtrip("(typ 7)") != 0 { println(" ^ typ7"); }
- if check_roundtrip("(nat)") != 0 { println(" ^ nat"); }
- if check_roundtrip("(zero)") != 0 { println(" ^ zero"); }
- if check_roundtrip("(succ (zero))") != 0 { println(" ^ succ"); }
- if check_roundtrip("(natrec (nat) (zero) (fn (nat) (succ (var 0))) (succ (zero)))") != 0 { println(" ^ natrec"); }
- if check_roundtrip("(pi (nat) (nat))") != 0 { println(" ^ pi"); }
- if check_roundtrip("(fn (nat) (var 0))") != 0 { println(" ^ fn"); }
- if check_roundtrip("(app (fn (nat) (var 0)) (zero))") != 0 { println(" ^ app"); }
- if check_roundtrip("(var 0)") != 0 { println(" ^ var"); }
- if check_roundtrip("(var 12)") != 0 { println(" ^ var12"); }
- if check_roundtrip("(sub (var 0) (id))") != 0 { println(" ^ sub-id"); }
- if check_roundtrip("(sub (var 0) (weaken))") != 0 { println(" ^ sub-weaken"); }
- if check_roundtrip("(sub (var 0) (compose (weaken) (id)))") != 0 { println(" ^ sub-compose"); }
- if check_roundtrip("(sub (succ (var 0)) (extend (id) (zero)))") != 0 { println(" ^ sub-extend"); }
- if check_roundtrip("(sub (sub (var 0) (weaken)) (compose (extend (id) (zero)) (weaken)))") != 0 { println(" ^ nested sub"); }
- if check_roundtrip("(app (var 3) (var 0))") != 0 { println(" ^ app var"); }
- if check_roundtrip("(pi (typ 1) (var 0))") != 0 { println(" ^ pi typ"); }
+ if check_roundtrip("(typ 0)") != 0:
+ println(" ^ typ")
+ if check_roundtrip("(typ 7)") != 0:
+ println(" ^ typ7")
+ if check_roundtrip("(nat)") != 0:
+ println(" ^ nat")
+ if check_roundtrip("(zero)") != 0:
+ println(" ^ zero")
+ if check_roundtrip("(succ (zero))") != 0:
+ println(" ^ succ")
+ if check_roundtrip("(natrec (nat) (zero) (fn (nat) (succ (var 0))) (succ (zero)))") != 0:
+ println(" ^ natrec")
+ if check_roundtrip("(pi (nat) (nat))") != 0:
+ println(" ^ pi")
+ if check_roundtrip("(fn (nat) (var 0))") != 0:
+ println(" ^ fn")
+ if check_roundtrip("(app (fn (nat) (var 0)) (zero))") != 0:
+ println(" ^ app")
+ if check_roundtrip("(var 0)") != 0:
+ println(" ^ var")
+ if check_roundtrip("(var 12)") != 0:
+ println(" ^ var12")
+ if check_roundtrip("(sub (var 0) (id))") != 0:
+ println(" ^ sub-id")
+ if check_roundtrip("(sub (var 0) (weaken))") != 0:
+ println(" ^ sub-weaken")
+ if check_roundtrip("(sub (var 0) (compose (weaken) (id)))") != 0:
+ println(" ^ sub-compose")
+ if check_roundtrip("(sub (succ (var 0)) (extend (id) (zero)))") != 0:
+ println(" ^ sub-extend")
+ if check_roundtrip("(sub (sub (var 0) (weaken)) (compose (extend (id) (zero)) (weaken)))") != 0:
+ println(" ^ nested sub")
+ if check_roundtrip("(app (var 3) (var 0))") != 0:
+ println(" ^ app var")
+ if check_roundtrip("(pi (typ 1) (var 0))") != 0:
+ println(" ^ pi typ")
// ── 空白容忍(打印器输出规范紧凑形式)──
- if check_roundtrip_compact(" (nat) ", "(nat)") != 0 { println(" ^ leading/trailing ws"); }
- if check_roundtrip_compact("( succ ( zero ) )", "(succ (zero))") != 0 { println(" ^ inner ws"); }
- if check_roundtrip_compact("(var 7)", "(var 7)") != 0 { println(" ^ ws before num"); }
+ if check_roundtrip_compact(" (nat) ", "(nat)") != 0:
+ println(" ^ leading/trailing ws")
+ if check_roundtrip_compact("( succ ( zero ) )", "(succ (zero))") != 0:
+ println(" ^ inner ws")
+ if check_roundtrip_compact("(var 7)", "(var 7)") != 0:
+ println(" ^ ws before num")
// ── 非法输入 ──
- if check_parse_fail("") != 0 { println(" ^ empty"); }
- if check_parse_fail("(bogus)") != 0 { println(" ^ bogus"); }
- if check_parse_fail("(succ)") != 0 { println(" ^ succ no child"); }
- if check_parse_fail("(succ (zero)") != 0 { println(" ^ unclosed"); }
- if check_parse_fail("(nat) extra") != 0 { println(" ^ trailing"); }
- if check_parse_fail("(var x)") != 0 { println(" ^ var nonnum"); }
+ if check_parse_fail("") != 0:
+ println(" ^ empty")
+ if check_parse_fail("(bogus)") != 0:
+ println(" ^ bogus")
+ if check_parse_fail("(succ)") != 0:
+ println(" ^ succ no child")
+ if check_parse_fail("(succ (zero)") != 0:
+ println(" ^ unclosed")
+ if check_parse_fail("(nat) extra") != 0:
+ println(" ^ trailing")
+ if check_parse_fail("(var x)") != 0:
+ println(" ^ var nonnum")
// ── Step 4:案卷前 3 行 + 第 16 条 infer(1 基)──
- data := read_file("tests/kernel/cases/corpus_manual.txt");
- if str_len(data) == 0 {
- g_fail_count = g_fail_count + 1;
- println("FAIL cannot read corpus_manual.txt (run from repo root)");
- } else {
+ data := read_file("tests/kernel/cases/corpus_manual.txt")
+ if str_len(data) == 0:
+ g_fail_count = g_fail_count + 1
+ println("FAIL cannot read corpus_manual.txt (run from repo root)")
+ else:
// 按行处理(前 3 行 + 第 16 行为验收点,其余顺带全查)
- line_no : int, mut = 0;
- pos : int, mut = 0;
- dlen := str_len(data);
- loop {
- if pos >= dlen { break; }
- if line_no >= 25 { break; }
+ line_no : int, mut = 0
+ pos : int, mut = 0
+ dlen := str_len(data)
+ loop:
+ if pos >= dlen:
+ break
+ if line_no >= 25:
+ break
// 取一行
- eol : int, mut = pos;
- loop {
- if eol >= dlen { break; }
- if load8(data, eol) == 10 { break; }
- eol = eol + 1;
- }
- line := str_sub(data, pos, eol - pos);
- if line_no < 3 || line_no == 15 {
- println("line " + int_str(line_no + 1) + ": " + line);
- }
- if check_line_exps(line) != 0 { println(" ^ corpus line " + int_str(line_no + 1)); }
- line_no = line_no + 1;
- pos = eol + 1;
- }
- println("corpus lines checked: " + int_str(line_no));
- }
+ eol : int, mut = pos
+ loop:
+ if eol >= dlen:
+ break
+ if load8(data, eol) == 10:
+ break
+ eol = eol + 1
+ line := str_sub(data, pos, eol - pos)
+ if line_no < 3 || line_no == 15:
+ println("line " + int_str(line_no + 1) + ": " + line)
+ if check_line_exps(line) != 0:
+ println(" ^ corpus line " + int_str(line_no + 1))
+ line_no = line_no + 1
+ pos = eol + 1
+ println("corpus lines checked: " + int_str(line_no))
- if g_fail_count == 0 {
- println("ALL PASS");
- return 0;
- }
- println("FAILURES: " + int_str(g_fail_count));
- return 1;
-}
+ if g_fail_count == 0:
+ println("ALL PASS")
+ return 0
+ println("FAILURES: " + int_str(g_fail_count))
+ return 1
diff --git a/src/lattice/ent_kernel.cr b/src/lattice/ent_kernel.cr
index d3d95cf2..dc61f8c0 100644
--- a/src/lattice/ent_kernel.cr
+++ b/src/lattice/ent_kernel.cr
@@ -61,107 +61,118 @@
// 不乘固定稠密系数(live_range_slot 即该前缀累计;16B 记录 + grow 风格同
// g_ir_slice_lens)。
-fn grow_live_ranges(needed: int) {
- if needed < g_live_range_cap { return; }
- nc := g_live_range_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; }
- nb := alloc(nc * 16); _dyncpy(g_ir_live_ranges, g_live_range_cap * 16, nb);
- g_ir_live_ranges = nb; g_live_range_cap = nc;
-}
+fn grow_live_ranges(needed: int):
+ if needed < g_live_range_cap:
+ return
+ nc := g_live_range_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ nb := alloc(nc * 16)
+ _dyncpy(g_ir_live_ranges, g_live_range_cap * 16, nb)
+ g_ir_live_ranges = nb
+ g_live_range_cap = nc
-fn live_range_slot(func_i: int, var_i: int) -> int {
+fn live_range_slot(func_i: int, var_i: int) -> int:
// 函数内 var 索引 = var_i − var_start[func_i];func_i 段起始 = 前缀 var_count 累计
- off : ., mut = 0;
- fi : ., mut = 0;
- loop { if fi >= func_i { break; }
- off = off + r64(g_ir_func_var_count, fi * 8);
- fi = fi + 1; }
- return (off + (var_i - r64(g_ir_func_var_start, func_i * 8))) * 16;
-}
+ off : ., mut = 0
+ fi : ., mut = 0
+ loop:
+ if fi >= func_i:
+ break
+ off = off + r64(g_ir_func_var_count, fi * 8)
+ fi = fi + 1
+ return (off + (var_i - r64(g_ir_func_var_start, func_i * 8))) * 16
-fn live_first(func_i: int, var_i: int) -> int {
- if func_i < 0 || var_i < 0 { return -1; }
- return r64(g_ir_live_ranges, live_range_slot(func_i, var_i));
-}
+fn live_first(func_i: int, var_i: int) -> int:
+ if func_i < 0 || var_i < 0:
+ return -1
+ return r64(g_ir_live_ranges, live_range_slot(func_i, var_i))
-fn live_last(func_i: int, var_i: int) -> int {
- if func_i < 0 || var_i < 0 { return -1; }
- return r64(g_ir_live_ranges, live_range_slot(func_i, var_i) + 8);
-}
+fn live_last(func_i: int, var_i: int) -> int:
+ if func_i < 0 || var_i < 0:
+ return -1
+ return r64(g_ir_live_ranges, live_range_slot(func_i, var_i) + 8)
// 存在区间推导:填充 g_ir_live_ranges。语义 = 原 alloc_registers 内联 iv_buf
// 构建(:210-241):逐函数逐节点扫描(节点字段读 = 对象面 nod_*——A 通道
// 中立化 2026-09-10,同 index 数值与线性流时代 iri_* 逐字节同),dest/s1/s2
// 落在 [vs, vs+vc) 内则扩展 [first_ref,last_ref](首见写 first,之后推进
// last);未使用 var 两条均为 -1。
-fn compute_live_ranges() {
- total : ., mut = 0;
- fi : ., mut = 0;
- loop { if fi >= g_ir_func_count { break; }
- total = total + r64(g_ir_func_var_count, fi * 8);
- fi = fi + 1; }
- grow_live_ranges(total);
- g_live_range_count = total;
+fn compute_live_ranges():
+ total : ., mut = 0
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ total = total + r64(g_ir_func_var_count, fi * 8)
+ fi = fi + 1
+ grow_live_ranges(total)
+ g_live_range_count = total
// 首遍写 -1(区间未知 = -1,同 alloc_registers 的 iv_buf 初始化语义)
- zi : ., mut = 0;
- loop { if zi >= total { break; }
- w64(g_ir_live_ranges, zi * 16, -1);
- w64(g_ir_live_ranges, zi * 16 + 8, -1);
- zi = zi + 1; }
+ zi : ., mut = 0
+ loop:
+ if zi >= total:
+ break
+ w64(g_ir_live_ranges, zi * 16, -1)
+ w64(g_ir_live_ranges, zi * 16 + 8, -1)
+ zi = zi + 1
// 逐函数逐节点扫描:段偏移 = 运行中前缀累计(与 live_range_slot 前缀一致)。
// 函数窗口源 = g_ir_func_instr_start/count——值 = NOD 节点坐标(v7 节点序
// = 指令序 index-aligned,窗口 = 函数节点范围 [start, start+count);
// loader 侧 REG root span 派生、构建侧区域快照,双进程同值——F3 注记,
// A 通道中立化 2026-09-10)。节点字段读全走对象面 nod_*(同 index——
// 数值与线性流时代 iri_* 逐字节同,见语义对象节)。
- seg : ., mut = 0;
- fi = 0;
- loop {
- if fi >= g_ir_func_count { break; }
- ic := r64(g_ir_func_instr_count, fi * 8);
- ist := r64(g_ir_func_instr_start, fi * 8);
- vc := r64(g_ir_func_var_count, fi * 8);
- vs := r64(g_ir_func_var_start, fi * 8);
- if vc > 0 {
- ii : ., mut = 0;
- loop {
- if ii >= ic { break; }
- inst := ist + ii;
- d := nod_dest(inst); s1 := nod_s1(inst); s2 := nod_s2(inst);
- if d >= vs && d < vs + vc {
- lv := d - vs;
- st := (seg + lv) * 16;
- if r64(g_ir_live_ranges, st) < 0 { w64(g_ir_live_ranges, st, ii); }
- w64(g_ir_live_ranges, st + 8, ii);
- }
- if s1 >= vs && s1 < vs + vc {
- lv := s1 - vs;
- st := (seg + lv) * 16;
- if r64(g_ir_live_ranges, st) < 0 { w64(g_ir_live_ranges, st, ii); }
- w64(g_ir_live_ranges, st + 8, ii);
- }
- if s2 >= vs && s2 < vs + vc {
- lv := s2 - vs;
- st := (seg + lv) * 16;
- if r64(g_ir_live_ranges, st) < 0 { w64(g_ir_live_ranges, st, ii); }
- w64(g_ir_live_ranges, st + 8, ii);
- }
- ii = ii + 1;
- }
- }
- seg = seg + vc;
- fi = fi + 1;
- }
+ seg : ., mut = 0
+ fi = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ ic := r64(g_ir_func_instr_count, fi * 8)
+ ist := r64(g_ir_func_instr_start, fi * 8)
+ vc := r64(g_ir_func_var_count, fi * 8)
+ vs := r64(g_ir_func_var_start, fi * 8)
+ if vc > 0:
+ ii : ., mut = 0
+ loop:
+ if ii >= ic:
+ break
+ inst := ist + ii
+ d := nod_dest(inst)
+ s1 := nod_s1(inst)
+ s2 := nod_s2(inst)
+ if d >= vs && d < vs + vc:
+ lv := d - vs
+ st := (seg + lv) * 16
+ if r64(g_ir_live_ranges, st) < 0:
+ w64(g_ir_live_ranges, st, ii)
+ w64(g_ir_live_ranges, st + 8, ii)
+ if s1 >= vs && s1 < vs + vc:
+ lv := s1 - vs
+ st := (seg + lv) * 16
+ if r64(g_ir_live_ranges, st) < 0:
+ w64(g_ir_live_ranges, st, ii)
+ w64(g_ir_live_ranges, st + 8, ii)
+ if s2 >= vs && s2 < vs + vc:
+ lv := s2 - vs
+ st := (seg + lv) * 16
+ if r64(g_ir_live_ranges, st) < 0:
+ w64(g_ir_live_ranges, st, ii)
+ w64(g_ir_live_ranges, st + 8, ii)
+ ii = ii + 1
+ seg = seg + vc
+ fi = fi + 1
// v6 Task 2:条目版本化——对全部函数切分版本条目(逐函数升序,
// compute_entries 的 func_i==0 分支负责整表重建;本函数幂等可重跑)。
// 与 opt 门控解耦:compute_live_ranges 自身在 cir --dump-entries 与
// alloc_registers(O2)两处被调,条目表随算随新。
- ef : ., mut = 0;
- loop {
- if ef >= g_ir_func_count { break; }
- compute_entries(ef);
- ef = ef + 1;
- }
-}
+ ef : ., mut = 0
+ loop:
+ if ef >= g_ir_func_count:
+ break
+ compute_entries(ef)
+ ef = ef + 1
// ------------------------------------------------------------------
// v6 条目版本化:变量 × 定值点切分版本条目
@@ -189,21 +200,35 @@ fn compute_live_ranges() {
// 调用前置:compute_live_ranges() 已先行(截断用 last_ref),func_i 升序调用
// (func_i==0 重置全局计数——整表重建,重复调用幂等)。
-fn grow_entries(needed: int) {
- if needed < g_entry_cap { return; }
- nc : ., mut = g_entry_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; }
- nb := alloc(nc * ESZ_ENTRY); _dyncpy(g_ir_entries, g_entry_cap * ESZ_ENTRY, nb);
- g_ir_entries = nb; g_entry_cap = nc;
-}
+fn grow_entries(needed: int):
+ if needed < g_entry_cap:
+ return
+ nc : ., mut = g_entry_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ nb := alloc(nc * ESZ_ENTRY)
+ _dyncpy(g_ir_entries, g_entry_cap * ESZ_ENTRY, nb)
+ g_ir_entries = nb
+ g_entry_cap = nc
-fn grow_func_entry_meta(needed: int) {
- if needed < g_ir_func_entry_cap { return; }
- nc : ., mut = g_ir_func_entry_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; }
- sz := nc * 8;
- n1 := alloc(sz); _dyncpy(g_ir_func_entry_start, g_ir_func_entry_cap * 8, n1); g_ir_func_entry_start = n1;
- n2 := alloc(sz); _dyncpy(g_ir_func_entry_count, g_ir_func_entry_cap * 8, n2); g_ir_func_entry_count = n2;
- g_ir_func_entry_cap = nc;
-}
+fn grow_func_entry_meta(needed: int):
+ if needed < g_ir_func_entry_cap:
+ return
+ nc : ., mut = g_ir_func_entry_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ sz := nc * 8
+ n1 := alloc(sz)
+ _dyncpy(g_ir_func_entry_start, g_ir_func_entry_cap * 8, n1)
+ g_ir_func_entry_start = n1
+ n2 := alloc(sz)
+ _dyncpy(g_ir_func_entry_count, g_ir_func_entry_cap * 8, n2)
+ g_ir_func_entry_count = n2
+ g_ir_func_entry_cap = nc
// 条目表字段访问器(24B/条、4B 字段 LE;字段布局注释见 globals.cr)。
// 读统一走 buf_read_i32(ccr_io.cr,真实函数体带符号扩展)——不能调 r32:
@@ -211,213 +236,260 @@ fn grow_func_entry_meta(needed: int) {
// (零扩展 32 位读),bootstrap 产物里负值(-1 home/def)会读成 4294967295
// (x86_64_stack_asm.py:242;r32 源码里的符号修正逻辑只在自举产物中生效)。
// 写侧 w32 内联为 `mov [rdi+rsi],edx`(低 32 位存储)——补码语义正确,可用。
-fn ent_off(e: int) -> int { return e * ESZ_ENTRY; }
-fn ent_var(e: int) -> int { return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_VAR); }
-fn ent_def(e: int) -> int { return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_DEF); }
-fn ent_live_start(e: int) -> int { return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_LS); }
-fn ent_live_end(e: int) -> int { return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_LE); }
-fn ent_home(e: int) -> int { return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_HOME); }
-fn ent_flags(e: int) -> int { return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_FLAGS); }
+fn ent_off(e: int) -> int:
+ return e * ESZ_ENTRY
+fn ent_var(e: int) -> int:
+ return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_VAR)
+fn ent_def(e: int) -> int:
+ return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_DEF)
+fn ent_live_start(e: int) -> int:
+ return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_LS)
+fn ent_live_end(e: int) -> int:
+ return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_LE)
+fn ent_home(e: int) -> int:
+ return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_HOME)
+fn ent_flags(e: int) -> int:
+ return buf_read_i32(g_ir_entries, ent_off(e) + OFF_ENTRY_FLAGS)
// 函数条目段界(全局条目下标;compute_entries 已跑过才有效)
-fn entry_start(func_i: int) -> int {
- if func_i < 0 || func_i >= g_ir_func_count { return 0; }
- return r64(g_ir_func_entry_start, func_i * 8);
-}
+fn entry_start(func_i: int) -> int:
+ if func_i < 0 || func_i >= g_ir_func_count:
+ return 0
+ return r64(g_ir_func_entry_start, func_i * 8)
-fn entry_count(func_i: int) -> int {
- if func_i < 0 || func_i >= g_ir_func_count { return 0; }
- return r64(g_ir_func_entry_count, func_i * 8);
-}
+fn entry_count(func_i: int) -> int:
+ if func_i < 0 || func_i >= g_ir_func_count:
+ return 0
+ return r64(g_ir_func_entry_count, func_i * 8)
-fn compute_entries(func_i: int) -> int {
- if func_i == 0 {
- g_entry_count = 0;
+fn compute_entries(func_i: int) -> int:
+ if func_i == 0:
+ g_entry_count = 0
// 条目表整代重建——旧登记全失效(B 通道中立化 2026-09-10:登记 =
// 本代条目语义——新代条目复用旧槽位,不清 = 陈旧 loc 误读;实例登记
// 只发生在本代 compute 完成之后 = phase 5/注入,时序安全)
- loc_registry_reset();
- }
+ loc_registry_reset()
// 函数窗口源同 compute_live_ranges(F3 注记,2026-09-10):ist/ic =
// g_ir_func_instr_start/count——值 = NOD 节点坐标(节点序 = 指令序
// index-aligned);节点字段读 = 对象面 nod_*(A 通道中立化)。
- ic := r64(g_ir_func_instr_count, func_i * 8);
- ist := r64(g_ir_func_instr_start, func_i * 8);
- vc := r64(g_ir_func_var_count, func_i * 8);
- vs := r64(g_ir_func_var_start, func_i * 8);
- cnt : ., mut = 0;
- if ic > 0 && vc > 0 {
+ ic := r64(g_ir_func_instr_count, func_i * 8)
+ ist := r64(g_ir_func_instr_start, func_i * 8)
+ vc := r64(g_ir_func_var_count, func_i * 8)
+ vs := r64(g_ir_func_var_start, func_i * 8)
+ cnt : ., mut = 0
+ if ic > 0 && vc > 0:
// 每「函数内 var」一条最近打开条目(-1 = 未打开):定值序列切割 O(1) 收口
- prev : string, mut = alloc(vc * 8);
- pz : ., mut = 0;
- loop {
- if pz >= vc { break; }
- w64(prev, pz * 8, -1);
- pz = pz + 1;
- }
+ prev : string, mut = alloc(vc * 8)
+ pz : ., mut = 0
+ loop:
+ if pz >= vc:
+ break
+ w64(prev, pz * 8, -1)
+ pz = pz + 1
// 单遍扫描:定值点 = IR_STORE 的目标槽(s1=var)∪ 其余指令 dest≥0
// 命中函数段(格式定稿 §4.1——GC 批 2 扩权,见本区头:ALLOC_ARRAY/
// ALLOC_STRUCT 等内存对象诞生 + 全部 producer 直写并入版本切分;
// STORE_INDEX_VAR/STORE_PTR/DYN_DISPATCH 的 dest 非定值,不判)
- ii : ., mut = 0;
- loop {
- if ii >= ic { break; }
- inst := ist + ii;
- op := nod_op(inst);
- dv : ., mut = -1;
- if op == IR_STORE {
- s1 := nod_s1(inst);
- if s1 >= vs && s1 < vs + vc { dv = s1; }
- } else if op != IR_STORE_INDEX_VAR && op != IR_STORE_PTR && op != IR_DYN_DISPATCH {
- d := nod_dest(inst);
- if d >= vs && d < vs + vc { dv = d; }
- }
- if dv >= 0 {
- lv := dv - vs;
- last_global : ., mut = -1;
- ll := live_last(func_i, dv);
- if ll >= 0 { last_global = ist + ll; }
+ ii : ., mut = 0
+ loop:
+ if ii >= ic:
+ break
+ inst := ist + ii
+ op := nod_op(inst)
+ dv : ., mut = -1
+ if op == IR_STORE:
+ s1 := nod_s1(inst)
+ if s1 >= vs && s1 < vs + vc:
+ dv = s1
+ else if op != IR_STORE_INDEX_VAR && op != IR_STORE_PTR && op != IR_DYN_DISPATCH:
+ d := nod_dest(inst)
+ if d >= vs && d < vs + vc:
+ dv = d
+ if dv >= 0:
+ lv := dv - vs
+ last_global : ., mut = -1
+ ll := live_last(func_i, dv)
+ if ll >= 0:
+ last_global = ist + ll
// 收口上一版本:end = min(def−1, last_ref)(last_ref ≥ 次定值,恒取 def−1)
- pe := r64(prev, lv * 8);
- if pe >= 0 {
- pend : ., mut = inst - 1;
- if last_global >= 0 && last_global < pend { pend = last_global; }
- w32(g_ir_entries, pe * ESZ_ENTRY + OFF_ENTRY_LE, pend);
- }
+ pe := r64(prev, lv * 8)
+ if pe >= 0:
+ pend : ., mut = inst - 1
+ if last_global >= 0 && last_global < pend:
+ pend = last_global
+ w32(g_ir_entries, pe * ESZ_ENTRY + OFF_ENTRY_LE, pend)
// 开新版本:区间端点暂定 = 定值点..last_ref,末版直接成立
- grow_entries(g_entry_count + 1);
- eo := g_entry_count * ESZ_ENTRY;
- w32(g_ir_entries, eo + OFF_ENTRY_VAR, dv);
- w32(g_ir_entries, eo + OFF_ENTRY_DEF, inst);
- w32(g_ir_entries, eo + OFF_ENTRY_LS, inst);
- w32(g_ir_entries, eo + OFF_ENTRY_LE, last_global);
- w32(g_ir_entries, eo + OFF_ENTRY_HOME, -1);
- w32(g_ir_entries, eo + OFF_ENTRY_FLAGS, 0);
- w64(prev, lv * 8, g_entry_count);
- g_entry_count = g_entry_count + 1;
- cnt = cnt + 1;
- }
- ii = ii + 1;
- }
+ grow_entries(g_entry_count + 1)
+ eo := g_entry_count * ESZ_ENTRY
+ w32(g_ir_entries, eo + OFF_ENTRY_VAR, dv)
+ w32(g_ir_entries, eo + OFF_ENTRY_DEF, inst)
+ w32(g_ir_entries, eo + OFF_ENTRY_LS, inst)
+ w32(g_ir_entries, eo + OFF_ENTRY_LE, last_global)
+ w32(g_ir_entries, eo + OFF_ENTRY_HOME, -1)
+ w32(g_ir_entries, eo + OFF_ENTRY_FLAGS, 0)
+ w64(prev, lv * 8, g_entry_count)
+ g_entry_count = g_entry_count + 1
+ cnt = cnt + 1
+ ii = ii + 1
// 无定值但有引用的 var(参数/单写临时值等):单条目 def=-1
- lv2 : ., mut = 0;
- loop {
- if lv2 >= vc { break; }
- if r64(prev, lv2 * 8) < 0 {
- gv := vs + lv2;
- ff := live_first(func_i, gv);
- ll := live_last(func_i, gv);
- if ff >= 0 && ll >= 0 {
- grow_entries(g_entry_count + 1);
- eo := g_entry_count * ESZ_ENTRY;
- w32(g_ir_entries, eo + OFF_ENTRY_VAR, gv);
- w32(g_ir_entries, eo + OFF_ENTRY_DEF, -1);
- w32(g_ir_entries, eo + OFF_ENTRY_LS, ist + ff);
- w32(g_ir_entries, eo + OFF_ENTRY_LE, ist + ll);
- w32(g_ir_entries, eo + OFF_ENTRY_HOME, -1);
- w32(g_ir_entries, eo + OFF_ENTRY_FLAGS, 0);
- g_entry_count = g_entry_count + 1;
- cnt = cnt + 1;
- }
- }
- lv2 = lv2 + 1;
- }
- }
- grow_func_entry_meta(func_i + 1);
- w64(g_ir_func_entry_start, func_i * 8, g_entry_count - cnt);
- w64(g_ir_func_entry_count, func_i * 8, cnt);
- return cnt;
-}
+ lv2 : ., mut = 0
+ loop:
+ if lv2 >= vc:
+ break
+ if r64(prev, lv2 * 8) < 0:
+ gv := vs + lv2
+ ff := live_first(func_i, gv)
+ ll := live_last(func_i, gv)
+ if ff >= 0 && ll >= 0:
+ grow_entries(g_entry_count + 1)
+ eo := g_entry_count * ESZ_ENTRY
+ w32(g_ir_entries, eo + OFF_ENTRY_VAR, gv)
+ w32(g_ir_entries, eo + OFF_ENTRY_DEF, -1)
+ w32(g_ir_entries, eo + OFF_ENTRY_LS, ist + ff)
+ w32(g_ir_entries, eo + OFF_ENTRY_LE, ist + ll)
+ w32(g_ir_entries, eo + OFF_ENTRY_HOME, -1)
+ w32(g_ir_entries, eo + OFF_ENTRY_FLAGS, 0)
+ g_entry_count = g_entry_count + 1
+ cnt = cnt + 1
+ lv2 = lv2 + 1
+ grow_func_entry_meta(func_i + 1)
+ w64(g_ir_func_entry_start, func_i * 8, g_entry_count - cnt)
+ w64(g_ir_func_entry_count, func_i * 8, cnt)
+ return cnt
// (2026-09-10 内核抽取 Task 2 自 regalloc.cr 迁入——本函数唯一调用方 =
// dump_entries_summary(--dump-entries kind= 字段映射);机器侧零引用。
// 定值指令种类名(--dump-entries kind= 字段):定值点 = dest≥0 producer
// opcode ∪ IR_STORE(s1)(本区头规则)——只列会作为定值点出现的 opcode,
// 未列 opcode 回退数字(不该出现;出现即探明新定值形态的信号)。
-fn ir_op_kind_name(op: int) -> string {
- if op == IR_ALLOC { return "ALLOC"; }
- if op == IR_ALLOC_STRUCT { return "ALLOC_STRUCT"; }
- if op == IR_ALLOC_ARRAY { return "ALLOC_ARRAY"; }
- if op == IR_STORE { return "STORE"; }
- if op == IR_CONST { return "CONST"; }
- if op == IR_LOAD { return "LOAD"; }
- if op == IR_LOAD_FIELD { return "LOAD_FIELD"; }
- if op == IR_LOAD_INDEX { return "LOAD_INDEX"; }
- if op == IR_LOAD_INDEX_VAR { return "LOAD_INDEX_VAR"; }
- if op == IR_BINARY { return "BINARY"; }
- if op == IR_UNARY { return "UNARY"; }
- if op == IR_CALL { return "CALL"; }
- if op == IR_CALL_EXTERN { return "CALL_EXTERN"; }
- if op == IR_HOTPATCH_ROUTE { return "HOTPATCH_ROUTE"; }
- if op == IR_MAKE_ENUM { return "MAKE_ENUM"; }
- if op == IR_REF { return "REF"; }
- if op == IR_DEREF { return "DEREF"; }
- if op == IR_LOAD_ENUM_TAG { return "LOAD_ENUM_TAG"; }
- if op == IR_SLICE { return "SLICE"; }
- if op == IR_ADDR_INDEX { return "ADDR_INDEX"; }
- if op == IR_SPAWN { return "SPAWN"; }
- if op == IR_AWAIT { return "AWAIT"; }
- if op == IR_ARENA_NEW { return "ARENA_NEW"; }
- if op == IR_DYN_PACK { return "DYN_PACK"; }
- if op == IR_DYN_TAG { return "DYN_TAG"; }
- if op == IR_DYN_VAL { return "DYN_VAL"; }
- if op == IR_LAZY_THUNK { return "LAZY_THUNK"; }
- if op == IR_LAZY_FORCE { return "LAZY_FORCE"; }
- if op == IR_FNADDR { return "FNADDR"; }
- if op == IR_I2F { return "I2F"; }
- if op == IR_F2I { return "F2I"; }
- if op == IR_PHI { return "PHI"; }
- return "OP" + int_str(op);
-}
+fn ir_op_kind_name(op: int) -> string:
+ if op == IR_ALLOC:
+ return "ALLOC"
+ if op == IR_ALLOC_STRUCT:
+ return "ALLOC_STRUCT"
+ if op == IR_ALLOC_ARRAY:
+ return "ALLOC_ARRAY"
+ if op == IR_STORE:
+ return "STORE"
+ if op == IR_CONST:
+ return "CONST"
+ if op == IR_LOAD:
+ return "LOAD"
+ if op == IR_LOAD_FIELD:
+ return "LOAD_FIELD"
+ if op == IR_LOAD_INDEX:
+ return "LOAD_INDEX"
+ if op == IR_LOAD_INDEX_VAR:
+ return "LOAD_INDEX_VAR"
+ if op == IR_BINARY:
+ return "BINARY"
+ if op == IR_UNARY:
+ return "UNARY"
+ if op == IR_CALL:
+ return "CALL"
+ if op == IR_CALL_EXTERN:
+ return "CALL_EXTERN"
+ if op == IR_HOTPATCH_ROUTE:
+ return "HOTPATCH_ROUTE"
+ if op == IR_MAKE_ENUM:
+ return "MAKE_ENUM"
+ if op == IR_REF:
+ return "REF"
+ if op == IR_DEREF:
+ return "DEREF"
+ if op == IR_LOAD_ENUM_TAG:
+ return "LOAD_ENUM_TAG"
+ if op == IR_SLICE:
+ return "SLICE"
+ if op == IR_ADDR_INDEX:
+ return "ADDR_INDEX"
+ if op == IR_SPAWN:
+ return "SPAWN"
+ if op == IR_AWAIT:
+ return "AWAIT"
+ if op == IR_ARENA_NEW:
+ return "ARENA_NEW"
+ if op == IR_DYN_PACK:
+ return "DYN_PACK"
+ if op == IR_DYN_TAG:
+ return "DYN_TAG"
+ if op == IR_DYN_VAL:
+ return "DYN_VAL"
+ if op == IR_LAZY_THUNK:
+ return "LAZY_THUNK"
+ if op == IR_LAZY_FORCE:
+ return "LAZY_FORCE"
+ if op == IR_FNADDR:
+ return "FNADDR"
+ if op == IR_I2F:
+ return "I2F"
+ if op == IR_F2I:
+ return "F2I"
+ if op == IR_PHI:
+ return "PHI"
+ return "OP" + int_str(op)
// --dump-entries 调试通道输出(cir 命令调用,Task 2 测试载体):
// 每函数一段、一行一条目;坐标 = 全局指令序/全局变量索引(与表内一致),
// v = 组内版本序(1-based),kind = 定值指令种类(def≥0 = producer opcode
// 名,GC 批 2 后不再止于 ALLOC/STORE;def=-1 → "-")。
-fn dump_entries_summary() {
- fi : ., mut = 0;
- loop {
- if fi >= g_ir_func_count { break; }
- es := entry_start(fi);
- ec := entry_count(fi);
- print("== entries func "); print(int_str(fi)); print(" (");
- print(istr_get(r64(g_ir_func_name_idx, fi * 8))); print("): ");
- println(int_str(ec));
- ei : ., mut = 0;
- loop {
- if ei >= ec { break; }
- e := es + ei;
- gv := ent_var(e);
- ord : ., mut = 1;
- ej : ., mut = es;
- loop {
- if ej >= e { break; }
- if ent_var(ej) == gv { ord = ord + 1; }
- ej = ej + 1;
- }
- print(" e "); print(int_str(e));
- print(" var "); print(int_str(gv));
- vn := get_ir_var_name(gv);
- if str_len(vn) > 0 { print(" name="); print(vn); }
- print(" v "); print(int_str(ord));
- print(" def "); print(int_str(ent_def(e)));
- d := ent_def(e);
- if d >= 0 {
+fn dump_entries_summary():
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ es := entry_start(fi)
+ ec := entry_count(fi)
+ print("== entries func ")
+ print(int_str(fi))
+ print(" (")
+ print(istr_get(r64(g_ir_func_name_idx, fi * 8)))
+ print("): ")
+ println(int_str(ec))
+ ei : ., mut = 0
+ loop:
+ if ei >= ec:
+ break
+ e := es + ei
+ gv := ent_var(e)
+ ord : ., mut = 1
+ ej : ., mut = es
+ loop:
+ if ej >= e:
+ break
+ if ent_var(ej) == gv:
+ ord = ord + 1
+ ej = ej + 1
+ print(" e ")
+ print(int_str(e))
+ print(" var ")
+ print(int_str(gv))
+ vn := get_ir_var_name(gv)
+ if str_len(vn) > 0:
+ print(" name=")
+ print(vn)
+ print(" v ")
+ print(int_str(ord))
+ print(" def ")
+ print(int_str(ent_def(e)))
+ d := ent_def(e)
+ if d >= 0:
// d = 定值点 = 全局节点坐标(A 通道中立化:对象面 nod_op 同
// index——线性流读点 F2 清,2026-09-10)
- print(" kind="); print(ir_op_kind_name(nod_op(d)));
- } else {
- print(" kind=-");
- }
- print(" live "); print(int_str(ent_live_start(e))); print("..");
- print(int_str(ent_live_end(e)));
- print(" home "); print(int_str(ent_home(e)));
- print(" flags "); println(int_str(ent_flags(e)));
- ei = ei + 1;
- }
- fi = fi + 1;
- }
-}
+ print(" kind=")
+ print(ir_op_kind_name(nod_op(d)))
+ else:
+ print(" kind=-")
+ print(" live ")
+ print(int_str(ent_live_start(e)))
+ print("..")
+ print(int_str(ent_live_end(e)))
+ print(" home ")
+ print(int_str(ent_home(e)))
+ print(" flags ")
+ println(int_str(ent_flags(e)))
+ ei = ei + 1
+ fi = fi + 1
// ===== v6 Task 3:共存推导(存在区间相交;不落盘——D3 判定现算)=====
// 格层语义:共存 = 对称关系(无传递性,最弱理论)。条目的 live 区间为
@@ -426,93 +498,95 @@ fn dump_entries_summary() {
// 单对查询:两条目存在区间相交 ⟺ ls1 ≤ le2 && ls2 ≤ le1(闭区间)。
// e1/e2 = 全局条目索引;func_i 保留兼容调用约定(跨函数指令区间天然
// 不重叠,无需按函数过滤)。判定四条之共存互斥的输入。
-fn entries_coexist(func_i: int, e1: int, e2: int) -> int {
+fn entries_coexist(func_i: int, e1: int, e2: int) -> int:
// GC-1(M-5):无上界校验收口——e1/e2 ≥ g_entry_count 属越界索引
// (条目表容量 ≥ 计数:槽后区域读到零填充/缓冲外 → 判定垃圾或崩溃),
// 防御性返回 0,风格与访问器约定一致(判定原语化前补)。
- if e1 < 0 || e2 < 0 || e1 >= g_entry_count || e2 >= g_entry_count { return 0; }
- if e1 == e2 { return 0; }
- s1 := ent_live_start(e1); n1 := ent_live_end(e1);
- s2 := ent_live_start(e2); n2 := ent_live_end(e2);
- if s1 < 0 || s2 < 0 { return 0; }
- if s1 <= n2 && s2 <= n1 { return 1; }
- return 0;
-}
+ if e1 < 0 || e2 < 0 || e1 >= g_entry_count || e2 >= g_entry_count:
+ return 0
+ if e1 == e2:
+ return 0
+ s1 := ent_live_start(e1)
+ n1 := ent_live_end(e1)
+ s2 := ent_live_start(e2)
+ n2 := ent_live_end(e2)
+ if s1 < 0 || s2 < 0:
+ return 0
+ if s1 <= n2 && s2 <= n1:
+ return 1
+ return 0
// 同 var 跨版本冲突数(数据自检):版本按定值点切割,构造保证
// 版本 j 区间终点 = 版本 j+1 定值点 −1 < 其起点 → 相邻版本必不交。
// 返回 0 = 版本化正确(任何 >0 = 版本切割 bug)。O(n) 每 var 组。
-fn coexist_version_conflicts(func_i: int) -> int {
- es := entry_start(func_i);
- ec := entry_count(func_i);
- conflicts : ., mut = 0;
- ei : ., mut = 0;
- loop {
- if ei >= ec { break; }
- e := es + ei;
- gv := ent_var(e);
+fn coexist_version_conflicts(func_i: int) -> int:
+ es := entry_start(func_i)
+ ec := entry_count(func_i)
+ conflicts : ., mut = 0
+ ei : ., mut = 0
+ loop:
+ if ei >= ec:
+ break
+ e := es + ei
+ gv := ent_var(e)
// 找同 var 的下一版本条目(版本按定值序相邻)
- ej : ., mut = ei + 1;
- loop {
- if ej >= ec { break; }
- if ent_var(es + ej) == gv {
- if entries_coexist(func_i, e, es + ej) != 0 {
- conflicts = conflicts + 1;
- }
- break;
- }
- ej = ej + 1;
- }
- ei = ei + 1;
- }
- return conflicts;
-}
+ ej : ., mut = ei + 1
+ loop:
+ if ej >= ec:
+ break
+ if ent_var(es + ej) == gv:
+ if entries_coexist(func_i, e, es + ej) != 0:
+ conflicts = conflicts + 1
+ break
+ ej = ej + 1
+ ei = ei + 1
+ return conflicts
// 同 home 组内冲突数(判定输入雏形——共存互斥:同槽条目不共存)。
// home = -1(未分配)不参与。真实成本注记(评审 I-2):home ≥ 0 时对每函数
// 做 O(E²) 相等探测(与组大小 k 无关;当前无回填路径 = 内层不进入 = O(E))。
// 触发点 = 判定进入消费端(分配器/自检回填 home 后)——届时须按 v6 格式定稿
// §4.2 per-group sweep O(k log k) 重写,不得直接复用本函数(ledger 门禁注记)。
-fn coexist_home_conflicts(func_i: int) -> int {
- es := entry_start(func_i);
- ec := entry_count(func_i);
- conflicts : ., mut = 0;
- ei : ., mut = 0;
- loop {
- if ei >= ec { break; }
- e1 := es + ei;
- h1 := ent_home(e1);
- if h1 >= 0 {
- ej : ., mut = ei + 1;
- loop {
- if ej >= ec { break; }
- e2 := es + ej;
- if ent_home(e2) == h1 {
- if entries_coexist(func_i, e1, e2) != 0 {
- conflicts = conflicts + 1;
- }
- }
- ej = ej + 1;
- }
- }
- ei = ei + 1;
- }
- return conflicts;
-}
+fn coexist_home_conflicts(func_i: int) -> int:
+ es := entry_start(func_i)
+ ec := entry_count(func_i)
+ conflicts : ., mut = 0
+ ei : ., mut = 0
+ loop:
+ if ei >= ec:
+ break
+ e1 := es + ei
+ h1 := ent_home(e1)
+ if h1 >= 0:
+ ej : ., mut = ei + 1
+ loop:
+ if ej >= ec:
+ break
+ e2 := es + ej
+ if ent_home(e2) == h1:
+ if entries_coexist(func_i, e1, e2) != 0:
+ conflicts = conflicts + 1
+ ej = ej + 1
+ ei = ei + 1
+ return conflicts
// --dump-coexist 调试通道(cir 命令调用,Task 3 测试载体):
// 每函数输出版本冲突数(应 0)与同 home 组内冲突数(未分配时应 0)。
-fn dump_coexist_summary() {
- fi : ., mut = 0;
- loop {
- if fi >= g_ir_func_count { break; }
- print("== coexist func "); print(int_str(fi)); print(" (");
- print(istr_get(r64(g_ir_func_name_idx, fi * 8))); print("):");
- print(" ver_conf "); print(int_str(coexist_version_conflicts(fi)));
- print(" home_conf "); println(int_str(coexist_home_conflicts(fi)));
- fi = fi + 1;
- }
-}
+fn dump_coexist_summary():
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ print("== coexist func ")
+ print(int_str(fi))
+ print(" (")
+ print(istr_get(r64(g_ir_func_name_idx, fi * 8)))
+ print("):")
+ print(" ver_conf ")
+ print(int_str(coexist_version_conflicts(fi)))
+ print(" home_conf ")
+ println(int_str(coexist_home_conflicts(fi)))
+ fi = fi + 1
// ===== v6 Task 5:判定消费最小闭环(一致性自检——共 specs/
// regalloc-consistency.corespec 规约)=====
// 分配结果:实例侧 g_opt_meta 的 OPT_KEY_REG_ASSIGN 对(var_idx → 位置——x86
@@ -541,7 +615,7 @@ fn dump_coexist_summary() {
// 规则违反诊断打印上限(rl_report_rule1/2 防病理刷屏,计数不封顶)——唯一
// 使用方 = 本文件判定函数(rl_rule2_func/verify_regalloc_consistency);机器
// 侧零引用(2026-09-10 内核抽取 Task 2 自 regalloc.cr 迁入)。
-RPT_MAX : int = 8; // 规则违反诊断每函数每规则打印上限(计数不封顶)
+RPT_MAX : int = 8 // 规则违反诊断每函数每规则打印上限(计数不封顶)
// ===== 位置登记表(B 通道中立化——内核完备 Task 3,2026-09-10)=====
// 判定输入 = 实例分配结果的统一形态——{entry → loc} 登记。loc = 不透明整数:
@@ -557,49 +631,49 @@ RPT_MAX : int = 8; // 规则违反诊断每函数每规则打印上
// 命名注记(Task 4 措辞批——Task 3 评审 Minor 2 候选):旧名 g_loc_reg_buf
// 的 "reg" 缩写 = 寄存器时代措辞(内核零经典概念原则)——改全词 registry
// (登记表——与 loc_registry_reset 命名族一致;registry 无寄存器语义)。
-g_loc_registry_buf : string, mut; // 登记表缓冲(4B/槽——槽 e = 条目 e 的 loc 或 -1)
-g_loc_registry_cap : int, mut; // 登记表容量(槽数)
+g_loc_registry_buf : string, mut // 登记表缓冲(4B/槽——槽 e = 条目 e 的 loc 或 -1)
+g_loc_registry_cap : int, mut // 登记表容量(槽数)
-fn loc_registry_reset() {
+fn loc_registry_reset():
// 条目重建点调用(compute_entries func_i==0)——已登记区整清 -1
// (O(cap) 一次/代;新增长槽已在 kern_loc_assign -1 初始化)
- zi : ., mut = 0;
- loop {
- if zi >= g_loc_registry_cap { break; }
- w32(g_loc_registry_buf, zi * 4, -1);
- zi = zi + 1;
- }
-}
+ zi : ., mut = 0
+ loop:
+ if zi >= g_loc_registry_cap:
+ break
+ w32(g_loc_registry_buf, zi * 4, -1)
+ zi = zi + 1
-fn kern_loc_assign(entry_idx: int, loc: int) {
- if entry_idx < 0 { return; }
- if entry_idx >= g_loc_registry_cap {
- nc : ., mut = g_loc_registry_cap * 2;
- if nc < 64 { nc = 64; }
- if nc <= entry_idx { nc = entry_idx + 64; }
- nb := alloc(nc * 4);
- _dyncpy(g_loc_registry_buf, g_loc_registry_cap * 4, nb);
- zi : ., mut = g_loc_registry_cap;
- loop {
- if zi >= nc { break; }
- w32(nb, zi * 4, -1); // 新槽 -1 初始化(未登记 = -1 哨兵)
- zi = zi + 1;
- }
- g_loc_registry_buf = nb;
- g_loc_registry_cap = nc;
- }
- w32(g_loc_registry_buf, entry_idx * 4, loc);
-}
+fn kern_loc_assign(entry_idx: int, loc: int):
+ if entry_idx < 0:
+ return
+ if entry_idx >= g_loc_registry_cap:
+ nc : ., mut = g_loc_registry_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc <= entry_idx:
+ nc = entry_idx + 64
+ nb := alloc(nc * 4)
+ _dyncpy(g_loc_registry_buf, g_loc_registry_cap * 4, nb)
+ zi : ., mut = g_loc_registry_cap
+ loop:
+ if zi >= nc:
+ break
+ w32(nb, zi * 4, -1) // 新槽 -1 初始化(未登记 = -1 哨兵)
+ zi = zi + 1
+ g_loc_registry_buf = nb
+ g_loc_registry_cap = nc
+ w32(g_loc_registry_buf, entry_idx * 4, loc)
-fn kern_loc_clear(entry_idx: int) {
- if entry_idx < 0 || entry_idx >= g_loc_registry_cap { return; }
- w32(g_loc_registry_buf, entry_idx * 4, -1);
-}
+fn kern_loc_clear(entry_idx: int):
+ if entry_idx < 0 || entry_idx >= g_loc_registry_cap:
+ return
+ w32(g_loc_registry_buf, entry_idx * 4, -1)
-fn kern_loc_of(entry_idx: int) -> int {
- if entry_idx < 0 || entry_idx >= g_loc_registry_cap { return -1; }
- return buf_read_i32(g_loc_registry_buf, entry_idx * 4);
-}
+fn kern_loc_of(entry_idx: int) -> int:
+ if entry_idx < 0 || entry_idx >= g_loc_registry_cap:
+ return -1
+ return buf_read_i32(g_loc_registry_buf, entry_idx * 4)
// var 级驻留查询(判定读通道——B 通道中立化 2026-09-10 函数体等价改写:旧 =
// 直读 g_opt_meta 实例布局 → 现 = 登记表查询——kern_loc_of 逐条目)。var 级
@@ -612,92 +686,102 @@ fn kern_loc_of(entry_idx: int) -> int {
// check_regalloc_violations/read_gap_nonfunc0)。
// 窗口搜索注记:var 的条目只存在于所属函数的条目段——先按 var 窗口定位函数
// 再扫该段(避免全表扫描;与 rl_rule2_func 既有 per-var 条目收集同界)。
-fn meta_reg_for_var(var_idx: int) -> int {
- fi : ., mut = 0;
- loop {
- if fi >= g_ir_func_count { break; }
- vs := r64(g_ir_func_var_start, fi * 8);
- vc := r64(g_ir_func_var_count, fi * 8);
- if var_idx >= vs && var_idx < vs + vc {
- es := entry_start(fi);
- ec := entry_count(fi);
- ei : ., mut = 0;
- loop {
- if ei >= ec { break; }
- e := es + ei;
- if ent_var(e) == var_idx {
- loc := kern_loc_of(e);
- if loc >= 0 { return loc; }
- }
- ei = ei + 1;
- }
- return -1; // 窗口内无登记条目 = 非驻留
- }
- fi = fi + 1;
- }
- return -1; // 不在任何函数 var 窗口(全局 var 等)——恒非驻留
-}
+fn meta_reg_for_var(var_idx: int) -> int:
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ vs := r64(g_ir_func_var_start, fi * 8)
+ vc := r64(g_ir_func_var_count, fi * 8)
+ if var_idx >= vs && var_idx < vs + vc:
+ es := entry_start(fi)
+ ec := entry_count(fi)
+ ei : ., mut = 0
+ loop:
+ if ei >= ec:
+ break
+ e := es + ei
+ if ent_var(e) == var_idx:
+ loc := kern_loc_of(e)
+ if loc >= 0:
+ return loc
+ ei = ei + 1
+ return -1 // 窗口内无登记条目 = 非驻留
+ fi = fi + 1
+ return -1 // 不在任何函数 var 窗口(全局 var 等)——恒非驻留
// 16B 记录比较(归并用):key = (loc, entry 的 live_start),均升序
-fn rl_rec_lt(buf: string, a: int, b: int) -> int {
- la := r64(buf, a * 16); lb := r64(buf, b * 16);
- if la != lb { if la < lb { return 1; } return 0; }
- ea := r64(buf, a * 16 + 8); eb := r64(buf, b * 16 + 8);
- if ent_live_start(ea) < ent_live_start(eb) { return 1; }
- return 0;
-}
+fn rl_rec_lt(buf: string, a: int, b: int) -> int:
+ la := r64(buf, a * 16)
+ lb := r64(buf, b * 16)
+ if la != lb:
+ if la < lb:
+ return 1
+ return 0
+ ea := r64(buf, a * 16 + 8)
+ eb := r64(buf, b * 16 + 8)
+ if ent_live_start(ea) < ent_live_start(eb):
+ return 1
+ return 0
// 自底向上归并排序(16B 记录 {loc:8, entry:8})——O(k log k),
// v6 格式定稿 §4.2 sweep 门禁(同位置组内检查不得逐对 O(E²))。
-fn rl_merge_sort(buf: string, n: int) {
- if n <= 1 { return; }
- tmp := alloc(n * 16);
- width : ., mut = 1;
- loop {
- if width >= n { break; }
- left : ., mut = 0;
- loop {
- if left >= n { break; }
- mid : ., mut = left + width; if mid > n { mid = n; }
- right : ., mut = left + width * 2; if right > n { right = n; }
- i : ., mut = left; j : ., mut = mid; k : ., mut = left;
- loop {
- if i >= mid || j >= right { break; }
- if rl_rec_lt(buf, i, j) != 0 {
- w64(tmp, k * 16, r64(buf, i * 16));
- w64(tmp, k * 16 + 8, r64(buf, i * 16 + 8));
- i = i + 1;
- } else {
- w64(tmp, k * 16, r64(buf, j * 16));
- w64(tmp, k * 16 + 8, r64(buf, j * 16 + 8));
- j = j + 1;
- }
- k = k + 1;
- }
- loop {
- if i >= mid { break; }
- w64(tmp, k * 16, r64(buf, i * 16));
- w64(tmp, k * 16 + 8, r64(buf, i * 16 + 8));
- i = i + 1; k = k + 1;
- }
- loop {
- if j >= right { break; }
- w64(tmp, k * 16, r64(buf, j * 16));
- w64(tmp, k * 16 + 8, r64(buf, j * 16 + 8));
- j = j + 1; k = k + 1;
- }
- left = right;
- }
- zi : ., mut = 0;
- loop {
- if zi >= n { break; }
- w64(buf, zi * 16, r64(tmp, zi * 16));
- w64(buf, zi * 16 + 8, r64(tmp, zi * 16 + 8));
- zi = zi + 1;
- }
- width = width * 2;
- }
-}
+fn rl_merge_sort(buf: string, n: int):
+ if n <= 1:
+ return
+ tmp := alloc(n * 16)
+ width : ., mut = 1
+ loop:
+ if width >= n:
+ break
+ left : ., mut = 0
+ loop:
+ if left >= n:
+ break
+ mid : ., mut = left + width
+ if mid > n:
+ mid = n
+ right : ., mut = left + width * 2
+ if right > n:
+ right = n
+ i : ., mut = left
+ j : ., mut = mid
+ k : ., mut = left
+ loop:
+ if i >= mid || j >= right:
+ break
+ if rl_rec_lt(buf, i, j) != 0:
+ w64(tmp, k * 16, r64(buf, i * 16))
+ w64(tmp, k * 16 + 8, r64(buf, i * 16 + 8))
+ i = i + 1
+ else:
+ w64(tmp, k * 16, r64(buf, j * 16))
+ w64(tmp, k * 16 + 8, r64(buf, j * 16 + 8))
+ j = j + 1
+ k = k + 1
+ loop:
+ if i >= mid:
+ break
+ w64(tmp, k * 16, r64(buf, i * 16))
+ w64(tmp, k * 16 + 8, r64(buf, i * 16 + 8))
+ i = i + 1
+ k = k + 1
+ loop:
+ if j >= right:
+ break
+ w64(tmp, k * 16, r64(buf, j * 16))
+ w64(tmp, k * 16 + 8, r64(buf, j * 16 + 8))
+ j = j + 1
+ k = k + 1
+ left = right
+ zi : ., mut = 0
+ loop:
+ if zi >= n:
+ break
+ w64(buf, zi * 16, r64(tmp, zi * 16))
+ w64(buf, zi * 16 + 8, r64(tmp, zi * 16 + 8))
+ zi = zi + 1
+ width = width * 2
// 打印位置值(Task 4 措辞中性化——不透明 loc 直印,去 "reg N"/"home slot N"
// 分类措辞:值域分类 = 实例事务,内核只印不透明整数)。规则① 两遍(登记表遍/
@@ -705,83 +789,97 @@ fn rl_merge_sort(buf: string, n: int) {
// 格式相同、遍来源不印(Task 3 遍来源标记参数 = 仅诊断措辞面,Task 4 随分类
// 措辞同撤);判据只消费规则号/条目/loc 值,诊断可读性由 entries/var/区间/
// loc 全量信息承载。无域偏移合成。
-fn rl_print_loc(loc: int) {
- print("loc "); print(int_str(loc));
-}
+fn rl_print_loc(loc: int):
+ print("loc ")
+ print(int_str(loc))
-fn rl_func_name(fi: int) {
- print("func "); print(int_str(fi)); print(" (");
- print(istr_get(r64(g_ir_func_name_idx, fi * 8))); print(")");
-}
+fn rl_func_name(fi: int):
+ print("func ")
+ print(int_str(fi))
+ print(" (")
+ print(istr_get(r64(g_ir_func_name_idx, fi * 8)))
+ print(")")
// 规则 ① 违反诊断(打印上限 RPT_MAX 防病理刷屏,计数不封顶)。
// 前缀措辞中性化(Task 4 输出面批):旧前缀 "regalloc-consistency" = x86 时代
// 检查名——改检查域语义名 "entry-consistency"(条目版本表一致性——规则①
// 同值互斥 + 规则② 读覆盖);spec 文件名引用保留于本文件判定区头注
// (spec/regalloc-consistency.corespec R3/R4——规约文档名不变)。
-fn rl_report_rule1(func_i: int, loc: int, e1: int, e2: int) {
- print("entry-consistency: "); rl_func_name(func_i);
- print(": rule 1 violation: entries "); print(int_str(e1));
- print(" (var "); print(int_str(ent_var(e1))); print(") and "); print(int_str(e2));
- print(" (var "); print(int_str(ent_var(e2))); print(") both at ");
- rl_print_loc(loc);
- print(", coexist ["); print(int_str(ent_live_start(e1))); print("..");
- print(int_str(ent_live_end(e1))); print("] x ["); print(int_str(ent_live_start(e2)));
- print(".."); print(int_str(ent_live_end(e2))); println("]");
-}
+fn rl_report_rule1(func_i: int, loc: int, e1: int, e2: int):
+ print("entry-consistency: ")
+ rl_func_name(func_i)
+ print(": rule 1 violation: entries ")
+ print(int_str(e1))
+ print(" (var ")
+ print(int_str(ent_var(e1)))
+ print(") and ")
+ print(int_str(e2))
+ print(" (var ")
+ print(int_str(ent_var(e2)))
+ print(") both at ")
+ rl_print_loc(loc)
+ print(", coexist [")
+ print(int_str(ent_live_start(e1)))
+ print("..")
+ print(int_str(ent_live_end(e1)))
+ print("] x [")
+ print(int_str(ent_live_start(e2)))
+ print("..")
+ print(int_str(ent_live_end(e2)))
+ println("]")
// 规则① 同值互斥遍(归并段扫——sweep 门禁):rec = {loc:8, entry:8} 记录按
// (loc, live_start) 归并排序(rl_merge_sort)——同 loc 连续段内维持最大
// live_end:max_end ≥ 当前 ls ⟹ 区间相交 = 违反(rl_report_rule1 报告)。
// cap_base = 前遍已打印数——RPT_MAX 按规则合并封顶(两遍共享 = 与单遍合成
// 打印同界;Task 3 遍来源标记参数随 Task 4 措辞批同撤——两遍同报告格式)。
-fn rl_rule1_sweep(func_i: int, rec: string, cnt: int, cap_base: int) -> int {
- viol : ., mut = 0;
- rl_merge_sort(rec, cnt);
- run_start : ., mut = 0;
- loop {
- if run_start >= cnt { break; }
- run_end : ., mut = run_start + 1;
- loop {
- if run_end >= cnt { break; }
- if r64(rec, run_end * 16) != r64(rec, run_start * 16) { break; }
- run_end = run_end + 1;
- }
- maxj : ., mut = -1;
- zi : ., mut = run_start;
- loop {
- if zi >= run_end { break; }
- e := r64(rec, zi * 16 + 8);
- if maxj >= 0 {
- mej := r64(rec, maxj * 16 + 8);
- if ent_live_end(mej) >= ent_live_start(e) {
- if cap_base + viol < RPT_MAX {
- rl_report_rule1(func_i, r64(rec, zi * 16), mej, e);
- }
- viol = viol + 1;
- }
- }
- if maxj < 0 || ent_live_end(e) > ent_live_end(r64(rec, maxj * 16 + 8)) {
- maxj = zi;
- }
- zi = zi + 1;
- }
- run_start = run_end;
- }
- return viol;
-}
+fn rl_rule1_sweep(func_i: int, rec: string, cnt: int, cap_base: int) -> int:
+ viol : ., mut = 0
+ rl_merge_sort(rec, cnt)
+ run_start : ., mut = 0
+ loop:
+ if run_start >= cnt:
+ break
+ run_end : ., mut = run_start + 1
+ loop:
+ if run_end >= cnt:
+ break
+ if r64(rec, run_end * 16) != r64(rec, run_start * 16):
+ break
+ run_end = run_end + 1
+ maxj : ., mut = -1
+ zi : ., mut = run_start
+ loop:
+ if zi >= run_end:
+ break
+ e := r64(rec, zi * 16 + 8)
+ if maxj >= 0:
+ mej := r64(rec, maxj * 16 + 8)
+ if ent_live_end(mej) >= ent_live_start(e):
+ if cap_base + viol < RPT_MAX:
+ rl_report_rule1(func_i, r64(rec, zi * 16), mej, e)
+ viol = viol + 1
+ if maxj < 0 || ent_live_end(e) > ent_live_end(r64(rec, maxj * 16 + 8)):
+ maxj = zi
+ zi = zi + 1
+ run_start = run_end
+ return viol
// 规则 ② 违反诊断(前缀中性化同 rl_report_rule1——"entry-consistency";
// 正文语义词 = 读覆盖(read ... not covered by any active version entry),
// Task 4 措辞批保留)。
-fn rl_report_rule2(func_i: int, gv: int, inst: int) {
- print("entry-consistency: "); rl_func_name(func_i);
- print(": rule 2 violation: read of var "); print(int_str(gv));
- vn := get_ir_var_name(gv);
- if str_len(vn) > 0 { print(" name="); print(vn); }
- print(" at instr "); print(int_str(inst));
- println(" not covered by any active version entry");
-}
+fn rl_report_rule2(func_i: int, gv: int, inst: int):
+ print("entry-consistency: ")
+ rl_func_name(func_i)
+ print(": rule 2 violation: read of var ")
+ print(int_str(gv))
+ vn := get_ir_var_name(gv)
+ if str_len(vn) > 0:
+ print(" name=")
+ print(vn)
+ print(" at instr ")
+ print(int_str(inst))
+ println(" not covered by any active version entry")
// 规则 ②(框架):寄存器驻留变量的读点必须有活跃版本覆盖。
// 读点 = 指令 i 以 v 为源操作数(IR_STORE 的 s1 是写目标,排除)——只扫 s1/s2
@@ -796,40 +894,46 @@ fn rl_report_rule2(func_i: int, gv: int, inst: int) {
// 扩为 dest≥0 全定值(含 ALLOC_ARRAY/ALLOC_STRUCT 内存对象诞生),义务前读
// 窗口(旧「非版本化定值供给」区)自动纳入:版本区间自定值点起连续覆盖至
// last_ref,义务内读点恒有版本(构造不变量)——本检查零改动,承诺已验证。
-fn rl_rule2_func(func_i: int, vs: int, vc: int, nst: int, nc: int, es: int, ec: int) -> int {
+fn rl_rule2_func(func_i: int, vs: int, vc: int, nst: int, nc: int, es: int, ec: int) -> int:
// 签名措辞中性化(Task 2 F3,2026-09-10——值不变):窗口参数 = 语义对象
// 空间切片——vs/vc = 变量窗口(全局 var 命名空间 [vs, vs+vc))、nst/nc =
// 节点窗口(函数在 NOD 节点坐标空间的 [nst, nst+nc),源 = 函数窗口表
// g_ir_func_instr_start/count——节点序 = 指令序 index-aligned,见
// compute_live_ranges F3 注记)。调用方位置传参,重命名零行为影响。
- violations : ., mut = 0;
- lv : ., mut = 0;
- loop {
- if lv >= vc { break; }
- gv := vs + lv;
- if meta_reg_for_var(gv) < 0 { lv = lv + 1; continue; }
+ violations : ., mut = 0
+ lv : ., mut = 0
+ loop:
+ if lv >= vc:
+ break
+ gv := vs + lv
+ if meta_reg_for_var(gv) < 0:
+ lv = lv + 1
+ continue
// 收集该 var 的版本条目(def ≥ 0;表内按定值点升序)——先数再收集
- m : ., mut = 0;
- ei : ., mut = 0;
- loop {
- if ei >= ec { break; }
- e := es + ei;
- if ent_var(e) == gv && ent_def(e) >= 0 { m = m + 1; }
- ei = ei + 1;
- }
- if m <= 0 { lv = lv + 1; continue; } // 无版本化定值:义务范围为空
- vers : string, mut = alloc(m * 8);
- vj : ., mut = 0;
- ei = 0;
- loop {
- if ei >= ec { break; }
- e := es + ei;
- if ent_var(e) == gv && ent_def(e) >= 0 {
- w64(vers, vj * 8, e);
- vj = vj + 1;
- }
- ei = ei + 1;
- }
+ m : ., mut = 0
+ ei : ., mut = 0
+ loop:
+ if ei >= ec:
+ break
+ e := es + ei
+ if ent_var(e) == gv && ent_def(e) >= 0:
+ m = m + 1
+ ei = ei + 1
+ if m <= 0:
+ lv = lv + 1
+ continue
+ // 无版本化定值:义务范围为空
+ vers : string, mut = alloc(m * 8)
+ vj : ., mut = 0
+ ei = 0
+ loop:
+ if ei >= ec:
+ break
+ e := es + ei
+ if ent_var(e) == gv && ent_def(e) >= 0:
+ w64(vers, vj * 8, e)
+ vj = vj + 1
+ ei = ei + 1
// 逐节点升序扫读点(读点 = 节点坐标——F1:判定② 读点扫描点,A 通道
// 中立化 2026-09-10 后 = 对象面 nod_op/nod_s1/nod_s2 同 index 读取,
// 数值与线性流时代 iri_* 逐字节同);版本游标单调推进(版本区间自 def
@@ -839,54 +943,56 @@ fn rl_rule2_func(func_i: int, vs: int, vc: int, nst: int, nc: int, es: int, ec:
// inst 不得用局部 ii;func 0 上 nst=0 使 ii == inst 掩盖该错配,非
// func 0 函数上规则 ② 会失明(只漏报不误报;回归 = test_live_ranges
// check_regalloc_read_gap_nonfunc0)。
- cursor : ., mut = 0;
- first_def := r64(vers, 0 * 8);
- ii : ., mut = 0;
- loop {
- if ii >= nc { break; }
- inst := nst + ii;
- op := nod_op(inst);
- rd : ., mut = 0;
- s1 := nod_s1(inst);
- s2 := nod_s2(inst);
- if s1 == gv && op != IR_STORE { rd = 1; }
- if s2 == gv { rd = 1; }
- if rd != 0 && inst >= ent_def(first_def) {
+ cursor : ., mut = 0
+ first_def := r64(vers, 0 * 8)
+ ii : ., mut = 0
+ loop:
+ if ii >= nc:
+ break
+ inst := nst + ii
+ op := nod_op(inst)
+ rd : ., mut = 0
+ s1 := nod_s1(inst)
+ s2 := nod_s2(inst)
+ if s1 == gv && op != IR_STORE:
+ rd = 1
+ if s2 == gv:
+ rd = 1
+ if rd != 0 && inst >= ent_def(first_def):
// 推进游标至最后一个 def ≤ inst 的版本
- loop {
- if cursor + 1 >= m { break; }
- nx := r64(vers, (cursor + 1) * 8);
- if ent_def(nx) > inst { break; }
- cursor = cursor + 1;
- }
- cv := r64(vers, cursor * 8);
- if ent_live_end(cv) < inst {
- if violations < RPT_MAX { rl_report_rule2(func_i, gv, inst); }
- violations = violations + 1;
- }
- }
- ii = ii + 1;
- }
- lv = lv + 1;
- }
- return violations;
-}
+ loop:
+ if cursor + 1 >= m:
+ break
+ nx := r64(vers, (cursor + 1) * 8)
+ if ent_def(nx) > inst:
+ break
+ cursor = cursor + 1
+ cv := r64(vers, cursor * 8)
+ if ent_live_end(cv) < inst:
+ if violations < RPT_MAX:
+ rl_report_rule2(func_i, gv, inst)
+ violations = violations + 1
+ ii = ii + 1
+ lv = lv + 1
+ return violations
// 判定实现(0 = 一致 1 = 违反)——消费条目表(存在区间/home 字段)+ 位置
// 登记表(分配结果统一形态——B 通道中立化 2026-09-10,见登记表节)。
// precondition:alloc_registers() 已跑(条目表随算随新、登记已配对)。
-fn verify_regalloc_consistency(func_i: int) -> int {
- if func_i < 0 || func_i >= g_ir_func_count { return 0; }
- es := entry_start(func_i);
- ec := entry_count(func_i);
- if ec <= 0 { return 0; }
+fn verify_regalloc_consistency(func_i: int) -> int:
+ if func_i < 0 || func_i >= g_ir_func_count:
+ return 0
+ es := entry_start(func_i)
+ ec := entry_count(func_i)
+ if ec <= 0:
+ return 0
// 函数窗口源同 compute_live_ranges(F3 注记,2026-09-10):g_ir_func_instr_*
// 值 = NOD 节点坐标(节点序 = 指令序 index-aligned);ic/ist 传 rl_rule2_func
// 的 nst/nc 节点窗口参数(位置传参)。规则② 节点字段读 = 对象面 nod_*。
- ic := r64(g_ir_func_instr_count, func_i * 8);
- ist := r64(g_ir_func_instr_start, func_i * 8);
- vc := r64(g_ir_func_var_count, func_i * 8);
- vs := r64(g_ir_func_var_start, func_i * 8);
+ ic := r64(g_ir_func_instr_count, func_i * 8)
+ ist := r64(g_ir_func_instr_start, func_i * 8)
+ vc := r64(g_ir_func_var_count, func_i * 8)
+ vs := r64(g_ir_func_var_start, func_i * 8)
// 规则 ①:同值互斥两遍(B 通道中立化 2026-09-10——设计 spec §2.2 修正:
// 位置 = 不透明整数,内核无 reg/home 值域分类与编码合成概念)——
@@ -900,69 +1006,63 @@ fn verify_regalloc_consistency(func_i: int) -> int {
// 排他注记(与现 else-if 合成语义逐条等价):已登记条目不进 home 遍——
// 双态条目(已登记 + home ≥ 0)不可达(注入路径先清登记再写 home;真实
// 分配不回填 home),排他 = 现语义 reg 优先的保持(防双态假冲突)。
- reg_cnt : ., mut = 0;
- home_cnt : ., mut = 0;
- ei : ., mut = 0;
- loop {
- if ei >= ec { break; }
- e := es + ei;
- if ent_live_start(e) >= 0 && ent_live_end(e) >= 0 {
- if kern_loc_of(e) >= 0 { reg_cnt = reg_cnt + 1; }
- else if ent_home(e) >= 0 { home_cnt = home_cnt + 1; }
- }
- ei = ei + 1;
- }
- rule1_viol : ., mut = 0;
+ reg_cnt : ., mut = 0
+ home_cnt : ., mut = 0
+ ei : ., mut = 0
+ loop:
+ if ei >= ec:
+ break
+ e := es + ei
+ if ent_live_start(e) >= 0 && ent_live_end(e) >= 0:
+ if kern_loc_of(e) >= 0:
+ reg_cnt = reg_cnt + 1
+ else if ent_home(e) >= 0:
+ home_cnt = home_cnt + 1
+ ei = ei + 1
+ rule1_viol : ., mut = 0
// 登记表遍(先)
- if reg_cnt > 1 {
- rec : string, mut = alloc(reg_cnt * 16);
- ci : ., mut = 0;
- ei = 0;
- loop {
- if ei >= ec { break; }
- e := es + ei;
- if ent_live_start(e) >= 0 && ent_live_end(e) >= 0 {
- loc := kern_loc_of(e);
- if loc >= 0 {
- w64(rec, ci * 16, loc);
- w64(rec, ci * 16 + 8, e);
- ci = ci + 1;
- }
- }
- ei = ei + 1;
- }
- rule1_viol = rl_rule1_sweep(func_i, rec, reg_cnt, 0);
- }
+ if reg_cnt > 1:
+ rec : string, mut = alloc(reg_cnt * 16)
+ ci : ., mut = 0
+ ei = 0
+ loop:
+ if ei >= ec:
+ break
+ e := es + ei
+ if ent_live_start(e) >= 0 && ent_live_end(e) >= 0:
+ loc := kern_loc_of(e)
+ if loc >= 0:
+ w64(rec, ci * 16, loc)
+ w64(rec, ci * 16 + 8, e)
+ ci = ci + 1
+ ei = ei + 1
+ rule1_viol = rl_rule1_sweep(func_i, rec, reg_cnt, 0)
// home 字段遍(独立遍——cap_base = 登记表遍已打印数(RPT_MAX 合并封顶))
- if home_cnt > 1 {
- rec : string, mut = alloc(home_cnt * 16);
- ci : ., mut = 0;
- ei = 0;
- loop {
- if ei >= ec { break; }
- e := es + ei;
- if ent_live_start(e) >= 0 && ent_live_end(e) >= 0 {
- h := ent_home(e);
- if h >= 0 {
- w64(rec, ci * 16, h);
- w64(rec, ci * 16 + 8, e);
- ci = ci + 1;
- }
- }
- ei = ei + 1;
- }
- rule1_viol = rule1_viol + rl_rule1_sweep(func_i, rec, home_cnt, rule1_viol);
- }
+ if home_cnt > 1:
+ rec : string, mut = alloc(home_cnt * 16)
+ ci : ., mut = 0
+ ei = 0
+ loop:
+ if ei >= ec:
+ break
+ e := es + ei
+ if ent_live_start(e) >= 0 && ent_live_end(e) >= 0:
+ h := ent_home(e)
+ if h >= 0:
+ w64(rec, ci * 16, h)
+ w64(rec, ci * 16 + 8, e)
+ ci = ci + 1
+ ei = ei + 1
+ rule1_viol = rule1_viol + rl_rule1_sweep(func_i, rec, home_cnt, rule1_viol)
// 规则 ②(框架):寄存器驻留变量的读点活跃版本覆盖
- rule2_viol : ., mut = 0;
- if vc > 0 && ic > 0 {
- rule2_viol = rl_rule2_func(func_i, vs, vc, ist, ic, es, ec);
- }
+ rule2_viol : ., mut = 0
+ if vc > 0 && ic > 0:
+ rule2_viol = rl_rule2_func(func_i, vs, vc, ist, ic, es, ec)
- if rule1_viol > 0 || rule2_viol > 0 { return 1; }
- return 0;
-}
+ if rule1_viol > 0 || rule2_viol > 0:
+ return 1
+ return 0
// 全函数自检(O2 构建路径调用点):0 = 全部一致;违反时打印诊断并返回违反
// 函数数。成功静默(自检通过 = 不打扰构建输出)。
@@ -972,16 +1072,15 @@ fn verify_regalloc_consistency(func_i: int) -> int {
// 不加 kern_ 包装层,YAGNI);"判定结果回传实例" = 本函数 + 证据查询面
// (entries_coexist/coexist_version_conflicts/coexist_home_conflicts——实例
// 自取),内核不写实例结构。
-fn regalloc_verify_all() -> int {
- bad : ., mut = 0;
- fi : ., mut = 0;
- loop {
- if fi >= g_ir_func_count { break; }
- bad = bad + verify_regalloc_consistency(fi);
- fi = fi + 1;
- }
- return bad;
-}
+fn regalloc_verify_all() -> int:
+ bad : ., mut = 0
+ fi : ., mut = 0
+ loop:
+ if fi >= g_ir_func_count:
+ break
+ bad = bad + verify_regalloc_consistency(fi)
+ fi = fi + 1
+ return bad
// ==================================================================
// 语义对象模型(内核完备 Task 1,2026-09-10):对象面 API + NOD 对象留存。
@@ -1007,43 +1106,54 @@ fn regalloc_verify_all() -> int {
// 保证界内——ent_* 同约)。字段读走 buf_read_*(ccr_io.cr 真实函数体带符号
// 扩展——r32 在 bootstrap 产物里零扩展,负值会读错,见 ent_var 注);无界
// 检查与 ent_* 约定一致。
-ESZ_NOD_SEM : int = 32; // 内存对象记录 32B(= 盘 40B 剥离 first_edge/edge_count;R2 P6 T3:+4B 项索引)
-ESZ_NOD_META : int = 16; // 邻接域记录 16B {first_edge i64 @0, edge_count i64 @8}
-OFF_NS_OP : int = 0; // 语义字段 offset(布局镜像盘记录:s1 = 8B 占 +8..+16)
-OFF_NS_DEST : int = 4;
-OFF_NS_S1 : int = 8;
-OFF_NS_S2 : int = 16;
-OFF_NS_S3 : int = 20;
-OFF_NS_TK : int = 24;
+ESZ_NOD_SEM : int = 32 // 内存对象记录 32B(= 盘 40B 剥离 first_edge/edge_count;R2 P6 T3:+4B 项索引)
+ESZ_NOD_META : int = 16 // 邻接域记录 16B {first_edge i64 @0, edge_count i64 @8}
+OFF_NS_OP : int = 0 // 语义字段 offset(布局镜像盘记录:s1 = 8B 占 +8..+16)
+OFF_NS_DEST : int = 4
+OFF_NS_S1 : int = 8
+OFF_NS_S2 : int = 16
+OFF_NS_S3 : int = 20
+OFF_NS_TK : int = 24
// R2 P6 Task 3(β):TYPE 段**文件空间**项索引(i32;-1 = 无项)。盘记录 +28,
// 邻接域自 +28/+32 顺移 +32/+36(语义区在前惯例自 v5 保持)。写侧 = 保存期
// 单遍装填(ccr_types.cr——文件空间只在 ccr_type_populate 重建后成立);
// 读侧 = loader 直读 + TYPE 段解析后的域/一致性硬校验(ccr_io.cr load 尾)。
-OFF_NS_ITEM : int = 28;
+OFF_NS_ITEM : int = 28
-g_v7_nod_sem : string, mut; // NOD 语义字段对象缓冲(ESZ_NOD_SEM/节点——loader 载入)
-g_v7_nod_meta : string, mut; // NOD 邻接域缓冲(ESZ_NOD_META/节点——EDG 守卫暂存同源)
-g_v7_nod_count : int, mut; // 对象缓冲记录数(= NOD 段节点数——load 后可用)
+g_v7_nod_sem : string, mut // NOD 语义字段对象缓冲(ESZ_NOD_SEM/节点——loader 载入)
+g_v7_nod_meta : string, mut // NOD 邻接域缓冲(ESZ_NOD_META/节点——EDG 守卫暂存同源)
+g_v7_nod_count : int, mut // 对象缓冲记录数(= NOD 段节点数——load 后可用)
// 节点面访问器(n = NOD 节点坐标 0..g_v7_nod_count-1):语义字段读
// g_v7_nod_sem、邻接索引读 g_v7_nod_meta——数值与 loader 解析(buf_read_*)
// 逐字节同(u32 字段 buf_read_u32 / 有符号 buf_read_i32 / s1 buf_read_i64)。
-fn nod_op(n: int) -> int { return buf_read_u32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_OP); }
-fn nod_dest(n: int) -> int { return buf_read_i32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_DEST); }
-fn nod_s1(n: int) -> int { return buf_read_i64(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_S1); }
-fn nod_s2(n: int) -> int { return buf_read_i32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_S2); }
-fn nod_s3(n: int) -> int { return buf_read_i32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_S3); }
-fn nod_tk(n: int) -> int { return buf_read_u32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_TK); }
+fn nod_op(n: int) -> int:
+ return buf_read_u32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_OP)
+fn nod_dest(n: int) -> int:
+ return buf_read_i32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_DEST)
+fn nod_s1(n: int) -> int:
+ return buf_read_i64(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_S1)
+fn nod_s2(n: int) -> int:
+ return buf_read_i32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_S2)
+fn nod_s3(n: int) -> int:
+ return buf_read_i32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_S3)
+fn nod_tk(n: int) -> int:
+ return buf_read_u32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_TK)
// R2 P6 Task 3(β):项索引读访问器——**i32**(-1 = 无项必须读到 -1;码槽的
// -1 在盘上是 u32 0xFFFFFFFF,两者语义不同,不得混用读法)。
-fn nod_item(n: int) -> int { return buf_read_i32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_ITEM); }
-fn nod_edge_first(n: int) -> int { return r64(g_v7_nod_meta, n * ESZ_NOD_META); }
-fn nod_edge_count(n: int) -> int { return r64(g_v7_nod_meta, n * ESZ_NOD_META + 8); }
+fn nod_item(n: int) -> int:
+ return buf_read_i32(g_v7_nod_sem, n * ESZ_NOD_SEM + OFF_NS_ITEM)
+fn nod_edge_first(n: int) -> int:
+ return r64(g_v7_nod_meta, n * ESZ_NOD_META)
+fn nod_edge_count(n: int) -> int:
+ return r64(g_v7_nod_meta, n * ESZ_NOD_META + 8)
// 边面访问器(e = 全局边下标 0..g_v7_edge_count-1):读 EDG 缓冲 8B 记录
// {to_nod u32 @0, kind u32 @4}(loader 打包 {to, kind×2^32} 的低/高 32 位)。
-fn v7_edge_to(e: int) -> int { return buf_read_u32(g_v7_edges, e * 8); }
-fn v7_edge_kind(e: int) -> int { return buf_read_u32(g_v7_edges, e * 8 + 4); }
+fn v7_edge_to(e: int) -> int:
+ return buf_read_u32(g_v7_edges, e * 8)
+fn v7_edge_kind(e: int) -> int:
+ return buf_read_u32(g_v7_edges, e * 8 + 4)
// 配方查询(薄封装):节点 n 的配方输入集 = 出边遍历——邻接索引区间
// [nod_edge_first(n), nod_edge_first(n) + nod_edge_count(n))(v7 邻接约定:
@@ -1055,14 +1165,16 @@ fn v7_edge_kind(e: int) -> int { return buf_read_u32(g_v7_edges, e * 8 + 4); }
// 体搬移,dump 输出逐字节同,判据 = test_ccr_v7 对象面断言 + --dump-objects
// 语料 byte-compare)。纯值消费方(未来验证器)= 访问器直读模式(M-1 注记:
// 访问器齐备后遍历即查询)。
-fn nod_inputs(n: int) {
- last : ., mut = nod_edge_first(n) + nod_edge_count(n);
- ej : ., mut = nod_edge_first(n);
- loop {
- if ej >= last { break; }
- print("edge "); print(int_str(n));
- print(" to "); print(int_str(v7_edge_to(ej)));
- print(" kind "); println(int_str(v7_edge_kind(ej)));
- ej = ej + 1;
- }
-}
+fn nod_inputs(n: int):
+ last : ., mut = nod_edge_first(n) + nod_edge_count(n)
+ ej : ., mut = nod_edge_first(n)
+ loop:
+ if ej >= last:
+ break
+ print("edge ")
+ print(int_str(n))
+ print(" to ")
+ print(int_str(v7_edge_to(ej)))
+ print(" kind ")
+ println(int_str(v7_edge_kind(ej)))
+ ej = ej + 1
diff --git a/src/lsp/analysis.cr b/src/lsp/analysis.cr
index 621b4f84..64e14b12 100644
--- a/src/lsp/analysis.cr
+++ b/src/lsp/analysis.cr
@@ -31,533 +31,540 @@
// ── 类型名(快照只读,不调 res_type_node——那会分配类型条目)──
// TY_* 常量 → 名字
-fn analysis_tyname(ty: int) -> string {
- if ty == TY_INT { return "int"; }
- if ty == TY_DEX { return "dex"; }
- if ty == TY_BOOL { return "bool"; }
- if ty == TY_STRING { return "string"; }
- if ty == TY_UNIT { return "unit"; }
- if ty == TY_NEVER { return "never"; }
- if ty == TY_CHAR { return "char"; }
- if ty == TI_DYN { return "dyn"; }
- return "?";
-}
+fn analysis_tyname(ty: int) -> string:
+ if ty == TY_INT:
+ return "int"
+ if ty == TY_DEX:
+ return "dex"
+ if ty == TY_BOOL:
+ return "bool"
+ if ty == TY_STRING:
+ return "string"
+ if ty == TY_UNIT:
+ return "unit"
+ if ty == TY_NEVER:
+ return "never"
+ if ty == TY_CHAR:
+ return "char"
+ if ty == TI_DYN:
+ return "dyn"
+ return "?"
// 类型表索引 → 名字(TYP_BASE / TYP_NAMED / TYP_REF / TYP_PTR / TYP_SLICE /
// TYP_ARRAY / TYP_GENERIC_APPLY / TYP_GENERIC_PARAM / TYP_TUPLE)
-fn analysis_type_name_ti(ti: int) -> string {
- k := get_type_kind(ti);
- if k < 0 { return "?"; }
- if k == TYP_BASE { return analysis_tyname(get_type_data(ti)); }
- if k == TYP_NAMED || k == TYP_GENERIC_PARAM { return istr_get(get_type_data(ti)); }
- if k == TYP_REF {
- out : string, mut = "&";
- if get_type_extra(ti) != 0 { out = out + "mut "; }
- out = out + analysis_type_name_ti(get_type_data(ti));
- return out;
- }
- if k == TYP_PTR {
- out : string, mut = "*";
- out = out + analysis_type_name_ti(get_type_data(ti));
- return out;
- }
- if k == TYP_SLICE {
- out : string, mut = "[]";
- out = out + analysis_type_name_ti(get_type_data(ti));
- return out;
- }
- if k == TYP_ARRAY {
- out : string, mut = analysis_type_name_ti(get_type_data(ti));
- out = out + "[";
- out = out + int_str(get_type_extra(ti));
- out = out + "]";
- return out;
- }
- if k == TYP_GENERIC_APPLY {
- return analysis_type_name_ti(get_type_data(ti));
- }
- if k == TYP_TUPLE {
- cnt := get_type_data(ti);
- out : string, mut = "(";
- e : ., mut = 0;
- loop {
- if e >= cnt { break; }
- if e > 0 { out = out + ", "; }
- out = out + analysis_type_name_ti(r64(g_gen_apply_data, (get_type_extra(ti) + e) * 8));
- e = e + 1;
- }
- out = out + ")";
- return out;
- }
- return "?";
-}
+fn analysis_type_name_ti(ti: int) -> string:
+ k := get_type_kind(ti)
+ if k < 0:
+ return "?"
+ if k == TYP_BASE:
+ return analysis_tyname(get_type_data(ti))
+ if k == TYP_NAMED || k == TYP_GENERIC_PARAM:
+ return istr_get(get_type_data(ti))
+ if k == TYP_REF:
+ out : string, mut = "&"
+ if get_type_extra(ti) != 0:
+ out = out + "mut "
+ out = out + analysis_type_name_ti(get_type_data(ti))
+ return out
+ if k == TYP_PTR:
+ out : string, mut = "*"
+ out = out + analysis_type_name_ti(get_type_data(ti))
+ return out
+ if k == TYP_SLICE:
+ out : string, mut = "[]"
+ out = out + analysis_type_name_ti(get_type_data(ti))
+ return out
+ if k == TYP_ARRAY:
+ out : string, mut = analysis_type_name_ti(get_type_data(ti))
+ out = out + "["
+ out = out + int_str(get_type_extra(ti))
+ out = out + "]"
+ return out
+ if k == TYP_GENERIC_APPLY:
+ return analysis_type_name_ti(get_type_data(ti))
+ if k == TYP_TUPLE:
+ cnt := get_type_data(ti)
+ out : string, mut = "("
+ e : ., mut = 0
+ loop:
+ if e >= cnt:
+ break
+ if e > 0:
+ out = out + ", "
+ out = out + analysis_type_name_ti(r64(g_gen_apply_data, (get_type_extra(ti) + e) * 8))
+ e = e + 1
+ out = out + ")"
+ return out
+ return "?"
// AST 类型节点 → 名字(快照只读;depth 防深链失控)
-fn analysis_type_node_name(node: int, depth: int) -> string {
- if node < 0 || node >= g_ast_count || depth > 8 { return "?"; }
- k := ast_kind(node);
- if k == 0 { return analysis_tyname(ast_type_val(node)); }
- if k == EXPR_IDENT { return istr_get(ast_int_val(node)); }
- if k == EXPR_REFTYPE {
- out : string, mut = "&";
- if ast_data(node) != 0 { out = out + "mut "; }
- out = out + analysis_type_node_name(ast_a(node), depth + 1);
- return out;
- }
- if k == EXPR_PTRTYPE {
- out : string, mut = "*";
- out = out + analysis_type_node_name(ast_a(node), depth + 1);
- return out;
- }
- if k == EXPR_OPTIONAL {
+fn analysis_type_node_name(node: int, depth: int) -> string:
+ if node < 0 || node >= g_ast_count || depth > 8:
+ return "?"
+ k := ast_kind(node)
+ if k == 0:
+ return analysis_tyname(ast_type_val(node))
+ if k == EXPR_IDENT:
+ return istr_get(ast_int_val(node))
+ if k == EXPR_REFTYPE:
+ out : string, mut = "&"
+ if ast_data(node) != 0:
+ out = out + "mut "
+ out = out + analysis_type_node_name(ast_a(node), depth + 1)
+ return out
+ if k == EXPR_PTRTYPE:
+ out : string, mut = "*"
+ out = out + analysis_type_node_name(ast_a(node), depth + 1)
+ return out
+ if k == EXPR_OPTIONAL:
// R2 P3 Task 4:`T?` 的悬停/补全显示(内层名 + "?")
- out : string, mut = "";
- out = out + analysis_type_node_name(ast_a(node), depth + 1);
- out = out + "?";
- return out;
- }
- if k == EXPR_ARRAY {
- out : string, mut = "[";
- out = out + analysis_type_node_name(ast_a(node), depth + 1);
- if ast_int_val(node) != 0 {
- out = out + ";";
- out = out + int_str(ast_int_val(node));
- }
- out = out + "]";
- return out;
- }
- if k == EXPR_GENERIC_APPLY {
- out : string, mut = istr_get(ast_a(node));
- out = out + "<";
- ac : ., mut = 0;
- an : ., mut = ast_b(node);
- loop {
- if ac >= ast_c(node) { break; }
- if ac > 0 { out = out + ", "; }
- out = out + analysis_type_node_name(an, depth + 1);
- ac = ac + 1;
- an = an + 1;
- }
- out = out + ">";
- return out;
- }
- return "?";
-}
+ out : string, mut = ""
+ out = out + analysis_type_node_name(ast_a(node), depth + 1)
+ out = out + "?"
+ return out
+ if k == EXPR_ARRAY:
+ out : string, mut = "["
+ out = out + analysis_type_node_name(ast_a(node), depth + 1)
+ if ast_int_val(node) != 0:
+ out = out + ";"
+ out = out + int_str(ast_int_val(node))
+ out = out + "]"
+ return out
+ if k == EXPR_GENERIC_APPLY:
+ out : string, mut = istr_get(ast_a(node))
+ out = out + "<"
+ ac : ., mut = 0
+ an : ., mut = ast_b(node)
+ loop:
+ if ac >= ast_c(node):
+ break
+ if ac > 0:
+ out = out + ", "
+ out = out + analysis_type_node_name(an, depth + 1)
+ ac = ac + 1
+ an = an + 1
+ out = out + ">"
+ return out
+ return "?"
// ── 令牌定位 ──
// 扫 g_tokens 找覆盖 (line, col)(0-based,col 为 UTF-16 code units)的令牌,
// 返回令牌索引;无则 -1。源码 lexer 的列按字节记录,定位时先转换回字节。
-fn analysis_token_at(line: int, col: int) -> int {
- if line < 0 || col < 0 { return -1; }
- tl : ., mut = line + 1;
- line_start := analysis_line_start(line);
- cursor := analysis_pos_of(line, col);
- tc : ., mut = cursor - line_start + 1;
- i : ., mut = 0;
- loop {
- if i >= g_token_count { return -1; }
- if r64(g_tokens, i * ESZ_TOKEN + OFF_TK_KIND) == T_EOF { return -1; }
- if r64(g_tokens, i * ESZ_TOKEN + OFF_TK_LINE) == tl {
- cl := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_COL);
- lex := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_LEXEME);
- w : ., mut = 1;
- if lex >= 0 { w = str_len(istr_get(lex)); }
- if tc >= cl && tc < cl + w { return i; }
- }
- i = i + 1;
- }
-}
+fn analysis_token_at(line: int, col: int) -> int:
+ if line < 0 || col < 0:
+ return -1
+ tl : ., mut = line + 1
+ line_start := analysis_line_start(line)
+ cursor := analysis_pos_of(line, col)
+ tc : ., mut = cursor - line_start + 1
+ i : ., mut = 0
+ loop:
+ if i >= g_token_count:
+ return -1
+ if r64(g_tokens, i * ESZ_TOKEN + OFF_TK_KIND) == T_EOF:
+ return -1
+ if r64(g_tokens, i * ESZ_TOKEN + OFF_TK_LINE) == tl:
+ cl := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_COL)
+ lex := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_LEXEME)
+ w : ., mut = 1
+ if lex >= 0:
+ w = str_len(istr_get(lex))
+ if tc >= cl && tc < cl + w:
+ return i
+ i = i + 1
// Return the byte offset of a zero-based source line.
-fn analysis_line_start(line: int) -> int {
- if line <= 0 { return 0; }
- sl := str_len(g_source);
- current : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= sl { return sl; }
- if load8(g_source, i) == 10 {
- current = current + 1;
- i = i + 1;
- if current >= line { return i; }
- } else { i = i + 1; }
- }
- return sl;
-}
+fn analysis_line_start(line: int) -> int:
+ if line <= 0:
+ return 0
+ sl := str_len(g_source)
+ current : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= sl:
+ return sl
+ if load8(g_source, i) == 10:
+ current = current + 1
+ i = i + 1
+ if current >= line:
+ return i
+ else:
+ i = i + 1
+ return sl
// Decode one UTF-8 sequence from g_source. Invalid bytes occupy one unit.
-fn analysis_utf8_next(pos: int, sl: int) -> int {
- if pos < 0 || pos >= sl { return 1; }
- b0 := load8(g_source, pos);
- if b0 < 128 { return 1; }
- if b0 < 224 && pos + 1 < sl {
- b1 := load8(g_source, pos + 1);
- if b1 >= 128 && b1 < 192 { return 2; }
- }
- if b0 < 240 && pos + 2 < sl {
- b1 := load8(g_source, pos + 1);
- b2 := load8(g_source, pos + 2);
- if b1 >= 128 && b1 < 192 && b2 >= 128 && b2 < 192 { return 3; }
- }
- if b0 >= 240 && b0 < 248 && pos + 3 < sl {
- b1 := load8(g_source, pos + 1);
- b2 := load8(g_source, pos + 2);
- b3 := load8(g_source, pos + 3);
- if b1 >= 128 && b1 < 192 && b2 >= 128 && b2 < 192 && b3 >= 128 && b3 < 192 { return 4; }
- }
- return 1;
-}
+fn analysis_utf8_next(pos: int, sl: int) -> int:
+ if pos < 0 || pos >= sl:
+ return 1
+ b0 := load8(g_source, pos)
+ if b0 < 128:
+ return 1
+ if b0 < 224 && pos + 1 < sl:
+ b1 := load8(g_source, pos + 1)
+ if b1 >= 128 && b1 < 192:
+ return 2
+ if b0 < 240 && pos + 2 < sl:
+ b1 := load8(g_source, pos + 1)
+ b2 := load8(g_source, pos + 2)
+ if b1 >= 128 && b1 < 192 && b2 >= 128 && b2 < 192:
+ return 3
+ if b0 >= 240 && b0 < 248 && pos + 3 < sl:
+ b1 := load8(g_source, pos + 1)
+ b2 := load8(g_source, pos + 2)
+ b3 := load8(g_source, pos + 3)
+ if b1 >= 128 && b1 < 192 && b2 >= 128 && b2 < 192 && b3 >= 128 && b3 < 192:
+ return 4
+ return 1
-fn analysis_utf8_cp(pos: int, adv: int) -> int {
- b0 := load8(g_source, pos);
- if adv == 1 { return b0; }
- if adv == 2 { return (b0 - 192) * 64 + load8(g_source, pos + 1) - 128; }
- if adv == 3 { return (b0 - 224) * 4096 + (load8(g_source, pos + 1) - 128) * 64 + load8(g_source, pos + 2) - 128; }
- return (b0 - 240) * 262144 + (load8(g_source, pos + 1) - 128) * 4096 + (load8(g_source, pos + 2) - 128) * 64 + load8(g_source, pos + 3) - 128;
-}
+fn analysis_utf8_cp(pos: int, adv: int) -> int:
+ b0 := load8(g_source, pos)
+ if adv == 1:
+ return b0
+ if adv == 2:
+ return (b0 - 192) * 64 + load8(g_source, pos + 1) - 128
+ if adv == 3:
+ return (b0 - 224) * 4096 + (load8(g_source, pos + 1) - 128) * 64 + load8(g_source, pos + 2) - 128
+ return (b0 - 240) * 262144 + (load8(g_source, pos + 1) - 128) * 4096 + (load8(g_source, pos + 2) - 128) * 64 + load8(g_source, pos + 3) - 128
-fn analysis_utf16_units(start: int, end: int) -> int {
- sl := str_len(g_source);
- p : ., mut = start;
- units : ., mut = 0;
- loop {
- if p >= end || p >= sl { break; }
- adv := analysis_utf8_next(p, sl);
- if p + adv > end { adv = 1; }
- cp := analysis_utf8_cp(p, adv);
- if cp >= 65536 { units = units + 2; } else { units = units + 1; }
- p = p + adv;
- }
- return units;
-}
+fn analysis_utf16_units(start: int, end: int) -> int:
+ sl := str_len(g_source)
+ p : ., mut = start
+ units : ., mut = 0
+ loop:
+ if p >= end || p >= sl:
+ break
+ adv := analysis_utf8_next(p, sl)
+ if p + adv > end:
+ adv = 1
+ cp := analysis_utf8_cp(p, adv)
+ if cp >= 65536:
+ units = units + 2
+ else:
+ units = units + 1
+ p = p + adv
+ return units
-fn analysis_source_byte(pos: int, sl: int) -> int {
- if pos < 0 || pos >= sl { return -1; }
- return load8(g_source, pos);
-}
+fn analysis_source_byte(pos: int, sl: int) -> int:
+ if pos < 0 || pos >= sl:
+ return -1
+ return load8(g_source, pos)
// ── 函数 hover ──
// EXPR_PARAM 节点 → 参数类型名
-fn analysis_param_type_name(pn: int) -> string {
- tn := ast_data(pn);
- if tn >= 0 && tn < g_ast_count && ast_kind(tn) != 0 { return analysis_type_node_name(tn, 0); }
- return analysis_tyname(ast_type_val(pn));
-}
+fn analysis_param_type_name(pn: int) -> string:
+ tn := ast_data(pn)
+ if tn >= 0 && tn < g_ast_count && ast_kind(tn) != 0:
+ return analysis_type_node_name(tn, 0)
+ return analysis_tyname(ast_type_val(pn))
// 函数返回类型名(EXPR_FN type_val 槽 = 返回类型节点;0 = 无 -> 声明)
-fn analysis_fn_ret_name(fi: int) -> string {
- fn_node := fi_ast_node(fi);
- if fn_node >= 0 && fn_node < g_ast_count {
- tn := ast_type_val(fn_node);
- if tn >= 0 && tn < g_ast_count {
- if ast_kind(tn) != 0 { return analysis_type_node_name(tn, 0); }
- return analysis_tyname(ast_type_val(tn));
- }
- }
- return analysis_tyname(fi_return_type(fi));
-}
+fn analysis_fn_ret_name(fi: int) -> string:
+ fn_node := fi_ast_node(fi)
+ if fn_node >= 0 && fn_node < g_ast_count:
+ tn := ast_type_val(fn_node)
+ if tn >= 0 && tn < g_ast_count:
+ if ast_kind(tn) != 0:
+ return analysis_type_node_name(tn, 0)
+ return analysis_tyname(ast_type_val(tn))
+ return analysis_tyname(fi_return_type(fi))
// 函数签名:"fn 名(参数类型, ...) -> 返回类型"
-fn analysis_hover_fn(fi: int) -> string {
- out : string, mut = "fn ";
- out = out + istr_get(fi_name(fi));
- out = out + "(";
- first_param : ., mut = -1;
- param_count : ., mut = 0;
- fn_node := fi_ast_node(fi);
- if fn_node >= 0 && fn_node < g_ast_count {
- first_param = ast_b(fn_node);
- param_count = ast_c(fn_node);
- }
- pi : ., mut = 0;
- pn : ., mut = first_param;
- loop {
- if pi >= param_count { break; }
- if pn < 0 || pn >= g_ast_count { break; }
- if pi > 0 { out = out + ", "; }
- if ast_kind(pn) == EXPR_PARAM { out = out + analysis_param_type_name(pn); }
- pi = pi + 1;
- pn = pn + 1;
+fn analysis_hover_fn(fi: int) -> string:
+ out : string, mut = "fn "
+ out = out + istr_get(fi_name(fi))
+ out = out + "("
+ first_param : ., mut = -1
+ param_count : ., mut = 0
+ fn_node := fi_ast_node(fi)
+ if fn_node >= 0 && fn_node < g_ast_count:
+ first_param = ast_b(fn_node)
+ param_count = ast_c(fn_node)
+ pi : ., mut = 0
+ pn : ., mut = first_param
+ loop:
+ if pi >= param_count:
+ break
+ if pn < 0 || pn >= g_ast_count:
+ break
+ if pi > 0:
+ out = out + ", "
+ if ast_kind(pn) == EXPR_PARAM:
+ out = out + analysis_param_type_name(pn)
+ pi = pi + 1
+ pn = pn + 1
// 参数节点不连续(类型节点插在中间)——顺延找下一个 EXPR_PARAM
- loop {
- if pn >= g_ast_count { break; }
- if ast_kind(pn) == EXPR_PARAM { break; }
- pn = pn + 1;
- }
- }
- out = out + ") -> ";
- out = out + analysis_fn_ret_name(fi);
- return out;
-}
+ loop:
+ if pn >= g_ast_count:
+ break
+ if ast_kind(pn) == EXPR_PARAM:
+ break
+ pn = pn + 1
+ out = out + ") -> "
+ out = out + analysis_fn_ret_name(fi)
+ return out
// 结构体 hover:"struct 名 { 字段: 类型, ... }"
-fn analysis_hover_struct(si: int) -> string {
- out : string, mut = "struct ";
- out = out + istr_get(si_name(si));
- out = out + " {";
- f : ., mut = 0;
- loop {
- if f >= si_field_count(si) { break; }
- out = out + " ";
- out = out + istr_get(si_field_name(si, f));
- out = out + ": ";
- tn := si_field_type_node(si, f);
- if tn >= 0 && tn < g_ast_count && ast_kind(tn) != 0 { out = out + analysis_type_node_name(tn, 0); }
- else { out = out + analysis_tyname(si_field_type(si, f)); }
- out = out + ",";
- f = f + 1;
- }
- out = out + " }";
- return out;
-}
+fn analysis_hover_struct(si: int) -> string:
+ out : string, mut = "struct "
+ out = out + istr_get(si_name(si))
+ out = out + " {"
+ f : ., mut = 0
+ loop:
+ if f >= si_field_count(si):
+ break
+ out = out + " "
+ out = out + istr_get(si_field_name(si, f))
+ out = out + ": "
+ tn := si_field_type_node(si, f)
+ if tn >= 0 && tn < g_ast_count && ast_kind(tn) != 0:
+ out = out + analysis_type_node_name(tn, 0)
+ else:
+ out = out + analysis_tyname(si_field_type(si, f))
+ out = out + ","
+ f = f + 1
+ out = out + " }"
+ return out
// 枚举 hover:"enum 名 { 变体, ... }"
-fn analysis_hover_enum(ei: int) -> string {
- out : string, mut = "enum ";
- out = out + istr_get(ei_name(ei));
- out = out + " {";
- v : ., mut = 0;
- loop {
- if v >= ei_variant_count(ei) { break; }
- out = out + " ";
- out = out + istr_get(ei_variant_name(ei, v));
- out = out + ",";
- v = v + 1;
- }
- out = out + " }";
- return out;
-}
+fn analysis_hover_enum(ei: int) -> string:
+ out : string, mut = "enum "
+ out = out + istr_get(ei_name(ei))
+ out = out + " {"
+ v : ., mut = 0
+ loop:
+ if v >= ei_variant_count(ei):
+ break
+ out = out + " "
+ out = out + istr_get(ei_variant_name(ei, v))
+ out = out + ","
+ v = v + 1
+ out = out + " }"
+ return out
// ── 局部变量(AST 反查)──
// 查声明 name_ni 的 AST 节点:EXPR_LET(a=名)/ EXPR_PARAM(a=名)/
// EXPR_FOR(a=变量名);取 (line, col) <= 查询位置(0-based 转 1-based)
// 中最近的一个(近似作用域)。无则 -1。
-fn analysis_var_decl(name_ni: int, line: int, col: int) -> int {
- tl : ., mut = line + 1;
- tc := analysis_pos_of(line, col) - analysis_line_start(line) + 1;
- best : ., mut = -1;
- bl : ., mut = -1;
- bc : ., mut = -1;
- i : ., mut = 0;
- loop {
- if i >= g_ast_count { break; }
- k := ast_kind(i);
- if k == EXPR_LET || k == EXPR_PARAM || k == EXPR_FOR {
- if ast_a(i) == name_ni {
- ln := ast_line(i);
- cl := ast_col(i);
- if ln < tl || (ln == tl && cl <= tc) {
- if ln > bl || (ln == bl && cl > bc) {
- best = i;
- bl = ln;
- bc = cl;
- }
- }
- }
- }
- i = i + 1;
- }
- return best;
-}
+fn analysis_var_decl(name_ni: int, line: int, col: int) -> int:
+ tl : ., mut = line + 1
+ tc := analysis_pos_of(line, col) - analysis_line_start(line) + 1
+ best : ., mut = -1
+ bl : ., mut = -1
+ bc : ., mut = -1
+ i : ., mut = 0
+ loop:
+ if i >= g_ast_count:
+ break
+ k := ast_kind(i)
+ if k == EXPR_LET || k == EXPR_PARAM || k == EXPR_FOR:
+ if ast_a(i) == name_ni:
+ ln := ast_line(i)
+ cl := ast_col(i)
+ if ln < tl || (ln == tl && cl <= tc):
+ if ln > bl || (ln == bl && cl > bc):
+ best = i
+ bl = ln
+ bc = cl
+ i = i + 1
+ return best
// 声明节点 → 变量类型名
-fn analysis_var_type(vd: int, depth: int) -> string {
- if vd < 0 || depth > 8 { return "?"; }
- k := ast_kind(vd);
- if k == EXPR_PARAM {
- return analysis_param_type_name(vd);
- }
- if k == EXPR_FOR { return "int"; }
- if k == EXPR_LET {
- tn := ast_b(vd);
- if tn >= 0 && tn < g_ast_count {
- if ast_kind(tn) != 0 { return analysis_type_node_name(tn, 0); }
- return analysis_tyname(ast_type_val(tn));
- }
- return analysis_type_of_expr(ast_c(vd), depth + 1);
- }
- return "?";
-}
+fn analysis_var_type(vd: int, depth: int) -> string:
+ if vd < 0 || depth > 8:
+ return "?"
+ k := ast_kind(vd)
+ if k == EXPR_PARAM:
+ return analysis_param_type_name(vd)
+ if k == EXPR_FOR:
+ return "int"
+ if k == EXPR_LET:
+ tn := ast_b(vd)
+ if tn >= 0 && tn < g_ast_count:
+ if ast_kind(tn) != 0:
+ return analysis_type_node_name(tn, 0)
+ return analysis_tyname(ast_type_val(tn))
+ return analysis_type_of_expr(ast_c(vd), depth + 1)
+ return "?"
// 表达式 → 类型名(轻量恢复:字面量/调用/标识符转发/引用;depth 防环)
-fn analysis_type_of_expr(node: int, depth: int) -> string {
- if node < 0 || depth > 8 { return "?"; }
- k := ast_kind(node);
- if k == EXPR_INT { return "int"; }
- if k == EXPR_DEX { return "dex"; }
- if k == EXPR_BOOL { return "bool"; }
- if k == EXPR_STRING { return "string"; }
- if k == EXPR_CHAR { return "char"; }
- if k == EXPR_CALL {
- f := ast_a(node);
- if f >= 0 && ast_kind(f) == EXPR_IDENT {
- fi := find_func(ast_int_val(f));
- if fi >= 0 { return analysis_fn_ret_name(fi); }
- }
- return "?";
- }
- if k == EXPR_IDENT {
- vd := analysis_var_decl(ast_int_val(node), ast_line(node) - 1, ast_col(node) - 1);
- if vd >= 0 { return analysis_var_type(vd, depth + 1); }
- return "?";
- }
- if k == EXPR_UNARY && ast_c(node) == UOP_REF {
- out : string, mut = "&";
- out = out + analysis_type_of_expr(ast_a(node), depth + 1);
- return out;
- }
- return "?";
-}
+fn analysis_type_of_expr(node: int, depth: int) -> string:
+ if node < 0 || depth > 8:
+ return "?"
+ k := ast_kind(node)
+ if k == EXPR_INT:
+ return "int"
+ if k == EXPR_DEX:
+ return "dex"
+ if k == EXPR_BOOL:
+ return "bool"
+ if k == EXPR_STRING:
+ return "string"
+ if k == EXPR_CHAR:
+ return "char"
+ if k == EXPR_CALL:
+ f := ast_a(node)
+ if f >= 0 && ast_kind(f) == EXPR_IDENT:
+ fi := find_func(ast_int_val(f))
+ if fi >= 0:
+ return analysis_fn_ret_name(fi)
+ return "?"
+ if k == EXPR_IDENT:
+ vd := analysis_var_decl(ast_int_val(node), ast_line(node) - 1, ast_col(node) - 1)
+ if vd >= 0:
+ return analysis_var_type(vd, depth + 1)
+ return "?"
+ if k == EXPR_UNARY && ast_c(node) == UOP_REF:
+ out : string, mut = "&"
+ out = out + analysis_type_of_expr(ast_a(node), depth + 1)
+ return out
+ return "?"
// ── hover ──
// 位置 → hover 内容:函数签名 / 变量类型 / 结构体字段 / 枚举变体;无结果空串
-fn analysis_hover(line: int, col: int) -> string {
- ti := analysis_token_at(line, col);
- if ti < 0 { return ""; }
- if r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_KIND) != T_IDENT { return ""; }
- name_ni := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_LEXEME);
+fn analysis_hover(line: int, col: int) -> string:
+ ti := analysis_token_at(line, col)
+ if ti < 0:
+ return ""
+ if r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_KIND) != T_IDENT:
+ return ""
+ name_ni := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_LEXEME)
// 局部变量/参数优先(遮蔽函数/类型名)
- vd := analysis_var_decl(name_ni, line, col);
- if vd >= 0 {
- t := analysis_var_type(vd, 0);
- if str_len(t) > 0 { return t; }
- }
+ vd := analysis_var_decl(name_ni, line, col)
+ if vd >= 0:
+ t := analysis_var_type(vd, 0)
+ if str_len(t) > 0:
+ return t
// 函数
- fi := find_func(name_ni);
- if fi >= 0 { return analysis_hover_fn(fi); }
+ fi := find_func(name_ni)
+ if fi >= 0:
+ return analysis_hover_fn(fi)
// 结构体
- si := find_struct_by_name(name_ni);
- if si >= 0 { return analysis_hover_struct(si); }
+ si := find_struct_by_name(name_ni)
+ if si >= 0:
+ return analysis_hover_struct(si)
// 枚举
- ei := find_enum(name_ni);
- if ei >= 0 { return analysis_hover_enum(ei); }
- return "";
-}
+ ei := find_enum(name_ni)
+ if ei >= 0:
+ return analysis_hover_enum(ei)
+ return ""
// ── definition ──
// 扫 g_tokens 找声明关键字(T_STRUCT/T_ENUM)后紧跟同名 T_IDENT 的令牌;
// 返回该名字令牌索引,无则 -1(g_ast 无结构体/枚举声明节点,见文件头注)
-fn analysis_decl_tok(kw: int, name_ni: int) -> int {
- i : ., mut = 0;
- loop {
- if i + 1 >= g_token_count { return -1; }
- if r64(g_tokens, i * ESZ_TOKEN + OFF_TK_KIND) == kw {
- if r64(g_tokens, (i + 1) * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT &&
- r64(g_tokens, (i + 1) * ESZ_TOKEN + OFF_TK_LEXEME) == name_ni {
- return i + 1;
- }
- }
- i = i + 1;
- }
-}
+fn analysis_decl_tok(kw: int, name_ni: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i + 1 >= g_token_count:
+ return -1
+ if r64(g_tokens, i * ESZ_TOKEN + OFF_TK_KIND) == kw:
+ if r64(g_tokens, (i + 1) * ESZ_TOKEN + OFF_TK_KIND) == T_IDENT && r64(g_tokens, (i + 1) * ESZ_TOKEN + OFF_TK_LEXEME) == name_ni:
+ return i + 1
+ i = i + 1
// 1-based 行 → 文件路径(g_line_fileid → file_id → g_files);兜底主文件
-fn analysis_path_for_line(ln1: int) -> string {
- fid : ., mut = -1;
- if ln1 >= 1 && ln1 - 1 < g_line_count { fid = r64(g_line_fileid, (ln1 - 1) * 8); }
- if fid < 0 && g_file_count > 0 { fid = r64(g_files, 0); }
- i : ., mut = 0;
- loop {
- if i >= g_file_count { break; }
- if r64(g_files, i * 16) == fid {
- p := load_str_ptr(g_files, i * 16 + 8);
- if str_len(p) > 0 { return p; }
- }
- i = i + 1;
- }
- return "";
-}
+fn analysis_path_for_line(ln1: int) -> string:
+ fid : ., mut = -1
+ if ln1 >= 1 && ln1 - 1 < g_line_count:
+ fid = r64(g_line_fileid, (ln1 - 1) * 8)
+ if fid < 0 && g_file_count > 0:
+ fid = r64(g_files, 0)
+ i : ., mut = 0
+ loop:
+ if i >= g_file_count:
+ break
+ if r64(g_files, i * 16) == fid:
+ p := load_str_ptr(g_files, i * 16 + 8)
+ if str_len(p) > 0:
+ return p
+ i = i + 1
+ return ""
// 1-based 行 → 所在段在主文件后的行偏移(拼接坐标 → 目标文件自身坐标)
-fn analysis_line_offset(ln1: int) -> int {
- fid : ., mut = -1;
- if ln1 >= 1 && ln1 - 1 < g_line_count { fid = r64(g_line_fileid, (ln1 - 1) * 8); }
- if fid < 0 { return 0; }
- i : ., mut = 1;
- loop {
- if i >= g_seg_count { break; }
- if r64(g_seg_fileids, i * 8) == fid {
- limit := r64(g_seg_starts, i * 8);
- off_lines : ., mut = 0;
- pos : ., mut = 0;
- loop {
- if pos >= limit { break; }
- if load8(g_source, pos) == 10 { off_lines = off_lines + 1; }
- pos = pos + 1;
- }
- return off_lines;
- }
- i = i + 1;
- }
- return 0; // 主文件(段 0):偏移 0
-}
+fn analysis_line_offset(ln1: int) -> int:
+ fid : ., mut = -1
+ if ln1 >= 1 && ln1 - 1 < g_line_count:
+ fid = r64(g_line_fileid, (ln1 - 1) * 8)
+ if fid < 0:
+ return 0
+ i : ., mut = 1
+ loop:
+ if i >= g_seg_count:
+ break
+ if r64(g_seg_fileids, i * 8) == fid:
+ limit := r64(g_seg_starts, i * 8)
+ off_lines : ., mut = 0
+ pos : ., mut = 0
+ loop:
+ if pos >= limit:
+ break
+ if load8(g_source, pos) == 10:
+ off_lines = off_lines + 1
+ pos = pos + 1
+ return off_lines
+ i = i + 1
+ return 0 // 主文件(段 0):偏移 0
// 声明位置(1-based 拼接坐标)→ Location JSON;行/列转 0-based + 段偏移还原。
// uri 经 lsp_json_escape_str 转义(lsp.cr,同翻译单元——concat 顺序无关)。
-fn analysis_def_json(ln1: int, cl1: int) -> string {
- off := analysis_line_offset(ln1);
- line0 : ., mut = ln1 - 1 - off;
- line_start := analysis_line_start(ln1 - 1);
- decl_pos := line_start + cl1 - 1;
- col0 := analysis_utf16_units(line_start, decl_pos);
- uri : string, mut = "file://";
- uri = uri + analysis_path_for_line(ln1);
- out : string, mut = "{\"uri\":";
- out = out + lsp_json_escape_str(uri);
- out = out + ",\"range\":{\"start\":{\"line\":";
- out = out + int_str(line0);
- out = out + ",\"character\":";
- out = out + int_str(col0);
- out = out + "},\"end\":{\"line\":";
- out = out + int_str(line0);
- out = out + ",\"character\":";
- adv := analysis_utf8_next(decl_pos, str_len(g_source));
- out = out + int_str(analysis_utf16_units(line_start, decl_pos + adv));
- out = out + "}}}";
- return out;
-}
+fn analysis_def_json(ln1: int, cl1: int) -> string:
+ off := analysis_line_offset(ln1)
+ line0 : ., mut = ln1 - 1 - off
+ line_start := analysis_line_start(ln1 - 1)
+ decl_pos := line_start + cl1 - 1
+ col0 := analysis_utf16_units(line_start, decl_pos)
+ uri : string, mut = "file://"
+ uri = uri + analysis_path_for_line(ln1)
+ out : string, mut = "{\"uri\":"
+ out = out + lsp_json_escape_str(uri)
+ out = out + ",\"range\":{\"start\":{\"line\":"
+ out = out + int_str(line0)
+ out = out + ",\"character\":"
+ out = out + int_str(col0)
+ out = out + "},\"end\":{\"line\":"
+ out = out + int_str(line0)
+ out = out + ",\"character\":"
+ adv := analysis_utf8_next(decl_pos, str_len(g_source))
+ out = out + int_str(analysis_utf16_units(line_start, decl_pos + adv))
+ out = out + "}}}"
+ return out
// 位置 → Location JSON({"uri","range"});无结果空串
-fn analysis_definition(line: int, col: int) -> string {
- ti := analysis_token_at(line, col);
- if ti < 0 { return ""; }
- if r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_KIND) != T_IDENT { return ""; }
- name_ni := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_LEXEME);
+fn analysis_definition(line: int, col: int) -> string:
+ ti := analysis_token_at(line, col)
+ if ti < 0:
+ return ""
+ if r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_KIND) != T_IDENT:
+ return ""
+ name_ni := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_LEXEME)
// 局部变量/参数
- vd := analysis_var_decl(name_ni, line, col);
- if vd >= 0 { return analysis_def_json(ast_line(vd), ast_col(vd)); }
+ vd := analysis_var_decl(name_ni, line, col)
+ if vd >= 0:
+ return analysis_def_json(ast_line(vd), ast_col(vd))
// 函数
- fi := find_func(name_ni);
- if fi >= 0 {
- dfn := analysis_decl_tok(T_FN, name_ni);
- if dfn >= 0 {
+ fi := find_func(name_ni)
+ if fi >= 0:
+ dfn := analysis_decl_tok(T_FN, name_ni)
+ if dfn >= 0:
return analysis_def_json(r64(g_tokens, dfn * ESZ_TOKEN + OFF_TK_LINE),
- r64(g_tokens, dfn * ESZ_TOKEN + OFF_TK_COL));
- }
- return "";
- }
+ r64(g_tokens, dfn * ESZ_TOKEN + OFF_TK_COL))
+ return ""
// 结构体 / 枚举(令牌反查声明)
- if find_struct_by_name(name_ni) >= 0 {
- d := analysis_decl_tok(T_STRUCT, name_ni);
- if d >= 0 {
+ if find_struct_by_name(name_ni) >= 0:
+ d := analysis_decl_tok(T_STRUCT, name_ni)
+ if d >= 0:
return analysis_def_json(r64(g_tokens, d * ESZ_TOKEN + OFF_TK_LINE),
- r64(g_tokens, d * ESZ_TOKEN + OFF_TK_COL));
- }
- }
- if find_enum(name_ni) >= 0 {
- d := analysis_decl_tok(T_ENUM, name_ni);
- if d >= 0 {
+ r64(g_tokens, d * ESZ_TOKEN + OFF_TK_COL))
+ if find_enum(name_ni) >= 0:
+ d := analysis_decl_tok(T_ENUM, name_ni)
+ if d >= 0:
return analysis_def_json(r64(g_tokens, d * ESZ_TOKEN + OFF_TK_LINE),
- r64(g_tokens, d * ESZ_TOKEN + OFF_TK_COL));
- }
- }
- return "";
-}
+ r64(g_tokens, d * ESZ_TOKEN + OFF_TK_COL))
+ return ""
// ── completion(Task 5)──────────────────────────────────────
// 位置 → 前缀(光标前最近标识符;@ 后为 @ 内建上下文)→ 候选过滤 → JSON。
@@ -573,233 +580,452 @@ fn analysis_definition(line: int, col: int) -> string {
// (line, col)(0-based,col 为 UTF-16 code units)→ g_source 字节偏移。
// 光标落在 surrogate pair 中间时钳到该 code point 起点。
-fn analysis_pos_of(line: int, col: int) -> int {
- sl := str_len(g_source);
- if line < 0 { return 0; }
- start := analysis_line_start(line);
- p : ., mut = start;
- units : ., mut = 0;
- want : ., mut = col;
- if want < 0 { want = 0; }
- loop {
- if p >= sl || load8(g_source, p) == 10 || units >= want { break; }
- adv := analysis_utf8_next(p, sl);
- cp := analysis_utf8_cp(p, adv);
- next_units : ., mut = 1;
- if cp >= 65536 { next_units = 2; }
- if units + next_units > want { break; }
- p = p + adv;
- units = units + next_units;
- }
- return p;
-}
+fn analysis_pos_of(line: int, col: int) -> int:
+ sl := str_len(g_source)
+ if line < 0:
+ return 0
+ start := analysis_line_start(line)
+ p : ., mut = start
+ units : ., mut = 0
+ want : ., mut = col
+ if want < 0:
+ want = 0
+ loop:
+ if p >= sl || load8(g_source, p) == 10 || units >= want:
+ break
+ adv := analysis_utf8_next(p, sl)
+ cp := analysis_utf8_cp(p, adv)
+ next_units : ., mut = 1
+ if cp >= 65536:
+ next_units = 2
+ if units + next_units > want:
+ break
+ p = p + adv
+ units = units + next_units
+ return p
// pos 前连续标识符字符(字母/数字/_)的起点偏移
-fn analysis_prefix_start(pos: int) -> int {
- s : ., mut = pos;
- loop {
- if s <= 0 { break; }
- if is_ident_char(load8(g_source, s - 1)) == 0 { break; }
- s = s - 1;
- }
- return s;
-}
+fn analysis_prefix_start(pos: int) -> int:
+ s : ., mut = pos
+ loop:
+ if s <= 0:
+ break
+ if is_ident_char(load8(g_source, s - 1)) == 0:
+ break
+ s = s - 1
+ return s
// g_source 字节段 → 稳定堆字符串(前缀是暂态字节范围,需复制)
-fn analysis_sub_copy(start: int, end: int) -> string {
- n := end - start;
- s := alloc(n + 1);
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- store8(s, i, load8(g_source, start + i));
- i = i + 1;
- }
- store8(s, n, 0);
- return s;
-}
+fn analysis_sub_copy(start: int, end: int) -> string:
+ n := end - start
+ s := alloc(n + 1)
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ store8(s, i, load8(g_source, start + i))
+ i = i + 1
+ store8(s, n, 0)
+ return s
// name 是否以 prefix 开头(空前缀恒真;大小写不敏感——LSP 惯例)
-fn analysis_has_prefix(name: string, prefix: string) -> int {
- pl := str_len(prefix);
- if pl == 0 { return 1; }
- if str_len(name) < pl { return 0; }
- i : ., mut = 0;
- loop {
- if i >= pl { break; }
- nc := load8(name, i);
- pc := load8(prefix, i);
- if nc >= 65 && nc <= 90 { nc = nc + 32; }
- if pc >= 65 && pc <= 90 { pc = pc + 32; }
- if nc != pc { return 0; }
- i = i + 1;
- }
- return 1;
-}
+fn analysis_has_prefix(name: string, prefix: string) -> int:
+ pl := str_len(prefix)
+ if pl == 0:
+ return 1
+ if str_len(name) < pl:
+ return 0
+ i : ., mut = 0
+ loop:
+ if i >= pl:
+ break
+ nc := load8(name, i)
+ pc := load8(prefix, i)
+ if nc >= 65 && nc <= 90:
+ nc = nc + 32
+ if pc >= 65 && pc <= 90:
+ pc = pc + 32
+ if nc != pc:
+ return 0
+ i = i + 1
+ return 1
// 单条补全项 JSON:{"label":..., "kind":N}
-fn analysis_citem(name: string, kind: int) -> string {
- out : string, mut = "{\"label\":";
- out = out + lsp_json_escape_str(name);
- out = out + ",\"kind\":";
- out = out + int_str(kind);
- out = out + "}";
- return out;
-}
+fn analysis_citem(name: string, kind: int) -> string:
+ out : string, mut = "{\"label\":"
+ out = out + lsp_json_escape_str(name)
+ out = out + ",\"kind\":"
+ out = out + int_str(kind)
+ out = out + "}"
+ return out
// 关键字候选 JSON(lexer.cr lookup_keyword() 字面量清单,唯一真源;kind=14)。
// 命中的项以逗号连接(无命中返回空串——调用方拼进 items 数组)。
-fn analysis_kw_items(prefix: string) -> string {
- out : string, mut = "";
- first : ., mut = 1;
- if analysis_has_prefix("fn", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("fn", 14); first = 0; }
- if analysis_has_prefix("mut", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("mut", 14); first = 0; }
- if analysis_has_prefix("return", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("return", 14); first = 0; }
- if analysis_has_prefix("if", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("if", 14); first = 0; }
- if analysis_has_prefix("else", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("else", 14); first = 0; }
- if analysis_has_prefix("loop", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("loop", 14); first = 0; }
- if analysis_has_prefix("while", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("while", 14); first = 0; }
- if analysis_has_prefix("for", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("for", 14); first = 0; }
- if analysis_has_prefix("break", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("break", 14); first = 0; }
- if analysis_has_prefix("continue", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("continue", 14); first = 0; }
- if analysis_has_prefix("true", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("true", 14); first = 0; }
- if analysis_has_prefix("false", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("false", 14); first = 0; }
- if analysis_has_prefix("struct", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("struct", 14); first = 0; }
- if analysis_has_prefix("enum", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("enum", 14); first = 0; }
- if analysis_has_prefix("extern", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("extern", 14); first = 0; }
- if analysis_has_prefix("impl", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("impl", 14); first = 0; }
- if analysis_has_prefix("match", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("match", 14); first = 0; }
- if analysis_has_prefix("import", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("import", 14); first = 0; }
- if analysis_has_prefix("pub", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("pub", 14); first = 0; }
- if analysis_has_prefix("go", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("go", 14); first = 0; }
- if analysis_has_prefix("await", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("await", 14); first = 0; }
- if analysis_has_prefix("unsafe", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("unsafe", 14); first = 0; }
- if analysis_has_prefix("flow", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("flow", 14); first = 0; }
- if analysis_has_prefix("yield", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("yield", 14); first = 0; }
- if analysis_has_prefix("interface", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("interface", 14); first = 0; }
- if analysis_has_prefix("type", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("type", 14); first = 0; }
- if analysis_has_prefix("mod", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("mod", 14); first = 0; }
- if analysis_has_prefix("as", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("as", 14); first = 0; }
- if analysis_has_prefix("auto", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("auto", 14); first = 0; }
- if analysis_has_prefix("fileid", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("fileid", 14); first = 0; }
- if analysis_has_prefix("move", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("move", 14); first = 0; }
- if analysis_has_prefix("in", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("in", 14); first = 0; }
- if analysis_has_prefix("None", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("None", 14); first = 0; }
- if analysis_has_prefix("Some", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("Some", 14); first = 0; }
- if analysis_has_prefix("unit", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("unit", 14); first = 0; }
- return out;
-}
+fn analysis_kw_items(prefix: string) -> string:
+ out : string, mut = ""
+ first : ., mut = 1
+ if analysis_has_prefix("fn", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("fn", 14)
+ first = 0
+ if analysis_has_prefix("mut", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("mut", 14)
+ first = 0
+ if analysis_has_prefix("return", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("return", 14)
+ first = 0
+ if analysis_has_prefix("if", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("if", 14)
+ first = 0
+ if analysis_has_prefix("else", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("else", 14)
+ first = 0
+ if analysis_has_prefix("loop", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("loop", 14)
+ first = 0
+ if analysis_has_prefix("while", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("while", 14)
+ first = 0
+ if analysis_has_prefix("for", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("for", 14)
+ first = 0
+ if analysis_has_prefix("break", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("break", 14)
+ first = 0
+ if analysis_has_prefix("continue", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("continue", 14)
+ first = 0
+ if analysis_has_prefix("true", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("true", 14)
+ first = 0
+ if analysis_has_prefix("false", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("false", 14)
+ first = 0
+ if analysis_has_prefix("struct", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("struct", 14)
+ first = 0
+ if analysis_has_prefix("enum", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("enum", 14)
+ first = 0
+ if analysis_has_prefix("extern", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("extern", 14)
+ first = 0
+ if analysis_has_prefix("impl", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("impl", 14)
+ first = 0
+ if analysis_has_prefix("match", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("match", 14)
+ first = 0
+ if analysis_has_prefix("import", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("import", 14)
+ first = 0
+ if analysis_has_prefix("pub", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("pub", 14)
+ first = 0
+ if analysis_has_prefix("go", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("go", 14)
+ first = 0
+ if analysis_has_prefix("await", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("await", 14)
+ first = 0
+ if analysis_has_prefix("unsafe", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("unsafe", 14)
+ first = 0
+ if analysis_has_prefix("flow", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("flow", 14)
+ first = 0
+ if analysis_has_prefix("yield", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("yield", 14)
+ first = 0
+ if analysis_has_prefix("interface", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("interface", 14)
+ first = 0
+ if analysis_has_prefix("type", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("type", 14)
+ first = 0
+ if analysis_has_prefix("mod", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("mod", 14)
+ first = 0
+ if analysis_has_prefix("as", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("as", 14)
+ first = 0
+ if analysis_has_prefix("auto", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("auto", 14)
+ first = 0
+ if analysis_has_prefix("fileid", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("fileid", 14)
+ first = 0
+ if analysis_has_prefix("move", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("move", 14)
+ first = 0
+ if analysis_has_prefix("in", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("in", 14)
+ first = 0
+ if analysis_has_prefix("None", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("None", 14)
+ first = 0
+ if analysis_has_prefix("Some", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("Some", 14)
+ first = 0
+ if analysis_has_prefix("unit", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("unit", 14)
+ first = 0
+ return out
// @ 内建候选 JSON(checker.cr EXPR_AT 分发 14 个 + parser.cr @ffi,唯一真源;
// kind=3 Function——均以内建函数方式调用)。label 不含 '@'。
-fn analysis_at_items(prefix: string) -> string {
- out : string, mut = "";
- first : ., mut = 1;
- if analysis_has_prefix("sizeOf", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("sizeOf", 3); first = 0; }
- if analysis_has_prefix("addr", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("addr", 3); first = 0; }
- if analysis_has_prefix("alignOf", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("alignOf", 3); first = 0; }
- if analysis_has_prefix("fields", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("fields", 3); first = 0; }
- if analysis_has_prefix("hasField", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("hasField", 3); first = 0; }
- if analysis_has_prefix("field", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("field", 3); first = 0; }
- if analysis_has_prefix("typeInfo", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("typeInfo", 3); first = 0; }
- if analysis_has_prefix("raw_int", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("raw_int", 3); first = 0; }
- if analysis_has_prefix("comptime", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("comptime", 3); first = 0; }
- if analysis_has_prefix("inline", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("inline", 3); first = 0; }
- if analysis_has_prefix("NoBoundsCheck", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("NoBoundsCheck", 3); first = 0; }
- if analysis_has_prefix("fast", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("fast", 3); first = 0; }
- if analysis_has_prefix("unroll", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("unroll", 3); first = 0; }
- if analysis_has_prefix("section", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("section", 3); first = 0; }
- if analysis_has_prefix("hotpatch", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("hotpatch", 3); first = 0; }
- if analysis_has_prefix("ffi", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("ffi", 3); first = 0; }
+fn analysis_at_items(prefix: string) -> string:
+ out : string, mut = ""
+ first : ., mut = 1
+ if analysis_has_prefix("sizeOf", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("sizeOf", 3)
+ first = 0
+ if analysis_has_prefix("addr", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("addr", 3)
+ first = 0
+ if analysis_has_prefix("alignOf", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("alignOf", 3)
+ first = 0
+ if analysis_has_prefix("fields", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("fields", 3)
+ first = 0
+ if analysis_has_prefix("hasField", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("hasField", 3)
+ first = 0
+ if analysis_has_prefix("field", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("field", 3)
+ first = 0
+ if analysis_has_prefix("typeInfo", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("typeInfo", 3)
+ first = 0
+ if analysis_has_prefix("raw_int", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("raw_int", 3)
+ first = 0
+ if analysis_has_prefix("comptime", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("comptime", 3)
+ first = 0
+ if analysis_has_prefix("inline", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("inline", 3)
+ first = 0
+ if analysis_has_prefix("NoBoundsCheck", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("NoBoundsCheck", 3)
+ first = 0
+ if analysis_has_prefix("fast", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("fast", 3)
+ first = 0
+ if analysis_has_prefix("unroll", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("unroll", 3)
+ first = 0
+ if analysis_has_prefix("section", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("section", 3)
+ first = 0
+ if analysis_has_prefix("hotpatch", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("hotpatch", 3)
+ first = 0
+ if analysis_has_prefix("ffi", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("ffi", 3)
+ first = 0
// 2(a) 视图内建(`@ptr_of`/`@str_of`):语言面新增内建必须同批进 LSP 表——
// 由 `tests/bootstrap/…` 的 L1/L2/L3(真源枚举 · 双向差集)机械拦:缺一名即 L2 红。
- if analysis_has_prefix("ptr_of", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("ptr_of", 3); first = 0; }
- if analysis_has_prefix("str_of", prefix) != 0 { if first == 0 { out = out + ","; } out = out + analysis_citem("str_of", 3); first = 0; }
- return out;
-}
+ if analysis_has_prefix("ptr_of", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("ptr_of", 3)
+ first = 0
+ if analysis_has_prefix("str_of", prefix) != 0:
+ if first == 0:
+ out = out + ","
+ out = out + analysis_citem("str_of", 3)
+ first = 0
+ return out
// 候选缓冲追加(去重:str_intern 保证同名同 name_ni);已存在返回 0
-fn analysis_cand_add(cand: string, count: int, ni: int, kind: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= count { break; }
- if r64(cand, i * 16) == ni { return 0; }
- i = i + 1;
- }
- w64(cand, count * 16, ni);
- w64(cand, count * 16 + 8, kind);
- return 1;
-}
+fn analysis_cand_add(cand: string, count: int, ni: int, kind: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= count:
+ break
+ if r64(cand, i * 16) == ni:
+ return 0
+ i = i + 1
+ w64(cand, count * 16, ni)
+ w64(cand, count * 16 + 8, kind)
+ return 1
// SYM_* 种类 → CompletionItemKind 规范值(FN/SO_FN→3 函数、
// GLOBAL/LOCAL/PARAM→6 变量、TYPE→22 结构体、MODULE→9 模块)
-fn analysis_sym_item_kind(sk: int) -> int {
- if sk == SYM_FN || sk == SYM_SO_FN { return 3; }
- if sk == SYM_GLOBAL || sk == SYM_LOCAL || sk == SYM_PARAM { return 6; }
- if sk == SYM_TYPE { return 22; }
- return 9;
-}
+fn analysis_sym_item_kind(sk: int) -> int:
+ if sk == SYM_FN || sk == SYM_SO_FN:
+ return 3
+ if sk == SYM_GLOBAL || sk == SYM_LOCAL || sk == SYM_PARAM:
+ return 6
+ if sk == SYM_TYPE:
+ return 22
+ return 9
// 位置 → completion JSON {"items":[...]}(快照查询,不触发检查)
-fn analysis_completion(line: int, col: int) -> string {
- pos := analysis_pos_of(line, col);
- pstart := analysis_prefix_start(pos);
- at_ctx : ., mut = 0;
- if pstart > 0 && load8(g_source, pstart - 1) == 64 { at_ctx = 1; }
- prefix := analysis_sub_copy(pstart, pos);
- out : string, mut = "{\"items\":[";
- if at_ctx != 0 {
- out = out + analysis_at_items(prefix);
- } else {
- out = out + analysis_kw_items(prefix);
+fn analysis_completion(line: int, col: int) -> string:
+ pos := analysis_pos_of(line, col)
+ pstart := analysis_prefix_start(pos)
+ at_ctx : ., mut = 0
+ if pstart > 0 && load8(g_source, pstart - 1) == 64:
+ at_ctx = 1
+ prefix := analysis_sub_copy(pstart, pos)
+ out : string, mut = "{\"items\":["
+ if at_ctx != 0:
+ out = out + analysis_at_items(prefix)
+ else:
+ out = out + analysis_kw_items(prefix)
// 符号候选:g_syms(check_all 后剩顶层:函数/全局/类型/内建)
// + g_funcs + g_structs + g_enums(按候选总数精确分配,无需扩容)
- total := g_sym_count + g_func_count + g_struct_count + g_enum_count;
- if total < 1 { total = 1; } // 防 alloc(0)
- cand : string, mut = alloc(total * 16);
- cnt : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= g_sym_count { break; }
- kk : ., mut = analysis_sym_item_kind(sym_kind(i));
+ total := g_sym_count + g_func_count + g_struct_count + g_enum_count
+ if total < 1:
+ total = 1
+ // 防 alloc(0)
+ cand : string, mut = alloc(total * 16)
+ cnt : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= g_sym_count:
+ break
+ kk : ., mut = analysis_sym_item_kind(sym_kind(i))
// SYM_TYPE 混装结构体/枚举/接口(collect_decls 统一注册)——
// 枚举按名字区分(g_enums 快照),发 Enum=13;否则按结构体 22
- if sym_kind(i) == SYM_TYPE && find_enum(sym_name(i)) >= 0 { kk = 13; }
- cnt = cnt + analysis_cand_add(cand, cnt, sym_name(i), kk);
- i = i + 1;
- }
- i = 0;
- loop {
- if i >= g_func_count { break; }
- cnt = cnt + analysis_cand_add(cand, cnt, fi_name(i), 3);
- i = i + 1;
- }
- i = 0;
- loop {
- if i >= g_struct_count { break; }
- cnt = cnt + analysis_cand_add(cand, cnt, si_name(i), 22); // Struct
- i = i + 1;
- }
- i = 0;
- loop {
- if i >= g_enum_count { break; }
- cnt = cnt + analysis_cand_add(cand, cnt, ei_name(i), 13); // Enum
- i = i + 1;
- }
- j : ., mut = 0;
- loop {
- if j >= cnt { break; }
- ni := r64(cand, j * 16);
- if analysis_has_prefix(istr_get(ni), prefix) != 0 {
- if str_len(out) > 10 { out = out + ","; }
- out = out + analysis_citem(istr_get(ni), r64(cand, j * 16 + 8));
- }
- j = j + 1;
- }
- }
- out = out + "]}";
- return out;
-}
+ if sym_kind(i) == SYM_TYPE && find_enum(sym_name(i)) >= 0:
+ kk = 13
+ cnt = cnt + analysis_cand_add(cand, cnt, sym_name(i), kk)
+ i = i + 1
+ i = 0
+ loop:
+ if i >= g_func_count:
+ break
+ cnt = cnt + analysis_cand_add(cand, cnt, fi_name(i), 3)
+ i = i + 1
+ i = 0
+ loop:
+ if i >= g_struct_count:
+ break
+ cnt = cnt + analysis_cand_add(cand, cnt, si_name(i), 22) // Struct
+ i = i + 1
+ i = 0
+ loop:
+ if i >= g_enum_count:
+ break
+ cnt = cnt + analysis_cand_add(cand, cnt, ei_name(i), 13) // Enum
+ i = i + 1
+ j : ., mut = 0
+ loop:
+ if j >= cnt:
+ break
+ ni := r64(cand, j * 16)
+ if analysis_has_prefix(istr_get(ni), prefix) != 0:
+ if str_len(out) > 10:
+ out = out + ","
+ out = out + analysis_citem(istr_get(ni), r64(cand, j * 16 + 8))
+ j = j + 1
+ out = out + "]}"
+ return out
// ── documentSymbol(Task 5)────────────────────────────────────
// 顶层符号 JSON 数组。g_ast 无 STRUCT_DEF/ENUM_DEF 声明节点(Task 4 已确认),
@@ -809,130 +1035,129 @@ fn analysis_completion(line: int, col: int) -> string {
// 插入排序输出。跨文件:仅主文件(段偏移 0)符号——LSP 文档即主文件。
// 1-based (line,col) → LSP range JSON(0-based 减 1,起点到名字后一字符)
-fn analysis_range_json(ln1: int, cl1: int) -> string {
- line_start := analysis_line_start(ln1 - 1);
- start_pos := line_start + cl1 - 1;
- start_col := analysis_utf16_units(line_start, start_pos);
- adv := analysis_utf8_next(start_pos, str_len(g_source));
- end_col := analysis_utf16_units(line_start, start_pos + adv);
- out : string, mut = "{\"start\":{\"line\":";
- out = out + int_str(ln1 - 1);
- out = out + ",\"character\":";
- out = out + int_str(start_col);
- out = out + "},\"end\":{\"line\":";
- out = out + int_str(ln1 - 1);
- out = out + ",\"character\":";
- out = out + int_str(end_col);
- out = out + "}}";
- return out;
-}
+fn analysis_range_json(ln1: int, cl1: int) -> string:
+ line_start := analysis_line_start(ln1 - 1)
+ start_pos := line_start + cl1 - 1
+ start_col := analysis_utf16_units(line_start, start_pos)
+ adv := analysis_utf8_next(start_pos, str_len(g_source))
+ end_col := analysis_utf16_units(line_start, start_pos + adv)
+ out : string, mut = "{\"start\":{\"line\":"
+ out = out + int_str(ln1 - 1)
+ out = out + ",\"character\":"
+ out = out + int_str(start_col)
+ out = out + "},\"end\":{\"line\":"
+ out = out + int_str(ln1 - 1)
+ out = out + ",\"character\":"
+ out = out + int_str(end_col)
+ out = out + "}}"
+ return out
// 顶层符号 → JSON 数组(无符号 → "[]")
-fn analysis_document_symbol() -> string {
- total := g_func_count + g_struct_count + g_enum_count;
- if total <= 0 { return "[]"; }
+fn analysis_document_symbol() -> string:
+ total := g_func_count + g_struct_count + g_enum_count
+ if total <= 0:
+ return "[]"
// 条目缓冲:{name_ni, kind, line(1-based), col(1-based)} = 32 字节
- ent : string, mut = alloc(total * 32);
- cnt : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= g_func_count { break; }
- ni := fi_name(i);
- fn_node := fi_ast_node(i);
- ln : ., mut = 0; cl : ., mut = 0;
- if fn_node >= 0 && fn_node < g_ast_count { ln = ast_line(fn_node); cl = ast_col(fn_node); }
- if ln > 0 && analysis_line_offset(ln) == 0 {
- w64(ent, cnt * 32, ni);
- w64(ent, cnt * 32 + 8, 12); // SymbolKind.Function = 12
- w64(ent, cnt * 32 + 16, ln);
- w64(ent, cnt * 32 + 24, cl);
- cnt = cnt + 1;
- }
- i = i + 1;
- }
- i = 0;
- loop {
- if i >= g_struct_count { break; }
- ni := si_name(i);
- d := analysis_decl_tok(T_STRUCT, ni);
- if d >= 0 {
- ln := r64(g_tokens, d * ESZ_TOKEN + OFF_TK_LINE);
- if analysis_line_offset(ln) == 0 {
- w64(ent, cnt * 32, ni);
- w64(ent, cnt * 32 + 8, 23); // SymbolKind.Struct = 23
- w64(ent, cnt * 32 + 16, ln);
- w64(ent, cnt * 32 + 24, r64(g_tokens, d * ESZ_TOKEN + OFF_TK_COL));
- cnt = cnt + 1;
- }
- }
- i = i + 1;
- }
- i = 0;
- loop {
- if i >= g_enum_count { break; }
- ni := ei_name(i);
- d := analysis_decl_tok(T_ENUM, ni);
- if d >= 0 {
- ln := r64(g_tokens, d * ESZ_TOKEN + OFF_TK_LINE);
- if analysis_line_offset(ln) == 0 {
- w64(ent, cnt * 32, ni);
- w64(ent, cnt * 32 + 8, 10); // SymbolKind.Enum = 10(LSP 规范;
+ ent : string, mut = alloc(total * 32)
+ cnt : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= g_func_count:
+ break
+ ni := fi_name(i)
+ fn_node := fi_ast_node(i)
+ ln : ., mut = 0
+ cl : ., mut = 0
+ if fn_node >= 0 && fn_node < g_ast_count:
+ ln = ast_line(fn_node)
+ cl = ast_col(fn_node)
+ if ln > 0 && analysis_line_offset(ln) == 0:
+ w64(ent, cnt * 32, ni)
+ w64(ent, cnt * 32 + 8, 12) // SymbolKind.Function = 12
+ w64(ent, cnt * 32 + 16, ln)
+ w64(ent, cnt * 32 + 24, cl)
+ cnt = cnt + 1
+ i = i + 1
+ i = 0
+ loop:
+ if i >= g_struct_count:
+ break
+ ni := si_name(i)
+ d := analysis_decl_tok(T_STRUCT, ni)
+ if d >= 0:
+ ln := r64(g_tokens, d * ESZ_TOKEN + OFF_TK_LINE)
+ if analysis_line_offset(ln) == 0:
+ w64(ent, cnt * 32, ni)
+ w64(ent, cnt * 32 + 8, 23) // SymbolKind.Struct = 23
+ w64(ent, cnt * 32 + 16, ln)
+ w64(ent, cnt * 32 + 24, r64(g_tokens, d * ESZ_TOKEN + OFF_TK_COL))
+ cnt = cnt + 1
+ i = i + 1
+ i = 0
+ loop:
+ if i >= g_enum_count:
+ break
+ ni := ei_name(i)
+ d := analysis_decl_tok(T_ENUM, ni)
+ if d >= 0:
+ ln := r64(g_tokens, d * ESZ_TOKEN + OFF_TK_LINE)
+ if analysis_line_offset(ln) == 0:
+ w64(ent, cnt * 32, ni)
+ w64(ent, cnt * 32 + 8, 10) // SymbolKind.Enum = 10(LSP 规范;
// Task 5 brief 误为 23)
- w64(ent, cnt * 32 + 16, ln);
- w64(ent, cnt * 32 + 24, r64(g_tokens, d * ESZ_TOKEN + OFF_TK_COL));
- cnt = cnt + 1;
- }
- }
- i = i + 1;
- }
+ w64(ent, cnt * 32 + 16, ln)
+ w64(ent, cnt * 32 + 24, r64(g_tokens, d * ESZ_TOKEN + OFF_TK_COL))
+ cnt = cnt + 1
+ i = i + 1
// 按 (line, col) 升序插入排序(源顺序输出)
- j : ., mut = 1;
- loop {
- if j >= cnt { break; }
- key_ni := r64(ent, j * 32);
- key_kind := r64(ent, j * 32 + 8);
- key_ln := r64(ent, j * 32 + 16);
- key_cl := r64(ent, j * 32 + 24);
- k : ., mut = j;
- loop {
- if k <= 0 { break; }
- pln := r64(ent, (k - 1) * 32 + 16);
- pcl := r64(ent, (k - 1) * 32 + 24);
- if pln < key_ln || (pln == key_ln && pcl <= key_cl) { break; }
- w64(ent, k * 32, r64(ent, (k - 1) * 32));
- w64(ent, k * 32 + 8, r64(ent, (k - 1) * 32 + 8));
- w64(ent, k * 32 + 16, pln);
- w64(ent, k * 32 + 24, pcl);
- k = k - 1;
- }
- w64(ent, k * 32, key_ni);
- w64(ent, k * 32 + 8, key_kind);
- w64(ent, k * 32 + 16, key_ln);
- w64(ent, k * 32 + 24, key_cl);
- j = j + 1;
- }
- out : string, mut = "[";
- q : ., mut = 0;
- loop {
- if q >= cnt { break; }
- if q > 0 { out = out + ","; }
- ni := r64(ent, q * 32);
- ln1 := r64(ent, q * 32 + 16);
- cl1 := r64(ent, q * 32 + 24);
- out = out + "{\"name\":";
- out = out + lsp_json_escape_str(istr_get(ni));
- out = out + ",\"kind\":";
- out = out + int_str(r64(ent, q * 32 + 8));
- out = out + ",\"range\":";
- out = out + analysis_range_json(ln1, cl1);
- out = out + ",\"selectionRange\":";
- out = out + analysis_range_json(ln1, cl1);
- out = out + ",\"children\":[]}";
- q = q + 1;
- }
- out = out + "]";
- return out;
-}
+ j : ., mut = 1
+ loop:
+ if j >= cnt:
+ break
+ key_ni := r64(ent, j * 32)
+ key_kind := r64(ent, j * 32 + 8)
+ key_ln := r64(ent, j * 32 + 16)
+ key_cl := r64(ent, j * 32 + 24)
+ k : ., mut = j
+ loop:
+ if k <= 0:
+ break
+ pln := r64(ent, (k - 1) * 32 + 16)
+ pcl := r64(ent, (k - 1) * 32 + 24)
+ if pln < key_ln || (pln == key_ln && pcl <= key_cl):
+ break
+ w64(ent, k * 32, r64(ent, (k - 1) * 32))
+ w64(ent, k * 32 + 8, r64(ent, (k - 1) * 32 + 8))
+ w64(ent, k * 32 + 16, pln)
+ w64(ent, k * 32 + 24, pcl)
+ k = k - 1
+ w64(ent, k * 32, key_ni)
+ w64(ent, k * 32 + 8, key_kind)
+ w64(ent, k * 32 + 16, key_ln)
+ w64(ent, k * 32 + 24, key_cl)
+ j = j + 1
+ out : string, mut = "["
+ q : ., mut = 0
+ loop:
+ if q >= cnt:
+ break
+ if q > 0:
+ out = out + ","
+ ni := r64(ent, q * 32)
+ ln1 := r64(ent, q * 32 + 16)
+ cl1 := r64(ent, q * 32 + 24)
+ out = out + "{\"name\":"
+ out = out + lsp_json_escape_str(istr_get(ni))
+ out = out + ",\"kind\":"
+ out = out + int_str(r64(ent, q * 32 + 8))
+ out = out + ",\"range\":"
+ out = out + analysis_range_json(ln1, cl1)
+ out = out + ",\"selectionRange\":"
+ out = out + analysis_range_json(ln1, cl1)
+ out = out + ",\"children\":[]}"
+ q = q + 1
+ out = out + "]"
+ return out
// ── semanticTokens(Task 6)──────────────────────────────────
// 快照 g_tokens → LSP semanticTokens/full 的 data 差分编码(相对上一令牌
@@ -955,12 +1180,14 @@ fn analysis_document_symbol() -> string {
// rpc_send_initialize 声明,顺序必须与这里一致):
// keyword (0): T_FN T_MUT T_IF T_ELSE T_LOOP T_WHILE T_FOR T_IN
// T_RETURN T_BREAK T_CONTINUE T_STRUCT T_ENUM T_IMPL T_PUB
-// T_TRUE T_FALSE T_MOVE T_SELF T_MATCH T_TYPE T_MOD
+// T_TRUE T_FALSE T_SELF T_MATCH T_TYPE T_MOD
// T_IMPORT T_AS T_GO T_AWAIT T_FLOW T_YIELD T_UNSAFE
-// T_INTERFACE T_AUTO T_FILEID T_NONE T_SOME T_EXTERN
+// T_INTERFACE T_AUTO T_FILEID T_EXTERN T_CATCH T_FAIL T_SPEC
+// (v4 关键字 36→39,T5:去 T_MOVE/T_SOME;T_NONE 保留——它现在是
+// **小写 `none`** 的令牌,仍是关键字;T_NEVER 归 type(1),见下)
// type (1): T_UNIT(unit 关键字令牌——parser 产 TY_UNIT)
// T_INT_TYPE..T_AUTO_TYPE
-// T_REF T_DYN;以及 T_IDENT 且(内置类型名 int/float/
+// T_REF T_DYN T_NEVER(v4:never/dyn 已升格为关键字令牌);以及 T_IDENT 且(内置类型名 int/float/
// bool/string/char/never/dyn——parser.cr parse_type
// T_IDENT 分支字面量清单,唯一真源——或 find_struct_by_
// name / find_enum 命中的结构体/枚举名)
@@ -979,217 +1206,255 @@ fn analysis_document_symbol() -> string {
// number (7): T_INT T_DEX(字面量令牌)
// kind → legend 下标;T_IDENT 返回 -1(需按名字分类,见 analysis_token_type)
-fn analysis_kind_type(k: int) -> int {
- if k == T_FN || k == T_MUT || k == T_IF || k == T_ELSE || k == T_LOOP ||
- k == T_WHILE || k == T_FOR || k == T_IN || k == T_RETURN ||
- k == T_BREAK ||
- k == T_CONTINUE || k == T_STRUCT || k == T_ENUM || k == T_IMPL ||
- k == T_PUB || k == T_TRUE || k == T_FALSE || k == T_MOVE ||
- k == T_SELF || k == T_MATCH || k == T_TYPE || k == T_MOD ||
- k == T_IMPORT || k == T_AS || k == T_GO || k == T_AWAIT ||
- k == T_FLOW || k == T_YIELD || k == T_UNSAFE || k == T_INTERFACE ||
- k == T_AUTO || k == T_FILEID || k == T_NONE || k == T_SOME ||
- k == T_EXTERN { return 0; }
- if k == T_UNIT || (k >= T_INT_TYPE && k <= T_AUTO_TYPE) ||
- k == T_REF || k == T_DYN {
- return 1;
- }
- if k == T_STRING || k == T_CHAR { return 5; }
- if k == T_INT || k == T_DEX { return 7; }
- if k == T_IDENT { return -1; }
- return 6; // 运算符/分隔符:其余全部 kind
-}
+fn analysis_kind_type(k: int) -> int:
+ if k == T_FN || k == T_MUT || k == T_IF || k == T_ELSE || k == T_LOOP || k == T_WHILE || k == T_FOR || k == T_IN || k == T_RETURN || k == T_BREAK || k == T_CONTINUE || k == T_STRUCT || k == T_ENUM || k == T_IMPL || k == T_PUB || k == T_TRUE || k == T_FALSE || k == T_SELF || k == T_MATCH || k == T_TYPE || k == T_MOD || k == T_IMPORT || k == T_AS || k == T_GO || k == T_AWAIT || k == T_FLOW || k == T_YIELD || k == T_UNSAFE || k == T_INTERFACE || k == T_AUTO || k == T_FILEID || k == T_NONE || k == T_EXTERN || k == T_CATCH || k == T_FAIL || k == T_SPEC:
+ return 0
+ if k == T_UNIT || (k >= T_INT_TYPE && k <= T_AUTO_TYPE) || k == T_REF || k == T_DYN || k == T_NEVER:
+ return 1
+ if k == T_STRING || k == T_CHAR:
+ return 5
+ if k == T_INT || k == T_DEX:
+ return 7
+ if k == T_IDENT:
+ return -1
+ return 6 // 运算符/分隔符:其余全部 kind
// 名字是否为内置类型名(parser.cr parse_type 的 T_IDENT 分支字面量清单)
-fn analysis_is_builtin_type(ni: int) -> int {
- s := istr_get(ni);
- if str_eq(s, "int") != 0 || str_eq(s, "dex") != 0 ||
- str_eq(s, "bool") != 0 || str_eq(s, "string") != 0 ||
- str_eq(s, "char") != 0 || str_eq(s, "never") != 0 ||
- str_eq(s, "dyn") != 0 { return 1; }
- return 0;
-}
+fn analysis_is_builtin_type(ni: int) -> int:
+ s := istr_get(ni)
+ if str_eq(s, "int") != 0 || str_eq(s, "dex") != 0 || str_eq(s, "bool") != 0 || str_eq(s, "string") != 0 || str_eq(s, "char") != 0 || str_eq(s, "never") != 0 || str_eq(s, "dyn") != 0:
+ return 1
+ return 0
// 令牌索引 → legend 下标(T_IDENT 按符号表/内置类型名分类)
-fn analysis_token_type(ti: int) -> int {
- k := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_KIND);
- if k != T_IDENT { return analysis_kind_type(k); }
- ni := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_LEXEME);
- if analysis_is_builtin_type(ni) != 0 { return 1; }
- if find_func(ni) >= 0 { return 2; }
- if find_struct_by_name(ni) >= 0 { return 1; }
- if find_enum(ni) >= 0 { return 1; }
- return 3;
-}
+fn analysis_token_type(ti: int) -> int:
+ k := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_KIND)
+ if k != T_IDENT:
+ return analysis_kind_type(k)
+ ni := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_LEXEME)
+ if analysis_is_builtin_type(ni) != 0:
+ return 1
+ if find_func(ni) >= 0:
+ return 2
+ if find_struct_by_name(ni) >= 0:
+ return 1
+ if find_enum(ni) >= 0:
+ return 1
+ return 3
// 令牌索引 → 源文本字节跨度(从起始偏移 st 起按 kind 镜像 lexer 消耗规则)
-fn analysis_tok_span(ti: int, st: int, sl: int) -> int {
- k := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_KIND);
+fn analysis_tok_span(ti: int, st: int, sl: int) -> int:
+ k := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_KIND)
// 字符串/字符(镜像 lexer;批 8 插值展开后**词法把含洞字面量拆成 part** ⇒ 本函数按 part 计 span):
// · `T_STRING` = 字面**段**:开引号 → 未转义闭合引号 / **下一个 `${`**(段在此截断)/ 换行(未闭合);
// · `T_INTERP` = **洞** token:`${` + **花括号配平**(跳洞内字符串字面量与其转义)到配对 `}`,含 `}`。
// ⚠ 旧契约文字「跳至 `}` 并**多吃一字节**」= **把 bug 写成规格**(当时的镜像逐字复制了 lexer 的双推进,
// 实现在此已删)——2026-09-18 与 lexer 修复同批重定。未闭合串末尾的反斜杠只能覆盖到源末,
// 不能把 span 推出源缓冲区。
- if k == T_STRING || k == T_CHAR {
- q := analysis_source_byte(st, sl);
- p : ., mut = st + 1;
- loop {
- if p >= sl { break; }
- c := analysis_source_byte(p, sl);
- if c == 92 {
- if p + 1 >= sl { p = sl; break; }
- p = p + 2;
- }
- else if c == q { p = p + 1; break; }
- else if c == 10 { break; }
- else if c == 36 && analysis_source_byte(p + 1, sl) == 123 { break; } // 段止于 `${`
- else { p = p + 1; }
- }
- return p - st;
- }
- if k == T_INTERP {
+ if k == T_STRING || k == T_CHAR:
+ q := analysis_source_byte(st, sl)
+ p : ., mut = st + 1
+ loop:
+ if p >= sl:
+ break
+ c := analysis_source_byte(p, sl)
+ if c == 92:
+ if p + 1 >= sl:
+ p = sl
+ break
+ p = p + 2
+ else if c == q:
+ p = p + 1
+ break
+ else if c == 10:
+ break
+ else if c == 36 && analysis_source_byte(p + 1, sl) == 123:
+ break
+ // 段止于 `${`
+ else:
+ p = p + 1
+ return p - st
+ if k == T_INTERP:
// 洞 token 的源跨度 = `${` … 配对 `}`(配平;洞内字符串字面量与其转义整体跳过)
- p : ., mut = st + 2;
- depth : ., mut = 1;
- loop {
- if p >= sl { break; }
- c := analysis_source_byte(p, sl);
- if c == 10 { break; }
- if c == 34 {
- p = p + 1;
- loop {
- if p >= sl { break; }
- sc := analysis_source_byte(p, sl);
- if sc == 10 { break; }
- if sc == 92 { p = p + 2; continue; }
- p = p + 1;
- if sc == 34 { break; }
- }
- continue;
- }
- if c == 123 { depth = depth + 1; }
- if c == 125 { depth = depth - 1; if depth == 0 { p = p + 1; break; } }
- p = p + 1;
- }
- return p - st;
- }
+ p : ., mut = st + 2
+ depth : ., mut = 1
+ loop:
+ if p >= sl:
+ break
+ c := analysis_source_byte(p, sl)
+ if c == 10:
+ break
+ if c == 34:
+ p = p + 1
+ loop:
+ if p >= sl:
+ break
+ sc := analysis_source_byte(p, sl)
+ if sc == 10:
+ break
+ if sc == 92:
+ p = p + 2
+ continue
+ p = p + 1
+ if sc == 34:
+ break
+ continue
+ if c == 123:
+ depth = depth + 1
+ if c == 125:
+ depth = depth - 1
+ if depth == 0:
+ p = p + 1
+ break
+ p = p + 1
+ return p - st
// 数字:镜像 lexer 数字分支('.' 起始、hex/oct/bin 前缀、小数、字母后缀)
- if k == T_INT || k == T_DEX {
- p : ., mut = st;
- if analysis_source_byte(p, sl) == 46 && is_digit(analysis_source_byte(p + 1, sl)) != 0 { p = p + 1; }
- loop { if is_digit(analysis_source_byte(p, sl)) != 0 { p = p + 1; } else { break; } }
- if p - st == 1 && load8(g_source, st) == 48 {
- nx := analysis_source_byte(p, sl);
- if nx == 120 || nx == 88 {
- p = p + 1;
- loop { hc := analysis_source_byte(p, sl); if is_digit(hc) != 0 || (hc >= 65 && hc <= 70) || (hc >= 97 && hc <= 102) { p = p + 1; } else { break; } }
- } else if nx == 111 || nx == 79 {
- p = p + 1;
- loop { oc := analysis_source_byte(p, sl); if oc >= 48 && oc <= 55 { p = p + 1; } else { break; } }
- } else if nx == 98 || nx == 66 {
- p = p + 1;
- loop { bc := analysis_source_byte(p, sl); if bc == 48 || bc == 49 { p = p + 1; } else { break; } }
- }
- }
- if analysis_source_byte(p, sl) == 46 && analysis_source_byte(p + 1, sl) != 46 {
- p = p + 1;
- loop { if is_digit(analysis_source_byte(p, sl)) != 0 { p = p + 1; } else { break; } }
- }
- loop { if is_alpha(analysis_source_byte(p, sl)) != 0 { p = p + 1; } else { break; } }
- return p - st;
- }
+ if k == T_INT || k == T_DEX:
+ p : ., mut = st
+ if analysis_source_byte(p, sl) == 46 && is_digit(analysis_source_byte(p + 1, sl)) != 0:
+ p = p + 1
+ loop:
+ if is_digit(analysis_source_byte(p, sl)) != 0:
+ p = p + 1
+ else:
+ break
+ if p - st == 1 && load8(g_source, st) == 48:
+ nx := analysis_source_byte(p, sl)
+ if nx == 120 || nx == 88:
+ p = p + 1
+ loop:
+ hc := analysis_source_byte(p, sl)
+ if is_digit(hc) != 0 || (hc >= 65 && hc <= 70) || (hc >= 97 && hc <= 102):
+ p = p + 1
+ else:
+ break
+ else if nx == 111 || nx == 79:
+ p = p + 1
+ loop:
+ oc := analysis_source_byte(p, sl)
+ if oc >= 48 && oc <= 55:
+ p = p + 1
+ else:
+ break
+ else if nx == 98 || nx == 66:
+ p = p + 1
+ loop:
+ bc := analysis_source_byte(p, sl)
+ if bc == 48 || bc == 49:
+ p = p + 1
+ else:
+ break
+ if analysis_source_byte(p, sl) == 46 && analysis_source_byte(p + 1, sl) != 46:
+ p = p + 1
+ loop:
+ if is_digit(analysis_source_byte(p, sl)) != 0:
+ p = p + 1
+ else:
+ break
+ loop:
+ if is_alpha(analysis_source_byte(p, sl)) != 0:
+ p = p + 1
+ else:
+ break
+ return p - st
// 标识符/关键字/类型关键字:lexeme 即源文本(add_tok_str)
- lex := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_LEXEME);
- if lex >= 0 { return str_len(istr_get(lex)); }
+ lex := r64(g_tokens, ti * ESZ_TOKEN + OFF_TK_LEXEME)
+ if lex >= 0:
+ return str_len(istr_get(lex))
// 运算符/分隔符(lexeme = -1):lexer 定长表(其余单字符)
- if k == T_EQEQ || k == T_BANGEQ || k == T_LTEQ || k == T_GTEQ ||
- k == T_ANDAND || k == T_PIPEPIPE || k == T_ARROW || k == T_FATARROW ||
- k == T_COLON_EQ || k == T_PATHSEP || k == T_PLUS_EQ || k == T_MINUS_EQ ||
- k == T_STAR_EQ || k == T_SLASH_EQ || k == T_DOTDOT { return 2; }
- if k == T_DOTDOTDOT { return 3; }
- return 1;
-}
+ if k == T_EQEQ || k == T_BANGEQ || k == T_LTEQ || k == T_GTEQ || k == T_ANDAND || k == T_PIPEPIPE || k == T_ARROW || k == T_FATARROW || k == T_COLON_EQ || k == T_PATHSEP || k == T_PLUS_EQ || k == T_MINUS_EQ || k == T_STAR_EQ || k == T_SLASH_EQ || k == T_DOTDOT:
+ return 2
+ if k == T_DOTDOTDOT:
+ return 3
+ return 1
// 令牌流(至 T_EOF 止)→ {"data":[...]} 差分编码 JSON;无令牌 → 空数组
-fn analysis_semantic_tokens() -> string {
+fn analysis_semantic_tokens() -> string:
// 实际令牌数(T_EOF 前)
- n : ., mut = 0;
- loop {
- if n >= g_token_count { break; }
- if r64(g_tokens, n * ESZ_TOKEN + OFF_TK_KIND) == T_EOF { break; }
- n = n + 1;
- }
- if n == 0 { return "{\"data\":[]}"; }
+ n : ., mut = 0
+ loop:
+ if n >= g_token_count:
+ break
+ if r64(g_tokens, n * ESZ_TOKEN + OFF_TK_KIND) == T_EOF:
+ break
+ n = n + 1
+ if n == 0:
+ return "{\"data\":[]}"
// pass 1:令牌起始字节偏移(单遍扫 g_source;列按字节计,与 lexer 一致)
- offs : string, mut = alloc(n * 8);
- pos : ., mut = 0;
- ln : ., mut = 1;
- cl : ., mut = 1;
- sl := str_len(g_source);
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- tline := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_LINE);
- tcol := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_COL);
- loop { // 跨行到 tline
- if ln >= tline { break; }
- if pos >= sl { break; }
- if load8(g_source, pos) == 10 { ln = ln + 1; cl = 1; }
- else { cl = cl + 1; }
- pos = pos + 1;
- }
- loop { // 行内前进到 tcol
- if cl >= tcol { break; }
- if pos >= sl { break; }
- pos = pos + 1;
- cl = cl + 1;
- }
- w64(offs, i * 8, pos);
- i = i + 1;
- }
+ offs : string, mut = alloc(n * 8)
+ pos : ., mut = 0
+ ln : ., mut = 1
+ cl : ., mut = 1
+ sl := str_len(g_source)
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ tline := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_LINE)
+ tcol := r64(g_tokens, i * ESZ_TOKEN + OFF_TK_COL)
+ loop:
+ // 跨行到 tline
+ if ln >= tline:
+ break
+ if pos >= sl:
+ break
+ if load8(g_source, pos) == 10:
+ ln = ln + 1
+ cl = 1
+ else:
+ cl = cl + 1
+ pos = pos + 1
+ loop:
+ // 行内前进到 tcol
+ if cl >= tcol:
+ break
+ if pos >= sl:
+ break
+ pos = pos + 1
+ cl = cl + 1
+ w64(offs, i * 8, pos)
+ i = i + 1
// pass 2:差分编码(相对上一令牌;首令牌相对 (0,0);modifiers 恒 0)。
// 仅主文件令牌(起始偏移 < 段 1 偏移;无导入时 g_seg_count == 1 → 全源)
- main_limit : ., mut = sl;
- if g_seg_count > 1 { main_limit = r64(g_seg_starts, 8); }
- out : string, mut = "{\"data\":[";
- prev_line : ., mut = 0;
- prev_col : ., mut = 0;
- first : ., mut = 1;
- j : ., mut = 0;
- loop {
- if j >= n { break; }
- st := r64(offs, j * 8);
- if st < main_limit {
- line0 : ., mut = r64(g_tokens, j * ESZ_TOKEN + OFF_TK_LINE) - 1;
- token_line_start := analysis_line_start(line0);
- col0 := analysis_utf16_units(token_line_start, st);
- if first == 0 { out = out + ","; }
- if line0 > prev_line {
+ main_limit : ., mut = sl
+ if g_seg_count > 1:
+ main_limit = r64(g_seg_starts, 8)
+ out : string, mut = "{\"data\":["
+ prev_line : ., mut = 0
+ prev_col : ., mut = 0
+ first : ., mut = 1
+ j : ., mut = 0
+ loop:
+ if j >= n:
+ break
+ st := r64(offs, j * 8)
+ if st < main_limit:
+ line0 : ., mut = r64(g_tokens, j * ESZ_TOKEN + OFF_TK_LINE) - 1
+ token_line_start := analysis_line_start(line0)
+ col0 := analysis_utf16_units(token_line_start, st)
+ if first == 0:
+ out = out + ","
+ if line0 > prev_line:
// 跨行令牌:deltaStartChar 为绝对列(LSP 差分编码规范——
// deltaLine > 0 时列非相对差)。旧实现恒输出 col0 - prev_col,
// 跨行令牌产生负 deltaStartChar,客户端解码得到非法列。
// (Task 6 测试用单行源码,跨行路径未被覆盖——Task 8 客户端
// 冒烟测试暴露,已补多行用例。)
- out = out + int_str(line0 - prev_line);
- out = out + ",";
- out = out + int_str(col0);
- } else {
- out = out + "0";
- out = out + ",";
- out = out + int_str(col0 - prev_col);
- }
- out = out + ",";
- out = out + int_str(analysis_utf16_units(st, st + analysis_tok_span(j, st, sl)));
- out = out + ",";
- out = out + int_str(analysis_token_type(j));
- out = out + ",0";
- prev_line = line0;
- prev_col = col0;
- first = 0;
- }
- j = j + 1;
- }
- out = out + "]}";
- return out;
-}
+ out = out + int_str(line0 - prev_line)
+ out = out + ","
+ out = out + int_str(col0)
+ else:
+ out = out + "0"
+ out = out + ","
+ out = out + int_str(col0 - prev_col)
+ out = out + ","
+ out = out + int_str(analysis_utf16_units(st, st + analysis_tok_span(j, st, sl)))
+ out = out + ","
+ out = out + int_str(analysis_token_type(j))
+ out = out + ",0"
+ prev_line = line0
+ prev_col = col0
+ first = 0
+ j = j + 1
+ out = out + "]}"
+ return out
diff --git a/src/lsp/json.cr b/src/lsp/json.cr
index b5c67e0a..db62cb86 100644
--- a/src/lsp/json.cr
+++ b/src/lsp/json.cr
@@ -26,633 +26,728 @@
// 统一使用大写 \uXXXX(非 BMP 输出为一对代理项)。
// ── 常量(全局初始化必须是字面量——ELF 后端限制)──
-J_NULL : int = 0; J_BOOL : int = 1; J_NUM : int = 2;
-J_STR : int = 3; J_ARRAY : int = 4; J_OBJ : int = 5;
-
-J_NODE_SLOTS : int = 5; // 每节点槽数
-J_NODE_BYTES : int = 40; // 5 × 8
-J_ELEM_BYTES : int = 8; // 元素表每元素字节数
-J_MEMBER_BYTES : int = 24; // 成员表每组字节数
+J_NULL : int = 0
+J_BOOL : int = 1
+J_NUM : int = 2
+J_STR : int = 3
+J_ARRAY : int = 4
+J_OBJ : int = 5
+
+J_NODE_SLOTS : int = 5 // 每节点槽数
+J_NODE_BYTES : int = 40 // 5 × 8
+J_ELEM_BYTES : int = 8 // 元素表每元素字节数
+J_MEMBER_BYTES : int = 24 // 成员表每组字节数
// ── 存储(brief 规定的接口全局)──
-g_json_nodes : string, mut; // 节点字节缓冲(惰性 alloc)
-g_json_count : int, mut; // 节点数
-g_json_strs : string, mut; // 字符串字节池
-g_json_str_count : int, mut; // 池中字符串数
+g_json_nodes : string, mut // 节点字节缓冲(惰性 alloc)
+g_json_count : int, mut // 节点数
+g_json_strs : string, mut // 字符串字节池
+g_json_str_count : int, mut // 池中字符串数
// ── 内部:容量/长度计数 + 元素表/成员表缓冲 ──
-g_json_nodes_cap : int, mut;
-g_json_strs_len : int, mut;
-g_json_strs_cap : int, mut;
-g_json_tables : string, mut;
-g_json_tables_len : int, mut;
-g_json_tables_cap : int, mut;
+g_json_nodes_cap : int, mut
+g_json_strs_len : int, mut
+g_json_strs_cap : int, mut
+g_json_tables : string, mut
+g_json_tables_len : int, mut
+g_json_tables_cap : int, mut
// ── 低层字节助手(自包含,不依赖 dyn_arr.cr 的 w64/r64)──
-fn _jw64(buf: string, pos: int, val: int) {
- cur : ., mut = val;
- i : ., mut = 0;
- loop {
- if i >= 8 { break; }
- byte : ., mut = cur % 256;
- if byte < 0 { byte = byte + 256; }
- store8(buf, pos + i, byte);
- cur = (cur - byte) / 256;
- i = i + 1;
- }
-}
-
-fn _jr64(buf: string, pos: int) -> int {
+fn _jw64(buf: string, pos: int, val: int):
+ cur : ., mut = val
+ i : ., mut = 0
+ loop:
+ if i >= 8:
+ break
+ byte : ., mut = cur % 256
+ if byte < 0:
+ byte = byte + 256
+ store8(buf, pos + i, byte)
+ cur = (cur - byte) / 256
+ i = i + 1
+
+fn _jr64(buf: string, pos: int) -> int:
// 与 dyn_arr.cr r64 相同策略:低 32 位按无符号读,高 32 位经两次
// 65536 乘法回绕得到正确的符号扩展(-1 → -1 + (-1 × 2^32))。
- lo := load8(buf, pos) + load8(buf, pos + 1) * 256 + load8(buf, pos + 2) * 65536 + load8(buf, pos + 3) * 16777216;
- hi := load8(buf, pos + 4) + load8(buf, pos + 5) * 256 + load8(buf, pos + 6) * 65536 + load8(buf, pos + 7) * 16777216;
- hi_part := hi * 65536; hi_part = hi_part * 65536;
- return lo + hi_part;
-}
-
-fn _jcopy(src: string, n: int, dst: string) {
- ci : ., mut = 0;
- loop { if ci >= n { break; } store8(dst, ci, load8(src, ci)); ci = ci + 1; } }
+ lo := load8(buf, pos) + load8(buf, pos + 1) * 256 + load8(buf, pos + 2) * 65536 + load8(buf, pos + 3) * 16777216
+ hi := load8(buf, pos + 4) + load8(buf, pos + 5) * 256 + load8(buf, pos + 6) * 65536 + load8(buf, pos + 7) * 16777216
+ hi_part := hi * 65536
+ hi_part = hi_part * 65536
+ return lo + hi_part
+
+fn _jcopy(src: string, n: int, dst: string):
+ ci : ., mut = 0
+ loop:
+ if ci >= n:
+ break
+ store8(dst, ci, load8(src, ci))
+ ci = ci + 1
// ── 扩容(惰性 alloc + 倍增)──
-fn _json_grow_nodes(needed: int) {
- if needed <= g_json_nodes_cap { return; }
- nc : ., mut = g_json_nodes_cap * 2; if nc < 256 { nc = 256; } if nc < needed { nc = needed + 256; }
- nb := alloc(nc); _jcopy(g_json_nodes, g_json_nodes_cap, nb);
- g_json_nodes = nb; g_json_nodes_cap = nc; }
-
-fn _json_grow_tables(needed: int) {
- if needed <= g_json_tables_cap { return; }
- nc : ., mut = g_json_tables_cap * 2; if nc < 256 { nc = 256; } if nc < needed { nc = needed + 256; }
- nb := alloc(nc); _jcopy(g_json_tables, g_json_tables_cap, nb);
- g_json_tables = nb; g_json_tables_cap = nc; }
-
-fn _json_grow_strs(needed: int) {
- if needed <= g_json_strs_cap { return; }
- nc : ., mut = g_json_strs_cap * 2; if nc < 256 { nc = 256; } if nc < needed { nc = needed + 256; }
- nb := alloc(nc); _jcopy(g_json_strs, g_json_strs_cap, nb);
- g_json_strs = nb; g_json_strs_cap = nc; }
+fn _json_grow_nodes(needed: int):
+ if needed <= g_json_nodes_cap:
+ return
+ nc : ., mut = g_json_nodes_cap * 2
+ if nc < 256:
+ nc = 256
+ if nc < needed:
+ nc = needed + 256
+ nb := alloc(nc)
+ _jcopy(g_json_nodes, g_json_nodes_cap, nb)
+ g_json_nodes = nb
+ g_json_nodes_cap = nc
+
+fn _json_grow_tables(needed: int):
+ if needed <= g_json_tables_cap:
+ return
+ nc : ., mut = g_json_tables_cap * 2
+ if nc < 256:
+ nc = 256
+ if nc < needed:
+ nc = needed + 256
+ nb := alloc(nc)
+ _jcopy(g_json_tables, g_json_tables_cap, nb)
+ g_json_tables = nb
+ g_json_tables_cap = nc
+
+fn _json_grow_strs(needed: int):
+ if needed <= g_json_strs_cap:
+ return
+ nc : ., mut = g_json_strs_cap * 2
+ if nc < 256:
+ nc = 256
+ if nc < needed:
+ nc = needed + 256
+ nb := alloc(nc)
+ _jcopy(g_json_strs, g_json_strs_cap, nb)
+ g_json_strs = nb
+ g_json_strs_cap = nc
// ── 节点接口(Task 2-6 依赖)──
// 新建节点,返回节点索引(起始槽号)
-fn json_new(kind: int) -> int {
- need := g_json_count * J_NODE_BYTES + J_NODE_BYTES;
- _json_grow_nodes(need);
- i := g_json_count * J_NODE_SLOTS;
- _jw64(g_json_nodes, i * 8, kind);
- _jw64(g_json_nodes, (i + 1) * 8, 0);
- _jw64(g_json_nodes, (i + 2) * 8, 0);
- _jw64(g_json_nodes, (i + 3) * 8, 0);
- _jw64(g_json_nodes, (i + 4) * 8, 0);
- g_json_count = g_json_count + 1;
- return i;
-}
-
-fn json_set(node: int, slot: int, val: int) {
- if node < 0 || node % J_NODE_SLOTS != 0 || node / J_NODE_SLOTS >= g_json_count ||
- slot < 0 || slot >= J_NODE_SLOTS { return; }
- _jw64(g_json_nodes, (node + slot) * 8, val);
-}
-
-fn json_get(node: int, slot: int) -> int {
- if node < 0 || node % J_NODE_SLOTS != 0 || node / J_NODE_SLOTS >= g_json_count ||
- slot < 0 || slot >= J_NODE_SLOTS { return -1; }
- return _jr64(g_json_nodes, (node + slot) * 8);
-}
+fn json_new(kind: int) -> int:
+ need := g_json_count * J_NODE_BYTES + J_NODE_BYTES
+ _json_grow_nodes(need)
+ i := g_json_count * J_NODE_SLOTS
+ _jw64(g_json_nodes, i * 8, kind)
+ _jw64(g_json_nodes, (i + 1) * 8, 0)
+ _jw64(g_json_nodes, (i + 2) * 8, 0)
+ _jw64(g_json_nodes, (i + 3) * 8, 0)
+ _jw64(g_json_nodes, (i + 4) * 8, 0)
+ g_json_count = g_json_count + 1
+ return i
+
+fn json_set(node: int, slot: int, val: int):
+ if node < 0 || node % J_NODE_SLOTS != 0 || node / J_NODE_SLOTS >= g_json_count || slot < 0 || slot >= J_NODE_SLOTS:
+ return
+ _jw64(g_json_nodes, (node + slot) * 8, val)
+
+fn json_get(node: int, slot: int) -> int:
+ if node < 0 || node % J_NODE_SLOTS != 0 || node / J_NODE_SLOTS >= g_json_count || slot < 0 || slot >= J_NODE_SLOTS:
+ return -1
+ return _jr64(g_json_nodes, (node + slot) * 8)
// ── 解析状态 ──
-g_json_parse_pos : int, mut;
-g_json_parse_text : string, mut;
-g_json_parse_failed : int, mut;
-g_json_parse_depth : int, mut;
-J_MAX_PARSE_DEPTH : int = 128;
+g_json_parse_pos : int, mut
+g_json_parse_text : string, mut
+g_json_parse_failed : int, mut
+g_json_parse_depth : int, mut
+J_MAX_PARSE_DEPTH : int = 128
-fn _jp_len() -> int { return str_len(g_json_parse_text); }
+fn _jp_len() -> int:
+ return str_len(g_json_parse_text)
// 当前位置的字符;文件尾返回 -1
-fn _jp_peek() -> int {
- if g_json_parse_pos >= _jp_len() { return -1; }
- return load8(g_json_parse_text, g_json_parse_pos);
-}
-
-fn _jskip_ws() {
- loop {
- if g_json_parse_pos >= _jp_len() { break; }
- c := load8(g_json_parse_text, g_json_parse_pos);
- if c == 32 || c == 9 || c == 10 || c == 13 { g_json_parse_pos = g_json_parse_pos + 1; }
- else { break; }
- }
-}
+fn _jp_peek() -> int:
+ if g_json_parse_pos >= _jp_len():
+ return -1
+ return load8(g_json_parse_text, g_json_parse_pos)
+
+fn _jskip_ws():
+ loop:
+ if g_json_parse_pos >= _jp_len():
+ break
+ c := load8(g_json_parse_text, g_json_parse_pos)
+ if c == 32 || c == 9 || c == 10 || c == 13:
+ g_json_parse_pos = g_json_parse_pos + 1
+ else:
+ break
// 关键字匹配(true/false/null)并消费;后随字符必须是边界(非标识符字符)
-fn _jk_match(word: string) -> int {
- wl := str_len(word);
- if g_json_parse_pos + wl > _jp_len() { return 0; }
- i : ., mut = 0;
- loop {
- if i >= wl { break; }
- if load8(g_json_parse_text, g_json_parse_pos + i) != load8(word, i) { return 0; }
- i = i + 1;
- }
- if g_json_parse_pos + wl >= _jp_len() { g_json_parse_pos = g_json_parse_pos + wl; return 1; }
- c := load8(g_json_parse_text, g_json_parse_pos + wl);
- if c >= 97 && c <= 122 { return 0; } // a-z
- if c >= 65 && c <= 90 { return 0; } // A-Z
- if c >= 48 && c <= 57 { return 0; } // 0-9
- if c == 95 { return 0; } // _
- g_json_parse_pos = g_json_parse_pos + wl;
- return 1;
-}
+fn _jk_match(word: string) -> int:
+ wl := str_len(word)
+ if g_json_parse_pos + wl > _jp_len():
+ return 0
+ i : ., mut = 0
+ loop:
+ if i >= wl:
+ break
+ if load8(g_json_parse_text, g_json_parse_pos + i) != load8(word, i):
+ return 0
+ i = i + 1
+ if g_json_parse_pos + wl >= _jp_len():
+ g_json_parse_pos = g_json_parse_pos + wl
+ return 1
+ c := load8(g_json_parse_text, g_json_parse_pos + wl)
+ if c >= 97 && c <= 122:
+ return 0
+ // a-z
+ if c >= 65 && c <= 90:
+ return 0
+ // A-Z
+ if c >= 48 && c <= 57:
+ return 0
+ // 0-9
+ if c == 95:
+ return 0
+ // _
+ g_json_parse_pos = g_json_parse_pos + wl
+ return 1
// 数字:可选负号 + 十进制整数;溢出/非法置 g_json_parse_failed
-fn _jnum() -> int {
- neg : ., mut = 0;
- if g_json_parse_pos < _jp_len() && load8(g_json_parse_text, g_json_parse_pos) == 45 {
- neg = 1; g_json_parse_pos = g_json_parse_pos + 1; }
- dstart := g_json_parse_pos;
- loop {
- if g_json_parse_pos >= _jp_len() { break; }
- c := load8(g_json_parse_text, g_json_parse_pos);
- if c >= 48 && c <= 57 { g_json_parse_pos = g_json_parse_pos + 1; }
- else { break; }
- }
- if g_json_parse_pos == dstart { g_json_parse_failed = 1; return 0; }
- if g_json_parse_pos - dstart > 1 && load8(g_json_parse_text, dstart) == 48 {
- g_json_parse_failed = 1; return 0;
- }
- v : ., mut = 0;
- i : ., mut = dstart;
- loop {
- if i >= g_json_parse_pos { break; }
- digit := load8(g_json_parse_text, i) - 48;
+fn _jnum() -> int:
+ neg : ., mut = 0
+ if g_json_parse_pos < _jp_len() && load8(g_json_parse_text, g_json_parse_pos) == 45:
+ neg = 1
+ g_json_parse_pos = g_json_parse_pos + 1
+ dstart := g_json_parse_pos
+ loop:
+ if g_json_parse_pos >= _jp_len():
+ break
+ c := load8(g_json_parse_text, g_json_parse_pos)
+ if c >= 48 && c <= 57:
+ g_json_parse_pos = g_json_parse_pos + 1
+ else:
+ break
+ if g_json_parse_pos == dstart:
+ g_json_parse_failed = 1
+ return 0
+ if g_json_parse_pos - dstart > 1 && load8(g_json_parse_text, dstart) == 48:
+ g_json_parse_failed = 1
+ return 0
+ v : ., mut = 0
+ i : ., mut = dstart
+ loop:
+ if i >= g_json_parse_pos:
+ break
+ digit := load8(g_json_parse_text, i) - 48
// Accumulate negative values negatively so INT64_MIN is representable.
- if neg != 0 {
- if v < -922337203685477580 ||
- (v == -922337203685477580 && digit > 8) {
- g_json_parse_failed = 1; return 0;
- }
- v = v * 10 - digit;
- } else {
- if v > 922337203685477580 ||
- (v == 922337203685477580 && digit > 7) {
- g_json_parse_failed = 1; return 0;
- }
- v = v * 10 + digit;
- }
- i = i + 1;
- }
+ if neg != 0:
+ if v < -922337203685477580 || (v == -922337203685477580 && digit > 8):
+ g_json_parse_failed = 1
+ return 0
+ v = v * 10 - digit
+ else:
+ if v > 922337203685477580 || (v == 922337203685477580 && digit > 7):
+ g_json_parse_failed = 1
+ return 0
+ v = v * 10 + digit
+ i = i + 1
// 尾随 '.' / 'e' / 'E':v1 不支持浮点 → 失败(不静默截断)
- if g_json_parse_pos < _jp_len() {
- c2 := load8(g_json_parse_text, g_json_parse_pos);
- if c2 == 46 || c2 == 101 || c2 == 69 { g_json_parse_failed = 1; return 0; }
- }
- return v;
-}
+ if g_json_parse_pos < _jp_len():
+ c2 := load8(g_json_parse_text, g_json_parse_pos)
+ if c2 == 46 || c2 == 101 || c2 == 69:
+ g_json_parse_failed = 1
+ return 0
+ return v
// 十六进制数字值;非法返回 -1
-fn _jhex_val(c: int) -> int {
- if c >= 48 && c <= 57 { return c - 48; }
- if c >= 97 && c <= 102 { return c - 87; }
- if c >= 65 && c <= 70 { return c - 55; }
- return -1;
-}
+fn _jhex_val(c: int) -> int:
+ if c >= 48 && c <= 57:
+ return c - 48
+ if c >= 97 && c <= 102:
+ return c - 87
+ if c >= 65 && c <= 70:
+ return c - 55
+ return -1
// ── 字符串池写入 ──
-fn _jstr_byte(b: int) {
- need := g_json_strs_len + 1;
- _json_grow_strs(need);
- store8(g_json_strs, g_json_strs_len, b);
- g_json_strs_len = g_json_strs_len + 1;
-}
+fn _jstr_byte(b: int):
+ need := g_json_strs_len + 1
+ _json_grow_strs(need)
+ store8(g_json_strs, g_json_strs_len, b)
+ g_json_strs_len = g_json_strs_len + 1
// 码点 → UTF-8 编码写入池
-fn _jstr_cp(cp: int) {
- if cp < 128 {
- _jstr_byte(cp);
- } else if cp < 2048 {
- _jstr_byte(192 + cp / 64);
- _jstr_byte(128 + cp % 64);
- } else if cp < 65536 {
- _jstr_byte(224 + cp / 4096);
- _jstr_byte(128 + (cp / 64) % 64);
- _jstr_byte(128 + cp % 64);
- } else if cp <= 1114111 {
- _jstr_byte(240 + cp / 262144);
- _jstr_byte(128 + (cp / 4096) % 64);
- _jstr_byte(128 + (cp / 64) % 64);
- _jstr_byte(128 + cp % 64);
- } else { g_json_parse_failed = 1; }
-}
-
-fn _jparse_hex4(pos: int) -> int {
- cp : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= 4 { break; }
- hv := _jhex_val(load8(g_json_parse_text, pos + i));
- if hv < 0 { g_json_parse_failed = 1; return -1; }
- cp = cp * 16 + hv;
- i = i + 1;
- }
- return cp;
-}
+fn _jstr_cp(cp: int):
+ if cp < 128:
+ _jstr_byte(cp)
+ else if cp < 2048:
+ _jstr_byte(192 + cp / 64)
+ _jstr_byte(128 + cp % 64)
+ else if cp < 65536:
+ _jstr_byte(224 + cp / 4096)
+ _jstr_byte(128 + (cp / 64) % 64)
+ _jstr_byte(128 + cp % 64)
+ else if cp <= 1114111:
+ _jstr_byte(240 + cp / 262144)
+ _jstr_byte(128 + (cp / 4096) % 64)
+ _jstr_byte(128 + (cp / 64) % 64)
+ _jstr_byte(128 + cp % 64)
+ else:
+ g_json_parse_failed = 1
+
+fn _jparse_hex4(pos: int) -> int:
+ cp : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= 4:
+ break
+ hv := _jhex_val(load8(g_json_parse_text, pos + i))
+ if hv < 0:
+ g_json_parse_failed = 1
+ return -1
+ cp = cp * 16 + hv
+ i = i + 1
+ return cp
// 解析 JSON 字符串(当前位置必须是 '"'),返回 J_STR 节点;失败返回 -1
-fn _jparse_str() -> int {
- if _jp_peek() != 34 { g_json_parse_failed = 1; return -1; }
- g_json_parse_pos = g_json_parse_pos + 1; // 消费 '"'
- off := g_json_strs_len;
- loop {
- if g_json_parse_pos >= _jp_len() { g_json_parse_failed = 1; return -1; } // 未闭合
- c := load8(g_json_parse_text, g_json_parse_pos);
- if c == 34 {
- g_json_parse_pos = g_json_parse_pos + 1;
- n := json_new(J_STR);
- json_set(n, 1, off);
- json_set(n, 2, g_json_strs_len - off);
- g_json_str_count = g_json_str_count + 1;
- return n;
- }
- if c == 92 { // '\'
- g_json_parse_pos = g_json_parse_pos + 1;
- if g_json_parse_pos >= _jp_len() { g_json_parse_failed = 1; return -1; }
- e := load8(g_json_parse_text, g_json_parse_pos);
- g_json_parse_pos = g_json_parse_pos + 1;
- if e == 34 { _jstr_byte(34); }
- else if e == 92 { _jstr_byte(92); }
- else if e == 47 { _jstr_byte(47); }
- else if e == 98 { _jstr_byte(8); }
- else if e == 102 { _jstr_byte(12); }
- else if e == 110 { _jstr_byte(10); }
- else if e == 114 { _jstr_byte(13); }
- else if e == 116 { _jstr_byte(9); }
- else if e == 117 { // 'u'
- if g_json_parse_pos + 4 > _jp_len() { g_json_parse_failed = 1; return -1; }
- cp := _jparse_hex4(g_json_parse_pos);
- if cp < 0 { return -1; }
- g_json_parse_pos = g_json_parse_pos + 4;
- if cp >= 55296 && cp <= 56319 {
+fn _jparse_str() -> int:
+ if _jp_peek() != 34:
+ g_json_parse_failed = 1
+ return -1
+ g_json_parse_pos = g_json_parse_pos + 1 // 消费 '"'
+ off := g_json_strs_len
+ loop:
+ if g_json_parse_pos >= _jp_len():
+ g_json_parse_failed = 1
+ return -1
+ // 未闭合
+ c := load8(g_json_parse_text, g_json_parse_pos)
+ if c == 34:
+ g_json_parse_pos = g_json_parse_pos + 1
+ n := json_new(J_STR)
+ json_set(n, 1, off)
+ json_set(n, 2, g_json_strs_len - off)
+ g_json_str_count = g_json_str_count + 1
+ return n
+ if c == 92:
+ // '\'
+ g_json_parse_pos = g_json_parse_pos + 1
+ if g_json_parse_pos >= _jp_len():
+ g_json_parse_failed = 1
+ return -1
+ e := load8(g_json_parse_text, g_json_parse_pos)
+ g_json_parse_pos = g_json_parse_pos + 1
+ if e == 34:
+ _jstr_byte(34)
+ else if e == 92:
+ _jstr_byte(92)
+ else if e == 47:
+ _jstr_byte(47)
+ else if e == 98:
+ _jstr_byte(8)
+ else if e == 102:
+ _jstr_byte(12)
+ else if e == 110:
+ _jstr_byte(10)
+ else if e == 114:
+ _jstr_byte(13)
+ else if e == 116:
+ _jstr_byte(9)
+ else if e == 117:
+ // 'u'
+ if g_json_parse_pos + 4 > _jp_len():
+ g_json_parse_failed = 1
+ return -1
+ cp := _jparse_hex4(g_json_parse_pos)
+ if cp < 0:
+ return -1
+ g_json_parse_pos = g_json_parse_pos + 4
+ if cp >= 55296 && cp <= 56319:
// A high surrogate must be immediately followed by a low
// surrogate escape; store the resulting scalar as UTF-8.
- if g_json_parse_pos + 6 > _jp_len() ||
- load8(g_json_parse_text, g_json_parse_pos) != 92 ||
- load8(g_json_parse_text, g_json_parse_pos + 1) != 117 {
- g_json_parse_failed = 1; return -1;
- }
- low := _jparse_hex4(g_json_parse_pos + 2);
- if low < 56320 || low > 57343 { g_json_parse_failed = 1; return -1; }
- g_json_parse_pos = g_json_parse_pos + 6;
- cp = 65536 + (cp - 55296) * 1024 + (low - 56320);
- } else if cp >= 56320 && cp <= 57343 {
- g_json_parse_failed = 1; return -1;
- }
- _jstr_cp(cp);
- }
- else { g_json_parse_failed = 1; return -1; } // 未知转义
- } else if c < 32 {
- g_json_parse_failed = 1; return -1; // 控制字符必须转义
- } else {
- _jstr_byte(c); // 原始字节(UTF-8 直通)
- g_json_parse_pos = g_json_parse_pos + 1;
- }
- }
-}
+ if g_json_parse_pos + 6 > _jp_len() || load8(g_json_parse_text, g_json_parse_pos) != 92 || load8(g_json_parse_text, g_json_parse_pos + 1) != 117:
+ g_json_parse_failed = 1
+ return -1
+ low := _jparse_hex4(g_json_parse_pos + 2)
+ if low < 56320 || low > 57343:
+ g_json_parse_failed = 1
+ return -1
+ g_json_parse_pos = g_json_parse_pos + 6
+ cp = 65536 + (cp - 55296) * 1024 + (low - 56320)
+ else if cp >= 56320 && cp <= 57343:
+ g_json_parse_failed = 1
+ return -1
+ _jstr_cp(cp)
+ else:
+ g_json_parse_failed = 1
+ return -1
+ // 未知转义
+ else if c < 32:
+ g_json_parse_failed = 1
+ return -1 // 控制字符必须转义
+ else:
+ _jstr_byte(c) // 原始字节(UTF-8 直通)
+ g_json_parse_pos = g_json_parse_pos + 1
// ── 值解析(递归下降)──
-fn _jparse_obj(depth: int) -> int {
- if depth > J_MAX_PARSE_DEPTH { g_json_parse_failed = 1; return -1; }
- g_json_parse_pos = g_json_parse_pos + 1; // 消费 '{'
- tbl : ., mut = -1; // 成员表偏移(惰性:首成员时分配)
- count : ., mut = 0;
- loop {
- _jskip_ws();
- if _jp_peek() == 125 { // '}'
- g_json_parse_pos = g_json_parse_pos + 1;
- break;
- }
- if count > 0 {
- if _jp_peek() != 44 { g_json_parse_failed = 1; return -1; } // ','
- g_json_parse_pos = g_json_parse_pos + 1;
- _jskip_ws();
- }
- key_node := _jparse_str();
- if key_node < 0 { return -1; }
- _jskip_ws();
- if _jp_peek() != 58 { g_json_parse_failed = 1; return -1; } // ':'
- g_json_parse_pos = g_json_parse_pos + 1;
- val := parse_value(depth + 1);
- if val < 0 { return -1; }
+fn _jparse_obj(depth: int) -> int:
+ if depth > J_MAX_PARSE_DEPTH:
+ g_json_parse_failed = 1
+ return -1
+ g_json_parse_pos = g_json_parse_pos + 1 // 消费 '{'
+ tbl : ., mut = -1 // 成员表偏移(惰性:首成员时分配)
+ count : ., mut = 0
+ loop:
+ _jskip_ws()
+ if _jp_peek() == 125:
+ // '}'
+ g_json_parse_pos = g_json_parse_pos + 1
+ break
+ if count > 0:
+ if _jp_peek() != 44:
+ g_json_parse_failed = 1
+ return -1
+ // ','
+ g_json_parse_pos = g_json_parse_pos + 1
+ _jskip_ws()
+ key_node := _jparse_str()
+ if key_node < 0:
+ return -1
+ _jskip_ws()
+ if _jp_peek() != 58:
+ g_json_parse_failed = 1
+ return -1
+ // ':'
+ g_json_parse_pos = g_json_parse_pos + 1
+ val := parse_value(depth + 1)
+ if val < 0:
+ return -1
// 表 = 可增长列表:新成员时把已有成员迁移到当前末尾(子容器表在下方,
// 不受影响),再写入新成员——保证成员表连续且不与子容器表重叠。
- if count == 0 {
- tbl = g_json_tables_len;
- _json_grow_tables(tbl + J_MEMBER_BYTES);
- g_json_tables_len = tbl + J_MEMBER_BYTES;
- } else {
- npos := g_json_tables_len;
- need := npos + (count + 1) * J_MEMBER_BYTES;
- _json_grow_tables(need);
- ci : ., mut = 0;
- loop {
- if ci >= count * J_MEMBER_BYTES { break; }
- store8(g_json_tables, npos + ci, load8(g_json_tables, tbl + ci));
- ci = ci + 1;
- }
- tbl = npos;
- g_json_tables_len = need;
- }
- _jw64(g_json_tables, tbl + count * J_MEMBER_BYTES, json_get(key_node, 1));
- _jw64(g_json_tables, tbl + count * J_MEMBER_BYTES + 8, json_get(key_node, 2));
- _jw64(g_json_tables, tbl + count * J_MEMBER_BYTES + 16, val);
- count = count + 1;
- }
- if count == 0 { tbl = g_json_tables_len; }
- n := json_new(J_OBJ);
- json_set(n, 1, tbl);
- json_set(n, 2, count);
- return n;
-}
-
-fn _jparse_arr(depth: int) -> int {
- if depth > J_MAX_PARSE_DEPTH { g_json_parse_failed = 1; return -1; }
- g_json_parse_pos = g_json_parse_pos + 1; // 消费 '['
- tbl : ., mut = -1; // 元素表偏移(惰性:首元素时分配)
- count : ., mut = 0;
- loop {
- _jskip_ws();
- if _jp_peek() == 93 { // ']'
- g_json_parse_pos = g_json_parse_pos + 1;
- break;
- }
- if count > 0 {
- if _jp_peek() != 44 { g_json_parse_failed = 1; return -1; }
- g_json_parse_pos = g_json_parse_pos + 1;
- _jskip_ws();
- }
- v := parse_value(depth + 1);
- if v < 0 { return -1; }
- if count == 0 {
- tbl = g_json_tables_len;
- _json_grow_tables(tbl + J_ELEM_BYTES);
- g_json_tables_len = tbl + J_ELEM_BYTES;
- } else {
- npos := g_json_tables_len;
- need := npos + (count + 1) * J_ELEM_BYTES;
- _json_grow_tables(need);
- ci : ., mut = 0;
- loop {
- if ci >= count * J_ELEM_BYTES { break; }
- store8(g_json_tables, npos + ci, load8(g_json_tables, tbl + ci));
- ci = ci + 1;
- }
- tbl = npos;
- g_json_tables_len = need;
- }
- _jw64(g_json_tables, tbl + count * J_ELEM_BYTES, v);
- count = count + 1;
- }
- if count == 0 { tbl = g_json_tables_len; }
- n := json_new(J_ARRAY);
- json_set(n, 1, tbl);
- json_set(n, 2, count);
- return n;
-}
-
-fn parse_value(depth: int) -> int {
- if depth > J_MAX_PARSE_DEPTH { g_json_parse_failed = 1; return -1; }
- _jskip_ws();
- c := _jp_peek();
- if c < 0 { return -1; }
- if c == 123 { return _jparse_obj(depth); }
- if c == 91 { return _jparse_arr(depth); }
- if c == 34 { return _jparse_str(); }
- if c == 116 { // 't' → true
- if _jk_match("true") != 0 { n1 := json_new(J_BOOL); json_set(n1, 1, 1); return n1; }
- return -1;
- }
- if c == 102 { // 'f' → false
- if _jk_match("false") != 0 { n2 := json_new(J_BOOL); json_set(n2, 1, 0); return n2; }
- return -1;
- }
- if c == 110 { // 'n' → null
- if _jk_match("null") != 0 { return json_new(J_NULL); }
- return -1;
- }
- if c == 45 || (c >= 48 && c <= 57) { // '-' 或数字
- v := _jnum();
- if g_json_parse_failed != 0 { return -1; }
- n3 := json_new(J_NUM);
- json_set(n3, 1, v);
- return n3;
- }
- return -1;
-}
+ if count == 0:
+ tbl = g_json_tables_len
+ _json_grow_tables(tbl + J_MEMBER_BYTES)
+ g_json_tables_len = tbl + J_MEMBER_BYTES
+ else:
+ npos := g_json_tables_len
+ need := npos + (count + 1) * J_MEMBER_BYTES
+ _json_grow_tables(need)
+ ci : ., mut = 0
+ loop:
+ if ci >= count * J_MEMBER_BYTES:
+ break
+ store8(g_json_tables, npos + ci, load8(g_json_tables, tbl + ci))
+ ci = ci + 1
+ tbl = npos
+ g_json_tables_len = need
+ _jw64(g_json_tables, tbl + count * J_MEMBER_BYTES, json_get(key_node, 1))
+ _jw64(g_json_tables, tbl + count * J_MEMBER_BYTES + 8, json_get(key_node, 2))
+ _jw64(g_json_tables, tbl + count * J_MEMBER_BYTES + 16, val)
+ count = count + 1
+ if count == 0:
+ tbl = g_json_tables_len
+ n := json_new(J_OBJ)
+ json_set(n, 1, tbl)
+ json_set(n, 2, count)
+ return n
+
+fn _jparse_arr(depth: int) -> int:
+ if depth > J_MAX_PARSE_DEPTH:
+ g_json_parse_failed = 1
+ return -1
+ g_json_parse_pos = g_json_parse_pos + 1 // 消费 '['
+ tbl : ., mut = -1 // 元素表偏移(惰性:首元素时分配)
+ count : ., mut = 0
+ loop:
+ _jskip_ws()
+ if _jp_peek() == 93:
+ // ']'
+ g_json_parse_pos = g_json_parse_pos + 1
+ break
+ if count > 0:
+ if _jp_peek() != 44:
+ g_json_parse_failed = 1
+ return -1
+ g_json_parse_pos = g_json_parse_pos + 1
+ _jskip_ws()
+ v := parse_value(depth + 1)
+ if v < 0:
+ return -1
+ if count == 0:
+ tbl = g_json_tables_len
+ _json_grow_tables(tbl + J_ELEM_BYTES)
+ g_json_tables_len = tbl + J_ELEM_BYTES
+ else:
+ npos := g_json_tables_len
+ need := npos + (count + 1) * J_ELEM_BYTES
+ _json_grow_tables(need)
+ ci : ., mut = 0
+ loop:
+ if ci >= count * J_ELEM_BYTES:
+ break
+ store8(g_json_tables, npos + ci, load8(g_json_tables, tbl + ci))
+ ci = ci + 1
+ tbl = npos
+ g_json_tables_len = need
+ _jw64(g_json_tables, tbl + count * J_ELEM_BYTES, v)
+ count = count + 1
+ if count == 0:
+ tbl = g_json_tables_len
+ n := json_new(J_ARRAY)
+ json_set(n, 1, tbl)
+ json_set(n, 2, count)
+ return n
+
+fn parse_value(depth: int) -> int:
+ if depth > J_MAX_PARSE_DEPTH:
+ g_json_parse_failed = 1
+ return -1
+ _jskip_ws()
+ c := _jp_peek()
+ if c < 0:
+ return -1
+ if c == 123:
+ return _jparse_obj(depth)
+ if c == 91:
+ return _jparse_arr(depth)
+ if c == 34:
+ return _jparse_str()
+ if c == 116:
+ // 't' → true
+ if _jk_match("true") != 0:
+ n1 := json_new(J_BOOL)
+ json_set(n1, 1, 1)
+ return n1
+ return -1
+ if c == 102:
+ // 'f' → false
+ if _jk_match("false") != 0:
+ n2 := json_new(J_BOOL)
+ json_set(n2, 1, 0)
+ return n2
+ return -1
+ if c == 110:
+ // 'n' → null
+ if _jk_match("null") != 0:
+ return json_new(J_NULL)
+ return -1
+ if c == 45 || (c >= 48 && c <= 57):
+ // '-' 或数字
+ v := _jnum()
+ if g_json_parse_failed != 0:
+ return -1
+ n3 := json_new(J_NUM)
+ json_set(n3, 1, v)
+ return n3
+ return -1
// ── 公开解析接口 ──
// 解析 JSON 文本 → 根节点索引;失败返回 -1。每次调用重置全部池。
-fn json_parse(text: string) -> int {
- g_json_count = 0;
- g_json_str_count = 0;
- g_json_strs_len = 0;
- g_json_tables_len = 0;
- g_json_parse_failed = 0;
- g_json_parse_depth = 0;
- g_json_parse_text = text;
- g_json_parse_pos = 0;
- idx := parse_value(0);
- if g_json_parse_failed != 0 { return -1; }
- if idx < 0 { return -1; }
- _jskip_ws();
- if g_json_parse_pos < _jp_len() { return -1; } // 尾部多余内容
- return idx;
-}
+fn json_parse(text: string) -> int:
+ g_json_count = 0
+ g_json_str_count = 0
+ g_json_strs_len = 0
+ g_json_tables_len = 0
+ g_json_parse_failed = 0
+ g_json_parse_depth = 0
+ g_json_parse_text = text
+ g_json_parse_pos = 0
+ idx := parse_value(0)
+ if g_json_parse_failed != 0:
+ return -1
+ if idx < 0:
+ return -1
+ _jskip_ws()
+ if g_json_parse_pos < _jp_len():
+ return -1
+ // 尾部多余内容
+ return idx
// ── 序列化 ──
-fn _jhex_digit(v: int) -> string {
- if v < 10 { return chr(48 + v); }
- return chr(65 + v - 10); // 大写 A-F
-}
+fn _jhex_digit(v: int) -> string:
+ if v < 10:
+ return chr(48 + v)
+ return chr(65 + v - 10) // 大写 A-F
// 码点 → \uXXXX(大写十六进制)
-fn _jhex4(v: int) -> string {
+fn _jhex4(v: int) -> string:
// 逐段累加:Python bootstrap 对 BinaryOp 结果变量不做字符串类型传播,
// 裸表达式链会被编译成整数 add(见 Task 1 报告);累加器从字面量初始化
// 则类型正确,两条管线(bootstrap/corec 与自举 corec)行为一致。
- out : string, mut = "\\u";
- out = out + _jhex_digit((v / 4096) % 16);
- out = out + _jhex_digit((v / 256) % 16);
- out = out + _jhex_digit((v / 16) % 16);
- out = out + _jhex_digit(v % 16);
- return out;
-}
+ out : string, mut = "\\u"
+ out = out + _jhex_digit((v / 4096) % 16)
+ out = out + _jhex_digit((v / 256) % 16)
+ out = out + _jhex_digit((v / 16) % 16)
+ out = out + _jhex_digit(v % 16)
+ return out
-g_json_utf8_cp : int, mut; // _jutf8_dec 的解码结果(内部暂存)
+g_json_utf8_cp : int, mut // _jutf8_dec 的解码结果(内部暂存)
// 从字符串池 off 处解码 UTF-8 序列;返回字节推进数(非法序列返回 1,cp = 原字节)
-fn _jutf8_dec(off: int) -> int {
- b0 := load8(g_json_strs, off);
- if b0 < 128 { g_json_utf8_cp = b0; return 1; }
- if b0 < 224 {
- if off + 1 < g_json_strs_len {
- b1 := load8(g_json_strs, off + 1);
- if b1 >= 128 && b1 < 192 {
- g_json_utf8_cp = (b0 - 192) * 64 + (b1 - 128);
- return 2;
- }
- }
- g_json_utf8_cp = b0; return 1;
- }
- if b0 < 240 {
- if off + 2 < g_json_strs_len {
- b1 := load8(g_json_strs, off + 1);
- b2 := load8(g_json_strs, off + 2);
- if b1 >= 128 && b1 < 192 && b2 >= 128 && b2 < 192 {
- g_json_utf8_cp = (b0 - 224) * 4096 + (b1 - 128) * 64 + (b2 - 128);
- return 3;
- }
- }
- g_json_utf8_cp = b0; return 1;
- }
- if off + 3 < g_json_strs_len {
- b1 := load8(g_json_strs, off + 1);
- b2 := load8(g_json_strs, off + 2);
- b3 := load8(g_json_strs, off + 3);
- if b1 >= 128 && b1 < 192 && b2 >= 128 && b2 < 192 && b3 >= 128 && b3 < 192 {
- g_json_utf8_cp = (b0 - 240) * 262144 + (b1 - 128) * 4096 + (b2 - 128) * 64 + (b3 - 128);
- return 4;
- }
- }
- g_json_utf8_cp = b0; return 1;
-}
+fn _jutf8_dec(off: int) -> int:
+ b0 := load8(g_json_strs, off)
+ if b0 < 128:
+ g_json_utf8_cp = b0
+ return 1
+ if b0 < 224:
+ if off + 1 < g_json_strs_len:
+ b1 := load8(g_json_strs, off + 1)
+ if b1 >= 128 && b1 < 192:
+ g_json_utf8_cp = (b0 - 192) * 64 + (b1 - 128)
+ return 2
+ g_json_utf8_cp = b0
+ return 1
+ if b0 < 240:
+ if off + 2 < g_json_strs_len:
+ b1 := load8(g_json_strs, off + 1)
+ b2 := load8(g_json_strs, off + 2)
+ if b1 >= 128 && b1 < 192 && b2 >= 128 && b2 < 192:
+ g_json_utf8_cp = (b0 - 224) * 4096 + (b1 - 128) * 64 + (b2 - 128)
+ return 3
+ g_json_utf8_cp = b0
+ return 1
+ if off + 3 < g_json_strs_len:
+ b1 := load8(g_json_strs, off + 1)
+ b2 := load8(g_json_strs, off + 2)
+ b3 := load8(g_json_strs, off + 3)
+ if b1 >= 128 && b1 < 192 && b2 >= 128 && b2 < 192 && b3 >= 128 && b3 < 192:
+ g_json_utf8_cp = (b0 - 240) * 262144 + (b1 - 128) * 4096 + (b2 - 128) * 64 + (b3 - 128)
+ return 4
+ g_json_utf8_cp = b0
+ return 1
// 池中字节段 → JSON 字符串文本(含引号;转义反转义;非 ASCII 一律 \uXXXX)
-fn _jstr_out(off: int, len: int) -> string {
- out : string, mut = "\"";
- i : ., mut = 0;
- loop {
- if i >= len { break; }
- b := load8(g_json_strs, off + i);
- if b == 34 { out = out + "\\\""; i = i + 1; }
- else if b == 92 { out = out + "\\\\"; i = i + 1; }
- else if b == 10 { out = out + "\\n"; i = i + 1; }
- else if b == 13 { out = out + "\\r"; i = i + 1; }
- else if b == 9 { out = out + "\\t"; i = i + 1; }
- else if b < 32 { out = out + _jhex4(b); i = i + 1; }
- else if b < 128 { out = out + chr(b); i = i + 1; }
- else {
- adv := _jutf8_dec(off + i);
- cp := g_json_utf8_cp;
- if cp >= 65536 {
+fn _jstr_out(off: int, len: int) -> string:
+ out : string, mut = "\""
+ i : ., mut = 0
+ loop:
+ if i >= len:
+ break
+ b := load8(g_json_strs, off + i)
+ if b == 34:
+ out = out + "\\\""
+ i = i + 1
+ else if b == 92:
+ out = out + "\\\\"
+ i = i + 1
+ else if b == 10:
+ out = out + "\\n"
+ i = i + 1
+ else if b == 13:
+ out = out + "\\r"
+ i = i + 1
+ else if b == 9:
+ out = out + "\\t"
+ i = i + 1
+ else if b < 32:
+ out = out + _jhex4(b)
+ i = i + 1
+ else if b < 128:
+ out = out + chr(b)
+ i = i + 1
+ else:
+ adv := _jutf8_dec(off + i)
+ cp := g_json_utf8_cp
+ if cp >= 65536:
// 非 BMP:编码为代理对两个 \uXXXX(JSON 规范要求)
- c0 := cp - 65536;
- hi := 55296 + c0 / 1024; // 0xD800 + (cp-0x10000)>>10
- lo := 56320 + c0 % 1024; // 0xDC00 + (cp-0x10000)&0x3FF
- out = out + _jhex4(hi) + _jhex4(lo);
- } else {
- out = out + _jhex4(cp);
- }
- i = i + adv;
- }
- }
- out = out + "\"";
- return out;
-}
-
-fn _jstringify_rec(idx: int) -> string {
- k := json_get(idx, 0);
- if k == J_NULL { return "null"; }
- if k == J_BOOL {
- if json_get(idx, 1) != 0 { return "true"; }
- return "false";
- }
- if k == J_NUM { return int_str(json_get(idx, 1)); }
- if k == J_STR { return _jstr_out(json_get(idx, 1), json_get(idx, 2)); }
- if k == J_ARRAY {
- tbl := json_get(idx, 1);
- cnt := json_get(idx, 2);
- out : string, mut = "[";
- i : ., mut = 0;
- loop {
- if i >= cnt { break; }
- if i > 0 { out = out + ","; }
- out = out + _jstringify_rec(_jr64(g_json_tables, tbl + i * J_ELEM_BYTES));
- i = i + 1;
- }
- out = out + "]";
- return out;
- }
- if k == J_OBJ {
- tbl := json_get(idx, 1);
- cnt := json_get(idx, 2);
- out : string, mut = "{";
- i : ., mut = 0;
- loop {
- if i >= cnt { break; }
- if i > 0 { out = out + ","; }
- koff := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES);
- klen := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES + 8);
- v := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES + 16);
- out = out + _jstr_out(koff, klen) + ":" + _jstringify_rec(v);
- i = i + 1;
- }
- out = out + "}";
- return out;
- }
- return "null";
-}
+ c0 := cp - 65536
+ hi := 55296 + c0 / 1024 // 0xD800 + (cp-0x10000)>>10
+ lo := 56320 + c0 % 1024 // 0xDC00 + (cp-0x10000)&0x3FF
+ out = out + _jhex4(hi) + _jhex4(lo)
+ else:
+ out = out + _jhex4(cp)
+ i = i + adv
+ out = out + "\""
+ return out
+
+fn _jstringify_rec(idx: int) -> string:
+ k := json_get(idx, 0)
+ if k == J_NULL:
+ return "null"
+ if k == J_BOOL:
+ if json_get(idx, 1) != 0:
+ return "true"
+ return "false"
+ if k == J_NUM:
+ return int_str(json_get(idx, 1))
+ if k == J_STR:
+ return _jstr_out(json_get(idx, 1), json_get(idx, 2))
+ if k == J_ARRAY:
+ tbl := json_get(idx, 1)
+ cnt := json_get(idx, 2)
+ out : string, mut = "["
+ i : ., mut = 0
+ loop:
+ if i >= cnt:
+ break
+ if i > 0:
+ out = out + ","
+ out = out + _jstringify_rec(_jr64(g_json_tables, tbl + i * J_ELEM_BYTES))
+ i = i + 1
+ out = out + "]"
+ return out
+ if k == J_OBJ:
+ tbl := json_get(idx, 1)
+ cnt := json_get(idx, 2)
+ out : string, mut = "{"
+ i : ., mut = 0
+ loop:
+ if i >= cnt:
+ break
+ if i > 0:
+ out = out + ","
+ koff := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES)
+ klen := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES + 8)
+ v := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES + 16)
+ out = out + _jstr_out(koff, klen) + ":" + _jstringify_rec(v)
+ i = i + 1
+ out = out + "}"
+ return out
+ return "null"
// 节点 → JSON 文本;非法索引返回空串
-fn json_stringify(idx: int) -> string {
- if idx < 0 || idx % J_NODE_SLOTS != 0 || idx / J_NODE_SLOTS >= g_json_count ||
- g_json_count == 0 { return ""; }
- return _jstringify_rec(idx);
-}
+fn json_stringify(idx: int) -> string:
+ if idx < 0 || idx % J_NODE_SLOTS != 0 || idx / J_NODE_SLOTS >= g_json_count || g_json_count == 0:
+ return ""
+ return _jstringify_rec(idx)
// ── 查找接口(Task 2-6 依赖)──
// 对象按键查找:线性扫描成员表;找不到返回 -1
-fn json_obj_get(obj: int, key: string) -> int {
- if obj < 0 || obj % J_NODE_SLOTS != 0 || obj / J_NODE_SLOTS >= g_json_count ||
- json_get(obj, 0) != J_OBJ { return -1; }
- tbl := json_get(obj, 1);
- cnt := json_get(obj, 2);
- kl := str_len(key);
- found_value : ., mut = -1;
- i : ., mut = 0;
- loop {
- if i >= cnt { break; }
- koff := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES);
- klen := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES + 8);
- if klen == kl {
- matched : ., mut = 1;
- j : ., mut = 0;
- loop {
- if j >= kl { break; }
- if load8(g_json_strs, koff + j) != load8(key, j) { matched = 0; break; }
- j = j + 1;
- }
- if matched != 0 { found_value = _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES + 16); }
- }
- i = i + 1;
- }
- return found_value;
-}
+fn json_obj_get(obj: int, key: string) -> int:
+ if obj < 0 || obj % J_NODE_SLOTS != 0 || obj / J_NODE_SLOTS >= g_json_count || json_get(obj, 0) != J_OBJ:
+ return -1
+ tbl := json_get(obj, 1)
+ cnt := json_get(obj, 2)
+ kl := str_len(key)
+ found_value : ., mut = -1
+ i : ., mut = 0
+ loop:
+ if i >= cnt:
+ break
+ koff := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES)
+ klen := _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES + 8)
+ if klen == kl:
+ matched : ., mut = 1
+ j : ., mut = 0
+ loop:
+ if j >= kl:
+ break
+ if load8(g_json_strs, koff + j) != load8(key, j):
+ matched = 0
+ break
+ j = j + 1
+ if matched != 0:
+ found_value = _jr64(g_json_tables, tbl + i * J_MEMBER_BYTES + 16)
+ i = i + 1
+ return found_value
// 数组按下标取元素;越界或非数组返回 -1
-fn json_array_get(arr: int, i: int) -> int {
- if arr < 0 || arr % J_NODE_SLOTS != 0 || arr / J_NODE_SLOTS >= g_json_count ||
- json_get(arr, 0) != J_ARRAY { return -1; }
- cnt := json_get(arr, 2);
- if i < 0 || i >= cnt { return -1; }
- tbl := json_get(arr, 1);
- return _jr64(g_json_tables, tbl + i * J_ELEM_BYTES);
-}
+fn json_array_get(arr: int, i: int) -> int:
+ if arr < 0 || arr % J_NODE_SLOTS != 0 || arr / J_NODE_SLOTS >= g_json_count || json_get(arr, 0) != J_ARRAY:
+ return -1
+ cnt := json_get(arr, 2)
+ if i < 0 || i >= cnt:
+ return -1
+ tbl := json_get(arr, 1)
+ return _jr64(g_json_tables, tbl + i * J_ELEM_BYTES)
diff --git a/src/lsp/lsp.cr b/src/lsp/lsp.cr
index ee9b0624..822dcdb1 100644
--- a/src/lsp/lsp.cr
+++ b/src/lsp/lsp.cr
@@ -21,306 +21,329 @@
// 注意(Python bootstrap 地雷):字符串累加必须从字面量初始化的
// `: string, mut` 累加器出发;本文件所有拼接均遵循该模式。
-g_lsp_snapshot_path : string, mut;
+g_lsp_snapshot_path : string, mut
-fn lsp_request_matches_snapshot(root: int) -> int {
- params := json_obj_get(root, "params");
- if params < 0 { return 0; }
- td := json_obj_get(params, "textDocument");
- if td < 0 { return 0; }
- un := json_obj_get(td, "uri");
- if un < 0 || json_get(un, 0) != J_STR { return 0; }
- uri := lsp_str_pool_copy(json_get(un, 1), json_get(un, 2));
- return str_eq(lsp_uri_to_path(uri), g_lsp_snapshot_path);
-}
+fn lsp_request_matches_snapshot(root: int) -> int:
+ params := json_obj_get(root, "params")
+ if params < 0:
+ return 0
+ td := json_obj_get(params, "textDocument")
+ if td < 0:
+ return 0
+ un := json_obj_get(td, "uri")
+ if un < 0 || json_get(un, 0) != J_STR:
+ return 0
+ uri := lsp_str_pool_copy(json_get(un, 1), json_get(un, 2))
+ return str_eq(lsp_uri_to_path(uri), g_lsp_snapshot_path)
// 从 JSON 字符串池复制字节段 → 稳定堆字符串。
// 池在每次 json_parse 会被重置复用,直接存池内指针会在下一帧失效。
-fn lsp_str_pool_copy(off: int, len: int) -> string {
- s := alloc(len + 1);
- i : ., mut = 0;
- loop {
- if i >= len { break; }
- store8(s, i, load8(g_json_strs, off + i));
- i = i + 1;
- }
- store8(s, len, 0);
- return s;
-}
+fn lsp_str_pool_copy(off: int, len: int) -> string:
+ s := alloc(len + 1)
+ i : ., mut = 0
+ loop:
+ if i >= len:
+ break
+ store8(s, i, load8(g_json_strs, off + i))
+ i = i + 1
+ store8(s, len, 0)
+ return s
// "file:///tmp/x.cr" → "/tmp/x.cr";无前缀原样返回
-fn lsp_uri_to_path(uri: string) -> string {
- ul := str_len(uri);
- if ul >= 7 && load8(uri, 0) == 102 && load8(uri, 1) == 105 &&
- load8(uri, 2) == 108 && load8(uri, 3) == 101 &&
- load8(uri, 4) == 58 && load8(uri, 5) == 47 && load8(uri, 6) == 47 {
- return str_sub(uri, 7, ul - 7);
- }
- return uri;
-}
+fn lsp_uri_to_path(uri: string) -> string:
+ ul := str_len(uri)
+ if ul >= 7 && load8(uri, 0) == 102 && load8(uri, 1) == 105 && load8(uri, 2) == 108 && load8(uri, 3) == 101 && load8(uri, 4) == 58 && load8(uri, 5) == 47 && load8(uri, 6) == 47:
+ return str_sub(uri, 7, ul - 7)
+ return uri
// JSON 字符串转义(诊断消息含引号/反斜杠/控制符时保证合法 JSON)
-fn lsp_json_escape_str(s: string) -> string {
- sl := str_len(s);
- out : string, mut = "\"";
- i : ., mut = 0;
- loop {
- if i >= sl { break; }
- c := load8(s, i);
- if c == 34 { out = out + "\\\""; }
- else if c == 92 { out = out + "\\\\"; }
- else if c == 10 { out = out + "\\n"; }
- else if c == 13 { out = out + "\\r"; }
- else if c == 9 { out = out + "\\t"; }
- else if c < 32 { out = out + _jhex4(c); }
- else { out = out + chr(c); }
- i = i + 1;
- }
- out = out + "\"";
- return out;
-}
+fn lsp_json_escape_str(s: string) -> string:
+ sl := str_len(s)
+ out : string, mut = "\""
+ i : ., mut = 0
+ loop:
+ if i >= sl:
+ break
+ c := load8(s, i)
+ if c == 34:
+ out = out + "\\\""
+ else if c == 92:
+ out = out + "\\\\"
+ else if c == 10:
+ out = out + "\\n"
+ else if c == 13:
+ out = out + "\\r"
+ else if c == 9:
+ out = out + "\\t"
+ else if c < 32:
+ out = out + _jhex4(c)
+ else:
+ out = out + chr(c)
+ i = i + 1
+ out = out + "\""
+ return out
// 单条诊断 → JSON 片段(范围 1-based → 0-based 减 1;severity=1 错误)
-fn lsp_diag_json(di: int) -> string {
- ln := r64(g_diags, di * DIAG_REC_SIZE + 16);
- cl := r64(g_diags, di * DIAG_REC_SIZE + 24);
- msg := load_str_ptr(g_diags, di * DIAG_REC_SIZE + 8);
- line0 : ., mut = ln - 1; if line0 < 0 { line0 = 0; }
- col0 : ., mut = cl - 1; if col0 < 0 { col0 = 0; }
- out : string, mut = "{\"range\":{\"start\":{\"line\":";
- out = out + int_str(line0);
- out = out + ",\"character\":";
- out = out + int_str(col0);
- out = out + "},\"end\":{\"line\":";
- out = out + int_str(line0);
- out = out + ",\"character\":";
- out = out + int_str(col0 + 1);
- out = out + "}},\"severity\":1,\"message\":";
- out = out + lsp_json_escape_str(msg);
- out = out + "}";
- return out;
-}
+fn lsp_diag_json(di: int) -> string:
+ ln := r64(g_diags, di * DIAG_REC_SIZE + 16)
+ cl := r64(g_diags, di * DIAG_REC_SIZE + 24)
+ msg := load_str_ptr(g_diags, di * DIAG_REC_SIZE + 8)
+ line0 : ., mut = ln - 1
+ if line0 < 0:
+ line0 = 0
+ col0 : ., mut = cl - 1
+ if col0 < 0:
+ col0 = 0
+ out : string, mut = "{\"range\":{\"start\":{\"line\":"
+ out = out + int_str(line0)
+ out = out + ",\"character\":"
+ out = out + int_str(col0)
+ out = out + "},\"end\":{\"line\":"
+ out = out + int_str(line0)
+ out = out + ",\"character\":"
+ out = out + int_str(col0 + 1)
+ out = out + "}},\"severity\":1,\"message\":"
+ out = out + lsp_json_escape_str(msg)
+ out = out + "}"
+ return out
// 发送某文件(file_id = fni)的 publishDiagnostics 通知;fni = -1 时无匹配
// 诊断 → 空数组(清诊断用)
-fn lsp_send_file_diags(uri: string, fni: int) {
- out : string, mut = "{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/publishDiagnostics\",\"params\":{\"uri\":";
- out = out + lsp_json_escape_str(uri);
- out = out + ",\"diagnostics\":[";
- first : ., mut = 1;
- i : ., mut = 0;
- loop {
- if i >= g_diag_count { break; }
- if r64(g_diags, i * DIAG_REC_SIZE + 32) == fni {
- if first == 0 { out = out + ","; }
- out = out + lsp_diag_json(i);
- first = 0;
- }
- i = i + 1;
- }
- out = out + "]}}";
- rpc_send(out);
-}
+fn lsp_send_file_diags(uri: string, fni: int):
+ out : string, mut = "{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/publishDiagnostics\",\"params\":{\"uri\":"
+ out = out + lsp_json_escape_str(uri)
+ out = out + ",\"diagnostics\":["
+ first : ., mut = 1
+ i : ., mut = 0
+ loop:
+ if i >= g_diag_count:
+ break
+ if r64(g_diags, i * DIAG_REC_SIZE + 32) == fni:
+ if first == 0:
+ out = out + ","
+ out = out + lsp_diag_json(i)
+ first = 0
+ i = i + 1
+ out = out + "]}}"
+ rpc_send(out)
// 对所有有诊断的文件发布;主文件无条件发布(空数组清旧诊断)
-fn lsp_publish_diags() {
- main_fni : ., mut = -1;
- if g_file_count > 0 { main_fni = r64(g_files, 0); }
- main_uri : string, mut = "file://";
- if g_file_count > 0 {
- mp := load_str_ptr(g_files, 8);
- if str_len(mp) > 0 { main_uri = "file://" + mp; }
- }
- lsp_send_file_diags(main_uri, main_fni);
+fn lsp_publish_diags():
+ main_fni : ., mut = -1
+ if g_file_count > 0:
+ main_fni = r64(g_files, 0)
+ main_uri : string, mut = "file://"
+ if g_file_count > 0:
+ mp := load_str_ptr(g_files, 8)
+ if str_len(mp) > 0:
+ main_uri = "file://" + mp
+ lsp_send_file_diags(main_uri, main_fni)
// 其余文件:仅发布有诊断者(按 file_id 去重,经 g_files 路径表映射 uri)
- i : ., mut = 0;
- loop {
- if i >= g_diag_count { break; }
- fni := r64(g_diags, i * DIAG_REC_SIZE + 32);
- if fni != main_fni && fni >= 0 {
- uri : string, mut = "file://";
- fi : ., mut = 0;
- loop {
- if fi >= g_file_count { break; }
- if r64(g_files, fi * 16) == fni {
- fp := load_str_ptr(g_files, fi * 16 + 8);
- if str_len(fp) > 0 { uri = "file://" + fp; }
- break;
- }
- fi = fi + 1;
- }
- if str_len(uri) > 7 {
- already : ., mut = 0;
- j : ., mut = 0;
- loop {
- if j >= i { break; }
- if r64(g_diags, j * DIAG_REC_SIZE + 32) == fni { already = 1; break; }
- j = j + 1;
- }
- if already == 0 { lsp_send_file_diags(uri, fni); }
- }
- }
- i = i + 1;
- }
-}
+ i : ., mut = 0
+ loop:
+ if i >= g_diag_count:
+ break
+ fni := r64(g_diags, i * DIAG_REC_SIZE + 32)
+ if fni != main_fni && fni >= 0:
+ uri : string, mut = "file://"
+ fi : ., mut = 0
+ loop:
+ if fi >= g_file_count:
+ break
+ if r64(g_files, fi * 16) == fni:
+ fp := load_str_ptr(g_files, fi * 16 + 8)
+ if str_len(fp) > 0:
+ uri = "file://" + fp
+ break
+ fi = fi + 1
+ if str_len(uri) > 7:
+ already : ., mut = 0
+ j : ., mut = 0
+ loop:
+ if j >= i:
+ break
+ if r64(g_diags, j * DIAG_REC_SIZE + 32) == fni:
+ already = 1
+ break
+ j = j + 1
+ if already == 0:
+ lsp_send_file_diags(uri, fni)
+ i = i + 1
// 静默检查管线(禁止 run_frontend——进度 println 污染协议通道)
-fn lsp_check_file(path: string, src: string) {
- g_lsp_snapshot_path = path;
- g_source = src;
- g_source_dir = dirname(path);
- reset_frontend_state();
- tokenize(g_source);
- res_imports();
+fn lsp_check_file(path: string, src: string):
+ g_lsp_snapshot_path = path
+ g_source = src
+ g_source_dir = dirname(path)
+ reset_frontend_state()
+ tokenize(g_source, 0)
+ res_imports()
// res_imports 把主文件注册到 g_files[0] 时路径为空串——补上真实路径
// (供 publishDiagnostics 的 file_id → uri 映射;path 为稳定堆字符串)。
// 记录布局 {file_id@0, path@8}(module.cr reg_fileid)——旧代码误写 +16
// (记录 1 的 id 槽)仅靠读写同侧巧合工作,Task 4 的 analysis 按真实布局
// 读 +8 会拿到空串,故统一为 +8(root cause 修复)。
- if g_file_count > 0 { store_str_ptr(g_files, 8, path); }
- parse_all();
- if g_diag_count > 0 {
+ if g_file_count > 0:
+ store_str_ptr(g_files, 8, path)
+ parse_all()
+ if g_diag_count > 0:
// parse 阶段诊断:AST 可能不完整,跳过 check_all(与 run_frontend 一致)
- lsp_publish_diags();
- return;
- }
- check_all();
- lsp_publish_diags();
-}
+ lsp_publish_diags()
+ return
+ check_all()
+ lsp_publish_diags()
// ── 文档同步处理器(通知,不回响应)───────────────────────────────
-fn lsp_did_open(root: int) {
- params := json_obj_get(root, "params");
- if params < 0 { return; }
- td := json_obj_get(params, "textDocument");
- if td < 0 { return; }
- uri_node := json_obj_get(td, "uri");
- text_node := json_obj_get(td, "text");
- if uri_node < 0 || text_node < 0 { return; }
- if json_get(uri_node, 0) != J_STR || json_get(text_node, 0) != J_STR { return; }
- uri := lsp_str_pool_copy(json_get(uri_node, 1), json_get(uri_node, 2));
- src := lsp_str_pool_copy(json_get(text_node, 1), json_get(text_node, 2));
- path := lsp_uri_to_path(uri);
- module_open_doc_set(path, src);
- lsp_check_file(path, src);
-}
+fn lsp_did_open(root: int):
+ params := json_obj_get(root, "params")
+ if params < 0:
+ return
+ td := json_obj_get(params, "textDocument")
+ if td < 0:
+ return
+ uri_node := json_obj_get(td, "uri")
+ text_node := json_obj_get(td, "text")
+ if uri_node < 0 || text_node < 0:
+ return
+ if json_get(uri_node, 0) != J_STR || json_get(text_node, 0) != J_STR:
+ return
+ uri := lsp_str_pool_copy(json_get(uri_node, 1), json_get(uri_node, 2))
+ src := lsp_str_pool_copy(json_get(text_node, 1), json_get(text_node, 2))
+ path := lsp_uri_to_path(uri)
+ module_open_doc_set(path, src)
+ lsp_check_file(path, src)
-fn lsp_did_change(root: int) {
- params := json_obj_get(root, "params");
- if params < 0 { return; }
- td := json_obj_get(params, "textDocument");
- changes := json_obj_get(params, "contentChanges");
- if td < 0 || changes < 0 { return; }
- uri_node := json_obj_get(td, "uri");
- if uri_node < 0 || json_get(uri_node, 0) != J_STR { return; }
+fn lsp_did_change(root: int):
+ params := json_obj_get(root, "params")
+ if params < 0:
+ return
+ td := json_obj_get(params, "textDocument")
+ changes := json_obj_get(params, "contentChanges")
+ if td < 0 || changes < 0:
+ return
+ uri_node := json_obj_get(td, "uri")
+ if uri_node < 0 || json_get(uri_node, 0) != J_STR:
+ return
// 全量同步(textDocumentSync=1):contentChanges[0].text = 完整新文本
- c0 := json_array_get(changes, 0);
- text_node : ., mut = -1;
- if c0 >= 0 { text_node = json_obj_get(c0, "text"); }
- if text_node < 0 || json_get(text_node, 0) != J_STR { return; }
- uri := lsp_str_pool_copy(json_get(uri_node, 1), json_get(uri_node, 2));
- src := lsp_str_pool_copy(json_get(text_node, 1), json_get(text_node, 2));
- path := lsp_uri_to_path(uri);
- module_open_doc_set(path, src);
- lsp_check_file(path, src);
-}
+ c0 := json_array_get(changes, 0)
+ text_node : ., mut = -1
+ if c0 >= 0:
+ text_node = json_obj_get(c0, "text")
+ if text_node < 0 || json_get(text_node, 0) != J_STR:
+ return
+ uri := lsp_str_pool_copy(json_get(uri_node, 1), json_get(uri_node, 2))
+ src := lsp_str_pool_copy(json_get(text_node, 1), json_get(text_node, 2))
+ path := lsp_uri_to_path(uri)
+ module_open_doc_set(path, src)
+ lsp_check_file(path, src)
-fn lsp_did_save(root: int) {
- params := json_obj_get(root, "params");
- if params < 0 { return; }
- td := json_obj_get(params, "textDocument");
- if td < 0 { return; }
- uri_node := json_obj_get(td, "uri");
- if uri_node < 0 || json_get(uri_node, 0) != J_STR { return; }
- uri := lsp_str_pool_copy(json_get(uri_node, 1), json_get(uri_node, 2));
- path := lsp_uri_to_path(uri);
+fn lsp_did_save(root: int):
+ params := json_obj_get(root, "params")
+ if params < 0:
+ return
+ td := json_obj_get(params, "textDocument")
+ if td < 0:
+ return
+ uri_node := json_obj_get(td, "uri")
+ if uri_node < 0 || json_get(uri_node, 0) != J_STR:
+ return
+ uri := lsp_str_pool_copy(json_get(uri_node, 1), json_get(uri_node, 2))
+ path := lsp_uri_to_path(uri)
// 重跑检查(源文本取打开文档——编辑器内存内容优先于磁盘)
- src := module_get_source(path);
- if str_len(src) > 0 { lsp_check_file(path, src); }
-}
+ src := module_get_source(path)
+ if str_len(src) > 0:
+ lsp_check_file(path, src)
-fn lsp_did_close(root: int) {
- params := json_obj_get(root, "params");
- if params < 0 { return; }
- td := json_obj_get(params, "textDocument");
- if td < 0 { return; }
- uri_node := json_obj_get(td, "uri");
- if uri_node < 0 || json_get(uri_node, 0) != J_STR { return; }
- uri := lsp_str_pool_copy(json_get(uri_node, 1), json_get(uri_node, 2));
- path := lsp_uri_to_path(uri);
- module_open_doc_remove(path);
- if str_eq(path, g_lsp_snapshot_path) != 0 { g_lsp_snapshot_path = ""; }
+fn lsp_did_close(root: int):
+ params := json_obj_get(root, "params")
+ if params < 0:
+ return
+ td := json_obj_get(params, "textDocument")
+ if td < 0:
+ return
+ uri_node := json_obj_get(td, "uri")
+ if uri_node < 0 || json_get(uri_node, 0) != J_STR:
+ return
+ uri := lsp_str_pool_copy(json_get(uri_node, 1), json_get(uri_node, 2))
+ path := lsp_uri_to_path(uri)
+ module_open_doc_remove(path)
+ if str_eq(path, g_lsp_snapshot_path) != 0:
+ g_lsp_snapshot_path = ""
// 清诊断:发布空数组
- lsp_send_file_diags("file://" + path, -1);
-}
+ lsp_send_file_diags("file://" + path, -1)
// ── hover / definition(Task 4)──────────────────────────────
// 请求(带 id)→ 响应。查询基于最后一次成功检查的快照(analysis.cr),
// 不触发检查。position 为 LSP 0-based;无结果 → result:null。
// 响应体:contents 非空 → {"contents": "<文本>"},否则 null
-fn lsp_send_hover_resp(root: int, contents: string) {
- idnode := json_obj_get(root, "id");
- id_val : ., mut = 0;
- if idnode >= 0 && json_get(idnode, 0) == J_NUM { id_val = json_get(idnode, 1); }
- out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":";
- out = out + int_str(id_val);
- if str_len(contents) == 0 {
- out = out + ",\"result\":null}";
- } else {
- out = out + ",\"result\":{\"contents\":";
- out = out + lsp_json_escape_str(contents);
- out = out + "}}";
- }
- rpc_send(out);
-}
+fn lsp_send_hover_resp(root: int, contents: string):
+ idnode := json_obj_get(root, "id")
+ id_val : ., mut = 0
+ if idnode >= 0 && json_get(idnode, 0) == J_NUM:
+ id_val = json_get(idnode, 1)
+ out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":"
+ out = out + int_str(id_val)
+ if str_len(contents) == 0:
+ out = out + ",\"result\":null}"
+ else:
+ out = out + ",\"result\":{\"contents\":"
+ out = out + lsp_json_escape_str(contents)
+ out = out + "}}"
+ rpc_send(out)
// 响应体:loc 非空 → {"uri","range"} Location,否则 null
-fn lsp_send_def_resp(root: int, loc: string) {
- idnode := json_obj_get(root, "id");
- id_val : ., mut = 0;
- if idnode >= 0 && json_get(idnode, 0) == J_NUM { id_val = json_get(idnode, 1); }
- out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":";
- out = out + int_str(id_val);
- out = out + ",\"result\":";
- if str_len(loc) == 0 { out = out + "null"; }
- else { out = out + loc; }
- out = out + "}";
- rpc_send(out);
-}
+fn lsp_send_def_resp(root: int, loc: string):
+ idnode := json_obj_get(root, "id")
+ id_val : ., mut = 0
+ if idnode >= 0 && json_get(idnode, 0) == J_NUM:
+ id_val = json_get(idnode, 1)
+ out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":"
+ out = out + int_str(id_val)
+ out = out + ",\"result\":"
+ if str_len(loc) == 0:
+ out = out + "null"
+ else:
+ out = out + loc
+ out = out + "}"
+ rpc_send(out)
-fn lsp_hover(root: int) {
- if lsp_request_matches_snapshot(root) == 0 { lsp_send_hover_resp(root, ""); return; }
- params := json_obj_get(root, "params");
- pos : ., mut = -1;
- if params >= 0 { pos = json_obj_get(params, "position"); }
- if pos < 0 || json_get(pos, 0) != J_OBJ { lsp_send_hover_resp(root, ""); return; }
- line_node := json_obj_get(pos, "line");
- col_node := json_obj_get(pos, "character");
- if line_node < 0 || col_node < 0 ||
- json_get(line_node, 0) != J_NUM || json_get(col_node, 0) != J_NUM {
- lsp_send_hover_resp(root, "");
- return;
- }
- lsp_send_hover_resp(root, analysis_hover(json_get(line_node, 1), json_get(col_node, 1)));
-}
+fn lsp_hover(root: int):
+ if lsp_request_matches_snapshot(root) == 0:
+ lsp_send_hover_resp(root, "")
+ return
+ params := json_obj_get(root, "params")
+ pos : ., mut = -1
+ if params >= 0:
+ pos = json_obj_get(params, "position")
+ if pos < 0 || json_get(pos, 0) != J_OBJ:
+ lsp_send_hover_resp(root, "")
+ return
+ line_node := json_obj_get(pos, "line")
+ col_node := json_obj_get(pos, "character")
+ if line_node < 0 || col_node < 0 || json_get(line_node, 0) != J_NUM || json_get(col_node, 0) != J_NUM:
+ lsp_send_hover_resp(root, "")
+ return
+ lsp_send_hover_resp(root, analysis_hover(json_get(line_node, 1), json_get(col_node, 1)))
-fn lsp_definition(root: int) {
- if lsp_request_matches_snapshot(root) == 0 { lsp_send_def_resp(root, ""); return; }
- params := json_obj_get(root, "params");
- pos : ., mut = -1;
- if params >= 0 { pos = json_obj_get(params, "position"); }
- if pos < 0 || json_get(pos, 0) != J_OBJ { lsp_send_def_resp(root, ""); return; }
- line_node := json_obj_get(pos, "line");
- col_node := json_obj_get(pos, "character");
- if line_node < 0 || col_node < 0 ||
- json_get(line_node, 0) != J_NUM || json_get(col_node, 0) != J_NUM {
- lsp_send_def_resp(root, "");
- return;
- }
- lsp_send_def_resp(root, analysis_definition(json_get(line_node, 1), json_get(col_node, 1)));
-}
+fn lsp_definition(root: int):
+ if lsp_request_matches_snapshot(root) == 0:
+ lsp_send_def_resp(root, "")
+ return
+ params := json_obj_get(root, "params")
+ pos : ., mut = -1
+ if params >= 0:
+ pos = json_obj_get(params, "position")
+ if pos < 0 || json_get(pos, 0) != J_OBJ:
+ lsp_send_def_resp(root, "")
+ return
+ line_node := json_obj_get(pos, "line")
+ col_node := json_obj_get(pos, "character")
+ if line_node < 0 || col_node < 0 || json_get(line_node, 0) != J_NUM || json_get(col_node, 0) != J_NUM:
+ lsp_send_def_resp(root, "")
+ return
+ lsp_send_def_resp(root, analysis_definition(json_get(line_node, 1), json_get(col_node, 1)))
// ── completion / documentSymbol(Task 5)────────────────────────
// 请求(带 id)→ 响应。查询基于最后一次成功检查的快照(analysis.cr),
@@ -328,55 +351,60 @@ fn lsp_definition(root: int) {
// textDocument/completion:params.position(0-based)+ context(当前仅
// 忽略——触发类型不影响候选);result 为 {"items":[...]},坏参数 → 空 items。
-fn lsp_completion(root: int) {
- if lsp_request_matches_snapshot(root) == 0 { lsp_send_def_resp(root, "{\"items\":[]}"); return; }
- params := json_obj_get(root, "params");
- pos : ., mut = -1;
- if params >= 0 { pos = json_obj_get(params, "position"); }
- if pos < 0 || json_get(pos, 0) != J_OBJ {
- lsp_send_def_resp(root, "{\"items\":[]}");
- return;
- }
- line_node := json_obj_get(pos, "line");
- col_node := json_obj_get(pos, "character");
- if line_node < 0 || col_node < 0 ||
- json_get(line_node, 0) != J_NUM || json_get(col_node, 0) != J_NUM {
- lsp_send_def_resp(root, "{\"items\":[]}");
- return;
- }
- lsp_send_def_resp(root, analysis_completion(json_get(line_node, 1), json_get(col_node, 1)));
-}
+fn lsp_completion(root: int):
+ if lsp_request_matches_snapshot(root) == 0:
+ lsp_send_def_resp(root, "{\"items\":[]}")
+ return
+ params := json_obj_get(root, "params")
+ pos : ., mut = -1
+ if params >= 0:
+ pos = json_obj_get(params, "position")
+ if pos < 0 || json_get(pos, 0) != J_OBJ:
+ lsp_send_def_resp(root, "{\"items\":[]}")
+ return
+ line_node := json_obj_get(pos, "line")
+ col_node := json_obj_get(pos, "character")
+ if line_node < 0 || col_node < 0 || json_get(line_node, 0) != J_NUM || json_get(col_node, 0) != J_NUM:
+ lsp_send_def_resp(root, "{\"items\":[]}")
+ return
+ lsp_send_def_resp(root, analysis_completion(json_get(line_node, 1), json_get(col_node, 1)))
// textDocument/documentSymbol:params.textDocument.uri 只需存在即可
// (符号来自快照,与 uri 具体值无关);result 为 JSON 数组。
-fn lsp_document_symbol(root: int) {
- if lsp_request_matches_snapshot(root) == 0 { lsp_send_def_resp(root, "[]"); return; }
- params := json_obj_get(root, "params");
- td : ., mut = -1;
- if params >= 0 { td = json_obj_get(params, "textDocument"); }
- if td < 0 { lsp_send_def_resp(root, "[]"); return; }
- uri_node := json_obj_get(td, "uri");
- if uri_node < 0 || json_get(uri_node, 0) != J_STR {
- lsp_send_def_resp(root, "[]");
- return;
- }
- lsp_send_def_resp(root, analysis_document_symbol());
-}
+fn lsp_document_symbol(root: int):
+ if lsp_request_matches_snapshot(root) == 0:
+ lsp_send_def_resp(root, "[]")
+ return
+ params := json_obj_get(root, "params")
+ td : ., mut = -1
+ if params >= 0:
+ td = json_obj_get(params, "textDocument")
+ if td < 0:
+ lsp_send_def_resp(root, "[]")
+ return
+ uri_node := json_obj_get(td, "uri")
+ if uri_node < 0 || json_get(uri_node, 0) != J_STR:
+ lsp_send_def_resp(root, "[]")
+ return
+ lsp_send_def_resp(root, analysis_document_symbol())
// ── semanticTokens(Task 6)──────────────────────────────────
// textDocument/semanticTokens/full:params.textDocument.uri 只需存在即可
// (令牌来自快照,与 uri 具体值无关——与 documentSymbol 同模式);result
// 为 {"data":[...]}(差分编码见 analysis.cr)。坏参数 → 空 data。
-fn lsp_semantic_tokens(root: int) {
- if lsp_request_matches_snapshot(root) == 0 { lsp_send_def_resp(root, "{\"data\":[]}"); return; }
- params := json_obj_get(root, "params");
- td : ., mut = -1;
- if params >= 0 { td = json_obj_get(params, "textDocument"); }
- if td < 0 { lsp_send_def_resp(root, "{\"data\":[]}"); return; }
- uri_node := json_obj_get(td, "uri");
- if uri_node < 0 || json_get(uri_node, 0) != J_STR {
- lsp_send_def_resp(root, "{\"data\":[]}");
- return;
- }
- lsp_send_def_resp(root, analysis_semantic_tokens());
-}
+fn lsp_semantic_tokens(root: int):
+ if lsp_request_matches_snapshot(root) == 0:
+ lsp_send_def_resp(root, "{\"data\":[]}")
+ return
+ params := json_obj_get(root, "params")
+ td : ., mut = -1
+ if params >= 0:
+ td = json_obj_get(params, "textDocument")
+ if td < 0:
+ lsp_send_def_resp(root, "{\"data\":[]}")
+ return
+ uri_node := json_obj_get(td, "uri")
+ if uri_node < 0 || json_get(uri_node, 0) != J_STR:
+ lsp_send_def_resp(root, "{\"data\":[]}")
+ return
+ lsp_send_def_resp(root, analysis_semantic_tokens())
diff --git a/src/lsp/main.cr b/src/lsp/main.cr
index 14a214d4..1165508a 100644
--- a/src/lsp/main.cr
+++ b/src/lsp/main.cr
@@ -1,9 +1,8 @@
// main.cr — corelsp 入口
import _import
-fn lsp_main() -> int {
+fn lsp_main() -> int:
// LSP 协议通道是 stdout——任何非协议字节都会使严格客户端(VS Code)断连。
// res_imports 的进度/警告输出在此静默(corec 命令行不受影响,默认 0)。
- g_silent_stdout = 1;
- return rpc_loop();
-}
+ g_silent_stdout = 1
+ return rpc_loop()
diff --git a/src/lsp/rpc.cr b/src/lsp/rpc.cr
index 3579da24..2d88b416 100644
--- a/src/lsp/rpc.cr
+++ b/src/lsp/rpc.cr
@@ -19,178 +19,207 @@
// 不经 json 节点树构建(json.cr 无公开的成员表写入接口)。
// ── 常量 ──
-RPC_HDR_MAX : int = 8192; // 头缓冲上限(字节)
-RPC_BODY_MAX : int = 16777216; // 体上限(16MB 防呆保护)
+RPC_HDR_MAX : int = 8192 // 头缓冲上限(字节)
+RPC_BODY_MAX : int = 16777216 // 体上限(16MB 防呆保护)
// ── 状态 ──
-g_rpc_initialized : int, mut; // 是否已收到 initialize
-g_rpc_shutdown : int, mut; // 是否已收到 shutdown
-g_rpc_exit_code : int, mut; // 帧循环结束时的进程退出码
-g_rpc_hdr_buf : string, mut; // 头缓冲(惰性 alloc 一次)
-g_rpc_hdr_ok : int, mut;
-g_rpc_in_buf : string, mut; // stdin 分块缓冲,避免 read(1) 系统调用风暴
-g_rpc_in_pos : int, mut;
-g_rpc_in_len : int, mut;
-g_rpc_in_ok : int, mut;
+g_rpc_initialized : int, mut // 是否已收到 initialize
+g_rpc_shutdown : int, mut // 是否已收到 shutdown
+g_rpc_exit_code : int, mut // 帧循环结束时的进程退出码
+g_rpc_hdr_buf : string, mut // 头缓冲(惰性 alloc 一次)
+g_rpc_hdr_ok : int, mut
+g_rpc_in_buf : string, mut // stdin 分块缓冲,避免 read(1) 系统调用风暴
+g_rpc_in_pos : int, mut
+g_rpc_in_len : int, mut
+g_rpc_in_ok : int, mut
// ── 帧读 ──
// 从 stdin(fd 0)取一个字节;底层按 4KB 分块读取,EOF/错误返回 -1。
-fn rpc_read_byte() -> int {
- if g_rpc_in_ok == 0 {
- g_rpc_in_buf = alloc(4096);
- g_rpc_in_pos = 0;
- g_rpc_in_len = 0;
- g_rpc_in_ok = 1;
- }
- if g_rpc_in_pos >= g_rpc_in_len {
- n := syscall3(0, 0, g_rpc_in_buf, 4096);
- if n <= 0 { return -1; }
- g_rpc_in_pos = 0;
- g_rpc_in_len = n;
- }
- c := load8(g_rpc_in_buf, g_rpc_in_pos);
- g_rpc_in_pos = g_rpc_in_pos + 1;
- return c;
-}
+fn rpc_read_byte() -> int:
+ if g_rpc_in_ok == 0:
+ g_rpc_in_buf = alloc(4096)
+ g_rpc_in_pos = 0
+ g_rpc_in_len = 0
+ g_rpc_in_ok = 1
+ if g_rpc_in_pos >= g_rpc_in_len:
+ n := syscall3(0, 0, g_rpc_in_buf, 4096)
+ if n <= 0:
+ return -1
+ g_rpc_in_pos = 0
+ g_rpc_in_len = n
+ c := load8(g_rpc_in_buf, g_rpc_in_pos)
+ g_rpc_in_pos = g_rpc_in_pos + 1
+ return c
// 读头直到 "\r\n\r\n",解析 Content-Length;EOF/坏头返回 -1
-fn rpc_read_header() -> int {
- if g_rpc_hdr_ok == 0 {
- g_rpc_hdr_buf = alloc(RPC_HDR_MAX);
- g_rpc_hdr_ok = 1;
- }
- buf := g_rpc_hdr_buf;
- hlen : ., mut = 0;
- seen : ., mut = 0; // 已匹配 "\r\n\r\n" 前缀的连续字节数
- loop {
- c := rpc_read_byte();
- if c < 0 { return -1; } // EOF
- if hlen >= RPC_HDR_MAX { return -1; } // 头过长
- store8(buf, hlen, c);
- hlen = hlen + 1;
- if c == 13 && seen == 0 { seen = 1; }
- else if c == 10 && seen == 1 { seen = 2; }
- else if c == 13 && seen == 2 { seen = 3; }
- else if c == 10 && seen == 3 { seen = 4; }
- else {
- seen = 0;
- if c == 13 { seen = 1; } // 当前字节可作新一轮 \r 起点
- }
- if seen >= 4 { break; }
- }
- return rpc_find_len(buf, hlen);
-}
+fn rpc_read_header() -> int:
+ if g_rpc_hdr_ok == 0:
+ g_rpc_hdr_buf = alloc(RPC_HDR_MAX)
+ g_rpc_hdr_ok = 1
+ buf := g_rpc_hdr_buf
+ hlen : ., mut = 0
+ seen : ., mut = 0 // 已匹配 "\r\n\r\n" 前缀的连续字节数
+ loop:
+ c := rpc_read_byte()
+ if c < 0:
+ return -1
+ // EOF
+ if hlen >= RPC_HDR_MAX:
+ return -1
+ // 头过长
+ store8(buf, hlen, c)
+ hlen = hlen + 1
+ if c == 13 && seen == 0:
+ seen = 1
+ else if c == 10 && seen == 1:
+ seen = 2
+ else if c == 13 && seen == 2:
+ seen = 3
+ else if c == 10 && seen == 3:
+ seen = 4
+ else:
+ seen = 0
+ if c == 13:
+ seen = 1
+ // 当前字节可作新一轮 \r 起点
+ if seen >= 4:
+ break
+ return rpc_find_len(buf, hlen)
// buf[pos..] 与 key 大小写不敏感比较(键后必须为 ':' 或空白)
-fn rpc_key_at(buf: string, pos: int, key: string) -> int {
- kl := str_len(key);
- if pos < 0 { return 0; }
- i : ., mut = 0;
- loop {
- if i >= kl { break; }
- c := load8(buf, pos + i);
- kc := load8(key, i);
- if c >= 65 && c <= 90 { c = c + 32; } // 大写转小写
- if c != kc { return 0; }
- i = i + 1;
- }
- c2 := load8(buf, pos + kl);
- if c2 == 58 { return 1; } // ':'
- if c2 == 32 || c2 == 9 { return 1; } // 空格 / tab
- return 0;
-}
+fn rpc_key_at(buf: string, pos: int, key: string) -> int:
+ kl := str_len(key)
+ if pos < 0:
+ return 0
+ i : ., mut = 0
+ loop:
+ if i >= kl:
+ break
+ c := load8(buf, pos + i)
+ kc := load8(key, i)
+ if c >= 65 && c <= 90:
+ c = c + 32
+ // 大写转小写
+ if c != kc:
+ return 0
+ i = i + 1
+ c2 := load8(buf, pos + kl)
+ if c2 == 58:
+ return 1
+ // ':'
+ if c2 == 32 || c2 == 9:
+ return 1
+ // 空格 / tab
+ return 0
// 从头缓冲解析 Content-Length;找不到/非法/超上限返回 -1
-fn rpc_find_len(buf: string, blen: int) -> int {
- i : ., mut = 0;
- found : ., mut = 0;
- found_len : ., mut = -1;
- loop {
- if i >= blen { break; }
+fn rpc_find_len(buf: string, blen: int) -> int:
+ i : ., mut = 0
+ found : ., mut = 0
+ found_len : ., mut = -1
+ loop:
+ if i >= blen:
+ break
// Header fields are matched only at line starts. This prevents a
// body-like substring in another header from being accepted.
- if i + 1 < blen && load8(buf, i) == 13 && load8(buf, i + 1) == 10 {
- break;
- }
- line_end : ., mut = i;
- loop {
- if line_end + 1 >= blen { return -1; }
- if load8(buf, line_end) == 13 && load8(buf, line_end + 1) == 10 { break; }
- line_end = line_end + 1;
- }
- if line_end - i < 15 { i = line_end + 2; continue; }
- if rpc_key_at(buf, i, "content-length") != 0 {
- j : ., mut = i + 14;
- if j >= line_end { return -1; }
+ if i + 1 < blen && load8(buf, i) == 13 && load8(buf, i + 1) == 10:
+ break
+ line_end : ., mut = i
+ loop:
+ if line_end + 1 >= blen:
+ return -1
+ if load8(buf, line_end) == 13 && load8(buf, line_end + 1) == 10:
+ break
+ line_end = line_end + 1
+ if line_end - i < 15:
+ i = line_end + 2
+ continue
+ if rpc_key_at(buf, i, "content-length") != 0:
+ j : ., mut = i + 14
+ if j >= line_end:
+ return -1
// The key matcher permits whitespace before the colon.
- loop { if j < line_end && (load8(buf, j) == 32 || load8(buf, j) == 9) { j = j + 1; } else { break; } }
- if j >= line_end || load8(buf, j) != 58 { return -1; }
- j = j + 1;
- loop { if j < line_end && (load8(buf, j) == 32 || load8(buf, j) == 9) { j = j + 1; } else { break; } }
- v : ., mut = 0;
- got : ., mut = 0;
- loop {
- if j >= line_end { break; }
- c2 := load8(buf, j);
- if c2 >= 48 && c2 <= 57 {
- if v > RPC_BODY_MAX / 10 || (v == RPC_BODY_MAX / 10 && c2 - 48 > RPC_BODY_MAX % 10) { return -1; }
- v = v * 10 + (c2 - 48);
- got = 1;
- j = j + 1;
- }
- else { break; }
- }
- if got == 0 { return -1; }
- loop { if j < line_end && (load8(buf, j) == 32 || load8(buf, j) == 9) { j = j + 1; } else { break; } }
- if j != line_end { return -1; }
- if found != 0 { return -1; }
- found = 1;
- found_len = v;
- }
- i = line_end + 2;
- }
- return found_len;
-}
+ loop:
+ if j < line_end && (load8(buf, j) == 32 || load8(buf, j) == 9):
+ j = j + 1
+ else:
+ break
+ if j >= line_end || load8(buf, j) != 58:
+ return -1
+ j = j + 1
+ loop:
+ if j < line_end && (load8(buf, j) == 32 || load8(buf, j) == 9):
+ j = j + 1
+ else:
+ break
+ v : ., mut = 0
+ got : ., mut = 0
+ loop:
+ if j >= line_end:
+ break
+ c2 := load8(buf, j)
+ if c2 >= 48 && c2 <= 57:
+ if v > RPC_BODY_MAX / 10 || (v == RPC_BODY_MAX / 10 && c2 - 48 > RPC_BODY_MAX % 10):
+ return -1
+ v = v * 10 + (c2 - 48)
+ got = 1
+ j = j + 1
+ else:
+ break
+ if got == 0:
+ return -1
+ loop:
+ if j < line_end && (load8(buf, j) == 32 || load8(buf, j) == 9):
+ j = j + 1
+ else:
+ break
+ if j != line_end:
+ return -1
+ if found != 0:
+ return -1
+ found = 1
+ found_len = v
+ i = line_end + 2
+ return found_len
// 读满 n 字节体;EOF 中断返回已读部分(调用方 json_parse 失败即忽略)
-fn rpc_read_body(n: int) -> string {
- buf := alloc(n + 1);
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- c := rpc_read_byte();
- if c < 0 { break; }
- store8(buf, i, c);
- i = i + 1;
- }
- store8(buf, i, 0);
- return buf;
-}
+fn rpc_read_body(n: int) -> string:
+ buf := alloc(n + 1)
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ c := rpc_read_byte()
+ if c < 0:
+ break
+ store8(buf, i, c)
+ i = i + 1
+ store8(buf, i, 0)
+ return buf
// 读一帧体;EOF/坏头返回 ""(str_len == 0 由调用方判定)
-fn rpc_read_frame() -> string {
- n := rpc_read_header();
- if n < 0 { return ""; }
- return rpc_read_body(n);
-}
+fn rpc_read_frame() -> string:
+ n := rpc_read_header()
+ if n < 0:
+ return ""
+ return rpc_read_body(n)
// ── 帧写 ──
// 写一帧:Content-Length 头 + 体(单次 write;响应 < PIPE_BUF,原子写)
-fn rpc_send(body: string) {
- bl := str_len(body);
- hdr : string, mut = "Content-Length: ";
- hdr = hdr + int_str(bl);
- hdr = hdr + "\r\n\r\n";
- hdr = hdr + body;
- syscall3(1, 1, hdr, str_len(hdr));
-}
+fn rpc_send(body: string):
+ bl := str_len(body)
+ hdr : string, mut = "Content-Length: "
+ hdr = hdr + int_str(bl)
+ hdr = hdr + "\r\n\r\n"
+ hdr = hdr + body
+ syscall3(1, 1, hdr, str_len(hdr))
// 固定形状响应体(错误消息按 code 选字面量,避免字符串参数拼接)
-fn rpc_send_initialize(id: int) {
- out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":";
- out = out + int_str(id);
+fn rpc_send_initialize(id: int):
+ out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":"
+ out = out + int_str(id)
// Task 5:声明 completion(@ 触发)/ documentSymbol 能力——客户端据此
// 才发送对应请求;textDocumentSync 保持 1(全量同步,Task 3 契约)。
// Task 6:semanticTokensProvider/full——legend 顺序与 analysis.cr
@@ -200,144 +229,167 @@ fn rpc_send_initialize(id: int) {
// Task 4 能力通告(2026-08-28):hover/definition 处理器已接线
// (rpc_dispatch L292-293),此前缺通告——客户端(Zed 等)只在通告后
// 才发送对应请求。
- out = out + ",\"result\":{\"capabilities\":{\"textDocumentSync\":1,\"hoverProvider\":true,\"definitionProvider\":true,\"completionProvider\":{\"triggerCharacters\":[\"@\"]},\"documentSymbolProvider\":true,\"semanticTokensProvider\":{\"legend\":{\"tokenTypes\":[\"keyword\",\"type\",\"function\",\"variable\",\"comment\",\"string\",\"operator\",\"number\"],\"tokenModifiers\":[]},\"full\":true}}}}";
- rpc_send(out);
-}
+ out = out + ",\"result\":{\"capabilities\":{\"textDocumentSync\":1,\"hoverProvider\":true,\"definitionProvider\":true,\"completionProvider\":{\"triggerCharacters\":[\"@\"]},\"documentSymbolProvider\":true,\"semanticTokensProvider\":{\"legend\":{\"tokenTypes\":[\"keyword\",\"type\",\"function\",\"variable\",\"comment\",\"string\",\"operator\",\"number\"],\"tokenModifiers\":[]},\"full\":true}}}}"
+ rpc_send(out)
-fn rpc_send_shutdown(id: int) {
- out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":";
- out = out + int_str(id);
- out = out + ",\"result\":null}";
- rpc_send(out);
-}
+fn rpc_send_shutdown(id: int):
+ out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":"
+ out = out + int_str(id)
+ out = out + ",\"result\":null}"
+ rpc_send(out)
// initialized 通知的最小响应帧。JSON-RPC 规范:通知(无 id)不应回响应;
// 但 brief 的集成测试(test_lsp.py test_lifecycle)对 initialized 调用
// read_frame 等待一帧(测试契约优先,逐字实现)——真实 LSP 客户端从不
// 读取 initialized 的响应,多余帧以 id=null 不匹配任何挂起请求而被忽略。
-fn rpc_send_initialized_ack() {
- rpc_send("{\"jsonrpc\":\"2.0\",\"id\":null,\"result\":null}");
-}
+fn rpc_send_initialized_ack():
+ rpc_send("{\"jsonrpc\":\"2.0\",\"id\":null,\"result\":null}")
-fn rpc_send_error(id: int, code: int) {
- out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":";
- out = out + int_str(id);
- out = out + ",\"error\":{\"code\":";
- out = out + int_str(code);
- out = out + ",\"message\":\"";
- if code == -32601 { out = out + "Method not found"; }
- else if code == -32602 { out = out + "Server not initialized"; }
- else { out = out + "Invalid Request"; }
- out = out + "\"}}";
- rpc_send(out);
-}
+fn rpc_send_error(id: int, code: int):
+ out : string, mut = "{\"jsonrpc\":\"2.0\",\"id\":"
+ out = out + int_str(id)
+ out = out + ",\"error\":{\"code\":"
+ out = out + int_str(code)
+ out = out + ",\"message\":\""
+ if code == -32601:
+ out = out + "Method not found"
+ else if code == -32602:
+ out = out + "Server not initialized"
+ else:
+ out = out + "Invalid Request"
+ out = out + "\"}}"
+ rpc_send(out)
// ── 分发 ──
// method 节点与名字比较(J_STR 槽:1 = 字符串池偏移,2 = 长度)
-fn rpc_method_eq(mnode: int, name: string) -> int {
- off := json_get(mnode, 1);
- ln := json_get(mnode, 2);
- if ln != str_len(name) { return 0; }
- i : ., mut = 0;
- loop {
- if i >= ln { break; }
- if load8(g_json_strs, off + i) != load8(name, i) { return 0; }
- i = i + 1;
- }
- return 1;
-}
+fn rpc_method_eq(mnode: int, name: string) -> int:
+ off := json_get(mnode, 1)
+ ln := json_get(mnode, 2)
+ if ln != str_len(name):
+ return 0
+ i : ., mut = 0
+ loop:
+ if i >= ln:
+ break
+ if load8(g_json_strs, off + i) != load8(name, i):
+ return 0
+ i = i + 1
+ return 1
// 分发一帧请求;返回 0 = 继续循环,1 = 退出
-fn rpc_dispatch(req: int) -> int {
- if json_get(req, 0) != J_OBJ { return 0; } // 非对象:v1 忽略
- mnode := json_obj_get(req, "method");
- idnode := json_obj_get(req, "id");
- has_id : ., mut = 0;
- id_val : ., mut = 0;
- if idnode >= 0 {
- if json_get(idnode, 0) == J_NUM { // v1 仅整数 id;字符串 id 视作通知
- has_id = 1;
- id_val = json_get(idnode, 1);
- }
- }
- if mnode < 0 {
- if has_id != 0 { rpc_send_error(id_val, -32600); }
- return 0;
- }
- if json_get(mnode, 0) != J_STR {
- if has_id != 0 { rpc_send_error(id_val, -32600); }
- return 0;
- }
+fn rpc_dispatch(req: int) -> int:
+ if json_get(req, 0) != J_OBJ:
+ return 0
+ // 非对象:v1 忽略
+ mnode := json_obj_get(req, "method")
+ idnode := json_obj_get(req, "id")
+ has_id : ., mut = 0
+ id_val : ., mut = 0
+ if idnode >= 0:
+ if json_get(idnode, 0) == J_NUM:
+ // v1 仅整数 id;字符串 id 视作通知
+ has_id = 1
+ id_val = json_get(idnode, 1)
+ if mnode < 0:
+ if has_id != 0:
+ rpc_send_error(id_val, -32600)
+ return 0
+ if json_get(mnode, 0) != J_STR:
+ if has_id != 0:
+ rpc_send_error(id_val, -32600)
+ return 0
// 生命周期
- if rpc_method_eq(mnode, "exit") != 0 {
+ if rpc_method_eq(mnode, "exit") != 0:
// exit 通知:shutdown 已收到 → 退出码 0,否则 1(LSP 规范)
- if g_rpc_shutdown != 0 { g_rpc_exit_code = 0; }
- else { g_rpc_exit_code = 1; }
- return 1;
- }
- if rpc_method_eq(mnode, "shutdown") != 0 {
- if g_rpc_initialized == 0 {
- if has_id != 0 { rpc_send_error(id_val, -32602); }
- return 0;
- }
- g_rpc_shutdown = 1;
- if has_id != 0 { rpc_send_shutdown(id_val); }
- return 0;
- }
- if rpc_method_eq(mnode, "initialize") != 0 {
- if g_rpc_initialized == 0 {
- g_rpc_initialized = 1;
- g_rpc_shutdown = 0;
- if has_id != 0 { rpc_send_initialize(id_val); }
- return 0;
- }
- if has_id != 0 { rpc_send_initialize(id_val); } // 重复 initialize:v1 再回一次
- return 0;
- }
- if rpc_method_eq(mnode, "initialized") != 0 {
+ if g_rpc_shutdown != 0:
+ g_rpc_exit_code = 0
+ else:
+ g_rpc_exit_code = 1
+ return 1
+ if rpc_method_eq(mnode, "shutdown") != 0:
+ if g_rpc_initialized == 0:
+ if has_id != 0:
+ rpc_send_error(id_val, -32602)
+ return 0
+ g_rpc_shutdown = 1
+ if has_id != 0:
+ rpc_send_shutdown(id_val)
+ return 0
+ if rpc_method_eq(mnode, "initialize") != 0:
+ if g_rpc_initialized == 0:
+ g_rpc_initialized = 1
+ g_rpc_shutdown = 0
+ if has_id != 0:
+ rpc_send_initialize(id_val)
+ return 0
+ if has_id != 0:
+ rpc_send_initialize(id_val)
+ // 重复 initialize:v1 再回一次
+ return 0
+ if rpc_method_eq(mnode, "initialized") != 0:
// 通知:按规范不回;brief 测试契约要求回一帧(见 rpc_send_initialized_ack)
- rpc_send_initialized_ack();
- return 0;
- }
- if g_rpc_initialized == 0 {
+ rpc_send_initialized_ack()
+ return 0
+ if g_rpc_initialized == 0:
// initialize 前的其他请求 → -32602
- if has_id != 0 { rpc_send_error(id_val, -32602); }
- return 0;
- }
- if g_rpc_shutdown != 0 {
+ if has_id != 0:
+ rpc_send_error(id_val, -32602)
+ return 0
+ if g_rpc_shutdown != 0:
// shutdown 后的请求 → -32600
- if has_id != 0 { rpc_send_error(id_val, -32600); }
- return 0;
- }
+ if has_id != 0:
+ rpc_send_error(id_val, -32600)
+ return 0
// 文档同步(Task 3):通知,不回响应——检查结果经 publishDiagnostics 通知回
- if rpc_method_eq(mnode, "textDocument/didOpen") != 0 { lsp_did_open(req); return 0; }
- if rpc_method_eq(mnode, "textDocument/didChange") != 0 { lsp_did_change(req); return 0; }
- if rpc_method_eq(mnode, "textDocument/didSave") != 0 { lsp_did_save(req); return 0; }
- if rpc_method_eq(mnode, "textDocument/didClose") != 0 { lsp_did_close(req); return 0; }
+ if rpc_method_eq(mnode, "textDocument/didOpen") != 0:
+ lsp_did_open(req)
+ return 0
+ if rpc_method_eq(mnode, "textDocument/didChange") != 0:
+ lsp_did_change(req)
+ return 0
+ if rpc_method_eq(mnode, "textDocument/didSave") != 0:
+ lsp_did_save(req)
+ return 0
+ if rpc_method_eq(mnode, "textDocument/didClose") != 0:
+ lsp_did_close(req)
+ return 0
// 语义查询(Task 4):请求,回响应——基于快照,不触发检查
- if rpc_method_eq(mnode, "textDocument/hover") != 0 { lsp_hover(req); return 0; }
- if rpc_method_eq(mnode, "textDocument/definition") != 0 { lsp_definition(req); return 0; }
+ if rpc_method_eq(mnode, "textDocument/hover") != 0:
+ lsp_hover(req)
+ return 0
+ if rpc_method_eq(mnode, "textDocument/definition") != 0:
+ lsp_definition(req)
+ return 0
// 语义查询(Task 5):completion / documentSymbol——同一快照模式
- if rpc_method_eq(mnode, "textDocument/completion") != 0 { lsp_completion(req); return 0; }
- if rpc_method_eq(mnode, "textDocument/documentSymbol") != 0 { lsp_document_symbol(req); return 0; }
+ if rpc_method_eq(mnode, "textDocument/completion") != 0:
+ lsp_completion(req)
+ return 0
+ if rpc_method_eq(mnode, "textDocument/documentSymbol") != 0:
+ lsp_document_symbol(req)
+ return 0
// 语义查询(Task 6):semanticTokens/full——快照令牌流 → 差分编码
- if rpc_method_eq(mnode, "textDocument/semanticTokens/full") != 0 { lsp_semantic_tokens(req); return 0; }
+ if rpc_method_eq(mnode, "textDocument/semanticTokens/full") != 0:
+ lsp_semantic_tokens(req)
+ return 0
// 未知方法 → -32601(通知静默忽略)
- if has_id != 0 { rpc_send_error(id_val, -32601); }
- return 0;
-}
+ if has_id != 0:
+ rpc_send_error(id_val, -32601)
+ return 0
// ── 帧循环 ──
// 读帧 → 分发 → 写响应,直到 exit 通知或 stdin EOF;返回进程退出码
-fn rpc_loop() -> int {
- loop {
- body := rpc_read_frame();
- if str_len(body) == 0 { break; } // EOF
- root := json_parse(body);
- if root < 0 { continue; } // 非法 JSON:v1 忽略
- if rpc_dispatch(root) != 0 { break; }
- }
- return g_rpc_exit_code;
-}
+fn rpc_loop() -> int:
+ loop:
+ body := rpc_read_frame()
+ if str_len(body) == 0:
+ break
+ // EOF
+ root := json_parse(body)
+ if root < 0:
+ continue
+ // 非法 JSON:v1 忽略
+ if rpc_dispatch(root) != 0:
+ break
+ return g_rpc_exit_code
diff --git a/src/lsp/test_json.cr b/src/lsp/test_json.cr
index a108ae7c..8ec67575 100644
--- a/src/lsp/test_json.cr
+++ b/src/lsp/test_json.cr
@@ -12,119 +12,111 @@ import json
import fmt
import io
-g_fail_count : int, mut = 0;
+g_fail_count : int, mut = 0
-fn t_expect(cond: bool, name: string) {
- if !cond {
- print("FAIL: ");
- println(name);
- g_fail_count = g_fail_count + 1;
- } else {
- print("ok: ");
- println(name);
- }
-}
+fn t_expect(cond: bool, name: string):
+ if !cond:
+ print("FAIL: ")
+ println(name)
+ g_fail_count = g_fail_count + 1
+ else:
+ print("ok: ")
+ println(name)
// 解析 + 序列化往返:输出须等于规范紧凑形式
-fn check_roundtrip(text: string, canonical: string) {
- idx := json_parse(text);
- t_expect(idx >= 0, "parse: " + text);
- if idx >= 0 {
- out := json_stringify(idx);
- t_expect(str_eq(out, canonical) != 0, "stringify == canonical");
- if str_eq(out, canonical) == 0 {
- print(" got: ");
- println(out);
- }
- }
-}
+fn check_roundtrip(text: string, canonical: string):
+ idx := json_parse(text)
+ t_expect(idx >= 0, "parse: " + text)
+ if idx >= 0:
+ out := json_stringify(idx)
+ t_expect(str_eq(out, canonical) != 0, "stringify == canonical")
+ if str_eq(out, canonical) == 0:
+ print(" got: ")
+ println(out)
// 非法输入必须返回 -1
-fn check_bad(text: string) {
- idx := json_parse(text);
- t_expect(idx < 0, "bad input rejected: " + text);
-}
+fn check_bad(text: string):
+ idx := json_parse(text)
+ t_expect(idx < 0, "bad input rejected: " + text)
-fn main() -> int {
+fn main() -> int:
// 1. 往返:对象 + 数组 + 字面量
check_roundtrip("{\"a\": 1, \"b\": [true, null, \"x\"]}",
- "{\"a\":1,\"b\":[true,null,\"x\"]}");
+ "{\"a\":1,\"b\":[true,null,\"x\"]}")
// 2. 三层嵌套对象/数组
check_roundtrip("{\"a\": {\"b\": {\"c\": [1, 2, [3, 4]]}}}",
- "{\"a\":{\"b\":{\"c\":[1,2,[3,4]]}}}");
+ "{\"a\":{\"b\":{\"c\":[1,2,[3,4]]}}}")
// 3. 字符串转义往返:\" \\ \n
- check_roundtrip("\"a\\\"b\\\\c\\nd\"", "\"a\\\"b\\\\c\\nd\"");
+ check_roundtrip("\"a\\\"b\\\\c\\nd\"", "\"a\\\"b\\\\c\\nd\"")
// \uXXXX:解析为码点,序列化输出大写十六进制
- check_roundtrip("\"\\u4e2d\\u00e9\"", "\"\\u4E2D\\u00E9\"");
+ check_roundtrip("\"\\u4e2d\\u00e9\"", "\"\\u4E2D\\u00E9\"")
// UTF-16 surrogate pair becomes one Unicode scalar and round-trips in
// the canonical JSON form.
- check_roundtrip("\"\\uD83D\\uDE00\"", "\"\\uD83D\\uDE00\"");
- check_roundtrip("\"a\\b\\f\\/\"", "\"a\\u0008\\u000C/\"");
+ check_roundtrip("\"\\uD83D\\uDE00\"", "\"\\uD83D\\uDE00\"")
+ check_roundtrip("\"a\\b\\f\\/\"", "\"a\\u0008\\u000C/\"")
// 4. json_obj_get:{"position": {"line": 3, "character": 7}} 取 line → 3
- root := json_parse("{\"position\": {\"line\": 3, \"character\": 7}}");
- t_expect(root >= 0, "obj_get: parse");
- pos := json_obj_get(root, "position");
- t_expect(pos >= 0, "obj_get: position found");
- ln := json_obj_get(pos, "line");
+ root := json_parse("{\"position\": {\"line\": 3, \"character\": 7}}")
+ t_expect(root >= 0, "obj_get: parse")
+ pos := json_obj_get(root, "position")
+ t_expect(pos >= 0, "obj_get: position found")
+ ln := json_obj_get(pos, "line")
t_expect(ln >= 0 && json_get(ln, 0) == J_NUM && json_get(ln, 1) == 3,
- "obj_get: line == 3");
- t_expect(json_obj_get(root, "nope") < 0, "obj_get: missing key -> -1");
+ "obj_get: line == 3")
+ t_expect(json_obj_get(root, "nope") < 0, "obj_get: missing key -> -1")
// 5. 错误输入:{ [1, "abc 123abc 空串
- check_bad("{");
- check_bad("[1,");
- check_bad("\"abc");
- check_bad("123abc");
- check_bad("");
+ check_bad("{")
+ check_bad("[1,")
+ check_bad("\"abc")
+ check_bad("123abc")
+ check_bad("")
// 6. 数字:-42 → J_NUM a=-42
- n := json_parse("-42");
+ n := json_parse("-42")
t_expect(n >= 0 && json_get(n, 0) == J_NUM && json_get(n, 1) == -42,
- "num: -42 -> J_NUM a=-42");
- t_expect(str_eq(json_stringify(n), "-42") != 0, "stringify: -42");
+ "num: -42 -> J_NUM a=-42")
+ t_expect(str_eq(json_stringify(n), "-42") != 0, "stringify: -42")
// JSON object keys are last-wins, and signed 64-bit boundaries are valid.
- dup := json_parse("{\"x\":1,\"x\":2}");
- dx := json_obj_get(dup, "x");
- t_expect(dx >= 0 && json_get(dx, 1) == 2, "obj_get: duplicate key last wins");
- min_i64 := json_parse("-9223372036854775808");
- max_i64 := json_parse("9223372036854775807");
+ dup := json_parse("{\"x\":1,\"x\":2}")
+ dx := json_obj_get(dup, "x")
+ t_expect(dx >= 0 && json_get(dx, 1) == 2, "obj_get: duplicate key last wins")
+ min_i64 := json_parse("-9223372036854775808")
+ max_i64 := json_parse("9223372036854775807")
t_expect(min_i64 >= 0 && json_get(min_i64, 1) == -9223372036854775808,
- "num: INT64_MIN accepted");
+ "num: INT64_MIN accepted")
t_expect(max_i64 >= 0 && json_get(max_i64, 1) == 9223372036854775807,
- "num: INT64_MAX accepted");
- check_bad("9223372036854775808");
- check_bad("-9223372036854775809");
- check_bad("01");
- check_bad("\"\\uD800\"");
+ "num: INT64_MAX accepted")
+ check_bad("9223372036854775808")
+ check_bad("-9223372036854775809")
+ check_bad("01")
+ check_bad("\"\\uD800\"")
// Excessive nesting must fail without exhausting the native call stack.
- nested : string, mut = "0";
- ni : ., mut = 0;
- loop {
- if ni >= 130 { break; }
- nested = "[" + nested + "]";
- ni = ni + 1;
- }
- check_bad(nested);
+ nested : string, mut = "0"
+ ni : ., mut = 0
+ loop:
+ if ni >= 130:
+ break
+ nested = "[" + nested + "]"
+ ni = ni + 1
+ check_bad(nested)
// 7. json_array_get:下标访问 + 越界
- a := json_parse("[10, 20]");
- e0 := json_array_get(a, 0);
+ a := json_parse("[10, 20]")
+ e0 := json_array_get(a, 0)
t_expect(e0 >= 0 && json_get(e0, 0) == J_NUM && json_get(e0, 1) == 10,
- "array_get: [0] == 10");
- e1 := json_array_get(a, 1);
- t_expect(e1 >= 0 && json_get(e1, 1) == 20, "array_get: [1] == 20");
- t_expect(json_array_get(a, 2) < 0, "array_get: out of bounds -> -1");
+ "array_get: [0] == 10")
+ e1 := json_array_get(a, 1)
+ t_expect(e1 >= 0 && json_get(e1, 1) == 20, "array_get: [1] == 20")
+ t_expect(json_array_get(a, 2) < 0, "array_get: out of bounds -> -1")
- if g_fail_count == 0 {
- println("ALL TESTS PASSED");
- return 0;
- }
- print("FAILURES: ");
- println(int_str(g_fail_count));
- return g_fail_count;
-}
+ if g_fail_count == 0:
+ println("ALL TESTS PASSED")
+ return 0
+ print("FAILURES: ")
+ println(int_str(g_fail_count))
+ return g_fail_count
diff --git a/src/os/linux/callseq.cr b/src/os/linux/callseq.cr
index c04d3af4..3d304c82 100644
--- a/src/os/linux/callseq.cr
+++ b/src/os/linux/callseq.cr
@@ -63,142 +63,166 @@
// 寄存器装载;超限者(第 7 int / 第 9 binary64 起)不在此处发射——留待
// cs_stack_args(调用点自行决定是否压栈:IR_CALL/IR_SPAWN 压,EXTERN 不压)。
// 返回新 cp。
-fn cs_args_dispatch(buf: string, pos: int, cp: int, fa: int, ac: int) -> int {
- ir_cnt : ., mut = 0; fr_cnt : ., mut = 0;
- ai := 0;
- loop { if ai >= ac { break; }
- pt := irv_type(fa + ai);
- if pt == TI_DEX {
- if fr_cnt < 8 {
+fn cs_args_dispatch(buf: string, pos: int, cp: int, fa: int, ac: int) -> int:
+ ir_cnt : ., mut = 0
+ fr_cnt : ., mut = 0
+ ai := 0
+ loop:
+ if ai >= ac:
+ break
+ pt := irv_type(fa + ai)
+ if pt == TI_DEX:
+ if fr_cnt < 8:
// 全局行实参走 seam(e2_sd_ld_var):单实参调用恒不打包(ir_gen need_pack),
// 全局实参可直达此处 ⇒ 修复前 e2_sd_load_x(g2_slot(全局)) 读帧外伪偏移。
- cp = cp + e2_sd_ld_var(buf, pos+cp, fr_cnt, fa + ai);
- fr_cnt = fr_cnt + 1;
- }
- } else {
- if ir_cnt < 6 {
- r := -1;
- if ir_cnt == 0 { r = 7; } if ir_cnt == 1 { r = 6; } if ir_cnt == 2 { r = 2; }
- if ir_cnt == 3 { r = 1; } if ir_cnt == 4 { r = 8; } if ir_cnt == 5 { r = 9; }
- cp = cp + e2_load_var(buf, pos+cp, r, fa + ai);
- ir_cnt = ir_cnt + 1;
- }
- }
- ai = ai + 1; }
- return cp;
-}
+ cp = cp + e2_sd_ld_var(buf, pos+cp, fr_cnt, fa + ai)
+ fr_cnt = fr_cnt + 1
+ else:
+ if ir_cnt < 6:
+ r := -1
+ if ir_cnt == 0:
+ r = 7
+ if ir_cnt == 1:
+ r = 6
+ if ir_cnt == 2:
+ r = 2
+ if ir_cnt == 3:
+ r = 1
+ if ir_cnt == 4:
+ r = 8
+ if ir_cnt == 5:
+ r = 9
+ cp = cp + e2_load_var(buf, pos+cp, r, fa + ai)
+ ir_cnt = ir_cnt + 1
+ ai = ai + 1
+ return cp
// ── ② 栈参:判定 / 计数 / 压栈(IR_CALL + IR_SPAWN 两处同源)──
// 第 i 个实参是否超限落栈(SysV:int 第 7 个起、binary64 第 9 个起)。
// 判定 = 类型 × 该类型在 i 之前的实参个数(与提取前内联段同一规则)。
// 1 = 落栈,0 = 走寄存器。
-fn cs_arg_on_stack(fa: int, i: int) -> int {
- ic2 : ., mut = 0; fc2 : ., mut = 0;
- j2 : ., mut = 0;
- loop { if j2 >= i { break; }
- if irv_type(fa + j2) == TI_DEX { fc2 = fc2 + 1; } else { ic2 = ic2 + 1; }
- j2 = j2 + 1; }
- if irv_type(fa + i) == TI_DEX {
- if fc2 >= 8 { return 1; }
- } else {
- if ic2 >= 6 { return 1; }
- }
- return 0;
-}
+fn cs_arg_on_stack(fa: int, i: int) -> int:
+ ic2 : ., mut = 0
+ fc2 : ., mut = 0
+ j2 : ., mut = 0
+ loop:
+ if j2 >= i:
+ break
+ if irv_type(fa + j2) == TI_DEX:
+ fc2 = fc2 + 1
+ else:
+ ic2 = ic2 + 1
+ j2 = j2 + 1
+ if irv_type(fa + i) == TI_DEX:
+ if fc2 >= 8:
+ return 1
+ else:
+ if ic2 >= 6:
+ return 1
+ return 0
// 实际压栈参数个数(cs_stack_cleanup 的 add rsp 立即数 = count*8)。
// 与 cs_stack_args 同规则(cs_arg_on_stack)——两处计数恒等。
-fn cs_stack_count(fa: int, ac: int) -> int {
- n : ., mut = 0; i : ., mut = 0;
- loop { if i >= ac { break; }
- if cs_arg_on_stack(fa, i) > 0 { n = n + 1; }
- i = i + 1; }
- return n;
-}
+fn cs_stack_count(fa: int, ac: int) -> int:
+ n : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= ac:
+ break
+ if cs_arg_on_stack(fa, i) > 0:
+ n = n + 1
+ i = i + 1
+ return n
// 栈参压栈(右到左压——保持栈上实参位置顺序:调用时 [rsp] = 第 7 int / 第 9
// binary64)。int → r10 装载 + push r10(41 52);binary64 → xmm0 装载 +
// e2_push_xmm0(sub rsp,8 + movsd [rsp],xmm0)。返回新 cp。
-fn cs_stack_args(buf: string, pos: int, cp: int, fa: int, ac: int) -> int {
- stack_ai : ., mut = ac - 1;
- loop {
- if stack_ai < 0 { break; }
- if cs_arg_on_stack(fa, stack_ai) > 0 {
- if irv_type(fa + stack_ai) == TI_DEX {
+fn cs_stack_args(buf: string, pos: int, cp: int, fa: int, ac: int) -> int:
+ stack_ai : ., mut = ac - 1
+ loop:
+ if stack_ai < 0:
+ break
+ if cs_arg_on_stack(fa, stack_ai) > 0:
+ if irv_type(fa + stack_ai) == TI_DEX:
// 栈参 dex 装载同样走 seam(与寄存器支同规约)
- cp = cp + e2_sd_ld_var(buf, pos+cp, 0, fa + stack_ai);
- cp = cp + e2_push_xmm0(buf, pos+cp);
- } else {
- cp = cp + e2_load_var(buf, pos+cp, 10, fa + stack_ai);
- e2_w8(buf, pos+cp, 65); e2_w8(buf, pos+cp+1, 82); cp = cp + 2; // push r10
- }
- }
- stack_ai = stack_ai - 1;
- }
- return cp;
-}
+ cp = cp + e2_sd_ld_var(buf, pos+cp, 0, fa + stack_ai)
+ cp = cp + e2_push_xmm0(buf, pos+cp)
+ else:
+ cp = cp + e2_load_var(buf, pos+cp, 10, fa + stack_ai)
+ e2_w8(buf, pos+cp, 65)
+ e2_w8(buf, pos+cp+1, 82)
+ cp = cp + 2 // push r10
+ stack_ai = stack_ai - 1
+ return cp
// ── ③ 栈清理(IR_CALL + IR_SPAWN 两处同源)──
// call 后恢复 rsp:add rsp, stack_count*8——字节数 ≤127 → 4B 立即数形
// (48 83 C4 imm8),否则 7B 形(48 81 C4 imm32)。返回新 cp。
-fn cs_stack_cleanup(buf: string, pos: int, cp: int, stack_count: int) -> int {
- if stack_count > 0 {
- stack_bytes := stack_count * 8;
- if stack_bytes <= 127 {
- e2_w8(buf, pos+cp, 72); e2_w8(buf, pos+cp+1, 131);
- e2_w8(buf, pos+cp+2, 196); e2_w8(buf, pos+cp+3, stack_bytes); cp = cp + 4;
- } else {
- e2_w8(buf, pos+cp, 72); e2_w8(buf, pos+cp+1, 129); e2_w8(buf, pos+cp+2, 196);
- e2_w32(buf, pos+cp+3, stack_bytes); cp = cp + 7;
- }
- }
- return cp;
-}
+fn cs_stack_cleanup(buf: string, pos: int, cp: int, stack_count: int) -> int:
+ if stack_count > 0:
+ stack_bytes := stack_count * 8
+ if stack_bytes <= 127:
+ e2_w8(buf, pos+cp, 72)
+ e2_w8(buf, pos+cp+1, 131)
+ e2_w8(buf, pos+cp+2, 196)
+ e2_w8(buf, pos+cp+3, stack_bytes)
+ cp = cp + 4
+ else:
+ e2_w8(buf, pos+cp, 72)
+ e2_w8(buf, pos+cp+1, 129)
+ e2_w8(buf, pos+cp+2, 196)
+ e2_w32(buf, pos+cp+3, stack_bytes)
+ cp = cp + 7
+ return cp
// ── ④ IR_RETURN 值序列 + ret_patch 登记 + jmp 占位 ──
// s1 < 0(无值)→ 只登记 ret_patch(尾声回填 jmp → epilogue)。
// 返回新 cp。
-fn cs_ret_value(buf: string, pos: int, cp: int, s1: int) -> int {
- if s1 >= 0 {
- if e2_is_glob(s1) != 0 {
+fn cs_ret_value(buf: string, pos: int, cp: int, s1: int) -> int:
+ if s1 >= 0:
+ if e2_is_glob(s1) != 0:
// 全局支**自身按型分派**(裁-SEAM-4 修正修法:不是把 dex 判定前移——前移
// 会让全局 dex 返回走 rax,而 dex 返回约定在 **XMM0**)。零字节代价:
// 全局 dex 返回当前不可达(返回点已转 scaled ⇒ s1 恒临时),属次序不变量加固。
- if irv_type(s1) == TI_DEX {
- cp = cp + e2_sd_ld_var(buf, pos+cp, 0, s1); // movsd xmm0, [rip 槽]
- } else {
+ if irv_type(s1) == TI_DEX:
+ cp = cp + e2_sd_ld_var(buf, pos+cp, 0, s1) // movsd xmm0, [rip 槽]
+ else:
// Global: load via RIP-relative into rax
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, pos + cp + 3);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, s1);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- cp = cp + e2_lr(buf, pos+cp, 0); // lea r10, [rip+0]
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, pos + cp + 3)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, s1)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ cp = cp + e2_lr(buf, pos+cp, 0) // lea r10, [rip+0]
// mov rax, [r10] — REX.WB + 0x8B
- cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 0, 10%8);
- }
- } else if irv_type(s1) == TI_DEX {
+ cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8)
+ e2_w8(buf, pos+cp, 139)
+ cp = cp + 1
+ cp = cp + emit_modrm(buf, pos+cp, 0, 0, 10%8)
+ else if irv_type(s1) == TI_DEX:
// binary64 返回:movsd xmm0, [slot](SysV 返回值在 XMM0,apx 快路径)
- cp = cp + e2_sd_load(buf, pos+cp, g2_slot(s1));
- } else {
- cp = cp + e2_ld(buf, pos+cp, 0, g2_slot(s1));
+ cp = cp + e2_sd_load(buf, pos+cp, g2_slot(s1))
+ else:
+ cp = cp + e2_ld(buf, pos+cp, 0, g2_slot(s1))
// int 多字 M1(Task 4)tag 读路径 A:return 的 tagged 局部值
// ——tag=1(槽 = 2-limb 指针)→ 解指针取低 limb → rax(exit
// 低 8 位 = 数学值低字节;不解 = 指针低字节 = 错值)。tag=0
// → 快值原样。行内(je rel8 跨 3B deref——tag 字节测试)。
- tg := g2_tag_off(s1);
- if tg != -1 {
- cp = cp + e2_mw_t8(buf, pos+cp, tg);
- w8(buf, pos+cp, 116); w8(buf, pos+cp+1, 3); cp = cp + 2; // je +3
- w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 139); w8(buf, pos+cp+2, 0); cp = cp + 3; // mov rax, [rax]
- }
- }
- }
+ tg := g2_tag_off(s1)
+ if tg != -1:
+ cp = cp + e2_mw_t8(buf, pos+cp, tg)
+ w8(buf, pos+cp, 116)
+ w8(buf, pos+cp+1, 3)
+ cp = cp + 2 // je +3
+ w8(buf, pos+cp, 72)
+ w8(buf, pos+cp+1, 139)
+ w8(buf, pos+cp+2, 0)
+ cp = cp + 3 // mov rax, [rax]
// record position for caller to patch jmp → epilogue
- grow_ret_patch(g_x86_ret_patch_count + 1); w64(g_x86_ret_patch_pos, g_x86_ret_patch_count * 8, pos + cp);
- g_x86_ret_patch_count = g_x86_ret_patch_count + 1;
- cp = cp + e2_jmp(buf, pos+cp, 0);
- return cp;
-}
+ grow_ret_patch(g_x86_ret_patch_count + 1)
+ w64(g_x86_ret_patch_pos, g_x86_ret_patch_count * 8, pos + cp)
+ g_x86_ret_patch_count = g_x86_ret_patch_count + 1
+ cp = cp + e2_jmp(buf, pos+cp, 0)
+ return cp
// ── ⑤ 通用调用路径(IR_CALL 的 s3 ≥ 0 分支)──
// 按函数名(interned string 索引)查 g_x86_func_offsets:
@@ -206,25 +230,31 @@ fn cs_ret_value(buf: string, pos: int, cp: int, s1: int) -> int {
// 未命中 → 外部位登记(g_x86_ext_rel_*,动态链接期解析)+ call 占位
// 两者都先登记 call 补丁(g_x86_call_patch_*,名字 → 后置回填实际 cp)。
// 末尾 d ≥ 0 → e2_store_ret(int → rax / dex → xmm0)。返回新 cp。
-fn cs_call_direct(buf: string, pos: int, cp: int, s3: int, d: int) -> int {
- fn2 := istr_get(s3);
- to := -1; tf := 0;
- loop { if tf >= g_x86_func_off_count { break; } if str_eq(istr_get(r64(g_x86_func_offsets, tf*16)), fn2) != 0 { to = r64(g_x86_func_offsets, tf*16+8); break; } tf = tf + 1; }
+fn cs_call_direct(buf: string, pos: int, cp: int, s3: int, d: int) -> int:
+ fn2 := istr_get(s3)
+ to := -1
+ tf := 0
+ loop:
+ if tf >= g_x86_func_off_count:
+ break
+ if str_eq(istr_get(r64(g_x86_func_offsets, tf*16)), fn2) != 0:
+ to = r64(g_x86_func_offsets, tf*16+8)
+ break
+ tf = tf + 1
// Record call position for post-emission patching
- grow_call_patch(g_x86_call_patch_count + 1);
- w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, pos + cp);
- w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern(fn2));
- g_x86_call_patch_count = g_x86_call_patch_count + 1;
- if to >= 0 {
- cp = cp + e2_call(buf, pos+cp, (176 + to) - (pos + cp + 5));
- } else {
+ grow_call_patch(g_x86_call_patch_count + 1)
+ w64(g_x86_call_patch_pos, g_x86_call_patch_count * 8, pos + cp)
+ w64(g_x86_call_patch_name, g_x86_call_patch_count * 8, str_intern(fn2))
+ g_x86_call_patch_count = g_x86_call_patch_count + 1
+ if to >= 0:
+ cp = cp + e2_call(buf, pos+cp, (176 + to) - (pos + cp + 5))
+ else:
// Unknown function: emit external relocation (for dynamic linking)
- grow_ext_rel(g_x86_ext_rel_count + 1);
- w64(g_x86_ext_rel_pos, g_x86_ext_rel_count * 8, pos + cp + 1);
- w64(g_x86_ext_rel_name, g_x86_ext_rel_count * 8, s3);
- g_x86_ext_rel_count = g_x86_ext_rel_count + 1;
- cp = cp + e2_call(buf, pos+cp, 0);
- }
- if d >= 0 { cp = cp + e2_store_ret(buf, pos+cp, d); }
- return cp;
-}
+ grow_ext_rel(g_x86_ext_rel_count + 1)
+ w64(g_x86_ext_rel_pos, g_x86_ext_rel_count * 8, pos + cp + 1)
+ w64(g_x86_ext_rel_name, g_x86_ext_rel_count * 8, s3)
+ g_x86_ext_rel_count = g_x86_ext_rel_count + 1
+ cp = cp + e2_call(buf, pos+cp, 0)
+ if d >= 0:
+ cp = cp + e2_store_ret(buf, pos+cp, d)
+ return cp
diff --git a/src/os/linux/entry.cr b/src/os/linux/entry.cr
index 36dfe1ed..09996123 100644
--- a/src/os/linux/entry.cr
+++ b/src/os/linux/entry.cr
@@ -12,125 +12,146 @@
// Depends on: x86_64/instr.cr(emit_rex/emit_modrm/emit_sib/e2_*)、
// x86_64/sizes.cr(sz_start_body/sz_start_argv_save)
-fn emit_start(buf: string, pos: int) -> int {
- cp : ., mut = pos;
+fn emit_start(buf: string, pos: int) -> int:
+ cp : ., mut = pos
// mov rdi, [rsp] — load argc (rdi=7)
- cp = cp + emit_rex(buf, cp, 1, 0, 0, 0);
- e2_w8(buf, cp, 139); cp = cp + 1;
- cp = cp + emit_modrm(buf, cp, 0, 7, 4); // [rsp] via SIB
- cp = cp + emit_sib(buf, cp, 0, 4, 4);
+ cp = cp + emit_rex(buf, cp, 1, 0, 0, 0)
+ e2_w8(buf, cp, 139)
+ cp = cp + 1
+ cp = cp + emit_modrm(buf, cp, 0, 7, 4) // [rsp] via SIB
+ cp = cp + emit_sib(buf, cp, 0, 4, 4)
// lea rsi, [rsp+8] — pointer to argv (rsi=6, no REX extension)
- cp = cp + emit_rex(buf, cp, 1, 0, 0, 0);
- e2_w8(buf, cp, 141); cp = cp + 1;
- cp = cp + emit_modrm(buf, cp, 1, 6, 4); // [rsp+disp8]
- cp = cp + emit_sib(buf, cp, 0, 4, 4);
- e2_w8(buf, cp, 8); cp = cp + 1;
+ cp = cp + emit_rex(buf, cp, 1, 0, 0, 0)
+ e2_w8(buf, cp, 141)
+ cp = cp + 1
+ cp = cp + emit_modrm(buf, cp, 1, 6, 4) // [rsp+disp8]
+ cp = cp + emit_sib(buf, cp, 0, 4, 4)
+ e2_w8(buf, cp, 8)
+ cp = cp + 1
- if gv_argc >= 0 {
+ if gv_argc >= 0:
// lea r10, [rip + 0] (placeholder, patched in Phase 3)
- rip_pos := cp + 3;
- cp = cp + e2_lr(buf, cp, 0);
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_argc);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ rip_pos := cp + 3
+ cp = cp + e2_lr(buf, cp, 0)
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_argc)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov [r10], rdi — store argc
- cp = cp + emit_rex(buf, cp, 1, 0, 0, 10/8);
- e2_w8(buf, cp, 137); cp = cp + 1;
- cp = cp + emit_modrm(buf, cp, 0, 7, 10%8);
- }
+ cp = cp + emit_rex(buf, cp, 1, 0, 0, 10/8)
+ e2_w8(buf, cp, 137)
+ cp = cp + 1
+ cp = cp + emit_modrm(buf, cp, 0, 7, 10%8)
- if gv_argv >= 0 {
- rip_pos2 := cp + 3;
- cp = cp + e2_lr(buf, cp, 0);
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos2);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_argv);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ if gv_argv >= 0:
+ rip_pos2 := cp + 3
+ cp = cp + e2_lr(buf, cp, 0)
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos2)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_argv)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov [r10], rsi — store argv
- cp = cp + emit_rex(buf, cp, 1, 0, 0, 10/8);
- e2_w8(buf, cp, 137); cp = cp + 1;
- cp = cp + emit_modrm(buf, cp, 0, 6, 10%8);
- }
+ cp = cp + emit_rex(buf, cp, 1, 0, 0, 10/8)
+ e2_w8(buf, cp, 137)
+ cp = cp + 1
+ cp = cp + emit_modrm(buf, cp, 0, 6, 10%8)
// Initialize g_current_arena = -1 (no arena active)
- if gv_current_arena >= 0 {
- rip_ca := cp + 3;
- cp = cp + e2_lr(buf, cp, 0); // lea r10, [rip+0]
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_ca);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_current_arena);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
+ if gv_current_arena >= 0:
+ rip_ca := cp + 3
+ cp = cp + e2_lr(buf, cp, 0) // lea r10, [rip+0]
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_ca)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gv_current_arena)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
// mov qword [r10], -1 — REX.WB + 0xC7 /0
- cp = cp + emit_rex(buf, cp, 1, 0, 0, 10/8);
- e2_w8(buf, cp, 199); cp = cp + 1; // 0xC7 MOV r/m64, imm32
- cp = cp + emit_modrm(buf, cp, 0, 0, 10%8);
- e2_w32(buf, cp, -1); cp = cp + 4; // immediate = -1 (0xFFFFFFFF)
- }
+ cp = cp + emit_rex(buf, cp, 1, 0, 0, 10/8)
+ e2_w8(buf, cp, 199)
+ cp = cp + 1 // 0xC7 MOV r/m64, imm32
+ cp = cp + emit_modrm(buf, cp, 0, 0, 10%8)
+ e2_w32(buf, cp, -1)
+ cp = cp + 4 // immediate = -1 (0xFFFFFFFF)
// Write compile-time constant global initializers (g_ir_globals[i].
// init_val, i64 at +16; 0 = none — BSS is already zero).
// g_current_arena is also covered by the explicit init above; the
// LET-based init below writes it again with the same value (harmless).
- gi0 : ., mut = 0;
- loop { if gi0 >= g_ir_global_count { break; }
- iv := r64(g_ir_globals, gi0 * 24 + 16);
- gvv0 := r64(g_ir_globals, gi0 * 24 + 8);
- if iv != 0 && gvv0 >= 0 {
+ gi0 : ., mut = 0
+ loop:
+ if gi0 >= g_ir_global_count:
+ break
+ iv := r64(g_ir_globals, gi0 * 24 + 16)
+ gvv0 := r64(g_ir_globals, gi0 * 24 + 8)
+ if iv != 0 && gvv0 >= 0:
// lea r10, [rip+0] — rip_patch for the global's BSS slot
- rip_pos_g := cp + 3;
- cp = cp + e2_lr(buf, cp, 0);
- grow_rip_patch(g_x86_rip_patch_count + 1);
- w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos_g);
- w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gvv0);
- g_x86_rip_patch_count = g_x86_rip_patch_count + 1;
- if iv >= -2147483647 - 1 && iv <= 2147483647 {
+ rip_pos_g := cp + 3
+ cp = cp + e2_lr(buf, cp, 0)
+ grow_rip_patch(g_x86_rip_patch_count + 1)
+ w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, rip_pos_g)
+ w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, gvv0)
+ g_x86_rip_patch_count = g_x86_rip_patch_count + 1
+ if iv >= -2147483647 - 1 && iv <= 2147483647:
// mov qword [r10], imm32 (sign-extended) — 49 C7 02 imm32
- w8(buf, cp, 73); w8(buf, cp+1, 199); w8(buf, cp+2, 2);
- e2_w32(buf, cp+3, iv); cp = cp + 7;
- } else {
+ w8(buf, cp, 73)
+ w8(buf, cp+1, 199)
+ w8(buf, cp+2, 2)
+ e2_w32(buf, cp+3, iv)
+ cp = cp + 7
+ else:
// mov rax, imm64; mov [r10], rax
- w8(buf, cp, 72); w8(buf, cp+1, 184); e2_w64(buf, cp+2, iv); cp = cp + 10;
- w8(buf, cp, 73); w8(buf, cp+1, 137); w8(buf, cp+2, 2); cp = cp + 3;
- }
- }
- gi0 = gi0 + 1; }
+ w8(buf, cp, 72)
+ w8(buf, cp+1, 184)
+ e2_w64(buf, cp+2, iv)
+ cp = cp + 10
+ w8(buf, cp, 73)
+ w8(buf, cp+1, 137)
+ w8(buf, cp+2, 2)
+ cp = cp + 3
+ gi0 = gi0 + 1
- g_call_main_pos = cp;
- cp = cp + e2_call(buf, cp, 0); // call main
+ g_call_main_pos = cp
+ cp = cp + e2_call(buf, cp, 0) // call main
// mov edi, eax
- e2_w8(buf, cp, 137); cp = cp + 1;
- cp = cp + emit_modrm(buf, cp, 3, 0, 7);
+ e2_w8(buf, cp, 137)
+ cp = cp + 1
+ cp = cp + emit_modrm(buf, cp, 3, 0, 7)
// mov eax, 60 (sys_exit)
- e2_w8(buf, cp, 184); cp = cp + 1; // 0xB8 MOV r, imm32 (rax)
- cp = cp + e2_w32(buf, cp, 60);
+ e2_w8(buf, cp, 184)
+ cp = cp + 1 // 0xB8 MOV r, imm32 (rax)
+ cp = cp + e2_w32(buf, cp, 60)
// syscall
- e2_w8(buf, cp, 15); cp = cp + 1;
- e2_w8(buf, cp, 5); cp = cp + 1;
+ e2_w8(buf, cp, 15)
+ cp = cp + 1
+ e2_w8(buf, cp, 5)
+ cp = cp + 1
- return cp - pos;
-}
+ return cp - pos
-fn emit_start_size() -> int {
- sz : ., mut = sz_start_body();
- if gv_argc >= 0 { sz = sz + sz_start_argv_save(); }
- if gv_argv >= 0 { sz = sz + sz_start_argv_save(); }
+fn emit_start_size() -> int:
+ sz : ., mut = sz_start_body()
+ if gv_argc >= 0:
+ sz = sz + sz_start_argv_save()
+ if gv_argv >= 0:
+ sz = sz + sz_start_argv_save()
// g_current_arena init: lea(7) + rex+mov+modrm+imm32(7) = 14 bytes
- if gv_current_arena >= 0 { sz = sz + 14; }
+ if gv_current_arena >= 0:
+ sz = sz + 14
// Constant global initializers: lea r10(7) + mov imm32(7) = 14 bytes,
// or mov rax imm64 + mov [r10],rax = 20 bytes for large values.
- gi0s : ., mut = 0;
- loop { if gi0s >= g_ir_global_count { break; }
- ivs := r64(g_ir_globals, gi0s * 24 + 16);
- gvvs := r64(g_ir_globals, gi0s * 24 + 8);
- if ivs != 0 && gvvs >= 0 {
- if ivs >= -2147483647 - 1 && ivs <= 2147483647 { sz = sz + 14; }
- else { sz = sz + 20; }
- }
- gi0s = gi0s + 1; }
- return sz;
-}
+ gi0s : ., mut = 0
+ loop:
+ if gi0s >= g_ir_global_count:
+ break
+ ivs := r64(g_ir_globals, gi0s * 24 + 16)
+ gvvs := r64(g_ir_globals, gi0s * 24 + 8)
+ if ivs != 0 && gvvs >= 0:
+ if ivs >= -2147483647 - 1 && ivs <= 2147483647:
+ sz = sz + 14
+ else:
+ sz = sz + 20
+ gi0s = gi0s + 1
+ return sz
diff --git a/src/os/linux/syscall.cr b/src/os/linux/syscall.cr
index df189a27..ffbe7c02 100644
--- a/src/os/linux/syscall.cr
+++ b/src/os/linux/syscall.cr
@@ -39,16 +39,18 @@
// ── syscall3(num, a, b, c) —— 三个非编号参数 ──
// 转位(rax ← rdi, rdi ← rsi, rsi ← rdx, rdx ← rcx)后 0F 05;返回值 rax
// 按 d 的类型回存(int 槽 / binary64 槽,见 e2_store_ret)。返回新 cp。
-fn sys_syscall3_stub(buf: string, pos: int, cp: int, d: int) -> int {
- cp = cp + e2_mov(buf, pos+cp, 0, 7);
- cp = cp + e2_mov(buf, pos+cp, 7, 6);
- cp = cp + e2_mov(buf, pos+cp, 6, 2);
- cp = cp + e2_mov(buf, pos+cp, 2, 1);
+fn sys_syscall3_stub(buf: string, pos: int, cp: int, d: int) -> int:
+ cp = cp + e2_mov(buf, pos+cp, 0, 7)
+ cp = cp + e2_mov(buf, pos+cp, 7, 6)
+ cp = cp + e2_mov(buf, pos+cp, 6, 2)
+ cp = cp + e2_mov(buf, pos+cp, 2, 1)
// syscall: 2-byte 0x0F 0x05
- e2_w8(buf, pos+cp, 15); e2_w8(buf, pos+cp+1, 5); cp = cp + 2;
- if d >= 0 { cp = cp + e2_store_ret(buf, pos+cp, d); }
- return cp;
-}
+ e2_w8(buf, pos+cp, 15)
+ e2_w8(buf, pos+cp+1, 5)
+ cp = cp + 2
+ if d >= 0:
+ cp = cp + e2_store_ret(buf, pos+cp, d)
+ return cp
// ── syscall4(num, a, b, c, d) —— 第四个非编号参数经 r10 ──
// syscall4(num, a, b, c, d)——第 4 参 d 经 r10 传递(x86-64 syscall
@@ -57,14 +59,16 @@ fn sys_syscall3_stub(buf: string, pos: int, cp: int, d: int) -> int {
// rcx(ir_cnt=3)、第 5 参放 r8(ir_cnt=4),syscall 读 r10 = 残留
// 垃圾 → 内核 EFAULT 或写错地址 → 退出码传播不可靠。
// 返回新 cp。
-fn sys_syscall4_stub(buf: string, pos: int, cp: int, d: int) -> int {
- cp = cp + e2_mov(buf, pos+cp, 0, 7); // rax = rdi — syscall number
- cp = cp + e2_mov(buf, pos+cp, 7, 6); // rdi = rsi — arg1
- cp = cp + e2_mov(buf, pos+cp, 6, 2); // rsi = rdx — arg2
- cp = cp + e2_mov(buf, pos+cp, 2, 1); // rdx = rcx — arg3
- cp = cp + e2_mov(buf, pos+cp, 10, 8); // r10 = r8 — arg4
+fn sys_syscall4_stub(buf: string, pos: int, cp: int, d: int) -> int:
+ cp = cp + e2_mov(buf, pos+cp, 0, 7) // rax = rdi — syscall number
+ cp = cp + e2_mov(buf, pos+cp, 7, 6) // rdi = rsi — arg1
+ cp = cp + e2_mov(buf, pos+cp, 6, 2) // rsi = rdx — arg2
+ cp = cp + e2_mov(buf, pos+cp, 2, 1) // rdx = rcx — arg3
+ cp = cp + e2_mov(buf, pos+cp, 10, 8) // r10 = r8 — arg4
// syscall: 2-byte 0x0F 0x05
- e2_w8(buf, pos+cp, 15); e2_w8(buf, pos+cp+1, 5); cp = cp + 2;
- if d >= 0 { cp = cp + e2_store_ret(buf, pos+cp, d); }
- return cp;
-}
+ e2_w8(buf, pos+cp, 15)
+ e2_w8(buf, pos+cp+1, 5)
+ cp = cp + 2
+ if d >= 0:
+ cp = cp + e2_store_ret(buf, pos+cp, d)
+ return cp
diff --git a/src/runtime/arena_globals.cr b/src/runtime/arena_globals.cr
index 266e65fd..b0aae02b 100644
--- a/src/runtime/arena_globals.cr
+++ b/src/runtime/arena_globals.cr
@@ -1,4 +1,4 @@
// Shared arena state used by the runtime allocator and arena stdlib.
-g_current_arena : int, mut = -1;
-g_arena_pool_data : string, mut;
-g_arena_free_list : int, mut = -1;
+g_current_arena : int, mut = -1
+g_arena_pool_data : string, mut
+g_arena_free_list : int, mut = -1
diff --git a/src/runtime/rt.cr b/src/runtime/rt.cr
index 1e810577..83293f6d 100644
--- a/src/runtime/rt.cr
+++ b/src/runtime/rt.cr
@@ -1,14 +1,14 @@
// Low-level runtime globals — used by rt.s (assembly) and ELF backend.
import arena_globals
-g_rt_argc : int, mut;
-g_rt_argv_ptr : string, mut;
+g_rt_argc : int, mut
+g_rt_argv_ptr : string, mut
// Bump allocator globals — must be Core globals so the ELF backend's
// rip_patch mechanism resolves their BSS addresses correctly.
-g_heap_ptr : string, mut;
-g_heap_end : string, mut;
+g_heap_ptr : string, mut
+g_heap_end : string, mut
// Hotpatch runtime state
-g_hp_config : string, mut;
-g_hp_inflight : string, mut;
+g_hp_config : string, mut
+g_hp_inflight : string, mut
diff --git a/src/scheduler/example.cr b/src/scheduler/example.cr
index 3684ce44..c88cda45 100644
--- a/src/scheduler/example.cr
+++ b/src/scheduler/example.cr
@@ -6,18 +6,16 @@
import io
-fn hello(name: string) {
- print("hello ");
- println(name);
-}
+fn hello(name: string):
+ print("hello ")
+ println(name)
-fn add(a: int, b: int) -> int {
- return a + b;
-}
+fn add(a: int, b: int) -> int:
+ return a + b
-fn main() -> int {
+fn main() -> int:
// 创建调度表(2 个条目)
- table := sched_create(2);
+ table := sched_create(2)
// 注册函数(把函数指针写入表)
// 注意:Core 没有函数指针类型,需要用 load_str_ptr + store_str_ptr
@@ -32,10 +30,9 @@ fn main() -> int {
// sched_call_1(table.entries, 0, "world");
// result := sched_call_2(table.entries, 1, 3, 5);
- println("scheduler example");
+ println("scheduler example")
// 目前只演示表操作,不实际调用
//(函数指针在 Core 层面不可达,待编译器支持)
- return 0;
-}
+ return 0
diff --git a/src/stdlib/arena.cr b/src/stdlib/arena.cr
index e681fb46..b5bccac2 100644
--- a/src/stdlib/arena.cr
+++ b/src/stdlib/arena.cr
@@ -4,100 +4,119 @@
import arena_globals
// Arena metadata — dynamic arrays (no fixed limit, grows like g_df_nodes)
-g_arena_cursors : string, mut; // int[] — bump cursor offset per arena
-g_arena_sizes : string, mut; // int[] — chunk capacity per arena
-g_arena_parents : string, mut; // int[] — parent arena ID (for nesting restore)
+g_arena_cursors : string, mut // int[] — bump cursor offset per arena
+g_arena_sizes : string, mut // int[] — chunk capacity per arena
+g_arena_parents : string, mut // int[] — parent arena ID (for nesting restore)
-g_arena_max_size : int, mut; // default chunk size per arena
-g_arena_count : int, mut = 0; // total slots allocated
-g_arena_cap : int, mut = 0; // metadata array capacity
+g_arena_max_size : int, mut // default chunk size per arena
+g_arena_count : int, mut = 0 // total slots allocated
+g_arena_cap : int, mut = 0 // metadata array capacity
// ── Internal: grow metadata arrays ──
-fn _grow_arena_meta(needed: int) {
- if needed < g_arena_cap { return; }
- nc : ., mut = g_arena_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; }
- saved_arena := g_current_arena;
- g_current_arena = -1;
+fn _grow_arena_meta(needed: int):
+ if needed < g_arena_cap:
+ return
+ nc : ., mut = g_arena_cap * 2
+ if nc < 64:
+ nc = 64
+ if nc < needed:
+ nc = needed + 64
+ saved_arena := g_current_arena
+ g_current_arena = -1
// cursors
- nb := alloc(nc * 8);
- zi : ., mut = 0; loop { if zi >= nc * 8 { break; } store8(nb, zi, 0); zi = zi + 1; }
- if g_arena_cap > 0 { _dyncpy(g_arena_cursors, g_arena_cap * 8, nb); }
- g_arena_cursors = nb;
+ nb := alloc(nc * 8)
+ zi : ., mut = 0
+ loop:
+ if zi >= nc * 8:
+ break
+ store8(nb, zi, 0)
+ zi = zi + 1
+ if g_arena_cap > 0:
+ _dyncpy(g_arena_cursors, g_arena_cap * 8, nb)
+ g_arena_cursors = nb
// sizes
- nb2 := alloc(nc * 8);
- zi = 0; loop { if zi >= nc * 8 { break; } store8(nb2, zi, 0); zi = zi + 1; }
- if g_arena_cap > 0 { _dyncpy(g_arena_sizes, g_arena_cap * 8, nb2); }
- g_arena_sizes = nb2;
+ nb2 := alloc(nc * 8)
+ zi = 0
+ loop:
+ if zi >= nc * 8:
+ break
+ store8(nb2, zi, 0)
+ zi = zi + 1
+ if g_arena_cap > 0:
+ _dyncpy(g_arena_sizes, g_arena_cap * 8, nb2)
+ g_arena_sizes = nb2
// parents
- nb3 := alloc(nc * 8);
- zi = 0; loop { if zi >= nc * 8 { break; } store8(nb3, zi, 0); zi = zi + 1; }
- if g_arena_cap > 0 { _dyncpy(g_arena_parents, g_arena_cap * 8, nb3); }
- g_arena_parents = nb3;
- g_arena_cap = nc;
- g_current_arena = saved_arena;
-}
+ nb3 := alloc(nc * 8)
+ zi = 0
+ loop:
+ if zi >= nc * 8:
+ break
+ store8(nb3, zi, 0)
+ zi = zi + 1
+ if g_arena_cap > 0:
+ _dyncpy(g_arena_parents, g_arena_cap * 8, nb3)
+ g_arena_parents = nb3
+ g_arena_cap = nc
+ g_current_arena = saved_arena
// ── Public API ──
-fn arena_init(pool_size: int, arena_size: int) {
+fn arena_init(pool_size: int, arena_size: int):
// The backing pool outlives the caller's automatic function arena.
- g_current_arena = -1;
- g_arena_pool_data = alloc(pool_size);
- g_arena_max_size = arena_size;
- g_arena_free_list = -1;
- g_arena_count = 0;
- g_arena_cap = 0;
-}
+ g_current_arena = -1
+ g_arena_pool_data = alloc(pool_size)
+ g_arena_max_size = arena_size
+ g_arena_free_list = -1
+ g_arena_count = 0
+ g_arena_cap = 0
-fn arena_new() -> int {
- ai : ., mut = -1;
+fn arena_new() -> int:
+ ai : ., mut = -1
// Try free list first
- if g_arena_free_list >= 0 {
- ai = g_arena_free_list;
- g_arena_free_list = r64(g_arena_parents, ai * 8); // pop head
- }
+ if g_arena_free_list >= 0:
+ ai = g_arena_free_list
+ g_arena_free_list = r64(g_arena_parents, ai * 8) // pop head
- if ai < 0 {
+ if ai < 0:
// Allocate new slot (grow metadata arrays)
- need := g_arena_count + 1;
- _grow_arena_meta(need);
- ai = g_arena_count;
- g_arena_count = need;
- }
+ need := g_arena_count + 1
+ _grow_arena_meta(need)
+ ai = g_arena_count
+ g_arena_count = need
// Initialize slot
- w64(g_arena_cursors, ai * 8, 0);
- w64(g_arena_sizes, ai * 8, g_arena_max_size);
- w64(g_arena_parents, ai * 8, -1);
+ w64(g_arena_cursors, ai * 8, 0)
+ w64(g_arena_sizes, ai * 8, g_arena_max_size)
+ w64(g_arena_parents, ai * 8, -1)
// Set parent = previous current arena
- if g_current_arena >= 0 {
- w64(g_arena_parents, ai * 8, g_current_arena);
- }
+ if g_current_arena >= 0:
+ w64(g_arena_parents, ai * 8, g_current_arena)
// Activate
- g_current_arena = ai;
- return ai;
-}
+ g_current_arena = ai
+ return ai
-fn arena_reset(ai: int) {
- if ai < 0 || ai >= g_arena_count { return; }
+fn arena_reset(ai: int):
+ if ai < 0 || ai >= g_arena_count:
+ return
// Save parent BEFORE free list overwrites g_arena_parents[ai]
- parent := r64(g_arena_parents, ai * 8);
+ parent := r64(g_arena_parents, ai * 8)
// Push to free list
- w64(g_arena_parents, ai * 8, g_arena_free_list);
- g_arena_free_list = ai;
+ w64(g_arena_parents, ai * 8, g_arena_free_list)
+ g_arena_free_list = ai
// Restore parent
- if parent >= 0 { g_current_arena = parent; }
- else { g_current_arena = -1; }
-}
+ if parent >= 0:
+ g_current_arena = parent
+ else:
+ g_current_arena = -1
-fn arena_avail(ai: int) -> int {
- if ai < 0 || ai >= g_arena_count { return 0; }
- cursor := r64(g_arena_cursors, ai * 8);
- limit := r64(g_arena_sizes, ai * 8);
- return limit - cursor;
-}
+fn arena_avail(ai: int) -> int:
+ if ai < 0 || ai >= g_arena_count:
+ return 0
+ cursor := r64(g_arena_cursors, ai * 8)
+ limit := r64(g_arena_sizes, ai * 8)
+ return limit - cursor
diff --git a/src/stdlib/assert.cr b/src/stdlib/assert.cr
index cc7bfc42..cae6bac2 100644
--- a/src/stdlib/assert.cr
+++ b/src/stdlib/assert.cr
@@ -16,110 +16,86 @@
// 条件为假时 panic
// 等价于 Rust 的 assert!(cond, "msg")
-fn assert(cond: int, msg: string) {
- if cond == 0 {
- panic_at(msg, "", 0, 0);
- }
-}
+fn assert(cond: int, msg: string):
+ if cond == 0:
+ panic_at(msg, "", 0, 0)
// 条件为真时 panic(用于反向断言)
-fn assert_not(cond: int, msg: string) {
- if cond != 0 {
- panic_at(msg, "", 0, 0);
- }
-}
+fn assert_not(cond: int, msg: string):
+ if cond != 0:
+ panic_at(msg, "", 0, 0)
// --- 值断言 ---
// a == b 不等时 panic
// 等价于 Rust 的 assert_eq!(a, b)
-fn assert_eq(a: int, b: int, msg: string) {
- if a != b {
- panic_at(msg, "", 0, 0);
- }
-}
+fn assert_eq(a: int, b: int, msg: string):
+ if a != b:
+ panic_at(msg, "", 0, 0)
// a != b 相等时 panic
// 等价于 Rust 的 assert_ne!(a, b)
-fn assert_ne(a: int, b: int, msg: string) {
- if a == b {
- panic_at(msg, "", 0, 0);
- }
-}
+fn assert_ne(a: int, b: int, msg: string):
+ if a == b:
+ panic_at(msg, "", 0, 0)
// 指针/引用值为空时 panic
-fn assert_not_null(ptr: string, msg: string) {
- if str_len(ptr) == 0 {
- panic_at(msg, "", 0, 0);
- }
-}
+fn assert_not_null(ptr: string, msg: string):
+ if str_len(ptr) == 0:
+ panic_at(msg, "", 0, 0)
// --- 调试断言(debug_assert)---
// 未来:由编译选项控制是否启用
// 目前等同 assert(始终检查)
-fn debug_assert(cond: int, msg: string) {
- if cond == 0 {
- panic_at(msg, "", 0, 0);
- }
-}
+fn debug_assert(cond: int, msg: string):
+ if cond == 0:
+ panic_at(msg, "", 0, 0)
-fn debug_assert_eq(a: int, b: int, msg: string) {
- if a != b {
- panic_at(msg, "", 0, 0);
- }
-}
+fn debug_assert_eq(a: int, b: int, msg: string):
+ if a != b:
+ panic_at(msg, "", 0, 0)
// --- 标记宏(markers)---
// 标记不可达代码
// 等价于 Rust 的 unreachable!()
-fn unreachable(msg: string) {
- panic_at("internal error: entered unreachable code", "", 0, 0);
-}
+fn unreachable(msg: string):
+ panic_at("internal error: entered unreachable code", "", 0, 0)
// 不可达代码(有返回值—用于函数必须有返回值的场景)
-fn unreachable_mut(msg: string) -> int {
- panic_at("internal error: entered unreachable code", "", 0, 0);
- return -1;
-}
+fn unreachable_mut(msg: string) -> int:
+ panic_at("internal error: entered unreachable code", "", 0, 0)
+ return -1
// 标记未完成的功能
// 等价于 Rust 的 todo!()
-fn todo(msg: string) {
- panic_at("not yet implemented: ", "", 0, 0);
-}
+fn todo(msg: string):
+ panic_at("not yet implemented: ", "", 0, 0)
-fn todo_mut(msg: string) -> int {
- panic_at("not yet implemented: ", "", 0, 0);
- return -1;
-}
+fn todo_mut(msg: string) -> int:
+ panic_at("not yet implemented: ", "", 0, 0)
+ return -1
// 标记未实现的功能(与 todo 类似但语义不同)
// 等价于 Rust 的 unimplemented!()
-fn unimplemented(msg: string) {
- panic_at("not implemented: ", "", 0, 0);
-}
+fn unimplemented(msg: string):
+ panic_at("not implemented: ", "", 0, 0)
-fn unimplemented_mut(msg: string) -> int {
- panic_at("not implemented: ", "", 0, 0);
- return -1;
-}
+fn unimplemented_mut(msg: string) -> int:
+ panic_at("not implemented: ", "", 0, 0)
+ return -1
// --- 边界检查 ---
// 数组访问的运行时边界检查
// 检查 index 是否在 [0, len) 范围内
// 超出范围时 panic
-fn check_bounds(index: int, len: int, msg: string) {
- if index < 0 || index >= len {
- panic_at(msg, "", 0, 0);
- }
-}
+fn check_bounds(index: int, len: int, msg: string):
+ if index < 0 || index >= len:
+ panic_at(msg, "", 0, 0)
// 范围检查(start..end 是否在 [0, len) 内)
-fn check_range(start: int, end: int, len: int, msg: string) {
- if start < 0 || start > end || end > len {
- panic_at(msg, "", 0, 0);
- }
-}
+fn check_range(start: int, end: int, len: int, msg: string):
+ if start < 0 || start > end || end > len:
+ panic_at(msg, "", 0, 0)
diff --git a/src/stdlib/chan.cr b/src/stdlib/chan.cr
index 3e863109..304ea7fb 100644
--- a/src/stdlib/chan.cr
+++ b/src/stdlib/chan.cr
@@ -2,14 +2,12 @@
import sched
// Auto-initialization: any channel op triggers sched_init if needed.
-g_chan_inited : int, mut = 0;
+g_chan_inited : int, mut = 0
-fn _chan_ensure_init() {
- if g_chan_inited == 0 {
- sched_init();
- g_chan_inited = 1;
- }
-}
+fn _chan_ensure_init():
+ if g_chan_inited == 0:
+ sched_init()
+ g_chan_inited = 1
// Channel layout (64 bytes):
// 0: buf — pointer to ring buffer
@@ -30,152 +28,143 @@ fn _chan_ensure_init() {
// 72: temp_val — temporary value storage for handoff (offset 56 is
// saved_fn — never write it from channel code)
-fn chan_make(elemsize: int, cap: int) -> string {
- _chan_ensure_init();
- ch := alloc(64);
- buf := alloc(cap * elemsize);
- w64(ch, 0, buf); // buf
- w64(ch, 8, cap); // cap
- w64(ch, 16, 0); // len
- w64(ch, 24, 0); // head
- w64(ch, 32, elemsize); // elemsize
- w64(ch, 40, -1); // send_wait = empty
- w64(ch, 48, -1); // recv_wait = empty
- w64(ch, 56, 0); // closed = false
- return ch;
-}
-
-fn chan_send(ch: string, val: int) {
- _chan_ensure_init();
- buf := r64(ch, 0);
- cap := r64(ch, 8);
- len := r64(ch, 16);
- head := r64(ch, 24);
- esize := r64(ch, 32);
+fn chan_make(elemsize: int, cap: int) -> string:
+ _chan_ensure_init()
+ ch := alloc(64)
+ buf := alloc(cap * elemsize)
+ w64(ch, 0, buf) // buf
+ w64(ch, 8, cap) // cap
+ w64(ch, 16, 0) // len
+ w64(ch, 24, 0) // head
+ w64(ch, 32, elemsize) // elemsize
+ w64(ch, 40, -1) // send_wait = empty
+ w64(ch, 48, -1) // recv_wait = empty
+ w64(ch, 56, 0) // closed = false
+ return ch
+
+fn chan_send(ch: string, val: int):
+ _chan_ensure_init()
+ buf := r64(ch, 0)
+ cap := r64(ch, 8)
+ len := r64(ch, 16)
+ head := r64(ch, 24)
+ esize := r64(ch, 32)
// Check for waiting receivers first (direct handoff)
- recv_wait := r64(ch, 48);
- if recv_wait >= 0 {
+ recv_wait := r64(ch, 48)
+ if recv_wait >= 0:
// Direct handoff: copy value to the waiting receiver's temp_val
- nxt := r64(recv_wait, 48); // save next before overwriting
- w64(recv_wait, 72, val); // store value in receiver's temp_val
- w64(recv_wait, 8, 0); // set to _Grunnable
- sched_enqueue(recv_wait);
- w64(ch, 48, nxt); // remove from recv_wait list
- return;
- }
-
- if len < cap {
+ nxt := r64(recv_wait, 48) // save next before overwriting
+ w64(recv_wait, 72, val) // store value in receiver's temp_val
+ w64(recv_wait, 8, 0) // set to _Grunnable
+ sched_enqueue(recv_wait)
+ w64(ch, 48, nxt) // remove from recv_wait list
+ return
+
+ if len < cap:
// Buffer has space
- tail := (head + len) % cap;
- w64(buf, tail * esize, val);
- w64(ch, 16, len + 1);
- return;
- }
+ tail := (head + len) % cap
+ w64(buf, tail * esize, val)
+ w64(ch, 16, len + 1)
+ return
// Buffer full: block on send_wait list
- g := sched_get_curg();
- if g >= 0 {
- w64(g, 72, val); // store value for later delivery (temp_val)
- w64(g, 8, 2); // _Gwaiting
- w64(g, 48, -1); // next = -1
+ g := sched_get_curg()
+ if g >= 0:
+ w64(g, 72, val) // store value for later delivery (temp_val)
+ w64(g, 8, 2) // _Gwaiting
+ w64(g, 48, -1) // next = -1
// Add to channel's send_wait list
- sw := r64(ch, 40);
- if sw < 0 {
- w64(ch, 40, g);
- } else {
- loop {
- nxt := r64(sw, 48);
- if nxt < 0 { w64(sw, 48, g); break; }
- sw = nxt;
- }
- }
- }
+ sw := r64(ch, 40)
+ if sw < 0:
+ w64(ch, 40, g)
+ else:
+ loop:
+ nxt := r64(sw, 48)
+ if nxt < 0:
+ w64(sw, 48, g)
+ break
+ sw = nxt
// Yield — scheduler will wake us when receiver comes
- sched_yield();
-}
-
-fn chan_recv(ch: string) -> int {
- _chan_ensure_init();
- buf := r64(ch, 0);
- cap := r64(ch, 8);
- len := r64(ch, 16);
- head := r64(ch, 24);
- esize := r64(ch, 32);
- closed := r64(ch, 56);
+ sched_yield()
+
+fn chan_recv(ch: string) -> int:
+ _chan_ensure_init()
+ buf := r64(ch, 0)
+ cap := r64(ch, 8)
+ len := r64(ch, 16)
+ head := r64(ch, 24)
+ esize := r64(ch, 32)
+ closed := r64(ch, 56)
// Check for waiting senders first (direct handoff)
- send_wait := r64(ch, 40);
- if send_wait >= 0 {
+ send_wait := r64(ch, 40)
+ if send_wait >= 0:
// Direct handoff: take value from the waiting sender's temp_val
- val := r64(send_wait, 72); // read sender's stored value
- nxt := r64(send_wait, 48);
- w64(send_wait, 8, 0); // set to _Grunnable
- sched_enqueue(send_wait);
- w64(ch, 40, nxt); // remove from send_wait list
- return val;
- }
-
- if len > 0 {
+ val := r64(send_wait, 72) // read sender's stored value
+ nxt := r64(send_wait, 48)
+ w64(send_wait, 8, 0) // set to _Grunnable
+ sched_enqueue(send_wait)
+ w64(ch, 40, nxt) // remove from send_wait list
+ return val
+
+ if len > 0:
// Buffer has data
- val := r64(buf, head * esize);
- w64(ch, 24, (head + 1) % cap);
- w64(ch, 16, len - 1);
- return val;
- }
+ val := r64(buf, head * esize)
+ w64(ch, 24, (head + 1) % cap)
+ w64(ch, 16, len - 1)
+ return val
- if closed != 0 { return 0; }
+ if closed != 0:
+ return 0
// Buffer empty: block on recv_wait list
- g := sched_get_curg();
- if g >= 0 {
- w64(g, 8, 2); // _Gwaiting
- w64(g, 48, -1); // next = -1
-
- rw := r64(ch, 48);
- if rw < 0 {
- w64(ch, 48, g);
- } else {
- loop {
- nxt := r64(rw, 48);
- if nxt < 0 { w64(rw, 48, g); break; }
- rw = nxt;
- }
- }
- }
-
- sched_yield();
+ g := sched_get_curg()
+ if g >= 0:
+ w64(g, 8, 2) // _Gwaiting
+ w64(g, 48, -1) // next = -1
+
+ rw := r64(ch, 48)
+ if rw < 0:
+ w64(ch, 48, g)
+ else:
+ loop:
+ nxt := r64(rw, 48)
+ if nxt < 0:
+ w64(rw, 48, g)
+ break
+ rw = nxt
+
+ sched_yield()
// After wakeup, value should be in this G's temp_val (delivered by sender)
- val := r64(g, 72);
- return val;
-}
+ val := r64(g, 72)
+ return val
-fn chan_close(ch: string) {
- _chan_ensure_init();
- w64(ch, 56, 1); // closed = true
+fn chan_close(ch: string):
+ _chan_ensure_init()
+ w64(ch, 56, 1) // closed = true
// Wake up all waiting senders
- sw := r64(ch, 40);
- loop {
- if sw < 0 { break; }
- nxt := r64(sw, 48);
- w64(sw, 8, 0); // _Grunnable
- sched_enqueue(sw);
- sw = nxt;
- }
- w64(ch, 40, -1); // clear send_wait
+ sw := r64(ch, 40)
+ loop:
+ if sw < 0:
+ break
+ nxt := r64(sw, 48)
+ w64(sw, 8, 0) // _Grunnable
+ sched_enqueue(sw)
+ sw = nxt
+ w64(ch, 40, -1) // clear send_wait
// Wake up all waiting receivers
- rw := r64(ch, 48);
- loop {
- if rw < 0 { break; }
- nxt := r64(rw, 48);
- w64(rw, 8, 0); // _Grunnable
- sched_enqueue(rw);
- rw = nxt;
- }
- w64(ch, 48, -1); // clear recv_wait
-}
+ rw := r64(ch, 48)
+ loop:
+ if rw < 0:
+ break
+ nxt := r64(rw, 48)
+ w64(rw, 8, 0) // _Grunnable
+ sched_enqueue(rw)
+ rw = nxt
+ w64(ch, 48, -1) // clear recv_wait
diff --git a/src/stdlib/cli.cr b/src/stdlib/cli.cr
index d9a31928..274a3441 100644
--- a/src/stdlib/cli.cr
+++ b/src/stdlib/cli.cr
@@ -20,371 +20,388 @@
// MAX_CLI_ARGS = 32
// --- Limits ---
-CLI_LONG_NAME_SIZE : int = 32;
+CLI_LONG_NAME_SIZE : int = 32
// --- Internal structs ---
-struct CliCmd {
+struct CliCmd:
name: string,
desc: string,
-}
-struct CliFlag {
+struct CliFlag:
long_name: string,
short_name: string,
desc: string,
value: string,
has_value: int,
is_bool: int,
-}
// --- Global state ---
-g_cli_prog : string, mut;
-g_cli_desc : string, mut;
-g_cli_cmds : string, mut; g_cli_cmd_count : int, mut; g_cli_cmd_cap : int, mut;
-g_cli_flags : string, mut; g_cli_flag_count : int, mut; g_cli_flag_cap : int, mut;
-g_cli_args : string, mut; g_cli_arg_count : int, mut; g_cli_arg_cap : int, mut;
-
-fn grow_cli_cmds(needed: int) {
- cur_cap : ., mut = g_cli_cmd_cap;
- if needed < cur_cap { return; }
- nc : ., mut = cur_cap * 2; if nc < 8 { nc = 8; } if nc < needed { nc = needed + 8; }
- nb := alloc(nc * 16); _dyncpy(g_cli_cmds, cur_cap * 16, nb); g_cli_cmds = nb; g_cli_cmd_cap = nc; }
-fn grow_cli_flags(needed: int) {
- cur_cap : ., mut = g_cli_flag_cap;
- if needed < cur_cap { return; }
- nc : ., mut = cur_cap * 2; if nc < 8 { nc = 8; } if nc < needed { nc = needed + 8; }
- nb := alloc(nc * 48); _dyncpy(g_cli_flags, cur_cap * 48, nb); g_cli_flags = nb; g_cli_flag_cap = nc; }
-fn grow_cli_args(needed: int) {
- cur_cap : ., mut = g_cli_arg_cap;
- if needed < cur_cap { return; }
- nc : ., mut = cur_cap * 2; if nc < 8 { nc = 8; } if nc < needed { nc = needed + 8; }
- nb := alloc(nc * 8); _dyncpy(g_cli_args, cur_cap * 8, nb); g_cli_args = nb; g_cli_arg_cap = nc; }
-g_cli_matched_cmd : string, mut;
+g_cli_prog : string, mut
+g_cli_desc : string, mut
+g_cli_cmds : string, mut
+g_cli_cmd_count : int, mut
+g_cli_cmd_cap : int, mut
+g_cli_flags : string, mut
+g_cli_flag_count : int, mut
+g_cli_flag_cap : int, mut
+g_cli_args : string, mut
+g_cli_arg_count : int, mut
+g_cli_arg_cap : int, mut
+
+fn grow_cli_cmds(needed: int):
+ cur_cap : ., mut = g_cli_cmd_cap
+ if needed < cur_cap:
+ return
+ nc : ., mut = cur_cap * 2
+ if nc < 8:
+ nc = 8
+ if nc < needed:
+ nc = needed + 8
+ nb := alloc(nc * 16)
+ _dyncpy(g_cli_cmds, cur_cap * 16, nb)
+ g_cli_cmds = nb
+ g_cli_cmd_cap = nc
+fn grow_cli_flags(needed: int):
+ cur_cap : ., mut = g_cli_flag_cap
+ if needed < cur_cap:
+ return
+ nc : ., mut = cur_cap * 2
+ if nc < 8:
+ nc = 8
+ if nc < needed:
+ nc = needed + 8
+ nb := alloc(nc * 48)
+ _dyncpy(g_cli_flags, cur_cap * 48, nb)
+ g_cli_flags = nb
+ g_cli_flag_cap = nc
+fn grow_cli_args(needed: int):
+ cur_cap : ., mut = g_cli_arg_cap
+ if needed < cur_cap:
+ return
+ nc : ., mut = cur_cap * 2
+ if nc < 8:
+ nc = 8
+ if nc < needed:
+ nc = needed + 8
+ nb := alloc(nc * 8)
+ _dyncpy(g_cli_args, cur_cap * 8, nb)
+ g_cli_args = nb
+ g_cli_arg_cap = nc
+g_cli_matched_cmd : string, mut
// --- Init ---
-fn cli_init(prog: string, desc: string) {
- g_cli_prog = prog;
- g_cli_desc = desc;
- g_cli_cmd_count = 0; g_cli_cmd_cap = 0;
- g_cli_flag_count = 0; g_cli_flag_cap = 0;
- g_cli_arg_count = 0; g_cli_arg_cap = 0;
- g_cli_matched_cmd = "";
-}
+fn cli_init(prog: string, desc: string):
+ g_cli_prog = prog
+ g_cli_desc = desc
+ g_cli_cmd_count = 0
+ g_cli_cmd_cap = 0
+ g_cli_flag_count = 0
+ g_cli_flag_cap = 0
+ g_cli_arg_count = 0
+ g_cli_arg_cap = 0
+ g_cli_matched_cmd = ""
// --- Registration ---
-fn cli_cmd(name: string, desc: string) {
- grow_cli_cmds(g_cli_cmd_count + 1);
- off : ., mut = g_cli_cmd_count * 16;
+fn cli_cmd(name: string, desc: string):
+ grow_cli_cmds(g_cli_cmd_count + 1)
+ off : ., mut = g_cli_cmd_count * 16
// 裸字表(16B/条:name、desc):串值以 64 位字存入 ⇒ 显式视图 `@ptr_of`(2(a);
// 语义 = 同一个字,不改存储内容)。安全面 (ii):视图必须出现在 unsafe 块内。
- unsafe {
- w64(g_cli_cmds, off, @ptr_of(name));
- w64(g_cli_cmds, off + 8, @ptr_of(desc));
- }
- g_cli_cmd_count = g_cli_cmd_count + 1;
-}
-
-fn cli_flag(long_name: string, short_name: string, desc: string) {
- grow_cli_flags(g_cli_flag_count + 1);
- off : ., mut = g_cli_flag_count * 48;
- unsafe {
- w64(g_cli_flags, off, @ptr_of(long_name));
- w64(g_cli_flags, off + 8, @ptr_of(short_name));
- w64(g_cli_flags, off + 16, @ptr_of(desc));
- w64(g_cli_flags, off + 24, @ptr_of("")); // value
- }
- w64(g_cli_flags, off + 32, 0); // has_value
- w64(g_cli_flags, off + 40, 0); // is_bool
- g_cli_flag_count = g_cli_flag_count + 1;
-}
-
-fn cli_flag_bool(long_name: string, short_name: string, desc: string) {
- grow_cli_flags(g_cli_flag_count + 1);
- off : ., mut = g_cli_flag_count * 48;
- unsafe {
- w64(g_cli_flags, off, @ptr_of(long_name));
- w64(g_cli_flags, off + 8, @ptr_of(short_name));
- w64(g_cli_flags, off + 16, @ptr_of(desc));
- w64(g_cli_flags, off + 24, @ptr_of("")); // value
- }
- w64(g_cli_flags, off + 32, 0); // has_value
- w64(g_cli_flags, off + 40, 1); // is_bool
- g_cli_flag_count = g_cli_flag_count + 1;
-}
+ unsafe:
+ w64(g_cli_cmds, off, @ptr_of(name))
+ w64(g_cli_cmds, off + 8, @ptr_of(desc))
+ g_cli_cmd_count = g_cli_cmd_count + 1
+
+fn cli_flag(long_name: string, short_name: string, desc: string):
+ grow_cli_flags(g_cli_flag_count + 1)
+ off : ., mut = g_cli_flag_count * 48
+ unsafe:
+ w64(g_cli_flags, off, @ptr_of(long_name))
+ w64(g_cli_flags, off + 8, @ptr_of(short_name))
+ w64(g_cli_flags, off + 16, @ptr_of(desc))
+ w64(g_cli_flags, off + 24, @ptr_of("")) // value
+ w64(g_cli_flags, off + 32, 0) // has_value
+ w64(g_cli_flags, off + 40, 0) // is_bool
+ g_cli_flag_count = g_cli_flag_count + 1
+
+fn cli_flag_bool(long_name: string, short_name: string, desc: string):
+ grow_cli_flags(g_cli_flag_count + 1)
+ off : ., mut = g_cli_flag_count * 48
+ unsafe:
+ w64(g_cli_flags, off, @ptr_of(long_name))
+ w64(g_cli_flags, off + 8, @ptr_of(short_name))
+ w64(g_cli_flags, off + 16, @ptr_of(desc))
+ w64(g_cli_flags, off + 24, @ptr_of("")) // value
+ w64(g_cli_flags, off + 32, 0) // has_value
+ w64(g_cli_flags, off + 40, 1) // is_bool
+ g_cli_flag_count = g_cli_flag_count + 1
// --- Internal helpers ---
-fn _cli_find_flag(name: string) -> int {
- i : ., mut = 0;
- loop {
- if i >= g_cli_flag_count { break; }
+fn _cli_find_flag(name: string) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= g_cli_flag_count:
+ break
// 裸字读出 ⇒ 视图 `@str_of`(同一个字,只是按串用)。
- unsafe {
- ln := @str_of(r64(g_cli_flags, i * 48));
- sn := @str_of(r64(g_cli_flags, i * 48 + 8));
- if str_len(ln) > 0 && str_eq(ln, name) != 0 { return i; }
- if str_len(sn) > 0 && str_eq(sn, name) != 0 { return i; }
- }
- i = i + 1;
- }
- return -1;
-}
-
-fn _cli_is_flag(arg: string) -> int {
- slen := str_len(arg);
- if slen < 2 { return 0; }
- c0 := get_char(arg, 0);
- if str_eq(c0, "-") != 0 { return 1; }
- return 0;
-}
-
-fn _cli_strip_dashes(arg: string) -> string {
- slen := str_len(arg);
- if slen == 0 { return ""; }
- start : ., mut = 0;
- if str_eq(get_char(arg, 0), "-") != 0 {
- start = 1;
- if slen > 1 && str_eq(get_char(arg, 1), "-") != 0 {
- start = 2;
- }
- }
- return str_sub(arg, start, slen - start);
-}
+ unsafe:
+ ln := @str_of(r64(g_cli_flags, i * 48))
+ sn := @str_of(r64(g_cli_flags, i * 48 + 8))
+ if str_len(ln) > 0 && str_eq(ln, name) != 0:
+ return i
+ if str_len(sn) > 0 && str_eq(sn, name) != 0:
+ return i
+ i = i + 1
+ return -1
+
+fn _cli_is_flag(arg: string) -> int:
+ slen := str_len(arg)
+ if slen < 2:
+ return 0
+ c0 := get_char(arg, 0)
+ if str_eq(c0, "-") != 0:
+ return 1
+ return 0
+
+fn _cli_strip_dashes(arg: string) -> string:
+ slen := str_len(arg)
+ if slen == 0:
+ return ""
+ start : ., mut = 0
+ if str_eq(get_char(arg, 0), "-") != 0:
+ start = 1
+ if slen > 1 && str_eq(get_char(arg, 1), "-") != 0:
+ start = 2
+ return str_sub(arg, start, slen - start)
// --- Parse ---
-fn cli_parse() -> int {
- argc := get_arg(0);
- argc_int : ., mut = 0;
+fn cli_parse() -> int:
+ argc := get_arg(0)
+ argc_int : ., mut = 0
// Count args by scanning until we get empty string
- loop {
- a := get_arg(argc_int);
- if str_len(a) == 0 { break; }
- argc_int = argc_int + 1;
- }
- if argc_int < 2 { return 0; } // no subcommand
+ loop:
+ a := get_arg(argc_int)
+ if str_len(a) == 0:
+ break
+ argc_int = argc_int + 1
+ if argc_int < 2:
+ return 0
+ // no subcommand
// Determine subcommand from argv[1]
- first := get_arg(1);
- if _cli_is_flag(first) == 0 && g_cli_cmd_count > 0 {
+ first := get_arg(1)
+ if _cli_is_flag(first) == 0 && g_cli_cmd_count > 0:
// First non-flag arg — check if it's a valid subcommand
- ci : ., mut = 0;
- found_cmd : ., mut = 0;
- loop {
- if ci >= g_cli_cmd_count { break; }
- if unsafe { str_eq(@str_of(r64(g_cli_cmds, ci * 16)), first) } != 0 {
- found_cmd = 1;
- break;
- }
- ci = ci + 1;
- }
- if found_cmd != 0 {
- g_cli_matched_cmd = first;
- } else {
+ ci : ., mut = 0
+ found_cmd : ., mut = 0
+ loop:
+ if ci >= g_cli_cmd_count:
+ break
+ if unsafe:
+ str_eq(@str_of(r64(g_cli_cmds, ci * 16)), first)
+ != 0:
+ found_cmd = 1
+ break
+ ci = ci + 1
+ if found_cmd != 0:
+ g_cli_matched_cmd = first
+ else:
// Not a command, treat as positional arg
- g_cli_matched_cmd = "";
- }
- } else {
- g_cli_matched_cmd = "";
- }
+ g_cli_matched_cmd = ""
+ else:
+ g_cli_matched_cmd = ""
// Parse remaining args (after command name)
- ai : ., mut = 2; // start after prog + cmd
- if str_len(g_cli_matched_cmd) == 0 {
+ ai : ., mut = 2 // start after prog + cmd
+ if str_len(g_cli_matched_cmd) == 0:
// No command, start from argv[1]
// But also handle --help
- if str_eq(first, "--help") != 0 || str_eq(first, "-h") != 0 {
- cli_help();
- return -1;
- }
- ai = 1;
- }
-
- loop {
- if ai >= argc_int { break; }
- arg := get_arg(ai);
- if str_len(arg) == 0 { break; }
+ if str_eq(first, "--help") != 0 || str_eq(first, "-h") != 0:
+ cli_help()
+ return -1
+ ai = 1
+
+ loop:
+ if ai >= argc_int:
+ break
+ arg := get_arg(ai)
+ if str_len(arg) == 0:
+ break
// --help or -h anywhere
- if str_eq(arg, "--help") != 0 || str_eq(arg, "-h") != 0 {
- cli_help();
- return -1;
- }
-
- if _cli_is_flag(arg) != 0 {
- name := _cli_strip_dashes(arg);
- fi := _cli_find_flag(name);
- if fi < 0 {
- print("unknown flag: ");
- println(arg);
- cli_help();
- return -1;
- }
- if r64(g_cli_flags, fi * 48 + 40) != 0 { // is_bool
- w64(g_cli_flags, fi * 48 + 32, 1); // has_value
- unsafe { w64(g_cli_flags, fi * 48 + 24, @ptr_of("1")); } // value(串字入裸字槽)
- } else {
- ai = ai + 1;
- if ai >= argc_int {
- print("flag ");
- print(arg);
- println(" requires a value");
- return -1;
- }
- val := get_arg(ai);
- unsafe { w64(g_cli_flags, fi * 48 + 24, @ptr_of(val)); } // value
- w64(g_cli_flags, fi * 48 + 32, 1); // has_value
- }
- } else {
+ if str_eq(arg, "--help") != 0 || str_eq(arg, "-h") != 0:
+ cli_help()
+ return -1
+
+ if _cli_is_flag(arg) != 0:
+ name := _cli_strip_dashes(arg)
+ fi := _cli_find_flag(name)
+ if fi < 0:
+ print("unknown flag: ")
+ println(arg)
+ cli_help()
+ return -1
+ if r64(g_cli_flags, fi * 48 + 40) != 0:
+ // is_bool
+ w64(g_cli_flags, fi * 48 + 32, 1) // has_value
+ unsafe:
+ w64(g_cli_flags, fi * 48 + 24, @ptr_of("1"))
+ // value(串字入裸字槽)
+ else:
+ ai = ai + 1
+ if ai >= argc_int:
+ print("flag ")
+ print(arg)
+ println(" requires a value")
+ return -1
+ val := get_arg(ai)
+ unsafe:
+ w64(g_cli_flags, fi * 48 + 24, @ptr_of(val))
+ // value
+ w64(g_cli_flags, fi * 48 + 32, 1) // has_value
+ else:
// Positional argument
- grow_cli_args(g_cli_arg_count + 1);
- unsafe { w64(g_cli_args, g_cli_arg_count * 8, @ptr_of(arg)); }
- g_cli_arg_count = g_cli_arg_count + 1;
- }
- ai = ai + 1;
- }
+ grow_cli_args(g_cli_arg_count + 1)
+ unsafe:
+ w64(g_cli_args, g_cli_arg_count * 8, @ptr_of(arg))
+ g_cli_arg_count = g_cli_arg_count + 1
+ ai = ai + 1
- return 0;
-}
+ return 0
// --- Query ---
-fn cli_cmd_name() -> string {
- return g_cli_matched_cmd;
-}
+fn cli_cmd_name() -> string:
+ return g_cli_matched_cmd
-fn cli_eq(cmd: string, expected: string) -> int {
- return str_eq(cmd, expected);
-}
+fn cli_eq(cmd: string, expected: string) -> int:
+ return str_eq(cmd, expected)
-fn cli_get(name: string) -> string {
- fi := _cli_find_flag(name);
- if fi >= 0 && r64(g_cli_flags, fi * 48 + 32) != 0 { // has_value
+fn cli_get(name: string) -> string:
+ fi := _cli_find_flag(name)
+ if fi >= 0 && r64(g_cli_flags, fi * 48 + 32) != 0:
+ // has_value
// 返回位同为裸字→串(S1P 只覆盖**调用实参**、不覆盖返回位 ⇒ 它不在 68 点里,
// 但同属一类;2(a) 一并收口)。
- unsafe { return @str_of(r64(g_cli_flags, fi * 48 + 24)); } // value
- }
- return "";
-}
-
-fn cli_has(name: string) -> int {
- fi := _cli_find_flag(name);
- if fi >= 0 {
- return r64(g_cli_flags, fi * 48 + 32); // has_value
- }
- return 0;
-}
-
-fn cli_arg(n: int) -> string {
- if n >= 0 && n < g_cli_arg_count {
- unsafe { return @str_of(r64(g_cli_args, n * 8)); } // 返回位裸字→串(同族)
- }
- return "";
-}
-
-fn cli_arg_count() -> int {
- return g_cli_arg_count;
-}
+ unsafe:
+ return @str_of(r64(g_cli_flags, fi * 48 + 24))
+ // value
+ return ""
+
+fn cli_has(name: string) -> int:
+ fi := _cli_find_flag(name)
+ if fi >= 0:
+ return r64(g_cli_flags, fi * 48 + 32) // has_value
+ return 0
+
+fn cli_arg(n: int) -> string:
+ if n >= 0 && n < g_cli_arg_count:
+ unsafe:
+ return @str_of(r64(g_cli_args, n * 8))
+ // 返回位裸字→串(同族)
+ return ""
+
+fn cli_arg_count() -> int:
+ return g_cli_arg_count
// --- Help ---
-fn cli_help() {
+fn cli_help():
// usage: prog [-h] {cmd1,cmd2,...} [options]
- print("usage: ");
- print(g_cli_prog);
- print(" [-h]");
- if g_cli_cmd_count > 0 {
- print(" {");
- ci : ., mut = 0;
- first : ., mut = 1;
- loop {
- if ci >= g_cli_cmd_count { break; }
- if first == 0 { print(","); }
- print(unsafe { @str_of(r64(g_cli_cmds, ci * 16)) });
- first = 0;
- ci = ci + 1;
- }
- print("}");
- }
- println(" [options]");
- println("");
-
- if str_len(g_cli_desc) > 0 {
- println(g_cli_desc);
- println("");
- }
+ print("usage: ")
+ print(g_cli_prog)
+ print(" [-h]")
+ if g_cli_cmd_count > 0:
+ print(" {")
+ ci : ., mut = 0
+ first : ., mut = 1
+ loop:
+ if ci >= g_cli_cmd_count:
+ break
+ if first == 0:
+ print(",")
+ cmd_name_str := unsafe:
+ @str_of(r64(g_cli_cmds, ci * 16))
+ print(cmd_name_str)
+ first = 0
+ ci = ci + 1
+ print("}")
+ println(" [options]")
+ println("")
+
+ if str_len(g_cli_desc) > 0:
+ println(g_cli_desc)
+ println("")
// Positional arguments (commands)
- if g_cli_cmd_count > 0 {
- println("positional arguments:");
- print(" {");
- ci : ., mut = 0;
- first : ., mut = 1;
- loop {
- if ci >= g_cli_cmd_count { break; }
- if first == 0 { print(","); }
- print(unsafe { @str_of(r64(g_cli_cmds, ci * 16)) });
- first = 0;
- ci = ci + 1;
- }
- println("}");
- ci = 0;
- loop {
- if ci >= g_cli_cmd_count { break; }
- unsafe {
- cmd_name := @str_of(r64(g_cli_cmds, ci * 16));
- cmd_desc := @str_of(r64(g_cli_cmds, ci * 16 + 8));
- print(" ");
- print(cmd_name);
- pad := str_len(cmd_name);
- loop {
- if pad >= 12 { break; }
- print(" ");
- pad = pad + 1;
- }
- println(cmd_desc);
- }
- ci = ci + 1;
- }
- println("");
- }
+ if g_cli_cmd_count > 0:
+ println("positional arguments:")
+ print(" {")
+ ci : ., mut = 0
+ first : ., mut = 1
+ loop:
+ if ci >= g_cli_cmd_count:
+ break
+ if first == 0:
+ print(",")
+ cmd_name_str := unsafe:
+ @str_of(r64(g_cli_cmds, ci * 16))
+ print(cmd_name_str)
+ first = 0
+ ci = ci + 1
+ println("}")
+ ci = 0
+ loop:
+ if ci >= g_cli_cmd_count:
+ break
+ unsafe:
+ cmd_name := @str_of(r64(g_cli_cmds, ci * 16))
+ cmd_desc := @str_of(r64(g_cli_cmds, ci * 16 + 8))
+ print(" ")
+ print(cmd_name)
+ pad := str_len(cmd_name)
+ loop:
+ if pad >= 12:
+ break
+ print(" ")
+ pad = pad + 1
+ println(cmd_desc)
+ ci = ci + 1
+ println("")
// Flags / options
- println("options:");
+ println("options:")
// Built-in -h, --help
- println(" -h, --help show this help message and exit");
- fi : ., mut = 0;
- loop {
- if fi >= g_cli_flag_count { break; }
- unsafe {
- f_short := @str_of(r64(g_cli_flags, fi * 48 + 8));
- f_long := @str_of(r64(g_cli_flags, fi * 48));
- f_desc := @str_of(r64(g_cli_flags, fi * 48 + 16));
- print(" ");
- if str_len(f_short) > 0 {
- print("-");
- print(f_short);
- print(", ");
- } else {
- print(" ");
- }
- print("--");
- print(f_long);
+ println(" -h, --help show this help message and exit")
+ fi : ., mut = 0
+ loop:
+ if fi >= g_cli_flag_count:
+ break
+ unsafe:
+ f_short := @str_of(r64(g_cli_flags, fi * 48 + 8))
+ f_long := @str_of(r64(g_cli_flags, fi * 48))
+ f_desc := @str_of(r64(g_cli_flags, fi * 48 + 16))
+ print(" ")
+ if str_len(f_short) > 0:
+ print("-")
+ print(f_short)
+ print(", ")
+ else:
+ print(" ")
+ print("--")
+ print(f_long)
// Pad to 24 chars total (prefix = " " + short/" " + "--")
- total : ., mut = 8;
- if str_len(f_short) > 0 {
- total = 8; // " " + "-X, " + "--" = 2+4+2 = 8
- }
- total = total + str_len(f_long);
- loop {
- if total >= 24 { break; }
- print(" ");
- total = total + 1;
- }
- println(f_desc);
- }
- fi = fi + 1;
- }
-}
+ total : ., mut = 8
+ if str_len(f_short) > 0:
+ total = 8 // " " + "-X, " + "--" = 2+4+2 = 8
+ total = total + str_len(f_long)
+ loop:
+ if total >= 24:
+ break
+ print(" ")
+ total = total + 1
+ println(f_desc)
+ fi = fi + 1
diff --git a/src/stdlib/collections.cr b/src/stdlib/collections.cr
index 9ec66dba..93012bfd 100644
--- a/src/stdlib/collections.cr
+++ b/src/stdlib/collections.cr
@@ -7,120 +7,144 @@
//
// Current limitations: operates on int arrays; no HashMap/HashSet yet.
-fn swap(arr: [int; N], i: int, j: int) {
- tmp := arr[i];
- arr[i] = arr[j];
- arr[j] = tmp;
-}
+fn swap(arr: [int; N], i: int, j: int):
+ tmp := arr[i]
+ arr[i] = arr[j]
+ arr[j] = tmp
-fn reverse(arr: [int; N]) {
- i : ., mut = 0;
- j : ., mut = N - 1;
- loop {
- if i >= j { break; }
- t := arr[i];
- arr[i] = arr[j];
- arr[j] = t;
- i = i + 1;
- j = j - 1;
- }
-}
+fn reverse(arr: [int; N]):
+ i : ., mut = 0
+ j : ., mut = N - 1
+ loop:
+ if i >= j:
+ break
+ t := arr[i]
+ arr[i] = arr[j]
+ arr[j] = t
+ i = i + 1
+ j = j - 1
-fn contains(arr: [int; N], val: int) -> bool {
- i : ., mut = 0;
- loop {
- if i >= N { break; }
- if arr[i] == val { return true; }
- i = i + 1;
- }
- return false;
-}
+fn contains(arr: [int; N], val: int) -> bool:
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ if arr[i] == val:
+ return true
+ i = i + 1
+ return false
-fn index_of(arr: [int; N], val: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= N { break; }
- if arr[i] == val { return i; }
- i = i + 1;
- }
- return -1;
-}
+fn index_of(arr: [int; N], val: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ if arr[i] == val:
+ return i
+ i = i + 1
+ return -1
-fn min_element(arr: [int; N]) -> int {
- if N == 0 { return 0; }
- m : ., mut = arr[0];
- i : ., mut = 1;
- loop {
- if i >= N { break; }
- if arr[i] < m { m = arr[i]; }
- i = i + 1;
- }
- return m;
-}
+fn min_element(arr: [int; N]) -> int:
+ if N == 0:
+ return 0
+ m : ., mut = arr[0]
+ i : ., mut = 1
+ loop:
+ if i >= N:
+ break
+ if arr[i] < m:
+ m = arr[i]
+ i = i + 1
+ return m
-fn max_element(arr: [int; N]) -> int {
- if N == 0 { return 0; }
- m : ., mut = arr[0];
- i : ., mut = 1;
- loop {
- if i >= N { break; }
- if arr[i] > m { m = arr[i]; }
- i = i + 1;
- }
- return m;
-}
+fn max_element(arr: [int; N]) -> int:
+ if N == 0:
+ return 0
+ m : ., mut = arr[0]
+ i : ., mut = 1
+ loop:
+ if i >= N:
+ break
+ if arr[i] > m:
+ m = arr[i]
+ i = i + 1
+ return m
-fn fill(arr: [int; N], val: int) {
- i : ., mut = 0;
- loop {
- if i >= N { break; }
- arr[i] = val;
- i = i + 1;
- }
-}
+fn fill(arr: [int; N], val: int):
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ arr[i] = val
+ i = i + 1
-fn sum(arr: [int; N]) -> int {
- s : ., mut = 0;
- i : ., mut = 0;
- loop { if i >= N { break; } s = s + arr[i]; i = i + 1; }
- return s;
-}
+fn sum(arr: [int; N]) -> int:
+ s : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ s = s + arr[i]
+ i = i + 1
+ return s
-fn product(arr: [int; N]) -> int {
- p : ., mut = 1;
- i : ., mut = 0;
- loop { if i >= N { break; } p = p * arr[i]; i = i + 1; }
- return p;
-}
+fn product(arr: [int; N]) -> int:
+ p : ., mut = 1
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ p = p * arr[i]
+ i = i + 1
+ return p
-fn count(arr: [int; N], val: int) -> int {
- c : ., mut = 0;
- i : ., mut = 0;
- loop { if i >= N { break; } if arr[i] == val { c = c + 1; } i = i + 1; }
- return c;
-}
+fn count(arr: [int; N], val: int) -> int:
+ c : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ if arr[i] == val:
+ c = c + 1
+ i = i + 1
+ return c
-fn find(arr: [int; N], val: int) -> int {
- i : ., mut = 0;
- loop { if i >= N { break; } if arr[i] == val { return i; } i = i + 1; }
- return -1;
-}
+fn find(arr: [int; N], val: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ if arr[i] == val:
+ return i
+ i = i + 1
+ return -1
-fn copy(src: [int; N], dst: [int; N]) {
- i : ., mut = 0;
- loop { if i >= N { break; } dst[i] = src[i]; i = i + 1; }
-}
+fn copy(src: [int; N], dst: [int; N]):
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ dst[i] = src[i]
+ i = i + 1
-fn equals(a: [int; N], b: [int; M]) -> bool {
- if N != M { return false; }
- i : ., mut = 0;
- loop { if i >= N { break; } if a[i] != b[i] { return false; } i = i + 1; }
- return true;
-}
+fn equals(a: [int; N], b: [int; M]) -> bool:
+ if N != M:
+ return false
+ i : ., mut = 0
+ loop:
+ if i >= N:
+ break
+ if a[i] != b[i]:
+ return false
+ i = i + 1
+ return true
-fn slice_sum(arr: [int; N], start: int, end: int) -> int {
- s : ., mut = 0;
- i : ., mut = start;
- loop { if i >= end || i >= N { break; } s = s + arr[i]; i = i + 1; }
- return s;
-}
+fn slice_sum(arr: [int; N], start: int, end: int) -> int:
+ s : ., mut = 0
+ i : ., mut = start
+ loop:
+ if i >= end || i >= N:
+ break
+ s = s + arr[i]
+ i = i + 1
+ return s
diff --git a/src/stdlib/dex.cr b/src/stdlib/dex.cr
index 2b001c56..c4be6f30 100644
--- a/src/stdlib/dex.cr
+++ b/src/stdlib/dex.cr
@@ -36,36 +36,38 @@
// 访问原始整数做打印(纯整数运算,无 dex 运算溢出约束)。
// 定点 → 十进制字符串(去尾零):3.14 → "3.14"、6.0 → "6"、0.1 → "0.1"
-fn dex_str(v: dex) -> string {
- n : ., mut = @raw_int(v); // 缩放整数原值
- neg : int = 0;
- if n < 0 { neg = 1; n = 0 - n; }
- ip := n / 1000000; // 整数部分(int 截断除法)
- fp := n % 1000000; // 小数部分(缩放)
- s : ., mut = "";
- if neg != 0 { s = "-"; }
- s = s + int_str(ip);
- if fp != 0 {
- s = s + ".";
- fs : ., mut = "";
- d : ., mut = fp;
- k : ., mut = 100000;
- loop {
- if k <= 0 { break; }
- dg := d / k;
- d = d - dg * k;
- fs = fs + int_str(dg);
- k = k / 10;
- }
+fn dex_str(v: dex) -> string:
+ n : ., mut = @raw_int(v) // 缩放整数原值
+ neg : int = 0
+ if n < 0:
+ neg = 1
+ n = 0 - n
+ ip := n / 1000000 // 整数部分(int 截断除法)
+ fp := n % 1000000 // 小数部分(缩放)
+ s : ., mut = ""
+ if neg != 0:
+ s = "-"
+ s = s + int_str(ip)
+ if fp != 0:
+ s = s + "."
+ fs : ., mut = ""
+ d : ., mut = fp
+ k : ., mut = 100000
+ loop:
+ if k <= 0:
+ break
+ dg := d / k
+ d = d - dg * k
+ fs = fs + int_str(dg)
+ k = k / 10
// 去尾零
- li : ., mut = str_len(fs) - 1;
- loop {
- if li < 0 { break; }
- if load8(fs, li) != 48 { break; }
- fs = str_sub(fs, 0, li);
- li = li - 1;
- }
- s = s + fs;
- }
- return s;
-}
+ li : ., mut = str_len(fs) - 1
+ loop:
+ if li < 0:
+ break
+ if load8(fs, li) != 48:
+ break
+ fs = str_sub(fs, 0, li)
+ li = li - 1
+ s = s + fs
+ return s
diff --git a/src/stdlib/fmt.cr b/src/stdlib/fmt.cr
index 34a43ab4..7409b0c3 100644
--- a/src/stdlib/fmt.cr
+++ b/src/stdlib/fmt.cr
@@ -1,294 +1,327 @@
// fmt — String formatting and conversion utilities.
// All functions are pure (no side effects).
-fn str_len(s: string) -> int {
- hdr := load64(s, -8); // total bytes allocated (includes null)
- if hdr <= 0 { return 0; }
- return hdr - 1; // exclude null terminator
-}
+fn str_len(s: string) -> int:
+ hdr := load64(s, -8) // total bytes allocated (includes null)
+ if hdr <= 0:
+ return 0
+ return hdr - 1 // exclude null terminator
-fn chr(c: int) -> string {
- res := alloc(2);
- store8(res, 0, c);
- store8(res, 1, 0);
- return res;
-}
+fn chr(c: int) -> string:
+ res := alloc(2)
+ store8(res, 0, c)
+ store8(res, 1, 0)
+ return res
-fn get_char(s: string, idx: int) -> string {
- sl := str_len(s);
- if idx < 0 || idx >= sl { return ""; }
- c := load8(s, idx);
- res := alloc(2);
- store8(res, 0, c);
- store8(res, 1, 0);
- return res;
-}
+fn get_char(s: string, idx: int) -> string:
+ sl := str_len(s)
+ if idx < 0 || idx >= sl:
+ return ""
+ c := load8(s, idx)
+ res := alloc(2)
+ store8(res, 0, c)
+ store8(res, 1, 0)
+ return res
-fn str_sub(s: string, start: int, len: int) -> string {
- slen := str_len(s);
- if start < 0 || start >= slen { return ""; }
- actual_len : ., mut = len;
- if start + actual_len > slen { actual_len = slen - start; }
- if actual_len <= 0 { return ""; }
- res := alloc(actual_len + 1);
- i : ., mut = 0;
- loop {
- if i >= actual_len { break; }
- c := load8(s, start + i);
- store8(res, i, c);
- i = i + 1;
- }
- store8(res, actual_len, 0);
- return res;
-}
+fn str_sub(s: string, start: int, len: int) -> string:
+ slen := str_len(s)
+ if start < 0 || start >= slen:
+ return ""
+ actual_len : ., mut = len
+ if start + actual_len > slen:
+ actual_len = slen - start
+ if actual_len <= 0:
+ return ""
+ res := alloc(actual_len + 1)
+ i : ., mut = 0
+ loop:
+ if i >= actual_len:
+ break
+ c := load8(s, start + i)
+ store8(res, i, c)
+ i = i + 1
+ store8(res, actual_len, 0)
+ return res
-fn str_eq(a: string, b: string) -> int {
- la := str_len(a); lb := str_len(b);
- if la != lb { return 0; }
- i : ., mut = 0;
- loop {
- if i >= la { return 1; }
- if load8(a, i) != load8(b, i) { return 0; }
- i = i + 1;
- }
- return 0;
-}
+fn str_eq(a: string, b: string) -> int:
+ la := str_len(a)
+ lb := str_len(b)
+ if la != lb:
+ return 0
+ i : ., mut = 0
+ loop:
+ if i >= la:
+ return 1
+ if load8(a, i) != load8(b, i):
+ return 0
+ i = i + 1
+ return 0
-fn str_cmp(a: string, b: string) -> int {
- i : ., mut = 0;
- loop {
- ca := load8(a, i);
- cb := load8(b, i);
- if ca == 0 && cb == 0 { return 0; }
- if ca == 0 { return -1; }
- if cb == 0 { return 1; }
- if ca < cb { return -1; }
- if ca > cb { return 1; }
- i = i + 1;
- }
- return 0;
-}
+fn str_cmp(a: string, b: string) -> int:
+ i : ., mut = 0
+ loop:
+ ca := load8(a, i)
+ cb := load8(b, i)
+ if ca == 0 && cb == 0:
+ return 0
+ if ca == 0:
+ return -1
+ if cb == 0:
+ return 1
+ if ca < cb:
+ return -1
+ if ca > cb:
+ return 1
+ i = i + 1
+ return 0
-fn concat(a: string, b: string) -> string {
- aa := a;
- bb := b;
- lena := str_len(aa);
- lenb := str_len(bb);
- res := alloc(lena + lenb + 1);
- i : ., mut = 0;
- loop {
- if i >= lena { break; }
- c := load8(aa, i);
- store8(res, i, c);
- i = i + 1;
- }
- j : ., mut = 0;
- loop {
- if j >= lenb { break; }
- c := load8(bb, j);
- store8(res, lena + j, c);
- j = j + 1;
- }
- store8(res, lena + lenb, 0);
- return res;
-}
+fn concat(a: string, b: string) -> string:
+ aa := a
+ bb := b
+ lena := str_len(aa)
+ lenb := str_len(bb)
+ res := alloc(lena + lenb + 1)
+ i : ., mut = 0
+ loop:
+ if i >= lena:
+ break
+ c := load8(aa, i)
+ store8(res, i, c)
+ i = i + 1
+ j : ., mut = 0
+ loop:
+ if j >= lenb:
+ break
+ c := load8(bb, j)
+ store8(res, lena + j, c)
+ j = j + 1
+ store8(res, lena + lenb, 0)
+ return res
-fn int_str(n: int) -> string {
- if n == 0 { return "0"; }
- val : ., mut = n;
- neg : ., mut = 0;
- if val < 0 { neg = 1; val = -val; }
- tmp : ., mut = val;
- ndigits : ., mut = 0;
- loop {
- ndigits = ndigits + 1;
- tmp = tmp / 10;
- if tmp == 0 { break; }
- }
- extra : ., mut = neg;
- buf := alloc(ndigits + extra + 1);
- end : ., mut = ndigits;
- pos : ., mut = ndigits - 1;
- loop {
- rem := val % 10;
- store8(buf, pos, rem + 48);
- val = val / 10;
- if pos == 0 { break; }
- pos = pos - 1;
- }
- if neg == 1 {
- k : ., mut = ndigits;
- loop {
- if k == 0 { break; }
- ci := load8(buf, k - 1);
- store8(buf, k, ci);
- k = k - 1;
- }
- store8(buf, 0, 45);
- end = end + 1;
- }
- store8(buf, end, 0);
- return buf;
-}
+fn int_str(n: int) -> string:
+ if n == 0:
+ return "0"
+ val : ., mut = n
+ neg : ., mut = 0
+ if val < 0:
+ neg = 1
+ val = -val
+ tmp : ., mut = val
+ ndigits : ., mut = 0
+ loop:
+ ndigits = ndigits + 1
+ tmp = tmp / 10
+ if tmp == 0:
+ break
+ extra : ., mut = neg
+ buf := alloc(ndigits + extra + 1)
+ end : ., mut = ndigits
+ pos : ., mut = ndigits - 1
+ loop:
+ rem := val % 10
+ store8(buf, pos, rem + 48)
+ val = val / 10
+ if pos == 0:
+ break
+ pos = pos - 1
+ if neg == 1:
+ k : ., mut = ndigits
+ loop:
+ if k == 0:
+ break
+ ci := load8(buf, k - 1)
+ store8(buf, k, ci)
+ k = k - 1
+ store8(buf, 0, 45)
+ end = end + 1
+ store8(buf, end, 0)
+ return buf
-fn str_int(s: string) -> int {
- slen := str_len(s);
- if slen == 0 { return 0; }
- i : ., mut = 0;
- neg : ., mut = 0;
- c0 := load8(s, 0);
- if c0 == 45 { neg = 1; i = 1; }
- res : ., mut = 0;
- loop {
- if i >= slen { break; }
- c := load8(s, i);
- if c < 48 || c > 57 { break; }
- res = res * 10 + (c - 48);
- i = i + 1;
- }
- if neg == 1 { return -res; }
- return res;
-}
+fn str_int(s: string) -> int:
+ slen := str_len(s)
+ if slen == 0:
+ return 0
+ i : ., mut = 0
+ neg : ., mut = 0
+ c0 := load8(s, 0)
+ if c0 == 45:
+ neg = 1
+ i = 1
+ res : ., mut = 0
+ loop:
+ if i >= slen:
+ break
+ c := load8(s, i)
+ if c < 48 || c > 57:
+ break
+ res = res * 10 + (c - 48)
+ i = i + 1
+ if neg == 1:
+ return -res
+ return res
-fn to_str(n: int) -> string {
- return int_str(n);
-}
+fn to_str(n: int) -> string:
+ return int_str(n)
// 字符串插值用(批 8 插值展开):`bool` 洞的转换。**不经 int**——遵维护者「bool 不隐式转 int」裁定,
// 故不写 `int_str(b)`,而按真值给出 `"true"`/`"false"`。
// ⚠ 为何必须是「函数」而非合成 `if` 表达式(实测):`"v=" + if b { "true" } else { "false" }`
// **rc=139**(手写同形亦崩 = 预存缺陷,另立条目)⇒ 转换只能走调用面,本函数即该调用面。
// ⚠ 代价(实测、已上报):本函数进 `fmt.cr` ⇒ **所有 `import fmt` 程序的产物变大**
// (pa ELF 28822→28854 = +32B、`.ccr` +725B)⇒ canary 载体面变化,按 §6 纪律停下上报 + 同批重锁。
-fn bool_str(b: bool) -> string {
- if b { return "true"; }
- return "false";
-}
+fn bool_str(b: bool) -> string:
+ if b:
+ return "true"
+ return "false"
// Format string: replace {} with args sequentially.
// Example: format("x = {} and y = {}", int_str(x), int_str(y))
// Simple string interpolation: replaces "{0}" with first arg, "{1}" with second, etc.
// Usage: format("Hello {0}, you are {1} years old", name, age_str)
-fn format(fmt_str: string, a0: string) -> string {
- fl := str_len(fmt_str);
- a0l := str_len(a0);
+fn format(fmt_str: string, a0: string) -> string:
+ fl := str_len(fmt_str)
+ a0l := str_len(a0)
// Fast path: no interpolation needed
- out_buf := alloc(fl + a0l + 16);
- ri := 0; // write position
- fi := 0; // read position
- loop {
- if fi >= fl { break; }
- c := load8(fmt_str, fi);
- if c == 123 && fi + 2 < fl && load8(fmt_str, fi+1) == 48 && load8(fmt_str, fi+2) == 125 {
+ out_buf := alloc(fl + a0l + 16)
+ ri := 0 // write position
+ fi := 0 // read position
+ loop:
+ if fi >= fl:
+ break
+ c := load8(fmt_str, fi)
+ if c == 123 && fi + 2 < fl && load8(fmt_str, fi+1) == 48 && load8(fmt_str, fi+2) == 125:
// "{0}" → replace with a0
- ai : ., mut = 0;
- loop { if ai >= a0l { break; } store8(out_buf, ri, load8(a0, ai)); ri = ri + 1; ai = ai + 1; }
- fi = fi + 3;
- } else {
- store8(out_buf, ri, c);
- ri = ri + 1; fi = fi + 1;
- }
- }
- store8(out_buf, ri, 0);
- return out_buf;
-}
+ ai : ., mut = 0
+ loop:
+ if ai >= a0l:
+ break
+ store8(out_buf, ri, load8(a0, ai))
+ ri = ri + 1
+ ai = ai + 1
+ fi = fi + 3
+ else:
+ store8(out_buf, ri, c)
+ ri = ri + 1
+ fi = fi + 1
+ store8(out_buf, ri, 0)
+ return out_buf
-fn format2(fmt_str: string, a0: string, a1: string) -> string {
- return format(fmt_str, a0); // fallback: format handles {0} only for now
-}
+fn format2(fmt_str: string, a0: string, a1: string) -> string:
+ return format(fmt_str, a0) // fallback: format handles {0} only for now
// Integer to string → format helper
-fn format_int(fmt_str: string, val: int) -> string {
- return format(fmt_str, int_str(val));
-}
+fn format_int(fmt_str: string, val: int) -> string:
+ return format(fmt_str, int_str(val))
// ── float 打印(IEEE 754 double → 十进制字符串,定点最多 6 位小数)──
// 纯整数实现:提取符号/指数/尾数 → 规范化 → 整数部分 + 小数长除
-fn fpow2i(k: int) -> int {
- v : int = 1; i : ., mut = 0;
- loop { if i >= k { break; } v = v * 2; i = i + 1; }
- return v;
-}
+fn fpow2i(k: int) -> int:
+ v : int = 1
+ i : ., mut = 0
+ loop:
+ if i >= k:
+ break
+ v = v * 2
+ i = i + 1
+ return v
-fn float_str_bits(bits: int) -> string {
+fn float_str_bits(bits: int) -> string:
// 符号(bit63)
- neg : int = 0; u : int = bits;
- if u < 0 {
- neg = 1;
+ neg : int = 0
+ u : int = bits
+ if u < 0:
+ neg = 1
// Avoid spelling INT64_MIN: the lexer cannot represent its positive
// magnitude as an integer token before applying unary minus.
- u = u - (-9223372036854775807) + 1;
- }
+ u = u - (-9223372036854775807) + 1
// 提取字段(除以 2^52 代替移位)
- exp := (u / 4503599627370496) % 2048;
- mant := u % 4503599627370496;
+ exp := (u / 4503599627370496) % 2048
+ mant := u % 4503599627370496
// 特殊值(IEEE 754 标准)
- if exp == 0 && mant == 0 {
- if neg != 0 { return "-0"; }
- return "0";
- }
- if exp == 2047 {
- if mant == 0 { if neg != 0 { return "-inf"; } return "inf"; }
- return "nan";
- }
+ if exp == 0 && mant == 0:
+ if neg != 0:
+ return "-0"
+ return "0"
+ if exp == 2047:
+ if mant == 0:
+ if neg != 0:
+ return "-inf"
+ return "inf"
+ return "nan"
// 归一化:m = 1.mant(正规)或 0.mant(次正规),e = exp - 1023
- m : int = mant; e : int = exp - 1023;
- if exp != 0 { m = mant + 4503599627370496; }
- else { e = e + 1; }
+ m : int = mant
+ e : int = exp - 1023
+ if exp != 0:
+ m = mant + 4503599627370496
+ else:
+ e = e + 1
// value = m × 2^(e-52)(m 是 2^52 缩放的尾数)
- ip : int = 0;
- den : int = 1; // 小数分母(小数部分 = r/den)
- r : int = 0;
- if e >= 52 {
- if e - 52 <= 10 { ip = m * fpow2i(e - 52); }
- else { ip = m * 1024; } // 大数近似(超出 int 范围)
- } else {
- if 52 - e <= 53 {
- den = fpow2i(52 - e);
- ip = m / den;
- r = m % den;
- } else {
- ip = 0; den = fpow2i(53); r = m; // 极小值
- }
- }
+ ip : int = 0
+ den : int = 1 // 小数分母(小数部分 = r/den)
+ r : int = 0
+ if e >= 52:
+ if e - 52 <= 10:
+ ip = m * fpow2i(e - 52)
+ else:
+ ip = m * 1024
+ // 大数近似(超出 int 范围)
+ else:
+ if 52 - e <= 53:
+ den = fpow2i(52 - e)
+ ip = m / den
+ r = m % den
+ else:
+ ip = 0
+ den = fpow2i(53)
+ r = m // 极小值
// 长除:r × 10 / den,提取 7 位(第 7 位用于舍入)
- frac_str : ., mut = "";
- r2 : ., mut = r;
- di : ., mut = 0;
- loop { if di >= 7 { break; }
- r2 = r2 * 10;
- dg2 := r2 / den;
- if dg2 > 9 { dg2 = 9; }
- r2 = r2 - dg2 * den;
- if di < 6 { frac_str = frac_str + int_str(dg2); }
- else if dg2 >= 5 {
+ frac_str : ., mut = ""
+ r2 : ., mut = r
+ di : ., mut = 0
+ loop:
+ if di >= 7:
+ break
+ r2 = r2 * 10
+ dg2 := r2 / den
+ if dg2 > 9:
+ dg2 = 9
+ r2 = r2 - dg2 * den
+ if di < 6:
+ frac_str = frac_str + int_str(dg2)
+ else if dg2 >= 5:
// 第 7 位 ≥ 5:从第 6 位向前传播进位。
- fl2 := str_len(frac_str);
- carry : ., mut = 1;
- ri : ., mut = fl2 - 1;
- loop {
- if ri < 0 || carry == 0 { break; }
- digit := load8(frac_str, ri) - 48;
- if digit < 9 {
- store8(frac_str, ri, digit + 49);
- carry = 0;
- } else {
- store8(frac_str, ri, 48);
- ri = ri - 1;
- }
- }
- if carry != 0 { ip = ip + 1; }
- }
- di = di + 1; }
+ fl2 := str_len(frac_str)
+ carry : ., mut = 1
+ ri : ., mut = fl2 - 1
+ loop:
+ if ri < 0 || carry == 0:
+ break
+ digit := load8(frac_str, ri) - 48
+ if digit < 9:
+ store8(frac_str, ri, digit + 49)
+ carry = 0
+ else:
+ store8(frac_str, ri, 48)
+ ri = ri - 1
+ if carry != 0:
+ ip = ip + 1
+ di = di + 1
// 去尾零
- fl := str_len(frac_str);
- loop { if fl <= 0 { break; } if load8(frac_str, fl - 1) != 48 { break; } fl = fl - 1; }
- if fl > 0 { frac_str = str_sub(frac_str, 0, fl); }
+ fl := str_len(frac_str)
+ loop:
+ if fl <= 0:
+ break
+ if load8(frac_str, fl - 1) != 48:
+ break
+ fl = fl - 1
+ if fl > 0:
+ frac_str = str_sub(frac_str, 0, fl)
// 组装
- out : ., mut = "";
- if neg != 0 { out = out + "-"; }
- out = out + int_str(ip);
- if fl > 0 { out = out + "." + frac_str; }
- return out;
-}
+ out : ., mut = ""
+ if neg != 0:
+ out = out + "-"
+ out = out + int_str(ip)
+ if fl > 0:
+ out = out + "." + frac_str
+ return out
diff --git a/src/stdlib/goroutine.cr b/src/stdlib/goroutine.cr
index 03d6c88b..5e6ada9e 100644
--- a/src/stdlib/goroutine.cr
+++ b/src/stdlib/goroutine.cr
@@ -6,12 +6,11 @@ import sched
// (rt.s / emitted by the ELF backend). The backend intercepts calls to
// this name and emits movabs r10, (patched at link time),
// so the stub body is never executed.
-fn goroutine_wrapper_addr() -> int {
- return 0;
-}
+fn goroutine_wrapper_addr() -> int:
+ return 0
// Goroutine ID counter
-g_next_id : int, mut = 1;
+g_next_id : int, mut = 1
// G struct layout (80 bytes):
// 0: id
@@ -25,46 +24,45 @@ g_next_id : int, mut = 1;
// 64: saved_arg (saved argument, for wrapper dispatch)
// 72: temp_val (temp value for wait queue handoff)
-fn g_new(entry_fn: int, arg: int, arg_type: int) -> string {
+fn g_new(entry_fn: int, arg: int, arg_type: int) -> string:
// Create the goroutine's arena FIRST: the fiber stack and G struct must
// live in the G's own arena (not a transient one), so they survive until
// g_free reclaims them at goroutine exit. With the subgraph arena model,
// alloc() routes to g_current_arena when it is >= 0 — arena_new() sets it.
- aid := arena_new();
+ aid := arena_new()
// Allocate stack (16KB) — from the G's arena
- stack := alloc(16384);
- stack_top := stack + 16384 - 8;
+ stack := alloc(16384)
+ stack_top := stack + 16384 - 8
// Initialize fiber. The entry is ALWAYS goroutine_entry_wrapper
// (rt.s / emitted by the ELF backend): it reads saved_fn/saved_arg
// from this G (offsets 56/64), calls saved_fn(saved_arg), and sends
// the result to result_ch (offset 40). goroutine_wrapper_addr() is a
// backend builtin resolving the wrapper's VA at link time.
- wrap_addr := goroutine_wrapper_addr();
- sp := fiber_init(stack_top, wrap_addr);
+ wrap_addr := goroutine_wrapper_addr()
+ sp := fiber_init(stack_top, wrap_addr)
// Allocate G struct (80 bytes)
- g := alloc(80);
- id := g_next_id; g_next_id = g_next_id + 1;
- w64(g, 0, id); // id
- w64(g, 8, 0); // _Grunnable
- w64(g, 16, sp); // stack pointer
- w64(g, 24, stack); // stack_lo
- w64(g, 32, aid); // arena_id
- w64(g, 40, 0); // result_ch = 0 (default)
- w64(g, 48, -1); // next = -1
- w64(g, 56, entry_fn); // saved_fn = entry function ptr
- w64(g, 64, arg); // saved_arg
- w64(g, 72, 0); // temp_val = 0
+ g := alloc(80)
+ id := g_next_id
+ g_next_id = g_next_id + 1
+ w64(g, 0, id) // id
+ w64(g, 8, 0) // _Grunnable
+ w64(g, 16, sp) // stack pointer
+ w64(g, 24, stack) // stack_lo
+ w64(g, 32, aid) // arena_id
+ w64(g, 40, 0) // result_ch = 0 (default)
+ w64(g, 48, -1) // next = -1
+ w64(g, 56, entry_fn) // saved_fn = entry function ptr
+ w64(g, 64, arg) // saved_arg
+ w64(g, 72, 0) // temp_val = 0
- return g;
-}
+ return g
-fn g_free(g: string) {
+fn g_free(g: string):
// Reset arena (reclaims the fiber stack + G struct, which live in it)
- aid := r64(g, 32);
- arena_reset(aid);
+ aid := r64(g, 32)
+ arena_reset(aid)
// Mark G dead so it is never re-enqueued (status 3 = _Gdead)
- w64(g, 8, 3);
-}
+ w64(g, 8, 3)
diff --git a/src/stdlib/hotpatch.cr b/src/stdlib/hotpatch.cr
index e3174bfd..1b65ec92 100644
--- a/src/stdlib/hotpatch.cr
+++ b/src/stdlib/hotpatch.cr
@@ -10,38 +10,34 @@
// Re-read .hotpatch.toml into g_hp_config.
// Safe to call from signal handler context (kernel saves/restores registers).
-fn hp_load_config() {
- tc := read_file(".hotpatch.toml");
- if str_len(tc) > 0 {
- g_hp_config = tc;
- }
-}
+fn hp_load_config():
+ tc := read_file(".hotpatch.toml")
+ if str_len(tc) > 0:
+ g_hp_config = tc
// Increment the in-flight counter for a given function version.
// fn_ver: 0-based index into the 64-slot in-flight buffer.
-fn hp_inflight_inc(fn_ver: int) {
- cur := r64(g_hp_inflight, fn_ver * 8);
- w64(g_hp_inflight, fn_ver * 8, cur + 1);
-}
+fn hp_inflight_inc(fn_ver: int):
+ cur := r64(g_hp_inflight, fn_ver * 8)
+ w64(g_hp_inflight, fn_ver * 8, cur + 1)
// Decrement the in-flight counter for a given function version.
// Saturates at 0 (never goes negative).
-fn hp_inflight_dec(fn_ver: int) {
- cur := r64(g_hp_inflight, fn_ver * 8);
- if cur > 0 { w64(g_hp_inflight, fn_ver * 8, cur - 1); }
-}
+fn hp_inflight_dec(fn_ver: int):
+ cur := r64(g_hp_inflight, fn_ver * 8)
+ if cur > 0:
+ w64(g_hp_inflight, fn_ver * 8, cur - 1)
// Initialize hotpatch system at startup.
// Allocates the in-flight counter buffer and loads the initial config.
-fn hp_init() {
- g_hp_config = "";
- g_hp_inflight = alloc(64 * 8); // 64 version slots, each 8 bytes
+fn hp_init():
+ g_hp_config = ""
+ g_hp_inflight = alloc(64 * 8) // 64 version slots, each 8 bytes
// Zero-initialise all slots
- i : ., mut = 0;
- loop {
- if i >= 64 { break; }
- w64(g_hp_inflight, i * 8, 0);
- i = i + 1;
- }
- hp_load_config();
-}
+ i : ., mut = 0
+ loop:
+ if i >= 64:
+ break
+ w64(g_hp_inflight, i * 8, 0)
+ i = i + 1
+ hp_load_config()
diff --git a/src/stdlib/io.cr b/src/stdlib/io.cr
index d39421e5..4eb94385 100644
--- a/src/stdlib/io.cr
+++ b/src/stdlib/io.cr
@@ -3,77 +3,80 @@
// Rust-style string interpolation via format() in fmt.cr.
// Note: depends on fmt.cr (str_len, int_str) — see stdlib/_import.cr or import fmt
-fn print(s: string) {
- slen := str_len(s);
- r1 := syscall3(1, 1, s, slen); // write(1, s, len)
- return;
-}
+fn print(s: string):
+ slen := str_len(s)
+ r1 := syscall3(1, 1, s, slen) // write(1, s, len)
+ return
-fn println(s: string) {
- slen := str_len(s);
- r1 := syscall3(1, 1, s, slen); // write(1, s, len)
- r2 := syscall3(1, 1, "\n", 1); // write(1, "\n", 1)
- return;
-}
+fn println(s: string):
+ slen := str_len(s)
+ r1 := syscall3(1, 1, s, slen) // write(1, s, len)
+ r2 := syscall3(1, 1, "\n", 1) // write(1, "\n", 1)
+ return
-fn print_i(n: int) {
- print(int_str(n));
-}
+fn print_i(n: int):
+ print(int_str(n))
-fn println_i(n: int) {
- println(int_str(n));
-}
+fn println_i(n: int):
+ println(int_str(n))
-fn read_file(path: string) -> string {
- fd := syscall3(2, path, 0, 0); // open(path, O_RDONLY, 0)
- if fd < 0 { return ""; }
- fsize := syscall3(8, fd, 0, 2); // lseek(fd, 0, SEEK_END)
- if fsize < 0 {
- r1 := syscall3(3, fd, 0, 0); // close(fd)
- return "";
- }
- if fsize == 0 {
+fn read_file(path: string) -> string:
+ fd := syscall3(2, path, 0, 0) // open(path, O_RDONLY, 0)
+ if fd < 0:
+ return ""
+ fsize := syscall3(8, fd, 0, 2) // lseek(fd, 0, SEEK_END)
+ if fsize < 0:
+ r1 := syscall3(3, fd, 0, 0) // close(fd)
+ return ""
+ if fsize == 0:
// I-1:伪文件(/proc/self/environ 等)——procfs 的 lseek SEEK_END 恒返回
// 0,长度不可信 → 循环读取直到 EOF。修复前 get_env("CORE_SAFE") 恒读
// 空串 → CORE_SAFE=0 关检查的分支永不可达。正常文件的 lseek 行为不变。
// 注意:不用 while 做增长(自托管 parser 对裸 while + 双标识符条件有
// 预存崩溃——见波 3 报告 N2),用 loop+break 等价实现。
- r1 := syscall3(8, fd, 0, 0); // lseek(fd, 0, SEEK_SET)
- cap : ., mut = 4096;
- buf := alloc(cap);
- chunk := alloc(4096);
- blen : ., mut = 0;
- loop {
- n := syscall3(0, fd, chunk, 4096); // read(fd, chunk, 4096)
- if n <= 0 { break; }
- if blen + n >= cap {
- cap2 : ., mut = cap;
- loop { if cap2 >= blen + n { break; } cap2 = cap2 * 2; }
- nb := alloc(cap2); _dyncpy(buf, blen, nb); buf = nb; cap = cap2;
- }
- ci : ., mut = 0;
- loop { if ci >= n { break; } store8(buf, blen + ci, load8(chunk, ci)); ci = ci + 1; }
- blen = blen + n;
- }
- r2 := syscall3(3, fd, 0, 0); // close(fd)
- if blen <= 0 { return ""; }
- return str_sub(buf, 0, blen);
- }
- r1 := syscall3(8, fd, 0, 0); // lseek(fd, 0, SEEK_SET)
- buf := alloc(fsize + 1);
- nread := syscall3(0, fd, buf, fsize); // read(fd, buf, size)
- r2 := syscall3(3, fd, 0, 0); // close(fd)
- if nread > 0 {
- store8(buf, nread, 0);
- }
- return buf;
-}
+ r1 := syscall3(8, fd, 0, 0) // lseek(fd, 0, SEEK_SET)
+ cap : ., mut = 4096
+ buf := alloc(cap)
+ chunk := alloc(4096)
+ blen : ., mut = 0
+ loop:
+ n := syscall3(0, fd, chunk, 4096) // read(fd, chunk, 4096)
+ if n <= 0:
+ break
+ if blen + n >= cap:
+ cap2 : ., mut = cap
+ loop:
+ if cap2 >= blen + n:
+ break
+ cap2 = cap2 * 2
+ nb := alloc(cap2)
+ _dyncpy(buf, blen, nb)
+ buf = nb
+ cap = cap2
+ ci : ., mut = 0
+ loop:
+ if ci >= n:
+ break
+ store8(buf, blen + ci, load8(chunk, ci))
+ ci = ci + 1
+ blen = blen + n
+ r2 := syscall3(3, fd, 0, 0) // close(fd)
+ if blen <= 0:
+ return ""
+ return str_sub(buf, 0, blen)
+ r1 := syscall3(8, fd, 0, 0) // lseek(fd, 0, SEEK_SET)
+ buf := alloc(fsize + 1)
+ nread := syscall3(0, fd, buf, fsize) // read(fd, buf, size)
+ r2 := syscall3(3, fd, 0, 0) // close(fd)
+ if nread > 0:
+ store8(buf, nread, 0)
+ return buf
-fn write_file(path: string, content: string) -> int {
- fd := syscall3(2, path, 577, 420); // open O_WRONLY|O_CREAT|O_TRUNC, 0644
- if fd < 0 { return -1; }
- clen := str_len(content);
- nwritten := syscall3(1, fd, content, clen); // write(fd, content, len)
- r1 := syscall3(3, fd, 0, 0); // close(fd)
- return nwritten;
-}
+fn write_file(path: string, content: string) -> int:
+ fd := syscall3(2, path, 577, 420) // open O_WRONLY|O_CREAT|O_TRUNC, 0644
+ if fd < 0:
+ return -1
+ clen := str_len(content)
+ nwritten := syscall3(1, fd, content, clen) // write(fd, content, len)
+ r1 := syscall3(3, fd, 0, 0) // close(fd)
+ return nwritten
diff --git a/src/stdlib/math.cr b/src/stdlib/math.cr
index b327d0a0..51e07c4d 100644
--- a/src/stdlib/math.cr
+++ b/src/stdlib/math.cr
@@ -7,71 +7,68 @@
//
// All functions work with the int type.
-fn abs(x: int) -> int {
- if x < 0 { return -x; }
- return x;
-}
+fn abs(x: int) -> int:
+ if x < 0:
+ return -x
+ return x
-fn min(a: int, b: int) -> int {
- if a < b { return a; }
- return b;
-}
+fn min(a: int, b: int) -> int:
+ if a < b:
+ return a
+ return b
-fn max(a: int, b: int) -> int {
- if a > b { return a; }
- return b;
-}
+fn max(a: int, b: int) -> int:
+ if a > b:
+ return a
+ return b
-fn clamp(val: int, lo: int, hi: int) -> int {
- if val < lo { return lo; }
- if val > hi { return hi; }
- return val;
-}
+fn clamp(val: int, lo: int, hi: int) -> int:
+ if val < lo:
+ return lo
+ if val > hi:
+ return hi
+ return val
-fn pow(base: int, exp: int) -> int {
- r : ., mut = 1;
- i : ., mut = 0;
- loop {
- if i >= exp { break; }
- r = r * base;
- i = i + 1;
- }
- return r;
-}
+fn pow(base: int, exp: int) -> int:
+ r : ., mut = 1
+ i : ., mut = 0
+ loop:
+ if i >= exp:
+ break
+ r = r * base
+ i = i + 1
+ return r
-fn gcd(a: int, b: int) -> int {
- x : ., mut = a;
- y : ., mut = b;
- loop {
- if y == 0 { break; }
- t := y;
- y = x % y;
- x = t;
- }
- return x;
-}
+fn gcd(a: int, b: int) -> int:
+ x : ., mut = a
+ y : ., mut = b
+ loop:
+ if y == 0:
+ break
+ t := y
+ y = x % y
+ x = t
+ return x
-fn lcm(a: int, b: int) -> int {
- if a == 0 || b == 0 { return 0; }
- return (a / gcd(a, b)) * b;
-}
+fn lcm(a: int, b: int) -> int:
+ if a == 0 || b == 0:
+ return 0
+ return (a / gcd(a, b)) * b
-fn is_even(n: int) -> bool {
- return n % 2 == 0;
-}
+fn is_even(n: int) -> bool:
+ return n % 2 == 0
-fn is_odd(n: int) -> bool {
- return n % 2 != 0;
-}
+fn is_odd(n: int) -> bool:
+ return n % 2 != 0
-fn factorial(n: int) -> int {
- if n <= 1 { return 1; }
- r : ., mut = 1;
- i : ., mut = 2;
- loop {
- if i > n { break; }
- r = r * i;
- i = i + 1;
- }
- return r;
-}
+fn factorial(n: int) -> int:
+ if n <= 1:
+ return 1
+ r : ., mut = 1
+ i : ., mut = 2
+ loop:
+ if i > n:
+ break
+ r = r * i
+ i = i + 1
+ return r
diff --git a/src/stdlib/os.cr b/src/stdlib/os.cr
index 5d627c83..9e7ff635 100644
--- a/src/stdlib/os.cr
+++ b/src/stdlib/os.cr
@@ -5,104 +5,110 @@
// 用于构造 execve argv 数组的结构体
// 内存布局:4 个连续的 8 字节值(指针数组)
// d=0 作为 NULL 终止符
-struct Argv4 { a: string, b: string, c: string, d: int }
+struct Argv4:
+ a: string, b: string, c: string, d: int
// get_cwd() - return the process working directory.
-fn get_cwd() -> string {
- buf := alloc(4096);
- n := syscall3(79, buf, 4096, 0);
- if n <= 1 { return ""; }
- return str_sub(buf, 0, n - 1);
-}
+fn get_cwd() -> string:
+ buf := alloc(4096)
+ n := syscall3(79, buf, 4096, 0)
+ if n <= 1:
+ return ""
+ return str_sub(buf, 0, n - 1)
// get_exe_path() - resolve the running executable even when argv[0] came from PATH.
-fn get_exe_path() -> string {
- buf := alloc(4096);
- n := syscall3(89, "/proc/self/exe", buf, 4095);
- if n <= 0 { return ""; }
- return str_sub(buf, 0, n);
-}
+fn get_exe_path() -> string:
+ buf := alloc(4096)
+ n := syscall3(89, "/proc/self/exe", buf, 4095)
+ if n <= 0:
+ return ""
+ return str_sub(buf, 0, n)
// system(cmd) — 执行 shell 命令
// 功能:fork() → 子进程 execve("/bin/sh", ["/bin/sh", "-c", cmd], environ)
// 父进程 wait4() 等待子进程结束,返回退出状态码
// 返回:子进程的退出码(0-255),失败返回 -1
-fn system(cmd: string) -> int {
+fn system(cmd: string) -> int:
// fork()
- pid := syscall3(57, 0, 0, 0);
- if pid < 0 { return -1; }
- if pid > 0 {
+ pid := syscall3(57, 0, 0, 0)
+ if pid < 0:
+ return -1
+ if pid > 0:
// 父进程:等待子进程结束
- status_buf := alloc(16);
+ status_buf := alloc(16)
// I-2:wait4 有 4 个非编号参数(pid, &status, options, rusage)——
// syscall3 只有 3 个非编号参数通道,第 4 参(rusage)经通用装载器落 rcx
// 被 syscall 指令破坏 → r10 残留垃圾 → 内核 EFAULT → 退出码传播不可靠
// (corec build 对编译错误仍返回 0)。syscall4 把第 4 参经 r10 传递。
- syscall4(61, pid, status_buf, 0, 0); // wait4(pid, &status, options=0, rusage=NULL)
+ syscall4(61, pid, status_buf, 0, 0) // wait4(pid, &status, options=0, rusage=NULL)
// Linux wait status stores a normal exit code in bits 8..15.
- return load8(status_buf, 1) % 256;
- }
+ return load8(status_buf, 1) % 256
// 子进程:执行命令
// Build argv explicitly so execve receives a raw pointer array.
- argv := alloc(32);
- store_str_ptr(argv, 0, "/bin/sh");
- store_str_ptr(argv, 8, "-c");
- store_str_ptr(argv, 16, cmd);
- zi : ., mut = 0;
- loop {
- if zi >= 8 { break; }
- store8(argv, 24 + zi, 0);
- zi = zi + 1;
- }
- syscall3(59, "/bin/sh", argv, 0); // execve — 成功则不返回
- syscall3(60, 127, 0, 0); // execve 失败时 _exit(127)
- return -1;
-}
+ argv := alloc(32)
+ store_str_ptr(argv, 0, "/bin/sh")
+ store_str_ptr(argv, 8, "-c")
+ store_str_ptr(argv, 16, cmd)
+ zi : ., mut = 0
+ loop:
+ if zi >= 8:
+ break
+ store8(argv, 24 + zi, 0)
+ zi = zi + 1
+ syscall3(59, "/bin/sh", argv, 0) // execve — 成功则不返回
+ syscall3(60, 127, 0, 0) // execve 失败时 _exit(127)
+ return -1
// get_env(name) — 读取环境变量
// 从 /proc/self/environ 中读取指定环境变量的值
// 返回:变量值字符串,未找到返回 ""
-fn get_env(name: string) -> string {
- env := read_file("/proc/self/environ");
- if str_len(env) == 0 { return ""; }
- elen := str_len(env);
- i : ., mut = 0;
- loop {
- if i >= elen { break; }
- eq_pos : ., mut = -1;
- j : ., mut = i;
- loop {
- if j >= elen { break; }
- c := load8(env, j);
- if c == 61 { eq_pos = j; break; } // '='
- if c == 0 { break; } // null 分隔符
- j = j + 1;
- }
- if eq_pos >= 0 {
- key_len := eq_pos - i;
- nlen := str_len(name);
- if key_len == nlen {
- is_match : ., mut = 1;
- ki : ., mut = 0;
- loop {
- if ki >= key_len { break; }
- if load8(env, i + ki) != load8(name, ki) { is_match = 0; break; }
- ki = ki + 1;
- }
- if is_match != 0 {
- val_start := eq_pos + 1;
- val_end : ., mut = val_start;
- loop {
- if val_end >= elen { break; }
- if load8(env, val_end) == 0 { break; }
- val_end = val_end + 1;
- }
- return str_sub(env, val_start, val_end - val_start);
- }
- }
- }
- while i < elen && load8(env, i) != 0 { i = i + 1; }
- i = i + 1;
- }
- return "";
-}
+fn get_env(name: string) -> string:
+ env := read_file("/proc/self/environ")
+ if str_len(env) == 0:
+ return ""
+ elen := str_len(env)
+ i : ., mut = 0
+ loop:
+ if i >= elen:
+ break
+ eq_pos : ., mut = -1
+ j : ., mut = i
+ loop:
+ if j >= elen:
+ break
+ c := load8(env, j)
+ if c == 61:
+ eq_pos = j
+ break
+ // '='
+ if c == 0:
+ break
+ // null 分隔符
+ j = j + 1
+ if eq_pos >= 0:
+ key_len := eq_pos - i
+ nlen := str_len(name)
+ if key_len == nlen:
+ is_match : ., mut = 1
+ ki : ., mut = 0
+ loop:
+ if ki >= key_len:
+ break
+ if load8(env, i + ki) != load8(name, ki):
+ is_match = 0
+ break
+ ki = ki + 1
+ if is_match != 0:
+ val_start := eq_pos + 1
+ val_end : ., mut = val_start
+ loop:
+ if val_end >= elen:
+ break
+ if load8(env, val_end) == 0:
+ break
+ val_end = val_end + 1
+ return str_sub(env, val_start, val_end - val_start)
+ while i < elen && load8(env, i) != 0:
+ i = i + 1
+ i = i + 1
+ return ""
diff --git a/src/stdlib/panic.cr b/src/stdlib/panic.cr
index 09c1096d..c691eafa 100644
--- a/src/stdlib/panic.cr
+++ b/src/stdlib/panic.cr
@@ -11,38 +11,35 @@
// panic::panic_at("index out of bounds", "src/main.cr", 42, 5);
// Write raw bytes to stderr (fd 2)
-fn _panic_write(s: string) {
- sl := str_len(s);
- if sl > 0 { r1 := syscall3(1, 2, s, sl); }
-}
+fn _panic_write(s: string):
+ sl := str_len(s)
+ if sl > 0:
+ r1 := syscall3(1, 2, s, sl)
-fn _panic_writeln(s: string) {
- _panic_write(s);
- r1 := syscall3(1, 2, "\n", 1);
-}
+fn _panic_writeln(s: string):
+ _panic_write(s)
+ r1 := syscall3(1, 2, "\n", 1)
// Core panic entry point — prints message + location to stderr, then aborts.
// Mirrors Rust's default_hook output format:
// panicked at FILE:LINE:COL:\nMESSAGE
-fn panic_at(msg: string, file: string, line: int, col: int) {
+fn panic_at(msg: string, file: string, line: int, col: int):
// Build: "panicked at FILE:LINE:COL:\nMESSAGE\n"
- _panic_write("panicked at ");
- _panic_write(file);
- _panic_write(":");
- _panic_write(int_str(line));
- _panic_write(":");
- _panic_write(int_str(col));
- _panic_writeln(":");
- _panic_writeln(msg);
+ _panic_write("panicked at ")
+ _panic_write(file)
+ _panic_write(":")
+ _panic_write(int_str(line))
+ _panic_write(":")
+ _panic_write(int_str(col))
+ _panic_writeln(":")
+ _panic_writeln(msg)
// Abort via exit(1)
- r1 := syscall3(60, 1, 0, 0);
-}
+ r1 := syscall3(60, 1, 0, 0)
// Convenience — panic without location info
// Prints: "panicked at:\nMESSAGE\n"
-fn panic(msg: string) {
- _panic_writeln("panicked at:");
- _panic_writeln(msg);
- r1 := syscall3(60, 1, 0, 0);
-}
+fn panic(msg: string):
+ _panic_writeln("panicked at:")
+ _panic_writeln(msg)
+ r1 := syscall3(60, 1, 0, 0)
diff --git a/src/stdlib/sched.cr b/src/stdlib/sched.cr
index dc74a673..8c628370 100644
--- a/src/stdlib/sched.cr
+++ b/src/stdlib/sched.cr
@@ -6,200 +6,189 @@ import chan
import arena
// M struct layout (32 bytes): id(0), cur_g(8), runq_head(16), runq_tail(24)
-g_machines : string, mut; // M array
-g_machine_count : int, mut;
+g_machines : string, mut // M array
+g_machine_count : int, mut
// Index of the M running the current thread. Each worker sets it on entry
// (sched_worker_run); the scheduler uses it to enqueue/dequeue on the
// current M's LOCAL queue instead of contending on a shared global one.
-g_current_m_idx : int, mut = 0;
+g_current_m_idx : int, mut = 0
-g_num_workers : int, mut = 0; // number of worker threads
-g_sched_inited : int, mut = 0; // 0 = not initialized, 1 = initialized
+g_num_workers : int, mut = 0 // number of worker threads
+g_sched_inited : int, mut = 0 // 0 = not initialized, 1 = initialized
-fn sched_init() {
- if g_sched_inited != 0 { return; }
+fn sched_init():
+ if g_sched_inited != 0:
+ return
// Initialize arena system (required by goroutine/chan)
- arena_init(1048576, 65536); // 1MB pool, 64KB chunks
+ arena_init(1048576, 65536) // 1MB pool, 64KB chunks
// Initialize M workers (one per CPU)
// For now: single-threaded (1 M, cooperative)
- m := alloc(32);
- w64(m, 0, 0); // id = 0
- w64(m, 8, -1); // cur_g = none
- w64(m, 16, -1); // runq_head = empty
- w64(m, 24, -1); // runq_tail = empty
- g_machines = m;
- g_machine_count = 1;
- g_current_m_idx = 0;
+ m := alloc(32)
+ w64(m, 0, 0) // id = 0
+ w64(m, 8, -1) // cur_g = none
+ w64(m, 16, -1) // runq_head = empty
+ w64(m, 24, -1) // runq_tail = empty
+ g_machines = m
+ g_machine_count = 1
+ g_current_m_idx = 0
// Register the main thread as G 0 so it can block/wake via channels.
// Its stack_ptr is filled in by fiber_switch the first time it yields
// (fiber_switch saves the current RSP into [G+16]).
- main_g := alloc(80);
- w64(main_g, 0, 0); // id = 0
- w64(main_g, 8, 1); // _Grunning
- w64(main_g, 16, 0); // stack_ptr (filled on first yield)
- w64(main_g, 24, 0); // stack_lo (thread stack — no arena)
- w64(main_g, 32, -1); // arena_id = none
- w64(main_g, 40, -1); // result_ch = none (never dispatched by a wrapper)
- w64(main_g, 48, -1); // next = -1
- w64(main_g, 56, 0); // saved_fn = 0 (never dispatched by a wrapper)
- w64(main_g, 64, 0); // saved_arg = 0
- w64(main_g, 72, 0); // temp_val = 0
- w64(m, 8, main_g); // M[0].cur_g = main_g
- g_set_curg(main_g);
- g_sched_inited = 1;
-}
+ main_g := alloc(80)
+ w64(main_g, 0, 0) // id = 0
+ w64(main_g, 8, 1) // _Grunning
+ w64(main_g, 16, 0) // stack_ptr (filled on first yield)
+ w64(main_g, 24, 0) // stack_lo (thread stack — no arena)
+ w64(main_g, 32, -1) // arena_id = none
+ w64(main_g, 40, -1) // result_ch = none (never dispatched by a wrapper)
+ w64(main_g, 48, -1) // next = -1
+ w64(main_g, 56, 0) // saved_fn = 0 (never dispatched by a wrapper)
+ w64(main_g, 64, 0) // saved_arg = 0
+ w64(main_g, 72, 0) // temp_val = 0
+ w64(m, 8, main_g) // M[0].cur_g = main_g
+ g_set_curg(main_g)
+ g_sched_inited = 1
// sched_current_m_idx: index of the M currently executing (set by
// sched_worker_run / sched_init). The asm goroutine wrapper calls
// sched_schedule without an argument, so the scheduler always resolves the
// current M through this.
-fn sched_current_m_idx() -> int {
- return g_current_m_idx;
-}
+fn sched_current_m_idx() -> int:
+ return g_current_m_idx
-fn sched_enqueue(g: string) {
+fn sched_enqueue(g: string):
// Add to the CURRENT M's local queue (no shared global queue → no
// cross-thread contention; each M only touches its own list).
- m_idx := sched_current_m_idx();
- if m_idx < 0 { m_idx = 0; }
- m := g_machines + m_idx * 32;
- head := r64(m, 16);
- if head < 0 {
- w64(m, 16, g); // runq_head = g
- w64(m, 24, g); // runq_tail = g
- } else {
- tail := r64(m, 24);
- w64(tail, 48, g); // tail.next = g
- w64(m, 24, g); // runq_tail = g
- }
- w64(g, 48, -1);
-}
-
-fn sched_dequeue(m_idx: int) -> int {
- if m_idx < 0 { m_idx = 0; }
- m := g_machines + m_idx * 32;
- head := r64(m, 16);
- if head < 0 { return -1; }
- w64(m, 16, r64(head, 48));
- if r64(m, 16) < 0 { w64(m, 24, -1); }
- w64(head, 48, -1);
- return head;
-}
-
-fn sched_get_curg() -> int {
- return g_get_curg();
-}
-
-fn sched_yield() {
+ m_idx := sched_current_m_idx()
+ if m_idx < 0:
+ m_idx = 0
+ m := g_machines + m_idx * 32
+ head := r64(m, 16)
+ if head < 0:
+ w64(m, 16, g) // runq_head = g
+ w64(m, 24, g) // runq_tail = g
+ else:
+ tail := r64(m, 24)
+ w64(tail, 48, g) // tail.next = g
+ w64(m, 24, g) // runq_tail = g
+ w64(g, 48, -1)
+
+fn sched_dequeue(m_idx: int) -> int:
+ if m_idx < 0:
+ m_idx = 0
+ m := g_machines + m_idx * 32
+ head := r64(m, 16)
+ if head < 0:
+ return -1
+ w64(m, 16, r64(head, 48))
+ if r64(m, 16) < 0:
+ w64(m, 24, -1)
+ w64(head, 48, -1)
+ return head
+
+fn sched_get_curg() -> int:
+ return g_get_curg()
+
+fn sched_yield():
// Current goroutine yields
- cur_g := sched_get_curg();
+ cur_g := sched_get_curg()
// Re-enqueue current G only if it is still runnable.
// Blocked (_Gwaiting) Gs stay on their channel wait lists until a
// sender/receiver handoff wakes them — re-enqueueing would double-schedule.
// Dead (_Gdead) Gs must never be re-enqueued (goroutine exit path).
- if cur_g >= 0 {
- st := r64(cur_g, 8);
- if st != 2 && st != 3 { // not _Gwaiting, not _Gdead
- w64(cur_g, 8, 0); // _Grunnable
- sched_enqueue(cur_g);
- }
- }
+ if cur_g >= 0:
+ st := r64(cur_g, 8)
+ if st != 2 && st != 3:
+ // not _Gwaiting, not _Gdead
+ w64(cur_g, 8, 0) // _Grunnable
+ sched_enqueue(cur_g)
// Schedule next
- sched_schedule();
-}
+ sched_schedule()
// sched_schedule: switch to the next runnable G from the current M's local
// queue. No m_idx parameter: the current M index is tracked in
// g_current_m_idx, and the assembly goroutine_entry_wrapper calls this
// directly (rdi is unspecified there) on the goroutine exit path.
-fn sched_schedule() {
- m_idx := sched_current_m_idx();
- next_g := sched_dequeue(m_idx);
- if next_g >= 0 {
- old_g := r64(g_machines, m_idx * 32 + 8);
- w64(g_machines, m_idx * 32 + 8, next_g);
- g_set_curg(next_g);
- w64(next_g, 8, 1); // _Grunning
-
- if old_g >= 0 {
+fn sched_schedule():
+ m_idx := sched_current_m_idx()
+ next_g := sched_dequeue(m_idx)
+ if next_g >= 0:
+ old_g := r64(g_machines, m_idx * 32 + 8)
+ w64(g_machines, m_idx * 32 + 8, next_g)
+ g_set_curg(next_g)
+ w64(next_g, 8, 1) // _Grunning
+
+ if old_g >= 0:
// Save old_g's sp, switch to next_g's sp
- old_sp_addr := old_g + 16; // &g.stack_ptr
- next_sp := r64(next_g, 16); // g.stack_ptr
- fiber_switch(old_sp_addr, next_sp);
- }
+ old_sp_addr := old_g + 16 // &g.stack_ptr
+ next_sp := r64(next_g, 16) // g.stack_ptr
+ fiber_switch(old_sp_addr, next_sp)
// else: first goroutine, just start it
- }
-}
// sched_worker_run: main loop for worker threads.
// Each worker dequeues and runs goroutines from ITS OWN M's local queue.
-fn sched_worker_run(m_idx: int) {
+fn sched_worker_run(m_idx: int):
// Store this worker's index in its M struct
- w64(g_machines, m_idx * 32, m_idx); // m.id = m_idx
- g_current_m_idx = m_idx;
-
- loop {
- next_g := sched_dequeue(m_idx);
- if next_g >= 0 {
- old_g := r64(g_machines, m_idx * 32 + 8);
- w64(g_machines, m_idx * 32 + 8, next_g);
- g_set_curg(next_g);
- w64(next_g, 8, 1); // _Grunning
-
- if old_g >= 0 {
- old_sp_addr := old_g + 16;
- next_sp := r64(next_g, 16);
- fiber_switch(old_sp_addr, next_sp);
- }
+ w64(g_machines, m_idx * 32, m_idx) // m.id = m_idx
+ g_current_m_idx = m_idx
+
+ loop:
+ next_g := sched_dequeue(m_idx)
+ if next_g >= 0:
+ old_g := r64(g_machines, m_idx * 32 + 8)
+ w64(g_machines, m_idx * 32 + 8, next_g)
+ g_set_curg(next_g)
+ w64(next_g, 8, 1) // _Grunning
+
+ if old_g >= 0:
+ old_sp_addr := old_g + 16
+ next_sp := r64(next_g, 16)
+ fiber_switch(old_sp_addr, next_sp)
// else: first goroutine on this M, start it
- }
// If no work, yield to OS
// For now: spin-wait (will add proper blocking later)
// yield(); // sched_yield_to_os() — future
- }
-}
// sched_go: spawn a goroutine that calls fn_ptr(arg), return a channel for the result.
// fn_ptr is the function's address (resolved by the backend at link time).
// arg is the single argument passed to the spawned function.
-fn sched_go(fn_ptr: int, arg: int) -> string {
+fn sched_go(fn_ptr: int, arg: int) -> string:
// Create a 1-element channel for collecting the result
- ch := chan_make(8, 1);
+ ch := chan_make(8, 1)
// Create a new goroutine via g_new
- g := g_new(fn_ptr, arg, 0);
+ g := g_new(fn_ptr, arg, 0)
// Store result channel in G struct (offset 40)
- w64(g, 40, ch);
+ w64(g, 40, ch)
// Enqueue goroutine to the scheduler
- sched_enqueue(g);
+ sched_enqueue(g)
// Return the channel so the caller can await the result
- return ch;
-}
+ return ch
// sched_spawn_workers: create n worker threads via m_start_workers (rt.s)
-fn sched_spawn_workers(n: int) {
- if n <= 1 { return; }
- total_ms := alloc(n * 32);
- mi : ., mut = 0;
- loop {
- if mi >= n { break; }
- w64(total_ms, mi * 32, mi); // m.id
- w64(total_ms, mi * 32 + 8, -1); // m.cur_g = none
- w64(total_ms, mi * 32 + 16, -1); // runq_head
- w64(total_ms, mi * 32 + 24, -1); // runq_tail
- mi = mi + 1;
- }
- g_machines = total_ms;
- g_machine_count = n;
- g_num_workers = n - 1;
- m_start_workers(n); // launch workers (assembly in rt.s)
-}
+fn sched_spawn_workers(n: int):
+ if n <= 1:
+ return
+ total_ms := alloc(n * 32)
+ mi : ., mut = 0
+ loop:
+ if mi >= n:
+ break
+ w64(total_ms, mi * 32, mi) // m.id
+ w64(total_ms, mi * 32 + 8, -1) // m.cur_g = none
+ w64(total_ms, mi * 32 + 16, -1) // runq_head
+ w64(total_ms, mi * 32 + 24, -1) // runq_tail
+ mi = mi + 1
+ g_machines = total_ms
+ g_machine_count = n
+ g_num_workers = n - 1
+ m_start_workers(n) // launch workers (assembly in rt.s)
diff --git a/src/stdlib/scheduler.cr b/src/stdlib/scheduler.cr
index aafa8029..5939286a 100644
--- a/src/stdlib/scheduler.cr
+++ b/src/stdlib/scheduler.cr
@@ -3,152 +3,169 @@
// Each `go node` is a Fiber with its own Arena. The scheduler round-robins
// through runnable fibers. Fibers yield cooperatively — no preemption.
-import arena;
+import arena
// ── Legacy: dispatch table for .so extensions ──
-fn sched_create(n: int) -> string { return alloc(n * 8); }
-
-fn sched_set(entries: string, idx: int, val: int) {
- p := idx * 8;
- v : ., mut = val;
- i : ., mut = 0;
- loop { if i >= 8 { break; } store8(entries, p + i, v % 256); v = v / 256; i = i + 1; }
-}
-
-fn sched_get(entries: string, idx: int) -> int {
- p := idx * 8;
- r : ., mut = 0;
- i : ., mut = 7;
- loop { if i < 0 { break; } b := load8(entries, p + i); if b < 0 { b = b + 256; } r = r * 256 + b; i = i - 1; }
- return r;
-}
+fn sched_create(n: int) -> string:
+ return alloc(n * 8)
+
+fn sched_set(entries: string, idx: int, val: int):
+ p := idx * 8
+ v : ., mut = val
+ i : ., mut = 0
+ loop:
+ if i >= 8:
+ break
+ store8(entries, p + i, v % 256)
+ v = v / 256
+ i = i + 1
+
+fn sched_get(entries: string, idx: int) -> int:
+ p := idx * 8
+ r : ., mut = 0
+ i : ., mut = 7
+ loop:
+ if i < 0:
+ break
+ b := load8(entries, p + i)
+ if b < 0:
+ b = b + 256
+ r = r * 256 + b
+ i = i - 1
+ return r
// ── Fiber states ──
-FIBER_FREE : int = 0;
-FIBER_RUNNABLE : int = 1;
-FIBER_WAITING : int = 2;
-FIBER_DONE : int = 3;
+FIBER_FREE : int = 0
+FIBER_RUNNABLE : int = 1
+FIBER_WAITING : int = 2
+FIBER_DONE : int = 3
// ── Fiber table (32 bytes each: fn_idx:8, arena:8, state:8, data:8) ──
-g_fibers : string, mut;
-g_fiber_count : int, mut;
-g_fiber_cap : int, mut;
+g_fibers : string, mut
+g_fiber_count : int, mut
+g_fiber_cap : int, mut
// ── Run queue (ring buffer of fiber indices) ──
-g_runq : string, mut;
-g_runq_head : int, mut;
-g_runq_tail : int, mut;
-g_runq_count : int, mut;
-g_runq_cap : int, mut;
+g_runq : string, mut
+g_runq_head : int, mut
+g_runq_tail : int, mut
+g_runq_count : int, mut
+g_runq_cap : int, mut
// ── Current executing fiber ──
-g_cur_fiber : int, mut;
-
-fn fiber_init() {
- g_fiber_cap = 64;
- g_fibers = alloc(g_fiber_cap * 32);
- g_fiber_count = 0;
- g_runq_cap = 64;
- g_runq = alloc(g_runq_cap * 8);
- g_runq_head = 0; g_runq_tail = 0; g_runq_count = 0;
- g_cur_fiber = -1;
-}
-
-fn runq_push(fi: int) {
- if g_runq_count >= g_runq_cap {
- nc := g_runq_cap * 2;
- nb := alloc(nc * 8);
- ci : ., mut = 0; pos := g_runq_head;
- loop { if ci >= g_runq_count { break; } w64(nb, ci * 8, r64(g_runq, pos * 8)); pos = (pos + 1) % g_runq_cap; ci = ci + 1; }
- g_runq = nb; g_runq_head = 0; g_runq_tail = g_runq_count; g_runq_cap = nc;
- }
- w64(g_runq, g_runq_tail * 8, fi);
- g_runq_tail = (g_runq_tail + 1) % g_runq_cap;
- g_runq_count = g_runq_count + 1;
-}
-
-fn runq_pop() -> int {
- if g_runq_count <= 0 { return -1; }
- fi := r64(g_runq, g_runq_head * 8);
- g_runq_head = (g_runq_head + 1) % g_runq_cap;
- g_runq_count = g_runq_count - 1;
- return fi;
-}
-
-fn fiber_spawn(fn_idx: int) -> int {
- i : ., mut = 0;
- loop {
- if i >= g_fiber_count { break; }
- if r64(g_fibers, i * 32 + 16) == FIBER_FREE {
- w64(g_fibers, i * 32, fn_idx);
- w64(g_fibers, i * 32 + 8, arena.arena_new());
- w64(g_fibers, i * 32 + 16, FIBER_RUNNABLE);
- runq_push(i);
- return i;
- }
- i = i + 1;
- }
- if g_fiber_count >= g_fiber_cap {
- nc := g_fiber_cap * 2;
- nb := alloc(nc * 32);
- _dyncpy(g_fibers, g_fiber_cap * 32, nb);
- g_fiber_cap = nc;
- g_fibers = nb;
- }
- fi := g_fiber_count;
- g_fiber_count = g_fiber_count + 1;
- off := fi * 32;
- w64(g_fibers, off, fn_idx);
- w64(g_fibers, off + 8, arena.arena_new());
- w64(g_fibers, off + 16, FIBER_RUNNABLE);
- w64(g_fibers, off + 24, 0);
- runq_push(fi);
- return fi;
-}
-
-fn fiber_yield() {
- if g_cur_fiber < 0 { return; }
- off := g_cur_fiber * 32;
- if r64(g_fibers, off + 16) == FIBER_RUNNABLE { runq_push(g_cur_fiber); }
-}
-
-fn fiber_wait(target: int) {
- if g_cur_fiber < 0 { return; }
- off := g_cur_fiber * 32;
- w64(g_fibers, off + 16, FIBER_WAITING);
- w64(g_fibers, off + 24, target);
-}
-
-fn fiber_wake(fi: int) {
- if fi < 0 { return; }
- off := fi * 32;
- if r64(g_fibers, off + 16) == FIBER_WAITING {
- w64(g_fibers, off + 16, FIBER_RUNNABLE);
- w64(g_fibers, off + 24, 0);
- runq_push(fi);
- }
-}
-
-fn fiber_done(fi: int) {
- if fi < 0 || fi >= g_fiber_count { return; }
- off := fi * 32;
- ai := r64(g_fibers, off + 8);
- if ai >= 0 { arena.arena_reset(ai); }
- w64(g_fibers, off + 16, FIBER_DONE);
-}
-
-fn sched_run() {
- loop {
- fi := runq_pop();
- if fi < 0 { break; }
- g_cur_fiber = fi;
- off := fi * 32;
- if r64(g_fibers, off + 16) != FIBER_RUNNABLE { continue; }
+g_cur_fiber : int, mut
+
+fn fiber_init():
+ g_fiber_cap = 64
+ g_fibers = alloc(g_fiber_cap * 32)
+ g_fiber_count = 0
+ g_runq_cap = 64
+ g_runq = alloc(g_runq_cap * 8)
+ g_runq_head = 0
+ g_runq_tail = 0
+ g_runq_count = 0
+ g_cur_fiber = -1
+
+fn runq_push(fi: int):
+ if g_runq_count >= g_runq_cap:
+ nc := g_runq_cap * 2
+ nb := alloc(nc * 8)
+ ci : ., mut = 0
+ pos := g_runq_head
+ loop:
+ if ci >= g_runq_count:
+ break
+ w64(nb, ci * 8, r64(g_runq, pos * 8))
+ pos = (pos + 1) % g_runq_cap
+ ci = ci + 1
+ g_runq = nb
+ g_runq_head = 0
+ g_runq_tail = g_runq_count
+ g_runq_cap = nc
+ w64(g_runq, g_runq_tail * 8, fi)
+ g_runq_tail = (g_runq_tail + 1) % g_runq_cap
+ g_runq_count = g_runq_count + 1
+
+fn runq_pop() -> int:
+ if g_runq_count <= 0:
+ return -1
+ fi := r64(g_runq, g_runq_head * 8)
+ g_runq_head = (g_runq_head + 1) % g_runq_cap
+ g_runq_count = g_runq_count - 1
+ return fi
+
+fn fiber_spawn(fn_idx: int) -> int:
+ i : ., mut = 0
+ loop:
+ if i >= g_fiber_count:
+ break
+ if r64(g_fibers, i * 32 + 16) == FIBER_FREE:
+ w64(g_fibers, i * 32, fn_idx)
+ w64(g_fibers, i * 32 + 8, arena.arena_new())
+ w64(g_fibers, i * 32 + 16, FIBER_RUNNABLE)
+ runq_push(i)
+ return i
+ i = i + 1
+ if g_fiber_count >= g_fiber_cap:
+ nc := g_fiber_cap * 2
+ nb := alloc(nc * 32)
+ _dyncpy(g_fibers, g_fiber_cap * 32, nb)
+ g_fiber_cap = nc
+ g_fibers = nb
+ fi := g_fiber_count
+ g_fiber_count = g_fiber_count + 1
+ off := fi * 32
+ w64(g_fibers, off, fn_idx)
+ w64(g_fibers, off + 8, arena.arena_new())
+ w64(g_fibers, off + 16, FIBER_RUNNABLE)
+ w64(g_fibers, off + 24, 0)
+ runq_push(fi)
+ return fi
+
+fn fiber_yield():
+ if g_cur_fiber < 0:
+ return
+ off := g_cur_fiber * 32
+ if r64(g_fibers, off + 16) == FIBER_RUNNABLE:
+ runq_push(g_cur_fiber)
+
+fn fiber_wait(target: int):
+ if g_cur_fiber < 0:
+ return
+ off := g_cur_fiber * 32
+ w64(g_fibers, off + 16, FIBER_WAITING)
+ w64(g_fibers, off + 24, target)
+
+fn fiber_wake(fi: int):
+ if fi < 0:
+ return
+ off := fi * 32
+ if r64(g_fibers, off + 16) == FIBER_WAITING:
+ w64(g_fibers, off + 16, FIBER_RUNNABLE)
+ w64(g_fibers, off + 24, 0)
+ runq_push(fi)
+
+fn fiber_done(fi: int):
+ if fi < 0 || fi >= g_fiber_count:
+ return
+ off := fi * 32
+ ai := r64(g_fibers, off + 8)
+ if ai >= 0:
+ arena.arena_reset(ai)
+ w64(g_fibers, off + 16, FIBER_DONE)
+
+fn sched_run():
+ loop:
+ fi := runq_pop()
+ if fi < 0:
+ break
+ g_cur_fiber = fi
+ off := fi * 32
+ if r64(g_fibers, off + 16) != FIBER_RUNNABLE:
+ continue
// Placeholder: fibers complete immediately in interpreter mode.
// Native backend (corearch) will call the actual function pointer
// stored at g_fibers[fi].fn_idx via the dispatch table.
- fiber_done(fi);
- }
- g_cur_fiber = -1;
-}
+ fiber_done(fi)
+ g_cur_fiber = -1
diff --git a/src/stdlib/toml.cr b/src/stdlib/toml.cr
index 20244c72..3a295c8f 100644
--- a/src/stdlib/toml.cr
+++ b/src/stdlib/toml.cr
@@ -16,259 +16,259 @@
// --- low-level helpers ---
-fn _skip_whitespace(content: string, pos: int) -> int {
- slen := str_len(content);
- p : ., mut = pos;
- loop {
- if p >= slen { break; }
- ch := get_char(content, p);
- if ch != " " && ch != "\t" { break; }
- p = p + 1;
- }
- return p;
-}
+fn _skip_whitespace(content: string, pos: int) -> int:
+ slen := str_len(content)
+ p : ., mut = pos
+ loop:
+ if p >= slen:
+ break
+ ch := get_char(content, p)
+ if ch != " " && ch != "\t":
+ break
+ p = p + 1
+ return p
-fn _is_at_line_start(content: string, pos: int) -> bool {
- if pos == 0 { return true; }
- prev := get_char(content, pos - 1);
- return prev == "\n";
-}
+fn _is_at_line_start(content: string, pos: int) -> bool:
+ if pos == 0:
+ return true
+ prev := get_char(content, pos - 1)
+ return prev == "\n"
-fn _skip_to_next_line(content: string, pos: int) -> int {
- slen := str_len(content);
- p : ., mut = pos;
- loop {
- if p >= slen { break; }
- if get_char(content, p) == "\n" { return p + 1; }
- p = p + 1;
- }
- return slen;
-}
+fn _skip_to_next_line(content: string, pos: int) -> int:
+ slen := str_len(content)
+ p : ., mut = pos
+ loop:
+ if p >= slen:
+ break
+ if get_char(content, p) == "\n":
+ return p + 1
+ p = p + 1
+ return slen
-fn _next_line_start(content: string, pos: int) -> int {
- slen := str_len(content);
- i : ., mut = pos;
- loop {
- if i >= slen { return slen; }
- if get_char(content, i) == "\n" { return i + 1; }
- i = i + 1;
- }
- return slen;
-}
+fn _next_line_start(content: string, pos: int) -> int:
+ slen := str_len(content)
+ i : ., mut = pos
+ loop:
+ if i >= slen:
+ return slen
+ if get_char(content, i) == "\n":
+ return i + 1
+ i = i + 1
+ return slen
// --- public API ---
// Extract a string value: name = "value"
// Returns empty string if not found.
-fn toml_get_str(content: string, key: string) -> string {
- slen := str_len(content);
- klen := str_len(key);
- pos : ., mut = 0;
- loop {
- if pos >= slen { return ""; }
- if !_is_at_line_start(content, pos) {
- pos = _next_line_start(content, pos);
- continue;
- }
- spos := _skip_whitespace(content, pos);
- npos : ., mut = 0;
- tlen : ., mut = 0;
+fn toml_get_str(content: string, key: string) -> string:
+ slen := str_len(content)
+ klen := str_len(key)
+ pos : ., mut = 0
+ loop:
+ if pos >= slen:
+ return ""
+ if !_is_at_line_start(content, pos):
+ pos = _next_line_start(content, pos)
+ continue
+ spos := _skip_whitespace(content, pos)
+ npos : ., mut = 0
+ tlen : ., mut = 0
// Check if this line starts with the key
- if spos + klen <= slen {
- sub := str_sub(content, spos, klen);
- if str_eq(sub, key) != 0 {
+ if spos + klen <= slen:
+ sub := str_sub(content, spos, klen)
+ if str_eq(sub, key) != 0:
// Skip key and look for =
- eq_pos := spos + klen;
+ eq_pos := spos + klen
// Skip whitespace before =
- eq_pos = _skip_whitespace(content, eq_pos);
- if get_char(content, eq_pos) == "=" {
+ eq_pos = _skip_whitespace(content, eq_pos)
+ if get_char(content, eq_pos) == "=":
// Skip whitespace after =
- val_pos := _skip_whitespace(content, eq_pos + 1);
- if get_char(content, val_pos) == "\"" {
- start := val_pos + 1;
- end : ., mut = start;
- loop {
- if end >= slen { return ""; }
- if get_char(content, end) == "\"" {
- return str_sub(content, start, end - start);
- }
- end = end + 1;
- }
- }
- }
- }
- }
- pos = _next_line_start(content, pos);
- }
- return "";
-}
+ val_pos := _skip_whitespace(content, eq_pos + 1)
+ if get_char(content, val_pos) == "\"":
+ start := val_pos + 1
+ end : ., mut = start
+ loop:
+ if end >= slen:
+ return ""
+ if get_char(content, end) == "\"":
+ return str_sub(content, start, end - start)
+ end = end + 1
+ pos = _next_line_start(content, pos)
+ return ""
// Extract an integer value: key = 123
// Returns 0 if not found or invalid.
-fn toml_get_int(content: string, key: string) -> int {
- slen := str_len(content);
- klen := str_len(key);
- pos : ., mut = 0;
- loop {
- if pos >= slen { return 0; }
- if !_is_at_line_start(content, pos) {
- pos = _next_line_start(content, pos);
- continue;
- }
- spos := _skip_whitespace(content, pos);
- if spos + klen <= slen {
- sub := str_sub(content, spos, klen);
- if str_eq(sub, key) != 0 {
- eq_pos := _skip_whitespace(content, spos + klen);
- if get_char(content, eq_pos) == "=" {
- val_pos := _skip_whitespace(content, eq_pos + 1);
+fn toml_get_int(content: string, key: string) -> int:
+ slen := str_len(content)
+ klen := str_len(key)
+ pos : ., mut = 0
+ loop:
+ if pos >= slen:
+ return 0
+ if !_is_at_line_start(content, pos):
+ pos = _next_line_start(content, pos)
+ continue
+ spos := _skip_whitespace(content, pos)
+ if spos + klen <= slen:
+ sub := str_sub(content, spos, klen)
+ if str_eq(sub, key) != 0:
+ eq_pos := _skip_whitespace(content, spos + klen)
+ if get_char(content, eq_pos) == "=":
+ val_pos := _skip_whitespace(content, eq_pos + 1)
// Read integer digits
- val : ., mut = 0;
- lp : ., mut = val_pos;
- neg : ., mut = 0;
- if get_char(content, lp) == "-" { neg = 1; lp = lp + 1; }
- loop {
- if lp >= slen { break; }
- c := load8(content, lp);
- if c >= 48 && c <= 57 {
- val = val * 10 + (c - 48);
- lp = lp + 1;
- } else { break; }
- }
- if neg == 1 { val = -val; }
- return val;
- }
- }
- }
- pos = _next_line_start(content, pos);
- }
- return 0;
-}
+ val : ., mut = 0
+ lp : ., mut = val_pos
+ neg : ., mut = 0
+ if get_char(content, lp) == "-":
+ neg = 1
+ lp = lp + 1
+ loop:
+ if lp >= slen:
+ break
+ c := load8(content, lp)
+ if c >= 48 && c <= 57:
+ val = val * 10 + (c - 48)
+ lp = lp + 1
+ else:
+ break
+ if neg == 1:
+ val = -val
+ return val
+ pos = _next_line_start(content, pos)
+ return 0
// Extract project name (shorthand for toml_get_str(content, "name"))
-fn extract_toml_name(content: string) -> string {
- return toml_get_str(content, "name");
-}
+fn extract_toml_name(content: string) -> string:
+ return toml_get_str(content, "name")
// Hex digit value (0-15), -1 if not a hex digit.
-fn _toml_hex_digit(c: int) -> int {
- if c >= 48 && c <= 57 { return c - 48; }
- if c >= 65 && c <= 70 { return c - 55; } // 'A'-'F'
- if c >= 97 && c <= 102 { return c - 87; } // 'a'-'f'
- return -1;
-}
+fn _toml_hex_digit(c: int) -> int:
+ if c >= 48 && c <= 57:
+ return c - 48
+ if c >= 65 && c <= 70:
+ return c - 55
+ // 'A'-'F'
+ if c >= 97 && c <= 102:
+ return c - 87
+ // 'a'-'f'
+ return -1
// Extract an int array value: key = [a, b, c](项支持十进制与 0x/0X 十六进制,
// 非负整数;值写入 out,每项 4B 小端)。供 HIT 表 opcode = [0x48, 0x29] 类
// 条目使用(见 src/arch/x86_64/core-x86.toml)。
// Returns item count on success(遇 ']' 收尾);-1 = key 缺 / 值非数组 /
// 项格式错 / 项数超过 max_items(不静默截断)。
-fn toml_get_int_list(content: string, key: string, out: string, max_items: int) -> int {
- slen := str_len(content);
- klen := str_len(key);
- pos : ., mut = 0;
- loop {
- if pos >= slen { return -1; }
- if !_is_at_line_start(content, pos) {
- pos = _next_line_start(content, pos);
- continue;
- }
- spos := _skip_whitespace(content, pos);
- if spos + klen > slen {
- pos = _next_line_start(content, pos);
- continue;
- }
- sub := str_sub(content, spos, klen);
- if str_eq(sub, key) == 0 {
- pos = _next_line_start(content, pos);
- continue;
- }
- eq_pos := _skip_whitespace(content, spos + klen);
- if load8(content, eq_pos) != 61 { // 非 '=' 的行不算命中
- pos = _next_line_start(content, pos);
- continue;
- }
- val_pos := _skip_whitespace(content, eq_pos + 1);
- if load8(content, val_pos) != 91 { // 值非 '[' 开头 → 非数组,继续找下一条
- pos = _next_line_start(content, pos);
- continue;
- }
+fn toml_get_int_list(content: string, key: string, out: string, max_items: int) -> int:
+ slen := str_len(content)
+ klen := str_len(key)
+ pos : ., mut = 0
+ loop:
+ if pos >= slen:
+ return -1
+ if !_is_at_line_start(content, pos):
+ pos = _next_line_start(content, pos)
+ continue
+ spos := _skip_whitespace(content, pos)
+ if spos + klen > slen:
+ pos = _next_line_start(content, pos)
+ continue
+ sub := str_sub(content, spos, klen)
+ if str_eq(sub, key) == 0:
+ pos = _next_line_start(content, pos)
+ continue
+ eq_pos := _skip_whitespace(content, spos + klen)
+ if load8(content, eq_pos) != 61:
+ // 非 '=' 的行不算命中
+ pos = _next_line_start(content, pos)
+ continue
+ val_pos := _skip_whitespace(content, eq_pos + 1)
+ if load8(content, val_pos) != 91:
+ // 值非 '[' 开头 → 非数组,继续找下一条
+ pos = _next_line_start(content, pos)
+ continue
// Parse list items
- p : ., mut = val_pos + 1;
- n : ., mut = 0;
- loop {
- if p >= slen { return -1; }
+ p : ., mut = val_pos + 1
+ n : ., mut = 0
+ loop:
+ if p >= slen:
+ return -1
// Skip whitespace (incl. newlines: lists may span lines)
- ch : ., mut = 0;
- loop {
- if p >= slen { return -1; }
- ch = load8(content, p);
- if ch == 32 || ch == 9 || ch == 10 || ch == 13 {
- p = p + 1;
- } else { break; }
- }
- if ch == 93 { break; } // ']' → list end(此处 return n)
- if ch == 44 { p = p + 1; continue; } // ',' — 宽容跳过分隔符
- if n >= max_items { return -1; } // 项数超限(不静默截断)
- v : ., mut = 0;
+ ch : ., mut = 0
+ loop:
+ if p >= slen:
+ return -1
+ ch = load8(content, p)
+ if ch == 32 || ch == 9 || ch == 10 || ch == 13:
+ p = p + 1
+ else:
+ break
+ if ch == 93:
+ break
+ // ']' → list end(此处 return n)
+ if ch == 44:
+ p = p + 1
+ continue
+ // ',' — 宽容跳过分隔符
+ if n >= max_items:
+ return -1
+ // 项数超限(不静默截断)
+ v : ., mut = 0
// Hex item: 0x/0X prefix
- if ch == 48 && p + 1 < slen &&
- (load8(content, p + 1) == 120 || load8(content, p + 1) == 88) {
- p = p + 2;
- if p >= slen { return -1; }
- hd := _toml_hex_digit(load8(content, p));
- if hd < 0 { return -1; }
- v = hd;
- p = p + 1;
- loop {
- if p >= slen { break; }
- ch = load8(content, p);
- hd2 := _toml_hex_digit(ch);
- if hd2 < 0 { break; }
- v = v * 16 + hd2;
- p = p + 1;
- }
- } else {
+ if ch == 48 && p + 1 < slen && (load8(content, p + 1) == 120 || load8(content, p + 1) == 88):
+ p = p + 2
+ if p >= slen:
+ return -1
+ hd := _toml_hex_digit(load8(content, p))
+ if hd < 0:
+ return -1
+ v = hd
+ p = p + 1
+ loop:
+ if p >= slen:
+ break
+ ch = load8(content, p)
+ hd2 := _toml_hex_digit(ch)
+ if hd2 < 0:
+ break
+ v = v * 16 + hd2
+ p = p + 1
+ else:
// Decimal item(须以数字开头)
- if ch < 48 || ch > 57 { return -1; }
- v = ch - 48;
- p = p + 1;
- loop {
- if p >= slen { break; }
- ch = load8(content, p);
- if ch >= 48 && ch <= 57 {
- v = v * 10 + (ch - 48);
- p = p + 1;
- } else { break; }
- }
- }
+ if ch < 48 || ch > 57:
+ return -1
+ v = ch - 48
+ p = p + 1
+ loop:
+ if p >= slen:
+ break
+ ch = load8(content, p)
+ if ch >= 48 && ch <= 57:
+ v = v * 10 + (ch - 48)
+ p = p + 1
+ else:
+ break
// Item terminator must be ws / ',' / ']'
- if ch != 32 && ch != 9 && ch != 10 && ch != 13 &&
- ch != 44 && ch != 93 { return -1; }
- store8(out, n * 4 + 0, v % 256);
- store8(out, n * 4 + 1, (v / 256) % 256);
- store8(out, n * 4 + 2, (v / 65536) % 256);
- store8(out, n * 4 + 3, (v / 16777216) % 256);
- n = n + 1;
- }
- return n;
- }
- return -1;
-}
+ if ch != 32 && ch != 9 && ch != 10 && ch != 13 && ch != 44 && ch != 93:
+ return -1
+ store8(out, n * 4 + 0, v % 256)
+ store8(out, n * 4 + 1, (v / 256) % 256)
+ store8(out, n * 4 + 2, (v / 65536) % 256)
+ store8(out, n * 4 + 3, (v / 16777216) % 256)
+ n = n + 1
+ return n
+ return -1
// Memory layout configuration
-struct MemLayout {
+struct MemLayout:
stack_size: int,
heap_size: int,
text_base: int,
data_base: int,
-}
-fn toml_read_memlayout(content: string) -> MemLayout {
+fn toml_read_memlayout(content: string) -> MemLayout:
return MemLayout {
stack_size = toml_get_int(content, "stack_size"),
heap_size = toml_get_int(content, "heap_size"),
text_base = toml_get_int(content, "text_base"),
data_base = toml_get_int(content, "data_base"),
- };
-}
+ }
diff --git a/src/stdlib/trace.cr b/src/stdlib/trace.cr
index 33a8602b..c205667e 100644
--- a/src/stdlib/trace.cr
+++ b/src/stdlib/trace.cr
@@ -7,17 +7,15 @@
//
// 编译器专用部分(需要编译器全局变量)在 src/compiler/trace_ext.cr
-fn trace_assert(cond: int, msg: string) {
- if cond != 0 { return; }
- println(msg);
-}
+fn trace_assert(cond: int, msg: string):
+ if cond != 0:
+ return
+ println(msg)
-fn trace_dbg(name: string, val: int) -> int {
- print_i(val);
- return val;
-}
+fn trace_dbg(name: string, val: int) -> int:
+ print_i(val)
+ return val
-fn trace_dbg_str(name: string, val: string) -> string {
- print(val);
- return val;
-}
+fn trace_dbg_str(name: string, val: string) -> string:
+ print(val)
+ return val
diff --git a/src/stdlib/variadic.cr b/src/stdlib/variadic.cr
index c4b69ec1..c0265708 100644
--- a/src/stdlib/variadic.cr
+++ b/src/stdlib/variadic.cr
@@ -13,22 +13,21 @@
// ═══════════════════════════════════════════
// 变参包计数:返回参数数量
-fn va_count(pack: string) -> int {
- if str_len(pack) < 8 { return 0; }
- return r64(pack, 0);
-}
+fn va_count(pack: string) -> int:
+ if str_len(pack) < 8:
+ return 0
+ return r64(pack, 0)
// 变参包取值:返回第 n 个参数的 IR 变量
-fn va_arg(pack: string, n: int) -> int {
- if str_len(pack) < (n + 1) * 8 + 8 { return -1; }
- return r64(pack, (n + 1) * 8);
-}
+fn va_arg(pack: string, n: int) -> int:
+ if str_len(pack) < (n + 1) * 8 + 8:
+ return -1
+ return r64(pack, (n + 1) * 8)
// 检测函数名是否含 "ln"(println → print + "\n")
-fn va_fn_has_ln(fn_name: string) -> bool {
- fnl := str_len(fn_name);
- if fnl >= 4 {
- if load8(fn_name, fnl-2) == 108 && load8(fn_name, fnl-1) == 110 { return true; }
- }
- return false;
-}
+fn va_fn_has_ln(fn_name: string) -> bool:
+ fnl := str_len(fn_name)
+ if fnl >= 4:
+ if load8(fn_name, fnl-2) == 108 && load8(fn_name, fnl-1) == 110:
+ return true
+ return false
diff --git a/src/targets/x86_64-linux/main.cr b/src/targets/x86_64-linux/main.cr
index 59453e0d..4a77e9fe 100644
--- a/src/targets/x86_64-linux/main.cr
+++ b/src/targets/x86_64-linux/main.cr
@@ -16,145 +16,207 @@
// 未来如需合并/删除,须同步双入口接线与 _import.cr 导入集(现 load 后行为同构;
// 表模式/调试通道的 flag 注册分歧 = TODO #2026-09-10-2,留波 2 收敛——本注记仅措辞同步)。
-fn init_backend_arrays() {
- g_x86_var_count = 0; g_x86_stack_size = 0; g_x86_func_idx = 0; g_x86_is_enum_count = 0;
- g_x86_var_cap = 0; g_x86_is_enum_cap = 0; g_stack_map = ""; }
+fn init_backend_arrays():
+ g_x86_var_count = 0
+ g_x86_stack_size = 0
+ g_x86_func_idx = 0
+ g_x86_is_enum_count = 0
+ g_x86_var_cap = 0
+ g_x86_is_enum_cap = 0
+ g_stack_map = ""
-fn split_links(val: string) {
- sl := str_len(val); start : ., mut = 0; i : ., mut = 0;
- loop { if i > sl { break; }
- if i == sl || load8(val, i) == 44 {
- if i > start { p := str_sub(val, start, i - start); ctx_add_so(p); }
- start = i + 1; }
- i = i + 1; } }
+fn split_links(val: string):
+ sl := str_len(val)
+ start : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i > sl:
+ break
+ if i == sl || load8(val, i) == 44:
+ if i > start:
+ p := str_sub(val, start, i - start)
+ ctx_add_so(p)
+ start = i + 1
+ i = i + 1
-fn corearch_main() -> int {
- cli_init("corearch", "Core architecture backend");
- cli_flag_bool("elf", "", "Output ELF binary (default)");
- cli_flag_bool("shared", "", "Output shared library (.so)");
- cli_flag_bool("static", "", "Static linking (embed runtime)");
- cli_flag("link", "l", "Comma-sep .so files, or 'auto' for ~/.core/lib/");
- cli_flag("output", "o", "Output path");
- cli_flag("opt-level", "O", "Optimization level (0-3, default=0)");
+fn corearch_main() -> int:
+ cli_init("corearch", "Core architecture backend")
+ cli_flag_bool("elf", "", "Output ELF binary (default)")
+ cli_flag_bool("shared", "", "Output shared library (.so)")
+ cli_flag_bool("static", "", "Static linking (embed runtime)")
+ cli_flag("link", "l", "Comma-sep .so files, or 'auto' for ~/.core/lib/")
+ cli_flag("output", "o", "Output path")
+ cli_flag("opt-level", "O", "Optimization level (0-3, default=0)")
- if cli_parse() != 0 { return 1; }
- g_opt_level = 0;
- ol : ., mut = cli_get("opt-level");
- if str_len(ol) > 0 { g_opt_level = str_int(ol); if g_opt_level > 3 { g_opt_level = 3; } if g_opt_level < 0 { g_opt_level = 0; } }
- if cli_arg_count() < 1 {
- println("usage: corearch [options]");
- println(" --elf ELF binary (default: dynamic)");
- println(" --static static linking (embed runtime)");
- println(" --shared shared library (.so)");
- println(" --link auto link ~/.core/lib/*.so (default)");
- println(" --link s1,s2 link specific .so files");
- println(" -o FILE output path");
- return 1; }
+ if cli_parse() != 0:
+ return 1
+ g_opt_level = 0
+ ol : ., mut = cli_get("opt-level")
+ if str_len(ol) > 0:
+ g_opt_level = str_int(ol)
+ if g_opt_level > 3:
+ g_opt_level = 3
+ if g_opt_level < 0:
+ g_opt_level = 0
+ if cli_arg_count() < 1:
+ println("usage: corearch [options]")
+ println(" --elf ELF binary (default: dynamic)")
+ println(" --static static linking (embed runtime)")
+ println(" --shared shared library (.so)")
+ println(" --link auto link ~/.core/lib/*.so (default)")
+ println(" --link s1,s2 link specific .so files")
+ println(" -o FILE output path")
+ return 1
- src_path := cli_arg(0);
- fd := syscall3(2, src_path, 0, 0);
- if fd < 0 { print("error: cannot open "); println(src_path); return 1; }
- fsize := syscall3(8, fd, 0, 2);
- syscall3(8, fd, 0, 0);
- if fsize < 36 { syscall3(3, fd, 0, 0); println("error: invalid .ccr file size"); return 1; }
- buf := alloc(fsize + 1);
- nread := syscall3(0, fd, buf, fsize);
- syscall3(3, fd, 0, 0);
- if nread != fsize { println("error: cannot read"); return 1; }
- r := load_ccr(buf, fsize);
- if r != 0 { println("error: invalid .ccr file"); return 1; }
- init_backend_arrays();
+ src_path := cli_arg(0)
+ fd := syscall3(2, src_path, 0, 0)
+ if fd < 0:
+ print("error: cannot open ")
+ println(src_path)
+ return 1
+ fsize := syscall3(8, fd, 0, 2)
+ syscall3(8, fd, 0, 0)
+ if fsize < 36:
+ syscall3(3, fd, 0, 0)
+ println("error: invalid .ccr file size")
+ return 1
+ buf := alloc(fsize + 1)
+ nread := syscall3(0, fd, buf, fsize)
+ syscall3(3, fd, 0, 0)
+ if nread != fsize:
+ println("error: cannot read")
+ return 1
+ r := load_ccr(buf, fsize)
+ if r != 0:
+ println("error: invalid .ccr file")
+ return 1
+ init_backend_arrays()
// 内核完备 Task 1(调度重建移实例):loader 只产语义对象——线性流重建 =
// 实例事务(build_linear_schedule——本文件所在自举 stage 链 = 本函数实际
// 消费方之一:load 后、elf_gen 前必须重建,产物逐字节同移出前)。
- build_linear_schedule();
+ build_linear_schedule()
- emit_so := cli_has("shared");
- link_val := cli_get("link");
- out_path := cli_get("output");
+ emit_so := cli_has("shared")
+ link_val := cli_get("link")
+ out_path := cli_get("output")
// Pure-static output does not link rt.s, so emit the current-g bridge
// stubs directly. Keep this in sync with the legacy corearch entrypoint
// so self-hosted backend stages generate identical binaries.
- g_x86_emit_rt_stubs = 0;
- if str_len(link_val) == 0 && emit_so == 0 { g_x86_emit_rt_stubs = 1; }
+ g_x86_emit_rt_stubs = 0
+ if str_len(link_val) == 0 && emit_so == 0:
+ g_x86_emit_rt_stubs = 1
- if emit_so != 0 {
- if str_len(out_path) == 0 { out_path = "core_lib.so"; }
- g_elf_buf = alloc(16777216);
- sz := elf_gen(g_elf_buf);
- w16(g_elf_buf, 16, 3);
- fd := syscall3(2, out_path, 577, 493);
- if fd < 0 { print("error: cannot write "); println(out_path); return 1; }
- syscall3(1, fd, g_elf_buf, sz);
- syscall3(3, fd, 0, 0);
- print(" -> "); println(out_path);
- return 0; }
+ if emit_so != 0:
+ if str_len(out_path) == 0:
+ out_path = "core_lib.so"
+ g_elf_buf = alloc(16777216)
+ sz := elf_gen(g_elf_buf)
+ w16(g_elf_buf, 16, 3)
+ fd := syscall3(2, out_path, 577, 493)
+ if fd < 0:
+ print("error: cannot write ")
+ println(out_path)
+ return 1
+ syscall3(1, fd, g_elf_buf, sz)
+ syscall3(3, fd, 0, 0)
+ print(" -> ")
+ println(out_path)
+ return 0
- if str_len(out_path) == 0 { out_path = "a.out"; }
- g_elf_buf = alloc(16777216);
+ if str_len(out_path) == 0:
+ out_path = "a.out"
+ g_elf_buf = alloc(16777216)
- is_static := cli_has("static");
+ is_static := cli_has("static")
- if str_len(link_val) > 0 {
- ctx_init();
- if str_eq(link_val, "auto") != 0 {
- sp := get_arg(0);
- sllen := str_len(sp);
- last_sl : ., mut = -1;
- sli : ., mut = 0;
- loop { if sli >= sllen { break; }
- if load8(sp, sli) == 47 { last_sl = sli; }
- sli = sli + 1; }
- if last_sl >= 0 {
- libp := str_sub(sp, 0, last_sl + 1) + "core_rt.so";
- if str_len(read_file(libp)) > 0 { ctx_add_so(libp); } }
- if str_len(read_file("./build/core_rt.so")) > 0 {
- ctx_add_so("./build/core_rt.so"); }
- else if str_len(read_file("./core_rt.so")) > 0 {
- ctx_add_so("./core_rt.so"); }
- if str_len(read_file("~/.core/lib/core_rt.so")) > 0 {
- ctx_add_so("~/.core/lib/core_rt.so"); }
- } else {
- split_links(link_val);
- }
- sz := elf_gen(g_elf_buf);
- cs : ., mut = sz - 176;
- if cs <= 0 { println("error: empty code"); return 1; }
- cd := alloc(cs);
- ci : ., mut = 0; loop { if ci >= cs { break; }
- store8(cd, ci, load8(g_elf_buf, 176+ci)); ci = ci + 1; }
- rpi : ., mut = 0;
- loop { if rpi >= g_x86_rip_patch_count { break; }
- ppos := r64(g_x86_rip_patch_pos, rpi * 8);
- if ppos >= 176 && ppos - 176 + 4 <= cs {
- w32(cd, ppos - 176, 0);
- w8(cd, ppos + 4 - 176, 144); w8(cd, ppos + 5 - 176, 144); w8(cd, ppos + 6 - 176, 144); }
- rpi = rpi + 1; }
+ if str_len(link_val) > 0:
+ ctx_init()
+ if str_eq(link_val, "auto") != 0:
+ sp := get_arg(0)
+ sllen := str_len(sp)
+ last_sl : ., mut = -1
+ sli : ., mut = 0
+ loop:
+ if sli >= sllen:
+ break
+ if load8(sp, sli) == 47:
+ last_sl = sli
+ sli = sli + 1
+ if last_sl >= 0:
+ libp := str_sub(sp, 0, last_sl + 1) + "core_rt.so"
+ if str_len(read_file(libp)) > 0:
+ ctx_add_so(libp)
+ if str_len(read_file("./build/core_rt.so")) > 0:
+ ctx_add_so("./build/core_rt.so")
+ else if str_len(read_file("./core_rt.so")) > 0:
+ ctx_add_so("./core_rt.so")
+ if str_len(read_file("~/.core/lib/core_rt.so")) > 0:
+ ctx_add_so("~/.core/lib/core_rt.so")
+ else:
+ split_links(link_val)
+ sz := elf_gen(g_elf_buf)
+ cs : ., mut = sz - 176
+ if cs <= 0:
+ println("error: empty code")
+ return 1
+ cd := alloc(cs)
+ ci : ., mut = 0
+ loop:
+ if ci >= cs:
+ break
+ store8(cd, ci, load8(g_elf_buf, 176+ci))
+ ci = ci + 1
+ rpi : ., mut = 0
+ loop:
+ if rpi >= g_x86_rip_patch_count:
+ break
+ ppos := r64(g_x86_rip_patch_pos, rpi * 8)
+ if ppos >= 176 && ppos - 176 + 4 <= cs:
+ w32(cd, ppos - 176, 0)
+ w8(cd, ppos + 4 - 176, 144)
+ w8(cd, ppos + 5 - 176, 144)
+ w8(cd, ppos + 6 - 176, 144)
+ rpi = rpi + 1
- if is_static != 0 {
- if g_so_count > 0 {
- ctx_set_user_code(cd, cs);
- sz = ctx_emit_static(g_elf_buf, out_path);
- } else {
- fd := syscall3(2, out_path, 577, 493); // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
- if fd < 0 { print("error: cannot write "); println(out_path); return 1; } syscall3(1, fd, g_elf_buf, sz);
- syscall3(3, fd, 0, 0); }
- } else {
- ri : ., mut = 0; loop { if ri >= g_x86_ext_rel_count { break; }
- fn_name := istr_get(r64(g_x86_ext_rel_name, ri * 8));
- ctx_add_plt(fn_name, 0); ri = ri + 1; }
- ctx_set_user_code(cd, cs);
- sz = ctx_emit_dyn(g_elf_buf, out_path);
- }
- if sz <= 0 { println("error: linking failed"); return 1; }
- } else {
- sz := elf_gen(g_elf_buf);
- fd := syscall3(2, out_path, 577, 493); // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
- if fd < 0 { print("error: cannot write "); println(out_path); return 1; } syscall3(1, fd, g_elf_buf, sz);
- syscall3(3, fd, 0, 0); }
- print(" -> "); println(out_path);
- return 0; }
+ if is_static != 0:
+ if g_so_count > 0:
+ ctx_set_user_code(cd, cs)
+ sz = ctx_emit_static(g_elf_buf, out_path)
+ else:
+ fd := syscall3(2, out_path, 577, 493) // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
+ if fd < 0:
+ print("error: cannot write ")
+ println(out_path)
+ return 1
+ syscall3(1, fd, g_elf_buf, sz)
+ syscall3(3, fd, 0, 0)
+ else:
+ ri : ., mut = 0
+ loop:
+ if ri >= g_x86_ext_rel_count:
+ break
+ fn_name := istr_get(r64(g_x86_ext_rel_name, ri * 8))
+ ctx_add_plt(fn_name, 0)
+ ri = ri + 1
+ ctx_set_user_code(cd, cs)
+ sz = ctx_emit_dyn(g_elf_buf, out_path)
+ if sz <= 0:
+ println("error: linking failed")
+ return 1
+ else:
+ sz := elf_gen(g_elf_buf)
+ fd := syscall3(2, out_path, 577, 493) // 0755:ELF 输出必须可执行(Task 6 修复 0644 怪癖)
+ if fd < 0:
+ print("error: cannot write ")
+ println(out_path)
+ return 1
+ syscall3(1, fd, g_elf_buf, sz)
+ syscall3(3, fd, 0, 0)
+ print(" -> ")
+ println(out_path)
+ return 0
-fn main() -> int { return corearch_main(); }
+fn main() -> int:
+ return corearch_main()
diff --git a/tests/bootstrap/test_apx_tag.py b/tests/bootstrap/test_apx_tag.py
index 83fcae1d..7ccbfcf1 100644
--- a/tests/bootstrap/test_apx_tag.py
+++ b/tests/bootstrap/test_apx_tag.py
@@ -55,12 +55,11 @@ def run_main(mod, *args):
def test_apx_parses_and_annotates():
src = '''
-fn main() -> int {
- x : int, apx = 42;
- y : int = 84;
- z : int, apx, mut = 126;
- return x + y + z;
-}
+fn main() -> int:
+ x : int, apx = 42
+ y : int = 84
+ z : int, apx, mut = 126
+ return x + y + z
'''
mod = compile_src(src)
n = count_approx(mod)
@@ -73,11 +72,10 @@ def test_apx_parses_and_annotates():
def test_plain_has_no_approx():
src = '''
-fn main() -> int {
- x : int = 42;
- y : int = 84;
- return x + y;
-}
+fn main() -> int:
+ x : int = 42
+ y : int = 84
+ return x + y
'''
mod = compile_src(src)
n = count_approx(mod)
@@ -91,10 +89,9 @@ def test_plain_has_no_approx():
def test_batch_apx():
# 批量声明:apx 标签作用于所有名字(每个名字一条注解)
src = '''
-fn main() -> int {
- a, b : int, apx = 1, 2;
- return a + b;
-}
+fn main() -> int:
+ a, b : int, apx = 1, 2
+ return a + b
'''
mod = compile_src(src)
n = count_approx(mod)
@@ -112,10 +109,9 @@ def test_batch_apx():
def test_unknown_tag_rejected():
src = '''
-fn main() -> int {
- x : int, bogus_tag = 42;
- return x;
-}
+fn main() -> int:
+ x : int, bogus_tag = 42
+ return x
'''
try:
compile_src(src)
@@ -130,18 +126,16 @@ def test_unknown_tag_rejected():
def test_no_semantic_change():
plain = '''
-fn main() -> int {
- x : int = 42;
- y : int = 84;
- return x + y;
-}
+fn main() -> int:
+ x : int = 42
+ y : int = 84
+ return x + y
'''
apx = '''
-fn main() -> int {
- x : int, apx = 42;
- y : int, apx = 84;
- return x + y;
-}
+fn main() -> int:
+ x : int, apx = 42
+ y : int, apx = 84
+ return x + y
'''
rp = run_main(compile_src(plain))
ra = run_main(compile_src(apx))
diff --git a/tests/bootstrap/test_borrow.py b/tests/bootstrap/test_borrow.py
index 42e0cde6..f56cd722 100644
--- a/tests/bootstrap/test_borrow.py
+++ b/tests/bootstrap/test_borrow.py
@@ -42,40 +42,36 @@ def test(src, desc, expect_errors):
# Immutable borrow should prevent use of original
test('''
-fn main() -> int {
- x := 10;
- r := &x;
- return x;
-}
+fn main() -> int:
+ x := 10
+ r := &x
+ return x
''', 'immutable borrow then use original', True)
# Mutable borrow should prevent use of original
test('''
-fn main() -> int {
- x : ., mut = 10;
- rm := &mut x;
- return x;
-}
+fn main() -> int:
+ x : ., mut = 10
+ rm := &mut x
+ return x
''', 'mut borrow then use original', True)
# Multiple immutable borrows are allowed
test('''
-fn main() -> int {
- x := 10;
- r1 := &x;
- r2 := &x;
- return *r1 + *r2;
-}
+fn main() -> int:
+ x := 10
+ r1 := &x
+ r2 := &x
+ return *r1 + *r2
''', 'multiple immutable borrows allowed', False)
# Immutable borrow then mutable borrow should fail
test('''
-fn main() -> int {
- x : ., mut = 10;
- r1 := &x;
- r2 := &mut x;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = 10
+ r1 := &x
+ r2 := &mut x
+ return 0
''', 'immutable then mutable borrow forbidden', True)
print(f"\n{passed}/{passed + failed} passed", end="")
diff --git a/tests/bootstrap/test_dex_arith.py b/tests/bootstrap/test_dex_arith.py
index 51380302..19341471 100644
--- a/tests/bootstrap/test_dex_arith.py
+++ b/tests/bootstrap/test_dex_arith.py
@@ -54,91 +54,92 @@ def run_test(name, src, expected):
def main():
results = [
run_test('Exact Add 0.1+0.2==0.3', '''
-fn main() -> int {
- a := 0.1 + 0.2;
- if a == 0.3 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := 0.1 + 0.2
+ if a == 0.3:
+ return 1
+ return 0
''', 1),
run_test('Exact Add 3.14+2.86==6.0', '''
-fn main() -> int {
- a := 3.14 + 2.86;
- if a == 6.0 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := 3.14 + 2.86
+ if a == 6.0:
+ return 1
+ return 0
''', 1),
run_test('Exact Div 1/10==0.1', '''
-fn main() -> int {
- a := 1.0 / 10.0;
- if a == 0.1 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := 1.0 / 10.0
+ if a == 0.1:
+ return 1
+ return 0
''', 1),
run_test('Exact Mul 1.5*2.0==3.0', '''
-fn main() -> int {
- a := 1.5 * 2.0;
- if a == 3.0 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := 1.5 * 2.0
+ if a == 3.0:
+ return 1
+ return 0
''', 1),
run_test('Exact Sub Neg 0.3-1.0==-0.7', '''
-fn main() -> int {
- a := 0.3 - 1.0;
- if a == -0.7 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := 0.3 - 1.0
+ if a == -0.7:
+ return 1
+ return 0
''', 1),
run_test('Int Participates 1+0.5==1.5', '''
-fn main() -> int {
- a := 1 + 0.5;
- if a == 1.5 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := 1 + 0.5
+ if a == 1.5:
+ return 1
+ return 0
''', 1),
run_test('Dex Var Add', '''
-fn main() -> int {
- x : dex = 0.1;
- y : dex = 0.2;
- if x + y == 0.3 { return 1; }
- return 0;
-}
+fn main() -> int:
+ x : dex = 0.1
+ y : dex = 0.2
+ if x + y == 0.3:
+ return 1
+ return 0
''', 1),
run_test('Fn Dex Boundary', '''
-fn add2(a: dex, b: dex) -> dex { return a + b; }
-fn main() -> int {
- r := add2(0.1, 0.2);
- if r == 0.3 { return 1; }
- return 0;
-}
+fn add2(a: dex, b: dex) -> dex:
+ return a + b
+fn main() -> int:
+ r := add2(0.1, 0.2)
+ if r == 0.3:
+ return 1
+ return 0
''', 1),
# 模运算截断恒等式(a - trunc(a/b)·b),含负数
run_test('Mod Trunc 7.0%2.5==2.0', '''
-fn main() -> int {
- a := 7.0 % 2.5;
- if a == 2.0 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := 7.0 % 2.5
+ if a == 2.0:
+ return 1
+ return 0
''', 1),
run_test('Mod Trunc -7.0%2.5==-2.0', '''
-fn main() -> int {
- a := -7.0 % 2.5;
- if a == -2.0 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := -7.0 % 2.5
+ if a == -2.0:
+ return 1
+ return 0
''', 1),
run_test('Mod Trunc 1.0%0.3==0.1', '''
-fn main() -> int {
- a := 1.0 % 0.3;
- if a == 0.1 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := 1.0 % 0.3
+ if a == 0.1:
+ return 1
+ return 0
''', 1),
run_test('Mod Trunc -1.0%0.3==-0.1', '''
-fn main() -> int {
- a := -1.0 % 0.3;
- if a == -0.1 { return 1; }
- return 0;
-}
+fn main() -> int:
+ a := -1.0 % 0.3
+ if a == -0.1:
+ return 1
+ return 0
''', 1),
]
# 打印格式(定点 → 十进制,去尾零)——直接断言格式函数(bootstrap 无 stdlib,
diff --git a/tests/bootstrap/test_dex_type.py b/tests/bootstrap/test_dex_type.py
index 01836b67..912836c9 100644
--- a/tests/bootstrap/test_dex_type.py
+++ b/tests/bootstrap/test_dex_type.py
@@ -53,10 +53,7 @@ def run_test(name, src, expected):
def expect_float_rejected():
"""float 类型名已移除(数值迁移 Task 5)——使用 float 必须报类型错误。"""
src = (
- "fn main() -> dex {\n"
- " x : float = 3.14;\n"
- " return x;\n"
- "}\n"
+ "fn main() -> dex:\n x : float = 3.14\n return x\n"
)
lex = Lexer(src)
ast = Parser(lex.tokenize()).parse_compilation_unit()
@@ -76,15 +73,13 @@ def expect_float_rejected():
def main():
results = [
run_test('Dex Declare + Literal', '''
-fn main() -> dex {
- x : dex = 3.14;
- return x;
-}
+fn main() -> dex:
+ x : dex = 3.14
+ return x
''', 3.14),
run_test('Dex Arithmetic', '''
-fn main() -> dex {
- return 1.5 + 1.25;
-}
+fn main() -> dex:
+ return 1.5 + 1.25
''', 2.75),
expect_float_rejected(),
]
diff --git a/tests/bootstrap/test_generics.py b/tests/bootstrap/test_generics.py
index 14809c7d..0da6232b 100644
--- a/tests/bootstrap/test_generics.py
+++ b/tests/bootstrap/test_generics.py
@@ -46,8 +46,11 @@ def run_test(name, src, expected):
# Generic function
if run_test('Generic Identity', '''
-fn identity[T](val: T) -> T { return val; }
-fn main() -> int { x := identity(42); return x; }
+fn identity[T](val: T) -> T:
+ return val
+fn main() -> int:
+ x := identity(42)
+ return x
''', 42):
passed += 1
else:
@@ -55,12 +58,13 @@ def run_test(name, src, expected):
# Generic struct
if run_test('Generic Struct Box', '''
-struct Box[T] { value: T }
-fn get_value[T](b: Box[T]) -> T { return b.value; }
-fn main() -> int {
- boxed := Box { value = 100 };
- return get_value(boxed);
-}
+struct Box[T]:
+ value: T
+fn get_value[T](b: Box[T]) -> T:
+ return b.value
+fn main() -> int:
+ boxed := Box { value = 100 }
+ return get_value(boxed)
''', 100):
passed += 1
else:
@@ -70,11 +74,12 @@ def run_test(name, src, expected):
# This exercises PathType handling in the type checker; scalar-only code must
# not assume every type has BaseType.name.
if run_test('Generic Recursive Function', '''
-fn fact[T](n: T) -> T {
- if n <= 1 { return 1; }
- return n * fact(n - 1);
-}
-fn main() -> int { return fact(5); }
+fn fact[T](n: T) -> T:
+ if n <= 1:
+ return 1
+ return n * fact(n - 1)
+fn main() -> int:
+ return fact(5)
''', 120):
passed += 1
else:
diff --git a/tests/bootstrap/test_modules.py b/tests/bootstrap/test_modules.py
index 6dbf81b6..323c4773 100644
--- a/tests/bootstrap/test_modules.py
+++ b/tests/bootstrap/test_modules.py
@@ -22,9 +22,9 @@ def main() -> int:
helper = os.path.join(directory, "helper.cr")
main_path = os.path.join(directory, "main.cr")
with open(helper, "w", encoding="utf-8") as file:
- file.write("fn value() -> int { return 42; }\n")
+ file.write("fn value() -> int:\n return 42\n")
with open(main_path, "w", encoding="utf-8") as file:
- file.write("import helper : h; fn main() -> int { return h.value(); }\n")
+ file.write("import helper : h\nfn main() -> int:\n return h.value()\n")
with open(main_path, encoding="utf-8") as file:
source = file.read()
diff --git a/tests/bootstrap/test_pipeline.py b/tests/bootstrap/test_pipeline.py
index 6ec728ae..04d364de 100644
--- a/tests/bootstrap/test_pipeline.py
+++ b/tests/bootstrap/test_pipeline.py
@@ -87,239 +87,300 @@ def test_raw(name, src, expected):
# ── Arithmetic & Function Calls ──
test('Arithmetic & Call', '''
-fn add(a: int, b: int) -> int { return a + b; }
-fn main() -> int { return add(3, 4); }
+fn add(a: int, b: int) -> int:
+ return a + b
+fn main() -> int:
+ return add(3, 4)
''', 7)
test('old is an identifier', '''
-fn main() -> int {
- old := 40;
- return old + 2;
-}
+fn main() -> int:
+ old := 40
+ return old + 2
+''', 42)
+
+test('V4 layout and contracts have zero runtime footprint', '''
+fn bounded(x: int) -> int:
+ #check(x >= 0)
+ #ensure(result >= x)
+ return x + 1
+
+fn main() -> int:
+ value := bounded(41)
+ if value == 42:
+ return value
+ else:
+ return 0
+''', 42)
+
+test('V4 layout struct and impl', '''
+struct Point:
+ x: int
+ y: int
+
+impl Point:
+ fn sum(&self) -> int:
+ return self.x + self.y
+
+fn main() -> int:
+ p := Point { x = 20, y = 22 }
+ return p.sum()
+''', 42)
+
+test('V4 layout enum and multiline match arm', '''
+enum Mode:
+ | Server
+ | Client
+
+fn main() -> int:
+ mode := Server
+ value := match mode:
+ | Server =>
+ base := 40
+ base + 2
+ | Client => 0
+ return value
+''', 42)
+
+test('V4 lowercase none', '''
+fn main() -> int:
+ value := none
+ return match value:
+ | none => 42
+ | _ => 0
''', 42)
# ── Loop & Break ──
test('Loop & Break', '''
-fn sum(n: int) -> int {
- i : ., mut = 0;
- s : ., mut = 0;
- loop {
- if i >= n { break; }
- s = s + i;
- i = i + 1;
- }
- return s;
-}
-fn main() -> int { return sum(5); }
+fn sum(n: int) -> int:
+ i : ., mut = 0
+ s : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ s = s + i
+ i = i + 1
+ return s
+fn main() -> int:
+ return sum(5)
''', 10)
# ── If / Else ──
test('If/Else', '''
-fn max(a: int, b: int) -> int {
- if a > b { return a; } else { return b; }
-}
-fn main() -> int { return max(3, 7); }
+fn max(a: int, b: int) -> int:
+ if a > b:
+ return a
+ else:
+ return b
+fn main() -> int:
+ return max(3, 7)
''', 7)
# ── Struct ──
test('Struct Field Access', '''
-struct Point { x: int, y: int }
-fn main() -> int {
- p := Point { x = 10, y = 20 };
- return p.x + p.y;
-}
+struct Point:
+ x: int, y: int
+fn main() -> int:
+ p := Point { x = 10, y = 20 }
+ return p.x + p.y
''', 30)
test('Method Call', '''
-struct Vec { x: int, y: int }
-impl Vec {
- fn norm(self: Vec) -> int { return self.x + self.y; }
-}
-fn main() -> int {
- v := Vec { x = 1, y = 2 };
- return v.norm();
-}
+struct Vec:
+ x: int, y: int
+impl Vec:
+ fn norm(self: Vec) -> int:
+ return self.x + self.y
+fn main() -> int:
+ v := Vec { x = 1, y = 2 }
+ return v.norm()
''', 3)
test('Nested Structs', '''
-struct Inner { a: int }
-struct Outer { inner: Inner, b: int }
-fn main() -> int {
- inner := Inner { a = 5 };
- outer := Outer { inner = inner, b = 10 };
- return outer.inner.a + outer.b;
-}
+struct Inner:
+ a: int
+struct Outer:
+ inner: Inner, b: int
+fn main() -> int:
+ inner := Inner { a = 5 }
+ outer := Outer { inner = inner, b = 10 }
+ return outer.inner.a + outer.b
''', 15)
# ── Comparisons & Logic ──
test('Comparisons', '''
-fn main() -> int {
- if 2 < 3 && 4 == 4 { return 1; }
- return 0;
-}
+fn main() -> int:
+ if 2 < 3 && 4 == 4:
+ return 1
+ return 0
''', 1)
# ── Enum & Match ──
test('Enum Match Unwrap', '''
-enum Option { Some(int), None }
-fn main() -> int {
- x := Some(42);
- match x {
+enum Option:
+ Some(int), none
+fn main() -> int:
+ x := Some(42)
+ match x:
Some(val) => val,
- None => 0,
- }
-}
+ none => 0,
''', 42)
test('Enum Multi Args', '''
-enum Color { Red, Green(int), Blue(int, int) }
-fn main() -> int {
- c := Blue(1, 2);
- match c {
+enum Color:
+ Red, Green(int), Blue(int, int)
+fn main() -> int:
+ c := Blue(1, 2)
+ match c:
Red => 0,
Green(n) => n,
Blue(a, b) => a + b,
- }
-}
''', 3)
# ── Dex ──
test('Dex Add', '''
-fn main() -> dex {
- a := 3.14;
- b := 2.86;
- return a + b;
-}
+fn main() -> dex:
+ a := 3.14
+ b := 2.86
+ return a + b
''', 6.0)
test('Int Dex Mix', '''
-fn main() -> dex {
- a := 2;
- b := 3.5;
- return a + b;
-}
+fn main() -> dex:
+ a := 2
+ b := 3.5
+ return a + b
''', 5.5)
# ── String ──
test_raw('String Concat', '''
-fn main() -> string {
- a := "Hello, ";
- b := "World!";
- return a + b;
-}
+fn main() -> string:
+ a := "Hello, "
+ b := "World!"
+ return a + b
''', "Hello, World!")
# ── Array ──
test('Array Read', '''
-fn main() -> int {
- arr := [10, 20, 30];
- return arr[0] + arr[1] + arr[2];
-}
+fn main() -> int:
+ arr := [10, 20, 30]
+ return arr[0] + arr[1] + arr[2]
''', 60)
test('Array Mutate', '''
-fn main() -> int {
- arr : ., mut = [10, 20, 30];
- arr[1] = 50;
- return arr[0] + arr[1] + arr[2];
-}
+fn main() -> int:
+ arr : ., mut = [10, 20, 30]
+ arr[1] = 50
+ return arr[0] + arr[1] + arr[2]
''', 90)
# ── For Loop ──
test('For Range Sum', '''
-fn main() -> int {
- sum : ., mut = 0;
- for i in 0..10 { sum = sum + i; }
- return sum;
-}
+fn main() -> int:
+ sum : ., mut = 0
+ for i in 0..10:
+ sum = sum + i
+ return sum
''', 45)
test('For Array Iter', '''
-fn main() -> int {
- arr := [10, 20, 30];
- s : ., mut = 0;
- for val in arr { s = s + val; }
- return s;
-}
+fn main() -> int:
+ arr := [10, 20, 30]
+ s : ., mut = 0
+ for val in arr:
+ s = s + val
+ return s
''', 60)
# ── References ──
test('Ref Deref', '''
-fn main() -> int {
- x := 42;
- r := &x;
- return *r;
-}
+fn main() -> int:
+ x := 42
+ r := &x
+ return *r
''', 42)
test('Mut Ref Write', '''
-fn main() -> int {
- x : ., mut = 10;
- r := &mut x;
- *r = 20;
- return *r;
-}
+fn main() -> int:
+ x : ., mut = 10
+ r := &mut x
+ *r = 20
+ return *r
''', 20)
# ── Enum Match (via desugar) ──
test('Enum Match Opt', '''
-fn main() -> int {
- opt := Some(99);
- match opt {
+fn main() -> int:
+ opt := Some(99)
+ match opt:
Some(val) => val,
- None => 0,
- }
-}
+ none => 0,
''', 99)
+# ── V4 relational type expression ──
+test('V4 typeof(expr)', '''
+fn main() -> int:
+ source := 40
+ copy : typeof(source) = source
+ return copy + 2
+''', 42)
+
# ── If without else (regression: two-variable comparison) ──
test('If No Else (gt, true)', '''
-fn main() -> int {
- a := 10; b := 3;
- if a > b { return 100; }
- return 200;
-}
+fn main() -> int:
+ a := 10
+ b := 3
+ if a > b:
+ return 100
+ return 200
''', 100)
test('If No Else (gt, false)', '''
-fn main() -> int {
- a := 3; b := 10;
- if a > b { return 100; }
- return 200;
-}
+fn main() -> int:
+ a := 3
+ b := 10
+ if a > b:
+ return 100
+ return 200
''', 200)
test('If No Else (eq, true)', '''
-fn main() -> int {
- a := 5; b := 5;
- if a == b { return 99; }
- return 88;
-}
+fn main() -> int:
+ a := 5
+ b := 5
+ if a == b:
+ return 99
+ return 88
''', 99)
test('If No Else (ne, false)', '''
-fn main() -> int {
- a := 5; b := 5;
- if a != b { return 99; }
- return 88;
-}
+fn main() -> int:
+ a := 5
+ b := 5
+ if a != b:
+ return 99
+ return 88
''', 88)
# ── 整数除/模向零截断(BC2/F10:对照 ELF idiv 与 CompCert Z.quot/Z.rem)──
test('Div trunc toward zero (-7/3)', '''
-fn main() -> int { return -7 / 3; }
+fn main() -> int:
+ return -7 / 3
''', -2)
test('Div trunc toward zero (7/-3)', '''
-fn main() -> int { return 7 / -3; }
+fn main() -> int:
+ return 7 / -3
''', -2)
test('Mod sign follows dividend (-7%3)', '''
-fn main() -> int { return -7 % 3; }
+fn main() -> int:
+ return -7 % 3
''', -1)
test('Mod sign follows dividend (7%-3)', '''
-fn main() -> int { return 7 % -3; }
+fn main() -> int:
+ return 7 % -3
''', 1)
# ── Lexer integer literal forms and wide apx literals ──
diff --git a/tests/fixtures/dex_ffi_test.cr b/tests/fixtures/dex_ffi_test.cr
index 0869034a..88715aae 100644
--- a/tests/fixtures/dex_ffi_test.cr
+++ b/tests/fixtures/dex_ffi_test.cr
@@ -1,7 +1,6 @@
import io
-extern fn dex_ffi_bits_check(d: dex) -> int;
+extern fn dex_ffi_bits_check(d: dex) -> int
-fn main() -> int {
- return dex_ffi_bits_check(3.14);
-}
+fn main() -> int:
+ return dex_ffi_bits_check(3.14)
diff --git a/tests/fixtures/so_index/README.md b/tests/fixtures/so_index/README.md
index fd6263ed..f4dc880e 100644
--- a/tests/fixtures/so_index/README.md
+++ b/tests/fixtures/so_index/README.md
@@ -1,6 +1,6 @@
# `.so` 扩展索引夹具(TODO #2026-09-16-20/#2026-09-16-21/#2026-09-17-1/#2026-09-17-2;第 4 批 T0)
-**为什么夹具必须入仓**(本批立的规矩):判据要跑「`HOME` 含索引 vs 不含索引」两态对拍;
+**夹具入仓的缘由**(本批确立的规矩):判据要跑「`HOME` 含索引 vs 不含索引」两态对拍;
若索引由**各机自备**(真实路径 `$HOME/.core/lib/<模块>/index`),则**判据自己就不可复现**——
正是 #82 要消灭的形态。⇒ 两态所需的索引一律用**本目录的夹具**(放进临时 `HOME`)。
@@ -10,11 +10,11 @@
|---|---|---|
| `io.index` | 判据 J1(主判据·未引用面) | 含两条 `io.cr` **未声明**的名字(`print_int`/`println_int`)⇒ 现状令 canary 语料 **+28B** |
| `io_benign.index` | 判据 J2(良性档) | 全部名字**已在** `io.cr` 声明 ⇒ 现状仍扰动产物(覆盖 + 索引平移) |
-| `use_ext.cr` | 判据 J3(**关键面**) | 调用**索引独有**名字 ⇒ 无索引必须**响亮失败**(`error[N06]`),有索引 rc=0 |
+| `use_ext.cr` | 判据 J3(**关键面**) | 调用**索引独有**名字 ⇒ 无索引必须**显式失败**(`error[N06]`),有索引 rc=0 |
## `N` 行大索引(判据 J9 / TODO #2026-09-17-1)
-不committed 成大文件:由探针**确定性生成**(同一生成器入仓 = 可复现)。生成规则:
+大索引文件不入库:由探针**确定性生成**(同一生成器入仓 = 可复现)。生成规则:
```
首行 `print: string, variadic, auto_str` + 随后 N 行 `ghost{i}: int`(i = 0..N-1)
diff --git a/tests/fixtures/so_index/use_ext.cr b/tests/fixtures/so_index/use_ext.cr
index 391c7d2a..a2c3a161 100644
--- a/tests/fixtures/so_index/use_ext.cr
+++ b/tests/fixtures/so_index/use_ext.cr
@@ -7,7 +7,6 @@
// 的判据对象——那条由 io.index 档下的 generics_test 承担(判据 J1/J2)。
import io
-fn main() -> int {
- print_int(42);
- return 0;
-}
+fn main() -> int:
+ print_int(42)
+ return 0
diff --git a/tests/harness/test_criteria_mutations.py b/tests/harness/test_criteria_mutations.py
index 1530fea5..fe1d3543 100644
--- a/tests/harness/test_criteria_mutations.py
+++ b/tests/harness/test_criteria_mutations.py
@@ -165,11 +165,18 @@ def mut_self_item2():
"""M7 **真跑腿**(`COREC_MUT_SELF=1`;默认关):在 /tmp 副本上把条目 2 的分派块**失效化** ⇒ 重建
⇒ 六位位码探针须回 **24**(= 修复前读数;2026-09-18 复核重跑实测);同时**原树正控**同探针须为 **30**。
成本 ≈ 1 次重建(~1 min)+ 2 次探针编译。用途:把「突变能命中目标」从文档承诺变成**机检**。"""
- probe = ("fn b2i(x: bool) -> int { if x { return 1; } return 0; }\n"
- "fn main() -> int {\n"
- " n : int? = None;\n m : int? = None;\n a : int? = 7;\n b : int? = 7;\n"
- " return b2i(n == Some(7)) + b2i(n == None) * 2 + b2i(n == m) * 4 + b2i(a == b) * 8"
- " + b2i(a == 7) * 16 + b2i(n == 7) * 32;\n}\n")
+ # ⚠ v4 迁移:载荷由 v3 形(`{ … ; }`)改为 v4 形(`:` + layout 缩进 + 无 `;`),
+ # 且可选字面量 `None` → **`none`**(v4 拼音面;`None` 在 v4 是 `error[N01] Undefined name`)。
+ # 语义(六位位码)不变:未突变树 = 30、突变树 = 24(本批 v4 形载荷实核 30)。
+ probe = ("fn b2i(x: bool) -> int:\n"
+ " if x:\n"
+ " return 1\n"
+ " return 0\n"
+ "\n"
+ "fn main() -> int:\n"
+ " n : int? = none\n m : int? = none\n a : int? = 7\n b : int? = 7\n"
+ " return b2i(n == Some(7)) + b2i(n == none) * 2 + b2i(n == m) * 4 + b2i(a == b) * 8"
+ " + b2i(a == 7) * 16 + b2i(n == 7) * 32\n")
tmp = Path(tempfile.mkdtemp(prefix="mutself_"))
try:
for item in ("src", "tools", "tests", "bootstrap"):
@@ -182,10 +189,11 @@ def mut_self_item2():
shutil.copy2(src, tmp / item)
p = tmp / "src" / "compiler" / "ir_gen.cr"
s = p.read_text()
- old = ("if (op == OP_EQ || op == OP_NE) && g_optrep_on != 0 {\n"
- " lo := opt_cmp_optish(left, left_var);")
- new = ("if (op == OP_EQ || op == OP_NE) && g_optrep_on != 0 && g_optrep_on == 999 {\n"
- " lo := opt_cmp_optish(left, left_var);")
+ # v4 形锚点(与 main() 的 M7 同源同处):去 `{`、去 `;`。
+ old = ("if (op == OP_EQ || op == OP_NE) && g_optrep_on != 0:\n"
+ " lo := opt_cmp_optish(left, left_var)")
+ new = ("if (op == OP_EQ || op == OP_NE) && g_optrep_on != 0 && g_optrep_on == 999:\n"
+ " lo := opt_cmp_optish(left, left_var)")
if s.count(old) != 1:
return False, "突变锚点漂移(副本内未唯一命中)"
p.write_text(s.replace(old, new))
@@ -386,8 +394,10 @@ def _once(path, needle):
return txt.count(needle)
# M7:条目 2(可选 == 表示透明)——突变 = 分派块失效化 ⇒ 位码回 **24**(2026-09-18 复核重跑实测)
- n1 = _once("src/compiler/ir_gen.cr", "if (op == OP_EQ || op == OP_NE) && g_optrep_on != 0 {")
- n2 = _once("src/compiler/ir_gen.cr", "lo := opt_cmp_optish(left, left_var);")
+ # ⚠ v4 迁移(layout 缩进):锚点由 v3 形 `… != 0 {` / `…left_var);` 改为 v4 形 `… != 0:`
+ # / `…left_var)`(**去 `{`、去 `;`**,语义面同一处代码;见 mut_self_item2 同源锚点)。
+ n1 = _once("src/compiler/ir_gen.cr", "if (op == OP_EQ || op == OP_NE) && g_optrep_on != 0:")
+ n2 = _once("src/compiler/ir_gen.cr", "lo := opt_cmp_optish(left, left_var)")
opt_eq = (BASE / "tests/selfhost/test_opt_eq.py").read_text()
pre = "BITCODE_PRE = 24" in opt_eq
post = "BITCODE_POST = 30" in opt_eq
@@ -397,9 +407,10 @@ def _once(path, needle):
f"锚点×2={n1}/{n2}(各自须 =1)· BITCODE_PRE/POST 24/30={pre}/{post} · run.sh 注 24/30={rs}"))
# M8:条目 3(extern 可选 ⇒ P24)——突变 = 撤 parser 的 extern_opt 检查 ⇒ 4 拒收例回 check=0
- n1 = _once("src/compiler/parser.cr", "extern_opt : ., mut = 0;")
- n2 = _once("src/compiler/parser.cr", "if extern_opt != 0 {")
- n3 = _once("src/compiler/ast.cr", "EC_P_EXTERN_OPTIONAL : int = 1024;")
+ # ⚠ v4 迁移:锚点去 `{` / 去 `;`(同处代码,语义不变)。
+ n1 = _once("src/compiler/parser.cr", "extern_opt : ., mut = 0")
+ n2 = _once("src/compiler/parser.cr", "if extern_opt != 0:")
+ n3 = _once("src/compiler/ast.cr", "EC_P_EXTERN_OPTIONAL : int = 1024")
ext = (BASE / "tests/selfhost/test_extern_opt.py").read_text()
batch8.append(("M8/批8-条目3 extern 可选 P24", n1 == 1 and n2 == 1 and n3 == 1 and "error[P24]" in ext,
f"锚点={n1}/{n2} · 码 1024={n3} · 套件期望 error[P24]={'error[P24]' in ext}"))
@@ -407,19 +418,22 @@ def _once(path, needle):
# M9:条目 4(顶层兜底 ⇒ P25)——突变 = 兜底退回裸 advance_tok() ⇒ 5 拒收例回 check=0
# 锚点收紧(2026-09-18):只用单行 `if tok_k(cur_tok()) != T_EOF {` 会被**无关新代码**撞形
# (插值展开批的 `interp_parse_holes` 曾加过同形行 ⇒ 本判据在 CI 假红)。改为**顶层兜底特有的两行合体**。
- n1 = _once("src/compiler/parser.cr", "if tok_k(cur_tok()) != T_EOF {\n check_error(EC_P_TOPLEVEL_TOKEN,")
+ # ⚠ v4 迁移:兜底锚去 `{`(`!= T_EOF:`)、`is_fileid` 锚去 `;`、码锚去 `;`;
+ # 「两行合体」的收紧口径**原样保留**(仍靠特有后继行区分同形行)。
+ n1 = _once("src/compiler/parser.cr", "if tok_k(cur_tok()) != T_EOF:\n check_error(EC_P_TOPLEVEL_TOKEN,")
n2 = _once("src/compiler/parser.cr", "EC_P_TOPLEVEL_TOKEN")
- n3 = _once("src/compiler/parser.cr", "is_fileid := tk == T_FILEID;")
- n4 = _once("src/compiler/ast.cr", "EC_P_TOPLEVEL_TOKEN : int = 1025;")
+ n3 = _once("src/compiler/parser.cr", "is_fileid := tk == T_FILEID")
+ n4 = _once("src/compiler/ast.cr", "EC_P_TOPLEVEL_TOKEN : int = 1025")
tlr = (BASE / "tests/selfhost/test_toplevel_reject.py").read_text()
batch8.append(("M9/批8-条目4 顶层兜底 P25", n1 == 1 and n2 >= 1 and n3 == 1 and n4 == 1
and "error[P25]" in tlr,
f"兜底锚={n1} · 码锚={n2} · import 整句消费锚={n3} · 码 1025={n4} · 套件 error[P25]={'error[P25]' in tlr}"))
# M10:条目 5(apx 白名单 ⇒ P26)——突变 = 撤白名单检查 ⇒ 5 拒收例回 check=0
- n1 = _once("src/compiler/parser.cr", "apx_ok : ., mut = 0;")
- n2 = _once("src/compiler/parser.cr", "if apx_ok == 0 {")
- n3 = _once("src/compiler/ast.cr", "EC_P_APX_TAG : int = 1026;")
+ # ⚠ v4 迁移:锚点去 `{` / 去 `;`(同处代码,语义不变)。
+ n1 = _once("src/compiler/parser.cr", "apx_ok : ., mut = 0")
+ n2 = _once("src/compiler/parser.cr", "if apx_ok == 0:")
+ n3 = _once("src/compiler/ast.cr", "EC_P_APX_TAG : int = 1026")
ats = (BASE / "tests/selfhost/test_apx_tag_scope.py").read_text()
batch8.append(("M10/批8-条目5 apx 白名单 P26", n1 == 1 and n2 == 1 and n3 == 1 and "error[P26]" in ats,
f"锚点={n1}/{n2} · 码 1026={n3} · 套件 error[P26]={'error[P26]' in ats}"))
diff --git a/tests/harness/test_lsp_builtin_table.py b/tests/harness/test_lsp_builtin_table.py
index 3c8548c0..9a3ed13e 100644
--- a/tests/harness/test_lsp_builtin_table.py
+++ b/tests/harness/test_lsp_builtin_table.py
@@ -62,31 +62,45 @@ def annotation_parsers(text):
return {m.group(1) for l in text.split("\n") for m in [ANN_FN.match(l)] if m}
+def top_level_body(lines, start):
+ """v4 体边界:`start` 行之后的**首个顶格行**(非空且首字符非空白)的行号。
+
+ v3 形以顶格 `}` 收束函数体;v4 形改 layout 缩进、函数**无闭括号** ⇒ 等价边界 =
+ 「下一个顶格行」(下一条 `fn` / 顶格注释 / 全局常量皆顶格)。边界与 v3 的 `}` 行同为**排他**。
+ """
+ return next((j for j in range(start + 1, len(lines))
+ if lines[j] and not lines[j][0].isspace()), None)
+
+
def annotation_names(text, fn_name):
"""某注解解析器函数体内被期望的注解名(`str_eq(, "X")` 的 X 集合)。
- 体边界 = `fn (` 行 → 之后首个顶格 `}` 行。
+ 体边界(v4 = layout 缩进)= `fn (` 行 → 之后首个顶格行(v3 的顶格 `}` 行等价物)。
"""
lines = text.split("\n")
start = next((i for i, l in enumerate(lines) if l.startswith("fn %s(" % fn_name)), None)
if start is None:
return None
- end = next((j for j in range(start + 1, len(lines)) if lines[j] == "}"), None)
+ end = top_level_body(lines, start)
if end is None:
return None
- return {m.group(2) for l in lines[start:end + 1] for m in STR_EQ_ANY.finditer(l)}
+ return {m.group(2) for l in lines[start + 1:end] for m in STR_EQ_ANY.finditer(l)}
def lsp_at_names(text):
- """LSP 侧:`analysis_at_items()` 体内的 `analysis_citem("X", 3)` 名字集合。"""
+ """LSP 侧:`analysis_at_items()` 体内的 `analysis_citem("X", 3)` 名字集合。
+
+ 体边界(v4 = layout 缩进)= `fn analysis_at_items(` 行 → 之后首个顶格行
+ (v3 的 `return out;` 行等价物——两形皆收束到函数体末尾为止)。
+ """
lines = text.split("\n")
start = next((i for i, l in enumerate(lines) if l.startswith("fn analysis_at_items(")), None)
if start is None:
return None
- end = next((j for j in range(start + 1, len(lines)) if lines[j].strip() == "return out;"), None)
+ end = top_level_body(lines, start)
if end is None:
return None
- return {m.group(1) for l in lines[start:end + 1] for m in CITEM.finditer(l)}
+ return {m.group(1) for l in lines[start + 1:end] for m in CITEM.finditer(l)}
def truth_set(ck_text, pp_text):
diff --git a/tests/hit/smoke_add.cr b/tests/hit/smoke_add.cr
index ca849ed6..c8e85e47 100644
--- a/tests/hit/smoke_add.cr
+++ b/tests/hit/smoke_add.cr
@@ -1,7 +1,6 @@
// === tests/hit/smoke_add.cr ===
// HIT M1 冒烟:减法(sub 事件直通;const 走常量池 load)。期望 exit 2(7-5)。
-fn main() -> int {
- a := 7;
- b := 5;
- return a - b;
-}
+fn main() -> int:
+ a := 7
+ b := 5
+ return a - b
diff --git a/tests/hit/smoke_mem.cr b/tests/hit/smoke_mem.cr
index 587d486b..269f8b48 100644
--- a/tests/hit/smoke_mem.cr
+++ b/tests/hit/smoke_mem.cr
@@ -6,10 +6,9 @@
// 无位与/位或运算符(& 为引用取址;&&/|| 恒短路分支化 = IR_BRANCH,超 M1 直线
// 子集),位与经 && 亦不可达 IR_BINARY(OP_AND)。载体改为链式加减 + 内存读写;
// and→nand 合成为 IR 层完备性代码(M2 位运算符落地后启用)。
-fn main() -> int {
- a: ., mut = 6;
- b := 3;
- a = a + b;
- a = a - 4;
- return a;
-}
+fn main() -> int:
+ a: ., mut = 6
+ b := 3
+ a = a + b
+ a = a - 4
+ return a
diff --git a/tests/kernel/README.md b/tests/kernel/README.md
index ad19b52f..f66b9cf8 100644
--- a/tests/kernel/README.md
+++ b/tests/kernel/README.md
@@ -37,10 +37,10 @@ harness 与 kernel CLI(`kernel_main.cr`)必须跳过 `#` 行**(随机层
| `cases/corpus_manual.txt` | **25** | 案卷:经典难项(β 归约、Π 逆变/协变、宇宙累积、natrec、显式替换组合) |
穷举层每项发射:`(ctx)` 下 infer + check(nat) + check(typ 0);类型形态项(首构造子为
-pi/typ/nat)加 subtype ×2;前 50 项加 convert;再以 `(ctx (nat))`、`(ctx (typ 0))`
+`pi`/`typ`/`nat`)加 subtype ×2;前 50 项加 convert;再以 `(ctx (nat))`、`(ctx (typ 0))`
上下文重复 infer/check。
-## 穷举层规模(--max-size)
+## 穷举层规模(`--max-size`)
生成器默认 `--max-size 3`(穷举层 size ≤ 3,产物约 2.4 MB)。size-4 全量
(221,520 项,产物约 141 MB)超过 GitHub 100MiB 单文件上传限制,须显式开启:
@@ -51,7 +51,7 @@ python3 tests/kernel/gen_corpus.py --max-size 4
`--max-size` 只影响穷举层;随机层(种子 20260815)与案卷不随其变化。
-## 与 brief(.superpowers/sdd/task-4-brief.md)的差异
+## 与 brief(`.superpowers/sdd/task-4-brief.md`)的差异
生成器按 brief Step 1-4 转写,运行后修正了下列实际问题(均不影响验收行数):
@@ -69,12 +69,12 @@ python3 tests/kernel/gen_corpus.py --max-size 4
表述对这 2 条不准确,此处更正;案卷条目本身不改(保持与已交付 harness 的兼容),
恢复原性质需把 λ 体改为 `(typ 0)`/`(typ 1)`,留待后续任务。
3. **穷举层无 natrec 项**:brief 的简化 natrec 方案(四子项均取 size-1 原子)最小总
- size=5,默认 max_size=3(size-4 亦同)下过滤条件恒不命中——按 brief 注记,natrec
- 覆盖由随机层(`rand_exp` 的 K_NATREC 分支)+ 案卷第 16/17 条补齐。
+ size=5,默认 `max_size=3`(size-4 亦同)下过滤条件恒不命中——按 brief 注记,natrec
+ 覆盖由随机层(`rand_exp` 的 `K_NATREC` 分支)+ 案卷第 16/17 条补齐。
4. **跨层重复项**:穷举层按 brief 原算法逐层去重(去重域 = 单层),同文本项可出现在
- 多个 size 层(如 `(succ (nat))` 在 size 2/3 层)——默认 size-3 下为 **6 个文本重复
- 出现 6 次(跨层)**(size-4 全量为 348 个文本重复出现 354 次)——差分测试两侧处理
- 相同行,无影响,予以保留。
+ 多个 size 层(如 `(succ (nat))` 在 size 2/3 层)——默认 size-3 下为 **6 个文本项
+ 跨层重复出现 6 次**(size-4 全量为 348 个文本项重复出现 354 次)——差分测试两侧
+ 处理相同行,无影响,故保留。
5. 结构性调整:`gen_exps` 返回按层分组的 dict(扁平列表语义不变,便于逐层加 `#`
注释);不导入 brief 中未使用的 `itertools`。
diff --git a/tests/probes/README.md b/tests/probes/README.md
index 5b7ad82a..2a4e09be 100644
--- a/tests/probes/README.md
+++ b/tests/probes/README.md
@@ -21,7 +21,7 @@ diff -rq /tmp/probes_now /tmp/probes_base # 两
## 清点(**29 档** = `/tmp/p5t0/probes` 11 + `/tmp/p5t3/probes` 18)
-> **U-4 收尾**:P5 清单曾记「30 档」——**这是假象**:迁移期 runner 的
+> **U-4 收尾**:P5 清单曾记「30 档」——**该计数不成立**:迁移期 runner 的
> `for f in /tmp/p5t3b/probes/*.cr` 在零匹配目录上迭代**字面 glob**,产生伪条目
> `_tmp_p5t3b_probes_*.cr`(rc=1,log = `error: cannot read …/*.cr`),两态恒等 ⇒ 该条对拍是
> **空洞证据**。**正式值 = 29**(R2 P6 T0 §3.2);`/tmp/p5t3b/probes` 是 T3b 的**输出**目录
@@ -64,11 +64,11 @@ diff -rq /tmp/probes_now /tmp/probes_base # 两
**逐档 sha256 交叉核**:入仓 29 档 sha 与 T0 的 `/tmp/p6t0/probes_manifest.txt` **29/29 逐条同**
(实拷、未改写——**不要**在探针源里加注释:逐字节保真才能复现 rc/日志)。
-## 运行条件(不得含糊)
+## 运行条件(均为硬性要求)
1. **变异态证据不在本目录**:T3b 的 `n13/n17/n18` 在**变异二进制**(M1..M4)下的转红证据
(`/tmp/p5t3b/probes/*.M{1..4}.log`、`.M2.dump`,共 15 件)需**先重造变异二进制**才能复跑
- ——配方见 `p5-task3b-report.md` §3.3,**不随语料入仓**(登记,不假装可复跑)。
+ ——配方见 `p5-task3b-report.md` §3.3,**不随语料入仓**(登记在案,不声称可复跑)。
2. **影子通道产物不可复现**:T3b 的 42 行 `[type-shadow…]` 摘要行(21 log × 2)**无二进制可产**
(通道已随 P5 T5 删除)⇒ **不得**引用为证据(三态纪律:不可产出的读数 = 无读数)。
3. **红态复现**(`n13/n17/n18` 的 pre-T3b 行为)须用**冻结基线**(其仍带影子旗标)——
diff --git a/tests/probes/n02_diff_named.cr b/tests/probes/n02_diff_named.cr
index 9c66c716..e9d21951 100644
--- a/tests/probes/n02_diff_named.cr
+++ b/tests/probes/n02_diff_named.cr
@@ -1,8 +1,9 @@
-struct NA { x: int }
-struct NB { x: int }
-fn main() -> int {
- a : ., mut = NA { x: 1 };
- b : ., mut = NB { x: 2 };
- a = b;
- return a.x;
-}
+struct NA:
+ x: int
+struct NB:
+ x: int
+fn main() -> int:
+ a : ., mut = NA { x= 1 }
+ b : ., mut = NB { x= 2 }
+ a = b
+ return a.x
diff --git a/tests/probes/n03_apply_twice.cr b/tests/probes/n03_apply_twice.cr
index 090e82cb..32b0e1ef 100644
--- a/tests/probes/n03_apply_twice.cr
+++ b/tests/probes/n03_apply_twice.cr
@@ -1,6 +1,7 @@
-struct Box[T] { v: T }
-fn g(a: Box[int], b: Box[int]) -> int {
- a = b;
- return a.v;
-}
-fn main() -> int { return 0; }
+struct Box[T]:
+ v: T
+fn g(a: Box[int], b: Box[int]) -> int:
+ a = b
+ return a.v
+fn main() -> int:
+ return 0
diff --git a/tests/probes/n04_apply_diff_args.cr b/tests/probes/n04_apply_diff_args.cr
index fe820c49..438d6b96 100644
--- a/tests/probes/n04_apply_diff_args.cr
+++ b/tests/probes/n04_apply_diff_args.cr
@@ -1,6 +1,7 @@
-struct Box[T] { v: T }
-fn g(a: Box[int], b: Box[str]) -> int {
- a = b;
- return a.v;
-}
-fn main() -> int { return 0; }
+struct Box[T]:
+ v: T
+fn g(a: Box[int], b: Box[str]) -> int:
+ a = b
+ return a.v
+fn main() -> int:
+ return 0
diff --git a/tests/probes/n05_recursive.cr b/tests/probes/n05_recursive.cr
index b315c648..bc4e37b4 100644
--- a/tests/probes/n05_recursive.cr
+++ b/tests/probes/n05_recursive.cr
@@ -1,7 +1,7 @@
-struct Node { val: int, next: *Node }
-fn main() -> int {
- a : ., mut = Node { val: 1, next: 0 };
- b : ., mut = Node { val: 2, next: 0 };
- a = b;
- return a.val;
-}
+struct Node:
+ val: int, next: *Node
+fn main() -> int:
+ a : ., mut = Node { val= 1, next= 0 }
+ b : ., mut = Node { val= 2, next= 0 }
+ a = b
+ return a.val
diff --git a/tests/probes/n09_t_vs_int.cr b/tests/probes/n09_t_vs_int.cr
index 431a7d77..b5c4f4ad 100644
--- a/tests/probes/n09_t_vs_int.cr
+++ b/tests/probes/n09_t_vs_int.cr
@@ -1,6 +1,6 @@
-fn h[T](a: T, b: T) -> T { return a; }
-fn main() -> int {
- x := h(1, 2);
- y : int = x;
- return y;
-}
+fn h[T](a: T, b: T) -> T:
+ return a
+fn main() -> int:
+ x := h(1, 2)
+ y : int = x
+ return y
diff --git a/tests/probes/n10_named_vs_int.cr b/tests/probes/n10_named_vs_int.cr
index a2884a22..6865dc94 100644
--- a/tests/probes/n10_named_vs_int.cr
+++ b/tests/probes/n10_named_vs_int.cr
@@ -1,7 +1,7 @@
-struct NA { x: int }
-fn main() -> int {
- a : NA = NA { x: 1 };
- b : int = 2;
- a = b;
- return a.x;
-}
+struct NA:
+ x: int
+fn main() -> int:
+ a : NA = NA { x= 1 }
+ b : int = 2
+ a = b
+ return a.x
diff --git a/tests/probes/n12_alias.cr b/tests/probes/n12_alias.cr
index 6b17c3a2..e49576c2 100644
--- a/tests/probes/n12_alias.cr
+++ b/tests/probes/n12_alias.cr
@@ -1,7 +1,6 @@
-type X = int;
-fn main() -> int {
- a : X = 1;
- b : int = 2;
- a = b;
- return a;
-}
+type X = int
+fn main() -> int:
+ a : X = 1
+ b : int = 2
+ a = b
+ return a
diff --git a/tests/probes/n13_arr_diff_named.cr b/tests/probes/n13_arr_diff_named.cr
index 7f349df2..29b08db7 100644
--- a/tests/probes/n13_arr_diff_named.cr
+++ b/tests/probes/n13_arr_diff_named.cr
@@ -1,8 +1,9 @@
-struct NA { x: int }
-struct NB { x: int }
-fn main() -> int {
- a : [NA; 2] = [NA { x: 1 }, NA { x: 2 }];
- b : [NB; 2] = [NB { x: 3 }, NB { x: 4 }];
- a = b;
- return 0;
-}
+struct NA:
+ x: int
+struct NB:
+ x: int
+fn main() -> int:
+ a : [NA; 2] = [NA { x= 1 }, NA { x= 2 }]
+ b : [NB; 2] = [NB { x= 3 }, NB { x= 4 }]
+ a = b
+ return 0
diff --git a/tests/probes/n14_optional_diff_named.cr b/tests/probes/n14_optional_diff_named.cr
index cde2f237..81be5fe9 100644
--- a/tests/probes/n14_optional_diff_named.cr
+++ b/tests/probes/n14_optional_diff_named.cr
@@ -1,8 +1,9 @@
-struct NA { x: int }
-struct NB { x: int }
-fn main() -> int {
- a : NA? = NA { x: 1 };
- b : NB? = NB { x: 2 };
- a = b;
- return 0;
-}
+struct NA:
+ x: int
+struct NB:
+ x: int
+fn main() -> int:
+ a : NA? = NA { x= 1 }
+ b : NB? = NB { x= 2 }
+ a = b
+ return 0
diff --git a/tests/probes/n15_apply_named_arg.cr b/tests/probes/n15_apply_named_arg.cr
index 33611e84..e978ba96 100644
--- a/tests/probes/n15_apply_named_arg.cr
+++ b/tests/probes/n15_apply_named_arg.cr
@@ -1,6 +1,14 @@
-struct NA { x: int }
-struct NB { x: int }
-struct Box[T] { v: T }
-fn g(a: Box[NA], b: Box[NA]) -> int { a = b; return a.v.x; }
-fn h(a: Box[NA], b: Box[NB]) -> int { a = b; return a.v.x; }
-fn main() -> int { return 0; }
+struct NA:
+ x: int
+struct NB:
+ x: int
+struct Box[T]:
+ v: T
+fn g(a: Box[NA], b: Box[NA]) -> int:
+ a = b
+ return a.v.x
+fn h(a: Box[NA], b: Box[NB]) -> int:
+ a = b
+ return a.v.x
+fn main() -> int:
+ return 0
diff --git a/tests/probes/n16_nested_apply.cr b/tests/probes/n16_nested_apply.cr
index 3388c116..e8ce89f1 100644
--- a/tests/probes/n16_nested_apply.cr
+++ b/tests/probes/n16_nested_apply.cr
@@ -1,3 +1,7 @@
-struct Box[T] { v: T }
-fn g(a: Box[Box[int]], b: Box[Box[int]]) -> int { a = b; return 0; }
-fn main() -> int { return 0; }
+struct Box[T]:
+ v: T
+fn g(a: Box[Box[int]], b: Box[Box[int]]) -> int:
+ a = b
+ return 0
+fn main() -> int:
+ return 0
diff --git a/tests/probes/n17_ptr_named.cr b/tests/probes/n17_ptr_named.cr
index 6cf1c3e9..fdad07e7 100644
--- a/tests/probes/n17_ptr_named.cr
+++ b/tests/probes/n17_ptr_named.cr
@@ -1,4 +1,9 @@
-struct NA { x: int }
-struct NB { x: int }
-fn g(a: *NA, b: *NB) -> int { a = b; return 0; }
-fn main() -> int { return 0; }
+struct NA:
+ x: int
+struct NB:
+ x: int
+fn g(a: *NA, b: *NB) -> int:
+ a = b
+ return 0
+fn main() -> int:
+ return 0
diff --git a/tests/probes/n18_tuple_named.cr b/tests/probes/n18_tuple_named.cr
index aa3b7390..50b6e415 100644
--- a/tests/probes/n18_tuple_named.cr
+++ b/tests/probes/n18_tuple_named.cr
@@ -1,8 +1,9 @@
-struct NA { x: int }
-struct NB { x: int }
-fn main() -> int {
- a : ., mut = (NA { x: 1 }, 2);
- b : ., mut = (NB { x: 3 }, 4);
- a = b;
- return 0;
-}
+struct NA:
+ x: int
+struct NB:
+ x: int
+fn main() -> int:
+ a : ., mut = (NA { x= 1 }, 2)
+ b : ., mut = (NB { x= 3 }, 4)
+ a = b
+ return 0
diff --git a/tests/probes/n19_ref_named.cr b/tests/probes/n19_ref_named.cr
index 37a57c49..51b54462 100644
--- a/tests/probes/n19_ref_named.cr
+++ b/tests/probes/n19_ref_named.cr
@@ -1,11 +1,13 @@
-struct NA { x: int }
-struct NB { x: int }
-fn g(a: &NA, b: &NB) -> int { return 0; }
-fn main() -> int {
- x : ., mut = NA { x: 1 };
- y : ., mut = NB { x: 2 };
- p := &x;
- q := &y;
- g(p, q);
- return 0;
-}
+struct NA:
+ x: int
+struct NB:
+ x: int
+fn g(a: &NA, b: &NB) -> int:
+ return 0
+fn main() -> int:
+ x : ., mut = NA { x= 1 }
+ y : ., mut = NB { x= 2 }
+ p := &x
+ q := &y
+ g(p, q)
+ return 0
diff --git a/tests/probes/n20_apply_named_vs_int.cr b/tests/probes/n20_apply_named_vs_int.cr
index 3f8aa9fc..8915bf19 100644
--- a/tests/probes/n20_apply_named_vs_int.cr
+++ b/tests/probes/n20_apply_named_vs_int.cr
@@ -1,4 +1,9 @@
-struct NA { x: int }
-struct Box[T] { v: T }
-fn g(a: Box[NA], b: Box[int]) -> int { a = b; return 0; }
-fn main() -> int { return 0; }
+struct NA:
+ x: int
+struct Box[T]:
+ v: T
+fn g(a: Box[NA], b: Box[int]) -> int:
+ a = b
+ return 0
+fn main() -> int:
+ return 0
diff --git a/tests/probes/n21_t_assign_int.cr b/tests/probes/n21_t_assign_int.cr
index 62847044..5fad331b 100644
--- a/tests/probes/n21_t_assign_int.cr
+++ b/tests/probes/n21_t_assign_int.cr
@@ -1,5 +1,5 @@
-fn h[T](a: T, b: int) -> int {
- a = b;
- return 0;
-}
-fn main() -> int { return h(1, 2); }
+fn h[T](a: T, b: int) -> int:
+ a = b
+ return 0
+fn main() -> int:
+ return h(1, 2)
diff --git a/tests/probes/n22_named_struct_field.cr b/tests/probes/n22_named_struct_field.cr
index 4b1c6928..53e70cad 100644
--- a/tests/probes/n22_named_struct_field.cr
+++ b/tests/probes/n22_named_struct_field.cr
@@ -1,8 +1,9 @@
-struct NA { x: int }
-fn take(v: NA) -> int { return v.x; }
-fn main() -> int {
- a : ., mut = NA { x: 1 };
- b : ., mut = NA { x: 2 };
- a = b;
- return take(a);
-}
+struct NA:
+ x: int
+fn take(v: NA) -> int:
+ return v.x
+fn main() -> int:
+ a : ., mut = NA { x= 1 }
+ b : ., mut = NA { x= 2 }
+ a = b
+ return take(a)
diff --git a/tests/probes/n23_enum_named.cr b/tests/probes/n23_enum_named.cr
index 0437380a..779ef6a2 100644
--- a/tests/probes/n23_enum_named.cr
+++ b/tests/probes/n23_enum_named.cr
@@ -1,8 +1,9 @@
-enum EA { X, Y }
-enum EB { X, Y }
-fn main() -> int {
- a : ., mut = EA.X;
- b : ., mut = EB.X;
- a = b;
- return 0;
-}
+enum EA:
+ X, Y
+enum EB:
+ X, Y
+fn main() -> int:
+ a : ., mut = EA.X
+ b : ., mut = EB.X
+ a = b
+ return 0
diff --git a/tests/probes/p_annots.cr b/tests/probes/p_annots.cr
index d0a35020..acb802dd 100644
--- a/tests/probes/p_annots.cr
+++ b/tests/probes/p_annots.cr
@@ -1,9 +1,9 @@
-fn add(a: int, b: int) -> int { return a + b; }
-fn main() -> int {
- @NoBoundsCheck;
- @fast;
- @unroll(4);
- @section("hot");
- r := @inline(add)(3, 4);
- return r;
-}
+fn add(a: int, b: int) -> int:
+ return a + b
+fn main() -> int:
+ @NoBoundsCheck
+ @fast
+ @unroll(4)
+ @section("hot")
+ r := @inline(add)(3, 4)
+ return r
diff --git a/tests/probes/p_annots2.cr b/tests/probes/p_annots2.cr
index fd2bb151..8acec4b2 100644
--- a/tests/probes/p_annots2.cr
+++ b/tests/probes/p_annots2.cr
@@ -1,7 +1,7 @@
-fn add(a: int, b: int) -> int { return a + b; }
-fn main() -> int {
- @NoBoundsCheck();
- @fast();
- r := @inline(add)(3, 4);
- return r;
-}
+fn add(a: int, b: int) -> int:
+ return a + b
+fn main() -> int:
+ @NoBoundsCheck()
+ @fast()
+ r := @inline(add)(3, 4)
+ return r
diff --git a/tests/probes/p_dex.cr b/tests/probes/p_dex.cr
index 07d1f12b..203b2653 100644
--- a/tests/probes/p_dex.cr
+++ b/tests/probes/p_dex.cr
@@ -1,7 +1,6 @@
-fn main() -> int {
- d := 1 + 0.5;
- n := d as int;
- i : int = 7;
- e := i + 0.25;
- return n;
-}
+fn main() -> int:
+ d := 1 + 0.5
+ n := d as int
+ i : int = 7
+ e := i + 0.25
+ return n
diff --git a/tests/probes/p_dyn.cr b/tests/probes/p_dyn.cr
index d8aa0b98..46ce4f41 100644
--- a/tests/probes/p_dyn.cr
+++ b/tests/probes/p_dyn.cr
@@ -1,6 +1,8 @@
-fn main() -> int {
- cond : int = 1;
- x : dyn = 0;
- if cond != 0 { x = 42; } else { x = "hello"; }
- return 0;
-}
+fn main() -> int:
+ cond : int = 1
+ x : dyn = 0
+ if cond != 0:
+ x = 42
+ else:
+ x = "hello"
+ return 0
diff --git a/tests/probes/p_enum.cr b/tests/probes/p_enum.cr
index b74cdd7f..16a34163 100644
--- a/tests/probes/p_enum.cr
+++ b/tests/probes/p_enum.cr
@@ -1,5 +1,6 @@
-enum Color { Red, Green, Blue }
-fn main() -> int {
- x := Green();
- return match x { Red => 0, Green => 1, Blue => 2, };
-}
+enum Color:
+ Red, Green, Blue
+fn main() -> int:
+ x := Green()
+ return match x:
+ Red => 0, Green => 1, Blue => 2,
diff --git a/tests/probes/p_ffi.cr b/tests/probes/p_ffi.cr
index ccc2f6a4..4c3adead 100644
--- a/tests/probes/p_ffi.cr
+++ b/tests/probes/p_ffi.cr
@@ -1,5 +1,4 @@
-extern "C" fn putchar(c: int) -> int;
-fn main() -> int {
- putchar(65);
- return 0;
-}
+extern "C" fn putchar(c: int) -> int
+fn main() -> int:
+ putchar(65)
+ return 0
diff --git a/tests/probes/p_ffi2.cr b/tests/probes/p_ffi2.cr
index 08dd3e04..22609c5d 100644
--- a/tests/probes/p_ffi2.cr
+++ b/tests/probes/p_ffi2.cr
@@ -1,5 +1,4 @@
-extern fn putchar(c: int) -> int;
-fn main() -> int {
- putchar(65);
- return 0;
-}
+extern fn putchar(c: int) -> int
+fn main() -> int:
+ putchar(65)
+ return 0
diff --git a/tests/probes/p_go.cr b/tests/probes/p_go.cr
index 52de8aec..941ff27c 100644
--- a/tests/probes/p_go.cr
+++ b/tests/probes/p_go.cr
@@ -1,6 +1,6 @@
-fn work() -> int { return 1; }
-fn main() -> int {
- f := go work();
- r := await f;
- return r;
-}
+fn work() -> int:
+ return 1
+fn main() -> int:
+ f := go work()
+ r := await f
+ return r
diff --git a/tests/probes/p_i2f.cr b/tests/probes/p_i2f.cr
index 6dc8631d..2af93396 100644
--- a/tests/probes/p_i2f.cr
+++ b/tests/probes/p_i2f.cr
@@ -1,6 +1,6 @@
-fn half() -> dex { return 0.5; }
-fn main() -> int {
- x : dex = half();
- y := 3 + x;
- return 0;
-}
+fn half() -> dex:
+ return 0.5
+fn main() -> int:
+ x : dex = half()
+ y := 3 + x
+ return 0
diff --git a/tests/probes/p_opt.cr b/tests/probes/p_opt.cr
index d8a12a42..26df1426 100644
--- a/tests/probes/p_opt.cr
+++ b/tests/probes/p_opt.cr
@@ -1,6 +1,5 @@
-fn main() -> int {
- x : int? = Some(5);
- y := x?;
- z : int? = None;
- return y;
-}
+fn main() -> int:
+ x : int? = Some(5)
+ y := x?
+ z : int? = none
+ return y
diff --git a/tests/probes/p_spawn.cr b/tests/probes/p_spawn.cr
index bf876b66..73c655b2 100644
--- a/tests/probes/p_spawn.cr
+++ b/tests/probes/p_spawn.cr
@@ -1,5 +1,5 @@
-fn square(x: int) -> int { return x * x; }
-fn main() -> int {
- arr := go i 0..3 square(i);
- return arr[0] + arr[1] + arr[2];
-}
+fn square(x: int) -> int:
+ return x * x
+fn main() -> int:
+ arr := go i 0..3 square(i)
+ return arr[0] + arr[1] + arr[2]
diff --git a/tests/probes/warm/README.md b/tests/probes/warm/README.md
index 9544f230..fa8be445 100644
--- a/tests/probes/warm/README.md
+++ b/tests/probes/warm/README.md
@@ -5,7 +5,7 @@
的任何清单收集——那些都是非递归 glob)——它们是 `tools/baseline/warm_run.sh`(= `warm_leg.sh
--with-corpus`)与 `tests/selfhost/test_warm_cache_gate.py` 的**两态断言输入**。
-## 设计要点:**定路径**
+## 设计要点:定路径
缓存键 = `源路径::函数名`,指纹 = 纯 AST。把语料拷到唯一 temp 路径(既有套件的普遍写法)
⇒ 键唯一 ⇒ **结构性无暖态** ⇒ 判据恒绿而空洞(T1 方法学发现;突变 M3 实证:缺陷在场时
@@ -25,7 +25,7 @@
| 7 | `alloc_witness.cr` | **见证面**(数组字面量 + 取址 ⇒ ir_gen 期分配复合行) | rc=0 → rc=0 ∧ **自档 `main` 无条目**(#2026-09-15-5 T2 见证规则) | T2 §3.2 |
**旁面对照的意义**:`tk01_*` 三档走 `g_pts`/辅码宽度(**每次构建重算**),不依赖 ir_gen 期类型行
-⇒ 暖态**本就不该**变脸;它们的绿 = 缺陷面被精确锁定在「读生成期类型行」的判定(T1 E1 旁证)。
+⇒ 暖态**本不应**变化;它们的绿 = 缺陷面被精确锁定在「读生成期类型行」的判定(T1 E1 旁证)。
## 用法
@@ -36,7 +36,7 @@ bash tools/baseline/warm_run.sh /tmp//corec /tmp/warm_before # pre-fi
**判读**:`WARM LEG DONE(…):7 档 · **暖态生效(≥1 真命中)档数 = N** · FAIL=M`
—— `FAIL>0` = 冷/暖分歧(缺陷回归)或期望值不命中;**`暖态生效档数 = 0` = 空洞警报**
-(判据绿但根本没走到暖态,例如路径不固定/缓存被关),二者都不可接受。
+(判据绿但未进入暖态,例如路径不固定/缓存被关),二者都不可接受。
## 与既有 runner 的关系(#2026-09-15-5 T3 落位)
diff --git a/tests/probes/warm/alloc_witness.cr b/tests/probes/warm/alloc_witness.cr
index ab5f2f94..d913dabf 100644
--- a/tests/probes/warm/alloc_witness.cr
+++ b/tests/probes/warm/alloc_witness.cr
@@ -1,7 +1,6 @@
// #2026-09-15-5 T2 见证面:数组字面量 + 取址 ⇒ ir_gen 期分配复合类型行
// (ir_gen.cr:2584/:1403)⇒ 本函数不落缓存条目(下跑必 miss 重放)。程序本身合法。
-fn main() -> int {
- arr := [10, 20, 30];
- p := &arr[1];
- return *p;
-}
+fn main() -> int:
+ arr := [10, 20, 30]
+ p := &arr[1]
+ return *p
diff --git a/tests/probes/warm/plain.cr b/tests/probes/warm/plain.cr
index a3e43f61..c27730c7 100644
--- a/tests/probes/warm/plain.cr
+++ b/tests/probes/warm/plain.cr
@@ -1,4 +1,3 @@
-fn main() -> int {
- x := 1 + 2;
- return x;
-}
+fn main() -> int:
+ x := 1 + 2
+ return x
diff --git a/tests/probes/warm/tk01_oob_load.cr b/tests/probes/warm/tk01_oob_load.cr
index 79353559..1b8febf9 100644
--- a/tests/probes/warm/tk01_oob_load.cr
+++ b/tests/probes/warm/tk01_oob_load.cr
@@ -1,5 +1,4 @@
-fn main() -> int {
- arr := [1];
- p := &arr[0] + 1;
- return *p;
-}
+fn main() -> int:
+ arr := [1]
+ p := &arr[0] + 1
+ return *p
diff --git a/tests/probes/warm/tk01_oob_store.cr b/tests/probes/warm/tk01_oob_store.cr
index bb9b35bc..9bf4da4f 100644
--- a/tests/probes/warm/tk01_oob_store.cr
+++ b/tests/probes/warm/tk01_oob_store.cr
@@ -1,6 +1,5 @@
-fn main() -> int {
- arr := [1];
- p := &arr[0] + 1;
- *p = 2;
- return 0;
-}
+fn main() -> int:
+ arr := [1]
+ p := &arr[0] + 1
+ *p = 2
+ return 0
diff --git a/tests/probes/warm/tk01_width.cr b/tests/probes/warm/tk01_width.cr
index 76f5a24e..62503384 100644
--- a/tests/probes/warm/tk01_width.cr
+++ b/tests/probes/warm/tk01_width.cr
@@ -1,6 +1,5 @@
-fn main() -> int {
- arr := [1, 2];
- p := (&arr[1]) as *[int; 2];
- wide := *p;
- return 0;
-}
+fn main() -> int:
+ arr := [1, 2]
+ p := (&arr[1]) as *[int; 2]
+ wide := *p
+ return 0
diff --git a/tests/probes/warm/tu03_load.cr b/tests/probes/warm/tu03_load.cr
index 4cef0b7e..ebf4903d 100644
--- a/tests/probes/warm/tu03_load.cr
+++ b/tests/probes/warm/tu03_load.cr
@@ -1,4 +1,3 @@
-fn main() -> int {
- p := 4096 as *int;
- return *p;
-}
+fn main() -> int:
+ p := 4096 as *int
+ return *p
diff --git a/tests/probes/warm/tu03_store.cr b/tests/probes/warm/tu03_store.cr
index 879c2ea0..dbe66d02 100644
--- a/tests/probes/warm/tu03_store.cr
+++ b/tests/probes/warm/tu03_store.cr
@@ -1,5 +1,4 @@
-fn main() -> int {
- p := 4096 as *int;
- *p = 1;
- return 0;
-}
+fn main() -> int:
+ p := 4096 as *int
+ *p = 1
+ return 0
diff --git a/tests/selfhost/test_agg_checks.py b/tests/selfhost/test_agg_checks.py
index 92e07fc7..283bbb12 100644
--- a/tests/selfhost/test_agg_checks.py
+++ b/tests/selfhost/test_agg_checks.py
@@ -41,93 +41,98 @@
(
"struct: 乱序字段按名字绑定(①主判据;修复前静默得 1122)",
"""
-struct P { a: int, b: int }
-fn main() -> int {
- p := P{b: 11, a: 22};
- return p.a * 100 + p.b;
-}
+struct P:
+ a: int, b: int
+fn main() -> int:
+ p := P{b= 11, a= 22}
+ return p.a * 100 + p.b
""",
2211,
),
(
"struct: 乱序 + 求值顺序 = 源序(副作用判据)",
"""
-g : int, mut = 0;
-fn nx() -> int { g = g + 1; return g; }
-struct P { a: int, b: int }
-fn main() -> int {
- p := P{b: nx(), a: nx()};
- return p.a * 100 + p.b;
-}
+g : int, mut = 0
+fn nx() -> int:
+ g = g + 1
+ return g
+struct P:
+ a: int, b: int
+fn main() -> int:
+ p := P{b= nx(), a= nx()}
+ return p.a * 100 + p.b
""",
201,
),
(
"struct: 三字段逆序(错位累积面)",
"""
-struct P { a: int, b: int, c: int }
-fn main() -> int {
- p := P{c: 3, b: 2, a: 1};
- return p.a * 100 + p.b * 10 + p.c;
-}
+struct P:
+ a: int, b: int, c: int
+fn main() -> int:
+ p := P{c= 3, b= 2, a= 1}
+ return p.a * 100 + p.b * 10 + p.c
""",
123,
),
(
"struct: 乱序 + 复合字段值(嵌套字面量)",
"""
-struct Q { u: int, v: int }
-struct P { a: int, b: Q }
-fn main() -> int {
- p := P{b: Q{u: 2, v: 3}, a: 1};
- return p.a * 100 + p.b.u * 10 + p.b.v;
-}
+struct Q:
+ u: int, v: int
+struct P:
+ a: int, b: Q
+fn main() -> int:
+ p := P{b= Q{u= 2, v= 3}, a= 1}
+ return p.a * 100 + p.b.u * 10 + p.b.v
""",
123,
),
(
"generic struct: 乱序字段 + 泛型参数绑定(Pair[T])",
"""
-struct Pair[T] { left: T, right: T }
-fn main() -> int {
- p := Pair { right = 2, left = 1 };
- return p.left * 10 + p.right;
-}
+struct Pair[T]:
+ left: T, right: T
+fn main() -> int:
+ p := Pair { right = 2, left = 1 }
+ return p.left * 10 + p.right
""",
12,
),
(
"generic struct: 双参数、字段序 ≠ 参数序(实参须按参数声明序)",
"""
-struct Sw[A, B] { y: B, x: A }
-fn main() -> int {
- s := Sw { x = 1, y = 2 };
- return s.x * 10 + s.y;
-}
+struct Sw[A, B]:
+ y: B, x: A
+fn main() -> int:
+ s := Sw { x = 1, y = 2 }
+ return s.x * 10 + s.y
""",
12,
),
(
"generic fn body: 乱序字面量经 monomorph 克隆仍按名字绑定(名字随克隆保留)",
"""
-struct P { a: int, b: int }
-fn f[T](x: T) -> int {
- p := P{b: 2, a: x};
- return p.a * 10 + p.b;
-}
-fn main() -> int { return f(1); }
+struct P:
+ a: int, b: int
+fn f[T](x: T) -> int:
+ p := P{b= 2, a= x}
+ return p.a * 10 + p.b
+fn main() -> int:
+ return f(1)
""",
12,
),
(
"嵌套泛型应用字段类型 Box[Box[int]](既存载荷写坏回归——修复前假拒)",
"""
-struct Box[T] { val: T }
-struct Holder { b: Box[Box[int]] }
-fn main() -> int {
- h := Holder{b: Box{val: Box{val: 7}}};
- return h.b.val.val;
-}
+struct Box[T]:
+ val: T
+struct Holder:
+ b: Box[Box[int]]
+fn main() -> int:
+ h := Holder{b= Box{val= Box{val= 7}}}
+ return h.b.val.val
""",
7,
),
@@ -139,76 +144,75 @@
(
"① 未知字段 + 缺字段(TS02 + TS01)",
"""
-struct P { a: int, b: int }
-fn main() -> int {
- p := P{c: 1, a: 2};
- return 0;
-}
+struct P:
+ a: int, b: int
+fn main() -> int:
+ p := P{c= 1, a= 2}
+ return 0
""",
"TS02",
),
(
"① 重复字段(TS04)",
"""
-struct P { a: int, b: int }
-fn main() -> int {
- p := P{a: 1, a: 2, b: 3};
- return 0;
-}
+struct P:
+ a: int, b: int
+fn main() -> int:
+ p := P{a= 1, a= 2, b= 3}
+ return 0
""",
"TS04",
),
(
"① 缺字段(TS01)",
"""
-struct P { a: int, b: int }
-fn main() -> int {
- p := P{a: 1};
- return 0;
-}
+struct P:
+ a: int, b: int
+fn main() -> int:
+ p := P{a= 1}
+ return 0
""",
"TS01",
),
(
"② 字段类型与声明不符(TS03;b: int 收 string)",
"""
-struct P { a: int, b: int }
-fn main() -> int {
- p := P{a: 1, b: "x"};
- return 0;
-}
+struct P:
+ a: int, b: int
+fn main() -> int:
+ p := P{a= 1, b= "x"}
+ return 0
""",
"TS03",
),
(
"② 嵌套结构体字段错型(TS03;b: Q 收 int)",
"""
-struct Q { u: int, v: int }
-struct P { a: int, b: Q }
-fn main() -> int {
- p := P{a: 1, b: 3};
- return 0;
-}
+struct Q:
+ u: int, v: int
+struct P:
+ a: int, b: Q
+fn main() -> int:
+ p := P{a= 1, b= 3}
+ return 0
""",
"TS03",
),
(
"③ 数组元素异质(TK02)",
"""
-fn main() -> int {
- a := [1, "x", 3];
- return 0;
-}
+fn main() -> int:
+ a := [1, "x", 3]
+ return 0
""",
"TK02",
),
(
"③ 数组元素异质:嵌套 vs 扁平(TK02)",
"""
-fn main() -> int {
- a := [[1, 2], 3];
- return 0;
-}
+fn main() -> int:
+ a := [[1, 2], 3]
+ return 0
""",
"TK02",
),
@@ -216,52 +220,60 @@
(
"正控:乱序但名/型/完整性全对 → 接受",
"""
-struct P { a: int, b: int }
-fn main() -> int {
- p := P{b: 11, a: 22};
- return p.a * 100 + p.b;
-}
+struct P:
+ a: int, b: int
+fn main() -> int:
+ p := P{b= 11, a= 22}
+ return p.a * 100 + p.b
""",
"ACCEPT",
),
(
"正控:泛型函数体内泛型参数值赋给确定类型字段(不得假拒)",
"""
-struct P { a: int, b: int }
-fn f[T](x: T) -> int {
- p := P{a: 1, b: x};
- return p.a * 100 + p.b;
-}
-fn main() -> int { return f(7); }
+struct P:
+ a: int, b: int
+fn f[T](x: T) -> int:
+ p := P{a= 1, b= x}
+ return p.a * 100 + p.b
+fn main() -> int:
+ return f(7)
""",
"ACCEPT",
),
(
"正控:同质数组 + 嵌套同形数组 → 接受",
"""
-fn main() -> int {
- a := [1, 2, 3];
- b := [[1, 2], [3, 4]];
- return a[0] + b[1][1];
-}
+fn main() -> int:
+ a := [1, 2, 3]
+ b := [[1, 2], [3, 4]]
+ return a[0] + b[1][1]
""",
"ACCEPT",
),
(
"正控:嵌套泛型应用在**返回位**(既存载荷写坏回归——修复前假拒 TF01)",
"""
-struct Box[T] { val: T }
-fn mk() -> Box[Box[int]] { return Box{val: Box{val: 1}}; }
-fn main() -> int { b := mk(); return b.val.val; }
+struct Box[T]:
+ val: T
+fn mk() -> Box[Box[int]]:
+ return Box{val= Box{val= 1}}
+fn main() -> int:
+ b := mk()
+ return b.val.val
""",
"ACCEPT",
),
(
"负控:嵌套泛型应用**错型**仍拒(两趟修复不得引入假阴性——评审 Important #1 的反面)",
"""
-struct Box[T] { val: T }
-struct P { b: Box[Box[int]] }
-fn main() -> int { p := P{b: Box{val: Box{val: "s"}}}; return 0; }
+struct Box[T]:
+ val: T
+struct P:
+ b: Box[Box[int]]
+fn main() -> int:
+ p := P{b= Box{val= Box{val= "s"}}}
+ return 0
""",
"TS03",
),
diff --git a/tests/selfhost/test_agg_read_type.py b/tests/selfhost/test_agg_read_type.py
index 047ae78e..843aff36 100644
--- a/tests/selfhost/test_agg_read_type.py
+++ b/tests/selfhost/test_agg_read_type.py
@@ -55,89 +55,99 @@
COREC = BASE / "build" / "corec"
R1 = """
-struct S { f: dex }
-fn main() -> int {
- d : dex, apx = 7.0;
- s : ., mut = S { f = d };
- x := s.f;
- if x * 2.0 != 14.0 { return 1; }
- return 7;
-}
+struct S:
+ f: dex
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S { f = d }
+ x := s.f
+ if x * 2.0 != 14.0:
+ return 1
+ return 7
"""
R2 = """
-enum E { V(dex) }
-fn main() -> int {
- d : dex, apx = 7.0;
- e : ., mut = V(d);
- return match e { V(x) => { if x * 2.0 != 14.0 { return 1; } return 7; } };
-}
+enum E:
+ V(dex)
+fn main() -> int:
+ d : dex, apx = 7.0
+ e : ., mut = V(d)
+ return match e:
+ V(x) =>:
+ if x * 2.0 != 14.0:
+ return 1
+ return 7
"""
R3 = """
-fn main() -> int {
- d : dex, apx = 7.0;
- a : [dex; 2] = [d, 1.0];
- if a[0] * 2.0 != 14.0 { return 1; }
- return 7;
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ a : [dex; 2] = [d, 1.0]
+ if a[0] * 2.0 != 14.0:
+ return 1
+ return 7
"""
R4 = """
-fn main() -> int {
- d : dex, apx = 7.0;
- t := (d, 1.0);
- if (t . 0) * 2.0 != 14.0 { return 1; }
- return 7;
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ t := (d, 1.0)
+ if (t . 0) * 2.0 != 14.0:
+ return 1
+ return 7
"""
R5 = """
-g : dex, apx, mut = 1.0;
-struct S { f: dex }
-fn main() -> int {
- d : dex, apx = 7.0;
- s : ., mut = S { f = d };
- g = s.f;
- if g != 7.0 { return 1; }
- return 7;
-}
+g : dex, apx, mut = 1.0
+struct S:
+ f: dex
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S { f = d }
+ g = s.f
+ if g != 7.0:
+ return 1
+ return 7
"""
# R6:extern 实参——**仅作 cir 断言载体**(运行路径既有崩溃,见头注)
R6 = """
-struct S { f: dex }
-extern fn dex_agg_arg_check(d: dex) -> int;
-fn main() -> int {
- d : dex, apx = 7.0;
- s : ., mut = S { f = d };
- r := dex_agg_arg_check(s.f);
- return r;
-}
+struct S:
+ f: dex
+extern fn dex_agg_arg_check(d: dex) -> int
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S { f = d }
+ r := dex_agg_arg_check(s.f)
+ return r
"""
# ── 腿 C:非回归钉子(改前即绿,修后必须仍绿)──
R7 = """
-struct S { f: dex }
-fn dbl(x: dex) -> dex { return x * 2.0; }
-fn main() -> int {
- d : dex, apx = 7.0;
- s : ., mut = S { f = d };
- y := dbl(s.f);
- if y != 14.0 { return 1; }
- return 7;
-}
+struct S:
+ f: dex
+fn dbl(x: dex) -> dex:
+ return x * 2.0
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S { f = d }
+ y := dbl(s.f)
+ if y != 14.0:
+ return 1
+ return 7
"""
N1 = """
-struct S { f: dex }
-fn main() -> int {
- d : dex, apx = 7.0;
- s : ., mut = S { f = d };
- if @raw_int(s.f) / 1000000 != 7 { return 1; }
- if s.f != 7.0 { return 2; }
- return 7;
-}
+struct S:
+ f: dex
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S { f = d }
+ if @raw_int(s.f) / 1000000 != 7:
+ return 1
+ if s.f != 7.0:
+ return 2
+ return 7
"""
# (name, expect_rc, src, kind)
diff --git a/tests/selfhost/test_agg_slots.py b/tests/selfhost/test_agg_slots.py
index 17fea2e0..8002da3d 100644
--- a/tests/selfhost/test_agg_slots.py
+++ b/tests/selfhost/test_agg_slots.py
@@ -36,106 +36,109 @@
(
"struct: compound value in last field (F5 ①主判据)",
"""
-struct P { a: int, b: int }
-fn g() -> int { return 3; }
-fn main() -> int {
- p := P{a: 11, b: g()};
- return p.a * 100 + p.b;
-}
+struct P:
+ a: int, b: int
+fn g() -> int:
+ return 3
+fn main() -> int:
+ p := P{a= 11, b= g()}
+ return p.a * 100 + p.b
""",
1103,
),
(
"struct: both fields compound (F5 ①主判据)",
"""
-struct P { a: int, b: int }
-fn g() -> int { return 3; }
-fn h() -> int { return 4; }
-fn main() -> int {
- p := P{a: g(), b: h()};
- return p.a * 10 + p.b;
-}
+struct P:
+ a: int, b: int
+fn g() -> int:
+ return 3
+fn h() -> int:
+ return 4
+fn main() -> int:
+ p := P{a= g(), b= h()}
+ return p.a * 10 + p.b
""",
34,
),
(
"struct: 3 fields, compound in middle (错位累积面)",
"""
-struct P { a: int, b: int, c: int }
-fn g() -> int { return 5; }
-fn main() -> int {
- p := P{a: 1, b: g(), c: 2};
- return p.a * 100 + p.b * 10 + p.c;
-}
+struct P:
+ a: int, b: int, c: int
+fn g() -> int:
+ return 5
+fn main() -> int:
+ p := P{a= 1, b= g(), c= 2}
+ return p.a * 100 + p.b * 10 + p.c
""",
152,
),
(
"struct: nested struct literal as field value",
"""
-struct Q { u: int, v: int }
-struct P { a: int, b: Q }
-fn main() -> int {
- p := P{a: 1, b: Q{u: 2, v: 3}};
- return p.a * 100 + p.b.u * 10 + p.b.v;
-}
+struct Q:
+ u: int, v: int
+struct P:
+ a: int, b: Q
+fn main() -> int:
+ p := P{a= 1, b= Q{u= 2, v= 3}}
+ return p.a * 100 + p.b.u * 10 + p.b.v
""",
123,
),
(
"struct: single-slot fields only (反证边界——旧交错顺序下此形本已正确)",
"""
-struct P { a: int, b: int }
-fn main() -> int {
- p := P{a: 11, b: 22};
- return p.a * 100 + p.b;
-}
+struct P:
+ a: int, b: int
+fn main() -> int:
+ p := P{a= 11, b= 22}
+ return p.a * 100 + p.b
""",
1122,
),
(
"generic fn body: struct literal cloned by monomorph",
"""
-struct P { a: int, b: int }
-fn f[T](x: T) -> int {
- p := P{a: 1, b: x};
- return p.a * 100 + p.b;
-}
-fn main() -> int {
- return f(7);
-}
+struct P:
+ a: int, b: int
+fn f[T](x: T) -> int:
+ p := P{a= 1, b= x}
+ return p.a * 100 + p.b
+fn main() -> int:
+ return f(7)
""",
107,
),
(
"array: compound element in middle (F5 ③主判据)",
"""
-fn g() -> int { return 7; }
-fn main() -> int {
- a := [1, g(), 3];
- return a[0] * 10 + a[1];
-}
+fn g() -> int:
+ return 7
+fn main() -> int:
+ a := [1, g(), 3]
+ return a[0] * 10 + a[1]
""",
17,
),
(
"array: nested array element read (修复前 a[1][0] SIGSEGV)",
"""
-fn main() -> int {
- a := [[1, 2], [3, 4]];
- return a[0][0] * 10 + a[1][1];
-}
+fn main() -> int:
+ a := [[1, 2], [3, 4]]
+ return a[0][0] * 10 + a[1][1]
""",
14,
),
(
"array: repeat form [value; N] 共享值节点",
"""
-fn g() -> int { return 4; }
-fn main() -> int {
- a := [g() + 1; 3];
- return a[0] + a[1] + a[2];
-}
+fn g() -> int:
+ return 4
+fn main() -> int:
+ a := [g() + 1; 3]
+ return a[0] + a[1] + a[2]
""",
15,
),
@@ -146,46 +149,42 @@
(
"soundness: nested vs flat array literal rejected (F5 ③)",
"""
-fn main() -> int {
- x : ., mut = [[1, 2], [3, 4]];
- y : ., mut = [5, 6];
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = [[1, 2], [3, 4]]
+ y : ., mut = [5, 6]
+ x = y
+ return 0
""",
"TA01",
),
(
"array element count mismatch rejected",
"""
-fn main() -> int {
- x : ., mut = [1, 2, 3];
- y : ., mut = [5, 6];
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = [1, 2, 3]
+ y : ., mut = [5, 6]
+ x = y
+ return 0
""",
"LEN",
),
(
"same-shape nested arrays accepted (反证边界)",
"""
-fn main() -> int {
- x : ., mut = [[1, 2], [3, 4]];
- y : ., mut = [[5, 6], [7, 8]];
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = [[1, 2], [3, 4]]
+ y : ., mut = [[5, 6], [7, 8]]
+ x = y
+ return 0
""",
"ACCEPT",
),
(
"array type form [T; N] + literal accepted (类型形不受字面量契约影响)",
"""
-fn main() -> int {
- a : [int; 3] = [1, 2, 3];
- return a[2];
-}
+fn main() -> int:
+ a : [int; 3] = [1, 2, 3]
+ return a[2]
""",
"ACCEPT",
),
diff --git a/tests/selfhost/test_apx_conversion.py b/tests/selfhost/test_apx_conversion.py
index 339650b4..7f5e191b 100644
--- a/tests/selfhost/test_apx_conversion.py
+++ b/tests/selfhost/test_apx_conversion.py
@@ -92,144 +92,214 @@ def build_and_run(source, tag):
CASES = [
# ── #2026-09-16-17:非直调调用形态 ──
("method_arg_apx", """
-struct S1 { v: int }
-impl S1 { fn m(self: S1, x: dex) -> int { return @raw_int(x) / 1000000; } }
-fn main() -> int { d : dex, apx = 7.0; s : ., mut = S1 { v = 0 }; return s.m(d); }
+struct S1:
+ v: int
+impl S1:
+ fn m(self: S1, x: dex) -> int:
+ return @raw_int(x) / 1000000
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S1 { v = 0 }
+ return s.m(d)
""", 7, "方法调用实参(#2026-09-16-17 原形)"),
("method_arg_self_offset", """
-struct S2 { v: int }
-impl S2 { fn m(self: S2, k: int, x: dex) -> int { return @raw_int(x) / 1000000; } }
-fn main() -> int { d : dex, apx = 7.0; s : ., mut = S2 { v = 0 }; return s.m(1, d); }
+struct S2:
+ v: int
+impl S2:
+ fn m(self: S2, k: int, x: dex) -> int:
+ return @raw_int(x) / 1000000
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S2 { v = 0 }
+ return s.m(1, d)
""", 7, "方法调用 + self/形参偏移(接收者占 arg_vars[0])"),
("module_qualified_call", """
import dex
-fn main() -> int {
- d : dex, apx = 7.0;
- a := dex_str(d);
- if !str_eq(a, "7") { return 3; }
- b := dex.dex_str(d);
- if !str_eq(b, "7") { return 4; }
- return 7;
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ a := dex_str(d)
+ if !str_eq(a, "7"):
+ return 3
+ b := dex.dex_str(d)
+ if !str_eq(b, "7"):
+ return 4
+ return 7
""", 7, "模块限定调用 m.f(x)(apx 批 T2 新增活点;rc=4 即该形态未转换)"),
# ── #2026-09-16-18:第 9 个 binary64 栈参(= #2026-09-16-17 同一修复)──
("stack_arg_9th_method", """
-struct S9 { v: int }
-impl S9 {
- fn m(self: S9, a: dex, b: dex, c: dex, e: dex, f: dex, g: dex, h: dex, i: dex, x: dex) -> int {
- return @raw_int(x) / 1000000;
- }
-}
-fn main() -> int {
- s : ., mut = S9 { v = 0 };
- a1 : dex, apx = 1.0;
- a2 : dex, apx = 2.0;
- a3 : dex, apx = 3.0;
- a4 : dex, apx = 4.0;
- a5 : dex, apx = 5.0;
- a6 : dex, apx = 6.0;
- a7 : dex, apx = 7.0;
- a8 : dex, apx = 8.0;
- lx : dex, apx = 7.0;
- return s.m(a1, a2, a3, a4, a5, a6, a7, a8, lx);
-}
+struct S9:
+ v: int
+impl S9:
+ fn m(self: S9, a: dex, b: dex, c: dex, e: dex, f: dex, g: dex, h: dex, i: dex, x: dex) -> int:
+ return @raw_int(x) / 1000000
+fn main() -> int:
+ s : ., mut = S9 { v = 0 }
+ a1 : dex, apx = 1.0
+ a2 : dex, apx = 2.0
+ a3 : dex, apx = 3.0
+ a4 : dex, apx = 4.0
+ a5 : dex, apx = 5.0
+ a6 : dex, apx = 6.0
+ a7 : dex, apx = 7.0
+ a8 : dex, apx = 8.0
+ lx : dex, apx = 7.0
+ return s.m(a1, a2, a3, a4, a5, a6, a7, a8, lx)
""", 7, "#2026-09-16-18 第 9 个 binary64 栈参(方法形)"),
("stack_arg_9th_direct", """
-fn f9(a: dex, b: dex, c: dex, e: dex, f: dex, g: dex, h: dex, i: dex, x: dex) -> int {
- return @raw_int(x) / 1000000;
-}
-fn main() -> int {
- a1 : dex, apx = 1.0;
- a2 : dex, apx = 2.0;
- a3 : dex, apx = 3.0;
- a4 : dex, apx = 4.0;
- a5 : dex, apx = 5.0;
- a6 : dex, apx = 6.0;
- a7 : dex, apx = 7.0;
- a8 : dex, apx = 8.0;
- lx : dex, apx = 7.0;
- return f9(a1, a2, a3, a4, a5, a6, a7, a8, lx);
-}
+fn f9(a: dex, b: dex, c: dex, e: dex, f: dex, g: dex, h: dex, i: dex, x: dex) -> int:
+ return @raw_int(x) / 1000000
+fn main() -> int:
+ a1 : dex, apx = 1.0
+ a2 : dex, apx = 2.0
+ a3 : dex, apx = 3.0
+ a4 : dex, apx = 4.0
+ a5 : dex, apx = 5.0
+ a6 : dex, apx = 6.0
+ a7 : dex, apx = 7.0
+ a8 : dex, apx = 8.0
+ lx : dex, apx = 7.0
+ return f9(a1, a2, a3, a4, a5, a6, a7, a8, lx)
""", 7, "直调同形对照(#2026-09-16-18 机理裁定用:同形只差调用形态)"),
# ── 聚合四类写点 ──
("struct_literal_field", """
-struct S3 { f: dex }
-fn main() -> int { d : dex, apx = 7.0; s : ., mut = S3 { f = d }; return @raw_int(s.f) / 1000000; }
+struct S3:
+ f: dex
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S3 { f = d }
+ return @raw_int(s.f) / 1000000
""", 7, "结构体字面量字段写点"),
("struct_field_assign", """
-struct S3 { f: dex }
-fn main() -> int { d : dex, apx = 7.0; s : ., mut = S3 { f = 1.0 }; s.f = d; return @raw_int(s.f) / 1000000; }
+struct S3:
+ f: dex
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S3 { f = 1.0 }
+ s.f = d
+ return @raw_int(s.f) / 1000000
""", 7, "字段赋值写点"),
("array_literal_elem", """
-fn main() -> int { d : dex, apx = 7.0; a : [dex; 2] = [d, 1.0]; return @raw_int(a[0]) / 1000000; }
+fn main() -> int:
+ d : dex, apx = 7.0
+ a : [dex; 2] = [d, 1.0]
+ return @raw_int(a[0]) / 1000000
""", 7, "数组字面量元素写点"),
("index_assign_dynamic", """
-fn main() -> int { d : dex, apx = 7.0; a : [dex; 2] = [1.0, 1.0]; i : ., mut = 0; a[i] = d; return @raw_int(a[i]) / 1000000; }
+fn main() -> int:
+ d : dex, apx = 7.0
+ a : [dex; 2] = [1.0, 1.0]
+ i : ., mut = 0
+ a[i] = d
+ return @raw_int(a[i]) / 1000000
""", 7, "动态下标赋值写点"),
("slice_elem_assign", """
-fn main() -> int { d : dex, apx = 7.0; a : [dex; 3] = [1.0, 1.0, 1.0]; s := a[0..2]; s[1] = d; return @raw_int(s[1]) / 1000000; }
+fn main() -> int:
+ d : dex, apx = 7.0
+ a : [dex; 3] = [1.0, 1.0, 1.0]
+ s := a[0..2]
+ s[1] = d
+ return @raw_int(s[1]) / 1000000
""", 7, "切片元素写点"),
("tuple_elem", """
-fn main() -> int { d : dex, apx = 7.0; t := (d, 1.0); return @raw_int(t . 0) / 1000000; }
+fn main() -> int:
+ d : dex, apx = 7.0
+ t := (d, 1.0)
+ return @raw_int(t . 0) / 1000000
""", 7, "元组元素写点(数字下标须写 `t . 0`,带空格——`t.0` 会被词法器读成 dex 字面量)"),
("enum_payload", """
-enum E1 { V(dex) }
-fn main() -> int { d : dex, apx = 7.0; e := V(d); return match e { V(x) => { return @raw_int(x) / 1000000; } }; }
+enum E1:
+ V(dex)
+fn main() -> int:
+ d : dex, apx = 7.0
+ e := V(d)
+ return match e:
+ V(x) =>:
+ return @raw_int(x) / 1000000
""", 7, "枚举载荷写点"),
("pointer_write", """
-fn main() -> int {
- d : dex, apx = 7.0;
- x : dex, mut = 1.0;
- p := &x;
- *p = d;
- return @raw_int(x) / 1000000;
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ x : dex, mut = 1.0
+ p := &x
+ *p = d
+ return @raw_int(x) / 1000000
""", 7, "指针写 `*p = d`(apx 批 T2 新增活点;check 另发 B04 软诊断 = TODO #2026-09-16-14 既有面)"),
# ── ⑦a:全局运行期初值 ──
("global_runtime_init_apx", """
-fn sc() -> dex { return 7.0; }
-g11 : dex, apx, mut = sc();
-fn main() -> int { return @raw_int(g11) / 1000000; }
+fn sc() -> dex:
+ return 7.0
+g11 : dex, apx, mut = sc()
+fn main() -> int:
+ return @raw_int(g11) / 1000000
""", 7, "⑦a 全局运行期初值(apx 全局,mut 必写)"),
("global_apx_as_method_arg", """
-struct S1 { v: int }
-impl S1 { fn m(self: S1, x: dex) -> int { return @raw_int(x) / 1000000; } }
-g13 : dex, apx, mut = 7.0;
-fn main() -> int { s : ., mut = S1 { v = 0 }; return s.m(g13); }
+struct S1:
+ v: int
+impl S1:
+ fn m(self: S1, x: dex) -> int:
+ return @raw_int(x) / 1000000
+g13 : dex, apx, mut = 7.0
+fn main() -> int:
+ s : ., mut = S1 { v = 0 }
+ return s.m(g13)
""", 7, "apx 全局作方法实参(全局 vs 局部同形对拍)"),
# ── 比较点声明面查表(L10)──
("compare_agg_read_vs_exact", """
-struct S3 { f: dex }
-fn main() -> int {
- e : dex = 1.5;
- s : ., mut = S3 { f = 1.5 };
- if s.f == e { return 1; }
- return 0;
-}
+struct S3:
+ f: dex
+fn main() -> int:
+ e : dex = 1.5
+ s : ., mut = S3 { f = 1.5 }
+ if s.f == e:
+ return 1
+ return 0
""", 1, "聚合读 vs 精确值比较(L10;无声明面查表 ⇒ 0)"),
# ── 非回归(修法不得改坏已覆盖面)──
("nonreg_direct_call", """
-fn g(x: dex) -> int { return @raw_int(x) / 1000000; }
-fn main() -> int { d : dex, apx = 7.0; return g(d); }
+fn g(x: dex) -> int:
+ return @raw_int(x) / 1000000
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(d)
""", 7, "直调实参(已覆盖面)"),
("nonreg_return_site", """
-fn f() -> dex { d : dex, apx = 7.0; return d; }
-fn main() -> int { v := f(); return @raw_int(v) / 1000000; }
+fn f() -> dex:
+ d : dex, apx = 7.0
+ return d
+fn main() -> int:
+ v := f()
+ return @raw_int(v) / 1000000
""", 7, "返回点(已覆盖面;apx 审计 ②a「恒不触发」已被证伪)"),
("nonreg_generic_dex_param", """
-fn g12[T](t: T, x: dex) -> int { return @raw_int(x) / 1000000; }
-fn main() -> int { d : dex, apx = 7.0; return g12(1, d); }
+fn g12[T](t: T, x: dex) -> int:
+ return @raw_int(x) / 1000000
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g12(1, d)
""", 7, "泛型实例化后 dex 形参(非回归钉)"),
("nonreg_exact_struct", """
-struct S3 { f: dex }
-fn main() -> int { d : dex = 7.0; s : ., mut = S3 { f = d }; return @raw_int(s.f) / 1000000; }
+struct S3:
+ f: dex
+fn main() -> int:
+ d : dex = 7.0
+ s : ., mut = S3 { f = d }
+ return @raw_int(s.f) / 1000000
""", 7, "精确形对照(结构体字段)"),
("nonreg_exact_array", """
-fn main() -> int { d : dex = 7.0; a : [dex; 2] = [d, 1.0]; return @raw_int(a[0]) / 1000000; }
+fn main() -> int:
+ d : dex = 7.0
+ a : [dex; 2] = [d, 1.0]
+ return @raw_int(a[0]) / 1000000
""", 7, "精确形对照(数组元素)"),
("nonreg_exact_enum", """
-enum E1 { V(dex) }
-fn main() -> int { d : dex = 7.0; e := V(d); return match e { V(x) => { return @raw_int(x) / 1000000; } }; }
+enum E1:
+ V(dex)
+fn main() -> int:
+ d : dex = 7.0
+ e := V(d)
+ return match e:
+ V(x) =>:
+ return @raw_int(x) / 1000000
""", 7, "精确形对照(枚举载荷)"),
# ══════════════════════════════════════════════════════════════════════════
# ✅ **已重锁(2026-09-17 批 5 / opt-dex;TODO #2026-09-16-29 = 原 #91)—— 旧值 15 留痕**
@@ -245,11 +315,14 @@ def build_and_run(source, tag):
# · 覆盖面(本批新增的完整判据网)见 `tests/selfhost/test_opt_dex.py`(30 例 + 四态对拍)。
# ══════════════════════════════════════════════════════════════════════════
("relocked_optional_dex_pinch", """
-fn main() -> int {
- d : dex, apx = 7.0;
- x : dex? = d;
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ x : dex? = d
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "重锁(批 5 · 原哨兵值 15 已退役;留痕见上注)"),
]
@@ -293,8 +366,8 @@ def test_sentinel_annotation_present():
def test_decl_form_selfcheck():
"""**覆盖面自证(防「探针不触发」假绿)**:显式形建立 apx 槽、推断形不建立。
判别法 = `.cir` 里是否出现 binary64 位模式常量(`const dex = <大整数>`)。"""
- explicit = ("// x\nfn main() -> int { d : dex, apx = 7.0; return @raw_int(d) / 1000000; }\n")
- inferred = ("// x\nfn main() -> int { d : ., apx = 7.0; return @raw_int(d) / 1000000; }\n")
+ explicit = ("// x\nfn main() -> int:\n d : dex, apx = 7.0\n return @raw_int(d) / 1000000\n")
+ inferred = ("// x\nfn main() -> int:\n d : ., apx = 7.0\n return @raw_int(d) / 1000000\n")
r1 = run_corec(["cir"], explicit)
import re
def max_const(txt):
@@ -319,7 +392,7 @@ def max_const(txt):
v2 = -1
# 反向自证:显式形在解释器下必被拒收(IR_F2I 无 binary64 语义)
it = subprocess.run([str(COREC), "run",
- "fn main() -> int { d : dex, apx = 7.0; return @raw_int(d) / 1000000; }"],
+ "fn main() -> int:\n d : dex, apx = 7.0\n return @raw_int(d) / 1000000\n"],
cwd=BASE, capture_output=True, text=True, timeout=120)
if it.returncode != 255:
print(f"[FAIL] 显式形解释器未拒收(rc={it.returncode},期望 255)")
@@ -332,14 +405,24 @@ def test_double_form_parity():
"""C1 双形对拍(通用腿):同一形态的 **apx 形 vs 精确形** 结果必须一致。"""
pairs = [
("field", """
-struct S3 { f: dex }
-fn main() -> int { d : D = DVAL; s : ., mut = S3 { f = d }; return @raw_int(s.f) / 1000000; }
+struct S3:
+ f: dex
+fn main() -> int:
+ d : D = DVAL
+ s : ., mut = S3 { f = d }
+ return @raw_int(s.f) / 1000000
"""),
("elem", """
-fn main() -> int { d : D = DVAL; a : [dex; 2] = [d, 1.0]; return @raw_int(a[0]) / 1000000; }
+fn main() -> int:
+ d : D = DVAL
+ a : [dex; 2] = [d, 1.0]
+ return @raw_int(a[0]) / 1000000
"""),
("tuple", """
-fn main() -> int { d : D = DVAL; t := (d, 1.0); return @raw_int(t . 0) / 1000000; }
+fn main() -> int:
+ d : D = DVAL
+ t := (d, 1.0)
+ return @raw_int(t . 0) / 1000000
"""),
]
bad = 0
diff --git a/tests/selfhost/test_apx_tag.py b/tests/selfhost/test_apx_tag.py
index e4073cf0..6b762e95 100644
--- a/tests/selfhost/test_apx_tag.py
+++ b/tests/selfhost/test_apx_tag.py
@@ -58,11 +58,7 @@ def run_inline(source):
def test_apx_tag_parses():
# 1) apx 标签合法:check 通过(exit 0)
src = (
- "fn main() -> int {\n"
- " x : int, apx = 42;\n"
- " y : int, apx, mut = 84;\n" # apx 与 mut 同槽位、可混排
- " return x + y;\n"
- "}\n"
+ "fn main() -> int:\n x : int, apx = 42\n y : int, apx, mut = 84\n return x + y\n"
)
r = run_corec(["check"], src)
if r.returncode != 0:
@@ -73,10 +69,7 @@ def test_apx_tag_parses():
# 2) 未知标签非法:check 报错(exit != 0,TA08)
src2 = (
- "fn main() -> int {\n"
- " x : int, bogus_tag = 42;\n"
- " return x;\n"
- "}\n"
+ "fn main() -> int:\n x : int, bogus_tag = 42\n return x\n"
)
r2 = run_corec(["check"], src2)
output2 = r2.stdout + r2.stderr
@@ -94,8 +87,8 @@ def test_apx_tag_parses():
def test_apx_tag_no_semantic_change():
# 1) 语义不变:带/不带 apx 的同一程序 run 返回值一致(interp 跳过 IR_APPROX)
- plain_src = "fn main() -> int { x : int = 42; y : int = 84; return x + y; }"
- apx_src = "fn main() -> int { x : int, apx = 42; y : int, apx = 84; return x + y; }"
+ plain_src = "fn main() -> int:\n x : int = 42\n y : int = 84\n return x + y\n"
+ apx_src = "fn main() -> int:\n x : int, apx = 42\n y : int, apx = 84\n return x + y\n"
rp = run_inline(plain_src)
ra = run_inline(apx_src)
if rp.returncode != ra.returncode or rp.returncode != 126:
@@ -107,19 +100,10 @@ def test_apx_tag_no_semantic_change():
# 2) IR 差异:仅 apx 变量处多 IR_APPROX(cir dump 每变量恰一条 `approx`)
plain_file = (
- "fn main() -> int {\n"
- " x : int = 42;\n"
- " y : int = 84;\n"
- " return x + y;\n"
- "}\n"
+ "fn main() -> int:\n x : int = 42\n y : int = 84\n return x + y\n"
)
apx_file = (
- "fn main() -> int {\n"
- " x : int, apx = 42;\n"
- " y : int = 84;\n" # 无 apx 的变量不发射
- " z : int, apx = 126;\n"
- " return x + y + z;\n"
- "}\n"
+ "fn main() -> int:\n x : int, apx = 42\n y : int = 84\n z : int, apx = 126\n return x + y + z\n"
)
rc = run_corec(["cir"], plain_file)
out_plain = rc.stdout + rc.stderr
diff --git a/tests/selfhost/test_apx_tag_scope.py b/tests/selfhost/test_apx_tag_scope.py
index 09c98cb0..cafd7b6d 100644
--- a/tests/selfhost/test_apx_tag_scope.py
+++ b/tests/selfhost/test_apx_tag_scope.py
@@ -28,22 +28,29 @@
COREC = BASE / "build" / "corec"
REJECTS = [
- ("optdex_apx", "x : dex?, apx = None;", "可选 dex(无表示路径)"),
- ("inferred_dot_apx", "x : ., apx = 1.0;", "推断形(`.`)——errata 记载:declared_ti 落 TI_UNIT,apx 槽压根不建立"),
- ("auto_apx", "x : auto, apx = 1.0;", "auto(推断)"),
- ("string_apx", 'x : string, apx = "s";', "string 声明"),
- ("bool_apx", "x : bool, apx = true;", "bool 声明"),
+ ("optdex_apx", "x : dex?, apx = none\n", "可选 dex(无表示路径)"),
+ ("inferred_dot_apx", "x : ., apx = 1.0\n", "推断形(`.`)——errata 记载:declared_ti 落 TI_UNIT,apx 槽压根不建立"),
+ ("auto_apx", "x : auto, apx = 1.0\n", "auto(推断)"),
+ ("string_apx", 'x : string, apx = "s"\n', "string 声明"),
+ ("bool_apx", "x : bool, apx = true\n", "bool 声明"),
]
ACCEPTS = [
- ("dex_apx", "x : dex, apx = 7.0;", 0, "白名单:表示路径(合法形,逐字节不变面)"),
- ("int_apx", "x : int, apx = 42;", 0, "白名单:既有契约的纯注解(test_apx_tag 钉)"),
+ ("dex_apx", "x : dex, apx = 7.0\n", 0, "白名单:表示路径(合法形,逐字节不变面)"),
+ ("int_apx", "x : int, apx = 42\n", 0, "白名单:既有契约的纯注解(test_apx_tag 钉)"),
]
+def _indent_body(b: str) -> str:
+ """声明片段(自带换行)⇒ v4 函数体 region:逐行 +4 空格。"""
+ if not b.endswith("\n"):
+ b += "\n"
+ return "".join((" " + ln) if ln.strip() else ln for ln in b.splitlines(keepends=True))
+
+
def run_case(name, decl, expect_reject):
src = (f"// apxscope-{uuid.uuid4()}\n"
- f"fn main() -> int {{ {decl} return 0; }}\n")
+ f"fn main() -> int:\n{_indent_body(decl)} return 0\n")
with tempfile.NamedTemporaryFile("w", suffix=".cr", delete=False) as f:
f.write(src)
path = f.name
diff --git a/tests/selfhost/test_arg_inference_gap.py b/tests/selfhost/test_arg_inference_gap.py
index 7747955f..1f424e39 100644
--- a/tests/selfhost/test_arg_inference_gap.py
+++ b/tests/selfhost/test_arg_inference_gap.py
@@ -46,93 +46,166 @@
# ── 腿 A:响亮面(139)──
("A1_module_call_as_arg", "crash", 0, """
import fmt
-fn main() -> int { if !str_eq(fmt.int_str(7), "7") { return 3; } return 0; }
+fn main() -> int:
+ if !str_eq(fmt.int_str(7), "7"):
+ return 3
+ return 0
"""),
("A2_two_module_calls_as_args", "crash", 0, """
import fmt
-fn main() -> int { if !str_eq(fmt.int_str(7), fmt.int_str(7)) { return 3; } return 0; }
+fn main() -> int:
+ if !str_eq(fmt.int_str(7), fmt.int_str(7)):
+ return 3
+ return 0
"""),
("A3_method_call_as_arg", "crash", 0, """
-struct S { f: int }
-impl S { fn m(self: S, x: int) -> int { return x + 1; } }
-fn m_eq(a: int, b: int) -> int { if a == b { return 1; } return 0; }
-fn main() -> int { s : ., mut = S { f = 0 }; if m_eq(s.m(6), 7) == 0 { return 3; } return 0; }
+struct S:
+ f: int
+impl S:
+ fn m(self: S, x: int) -> int:
+ return x + 1
+fn m_eq(a: int, b: int) -> int:
+ if a == b:
+ return 1
+ return 0
+fn main() -> int:
+ s : ., mut = S { f = 0 }
+ if m_eq(s.m(6), 7) == 0:
+ return 3
+ return 0
"""),
("A4_helper_one_module_call", "crash", 0, """
import fmt
-fn one(a: string) -> int { if !str_eq(a, "7") { return 3; } return 0; }
-fn main() -> int { return one(fmt.int_str(7)); }
+fn one(a: string) -> int:
+ if !str_eq(a, "7"):
+ return 3
+ return 0
+fn main() -> int:
+ return one(fmt.int_str(7))
"""),
("A5_helper_method_result", "crash", 0, """
-struct P { v: int }
-impl P { fn get(self: P) -> int { return self.v; } }
-fn show(x: int) -> int { return x; }
-fn main() -> int { p : ., mut = P { v = 0 }; return show(p.get()); }
+struct P:
+ v: int
+impl P:
+ fn get(self: P) -> int:
+ return self.v
+fn show(x: int) -> int:
+ return x
+fn main() -> int:
+ p : ., mut = P { v = 0 }
+ return show(p.get())
"""),
("A6_three_arg_outer", "crash", 0, """
import fmt
-fn str_neq_3(a: string, b: string, c: int) -> int { if !str_eq(a, b) { return 1; } return 0; }
-fn main() -> int { return str_neq_3(fmt.int_str(7), "7", 1); }
+fn str_neq_3(a: string, b: string, c: int) -> int:
+ if !str_eq(a, b):
+ return 1
+ return 0
+fn main() -> int:
+ return str_neq_3(fmt.int_str(7), "7", 1)
"""),
("A7_module_call_arg_in_let", "crash", 0, """
import fmt
-fn main() -> int { b := str_eq(fmt.int_str(7), "7"); if !b { return 3; } return 0; }
+fn main() -> int:
+ b := str_eq(fmt.int_str(7), "7")
+ if !b:
+ return 3
+ return 0
"""),
("A8_module_call_arg_in_if", "crash", 0, """
import fmt
-fn main() -> int { if !str_eq(fmt.int_str(7), "7") { return 3; } return 0; }
+fn main() -> int:
+ if !str_eq(fmt.int_str(7), "7"):
+ return 3
+ return 0
"""),
# ── 腿 B:静默面(零诊断)──
# 注意:B1 当前**同时**是 check 零诊断(静默面)**且**运行时 139 —— 静默指的正是「无诊断」这一层。
("B1_undefined_fn_in_arg_of_resolved_call", "silent", None, """
-fn g(x: int) -> int { return x; }
-fn main() -> int { return g(nosuchfn(1)); }
+fn g(x: int) -> int:
+ return x
+fn main() -> int:
+ return g(nosuchfn(1))
"""),
# ── 对照(当前即绿)──
("C1_binding_form", "green", 0, """
import fmt
-fn main() -> int { x := fmt.int_str(7); if !str_eq(x, "7") { return 3; } return 0; }
+fn main() -> int:
+ x := fmt.int_str(7)
+ if !str_eq(x, "7"):
+ return 3
+ return 0
"""),
("C2_binding_form_stmt", "green", 0, """
import fmt
-fn main() -> int { x := fmt.int_str(7); return 0; }
+fn main() -> int:
+ x := fmt.int_str(7)
+ return 0
"""),
("C3_module_outer_single_arg", "green", 0, """
import fmt
import io
-fn main() -> int { println(fmt.int_str(7)); return 0; }
+fn main() -> int:
+ println(fmt.int_str(7))
+ return 0
"""),
("C4_direct_nested", "green", 0, """
import fmt
-fn main() -> int { if !str_eq(int_str(7), "7") { return 3; } return 0; }
+fn main() -> int:
+ if !str_eq(int_str(7), "7"):
+ return 3
+ return 0
"""),
("C5_generic_nested", "green", 0, """
-fn idf[T](x: T) -> T { return x; }
-fn ieq(a: int, b: int) -> int { if a == b { return 1; } return 0; }
-fn main() -> int { if ieq(idf(7), 7) == 0 { return 3; } return 0; }
+fn idf[T](x: T) -> T:
+ return x
+fn ieq(a: int, b: int) -> int:
+ if a == b:
+ return 1
+ return 0
+fn main() -> int:
+ if ieq(idf(7), 7) == 0:
+ return 3
+ return 0
"""),
("C6_direct_in_if", "green", 0, """
import fmt
-fn main() -> int { if !str_eq(int_str(7), "7") { return 3; } return 0; }
+fn main() -> int:
+ if !str_eq(int_str(7), "7"):
+ return 3
+ return 0
"""),
("C7_module_outer_infers_args", "silent_control", None, """
import fmt
-fn main() -> int { x := fmt.int_str(nosuchfn(1)); return 0; }
+fn main() -> int:
+ x := fmt.int_str(nosuchfn(1))
+ return 0
"""),
("C8_position_independence_exact", "green", 7, """
-fn seven() -> int { return 7; }
-fn main() -> int { return seven(); }
+fn seven() -> int:
+ return 7
+fn main() -> int:
+ return seven()
"""),
("C9_method_outer_infers_args", "silent_control", None, """
-struct S { f: int }
-impl S { fn m2(self: S, x: int) -> int { return x; } }
-fn main() -> int { s : ., mut = S { f = 0 }; return s.m2(nosuchfn(1)); }
+struct S:
+ f: int
+impl S:
+ fn m2(self: S, x: int) -> int:
+ return x
+fn main() -> int:
+ s : ., mut = S { f = 0 }
+ return s.m2(nosuchfn(1))
"""),
("A9_local_helper_wrapping_io", "crash", 0, """
import fmt
import io
-fn main() -> int { log2(fmt.int_str(7)); return 0; }
-fn log2(s: string) -> int { println(s); return 0; }
+fn main() -> int:
+ log2(fmt.int_str(7))
+ return 0
+fn log2(s: string) -> int:
+ println(s)
+ return 0
"""),
]
@@ -177,22 +250,25 @@ def test_leg_e_range_go_iter_var():
背景:本条 = **修实参推断顺带暴露的 checker `go` 绑定缺口**(`parser.cr:617` 只记名、
`checker.cr:2981-3000` 原先不 bind)—— 这是本批**第二个**顺带修复的既有缺陷。"""
e1 = """
-fn square(x: int) -> int { return x * x; }
-fn main() -> int {
- arr := go i 0..3 square(i);
- return arr[0] + arr[1] + arr[2];
-}
+fn square(x: int) -> int:
+ return x * x
+fn main() -> int:
+ arr := go i 0..3 square(i)
+ return arr[0] + arr[1] + arr[2]
"""
e2 = """
-fn square(x: int) -> int { return x * x; }
-fn main() -> int {
- arr := go i 0..3 square(i);
- return i;
-}
+fn square(x: int) -> int:
+ return x * x
+fn main() -> int:
+ arr := go i 0..3 square(i)
+ return i
"""
e3 = """
-fn square(x: int) -> int { return x * x; }
-fn main() -> int { ch := go square(21); return 0; }
+fn square(x: int) -> int:
+ return x * x
+fn main() -> int:
+ ch := go square(21)
+ return 0
"""
bad = 0
chk, codes, bld, elf = observe(e1)
@@ -235,15 +311,27 @@ def test_leg_d_generic_instance_key():
不得是退化键(`idf[unit]`)—— **TODO #2026-09-16-33 的既有缺陷 = 本批附带修复**。
与腿 B 同性质:**「修好了」的正据**(改前实参位必得 `idf[unit]`)。"""
let_src = """
-struct P { v: int }
-fn idf[T](x: T) -> int { return 7; }
-fn main() -> int { p : ., mut = P { v = 1 }; r := idf(p); return r; }
+struct P:
+ v: int
+fn idf[T](x: T) -> int:
+ return 7
+fn main() -> int:
+ p : ., mut = P { v = 1 }
+ r := idf(p)
+ return r
"""
arg_src = """
-struct P { v: int }
-fn idf[T](x: T) -> int { return 7; }
-fn ieq(a: int, b: int) -> int { if a == b { return 1; } return 0; }
-fn main() -> int { p : ., mut = P { v = 1 }; return ieq(idf(p), 7); }
+struct P:
+ v: int
+fn idf[T](x: T) -> int:
+ return 7
+fn ieq(a: int, b: int) -> int:
+ if a == b:
+ return 1
+ return 0
+fn main() -> int:
+ p : ., mut = P { v = 1 }
+ return ieq(idf(p), 7)
"""
bad = 0
for tag, src in (("LET 位", let_src), ("实参位", arg_src)):
diff --git a/tests/selfhost/test_at_rename.py b/tests/selfhost/test_at_rename.py
index 0dd8b5f2..d3249713 100644
--- a/tests/selfhost/test_at_rename.py
+++ b/tests/selfhost/test_at_rename.py
@@ -124,7 +124,7 @@ def case_old_check(name, source, lineno, colno):
def case_run_face(name, snippet, expect_rc, needle=None):
"""`run`(解释器面)同判:期望 rc + (可选)诊断文本。"""
- r = _run(["run", f"fn main() -> int {{ {snippet} return 7; }}"])
+ r = _run(["run", f"fn main() -> int:\n {snippet}\n return 7\n"])
log = r.stdout + r.stderr
if r.returncode != expect_rc:
print(f"[FAIL] {name}: expected rc {expect_rc}, got {r.returncode}: {log}")
@@ -187,10 +187,10 @@ def _cir_dump(source: str):
def main():
- stmt_old = "fn f() -> int {\n @no_bounds_check;\n return 7;\n}\nfn main() -> int { return f(); }\n"
- paren_old = "fn f() -> int {\n @no_bounds_check();\n return 7;\n}\nfn main() -> int { return f(); }\n"
- stmt_new = "fn f() -> int {\n @NoBoundsCheck;\n return 7;\n}\nfn main() -> int { return f(); }\n"
- paren_new = "fn f() -> int {\n @NoBoundsCheck();\n return 7;\n}\nfn main() -> int { return f(); }\n"
+ stmt_old = "fn f() -> int:\n @no_bounds_check\n return 7\nfn main() -> int:\n return f()\n"
+ paren_old = "fn f() -> int:\n @no_bounds_check()\n return 7\nfn main() -> int:\n return f()\n"
+ stmt_new = "fn f() -> int:\n @NoBoundsCheck\n return 7\nfn main() -> int:\n return f()\n"
+ paren_new = "fn f() -> int:\n @NoBoundsCheck()\n return 7\nfn main() -> int:\n return f()\n"
ok = [
# ── A. 旧名响亮失败 ──
@@ -198,11 +198,11 @@ def main():
case_old_rejected("old_paren_build_rejected", paren_old),
case_old_check("old_stmt_check_location", stmt_old, 2, 5),
case_old_check("old_paren_check_location", paren_old, 2, 5),
- case_run_face("old_run_rejected", "@no_bounds_check();", 1, NEEDLE_OLD),
+ case_run_face("old_run_rejected", "@no_bounds_check()", 1, NEEDLE_OLD),
# ── B. 新名等价(正控)──
case_new_ok("new_stmt_ok", stmt_new),
case_new_ok("new_paren_ok", paren_new),
- case_run_face("new_run_ok", "@NoBoundsCheck();", 7),
+ case_run_face("new_run_ok", "@NoBoundsCheck()", 7),
case_corpus("corpus_at_test", "tests/suite/at_test.cr"),
case_corpus("corpus_at_test_mini7", "tests/suite/at_test_mini7.cr"),
# ── C. .cir 显示名(括号形态有行 / 语句形态零 IR = F4 既有语义)──
@@ -277,7 +277,7 @@ def dispatch_sites_case():
def opcode_constant_case():
"""IR 操作码常量**不改**(内部标识,非语言面名字)——钉住本批的取舍。"""
text = _read("src/compiler/ast.cr")
- needle = "IR_NO_BOUNDS_CHECK : int = 35;"
+ needle = "IR_NO_BOUNDS_CHECK : int = 35"
if needle not in text:
print(f"[FAIL] opcode_constant: ast.cr 缺 {needle!r}(内部常量被误改?)")
return False
diff --git a/tests/selfhost/test_backend_bootstrap.py b/tests/selfhost/test_backend_bootstrap.py
index 47e3f070..bf4e3232 100644
--- a/tests/selfhost/test_backend_bootstrap.py
+++ b/tests/selfhost/test_backend_bootstrap.py
@@ -108,7 +108,7 @@ def main() -> int:
return 1
print("[PASS] stage1, stage2, and stage3 are byte-identical")
- smoke_src.write_text("fn main() -> int { return 7; }\n", encoding="utf-8")
+ smoke_src.write_text("fn main() -> int:\n return 7\n", encoding="utf-8")
if not run_checked(
[COREC, "build", smoke_src, "-o", smoke0, "--static", "-O", "0"],
"stage0 builds smoke CCR",
diff --git a/tests/selfhost/test_borrow.py b/tests/selfhost/test_borrow.py
index d060f84b..20f8b9bd 100644
--- a/tests/selfhost/test_borrow.py
+++ b/tests/selfhost/test_borrow.py
@@ -16,63 +16,76 @@
(
"immutable borrow then use original",
"""
-fn main() -> int {
- x := 42; r := &x; y := x; return y;
-}
+fn main() -> int:
+ x := 42
+ r := &x
+ y := x
+ return y
""",
True,
),
(
"mutable borrow then use original",
"""
-fn main() -> int {
- x : ., mut = 42; r := &mut x; y := x; return y;
-}
+fn main() -> int:
+ x : ., mut = 42
+ r := &mut x
+ y := x
+ return y
""",
True,
),
(
"multiple immutable borrows allowed",
"""
-fn main() -> int {
- x := 42; r1 := &x; r2 := &x; return 0;
-}
+fn main() -> int:
+ x := 42
+ r1 := &x
+ r2 := &x
+ return 0
""",
False,
),
(
"immutable then mutable borrow",
"""
-fn main() -> int {
- x : ., mut = 42; r1 := &x; r2 := &mut x; return 0;
-}
+fn main() -> int:
+ x : ., mut = 42
+ r1 := &x
+ r2 := &mut x
+ return 0
""",
True,
),
(
"borrow released after block scope exit",
"""
-fn main() -> int {
- x := 42;
- { r := &x; }
- y := x; return y;
-}
+fn main() -> int:
+ x := 42:
+ r := &x
+ y := x
+ return y
""",
False,
),
(
"normal copy use",
"""
-fn main() -> int { x := 42; y := x; return y; }
+fn main() -> int:
+ x := 42
+ y := x
+ return y
""",
False,
),
(
"mutable then immutable borrow",
"""
-fn main() -> int {
- x : ., mut = 42; r1 := &mut x; r2 := &x; return 0;
-}
+fn main() -> int:
+ x : ., mut = 42
+ r1 := &mut x
+ r2 := &x
+ return 0
""",
True,
),
diff --git a/tests/selfhost/test_cache_identity.py b/tests/selfhost/test_cache_identity.py
index 7eff8951..dfac47c3 100644
--- a/tests/selfhost/test_cache_identity.py
+++ b/tests/selfhost/test_cache_identity.py
@@ -60,22 +60,19 @@
M64 = 1 << 64
PROBE = """// cache identity probe (tests/selfhost/test_cache_identity.py)
-fn alpha(a: int, b: int) -> int {
- x := a + b;
- y := x * 2;
- z := y - a;
- return z;
-}
-
-fn beta(p: int) -> int {
- m := p + 1;
- n := m * m;
- return n;
-}
-
-fn main() -> int {
- return alpha(3, 4) + beta(5);
-}
+fn alpha(a: int, b: int) -> int:
+ x := a + b
+ y := x * 2
+ z := y - a
+ return z
+
+fn beta(p: int) -> int:
+ m := p + 1
+ n := m * m
+ return n
+
+fn main() -> int:
+ return alpha(3, 4) + beta(5)
"""
@@ -287,11 +284,7 @@ def check(name, cond, detail=""):
opt_fd, opt_name = tempfile.mkstemp(suffix="_cacheid_opt.cr")
opt_src = pathlib.Path(opt_name)
with os.fdopen(opt_fd, "w") as f:
- f.write("// optional-using probe (batch 8; cache must stay OFF)\n"
- "fn alpha(x: int?, y: int) -> int {\n"
- " return match x { Some(v) => { return v + y; } None => { return y; } };\n"
- "}\n"
- "fn main() -> int { return alpha(None, 1) - 1; }\n")
+ f.write("// optional-using probe (batch 8; cache must stay OFF)\nfn alpha(x: int?, y: int) -> int:\n return match x:\n Some(v) => v + y\n none => y\nfn main() -> int:\n return alpha(none, 1) - 1\n")
opt_prefix = str(opt_src).replace("/", "_")
try:
before = len(list(CACHE_DIR.glob(f"{opt_prefix}::*.cir")))
diff --git a/tests/selfhost/test_ccr_types.py b/tests/selfhost/test_ccr_types.py
index 37b205e0..039a6b58 100644
--- a/tests/selfhost/test_ccr_types.py
+++ b/tests/selfhost/test_ccr_types.py
@@ -207,8 +207,7 @@ def _rebuild_v7(data: bytes) -> bytes:
def _prog_src() -> str:
- return ("fn add(a: int, b: int) -> int { return a + b; }\n"
- "fn main() -> int { return add(40, 2); }\n")
+ return ("fn add(a: int, b: int) -> int:\n return a + b\nfn main() -> int:\n return add(40, 2)\n")
def _shell_fixture(name: str):
@@ -1038,11 +1037,7 @@ def iface_seg(data: bytes) -> bytes:
# 夹具源:2 接口(self 接收者 + &self + 带参方法)+ 1 结构 + impl 块
# (g_impl_for 边 + g_methods 方法表 + 接口方法签名项——五小节全非空)
-_T3_SRC = ("interface Show { fn show(self) -> int; }\n"
- "interface Pair2 { fn first(&self) -> int; fn second(self, x: int) -> int; }\n"
- "struct S { a: int }\n"
- "impl Show for S { fn show(self: S) -> int { return 2; } }\n"
- "fn main() -> int { s := S { a = 2 }; return s.a; }\n")
+_T3_SRC = ("interface Show:\n fn show(self) -> int\ninterface Pair2:\n fn first(&self) -> int\n fn second(self, x: int) -> int\nstruct S:\n a: int\nimpl Show for S:\n fn show(self: S) -> int:\n return 2\nfn main() -> int:\n s := S { a = 2 }\n return s.a\n")
def _t3_fixture(name: str):
@@ -1428,25 +1423,27 @@ def _cleanup(*paths):
# 复合行夹具(F2 面):BINARY 的操作数行是指针行(AK_PTR 项:b = -1 ⇒ 不可逆)——
# 该节点的项槽必须为 -1、辅码槽 = 原行号,派生码 ≡ 行号(单槽化前该槽的值)。
COMPOSITE_FIXTURE = """// R2 P5 Task 2 composite-row probe
-fn add1(p: *int) -> int { return *p + 1; }
-fn main() -> int {
- arr := [10, 20, 30];
- p := &arr[1];
- q := p + 1;
- if *q != 30 { return 1; }
- return add1(p);
-}
+fn add1(p: *int) -> int:
+ return *p + 1
+fn main() -> int:
+ arr := [10, 20, 30]
+ p := &arr[1]
+ q := p + 1
+ if *q != 30:
+ return 1
+ return add1(p)
"""
# #2026-09-15-5 T2:**可缓存**夹具(无 ir_gen 期类型行分配 ⇒ `main` 有条目)——㊲ 重钉用
# (复合行的可达性见 ㊲ 注:复合 mint 行的唯一来源 = ir_gen 分配行 ⇒ 见证下不落盘)。
PLAIN_FIXTURE = """// R2 P5 Task 2 disk-code probe (T2 重钉:可缓存形态)
-fn add(a: int, b: int) -> int { return a + b; }
-fn main() -> int {
- x := add(1, 2);
- if x != 3 { return 1; }
- return 0;
-}
+fn add(a: int, b: int) -> int:
+ return a + b
+fn main() -> int:
+ x := add(1, 2)
+ if x != 3:
+ return 1
+ return 0
"""
# 探针源(内联夹具;覆盖清单内 4 个类型行 + 三个陷阱形态):
@@ -1454,26 +1451,30 @@ def _cleanup(*paths):
# IR_BOUNDS_CHECK 的 tk=0/1(旗标;1 数值恰是 TI_DEX 行)、
# IR_CALL 的 tk ∈ {int,bool,str,unit}(合法行但后端不按 ti 分派)。
TK_FIXTURE = """// R2 P4 Task 4 tk-slot probe
-fn main() -> int {
- arr := [10, 20, 30, 40, 50];
- p := &arr[2];
- if *p != 30 { return 1; }
- q : ., mut = 42;
- qp := &q;
- *qp = 99;
- s := "hi";
- b := true;
- d := 1.5;
- x := 40 + 2;
- if b { x = x + 1; }
- lo : ., mut = 1;
- hi : ., mut = 3;
- sl := arr[lo..hi];
- if sl[0] != 20 { return 2; }
- if x > d { return 3; }
- if s != "hi" { return 4; }
- return x;
-}
+fn main() -> int:
+ arr := [10, 20, 30, 40, 50]
+ p := &arr[2]
+ if *p != 30:
+ return 1
+ q : ., mut = 42
+ qp := &q
+ *qp = 99
+ s := "hi"
+ b := true
+ d := 1.5
+ x := 40 + 2
+ if b:
+ x = x + 1
+ lo : ., mut = 1
+ hi : ., mut = 3
+ sl := arr[lo..hi]
+ if sl[0] != 20:
+ return 2
+ if x > d:
+ return 3
+ if s != "hi":
+ return 4
+ return x
"""
diff --git a/tests/selfhost/test_ccr_v7.py b/tests/selfhost/test_ccr_v7.py
index 926bfbc4..d031e73e 100644
--- a/tests/selfhost/test_ccr_v7.py
+++ b/tests/selfhost/test_ccr_v7.py
@@ -367,18 +367,7 @@ def read_ccr(path: str) -> bytes:
# --- tests ---
PROBE_SRC = (
- "fn pure_add(a: int, b: int) -> int { return a + b; }\n"
- "fn main() -> int {\n"
- " arr : [int; 4], mut = [0, 0, 0, 0];\n"
- " i : int = 1;\n"
- " v : int = 9;\n"
- " arr[i] = v;\n"
- " arr[0] = v + 1;\n"
- " x := arr[i];\n"
- " s : int = pure_add(x, v);\n"
- " s = s + arr[0];\n"
- " return s;\n"
- "}\n")
+ "fn pure_add(a: int, b: int) -> int:\n return a + b\nfn main() -> int:\n arr : [int; 4], mut = [0, 0, 0, 0]\n i : int = 1\n v : int = 9\n arr[i] = v\n arr[0] = v + 1\n x := arr[i]\n s : int = pure_add(x, v)\n s = s + arr[0]\n return s\n")
# --- Task 2: ENT 实记录期望(Python 独立模型 + 手算对照)---
@@ -394,13 +383,7 @@ def read_ccr(path: str) -> bytes:
IR_CALL_EXTERN = 45
ENT_SRC = (
- "fn identity(n: int) -> int { return n; }\n"
- "fn main() -> int {\n"
- " x := 1;\n"
- " x = x + 1;\n"
- " x = x + 2;\n"
- " return x;\n"
- "}\n")
+ "fn identity(n: int) -> int:\n return n\nfn main() -> int:\n x := 1\n x = x + 1\n x = x + 2\n return x\n")
def model_compute_entries(nod, funcs, gcount, regs):
@@ -762,7 +745,7 @@ def _mutate_ent_field(data, rec_idx, field_off, value, fmt=' instr_cnt)
→ 拒绝。"""
- src = "fn main() -> int { return 42; }\n"
+ src = "fn main() -> int:\n return 42\n"
ccr_path = os.path.join(BASE, 'build/test_v7_entle.ccr')
try:
os.unlink(ccr_path)
@@ -828,7 +811,7 @@ def test_v7_loader_rejects_ent_liveend_oob():
def test_v7_loader_rejects_ent_ls_ge_le():
"""loader ENT 区间校验:live_start ≥ live_end(半开区间倒置/退化)→
拒绝。"""
- src = "fn main() -> int { return 42; }\n"
+ src = "fn main() -> int:\n return 42\n"
ccr_path = os.path.join(BASE, 'build/test_v7_entls.ccr')
try:
os.unlink(ccr_path)
@@ -861,8 +844,7 @@ def test_v7_loader_rejects_sym_ent_block_mismatch():
"""loader 双写对照(激活面):SYM func first_ent 与 ENT 实块界失配 →
拒绝。byte mutation:func0 记录 first_ent 字段 +1(REG 根行对照与
ENT 块界对照双路径同源拒绝)。"""
- src = ("fn add(a: int, b: int) -> int { return a + b; }\n"
- "fn main() -> int { return 42; }\n")
+ src = ("fn add(a: int, b: int) -> int:\n return a + b\nfn main() -> int:\n return 42\n")
ccr_path = os.path.join(BASE, 'build/test_v7_entblk.ccr')
try:
os.unlink(ccr_path)
@@ -905,12 +887,7 @@ def test_v7_layout_and_walk():
"""段表架构:magic/version=8/8 段规范序(EDG=tag 6 必落;TYPE=7/IFACE=8
空壳——R2 P4 Task 1)/offset 连续/NOD 40B(P6 T3 起)+ 邻接域/EDG 段完整走查 ==
文件大小。"""
- src = ("fn add(a: int, b: int) -> int { return a + b; }\n"
- "fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " for i in 0..4 { s = s + i; }\n"
- " return s;\n"
- "}\n")
+ src = ("fn add(a: int, b: int) -> int:\n return a + b\nfn main() -> int:\n s : ., mut = 0\n for i in 0..4:\n s = s + i\n return s\n")
ccr_path = os.path.join(BASE, 'build/test_v7_layout.ccr')
for p in (ccr_path,):
try:
@@ -1014,7 +991,7 @@ def test_v7_object_surface_recipe_readable():
# 出边(函数化收敛)。上列运行时断言经收敛后通道 = 封装体行为证明。
kern_src = os.path.join(BASE, 'src/lattice/ent_kernel.cr')
ktext = open(kern_src, encoding='utf-8').read()
- assert 'fn nod_inputs(n: int) {' in ktext, \
+ assert 'fn nod_inputs(n: int):' in ktext, \
"kernel nod_inputs recipe-query wrapper missing (dangling note reverted)"
drv_src = os.path.join(BASE, 'src/compiler/corearch.cr')
dtext = open(drv_src, encoding='utf-8').read()
@@ -1098,7 +1075,7 @@ def test_v7_loader_rejects_version_ne_7():
"""v9-only(R2 P6 Task 3 起合法版本 = 9):version 改成 7/8/6/5(**旧 v7 六段
文件与 v8 文件整类拒收**——D10 的落点:不得静默当「TYPE/IFACE 缺席 = 空表」)或
任意非 9 → corearch 必须拒绝。"""
- src = "fn main() -> int { return 42; }\n"
+ src = "fn main() -> int:\n return 42\n"
ccr_path = os.path.join(BASE, 'build/test_v7_reject.ccr')
try:
os.unlink(ccr_path)
@@ -1132,7 +1109,7 @@ def test_v7_loader_rejects_backward_edge():
"""拓扑不变量(v7 §4 规则 1):EDG 边 to_nod 必须 > 所属节点——byte
mutation 把 node 0 唯一出边(0→3 arena def-use)的 to_nod 改成 0(自环)
→ corearch 必须拒绝('invalid .ccr')。"""
- src = "fn main() -> int { return 42; }\n"
+ src = "fn main() -> int:\n return 42\n"
ccr_path = os.path.join(BASE, 'build/test_v7_selfloop.ccr')
try:
os.unlink(ccr_path)
@@ -1169,7 +1146,7 @@ def test_v7_loader_rejects_backward_edge():
def test_v7_loader_rejects_edg_count_mismatch():
"""Σ 校验(v7 §4 规则 3):NOD edge_count 总和 ≠ EDG edg_count → corearch
必须拒绝。byte mutation:node 0 edge_count 1 → 2(EDG 段未加记录)。"""
- src = "fn main() -> int { return 42; }\n"
+ src = "fn main() -> int:\n return 42\n"
ccr_path = os.path.join(BASE, 'build/test_v7_edgcnt.ccr')
try:
os.unlink(ccr_path)
@@ -1208,11 +1185,7 @@ def test_v7_roundtrip_elf():
0+1+2+3+4+5 = 15 → ELF 退出码 15;corearch 直载同文件同结果;中间产物 =
v7 段表架构(version 9/EDG 必落/走查全绿——R2 P4 Task 1 起 +TYPE/IFACE
空壳两段)。"""
- src = ("fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " for i in 0..6 { s = s + i; }\n"
- " return s;\n"
- "}\n")
+ src = ("fn main() -> int:\n s : ., mut = 0\n for i in 0..6:\n s = s + i\n return s\n")
ccr_path = os.path.join(BASE, 'build/test_v7_rt.ccr')
out = os.path.join(BASE, 'build/test_v7_rt')
with tempfile.NamedTemporaryFile('w', suffix='.cr', delete=False) as f:
@@ -1339,11 +1312,7 @@ def test_v7_sym_reg_target_shape():
- 根 region(SG_FUNC)行与 func 记录 1:1,span 连续铺满 NOD 空间,
first/last = 本函数条目块;嵌套 region 条目范围 = 定值点 ∈ [enter, exit)
(文件条目序连续一段);变量命名空间行数覆盖 ENT/NOD 引用。"""
- src = ("fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " for i in 0..4 { s = s + i; }\n"
- " return s;\n"
- "}\n")
+ src = ("fn main() -> int:\n s : ., mut = 0\n for i in 0..4:\n s = s + i\n return s\n")
ccr_path = os.path.join(BASE, 'build/test_v7_symreg.ccr')
try:
os.unlink(ccr_path)
@@ -1430,13 +1399,7 @@ def test_v7_sym_func_shapes():
参数 = var 声明区前 param_count 个(行序 = 参数序,类型 int);root_region
行序 1:1、span 连续铺满 NOD 空间;first/last_ent 实回填(add 参数 a/b 从未
定值 → def=-1 条目 → param_ents = 其条目 id;main 无参;条目范围 = 块界)。"""
- src = ("fn add(a: int, b: int) -> int { return a + b; }\n"
- "fn main() -> int {\n"
- " x := 1;\n"
- " x = x + 1;\n"
- " x = x + 2;\n"
- " return x;\n"
- "}\n")
+ src = ("fn add(a: int, b: int) -> int:\n return a + b\nfn main() -> int:\n x := 1\n x = x + 1\n x = x + 2\n return x\n")
ccr_path = os.path.join(BASE, 'build/test_v7_symparams.ccr')
try:
os.unlink(ccr_path)
@@ -1518,11 +1481,7 @@ def test_v7_loader_rejects_root_span_beyond_nod_space():
无上界校验(ENT 有 ele > instr_cnt 拒绝先例)。损坏文件把末函数 root
region 的 exit_nod 推出 NOD 空间(exit == instr_cnt + 1)→ corearch 必须
拒绝('invalid .ccr')。"""
- src = ("fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " for i in 0..4 { s = s + i; }\n"
- " return s;\n"
- "}\n")
+ src = ("fn main() -> int:\n s : ., mut = 0\n for i in 0..4:\n s = s + i\n return s\n")
ccr_path = os.path.join(BASE, 'build/test_v7_rootspan.ccr')
try:
os.unlink(ccr_path)
@@ -1571,11 +1530,7 @@ def test_v7_save_rejects_var_block_misalignment():
构建路径永不注入)后 Σ 不变,旧实现静默落盘行序错位的文件(声明区/
var 命名空间漂移)。位置级守卫(vs == 前缀累计)必须拒绝:rc != 0、
不落盘。"""
- src = ("fn add(a: int, b: int) -> int { return a + b; }\n"
- "fn main() -> int {\n"
- " x := 1;\n"
- " return x + 1;\n"
- "}\n")
+ src = ("fn add(a: int, b: int) -> int:\n return a + b\nfn main() -> int:\n x := 1\n return x + 1\n")
ccr_path = os.path.join(BASE, 'build/test_v7_varshift.ccr')
with tempfile.NamedTemporaryFile('w', suffix='.cr', delete=False) as f:
f.write(src)
@@ -1616,8 +1571,7 @@ def test_v7_loader_rejects_ent_var_foreign_block():
起点 → 逐条语义校验(ev 命名空间 :1431/区间 :1432/def 关系 :1433-1436)
全过(只动 var_id 一字段)→ 块重推导见 func0 首条 var 不在其窗口 →
pcnt=0 与 SYM first_ent 实值失配 → 拒绝。命中点唯一 = :1471-1478。"""
- src = ("fn add(a: int, b: int) -> int { return a + b; }\n"
- "fn main() -> int { return 42; }\n")
+ src = ("fn add(a: int, b: int) -> int:\n return a + b\nfn main() -> int:\n return 42\n")
ccr_path = os.path.join(BASE, 'build/test_v7_entblk2.ccr')
try:
os.unlink(ccr_path)
@@ -1658,7 +1612,7 @@ def test_v7_loader_rejects_ent_var_foreign_block():
def test_v7_loader_rejects_ent_var_namespace_oob():
"""Task 2 review R2——ENT var_id 命名空间校验(ccr_io.cr :1431):var_id
改写出 SYM 行重建总量(= loader 侧 g_ir_var_count)→ 逐条校验拒绝。"""
- src = "fn main() -> int { return 42; }\n"
+ src = "fn main() -> int:\n return 42\n"
ccr_path = os.path.join(BASE, 'build/test_v7_entns.ccr')
try:
os.unlink(ccr_path)
@@ -1703,7 +1657,7 @@ def _first_def_entry(ents):
def test_v7_loader_rejects_ent_def_nod_oob():
"""Task 2 review R2——ENT def_nod 越界(ccr_io.cr :1434):定值条目的
def_nod 改写为 instr_cnt(= NOD 空间外第一个坐标)→ 拒绝。"""
- src = "fn main() -> int { return 42; }\n"
+ src = "fn main() -> int:\n return 42\n"
ccr_path = os.path.join(BASE, 'build/test_v7_entdef.ccr')
try:
os.unlink(ccr_path)
@@ -1739,7 +1693,7 @@ def test_v7_loader_rejects_ent_def_ne_live_start():
"""Task 2 review R2——ENT 定值条目 def == live_start 失配(ccr_io.cr
:1435):定值条目 def_nod 改写为 els+1(仍在 NOD 空间内 → 只触发
ed != els 分支)→ 拒绝。"""
- src = "fn main() -> int { return 42; }\n"
+ src = "fn main() -> int:\n return 42\n"
ccr_path = os.path.join(BASE, 'build/test_v7_entdls.ccr')
try:
os.unlink(ccr_path)
@@ -1803,12 +1757,7 @@ def test_v7_cache_hit_restore_path():
elf_cold2 = os.path.join(BASE, 'build', 'test_v7_cache_cold2.elf')
artifacts = [src_path, out_cold, out_warm, out_hyb, out_cold2,
elf_cold, elf_warm, elf_hyb, elf_cold2]
- src1 = ("fn mul2(x: int) -> int { return x * 2; }\n"
- "fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " for i in 0..4 { s = s + mul2(i); }\n"
- " return s;\n" # Σ mul2(0..3) = 0+2+4+6 = 12
- "}\n")
+ src1 = ("fn mul2(x: int) -> int:\n return x * 2\nfn main() -> int:\n s : ., mut = 0\n for i in 0..4:\n s = s + mul2(i)\n return s\n")
src2 = src1.replace('0..4', '0..6') # Σ mul2(0..5) = 30
def ccr_run(out: str) -> None:
@@ -1902,32 +1851,7 @@ def arch_elf(ccr_in: str, elf_out: str) -> None:
# 边跨函数 = 0、15 个函数各自携带 kind=1 边 ⇒ ③ 非空非退化)。
CHAIN_SRC = (
- "fn pure_add(a: int, b: int) -> int { return a + b; }\n"
- "fn id[T](x: T) -> T { return x; }\n"
- "fn effect() { a : ., mut = 0; a = 1; a = 2; }\n"
- "extern fn ext_probe(x: int) -> int;\n"
- "struct Counter { n: int }\n"
- "impl Counter {\n"
- " fn bump(self) { }\n" # dyn 方法(间接调用载体)
- "}\n"
- "fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " s = 1;\n"
- " p := pure_add(s, 1);\n" # 可证纯调用(性质①载体)
- " s = p;\n"
- " q := id(s);\n" # 泛型纯调用(Task 1 前 = 意外入链的 RED 载体)
- " s = s + q;\n"
- " effect();\n" # store 体效应调用(②-a)
- " r := ext_probe(s);\n" # extern(②-b)
- " s = s + r;\n"
- " b := load64(s);\n" # 不可解析 runtime builtin(②-c)
- " s = s + b;\n"
- " c : Counter = Counter { n: 7 };\n"
- " d : dyn = c;\n"
- " d.bump();\n" # 间接调用(②-d)
- " s = s + 1;\n"
- " return s;\n"
- "}\n")
+ "fn pure_add(a: int, b: int) -> int:\n return a + b\nfn id[T](x: T) -> T:\n return x\nfn effect():\n a : ., mut = 0\n a = 1\n a = 2\nextern fn ext_probe(x: int) -> int\nstruct Counter:\n n: int\nimpl Counter:\n fn bump(self):\nfn main() -> int:\n s : ., mut = 0\n s = 1\n p := pure_add(s, 1)\n s = p\n q := id(s)\n s = s + q\n effect()\n r := ext_probe(s)\n s = s + r\n b := load64(s)\n s = s + b\n c : Counter = Counter { n= 7 }\n d : dyn = c\n d.bump()\n s = s + 1\n return s\n")
def _op_nodes(nod, opcode, lo=0, hi=-1):
diff --git a/tests/selfhost/test_chan_handle_model.py b/tests/selfhost/test_chan_handle_model.py
index b8dd079b..92b90ca0 100644
--- a/tests/selfhost/test_chan_handle_model.py
+++ b/tests/selfhost/test_chan_handle_model.py
@@ -83,14 +83,7 @@ def main():
if os.path.exists(p):
os.unlink(p)
# ── ④ 对齐形态自证(handle 可作 string 流经:赋值 + 传参)──────────────
- probe = ("import chan\n"
- "fn main() -> int {\n"
- " ch : string = chan_make(8, 1);\n" # 返回型 = string(模型)
- " chan_send(ch, 1);\n" # 形参 = string
- " v := chan_recv(ch);\n"
- " chan_close(ch);\n"
- " return v - 1;\n"
- "}\n")
+ probe = ("import chan\nfn main() -> int:\n ch : string = chan_make(8, 1)\n chan_send(ch, 1)\n v := chan_recv(ch)\n chan_close(ch)\n return v - 1\n")
r = run_corec(["check"], probe)
if r.returncode == 0:
print("[PASS] aligned_forms: chan_make→string 赋值 + chan_send/recv/close(string) 通过")
diff --git a/tests/selfhost/test_cir_cache_narrow.py b/tests/selfhost/test_cir_cache_narrow.py
index 77571956..c36b69d3 100644
--- a/tests/selfhost/test_cir_cache_narrow.py
+++ b/tests/selfhost/test_cir_cache_narrow.py
@@ -62,7 +62,7 @@ def many_fn_src(node_delta: bool = False, extra_var: bool = False) -> str:
body.append(f" x0 := a + {i};")
for j in range(STMTS):
if i == 0 and j == 5 and extra_var:
- body.append(" xv := x0 + 7;")
+ body.append(" xv := x0 + 7\n")
nxt = "xv" if (i == 0 and extra_var and j >= 5) else f"x{j}"
if i == 0 and j == 3 and node_delta:
# 同一 dest(x4)、只多一个参与 `a` 的二元节点(不可被常量折叠掉)
@@ -74,8 +74,8 @@ def many_fn_src(node_delta: bool = False, extra_var: bool = False) -> str:
out.extend(body)
out.append("}")
# 极小函数:自身节点/边极少(P1 的被测面)
- out.append("fn tiny(a: int) -> int { return a + 1; }")
- out.append("fn main() -> int { return tiny(41); }")
+ out.append("fn tiny(a: int) -> int:\n return a + 1\n")
+ out.append("fn main() -> int:\n return tiny(41)\n")
return "\n".join(out) + "\n"
diff --git a/tests/selfhost/test_cir_str_domain_warm.py b/tests/selfhost/test_cir_str_domain_warm.py
index 42a26d9c..63d750cd 100644
--- a/tests/selfhost/test_cir_str_domain_warm.py
+++ b/tests/selfhost/test_cir_str_domain_warm.py
@@ -43,76 +43,81 @@
# ── 语料 ────────────────────────────────────────────────────────────────────
REPRO = """import io
-struct Point { x: int, y: int }
-
-fn fields_of_point() -> int {
- f := @fields(Point);
- print("fields=[");
- print(f);
- print("] len=");
- println(int_str(str_len(f)));
- return str_len(f);
-}
-
-fn main() -> int {
- r := fields_of_point();
- return r - 3;
-}
+struct Point:
+ x: int, y: int
+
+fn fields_of_point() -> int:
+ f := @fields(Point)
+ print("fields=[")
+ print(f)
+ print("] len=")
+ println(int_str(str_len(f)))
+ return str_len(f)
+
+fn main() -> int:
+ r := fields_of_point()
+ return r - 3
"""
FIRSTINTERN = """import io
-struct One { x: int }
-struct Two { x: int, y: int }
-
-fn main() -> int {
- print("ONE="); println(@fields(One));
- print("TWO="); println(@fields(Two));
- return 0;
-}
+struct One:
+ x: int
+struct Two:
+ x: int, y: int
+
+fn main() -> int:
+ print("ONE=")
+ println(@fields(One))
+ print("TWO=")
+ println(@fields(Two))
+ return 0
"""
VARNAME = """import io
-fn cat_helper(a: string, b: string) -> int {
- print("CAT="); println(a + b);
- return 0;
-}
+fn cat_helper(a: string, b: string) -> int:
+ print("CAT=")
+ println(a + b)
+ return 0
-fn main() -> int {
- cat_helper("ab", "cd");
- return 0;
-}
+fn main() -> int:
+ cat_helper("ab", "cd")
+ return 0
"""
MIX = """import io
-fn f1(n: int) -> int {
- s : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- if i % 3 == 0 { s = s + i * 2; } else { s = s + 1; }
- i = i + 1;
- }
- return s;
-}
-
-fn f2(n: int) -> int {
- s : ., mut = 1;
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- if i % 2 == 0 { s = s * 2; } else { s = s + 3; }
- i = i + 1;
- }
- return s;
-}
-
-fn main() -> int {
- print("R="); println(int_str(f1(10) + f2(9)));
- return 0;
-}
+fn f1(n: int) -> int:
+ s : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ if i % 3 == 0:
+ s = s + i * 2
+ else:
+ s = s + 1
+ i = i + 1
+ return s
+
+fn f2(n: int) -> int:
+ s : ., mut = 1
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ if i % 2 == 0:
+ s = s * 2
+ else:
+ s = s + 3
+ i = i + 1
+ return s
+
+fn main() -> int:
+ print("R=")
+ println(int_str(f1(10) + f2(9)))
+ return 0
"""
diff --git a/tests/selfhost/test_cir_warm_path.py b/tests/selfhost/test_cir_warm_path.py
index 2723d428..9b0aa31d 100644
--- a/tests/selfhost/test_cir_warm_path.py
+++ b/tests/selfhost/test_cir_warm_path.py
@@ -50,55 +50,49 @@
# ── 探针源(无 import、无泛型、无可选 ⇒ 缓存全开)──────────────────────────
BASE_PROBE = """// warm-path probe (tests/selfhost/test_cir_warm_path.py)
-fn add(a: int, b: int) -> int {
- return a + b;
-}
-
-fn scale(x: int) -> int {
- return x * 3;
-}
-
-fn pick(i: int) -> string {
- if i > 0 { return "alpha"; }
- if i > 1 { return "beta"; }
- return "gamma";
-}
-
-fn main() -> int {
- s : ., mut = add(1, 2);
- s = s + scale(4);
- t := pick(0);
- return s;
-}
+fn add(a: int, b: int) -> int:
+ return a + b
+
+fn scale(x: int) -> int:
+ return x * 3
+
+fn pick(i: int) -> string:
+ if i > 0:
+ return "alpha"
+ if i > 1:
+ return "beta"
+ return "gamma"
+
+fn main() -> int:
+ s : ., mut = add(1, 2)
+ s = s + scale(4)
+ t := pick(0)
+ return s
"""
ZERO_STR_PROBE = """// warm-path probe: 无字符串常量
-fn twice(x: int) -> int {
- return x * 2;
-}
-
-fn main() -> int {
- a : ., mut = 0;
- i : ., mut = 1;
- loop {
- if i > 8 { break; }
- a = a + twice(i);
- i = i + 1;
- }
- return a;
-}
+fn twice(x: int) -> int:
+ return x * 2
+
+fn main() -> int:
+ a : ., mut = 0
+ i : ., mut = 1
+ loop:
+ if i > 8:
+ break
+ a = a + twice(i)
+ i = i + 1
+ return a
"""
BIG_STR_PROBE = """// warm-path probe: 大字符串字面量(4KB)
-fn big() -> string {
- s := "%s";
- return s;
-}
-
-fn main() -> int {
- t := big();
- return 42;
-}
+fn big() -> string:
+ s := "%s"
+ return s
+
+fn main() -> int:
+ t := big()
+ return 42
""" % ("A" * 4096)
@@ -106,18 +100,19 @@ def many_funcs_probe(n: int) -> str:
parts = ["// warm-path probe: %d 函数" % n]
for i in range(n):
parts.append("fn f%d(x: int) -> int { return x + %d; }" % (i, i))
- parts.append("fn main() -> int { return f0(0) + f1(1) + f2(2); }")
+ parts.append("fn main() -> int:\n return f0(0) + f1(1) + f2(2)\n")
return "\n".join(parts) + "\n"
OPTIONAL_PROBE = """// warm-path probe: 可选程序(表示面启用 ⇒ .cir 缓存关闭)
-fn g() -> int? { return Some(1); }
-
-fn main() -> int {
- x : int? = 5;
- y := g();
- return match x { Some(v) => v, None => 0, };
-}
+fn g() -> int?:
+ return Some(1)
+
+fn main() -> int:
+ x : int? = 5
+ y := g()
+ return match x:
+ Some(v) => v, none => 0,
"""
PAD_FUNCS = 400
diff --git a/tests/selfhost/test_compile.py b/tests/selfhost/test_compile.py
index 60f77944..856a7b9e 100644
--- a/tests/selfhost/test_compile.py
+++ b/tests/selfhost/test_compile.py
@@ -109,8 +109,11 @@ def compile_selfhost():
# ── Test 1: Basic interpreter run ──
print("=== Test 1: Basic Interpreter Run ===")
src1 = '''
-fn add(a: int, b: int) -> int { return a + b; }
-fn main() -> int { return add(3, 4); }
+fn add(a: int, b: int) -> int:
+ return a + b
+
+fn main() -> int:
+ return add(3, 4)
'''
lex = Lexer(src1)
ast = Parser(lex.tokenize()).parse_compilation_unit()
@@ -156,7 +159,33 @@ def compile_selfhost():
os.remove(p)
with open(test_src, 'w') as f:
- f.write("fn main() -> int { return 42; }\n")
+ f.write("""struct Point:
+ x: int
+ y: int
+
+enum Mode:
+ | Sum
+ | Zero
+
+impl Point:
+ fn sum(&self) -> int:
+ return self.x + self.y
+
+fn main() -> int:
+ #check(1 < 2)
+ #ensure(result == 42)
+ point := Point { x = 20, y = 22 }
+ mode := Sum
+ empty : int? = none
+ ignored := match empty:
+ | none => 0
+ | value => value
+ return match mode:
+ | Sum =>
+ value : typeof(point.x) = point.sum()
+ value
+ | Zero => 0
+""")
r = subprocess.run(
[os.path.join(build_dir, 'corec'), 'build', test_src, '-o', test_bin, '--static'],
diff --git a/tests/selfhost/test_dex_arith.py b/tests/selfhost/test_dex_arith.py
index 327fb9ab..8b75e3d0 100644
--- a/tests/selfhost/test_dex_arith.py
+++ b/tests/selfhost/test_dex_arith.py
@@ -56,49 +56,17 @@ def run_corec(args, source):
EXACT_SRC = (
- "fn main() -> int {\n"
- " a := 3.14 + 2.86;\n"
- " if a != 6.0 { return 1; }\n"
- " b := 0.1 + 0.2;\n"
- " if b != 0.3 { return 2; }\n"
- " c := 1.0 / 10.0;\n"
- " if c != 0.1 { return 3; }\n"
- " d := 1.5 * 2.0;\n"
- " if d != 3.0 { return 4; }\n"
- " e := 0.3 - 1.0;\n"
- " if e != -0.7 { return 5; }\n"
- " f := 1 + 0.5;\n"
- " if f != 1.5 { return 6; }\n"
- " g : dex = 0.1;\n"
- " h : dex = 0.2;\n"
- " if g + h != 0.3 { return 7; }\n"
- " r := dex_add_fn(0.1, 0.2);\n"
- " if r != 0.3 { return 8; }\n"
- " q := 1.0 / 3.0;\n"
- " if q != 0.3333333 { return 9; }\n"
- " return 0;\n"
- "}\n"
- "fn dex_add_fn(a: dex, b: dex) -> dex { return a + b; }\n"
+ "fn main() -> int:\n a := 3.14 + 2.86\n if a != 6.0:\n return 1\n b := 0.1 + 0.2\n if b != 0.3:\n return 2\n c := 1.0 / 10.0\n if c != 0.1:\n return 3\n d := 1.5 * 2.0\n if d != 3.0:\n return 4\n e := 0.3 - 1.0\n if e != -0.7:\n return 5\n f := 1 + 0.5\n if f != 1.5:\n return 6\n g : dex = 0.1\n h : dex = 0.2\n if g + h != 0.3:\n return 7\n r := dex_add_fn(0.1, 0.2)\n if r != 0.3:\n return 8\n q := 1.0 / 3.0\n if q != 0.3333333:\n return 9\n return 0\nfn dex_add_fn(a: dex, b: dex) -> dex:\n return a + b\n"
)
# 同一程序 + apx 标签:x/y 是 binary64 位模式 → z = 1.0b/3.0b = 0.3333333333333333 != 0.3333333
# (1/3 判别子:binary64 与定点 6 位结果必然不同——精确世界 z == 0.3333333 为真)
APX_SRC = (
- "fn main() -> int {\n"
- " x : dex, apx = 1.0;\n"
- " y : dex, apx = 3.0;\n"
- " z := x / y;\n"
- " if z == 0.3333333 { return 1; }\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n x : dex, apx = 1.0\n y : dex, apx = 3.0\n z := x / y\n if z == 0.3333333:\n return 1\n return 0\n"
)
APX_LIT_SRC = (
- "fn main() -> int {\n"
- " x : dex, apx = 1.0;\n"
- " if x / 3.0 == 0.3333333 { return 1; }\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n x : dex, apx = 1.0\n if x / 3.0 == 0.3333333:\n return 1\n return 0\n"
)
# LET 边界转换回归(审查发现):`y : dex = x`(x 为 apx 变量,存 binary64 bits)时
@@ -106,29 +74,13 @@ def run_corec(args, source):
# 修复前:y 原样存 bits 且被定型 TI_DEX(无 apx 标签却永久走 binary64),
# 1.0/y 得到垃圾(bits 当缩放整数用)→ != 0.3333333(修复后为真——精确)。
LET_APX_EXACT_SRC = (
- "fn main() -> int {\n"
- " x : dex, apx = 3.0;\n"
- " y : dex = x;\n"
- " z := 1.0 / y;\n"
- " if z != 0.3333333 { return 1; }\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n x : dex, apx = 3.0\n y : dex = x\n z := 1.0 / y\n if z != 0.3333333:\n return 1\n return 0\n"
)
# % 截断恒等式(5 指令序列:a - trunc(a/b)·b)——含负数:
# 7.0%2.5=2.0、-7.0%2.5=-2.0、1.0%0.3=0.1、-1.0%0.3=-0.1
MOD_SRC = (
- "fn main() -> int {\n"
- " a := 7.0 % 2.5;\n"
- " if a != 2.0 { return 1; }\n"
- " b := -7.0 % 2.5;\n"
- " if b != -2.0 { return 2; }\n"
- " c := 1.0 % 0.3;\n"
- " if c != 0.1 { return 3; }\n"
- " d := -1.0 % 0.3;\n"
- " if d != -0.1 { return 4; }\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n a := 7.0 % 2.5\n if a != 2.0:\n return 1\n b := -7.0 % 2.5\n if b != -2.0:\n return 2\n c := 1.0 % 0.3\n if c != 0.1:\n return 3\n d := -1.0 % 0.3\n if d != -0.1:\n return 4\n return 0\n"
)
# apx 打印定稿(Task 6):apx 变量经 dex_str 打印 = 6 位定点舍入(四舍五入半进,
@@ -136,22 +88,7 @@ def run_corec(args, source):
# 判别点:u = 1.0000006 → bits×1e6 ≈ 1000000.6 → 舍入 1000001("1.000001");
# 截断实现会得 1000000("1")。负半进:-0.5 → -1。
APX_PRINT_SRC = (
- "import io\n"
- "import fmt\n"
- "import dex\n"
- "fn main() -> int {\n"
- " w : dex, apx = 0.1;\n"
- " if !str_eq(dex_str(w), \"0.1\") { return 1; }\n"
- " x : dex, apx = 1.0;\n"
- " y : dex, apx = 3.0;\n"
- " if !str_eq(dex_str(x / y), \"0.333333\") { return 2; }\n"
- " u : dex, apx = 1.0000006;\n"
- " if !str_eq(dex_str(u), \"1.000001\") { return 3; }\n"
- " n : dex, apx = 0.1;\n"
- " v : dex, apx = 0.0 - n;\n"
- " if !str_eq(dex_str(v), \"-0.1\") { return 4; }\n"
- " return 0;\n"
- "}\n"
+ "import io\nimport fmt\nimport dex\nfn main() -> int:\n w : dex, apx = 0.1\n if !str_eq(dex_str(w), \"0.1\"):\n return 1\n x : dex, apx = 1.0\n y : dex, apx = 3.0\n if !str_eq(dex_str(x / y), \"0.333333\"):\n return 2\n u : dex, apx = 1.0000006\n if !str_eq(dex_str(u), \"1.000001\"):\n return 3\n n : dex, apx = 0.1\n v : dex, apx = 0.0 - n\n if !str_eq(dex_str(v), \"-0.1\"):\n return 4\n return 0\n"
)
# apx 跨函数边界转换(b1/b2 场景):
@@ -159,19 +96,7 @@ def run_corec(args, source):
# b2 返回点:apx 计算结果(binary64 bits)→ 返回处转 scaled(caller 收精确形式)
# 断言均须为真(精确)——缺任一转换则 bits 被当缩放整数用,断言失败。
APX_BOUNDARY_SRC = (
- "fn main() -> int {\n"
- " x : dex, apx = 3.0;\n"
- " r := dex_double_fn(x);\n"
- " if r != 6.0 { return 1; }\n"
- " s := dex_apx_ret_fn();\n"
- " if s != 0.5 { return 2; }\n"
- " return 0;\n"
- "}\n"
- "fn dex_double_fn(a: dex) -> dex { return a * 2.0; }\n"
- "fn dex_apx_ret_fn() -> dex {\n"
- " v : dex, apx = 1.0;\n"
- " return v / 2.0;\n"
- "}\n"
+ "fn main() -> int:\n x : dex, apx = 3.0\n r := dex_double_fn(x)\n if r != 6.0:\n return 1\n s := dex_apx_ret_fn()\n if s != 0.5:\n return 2\n return 0\nfn dex_double_fn(a: dex) -> dex:\n return a * 2.0\nfn dex_apx_ret_fn() -> dex:\n v : dex, apx = 1.0\n return v / 2.0\n"
)
@@ -215,7 +140,7 @@ def test_apx_binary64_elf():
def test_exact_literal_scaled_in_cir():
# cir dump:精确字面量 3.14 → 缩放整数常量 3140000(非 binary64 位模式)
- src = "fn main() -> int { a := 3.14; return 1; }\n"
+ src = "fn main() -> int:\n a := 3.14\n return 1\n"
r = run_corec(["cir"], src)
out = r.stdout + r.stderr
if re.search(r"const\s+dex\s*=\s*3140000", out) is None:
@@ -228,7 +153,7 @@ def test_exact_literal_scaled_in_cir():
def test_dex_run_interp():
# corec run 解释器:精确运算(裸 64 位整数路径)——run 取内联代码,非文件
- code = "fn main() -> int { a := 0.1 + 0.2; if a == 0.3 { return 42; } return 1; }"
+ code = "fn main() -> int:\n a := 0.1 + 0.2\n if a == 0.3:\n return 42\n return 1\n"
r = subprocess.run(
[str(COREC), "run", code],
cwd=BASE,
@@ -294,7 +219,7 @@ def test_apx_print_rounding():
def test_interp_rejects_apx_dex():
# The interpreter has no binary64 conversion instructions. Reject the
# path explicitly instead of returning a stale or silently truncated value.
- src = "fn main() -> int { x : dex, apx = 0.1; return @raw_int(x); }"
+ src = "fn main() -> int:\n x : dex, apx = 0.1\n return @raw_int(x)\n"
r = subprocess.run(
[str(COREC), "run", src],
cwd=BASE,
@@ -321,11 +246,7 @@ def test_extern_dex_arg_cir():
断言,确认转换发生在调用点。
"""
src = (
- "extern fn dex_ffi_bits_check(d: dex) -> int;\n"
- "fn main() -> int {\n"
- " r := dex_ffi_bits_check(3.14);\n"
- " return r;\n"
- "}\n"
+ "extern fn dex_ffi_bits_check(d: dex) -> int\nfn main() -> int:\n r := dex_ffi_bits_check(3.14)\n return r\n"
)
r = run_corec(["cir"], src)
out = r.stdout + r.stderr
@@ -353,8 +274,7 @@ def test_extern_dex_arg_cir():
def test_extern_dex_static_link():
"""Static --link must relocate an extern call after embedding .so text."""
src = (
- "extern fn dex_ffi_bits_check(d: dex) -> int;\n"
- "fn main() -> int { return dex_ffi_bits_check(3.14); }\n"
+ "extern fn dex_ffi_bits_check(d: dex) -> int\nfn main() -> int:\n return dex_ffi_bits_check(3.14)\n"
)
ccr = BASE / "build" / "dex_ffi_runtime.ccr"
binary = BASE / "build" / "dex_ffi_runtime"
diff --git a/tests/selfhost/test_dex_type.py b/tests/selfhost/test_dex_type.py
index cce5acf4..4badf787 100644
--- a/tests/selfhost/test_dex_type.py
+++ b/tests/selfhost/test_dex_type.py
@@ -50,10 +50,7 @@ def run_corec(args, source):
def test_dex_type_declares():
# 1) 变量声明:x : dex = 3.14 → check exit 0
src = (
- "fn main() -> int {\n"
- " x : dex = 3.14;\n"
- " return 1;\n"
- "}\n"
+ "fn main() -> int:\n x : dex = 3.14\n return 1\n"
)
r = run_corec(["check"], src)
if r.returncode != 0:
@@ -64,23 +61,21 @@ def test_dex_type_declares():
# 2) 函数返回类型:fn f() -> dex { return 3.14; } → check exit 0
src2 = (
- "fn f() -> dex { return 3.14; }\n"
- "fn main() -> int { return 1; }\n"
+ "fn f() -> dex:\n return 3.14\nfn main() -> int:\n return 1\n"
)
r2 = run_corec(["check"], src2)
if r2.returncode != 0:
print(f"[FAIL] dex return type: exit={r2.returncode}")
print(r2.stdout + r2.stderr)
return False
- print("[PASS] fn f() -> dex { return 3.14; } (check exit 0)")
+ print("[PASS] fn f() -> dex:\n return 3.14\n(check exit 0)\n")
# 3) 移除守卫(Task 5):float 类型名不再映射 TY_DEX——按未知类型名走 lenient
# TYP_NAMED 路径(TF01 非致命、check 报诊断;与任何未知名字一致)。
# (终审 Minor 2:守卫收紧——断言 TF01 出现且退出码按 F19 契约反映诊断,
# 防"漏报/误报"双向漂移。第四轮 F19:check 有诊断 rc=1、无诊断 rc=0)
src3 = (
- "fn f() -> float { return 3.14; }\n"
- "fn main() -> int { return 1; }\n"
+ "fn f() -> float:\n return 3.14\nfn main() -> int:\n return 1\n"
)
r3 = run_corec(["check"], src3)
out3 = r3.stdout + r3.stderr
@@ -88,13 +83,13 @@ def test_dex_type_declares():
print(f"[FAIL] float keyword should be rejected (TF01, F19 diagnostic exit 1): exit={r3.returncode}")
print(out3)
return False
- print("[PASS] fn f() -> float { ... } rejected with TF01, exit 1 (float type name removed, F19)")
+ print("[PASS] fn f() -> float:\n ...\nrejected with TF01, exit 1 (float type name removed, F19)\n")
return True
def test_dex_literal_type():
# 1) 字面量推断:x := 3.14 不报错(3.14 推断为 dex——返回 1 走 int 路径)
- src = "fn main() -> int { x := 3.14; return 1; }\n"
+ src = "fn main() -> int:\n x := 3.14\n return 1\n"
r = run_corec(["check"], src)
if r.returncode != 0:
print(f"[FAIL] literal infers dex: exit={r.returncode}")
@@ -117,7 +112,7 @@ def test_dex_literal_type():
def test_wide_decimal_literal():
# A value whose integer part is wider than the 53-bit significand must
# not call the integer power helper with a negative exponent.
- src = "fn main() -> int { x : dex = 2305843009213693952.0; return 1; }\n"
+ src = "fn main() -> int:\n x : dex = 2305843009213693952.0\n return 1\n"
r = run_corec(["check"], src)
if r.returncode != 0:
print(f"[FAIL] wide decimal literal: exit={r.returncode}")
@@ -128,7 +123,7 @@ def test_wide_decimal_literal():
def test_static_string_bounds():
- src = 'fn main() -> int { return "abc"[3]; }\n'
+ src = 'fn main() -> int:\n return "abc"[3]\n'
r = run_corec(["check"], src)
out = r.stdout + r.stderr
if r.returncode != 1 or "R02" not in out:
@@ -140,7 +135,7 @@ def test_static_string_bounds():
def test_decimal_literal_overflow_is_reported():
- src = "fn main() -> int { x : dex = 123456789012345678901.0; return 1; }\n"
+ src = "fn main() -> int:\n x : dex = 123456789012345678901.0\n return 1\n"
r = run_corec(["check"], src)
out = r.stdout + r.stderr
if r.returncode == 0 or "too wide" not in out:
diff --git a/tests/selfhost/test_diag_gate.py b/tests/selfhost/test_diag_gate.py
index daee2411..b0521516 100644
--- a/tests/selfhost/test_diag_gate.py
+++ b/tests/selfhost/test_diag_gate.py
@@ -98,7 +98,7 @@ def build_ok(name, src_path, want_codes=()):
# · **`build` 面**保留 `build_ok`(钉「能过 + 有产物」那一半)。
# 实测(本批基点):级联夹具 check rc=1 · TF07×2 · TB01×1;build rc=0 · 产物 ✓ · TF07×2 · TB01×1。
build_ok("tf07_tb01", write("tf07_tb01_cascade",
- 'fn main() -> int { s := "a"; t := "b"; return @raw_int(s) - @raw_int(t); }\n'),
+ 'fn main() -> int:\n s := "a"\n t := "b"\n return @raw_int(s) - @raw_int(t)\n'),
("TF07", "TB01"))
clean()
_r = cc(["check", "tests/suite/ptr_ref_first.cr"])
@@ -128,32 +128,30 @@ def neg_check(name, src_path, want_code):
# ⚠ 探针形态:**直接把 `@raw_int(...)` 当返回值**(`int` 函数)。写成 `@raw_int(x) != 0` 会得到
# `bool` ⇒ 与 `-> int` 冲突 ⇒ **TF01**(我第一版就这么写,三条正/对照钉全红——**是探针错,不是门错**)。
_s2_addr = write("s2_addr_ok",
- "fn main() -> int {\n x : ., mut = 7;\n return @raw_int(&x);\n}\n")
+ "fn main() -> int:\n x : ., mut = 7\n return @raw_int(&x)\n")
clean()
_r = cc(["check", str(_s2_addr)])
t.ok("s2_raw_int_ref_accepted", _r.returncode == 0,
f"check rc={_r.returncode}(正钉:地址型 = PTR ∪ REF ⇒ REF 必须受)")
# 反钉(防漏放):**四类各一颗**,逐类断言 `error[TF07]` + rc=1(不是只断 rc)
-neg_check("s2_raw_int_string", write("s2_str", 'fn main() -> int { s := "a"; return @raw_int(s); }\n'), "TF07")
-neg_check("s2_raw_int_bool", write("s2_bool", "fn main() -> int { b := true; return @raw_int(b); }\n"), "TF07")
-neg_check("s2_raw_int_array", write("s2_arr", "fn main() -> int { a := [1, 2, 3]; return @raw_int(a); }\n"), "TF07")
-neg_check("s2_raw_int_slice", write("s2_slice", "fn main() -> int { a := [1, 2, 3]; s := a[0..2]; return @raw_int(s); }\n"), "TF07")
+neg_check("s2_raw_int_string", write("s2_str", 'fn main() -> int:\n s := "a"\n return @raw_int(s)\n'), "TF07")
+neg_check("s2_raw_int_bool", write("s2_bool", "fn main() -> int:\n b := true\n return @raw_int(b)\n"), "TF07")
+neg_check("s2_raw_int_array", write("s2_arr", "fn main() -> int:\n a := [1, 2, 3]\n return @raw_int(a)\n"), "TF07")
+neg_check("s2_raw_int_slice", write("s2_slice", "fn main() -> int:\n a := [1, 2, 3]\n s := a[0..2]\n return @raw_int(s)\n"), "TF07")
# 对照钉(防「一律放」):int / dex 仍受
-_s2_int = write("s2_int_ok", "fn main() -> int { n := 5; return @raw_int(n); }\n")
+_s2_int = write("s2_int_ok", "fn main() -> int:\n n := 5\n return @raw_int(n)\n")
clean()
_r = cc(["check", str(_s2_int)])
t.ok("s2_raw_int_int_ok", _r.returncode == 0, f"check rc={_r.returncode}")
-_s2_dex = write("s2_dex_ok", 'fn main() -> int { d : dex, apx = 7.0; return @raw_int(d); }\n')
+_s2_dex = write("s2_dex_ok", 'fn main() -> int:\n d : dex, apx = 7.0\n return @raw_int(d)\n')
clean()
_r = cc(["check", str(_s2_dex)])
t.ok("s2_raw_int_dex_ok", _r.returncode == 0, f"check rc={_r.returncode}")
-tm04 = write("tm04", "enum Color { Red, Green, Blue }\n"
- "fn main() -> int { c := Red(); "
- "return match c { Red => 1, Red => 2, Green => 3, Blue => 4, }; }\n")
+tm04 = write("tm04", "enum Color:\n Red, Green, Blue\nfn main() -> int:\n c := Red()\n return match c:\n Red => 1, Red => 2, Green => 3, Blue => 4,\n")
build_ok("tm04", tm04, ("TM04",))
-tk01 = write("tk01", "\nfn main() -> int {\n x := 5;\n return x[0];\n}\n")
+tk01 = write("tk01", "\nfn main() -> int:\n x := 5\n return x[0]\n")
build_ok("tk01", tk01, ("TK01",))
build_ok("b04", "tests/suite/ptr_arith.cr")
@@ -180,16 +178,13 @@ def neg(name, src_path, want_code):
neg("syntax_p21", BASE / "tests/suite/at_test_mini4.cr", "P21")
-neg("type_ta02", write("ta02", 'fn main() -> int {\n x : int = "s";\n return 0;\n}\n'), "TA02")
-neg("type_r02", write("r02", "fn main() -> int {\n arr := [1, 2, 3];\n return arr[5];\n}\n"), "R02")
-neg("type_tm03", write("tm03", "enum E { A, B }\nfn main() -> int { e := A(); "
- "return match e { A => 1, }; }\n"), "TM03")
-neg("type_tk05", write("tk05", "fn main() -> int {\n arr := [1, 2, 3];\n"
- " s := arr[0..5];\n return 0;\n}\n"), "TK05")
-neg("safety_tu03", write("tu03", "fn main() -> int {\n p := 4096 as *int;\n"
- " return *p;\n}\n"), "TU03")
+neg("type_ta02", write("ta02", 'fn main() -> int:\n x : int = "s"\n return 0\n'), "TA02")
+neg("type_r02", write("r02", "fn main() -> int:\n arr := [1, 2, 3]\n return arr[5]\n"), "R02")
+neg("type_tm03", write("tm03", "enum E:\n A, B\nfn main() -> int:\n e := A()\n return match e:\n A => 1,\n"), "TM03")
+neg("type_tk05", write("tk05", "fn main() -> int:\n arr := [1, 2, 3]\n s := arr[0..5]\n return 0\n"), "TK05")
+neg("safety_tu03", write("tu03", "fn main() -> int:\n p := 4096 as *int\n return *p\n"), "TU03")
# TF01 撤条后的**负控**(A₂):真 TF01(string 值返 int 声明)⇒ 仍阻断(rc=1 + 零产物)——「撤条 ≠ 放行」
-neg("type_tf01", write("tf01", 'fn main() -> int {\n s := "x";\n return s;\n}\n'), "TF01")
+neg("type_tf01", write("tf01", 'fn main() -> int:\n s := "x"\n return s\n'), "TF01")
# ── 零产物 1:前端失败(P21)⇒ 无 ELF / 无 .ccr(并入 neg_syntax_p21 断言)──
# ── 零产物 2:corearch 失败(stub)⇒ 本次 .ccr 被删 ─────────────────────
@@ -198,7 +193,7 @@ def neg(name, src_path, want_code):
shutil.copy(COREC, sim / "build" / "corec")
(sim / "build" / "corearch").write_text("#!/bin/sh\necho 'error: simulated backend failure' >&2\nexit 1\n")
(sim / "build" / "corearch").chmod(0o755)
-ok_src = write("ok_src", "fn main() -> int { return 0; }\n")
+ok_src = write("ok_src", "fn main() -> int:\n return 0\n")
out2 = TMP / "c2.bin"
for f in (out2, Path(str(out2) + ".ccr")):
if f.exists():
diff --git a/tests/selfhost/test_directory_build.py b/tests/selfhost/test_directory_build.py
index e7a7804b..2e8d2ee5 100644
--- a/tests/selfhost/test_directory_build.py
+++ b/tests/selfhost/test_directory_build.py
@@ -39,11 +39,10 @@ def main() -> int:
)
(project / "_import.cr").write_text("import helper\n", encoding="utf-8")
(project / "helper.cr").write_text(
- "fn imported_result() -> int { return 23; }\n", encoding="utf-8"
+ "fn imported_result() -> int:\n return 23\n", encoding="utf-8"
)
(project / "main.cr").write_text(
- "fn runtime_symbol_visible() -> string { return g_heap_ptr; }\n"
- "fn main() -> int { return imported_result(); }\n",
+ "fn runtime_symbol_visible() -> string:\n return g_heap_ptr\nfn main() -> int:\n return imported_result()\n",
encoding="utf-8",
)
@@ -75,7 +74,7 @@ def main() -> int:
)
(project / "helper.cr").write_text(
- "fn imported_result() -> int { return 25; }\n", encoding="utf-8"
+ "fn imported_result() -> int:\n return 25\n", encoding="utf-8"
)
rebuilt = run_corec(["build", ".", "--static", "-O", "0"], project)
if rebuilt.returncode != 0:
@@ -95,7 +94,7 @@ def main() -> int:
unnamed = TEST_BUILD / "unnamed-directory"
unnamed.mkdir()
(unnamed / "main.cr").write_text(
- "fn main() -> int { return 24; }\n", encoding="utf-8"
+ "fn main() -> int:\n return 24\n", encoding="utf-8"
)
unnamed_result = run_corec(["build", ".", "--static", "-O", "0"], unnamed)
unnamed_output = unnamed / "unnamed-directory"
@@ -117,7 +116,7 @@ def main() -> int:
print("[PASS] an unnamed `.` project falls back to its directory name")
(TEST_BUILD / "main.cr").write_text(
- "fn main() -> int { return 99; }\n", encoding="utf-8"
+ "fn main() -> int:\n return 99\n", encoding="utf-8"
)
missing = run_corec(["check", "missing-project"], TEST_BUILD)
if missing.returncode == 0:
diff --git a/tests/selfhost/test_enum_limit.py b/tests/selfhost/test_enum_limit.py
index 667599e9..6a7bc8b9 100644
--- a/tests/selfhost/test_enum_limit.py
+++ b/tests/selfhost/test_enum_limit.py
@@ -117,36 +117,43 @@ def case_reject(name, source, needles, cmd="build", forbid=()):
# ─── 语料构造 ───
+def _body(b: str) -> str:
+ """函数体片段(多行、自带**相对**缩进)⇒ v4 region 体:逐行 +4 空格。"""
+ if not b.endswith("\n"):
+ b += "\n"
+ return "".join((" " + ln) if ln.strip() else ln for ln in b.splitlines(keepends=True))
+
+
def enum_src(n, extra="return 0"):
"""n 变体枚举 + main(`extra` = main 体)。"""
vs = ", ".join(f"V{i}" for i in range(n))
- return f"enum E{n} {{ {vs} }}\nfn main() -> int {{ {extra}; }}\n"
+ return f"enum E{n}:\n {vs}\nfn main() -> int:\n{_body(extra)}"
def enum_exhaustive_src(n, pick):
"""n 变体枚举 + 全臂 match(返回被选变体下标 ⇒ 逐变体可判值正确)。"""
vs = ", ".join(f"V{i}" for i in range(n))
arms = ", ".join(f"V{i} => {i}" for i in range(n))
- return (f"enum E{n} {{ {vs} }}\n"
- f"fn main() -> int {{ x := V{pick}(); return match x {{ {arms}, }}; }}\n")
+ return (f"enum E{n}:\n {vs}\n"
+ f"fn main() -> int:\n x := V{pick}()\n return match x:\n {arms},\n")
def enum_missing_arm_src(n):
"""n 变体枚举 + n-1 臂 match(缺最后一变体 ⇒ 真·非穷尽)。"""
vs = ", ".join(f"V{i}" for i in range(n))
arms = ", ".join(f"V{i} => {i}" for i in range(n - 1))
- return (f"enum E{n} {{ {vs} }}\n"
- f"fn main() -> int {{ x := V0(); return match x {{ {arms}, }}; }}\n")
+ return (f"enum E{n}:\n {vs}\n"
+ f"fn main() -> int:\n x := V0()\n return match x:\n {arms},\n")
def payload_src(n, extra="return 0"):
ps = ", ".join("int" for _ in range(n))
- return f"enum P {{ A({ps}), B }}\nfn main() -> int {{ {extra}; }}\n"
+ return f"enum P:\n A({ps}), B\nfn main() -> int:\n{_body(extra)}"
def struct_src(n, extra="return 0"):
fs = ", ".join(f"f{i}: int" for i in range(n))
- return f"struct S{n} {{ {fs} }}\nfn main() -> int {{ {extra}; }}\n"
+ return f"struct S{n}:\n {fs}\nfn main() -> int:\n{_body(extra)}"
def main():
@@ -154,46 +161,42 @@ def main():
# ── 16 = 旧边界(含):三面全对(回归钉)──
case_run("enum16_exhaustive_ok", enum_exhaustive_src(16, 9), 9),
case_run("enum16_decl_only_ok", enum_src(16), 0),
- case_run("payload16_ok", payload_src(16, "x := B(); return 4"), 4),
+ case_run("payload16_ok", payload_src(16, "x := B()\nreturn 4\n"), 4),
case_run("struct16_ok",
- struct_src(16, "s := S16 { " + ", ".join(f"f{i}: {i}" for i in range(16))
- + " }; return s.f15"),
+ struct_src(16, "s := S16 { " + ", ".join(f"f{i} = {i}" for i in range(16))
+ + " }\nreturn s.f15\n"),
15),
# ── >16(17/40):旧 P022/P023 拒绝面的**转正**(死亡证据 = 侧表解除)──
case_run("enum17_now_ok", enum_exhaustive_src(17, 13), 13),
case_run("enum40_now_ok", enum_exhaustive_src(40, 33), 33),
- case_run("payload17_now_ok", payload_src(17, "x := A(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17); return match x { A(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17) => { return a17; } B => { return 0; } }"), 17),
+ case_run("payload17_now_ok", payload_src(17, "x := A(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)\nreturn match x:\n A(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17) => a17\n B => 0\n"), 17),
case_run("struct17_now_ok",
- struct_src(17, "s := S17 { " + ", ".join(f"f{i}: {i}" for i in range(17))
- + " }; return s.f16"),
+ struct_src(17, "s := S17 { " + ", ".join(f"f{i} = {i}" for i in range(17))
+ + " }\nreturn s.f16\n"),
16),
case_run("struct40_now_ok",
- struct_src(40, "s := S40 { " + ", ".join(f"f{i}: {i}" for i in range(40))
- + " }; return s.f39"),
+ struct_src(40, "s := S40 { " + ", ".join(f"f{i} = {i}" for i in range(40))
+ + " }\nreturn s.f39\n"),
39),
# ── 跨记录完整性(侧表基址不重叠:宽记录 + 邻记录)──
case_run("enum40_plus_small_ok",
- enum_src(40, "v := V39(); return 0") + "enum F3 { X, Y, Z }\n"
- "fn g() -> int { w := Z(); return match w { X => { return 1; } Y => { return 2; } Z => { return 3; } }; }\n", 0),
+ enum_src(40, "v := V39()\nreturn 0\n") + "enum F3:\n X, Y, Z\nfn g() -> int:\n w := Z()\n return match w:\n X => 1\n Y => 2\n Z => 3\n", 0),
# 记录碰撞敏感面(**判别性**):大枚举之后声明小枚举 ⇒ 大枚举的**判定面**
# (穷尽性)仍须正确(侧表基址不重叠的机器抓手)
case_reject("enum40_then_small_missing_arm_rejected",
- enum_src(40, "v := V0(); return 0") + "enum H4 { S, T, U }\n"
- "fn hm(x: E40) -> int { return match x { "
- + ", ".join(f"V{i} => {{ return {i}; }}" for i in range(39)) + " }; }\n",
+ enum_src(40, "v := V0()\nreturn 0\n") + "enum H4:\n S, T, U\n"
+ "fn hm(x: E40) -> int:\n return match x:\n "
+ + ", ".join(f"V{i} => {i}" for i in range(39)) + ",\n",
["error[TM03]", "missing variant 'V39'"], cmd="check"),
case_run("enum40_then_small_then_match_big_ok",
- enum_src(40, "v := V0(); return 0") + "enum H3 { S, T, U }\n"
- "fn hm(x: E40) -> int { return match x { " + ", ".join(f"V{i} => {{ return {i}; }}" for i in range(40)) + " }; }\n"
- "fn main3() -> int { return 0; }\n", 0),
+ enum_src(40, "v := V0()\nreturn 0\n") + "enum H3:\n S, T, U\n"
+ "fn hm(x: E40) -> int:\n return match x:\n " + ", ".join(f"V{i} => {i}" for i in range(40)) + ",\n"
+ "fn main3() -> int:\n return 0\n", 0),
case_run("enum40_plus_small_match_ok",
- enum_src(40, "v := V7(); return 0") + "enum G3 { P, Q, R }\n"
- "fn gm(x: G3) -> int { return match x { P => { return 41; } Q => { return 42; } R => { return 43; } }; }\n"
- "fn main2() -> int { return 0; }\n", 0),
+ enum_src(40, "v := V7()\nreturn 0\n") + "enum G3:\n P, Q, R\nfn gm(x: G3) -> int:\n return match x:\n P => 41\n Q => 42\n R => 43\nfn main2() -> int:\n return 0\n", 0),
case_run("struct40_plus_pair_ok",
- struct_src(40, "a := S40 { " + ", ".join(f"f{i}: {i}" for i in range(40)) + " }; return a.f39")
- + "struct P2 { x: int, y: int }\n"
- "fn h() -> int { p : ., mut = P2 { x: 7, y: 8 }; return p.y; }\n", 39),
+ struct_src(40, "a := S40 { " + ", ".join(f"f{i} = {i}" for i in range(40)) + " }\nreturn a.f39\n")
+ + "struct P2:\n x: int, y: int\nfn h() -> int:\n p : ., mut = P2 { x = 7, y = 8 }\n return p.y\n", 39),
# ── 覆盖位无界(≥63 变体):穷尽性判定仍正确 ──
case_run("enum64_exhaustive_ok", enum_exhaustive_src(64, 63), 63 % 256),
case_run("enum70_exhaustive_ok", enum_exhaustive_src(70, 69), 69),
diff --git a/tests/selfhost/test_extern_opt.py b/tests/selfhost/test_extern_opt.py
index 04a0012b..c834dad4 100644
--- a/tests/selfhost/test_extern_opt.py
+++ b/tests/selfhost/test_extern_opt.py
@@ -31,23 +31,23 @@
# (name, extern 声明行, 是否应拒)
CASES = [
- ("reject_optdex_param", "extern fn e_opt(x: dex?) -> int;", True),
- ("reject_optint_param", "extern fn e_int(x: int?) -> int;", True),
- ("reject_optdex_ret", "extern fn e_ret() -> dex?;", True),
- ("reject_optint_ret", "extern fn e_iret() -> int?;", True),
- ("reject_mixed_params", "extern fn e_mix(a: int, b: dex?) -> int;", True),
- ("reject_optstr_param", "extern fn e_str(s: string?) -> int;", True),
- ("accept_plain_dex", "extern fn f_ok(x: dex) -> dex;", False),
- ("accept_plain_int", "extern fn putchar(c: int) -> int;", False),
- ("accept_plain_never", "extern fn f_nv() -> never;", False),
- ("accept_plain_char", "extern fn f_ch() -> char;", False),
+ ("reject_optdex_param", "extern fn e_opt(x: dex?) -> int\n", True),
+ ("reject_optint_param", "extern fn e_int(x: int?) -> int\n", True),
+ ("reject_optdex_ret", "extern fn e_ret() -> dex?\n", True),
+ ("reject_optint_ret", "extern fn e_iret() -> int?\n", True),
+ ("reject_mixed_params", "extern fn e_mix(a: int, b: dex?) -> int\n", True),
+ ("reject_optstr_param", "extern fn e_str(s: string?) -> int\n", True),
+ ("accept_plain_dex", "extern fn f_ok(x: dex) -> dex\n", False),
+ ("accept_plain_int", "extern fn putchar(c: int) -> int\n", False),
+ ("accept_plain_never", "extern fn f_nv() -> never\n", False),
+ ("accept_plain_char", "extern fn f_ch() -> char\n", False),
]
def run_case(decl, should_reject):
"""check(rc + 诊断码 + 定位)→ build(rc + 产物)。返回 (ok, detail)。"""
src = (f"// extopt-{uuid.uuid4()}\n{decl}\n"
- "fn main() -> int { return 0; }\n")
+ "fn main() -> int:\n return 0\n")
with tempfile.NamedTemporaryFile("w", suffix=".cr", delete=False) as f:
f.write(src)
path = f.name
diff --git a/tests/selfhost/test_generic_constr.py b/tests/selfhost/test_generic_constr.py
index cedc700f..56d27e6a 100644
--- a/tests/selfhost/test_generic_constr.py
+++ b/tests/selfhost/test_generic_constr.py
@@ -166,78 +166,137 @@ def case_ccr_names(name, source, present, absent=()):
# A/B:本质轴约束(函数侧 + 结构侧 + 枚举侧)
# 返回型 = T(**既有语义约束**:泛型体内 `return a`(a: T)对**具体**返回型会 TF01——实测
# 新旧一致,非本批面);调用点 int 返回 T 实例化的结果
-FUNC_INT_CONSTR = """fn f[T: int](a: T) -> T { return a; }
-fn main() -> int { return f(1); }
+FUNC_INT_CONSTR = """fn f[T: int](a: T) -> T:
+ return a
+fn main() -> int:
+ return f(1)
"""
-FUNC_INT_CONSTR_BAD = """fn f[T: int](a: T) -> T { return a; }
-fn main() -> int { return f("s"); }
+FUNC_INT_CONSTR_BAD = """fn f[T: int](a: T) -> T:
+ return a
+fn main() -> int:
+ return f("s")
"""
-STRUCT_INT_CONSTR = """struct Box[T: int] { v: T }
-fn g(b: Box[int]) -> int { return b.v; }
-fn main() -> int { return g(Box { v: 7 }); }
+STRUCT_INT_CONSTR = """struct Box[T: int]:
+ v: T
+fn g(b: Box[int]) -> int:
+ return b.v
+fn main() -> int:
+ return g(Box { v= 7 })
"""
-STRUCT_INT_CONSTR_BAD = """struct Box[T: int] { v: T }
-struct S { a: int }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+STRUCT_INT_CONSTR_BAD = """struct Box[T: int]:
+ v: T
+struct S:
+ a: int
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
-STRUCT_INT_CONSTR_STR_BAD = """struct Box[T: int] { v: T }
-fn g(b: Box[string]) -> int { return 0; }
-fn main() -> int { return 0; }
+STRUCT_INT_CONSTR_STR_BAD = """struct Box[T: int]:
+ v: T
+fn g(b: Box[string]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
-ENUM_INT_CONSTR_BAD = """enum EBox[T: int] { V(T), N }
-fn g(b: EBox[string]) -> int { return 0; }
-fn main() -> int { return 0; }
+ENUM_INT_CONSTR_BAD = """enum EBox[T: int]:
+ V(T), N
+fn g(b: EBox[string]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 无约束泛型(对照:约束面落地不得波及无约束声明)
-STRUCT_NO_CONSTR = """struct Wrap[T] { v: T }
-struct S { a: int }
-fn g(b: Wrap[S]) -> int { return b.v.a; }
-fn main() -> int { return g(Wrap { v: S { a: 3 } }); }
+STRUCT_NO_CONSTR = """struct Wrap[T]:
+ v: T
+struct S:
+ a: int
+fn g(b: Wrap[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ return g(Wrap { v= S { a= 3 } })
"""
# C:用户接口约束 = P3b 边界(零诊断;函数侧走既有 check_iface,结构侧 = 不判)
-IFACE_LEGACY_OK = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 1; } }
-fn f[T: Show](a: T) -> int { return 0; }
-fn main() -> int { s := S { a: 1 }; return f(s); }
+IFACE_LEGACY_OK = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 1
+fn f[T: Show](a: T) -> int:
+ return 0
+fn main() -> int:
+ s := S { a= 1 }
+ return f(s)
"""
-IFACE_LEGACY_BAD = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-fn f[T: Show](a: T) -> int { return 0; }
-fn main() -> int { s := S { a: 1 }; return f(s); }
+IFACE_LEGACY_BAD = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+fn f[T: Show](a: T) -> int:
+ return 0
+fn main() -> int:
+ s := S { a= 1 }
+ return f(s)
"""
-STRUCT_IFACE_REJECT = """interface Show { fn show(self) -> int; }
-struct Box[T: Show] { v: T }
-struct S { a: int }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+STRUCT_IFACE_REJECT = """interface Show:
+ fn show(self) -> int
+struct Box[T: Show]:
+ v: T
+struct S:
+ a: int
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 结构侧正控:方法在位 ⇒ 满足(P3b Task 0 起实例化点**真判定**——本常量 = 新判定不误报的守门)
-STRUCT_IFACE_ACCEPT = """interface Show { fn show(self) -> int; }
-struct Box[T: Show] { v: T }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 1; } }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { return g(Box { v = S { a = 7 } }); }
+STRUCT_IFACE_ACCEPT = """interface Show:
+ fn show(self) -> int
+struct Box[T: Show]:
+ v: T
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 1
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ return g(Box { v = S { a = 7 } })
"""
-UNKNOWN_CONSTR_NAME = """fn f[T: NoSuchThing](a: T) -> int { return 0; }
-fn main() -> int { return f(1); }
+UNKNOWN_CONSTR_NAME = """fn f[T: NoSuchThing](a: T) -> int:
+ return 0
+fn main() -> int:
+ return f(1)
"""
# D:F4 形参链(旧态:后续形参的声明类型被绕过 → T 未绑定 → 假拒 TF01)
-F4_LATER_PARAM = """fn foo(s: string) -> string { return s; }
-fn take[T](n: int, a: T) -> T { return a; }
-fn main() -> int { return take(1, 2); }
+F4_LATER_PARAM = """fn foo(s: string) -> string:
+ return s
+fn take[T](n: int, a: T) -> T:
+ return a
+fn main() -> int:
+ return take(1, 2)
"""
-F4_LATER_PARAM_BAD = """fn foo(s: string) -> string { return s; }
-fn take[T](n: int, a: T) -> T { return a; }
-fn main() -> int { return take(1, "s"); }
+F4_LATER_PARAM_BAD = """fn foo(s: string) -> string:
+ return s
+fn take[T](n: int, a: T) -> T:
+ return a
+fn main() -> int:
+ return take(1, "s")
"""
# E:实例键(两个不同结构体实参)
-TWO_STRUCTS = """struct A { a: int }
-struct B { b: int, c: int }
-fn f[T](x: T) -> int { return 1; }
-fn main() -> int { p := A { a: 1 }; q := B { b: 2, c: 3 }; return f(p) + f(q); }
+TWO_STRUCTS = """struct A:
+ a: int
+struct B:
+ b: int, c: int
+fn f[T](x: T) -> int:
+ return 1
+fn main() -> int:
+ p := A { a= 1 }
+ q := B { b= 2, c= 3 }
+ return f(p) + f(q)
"""
diff --git a/tests/selfhost/test_generic_param_erasure.py b/tests/selfhost/test_generic_param_erasure.py
index 53d66a61..1e1fef5d 100644
--- a/tests/selfhost/test_generic_param_erasure.py
+++ b/tests/selfhost/test_generic_param_erasure.py
@@ -44,54 +44,75 @@
COREC = Path(os.environ.get("COREC_BIN", str(BASE / "build" / "corec")))
# ── 探针(自包含;dex 两源:bits = `dex, apx` / scaled = `dex`)───────────────────
-PROBE_FORMS = """fn h(x: dex) -> int { return 1; }
-fn g1[T](x: T) -> int { return 1; }
-fn g2[T](x: T?) -> int { return 1; }
-fn gi[T](x: T) -> int { return 1; }
-fn main() -> int {
- d : dex, apx = 7.0;
- e : dex = 7.0;
- a := h(d);
- b := g1(d);
- c := g1(e);
- f := g2(d);
- k := gi(1);
- return a + b + c + f + k;
-}
+PROBE_FORMS = """fn h(x: dex) -> int:
+ return 1
+fn g1[T](x: T) -> int:
+ return 1
+fn g2[T](x: T?) -> int:
+ return 1
+fn gi[T](x: T) -> int:
+ return 1
+fn main() -> int:
+ d : dex, apx = 7.0
+ e : dex = 7.0
+ a := h(d)
+ b := g1(d)
+ c := g1(e)
+ f := g2(d)
+ k := gi(1)
+ return a + b + c + f + k
"""
-PROBE_VALUES_BITS = """fn h(x: dex) -> int { if x == 7.0 { return 1; } return 0; }
-fn gp[T](x: T) -> int { if x == 7.0 { return 1; } return 0; }
-fn main() -> int {
- d : dex, apx = 7.0;
- if gp(d) != 1 { return 21; }
- if h(d) != 1 { return 11; }
- return 0;
-}
+PROBE_VALUES_BITS = """fn h(x: dex) -> int:
+ if x == 7.0:
+ return 1
+ return 0
+fn gp[T](x: T) -> int:
+ if x == 7.0:
+ return 1
+ return 0
+fn main() -> int:
+ d : dex, apx = 7.0
+ if gp(d) != 1:
+ return 21
+ if h(d) != 1:
+ return 11
+ return 0
"""
-PROBE_VALUES_SCALED = """fn h(x: dex) -> int { if x == 7.0 { return 1; } return 0; }
-fn gp[T](x: T) -> int { if x == 7.0 { return 1; } return 0; }
-fn main() -> int {
- e : dex = 7.0;
- if h(e) != 1 { return 31; }
- if gp(e) != 1 { return 41; }
- return 0;
-}
+PROBE_VALUES_SCALED = """fn h(x: dex) -> int:
+ if x == 7.0:
+ return 1
+ return 0
+fn gp[T](x: T) -> int:
+ if x == 7.0:
+ return 1
+ return 0
+fn main() -> int:
+ e : dex = 7.0
+ if h(e) != 1:
+ return 31
+ if gp(e) != 1:
+ return 41
+ return 0
"""
-PROBE_MIXED_BITS = """fn mixed[T](t: T, x: dex) -> int { if t == x { return 1; } return 0; }
-fn main() -> int {
- d : dex, apx = 7.0;
- return mixed(d, d) + 0;
-}
+PROBE_MIXED_BITS = """fn mixed[T](t: T, x: dex) -> int:
+ if t == x:
+ return 1
+ return 0
+fn main() -> int:
+ d : dex, apx = 7.0
+ return mixed(d, d) + 0
"""
-PROBE_MIXED_SCALED = """fn mixed[T](t: T, x: dex) -> int { if t == x { return 1; } return 0; }
-fn main() -> int {
- e : dex = 7.0;
- return mixed(e, e) + 0;
-}
+PROBE_MIXED_SCALED = """fn mixed[T](t: T, x: dex) -> int:
+ if t == x:
+ return 1
+ return 0
+fn main() -> int:
+ e : dex = 7.0
+ return mixed(e, e) + 0
"""
diff --git a/tests/selfhost/test_global_init.py b/tests/selfhost/test_global_init.py
index 11669f04..e70a3c65 100644
--- a/tests/selfhost/test_global_init.py
+++ b/tests/selfhost/test_global_init.py
@@ -27,79 +27,79 @@
CASES = [
(
"array_global_literal",
- "g : [int;2] = [8,9];\nfn main()->int{return g[1];}",
+ "g : [int;2] = [8,9]\nfn main()->int:\n return g[1]\n",
9,
),
(
"array_global_no_init",
- "g : [int;2];\nfn main()->int{ g[1]=7; return g[1]; }",
+ "g : [int;2]\nfn main()->int:\n g[1]=7\n return g[1]\n",
7,
),
(
"array_global_copy",
- "a : [int;2] = [8,9];\nb : [int;2] = a;\nfn main()->int{return b[1];}",
+ "a : [int;2] = [8,9]\nb : [int;2] = a\nfn main()->int:\n return b[1]\n",
9,
),
(
"array_global_unused",
- "g : [int;4] = [1,2,3,4];\nfn main()->int{return 5;}",
+ "g : [int;4] = [1,2,3,4]\nfn main()->int:\n return 5\n",
5,
),
(
"scalar_mut_global",
- "x : int, mut = 5;\nfn main()->int{ x = x + 1; return x; }",
+ "x : int, mut = 5\nfn main()->int:\n x = x + 1\n return x\n",
6,
),
(
"scalar_const_global",
- "x : int = 5;\nfn main()->int{return x;}",
+ "x : int = 5\nfn main()->int:\n return x\n",
5,
),
(
"array_global_cross_func",
- "g : [int;2] = [3,4];\nfn get()->int{return g[1];}\nfn main()->int{return get();}",
+ "g : [int;2] = [3,4]\nfn get()->int:\n return g[1]\nfn main()->int:\n return get()\n",
4,
),
(
"array_global_two_refs",
- "a : [int;2] = [8,9];\nb : [int;2] = a;\nfn main()->int{return a[0]+b[1];}",
+ "a : [int;2] = [8,9]\nb : [int;2] = a\nfn main()->int:\n return a[0]+b[1]\n",
17,
),
# —— 以下为同一修复面(R1 ② 判据)的扩展 pin:非字面量初值的其它形态 + callee 侧
# 聚合访问(解释器外函数内联路径的聚合族 opcode;ELF 全局基址字段读写)。 ——
(
"struct_global_field_read",
- "struct P { x: int, y: int }\ng : P = P { x = 30, y = 12 };\nfn main()->int{return g.y;}",
+ "struct P:\n x: int, y: int\ng : P = P { x = 30, y = 12 }\nfn main()->int:\n return g.y\n",
12,
),
(
"struct_global_field_write_callee",
- "struct P { x: int, y: int }\ng : P = P { x = 1, y = 2 };\nfn set()->int{ g.y = 40; return 0; }\nfn main()->int{ set(); return g.y; }",
+ "struct P:\n x: int, y: int\ng : P = P { x = 1, y = 2 }\nfn set()->int:\n g.y = 40\n return 0\nfn main()->int:\n set()\n return g.y\n",
40,
),
(
"string_global",
- 'g : string = "hello";\nfn main()->int{ if str_len(g) == 5 { return 7; } return 1; }',
+ 'g : string = "hello"\nfn main()->int:\n if str_len(g) == 5:\n return 7\n return 1\n',
7,
),
(
"call_init_global",
- "fn make()->int{ return 33; }\ng : int, mut = make();\nfn main()->int{ return g; }",
+ "fn make()->int:\n return 33\ng : int, mut = make()\nfn main()->int:\n return g\n",
33,
),
(
"callee_array_var_index",
- "g : [int;3] = [5,6,7];\nfn get(i: int)->int{ return g[i]; }\nfn main()->int{ return get(2); }",
+ "g : [int;3] = [5,6,7]\nfn get(i: int)->int:\n return g[i]\nfn main()->int:\n return get(2)\n",
7,
),
(
"alias_array_global_literal",
- "type Arr = [int;2];\ng : Arr = [3,4];\nfn main()->int{return g[1];}",
+ "type Arr = [int;2]\ng : Arr = [3,4]\nfn main()->int:\n return g[1]\n",
4,
),
(
"alias_array_global_no_init",
- "type Arr = [int;2];\ng : Arr;\nfn main()->int{ g[1] = 7; return g[1]; }",
+ "type Arr = [int;2]\ng : Arr\nfn main()->int:\n g[1] = 7\n return g[1]\n",
7,
),
]
diff --git a/tests/selfhost/test_global_seams.py b/tests/selfhost/test_global_seams.py
index 6b908199..503cb871 100644
--- a/tests/selfhost/test_global_seams.py
+++ b/tests/selfhost/test_global_seams.py
@@ -119,106 +119,104 @@ def case_elf_match(name, source, patterns):
# ── B1:IR_BINARY(TI_DEX) 双操作数(全局 vs 局部同形对拍 + 正负号差分)──
B1_NEG = """
-g : dex, apx, mut = -100.0;
-fn main() -> int {
- if g > 0.0 { return 7; }
- return 1;
-}
+g : dex, apx, mut = -100.0
+fn main() -> int:
+ if g > 0.0:
+ return 7
+ return 1
"""
B1_POS = """
-g : dex, apx, mut = 100.0;
-fn main() -> int {
- if g > 0.0 { return 7; }
- return 1;
-}
+g : dex, apx, mut = 100.0
+fn main() -> int:
+ if g > 0.0:
+ return 7
+ return 1
"""
B1_NEG_LOCAL = """
-fn main() -> int {
- g : dex, apx, mut = -100.0;
- if g > 0.0 { return 7; }
- return 1;
-}
+fn main() -> int:
+ g : dex, apx, mut = -100.0
+ if g > 0.0:
+ return 7
+ return 1
"""
# ── B2:IR_I2F 源(scaled 全局 → apx;局部同形对照)──
B2_NEG = """
-h : dex, mut = -100.0;
-fn main() -> int {
- d : dex, apx = h;
- if d > 0.0 { return 7; }
- return 1;
-}
+h : dex, mut = -100.0
+fn main() -> int:
+ d : dex, apx = h
+ if d > 0.0:
+ return 7
+ return 1
"""
B2_POS = """
-h : dex, mut = 100.0;
-fn main() -> int {
- d : dex, apx = h;
- if d > 0.0 { return 7; }
- return 1;
-}
+h : dex, mut = 100.0
+fn main() -> int:
+ d : dex, apx = h
+ if d > 0.0:
+ return 7
+ return 1
"""
B2_NEG_LOCAL = """
-fn main() -> int {
- h : dex, mut = -100.0;
- d : dex, apx = h;
- if d > 0.0 { return 7; }
- return 1;
-}
+fn main() -> int:
+ h : dex, mut = -100.0
+ d : dex, apx = h
+ if d > 0.0:
+ return 7
+ return 1
"""
# ── B4:IR_SLICE 数组指针 + 低界(全局数组;局部对照;字面量低界隔离 s1/s2)──
B4_GLOBAL = """
-g : [int;4] = [10, 20, 30, 40];
-lo : int, mut = 1;
-fn main() -> int {
- s := g[lo..3];
- return s[0];
-}
+g : [int;4] = [10, 20, 30, 40]
+lo : int, mut = 1
+fn main() -> int:
+ s := g[lo..3]
+ return s[0]
"""
B4_LOCAL = """
-fn main() -> int {
- g : [int;4] = [10, 20, 30, 40];
- lo : int, mut = 1;
- s := g[lo..3];
- return s[0];
-}
+fn main() -> int:
+ g : [int;4] = [10, 20, 30, 40]
+ lo : int, mut = 1
+ s := g[lo..3]
+ return s[0]
"""
# ── B5:IR_AWAIT 源(int 全局运行期赋值 ⇒ 不可折叠;局部对照)──
B5_GLOBAL = """
-g : int, mut = 5;
-fn main() -> int {
- g = 9;
- x := await g;
- return x;
-}
+g : int, mut = 5
+fn main() -> int:
+ g = 9
+ x := await g
+ return x
"""
B5_LOCAL = """
-fn main() -> int {
- g : int, mut = 5;
- g = 9;
- x := await g;
- return x;
-}
+fn main() -> int:
+ g : int, mut = 5
+ g = 9
+ x := await g
+ return x
"""
# ── B6(b):callseq dex 实参(单实参 extern = 恒不打包 ⇒ 全局实参直达分派)──
# 静态无 .so ⇒ 调用未解析符号必崩(对照 seam_ext(1.5) 同样 139)⇒ 判据只到发射字节。
B6B_EXTERN = """
-g : dex, apx, mut = 1.5;
-extern fn seam_ext(x: dex) -> dex;
-fn main() -> int {
- y := seam_ext(g);
- if y != 3.0 { return 1; }
- return 7;
-}
+g : dex, apx, mut = 1.5
+extern fn seam_ext(x: dex) -> dex
+fn main() -> int:
+ y := seam_ext(g)
+ if y != 3.0:
+ return 1
+ return 7
"""
# ── B7:非回归(非 dex 全局返回走 rax 路径,修复前后同字节)──
B7_RET_GLOBAL = """
-g : int, mut = 5;
-fn ret_g() -> int { return g; }
-fn main() -> int { return ret_g(); }
+g : int, mut = 5
+fn ret_g() -> int:
+ return g
+fn main() -> int:
+ return ret_g()
"""
diff --git a/tests/selfhost/test_hit_table.py b/tests/selfhost/test_hit_table.py
index 41cfc1d4..5e2aa81f 100644
--- a/tests/selfhost/test_hit_table.py
+++ b/tests/selfhost/test_hit_table.py
@@ -34,23 +34,22 @@
OPT = "1" # 与 corec build 默认同(corec/main.cr: g_opt_level 默认 1)
# 载体(直线子集:const/store/add/sub/load/return——无 &&/||(短路分支化超 M1))
-SUB_SRC = "fn main() -> int {\n a := 7;\n b := 5;\n return a - b;\n}\n"
+SUB_SRC = "fn main() -> int:\n a := 7\n b := 5\n return a - b\n"
SUB_RC = 2 # 7 - 5
-ADD_SRC = "fn main() -> int {\n a := 7;\n b := 5;\n return a + b;\n}\n"
+ADD_SRC = "fn main() -> int:\n a := 7\n b := 5\n return a + b\n"
ADD_RC = 12 # 7 + 5(add → sub 反减:12 = 7 - (0 - 5))
-MEM_SRC = """fn main() -> int {
- a: ., mut = 6;
- b := 3;
- a = a + b;
- a = a - 4;
- return a;
-}
+MEM_SRC = """fn main() -> int:
+ a: ., mut = 6
+ b := 3
+ a = a + b
+ a = a - 4
+ return a
"""
MEM_RC = 5 # 6+3-4(链式加减 + 内存读写,与 tests/hit/smoke_mem.cr 同源同期望)
-MOD_SRC = "fn main() -> int {\n a := 7;\n b := 3;\n return a % b;\n}\n"
+MOD_SRC = "fn main() -> int:\n a := 7\n b := 3\n return a % b\n"
# `--dump-events` 事件行白名单形态(B3/#2026-09-16-24 修复):` ev dst= s1= s2=`;
# v ∈ `\d+` 或 `pool\d+`(池引用)。emit 侧格式见 corearch.cr `dump_ev` 分支。
@@ -434,32 +433,29 @@ def test_hit_lower_sources_check_clean() -> bool:
# 逐字节对照载体只用非门面指令:store/load(as 槽载入)/jump/cst。
# jump 对照载体:if(无 else)体内 store 链 + 尾 jump 指向合并标签 = if 后首个
# 事件指令(d 的 load——事件序 4)。跳转目标 = 事件序(jump 事件 s1 域)。
-JUMP_SRC = """fn main() -> int {
- a : ., mut = 10;
- b := 3;
- if a > b {
- c := a as int;
- a = c;
- }
- d := a as int;
- return d;
-}
+JUMP_SRC = """fn main() -> int:
+ a : ., mut = 10
+ b := 3
+ if a > b:
+ c := a as int
+ a = c
+ d := a as int
+ return d
"""
JUMP_EVENTS = ["ev load", "ev store", "ev store", "ev jump s1=4", "ev load", "ev store"]
JUMP_RC = 10 # 10>3 真 → c=10、a=10 → d=10
# disp 对照载体:let 初始化 store ×2 + as 槽 load/store 链 + 变量移动 store
#(事件全部 auto disp8——旧路径 e2_ld/e2_st 同规则;固定 disp32 旧发射会红)
-DISP_SRC = """fn main() -> int {
- a : ., mut = 10;
- b := 3;
- c := a as int;
- a = c;
- d := b as int;
- e := a as int;
- a = d;
- return a;
-}
+DISP_SRC = """fn main() -> int:
+ a : ., mut = 10
+ b := 3
+ c := a as int
+ a = c
+ d := b as int
+ e := a as int
+ a = d
+ return a
"""
DISP_EVENTS = ["ev store", "ev store", "ev load", "ev store", "ev store",
"ev load", "ev store", "ev load", "ev store", "ev store"]
@@ -471,12 +467,11 @@ def test_hit_lower_sources_check_clean() -> bool:
def big_src() -> str:
- lines = ["fn main() -> int {"]
+ lines = ["fn main() -> int:"]
for i in range(20):
- lines.append(f" a{i} : ., mut = {i};")
- lines.append(" a19 = a18;")
- lines.append(" return a19;")
- lines.append("}")
+ lines.append(f" a{i} : ., mut = {i}")
+ lines.append(" a19 = a18")
+ lines.append(" return a19")
return "\n".join(lines) + "\n"
@@ -488,12 +483,12 @@ def big_src() -> str:
"[[event.proj.step]]\nrex_w = 1\nopcode = [0xC7]\nmodrm_reg_digit = 0\n"
"modrm_rm_role = \"dst\"\nrm_mode = 1\nimm_size = 4\nimm_role = \"src1\"\n")
-IMM_SRC = "fn main() -> int {\n a := 63;\n return a;\n}\n"
+IMM_SRC = "fn main() -> int:\n a := 63\n return a\n"
IMM_EVENTS = ["ev cst"]
IMM_RC = 63
# 池对照载体:const → 池 load(M1 语义——字节与旧路径 e2_li 有意不同,判据 = 运行)
-POOL_SRC = "fn main() -> int {\n a := 7;\n b := 5;\n return a - b;\n}\n"
+POOL_SRC = "fn main() -> int:\n a := 7\n b := 5\n return a - b\n"
POOL_LINES = ["pool 7 5"]
POOL_EVENTS = ["ev load s1=pool0", "ev store", "ev load s1=pool1", "ev store"]
POOL_RC = 2 # a-b 指令 = mw 门旧路径——池载入 + 初始化 store 经表
@@ -1590,7 +1585,7 @@ def main():
test_v2_fixture_multi_step_sections(tmp),
test_v2_bad_field_rejects(tmp),
# M2a Task 2:事件流注入通道 + v2 形态发射(跳转/disp/imm 逐字节对照)
- test_inject_byte_compare(tmp, "simple", "fn main() -> int {\n a : ., mut = 7;\n return a;\n}\n",
+ test_inject_byte_compare(tmp, "simple", "fn main() -> int:\n a : ., mut = 7\n return a\n",
["ev store"], 7),
test_inject_byte_compare(tmp, "jump", JUMP_SRC, JUMP_EVENTS, JUMP_RC),
test_inject_byte_compare(tmp, "disp", DISP_SRC, DISP_EVENTS, DISP_RC),
diff --git a/tests/selfhost/test_iface_ops.py b/tests/selfhost/test_iface_ops.py
index 9e05bd1e..178d1576 100644
--- a/tests/selfhost/test_iface_ops.py
+++ b/tests/selfhost/test_iface_ops.py
@@ -112,132 +112,132 @@ def case_diag_lines(name, source, expect):
def main():
ok = []
# ─── 正控(许可面):三个门各自的许可路径 ───
- ok.append(case_ok("pos_int_add", "fn main() -> int { x := 1 + 2; return x; }\n"))
- ok.append(case_ok("pos_int_mod", "fn main() -> int { x := 7 % 3; return x; }\n"))
- ok.append(case_ok("pos_dex_add", "fn main() -> int { d := 1.5 + 1; return 0; }\n"))
- ok.append(case_ok("pos_dex_dominates", "fn main() -> int { d := 1 + 1.5; return 0; }\n"))
- ok.append(case_ok("pos_str_concat", 'fn main() -> int { s := "a" + "b"; return 0; }\n'))
+ ok.append(case_ok("pos_int_add", "fn main() -> int:\n x := 1 + 2\n return x\n"))
+ ok.append(case_ok("pos_int_mod", "fn main() -> int:\n x := 7 % 3\n return x\n"))
+ ok.append(case_ok("pos_dex_add", "fn main() -> int:\n d := 1.5 + 1\n return 0\n"))
+ ok.append(case_ok("pos_dex_dominates", "fn main() -> int:\n d := 1 + 1.5\n return 0\n"))
+ ok.append(case_ok("pos_str_concat", 'fn main() -> int:\n s := "a" + "b"\n return 0\n'))
ok.append(case_ok("pos_str_concat_right",
- 'fn main() -> int { s := 1 + "b"; return 0; }\n'))
+ 'fn main() -> int:\n s := 1 + "b"\n return 0\n'))
ok.append(case_ok("pos_ptr_add_int",
- "fn main() -> int { x : ., mut = 5; p := &x; q := p + 1; return 0; }\n"))
+ "fn main() -> int:\n x : ., mut = 5\n p := &x\n q := p + 1\n return 0\n"))
ok.append(case_ok("pos_int_add_ptr",
- "fn main() -> int { x : ., mut = 5; p := &x; q := 1 + p; return 0; }\n"))
+ "fn main() -> int:\n x : ., mut = 5\n p := &x\n q := 1 + p\n return 0\n"))
ok.append(case_ok("pos_ptr_diff",
- "fn main() -> int { x : ., mut = 5; p := &x; q := &x; d := p - q; return d; }\n"))
- ok.append(case_ok("pos_str_index", 'fn main() -> int { s := "ab"; c := s[0]; return c; }\n'))
+ "fn main() -> int:\n x : ., mut = 5\n p := &x\n q := &x\n d := p - q\n return d\n"))
+ ok.append(case_ok("pos_str_index", 'fn main() -> int:\n s := "ab"\n c := s[0]\n return c\n'))
ok.append(case_ok("pos_tuple_field",
- "fn main() -> int { t := (1, 2); a := t . 0; return a; }\n"))
- ok.append(case_ok("pos_logic_int", "fn main() -> int { b := 1 && true; return 0; }\n"))
- ok.append(case_ok("pos_logic_bool", "fn main() -> int { b := true && false; return 0; }\n"))
- ok.append(case_ok("pos_cond_if_int", "fn main() -> int { if 1 { return 1; } return 0; }\n"))
- ok.append(case_ok("pos_cond_if_bool", "fn main() -> int { if true { return 1; } return 0; }\n"))
+ "fn main() -> int:\n t := (1, 2)\n a := t . 0\n return a\n"))
+ ok.append(case_ok("pos_logic_int", "fn main() -> int:\n b := 1 && true\n return 0\n"))
+ ok.append(case_ok("pos_logic_bool", "fn main() -> int:\n b := true && false\n return 0\n"))
+ ok.append(case_ok("pos_cond_if_int", "fn main() -> int:\n if 1:\n return 1\n return 0\n"))
+ ok.append(case_ok("pos_cond_if_bool", "fn main() -> int:\n if true:\n return 1\n return 0\n"))
ok.append(case_ok("pos_cond_while_bool",
- "fn main() -> int { n : ., mut = 0; while n < 3 { n = n + 1; } return n; }\n"))
- ok.append(case_ok("pos_range_int", "fn main() -> int { b := 1..3; return 0; }\n"))
+ "fn main() -> int:\n n : ., mut = 0\n while n < 3:\n n = n + 1\n return n\n"))
+ ok.append(case_ok("pos_range_int", "fn main() -> int:\n b := 1..3\n return 0\n"))
# ─── 负控(拒绝面,码逐字不变)───
# **关键守卫 1**:`*T + *T` —— 门集合若含 PTR(ANY 语义)即静默放行
ok.append(case_reject("neg_ptr_add_ptr",
- "fn main() -> int { x : ., mut = 5; p := &x; q := &x; r := p + q; return 0; }\n", "TB01"))
+ "fn main() -> int:\n x : ., mut = 5\n p := &x\n q := &x\n r := p + q\n return 0\n", "TB01"))
# **关键守卫 2**:`"a" - "b"` —— 串拼接许可在 :1946 早退(只认 OP_ADD),门集合若含 STRING 即放行
ok.append(case_reject("neg_str_sub_str",
- 'fn main() -> int { s := "a" - "b"; return 0; }\n', "TB01"))
+ 'fn main() -> int:\n s := "a" - "b"\n return 0\n', "TB01"))
ok.append(case_reject("neg_str_mul_str",
- 'fn main() -> int { s := "a" * "b"; return 0; }\n', "TB01"))
+ 'fn main() -> int:\n s := "a" * "b"\n return 0\n', "TB01"))
ok.append(case_reject("neg_arr_add_arr",
- "fn main() -> int { a := [1,2,3]; b := [4,5,6]; c := a + b; return 0; }\n", "TB01"))
+ "fn main() -> int:\n a := [1,2,3]\n b := [4,5,6]\n c := a + b\n return 0\n", "TB01"))
ok.append(case_reject("neg_char_add_char",
- "fn main() -> int { c := 'a' + 'b'; return 0; }\n", "TB01"))
+ "fn main() -> int:\n c := 'a' + 'b'\n return 0\n", "TB01"))
ok.append(case_reject("neg_logic_dex",
- "fn main() -> int { b := 1.5 && true; return 0; }\n", "TC01"))
+ "fn main() -> int:\n b := 1.5 && true\n return 0\n", "TC01"))
ok.append(case_reject("neg_logic_dex_or",
- "fn main() -> int { b := 1.5 || false; return 0; }\n", "TC01"))
+ "fn main() -> int:\n b := 1.5 || false\n return 0\n", "TC01"))
ok.append(case_reject("neg_logic_str",
- 'fn main() -> int { b := "a" && true; return 0; }\n', "TC01"))
+ 'fn main() -> int:\n b := "a" && true\n return 0\n', "TC01"))
ok.append(case_reject("neg_cond_if_arr",
- "fn main() -> int { if [1,2,3] { return 1; } return 0; }\n", "TC01"))
+ "fn main() -> int:\n if [1,2,3]:\n return 1\n return 0\n", "TC01"))
ok.append(case_reject("neg_cond_if_dex",
- "fn main() -> int { if 1.5 { return 1; } return 0; }\n", "TC01"))
+ "fn main() -> int:\n if 1.5:\n return 1\n return 0\n", "TC01"))
# `while` 与 `if` 现状**不同**(IP_COND_BOOL 只收 bool):int 在 if 收、在 while 拒
ok.append(case_reject("neg_cond_while_int",
- "fn main() -> int { while 1 { } return 0; }\n", "TC04"))
+ "fn main() -> int:\n while 1:\n return 0\n", "TC04"))
ok.append(case_reject("neg_cond_while_dex",
- "fn main() -> int { while 1.5 { } return 0; }\n", "TC04"))
+ "fn main() -> int:\n while 1.5:\n return 0\n", "TC04"))
ok.append(case_reject("neg_cond_while_arr",
- "fn main() -> int { while [1,2,3] { } return 0; }\n", "TC04"))
+ "fn main() -> int:\n while [1,2,3]:\n return 0\n", "TC04"))
ok.append(case_reject("neg_range_str_ends",
- 'fn main() -> int { b := "a".."b"; return 0; }\n', "TB01"))
+ 'fn main() -> int:\n b := "a".."b"\n return 0\n', "TB01"))
# ─── 登记面(现状宽松;本批断言「不动」= 保留为表的全许可格,P3 才收紧)───
ok.append(case_ok("reg_int_add_arr",
- "fn main() -> int { a := [1,2,3]; c := 1 + a; return 0; }\n"))
- ok.append(case_ok("reg_str_mul_int", 'fn main() -> int { s := "a" * 2; return 0; }\n'))
+ "fn main() -> int:\n a := [1,2,3]\n c := 1 + a\n return 0\n"))
+ ok.append(case_ok("reg_str_mul_int", 'fn main() -> int:\n s := "a" * 2\n return 0\n'))
ok.append(case_ok("reg_arr_index_bool",
- "fn main() -> int { a := [1,2,3]; c := a[true]; return 0; }\n"))
+ "fn main() -> int:\n a := [1,2,3]\n c := a[true]\n return 0\n"))
ok.append(case_ok("reg_not_arr",
- "fn main() -> int { a := [1,2,3]; b := !a; return 0; }\n"))
- ok.append(case_ok("reg_neg_str", 'fn main() -> int { s := "a"; t := -s; return 0; }\n'))
+ "fn main() -> int:\n a := [1,2,3]\n b := !a\n return 0\n"))
+ ok.append(case_ok("reg_neg_str", 'fn main() -> int:\n s := "a"\n t := -s\n return 0\n'))
ok.append(case_ok("reg_deref_int",
- "fn main() -> int { x := 5; y := *x; return 0; }\n"))
+ "fn main() -> int:\n x := 5\n y := *x\n return 0\n"))
ok.append(case_ok("reg_cmp_unchecked",
- 'fn main() -> int { b := "a" == 1; return 0; }\n'))
+ 'fn main() -> int:\n b := "a" == 1\n return 0\n'))
ok.append(case_ok("reg_as_identity",
- 'fn main() -> int { s := "a"; x := s as int; return 0; }\n'))
+ 'fn main() -> int:\n s := "a"\n x := s as int\n return 0\n'))
# ─── R2 P2b Task 5:容器面(**唯一接线点** = 索引兜底拒绝 → IP_INDEX 查表)───
# 接线口径 = 与改动前**一字等价**:门体即原 `EC_TK_INDEX` 调用;可达集(= 三个结果分支
# 之后的落空集)与表的拒绝集逐行相等(selftest `idx.gate_deny_covers_fallback` 钉死)。
# 字段/转换/dyn 三面**未接线**(无拒绝路径 / 谓词不是类级位)——本段以「现状不动」钉住,
# 防后续把 `IP_FIELD`/`IP_METHOD`/`IP_AS` 硬接成收紧或放宽。
- S5 = "struct S { a: int }\n"
+ S5 = "struct S:\n a: int\n"
# 正控:三个结果分支(数组→元素 / 切片→元素 / 数组 range→切片)
ok.append(case_ok("t5_pos_arr_index",
- "fn main() -> int { a := [1,2,3]; c := a[1]; return c; }\n"))
+ "fn main() -> int:\n a := [1,2,3]\n c := a[1]\n return c\n"))
ok.append(case_ok("t5_pos_slice_index",
- "fn main() -> int { a := [1,2,3]; s := a[0..2]; c := s[1]; return c; }\n"))
+ "fn main() -> int:\n a := [1,2,3]\n s := a[0..2]\n c := s[1]\n return c\n"))
ok.append(case_ok("t5_pos_arr_range",
- "fn main() -> int { a := [1,2,3]; s := a[1..2]; return 0; }\n"))
+ "fn main() -> int:\n a := [1,2,3]\n s := a[1..2]\n return 0\n"))
# 负控:非容器行一律 TK01(码/文案逐字不变)——给表的 IP_INDEX 加任一非容器类即静默放行
ok.append(case_reject("t5_neg_index_int",
- "fn main() -> int { x := 1; c := x[0]; return 0; }\n", "TK01"))
+ "fn main() -> int:\n x := 1\n c := x[0]\n return 0\n", "TK01"))
ok.append(case_reject("t5_neg_index_bool",
- "fn main() -> int { x := true; c := x[0]; return 0; }\n", "TK01"))
+ "fn main() -> int:\n x := true\n c := x[0]\n return 0\n", "TK01"))
ok.append(case_reject("t5_neg_index_dex",
- "fn main() -> int { x := 1.5; c := x[0]; return 0; }\n", "TK01"))
+ "fn main() -> int:\n x := 1.5\n c := x[0]\n return 0\n", "TK01"))
ok.append(case_reject("t5_neg_index_char",
- "fn main() -> int { c := 'a'[0]; return 0; }\n", "TK01"))
+ "fn main() -> int:\n c := 'a'[0]\n return 0\n", "TK01"))
ok.append(case_reject("t5_neg_index_ptr",
- "fn main() -> int { x : ., mut = 5; p := &x; c := p[0]; return 0; }\n", "TK01"))
+ "fn main() -> int:\n x : ., mut = 5\n p := &x\n c := p[0]\n return 0\n", "TK01"))
ok.append(case_reject("t5_neg_index_named",
- S5 + "fn main() -> int { s := S { a: 1 }; c := s[0]; return 0; }\n", "TK01"))
+ S5 + "fn main() -> int:\n s := S { a= 1 }\n c := s[0]\n return 0\n", "TK01"))
ok.append(case_reject("t5_neg_index_tuple",
- "fn main() -> int { t := (1,2); c := t[0]; return 0; }\n", "TK01"))
+ "fn main() -> int:\n t := (1,2)\n c := t[0]\n return 0\n", "TK01"))
ok.append(case_reject("t5_neg_index_dyn",
- "fn main() -> int { d : dyn = 5; c := d[0]; return 0; }\n", "TK01"))
+ "fn main() -> int:\n d : dyn = 5\n c := d[0]\n return 0\n", "TK01"))
# 登记面(现状静默;本批断言「不动」= P3 收紧面):
# range 索引的非数组落空 `return TI_UNIT` 无诊断(表 IP_INDEX_RANGE **未接线**——门恒真空转)
ok.append(case_ok("t5_reg_str_range",
- 'fn main() -> int { s := "ab"; t := s[0..1]; return 0; }\n'))
+ 'fn main() -> int:\n s := "ab"\n t := s[0..1]\n return 0\n'))
ok.append(case_ok("t5_reg_slice_range",
- "fn main() -> int { a := [1,2,3]; s := a[0..2]; t := s[0..1]; return 0; }\n"))
+ "fn main() -> int:\n a := [1,2,3]\n s := a[0..2]\n t := s[0..1]\n return 0\n"))
ok.append(case_ok("t5_reg_int_range",
- "fn main() -> int { x := 1; t := x[0..1]; return 0; }\n"))
+ "fn main() -> int:\n x := 1\n t := x[0..1]\n return 0\n"))
# 字段落空静默(EXPR_FIELD 全形 rc=0:非 struct / 越界元组位 / 指针·数组·dyn 操作数)
ok.append(case_ok("t5_reg_int_field",
- "fn main() -> int { x := 1; c := x.a; return 0; }\n"))
+ "fn main() -> int:\n x := 1\n c := x.a\n return 0\n"))
ok.append(case_ok("t5_reg_tuple_field_oob",
- "fn main() -> int { t := (1,2); c := t . 5; return 0; }\n"))
+ "fn main() -> int:\n t := (1,2)\n c := t . 5\n return 0\n"))
ok.append(case_ok("t5_reg_ptr_field",
- S5 + "fn main() -> int { s := S { a: 1 }; p := &s; c := p.a; return 0; }\n"))
+ S5 + "fn main() -> int:\n s := S { a= 1 }\n p := &s\n c := p.a\n return 0\n"))
ok.append(case_ok("t5_reg_dyn_field",
- "fn main() -> int { d : dyn = 5; c := d.a; return 0; }\n"))
+ "fn main() -> int:\n d : dyn = 5\n c := d.a\n return 0\n"))
# dyn 面:现状**有**拒绝路径(逐具体行的方法表判定)——int/string 候选行也发 N08;
# 类级 IP_METHOD 门会**抑制**它们(= 放宽)⇒ 本段把现有 N08 钉红
ok.append(case_reject("t5_dyn_int_method_missing",
- "fn main() -> int { d : dyn = 5; d.nosuch(); return 0; }\n", "N08"))
+ "fn main() -> int:\n d : dyn = 5\n d.nosuch()\n return 0\n", "N08"))
ok.append(case_reject("t5_dyn_str_method_missing",
- 'fn main() -> int { d : dyn = "a"; d.nosuch(); return 0; }\n', "N08"))
+ 'fn main() -> int:\n d : dyn = "a"\n d.nosuch()\n return 0\n', "N08"))
ok.append(case_reject("t5_dyn_struct_method_missing",
- S5 + "fn main() -> int { s := S { a: 1 }; d : dyn = s; d.nosuch(); return 0; }\n",
+ S5 + "fn main() -> int:\n s := S { a= 1 }\n d : dyn = s\n d.nosuch()\n return 0\n",
"N08"))
# ─── R2 P2b Task 6:res_type_node/res_call_type 双份 TY→TI 映射合一(单表 ty_code_to_ti)───
@@ -246,36 +246,32 @@ def main():
# 静默改成 char/never、把 S3 的 char 从 char 改成 unit 等)。行号 = 诊断所在行(区分站点)。
# ① 两表基型分支(res_type_node / res_call_type)
ok.append(case_ok("t6_R_dyn_decl",
- "fn main() -> int { x : dyn = 5; return 0; }\n"))
+ "fn main() -> int:\n x : dyn = 5\n return 0\n"))
# res_type_node 的 7 码格 ⇒ TI_DYN(dyn 方法分派据此走 N08 路径)
ok.append(case_reject("t6_R_dyn_cell_live",
- "fn main() -> int { x : dyn = 5; x.nosuch(); return 0; }\n", "N08"))
+ "fn main() -> int:\n x : dyn = 5\n x.nosuch()\n return 0\n", "N08"))
ok.append(case_ok("t6_R_char_ret",
- "fn f() -> char { return 'a'; }\nfn main() -> int { c := f(); return 0; }\n"))
+ "fn f() -> char:\n return 'a'\nfn main() -> int:\n c := f()\n return 0\n"))
# ② **两表唯一差异格 = NEVER**:res_call_type 对调用位点的 `-> never` 返回 unit(现状),
# res_type_node 对类型位 `x : never = 1` 映 TI_NEVER——后者由 t6_S1/S3/S4/S6 的排除面互为镜像
# TF01 收口(2026-09-13):`fn g[T](a: T) -> never { loop { } }` 体以**无 break 的 loop**
# 收尾 ⇒ 不落空 ⇒ 站点 5 不再误报 TF01@1(该函数语义上确为 never 函数)。本用例的关注面 =
# 调用位点(`never` 在调用位点被当 unit ⇒ @raw_int 报 TF07@2),该面**不变**。
ok.append(case_diag_lines("t6_C_never_call_unit",
- "fn g[T](a: T) -> never { loop { } }\n"
- "fn main() -> int { x := g(1); y := @raw_int(x); return 0; }\n",
+ "fn g[T](a: T) -> never:\n loop:\nfn main() -> int:\n x := g(1)\n y := @raw_int(x)\n return 0\n",
[("TF07", 2)]))
# 对照(同一调用位点、`-> int`)::1615 路径确实在判(unit 兜底假设下 @raw_int 必报 TF07)
ok.append(case_ok("t6_C_int_call_ctrl",
- "fn g[T](a: T) -> int { return 1; }\n"
- "fn main() -> int { x := g(1); y := @raw_int(x); return 0; }\n"))
+ "fn g[T](a: T) -> int:\n return 1\nfn main() -> int:\n x := g(1)\n y := @raw_int(x)\n return 0\n"))
ok.append(case_ok("t6_C_never_param",
- "fn f[T](a: T, b: never) -> int { return 1; }\n"
- "fn main() -> int { return f(1, 2); }\n"))
+ "fn f[T](a: T, b: never) -> int:\n return 1\nfn main() -> int:\n return f(1, 2)\n"))
# ③ 同族 6 处内联链:**逐站域**(同一形在不同站点产出不同类型 ⇒ 域差异载荷)
# S1(hotpatch/普通注册链,域缺 CHAR/NEVER/7)vs S3(extern 链,域含 CHAR):同形不同果
ok.append(case_diag_lines("t6_S1_char_unit",
- "fn f() -> char { return 'a'; }\n"
- "fn main() -> char { x := f(); return x; }\n",
+ "fn f() -> char:\n return 'a'\nfn main() -> char:\n x := f()\n return x\n",
[("TF01", 2)]))
ok.append(case_ok("t6_S3_char_covered",
- "extern fn f() -> char;\nfn main() -> char { x := f(); return x; }\n"))
+ "extern fn f() -> char\nfn main() -> char:\n x := f()\n return x\n"))
# TF01 收口(2026-09-13):TF01@1 = 同为「无 break 的 loop 收尾」误报面(已修)。
# R2 P6 Task 4a(E-11)**重钉**(2026-09-14):本用例改前钉的是**误报**——`f()` 的
# 调用推断此前回 unit(S1 注册链把 NEVER 钳成 unit,checker.cr:1491)⇒ `x` = unit ⇒
@@ -285,58 +281,44 @@ def main():
# **S1 链的域差异**(`:1491` 挡 NEVER)**仍然成立**,其证据面改由 t6_S3/S4/S5/S6 四钉子
# + `type_selftest` 的 `t6.never_cell_diff` 承担,不在本用例。
ok.append(case_ok("t6_S1_never_unit",
- "fn f() -> never { loop { } }\n"
- "fn main() -> never { x := f(); return x; }\n"))
+ "fn f() -> never:\n loop:\nfn main() -> never:\n x := f()\n return x\n"))
ok.append(case_diag_lines("t6_S3_never_unit",
- "extern fn f() -> never;\n"
- "fn main() -> never { x := f(); return x; }\n",
+ "extern fn f() -> never\nfn main() -> never:\n x := f()\n return x\n",
[("TF01", 2)]))
# R2 P6 Task 4a(E-11,裁②并入):方法调用站点的 never 透传(姊妹站点 checker.cr:2694)。
# 改前:`s.m()` 推断 = unit(mangled "S.m" 经同一注册链钳位 :1491)⇒ 误发 TA02;
# 改后:rc=0(守卫含 `fi_generic_count(fi_m) == 0` + `sym_type == unit` + 裸码 never)。
ok.append(case_ok("t4a_method_never_call",
- "struct S { a: int }\n"
- "impl S { fn m(self: S) -> never { loop { } } }\n"
- "fn main() -> int { s := S { a: 1 }; x : int = s.m(); return 0; }\n"))
+ "struct S:\n a: int\nimpl S:\n fn m(self: S) -> never:\n loop:\nfn main() -> int:\n s := S { a= 1 }\n x : int = s.m()\n return 0\n"))
# 登记钉(裁④ 的泛型对齐面):泛型方法**不动**(守卫含 `fi_generic_count(fi_m) == 0`,
# 与直调泛型面「调用推断 = unit」一致)——改前改后同为 TA02。
ok.append(case_reject("t4a_method_generic_never_unit",
- "struct S { a: int }\n"
- "impl S { fn m[T](self: S, v: T) -> never { loop { } } }\n"
- "fn main() -> int { s := S { a: 1 }; x : int = s.m(1); return 0; }\n",
+ "struct S:\n a: int\nimpl S:\n fn m[T](self: S, v: T) -> never:\n loop:\nfn main() -> int:\n s := S { a= 1 }\n x : int = s.m(1)\n return 0\n",
"TA02"))
# S4(`check_func` 形参链,域缺 NEVER):形参符号类型 = unit(@raw_int 只收 dex/int/never)
ok.append(case_diag_lines("t6_S4_param_never_unit",
- "fn f(b: never) -> int { x := @raw_int(b); return 0; }\n"
- "fn main() -> int { return 0; }\n",
+ "fn f(b: never) -> int:\n x := @raw_int(b)\n return 0\nfn main() -> int:\n return 0\n",
[("TF07", 1)]))
ok.append(case_ok("t6_S4_param_char",
- "fn f(b: char) -> int { y : char = b; return 0; }\n"
- "fn main() -> int { return 0; }\n"))
+ "fn f(b: char) -> int:\n y : char = b\n return 0\nfn main() -> int:\n return 0\n"))
# S5(`check_func` 返回链,域含 NEVER)/S1 的 never 格排除面:`-> never` 声明自身报体检查
ok.append(case_diag_lines("t6_S5_never_covered",
- "fn f() -> never { return 1; }\nfn main() -> int { return 0; }\n",
+ "fn f() -> never:\n return 1\nfn main() -> int:\n return 0\n",
[("TF01", 1)]))
# S6(iface 返回链,值域 = parser 写入的 TY_* 码;域缺 NEVER/7)——**显式化**撞车比较
- T6_S6 = "struct S { a: int }\n"
+ T6_S6 = "struct S:\n a: int\n"
ok.append(case_ok("t6_S6_iface_int",
- "interface Show { fn show(self) -> int; }\n" + T6_S6 +
- "impl S { fn show(self: S) -> int { return 1; } }\n"
- "fn f[T: Show](a: T) -> int { x := a.show(); return x; }\n"
- "fn main() -> int { s := S { a: 1 }; return f(s); }\n"))
+ "interface Show:\n fn show(self) -> int\n" + T6_S6 +
+ "impl S:\n fn show(self: S) -> int:\n return 1\nfn f[T: Show](a: T) -> int:\n x := a.show()\n return x\nfn main() -> int:\n s := S { a= 1 }\n return f(s)\n"))
# TF01 收口(2026-09-13):TF01@3 = 同为「无 break 的 loop 收尾」误报面(已修);
# 本用例的关注面 = S6 iface 返回链(域缺 NEVER ⇒ @raw_int 报 TF07@4),该面**不变**。
ok.append(case_diag_lines("t6_S6_iface_never_unit",
- "interface Show { fn show(self) -> never; }\n" + T6_S6 +
- "impl S { fn show(self: S) -> never { loop { } } }\n"
- "fn f[T: Show](a: T) -> int { x := a.show(); y := @raw_int(x); return 0; }\n"
- "fn main() -> int { s := S { a: 1 }; return f(s); }\n",
+ "interface Show:\n fn show(self) -> never\n" + T6_S6 +
+ "impl S:\n fn show(self: S) -> never:\n loop:\nfn f[T: Show](a: T) -> int:\n x := a.show()\n y := @raw_int(x)\n return 0\nfn main() -> int:\n s := S { a= 1 }\n return f(s)\n",
[("TF07", 4)]))
ok.append(case_ok("t6_S6_iface_char_covered",
- "interface Show { fn show(self) -> char; }\n" + T6_S6 +
- "impl S { fn show(self: S) -> char { return 'a'; } }\n"
- "fn f[T: Show](a: T) -> int { x := a.show(); y : char = x; return 0; }\n"
- "fn main() -> int { s := S { a: 1 }; return f(s); }\n"))
+ "interface Show:\n fn show(self) -> char\n" + T6_S6 +
+ "impl S:\n fn show(self: S) -> char:\n return 'a'\nfn f[T: Show](a: T) -> int:\n x := a.show()\n y : char = x\n return 0\nfn main() -> int:\n s := S { a= 1 }\n return f(s)\n"))
passed = sum(ok)
print(f"{passed}/{len(ok)} passed")
diff --git a/tests/selfhost/test_iface_satisfies.py b/tests/selfhost/test_iface_satisfies.py
index 659ec46e..ae9b2063 100644
--- a/tests/selfhost/test_iface_satisfies.py
+++ b/tests/selfhost/test_iface_satisfies.py
@@ -157,130 +157,237 @@ def case_unjudged(name, source):
# ── 源形 ──────────────────────────────────────────────────────────────
# 方法在位(固有 impl 形态;P3a 既有语义 = 结构判定,非名义声明)
-IFACE_OK = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 1; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { return g(Box { v = S { a = 7 } }); }
+IFACE_OK = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 1
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ return g(Box { v = S { a = 7 } })
"""
# 方法在位(`impl I for T` 形态)
-IFACE_IMPL_FOR_OK = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl Show for S { fn show(self: S) -> int { return 2; } }
-struct Box[T: Show] { v: T }
-fn main() -> int { b := Box { v = S { a = 2 } }; return b.v.a; }
+IFACE_IMPL_FOR_OK = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl Show for S:
+ fn show(self: S) -> int:
+ return 2
+struct Box[T: Show]:
+ v: T
+fn main() -> int:
+ b := Box { v = S { a = 2 } }
+ return b.v.a
"""
# 方法缺失(**本批新增判定**)
-IFACE_MISSING = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_MISSING = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 参数计数不符
-IFACE_CNT_MISMATCH = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S, x: int) -> int { return x; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_CNT_MISMATCH = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S, x: int) -> int:
+ return x
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 返回码不符(iface `-> int` 码 0 vs impl `-> string` 码 3)
-IFACE_RET_MISMATCH = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> string { return "x"; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_RET_MISMATCH = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> string:
+ return "x"
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 同一违反走**函数调用点**(既有路径;措辞应与实例化点同)
-IFACE_FUNC_RET_MISMATCH = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> string { return "x"; } }
-fn f[T: Show](a: T) -> int { return 0; }
-fn main() -> int { s := S { a = 1 }; return f(s); }
+IFACE_FUNC_RET_MISMATCH = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> string:
+ return "x"
+fn f[T: Show](a: T) -> int:
+ return 0
+fn main() -> int:
+ s := S { a = 1 }
+ return f(s)
"""
# 枚举实例化点(方法缺失)
-IFACE_ENUM_MISSING = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-enum EBox[T: Show] { V(T), N }
-fn g(b: EBox[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_ENUM_MISSING = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+enum EBox[T: Show]:
+ V(T), N
+fn g(b: EBox[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 多方法接口:实现一半
-IFACE_PARTIAL = """interface Pair2 { fn first(self) -> int; fn second(self) -> int; }
-struct S { a: int }
-impl S { fn first(self: S) -> int { return 1; } }
-struct Box[T: Pair2] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_PARTIAL = """interface Pair2:
+ fn first(self) -> int
+ fn second(self) -> int
+struct S:
+ a: int
+impl S:
+ fn first(self: S) -> int:
+ return 1
+struct Box[T: Pair2]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 两接口隔离:S 满足 Show、不满足 Name
-IFACE_TWO_A = """interface Name { fn name(self) -> int; }
-struct S { a: int }
-impl S { fn name(self: S) -> int { return 1; } }
-struct BoxA[T: Name] { v: T }
-fn g(b: BoxA[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_TWO_A = """interface Name:
+ fn name(self) -> int
+struct S:
+ a: int
+impl S:
+ fn name(self: S) -> int:
+ return 1
+struct BoxA[T: Name]:
+ v: T
+fn g(b: BoxA[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
-IFACE_TWO_B = """interface Show { fn show(self) -> int; }
-interface Name { fn name(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 1; } }
-struct BoxB[T: Name] { v: T }
-fn g(b: BoxB[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_TWO_B = """interface Show:
+ fn show(self) -> int
+interface Name:
+ fn name(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 1
+struct BoxB[T: Name]:
+ v: T
+fn g(b: BoxB[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 泛型形参实参(未实例化)⇒ 不判
-IFACE_GP_ARG = """interface Show { fn show(self) -> int; }
-struct Box[T: Show] { v: T }
-fn f[U: Show](b: Box[U]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_GP_ARG = """interface Show:
+ fn show(self) -> int
+struct Box[T: Show]:
+ v: T
+fn f[U: Show](b: Box[U]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 原生实参 ⇒ 不判(接口方法表只对命名行可查)
-IFACE_NATIVE_ARG = """interface Show { fn show(self) -> int; }
-struct Box[T: Show] { v: T }
-fn g(b: Box[int]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_NATIVE_ARG = """interface Show:
+ fn show(self) -> int
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[int]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 签名类型项化的直接可观测面(Task 6 Step 1/3):命名的返回型 vs int 返回 ⇒ **拒绝**
# (旧态编码面判「满足」= 静默通过;台账见文件头注)
-IFACE_NAMED_RET = """interface Show { fn show(self) -> S2; }
-struct S2 { b: int }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 1; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+IFACE_NAMED_RET = """interface Show:
+ fn show(self) -> S2
+struct S2:
+ b: int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 1
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 函数调用点:满足 ⇒ 既有路径放行(正控;P3a 既有语义保持)
-IFACE_FUNC_OK = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 3; } }
-fn f[T: Show](a: T) -> int { return 1; }
-fn main() -> int { s := S { a = 1 }; return f(s); }
+IFACE_FUNC_OK = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 3
+fn f[T: Show](a: T) -> int:
+ return 1
+fn main() -> int:
+ s := S { a = 1 }
+ return f(s)
"""
# 函数调用点:违反 ⇒ 既有措辞(**逐字不动**的钉)
-IFACE_FUNC_MISSING = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-fn f[T: Show](a: T) -> int { return 0; }
-fn main() -> int { s := S { a = 1 }; return f(s); }
+IFACE_FUNC_MISSING = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+fn f[T: Show](a: T) -> int:
+ return 0
+fn main() -> int:
+ s := S { a = 1 }
+ return f(s)
"""
# 空接口(零方法)⇒ 空洞满足(命名行)
-IFACE_EMPTY = """interface Empty { }
-struct S { a: int }
-struct Box[T: Empty] { v: T }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { return g(Box { v = S { a = 5 } }); }
+IFACE_EMPTY = """interface Empty:
+struct S:
+ a: int
+struct Box[T: Empty]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ return g(Box { v = S { a = 5 } })
"""
# `&self` 接收者形态(计数面)
-IFACE_REF_SELF = """interface Show { fn show(&self) -> int; }
-struct S { a: int }
-impl S { fn show(&self) -> int { return 1; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { return g(Box { v = S { a = 4 } }); }
+IFACE_REF_SELF = """interface Show:
+ fn show(&self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(&self) -> int:
+ return 1
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ return g(Box { v = S { a = 4 } })
"""
diff --git a/tests/selfhost/test_impl.py b/tests/selfhost/test_impl.py
index a2da57ce..0aea0160 100644
--- a/tests/selfhost/test_impl.py
+++ b/tests/selfhost/test_impl.py
@@ -16,44 +16,63 @@
(
"method returns constant",
"""
-struct Vec { x: int, y: int }
-impl Vec { fn get_x(self: Vec) -> int { return 42; } }
-fn main() -> int { v := Vec { x = 10, y = 20 }; return v.get_x(); }
+struct Vec:
+ x: int, y: int
+impl Vec:
+ fn get_x(self: Vec) -> int:
+ return 42
+fn main() -> int:
+ v := Vec { x = 10, y = 20 }
+ return v.get_x()
""",
),
(
"method reads self.x",
"""
-struct Vec { x: int, y: int }
-impl Vec { fn get_x(self: Vec) -> int { return self.x; } }
-fn main() -> int { v := Vec { x = 10, y = 20 }; return v.get_x(); }
+struct Vec:
+ x: int, y: int
+impl Vec:
+ fn get_x(self: Vec) -> int:
+ return self.x
+fn main() -> int:
+ v := Vec { x = 10, y = 20 }
+ return v.get_x()
""",
),
(
"struct field read",
"""
-struct Pos { x: int }
-fn main() -> int { p := Pos { x = 42 }; return p.x; }
+struct Pos:
+ x: int
+fn main() -> int:
+ p := Pos { x = 42 }
+ return p.x
""",
),
(
"method with self param",
"""
-struct Vec { x: int, y: int }
-impl Vec { fn sum(self: Vec) -> int { return self.x + self.y; } }
-fn main() -> int { v := Vec { x = 10, y = 20 }; return v.sum(); }
+struct Vec:
+ x: int, y: int
+impl Vec:
+ fn sum(self: Vec) -> int:
+ return self.x + self.y
+fn main() -> int:
+ v := Vec { x = 10, y = 20 }
+ return v.sum()
""",
),
(
"method returning struct",
"""
-struct Point { x: int, y: int }
-impl Point {
- fn double(self: Point) -> Point {
- return Point { x = self.x * 2, y = self.y * 2 };
- }
-}
-fn main() -> Point { p := Point { x = 5, y = 7 }; return p.double(); }
+struct Point:
+ x: int, y: int
+impl Point:
+ fn double(self: Point) -> Point:
+ return Point { x = self.x * 2, y = self.y * 2 }
+fn main() -> Point:
+ p := Point { x = 5, y = 7 }
+ return p.double()
""",
),
]
@@ -63,25 +82,32 @@
(
"self_method",
"""
-struct Point { x: int, y: int }
-impl Point { fn get_x(&self) -> int { return self.x; } }
-fn main() -> int { p := Point { x = 42, y = 100 }; return p.get_x(); }
+struct Point:
+ x: int, y: int
+impl Point:
+ fn get_x(&self) -> int:
+ return self.x
+fn main() -> int:
+ p := Point { x = 42, y = 100 }
+ return p.get_x()
""",
42,
),
(
"mut_self_method",
"""
-struct Counter { val: int }
-impl Counter {
- fn inc(&mut self) { self.val = self.val + 1; }
- fn get(&self) -> int { return self.val; }
-}
-fn main() -> int {
- c : ., mut = Counter { val = 5 };
- c.inc(); c.inc();
- return c.get();
-}
+struct Counter:
+ val: int
+impl Counter:
+ fn inc(&mut self):
+ self.val = self.val + 1
+ fn get(&self) -> int:
+ return self.val
+fn main() -> int:
+ c : ., mut = Counter { val = 5 }
+ c.inc()
+ c.inc()
+ return c.get()
""",
7,
),
diff --git a/tests/selfhost/test_impl_iface.py b/tests/selfhost/test_impl_iface.py
index 9479fdfc..71639eff 100644
--- a/tests/selfhost/test_impl_iface.py
+++ b/tests/selfhost/test_impl_iface.py
@@ -198,158 +198,305 @@ def case_hard(name, source, needles):
# ── 源形 ──────────────────────────────────────────────────────────────
# 正向:固有 impl 形态(结构口径)——**双站点**(实例化点 `Box[S]` 注解 + 函数调用点 `f(s)`)
-POS_INHERENT = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 5; } }
-struct Box[T: Show] { v: T }
-fn f[T: Show](a: T) -> int { return 0; }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { s := S { a = 7 }; z := f(s); return g(Box { v = s }); }
+POS_INHERENT = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 5
+struct Box[T: Show]:
+ v: T
+fn f[T: Show](a: T) -> int:
+ return 0
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ s := S { a = 7 }
+ z := f(s)
+ return g(Box { v = s })
"""
# 正向:`impl I for T` 形态(双站点)
-POS_IMPL_FOR = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl Show for S { fn show(self: S) -> int { return 2; } }
-struct Box[T: Show] { v: T }
-fn f[T: Show](a: T) -> int { return 0; }
-fn main() -> int { s := S { a = 2 }; z := f(s); return s.a + z; }
+POS_IMPL_FOR = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl Show for S:
+ fn show(self: S) -> int:
+ return 2
+struct Box[T: Show]:
+ v: T
+fn f[T: Show](a: T) -> int:
+ return 0
+fn main() -> int:
+ s := S { a = 2 }
+ z := f(s)
+ return s.a + z
"""
# 正向:命名参数类型 + 命名返回类型(签名类型项化的主要正控——旧态两侧皆码 0;双站点)
-POS_NAMED_SIG = """interface Conv { fn conv(self, x: S2) -> S3; }
-struct S2 { b: int }
-struct S3 { c: int }
-struct S { a: int }
-impl S { fn conv(self: S, x: S2) -> S3 { return S3 { c = x.b + 3 }; } }
-struct Box[T: Conv] { v: T }
-fn f[T: Conv](a: T) -> int { return 0; }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { s := S { a = 1 }; z := f(s); return g(Box { v = s }); }
+POS_NAMED_SIG = """interface Conv:
+ fn conv(self, x: S2) -> S3
+struct S2:
+ b: int
+struct S3:
+ c: int
+struct S:
+ a: int
+impl S:
+ fn conv(self: S, x: S2) -> S3:
+ return S3 { c = x.b + 3 }
+struct Box[T: Conv]:
+ v: T
+fn f[T: Conv](a: T) -> int:
+ return 0
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ s := S { a = 1 }
+ z := f(s)
+ return g(Box { v = s })
"""
# 正向:泛型应用实参(`Pair[int]` 两侧同型;双站点)
-POS_APPLY_SIG = """interface Take { fn take(self, x: Pair[int]) -> int; }
-struct Pair[T] { v: T }
-struct S { a: int }
-impl S { fn take(self: S, x: Pair[int]) -> int { return x.v; } }
-struct Box[T: Take] { v: T }
-fn f[T: Take](a: T) -> int { return 0; }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { s := S { a = 9 }; z := f(s); return g(Box { v = s }); }
+POS_APPLY_SIG = """interface Take:
+ fn take(self, x: Pair[int]) -> int
+struct Pair[T]:
+ v: T
+struct S:
+ a: int
+impl S:
+ fn take(self: S, x: Pair[int]) -> int:
+ return x.v
+struct Box[T: Take]:
+ v: T
+fn f[T: Take](a: T) -> int:
+ return 0
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ s := S { a = 9 }
+ z := f(s)
+ return g(Box { v = s })
"""
# 正向:`&self` 接收者(两侧同模式;双站点)
-POS_REF_SELF = """interface Show { fn show(&self) -> int; }
-struct S { a: int }
-impl S { fn show(&self) -> int { return 4; } }
-struct Box[T: Show] { v: T }
-fn f[T: Show](a: T) -> int { return 0; }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { s := S { a = 4 }; z := f(s); return g(Box { v = s }); }
+POS_REF_SELF = """interface Show:
+ fn show(&self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(&self) -> int:
+ return 4
+struct Box[T: Show]:
+ v: T
+fn f[T: Show](a: T) -> int:
+ return 0
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ s := S { a = 4 }
+ z := f(s)
+ return g(Box { v = s })
"""
# 泛型体内方法调用(mangling 退役的主用例:旧态**运行 rc=139**)——固有形态
-POS_GENERIC_BODY_CALL = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 7; } }
-fn f[T: Show](a: T) -> int { x := a.show(); return x; }
-fn main() -> int { s := S { a = 1 }; return f(s); }
+POS_GENERIC_BODY_CALL = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 7
+fn f[T: Show](a: T) -> int:
+ x := a.show()
+ return x
+fn main() -> int:
+ s := S { a = 1 }
+ return f(s)
"""
# 泛型体内方法调用——`impl I for T` 形态
-POS_GENERIC_BODY_CALL_FOR = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl Show for S { fn show(self: S) -> int { return 9; } }
-fn f[T: Show](a: T) -> int { x := a.show(); return x; }
-fn main() -> int { s := S { a = 1 }; return f(s); }
+POS_GENERIC_BODY_CALL_FOR = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl Show for S:
+ fn show(self: S) -> int:
+ return 9
+fn f[T: Show](a: T) -> int:
+ x := a.show()
+ return x
+fn main() -> int:
+ s := S { a = 1 }
+ return f(s)
"""
# 固有方法不受影响(无接口参与)
-POS_INHERENT_ONLY = """struct S { a: int }
-impl S { fn get(self: S) -> int { return self.a; } fn add(self: S, x: int) -> int { return self.a + x; } }
-fn main() -> int { s := S { a = 6 }; return s.add(1); }
+POS_INHERENT_ONLY = """struct S:
+ a: int
+impl S:
+ fn get(self: S) -> int:
+ return self.a
+ fn add(self: S, x: int) -> int:
+ return self.a + x
+fn main() -> int:
+ s := S { a = 6 }
+ return s.add(1)
"""
# 多接口隔离:S 满足 Show(另一接口 Name 未参与;双站点)
-POS_MULTI_IFACE = """interface Show { fn show(self) -> int; }
-interface Name { fn name(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 1; } }
-impl S { fn name(self: S) -> int { return 2; } }
-struct Box[T: Show] { v: T }
-fn f[T: Show](a: T) -> int { return 0; }
-fn g(b: Box[S]) -> int { return b.v.a; }
-fn main() -> int { s := S { a = 3 }; z := f(s); return g(Box { v = s }); }
+POS_MULTI_IFACE = """interface Show:
+ fn show(self) -> int
+interface Name:
+ fn name(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 1
+impl S:
+ fn name(self: S) -> int:
+ return 2
+struct Box[T: Show]:
+ v: T
+fn f[T: Show](a: T) -> int:
+ return 0
+fn g(b: Box[S]) -> int:
+ return b.v.a
+fn main() -> int:
+ s := S { a = 3 }
+ z := f(s)
+ return g(Box { v = s })
"""
# 负:缺方法
-NEG_MISSING = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+NEG_MISSING = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 负:参数计数
-NEG_ARITY = """interface Show { fn show(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S, x: int) -> int { return x; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+NEG_ARITY = """interface Show:
+ fn show(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S, x: int) -> int:
+ return x
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 负:**参数类型**不符(命名型——旧态裸码面不可见)
-NEG_NAMED_PARAM = """interface Show { fn m(self, x: S2) -> int; }
-struct S2 { b: int }
-struct S { a: int }
-impl S { fn m(self: S, x: int) -> int { return x; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+NEG_NAMED_PARAM = """interface Show:
+ fn m(self, x: S2) -> int
+struct S2:
+ b: int
+struct S:
+ a: int
+impl S:
+ fn m(self: S, x: int) -> int:
+ return x
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 负:**返回类型**不符(命名型 vs 原生——旧态编码面判「满足」)
-NEG_NAMED_RET = """interface Show { fn m(self) -> S2; }
-struct S2 { b: int }
-struct S { a: int }
-impl S { fn m(self: S) -> int { return 1; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+NEG_NAMED_RET = """interface Show:
+ fn m(self) -> S2
+struct S2:
+ b: int
+struct S:
+ a: int
+impl S:
+ fn m(self: S) -> int:
+ return 1
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 负:泛型应用实参不符(`Pair[string]` ← `Pair[int]`)
-NEG_APPLY_ARG = """interface Take { fn take(self, x: Pair[int]) -> int; }
-struct Pair[T] { v: T }
-struct S { a: int }
-impl S { fn take(self: S, x: Pair[string]) -> int { return 1; } }
-struct Box[T: Take] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+NEG_APPLY_ARG = """interface Take:
+ fn take(self, x: Pair[int]) -> int
+struct Pair[T]:
+ v: T
+struct S:
+ a: int
+impl S:
+ fn take(self: S, x: Pair[string]) -> int:
+ return 1
+struct Box[T: Take]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 负:接收者模式不符(iface `&self` vs impl `self`)
-NEG_RECV_MODE = """interface Show { fn show(&self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 1; } }
-struct Box[T: Show] { v: T }
-fn g(b: Box[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+NEG_RECV_MODE = """interface Show:
+ fn show(&self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 1
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 负:两接口隔离(S 满足 Show、不满足 Name)
-NEG_SECOND_IFACE = """interface Show { fn show(self) -> int; }
-interface Name { fn name(self) -> int; }
-struct S { a: int }
-impl S { fn show(self: S) -> int { return 1; } }
-struct BoxB[T: Name] { v: T }
-fn g(b: BoxB[S]) -> int { return 0; }
-fn main() -> int { return 0; }
+NEG_SECOND_IFACE = """interface Show:
+ fn show(self) -> int
+interface Name:
+ fn name(self) -> int
+struct S:
+ a: int
+impl S:
+ fn show(self: S) -> int:
+ return 1
+struct BoxB[T: Name]:
+ v: T
+fn g(b: BoxB[S]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 错误例:未定义接口(`impl I for T` 的声明侧校验)
-ERR_UNDEFINED_IFACE = """struct S { a: int }
-impl Nope for S { fn show(self: S) -> int { return 1; } }
-fn main() -> int { return 0; }
+ERR_UNDEFINED_IFACE = """struct S:
+ a: int
+impl Nope for S:
+ fn show(self: S) -> int:
+ return 1
+fn main() -> int:
+ return 0
"""
# 登记面:非命名实参(原生)⇒ 不判 ⇒ 零诊断
-UNJUDGED_NATIVE = """interface Show { fn show(self) -> int; }
-struct Box[T: Show] { v: T }
-fn g(b: Box[int]) -> int { return 0; }
-fn main() -> int { return 0; }
+UNJUDGED_NATIVE = """interface Show:
+ fn show(self) -> int
+struct Box[T: Show]:
+ v: T
+fn g(b: Box[int]) -> int:
+ return 0
+fn main() -> int:
+ return 0
"""
# 上限钉子:17 方法(> MAX_IFACE_METHODS=16)⇒ 硬错
-LIMIT_METHODS = "interface Many {\n" + "\n".join(
- f" fn m{i}(self) -> int;" for i in range(17)) + "\n}\nfn main() -> int { return 0; }\n"
+LIMIT_METHODS = "interface Many:\n" + "\n".join(
+ f" fn m{i}(self) -> int" for i in range(17)) + "\nfn main() -> int:\n return 0\n"
# 上限钉子:9 参数(> MAX_IFACE_METHOD_PARAMS=8)⇒ 硬错
-LIMIT_PARAMS = ("interface Wide { fn m(self, " + ", ".join(f"p{i}: int" for i in range(9)) +
- ") -> int; }\nfn main() -> int { return 0; }\n")
+LIMIT_PARAMS = ("interface Wide:\n fn m(self, " + ", ".join(f"p{i}: int" for i in range(9)) +
+ ") -> int\nfn main() -> int:\n return 0\n")
def main():
diff --git a/tests/selfhost/test_interp_float.py b/tests/selfhost/test_interp_float.py
index a9e1c0ad..c2862f2a 100644
--- a/tests/selfhost/test_interp_float.py
+++ b/tests/selfhost/test_interp_float.py
@@ -17,29 +17,29 @@
# (名称, 源码, 期望退出码) —— corec run 的退出码 = main() 返回值
CASES = [
# ── F9: interp TI_FLOAT 分派(IEEE 754 软件实现)──
- ("float_add", "fn main() -> int { x := 1.5; y := 2.5; z := x + y; if z == 4.0 { return 1; } return 0; }", 1),
- ("float_add_pow2", "fn main() -> int { x := 2.5; y := 2.5; z := x + y; if z == 5.0 { return 1; } return 0; }", 1),
- ("float_sub", "fn main() -> int { x := 3.5; y := 1.0; z := x - y; if z == 2.5 { return 1; } return 0; }", 1),
- ("float_mul", "fn main() -> int { x := 1.5; y := 2.0; z := x * y; if z == 3.0 { return 1; } return 0; }", 1),
- ("float_div", "fn main() -> int { x := 7.0; y := 2.0; z := x / y; if z == 3.5 { return 1; } return 0; }", 1),
- ("float_cmp", "fn main() -> int { x := 1.5; y := 2.5; if x < y { if y > x { return 1; } } return 0; }", 1),
- ("float_i2f", "fn main() -> int { y := 1099511627776; z := 1.5 + y; if z > 1000000000000.0 { return 1; } return 0; }", 1),
+ ("float_add", "fn main() -> int:\n x := 1.5\n y := 2.5\n z := x + y\n if z == 4.0:\n return 1\n return 0\n", 1),
+ ("float_add_pow2", "fn main() -> int:\n x := 2.5\n y := 2.5\n z := x + y\n if z == 5.0:\n return 1\n return 0\n", 1),
+ ("float_sub", "fn main() -> int:\n x := 3.5\n y := 1.0\n z := x - y\n if z == 2.5:\n return 1\n return 0\n", 1),
+ ("float_mul", "fn main() -> int:\n x := 1.5\n y := 2.0\n z := x * y\n if z == 3.0:\n return 1\n return 0\n", 1),
+ ("float_div", "fn main() -> int:\n x := 7.0\n y := 2.0\n z := x / y\n if z == 3.5:\n return 1\n return 0\n", 1),
+ ("float_cmp", "fn main() -> int:\n x := 1.5\n y := 2.5\n if x < y:\n if y > x:\n return 1\n return 0\n", 1),
+ ("float_i2f", "fn main() -> int:\n y := 1099511627776\n z := 1.5 + y\n if z > 1000000000000.0:\n return 1\n return 0\n", 1),
# (NaN/Inf 用例已删除:dex 世界 0 除按整数陷阱 SIGFPE,IEEE-754 语义退役)
- ("float_int_mix", "fn main() -> int { f : dex = 2.0; i := 3; r := f + i; if r == 5.0 { return 0; } return 1; }", 0),
+ ("float_int_mix", "fn main() -> int:\n f : dex = 2.0\n i := 3\n r := f + i\n if r == 5.0:\n return 0\n return 1\n", 0),
# ── F12: STORE_PTR 操作数(*p = v 写穿)──
- ("storeptr", "fn main() -> int { x := 5; p := &x; *p = 42; return x; }", 42),
- ("deref_read", "fn main() -> int { x : ., mut = 42; q := &x; if *q != 42 { return 1; } return 0; }", 0),
- ("ptr_arith", "fn main() -> int { arr := [10, 20, 30]; p := &arr[2]; if *p != 30 { return 1; } return 0; }", 0),
+ ("storeptr", "fn main() -> int:\n x := 5\n p := &x\n *p = 42\n return x\n", 42),
+ ("deref_read", "fn main() -> int:\n x : ., mut = 42\n q := &x\n if *q != 42:\n return 1\n return 0\n", 0),
+ ("ptr_arith", "fn main() -> int:\n arr := [10, 20, 30]\n p := &arr[2]\n if *p != 30:\n return 1\n return 0\n", 0),
# ── F13: 枚举 payload(堆镜像布局 [tag][payload])──
- ("enum_payload", "enum Choice { First(int), Second(int), Third(int) } fn main() -> int { c := Third(33); value := match c { First(v) => v, Second(v) => v, Third(v) => v, }; return value; }", 33),
- ("enum_tag_only", "enum Color { Red, Green, Blue } fn main() -> int { c := Green(); t := match c { Red => 1, Green => 2, Blue => 3, }; return t; }", 2),
+ ("enum_payload", "enum Choice:\n First(int), Second(int), Third(int)\nfn main() -> int:\n c := Third(33)\n value := match c:\n First(v) => v, Second(v) => v, Third(v) => v,\n return value\n", 33),
+ ("enum_tag_only", "enum Color:\n Red, Green, Blue\nfn main() -> int:\n c := Green()\n t := match c:\n Red => 1, Green => 2, Blue => 3,\n return t\n", 2),
# ── BC11: dyn 双槽 / ADDR_INDEX ──
- ("dyn_basic", "fn main() -> int { x : dyn = 42; if x != 42 { return 1; } return 0; }", 0),
- ("addr_index", "fn main() -> int { a := [10, 20, 30]; p := &a[1]; if p == 0 { return 1; } return 0; }", 0),
+ ("dyn_basic", "fn main() -> int:\n x : dyn = 42\n if x != 42:\n return 1\n return 0\n", 0),
+ ("addr_index", "fn main() -> int:\n a := [10, 20, 30]\n p := &a[1]\n if p == 0:\n return 1\n return 0\n", 0),
# ── 纯 int 回归 ──
- ("int_arith", "fn main() -> int { a := -7; b := 3; c := a / b; d := a % b; if c == -2 && d == -1 { return 1; } return 0; }", 1),
+ ("int_arith", "fn main() -> int:\n a := -7\n b := 3\n c := a / b\n d := a % b\n if c == -2 && d == -1:\n return 1\n return 0\n", 1),
# ── BC-CONST: interpreter string values remain intern indices ──
- ("interp_strings", "fn main() -> int { s := \"abc\"; t := \"ab\" + \"c\"; if str_len(s) != 3 { return 1; } if str_eq(s, t) == 0 { return 2; } i := 1; if s[i] != 98 { return 3; } return 0; }", 0),
+ ("interp_strings", "fn main() -> int:\n s := \"abc\"\n t := \"ab\" + \"c\"\n if str_len(s) != 3:\n return 1\n if str_eq(s, t) == 0:\n return 2\n i := 1\n if s[i] != 98:\n return 3\n return 0\n", 0),
]
diff --git a/tests/selfhost/test_interp_parity.py b/tests/selfhost/test_interp_parity.py
index a55118f8..4a615430 100644
--- a/tests/selfhost/test_interp_parity.py
+++ b/tests/selfhost/test_interp_parity.py
@@ -51,28 +51,27 @@
# —— 枚举族(17 MAKE_ENUM / 23 LOAD_ENUM_TAG / payload 走 11/12)——
(
"enum_payload_in_callee",
- "enum Choice { First(int), Second(int), Third(int) }",
- "c := Third(33); return match c { First(x) => x, Second(x) => x, Third(x) => x, };",
+ "enum Choice:\n First(int), Second(int), Third(int)\n",
+ "c := Third(33)\nreturn match c:\n First(x) => x, Second(x) => x, Third(x) => x,\n",
"parity", 33, 33,
),
(
# 构造在 callee(MAKE_ENUM)、match 在 main(LOAD_ENUM_TAG 跨函数)
"enum_construct_callee_match_main",
- "enum Choice { First(int), Second(int), Third(int) }\n"
- "fn make()->Choice { return Third(33); }",
- "c := make(); return match c { First(x) => x, Second(x) => x, Third(x) => x, };",
+ "enum Choice:\n First(int), Second(int), Third(int)\nfn make()->Choice:\n return Third(33)\n",
+ "c := make()\nreturn match c:\n First(x) => x, Second(x) => x, Third(x) => x,\n",
"parity", 33, 33,
),
(
"enum_tag_variant_in_callee",
- "enum Color { Red, Green, Blue }",
- "c := Green(); return match c { Red => 1, Green => 2, Blue => 3, };",
+ "enum Color:\n Red, Green, Blue\n",
+ "c := Green()\nreturn match c:\n Red => 1, Green => 2, Blue => 3,\n",
"parity", 2, 2,
),
(
"enum_payload_tag_only_in_callee",
- "enum Choice { First(int), Second(int), Third(int) }",
- "c := Third(33); return match c { First(x) => 1, Second(x) => 2, Third(x) => 3, };",
+ "enum Choice:\n First(int), Second(int), Third(int)\n",
+ "c := Third(33)\nreturn match c:\n First(x) => 1, Second(x) => 2, Third(x) => 3,\n",
"parity", 3, 3,
),
# —— 裸指针族(18 REF / 25 DEREF / 26 STORE_PTR / 31 ADDR_INDEX)——
@@ -80,19 +79,19 @@
# TODO #2026-09-10-7 复现原件:g:[int;3]=[5,6,7]; fn f(){ p:=&g[2]; return *p; }
"bare_ptr_deref_callee",
"g : [int;3] = [5,6,7];",
- "p := &g[2]; return *p;",
+ "p := &g[2]\nreturn *p\n",
"parity", 7, 7,
),
(
"ptr_store_callee",
"",
- "x : ., mut = 5; p := &x; *p = 42; return x;",
+ "x : ., mut = 5\np := &x\n*p = 42\nreturn x\n",
"parity", 42, 42,
),
(
"addr_index_deref_callee",
"",
- "a := [10,20,30]; p := &a[1]; return *p;",
+ "a := [10,20,30]\np := &a[1]\nreturn *p\n",
"parity", 20, 20,
),
# —— 切片 / 边界检查族(24 SLICE / 30 BOUNDS_CHECK)——
@@ -120,48 +119,47 @@
(
"dyn_pack_val_callee",
"",
- "x : dyn = 42; if x != 42 { return 1; } return 0;",
+ "x : dyn = 42\nif x != 42:\n return 1\nreturn 0\n",
"parity", 0, 0,
),
(
# 动态分发:interp 响亮报错(rc 2 + 诊断,与主循环同文案);ELF 占位 no-op
"dyn_dispatch_callee_loud",
- "struct Counter { n: int }\nimpl Counter {\n fn bump(self) { }\n}\n",
- "c : Counter = Counter { n = 7 }; d : dyn = c; d.bump(); return 3;",
+ "struct Counter:\n n: int\nimpl Counter:\n fn bump(self):\n",
+ "c : Counter = Counter { n = 7 }\nd : dyn = c\nd.bump()\nreturn 3\n",
"loud", 2, 3,
),
# —— 调用族(4 CALL:嵌套内联 / 递归 / 互递归)——
(
"nested_call_callee",
- "fn g2()->int { return 7; }\n",
+ "fn g2()->int:\n return 7\n",
"return g2();",
"parity", 7, 7,
),
(
"recursion_fib_callee",
- "fn fib(n: int)->int { if n < 2 { return n; } return fib(n-1) + fib(n-2); }\n",
+ "fn fib(n: int)->int:\n if n < 2:\n return n\n return fib(n-1) + fib(n-2)\n",
"return fib(10);",
"parity", 55, 55,
),
(
"mutual_recursion_callee",
- "fn is_even(n: int)->int { if n == 0 { return 1; } return is_odd(n - 1); }\n"
- "fn is_odd(n: int)->int { if n == 0 { return 0; } return is_even(n - 1); }\n",
+ "fn is_even(n: int)->int:\n if n == 0:\n return 1\n return is_odd(n - 1)\nfn is_odd(n: int)->int:\n if n == 0:\n return 0\n return is_even(n - 1)\n",
"return is_even(10);",
"parity", 1, 1,
),
(
# 深度守卫:无界递归必须响亮中止(rc 255 + 诊断),不挂死
"depth_guard_runaway_loud",
- "fn r(n: int)->int { return r(n + 1); }\n",
+ "fn r(n: int)->int:\n return r(n + 1)\n",
"return r(0);",
"loud", 255, SIGSEGV,
),
# —— 并发族(27 SPAWN:range go;28 YIELD / 29 AWAIT eager 近似)——
(
"range_go_spawn_callee",
- "fn square(x: int) -> int { return x * x; }\n",
- "arr := go i 0..3 square(i); return arr[0] + arr[1] + arr[2];",
+ "fn square(x: int) -> int:\n return x * x\n",
+ "arr := go i 0..3 square(i)\nreturn arr[0] + arr[1] + arr[2]\n",
"parity", 5, 5,
),
(
@@ -169,7 +167,7 @@
# callee 路径只用 label_poses——两条机制各走各的,必须同值)
"loop_in_callee",
"",
- "s : ., mut = 0; for i := 0..5 { s = s + i; } return s;",
+ "s : ., mut = 0\nfor i := 0..5:\n s = s + i\nreturn s\n",
"parity", 10, 10,
),
(
@@ -181,14 +179,14 @@
(
"await_in_callee",
"",
- "x := await 5; return x;",
+ "x := await 5\nreturn x\n",
"parity", 5, 5,
),
# —— 45 CALL_EXTERN:响亮报错(interp rc 2 + 诊断;ELF 静态构建运行期
# SIGSEGV——两侧都非静默)——
(
"extern_call_callee_loud",
- "extern fn putchar(c: int) -> int;\n",
+ "extern fn putchar(c: int) -> int\n",
"return putchar(65);",
"loud", 2, SIGSEGV,
),
@@ -196,8 +194,8 @@
(
# 解释器无真实地址(FNADDR 恒 0)——显式近似:只断言 callee ≡ main
"fnaddr_callee_approx",
- "fn square(x: int) -> int { return x * x; }\n",
- "p := @addr(square); if p == 0 { return 1; } return 0;",
+ "fn square(x: int) -> int:\n return x * x\n",
+ "p := @addr(square)\nif p == 0:\n return 1\nreturn 0\n",
"approx", 1, 0,
),
(
@@ -206,7 +204,7 @@
# 根本未发射,判据形同虚设(两形态的诊断奇偶断言也掩盖了它)。
"approx_apx_dex_callee",
"",
- "d : dex, apx = 2.0; return 7;",
+ "d : dex, apx = 2.0\nreturn 7\n",
"parity", 7, 7,
),
]
@@ -313,14 +311,20 @@ def run_native(name: str, source: str):
pass
+def _indent_body(body: str) -> str:
+ """函数体片段(多行、自带**相对**缩进)⇒ v4 region 体:逐行 +4 空格。"""
+ return "\n".join((" " + ln) if ln.strip() else ln for ln in body.split("\n"))
+
+
def callee_src(prelude: str, body: str) -> str:
"""内联路径:函数体包进 probe(),main 调 probe()。"""
- return f"{prelude}\nfn probe()->int {{ {body} }}\nfn main()->int {{ return probe(); }}"
+ return (f"{prelude}\nfn probe()->int:\n{_indent_body(body)}\n"
+ f"fn main()->int:\n return probe()")
def main_src(prelude: str, body: str) -> str:
"""主循环路径:同一段函数体直接内联进 main。"""
- return f"{prelude}\nfn main()->int {{ {body} }}"
+ return f"{prelude}\nfn main()->int:\n{_indent_body(body)}"
def probe_ops(name: str, source: str):
diff --git a/tests/selfhost/test_let_check.py b/tests/selfhost/test_let_check.py
index 7eb93b2b..6bfbd5e5 100644
--- a/tests/selfhost/test_let_check.py
+++ b/tests/selfhost/test_let_check.py
@@ -147,109 +147,95 @@ def case_reject(name, source, needles, cmd="build", forbid=STAGES, want_no_artif
# ─── 语料 ───
-SLICE_SRC = ("fn h(s: [int]) -> int { x : [int;3] = s; return 0; }\n"
- "fn main() -> int { return h([1,2,3]); }\n")
+SLICE_SRC = ("fn h(s: [int]) -> int:\n x : [int;3] = s\n return 0\nfn main() -> int:\n return h([1,2,3])\n")
def main():
ok = [
# ── 拒绝面(RED 三形态 + 同族扩展)──
- case_reject("let_int_string_build_rejected", 'fn main() -> int { x : int = "s"; return 0; }\n',
+ case_reject("let_int_string_build_rejected", 'fn main() -> int:\n x : int = "s"\n return 0\n',
["error[TA02]", "Variable declared as int, got string"]),
- case_reject("let_int_string_check_rejected", 'fn main() -> int { x : int = "s"; return 0; }\n',
+ case_reject("let_int_string_check_rejected", 'fn main() -> int:\n x : int = "s"\n return 0\n',
["error[TA02]"], cmd="check"),
case_reject("let_slice_to_fixed_rejected", SLICE_SRC,
["error[TA02]", "Array length constraint not satisfied"], cmd="check"),
case_reject("let_arr_len_literal_rejected",
- "fn main() -> int { x : [int;4] = [1,2,3]; return 0; }\n",
+ "fn main() -> int:\n x : [int;4] = [1,2,3]\n return 0\n",
["error[TA02]", "Array length constraint not satisfied"]),
case_reject("let_optional_narrow_rejected",
- "fn main() -> int { x : int? = 5; y : int = x; return y; }\n",
+ "fn main() -> int:\n x : int? = 5\n y : int = x\n return y\n",
["error[TA02]", "Variable declared as int, got int?"]),
case_reject("let_int_from_struct_rejected",
- "struct P { a: int }\nfn main() -> int { p := P { a: 1 }; i : int = p; return i; }\n",
+ "struct P:\n a: int\nfn main() -> int:\n p := P { a= 1 }\n i : int = p\n return i\n",
["error[TA02]"], cmd="check"),
case_reject("let_struct_from_int_rejected",
- "struct P { a: int }\nfn main() -> int { p : P = 5; return 0; }\n",
+ "struct P:\n a: int\nfn main() -> int:\n p : P = 5\n return 0\n",
["error[TA02]", "Variable declared as P, got int"], cmd="check"),
# 全局声明面(同形缺口:注册趟即取注解行)——本任务显式划界覆盖
- case_reject("let_global_rejected", 'g : int = "s";\nfn main() -> int { return 0; }\n',
+ case_reject("let_global_rejected", 'g : int = "s"\nfn main() -> int:\n return 0\n',
["error[TA02]", "Variable declared as int, got string"]),
# 批量声明(`a, b : int = ...`——每个名字一个 LET 节点,逐名判)
- case_reject("let_batch_rejected", 'fn main() -> int { a, b : int = 1, "s"; return a; }\n',
+ case_reject("let_batch_rejected", 'fn main() -> int:\n a, b : int = 1, "s"\n return a\n',
["error[TA02]", "Variable declared as int, got string"], cmd="check"),
# 丢弃名(`_ : int = ...`)同样受判
- case_reject("let_discard_rejected", 'fn main() -> int { _ : int = "s"; return 0; }\n',
+ case_reject("let_discard_rejected", 'fn main() -> int:\n _ : int = "s"\n return 0\n',
["error[TA02]"], cmd="check"),
# ── 级联抑制(值 = TI_NEVER 错误标记):只发原诊断,不叠 TA02 ──
case_reject("let_error_marker_no_cascade_ident",
- "fn main() -> int { x : int = nosuchname; return 0; }\n",
+ "fn main() -> int:\n x : int = nosuchname\n return 0\n",
["error[N01]"], cmd="check", forbid=(), exact_diags=1),
case_reject("let_error_marker_no_cascade_call",
- "fn main() -> int { x : int = nosuchfn(); return 0; }\n",
+ "fn main() -> int:\n x : int = nosuchfn()\n return 0\n",
["error[N06]"], cmd="check", forbid=(), exact_diags=1),
# ── R2 P6 Task 4a(E-11):`-> never` 调用的返回型透传(TA02 面)──
# 改前(RED 实测):`boom()` 推断 = unit(声明注册域守卫 checker.cr:1491 钳位)⇒
# 声明位豁免③(:526 `val_ti == TI_NEVER`)不触发 ⇒ 误发 TA02。
# 改后:调用推断 = never ⇒ 豁免③ 生效 ⇒ rc=0。
case_accept_check("let_never_call_ok",
- "fn boom() -> never { loop { } }\n"
- "fn main() -> int { x : int = boom(); return 0; }\n"),
+ "fn boom() -> never:\n loop:\nfn main() -> int:\n x : int = boom()\n return 0\n"),
# near-miss 负控(突变 Mu2 的稳定牙齿):普通 int 调用的注解位仍判,
# 守卫不得退化成「一律透传 never」。
case_accept_check("let_ordinary_call_unchanged",
- "fn f2() -> int { return 1; }\n"
- "fn main() -> int { x : int = f2(); return 0; }\n"),
+ "fn f2() -> int:\n return 1\nfn main() -> int:\n x : int = f2()\n return 0\n"),
# 强负控(Mu2 的**转红**牙齿):**普通调用**的返回型若真不符仍须拒——
# 守卫退化为「无条件 return TI_NEVER」时本例转绿(= 抑制面被误开)。
case_reject("call_result_mismatch_still_rejected",
- "fn f2() -> int { return 1; }\n"
- "fn main() -> int { x : char = f2(); return 0; }\n",
+ "fn f2() -> int:\n return 1\nfn main() -> int:\n x : char = f2()\n return 0\n",
["error[TA02]"], cmd="check", forbid=(), exact_diags=1),
# 宽面负控(C5):语句位调用本无 TA/TF 判定面,改动不得新开抑制/新开诊断。
case_accept_check("never_stmt_position_unchanged",
- "fn boom() -> never { loop { } }\n"
- "fn main() -> int { if 1 > 2 { boom(); } return 0; }\n"),
+ "fn boom() -> never:\n loop:\nfn main() -> int:\n if 1 > 2:\n boom()\n return 0\n"),
# 登记钉(裁③):赋值位无 never 豁免(EXPR_ASSIGN,checker.cr:3314-3336)——
# 改前(源 = unit)改后(源 = never)**都**报 TA01;既有缺口、非本改动引入,
# 入 TODO 登记(E-T4-5);同族豁免已在声明位/返回位/if 合并三处,赋值位是剩余缺口。
case_reject("assign_never_still_ta01",
- "fn boom() -> never { loop { } }\n"
- "fn main() -> int { busy : int, mut = 0; busy = boom(); return 0; }\n",
+ "fn boom() -> never:\n loop:\nfn main() -> int:\n busy : int, mut = 0\n busy = boom()\n return 0\n",
["error[TA01]"], cmd="check", forbid=(), exact_diags=1),
# ── 正控:合法注解 / 无注解 / auto / 泛型 / 可选注入 / 无初值 / 索引形态 ──
- case_run("let_exact_ok", "fn main() -> int { x : int = 5; return x; }\n", 5),
+ case_run("let_exact_ok", "fn main() -> int:\n x : int = 5\n return x\n", 5),
case_run("let_no_annot_ok",
- "fn main() -> int { x := 5; y : . = 6; z : auto = 7; return x + y + z; }\n", 18),
+ "fn main() -> int:\n x := 5\n y : . = 6\n z : auto = 7\n return x + y + z\n", 18),
case_run("let_generic_param_ok",
- "fn f[T](v: T) -> T { x : T = v; return x; }\n"
- "fn main() -> int { return f(3); }\n", 3),
+ "fn f[T](v: T) -> T:\n x : T = v\n return x\nfn main() -> int:\n return f(3)\n", 3),
case_run("let_generic_array_ok",
- "fn f[T](v: T) -> T { x : [T; 2] = [v, v]; return x[0]; }\n"
- "fn main() -> int { return f(4); }\n", 4),
+ "fn f[T](v: T) -> T:\n x : [T; 2] = [v, v]\n return x[0]\nfn main() -> int:\n return f(4)\n", 4),
case_run("let_optional_target_injection_ok",
- "fn main() -> int { x : int? = 5; y : int? = None; return 0; }\n", 0),
- case_accept_check("let_dyn_annotation_ok", "fn main() -> int { x : dyn = 5; return 0; }\n"),
- case_accept_check("let_no_init_ok", "fn main() -> int { x : int; return 0; }\n"),
+ "fn main() -> int:\n x : int? = 5\n y : int? = none\n return 0\n", 0),
+ case_accept_check("let_dyn_annotation_ok", "fn main() -> int:\n x : dyn = 5\n return 0\n"),
+ case_accept_check("let_no_init_ok", "fn main() -> int:\n x : int\n return 0\n"),
case_run("let_slice_ann_from_literal_ok",
- "fn f(s: [int]) -> int { x : [int] = [1,2,3]; return x[0]; }\n"
- "fn main() -> int { return f([1]); }\n", 1),
+ "fn f(s: [int]) -> int:\n x : [int] = [1,2,3]\n return x[0]\nfn main() -> int:\n return f([1])\n", 1),
case_run("let_fixed_ann_exact_literal_ok",
- "fn f(s: [int]) -> int { x : [int;3] = [1,2,3]; return s[0]; }\n"
- "fn main() -> int { return f([7]); }\n", 7),
+ "fn f(s: [int]) -> int:\n x : [int;3] = [1,2,3]\n return s[0]\nfn main() -> int:\n return f([7])\n", 7),
case_run("let_named_and_string_ok",
- 'struct P { a: int }\n'
- 'fn main() -> int { p := P { a: 1 }; q : P = p; s := "hi"; t : string = s; return q.a; }\n',
+ 'struct P:\n a: int\nfn main() -> int:\n p := P { a= 1 }\n q : P = p\n s := "hi"\n t : string = s\n return q.a\n',
1),
case_accept_check("let_generic_element_param_ok",
- "fn f[T](v: T) -> T { x : [T] = [v]; return x[0]; }\n"
- "fn main() -> int { return f(2); }\n", expect_rc=0),
+ "fn f[T](v: T) -> T:\n x : [T] = [v]\n return x[0]\nfn main() -> int:\n return f(2)\n", expect_rc=0),
# 泛型形参注解**不判**(豁免④)——与返回位点既有策略同款同证:`return 5` 在
# `-> T` 函数体内今天即 rc=0(返回位点的 TYP_GENERIC_PARAM 豁免)⇒ 声明位点同策略。
case_accept_check("let_generic_param_annotation_not_judged",
- "fn f[T](v: T) -> T { return 5; }\n" # 返回位点(既有策略)
- "fn g[T](v: T) -> T { x : T = 5; return x; }\n" # 声明位点(本检查同策略)
- "fn main() -> int { return 0; }\n", expect_rc=0),
+ "fn f[T](v: T) -> T:\n return 5\nfn g[T](v: T) -> T:\n x : T = 5\n return x\nfn main() -> int:\n return 0\n", expect_rc=0),
]
passed = sum(ok)
print(f"{passed}/{len(ok)} passed")
diff --git a/tests/selfhost/test_lexer_parity.py b/tests/selfhost/test_lexer_parity.py
index 25bff813..4cf3f5f5 100644
--- a/tests/selfhost/test_lexer_parity.py
+++ b/tests/selfhost/test_lexer_parity.py
@@ -9,7 +9,7 @@
BAD = ('1_000', '1_000.5', '0x1_0', '10f32', '1.5f64', '10u8')
def selfhost(src):
- r = subprocess.run(['nice', '-n', '19', COREC, 'run', 'fn main()->int{return %s;}' % src],
+ r = subprocess.run(['nice', '-n', '19', COREC, 'run', 'fn main()->int:\n return %s\n' % src],
cwd=BASE, capture_output=True, text=True)
return r.returncode, r.stdout + r.stderr
diff --git a/tests/selfhost/test_live_ranges.py b/tests/selfhost/test_live_ranges.py
index 44018105..5c973f5e 100644
--- a/tests/selfhost/test_live_ranges.py
+++ b/tests/selfhost/test_live_ranges.py
@@ -128,8 +128,7 @@ def check_versioned_entries() -> tuple:
会因临时值条目数变化而脆弱);每个 def'd 条目 ls == def 与同组版本链
不变量仍全表成立。
"""
- src = "fn identity(n:int)->int{return n;}\n" \
- "fn main()->int{x:=1;x=x+1;x=x+2;return x;}\n"
+ src = "fn identity(n:int)->int:\n return n\nfn main()->int:\n x:=1\n x=x+1\n x=x+2\n return x\n"
rc, out = dump_entries(src)
if rc != 0:
return False, f"cir --dump-entries rc={rc}\n{out[-500:]}"
@@ -198,15 +197,7 @@ def check_array_birth_versions() -> tuple:
dest≥0 全定值扩权后:a 的版本 = [ALLOC_ARRAY(诞生), STORE(重定值)] 两条,
区间按 [def_j, def_{j+1}-1] 切割——诞生版覆盖元素写/拷贝读(a[0]=5、
b := a),STORE 版覆盖重定值后读(a[0]+a[1]+a[i])。"""
- src = "fn main()->int{\n" \
- " a : [int; 3];\n" \
- " a[0] = 5; a[1] = 7;\n" \
- " b := a;\n" \
- " a = [1, 2, 3];\n" \
- " i := 0;\n" \
- " a[i] = 9;\n" \
- " return a[0] + a[1] + b[0] + a[i];\n" \
- "}\n"
+ src = "fn main()->int:\n a : [int; 3]\n a[0] = 5\n a[1] = 7\n b := a\n a = [1, 2, 3]\n i := 0\n a[i] = 9\n return a[0] + a[1] + b[0] + a[i]\n"
rc, out = dump_entries(src)
if rc != 0:
return False, f"cir --dump-entries rc={rc}\n{out[-500:]}"
@@ -252,8 +243,7 @@ def check_array_birth_versions() -> tuple:
def run_smoke() -> tuple:
"""Task 1 存量冒烟:fib(10)==55 at O1-default / O2。"""
- src = "fn fib(n:int)->int{if n<2{return n;}return fib(n-1)+fib(n-2);}\n" \
- "fn main()->int{return fib(10);}\n"
+ src = "fn fib(n:int)->int:\n if n<2:\n return n\n return fib(n-1)+fib(n-2)\nfn main()->int:\n return fib(10)\n"
passed = 0
total = 2
detail = []
@@ -286,7 +276,7 @@ def check_coexistence() -> tuple:
(c) 概念断言(Python 侧用 --dump-entries 区间数据):a/b 两变量条目
存在区间相交(共存),同一变量两版本区间不相交(不共存)。
"""
- src = "fn main()->int{a:=1;b:=2;return a+b;}\n"
+ src = "fn main()->int:\n a:=1\n b:=2\n return a+b\n"
rc, out = dump_coexist(src)
if rc != 0:
return False, f"cir --dump-coexist rc={rc}\n{out[-500:]}"
@@ -350,10 +340,8 @@ def check_regalloc_consistency() -> tuple:
(check_regalloc_violations / check_regalloc_read_gap_nonfunc0,注入现以
改写真实分配输出为手段);fib/6 变量绿程序按行为锚点保留。"""
for name, src in (
- ("fib", "fn fib(n:int)->int{if n<2{return n;}return fib(n-1)+fib(n-2);}\n"
- "fn main()->int{return fib(10);}\n"),
- ("multi-var", "fn main()->int{a:=1;b:=2;c:=3;d:=4;e:=5;f:=6;"
- "return a+b+c+d+e+f;}\n"),
+ ("fib", "fn fib(n:int)->int:\n if n<2:\n return n\n return fib(n-1)+fib(n-2)\nfn main()->int:\n return fib(10)\n"),
+ ("multi-var", "fn main()->int:\n a:=1\n b:=2\n c:=3\n d:=4\n e:=5\n f:=6\n return a+b+c+d+e+f\n"),
):
rc, out = check_regalloc(src, [])
if rc != 0:
@@ -382,7 +370,7 @@ def check_regalloc_real_use() -> tuple:
6 共存 int var 的作用是把共存压力拉到 5 callee-saved 上限,使分配必然发生
且必有栈驻留余数(不分配 = 保留栈 home;分配器无驱逐事件,不设驱逐路径)。
"""
- src = "fn main()->int{a:=1;b:=2;c:=3;d:=4;e:=5;f:=6;return a+b+c+d+e+f;}\n"
+ src = "fn main()->int:\n a:=1\n b:=2\n c:=3\n d:=4\n e:=5\n f:=6\n return a+b+c+d+e+f\n"
rc, out = check_regalloc(src, [])
if rc != 0:
return False, f"check-regalloc rc={rc}:\n{out[-500:]}"
@@ -401,16 +389,7 @@ def check_regalloc_real_use() -> tuple:
LOOP_CARRY_SRC = (
- "fn main()->int{\n"
- " i:=0;s:=0;\n"
- " loop {\n"
- " if i>=4 { break; }\n"
- " i = i + 1;\n"
- " d := 5;\n"
- " s = s + d;\n"
- " }\n"
- " return s;\n"
- "}\n"
+ "fn main()->int:\n i:=0\n s:=0\n loop:\n if i>=4:\n break\n i = i + 1\n d := 5\n s = s + d\n return s\n"
)
@@ -450,30 +429,8 @@ def check_regalloc_cond_def_carry() -> tuple:
断言 O2(真实分配)== 期望;O1(无分配路径基线)同断言。
"""
for name, src, expect in (
- ("v_noz", "fn main()->int{\n"
- " i:=0;s:=0;\n"
- " x : int, mut = 3;\n"
- " loop {\n"
- " if i>=2 { break; }\n"
- " if i==0 { x = 7; }\n"
- " s = s + x;\n"
- " i = i + 1;\n"
- " }\n"
- " return s;\n"
- "}\n", 14),
- ("conddef-z", "fn main()->int{\n"
- " i:=0;s:=0;\n"
- " x : int, mut = 3;\n"
- " loop {\n"
- " if i>=2 { break; }\n"
- " if i==0 { x = 7; }\n"
- " s = s + x;\n"
- " i = i + 1;\n"
- " z := 5;\n"
- " s = s + z;\n"
- " }\n"
- " return s;\n"
- "}\n", 24),
+ ("v_noz", "fn main()->int:\n i:=0\n s:=0\n x : int, mut = 3\n loop:\n if i>=2:\n break\n if i==0:\n x = 7\n s = s + x\n i = i + 1\n return s\n", 14),
+ ("conddef-z", "fn main()->int:\n i:=0\n s:=0\n x : int, mut = 3\n loop:\n if i>=2:\n break\n if i==0:\n x = 7\n s = s + x\n i = i + 1\n z := 5\n s = s + z\n return s\n", 24),
):
for mode, flags in (("O1-baseline", []), ("O2-regalloc", ["--opt-level", "2"])):
rc = build_and_run(src, flags)
@@ -503,27 +460,8 @@ def check_regalloc_else_def_carry() -> tuple:
断言 O2(真实分配)== 期望;O1(无分配路径基线)同断言。
"""
for name, src, expect in (
- ("else1", "fn main()->int{\n"
- " i:=0;s:=0;\n"
- " x : int, mut = 3;\n"
- " loop {\n"
- " if i>=4 { break; }\n"
- " if i<2 { s = s + 1; } else { x = 7; }\n"
- " s = s + x;\n"
- " i = i + 1;\n"
- " }\n"
- " return s;\n"
- "}\n", 22),
- ("else-while", "fn main()->int{\n"
- " i:=0;s:=0;\n"
- " x : int, mut = 3;\n"
- " while i < 4 {\n"
- " if i<2 { s = s + 1; } else { x = 7; }\n"
- " s = s + x;\n"
- " i = i + 1;\n"
- " }\n"
- " return s;\n"
- "}\n", 22),
+ ("else1", "fn main()->int:\n i:=0\n s:=0\n x : int, mut = 3\n loop:\n if i>=4:\n break\n if i<2:\n s = s + 1\n else:\n x = 7\n s = s + x\n i = i + 1\n return s\n", 22),
+ ("else-while", "fn main()->int:\n i:=0\n s:=0\n x : int, mut = 3\n while i < 4:\n if i<2:\n s = s + 1\n else:\n x = 7\n s = s + x\n i = i + 1\n return s\n", 22),
):
for mode, flags in (("O1-baseline", []), ("O2-regalloc", ["--opt-level", "2"])):
rc = build_and_run(src, flags)
@@ -545,29 +483,8 @@ def check_regalloc_else_controls() -> tuple:
断言 O2(真实分配)== 期望。
"""
for name, src, expect in (
- ("then2", "fn main()->int{\n"
- " i:=0;s:=0;\n"
- " x : int, mut = 3;\n"
- " loop {\n"
- " if i>=4 { break; }\n"
- " if i<2 { x = 7; } else { s = s + 1; }\n"
- " s = s + x;\n"
- " i = i + 1;\n"
- " }\n"
- " return s;\n"
- "}\n", 30),
- ("cont", "fn main()->int{\n"
- " i:=0;s:=0;\n"
- " x : int, mut = 3;\n"
- " loop {\n"
- " if i>=5 { break; }\n"
- " if i==0 { i = i + 1; continue; }\n"
- " if i<2 { x = 7; } else { s = s + 1; }\n"
- " s = s + x;\n"
- " i = i + 1;\n"
- " }\n"
- " return s;\n"
- "}\n", 31),
+ ("then2", "fn main()->int:\n i:=0\n s:=0\n x : int, mut = 3\n loop:\n if i>=4:\n break\n if i<2:\n x = 7\n else:\n s = s + 1\n s = s + x\n i = i + 1\n return s\n", 30),
+ ("cont", "fn main()->int:\n i:=0\n s:=0\n x : int, mut = 3\n loop:\n if i>=5:\n break\n if i==0:\n i = i + 1\n continue\n if i<2:\n x = 7\n else:\n s = s + 1\n s = s + x\n i = i + 1\n return s\n", 31),
):
rc = build_and_run(src, ["--opt-level", "2"])
ok = rc == expect
@@ -585,7 +502,7 @@ def check_regalloc_violations() -> tuple:
- --inject-read-gap : 寄存器驻留 var 末版区间截断到定值点 → 规则 2(读点无版本)
O2 正确程序(无注入)rc=0 已在 check_regalloc_consistency 断言——同一二进制
注入后 rc=1 即证明 verify 真消费了分配/条目数据而非恒真。"""
- src = "fn main()->int{a:=1;b:=2;c:=3;d:=4;e:=5;f:=6;return a+b+c+d+e+f;}\n"
+ src = "fn main()->int:\n a:=1\n b:=2\n c:=3\n d:=4\n e:=5\n f:=6\n return a+b+c+d+e+f\n"
for flag, rule in (("--inject-home-conflict", "1"),
("--inject-reg-conflict", "1"),
("--inject-read-gap", "2")):
@@ -614,16 +531,7 @@ def check_regalloc_read_gap_nonfunc0() -> tuple:
inject_read_gap 的迭代序改为 1..n-1 再 0(调试钩子,真实路径永不注入),
注入恒落非 func 0 函数;注入目标函数不再固定为 sum6(按函数序首个可注入
者定,此处为 ist>0 的 stdlib/用户函数)——断言 = func > 0 + rule 2。"""
- src = "fn main()->int{return n0(1,2);}\n" \
- "fn n0(a:int,b:int)->int{return a+b;}\n" \
- "fn n1(a:int,b:int)->int{return a+b;}\n" \
- "fn n2(a:int,b:int)->int{return a+b;}\n" \
- "fn n3(a:int,b:int)->int{return a+b;}\n" \
- "fn n4(a:int,b:int)->int{return a+b;}\n" \
- "fn n5(a:int,b:int)->int{return a+b;}\n" \
- "fn n6(a:int,b:int)->int{return a+b;}\n" \
- "fn n7(a:int,b:int)->int{return a+b;}\n" \
- "fn sum6()->int{a:=1;b:=2;c:=3;d:=4;e:=5;f:=6;return a+b+c+d+e+f;}\n"
+ src = "fn main()->int:\n return n0(1,2)\nfn n0(a:int,b:int)->int:\n return a+b\nfn n1(a:int,b:int)->int:\n return a+b\nfn n2(a:int,b:int)->int:\n return a+b\nfn n3(a:int,b:int)->int:\n return a+b\nfn n4(a:int,b:int)->int:\n return a+b\nfn n5(a:int,b:int)->int:\n return a+b\nfn n6(a:int,b:int)->int:\n return a+b\nfn n7(a:int,b:int)->int:\n return a+b\nfn sum6()->int:\n a:=1\n b:=2\n c:=3\n d:=4\n e:=5\n f:=6\n return a+b+c+d+e+f\n"
rc, out = check_regalloc(src, ["--inject-read-gap"])
if rc != 1:
return False, f"check-regalloc +--inject-read-gap (non-func0): rc={rc}, expected 1:\n{out[-500:]}"
@@ -650,7 +558,7 @@ def check_coexist_oob_guard() -> tuple:
--inject-coexist-oob 探针通道:输出 "coexist-oob-guard: ",
r != 0(探针自检失败)→ 退出码 1。与 dump-coexist 摘要同源同前置
(compute_live_ranges),真实构建路径永不注入。"""
- src = "fn main()->int{a:=1;b:=2;return a+b;}\n"
+ src = "fn main()->int:\n a:=1\n b:=2\n return a+b\n"
rc, out = corearch_chan(src, "--inject-coexist-oob")
if rc != 0:
return False, f"corearch --inject-coexist-oob rc={rc}\n{out[-500:]}"
diff --git a/tests/selfhost/test_lsp.py b/tests/selfhost/test_lsp.py
index a869cbe3..aa04e033 100644
--- a/tests/selfhost/test_lsp.py
+++ b/tests/selfhost/test_lsp.py
@@ -102,7 +102,7 @@ def test_hover_and_definition():
# 5: x := add(1, 2);
# 6: return x;
# 7: }
- src = "fn add(a: int, b: int) -> int {\n return a + b;\n}\n\nfn main() -> int {\n x := add(1, 2);\n return x;\n}\n"
+ src = "fn add(a: int, b: int) -> int:\n return a + b\n\nfn main() -> int:\n x := add(1, 2)\n return x\n"
# 注意:didOpen 不能用 send()——它自带 read_frame 会吞掉 publishDiagnostics
# 帧(brief 原文 send()+read_frame() 双读会永久阻塞);直接写帧再读一帧。
body = json.dumps({"jsonrpc": "2.0", "method": "textDocument/didOpen",
@@ -140,10 +140,7 @@ def test_completion_and_document_symbol():
# 9: poi := add(1, 2);
# 10: return @sizeOf(int);
# 11: }
- src = ("fn add(a: int, b: int) -> int {\n return a + b;\n}\n\n"
- "struct Point { x: int, y: int }\n\n"
- "enum Color { Red, Green, Blue }\n\n"
- "fn main() -> int {\n poi := add(1, 2);\n return @sizeOf(int);\n}\n")
+ src = ("fn add(a: int, b: int) -> int:\n return a + b\n\nstruct Point:\n x: int, y: int\n\nenum Color:\n Red, Green, Blue\n\nfn main() -> int:\n poi := add(1, 2)\n return @sizeOf(int)\n")
body = json.dumps({"jsonrpc": "2.0", "method": "textDocument/didOpen",
"params": {"textDocument": {"uri": uri, "version": 1,
"text": src}}}).encode()
@@ -202,7 +199,7 @@ def test_semantic_tokens():
proc = subprocess.Popen([BIN], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
send(proc, {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}})
uri = "file:///tmp/semantic_test.cr"
- src = "fn main() -> int { return 42; }"
+ src = "fn main() -> int:\n return 42\n"
body = json.dumps({"jsonrpc": "2.0", "method": "textDocument/didOpen",
"params": {"textDocument": {"uri": uri, "version": 1,
"text": src}}}).encode()
@@ -250,7 +247,7 @@ def test_semantic_tokens_multiline():
proc = subprocess.Popen([BIN], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
send(proc, {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}})
uri = "file:///tmp/semantic_ml.cr"
- src = "fn main() -> int {\n return 42;\n}\n"
+ src = "fn main() -> int:\n return 42\n"
body = json.dumps({"jsonrpc": "2.0", "method": "textDocument/didOpen",
"params": {"textDocument": {"uri": uri, "version": 1,
"text": src}}}).encode()
@@ -369,7 +366,7 @@ def test_large_frame_body():
# Keep the request valid while forcing several 4KB stdin refills.
uri = "file:///tmp/large_frame.cr"
- text = "fn main() -> int { return 0; }\n" + ("// padding\n" * 600)
+ text = "fn main() -> int:\n return 0\n" + ("// padding\n" * 600)
request = {"jsonrpc": "2.0", "method": "textDocument/didOpen",
"params": {"textDocument": {"uri": uri, "version": 1,
"text": text}}}
@@ -450,26 +447,14 @@ def main() -> int:
print(f"lsp suite: ALL PASS ({len(TESTS)} tests)")
return 0
-SAMPLE = 'fn main() -> int { return 42; }'
-BAD = 'fn main() -> int { return ; }'
+SAMPLE = 'fn main() -> int:\n return 42\n'
+BAD = 'fn main() -> int:\n return\n'
# 桥接缓存跨请求失效回归(R2 P2a Task 3 评审 Critical)——两版只差 `a` 的元素型:
# V1 `[int;3]` → 新进程 rc=0(ok);V2 `[bool;3]` → 新进程 1 条 error[TA01] Assignment
# type mismatch。两次 didOpen 之间类型行号被复用(同 URI 重开),故缓存不失效即漏报。
-BRIDGE_V1 = ("fn f() -> int {\n"
- " a : [int;3] = [1,2,3];\n"
- " b : [int;3], mut = [4,5,6];\n"
- " b = a;\n"
- " return 0;\n"
- "}\n"
- "fn main() -> int { return f(); }\n")
-BRIDGE_V2 = ("fn f() -> int {\n"
- " a : [bool;3] = [true,false,true];\n"
- " b : [int;3], mut = [4,5,6];\n"
- " b = a;\n"
- " return 0;\n"
- "}\n"
- "fn main() -> int { return f(); }\n")
+BRIDGE_V1 = ("fn f() -> int:\n a : [int;3] = [1,2,3]\n b : [int;3], mut = [4,5,6]\n b = a\n return 0\nfn main() -> int:\n return f()\n")
+BRIDGE_V2 = ("fn f() -> int:\n a : [bool;3] = [true,false,true]\n b : [int;3], mut = [4,5,6]\n b = a\n return 0\nfn main() -> int:\n return f()\n")
if __name__ == "__main__":
sys.exit(main())
diff --git a/tests/selfhost/test_match_exhaust.py b/tests/selfhost/test_match_exhaust.py
index 1c45682f..73c303f9 100644
--- a/tests/selfhost/test_match_exhaust.py
+++ b/tests/selfhost/test_match_exhaust.py
@@ -145,78 +145,65 @@ def case_soft(name, source, needle):
# ── 源形 ──────────────────────────────────────────────────────────────
-COLOR = "enum Color { Red, Green, Blue }\n"
-CHOICE = "enum Choice { First(int), Second(int), Third(int) }\n"
+COLOR = "enum Color:\n Red, Green, Blue\n"
+CHOICE = "enum Choice:\n First(int), Second(int), Third(int)\n"
def missing_arm_src(scrutinee="Blue"):
- return COLOR + f"""fn main() -> int {{
- c := {scrutinee}();
- v := match c {{
+ return COLOR + f"""fn main() -> int:
+ c := {scrutinee}()
+ v := match c:
Red => 1,
Green => 2,
- }};
- return v + 100;
-}}
+ return v + 100
"""
def main():
ok = [
# 正:全覆盖 ELF 路径(Green ⇒ 2)
- case_run("exhaustive_elf", COLOR + "fn main() -> int { c := Green(); "
- "return match c { Red => 1, Green => 2, Blue => 3, }; }\n", 2),
+ case_run("exhaustive_elf", COLOR + "fn main() -> int:\n c := Green()\n return match c:\n Red => 1, Green => 2, Blue => 3,\n", 2),
# 正:同源解释器路径(Blue ⇒ 3;与 ELF 路径共享判定面)
case_interp("interp_exhaustive",
- COLOR + "fn main() -> int { c := Blue(); return match c { Red => 1, Green => 2, Blue => 3, }; }\n", 3),
+ COLOR + "fn main() -> int:\n c := Blue()\n return match c:\n Red => 1, Green => 2, Blue => 3,\n", 3),
# 正:通配臂吸收(⊤)
- case_run("wildcard_absorbs", COLOR + "fn main() -> int { c := Blue(); "
- "return match c { Red => 1, _ => 7, }; }\n", 7),
+ case_run("wildcard_absorbs", COLOR + "fn main() -> int:\n c := Blue()\n return match c:\n Red => 1, _ => 7,\n", 7),
# 正:绑定臂吸收
- case_run("binding_absorbs", COLOR + "fn main() -> int { c := Red(); "
- "return match c { x => 9, }; }\n", 9),
+ case_run("binding_absorbs", COLOR + "fn main() -> int:\n c := Red()\n return match c:\n x => 9,\n", 9),
# 正:限定名模式(Enum.Variant)
- case_run("qualified_pattern", COLOR + "fn main() -> int { c := Blue(); "
- "return match c { Color.Red => 1, Color.Green => 2, Color.Blue => 3, }; }\n", 3),
+ case_run("qualified_pattern", COLOR + "fn main() -> int:\n c := Blue()\n return match c:\n Color.Red => 1, Color.Green => 2, Color.Blue => 3,\n", 3),
# 正:payload 变体(三臂全列)
- case_run("payload_exhaustive", CHOICE + "fn main() -> int { c := Third(33); "
- "return match c { First(v) => v, Second(v) => v, Third(v) => v, }; }\n", 33),
+ case_run("payload_exhaustive", CHOICE + "fn main() -> int:\n c := Third(33)\n return match c:\n First(v) => v, Second(v) => v, Third(v) => v,\n", 33),
# 正:泛型枚举实例(Opt[int])
case_run("generic_enum_exhaustive",
- "enum Opt[T] { N, S(T) }\nfn main() -> int { c := S(5); "
- "return match c { N => 1, S(x) => x, }; }\n", 5),
+ "enum Opt[T]:\n N, S(T)\nfn main() -> int:\n c := S(5)\n return match c:\n N => 1, S(x) => x,\n", 5),
# 正:单变体枚举(域最小边界)
case_run("single_variant_exhaustive",
- "enum Only { One }\nfn main() -> int { c := One(); "
- "return match c { One => 4, }; }\n", 4),
+ "enum Only:\n One\nfn main() -> int:\n c := One()\n return match c:\n One => 4,\n", 4),
# 正:枚举形参位(scrutinee 来自形参 ti 而非构造器)
- case_run("enum_param_exhaustive", COLOR + "fn f(c: Color) -> int { "
- "return match c { Red => 1, Green => 2, Blue => 3, }; }\n"
- "fn main() -> int { return f(Green()); }\n", 2),
+ case_run("enum_param_exhaustive", COLOR + "fn f(c: Color) -> int:\n return match c:\n Red => 1, Green => 2, Blue => 3,\nfn main() -> int:\n return f(Green())\n", 2),
# 负:缺臂 ⇒ rc=1 + TM03(含具体缺失变体名)+ 无产物
case_reject("missing_arm_rejected", missing_arm_src(),
["error[TM03]", "Non-exhaustive match", "missing variant 'Blue'"]),
# 负:无臂(空 match 体)⇒ 同上(未覆盖面 = 全域,首个变体即反例)
case_reject("no_arms_rejected",
- COLOR + "fn main() -> int { c := Red(); return match c { }; }\n",
+ COLOR + "fn main() -> int:\n c := Red()\n return match c:\n",
["error[TM03]", "missing variant 'Red'"]),
# 负:check 子命令同拒(判定在共享前端,非 ELF 路径专属)
case_reject("check_path_rejected", missing_arm_src(), ["error[TM03]"], cmd="check"),
# 负:run(解释器)路径同拒(同一 run_frontend ⇒ 同一判定面)
case_run_reject("run_path_rejected",
- COLOR + "fn main() -> int { c := Blue(); return match c { Red => 1, Green => 2, }; }\n",
+ COLOR + "fn main() -> int:\n c := Blue()\n return match c:\n Red => 1, Green => 2,\n",
["error[TM03]", "missing variant 'Blue'"]),
# 登记:非枚举域不判穷尽(int 字面量匹配 ⇒ 零诊断,rc=0)
case_run("non_enum_domain_not_judged",
- "fn main() -> int { n := 3; return match n { 1 => 10, 2 => 20, }; }\n", 0),
+ "fn main() -> int:\n n := 3\n return match n:\n 1 => 10, 2 => 20,\n", 0),
# 登记:不可映射模式(枚举匹配混字面量臂)不判穷尽(-1 = 不判,不得当「不穷尽」)
case_run("unmappable_pattern_not_judged",
- "enum Color2 { Red2, Green2, Blue2 }\nfn main() -> int { c := Blue2(); "
- "return match c { Red2 => 1, 5 => 2, }; }\n", 0),
+ "enum Color2:\n Red2, Green2, Blue2\nfn main() -> int:\n c := Blue2()\n return match c:\n Red2 => 1, 5 => 2,\n", 0),
# 软面:重复臂 ⇒ TM04 非硬门(rc=0 + 产物照出)
case_soft("redundant_arm_soft",
- COLOR + "fn main() -> int { c := Red(); "
- "return match c { Red => 1, Red => 2, Green => 3, Blue => 4, }; }\n",
+ COLOR + "fn main() -> int:\n c := Red()\n return match c:\n Red => 1, Red => 2, Green => 3, Blue => 4,\n",
"error[TM04]"),
]
passed = sum(1 for x in ok if x is True)
diff --git a/tests/selfhost/test_mw_task1.py b/tests/selfhost/test_mw_task1.py
index 26d77e43..03547a73 100644
--- a/tests/selfhost/test_mw_task1.py
+++ b/tests/selfhost/test_mw_task1.py
@@ -185,17 +185,17 @@ def find_main_frame(elf_path, opt):
]
SRCS = {
- "s1_noarith": "fn main() -> int {\n return 7;\n}\n",
- "s2_intadd": "fn main() -> int {\n a := 2000000000;\n b := 2000000000;\n c := a + b;\n return c;\n}\n",
- "s3_sub": "fn main() -> int {\n a := 10;\n b := 3;\n c := a - b;\n return c;\n}\n",
- "s4_addcopy": "fn main() -> int {\n a := 1;\n b := 2;\n c := a + b;\n d := c;\n e := d + c;\n f := e;\n return f;\n}\n",
- "s5_loop": "fn main() -> int {\n sum := 0;\n i := 0;\n while i < 10 {\n sum = sum + i;\n i = i + 1;\n }\n return sum;\n}\n",
+ "s1_noarith": "fn main() -> int:\n return 7\n",
+ "s2_intadd": "fn main() -> int:\n a := 2000000000\n b := 2000000000\n c := a + b\n return c\n",
+ "s3_sub": "fn main() -> int:\n a := 10\n b := 3\n c := a - b\n return c\n",
+ "s4_addcopy": "fn main() -> int:\n a := 1\n b := 2\n c := a + b\n d := c\n e := d + c\n f := e\n return f\n",
+ "s5_loop": "fn main() -> int:\n sum := 0\n i := 0\n while i < 10:\n sum = sum + i\n i = i + 1\n return sum\n",
# 评审场景:snap 的拷贝点线性先于 tag 源(x = x + k)的定值——运行时
# x 的 tag 态沿回边携带,迭代 ≥2 的 snap = x as int 拷贝的是 2-limb x。
- "s6_loopcopy": "fn main() -> int {\n x : ., mut = 0;\n i : ., mut = 0;\n snap := 0;\n while i < 3 {\n snap = x as int;\n x = x + 1;\n i = i + 1;\n }\n return snap;\n}\n",
+ "s6_loopcopy": "fn main() -> int:\n x : ., mut = 0\n i : ., mut = 0\n snap := 0\n while i < 3:\n snap = x as int\n x = x + 1\n i = i + 1\n return snap\n",
# 8 个 add 定值点(旧规则 tag 数 = 8)后跟一个拷贝变量行 s(新规则 +2):
# vc*8 = 160 时 O1/O2 帧 168(旧)vs 184(新)——二进制级可观测差。
- "s7_framediff": "fn main() -> int {\n r : ., mut = 0;\n r = r + 1;\n r = r + 1;\n r = r + 1;\n r = r + 1;\n r = r + 1;\n r = r + 1;\n r = r + 1;\n r = r + 1;\n s := r;\n return s;\n}\n",
+ "s7_framediff": "fn main() -> int:\n r : ., mut = 0\n r = r + 1\n r = r + 1\n r = r + 1\n r = r + 1\n r = r + 1\n r = r + 1\n r = r + 1\n r = r + 1\n s := r\n return s\n",
}
EXPECTED_EXIT = {"s1_noarith": 7, "s2_intadd": 0, "s3_sub": 7,
diff --git a/tests/selfhost/test_mw_task2.py b/tests/selfhost/test_mw_task2.py
index 5ffef734..ba33c3cf 100644
--- a/tests/selfhost/test_mw_task2.py
+++ b/tests/selfhost/test_mw_task2.py
@@ -241,24 +241,17 @@ def x86_walk(buf, base=0):
]
SRCS = {
- "t1_add": "fn main() -> int {\n a := 2000000000;\n b := 2000000000;\n"
- " c := a + b;\n return c;\n}\n",
- "t2_add_overflow": "fn main() -> int {\n x : ., mut = 4611686018427387904;\n"
- " x = x + 4611686018427387904;\n"
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "t1_add": "fn main() -> int:\n a := 2000000000\n b := 2000000000\n c := a + b\n return c\n",
+ "t2_add_overflow": "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n r := syscall3(1, 1, x, 16)\n return r\n",
"t3_bigfunc": None, # Python 生成(250 次 x = x + 1)
- "t4_sub_overflow": "fn main() -> int {\n x : ., mut = 4611686018427387904;\n"
- " x = x - -4611686018427387904;\n" # 2^62 − (−2^62) = 2^63
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
- "z1_noarith": "fn main() -> int {\n return 7;\n}\n",
- "z2_copy": "fn main() -> int {\n a := 123456;\n b := a;\n"
- " c := b;\n return 100;\n}\n",
- "z3_branch": "fn main() -> int {\n x : ., mut = 0;\n"
- " while x > 0 {\n x = 0;\n }\n return 9;\n}\n",
+ "t4_sub_overflow": "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x - -4611686018427387904\n r := syscall3(1, 1, x, 16)\n return r\n",
+ "z1_noarith": "fn main() -> int:\n return 7\n",
+ "z2_copy": "fn main() -> int:\n a := 123456\n b := a\n c := b\n return 100\n",
+ "z3_branch": "fn main() -> int:\n x : ., mut = 0\n while x > 0:\n x = 0\n return 9\n",
}
-SRCS["t3_bigfunc"] = ("fn main() -> int {\n x : ., mut = 0;\n"
- + "\n".join(" x = x + 1;" for _ in range(250))
- + "\n return x;\n}\n")
+SRCS["t3_bigfunc"] = ("fn main() -> int:\n x : ., mut = 0\n"
+ + "\n".join(" x = x + 1" for _ in range(250))
+ + "\n return x\n")
def _selftest_failclosed_paths():
diff --git a/tests/selfhost/test_mw_task3.py b/tests/selfhost/test_mw_task3.py
index 5588e8fe..3aa74a2d 100644
--- a/tests/selfhost/test_mw_task3.py
+++ b/tests/selfhost/test_mw_task3.py
@@ -47,51 +47,22 @@ def limb_bytes(S):
S64 = 1 << 63
CASES = [
("m1_add_pos",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n" # 2^62
- " x = x + 4611686018427387904;\n" # S = 2^63:正溢出 CF=0 → hi=0
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n r := syscall3(1, 1, x, 16)\n return r\n",
S64, "add 正溢出:CF=0 → 高 limb = 0(lo=2^63 环绕 0x8000..0)"),
("m2_add_neg",
- "fn main() -> int {\n"
- " x : ., mut = -9223372036854775807;\n" # -(2^63-1)
- " x = x + -2;\n" # S = -2^63-1:负溢出 CF=1 → hi=-1
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = -9223372036854775807\n x = x + -2\n r := syscall3(1, 1, x, 16)\n return r\n",
-S64 - 1, "add 负溢出:CF=1 → 高 limb = -1(lo=2^63-1、hi=0xFF..F)"),
("m3_sub_pos",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n" # 2^62
- " x = x - -4611686018427387904;\n" # S = 2^63:正溢出借位 CF=1 →
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n", # sub 规则 hi=0(add 规则会给 -1 → 红)
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x - -4611686018427387904\n r := syscall3(1, 1, x, 16)\n return r\n", # sub 规则 hi=0(add 规则会给 -1 → 红)
S64, "sub 正溢出:CF=1 → 高 limb = 0(判别:add 规则在此给 -1)"),
("m4_sub_neg",
- "fn main() -> int {\n"
- " x : ., mut = -4611686018427387905;\n" # -(2^62+1)
- " x = x - 4611686018427387904;\n" # S = -2^63-1:负溢出(混合符号
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n", # 无借位 CF=0)→ sub 规则 hi=-1
+ "fn main() -> int:\n x : ., mut = -4611686018427387905\n x = x - 4611686018427387904\n r := syscall3(1, 1, x, 16)\n return r\n", # 无借位 CF=0)→ sub 规则 hi=-1
-S64 - 1, "sub 负溢出:CF=0 → 高 limb = -1(判别:add 规则在此给 0)"),
("m5_two_add_sites",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " x = x + 4611686018427387904;\n" # 站点 1:2^63
- " r1 := syscall3(1, 1, x, 16);\n"
- " y : ., mut = -9223372036854775807;\n"
- " y = y + -2;\n" # 站点 2:-2^63-1
- " r2 := syscall3(1, 1, y, 16);\n"
- " return r1 + r2;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n r1 := syscall3(1, 1, x, 16)\n y : ., mut = -9223372036854775807\n y = y + -2\n r2 := syscall3(1, 1, y, 16)\n return r1 + r2\n",
None, "同函数双 add 站点:两独立块都执行、都正确(rc=32 + 32B 流)"),
("m6_mix_sites",
- "fn main() -> int {\n"
- " a : ., mut = 4611686018427387904;\n"
- " a = a - -4611686018427387904;\n" # sub 正溢出 → 2^63
- " r1 := syscall3(1, 1, a, 16);\n"
- " b : ., mut = -4611686018427387905;\n"
- " b = b - 4611686018427387904;\n" # sub 负溢出 → -2^63-1
- " r2 := syscall3(1, 1, b, 16);\n"
- " c : ., mut = -9223372036854775807;\n"
- " c = c + -2;\n" # add 负溢出 → -2^63-1
- " r3 := syscall3(1, 1, c, 16);\n"
- " return r1 + r2 + r3;\n}\n",
+ "fn main() -> int:\n a : ., mut = 4611686018427387904\n a = a - -4611686018427387904\n r1 := syscall3(1, 1, a, 16)\n b : ., mut = -4611686018427387905\n b = b - 4611686018427387904\n r2 := syscall3(1, 1, b, 16)\n c : ., mut = -9223372036854775807\n c = c + -2\n r3 := syscall3(1, 1, c, 16)\n return r1 + r2 + r3\n",
None, "add+sub 混站:sub 块(含 not 修正)与 add 块同函数共存"),
]
diff --git a/tests/selfhost/test_mw_task4.py b/tests/selfhost/test_mw_task4.py
index 3083c479..315d2c82 100644
--- a/tests/selfhost/test_mw_task4.py
+++ b/tests/selfhost/test_mw_task4.py
@@ -56,116 +56,48 @@ def limb_bytes(S):
CASES = [
# ── B① return 解指针(无解引用 = exit = 指针低字节 ≠ 期望)──
("r1_ret_big_pos",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387910;\n" # 2^62 + 6
- " x = x + 4611686018427387904;\n" # = 2^63+6(正溢出 2-limb)
- " return x;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387910\n x = x + 4611686018427387904\n return x\n",
None, 6, "return 2L:exit 低 8 位 = 数学值 2^63+6 的低字节 6(无 deref = 指针字节)"),
("r2_ret_big_neg",
- "fn main() -> int {\n"
- " x : ., mut = -9223372036854775807;\n" # -(2^63-1)
- " x = x + -2;\n" # = -2^63-1(负溢出 2-limb)
- " return x;\n}\n",
+ "fn main() -> int:\n x : ., mut = -9223372036854775807\n x = x + -2\n return x\n",
None, 255, "return 2L 负值:低字节 0xFF = 255"),
# ── B② 比较(判别:指针比较给反 / 低 limb 有符号给反)──
("c1_cmp_neg_lt_zero",
- "fn main() -> int {\n"
- " x : ., mut = -9223372036854775807;\n"
- " x = x + -2;\n" # -2^63-1(2-limb,hi=-1)
- " if x < 0 { return 1; }\n"
- " return 2;\n}\n",
+ "fn main() -> int:\n x : ., mut = -9223372036854775807\n x = x + -2\n if x < 0:\n return 1\n return 2\n",
None, 1, "2L 负数 < 0 = 真(指针为正 → 指针比较给 2——判别)"),
("c2_cmp_2l_vs_fast_neg",
- "fn main() -> int {\n"
- " x : ., mut = -9223372036854775807;\n"
- " x = x + -2;\n" # -2^63-1(2-limb)
- " if x > -5 { return 1; }\n"
- " return 2;\n}\n",
+ "fn main() -> int:\n x : ., mut = -9223372036854775807\n x = x + -2\n if x > -5:\n return 1\n return 2\n",
None, 2, "2L(-2^63-1) > -5 = 假(指针为正 → 给 1——判别)"),
("c3_cmp_lo_unsigned",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " x = x + 1;\n" # 2^63+1(2L:hi=0 lo=2^63+1)
- " if 5 < x { return 1; }\n" # 快操作数在 s1(快+2L 分派)
- " return 2;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 1\n if 5 < x:\n return 1\n return 2\n",
None, 1, "5 < 2^63+1 = 真——低 limb 须无符号比较(有符号 lo:5 > -2^63+1 → 给 2)"),
("c4_cmp_eq_diff_obj",
- "fn main() -> int {\n"
- " a : ., mut = 4611686018427387904;\n"
- " a = a + 4611686018427387904;\n" # 2^63 对象 1
- " b : ., mut = 4611686018427387904;\n"
- " b = b + 4611686018427387904;\n" # 2^63 对象 2(不同指针)
- " if a == b { return 1; }\n"
- " return 2;\n}\n",
+ "fn main() -> int:\n a : ., mut = 4611686018427387904\n a = a + 4611686018427387904\n b : ., mut = 4611686018427387904\n b = b + 4611686018427387904\n if a == b:\n return 1\n return 2\n",
None, 1, "2L == 2L(同值异对象):指针比较给 2——判别 128 位 EQ"),
("c5_cmp_ge_2l",
- "fn main() -> int {\n"
- " a : ., mut = 4611686018427387904;\n"
- " a = a + 4611686018427387904;\n" # 2^63
- " b : ., mut = 4611686018427387904;\n"
- " b = b + 4611686018427387904;\n" # 2^63
- " if a >= b && a <= b { return 1; }\n" # GE + LE(2L vs 2L 同值)
- " return 2;\n}\n",
+ "fn main() -> int:\n a : ., mut = 4611686018427387904\n a = a + 4611686018427387904\n b : ., mut = 4611686018427387904\n b = b + 4611686018427387904\n if a >= b && a <= b:\n return 1\n return 2\n",
None, 1, "2L GE/LE 同值链(布尔合并 = 比较结果再参与运算)"),
# ── B③ 链式运算(2L 再参与 add/sub——128 位混合算术)──
("a1_chain_mixed_add",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " x = x + 4611686018427387904;\n" # 2^63(2-limb)
- " x = x + 5;\n" # 2L + 快 → 2^63+5
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n x = x + 5\n r := syscall3(1, 1, x, 16)\n return r\n",
limb_bytes((1 << 63) + 5), 16, "2L + 快正值:2^63+5(钩子验全 128)"),
("a2_chain_fast_first",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " x = x + 4611686018427387904;\n" # 2^63(2-limb)
- " y : ., mut = 6;\n"
- " y = y + x;\n" # 快在 s1 + 2L 在 s2(分派 B 路)
- " r := syscall3(1, 1, y, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n y : ., mut = 6\n y = y + x\n r := syscall3(1, 1, y, 16)\n return r\n",
limb_bytes((1 << 63) + 6), 16, "快 + 2L(操作数序反转):2^63+6"),
("a3_chain_sub_2l_fast",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387911;\n" # 2^62 + 7
- " x = x + 4611686018427387904;\n" # 2^63+7(2-limb)
- " x = x - 1;\n" # 2L − 快 → 2^63+6(仍 2L)
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387911\n x = x + 4611686018427387904\n x = x - 1\n r := syscall3(1, 1, x, 16)\n return r\n",
limb_bytes((1 << 63) + 6), 16, "2L − 快:2^63+6(保持 2L)"),
("a4_chain_sub_downnorm",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " x = x + 4611686018427387904;\n" # 2^63(2-limb)
- " x = x - 5;\n" # = 2^63-5:可装 64 位 → 降级快值
- " return x;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n x = x - 5\n return x\n",
None, 251, "2L − 快降级回 64 位:2^63−5 低字节 0xFB = 251"),
("a5_chain_2l_2l_neg_correc",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " x = x + 4611686018427387904;\n" # 2^63(2-limb)
- " y : ., mut = -9223372036854775807;\n"
- " y = y + -2;\n" # -2^63-1(2-limb,hi=-1)
- " z : ., mut = x + y;\n" # 2L + 2L = -1 → 降级快值
- " w : ., mut = z + 7;\n"
- " return w;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n y : ., mut = -9223372036854775807\n y = y + -2\n z : ., mut = x + y\n w : ., mut = z + 7\n return w\n",
None, 6, "2L+2L 降级(2^63 + (-2^63-1) = -1 → 快值)+ 快链继续 → 6"),
("a6_chain_2l_2l_borrow",
- "fn main() -> int {\n"
- " m : ., mut = -9223372036854775807;\n"
- " m = m + -4;\n" # -2^63-3(2-limb hi=-1 lo=2^63-3)
- " a : ., mut = 4611686018427387904;\n"
- " a = a + 4611686018427387904;\n" # 2^63
- " b : ., mut = a + 5;\n" # 2^63+5(2-limb hi=0 lo=2^63+5)
- " d : ., mut = m - b;\n" # (-2^63-3)-(2^63+5) = -2^64-8:
- " r := syscall3(1, 1, d, 16);\n return r;\n}\n", # hi=-2(出 {0,-1} 域)lo=2^64-8
+ "fn main() -> int:\n m : ., mut = -9223372036854775807\n m = m + -4\n a : ., mut = 4611686018427387904\n a = a + 4611686018427387904\n b : ., mut = a + 5\n d : ., mut = m - b\n r := syscall3(1, 1, d, 16)\n return r\n", # hi=-2(出 {0,-1} 域)lo=2^64-8
limb_bytes(-(1 << 64) - 8), 16, "2L−2L 双 limb 借位链:−2^64−8 → hi=−2(128 码域内精确)"),
("a7_chain_loop_hi1",
- "fn main() -> int {\n"
- " x : ., mut = 0;\n"
- " i : ., mut = 0;\n"
- " while i < 6 {\n"
- " x = x + 4611686018427387904;\n" # 每轮 +2^62:2^62→2^63(溢出 2L)
- " i = i + 1;\n" # →3·2^62→2^64(hi=1)→…
- " }\n" # 6 轮 = 6·2^62 = 2^64+2^63
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = 0\n i : ., mut = 0\n while i < 6:\n x = x + 4611686018427387904\n i = i + 1\n r := syscall3(1, 1, x, 16)\n return r\n",
limb_bytes((1 << 64) + (1 << 63)), 16,
"循环携带链:同站点 快→溢出→混合→hi=1(6·2^62 = 2^64+2^63)"),
# ── 判别回归(fits-64 假拟合——hi==lo 恰在 {0,−1} 之外,其余用例不可见)──
@@ -175,69 +107,28 @@ def limb_bytes(S):
# 降级截断(−2 / 1 快值落槽 + tag 0)→ syscall3 把快值当指针 → EFAULT
# (红证据:stdout 空 + exit ≠ 16)。
("d1_chain_neg_fitdisc",
- "fn main() -> int {\n"
- " m : ., mut = -9223372036854775807;\n"
- " m = m + -2;\n" # -2^63-1(2L:hi=-1 lo=2^63-1)
- " b : ., mut = 4611686018427387904;\n"
- " b = b + 4611686018427387904;\n" # 2^63(2L:hi=0 lo=2^63)
- " b = b + 1;\n" # 2^63+1(2L:hi=0 lo=2^63+1)
- " d : ., mut = m - b;\n" # (-2^63-1)-(2^63+1) = -2^64-2
- " r := syscall3(1, 1, d, 16);\n return r;\n}\n",
+ "fn main() -> int:\n m : ., mut = -9223372036854775807\n m = m + -2\n b : ., mut = 4611686018427387904\n b = b + 4611686018427387904\n b = b + 1\n d : ., mut = m - b\n r := syscall3(1, 1, d, 16)\n return r\n",
# (lo=2^64-2 hi=2^64-2——同值非同 fit:lo 负 → signmask = -1 ≠ hi)
limb_bytes(-(1 << 64) - 2), 16, "假拟合判别:−2^64−2 → hi==lo==−2 须保持 2L(错编 cmp hi,lo 截断 −2)"),
("d2_chain_pos_fitdisc",
- "fn main() -> int {\n"
- " a : ., mut = 4611686018427387904;\n"
- " a = a + 4611686018427387904;\n" # 2^63(2L:hi=0 lo=2^63)
- " b : ., mut = 4611686018427387904;\n"
- " b = b + 4611686018427387904;\n" # 2^63(2L:hi=0 lo=2^63)
- " b = b + 1;\n" # 2^63+1(2L:hi=0 lo=2^63+1)
- " c : ., mut = a + b;\n" # 2^63+(2^63+1) = 2^64+1
- " r := syscall3(1, 1, c, 16);\n return r;\n}\n",
+ "fn main() -> int:\n a : ., mut = 4611686018427387904\n a = a + 4611686018427387904\n b : ., mut = 4611686018427387904\n b = b + 4611686018427387904\n b = b + 1\n c : ., mut = a + b\n r := syscall3(1, 1, c, 16)\n return r\n",
# (lo=1 hi=1——lo 正 → signmask = 0 ≠ hi)
limb_bytes((1 << 64) + 1), 16, "假拟合判别:2^64+1 → hi==lo==1 须保持 2L(错编 cmp hi,lo 截断 1)"),
# ── A 卫生:溢出后重定义/拷贝/参数,快值不得被误读为 2L ──
("h1_hygiene_store_redef",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " x = x + 4611686018427387904;\n" # 2^63(2-limb,tag=1)
- " x = 7;\n" # 常量定值(IR_STORE 清 tag)
- " return x;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n x = 7\n return x\n",
None, 7, "卫生:2L 后常量重定义 → return 快值 7(stale tag 会解引用 7 → 崩)"),
("h2_hygiene_site_reexec",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " i : ., mut = 0;\n"
- " while i < 3 {\n"
- " x = x + 4611686018427387904;\n" # 同站点回边:快(2^62)→溢出(2^63)
- " x = x - 4611686018427387904;\n" # 混合减法:→2^62(降级快)
- " i = i + 1;\n"
- " }\n" # 每轮归位 → 终值 2^62
- " x = x - 4611686018427387904;\n" # → 0
- " return x;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n i : ., mut = 0\n while i < 3:\n x = x + 4611686018427387904\n x = x - 4611686018427387904\n i = i + 1\n x = x - 4611686018427387904\n return x\n",
None, 0, "卫生:同站点快/慢交替(stale tag=1 会把快值 2^62 解引用 → 崩)"),
("h3_hygiene_copy_prop",
- "fn main() -> int {\n"
- " x : ., mut = 4611686018427387904;\n"
- " x = x + 4611686018427387904;\n" # 2^63(2-limb,tag=1)
- " y := x;\n" # IR_STORE 拷贝 → tag 传播
- " r := syscall3(1, 1, y, 16);\n"
- " z := x as int;\n" # IR_LOAD 拷贝(as)→ tag 传播
- " r2 := syscall3(1, 1, z, 16);\n"
- " return r + r2;\n}\n",
+ "fn main() -> int:\n x : ., mut = 4611686018427387904\n x = x + 4611686018427387904\n y := x\n r := syscall3(1, 1, y, 16)\n z := x as int\n r2 := syscall3(1, 1, z, 16)\n return r + r2\n",
limb_bytes(1 << 63) * 2, 32, "拷贝链 tag 传播:y/z 都读到 2^63(无传播 = 指针低字节)"),
("h4_hygiene_param",
# 参数行 prologue 清 tag 的回归护栏:call 1 令 p 以 2L 态(tag=1)离开
# (函数内最后一次 p 定值 = 溢出的 p=p+2^62),call 2 若不清参数 tag,
# p=p+2^62 站点会把 64 位参数值当 2L 指针解引用(值 ~4.6e18 → 崩)。
- "fn fb(p: int) -> int {\n"
- " p = p + 4611686018427387904;\n" # 2^62+6 → 2^63+6(2L tag=1)
- " q : ., mut = p - p;\n" # 2L − 2L 同值 = 0 → 降级快值
- " return q;\n}\n"
- "fn main() -> int {\n"
- " r1 := fb(4611686018427387910);\n" # 参数 2^62+6(64 位可载)
- " r2 := fb(4611686018427387910);\n" # 第 2 次调用(栈帧复用)
- " return r1 + r2;\n}\n",
+ "fn fb(p: int) -> int:\n p = p + 4611686018427387904\n q : ., mut = p - p\n return q\nfn main() -> int:\n r1 := fb(4611686018427387910)\n r2 := fb(4611686018427387910)\n return r1 + r2\n",
None, 0, "卫生:参数 prologue 清 tag(2 次调用都须把 64 位参数当快值)"),
]
diff --git a/tests/selfhost/test_mw_task5.py b/tests/selfhost/test_mw_task5.py
index af80023a..0eb7a913 100644
--- a/tests/selfhost/test_mw_task5.py
+++ b/tests/selfhost/test_mw_task5.py
@@ -86,36 +86,16 @@ def dump_regassign(ccr_path, opt_level) -> dict:
CASES = [
# h4 同形:参数行 2L 态 + 跨调用帧复用(O2 下 fb 的 p/q 驻 callee-saved)
("t5_param_2l_reg",
- "fn fb(p: int) -> int {\n"
- " p = p + 4611686018427387904;\n" # 2^62+6 → 2^63+6(2L,tag=1)
- " q : ., mut = p - p;\n" # 2L − 2L 同值 = 0 → 降级快值
- " return q;\n}\n"
- "fn main() -> int {\n"
- " r1 := fb(4611686018427387910);\n"
- " r2 := fb(4611686018427387910);\n"
- " return r1 + r2;\n}\n",
+ "fn fb(p: int) -> int:\n p = p + 4611686018427387904\n q : ., mut = p - p\n return q\nfn main() -> int:\n r1 := fb(4611686018427387910)\n r2 := fb(4611686018427387910)\n return r1 + r2\n",
["fb"], None, 0, "O2 元断言目标:fb 的 p/q tagged 且驻寄存器;2 次调用绿"),
# a7 同形:循环携带 2L 态跨迭代驻 reg(每轮 jo 慢路径 + alloc 新对象)
("t5_loop_carry_2l_reg",
- "fn main() -> int {\n"
- " x : ., mut = 0;\n"
- " i : ., mut = 0;\n"
- " while i < 6 {\n"
- " x = x + 4611686018427387904;\n" # 每轮 +2^62:→2^63(2L)…
- " i = i + 1;\n"
- " }\n" # 6 轮 = 2^64+2^63(hi=1)
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = 0\n i : ., mut = 0\n while i < 6:\n x = x + 4611686018427387904\n i = i + 1\n r := syscall3(1, 1, x, 16)\n return r\n",
["main"], limb_bytes((1 << 64) + (1 << 63)), 16,
"O2 元断言目标:循环携带 x 驻 reg 且运行时达 2L 态(hi=1)——16B 通道验证"),
# c5 同形:双 2L 对象比较(a/b 各自溢出生 2L 堆对象,比较读 tag 解指针)
("t5_two2l_cmp_reg",
- "fn main() -> int {\n"
- " a : ., mut = 4611686018427387904;\n"
- " a = a + 4611686018427387904;\n" # 2^63(2-limb 对象 1)
- " b : ., mut = 4611686018427387904;\n"
- " b = b + 4611686018427387904;\n" # 2^63(2-limb 对象 2)
- " if a >= b && a <= b { return 1; }\n"
- " return 2;\n}\n",
+ "fn main() -> int:\n a : ., mut = 4611686018427387904\n a = a + 4611686018427387904\n b : ., mut = 4611686018427387904\n b = b + 4611686018427387904\n if a >= b && a <= b:\n return 1\n return 2\n",
["main"], None, 1, "O2 元断言目标:a/b 2L 态驻 reg;128 位比较绿"),
]
diff --git a/tests/selfhost/test_mw_task6.py b/tests/selfhost/test_mw_task6.py
index 5dfcccd3..6023d869 100644
--- a/tests/selfhost/test_mw_task6.py
+++ b/tests/selfhost/test_mw_task6.py
@@ -45,99 +45,39 @@
CASES = [
# ── 上边界:i64max +1 = 恰好一步越界(jo 正溢出 hi=0)──
("e1_max_plus1",
- "fn main() -> int {\n"
- " x : ., mut = 9223372036854775807;\n" # i64max(最大快值)
- " x = x + 1;\n" # = 2^63 → 2L(hi=0 lo=0x8000..0)
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = 9223372036854775807\n x = x + 1\n r := syscall3(1, 1, x, 16)\n return r\n",
limb_bytes(S64), 16, "上边界 +1:i64max → 2^63 恰好一步越界"),
# ── 上边界往返:三步连续越界 + 降级回快值 + 再越界(fits 判据 lo 符号位)──
("e2_max_chain_roundtrip",
- "fn main() -> int {\n"
- " x : ., mut = 9223372036854775807;\n"
- " x = x + 1;\n" # 2^63(2L)
- " x = x + 1;\n" # 2^63+1(2L+快链)
- " x = x + 1;\n" # 2^63+2(2L)
- " r1 := syscall3(1, 1, x, 16);\n" # 流 1:2^63+2
- " x = x - 3;\n" # = 2^63-1 = i64max → 降级快值
- " x = x + 1;\n" # → 2^63(快→再越界 2L)
- " r2 := syscall3(1, 1, x, 16);\n" # 流 2:2^63
- " return r1 + r2;\n}\n",
+ "fn main() -> int:\n x : ., mut = 9223372036854775807\n x = x + 1\n x = x + 1\n x = x + 1\n r1 := syscall3(1, 1, x, 16)\n x = x - 3\n x = x + 1\n r2 := syscall3(1, 1, x, 16)\n return r1 + r2\n",
limb_bytes(S64 + 2) + limb_bytes(S64), 32,
"上边界往返:3 步越界链(2L+快)→ −3 降级回 i64max(fits:hi==signmask(2^63−1)==0)→ +1 再越界"),
# ── 下边界邻域:快值恰在 −2^63(不溢出)+ add/sub 双越界 + 回升降级 ──
("e3_min_edge_addsub",
- "fn main() -> int {\n"
- " x : ., mut = -9223372036854775807;\n" # i64min+1(可写最小字面量)
- " x = x + -1;\n" # = -2^63 **快值**(恰下边界——不 OF)
- " x = x + -1;\n" # = -2^63-1 → 2L(hi=-1 lo=2^63-1)
- " r1 := syscall3(1, 1, x, 16);\n" # 流 1:-2^63-1
- " x = x - 1;\n" # = -2^63-2 → 2L(sub 负溢出)
- " r2 := syscall3(1, 1, x, 16);\n" # 流 2:-2^63-2(lo=2^63-2)
- " x = x + 3;\n" # = -2^63+1 → 降级快值(hi=-1==signmask(lo))
- " return x;\n}\n", # exit = (-2^63+1) 低字节 0x01
+ "fn main() -> int:\n x : ., mut = -9223372036854775807\n x = x + -1\n x = x + -1\n r1 := syscall3(1, 1, x, 16)\n x = x - 1\n r2 := syscall3(1, 1, x, 16)\n x = x + 3\n return x\n", # exit = (-2^63+1) 低字节 0x01
limb_bytes(-S64 - 1) + limb_bytes(-S64 - 2), 1,
"下边界:−(2^63−1)+−1 = −2^63 快值不溢出(负 OF 只发生在 < −2^63)→ add/sub 连续越界 → +3 降级回快值 return 1"),
# ── sub 形式的上边界(i64max − −n)+ 降级后再越界 ──
("e4_sub_neg_edge",
- "fn main() -> int {\n"
- " x : ., mut = 9223372036854775807;\n" # i64max
- " x = x - -1;\n" # = 2^63 → 2L(sub 正溢出 CF=1 → hi=0)
- " r1 := syscall3(1, 1, x, 16);\n" # 流 1:2^63
- " x = x - 1;\n" # = 2^63-1 → 降级快值 i64max
- " x = x - -2;\n" # = 2^63+1 → 快+快再越界(jo)
- " r2 := syscall3(1, 1, x, 16);\n" # 流 2:2^63+1
- " return r1 + r2;\n}\n",
+ "fn main() -> int:\n x : ., mut = 9223372036854775807\n x = x - -1\n r1 := syscall3(1, 1, x, 16)\n x = x - 1\n x = x - -2\n r2 := syscall3(1, 1, x, 16)\n return r1 + r2\n",
limb_bytes(S64) + limb_bytes(S64 + 1), 32,
"sub 边界:i64max − −1 = 2^63(CF 判别)→ −1 降级 → − −2 快→溢再越界"),
# ── 上下边界同函数双站越界 + 2L vs 2L 高 limb 符号判别 ──
("e5_two_edge_cross_cmp",
- "fn main() -> int {\n"
- " a : ., mut = 9223372036854775807;\n"
- " a = a + 1;\n" # 2^63(2L hi=0——上边界越界)
- " b : ., mut = -9223372036854775807;\n"
- " b = b + -1;\n" # -2^63 快值
- " b = b + -1;\n" # -2^63-1(2L hi=-1——下边界越界)
- " r : ., mut = syscall3(1, 1, a, 16);\n" # 流 1:2^63
- " r = r + syscall3(1, 1, b, 16);\n" # 流 2:-2^63-1
- " if a > b { r = r + 1; }\n" # 2L(hi=0) > 2L(hi=-1):高 limb 符号判别
- " return r;\n}\n", # 16+16+1 = 33
+ "fn main() -> int:\n a : ., mut = 9223372036854775807\n a = a + 1\n b : ., mut = -9223372036854775807\n b = b + -1\n b = b + -1\n r : ., mut = syscall3(1, 1, a, 16)\n r = r + syscall3(1, 1, b, 16)\n if a > b:\n r = r + 1\n return r\n", # 16+16+1 = 33
limb_bytes(S64) + limb_bytes(-S64 - 1), 33,
"上下边界混合:双站(上/下各一步越界)+ 2L vs 2L 高 limb 判别(同低 limb 无符号形给反)"),
# ── i64max 边界 fast↔2L 比较真值表(LT/GT 双分派 + EQ/GE 假性)──
("e6_max_cmp_dispatch",
- "fn main() -> int {\n"
- " x : ., mut = 9223372036854775807;\n"
- " x = x + 1;\n" # 2^63(2L)
- " ok : ., mut = 0;\n"
- " if 9223372036854775807 < x { ok = ok + 1; }\n" # fast(s1) < 2L(s2):B 路——紧贴边界的最大快值
- " if x > 9223372036854775807 { ok = ok + 1; }\n" # 2L(s1) > fast(s2):A 路镜像
- " if x == 9223372036854775807 { ok = ok - 10; }\n" # 128 EQ 必须假(值不等)——恒真实现给 248
- " if 9223372036854775807 >= x { ok = ok - 10; }\n" # GE 必须假——(i64max, 2^63) 最紧假例
- " return ok;\n}\n",
+ "fn main() -> int:\n x : ., mut = 9223372036854775807\n x = x + 1\n ok : ., mut = 0\n if 9223372036854775807 < x:\n ok = ok + 1\n if x > 9223372036854775807:\n ok = ok + 1\n if x == 9223372036854775807:\n ok = ok - 10\n if 9223372036854775807 >= x:\n ok = ok - 10\n return ok\n",
None, 2, "i64max 边界比较真值表:max<2^63 两分派方向真、EQ/GE 假(−10 哨兵)"),
# ── i64min 边界:快值 −2^63 vs 2L −2^63−1——同 hi 低 limb 无符号判别 ──
("e7_min_cmp_lo_unsigned",
- "fn main() -> int {\n"
- " m : ., mut = -9223372036854775807;\n"
- " m = m + -1;\n" # -2^63 快值(恰下边界,不 2L)
- " n : ., mut = m;\n"
- " n = n + -1;\n" # -2^63-1 → 2L(hi=-1 lo=2^63-1)
- " o : ., mut = 0;\n"
- " if n < m { o = o + 1; }\n" # hi 同为 -1(m 快值符号扩展)→ 低 limb 无符号:
- " if m > n { o = o + 1; }\n" # n lo=2^63-1 < m lo=2^63 才真——有符号 lo 给反
- " if n > m { o = o + 100; }\n" # 反哨兵(错序 + 100)
- " return o;\n}\n",
+ "fn main() -> int:\n m : ., mut = -9223372036854775807\n m = m + -1\n n : ., mut = m\n n = n + -1\n o : ., mut = 0\n if n < m:\n o = o + 1\n if m > n:\n o = o + 1\n if n > m:\n o = o + 100\n return o\n",
None, 2, "i64min 边界:快值 −2^63 vs 2L −2^63−1——同 hi(−1) 低 limb 无符号判别(有符号 lo 给 101)"),
# ── 循环携带越过上边界(同站点回边逐轮 2L 化)+ 独立快计数器 ──
("e8_loop_max_chain",
- "fn main() -> int {\n"
- " x : ., mut = 9223372036854775807;\n"
- " i : ., mut = 0;\n"
- " while i < 3 {\n"
- " x = x + 1;\n" # 每轮 +1:2^63 → 2^63+1 → 2^63+2
- " i = i + 1;\n" # 快计数器(永不越界)
- " }\n"
- " r := syscall3(1, 1, x, 16);\n return r;\n}\n",
+ "fn main() -> int:\n x : ., mut = 9223372036854775807\n i : ., mut = 0\n while i < 3:\n x = x + 1\n i = i + 1\n r := syscall3(1, 1, x, 16)\n return r\n",
limb_bytes(S64 + 2), 16,
"循环携带越过上边界:i64max 起每轮 +1(快→2L 同站点回边链)+ 独立快计数"),
]
diff --git a/tests/selfhost/test_named_face.py b/tests/selfhost/test_named_face.py
index d5a8387e..4cce9ffd 100644
--- a/tests/selfhost/test_named_face.py
+++ b/tests/selfhost/test_named_face.py
@@ -113,100 +113,60 @@ def case_reject(name, source, needle):
TA01 = "Assignment type mismatch"
-NA_NB = "struct NA { x: int }\nstruct NB { x: int }\n"
-BOX = "struct Box[T] { v: T }\n"
+NA_NB = "struct NA:\n x: int\nstruct NB:\n x: int\n"
+BOX = "struct Box[T]:\n v: T\n"
def main():
ok = [
# ── ① 受:命名面同链(身份链逐元素同 ⇒ 1)──
- case_accept("named.same_name_assign", NA_NB.replace("struct NB { x: int }\n", "") +
- "fn main() -> int {\n"
- " a : ., mut = NA { x: 1 };\n"
- " b : ., mut = NA { x: 2 };\n"
- " a = b;\n"
- " return a.x - 2;\n"
- "}\n"),
+ case_accept("named.same_name_assign", NA_NB.replace("struct NB:\n x: int\n", "") +
+ "fn main() -> int:\n a : ., mut = NA { x= 1 }\n b : ., mut = NA { x= 2 }\n a = b\n return a.x - 2\n"),
# 泛型应用两次实例化(**两行**同实参)——RED 形态之一,修复前 = 引擎 -1 + 回落。
# 形参位声明(应用行随每处出现各分配一行)。注:`Box[int] { … }` 字面量形态在本
# 语言 parser 下不可解析(P01,冻结基线同——预存面,见 T0 探针 d3 变体),故走形参位。
case_accept("apply.two_instantiations_same_args", BOX +
- "fn g(a: Box[int], b: Box[int]) -> int {\n"
- " a = b;\n"
- " return a.v - b.v;\n"
- "}\n"
- "fn main() -> int { return 0; }\n"),
+ "fn g(a: Box[int], b: Box[int]) -> int:\n a = b\n return a.v - b.v\nfn main() -> int:\n return 0\n"),
# 嵌套泛型应用(外层实参 = 内层应用,两处**不同行**同实参)⇒ 规范形 ⇒ 同节点
case_accept("apply.nested_same_args", BOX +
- "fn g(a: Box[Box[int]], b: Box[Box[int]]) -> int { a = b; return 0; }\n"
- "fn main() -> int { return 0; }\n"),
+ "fn g(a: Box[Box[int]], b: Box[Box[int]]) -> int:\n a = b\n return 0\nfn main() -> int:\n return 0\n"),
# 泛型应用实参含命名型(同链)
case_accept("apply.named_arg_same", NA_NB + BOX +
- "fn g(a: Box[NA], b: Box[NA]) -> int { a = b; return 0; }\n"
- "fn main() -> int { return 0; }\n"),
+ "fn g(a: Box[NA], b: Box[NA]) -> int:\n a = b\n return 0\nfn main() -> int:\n return 0\n"),
# 容器/元组/指针含命名(同元素)——b 槽标注不入身份 + 同链
# (R2 P5 Task 6:指针位原为 `p : *NA = 0;`——`0` 是 int 字面量,声明位点此前无检查
# 故静默通过;TA02 落地后与**赋值位点**既有语义对齐(`*T ← int/null` 早已 TA01 拒绝,
# 见 p5-task6-report §收紧台账)= 改为无初值声明。指针身份面语义不变。)
- case_accept("named.in_container_same", NA_NB.replace("struct NB { x: int }\n", "") +
- "fn main() -> int {\n"
- " a : [NA; 2] = [NA { x: 1 }, NA { x: 2 }];\n"
- " b : [NA; 2] = [NA { x: 3 }, NA { x: 4 }];\n"
- " c : NA? = NA { x: 5 };\n"
- " d : NA? = NA { x: 6 };\n"
- " p : *NA, mut;\n"
- " q : *NA, mut;\n"
- " a = b; c = d; p = q;\n"
- " return 0;\n"
- "}\n"),
- case_accept("named.in_tuple_same", NA_NB.replace("struct NB { x: int }\n", "") +
- "fn main() -> int {\n"
- " a : ., mut = (NA { x: 1 }, 2);\n"
- " b : ., mut = (NA { x: 3 }, 4);\n"
- " a = b;\n"
- " return 0;\n"
- "}\n"),
+ case_accept("named.in_container_same", NA_NB.replace("struct NB:\n x: int\n", "") +
+ "fn main() -> int:\n a : [NA; 2] = [NA { x= 1 }, NA { x= 2 }]\n b : [NA; 2] = [NA { x= 3 }, NA { x= 4 }]\n c : NA? = NA { x= 5 }\n d : NA? = NA { x= 6 }\n p : *NA, mut\n q : *NA, mut\n a = b\n c = d\n p = q\n return 0\n"),
+ case_accept("named.in_tuple_same", NA_NB.replace("struct NB:\n x: int\n", "") +
+ "fn main() -> int:\n a : ., mut = (NA { x= 1 }, 2)\n b : ., mut = (NA { x= 3 }, 4)\n a = b\n return 0\n"),
# 递归命名(*Node 元素位 = 命名行,同链)
- case_accept("named.recursive_ptr_same", "struct Node { val: int, next: *Node }\n"
- "fn f(p: *Node, q: *Node) -> int { p = q; return 0; }\n"
- "fn main() -> int { return 0; }\n"),
+ case_accept("named.recursive_ptr_same", "struct Node:\n val: int, next: *Node\nfn f(p: *Node, q: *Node) -> int:\n p = q\n return 0\nfn main() -> int:\n return 0\n"),
# 泛型形参位 T vs T(同链:同一形参行)
- case_accept("named.generic_param_same", "fn pick[T](a: T, b: T) -> int { return 0; }\n"
- "fn main() -> int { return pick(1, 2); }\n"),
+ case_accept("named.generic_param_same", "fn pick[T](a: T, b: T) -> int:\n return 0\nfn main() -> int:\n return pick(1, 2)\n"),
# 别名一层:透明(alias 解析到 RHS 行,不产生命名行身份)
- case_accept("named.alias_transparent", "type X = int;\n"
- "fn main() -> int { a : X = 1; b : int = 2; a = b; return a - 2; }\n"),
+ case_accept("named.alias_transparent", "type X = int\nfn main() -> int:\n a : X = 1\n b : int = 2\n a = b\n return a - 2\n"),
# 命名型经函数边界(形参/返回位同链)
- case_accept("named.fn_boundary", NA_NB.replace("struct NB { x: int }\n", "") +
- "fn take(v: NA) -> int { return v.x; }\n"
- "fn main() -> int { a : ., mut = NA { x: 7 }; b : ., mut = NA { x: 7 }; a = b; return take(a) - 7; }\n"),
+ case_accept("named.fn_boundary", NA_NB.replace("struct NB:\n x: int\n", "") +
+ "fn take(v: NA) -> int:\n return v.x\nfn main() -> int:\n a : ., mut = NA { x= 7 }\n b : ., mut = NA { x= 7 }\n a = b\n return take(a) - 7\n"),
# ── ② 拒:链异 ⇒ 0(= legacy 拒;清零前的回落面)──
case_reject("named.diff_name_rejected", NA_NB +
- "fn main() -> int { a : ., mut = NA { x: 1 }; b : ., mut = NB { x: 2 }; a = b; return a.x; }\n", TA01),
+ "fn main() -> int:\n a : ., mut = NA { x= 1 }\n b : ., mut = NB { x= 2 }\n a = b\n return a.x\n", TA01),
case_reject("apply.diff_args_rejected", BOX +
- "fn g(a: Box[int], b: Box[str]) -> int { a = b; return a.v; }\n"
- "fn main() -> int { return 0; }\n", TA01),
- case_reject("named.vs_base_rejected", "struct NA { x: int }\n"
- "fn main() -> int { a : NA = NA { x: 1 }; b : int = 2; a = b; return a.x; }\n", TA01),
+ "fn g(a: Box[int], b: Box[str]) -> int:\n a = b\n return a.v\nfn main() -> int:\n return 0\n", TA01),
+ case_reject("named.vs_base_rejected", "struct NA:\n x: int\nfn main() -> int:\n a : NA = NA { x= 1 }\n b : int = 2\n a = b\n return a.x\n", TA01),
case_reject("named.vs_apply_rejected", NA_NB + BOX +
- "fn g(a: Box[NA], b: Box[int]) -> int { a = b; return 0; }\n"
- "fn main() -> int { return 0; }\n", TA01),
+ "fn g(a: Box[NA], b: Box[int]) -> int:\n a = b\n return 0\nfn main() -> int:\n return 0\n", TA01),
case_reject("named.optional_diff_rejected", NA_NB +
- "fn main() -> int { a : NA? = NA { x: 1 }; b : NB? = NB { x: 2 }; a = b; return 0; }\n", TA01),
+ "fn main() -> int:\n a : NA? = NA { x= 1 }\n b : NB? = NB { x= 2 }\n a = b\n return 0\n", TA01),
case_reject("named.generic_param_vs_int_rejected",
- "fn h[T](a: T, b: int) -> int { a = b; return 0; }\n"
- "fn main() -> int { return h(1, 2); }\n", TA01),
+ "fn h[T](a: T, b: int) -> int:\n a = b\n return 0\nfn main() -> int:\n return h(1, 2)\n", TA01),
# ── ③ 残留登记(停条件②面:不变槽元素非同形——行为已正确,本任务不动其清零)──
case_reject("residual.invariant_slot_arr_rejected", NA_NB +
- "fn main() -> int {\n"
- " a : [NA; 2] = [NA { x: 1 }, NA { x: 2 }];\n"
- " b : [NB; 2] = [NB { x: 3 }, NB { x: 4 }];\n"
- " a = b;\n"
- " return 0;\n"
- "}\n", TA01),
+ "fn main() -> int:\n a : [NA; 2] = [NA { x= 1 }, NA { x= 2 }]\n b : [NB; 2] = [NB { x= 3 }, NB { x= 4 }]\n a = b\n return 0\n", TA01),
case_reject("residual.invariant_slot_ptr_rejected", NA_NB +
- "fn g(a: *NA, b: *NB) -> int { a = b; return 0; }\n"
- "fn main() -> int { return 0; }\n", TA01),
+ "fn g(a: *NA, b: *NB) -> int:\n a = b\n return 0\nfn main() -> int:\n return 0\n", TA01),
]
passed = sum(ok)
print(f"{passed}/{len(ok)} passed")
diff --git a/tests/selfhost/test_native_float.py b/tests/selfhost/test_native_float.py
index 48d968dc..d8e490de 100644
--- a/tests/selfhost/test_native_float.py
+++ b/tests/selfhost/test_native_float.py
@@ -17,12 +17,12 @@
(
"i2f_big",
"""
-fn main() -> int {
- y := 1099511627776; // 2^40
- z := 1.5 + y;
- if z > 1000000000000.0 { return 1; }
- return 0;
-}
+fn main() -> int:
+ y := 1099511627776 // 2^40
+ z := 1.5 + y
+ if z > 1000000000000.0:
+ return 1
+ return 0
""",
1,
),
@@ -30,30 +30,48 @@
(
"float_normal_cmp",
"""
-fn main() -> int {
- if 1.5 < 2.5 { } else { return 1; }
- if 2.5 > 1.5 { } else { return 2; }
- if 1.5 <= 1.5 { } else { return 3; }
- if 2.5 >= 2.5 { } else { return 4; }
- if 2.5 == 2.5 { } else { return 5; }
- if 1.5 != 2.5 { } else { return 6; }
- return 0;
-}
+fn main() -> int:
+ if 1.5 < 2.5:
+ else:
+ return 1
+ if 2.5 > 1.5:
+ else:
+ return 2
+ if 1.5 <= 1.5:
+ else:
+ return 3
+ if 2.5 >= 2.5:
+ else:
+ return 4
+ if 2.5 == 2.5:
+ else:
+ return 5
+ if 1.5 != 2.5:
+ else:
+ return 6
+ return 0
""",
0,
),
(
"float_arith",
"""
-fn main() -> int {
- x := 1.5;
- y := 2.5;
- if x + y == 4.0 { } else { return 1; }
- if x * y == 3.75 { } else { return 2; }
- if y - x == 1.0 { } else { return 3; }
- if y / x == 5.0 / 3.0 { } else { return 4; }
- return 0;
-}
+fn main() -> int:
+ x := 1.5
+ y := 2.5
+ if x + y == 4.0:
+ else:
+ return 1
+ if x * y == 3.75:
+ else:
+ return 2
+ if y - x == 1.0:
+ else:
+ return 3
+ if y / x == 5.0 / 3.0:
+ else:
+ return 4
+ return 0
""",
0,
),
diff --git a/tests/selfhost/test_native_memory.py b/tests/selfhost/test_native_memory.py
index d2f341db..5f806957 100644
--- a/tests/selfhost/test_native_memory.py
+++ b/tests/selfhost/test_native_memory.py
@@ -15,11 +15,11 @@
(
"negative_global_initializer",
"""
-g_negative : int, mut = -1;
-fn main() -> int {
- if g_negative < 0 { return 77; }
- return 1;
-}
+g_negative : int, mut = -1
+fn main() -> int:
+ if g_negative < 0:
+ return 77
+ return 1
""",
77,
0,
@@ -27,12 +27,12 @@
(
"struct_fields",
"""
-struct Pair { x: int, y: int }
-fn main() -> int {
- p : ., mut = Pair { x = 10, y = 20 };
- p.x = 7;
- return p.x + p.y;
-}
+struct Pair:
+ x: int, y: int
+fn main() -> int:
+ p : ., mut = Pair { x = 10, y = 20 }
+ p.x = 7
+ return p.x + p.y
""",
27,
0,
@@ -40,11 +40,10 @@
(
"array_constant_index",
"""
-fn main() -> int {
- arr : ., mut = [10, 20, 30];
- arr[1] = 9;
- return arr[0] + arr[1] + arr[2];
-}
+fn main() -> int:
+ arr : ., mut = [10, 20, 30]
+ arr[1] = 9
+ return arr[0] + arr[1] + arr[2]
""",
49,
0,
@@ -52,12 +51,11 @@
(
"array_variable_index",
"""
-fn main() -> int {
- arr : ., mut = [10, 20, 30];
- i := 1;
- arr[i] = 9;
- return arr[0] + arr[i] + arr[2];
-}
+fn main() -> int:
+ arr : ., mut = [10, 20, 30]
+ i := 1
+ arr[i] = 9
+ return arr[0] + arr[i] + arr[2]
""",
49,
0,
@@ -65,16 +63,15 @@
(
"enum_tag",
"""
-enum Choice { First(int), Second(int), Third(int) }
-fn main() -> int {
- c := Third(33);
- value := match c {
+enum Choice:
+ First(int), Second(int), Third(int)
+fn main() -> int:
+ c := Third(33)
+ value := match c:
First(v) => v,
Second(v) => v,
Third(v) => v,
- };
- return value;
-}
+ return value
""",
33,
0,
@@ -82,14 +79,14 @@
(
"aggregate_o1",
"""
-struct Pair { x: int, y: int }
-fn main() -> int {
- p := Pair { x = 7, y = 20 };
- arr : ., mut = [3, 4, 5];
- i := 1;
- arr[i] = 9;
- return p.x + p.y + arr[0] + arr[i] + arr[2];
-}
+struct Pair:
+ x: int, y: int
+fn main() -> int:
+ p := Pair { x = 7, y = 20 }
+ arr : ., mut = [3, 4, 5]
+ i := 1
+ arr[i] = 9
+ return p.x + p.y + arr[0] + arr[i] + arr[2]
""",
44,
1,
diff --git a/tests/selfhost/test_native_strings.py b/tests/selfhost/test_native_strings.py
index de4abcbb..b618a539 100644
--- a/tests/selfhost/test_native_strings.py
+++ b/tests/selfhost/test_native_strings.py
@@ -24,34 +24,44 @@ def main() -> int:
TEST_BUILD.mkdir(parents=True)
(TEST_BUILD / "src").symlink_to(BASE / "src", target_is_directory=True)
SOURCE.write_text(
- """\
-import fmt
+ """import fmt
import io
-struct Point { x: int, y: int }
+struct Point:
+ x: int, y: int
-fn main() -> int {
- one := int_str(7);
- if str_eq(one, "7") == 0 { return 1; }
- many := int_str(567);
- if str_eq(many, "567") == 0 { return 2; }
+fn main() -> int:
+ one := int_str(7)
+ if str_eq(one, "7") == 0:
+ return 1
+ many := int_str(567)
+ if str_eq(many, "567") == 0:
+ return 2
- joined := "AB" + "CD";
- if str_eq(joined, "ABCD") == 0 { return 3; }
- println(joined);
+ joined := "AB" + "CD"
+ if str_eq(joined, "ABCD") == 0:
+ return 3
+ println(joined)
- if str_len("hello") != 5 { return 4; }
- fields := @fields(Point);
- if str_len(fields) != 3 { return 5; }
+ if str_len("hello") != 5:
+ return 4
+ fields := @fields(Point)
+ if str_len(fields) != 3:
+ return 5
- if str_eq(float_str_bits(4614253070214989087), "3.14") == 0 { return 6; }
- if str_eq(float_str_bits(4611686016625948053), "2") == 0 { return 7; }
- if str_eq(float_str_bits(4621819117363791539), "10") == 0 { return 8; }
- if str_eq(float_str_bits(4607182415197137706), "1") == 0 { return 9; }
- if str_eq(float_str_bits(4636737291326488790), "100") == 0 { return 10; }
- if str_eq(float_str_bits(-4611686020228827755), "-2") == 0 { return 11; }
- return 0;
-}
+ if str_eq(float_str_bits(4614253070214989087), "3.14") == 0:
+ return 6
+ if str_eq(float_str_bits(4611686016625948053), "2") == 0:
+ return 7
+ if str_eq(float_str_bits(4621819117363791539), "10") == 0:
+ return 8
+ if str_eq(float_str_bits(4607182415197137706), "1") == 0:
+ return 9
+ if str_eq(float_str_bits(4636737291326488790), "100") == 0:
+ return 10
+ if str_eq(float_str_bits(-4611686020228827755), "-2") == 0:
+ return 11
+ return 0
""",
encoding="utf-8",
)
diff --git a/tests/selfhost/test_nested_fn.py b/tests/selfhost/test_nested_fn.py
index 10aee528..a5c1128f 100644
--- a/tests/selfhost/test_nested_fn.py
+++ b/tests/selfhost/test_nested_fn.py
@@ -57,22 +57,24 @@
PROC_TIMEOUT = 30
# 嵌套 fn 的最小件(TODO #2026-09-10-12 原文形态)
-NESTED_MIN = """fn outer() -> int {
- fn inner(a: int) -> int { return a + 1; }
- return inner(1);
-}
+NESTED_MIN = """fn outer() -> int:
+ fn inner(a: int) -> int:
+ return a + 1
+ return inner(1)
-fn main() -> int { return outer(); }
+fn main() -> int:
+ return outer()
"""
# 同逻辑扁平对照(语言面内形态):inner(1) = 2 ⇒ 退出码 2
-FLAT_CONTROL = """fn inner(a: int) -> int { return a + 1; }
+FLAT_CONTROL = """fn inner(a: int) -> int:
+ return a + 1
-fn outer() -> int {
- return inner(1);
-}
+fn outer() -> int:
+ return inner(1)
-fn main() -> int { return outer(); }
+fn main() -> int:
+ return outer()
"""
@@ -181,46 +183,51 @@ def main() -> int:
variants = [
("nested_inline_hint", """import io
-fn test_inline_hint() -> int {
- fn add(a: int, b: int) -> int { return a + b; }
- result := @inline(add)(3, 4);
- if result != 7 { return 1; }
- return 0;
-}
+fn test_inline_hint() -> int:
+ fn add(a: int, b: int) -> int:
+ return a + b
+ result := @inline(add)(3, 4)
+ if result != 7:
+ return 1
+ return 0
-fn main() -> int { return test_inline_hint(); }
+fn main() -> int:
+ return test_inline_hint()
""", "add"),
- ("nested_plain_call", """fn test() -> int {
- fn add(a: int, b: int) -> int { return a + b; }
- return add(3, 4);
-}
+ ("nested_plain_call", """fn test() -> int:
+ fn add(a: int, b: int) -> int:
+ return a + b
+ return add(3, 4)
-fn main() -> int { return test(); }
+fn main() -> int:
+ return test()
""", "add"),
- ("nested_pub_fn", """fn outer() -> int {
- pub fn inner() -> int { return 1; }
- return inner();
-}
+ ("nested_pub_fn", """fn outer() -> int:
+ pub fn inner() -> int:
+ return 1
+ return inner()
-fn main() -> int { return outer(); }
+fn main() -> int:
+ return outer()
""", "inner"),
- ("nested_double", """fn outer() -> int {
- fn mid() -> int {
- fn deep() -> int { return 1; }
- return deep();
- }
- return mid();
-}
-
-fn main() -> int { return outer(); }
+ ("nested_double", """fn outer() -> int:
+ fn mid() -> int:
+ fn deep() -> int:
+ return 1
+ return deep()
+ return mid()
+
+fn main() -> int:
+ return outer()
""", "mid"),
- ("nested_then_stmt", """fn outer() -> int {
- fn inner() -> int { return 1; }
- x := 41;
- return x + 1;
-}
-
-fn main() -> int { return outer(); }
+ ("nested_then_stmt", """fn outer() -> int:
+ fn inner() -> int:
+ return 1
+ x := 41
+ return x + 1
+
+fn main() -> int:
+ return outer()
""", "inner"),
]
for name, src, fn_name in variants:
diff --git a/tests/selfhost/test_opt_dex.py b/tests/selfhost/test_opt_dex.py
index bfada85f..9bac5593 100644
--- a/tests/selfhost/test_opt_dex.py
+++ b/tests/selfhost/test_opt_dex.py
@@ -129,20 +129,22 @@ def build_and_reject(source, tag):
os.unlink(p)
-MATCH_BODY = """ return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
+MATCH_BODY = """ return match x:
+ Some(v) => @raw_int(v) / 1000000
+ none => 0
"""
# ── 四态对拍四条(仅源形式与是否 Some 不同;主判据的基元)──
FOUR_STATE = {
- "fs_bare_bits": ("bits", " d : dex, apx = 7.0;\n x : dex? = d;\n"),
- "fs_bare_scaled": ("scaled", " e : dex = 7.0;\n x : dex? = e;\n"),
- "fs_boxed_bits": ("bits", " d : dex, apx = 7.0;\n x : dex? = Some(d);\n"),
- "fs_boxed_scaled": ("scaled", " e : dex = 7.0;\n x : dex? = Some(e);\n"),
+ "fs_bare_bits": ("bits", " d : dex, apx = 7.0\n x : dex? = d\n"),
+ "fs_bare_scaled": ("scaled", " e : dex = 7.0\n x : dex? = e\n"),
+ "fs_boxed_bits": ("bits", " d : dex, apx = 7.0\n x : dex? = Some(d)\n"),
+ "fs_boxed_scaled": ("scaled", " e : dex = 7.0\n x : dex? = Some(e)\n"),
}
def _four_state_src(setup):
- return "fn main() -> int {\n" + setup + MATCH_BODY + "}\n"
+ return "fn main() -> int:\n" + setup + MATCH_BODY
# ── 家族/钉子探针表:name, source, 期望 ELF rc, kind, 备注 ──
@@ -153,165 +155,203 @@ def _four_state_src(setup):
CASES = [
# ── 家族写点/边界面(修前 15 的九条 = 本批 RED 主体)──
("assign_bits", """
-fn main() -> int {
- d : dex, apx = 7.0;
- x : dex?, mut = None;
- x = d;
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ x : dex?, mut = none
+ x = d
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "bits", "赋值写点(修前 15)"),
("ptr_write_bits", """
-fn main() -> int {
- d : dex, apx = 7.0;
- x : dex?, mut = None;
- p := &x;
- *p = d;
- return match *p { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ x : dex?, mut = none
+ p := &x
+ *p = d
+ return match *p:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "bits", "指针写(INV-2;修前 15)"),
("addr_read_bits", """
-fn main() -> int {
- d : dex, apx = 7.0;
- x : dex? = d;
- p := &x;
- return match *p { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ x : dex? = d
+ p := &x
+ return match *p:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "bits", "取址槽(INV-1 交点;`*p` 形态绕开软诊断 B04;修前 15)"),
("ret_bits", """
-fn f() -> dex? {
- d : dex, apx = 7.0;
- return d;
-}
-fn main() -> int {
- x := f();
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+fn f() -> dex?:
+ d : dex, apx = 7.0
+ return d
+fn main() -> int:
+ x := f()
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "bits", "返回面 `-> dex?`(修前 15)"),
("param_bits", """
-fn g(x: dex?) -> int {
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-fn main() -> int {
- d : dex, apx = 7.0;
- return g(d);
-}
+fn g(x: dex?) -> int:
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(d)
""", 7, "bits", "形参面 `dex?` ← apx 实参(修前 ELF 0 / interp 15 = 双路径分歧)"),
("param_branch_bits", """
-fn g(x: dex?) -> int {
- match x {
- Some(v) => { return 100 + (@raw_int(v) % 100); }
- None => { return 200; }
- }
- return 55;
-}
-fn main() -> int {
- d : dex, apx = 7.0;
- return g(d);
-}
+fn g(x: dex?) -> int:
+ match x:
+ Some(v) =>:
+ return 100 + (@raw_int(v) % 100)
+ none =>:
+ return 200
+ return 55
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(d)
""", 100, "bits", "形参面·分支判别形(修前 ELF 101 / interp 172 = 分歧;100 = 100+0)"),
("field_lit_bits", """
-struct S { f: dex? }
-fn main() -> int {
- d : dex, apx = 7.0;
- s : ., mut = S { f = d };
- return match s.f { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+struct S:
+ f: dex?
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S { f = d }
+ return match s.f:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "bits", "结构体字面量字段(装箱序倒置面;修前 15)"),
("global_bits", """
-g : dex?, mut = None;
-fn main() -> int {
- d : dex, apx = 7.0;
- g = d;
- return match g { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+g : dex?, mut = none
+fn main() -> int:
+ d : dex, apx = 7.0
+ g = d
+ return match g:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "bits", "全局槽(必须 `mut`,见头注 ①;修前 15)"),
("enum_payload_opt_bits", """
-enum E { V(dex?) }
-fn main() -> int {
- d : dex, apx = 7.0;
- e := V(d);
- return match e { V(x) => { return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } }; } };
-}
+enum E:
+ V(dex?)
+fn main() -> int:
+ d : dex, apx = 7.0
+ e := V(d)
+ return match e:
+ V(x) =>:
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "bits", "用户枚举的可选 dex 载荷(修前 15)"),
# ── 已覆盖面/钉子(改法不得改坏)──
("field_assign_bits", """
-struct S { f: dex? }
-fn main() -> int {
- d : dex, apx = 7.0;
- s : ., mut = S { f = None };
- s.f = d;
- return match s.f { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+struct S:
+ f: dex?
+fn main() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = S { f = none }
+ s.f = d
+ return match s.f:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "bits", "字段**赋值**面(`:1498` norm→box 的正确序 ⇒ 修前已绿;钉子)"),
("try_unpack_bits", """
-fn main() -> int {
- d : dex, apx = 7.0;
- x : dex? = d;
- y := x?;
- return @raw_int(y) / 1000000;
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ x : dex? = d
+ y := x?
+ return @raw_int(y) / 1000000
""", 7, "bits", "`?` 解包(修前已绿:槽型=bits 自洽;钉住槽型声明化后仍绿)"),
("try_to_dex_bits", """
-fn main() -> int {
- d : dex, apx = 7.0;
- x : dex? = d;
- y := x?;
- z : dex = y;
- return @raw_int(z) / 1000000;
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ x : dex? = d
+ y := x?
+ z : dex = y
+ return @raw_int(z) / 1000000
""", 7, "bits", "`?` 解包再入 `dex` 槽(修前已绿;钉子)"),
("dexopt_apx_tag", """
-fn main() -> int {
- x : dex?, apx = 7.0;
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+fn main() -> int:
+ x : dex?, apx = 7.0
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 0, "reject", "`dex?, apx`:**批 8 条目 5(裁定 (B))后转硬错**(`error[P26]` + 零产物)。"
"**旧值留痕(批 5–批 7)**:`check=0 · ELF=interp=7`(kind=`scaled`,标签被静默忽略 ⇒ 落精确世界,"
"`TODO #2026-09-17-4` 登记面)——本批按计划条目 5 判据要件③「显式归因 + 同批重锁 + 旧值留痕」重锁。"),
("param_scaled", """
-fn g(x: dex?) -> int {
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-fn main() -> int {
- e : dex = 7.0;
- return g(e);
-}
+fn g(x: dex?) -> int:
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+fn main() -> int:
+ e : dex = 7.0
+ return g(e)
""", 7, "scaled", "形参面·对照(scaled 实参;修前已绿——分歧是 bits 实参特有)"),
("param_branch_scaled", """
-fn g(x: dex?) -> int {
- match x {
- Some(v) => { return 100 + (@raw_int(v) % 100); }
- None => { return 200; }
- }
- return 55;
-}
-fn main() -> int {
- e : dex = 7.0;
- return g(e);
-}
+fn g(x: dex?) -> int:
+ match x:
+ Some(v) =>:
+ return 100 + (@raw_int(v) % 100)
+ none =>:
+ return 200
+ return 55
+fn main() -> int:
+ e : dex = 7.0
+ return g(e)
""", 100, "scaled", "形参面·判别形对照(scaled 实参;修前已绿)"),
("ret_scaled", """
-fn f() -> dex? {
- e : dex = 7.0;
- return e;
-}
-fn main() -> int {
- x := f();
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+fn f() -> dex?:
+ e : dex = 7.0
+ return e
+fn main() -> int:
+ x := f()
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
""", 7, "scaled", "返回面·对照(scaled;修前已绿)"),
("param_some_bits", """
-fn g(x: dex?) -> int {
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-fn main() -> int {
- d : dex, apx = 7.0;
- return g(Some(d));
-}
+fn g(x: dex?) -> int:
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(Some(d))
""", 7, "bits", "形参面 ← `Some(apx)`(修前 ELF 已绿:枚举构造点漏斗覆盖;钉子)"),
("nonopt_direct_bits", """
-fn g(x: dex) -> int { return @raw_int(x) / 1000000; }
-fn main() -> int { d : dex, apx = 7.0; return g(d); }
+fn g(x: dex) -> int:
+ return @raw_int(x) / 1000000
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(d)
""", 7, "bits", "非可选 dex 直调(apx 批已覆盖面;非回归钉)"),
# ── G2(读点定型)判别判据:**载荷参与 dex 运算**(match 型载荷读槽的形式若丢,
# `dex_scale_int` 会把已 scaled 的载荷再 ×S = 双倍缩放)。改前实测 ELF 193
@@ -319,18 +359,24 @@ def _four_state_src(setup):
# 注:`?` 解包路径**不**具备判别力(其 dest 型 = `irv_type(inner)` = 槽型,本来自洽)
# ⇒ 本判据必须走 **match 载荷绑定**这一读点。
("g2_payload_dex_arith_scaled", """
-fn main() -> int {
- e : dex = 7.0;
- x : dex? = e;
- return match x { Some(v) => { return @raw_int(v + 1.0) / 1000000; } None => { return 0; } };
-}
+fn main() -> int:
+ e : dex = 7.0
+ x : dex? = e
+ return match x:
+ Some(v) =>:
+ return @raw_int(v + 1.0) / 1000000
+ none =>:
+ return 0
""", 8, "scaled", "G2 判别判据·精确源:match 载荷 + dex 算术(7.0 + 1.0 = 8;改前 193 = 双倍缩放)"),
("g2_payload_dex_arith_bits", """
-fn main() -> int {
- d : dex, apx = 7.0;
- x : dex? = d;
- return match x { Some(v) => { return @raw_int(v + 1.0) / 1000000; } None => { return 0; } };
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ x : dex? = d
+ return match x:
+ Some(v) =>:
+ return @raw_int(v + 1.0) / 1000000
+ none =>:
+ return 0
""", 8, "bits", "G2 判别判据·apx 源(写点归一 + 读点定型两段都得对才 = 8)"),
# ── M1 tag 对改判的**行为钉**(维护者 2026-09-17 附加判据)──
# 机理:`dex?` 槽型由 `TI_INT`(改前)→ `TI_DEX_S`(改后),而 M1 tag 闭包(`tag2l.cr:117/126/128/135/137`)
@@ -339,65 +385,82 @@ def _four_state_src(setup):
# 同一函数内**共置**「会走 M1 tag 编码的 int 链」(ADD/SUB 种子 + 拷贝元)与 `dex?` 值
# (形参 + 局部),断言**两侧各自往返无损**。出现任何新行为差异 ⇒ 报 lead(不得用「分类变化」一句带过)。
("mw_tag_coexist_bits", """
-fn mw_coexist_bits(e: dex?) -> int {
- a := 2000000000;
- b := 2000000000;
- c := a + b;
- s := c;
- x : dex? = e;
- y := x?;
- r := @raw_int(y) / 1000000;
- if r != 7 { return 1; }
- if s != 4000000000 { return 2; }
- return 0;
-}
-fn main() -> int {
- d : dex, apx = 7.0;
- return mw_coexist_bits(d);
-}
+fn mw_coexist_bits(e: dex?) -> int:
+ a := 2000000000
+ b := 2000000000
+ c := a + b
+ s := c
+ x : dex? = e
+ y := x?
+ r := @raw_int(y) / 1000000
+ if r != 7:
+ return 1
+ if s != 4000000000:
+ return 2
+ return 0
+fn main() -> int:
+ d : dex, apx = 7.0
+ return mw_coexist_bits(d)
""", 0, "bits", "M1 tag 对行为钉(bits 形):int 多字链与 `dex?` 共置 ⇒ 两侧往返一致(0 全过 / 1 dex 侧坏 / 2 int 侧坏)"),
("mw_tag_coexist_scaled", """
-fn mw_coexist_scaled(e: dex?) -> int {
- a := 2000000000;
- b := 2000000000;
- c := a + b;
- s := c;
- x : dex? = e;
- y := x?;
- r := @raw_int(y) / 1000000;
- if r != 7 { return 1; }
- if s != 4000000000 { return 2; }
- return 0;
-}
-fn main() -> int {
- e : dex = 7.0;
- return mw_coexist_scaled(e);
-}
+fn mw_coexist_scaled(e: dex?) -> int:
+ a := 2000000000
+ b := 2000000000
+ c := a + b
+ s := c
+ x : dex? = e
+ y := x?
+ r := @raw_int(y) / 1000000
+ if r != 7:
+ return 1
+ if s != 4000000000:
+ return 2
+ return 0
+fn main() -> int:
+ e : dex = 7.0
+ return mw_coexist_scaled(e)
""", 0, "scaled", "M1 tag 对行为钉·精确形对照(解释器腿可跑:ELF == interp == 0)"),
# ── 非 dex 对照(零足迹面:不得被本批改动)──
("int_opt_lit", """
-fn g(x: int?) -> int {
- return match x { Some(v) => { return v; } None => { return 0; } };
-}
-fn main() -> int { return g(7); }
+fn g(x: int?) -> int:
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ return g(7)
""", 7, "int", "`int?` 字面量(对照:非 dex 面不受影响)"),
("int_opt_var", """
-fn g(x: int?) -> int {
- return match x { Some(v) => { return v; } None => { return 0; } };
-}
-fn main() -> int { n := 7; return g(n); }
+fn g(x: int?) -> int:
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ n := 7
+ return g(n)
""", 7, "int", "`int?` 变量实参(对照)"),
("int_opt_some", """
-fn g(x: int?) -> int {
- return match x { Some(v) => { return v; } None => { return 0; } };
-}
-fn main() -> int { return g(Some(7)); }
+fn g(x: int?) -> int:
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ return g(Some(7))
""", 7, "int", "`int?` ← `Some(7)`(对照)"),
("int_opt_none", """
-fn g(x: int?) -> int {
- return match x { Some(v) => { return v; } None => { return 0; } };
-}
-fn main() -> int { return g(None); }
+fn g(x: int?) -> int:
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ return g(none)
""", 0, "int", "`int?` ← `None`(对照;0 = None 分支)"),
]
@@ -407,11 +470,14 @@ def _four_state_src(setup):
# 编译期拒绝面(响亮,非静默):`[dex?; N]` 字面量元素类型推断未接可选面
REJECT_SRC = """
-fn main() -> int {
- d : dex, apx = 7.0;
- a : [dex?; 2] = [d, None];
- return match a[0] { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
+fn main() -> int:
+ d : dex, apx = 7.0
+ a : [dex?; 2] = [d, none]
+ return match a[0]:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
"""
diff --git a/tests/selfhost/test_opt_eq.py b/tests/selfhost/test_opt_eq.py
index e2be02ce..49e4bd06 100644
--- a/tests/selfhost/test_opt_eq.py
+++ b/tests/selfhost/test_opt_eq.py
@@ -41,17 +41,15 @@
BASE = Path(__file__).resolve().parents[2]
COREC = BASE / "build" / "corec"
-B2I = "fn b2i(x: bool) -> int { if x { return 1; } return 0; }\n"
+B2I = "fn b2i(x: bool) -> int:\n if x:\n return 1\n return 0\n"
# 位码打包:五读数各占一位(ELF/interp 同判)
BITCODE = """
-fn main() -> int {
- n : int? = None;
- m : int? = None;
- a : int? = 7;
- b : int? = 7;
- return b2i(n == Some(7)) + b2i(n == None) * 2 + b2i(n == m) * 4
- + b2i(a == b) * 8 + b2i(a == 7) * 16 + b2i(n == 7) * 32;
-}
+fn main() -> int:
+ n : int? = none
+ m : int? = none
+ a : int? = 7
+ b : int? = 7
+ return b2i(n == Some(7)) + b2i(n == none) * 2 + b2i(n == m) * 4 + b2i(a == b) * 8 + b2i(a == 7) * 16 + b2i(n == 7) * 32
"""
BITCODE_PRE = 24 # 修复前实测(= 五读数 0/0/0/1/1 ⇒ bit3+bit4;lead 2026-09-18 裁定锚)
BITCODE_POST = 30 # 修复后期望:②③④⑤ 置位(① 与 bit5 不置位)
@@ -89,70 +87,120 @@ def case_dual(name, source, want, note=""):
CASES = [
# ── 判据 ①:Some(x)==Some(x)(两个**不同对象**、载荷相等)──
("some_eq_some_true", B2I + """
-fn main() -> int { return b2i(Some(7) == Some(7)); }
+fn main() -> int:
+ return b2i(Some(7) == Some(7))
""", 1, "① 装箱两对象载荷相等"),
("some_eq_some_false", B2I + """
-fn main() -> int { return b2i(Some(7) == Some(8)); }
+fn main() -> int:
+ return b2i(Some(7) == Some(8))
""", 0, "① 反向:载荷不等"),
# ── 判据 ②:None==None(两个不同 None 源)──
("none_eq_none_vars", B2I + """
-fn main() -> int { n : int? = None; m : int? = None; return b2i(n == m); }
+fn main() -> int:
+ n : int? = none
+ m : int? = none
+ return b2i(n == m)
""", 1, "② 两个 None 变量"),
("none_eq_none_lit", B2I + """
-fn main() -> int { n : int? = None; return b2i(n == None); }
+fn main() -> int:
+ n : int? = none
+ return b2i(n == none)
""", 1, "② 变量 vs None 字面量"),
# ── 判据 ③:Some(x)==None 必假(双向)──
("some_ne_none", B2I + """
-fn main() -> int { n : int? = Some(7); return b2i(n == None); }
+fn main() -> int:
+ n : int? = Some(7)
+ return b2i(n == none)
""", 0, "③ Some vs None"),
("none_ne_some", B2I + """
-fn main() -> int { n : int? = None; return b2i(n == Some(7)); }
+fn main() -> int:
+ n : int? = none
+ return b2i(n == Some(7))
""", 0, "③ None vs Some(反向)"),
# ── 判据 ④:同源自比较 x==x(bare / boxed 两表示)──
("self_eq_bare", B2I + """
-fn main() -> int { a : int? = 7; return b2i(a == a); }
+fn main() -> int:
+ a : int? = 7
+ return b2i(a == a)
""", 1, "④ 裸表示自比较"),
("self_eq_boxed", B2I + """
-fn main() -> int { a : int? = 7; p := &a; *p = Some(9); return b2i(*p == *p); }
+fn main() -> int:
+ a : int? = 7
+ p := &a
+ *p = Some(9)
+ return b2i(*p == *p)
""", 1, "④ 装箱表示自比较(INV-1 取址槽;`*p` 形态绕开软诊断 B04,同批 5 体例)"),
# ── 表示透明:同语义两种表示同判(本修复的核心命题)──
("rep_transparent_bare", B2I + """
-fn main() -> int { a : int? = 7; b : int? = 7; return b2i(a == b); }
+fn main() -> int:
+ a : int? = 7
+ b : int? = 7
+ return b2i(a == b)
""", 1, "裸 7 == 裸 7"),
("rep_transparent_boxed", B2I + """
-fn main() -> int { a : int? = 7; b : int? = 7; p := &a; q := &b; *p = Some(7); *q = Some(7); return b2i(*p == *q); }
+fn main() -> int:
+ a : int? = 7
+ b : int? = 7
+ p := &a
+ q := &b
+ *p = Some(7)
+ *q = Some(7)
+ return b2i(*p == *q)
""", 1, "装箱 Some(7) == 装箱 Some(7)"),
("boxed_vs_bare_mixed", B2I + """
-fn main() -> int { a : int? = 7; b : int? = 7; p := &a; *p = Some(7); return b2i(*p == b); }
+fn main() -> int:
+ a : int? = 7
+ b : int? = 7
+ p := &a
+ *p = Some(7)
+ return b2i(*p == b)
""", 1, "装箱 Some(7) == 裸 7(表示无关)"),
# ── `!=` 面 ──
("ne_some_diff", B2I + """
-fn main() -> int { return b2i(Some(7) != Some(8)); }
+fn main() -> int:
+ return b2i(Some(7) != Some(8))
""", 1, "!=:载荷不等 ⇒ 真"),
("ne_none_none", B2I + """
-fn main() -> int { n : int? = None; m : int? = None; return b2i(n != m); }
+fn main() -> int:
+ n : int? = none
+ m : int? = none
+ return b2i(n != m)
""", 0, "!=:两个 None ⇒ 假"),
# ── 合成/嵌套:比较结果再参与比较 ──
("composed_bool", B2I + """
-fn main() -> int { n : int? = None; m : int? = None; return b2i((n == None) == (m == None)); }
+fn main() -> int:
+ n : int? = none
+ m : int? = none
+ return b2i((n == none) == (m == none))
""", 1, "两比较结果相等(bool 面)"),
# ── 位码总钉(五读数打包;ELF 与 interp 同判)──
("bitcode_five_readings", B2I + BITCODE, BITCODE_POST,
f"五读数位码(修复前 {BITCODE_PRE})"),
# ── 判据 ⑤:非可选对比 = 零变化(逐值钉子)──
("plain_eq_true", B2I + """
-fn main() -> int { a := 7; b := 7; return b2i(a == b); }
+fn main() -> int:
+ a := 7
+ b := 7
+ return b2i(a == b)
""", 1, "⑤ 非可选 7==7"),
("plain_eq_false", B2I + """
-fn main() -> int { a := 7; b := 8; return b2i(a == b); }
+fn main() -> int:
+ a := 7
+ b := 8
+ return b2i(a == b)
""", 0, "⑤ 非可选 7==8"),
("plain_str_eq", B2I + """
import io
-fn main() -> int { a := "hi"; b := "hi"; return b2i(a == b); }
+fn main() -> int:
+ a := "hi"
+ b := "hi"
+ return b2i(a == b)
""", 1, "⑤ 非可选字符串相等(走 str_eq 原路径)"),
# ── 已登记未覆盖面(**记录现状**,不是判据:字符串载荷的装箱比较仍按指针)──
("known_uncovered_str_payload", B2I + """
-fn main() -> int { a : string? = None; return b2i(a == None); }
+fn main() -> int:
+ a : string? = none
+ return b2i(a == none)
""", 1, "未覆盖面抽样:None 判定(类型无关,已在覆盖面内)"),
]
diff --git a/tests/selfhost/test_optional.py b/tests/selfhost/test_optional.py
index aee12944..1e280408 100644
--- a/tests/selfhost/test_optional.py
+++ b/tests/selfhost/test_optional.py
@@ -5,17 +5,17 @@
docs/superpowers/specs/2026-09-10-type-interface-unification-design.md §5.4):
正(**解释器 + ELF 双路径同值**):`T ⊆ T?`(裸值 `return 5` 入 `int?` 返回位)/
- `null ⊆ T?`(`return None`)/ `Some(1)` 入 `int?` / `T?` 形参位 / `?` 解包回 T /
- `Some(x)` 与 `None` 的 match 两臂(运行时 tag 分派)
+ `null ⊆ T?`(`return none`)/ `Some(1)` 入 `int?` / `T?` 形参位 / `?` 解包回 T /
+ `Some(x)` 与 `none` 的 match 两臂(运行时 tag 分派)
负:`T? ⊄ T`(`fn f(x: int?) -> int { return x; }` ⇒ TF01——**方向性**:可选不是 T 的子类型)/
`Option` 名退役(`Option[int]` 作类型 = 未定义泛型应用 rc=1——退役前该名由内建注册)
- 硬门:`T?` 的 match 缺臂 ⇒ TM03 rc=1 + 具体反例名('None' / 'Some')+ 无产物
+ 硬门:`T?` 的 match 缺臂 ⇒ TM03 rc=1 + 具体反例名('none' / 'Some')+ 无产物
登记:载荷**类型节点列**(T0 交接 ①):`--verify-evp-nodes` 断言每槽有节点(bad=0),
并数出裸码列丢失真实类型的槽数(collapses>0 = 节点列携带的信息量;旧布局裸码把
非基型塌缩为 0 = TY_INT)
表示面(R2 P4 Task 5,裁决 5「解包侧判表示」——本套件下半段):可选槽配**表示位**
- (0 = 裸值 / 1 = 装箱,运行期值):写点置位、解包点(`match` 的 Some/None 臂、
- `?`)分派——裸值路径**值即载荷**(Some 臂直取、不读 tag;None 臂不命中),装箱
+ (0 = 裸值 / 1 = 装箱,运行期值):写点置位、解包点(`match` 的 Some/none 臂、
+ `?`)分派——裸值路径**值即载荷**(Some 臂直取、不读 tag;none 臂不命中),装箱
路径沿用既有 tag 分派 + 字段 fi+1。跨函数面(返回/形参)走隐藏全局信道(纯 IR)。
**前置红态(B.7 一等条目)**:裸值 + `Some` 臂 = 双路径 SIGSEGV(check/build rc=0
零诊断)——修复前后 rc 逐形态见任务报告。
@@ -208,138 +208,388 @@ def case_evp(name, source, needles):
# ── 源形 ──────────────────────────────────────────────────────────────
# 裸值入 T?(`int ⊆ int ∪ null`):判定点注入面(type_compat_strict 的可选目标分支)
-PLAIN_INTO_OPT = """fn g() -> int? { return 5; }
-fn main() -> int { return 42; }
+PLAIN_INTO_OPT = """fn g() -> int?:
+ return 5
+fn main() -> int:
+ return 42
"""
-NONE_INTO_OPT = """fn g() -> int? { return None; }
-fn main() -> int { return 42; }
+NONE_INTO_OPT = """fn g() -> int?:
+ return none
+fn main() -> int:
+ return 42
"""
-SOME_INTO_OPT = """fn g() -> int? { return Some(1); }
-fn main() -> int { return 42; }
+SOME_INTO_OPT = """fn g() -> int?:
+ return Some(1)
+fn main() -> int:
+ return 42
"""
# T? 形参位 + `?` 解包(EXPR_TRY 按类型项结构)
-UNWRAP_SRC = """fn f(x: int?) -> int { return x?; }
-fn main() -> int { return f(3); }
+UNWRAP_SRC = """fn f(x: int?) -> int:
+ return x?
+fn main() -> int:
+ return f(3)
"""
# 运行时两形态:Some 值(枚举对象 + tag)与 None
-SOME_FLOW = """fn g() -> int? { return Some(1); }
-fn main() -> int { v := g(); return match v { Some(x) => x + 100, None => 0, }; }
-"""
-NONE_FLOW = """fn g() -> int? { return None; }
-fn main() -> int { v := g(); return match v { Some(x) => x + 100, None => 7, }; }
+SOME_FLOW = """fn g() -> int?:
+ return Some(1)
+fn main() -> int:
+ v := g()
+ return match v:
+ Some(x) => x + 100, none => 0,
+"""
+NONE_FLOW = """fn g() -> int?:
+ return none
+fn main() -> int:
+ v := g()
+ return match v:
+ Some(x) => x + 100, none => 7,
"""
# ── R2 P4 Task 5(裁决 5:解包侧判表示):B.7 四形态 + 跨函数面 ──────────────
# 语义口径:裸值入 `T?` = 该值本身(`T ⊆ T?`)⇒ Some 臂**命中**且载荷 = 裸值。
-BARE_SOME_ARM = """fn main() -> int { x : int? = 5; return match x { Some(v) => { return v; } None => { return 0; } }; }
-"""
-BARE_SOME_WILDCARD = """fn main() -> int { x : int? = 5; return match x { Some(v) => { return v; } _ => { return 6; } }; }
-"""
-BARE_MATCH_EXPR = """fn main() -> int { x : int? = 5; y := match x { Some(v) => v, None => 0, }; return y; }
-"""
-BARE_WILDCARD = """fn main() -> int { x : int? = 5; return match x { _ => { return 7; } }; }
-"""
-BARE_THEN_BOXED_WRITE = """fn main() -> int { x : int? = 5; x = Some(7); return match x { Some(v) => { return v; } None => { return 0; } }; }
-"""
-BOXED_THEN_BARE_WRITE = """fn main() -> int { x : int? = Some(7); x = 3; return match x { Some(v) => { return v; } None => { return 0; } }; }
+BARE_SOME_ARM = """fn main() -> int:
+ x : int? = 5
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+BARE_SOME_WILDCARD = """fn main() -> int:
+ x : int? = 5
+ return match x:
+ Some(v) =>:
+ return v
+ _ =>:
+ return 6
+"""
+BARE_MATCH_EXPR = """fn main() -> int:
+ x : int? = 5
+ y := match x:
+ Some(v) => v, none => 0,
+ return y
+"""
+BARE_WILDCARD = """fn main() -> int:
+ x : int? = 5
+ return match x:
+ _ =>:
+ return 7
+"""
+BARE_THEN_BOXED_WRITE = """fn main() -> int:
+ x : int? = 5
+ x = Some(7)
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+BOXED_THEN_BARE_WRITE = """fn main() -> int:
+ x : int? = Some(7)
+ x = 3
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# 条件写:同一槽两条路径两种表示 ⇒ 表示位必须是**运行期值**(静态收窄无法覆盖)
-COND_ON = """fn main() -> int { x : int? = 5; c := 1; if c > 0 { x = Some(4); } return match x { Some(v) => { return v; } None => { return 0; } }; }
-"""
-COND_OFF = """fn main() -> int { x : int? = 5; c := 0; if c > 0 { x = Some(4); } return match x { Some(v) => { return v; } None => { return 0; } }; }
+COND_ON = """fn main() -> int:
+ x : int? = 5
+ c := 1
+ if c > 0:
+ x = Some(4)
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+COND_OFF = """fn main() -> int:
+ x : int? = 5
+ c := 0
+ if c > 0:
+ x = Some(4)
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# 跨函数面(返回信道 / 形参信道)
-BARE_RET_SOME_ARM = """fn g() -> int? { return 5; }
-fn main() -> int { v := g(); return match v { Some(x) => { return x; } None => { return 0; } }; }
-"""
-BOXED_RET_SOME_ARM = """fn g() -> int? { return Some(9); }
-fn main() -> int { v := g(); return match v { Some(x) => { return x; } None => { return 0; } }; }
-"""
-BARE_RET_WILDCARD = """fn g() -> int? { return 5; }
-fn main() -> int { v := g(); return match v { _ => { return 11; } }; }
-"""
-BARE_PARAM_SOME_ARM = """fn f(x: int?) -> int { return match x { Some(v) => { return v; } None => { return 0; } }; }
-fn main() -> int { return f(5); }
-"""
-BOXED_PARAM_SOME_ARM = """fn f(x: int?) -> int { return match x { Some(v) => { return v; } None => { return 0; } }; }
-fn main() -> int { return f(Some(6)); }
-"""
-BARE_PARAM_TRY = """fn f(x: int?) -> int { return x?; }
-fn main() -> int { return f(3); }
+BARE_RET_SOME_ARM = """fn g() -> int?:
+ return 5
+fn main() -> int:
+ v := g()
+ return match v:
+ Some(x) =>:
+ return x
+ none =>:
+ return 0
+"""
+BOXED_RET_SOME_ARM = """fn g() -> int?:
+ return Some(9)
+fn main() -> int:
+ v := g()
+ return match v:
+ Some(x) =>:
+ return x
+ none =>:
+ return 0
+"""
+BARE_RET_WILDCARD = """fn g() -> int?:
+ return 5
+fn main() -> int:
+ v := g()
+ return match v:
+ _ =>:
+ return 11
+"""
+BARE_PARAM_SOME_ARM = """fn f(x: int?) -> int:
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ return f(5)
+"""
+BOXED_PARAM_SOME_ARM = """fn f(x: int?) -> int:
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ return f(Some(6))
+"""
+BARE_PARAM_TRY = """fn f(x: int?) -> int:
+ return x?
+fn main() -> int:
+ return f(3)
"""
# `?` 解包装箱值:修复前 ELF 返回指针、解释器返回内部地址(**双路径分歧的静默错值**)
-BOXED_PARAM_TRY = """fn g() -> int? { return Some(7); }
-fn f(x: int?) -> int { return x?; }
-fn main() -> int { return f(g()); }
+BOXED_PARAM_TRY = """fn g() -> int?:
+ return Some(7)
+fn f(x: int?) -> int:
+ return x?
+fn main() -> int:
+ return f(g())
"""
# 混合返回(同函数两条 return 两种表示;表示位运行期分派 ⇒ 两条路径各自正确)
-MIXED_RET_BARE = """fn g(c: int) -> int? { if c > 0 { return 5; } return Some(4); }
-fn main() -> int { v := g(1); return match v { Some(x) => { return x; } None => { return 0; } }; }
-"""
-MIXED_RET_BOXED = """fn g(c: int) -> int? { if c > 0 { return 5; } return Some(4); }
-fn main() -> int { v := g(0); return match v { Some(x) => { return x; } None => { return 0; } }; }
+MIXED_RET_BARE = """fn g(c: int) -> int?:
+ if c > 0:
+ return 5
+ return Some(4)
+fn main() -> int:
+ v := g(1)
+ return match v:
+ Some(x) =>:
+ return x
+ none =>:
+ return 0
+"""
+MIXED_RET_BOXED = """fn g(c: int) -> int?:
+ if c > 0:
+ return 5
+ return Some(4)
+fn main() -> int:
+ v := g(0)
+ return match v:
+ Some(x) =>:
+ return x
+ none =>:
+ return 0
"""
# 装箱值 + 通配臂(既有语义保持)
-BOXED_WILDCARD = """fn main() -> int { x : int? = Some(9); return match x { _ => { return 12; } }; }
+BOXED_WILDCARD = """fn main() -> int:
+ x : int? = Some(9)
+ return match x:
+ _ =>:
+ return 12
"""
# 未覆盖面(登记,非本任务面):结构体字段裸值 + Some 臂 ⇒ 既有装箱假定 ⇒ 响亮失败
# (rc=139 双路径**同**:钉「未覆盖面不静默分歧」,不钉错误值本身)
-UNCOVERED_FIELD_BARE = """struct S { a: int? }
-fn main() -> int { s : ., mut = S { a: 5 }; return match s.a { Some(v) => { return v; } None => { return 0; } }; }
+UNCOVERED_FIELD_BARE = """struct S:
+ a: int?
+fn main() -> int:
+ s : ., mut = S { a= 5 }
+ return match s.a:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# 未覆盖面之装箱形态:照常正确(登记双面)
-UNCOVERED_FIELD_BOXED = """struct S { a: int? }
-fn main() -> int { s : ., mut = S { a: Some(5) }; return match s.a { Some(v) => { return v; } None => { return 0; } }; }
+UNCOVERED_FIELD_BOXED = """struct S:
+ a: int?
+fn main() -> int:
+ s : ., mut = S { a= Some(5) }
+ return match s.a:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# 全局槽(无表示位 = 未覆盖面,走既有装箱假定):装箱形态照常正确(**前提 = tag 读取
# 源支持全局行**——修复前 ELF 读帧外伪偏移 ⇒ 静默走空臂返回 0,与解释器 5 分歧)
-UNCOVERED_GLOBAL_BOXED = """g : int? = Some(5);
-fn main() -> int { return match g { Some(v) => { return v; } None => { return 0; } }; }
-"""
-UNCOVERED_GLOBAL_NONE = """g : int? = None;
-fn main() -> int { return match g { Some(v) => { return v; } None => { return 9; } }; }
+UNCOVERED_GLOBAL_BOXED = """g : int? = Some(5)
+fn main() -> int:
+ return match g:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+UNCOVERED_GLOBAL_NONE = """g : int? = none
+fn main() -> int:
+ return match g:
+ Some(v) =>:
+ return v
+ none =>:
+ return 9
"""
# ── 容量批 T2:聚合面存储边界规范化(裁-CAP-1 (a))——A 类 8 写点逐点覆盖 ──────────
# 每例 = 裸值写入可选聚合槽后解包(修复前 139;现须给精确值);装箱/None 形为对照。
-CAP_FIELD_ASSIGN = """struct S { a: int? }
-fn main() -> int { s : ., mut = S { a: Some(0) }; s.a = 5; return match s.a { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_FIELD_LITERAL = """struct S { a: int? }
-fn main() -> int { s : ., mut = S { a: 6 }; return match s.a { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_FIELD_NONE = """struct S { a: int? }
-fn main() -> int { s : ., mut = S { a: None }; return match s.a { Some(v) => { return v; } None => { return 3; } }; }
-"""
-CAP_ARR_ASSIGN_LIT = """fn main() -> int { a : [int?;2] = [Some(0), None]; a[0] = 7; return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_ARR_ASSIGN_DYN = """fn main() -> int { a : [int?;2] = [Some(1), None]; i := 1; a[i] = 8; return match a[i] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_ARR_LITERAL_IDENT = """fn main() -> int { x : int? = 5; a : [int?;2] = [x, None]; return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_ARR_BOXED_LITERAL = """fn main() -> int { a : [int?;2] = [Some(4), None]; return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_GLOBAL_ASSIGN = """g : int? = None;
-fn main() -> int { g = 9; return match g { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_GLOBAL_INIT_BARE = """g : int? = 10;
-fn main() -> int { return match g { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_MATCHRES_COND = """fn f(c: int) -> int? { return match c { 0 => 11, _ => None, }; }
-fn main() -> int { v := f(0); return match v { Some(x) => { return x; } None => { return 0; } }; }
-"""
-CAP_ENUM_PAYLOAD = """enum E { V(int?), W }
-fn main() -> int { e := V(12); return match e { V(x) => { return match x { Some(v) => { return v; } None => { return 0; } }; } W => { return 1; } }; }
-"""
-CAP_TUPLE_ELEM = """fn main() -> int { x : int? = 13; t := (x, 3); return match t . 0 { Some(v) => { return v; } None => { return 0; } }; }
-"""
-CAP_FIELD_BARE_CROSSFN = """struct S { a: int? }
-fn f(s: S) -> int { return match s.a { Some(v) => { return v; } None => { return 0; } }; }
-fn main() -> int { s : ., mut = S { a: Some(0) }; s.a = 14; return f(s); }
+CAP_FIELD_ASSIGN = """struct S:
+ a: int?
+fn main() -> int:
+ s : ., mut = S { a= Some(0) }
+ s.a = 5
+ return match s.a:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_FIELD_LITERAL = """struct S:
+ a: int?
+fn main() -> int:
+ s : ., mut = S { a= 6 }
+ return match s.a:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_FIELD_NONE = """struct S:
+ a: int?
+fn main() -> int:
+ s : ., mut = S { a= none }
+ return match s.a:
+ Some(v) =>:
+ return v
+ none =>:
+ return 3
+"""
+CAP_ARR_ASSIGN_LIT = """fn main() -> int:
+ a : [int?;2] = [Some(0), none]
+ a[0] = 7
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_ARR_ASSIGN_DYN = """fn main() -> int:
+ a : [int?;2] = [Some(1), none]
+ i := 1
+ a[i] = 8
+ return match a[i]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_ARR_LITERAL_IDENT = """fn main() -> int:
+ x : int? = 5
+ a : [int?;2] = [x, none]
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_ARR_BOXED_LITERAL = """fn main() -> int:
+ a : [int?;2] = [Some(4), none]
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_GLOBAL_ASSIGN = """g : int? = none
+fn main() -> int:
+ g = 9
+ return match g:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_GLOBAL_INIT_BARE = """g : int? = 10
+fn main() -> int:
+ return match g:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_MATCHRES_COND = """fn f(c: int) -> int?:
+ return match c:
+ 0 => 11, _ => none,
+fn main() -> int:
+ v := f(0)
+ return match v:
+ Some(x) =>:
+ return x
+ none =>:
+ return 0
+"""
+CAP_ENUM_PAYLOAD = """enum E:
+ V(int?), W
+fn main() -> int:
+ e := V(12)
+ return match e:
+ V(x) =>:
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+ W =>:
+ return 1
+"""
+CAP_TUPLE_ELEM = """fn main() -> int:
+ x : int? = 13
+ t := (x, 3)
+ return match t . 0:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+CAP_FIELD_BARE_CROSSFN = """struct S:
+ a: int?
+fn f(s: S) -> int:
+ return match s.a:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ s : ., mut = S { a= Some(0) }
+ s.a = 14
+ return f(s)
"""
# 负控:非可选聚合槽不受本律影响(值形态不变)
-CAP_NONOPT_FIELD = """struct S { a: int }
-fn main() -> int { s : ., mut = S { a: 15 }; s.a = 16; return s.a; }
+CAP_NONOPT_FIELD = """struct S:
+ a: int
+fn main() -> int:
+ s : ., mut = S { a= 15 }
+ s.a = 16
+ return s.a
"""
@@ -350,58 +600,206 @@ def case_evp(name, source, needles):
# `case_dual`(check 零诊断面:数组元素 / 非可选对照),`case_dual_rc`(登记面:REP-2/REP-3)。
# **形态③(全局)另钉第二根因**:ELF 后端 `IR_REF` 全局取址修复(`&g` 曾取帧外伪偏移 ⇒
# 与全局槽脱钩)——负控 `a_neg_nonopt_global_ptr` 即其钉子(修复前 ELF 恒初值)。
-A_LOCAL_BARE = """fn main() -> int { x : int? = Some(0); p := &x; *p = 7; return match x { Some(v) => { return v; } None => { return 0; } }; }
-"""
-A_LOCAL_BOXED = """fn main() -> int { x : int? = Some(0); p := &x; *p = Some(8); return match x { Some(v) => { return v; } None => { return 0; } }; }
-"""
-A_LOCAL_NONE_WRITE = """fn main() -> int { x : int? = Some(0); p := &x; *p = None; return match x { Some(v) => { return v; } None => { return 3; } }; }
-"""
-A_LOCAL_COND = """fn main() -> int { x : int? = None; p := &x; c := 1; if c > 0 { *p = 5; } else { *p = Some(6); } return match x { Some(v) => { return v; } None => { return 0; } }; }
-"""
-A_ARR_BARE = """fn main() -> int { a : [int?;2] = [Some(0), None]; p := &a[0]; *p = 7; return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-A_ARR_COND = """fn main() -> int { a : [int?;2] = [Some(1), None]; p := &a[0]; c := 0; if c > 0 { *p = 5; } else { *p = 9; } return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-A_GLOBAL_BARE = """g : int? = None;
-fn main() -> int { p := &g; *p = 5; return match g { Some(v) => { return v; } None => { return 0; } }; }
-"""
-A_GLOBAL_BOXED = """g : int? = None;
-fn main() -> int { p := &g; *p = Some(5); return match g { Some(v) => { return v; } None => { return 0; } }; }
-"""
-A_GLOBAL_NONE_WRITE = """g : int? = Some(1);
-fn main() -> int { p := &g; *p = None; return match g { Some(v) => { return v; } None => { return 4; } }; }
-"""
-A_GLOBAL_COND = """g : int? = None;
-fn main() -> int { p := &g; c := 1; if c > 0 { *p = 5; } else { *p = Some(6); } return match g { Some(v) => { return v; } None => { return 0; } }; }
+A_LOCAL_BARE = """fn main() -> int:
+ x : int? = Some(0)
+ p := &x
+ *p = 7
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+A_LOCAL_BOXED = """fn main() -> int:
+ x : int? = Some(0)
+ p := &x
+ *p = Some(8)
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+A_LOCAL_NONE_WRITE = """fn main() -> int:
+ x : int? = Some(0)
+ p := &x
+ *p = none
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 3
+"""
+A_LOCAL_COND = """fn main() -> int:
+ x : int? = none
+ p := &x
+ c := 1
+ if c > 0:
+ *p = 5
+ else:
+ *p = Some(6)
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+A_ARR_BARE = """fn main() -> int:
+ a : [int?;2] = [Some(0), none]
+ p := &a[0]
+ *p = 7
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+A_ARR_COND = """fn main() -> int:
+ a : [int?;2] = [Some(1), none]
+ p := &a[0]
+ c := 0
+ if c > 0:
+ *p = 5
+ else:
+ *p = 9
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+A_GLOBAL_BARE = """g : int? = none
+fn main() -> int:
+ p := &g
+ *p = 5
+ return match g:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+A_GLOBAL_BOXED = """g : int? = none
+fn main() -> int:
+ p := &g
+ *p = Some(5)
+ return match g:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+A_GLOBAL_NONE_WRITE = """g : int? = Some(1)
+fn main() -> int:
+ p := &g
+ *p = none
+ return match g:
+ Some(v) =>:
+ return v
+ none =>:
+ return 4
+"""
+A_GLOBAL_COND = """g : int? = none
+fn main() -> int:
+ p := &g
+ c := 1
+ if c > 0:
+ *p = 5
+ else:
+ *p = Some(6)
+ return match g:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# ④ 结构体字段取址:**裁-REP-3 维持登记**(`UOP_REF` 无字段分支 ⇒ 取临时量地址 ⇒ 写入丢失;
# 属另一缺陷,须新增 `IR_ADDR_FIELD` 面才能修)——本例只钉「双路径同 rc(响亮同态)**不静默分歧**」,
# 不钉错值本身(修好后本例会照常通过:rc=0 面两支同)。
-A_FIELD_ADDR = """struct S { a: int? }
-fn main() -> int { s : ., mut = S { a: Some(0) }; p := &s.a; *p = 5; return match s.a { Some(v) => { return v; } None => { return 0; } }; }
+A_FIELD_ADDR = """struct S:
+ a: int?
+fn main() -> int:
+ s : ., mut = S { a= Some(0) }
+ p := &s.a
+ *p = 5
+ return match s.a:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# ①d 形参槽(W4:形参序言**条件装箱** + 表示位钉 1)——裸值经信道入形参后被取址
-A_PARAM_BARE = """fn f(x: int?) -> int { p := &x; *p = 7; return match x { Some(v) => { return v; } None => { return 0; } }; }
-fn main() -> int { return f(3); }
+A_PARAM_BARE = """fn f(x: int?) -> int:
+ p := &x
+ *p = 7
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ return f(3)
"""
# 三子形态(T1 记录:c1 正确但脆弱 / c2 139 双路径 / c3 双路径分歧静默错值)
-A_C1_BIT0_BARE = """fn main() -> int { x : int? = 5; p := &x; *p = 7; return match x { Some(v) => { return v; } None => { return 0; } }; }
-"""
-A_C2_BIT1_BARE = """fn main() -> int { x : int? = Some(5); p := &x; *p = 7; return match x { Some(v) => { return v; } None => { return 0; } }; }
+A_C1_BIT0_BARE = """fn main() -> int:
+ x : int? = 5
+ p := &x
+ *p = 7
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+A_C2_BIT1_BARE = """fn main() -> int:
+ x : int? = Some(5)
+ p := &x
+ *p = 7
+ return match x:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# c3 转正判据按 T1 修正:**断言「= 正确值」不钉历史观测数值**(T1 实测 ELF 8 / interp 96,
# 数值随状态漂移)——判据内置:写入载荷 = 9 ⇒ 解包值须 == 9(自证,非外部钉数)。
-A_C3_BIT0_BOXED_SELFCHECK = """fn main() -> int { x : int? = 5; p := &x; *p = Some(9); return match x { Some(v) => { if v == 9 { return 1; } return 0; } None => { return 0; } }; }
+A_C3_BIT0_BOXED_SELFCHECK = """fn main() -> int:
+ x : int? = 5
+ p := &x
+ *p = Some(9)
+ return match x:
+ Some(v) =>:
+ if v == 9:
+ return 1
+ return 0
+ none =>:
+ return 0
"""
# REP-2 边界(指针算术伪造地址,裁-REP-2 登记 + 探针):`p + 1` 落**非取址**槽——记录现实
# 行为(当前布局下 y 未受影响 ⇒ 6,双路径同)。本律不覆盖该面;
-A_REP2_PTRADD = """fn main() -> int { x : int? = 5; y : int? = 6; p := &x; q := p + 1; *q = 7; return match y { Some(v) => { return v; } None => { return 0; } }; }
+A_REP2_PTRADD = """fn main() -> int:
+ x : int? = 5
+ y : int? = 6
+ p := &x
+ q := p + 1
+ *q = 7
+ return match y:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# 负控:**非可选**取址槽不受本律影响(不装箱、值形态不变);第二例同时钉 ELF 全局取址修复
-A_NEG_NONOPT_LOCAL = """fn main() -> int { n : int, mut = 1; p := &n; *p = 5; return n; }
-"""
-A_NEG_NONOPT_GLOBAL = """g : int, mut = 1;
-fn main() -> int { p := &g; *p = 5; return g; }
+A_NEG_NONOPT_LOCAL = """fn main() -> int:
+ n : int, mut = 1
+ p := &n
+ *p = 5
+ return n
+"""
+A_NEG_NONOPT_GLOBAL = """g : int, mut = 1
+fn main() -> int:
+ p := &g
+ *p = 5
+ return g
"""
@@ -411,36 +809,139 @@ def case_evp(name, source, needles):
# 修法 = 字面量/切片两站点按「元素可选性」登记声明面 + LET/全局初值处**继承到绑定 var**
#(登记在**值 var** 上、写点读**绑定 var**——本修的关键一环);**写点零改动**。
# 全部 `g_optrep_on` 门控 + 仅可选元素登记 ⇒ 非可选程序/既有语料零足迹。
-T3_INFERRED_ARR_BARE = """fn main() -> int { a := [Some(1), None]; a[0] = 5; return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_INFERRED_ARR_LIT_IDX = """fn main() -> int { a := [Some(1), None]; a[1] = 5; return match a[1] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_INFERRED_IDENT_ELEM = """fn main() -> int { x : int? = 5; a := [x, None]; a[0] = 7; return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_MIXED_LIT = """fn main() -> int { a := [Some(1), 2]; a[0] = 7; return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_NONE_SLOT = """fn main() -> int { a := [Some(1), None]; a[1] = 8; return match a[1] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_INFERRED_SLICE = """fn main() -> int { a := [Some(1), None, Some(3), Some(4)]; s := a[0..4]; s[0] = 5; return match s[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_ANNOT_ARR_SLICE = """fn main() -> int { a : [int?;4] = [Some(0), None, Some(2), Some(3)]; s := a[0..4]; s[0] = 5; return match s[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_INFERRED_ARR_PTR = """fn main() -> int { a := [Some(1), None]; p := &a[0]; *p = 6; return match a[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_SLICE_OF_SLICE = """fn main() -> int { a : [int?;4] = [Some(0), None, Some(2), Some(3)]; s := a[0..4]; t := s[1..3]; t[0] = 5; return match t[0] { Some(v) => { return v; } None => { return 0; } }; }
+T3_INFERRED_ARR_BARE = """fn main() -> int:
+ a := [Some(1), none]
+ a[0] = 5
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_INFERRED_ARR_LIT_IDX = """fn main() -> int:
+ a := [Some(1), none]
+ a[1] = 5
+ return match a[1]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_INFERRED_IDENT_ELEM = """fn main() -> int:
+ x : int? = 5
+ a := [x, none]
+ a[0] = 7
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_MIXED_LIT = """fn main() -> int:
+ a := [Some(1), 2]
+ a[0] = 7
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_NONE_SLOT = """fn main() -> int:
+ a := [Some(1), none]
+ a[1] = 8
+ return match a[1]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_INFERRED_SLICE = """fn main() -> int:
+ a := [Some(1), none, Some(3), Some(4)]
+ s := a[0..4]
+ s[0] = 5
+ return match s[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_ANNOT_ARR_SLICE = """fn main() -> int:
+ a : [int?;4] = [Some(0), none, Some(2), Some(3)]
+ s := a[0..4]
+ s[0] = 5
+ return match s[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_INFERRED_ARR_PTR = """fn main() -> int:
+ a := [Some(1), none]
+ p := &a[0]
+ *p = 6
+ return match a[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_SLICE_OF_SLICE = """fn main() -> int:
+ a : [int?;4] = [Some(0), none, Some(2), Some(3)]
+ s := a[0..4]
+ t := s[1..3]
+ t[0] = 5
+ return match t[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
"""
# 对照(修复前即正确,防回退):标注数组动态下标 / 标注切片形参 / 装箱写 / 只读
-T3_ANNOT_ARR_DYN = """fn main() -> int { a : [int?;2] = [Some(1), None]; i := 0; a[i] = 5; return match a[i] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_PARAM_SLICE = """fn f(s: [int?;4]) -> int { s[0] = 5; return match s[0] { Some(v) => { return v; } None => { return 0; } }; }
-fn main() -> int { a : [int?;4] = [Some(0), None, Some(2), Some(3)]; return f(a[0..4]); }
-"""
-T3_SLICE_BOXED = """fn main() -> int { a : [int?;4] = [Some(0), None, Some(2), Some(3)]; s := a[0..4]; s[0] = Some(6); return match s[0] { Some(v) => { return v; } None => { return 0; } }; }
-"""
-T3_READ_ONLY = """fn main() -> int { a := [Some(1), None, Some(3), Some(4)]; s := a[1..3]; return match s[0] { Some(v) => { return v; } None => { return 9; } }; }
+T3_ANNOT_ARR_DYN = """fn main() -> int:
+ a : [int?;2] = [Some(1), none]
+ i := 0
+ a[i] = 5
+ return match a[i]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_PARAM_SLICE = """fn f(s: [int?;4]) -> int:
+ s[0] = 5
+ return match s[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+fn main() -> int:
+ a : [int?;4] = [Some(0), none, Some(2), Some(3)]
+ return f(a[0..4])
+"""
+T3_SLICE_BOXED = """fn main() -> int:
+ a : [int?;4] = [Some(0), none, Some(2), Some(3)]
+ s := a[0..4]
+ s[0] = Some(6)
+ return match s[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 0
+"""
+T3_READ_ONLY = """fn main() -> int:
+ a := [Some(1), none, Some(3), Some(4)]
+ s := a[1..3]
+ return match s[0]:
+ Some(v) =>:
+ return v
+ none =>:
+ return 9
"""
# 负控:**非可选**推断数组写点不受本律影响(不装箱、值形态不变)
-T3_NEG_NONOPT = """fn main() -> int { a := [1, 2]; a[0] = 5; return a[0]; }
+T3_NEG_NONOPT = """fn main() -> int:
+ a := [1, 2]
+ a[0] = 5
+ return a[0]
"""
@@ -462,32 +963,31 @@ def main():
# 口径:TF01 是**软诊断**(本仓库硬门名单只含 R002/TK05-06/TS01-04/TK02/TM03,
# build 路径 rc=0 + 产物照出)⇒ 判据走 `check`(有诊断即 rc=1)+ 措辞断言。
case_reject("optional_not_assignable_to_plain",
- "fn f(x: int?) -> int { return x; }\nfn main() -> int { return f(1); }\n",
+ "fn f(x: int?) -> int:\n return x\nfn main() -> int:\n return f(1)\n",
["error[TF01]"], cmd="check"),
# 硬门:T? 的 match 缺 None 臂 ⇒ TM03 + 具体反例名('None')+ 无产物
case_reject("optional_match_missing_none",
- "fn main() -> int { x: int? = Some(3); return match x { Some(v) => v, }; }\n",
+ "fn main() -> int:\n x: int? = Some(3)\n return match x:\n Some(v) => v,\n",
["error[TM03]", "missing variant 'None'"]),
# 硬门:T? 的 match 缺 Some 臂 ⇒ TM03 + 'Some'
case_reject("optional_match_missing_some",
- "fn main() -> int { x: int? = Some(3); return match x { None => 0, }; }\n",
+ "fn main() -> int:\n x: int? = Some(3)\n return match x:\n none => 0,\n",
["error[TM03]", "missing variant 'Some'"]),
# 正:通配臂吸收 ⇒ 穷尽(零诊断)
case_dual("optional_match_wildcard",
- "fn main() -> int { x: int? = None; return match x { _ => 9, }; }\n", 9),
+ "fn main() -> int:\n x: int? = none\n return match x:\n _ => 9,\n", 9),
# 负:退役内建 Option 注册——`Option` 不再是语言内建类型名。
# 旧行为:collect_decls 自动注册命名行 ⇒ `Option[int]` 零诊断通过;新行为:该名未声明
# ⇒ `Undefined type in generic application`(EC_N_GENERIC_TYPE,**软诊断**:rc 面
# build 仍 0——故判据走 `check` 的 rc=1 + 措辞)。用户自声明 `enum Option` 时按普通
# 枚举解析(Task 3 的 p20 语义保持,见 test_match_exhaust.py)。
case_reject("builtin_option_name_retired",
- "fn f(x: Option[int]) -> int { return 0; }\nfn main() -> int { return f(0); }\n",
+ "fn f(x: Option[int]) -> int:\n return 0\nfn main() -> int:\n return f(0)\n",
["Undefined type in generic application"], cmd="check"),
# 登记:载荷类型节点列入库(每槽有节点 = bad=0)+ 裸码列丢失真实类型的信息量
# (`V(S)` 命名类型载荷与 `Some(T)` 泛型形参载荷在裸码列都塌缩为 0 = TY_INT)
case_evp("payload_type_nodes_recorded",
- "struct S { a: int }\nenum E { V(S), W(int) }\nenum Opt[T] { N, Some(T) }\n"
- "fn main() -> int { return 0; }\n",
+ "struct S:\n a: int\nenum E:\n V(S), W(int)\nenum Opt[T]:\n N, Some(T)\nfn main() -> int:\n return 0\n",
["[enum-payload-verify]", "slots=3", "collapses=2", "bad=0"]),
# ── R2 P4 Task 5:解包侧判表示(B.7 四形态;修复前多个形态双路径 139)──
diff --git a/tests/selfhost/test_params_limit.py b/tests/selfhost/test_params_limit.py
index d7f4a433..44d1f489 100644
--- a/tests/selfhost/test_params_limit.py
+++ b/tests/selfhost/test_params_limit.py
@@ -108,15 +108,17 @@ def sum_src(n):
ps = ", ".join(f"a{i}: int" for i in range(n))
args = ", ".join(str(i + 1) for i in range(n))
body = " + ".join(f"a{i}" for i in range(n))
- return f"fn f({ps}) -> int {{\n return {body};\n}}\nfn main() -> int {{ return f({args}); }}\n"
+ return (f"fn f({ps}) -> int:\n return {body}\n"
+ f"fn main() -> int:\n return f({args})\n")
def per_arg_src(n):
"""逐形参值断言形(求和会掩盖错位/串位;任一错位返回该参数序号)。"""
ps = ", ".join(f"a{i}: int" for i in range(n))
args = ", ".join(str(i + 1) for i in range(n))
- checks = "\n".join(f" if a{i} != {i + 1} {{ return {i + 1}; }}" for i in range(n))
- return f"fn f({ps}) -> int {{\n{checks}\n return 0;\n}}\nfn main() -> int {{ return f({args}); }}\n"
+ checks = "\n".join(f" if a{i} != {i + 1}:\n return {i + 1}" for i in range(n))
+ return (f"fn f({ps}) -> int:\n{checks}\n return 0\n"
+ f"fn main() -> int:\n return f({args})\n")
def main():
diff --git a/tests/selfhost/test_pointer_safety.py b/tests/selfhost/test_pointer_safety.py
index ff170bc7..bcd1a9b6 100644
--- a/tests/selfhost/test_pointer_safety.py
+++ b/tests/selfhost/test_pointer_safety.py
@@ -84,135 +84,81 @@ def assert_accepted(src: str):
def test_out_of_bounds_load_is_rejected():
assert_rejected(
- "fn main() -> int {\n"
- " arr := [1];\n"
- " p := &arr[0] + 1;\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n arr := [1]\n p := &arr[0] + 1\n return *p\n",
"TK01",
)
def test_out_of_bounds_store_is_rejected():
assert_rejected(
- "fn main() -> int {\n"
- " arr := [1];\n"
- " p := &arr[0] + 1;\n"
- " *p = 2;\n"
- " return 0;\n"
- "}\n",
+ "fn main() -> int:\n arr := [1]\n p := &arr[0] + 1\n *p = 2\n return 0\n",
"TK01",
)
def test_deref_width_cannot_cross_allocation_end():
assert_rejected(
- "fn main() -> int {\n"
- " arr := [1, 2];\n"
- " p := (&arr[1]) as *[int; 2];\n"
- " wide := *p;\n"
- " return 0;\n"
- "}\n",
+ "fn main() -> int:\n arr := [1, 2]\n p := (&arr[1]) as *[int; 2]\n wide := *p\n return 0\n",
"TK01",
)
def test_in_bounds_type_pun_is_accepted():
assert_accepted(
- "fn main() -> int {\n"
- " arr := [1, 2];\n"
- " p := (&arr[0]) as *[int; 2];\n"
- " wide := *p;\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n arr := [1, 2]\n p := (&arr[0]) as *[int; 2]\n wide := *p\n return 0\n"
)
def test_external_pointer_requires_unsafe_for_load():
assert_rejected(
- "fn main() -> int {\n"
- " p := 4096 as *int;\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n p := 4096 as *int\n return *p\n",
"external pointer dereference requires unsafe",
)
def test_external_pointer_requires_unsafe_for_store():
assert_rejected(
- "fn main() -> int {\n"
- " p := 4096 as *int;\n"
- " *p = 1;\n"
- " return 0;\n"
- "}\n",
+ "fn main() -> int:\n p := 4096 as *int\n *p = 1\n return 0\n",
"external pointer dereference requires unsafe",
)
def test_indirect_external_pointer_requires_unsafe():
assert_rejected(
- "fn main() -> int {\n"
- " address := 4096;\n"
- " p := address as *int;\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n address := 4096\n p := address as *int\n return *p\n",
"external pointer dereference requires unsafe",
)
def test_external_pointer_arithmetic_preserves_address_space():
assert_rejected(
- "fn main() -> int {\n"
- " p := (4096 as *int) + 1;\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n p := (4096 as *int) + 1\n return *p\n",
"external pointer dereference requires unsafe",
)
def test_alloc_buffer_cast_remains_tracked():
assert_accepted(
- "fn main() -> int {\n"
- " raw := alloc(8);\n"
- " p := raw as *int;\n"
- " value := *p;\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n raw := alloc(8)\n p := raw as *int\n value := *p\n return 0\n"
)
def test_deref_loaded_int_is_not_pointer_escape():
"""A dereference result with integer type must not trigger pointer escape checks."""
assert_accepted(
- "fn main() -> int {\n"
- " value := 42;\n"
- " pointer := &value;\n"
- " loaded := *pointer;\n"
- " return loaded;\n"
- "}\n"
+ "fn main() -> int:\n value := 42\n pointer := &value\n loaded := *pointer\n return loaded\n"
)
def test_external_pointer_is_accepted_inside_unsafe():
assert_accepted(
- "fn main() -> int {\n"
- " unsafe {\n"
- " p := 4096 as *int;\n"
- " value := *p;\n"
- " }\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n unsafe:\n p := 4096 as *int\n value := *p\n return 0\n"
)
def test_dynamic_in_bounds_load_runs():
result = build_and_run(
- "fn main() -> int {\n"
- " arr := [10, 20];\n"
- " i := 1;\n"
- " p := &arr[i];\n"
- " return *p - 20;\n"
- "}\n"
+ "fn main() -> int:\n arr := [10, 20]\n i := 1\n p := &arr[i]\n return *p - 20\n"
)
assert result.returncode == 0, (
f"in-bounds pointer load trapped: {result.returncode} "
@@ -222,13 +168,7 @@ def test_dynamic_in_bounds_load_runs():
def test_dynamic_in_bounds_store_runs():
result = build_and_run(
- "fn main() -> int {\n"
- " arr := [10, 20];\n"
- " i := 1;\n"
- " p := &arr[i];\n"
- " *p = 21;\n"
- " return *p - 21;\n"
- "}\n"
+ "fn main() -> int:\n arr := [10, 20]\n i := 1\n p := &arr[i]\n *p = 21\n return *p - 21\n"
)
assert result.returncode == 0, (
f"in-bounds pointer access trapped: {result.returncode} "
@@ -238,39 +178,21 @@ def test_dynamic_in_bounds_store_runs():
def test_dynamic_out_of_bounds_load_traps():
result = build_and_run(
- "fn main() -> int {\n"
- " arr := [10, 20];\n"
- " i := 2;\n"
- " p := &arr[i];\n"
- " return *p;\n"
- "}\n"
+ "fn main() -> int:\n arr := [10, 20]\n i := 2\n p := &arr[i]\n return *p\n"
)
assert result.returncode != 0, "out-of-bounds load executed successfully"
def test_dynamic_out_of_bounds_store_traps():
result = build_and_run(
- "fn main() -> int {\n"
- " arr := [10, 20];\n"
- " i := 2;\n"
- " p := &arr[i];\n"
- " *p = 30;\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n arr := [10, 20]\n i := 2\n p := &arr[i]\n *p = 30\n return 0\n"
)
assert result.returncode != 0, "out-of-bounds store executed successfully"
def test_dynamic_multi_target_pointer_is_rejected():
assert_rejected(
- "fn main() -> int {\n"
- " left := [10, 20];\n"
- " right := [30, 40];\n"
- " i := 1;\n"
- " p : ., mut = &left[i];\n"
- " p = &right[i];\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n left := [10, 20]\n right := [30, 40]\n i := 1\n p : ., mut = &left[i]\n p = &right[i]\n return *p\n",
"multiple allocation targets",
)
diff --git a/tests/selfhost/test_raw_int_ptr.py b/tests/selfhost/test_raw_int_ptr.py
index 6c765672..addb0dd7 100644
--- a/tests/selfhost/test_raw_int_ptr.py
+++ b/tests/selfhost/test_raw_int_ptr.py
@@ -56,23 +56,21 @@
# ⇒ 它的前提被**直接推翻**。按「改前提、不删断言」:**同形源码改判为正钉**(见下 `REF_OK`),
# **并补一个真该被拒的形态填空**(`optional` = `int?`,实测 `rc=1 TF07×1` ✓;`tuple` 亦实测被拒,取一即可)。
NEG = {
- "string": 'fn main() -> int { s := "hi"; return @raw_int(s); }\n',
- "bool": "fn main() -> int { b := true; return @raw_int(b); }\n",
- "array": "fn main() -> int { a := [1,2,3]; return @raw_int(a); }\n",
- "slice": "fn main() -> int { a := [1,2,3]; s := a[0..2]; return @raw_int(s); }\n",
- "optional": "fn main() -> int { x : int? = None; return @raw_int(x); }\n",
- "struct": "struct S { v: int }\n"
- "fn main() -> int { s : ., mut = S { v = 1 }; return @raw_int(s); }\n",
+ "string": 'fn main() -> int:\n s := "hi"\n return @raw_int(s)\n',
+ "bool": "fn main() -> int:\n b := true\n return @raw_int(b)\n",
+ "array": "fn main() -> int:\n a := [1,2,3]\n return @raw_int(a)\n",
+ "slice": "fn main() -> int:\n a := [1,2,3]\n s := a[0..2]\n return @raw_int(s)\n",
+ "optional": "fn main() -> int:\n x : int? = none\n return @raw_int(x)\n",
+ "struct": "struct S:\n v: int\nfn main() -> int:\n s : ., mut = S { v = 1 }\n return @raw_int(s)\n",
}
# **正钉(S2 新增)**:原 `ref_type` 负控的**同形源码**改判——`TYP_REF` **必须被接受**。
REF_OK = {
- "ref_type": "fn f(r: &int) -> int { return @raw_int(r); }\n"
- "fn main() -> int { x : ., mut = 1; return f(&x); }\n",
+ "ref_type": "fn f(r: &int) -> int:\n return @raw_int(r)\nfn main() -> int:\n x : ., mut = 1\n return f(&x)\n",
}
# 既有被接受形态(放宽不得把它们弄坏;两向钉子)
POS_FORMS = {
- "dex": "fn main() -> int { d : dex, mut = 1.5; return @raw_int(d); }\n",
- "int": "fn main() -> int { n : ., mut = 7; return @raw_int(n); }\n",
+ "dex": "fn main() -> int:\n d : dex, mut = 1.5\n return @raw_int(d)\n",
+ "int": "fn main() -> int:\n n : ., mut = 7\n return @raw_int(n)\n",
}
diff --git a/tests/selfhost/test_region_cfg.py b/tests/selfhost/test_region_cfg.py
index db20f7d0..cb9fa2f2 100644
--- a/tests/selfhost/test_region_cfg.py
+++ b/tests/selfhost/test_region_cfg.py
@@ -63,32 +63,32 @@ def assert_region_within_func(out: str, name: str, tail: bool = True):
return a, b, fs, fe
def test_if_region():
- out = cir_dump("fn f(x: int) -> int {\n if x > 0 { return 1; }\n return 0;\n}\nfn main() -> int { return f(1); }\n")
+ out = cir_dump("fn f(x: int) -> int:\n if x > 0:\n return 1\n return 0\nfn main() -> int:\n return f(1)\n")
assert 'Region: if' in out, f"SG_IF region missing in cir dump:\n{out}"
assert 'Region: func' in out, f"SG_FUNC region not labeled in cir dump:\n{out}"
assert_region_within_func(out, 'if')
def test_loop_region():
- out = cir_dump("fn main() -> int {\n s : ., mut = 0;\n for i in 0..3 { s = s + i; }\n return s;\n}\n")
+ out = cir_dump("fn main() -> int:\n s : ., mut = 0\n for i in 0..3:\n s = s + i\n return s\n")
assert 'Region: for' in out, f"SG_FOR region missing in cir dump:\n{out}"
assert 'Region: func' in out, f"SG_FUNC region not labeled in cir dump:\n{out}"
assert_region_within_func(out, 'for')
def test_node_region_mapping():
- out = cir_dump("fn main() -> int {\n s : ., mut = 0;\n for i in 0..3 { s = s + i; }\n return s;\n}\n")
+ out = cir_dump("fn main() -> int:\n s : ., mut = 0\n for i in 0..3:\n s = s + i\n return s\n")
# DOT cluster grouping: the for region's nodes appear in one cluster
assert 'cluster_for' in out, f"DOT region cluster missing:\n{out}"
def test_state_edges():
"""State edges (VSDG): side-effect chain + loop termination dependencies
must appear in the cir dump as 'state: nA -> nB' lines."""
- out = cir_dump("fn main() -> int {\n s : ., mut = 0;\n s = s + 1;\n s = s + 2;\n return s;\n}\n")
+ out = cir_dump("fn main() -> int:\n s : ., mut = 0\n s = s + 1\n s = s + 2\n return s\n")
assert re.search(r'state: n\d+ -> n\d+', out), f"state edges not shown in cir dump:\n{out}"
def test_loop_termination_edge():
"""A loop whose body has side effects must carry a termination dependency
from the last side-effect node to the loop exit node."""
- out = cir_dump("fn main() -> int {\n s : ., mut = 0;\n for i in 0..3 { s = s + i; }\n return s;\n}\n")
+ out = cir_dump("fn main() -> int:\n s : ., mut = 0\n for i in 0..3:\n s = s + i\n return s\n")
assert re.search(r'state: n\d+ -> n\d+', out), f"loop termination state edge missing in cir dump:\n{out}"
def _state_edges(out: str):
@@ -100,13 +100,7 @@ def test_termination_edge_source_guard():
SG_LOOP 循环体纯(无副作用)时,g_last_state_node 是循环前的 STORE——
源在 region 外,不得连终止边;且链头必须推进到 region exit 节点,
使循环后的 STORE 依赖循环终止(规格 §4.2:循环不终止则图不终止)。"""
- out = cir_dump("fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " s = s + 1;\n"
- " loop { break; }\n"
- " s = s + 2;\n"
- " return s;\n"
- "}\n")
+ out = cir_dump("fn main() -> int:\n s : ., mut = 0\n s = s + 1\n loop:\n break\n s = s + 2\n return s\n")
regs = parse_regions(out)
assert 'loop' in regs, f"loop region missing in cir dump:\n{out}"
a, b = regs['loop'][0]
@@ -127,12 +121,7 @@ def test_termination_edge_source_guard():
def test_termination_edge_source_in_region():
"""终止边源边界(正例):循环体有副作用时,终止边源必须在 region 内
(last side-effect node ∈ [NSTART, EXIT)),不能是 region 外的旧副作用。"""
- out = cir_dump("fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " s = s + 1;\n"
- " for i in 0..3 { s = s + i; }\n"
- " return s;\n"
- "}\n")
+ out = cir_dump("fn main() -> int:\n s : ., mut = 0\n s = s + 1\n for i in 0..3:\n s = s + i\n return s\n")
regs = parse_regions(out)
assert 'for' in regs, f"for region missing in cir dump:\n{out}"
a, b = regs['for'][0]
@@ -146,12 +135,7 @@ def test_termination_edge_source_in_region():
def test_while_region_and_termination_edge():
"""while 也必须有 SG_LOOP 区域,并把循环退出接入 state 链。"""
- out = cir_dump("fn main() -> int {\n"
- " n : ., mut = 0;\n"
- " while n < 5 { n = n + 1; }\n"
- " n = n + 1;\n"
- " return n;\n"
- "}\n")
+ out = cir_dump("fn main() -> int:\n n : ., mut = 0\n while n < 5:\n n = n + 1\n n = n + 1\n return n\n")
main_match = re.search(r'Function: main\n(.*?)(?=\nFunction: |\Z)', out, re.S)
assert main_match, f"main function missing in cir dump:\n{out}"
main_out = main_match.group(1)
@@ -175,21 +159,19 @@ def test_while_region_and_termination_edge():
def test_for_loop_run():
"""for 循环在解释器中正确执行并返回累加和(TODO #2026-07-25-1 回归用例)"""
r = subprocess.run(['./build/corec', 'run',
- 'fn main() -> int { s : ., mut = 0; for i in 0..4 { s = s + i; } return s; }'],
+ 'fn main() -> int:\n s : ., mut = 0\n for i in 0..4:\n s = s + i\n return s\n'],
capture_output=True, text=True, cwd=BASE, timeout=30)
assert r.returncode == 6, f"for loop expected 6, got exit={r.returncode} stdout={r.stdout!r} stderr={r.stderr!r}"
def test_while_loop_run():
r = subprocess.run(['./build/corec', 'run',
- 'fn main() -> int { n : ., mut = 0; while n < 5 { n = n + 1; } return n; }'],
+ 'fn main() -> int:\n n : ., mut = 0\n while n < 5:\n n = n + 1\n return n\n'],
capture_output=True, text=True, cwd=BASE, timeout=30)
assert r.returncode == 5, f"while loop expected 5, got exit={r.returncode} stdout={r.stdout!r} stderr={r.stderr!r}"
def test_while_break_continue_run():
r = subprocess.run(['./build/corec', 'run',
- 'fn main() -> int { n : ., mut = 0; s : ., mut = 0; '
- 'while n < 10 { n = n + 1; if n < 3 { continue; } '
- 'if n == 6 { break; } s = s + n; } return s; }'],
+ 'fn main() -> int:\n n : ., mut = 0\n s : ., mut = 0\n while n < 10:\n n = n + 1\n if n < 3:\n continue\n if n == 6:\n break\n s = s + n\n return s\n'],
capture_output=True, text=True, cwd=BASE, timeout=30)
assert r.returncode == 12, \
f"while break/continue expected 12, got exit={r.returncode} stdout={r.stdout!r} stderr={r.stderr!r}"
@@ -197,25 +179,21 @@ def test_while_break_continue_run():
def test_inline_callee_while_run():
"""内联 callee 的 while 必须更新局部状态并正常返回。"""
r = subprocess.run(['./build/corec', 'run',
- 'fn sum(n: int) -> int { s : ., mut = 0; '
- 'while n > 0 { s = s + n; n = n - 1; } return s; } '
- 'fn main() -> int { return sum(3); }'],
+ 'fn sum(n: int) -> int:\n s : ., mut = 0\n while n > 0:\n s = s + n\n n = n - 1\n return s\nfn main() -> int:\n return sum(3)\n'],
capture_output=True, text=True, cwd=BASE, timeout=10)
assert r.returncode == 6, \
f"inline callee while expected 6, got exit={r.returncode} stdout={r.stdout!r} stderr={r.stderr!r}"
def test_inline_callee_for_run():
r = subprocess.run(['./build/corec', 'run',
- 'fn sum() -> int { s : ., mut = 0; '
- 'for i in 0..4 { s = s + i; } return s; } '
- 'fn main() -> int { return sum(); }'],
+ 'fn sum() -> int:\n s : ., mut = 0\n for i in 0..4:\n s = s + i\n return s\nfn main() -> int:\n return sum()\n'],
capture_output=True, text=True, cwd=BASE, timeout=10)
assert r.returncode == 6, \
f"inline callee for expected 6, got exit={r.returncode} stdout={r.stdout!r} stderr={r.stderr!r}"
def test_break_continue_run():
r = subprocess.run(['./build/corec', 'run',
- 'fn main() -> int { s : ., mut = 0; for i in 0..10 { if i == 2 { continue; } if i == 6 { break; } s = s + i; } return s; }'],
+ 'fn main() -> int:\n s : ., mut = 0\n for i in 0..10:\n if i == 2:\n continue\n if i == 6:\n break\n s = s + i\n return s\n'],
capture_output=True, text=True, cwd=BASE, timeout=30)
assert r.returncode == 13, f"break/continue expected 13 (0+1+3+4+5), got exit={r.returncode} stdout={r.stdout!r} stderr={r.stderr!r}"
@@ -223,7 +201,7 @@ def test_nested_loop_run():
"""嵌套 for 循环:覆盖 innermost region 选择分支(e2 > cur_enter 路径)——
内层回跳必须命中内层 region enter,外层回跳必须命中外层 region enter。"""
r = subprocess.run(['./build/corec', 'run',
- 'fn main() -> int { s : ., mut = 0; for i in 0..3 { for j in 0..3 { s = s + 1; } } return s; }'],
+ 'fn main() -> int:\n s : ., mut = 0\n for i in 0..3:\n for j in 0..3:\n s = s + 1\n return s\n'],
capture_output=True, text=True, cwd=BASE, timeout=30)
assert r.returncode == 9, f"nested loop expected 9 (3x3), got exit={r.returncode} stdout={r.stdout!r} stderr={r.stderr!r}"
@@ -299,7 +277,7 @@ def body(tag):
def test_ccr_v6_reg_section():
""".ccr 序列化 v7 段表架构(Task 1 机械更新;R2 P6 Task 3 起 version==9,
8 段):REG 段(tag 5)含 func+for 两个 region"""
- src = "fn main() -> int {\n s : ., mut = 0;\n for i in 0..3 { s = s + i; }\n return s;\n}\n"
+ src = "fn main() -> int:\n s : ., mut = 0\n for i in 0..3:\n s = s + i\n return s\n"
with tempfile.NamedTemporaryFile('w', suffix='.cr', delete=False) as f:
f.write(src)
path = f.name
@@ -333,7 +311,7 @@ def test_ccr_writer_rejects_i32_overflow_inputs():
def test_ccr_roundtrip_v2():
"""save→load 往返守卫:v6 文件经 corearch 加载后 ELF 输出行为不变。
程序计算 0+1+2+3=6,ELF 运行时以 main 返回值为退出码。"""
- src = "fn main() -> int {\n s : ., mut = 0;\n for i in 0..4 { s = s + i; }\n return s;\n}\n"
+ src = "fn main() -> int:\n s : ., mut = 0\n for i in 0..4:\n s = s + i\n return s\n"
with tempfile.NamedTemporaryFile('w', suffix='.cr', delete=False) as f:
f.write(src)
path = f.name
@@ -383,7 +361,7 @@ def test_region_check_pointer_escape():
**⚠ 它不覆盖逃逸面**(该面零活覆盖,见上)——**勿据此断言「逃逸被检测」**;
也**不写**「输出 == ok」那种把「逃逸不报」固化成预期的断言(本仓纪律禁止)。
"""
- src = "fn bad() -> &int {\n x := 42;\n return &x;\n}\nfn main() -> int { return 0; }\n"
+ src = "fn bad() -> &int:\n x := 42\n return &x\nfn main() -> int:\n return 0\n"
with tempfile.NamedTemporaryFile('w', suffix='.cr', delete=False) as f:
f.write(src); path = f.name
r = subprocess.run(['./build/corec', 'check', path], capture_output=True, text=True,
@@ -399,7 +377,7 @@ def test_region_check_cache_hit():
"""RegionCheck 在缓存命中路径不回归:同路径第二次 build(全函数 cache hit)
不得因 g_df_node_region 未恢复而崩溃/误报。显式映射改造的回归守卫:
load_cir_cache 恢复节点时需同步写入 node→region 映射。"""
- src = "fn main() -> int {\n s : ., mut = 0;\n for i in 0..3 { s = s + i; }\n return s;\n}\n"
+ src = "fn main() -> int:\n s : ., mut = 0\n for i in 0..3:\n s = s + i\n return s\n"
with tempfile.NamedTemporaryFile('w', suffix='.cr', delete=False) as f:
f.write(src)
path = f.name
@@ -420,13 +398,7 @@ def test_region_check_cache_hit():
def test_nested_regions_cache_persist():
"""增量 .cir 命中必须恢复函数内的嵌套 SG,而不是只恢复 func region。"""
- src = ("fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " for i in 0..3 {\n"
- " for j in 0..2 { s = s + i + j; }\n"
- " }\n"
- " return s;\n"
- "}\n")
+ src = ("fn main() -> int:\n s : ., mut = 0\n for i in 0..3:\n for j in 0..2:\n s = s + i + j\n return s\n")
with tempfile.NamedTemporaryFile('w', suffix='.cr', delete=False) as f:
f.write(src)
path = f.name
@@ -455,7 +427,7 @@ def test_nested_regions_cache_persist():
def test_state_edges_cache_persist():
"""缓存命中路径不丢 state 边:同路径第二次 cir dump(cache hit)必须仍显示
state 边(cir_cache v2 边序列化带 kind 的回归守卫)"""
- src = "fn main() -> int {\n s : ., mut = 0;\n s = s + 1;\n s = s + 2;\n return s;\n}\n"
+ src = "fn main() -> int:\n s : ., mut = 0\n s = s + 1\n s = s + 2\n return s\n"
with tempfile.NamedTemporaryFile('w', suffix='.cr', delete=False) as f:
f.write(src)
path = f.name
diff --git a/tests/selfhost/test_region_escape.py b/tests/selfhost/test_region_escape.py
index bf26c60e..a7e74dff 100644
--- a/tests/selfhost/test_region_escape.py
+++ b/tests/selfhost/test_region_escape.py
@@ -113,17 +113,7 @@ def build_and_run(src: str, expect_rc: int = 0):
def test_p1_loop_alloc_deref_immediately_after_loop():
"""P1 边界格:循环内分配 → 循环后**紧邻**解引用(修前 rc=0 静默通过)。"""
assert_rejected(
- "fn main() -> int {\n"
- " seed := 0;\n"
- " p : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " p = &arr[0];\n"
- " i = i + 1;\n"
- " }\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n seed := 0\n p : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n p = &arr[0]\n i = i + 1\n return *p\n",
"error[B11]", "dangling pointer",
)
@@ -131,19 +121,7 @@ def test_p1_loop_alloc_deref_immediately_after_loop():
def test_p2_loop_alloc_deref_after_intervening_stmt():
"""P2 修前已能触发的格(隔一条语句)——防「改边界把老格弄丢」。"""
assert_rejected(
- "fn main() -> int {\n"
- " seed := 0;\n"
- " p : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " p = &arr[0];\n"
- " i = i + 1;\n"
- " }\n"
- " k := 1;\n"
- " k = k + 1;\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n seed := 0\n p : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n p = &arr[0]\n i = i + 1\n k := 1\n k = k + 1\n return *p\n",
"error[B11]", "dangling pointer",
)
@@ -157,20 +135,7 @@ def test_p3_return_escape_is_b010():
旧基(38e6c992)读数:同形 `-> *int` 版 = rc=1 但报 **B11**(码位错配);
新基线(仅 S6)= rc=0(只放宽 kind 不足以触发,边界缺陷仍在)。"""
assert_rejected(
- "fn make() -> &int {\n"
- " seed := 0;\n"
- " r : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " r = &arr[0];\n"
- " i = i + 1;\n"
- " }\n"
- " return r;\n"
- "}\n"
- "fn main() -> int {\n"
- " return 0;\n"
- "}\n",
+ "fn make() -> &int:\n seed := 0\n r : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n r = &arr[0]\n i = i + 1\n return r\nfn main() -> int:\n return 0\n",
"error[B10]", "region escape: returning pointer",
)
@@ -178,20 +143,7 @@ def test_p3_return_escape_is_b010():
def test_p4_store_escape_now_reachable():
"""P4 存储逃逸:修前判定值被整行丢弃 ⇒ 本形态 rc=0(检查从不触发)。"""
assert_rejected(
- "fn main() -> int {\n"
- " seed := 0;\n"
- " slot : ., mut = &seed;\n"
- " slotp := &slot;\n"
- " p : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " p = &arr[0];\n"
- " i = i + 1;\n"
- " }\n"
- " *slotp = p;\n"
- " return 0;\n"
- "}\n",
+ "fn main() -> int:\n seed := 0\n slot : ., mut = &seed\n slotp := &slot\n p : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n p = &arr[0]\n i = i + 1\n *slotp = p\n return 0\n",
"error[B11]", "store escape: storing pointer",
)
@@ -199,22 +151,7 @@ def test_p4_store_escape_now_reachable():
def test_p5_alloc_inside_if_inside_loop_escapes_loop():
"""P5 父链上溯:分配在 if 内、循环内 —— 归还它的是**循环**区(不是 if 区)。"""
assert_rejected(
- "fn main() -> int {\n"
- " seed := 0;\n"
- " p : ., mut = &seed;\n"
- " cond := 1;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " if cond == 1 {\n"
- " arr := [7, 8];\n"
- " p = &arr[0];\n"
- " }\n"
- " i = i + 1;\n"
- " }\n"
- " k := 1;\n"
- " k = k + 1;\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n seed := 0\n p : ., mut = &seed\n cond := 1\n i : ., mut = 0\n while i < 1:\n if cond == 1:\n arr := [7, 8]\n p = &arr[0]\n i = i + 1\n k := 1\n k = k + 1\n return *p\n",
"error[B11]", "dangling pointer",
)
@@ -222,25 +159,7 @@ def test_p5_alloc_inside_if_inside_loop_escapes_loop():
def test_p6_reassign_to_another_dead_pointer_still_reports():
"""P6 重赋值清除规则的**负控**:重赋的值本身也是死指针 ⇒ 不得清除、必须报。"""
assert_rejected(
- "fn main() -> int {\n"
- " seed := 0;\n"
- " p : ., mut = &seed;\n"
- " q : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " q = &arr[0];\n"
- " i = i + 1;\n"
- " }\n"
- " i = 0;\n"
- " while i < 1 {\n"
- " arr2 := [9, 9];\n"
- " p = &arr2[0];\n"
- " i = i + 1;\n"
- " }\n"
- " p = q;\n"
- " return *p;\n"
- "}\n",
+ "fn main() -> int:\n seed := 0\n p : ., mut = &seed\n q : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n q = &arr[0]\n i = i + 1\n i = 0\n while i < 1:\n arr2 := [9, 9]\n p = &arr2[0]\n i = i + 1\n p = q\n return *p\n",
"error[B11]", "dangling pointer",
)
@@ -249,17 +168,7 @@ def test_p7_build_face_is_hard_error_with_zero_artifact():
"""build 面同判:硬错 rc=1 且零产物(诊断不得只记录不拦截)。"""
with tempfile.NamedTemporaryFile("w", suffix=".cr", delete=False) as source:
source.write(
- "fn main() -> int {\n"
- " seed := 0;\n"
- " p : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " p = &arr[0];\n"
- " i = i + 1;\n"
- " }\n"
- " return *p;\n"
- "}\n"
+ "fn main() -> int:\n seed := 0\n p : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n p = &arr[0]\n i = i + 1\n return *p\n"
)
source_path = source.name
output_path = os.path.splitext(source_path)[0]
@@ -291,17 +200,7 @@ def test_p7_build_face_is_hard_error_with_zero_artifact():
def test_p9_ref_typed_dangling_deref_is_b011():
"""P9 同上但循环后解引用 ⇒ B11(REF 型走悬垂 DEREF 判定)。基线 rc=0。"""
assert_rejected(
- "fn main() -> int {\n"
- " seed := 0;\n"
- " r : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " r = &arr[0];\n"
- " i = i + 1;\n"
- " }\n"
- " return *r;\n"
- "}\n",
+ "fn main() -> int:\n seed := 0\n r : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n r = &arr[0]\n i = i + 1\n return *r\n",
"error[B11]", "dangling pointer",
)
@@ -314,15 +213,7 @@ def test_r1_function_level_alloc_may_be_returned():
形态同 P3 说明:本基上 `&local` 是 `TYP_REF`,`-> *int` 版是 TF01(与逃逸面无关)
⇒ 返回型写 `&int`。"""
assert_accepted(
- "fn make() -> &int {\n"
- " arr := [7, 8];\n"
- " k := 1;\n"
- " k = k + 1;\n"
- " return &arr[0];\n"
- "}\n"
- "fn main() -> int {\n"
- " return 0;\n"
- "}\n"
+ "fn make() -> &int:\n arr := [7, 8]\n k := 1\n k = k + 1\n return &arr[0]\nfn main() -> int:\n return 0\n"
)
@@ -330,18 +221,7 @@ def test_r2_if_branch_alloc_is_not_released_at_branch_end():
"""R2 if 型:EXPR_IF 只 sg_push/sg_pop、**不建 arena**(ir_gen.cr:2414/2437)
⇒ 分支后解引用合法。修前被误报 rc=1(本对照 = 修前实测的红态反例)。"""
src = (
- "fn main() -> int {\n"
- " seed := 0;\n"
- " p : ., mut = &seed;\n"
- " x := 1;\n"
- " if x == 1 {\n"
- " arr := [7, 8];\n"
- " p = &arr[0];\n"
- " }\n"
- " k := 1;\n"
- " k = k + 1;\n"
- " return *p - 7;\n"
- "}\n"
+ "fn main() -> int:\n seed := 0\n p : ., mut = &seed\n x := 1\n if x == 1:\n arr := [7, 8]\n p = &arr[0]\n k := 1\n k = k + 1\n return *p - 7\n"
)
assert_accepted(src)
# 运行期反证:内存确实没被归还 —— 读回的仍是 7(返回 0)。
@@ -351,20 +231,7 @@ def test_r2_if_branch_alloc_is_not_released_at_branch_end():
def test_r3_reassign_to_live_pointer_after_loop():
"""R3 重赋值型:循环后改指活对象,解引用合法(pts 流不敏感并集不得当事实用)。"""
src = (
- "fn main() -> int {\n"
- " seed := 5;\n"
- " p : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " p = &arr[0];\n"
- " i = i + 1;\n"
- " }\n"
- " p = &seed;\n"
- " k := 1;\n"
- " k = k + 1;\n"
- " return *p - 5;\n"
- "}\n"
+ "fn main() -> int:\n seed := 5\n p : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n p = &arr[0]\n i = i + 1\n p = &seed\n k := 1\n k = k + 1\n return *p - 5\n"
)
assert_accepted(src)
build_and_run(src, expect_rc=0)
@@ -373,17 +240,7 @@ def test_r3_reassign_to_live_pointer_after_loop():
def test_r4_use_inside_the_loop_stays_clean():
"""R4 循环内使用型:分配在循环内、使用也在循环内 ⇒ 合法。"""
src = (
- "fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " arr := [7, 8];\n"
- " p := &arr[0];\n"
- " s = s + *p;\n"
- " i = i + 1;\n"
- " }\n"
- " return s - 7;\n"
- "}\n"
+ "fn main() -> int:\n s : ., mut = 0\n i : ., mut = 0\n while i < 1:\n arr := [7, 8]\n p := &arr[0]\n s = s + *p\n i = i + 1\n return s - 7\n"
)
assert_accepted(src)
build_and_run(src, expect_rc=0)
@@ -392,49 +249,21 @@ def test_r4_use_inside_the_loop_stays_clean():
def test_r5_deref_loaded_int_is_not_pointer_escape():
"""R5 非指针面:deref 读出的 int 是普通数据,不做逃逸判定(既有回归钉子)。"""
assert_accepted(
- "fn main() -> int {\n"
- " value := 42;\n"
- " pointer := &value;\n"
- " loaded := *pointer;\n"
- " return loaded;\n"
- "}\n"
+ "fn main() -> int:\n value := 42\n pointer := &value\n loaded := *pointer\n return loaded\n"
)
def test_r6_store_of_live_pointer_stays_clean():
"""R6 存储逃逸反向对照:存入的指针仍活着 ⇒ 不得报(防存储检查「一律报」)。"""
assert_accepted(
- "fn main() -> int {\n"
- " seed := 0;\n"
- " slot : ., mut = &seed;\n"
- " slotp := &slot;\n"
- " p : ., mut = &seed;\n"
- " i : ., mut = 0;\n"
- " while i < 1 {\n"
- " i = i + 1;\n"
- " }\n"
- " k := 1;\n"
- " k = k + 1;\n"
- " p = &seed;\n"
- " *slotp = p;\n"
- " return 0;\n"
- "}\n"
+ "fn main() -> int:\n seed := 0\n slot : ., mut = &seed\n slotp := &slot\n p : ., mut = &seed\n i : ., mut = 0\n while i < 1:\n i = i + 1\n k := 1\n k = k + 1\n p = &seed\n *slotp = p\n return 0\n"
)
def test_r7_loop_without_heap_alloc_stays_clean():
"""R7 无堆分配面:循环内只有标量槽(IR_ALLOC 不参与 pts)⇒ 不得报。"""
assert_accepted(
- "fn main() -> int {\n"
- " s : ., mut = 0;\n"
- " i : ., mut = 0;\n"
- " while i < 3 {\n"
- " t := i + 1;\n"
- " s = s + t;\n"
- " i = i + 1;\n"
- " }\n"
- " return s - 6;\n"
- "}\n"
+ "fn main() -> int:\n s : ., mut = 0\n i : ., mut = 0\n while i < 3:\n t := i + 1\n s = s + t\n i = i + 1\n return s - 6\n"
)
diff --git a/tests/selfhost/test_s1p_liveness.py b/tests/selfhost/test_s1p_liveness.py
index aa8bad3e..bbe54331 100644
--- a/tests/selfhost/test_s1p_liveness.py
+++ b/tests/selfhost/test_s1p_liveness.py
@@ -52,55 +52,54 @@
]
# 活性命中探针:`b := bool` 传给 `a: int` 形参(非字面量 ⇒ 不被护栏③跳过)
-MISMATCH = """fn f(a: int) -> int { return a; }
-fn main() -> int {
- b := true;
- return f(b);
-}
+MISMATCH = """fn f(a: int) -> int:
+ return a
+fn main() -> int:
+ b := true
+ return f(b)
"""
-CLEAN = """fn g(a: int) -> int { return a + 1; }
-fn main() -> int {
- n := 41;
- return g(n);
-}
+CLEAN = """fn g(a: int) -> int:
+ return a + 1
+fn main() -> int:
+ n := 41
+ return g(n)
"""
-EXTERN = """extern fn putchar(c: int) -> int;
-fn main() -> int {
- b := true;
- return putchar(b);
-}
+EXTERN = """extern fn putchar(c: int) -> int
+fn main() -> int:
+ b := true
+ return putchar(b)
"""
# 护栏③:字面量多态(`f(3)` 必须**不**打点)
-LITERAL = """fn f(a: int) -> int { return a; }
-fn main() -> int {
- return f(3);
-}
+LITERAL = """fn f(a: int) -> int:
+ return a
+fn main() -> int:
+ return f(3)
"""
# 护栏⑥:元数不齐(含变参面)⇒ 静默跳过(**不打点**,且不得崩/挂)
-ARITY = """fn g2(a: int, b: int) -> int { return a + b; }
-fn main() -> int {
- c := true;
- return g2(c);
-}
+ARITY = """fn g2(a: int, b: int) -> int:
+ return a + b
+fn main() -> int:
+ c := true
+ return g2(c)
"""
# 护栏②:`None` → `T?` 必须**不**打点;对照腿(同一函数传 bool)**必须**打点
# ——对照腿是关键:它证明「调用本身到点」,否则 0 打点可能只是没覆盖。
-NONE_OPT = """fn h(o: int?) -> int { return 0; }
-fn main() -> int {
- return h(None);
-}
+NONE_OPT = """fn h(o: int?) -> int:
+ return 0
+fn main() -> int:
+ return h(none)
"""
-NONE_OPT_CTRL = """fn h(o: int?) -> int { return 0; }
-fn main() -> int {
- b := true;
- return h(b);
-}
+NONE_OPT_CTRL = """fn h(o: int?) -> int:
+ return 0
+fn main() -> int:
+ b := true
+ return h(b)
"""
# ✅ 覆盖面(2026-09-18 批 8(甲)刀 2 扩覆盖后**已翻**):方法调用 / 模块限定调用 / 枚举构造器
@@ -112,20 +111,25 @@
# ⚠ 两腿均用**非嵌套**形态(let 位):嵌套实参里的调用会被台账**打点两次**
# (**先于刀 2 存在**的既有缺陷:`g(f("hi"))` ⇒ ['f','f'],平铺 `g("hi")` ⇒ ['g'];pre/post 二进制同形 ⇒ 已登记)。
MODULE_GAP = """import fmt
-fn main() -> int { x := fmt.int_str("hi"); return 0; }
+fn main() -> int:
+ x := fmt.int_str("hi")
+ return 0
"""
-ENUM_GAP = """enum E { V(int) }
-fn main() -> int { e := V("hi"); return 0; }
+ENUM_GAP = """enum E:
+ V(int)
+fn main() -> int:
+ e := V("hi")
+ return 0
"""
-METHOD_GAP = """struct S { f: int }
-impl S {
- fn m(self: S, x: int) -> int { return x; }
-}
-fn main() -> int {
- b := true;
- s : ., mut = S { f = 0 };
- return s.m(b);
-}
+METHOD_GAP = """struct S:
+ f: int
+impl S:
+ fn m(self: S, x: int) -> int:
+ return x
+fn main() -> int:
+ b := true
+ s : ., mut = S { f = 0 }
+ return s.m(b)
"""
diff --git a/tests/selfhost/test_s1p_sentinel_skips.py b/tests/selfhost/test_s1p_sentinel_skips.py
index cc45431a..39b472a5 100644
--- a/tests/selfhost/test_s1p_sentinel_skips.py
+++ b/tests/selfhost/test_s1p_sentinel_skips.py
@@ -70,42 +70,44 @@ def write_probe(text):
A_DYN = """import fmt
-fn takes(s: string) -> int { return str_len(s); }
-fn main() -> int {
- x : dyn = 42;
- x = "hello";
- takes(x);
- return 0;
-}
+fn takes(s: string) -> int:
+ return str_len(s)
+fn main() -> int:
+ x : dyn = 42
+ x = "hello"
+ takes(x)
+ return 0
"""
B_GENERIC = """import fmt
-fn pair[A, B](a: A, b: B) -> int {
- if a != 1 { return 1; }
- if str_len(b) < 1 { return 1; }
- return 0;
-}
-fn main() -> int { return pair(1, "x") - 1; }
+fn pair[A, B](a: A, b: B) -> int:
+ if a != 1:
+ return 1
+ if str_len(b) < 1:
+ return 1
+ return 0
+fn main() -> int:
+ return pair(1, "x") - 1
"""
# ③ 非真空锚:**已定义的 int 变量**(绝不用未定义名——见模块注释末的警告)
C_REAL = """import fmt
-fn takes(s: string) -> int { return str_len(s); }
-fn main() -> int {
- n : int = 7;
- takes(n);
- return 0;
-}
+fn takes(s: string) -> int:
+ return str_len(s)
+fn main() -> int:
+ n : int = 7
+ takes(n)
+ return 0
"""
# ④ TI_NEVER:未定义名作实参(pre 记 1 行、post 应 0 行)
D_UNDEF = """import fmt
-fn takes(s: string) -> int { return str_len(s); }
-fn main() -> int {
- n := undef_fn();
- takes(n);
- return 0;
-}
+fn takes(s: string) -> int:
+ return str_len(s)
+fn main() -> int:
+ n := undef_fn()
+ takes(n)
+ return 0
"""
diff --git a/tests/selfhost/test_slice_bounds.py b/tests/selfhost/test_slice_bounds.py
index b44aa4eb..3cdb35a3 100644
--- a/tests/selfhost/test_slice_bounds.py
+++ b/tests/selfhost/test_slice_bounds.py
@@ -70,64 +70,62 @@ def main() -> int:
ok = [
# 运行时界 slice 越界读/写必须 trap
case("runtime_bounds_literal_index_oob_traps", """
-fn main() -> int {
- a : [int; 5] = [10, 20, 30, 40, 50];
- lo := 1; hi := 3;
- s := a[lo..hi];
- x := s[2];
- return x;
-}
+fn main() -> int:
+ a : [int; 5] = [10, 20, 30, 40, 50]
+ lo := 1
+ hi := 3
+ s := a[lo..hi]
+ x := s[2]
+ return x
""", SIGILL),
case("runtime_bounds_var_index_oob_traps", """
-fn main() -> int {
- a : [int; 5] = [10, 20, 30, 40, 50];
- lo := 1; hi := 3;
- s := a[lo..hi];
- i := 2;
- return s[i];
-}
+fn main() -> int:
+ a : [int; 5] = [10, 20, 30, 40, 50]
+ lo := 1
+ hi := 3
+ s := a[lo..hi]
+ i := 2
+ return s[i]
""", SIGILL),
case("runtime_bounds_store_oob_traps", """
-fn main() -> int {
- a : [int; 5] = [10, 20, 30, 40, 50];
- lo := 1; hi := 3;
- s := a[lo..hi];
- s[5] = 99;
- return 0;
-}
+fn main() -> int:
+ a : [int; 5] = [10, 20, 30, 40, 50]
+ lo := 1
+ hi := 3
+ s := a[lo..hi]
+ s[5] = 99
+ return 0
""", SIGILL),
# 空切片(len=0)任何访问都越界
case("empty_slice_index_traps", """
-fn main() -> int {
- a : [int; 5] = [10, 20, 30, 40, 50];
- lo := 2; hi := 2;
- s := a[lo..hi];
- return s[0];
-}
+fn main() -> int:
+ a : [int; 5] = [10, 20, 30, 40, 50]
+ lo := 2
+ hi := 2
+ s := a[lo..hi]
+ return s[0]
""", SIGILL),
# 合法访问不误伤:值必须正确(s[1] == 30)
case("runtime_bounds_in_bounds_load_ok", """
-fn main() -> int {
- a : [int; 5] = [10, 20, 30, 40, 50];
- lo := 1; hi := 3;
- s := a[lo..hi];
- return s[1];
-}
+fn main() -> int:
+ a : [int; 5] = [10, 20, 30, 40, 50]
+ lo := 1
+ hi := 3
+ s := a[lo..hi]
+ return s[1]
""", 30),
# 字面量界 slice 的既有守卫不回归
case("literal_bounds_oob_still_traps", """
-fn main() -> int {
- a : [int; 5] = [10, 20, 30, 40, 50];
- s := a[1..3];
- return s[2];
-}
+fn main() -> int:
+ a : [int; 5] = [10, 20, 30, 40, 50]
+ s := a[1..3]
+ return s[2]
""", SIGILL),
case("literal_bounds_in_bounds_ok", """
-fn main() -> int {
- a : [int; 5] = [10, 20, 30, 40, 50];
- s := a[1..3];
- return s[1];
-}
+fn main() -> int:
+ a : [int; 5] = [10, 20, 30, 40, 50]
+ s := a[1..3]
+ return s[1]
""", 30),
]
passed = sum(ok)
diff --git a/tests/selfhost/test_string_interp.py b/tests/selfhost/test_string_interp.py
index 96bb17bf..c52be453 100644
--- a/tests/selfhost/test_string_interp.py
+++ b/tests/selfhost/test_string_interp.py
@@ -35,9 +35,7 @@
COREC = os.environ.get("COREC_BIN") or str(BASE / "build" / "corec")
P21 = re.compile(r"error\[P21\]")
-PRELUDE = ('import io\nimport fmt\nstruct S { f: int }\n'
- 'fn f(v: int) -> int { return v * 3; }\n'
- 'fn g(s: string) -> int { return str_len(s); }\nfn f42(c: int) -> int { return 42; }\n')
+PRELUDE = ('import io\nimport fmt\nstruct S:\n f: int\nfn f(v: int) -> int:\n return v * 3\nfn g(s: string) -> int:\n return str_len(s)\nfn f42(c: int) -> int:\n return 42\n')
# (名, 串字面量, 期望值, 备注) —— 值 = **展开后**语义
VALUES = [
@@ -60,16 +58,11 @@
def build_run(lit, extra_prelude="", extra_body=""):
+ # ⚠ v4 迁移修复:`%s` **前不得有空格**——契约是「`extra_body` 自带缩进」(v3 形即
+ # `'%s'` 独占一行无缩进)。T6 迁移把它折成单行时误加了 4 空格 ⇒ `extra_body=""`(B 组
+ # 主路径)生成 8 空格缩进的 `return 0` ⇒ `error[P02]: unexpected dedent at top level`。
src = (PRELUDE + extra_prelude +
- 'fn main() -> int {\n'
- ' n := 7;\n'
- ' b := true;\n'
- ' str := "S";\n'
- ' s := "%s";\n'
- ' println(s);\n'
- '%s'
- ' return 0;\n'
- '}\n') % (lit, extra_body)
+ 'fn main() -> int:\n n := 7\n b := true\n str := "S"\n s := "%s"\n println(s)\n%s return 0\n') % (lit, extra_body)
with tempfile.NamedTemporaryFile("w", suffix=".cr", delete=False) as fh:
fh.write(src)
path = fh.name
@@ -104,9 +97,9 @@ def expect(name, cond, detail):
# A 解析完整性:插值**同一行**含 `}`/后续语句 ⇒ 不得 P21 级联,且同行后续语句仍生效
same_line = [
- ("same_line_return", 'fn main() -> int { s := "x=${7}"; return 7; }', 7),
- ("same_line_if", 'fn main() -> int { s := "A${7}"; if 1 == 1 { return 5; } return 0; }', 5),
- ("same_line_call", 'import io\nimport fmt\nfn main() -> int { println("n=${7}"); return 3; }', 3),
+ ("same_line_return", 'fn main() -> int:\n s := "x=${7}"\n return 7\n', 7),
+ ("same_line_if", 'fn main() -> int:\n s := "A${7}"\n if 1 == 1:\n return 5\n return 0\n', 5),
+ ("same_line_call", 'import io\nimport fmt\nfn main() -> int:\n println("n=${7}")\n return 3\n', 3),
]
for name, src, want_rc in same_line:
with tempfile.NamedTemporaryFile("w", suffix=".cr", delete=False) as fh:
@@ -134,7 +127,8 @@ def expect(name, cond, detail):
expect(f"B.{name}.value", val == want, f"得 {val!r}(build_rc={rc})")
# B' 实参位 / let 初值(位置形态)
- rc, val, p21, out = build_run("v=${n}", extra_body=' println(int_str(g(s)));\n')
+ # ⚠ v4 迁移修复:载荷去 v3 语句分号(v4 语句尾 `;` ⇒ `Unexpected token in expression`)。
+ rc, val, p21, out = build_run("v=${n}", extra_body=' println(int_str(g(s)))\n')
last = (val or "").splitlines()[-1] if val else None
print(f"[B arg_position] 串作实参 g(s) ⇒ 末行={last}(整输出=[{val}])build_rc={rc}")
expect("B.arg_position", last == "3", f"得 {val!r}(期望末行 3 = 'v=7' 长度)")
@@ -150,8 +144,7 @@ def expect(name, cond, detail):
]
# 泛型洞(真泛型上下文;洞型在实例化前不可得 ⇒ P028 + 未覆盖面)
with tempfile.NamedTemporaryFile("w", suffix=".cr", delete=False) as fh:
- fh.write(PRELUDE + 'fn h[T](x: T) -> string { return "${x}"; }\n'
- 'fn main() -> int { return 0; }\n')
+ fh.write(PRELUDE + 'fn h[T](x: T) -> string:\n return "${x}"\nfn main() -> int:\n return 0\n')
gpath = fh.name
gout = str(BASE / "build" / f"_interp_{uuid.uuid4().hex[:8]}")
try:
@@ -169,9 +162,9 @@ def expect(name, cond, detail):
os.unlink(q)
for name, lit, code, note in errs:
- pre = " d : dex = 1.5;\n db : dex, apx = 1.5;\n t : int = 7;\n"
+ pre = " d : dex = 1.5\n db : dex, apx = 1.5\n t : int = 7\n"
with tempfile.NamedTemporaryFile("w", suffix=".cr", delete=False) as fh:
- fh.write(PRELUDE + 'fn main() -> int {\n n := 7;\n' + pre + f' s := "{lit}";\n return 0;\n}}\n')
+ fh.write(PRELUDE + 'fn main() -> int:\n n := 7\n' + pre + f' s := "{lit}"\n return 0\n')
path = fh.name
out = str(BASE / "build" / f"_interp_{uuid.uuid4().hex[:8]}")
try:
@@ -192,7 +185,7 @@ def expect(name, cond, detail):
sys.path.insert(0, str(BASE / "bootstrap"))
try:
from corec.frontend.lexer import Lexer
- toks = Lexer('s := "x=${n}";').tokenize()
+ toks = Lexer('s := "x=${n}"\n').tokenize()
lexeme = [t.lexeme for t in toks if getattr(t.type, "name", "") == "STRING_LIT"]
print(f"[D bootstrap 面] lexeme={lexeme}(**未展开**:本批只改自举前端;分歧已登记)")
expect("D.bootstrap_unexpanded_fact", lexeme == ["x=${n}"], f"得 {lexeme}")
diff --git a/tests/selfhost/test_tc02_branch.py b/tests/selfhost/test_tc02_branch.py
index 165116a6..4a49f90d 100644
--- a/tests/selfhost/test_tc02_branch.py
+++ b/tests/selfhost/test_tc02_branch.py
@@ -50,54 +50,45 @@ def check_src(src: str):
# ── 正控:期望**无诊断**(rc=0) ──────────────────────────────────────
CASES_OK = [
("tc02_else_return_silenced",
- "fn main() -> int {\n if 1 < 2 { } else { return 1; }\n return 0;\n}\n"),
+ "fn main() -> int:\n if 1 < 2:\n else:\n return 1\n return 0\n"),
("tc02_else_return_after_stmt",
- "fn main() -> int {\n if 1 < 2 { } else { x := 1; return x; }\n return 0;\n}\n"),
+ "fn main() -> int:\n if 1 < 2:\n else:\n x := 1\n return x\n return 0\n"),
("tc02_loop_control_unchanged",
- "fn main() -> int {\n if 1 < 2 { } else { loop { } }\n return 0;\n}\n"),
+ "fn main() -> int:\n if 1 < 2:\n else:\n loop:\n return 0\n"),
("tc02_bare_return_unchanged",
- "fn main() -> int {\n if 1 < 2 { } else { return; }\n return 0;\n}\n"),
+ "fn main() -> int:\n if 1 < 2:\n else:\n return\n return 0\n"),
("tf01_fallthrough_still_exempt",
- "fn f() -> int { loop { } }\nfn main() -> int { return f(); }\n"),
+ "fn f() -> int:\n loop:\nfn main() -> int:\n return f()\n"),
("tc02_stmt_position_multi",
- "fn main() -> int {\n" +
- "".join(f" if 1.5 < 2.5 {{ }} else {{ return {i}; }}\n" for i in range(1, 7)) +
- " return 0;\n}\n"),
+ "fn main() -> int:\n" +
+ "".join(f" if 1.5 < 2.5:\n else:\n return {i}\n" for i in range(1, 7)) +
+ " return 0\n"),
]
# ── 负控/钉子:期望**仍报**(码 + rc=1) ─────────────────────────────
CASES_DIAG = [
("tc02_then_return_kept",
- "fn main() -> int {\n if 1 < 2 { return 1; } else { }\n return 0;\n}\n", ["TC02"]),
+ "fn main() -> int:\n if 1 < 2:\n return 1\n else:\n return 0\n", ["TC02"]),
("tc02_true_mismatch_kept",
- "fn main() -> int {\n if 1 < 2 { 1 } else { \"s\" }\n return 0;\n}\n", ["TC02"]),
+ "fn main() -> int:\n if 1 < 2:\n 1\n else:\n \"s\"\n return 0\n", ["TC02"]),
("tf01_still_reported",
- "fn f() -> int { return \"s\"; }\nfn main() -> int { return f(); }\n", ["TF01"]),
+ "fn f() -> int:\n return \"s\"\nfn main() -> int:\n return f()\n", ["TF01"]),
("ta02_still_reported",
- "fn main() -> int {\n x : int = \"s\";\n return 0;\n}\n", ["TA02"]),
+ "fn main() -> int:\n x : int = \"s\"\n return 0\n", ["TA02"]),
("ta02_never_exempt_still",
- "fn main() -> int {\n x : int = nosuchname;\n return 0;\n}\n", ["N01"]),
+ "fn main() -> int:\n x : int = nosuchname\n return 0\n", ["N01"]),
("tb01_negative_ptr_add",
- "fn main() -> int {\n x : ., mut = 1;\n p := &x;\n q := &x;\n return p + q;\n}\n", ["TB01"]),
+ "fn main() -> int:\n x : ., mut = 1\n p := &x\n q := &x\n return p + q\n", ["TB01"]),
("tb01_negative_str_sub",
- "fn main() -> int {\n return \"a\" - \"b\";\n}\n", ["TB01"]),
+ "fn main() -> int:\n return \"a\" - \"b\"\n", ["TB01"]),
]
# ── 端到端:期望 build 成功 + 运行 rc=0(= test_native_float 两源同形) ──
CASES_RUN = [
("tc02_end2end_cmp",
- "fn main() -> int {\n"
- " if 1.5 < 2.5 { } else { return 1; }\n"
- " if 2.5 > 1.5 { } else { return 2; }\n"
- " if 1.5 <= 1.5 { } else { return 3; }\n"
- " return 0;\n}\n"),
+ "fn main() -> int:\n if 1.5 < 2.5:\n else:\n return 1\n if 2.5 > 1.5:\n else:\n return 2\n if 1.5 <= 1.5:\n else:\n return 3\n return 0\n"),
("tc02_end2end_arith",
- "fn main() -> int {\n"
- " x := 1.5;\n"
- " y := 2.5;\n"
- " if x + y == 4.0 { } else { return 1; }\n"
- " if x * y == 3.75 { } else { return 2; }\n"
- " return 0;\n}\n"),
+ "fn main() -> int:\n x := 1.5\n y := 2.5\n if x + y == 4.0:\n else:\n return 1\n if x * y == 3.75:\n else:\n return 2\n return 0\n"),
]
diff --git a/tests/selfhost/test_tf01_fallthrough.py b/tests/selfhost/test_tf01_fallthrough.py
index 1ab12d34..a73373e3 100644
--- a/tests/selfhost/test_tf01_fallthrough.py
+++ b/tests/selfhost/test_tf01_fallthrough.py
@@ -116,142 +116,137 @@ def case_run(name, source, expect_rc):
# ─── 正控:确定不能走完的体(修复前全报 TF01,修复后接受)───
POS_LOOP_IF_RETURN = """
-fn f() -> int {
- loop {
- if 1 > 0 { return 5; }
- }
-}
+fn f() -> int:
+ loop:
+ if 1 > 0:
+ return 5
"""
-POS_LOOP_BARE_RETURN = "fn f() -> int { loop { return 5; } }\n"
+POS_LOOP_BARE_RETURN = "fn f() -> int:\n loop:\n return 5\n"
# 嵌套 loop:内层 break 归内层 ⇒ 外层无直系 break ⇒ 永不落空
-POS_NESTED_LOOP = "fn f() -> int { loop { loop { break; } } }\n"
+POS_NESTED_LOOP = "fn f() -> int:\n loop:\n loop:\n break\n"
# if-else 双 diverges(两支皆无 break 的 loop ⇒ 两支类型均 unit ⇒ 修复前 TF01)
POS_IF_ELSE_DIVERGE = """
-fn f(c: int) -> int {
- if c > 0 { loop { if c > 100 { return 1; } } }
- else { loop { return 2; } }
-}
+fn f(c: int) -> int:
+ if c > 0:
+ loop:
+ if c > 100:
+ return 1
+ else:
+ loop:
+ return 2
"""
# 语句包裹(`loop {...};` = EXPR_STMT(EXPR_LOOP))
-POS_STMT_WRAPPED = "fn f() -> int { loop { return 5; }; }\n"
+POS_STMT_WRAPPED = "fn f() -> int:\n loop:\n return 5\n"
# alloc 的模型一致声明(string)——与本组同族:真错面的「正确写法」
-POS_ALLOC_STRING = "fn f() -> string { b := alloc(8); return b; }\n"
+POS_ALLOC_STRING = "fn f() -> string:\n b := alloc(8)\n return b\n"
# 遍历分支的牙(各自钉住 break 扫描的一个下钻面——删除对应分支即本档转红):
# · match 臂链(EXPR_ARM 链 ≠ 连续槽):臂内无 break ⇒ 外 loop 不落空
POS_MATCH_NO_BREAK = """
-fn f(x: int) -> int {
- loop {
- match x {
- 0 => { return 1; },
- _ => { return 2; }
- }
- }
-}
+fn f(x: int) -> int:
+ loop:
+ match x:
+ 0 =>:
+ return 1
+ ,
+ _ =>:
+ return 2
"""
# · 连续 wrapper 段(EXPR_ARRAY)+ LET + 索引
POS_ARRAY_NO_BREAK = """
-fn f() -> int {
- loop {
- a := [1, 2, 3];
- if a[0] > 0 { return 1; }
- }
-}
+fn f() -> int:
+ loop:
+ a := [1, 2, 3]
+ if a[0] > 0:
+ return 1
"""
# · 调用链(EXPR_CALL)与赋值/比较
POS_LOOP_WITH_CALL = """
-fn g(x: int) -> int { return x; }
-fn f() -> int {
- loop {
- if g(1) > 0 { return 5; }
- }
-}
+fn g(x: int) -> int:
+ return x
+fn f() -> int:
+ loop:
+ if g(1) > 0:
+ return 5
"""
# 登记边界(**本批显式登记,非静默**):非落空体内 return 的**值类型**不核对——
# checker 现模型无「逐 return 核对」面(站点 5 只看块末类型),本条只把「无 break 的
# loop 收尾」从 TF01 误报中解放。修复前该形因「末语句类型 = unit」被**误拒**;修复后
# 按新口径接受(loop 永不落空)。若未来引入逐 return 核对,本条期望随之改为拒。
-POS_BOUNDARY_NO_RETURN_VALUE_CHECK = "fn f() -> int { loop { return \"x\"; } }\n"
+POS_BOUNDARY_NO_RETURN_VALUE_CHECK = "fn f() -> int:\n loop:\n return \"x\"\n"
# ─── R2 P6 Task 4a(E-11):`-> never` 调用的返回型透传(TF01 面)───
# 改前(RED 实测):`return boom()` 的块类型 = 调用推断 = unit(声明注册域守卫
# checker.cr:1491 把 NEVER 钳成 unit)⇒ `body_ti != TI_NEVER` 成立(是 unit)⇒
# 误发 TF01;改后:调用推断 = never ⇒ 返回位豁免(checker.cr:2234)⇒ 接受。
-NEVER_RETURN_SRC = ("fn boom() -> never { loop { } }\n"
- "fn f() -> int { return boom(); }\n"
- "fn main() -> int { return f(); }\n")
+NEVER_RETURN_SRC = ("fn boom() -> never:\n loop:\nfn f() -> int:\n return boom()\nfn main() -> int:\n return f()\n")
# 变量传播面(与 test_iface_ops 的重钉项 t6_S1_never_unit 同源):`x` 绑定 = never
# ⇒ `return x` 的块类型 = never ⇒ 返回位豁免(改前 = unit ⇒ 误发 TF01)。
-NEVER_PROPAGATE_SRC = ("fn boom() -> never { loop { } }\n"
- "fn main() -> int { x := boom(); return x; }\n")
+NEVER_PROPAGATE_SRC = ("fn boom() -> never:\n loop:\nfn main() -> int:\n x := boom()\n return x\n")
# 端到端(发射面回归):分支不执行 ⇒ 运行 rc=42;改前 build rc=1(TA02 在硬名单 ⇒ 无产物)。
-RUN_NEVER_DEAD_BRANCH = ("fn boom() -> never { loop { } }\n"
- "fn main() -> int { if 1 > 2 { x : int = boom(); }\n"
- " return 42; }\n")
+RUN_NEVER_DEAD_BRANCH = ("fn boom() -> never:\n loop:\nfn main() -> int:\n if 1 > 2:\n x : int = boom()\n return 42\n")
# ─── 负控:可落空的体(修复前报 TF01,修复后**必须仍拒**——静默接受洞的钉子)───
-NEG_FALLTHRU = "fn f() -> int { 1 + 1; }\n"
+NEG_FALLTHRU = "fn f() -> int:\n 1 + 1\n"
-NEG_LOOP_BREAK = "fn f() -> int { loop { if 1 > 0 { break; } } }\n"
+NEG_LOOP_BREAK = "fn f() -> int:\n loop:\n if 1 > 0:\n break\n"
-NEG_IF_NO_ELSE = "fn f(c: int) -> int { if c > 0 { return 1; } }\n"
+NEG_IF_NO_ELSE = "fn f(c: int) -> int:\n if c > 0:\n return 1\n"
# match 臂内 break:臂 = EXPR_ARM 链(非连续槽)——漏检即此处从「拒」变「接受」
NEG_MATCH_BREAK = """
-fn f(x: int) -> int {
- loop {
- match x {
- 0 => { break; },
- _ => { }
- }
- }
-}
+fn f(x: int) -> int:
+ loop:
+ match x:
+ 0 =>:
+ break
+ ,
+ _ =>:
"""
# 数组字面量(连续 wrapper 段)后 break——段扫描漏检即此处变「接受」
NEG_ARRAY_BREAK = """
-fn f() -> int {
- loop {
- a := [1, 2, 3];
- if a[0] > 0 { break; }
- }
-}
+fn f() -> int:
+ loop:
+ a := [1, 2, 3]
+ if a[0] > 0:
+ break
"""
# 嵌套 loop 之后仍有**直系** break ⇒ 可退出(截断只对「不下钻」,不得漏扫本层其余语句)
-NEG_NESTED_THEN_BREAK = "fn f() -> int { loop { loop { break; } break; } }\n"
+NEG_NESTED_THEN_BREAK = "fn f() -> int:\n loop:\n loop:\n break\n break\n"
# while 保守面:不判 diverging(常量真条件不做分析)⇒ 落空 = 照旧 TF01。
# 条件用 `c == true` 而非裸标识符:`while c {` 会被 parser 当**结构体字面量**
# (parse_while_expr 缺 if 同款的 g_parse_no_struct_literal 守卫——既有面,本批不修,
# 见报告 §登记)。
-NEG_WHILE = "fn f(c: bool) -> int { while c == true { break; } }\n"
+NEG_WHILE = "fn f(c: bool) -> int:\n while c == true:\n break\n"
# 真错面:alloc → int 声明(类型洗白)——修复**不得**把这条一起「修掉」
-NEG_ALLOC_INT_WASH = "fn f() -> int { b := alloc(8); return b; }\n"
+NEG_ALLOC_INT_WASH = "fn f() -> int:\n b := alloc(8)\n return b\n"
# ─── 端到端:接受面的语义不受影响 ───
RUN_LOOP_NO_BREAK = """
-fn f() -> int {
- i : ., mut = 0;
- loop {
- i = i + 1;
- if i >= 3 { return i * 14; }
- }
-}
-fn main() -> int { return f(); }
+fn f() -> int:
+ i : ., mut = 0
+ loop:
+ i = i + 1
+ if i >= 3:
+ return i * 14
+fn main() -> int:
+ return f()
"""
diff --git a/tests/selfhost/test_toplevel_reject.py b/tests/selfhost/test_toplevel_reject.py
index cb0ac355..cc23064c 100644
--- a/tests/selfhost/test_toplevel_reject.py
+++ b/tests/selfhost/test_toplevel_reject.py
@@ -79,24 +79,24 @@ def run_case(name, source, expect_reject):
REJECTS = [
- ("stray_rbrace", "fn main() -> int { return 0; }\n}\n", "① 顶层多余 `}`(修前 check=0·build=0·运行 7)"),
- ("typo_struct", "stuct S { f: int }\nfn main() -> int { return 0; }\n", "② typo 声明(修前被无声丢弃)"),
- ("typo_struct_used", "stuct S { f: int }\nfn main() -> int { s := S { f: 1 }; return s.f; }\n",
+ ("stray_rbrace", "fn main() -> int:\n return 0\n}\n", "① 顶层多余 `}`(修前 check=0·build=0·运行 7)"),
+ ("typo_struct", "stuct S:\n f: int\nfn main() -> int:\n return 0\n", "② typo 声明(修前被无声丢弃)"),
+ ("typo_struct_used", "stuct S:\n f: int\nfn main() -> int:\n s := S { f = 1 }\n return s.f\n",
"③ 同上 + 使用(修前 TF01 误报 + 运行 139)"),
- ("stray_semi", ";\nfn main() -> int { return 0; }\n", "游离 `;`"),
- ("bogus_kw", "fnn main() -> int { return 0; }\n", "typo 关键字 `fnn`"),
+ ("stray_semi", ";\nfn main() -> int:\n return 0\n", "游离 `;`"),
+ ("bogus_kw", "fnn main() -> int:\n return 0\n", "typo 关键字 `fnn`"),
]
ACCEPTS = [
- ("import_io", 'import io\nfn main() -> int { println("hi"); return 0; }\n',
+ ("import_io", 'import io\nfn main() -> int:\n println("hi")\n return 0\n',
"合法 import(**本轮新修**:路径/别名 token 此前靠静默吞)"),
- ("import_alias", "import io : i\nfn main() -> int { return 0; }\n", "带别名 import"),
- ("global_no_init", "g : int, mut;\nfn main() -> int { g = 1; return g - 1; }\n",
+ ("import_alias", "import io : i\nfn main() -> int:\n return 0\n", "带别名 import"),
+ ("global_no_init", "g : int, mut\nfn main() -> int:\n g = 1\n return g - 1\n",
"无初值全局声明(注入运行时源 `rt.cr:4` 同形;此前靠静默吞)"),
- ("global_init", "g : int, mut = 2;\nfn main() -> int { return g - 2; }\n", "有初值全局声明"),
- ("mod_decl", "mod m;\nfn main() -> int { return 0; }\n", "`mod` 声明"),
- ("type_alias", "type T = int;\nfn main() -> int { x : T = 0; return x; }\n", "type 别名"),
- ("hotpatch_ann", "@hotpatch(ver=1)\nfn f() -> int { return 0; }\nfn main() -> int { return f(); }\n",
+ ("global_init", "g : int, mut = 2\nfn main() -> int:\n return g - 2\n", "有初值全局声明"),
+ ("mod_decl", "mod m\nfn main() -> int:\n return 0\n", "`mod` 声明"),
+ ("type_alias", "type T = int\nfn main() -> int:\n x : T = 0\n return x\n", "type 别名"),
+ ("hotpatch_ann", "@hotpatch(ver=1) fn f() -> int:\n return 0\nfn main() -> int:\n return f()\n",
"`@` 注解 + 函数"),
]
diff --git a/tests/selfhost/test_topt_pattern.py b/tests/selfhost/test_topt_pattern.py
index 9ff2f2d7..1ade0fab 100644
--- a/tests/selfhost/test_topt_pattern.py
+++ b/tests/selfhost/test_topt_pattern.py
@@ -41,62 +41,99 @@
BASE = Path(__file__).resolve().parents[2]
COREC = Path(os.environ.get("COREC_BIN", str(BASE / "build" / "corec")))
-PROBE_C6 = """fn g[T](t: T, x: T?) -> int { return 1; }
-fn main() -> int { d : dex, apx = 7.0; return g(d, d); }
+PROBE_C6 = """fn g[T](t: T, x: T?) -> int:
+ return 1
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(d, d)
"""
-PROBE_C7 = """fn g2[T](x: T?) -> int { return 1; }
-fn main() -> int { d : dex, apx = 7.0; return g2(d); }
+PROBE_C7 = """fn g2[T](x: T?) -> int:
+ return 1
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g2(d)
"""
-PROBE_J = """fn g[T](x: T?, t: T) -> int { return 1; }
-fn main() -> int { d : dex, apx = 7.0; return g(d, d); }
+PROBE_J = """fn g[T](x: T?, t: T) -> int:
+ return 1
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(d, d)
"""
-PROBE_K = """fn g[T](x: T?, t: T) -> int { return 1; }
-fn main() -> int { d : dex, apx = 7.0; return g(Some(d), d); }
+PROBE_K = """fn g[T](x: T?, t: T) -> int:
+ return 1
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(Some(d), d)
"""
-PROBE_M = """fn g2[T](x: T?) -> int { return 1; }
-fn main() -> int { x : int = 3; return g2(x); }
+PROBE_M = """fn g2[T](x: T?) -> int:
+ return 1
+fn main() -> int:
+ x : int = 3
+ return g2(x)
"""
-PROBE_P0 = """fn g[T](t: T, x: T?) -> int {
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-fn main() -> int { d : dex, apx = 7.0; return g(1, d); }
+PROBE_P0 = """fn g[T](t: T, x: T?) -> int:
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g(1, d)
"""
-PROBE_G12 = """fn g12[T](t: T, x: dex) -> int { return @raw_int(x) / 1000000; }
-fn main() -> int { d : dex, apx = 7.0; return g12(1, d); }
+PROBE_G12 = """fn g12[T](t: T, x: dex) -> int:
+ return @raw_int(x) / 1000000
+fn main() -> int:
+ d : dex, apx = 7.0
+ return g12(1, d)
"""
# C7:T0 登记的同族 TF01 三例(根因 = 本刀;变异体 rc=1)
-PROBE_L = """fn g2[T](x: T?) -> int { return 1; }
-fn main() -> int { return g2(Some(3)); }
+PROBE_L = """fn g2[T](x: T?) -> int:
+ return 1
+fn main() -> int:
+ return g2(Some(3))
"""
-PROBE_B = """fn g2[T](x: T?) -> int { return 1; }
-fn main() -> int { x : int = 3; f := g2(x); return f; }
+PROBE_B = """fn g2[T](x: T?) -> int:
+ return 1
+fn main() -> int:
+ x : int = 3
+ f := g2(x)
+ return f
"""
-PROBE_E = """fn g2[T](x: T?) -> int { return 1; }
-fn main() -> int { x : int = 3; return g2(x); }
+PROBE_E = """fn g2[T](x: T?) -> int:
+ return 1
+fn main() -> int:
+ x : int = 3
+ return g2(x)
"""
-PROBE_F2 = """fn g2[T](x: T?) -> int { return 1; }
-fn main() -> int { x : int = 3; f := g2(x); return 0; }
+PROBE_F2 = """fn g2[T](x: T?) -> int:
+ return 1
+fn main() -> int:
+ x : int = 3
+ f := g2(x)
+ return 0
"""
# 实例键机械腿:C6 与 M 合用一档(`g[dex]` + `g2[int]`);C7 单档(`g2[dex]` + `_dxsc`)
-PROBE_KEYS = """fn g[T](t: T, x: T?) -> int { return 1; }
-fn g2[T](x: T?) -> int { return 1; }
-fn main() -> int {
- d : dex, apx = 7.0;
- a := g(d, d);
- b := g2(d);
- return a + b;
-}
+PROBE_KEYS = """fn g[T](t: T, x: T?) -> int:
+ return 1
+fn g2[T](x: T?) -> int:
+ return 1
+fn main() -> int:
+ d : dex, apx = 7.0
+ a := g(d, d)
+ b := g2(d)
+ return a + b
"""
diff --git a/tests/selfhost/test_tuple_slots.py b/tests/selfhost/test_tuple_slots.py
index 76e9fea9..4f02db5d 100644
--- a/tests/selfhost/test_tuple_slots.py
+++ b/tests/selfhost/test_tuple_slots.py
@@ -30,163 +30,151 @@
(
"compound elem same type accepted (F5 ①假拒回归)",
"""
-fn main() -> int {
- a : [int; 3] = [1, 2, 3];
- x : ., mut = (1, a);
- y : ., mut = (1, [1, 2, 3]);
- x = y;
- return 0;
-}
+fn main() -> int:
+ a : [int; 3] = [1, 2, 3]
+ x : ., mut = (1, a)
+ y : ., mut = (1, [1, 2, 3])
+ x = y
+ return 0
""",
"ACCEPT",
),
(
"compound elem diff type rejected (F5 ②soundness)",
"""
-fn h() -> int { return 5; }
-fn main() -> int {
- x : ., mut = (1, [1, 2, 3]);
- y : ., mut = (1, h());
- x = y;
- return 0;
-}
+fn h() -> int:
+ return 5
+fn main() -> int:
+ x : ., mut = (1, [1, 2, 3])
+ y : ., mut = (1, h())
+ x = y
+ return 0
""",
"TA01",
),
(
"compound elem length mismatch rejected (F5 ③N 面)",
"""
-fn main() -> int {
- x : ., mut = (1, [1, 2, 3]);
- y : ., mut = (1, [1, 2]);
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = (1, [1, 2, 3])
+ y : ., mut = (1, [1, 2])
+ x = y
+ return 0
""",
"LEN",
),
(
"both compound elems same type accepted",
"""
-fn main() -> int {
- x : ., mut = (1, [1, 2, 3]);
- y : ., mut = (2, [7, 8, 9]);
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = (1, [1, 2, 3])
+ y : ., mut = (2, [7, 8, 9])
+ x = y
+ return 0
""",
"ACCEPT",
),
(
"both compound elems diff elem type rejected",
"""
-fn main() -> int {
- x : ., mut = (1, [1, 2, 3]);
- y : ., mut = (2, ["a", "b", "c"]);
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = (1, [1, 2, 3])
+ y : ., mut = (2, ["a", "b", "c"])
+ x = y
+ return 0
""",
"TA01",
),
(
"array in first slot accepted (反证边界)",
"""
-fn main() -> int {
- a : [int; 3] = [1, 2, 3];
- x : ., mut = (a, 1);
- y : ., mut = ([1, 2, 3], 1);
- x = y;
- return 0;
-}
+fn main() -> int:
+ a : [int; 3] = [1, 2, 3]
+ x : ., mut = (a, 1)
+ y : ., mut = ([1, 2, 3], 1)
+ x = y
+ return 0
""",
"ACCEPT",
),
(
"single-node elems accepted (反证边界)",
"""
-fn main() -> int {
- a : [int; 3] = [1, 2, 3];
- x : ., mut = (1, a);
- y : ., mut = (1, a);
- x = y;
- return 0;
-}
+fn main() -> int:
+ a : [int; 3] = [1, 2, 3]
+ x : ., mut = (1, a)
+ y : ., mut = (1, a)
+ x = y
+ return 0
""",
"ACCEPT",
),
(
"single-node elems diff type rejected (反证边界)",
"""
-fn main() -> int {
- a : [int; 3] = [1, 2, 3];
- x : ., mut = (1, a);
- y : ., mut = (1, 5);
- x = y;
- return 0;
-}
+fn main() -> int:
+ a : [int; 3] = [1, 2, 3]
+ x : ., mut = (1, a)
+ y : ., mut = (1, 5)
+ x = y
+ return 0
""",
"TA01",
),
(
"ident elems length mismatch rejected",
"""
-fn main() -> int {
- a : [int; 3] = [1, 2, 3];
- b : [int; 4] = [1, 2, 3, 4];
- x : ., mut = (1, a);
- y : ., mut = (2, b);
- x = y;
- return 0;
-}
+fn main() -> int:
+ a : [int; 3] = [1, 2, 3]
+ b : [int; 4] = [1, 2, 3, 4]
+ x : ., mut = (1, a)
+ y : ., mut = (2, b)
+ x = y
+ return 0
""",
"LEN",
),
(
"nested tuple elems accepted",
"""
-fn main() -> int {
- x : ., mut = (1, (2, 3));
- y : ., mut = (1, (2, 3));
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = (1, (2, 3))
+ y : ., mut = (1, (2, 3))
+ x = y
+ return 0
""",
"ACCEPT",
),
(
"nested tuple arity mismatch rejected",
"""
-fn main() -> int {
- x : ., mut = (1, (2, 3));
- y : ., mut = (1, (2, 3, 4));
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = (1, (2, 3))
+ y : ., mut = (1, (2, 3, 4))
+ x = y
+ return 0
""",
"TA01",
),
(
"nested tuple vs int rejected",
"""
-fn main() -> int {
- x : ., mut = (1, (2, 3));
- y : ., mut = (1, 5);
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = (1, (2, 3))
+ y : ., mut = (1, 5)
+ x = y
+ return 0
""",
"TA01",
),
(
"nested tuple in first slot vs int rejected",
"""
-fn main() -> int {
- x : ., mut = ((2, 3), 1);
- y : ., mut = (5, 1);
- x = y;
- return 0;
-}
+fn main() -> int:
+ x : ., mut = ((2, 3), 1)
+ y : ., mut = (5, 1)
+ x = y
+ return 0
""",
"TA01",
),
@@ -194,11 +182,11 @@
# IR 路径冒烟:复合元素元组必须能过 ir_gen(wrapper 解引用 + 数组元素构造)
IR_SMOKE = """
-fn g() -> int { return 33; }
-fn main() -> int {
- t := (g() + 1, [10, 20, 30]);
- return 0;
-}
+fn g() -> int:
+ return 33
+fn main() -> int:
+ t := (g() + 1, [10, 20, 30])
+ return 0
"""
diff --git a/tests/selfhost/test_view_builtins.py b/tests/selfhost/test_view_builtins.py
index 430d6173..78fb4987 100644
--- a/tests/selfhost/test_view_builtins.py
+++ b/tests/selfhost/test_view_builtins.py
@@ -34,12 +34,13 @@
# ── 探针 ─────────────────────────────────────────────────────────────────────
# ok 腿:视图往返。42 既不是有效指针、也不是有效 intern 索引 ⇒ 「视图 = 换看法」成立才可能 = 42。
# (若实现里偷偷做了解引用/查表,本腿在任一运行期腿都会崩或给别的值。)
-VIEW_ROUNDTRIP = """fn main() -> int {
- p : ., mut = 42;
- q : ., mut = 0;
- unsafe { s := @str_of(p); q = @ptr_of(s); }
- return q;
-}
+VIEW_ROUNDTRIP = """fn main() -> int:
+ p : ., mut = 42
+ q : ., mut = 0
+ unsafe:
+ s := @str_of(p)
+ q = @ptr_of(s)
+ return q
"""
# 零代码生成(擦除):两侧**除函数体首行外逐字相同**,函数名/签名也相同
@@ -47,55 +48,58 @@
# ⚠ 对照必须**同处 `unsafe` 包络内**:实测 `unsafe { return p; }` 与 `return p;` 的 ELF **不同**
# (`.ccr` 差 +158B = SG_UNSAFE 区域元数据;那是区域面既有效应,与视图无关)⇒
# 跨包络对照测的是 `unsafe` 而不是视图。字符串侧同理用「往返三跳」对照「单跳」。
-ERASE_INT_VIEW = """fn f(p: int) -> int {
- unsafe { return @ptr_of(@str_of(p)); }
-}
-fn main() -> int { return f(42); }
+ERASE_INT_VIEW = """fn f(p: int) -> int:
+ unsafe:
+ return @ptr_of(@str_of(p))
+fn main() -> int:
+ return f(42)
"""
-ERASE_INT_PLAIN = """fn f(p: int) -> int {
- unsafe { return p; }
-}
-fn main() -> int { return f(42); }
+ERASE_INT_PLAIN = """fn f(p: int) -> int:
+ unsafe:
+ return p
+fn main() -> int:
+ return f(42)
"""
-ERASE_STR_VIEW = """fn f(s: string) -> int {
- unsafe { return @ptr_of(@str_of(@ptr_of(s))); }
-}
-fn main() -> int { return f("hi") / 1000000000; }
+ERASE_STR_VIEW = """fn f(s: string) -> int:
+ unsafe:
+ return @ptr_of(@str_of(@ptr_of(s)))
+fn main() -> int:
+ return f("hi") / 1000000000
"""
-ERASE_STR_ONE = """fn f(s: string) -> int {
- unsafe { return @ptr_of(s); }
-}
-fn main() -> int { return f("hi") / 1000000000; }
+ERASE_STR_ONE = """fn f(s: string) -> int:
+ unsafe:
+ return @ptr_of(s)
+fn main() -> int:
+ return f("hi") / 1000000000
"""
# 安全面 (ii):块外 ⇒ 两面都硬错
-OUTSIDE_UNSAFE = """fn main() -> int {
- p : ., mut = 42;
- s := @str_of(p);
- return 0;
-}
+OUTSIDE_UNSAFE = """fn main() -> int:
+ p : ., mut = 42
+ s := @str_of(p)
+ return 0
"""
# fail-closed③:未知名 ⇒ 两面都报错
-UNKNOWN_BUILTIN = """fn main() -> int {
- p : ., mut = 42;
- unsafe { q := @view_of(p); }
- return 0;
-}
+UNKNOWN_BUILTIN = """fn main() -> int:
+ p : ., mut = 42
+ unsafe:
+ q := @view_of(p)
+ return 0
"""
# 实参类型:`@ptr_of` 只收 string、`@str_of` 只收 int
-ARG_TYPE_PTR = """fn main() -> int {
- p : ., mut = 42;
- unsafe { n := @ptr_of(p); }
- return 0;
-}
+ARG_TYPE_PTR = """fn main() -> int:
+ p : ., mut = 42
+ unsafe:
+ n := @ptr_of(p)
+ return 0
"""
-ARG_TYPE_STR = """fn main() -> int {
- s := "hi";
- unsafe { n := @str_of(s); }
- return 0;
-}
+ARG_TYPE_STR = """fn main() -> int:
+ s := "hi"
+ unsafe:
+ n := @str_of(s)
+ return 0
"""
diff --git a/tests/selfhost/test_xcut_iface.py b/tests/selfhost/test_xcut_iface.py
index 7ea8f8bf..b2ce47ab 100644
--- a/tests/selfhost/test_xcut_iface.py
+++ b/tests/selfhost/test_xcut_iface.py
@@ -124,100 +124,89 @@ def case_reject(name, source, needles, soft):
# ─── 正例(三路同证):形状接管的三个结果分支 + range 产视图 ───
ARR_INDEX = """
-fn main() -> int {
- a := [10, 20, 30];
- return a[1];
-}
+fn main() -> int:
+ a := [10, 20, 30]
+ return a[1]
"""
SLICE_INDEX = """
-fn main() -> int {
- a := [10, 20, 30];
- s := a[0..3];
- return s[2];
-}
+fn main() -> int:
+ a := [10, 20, 30]
+ s := a[0..3]
+ return s[2]
"""
STR_INDEX = """
-fn main() -> int {
- s := "AB";
- return s[0];
-}
+fn main() -> int:
+ s := "AB"
+ return s[0]
"""
RANGE_ARRAY_SLICE = """
-fn main() -> int {
- a := [1, 2, 3, 4];
- s := a[1..3];
- return s[0];
-}
+fn main() -> int:
+ a := [1, 2, 3, 4]
+ s := a[1..3]
+ return s[0]
"""
RANGE_FULL_ARRAY = """
-fn main() -> int {
- a := [7, 8];
- s := a[0..2];
- return s[1];
-}
+fn main() -> int:
+ a := [7, 8]
+ s := a[0..2]
+ return s[1]
"""
# ─── 负例(收紧面同址;行为保持:改动前后同拒同码)──
INT_INDEX = """
-fn main() -> int {
- x := 5;
- return x[0];
-}
+fn main() -> int:
+ x := 5
+ return x[0]
"""
BOOL_INDEX = """
-fn main() -> int {
- b := true;
- return b[0];
-}
+fn main() -> int:
+ b := true
+ return b[0]
"""
PTR_INDEX = """
-fn main() -> int {
- x := 7;
- p := &x;
- return p[0];
-}
+fn main() -> int:
+ x := 7
+ p := &x
+ return p[0]
"""
STRUCT_INDEX = """
-struct S { a: int }
-fn main() -> int {
- s := S{a: 1};
- return s[0];
-}
+struct S:
+ a: int
+fn main() -> int:
+ s := S{a= 1}
+ return s[0]
"""
# ─── 结果分支/表示面钉子(行为保持:既有诊断与 range 结果形态逐字不变)──
OOB_LITERAL = """
-fn main() -> int {
- a := [1, 2];
- return a[5];
-}
+fn main() -> int:
+ a := [1, 2]
+ return a[5]
"""
SLICE_BOUNDS = """
-fn main() -> int {
- a := [1, 2, 3];
- s := a[0..5];
- return 0;
-}
+fn main() -> int:
+ a := [1, 2, 3]
+ s := a[0..5]
+ return 0
"""
# range 的**切片**分支现状 = `TI_UNIT`(A.2 #15 登记:IP_INDEX_RANGE 未接线)⇒ 二次切片当下
# 不可索引(TK01)。本钉即 range 分支固定性维度的咬合面:若丢掉固定性(切片 range 改产视图),
# 本例转 rc=0 = 静默放宽 ⇒ 红。
SLICE_RANGE_UNIT = """
-fn main() -> int {
- a := [1, 2, 3, 4];
- s := a[0..4];
- t := s[0..2];
- return t[0];
-}
+fn main() -> int:
+ a := [1, 2, 3, 4]
+ s := a[0..4]
+ t := s[0..2]
+ return t[0]
"""
diff --git a/tests/spec/README.md b/tests/spec/README.md
index c37f00ea..d101be35 100644
--- a/tests/spec/README.md
+++ b/tests/spec/README.md
@@ -1,7 +1,7 @@
# 规约语法判据语料(批 6:正式规约语法 `#check` / `#ensure`)
**性质**:**是**编译单元(由 `tests/selfhost/test_spec_grammar.py` 逐档驱动:`build --static`,
-负例断言 rc=1 + 诊断码 + **零产物**)。**不进**腿①(`tools/baseline/parity_run.sh`,74→75 档)与
+负例断言 rc=1 + 诊断码 + **零产物**)。**不进**腿①(`tools/baseline/parity_run.sh`,76 档)与
腿②(`tests/probes/`,29 档)两套语料——那两套是**既有行为回归网**,其**计数不变**本身就是
「本批对旧面零扰动」的最强证据(维护者 2026-09-17 确认)。
diff --git a/tests/spec/delta_d0_annot.cr b/tests/spec/delta_d0_annot.cr
index be518759..8133029f 100644
--- a/tests/spec/delta_d0_annot.cr
+++ b/tests/spec/delta_d0_annot.cr
@@ -1,4 +1,11 @@
-fn check(x: bool) -> bool { return x; }
-fn g() -> bool { return true; }
-fn f(a: int) -> int #check(true) { return a; }
-fn main() -> int { if check(g()) { return f(1); } return 0; }
+fn check(x: bool) -> bool:
+ return x
+fn g() -> bool:
+ return true
+fn f(a: int) -> int:
+ #check(true)
+ return a
+fn main() -> int:
+ if check(g()):
+ return f(1)
+ return 0
diff --git a/tests/spec/delta_d0_plain.cr b/tests/spec/delta_d0_plain.cr
index 010d7a2a..7f6e8d06 100644
--- a/tests/spec/delta_d0_plain.cr
+++ b/tests/spec/delta_d0_plain.cr
@@ -1,4 +1,10 @@
-fn check(x: bool) -> bool { return x; }
-fn g() -> bool { return true; }
-fn f(a: int) -> int { return a; }
-fn main() -> int { if check(g()) { return f(1); } return 0; }
+fn check(x: bool) -> bool:
+ return x
+fn g() -> bool:
+ return true
+fn f(a: int) -> int:
+ return a
+fn main() -> int:
+ if check(g()):
+ return f(1)
+ return 0
diff --git a/tests/spec/delta_d9_annot.cr b/tests/spec/delta_d9_annot.cr
index ed5babe7..ce3204e1 100644
--- a/tests/spec/delta_d9_annot.cr
+++ b/tests/spec/delta_d9_annot.cr
@@ -1,2 +1,5 @@
-fn f(a: int) -> int #check(1 > 0) { return a; }
-fn main() -> int { return f(1); }
+fn f(a: int) -> int:
+ #check(1 > 0)
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/delta_d9_plain.cr b/tests/spec/delta_d9_plain.cr
index 5349a5f5..ad77fa94 100644
--- a/tests/spec/delta_d9_plain.cr
+++ b/tests/spec/delta_d9_plain.cr
@@ -1,2 +1,4 @@
-fn f(a: int) -> int { return a; }
-fn main() -> int { return f(1); }
+fn f(a: int) -> int:
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t2_neg_after.cr b/tests/spec/t2_neg_after.cr
index 7c3d88cf..e225195b 100644
--- a/tests/spec/t2_neg_after.cr
+++ b/tests/spec/t2_neg_after.cr
@@ -1,2 +1,5 @@
-fn f() -> int { return 1; } #check(1 > 0)
-fn main() -> int { return f(); }
+fn f() -> int:
+ return 1
+#check(1 > 0)
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_before.cr b/tests/spec/t2_neg_before.cr
index c3c8f333..691ade0d 100644
--- a/tests/spec/t2_neg_before.cr
+++ b/tests/spec/t2_neg_before.cr
@@ -1,2 +1,4 @@
-#check(1 > 0) fn f() -> int { return 1; }
-fn main() -> int { return f(); }
+#check(1 > 0) fn f() -> int:
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_collide.cr b/tests/spec/t2_neg_collide.cr
index cae127c1..240cd197 100644
--- a/tests/spec/t2_neg_collide.cr
+++ b/tests/spec/t2_neg_collide.cr
@@ -1,3 +1,6 @@
-fn check(x: bool) -> bool { return x; }
-fn f() -> int #check(1 < 0) { return 1; }
-fn main() -> int { return f(); }
+fn check(x: bool) -> bool:
+ return x
+fn f() -> int #check(1 < 0):
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_constfalse.cr b/tests/spec/t2_neg_constfalse.cr
index eb3b72ed..f8453c46 100644
--- a/tests/spec/t2_neg_constfalse.cr
+++ b/tests/spec/t2_neg_constfalse.cr
@@ -1,2 +1,4 @@
-fn f() -> int #check(1 < 0) { return 1; }
-fn main() -> int { return f(); }
+fn f() -> int #check(1 < 0):
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_empty.cr b/tests/spec/t2_neg_empty.cr
index 65b683ef..6f1fdd90 100644
--- a/tests/spec/t2_neg_empty.cr
+++ b/tests/spec/t2_neg_empty.cr
@@ -1,2 +1,4 @@
-fn f() -> int #check() { return 1; }
-fn main() -> int { return f(); }
+fn f() -> int #check():
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_inbody.cr b/tests/spec/t2_neg_inbody.cr
index 27c10ef4..7b0fef3b 100644
--- a/tests/spec/t2_neg_inbody.cr
+++ b/tests/spec/t2_neg_inbody.cr
@@ -1,2 +1,4 @@
-fn f() -> int { #check(1 > 0) return 1; }
-fn main() -> int { return f(); }
+fn f() -> int:
+ #check(1 > 0) return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_nolparen.cr b/tests/spec/t2_neg_nolparen.cr
index 0f478dab..06a8c048 100644
--- a/tests/spec/t2_neg_nolparen.cr
+++ b/tests/spec/t2_neg_nolparen.cr
@@ -1,2 +1,4 @@
-fn f() -> int #check 1 { return 1; }
-fn main() -> int { return f(); }
+fn f() -> int #check 1:
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_nonident.cr b/tests/spec/t2_neg_nonident.cr
index 8642aa33..cd87d316 100644
--- a/tests/spec/t2_neg_nonident.cr
+++ b/tests/spec/t2_neg_nonident.cr
@@ -1,2 +1,4 @@
-fn f() -> int #1(1) { return 1; }
-fn main() -> int { return f(); }
+fn f() -> int #1(1):
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_stmt.cr b/tests/spec/t2_neg_stmt.cr
index 4738f645..b5bc6427 100644
--- a/tests/spec/t2_neg_stmt.cr
+++ b/tests/spec/t2_neg_stmt.cr
@@ -1,7 +1,8 @@
-fn g() -> int { return 3; }
-fn f() -> int {
- x := g();
+fn g() -> int:
+ return 3
+fn f() -> int:
+ x := g()
#check(1 > 0)
- return x;
-}
-fn main() -> int { return f(); }
+ return x
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_neg_unknowntag.cr b/tests/spec/t2_neg_unknowntag.cr
index 1da66e7b..b8443e08 100644
--- a/tests/spec/t2_neg_unknowntag.cr
+++ b/tests/spec/t2_neg_unknowntag.cr
@@ -1,2 +1,4 @@
-fn f() -> int #foo(1) { return 1; }
-fn main() -> int { return f(); }
+fn f() -> int #foo(1):
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_pos_check.cr b/tests/spec/t2_pos_check.cr
index f5e14198..0fb5a49b 100644
--- a/tests/spec/t2_pos_check.cr
+++ b/tests/spec/t2_pos_check.cr
@@ -1,6 +1,5 @@
-fn f() -> int
+fn f() -> int:
#check(1 >= 0)
-{
- return 1;
-}
-fn main() -> int { return f(); }
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_pos_dup.cr b/tests/spec/t2_pos_dup.cr
index 8ef26fb7..456883e0 100644
--- a/tests/spec/t2_pos_dup.cr
+++ b/tests/spec/t2_pos_dup.cr
@@ -1,2 +1,6 @@
-fn f() -> int #check(1 > 0) #check(1 > 0) { return 1; }
-fn main() -> int { return f(); }
+fn f() -> int:
+ #check(1 > 0)
+ #check(1 > 0)
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t2_pos_multi.cr b/tests/spec/t2_pos_multi.cr
index 43fddde3..b8b16cf7 100644
--- a/tests/spec/t2_pos_multi.cr
+++ b/tests/spec/t2_pos_multi.cr
@@ -1,8 +1,7 @@
-fn f(a: int) -> int
+fn f(a: int) -> int:
#check(a >= 0)
#check(a <= 100)
#ensure(result >= 0)
-{
- return a;
-}
-fn main() -> int { return f(7); }
+ return a
+fn main() -> int:
+ return f(7)
diff --git a/tests/spec/t2_pos_plain.cr b/tests/spec/t2_pos_plain.cr
index decb3ca7..5e469632 100644
--- a/tests/spec/t2_pos_plain.cr
+++ b/tests/spec/t2_pos_plain.cr
@@ -1,4 +1,4 @@
-fn f() -> int {
- return 1;
-}
-fn main() -> int { return f(); }
+fn f() -> int:
+ return 1
+fn main() -> int:
+ return f()
diff --git a/tests/spec/t3_neg_call_banned.cr b/tests/spec/t3_neg_call_banned.cr
index a1722d26..82697ef9 100644
--- a/tests/spec/t3_neg_call_banned.cr
+++ b/tests/spec/t3_neg_call_banned.cr
@@ -1,3 +1,6 @@
-fn helper(x: bool) -> bool { return x; }
-fn f(a: int) -> int #check(helper(true)) { return a; }
-fn main() -> int { return f(1); }
+fn helper(x: bool) -> bool:
+ return x
+fn f(a: int) -> int #check(helper(true)):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_neg_domain.cr b/tests/spec/t3_neg_domain.cr
index 667caf4e..4d4094d9 100644
--- a/tests/spec/t3_neg_domain.cr
+++ b/tests/spec/t3_neg_domain.cr
@@ -1,2 +1,4 @@
-fn f(a: int) -> int #check(nosuchvar > 0) { return a; }
-fn main() -> int { return f(1); }
+fn f(a: int) -> int #check(nosuchvar > 0):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_neg_dup_false.cr b/tests/spec/t3_neg_dup_false.cr
index f6dc3fe6..307c9576 100644
--- a/tests/spec/t3_neg_dup_false.cr
+++ b/tests/spec/t3_neg_dup_false.cr
@@ -1,7 +1,4 @@
-fn f(a: int) -> int
- #check(1 > 0)
- #check(1 < 0)
-{
- return a;
-}
-fn main() -> int { return f(1); }
+fn f(a: int) -> int #check(1 > 0) #check(1 < 0):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_neg_ensure_false.cr b/tests/spec/t3_neg_ensure_false.cr
index df1d6284..455ab767 100644
--- a/tests/spec/t3_neg_ensure_false.cr
+++ b/tests/spec/t3_neg_ensure_false.cr
@@ -1,2 +1,4 @@
-fn f(a: int) -> int #ensure(1 < 0) { return a; }
-fn main() -> int { return f(1); }
+fn f(a: int) -> int #ensure(1 < 0):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_neg_ensure_nonbool.cr b/tests/spec/t3_neg_ensure_nonbool.cr
index 3731413d..c2c7aa90 100644
--- a/tests/spec/t3_neg_ensure_nonbool.cr
+++ b/tests/spec/t3_neg_ensure_nonbool.cr
@@ -1,2 +1,4 @@
-fn f(a: int) -> int #ensure(result) { return a; }
-fn main() -> int { return f(1); }
+fn f(a: int) -> int #ensure(result):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_neg_nonbool.cr b/tests/spec/t3_neg_nonbool.cr
index 56604e36..2405fec3 100644
--- a/tests/spec/t3_neg_nonbool.cr
+++ b/tests/spec/t3_neg_nonbool.cr
@@ -1,2 +1,4 @@
-fn f(a: int) -> int #check(1) { return a; }
-fn main() -> int { return f(1); }
+fn f(a: int) -> int #check(1):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_neg_result_shadow.cr b/tests/spec/t3_neg_result_shadow.cr
index a9dcf93f..f39a454b 100644
--- a/tests/spec/t3_neg_result_shadow.cr
+++ b/tests/spec/t3_neg_result_shadow.cr
@@ -1,2 +1,4 @@
-fn f(result: int) -> int #ensure(result > 0) { return result; }
-fn main() -> int { return f(1); }
+fn f(result: int) -> int #ensure(result > 0):
+ return result
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_pos_both.cr b/tests/spec/t3_pos_both.cr
index 2d8342bd..664a361e 100644
--- a/tests/spec/t3_pos_both.cr
+++ b/tests/spec/t3_pos_both.cr
@@ -1,7 +1,6 @@
-fn f(a: int) -> int
+fn f(a: int) -> int:
#check(a >= 0)
#ensure(result > a)
-{
- return a + 1;
-}
-fn main() -> int { return f(1); }
+ return a + 1
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_pos_check_param.cr b/tests/spec/t3_pos_check_param.cr
index 5e42faa7..e472c833 100644
--- a/tests/spec/t3_pos_check_param.cr
+++ b/tests/spec/t3_pos_check_param.cr
@@ -1,6 +1,5 @@
-fn f(a: int) -> int
+fn f(a: int) -> int:
#check(a >= 0)
-{
- return a;
-}
-fn main() -> int { return f(1); }
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_pos_ensure_result.cr b/tests/spec/t3_pos_ensure_result.cr
index 9d0b664f..12951beb 100644
--- a/tests/spec/t3_pos_ensure_result.cr
+++ b/tests/spec/t3_pos_ensure_result.cr
@@ -1,6 +1,4 @@
-fn f(a: int) -> int
- #ensure(result >= 0)
-{
- return a;
-}
-fn main() -> int { return f(1); }
+fn f(a: int) -> int #ensure(result >= 0):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t3_pos_ensure_true.cr b/tests/spec/t3_pos_ensure_true.cr
index 31b5784d..486e99b1 100644
--- a/tests/spec/t3_pos_ensure_true.cr
+++ b/tests/spec/t3_pos_ensure_true.cr
@@ -1,6 +1,4 @@
-fn f(a: int) -> int
- #ensure(1 > 0)
-{
- return a;
-}
-fn main() -> int { return f(1); }
+fn f(a: int) -> int #ensure(1 > 0):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t4_three_states.cr b/tests/spec/t4_three_states.cr
index 00540218..1510f893 100644
--- a/tests/spec/t4_three_states.cr
+++ b/tests/spec/t4_three_states.cr
@@ -1,8 +1,4 @@
-fn f(a: int) -> int
- #check(1 > 0)
- #check(a >= 0)
- #check(1 < 0)
-{
- return a;
-}
-fn main() -> int { return f(1); }
+fn f(a: int) -> int #check(1 > 0) #check(a >= 0) #check(1 < 0):
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/spec/t4_xtalk.cr b/tests/spec/t4_xtalk.cr
index 8139b9ef..b43cb3f8 100644
--- a/tests/spec/t4_xtalk.cr
+++ b/tests/spec/t4_xtalk.cr
@@ -1,9 +1,14 @@
-struct A { v: int }
-struct B { v: int }
-impl A {
- fn get(self, alpha: int) -> int #check(alpha >= 0) { return self.v + alpha; }
-}
-impl B {
- fn get(self, beta: int) -> int #check(beta >= 0) { return self.v + beta; }
-}
-fn main() -> int { return A { v: 1 }.get(2); }
+struct A:
+ v: int
+struct B:
+ v: int
+impl A:
+ fn get(self, alpha: int) -> int:
+ #check(alpha >= 0)
+ return self.v + alpha
+impl B:
+ fn get(self, beta: int) -> int:
+ #check(beta >= 0)
+ return self.v + beta
+fn main() -> int:
+ return A { v= 1 }.get(2)
diff --git a/tests/spec/t4_yellow_only.cr b/tests/spec/t4_yellow_only.cr
index 5e42faa7..e472c833 100644
--- a/tests/spec/t4_yellow_only.cr
+++ b/tests/spec/t4_yellow_only.cr
@@ -1,6 +1,5 @@
-fn f(a: int) -> int
+fn f(a: int) -> int:
#check(a >= 0)
-{
- return a;
-}
-fn main() -> int { return f(1); }
+ return a
+fn main() -> int:
+ return f(1)
diff --git a/tests/suite/apx_conversion_test.cr b/tests/suite/apx_conversion_test.cr
index 1858b1e6..b9d2e49a 100644
--- a/tests/suite/apx_conversion_test.cr
+++ b/tests/suite/apx_conversion_test.cr
@@ -12,83 +12,104 @@
// `d : dex, apx = …`(类型位写 `.` 会让 apx 槽压根不建立 ⇒ 假绿)。
import dex
-struct S3 { f: dex }
+struct S3:
+ f: dex
-impl S3 {
- fn m(self: S3, x: dex) -> int { return @raw_int(x) / 1000000; }
-}
+impl S3:
+ fn m(self: S3, x: dex) -> int:
+ return @raw_int(x) / 1000000
-fn scaled7() -> dex { return 7.0; }
-g_apx : dex, apx, mut = scaled7();
-g_exact : dex, mut = scaled7();
+fn scaled7() -> dex:
+ return 7.0
+g_apx : dex, apx, mut = scaled7()
+g_exact : dex, mut = scaled7()
-fn main() -> int {
+fn main() -> int:
// 1. 方法调用实参(TODO #2026-09-16-17 原形)
- d : dex, apx = 7.0;
- s : ., mut = S3 { f = 0.0 };
- if s.m(d) != 7 { return 1; }
+ d : dex, apx = 7.0
+ s : ., mut = S3 { f = 0.0 }
+ if s.m(d) != 7:
+ return 1
// 2. 模块限定调用(apx 批 T2 新增活点;与直调同值对拍)
// ⚠ **必须先绑定到变量**:模块限定调用**直接作实参**(`str_eq(m.f(x), "y")`)在
// 本批起点即 **SIGSEGV 139**——**既有缺陷,非本批引入**(T3/T5 实测:T3 二进制、
// 预变更二进制、**冻结基线 97f4394f** 三者同崩)⇒ 见 TODO #2026-09-16-31;本档走绑定形。
- ma := dex.dex_str(d);
- me := dex_str(d);
- if !str_eq(ma, me) { return 2; }
- if !str_eq(ma, "7") { return 3; }
+ ma := dex.dex_str(d)
+ me := dex_str(d)
+ if !str_eq(ma, me):
+ return 2
+ if !str_eq(ma, "7"):
+ return 3
// 3. 结构体字面量字段 + 字段赋值
- f1 : ., mut = S3 { f = d };
- if @raw_int(f1.f) / 1000000 != 7 { return 4; }
- f1.f = d;
- if @raw_int(f1.f) / 1000000 != 7 { return 5; }
+ f1 : ., mut = S3 { f = d }
+ if @raw_int(f1.f) / 1000000 != 7:
+ return 4
+ f1.f = d
+ if @raw_int(f1.f) / 1000000 != 7:
+ return 5
// 4. 数组字面量元素 + 动态下标赋值
- a : [dex; 2] = [d, 1.0];
- if @raw_int(a[0]) / 1000000 != 7 { return 6; }
- i : ., mut = 1;
- a[i] = d;
- if @raw_int(a[i]) / 1000000 != 7 { return 7; }
+ a : [dex; 2] = [d, 1.0]
+ if @raw_int(a[0]) / 1000000 != 7:
+ return 6
+ i : ., mut = 1
+ a[i] = d
+ if @raw_int(a[i]) / 1000000 != 7:
+ return 7
// 5. 元组元素(数字下标须写 `t . 0`,带空格)
- t := (d, 1.0);
- if @raw_int(t . 0) / 1000000 != 7 { return 8; }
+ t := (d, 1.0)
+ if @raw_int(t . 0) / 1000000 != 7:
+ return 8
// 6. 指针写
- px : dex, mut = 1.0;
- p := &px;
- *p = d;
- if @raw_int(px) / 1000000 != 7 { return 9; }
+ px : dex, mut = 1.0
+ p := &px
+ *p = d
+ if @raw_int(px) / 1000000 != 7:
+ return 9
// 7. 全局运行期初值(⑦a;apx 全局须 mut)
- if @raw_int(g_apx) / 1000000 != 7 { return 10; }
- if @raw_int(g_exact) / 1000000 != 7 { return 11; }
+ if @raw_int(g_apx) / 1000000 != 7:
+ return 10
+ if @raw_int(g_exact) / 1000000 != 7:
+ return 11
// 8. 全局作方法实参(全局 vs 局部同形对拍)
- if s.m(g_apx) != 7 { return 12; }
+ if s.m(g_apx) != 7:
+ return 12
// 9. 比较点声明面查表(L10):聚合读 vs 精确值
- e : dex = 7.0;
- s9 : ., mut = S3 { f = 7.0 };
- if s9.f != e { return 13; }
+ e : dex = 7.0
+ s9 : ., mut = S3 { f = 7.0 }
+ if s9.f != e:
+ return 13
// 10. 枚举载荷
- if payload7(d) != 7 { return 14; }
+ if payload7(d) != 7:
+ return 14
// 11. 非回归:直调 + 泛型实例化 dex 形参
- if direct7(d) != 7 { return 15; }
- if generic7(1, d) != 7 { return 16; }
+ if direct7(d) != 7:
+ return 15
+ if generic7(1, d) != 7:
+ return 16
- return 0;
-}
+ return 0
-enum E1 { V(dex) }
+enum E1:
+ V(dex)
-fn payload7(d: dex) -> int {
- e := V(d);
- return match e { V(x) => { return @raw_int(x) / 1000000; } };
-}
+fn payload7(d: dex) -> int:
+ e := V(d)
+ return match e:
+ V(x) =>:
+ return @raw_int(x) / 1000000
-fn direct7(x: dex) -> int { return @raw_int(x) / 1000000; }
+fn direct7(x: dex) -> int:
+ return @raw_int(x) / 1000000
-fn generic7[T](t: T, x: dex) -> int { return @raw_int(x) / 1000000; }
+fn generic7[T](t: T, x: dex) -> int:
+ return @raw_int(x) / 1000000
diff --git a/tests/suite/arena_test.cr b/tests/suite/arena_test.cr
index 5f3c170b..5f6eadd6 100644
--- a/tests/suite/arena_test.cr
+++ b/tests/suite/arena_test.cr
@@ -5,84 +5,109 @@ import io
// Runtime globals (normally provided by rt.cr when --static is used)
// These are redeclared here so the test works without --static too.
-g_current_arena : int, mut = -1;
-g_arena_pool_data : string, mut;
-g_arena_free_list : int, mut = -1;
+g_current_arena : int, mut = -1
+g_arena_pool_data : string, mut
+g_arena_free_list : int, mut = -1
-fn test_arena_basic() -> int {
- arena_init(1048576, 65536); // 1MB pool, 64KB chunks
+fn test_arena_basic() -> int:
+ arena_init(1048576, 65536) // 1MB pool, 64KB chunks
// Create arena
- a1 := arena_new();
- if a1 < 0 { return 1; } // arena_new failed
- if g_current_arena != a1 { return 2; } // not activated
+ a1 := arena_new()
+ if a1 < 0:
+ return 1
+ // arena_new failed
+ if g_current_arena != a1:
+ return 2
+ // not activated
// Alloc should now use arena
- p := alloc(64);
- if p == 0 { return 3; } // alloc failed
+ p := alloc(64)
+ if p == 0:
+ return 3
+ // alloc failed
// Reset
- arena_reset(a1);
- if g_current_arena >= 0 { return 4; } // should be -1 after reset
+ arena_reset(a1)
+ if g_current_arena >= 0:
+ return 4
+ // should be -1 after reset
// Re-use arena from free list
- a2 := arena_new();
- if a2 != a1 { return 5; } // should reuse same ID
+ a2 := arena_new()
+ if a2 != a1:
+ return 5
+ // should reuse same ID
- arena_reset(a2);
- return 0; // pass
-}
+ arena_reset(a2)
+ return 0 // pass
-fn test_arena_nesting() -> int {
- arena_init(1048576, 65536);
+fn test_arena_nesting() -> int:
+ arena_init(1048576, 65536)
- a1 := arena_new(); // parent
- p1 := alloc(32);
- if p1 == 0 { return 1; }
+ a1 := arena_new() // parent
+ p1 := alloc(32)
+ if p1 == 0:
+ return 1
- a2 := arena_new(); // child (arena in loop)
- if g_current_arena != a2 { return 2; }
- p2 := alloc(64);
- if p2 == 0 { return 3; }
+ a2 := arena_new() // child (arena in loop)
+ if g_current_arena != a2:
+ return 2
+ p2 := alloc(64)
+ if p2 == 0:
+ return 3
// Child reset should restore parent
- arena_reset(a2);
- if g_current_arena != a1 { return 4; }
+ arena_reset(a2)
+ if g_current_arena != a1:
+ return 4
// Parent still works
- p3 := alloc(16);
- if p3 == 0 { return 5; }
+ p3 := alloc(16)
+ if p3 == 0:
+ return 5
- arena_reset(a1);
- return 0;
-}
+ arena_reset(a1)
+ return 0
-fn test_arena_free_list_reuse() -> int {
- arena_init(1048576, 65536);
+fn test_arena_free_list_reuse() -> int:
+ arena_init(1048576, 65536)
// Allocate multiple arenas
- a1 := arena_new(); arena_reset(a1);
- a2 := arena_new(); arena_reset(a2);
- a3 := arena_new(); arena_reset(a3);
+ a1 := arena_new()
+ arena_reset(a1)
+ a2 := arena_new()
+ arena_reset(a2)
+ a3 := arena_new()
+ arena_reset(a3)
// Next new should reuse a3 (LIFO free list)
- a4 := arena_new();
- if a4 != a3 { return 1; } // should reuse most recently freed
-
- arena_reset(a4);
- return 0;
-}
-
-fn main() -> int {
- r1 := test_arena_basic();
- if r1 != 0 { print("FAIL basic: "); println(int_str(r1)); return r1; }
-
- r2 := test_arena_nesting();
- if r2 != 0 { print("FAIL nesting: "); println(int_str(r2)); return r2; }
-
- r3 := test_arena_free_list_reuse();
- if r3 != 0 { print("FAIL freelist: "); println(int_str(r3)); return r3; }
-
- println("ALL PASS");
- return 0;
-}
+ a4 := arena_new()
+ if a4 != a3:
+ return 1
+ // should reuse most recently freed
+
+ arena_reset(a4)
+ return 0
+
+fn main() -> int:
+ r1 := test_arena_basic()
+ if r1 != 0:
+ print("FAIL basic: ")
+ println(int_str(r1))
+ return r1
+
+ r2 := test_arena_nesting()
+ if r2 != 0:
+ print("FAIL nesting: ")
+ println(int_str(r2))
+ return r2
+
+ r3 := test_arena_free_list_reuse()
+ if r3 != 0:
+ print("FAIL freelist: ")
+ println(int_str(r3))
+ return r3
+
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test.cr b/tests/suite/at_test.cr
index befd4d25..c3378819 100644
--- a/tests/suite/at_test.cr
+++ b/tests/suite/at_test.cr
@@ -1,73 +1,107 @@
// @ builtins test suite
import io
-fn test_sizeof_int() -> int {
- sz := @sizeOf(int);
+fn test_sizeof_int() -> int:
+ sz := @sizeOf(int)
// @sizeOf(int) should return 8 on x86-64
- if sz != 8 { return 1; }
- return 0;
-}
+ if sz != 8:
+ return 1
+ return 0
-fn test_sizeof_bool() -> int {
- sz := @sizeOf(bool);
- if sz != 1 { return 1; }
- return 0;
-}
+fn test_sizeof_bool() -> int:
+ sz := @sizeOf(bool)
+ if sz != 1:
+ return 1
+ return 0
-fn test_alignof_int() -> int {
- al := @alignOf(int);
- if al != 8 { return 1; }
- return 0;
-}
+fn test_alignof_int() -> int:
+ al := @alignOf(int)
+ if al != 8:
+ return 1
+ return 0
// Struct type for field tests
-struct Point { x: int, y: int }
+struct Point:
+ x: int, y: int
-fn test_sizeof_struct() -> int {
- sz := @sizeOf(Point);
+fn test_sizeof_struct() -> int:
+ sz := @sizeOf(Point)
// 终审 M1 收紧:Point = 2×int = 16(旧实现首个用户类型拿下标 8 = TI_DEX_S
// 哨兵,@sizeOf 恒返回 8——弱断言 sz < 8 漏检)
- if sz != 16 { return 1; }
- return 0;
-}
+ if sz != 16:
+ return 1
+ return 0
// M1 回归(终审):3 字段 struct 的首个动态类型场景——@sizeOf 必须返回 24
-struct P3 { a: int, b: int, c: int }
+struct P3:
+ a: int, b: int, c: int
-fn test_sizeof_3field_struct() -> int {
- sz := @sizeOf(P3);
- if sz != 24 { return 1; }
- return 0;
-}
+fn test_sizeof_3field_struct() -> int:
+ sz := @sizeOf(P3)
+ if sz != 24:
+ return 1
+ return 0
-fn test_no_bounds_check() -> int {
- @NoBoundsCheck;
- return 0; // just verifies it compiles
-}
+fn test_no_bounds_check() -> int:
+ @NoBoundsCheck
+ return 0 // just verifies it compiles
-fn add(a: int, b: int) -> int { return a + b; }
+fn add(a: int, b: int) -> int:
+ return a + b
-fn test_inline_hint() -> int {
- result := @inline(add)(3, 4);
- if result != 7 { return 1; }
- return 0;
-}
+fn test_inline_hint() -> int:
+ result := @inline(add)(3, 4)
+ if result != 7:
+ return 1
+ return 0
-fn test_fields_basic() -> int {
- flds := @fields(Point);
- if str_len(flds) < 3 { return 1; } // "x,y"
- return 0;
-}
+fn test_fields_basic() -> int:
+ flds := @fields(Point)
+ if str_len(flds) < 3:
+ return 1
+ // "x,y"
+ return 0
-fn main() -> int {
- r1 := test_sizeof_int(); if r1 != 0 { print("FAIL sizeof_int: "); println(int_str(r1)); return r1; }
- r2 := test_sizeof_bool(); if r2 != 0 { print("FAIL sizeof_bool: "); println(int_str(r2)); return r2; }
- r3 := test_alignof_int(); if r3 != 0 { print("FAIL alignof_int: "); println(int_str(r3)); return r3; }
- r4 := test_sizeof_struct(); if r4 != 0 { print("FAIL sizeof_struct: "); println(int_str(r4)); return r4; }
- r8 := test_sizeof_3field_struct(); if r8 != 0 { print("FAIL sizeof_3field: "); println(int_str(r8)); return r8; }
- r5 := test_no_bounds_check(); if r5 != 0 { print("FAIL no_bounds_check: "); println(int_str(r5)); return r5; }
- r6 := test_inline_hint(); if r6 != 0 { print("FAIL inline: "); println(int_str(r6)); return r6; }
- r7 := test_fields_basic(); if r7 != 0 { print("FAIL fields: "); println(int_str(r7)); return r7; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_sizeof_int()
+ if r1 != 0:
+ print("FAIL sizeof_int: ")
+ println(int_str(r1))
+ return r1
+ r2 := test_sizeof_bool()
+ if r2 != 0:
+ print("FAIL sizeof_bool: ")
+ println(int_str(r2))
+ return r2
+ r3 := test_alignof_int()
+ if r3 != 0:
+ print("FAIL alignof_int: ")
+ println(int_str(r3))
+ return r3
+ r4 := test_sizeof_struct()
+ if r4 != 0:
+ print("FAIL sizeof_struct: ")
+ println(int_str(r4))
+ return r4
+ r8 := test_sizeof_3field_struct()
+ if r8 != 0:
+ print("FAIL sizeof_3field: ")
+ println(int_str(r8))
+ return r8
+ r5 := test_no_bounds_check()
+ if r5 != 0:
+ print("FAIL no_bounds_check: ")
+ println(int_str(r5))
+ return r5
+ r6 := test_inline_hint()
+ if r6 != 0:
+ print("FAIL inline: ")
+ println(int_str(r6))
+ return r6
+ r7 := test_fields_basic()
+ if r7 != 0:
+ print("FAIL fields: ")
+ println(int_str(r7))
+ return r7
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini.cr b/tests/suite/at_test_mini.cr
index 8116868e..5dc25722 100644
--- a/tests/suite/at_test_mini.cr
+++ b/tests/suite/at_test_mini.cr
@@ -1,13 +1,16 @@
import io
-fn test_sizeof_int() -> int {
- sz := @sizeOf(int);
- if sz != 8 { return 1; }
- return 0;
-}
+fn test_sizeof_int() -> int:
+ sz := @sizeOf(int)
+ if sz != 8:
+ return 1
+ return 0
-fn main() -> int {
- r1 := test_sizeof_int(); if r1 != 0 { print("FAIL sizeof_int: "); println(int_str(r1)); return r1; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_sizeof_int()
+ if r1 != 0:
+ print("FAIL sizeof_int: ")
+ println(int_str(r1))
+ return r1
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini2.cr b/tests/suite/at_test_mini2.cr
index 3ecd7030..278e24db 100644
--- a/tests/suite/at_test_mini2.cr
+++ b/tests/suite/at_test_mini2.cr
@@ -1,20 +1,27 @@
import io
-fn test_sizeof_int() -> int {
- sz := @sizeOf(int);
- if sz != 8 { return 1; }
- return 0;
-}
+fn test_sizeof_int() -> int:
+ sz := @sizeOf(int)
+ if sz != 8:
+ return 1
+ return 0
-fn test_sizeof_bool() -> int {
- sz := @sizeOf(bool);
- if sz != 1 { return 1; }
- return 0;
-}
+fn test_sizeof_bool() -> int:
+ sz := @sizeOf(bool)
+ if sz != 1:
+ return 1
+ return 0
-fn main() -> int {
- r1 := test_sizeof_int(); if r1 != 0 { print("FAIL sizeof_int: "); println(int_str(r1)); return r1; }
- r2 := test_sizeof_bool(); if r2 != 0 { print("FAIL sizeof_bool: "); println(int_str(r2)); return r2; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_sizeof_int()
+ if r1 != 0:
+ print("FAIL sizeof_int: ")
+ println(int_str(r1))
+ return r1
+ r2 := test_sizeof_bool()
+ if r2 != 0:
+ print("FAIL sizeof_bool: ")
+ println(int_str(r2))
+ return r2
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini3.cr b/tests/suite/at_test_mini3.cr
index 83d692ab..ad1d441d 100644
--- a/tests/suite/at_test_mini3.cr
+++ b/tests/suite/at_test_mini3.cr
@@ -1,29 +1,41 @@
import io
-struct Point { x: int, y: int }
+struct Point:
+ x: int, y: int
-fn test_sizeof_int() -> int {
- sz := @sizeOf(int);
- if sz != 8 { return 1; }
- return 0;
-}
+fn test_sizeof_int() -> int:
+ sz := @sizeOf(int)
+ if sz != 8:
+ return 1
+ return 0
-fn test_sizeof_bool() -> int {
- sz := @sizeOf(bool);
- if sz != 1 { return 1; }
- return 0;
-}
+fn test_sizeof_bool() -> int:
+ sz := @sizeOf(bool)
+ if sz != 1:
+ return 1
+ return 0
-fn test_sizeof_struct() -> int {
- sz := @sizeOf(Point);
- if sz < 8 { return 1; }
- return 0;
-}
+fn test_sizeof_struct() -> int:
+ sz := @sizeOf(Point)
+ if sz < 8:
+ return 1
+ return 0
-fn main() -> int {
- r1 := test_sizeof_int(); if r1 != 0 { print("FAIL sizeof_int: "); println(int_str(r1)); return r1; }
- r2 := test_sizeof_bool(); if r2 != 0 { print("FAIL sizeof_bool: "); println(int_str(r2)); return r2; }
- r4 := test_sizeof_struct(); if r4 != 0 { print("FAIL sizeof_struct: "); println(int_str(r4)); return r4; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_sizeof_int()
+ if r1 != 0:
+ print("FAIL sizeof_int: ")
+ println(int_str(r1))
+ return r1
+ r2 := test_sizeof_bool()
+ if r2 != 0:
+ print("FAIL sizeof_bool: ")
+ println(int_str(r2))
+ return r2
+ r4 := test_sizeof_struct()
+ if r4 != 0:
+ print("FAIL sizeof_struct: ")
+ println(int_str(r4))
+ return r4
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini4.cr b/tests/suite/at_test_mini4.cr
index 36b55364..de9d4fc0 100644
--- a/tests/suite/at_test_mini4.cr
+++ b/tests/suite/at_test_mini4.cr
@@ -1,14 +1,18 @@
import io
-fn test_inline_hint() -> int {
- fn add(a: int, b: int) -> int { return a + b; }
- result := @inline(add)(3, 4);
- if result != 7 { return 1; }
- return 0;
-}
+fn test_inline_hint() -> int:
+ fn add(a: int, b: int) -> int:
+ return a + b
+ result := @inline(add)(3, 4)
+ if result != 7:
+ return 1
+ return 0
-fn main() -> int {
- r6 := test_inline_hint(); if r6 != 0 { print("FAIL inline: "); println(int_str(r6)); return r6; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r6 := test_inline_hint()
+ if r6 != 0:
+ print("FAIL inline: ")
+ println(int_str(r6))
+ return r6
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini5.cr b/tests/suite/at_test_mini5.cr
index 80b77b69..83b98053 100644
--- a/tests/suite/at_test_mini5.cr
+++ b/tests/suite/at_test_mini5.cr
@@ -1,15 +1,19 @@
import io
-fn add(a: int, b: int) -> int { return a + b; }
+fn add(a: int, b: int) -> int:
+ return a + b
-fn test_inline_hint() -> int {
- result := @inline(add)(3, 4);
- if result != 7 { return 1; }
- return 0;
-}
+fn test_inline_hint() -> int:
+ result := @inline(add)(3, 4)
+ if result != 7:
+ return 1
+ return 0
-fn main() -> int {
- r6 := test_inline_hint(); if r6 != 0 { print("FAIL inline: "); println(int_str(r6)); return r6; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r6 := test_inline_hint()
+ if r6 != 0:
+ print("FAIL inline: ")
+ println(int_str(r6))
+ return r6
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini6.cr b/tests/suite/at_test_mini6.cr
index 98e08848..4b43dcd0 100644
--- a/tests/suite/at_test_mini6.cr
+++ b/tests/suite/at_test_mini6.cr
@@ -1,14 +1,18 @@
import io
-fn test_inline_hint() -> int {
- fn add(a: int, b: int) -> int { return a + b; }
- result := add(3, 4);
- if result != 7 { return 1; }
- return 0;
-}
+fn test_inline_hint() -> int:
+ fn add(a: int, b: int) -> int:
+ return a + b
+ result := add(3, 4)
+ if result != 7:
+ return 1
+ return 0
-fn main() -> int {
- r6 := test_inline_hint(); if r6 != 0 { print("FAIL inline: "); println(int_str(r6)); return r6; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r6 := test_inline_hint()
+ if r6 != 0:
+ print("FAIL inline: ")
+ println(int_str(r6))
+ return r6
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini7.cr b/tests/suite/at_test_mini7.cr
index 00b87c9d..002568a2 100644
--- a/tests/suite/at_test_mini7.cr
+++ b/tests/suite/at_test_mini7.cr
@@ -1,12 +1,14 @@
import io
-fn test_no_bounds_check() -> int {
- @NoBoundsCheck;
- return 0;
-}
+fn test_no_bounds_check() -> int:
+ @NoBoundsCheck
+ return 0
-fn main() -> int {
- r5 := test_no_bounds_check(); if r5 != 0 { print("FAIL no_bounds_check: "); println(int_str(r5)); return r5; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r5 := test_no_bounds_check()
+ if r5 != 0:
+ print("FAIL no_bounds_check: ")
+ println(int_str(r5))
+ return r5
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini8.cr b/tests/suite/at_test_mini8.cr
index f7a50809..663621cd 100644
--- a/tests/suite/at_test_mini8.cr
+++ b/tests/suite/at_test_mini8.cr
@@ -1,13 +1,16 @@
import io
-fn test_alignof_int() -> int {
- al := @alignOf(int);
- if al != 8 { return 1; }
- return 0;
-}
+fn test_alignof_int() -> int:
+ al := @alignOf(int)
+ if al != 8:
+ return 1
+ return 0
-fn main() -> int {
- r3 := test_alignof_int(); if r3 != 0 { print("FAIL alignof_int: "); println(int_str(r3)); return r3; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r3 := test_alignof_int()
+ if r3 != 0:
+ print("FAIL alignof_int: ")
+ println(int_str(r3))
+ return r3
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_mini9.cr b/tests/suite/at_test_mini9.cr
index 35655282..eda22ba7 100644
--- a/tests/suite/at_test_mini9.cr
+++ b/tests/suite/at_test_mini9.cr
@@ -1,19 +1,23 @@
import io
-struct Point { x: int, y: int }
+struct Point:
+ x: int, y: int
-fn test_fields_basic() -> int {
- flds := @fields(Point);
+fn test_fields_basic() -> int:
+ flds := @fields(Point)
// check flds contains field names
// @fields 实现 = **逗号拼接、无尾分隔**(ir_gen.cr 的 `fields` 分支:`if fi > 0 { + "," }`)
// ⇒ Point{x,y} 得 "x,y" = **3 字符**。原判据 `< 4` 是对「逗号+空格」格式的旧期望(成文时点已不可考),
// 现按实测格式钉死为 `!= 3`(**强于** `>= 3`:3 字符的垃圾串也能骗过下界)。
- if str_len(flds) != 3 { return 1; }
- return 0;
-}
+ if str_len(flds) != 3:
+ return 1
+ return 0
-fn main() -> int {
- r7 := test_fields_basic(); if r7 != 0 { print("FAIL fields: "); println(int_str(r7)); return r7; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r7 := test_fields_basic()
+ if r7 != 0:
+ print("FAIL fields: ")
+ println(int_str(r7))
+ return r7
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/at_test_struct.cr b/tests/suite/at_test_struct.cr
index 33d7c831..ea7f745c 100644
--- a/tests/suite/at_test_struct.cr
+++ b/tests/suite/at_test_struct.cr
@@ -1,42 +1,55 @@
-struct Point { x: int, y: int }
+struct Point:
+ x: int, y: int
-fn test_sizeof_int() -> int {
- if @sizeOf(int) != 8 { return 1; }
- return 0;
-}
+fn test_sizeof_int() -> int:
+ if @sizeOf(int) != 8:
+ return 1
+ return 0
-fn test_fields_struct() -> int {
- flds := @fields(Point);
- if str_len(flds) < 3 { return 1; }
- return 0;
-}
+fn test_fields_struct() -> int:
+ flds := @fields(Point)
+ if str_len(flds) < 3:
+ return 1
+ return 0
-fn test_hasfield() -> int {
- if @hasField(Point, "x") == 0 { return 1; }
- if @hasField(Point, "z") != 0 { return 2; }
- return 0;
-}
+fn test_hasfield() -> int:
+ if @hasField(Point, "x") == 0:
+ return 1
+ if @hasField(Point, "z") != 0:
+ return 2
+ return 0
-fn test_field_offset() -> int {
- off := @field(Point, "x");
- if off < 0 { return 1; }
- if off % 8 != 0 { return 2; }
- return 0;
-}
+fn test_field_offset() -> int:
+ off := @field(Point, "x")
+ if off < 0:
+ return 1
+ if off % 8 != 0:
+ return 2
+ return 0
-fn test_typeinfo() -> int {
- ti := @typeInfo(Point);
- if str_len(ti) == 0 { return 1; }
- ti2 := @typeInfo(int);
- if str_len(ti2) == 0 { return 2; }
- return 0;
-}
+fn test_typeinfo() -> int:
+ ti := @typeInfo(Point)
+ if str_len(ti) == 0:
+ return 1
+ ti2 := @typeInfo(int)
+ if str_len(ti2) == 0:
+ return 2
+ return 0
-fn main() -> int {
- r1 := test_sizeof_int(); if r1 != 0 { return r1; }
- r2 := test_fields_struct(); if r2 != 0 { return r2; }
- r3 := test_hasfield(); if r3 != 0 { return r3; }
- r4 := test_field_offset(); if r4 != 0 { return r4; }
- r5 := test_typeinfo(); if r5 != 0 { return r5; }
- return 0;
-}
+fn main() -> int:
+ r1 := test_sizeof_int()
+ if r1 != 0:
+ return r1
+ r2 := test_fields_struct()
+ if r2 != 0:
+ return r2
+ r3 := test_hasfield()
+ if r3 != 0:
+ return r3
+ r4 := test_field_offset()
+ if r4 != 0:
+ return r4
+ r5 := test_typeinfo()
+ if r5 != 0:
+ return r5
+ return 0
diff --git a/tests/suite/cache_test.cr b/tests/suite/cache_test.cr
index cb03b9f6..783e26ff 100644
--- a/tests/suite/cache_test.cr
+++ b/tests/suite/cache_test.cr
@@ -5,20 +5,21 @@
import fmt
import io
-fn test_cache_basic() -> int {
+fn test_cache_basic() -> int:
// First compilation creates cache
// Second compilation should hit cache
// This test verifies the mechanism works end-to-end
// For now, just verify the cache directory was created
// by printing the cache status
- print("cache dir: .core/cache/cir/\n");
- return 0;
-}
+ print("cache dir: .core/cache/cir/\n")
+ return 0
-fn main() -> int {
- r1 := test_cache_basic();
- if r1 != 0 { print("FAIL: "); println(int_str(r1)); return r1; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_cache_basic()
+ if r1 != 0:
+ print("FAIL: ")
+ println(int_str(r1))
+ return r1
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/chan_test.cr b/tests/suite/chan_test.cr
index e7ea2746..236d206f 100644
--- a/tests/suite/chan_test.cr
+++ b/tests/suite/chan_test.cr
@@ -1,18 +1,21 @@
import io
import chan
-fn test_chan_basic() -> int {
- ch := chan_make(8, 10);
- if ch < 0 { return 1; }
- chan_send(ch, 42);
- val := chan_recv(ch);
- if val != 42 { return 2; }
- return 0;
-}
+fn test_chan_basic() -> int:
+ ch := chan_make(8, 10)
+ if ch < 0:
+ return 1
+ chan_send(ch, 42)
+ val := chan_recv(ch)
+ if val != 42:
+ return 2
+ return 0
-fn main() -> int {
- r1 := test_chan_basic();
- if r1 != 0 { print("FAIL: "); println(int_str(r1)); return r1; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_chan_basic()
+ if r1 != 0:
+ print("FAIL: ")
+ println(int_str(r1))
+ return r1
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/cli_view_test.cr b/tests/suite/cli_view_test.cr
index 8e9eeb73..60363fe9 100644
--- a/tests/suite/cli_view_test.cr
+++ b/tests/suite/cli_view_test.cr
@@ -11,20 +11,22 @@
import cli
import io
-fn main() -> int {
- cli_init("myprog", "my program");
- cli_cmd("build", "compile things");
- cli_cmd("cir", "show graph");
- cli_flag("output", "o", "out path");
- cli_flag_bool("verbose", "v", "more noise");
+fn main() -> int:
+ cli_init("myprog", "my program")
+ cli_cmd("build", "compile things")
+ cli_cmd("cir", "show graph")
+ cli_flag("output", "o", "out path")
+ cli_flag_bool("verbose", "v", "more noise")
// 查询面:`cli_get` 读回「value」槽(初值经 `@ptr_of("")` 写入)⇒ 必须是空串
- if cli_get("output") != "" { return 11; }
+ if cli_get("output") != "":
+ return 11
// `cli_has` 读 has_value 槽(int 语义,不经视图)⇒ 未解析前 = 0
- if cli_has("output") != 0 { return 12; }
+ if cli_has("output") != 0:
+ return 12
// 不存在旗标 ⇒ -1 分支(走 `_cli_find_flag` 的视图比较路径)
- if cli_has("nope") != 0 { return 13; }
+ if cli_has("nope") != 0:
+ return 13
- cli_help();
- return 0;
-}
+ cli_help()
+ return 0
diff --git a/tests/suite/conc_test.cr b/tests/suite/conc_test.cr
index bf9023b1..a3f1ac09 100644
--- a/tests/suite/conc_test.cr
+++ b/tests/suite/conc_test.cr
@@ -3,82 +3,99 @@ import io
import chan
import sched
-fn test_chan_fifo() -> int {
+fn test_chan_fifo() -> int:
// Test basic channel FIFO behavior with buffer
- ch := chan_make(8, 3);
- chan_send(ch, 10);
- chan_send(ch, 20);
- chan_send(ch, 30);
+ ch := chan_make(8, 3)
+ chan_send(ch, 10)
+ chan_send(ch, 20)
+ chan_send(ch, 30)
- v1 := chan_recv(ch);
- if v1 != 10 { return v1; }
- v2 := chan_recv(ch);
- if v2 != 20 { return v2; }
- v3 := chan_recv(ch);
- if v3 != 30 { return v3; }
- return 0;
-}
+ v1 := chan_recv(ch)
+ if v1 != 10:
+ return v1
+ v2 := chan_recv(ch)
+ if v2 != 20:
+ return v2
+ v3 := chan_recv(ch)
+ if v3 != 30:
+ return v3
+ return 0
-fn test_chan_send_recv() -> int {
+fn test_chan_send_recv() -> int:
// Test single send/recv
- ch := chan_make(8, 1);
- chan_send(ch, 42);
- val := chan_recv(ch);
- if val != 42 { return 1; }
- return 0;
-}
+ ch := chan_make(8, 1)
+ chan_send(ch, 42)
+ val := chan_recv(ch)
+ if val != 42:
+ return 1
+ return 0
-fn test_sched_get_curg() -> int {
+fn test_sched_get_curg() -> int:
// Test that sched_get_curg returns a valid G pointer
// On startup, there should be no current G (-1)
- cur_g := sched_get_curg();
+ cur_g := sched_get_curg()
// No goroutine is running here, so cur_g could be -1
// Just verify it doesn't crash
- if cur_g < -1 { return 1; }
- return 0;
-}
+ if cur_g < -1:
+ return 1
+ return 0
-fn test_chan_close() -> int {
- ch := chan_make(8, 1);
- chan_close(ch);
+fn test_chan_close() -> int:
+ ch := chan_make(8, 1)
+ chan_close(ch)
// After close, recv should return 0 (zero value)
- val := chan_recv(ch);
- if val != 0 { return 1; }
- return 0;
-}
+ val := chan_recv(ch)
+ if val != 0:
+ return 1
+ return 0
-fn test_chan_close_wakeup() -> int {
+fn test_chan_close_wakeup() -> int:
// Test that closing a channel wakes up waiters
- ch := chan_make(8, 1);
+ ch := chan_make(8, 1)
// Fill buffer
- chan_send(ch, 99);
+ chan_send(ch, 99)
// Close
- chan_close(ch);
+ chan_close(ch)
// Read the buffered value
- v1 := chan_recv(ch);
- if v1 != 99 { return v1; }
+ v1 := chan_recv(ch)
+ if v1 != 99:
+ return v1
// After buffer drain, closed returns 0
- v2 := chan_recv(ch);
- if v2 != 0 { return 2; }
- return 0;
-}
+ v2 := chan_recv(ch)
+ if v2 != 0:
+ return 2
+ return 0
-fn main() -> int {
- r1 := test_chan_send_recv();
- if r1 != 0 { print("FAIL chan_send_recv: "); println(int_str(r1)); return r1; }
+fn main() -> int:
+ r1 := test_chan_send_recv()
+ if r1 != 0:
+ print("FAIL chan_send_recv: ")
+ println(int_str(r1))
+ return r1
- r2 := test_chan_fifo();
- if r2 != 0 { print("FAIL chan_fifo: "); println(int_str(r2)); return r2; }
+ r2 := test_chan_fifo()
+ if r2 != 0:
+ print("FAIL chan_fifo: ")
+ println(int_str(r2))
+ return r2
- r3 := test_sched_get_curg();
- if r3 != 0 { print("FAIL sched_get_curg: "); println(int_str(r3)); return r3; }
+ r3 := test_sched_get_curg()
+ if r3 != 0:
+ print("FAIL sched_get_curg: ")
+ println(int_str(r3))
+ return r3
- r4 := test_chan_close();
- if r4 != 0 { print("FAIL chan_close: "); println(int_str(r4)); return r4; }
+ r4 := test_chan_close()
+ if r4 != 0:
+ print("FAIL chan_close: ")
+ println(int_str(r4))
+ return r4
- r5 := test_chan_close_wakeup();
- if r5 != 0 { print("FAIL chan_close_wakeup: "); println(int_str(r5)); return r5; }
+ r5 := test_chan_close_wakeup()
+ if r5 != 0:
+ print("FAIL chan_close_wakeup: ")
+ println(int_str(r5))
+ return r5
- println("ALL PASS");
- return 0;
-}
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/dex_test.cr b/tests/suite/dex_test.cr
index 7f1765ce..5e45c315 100644
--- a/tests/suite/dex_test.cr
+++ b/tests/suite/dex_test.cr
@@ -4,67 +4,123 @@ import io
import fmt
import dex
-fn main() -> int {
+fn main() -> int:
// 1. 精确加法:3.14 + 2.86 == 6.0
- a := 3.14 + 2.86;
- if a != 6.0 { print("FAIL 3.14+2.86: "); println(dex_str(a)); return 1; }
+ a := 3.14 + 2.86
+ if a != 6.0:
+ print("FAIL 3.14+2.86: ")
+ println(dex_str(a))
+ return 1
// 2. 0.1 + 0.2 == 0.3(精确——binary64 做不到)
- b := 0.1 + 0.2;
- if b != 0.3 { print("FAIL 0.1+0.2: "); println(dex_str(b)); return 2; }
+ b := 0.1 + 0.2
+ if b != 0.3:
+ print("FAIL 0.1+0.2: ")
+ println(dex_str(b))
+ return 2
// 3. 除法:1/10 = 0.1,打印 "0.1"
- c := 1.0 / 10.0;
- if c != 0.1 { print("FAIL 1/10: "); println(dex_str(c)); return 3; }
- if !str_eq(dex_str(c), "0.1") { print("FAIL print 1/10: "); println(dex_str(c)); return 4; }
+ c := 1.0 / 10.0
+ if c != 0.1:
+ print("FAIL 1/10: ")
+ println(dex_str(c))
+ return 3
+ if !str_eq(dex_str(c), "0.1"):
+ print("FAIL print 1/10: ")
+ println(dex_str(c))
+ return 4
// 4. 乘法:1.5 * 2.0 == 3.0
- d := 1.5 * 2.0;
- if d != 3.0 { print("FAIL 1.5*2.0: "); println(dex_str(d)); return 5; }
+ d := 1.5 * 2.0
+ if d != 3.0:
+ print("FAIL 1.5*2.0: ")
+ println(dex_str(d))
+ return 5
// 5. 减法 + 负数:0.3 - 1.0 == -0.7
- e := 0.3 - 1.0;
- if e != -0.7 { print("FAIL 0.3-1.0: "); println(dex_str(e)); return 6; }
+ e := 0.3 - 1.0
+ if e != -0.7:
+ print("FAIL 0.3-1.0: ")
+ println(dex_str(e))
+ return 6
// 6. 打印去尾零:6.0 → "6";0.10 → "0.1";3.14 → "3.14"
- if !str_eq(dex_str(6.0), "6") { print("FAIL print 6.0: "); println(dex_str(6.0)); return 7; }
- if !str_eq(dex_str(0.10), "0.1") { print("FAIL print 0.10: "); println(dex_str(0.10)); return 8; }
- if !str_eq(dex_str(3.14), "3.14") { print("FAIL print 3.14: "); println(dex_str(3.14)); return 9; }
+ if !str_eq(dex_str(6.0), "6"):
+ print("FAIL print 6.0: ")
+ println(dex_str(6.0))
+ return 7
+ if !str_eq(dex_str(0.10), "0.1"):
+ print("FAIL print 0.10: ")
+ println(dex_str(0.10))
+ return 8
+ if !str_eq(dex_str(3.14), "3.14"):
+ print("FAIL print 3.14: ")
+ println(dex_str(3.14))
+ return 9
// 7. 整数参与:1 + 0.5 == 1.5
- f := 1 + 0.5;
- if f != 1.5 { print("FAIL 1+0.5: "); println(dex_str(f)); return 10; }
+ f := 1 + 0.5
+ if f != 1.5:
+ print("FAIL 1+0.5: ")
+ println(dex_str(f))
+ return 10
// 8. 变量运算
- g : dex = 0.1;
- h : dex = 0.2;
- if g + h != 0.3 { print("FAIL var add: "); println(dex_str(g + h)); return 11; }
+ g : dex = 0.1
+ h : dex = 0.2
+ if g + h != 0.3:
+ print("FAIL var add: ")
+ println(dex_str(g + h))
+ return 11
// 9. 函数边界:dex 参数/返回走精确形式(缩放整数)
- r := dex_add_fn(0.1, 0.2);
- if r != 0.3 { print("FAIL fn dex: "); println(dex_str(r)); return 12; }
+ r := dex_add_fn(0.1, 0.2)
+ if r != 0.3:
+ print("FAIL fn dex: ")
+ println(dex_str(r))
+ return 12
// 10. 1/3 判别子:定点 6 位(0.333333)≠ binary64(0.3333333333333333)
- q := 1.0 / 3.0;
- if q != 0.3333333 { print("FAIL 1/3: "); println(dex_str(q)); return 13; }
+ q := 1.0 / 3.0
+ if q != 0.3333333:
+ print("FAIL 1/3: ")
+ println(dex_str(q))
+ return 13
// 11. 模运算截断恒等式(5 指令序列 a - trunc(a/b)·b),含负数
- if 7.0 % 2.5 != 2.0 { print("FAIL 7.0%2.5: "); println(dex_str(7.0 % 2.5)); return 14; }
- if -7.0 % 2.5 != -2.0 { print("FAIL -7.0%2.5: "); println(dex_str(-7.0 % 2.5)); return 15; }
- if 1.0 % 0.3 != 0.1 { print("FAIL 1.0%0.3: "); println(dex_str(1.0 % 0.3)); return 16; }
- if -1.0 % 0.3 != -0.1 { print("FAIL -1.0%0.3: "); println(dex_str(-1.0 % 0.3)); return 17; }
+ if 7.0 % 2.5 != 2.0:
+ print("FAIL 7.0%2.5: ")
+ println(dex_str(7.0 % 2.5))
+ return 14
+ if -7.0 % 2.5 != -2.0:
+ print("FAIL -7.0%2.5: ")
+ println(dex_str(-7.0 % 2.5))
+ return 15
+ if 1.0 % 0.3 != 0.1:
+ print("FAIL 1.0%0.3: ")
+ println(dex_str(1.0 % 0.3))
+ return 16
+ if -1.0 % 0.3 != -0.1:
+ print("FAIL -1.0%0.3: ")
+ println(dex_str(-1.0 % 0.3))
+ return 17
// 12. LET 边界转换(审查发现回归):`y : dex = x`(x apx bits)→ y 存缩放形式
- x : dex, apx = 3.0;
- y : dex = x;
- if 1.0 / y != 0.3333333 { print("FAIL LET apx->exact: "); println(dex_str(1.0 / y)); return 18; }
+ x : dex, apx = 3.0
+ y : dex = x
+ if 1.0 / y != 0.3333333:
+ print("FAIL LET apx->exact: ")
+ println(dex_str(1.0 / y))
+ return 18
// 13. apx 跨函数边界(b1 调用点 + b2 返回点:bits → 定点 6 位)
- b1 := dex_double_fn(x);
- if b1 != 6.0 { print("FAIL call-site bits->scaled: "); println(dex_str(b1)); return 19; }
- b2 := dex_apx_ret_fn();
- if b2 != 0.5 { print("FAIL return-site bits->scaled: "); println(dex_str(b2)); return 20; }
- println("ALL PASS");
- return 0;
-}
+ b1 := dex_double_fn(x)
+ if b1 != 6.0:
+ print("FAIL call-site bits->scaled: ")
+ println(dex_str(b1))
+ return 19
+ b2 := dex_apx_ret_fn()
+ if b2 != 0.5:
+ print("FAIL return-site bits->scaled: ")
+ println(dex_str(b2))
+ return 20
+ println("ALL PASS")
+ return 0
-fn dex_double_fn(a: dex) -> dex {
- return a * 2.0;
-}
+fn dex_double_fn(a: dex) -> dex:
+ return a * 2.0
-fn dex_apx_ret_fn() -> dex {
- v : dex, apx = 1.0;
- return v / 2.0;
-}
+fn dex_apx_ret_fn() -> dex:
+ v : dex, apx = 1.0
+ return v / 2.0
-fn dex_add_fn(a: dex, b: dex) -> dex {
- return a + b;
-}
+fn dex_add_fn(a: dex, b: dex) -> dex:
+ return a + b
diff --git a/tests/suite/dyn_test.cr b/tests/suite/dyn_test.cr
index ab92e108..e064bcb2 100644
--- a/tests/suite/dyn_test.cr
+++ b/tests/suite/dyn_test.cr
@@ -1,40 +1,46 @@
import io
-fn test_dyn_basic() -> int {
- x : dyn = 42;
+fn test_dyn_basic() -> int:
+ x : dyn = 42
// Single-path dyn should work like normal value
- if x != 42 { return 1; }
- return 0;
-}
+ if x != 42:
+ return 1
+ return 0
-fn test_dyn_reassign() -> int {
- x : dyn = 42;
- x = "hello";
+fn test_dyn_reassign() -> int:
+ x : dyn = 42
+ x = "hello"
// After reassignment, x should be string
- if str_len(x) < 1 { return 1; }
- return 0;
-}
+ if str_len(x) < 1:
+ return 1
+ return 0
-fn test_dyn_multi_path() -> int {
- cond : int = 1;
- x : dyn = 0;
- if cond != 0 {
- x = 42;
- } else {
- x = "hello";
- }
+fn test_dyn_multi_path() -> int:
+ cond : int = 1
+ x : dyn = 0
+ if cond != 0:
+ x = 42
+ else:
+ x = "hello"
// x could be int or string
// Just verify it compiles and runs
- return 0;
-}
+ return 0
-fn main() -> int {
- r1 := test_dyn_basic();
- if r1 != 0 { print("FAIL basic: "); println(int_str(r1)); return r1; }
- r2 := test_dyn_reassign();
- if r2 != 0 { print("FAIL reassign: "); println(int_str(r2)); return r2; }
- r3 := test_dyn_multi_path();
- if r3 != 0 { print("FAIL multipath: "); println(int_str(r3)); return r3; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_dyn_basic()
+ if r1 != 0:
+ print("FAIL basic: ")
+ println(int_str(r1))
+ return r1
+ r2 := test_dyn_reassign()
+ if r2 != 0:
+ print("FAIL reassign: ")
+ println(int_str(r2))
+ return r2
+ r3 := test_dyn_multi_path()
+ if r3 != 0:
+ print("FAIL multipath: ")
+ println(int_str(r3))
+ return r3
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/ffi_test.cr b/tests/suite/ffi_test.cr
index 7a39c80d..0d01d17a 100644
--- a/tests/suite/ffi_test.cr
+++ b/tests/suite/ffi_test.cr
@@ -1,18 +1,17 @@
import io
// Test extern function declarations at top level
-extern fn getchar() -> int;
-extern fn putchar(c: int) -> int;
+extern fn getchar() -> int
+extern fn putchar(c: int) -> int
// M2 终审:extern dex 参数声明面——dex 跨 C 边界 = binary64 bits(module.cr ABI 契约)。
// 仅声明(不调用):调用点转换由 tests/selfhost/test_dex_arith.py 的
// test_extern_dex_arg_cir 以 IR 层断言覆盖(运行时 FFI 被 corearch --link
// 静态路径既有崩溃阻塞,见 numeric-task-7-report Fix F)。
-extern fn dex_floor(d: dex) -> dex;
+extern fn dex_floor(d: dex) -> dex
-fn main() -> int {
+fn main() -> int:
// Verify that extern fn declarations compiled successfully
// by testing that we can call main correctly
- println("ALL PASS");
- return 0;
-}
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/fnaddr_test.cr b/tests/suite/fnaddr_test.cr
index 91ff24fa..5b4cdb25 100644
--- a/tests/suite/fnaddr_test.cr
+++ b/tests/suite/fnaddr_test.cr
@@ -6,12 +6,12 @@
import io
-fn square(n: int) -> int {
- return n * n;
-}
+fn square(n: int) -> int:
+ return n * n
-fn main() -> int {
- addr := @addr(square);
- if addr == 0 { return 1; } // address should be non-zero
- return 0;
-}
+fn main() -> int:
+ addr := @addr(square)
+ if addr == 0:
+ return 1
+ // address should be non-zero
+ return 0
diff --git a/tests/suite/generics_test.cr b/tests/suite/generics_test.cr
index 45b403e1..78ec0a3a 100644
--- a/tests/suite/generics_test.cr
+++ b/tests/suite/generics_test.cr
@@ -8,106 +8,95 @@ import fmt
// === Generic function: identity[T] ===
-fn identity[T](x: T) -> T {
- return x;
-}
+fn identity[T](x: T) -> T:
+ return x
// === Generic struct: Box[T] ===
-struct Box[T] {
+struct Box[T]:
val: T
-}
// === Function on generic struct ===
-fn get_val[T](b: Box[T]) -> T {
- return b.val;
-}
+fn get_val[T](b: Box[T]) -> T:
+ return b.val
// === Multi-param generic function ===
-fn pair[A, B](a: A, b: B) -> int {
- if a != 1 { return 1; }
- if str_len(b) < 1 { return 1; }
- return 0;
-}
+fn pair[A, B](a: A, b: B) -> int:
+ if a != 1:
+ return 1
+ if str_len(b) < 1:
+ return 1
+ return 0
// === Main: run all tests inline ===
-fn main() -> int {
+fn main() -> int:
// Test 1: Generic identity with int
- r1 := identity(42);
- if r1 != 42 {
- print("FAIL identity_int: ");
- println(int_str(r1));
- return 1;
- }
- println("PASS identity_int");
+ r1 := identity(42)
+ if r1 != 42:
+ print("FAIL identity_int: ")
+ println(int_str(r1))
+ return 1
+ println("PASS identity_int")
// Test 2: Generic identity with string
- r2 := identity("hello");
- if str_len(r2) != 5 {
- print("FAIL identity_str: ");
- println(int_str(str_len(r2)));
- return 2;
- }
- println("PASS identity_str");
+ r2 := identity("hello")
+ if str_len(r2) != 5:
+ print("FAIL identity_str: ")
+ println(int_str(str_len(r2)))
+ return 2
+ println("PASS identity_str")
// Test 3: Generic struct Box with int
- b1 := Box { val = 100 };
- if b1.val != 100 {
- print("FAIL box_int: ");
- println(int_str(b1.val));
- return 3;
- }
- println("PASS box_int");
+ b1 := Box { val = 100 }
+ if b1.val != 100:
+ print("FAIL box_int: ")
+ println(int_str(b1.val))
+ return 3
+ println("PASS box_int")
// Test 4: Generic struct Box with string
- b2 := Box { val = "world" };
- if str_len(b2.val) != 5 {
- print("FAIL box_str: ");
- println(int_str(str_len(b2.val)));
- return 4;
- }
- println("PASS box_str");
+ b2 := Box { val = "world" }
+ if str_len(b2.val) != 5:
+ print("FAIL box_str: ")
+ println(int_str(str_len(b2.val)))
+ return 4
+ println("PASS box_str")
// Test 5: Function on generic struct (type inference from argument)
- b3 := Box { val = 42 };
- v5 := get_val(b3);
- if v5 != 42 {
- print("FAIL get_val_int: ");
- println(int_str(v5));
- return 5;
- }
- println("PASS get_val_int");
+ b3 := Box { val = 42 }
+ v5 := get_val(b3)
+ if v5 != 42:
+ print("FAIL get_val_int: ")
+ println(int_str(v5))
+ return 5
+ println("PASS get_val_int")
// Test 6: Function on generic struct with string type
- b4 := Box { val = "hello" };
- v6 := get_val(b4);
- if str_len(v6) != 5 {
- print("FAIL get_val_str: ");
- println(int_str(str_len(v6)));
- return 6;
- }
- println("PASS get_val_str");
+ b4 := Box { val = "hello" }
+ v6 := get_val(b4)
+ if str_len(v6) != 5:
+ print("FAIL get_val_str: ")
+ println(int_str(str_len(v6)))
+ return 6
+ println("PASS get_val_str")
// Test 7: Multi-param generic function
- r7 := pair(1, "two");
- if r7 != 0 {
- print("FAIL multi_param: ");
- println(int_str(r7));
- return 7;
- }
- println("PASS multi_param");
+ r7 := pair(1, "two")
+ if r7 != 0:
+ print("FAIL multi_param: ")
+ println(int_str(r7))
+ return 7
+ println("PASS multi_param")
// Test 8: Generic identity with bool
- r8 := identity(true);
- if r8 != true {
- print("FAIL identity_bool");
- return 8;
- }
- println("PASS identity_bool");
-
- println("ALL PASS");
- return 0;
-}
+ r8 := identity(true)
+ if r8 != true:
+ print("FAIL identity_bool")
+ return 8
+ println("PASS identity_bool")
+
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/global_seam_test.cr b/tests/suite/global_seam_test.cr
index fe143422..4ac7ece1 100644
--- a/tests/suite/global_seam_test.cr
+++ b/tests/suite/global_seam_test.cr
@@ -7,26 +7,30 @@
// 「不可变 + 字面量初值」的全局折叠成 IR_CONST ⇒ 读点不碰全局行、探针不触达被测面。
// ② apx 算术**无解释器腿**(`corec run` 显式拒收 rc=255,能力边界非缺陷)⇒ 本档只走 ELF 腿。
-g1_neg : dex, apx, mut = -100.0;
-g1_pos : dex, apx, mut = 100.0;
-g2 : dex, mut = -100.0;
-g4 : [int;4] = [10, 20, 30, 40];
-lo : int, mut = 1;
-g5 : int, mut = 5;
+g1_neg : dex, apx, mut = -100.0
+g1_pos : dex, apx, mut = 100.0
+g2 : dex, mut = -100.0
+g4 : [int;4] = [10, 20, 30, 40]
+lo : int, mut = 1
+g5 : int, mut = 5
-fn main() -> int {
+fn main() -> int:
// B1(IR_BINARY TI_DEX 双操作数):负号全局判真 ⇒ 错;正号全局判负 ⇒ 错
- if g1_neg > 0.0 { return 1; }
- if g1_pos < 0.0 { return 2; }
+ if g1_neg > 0.0:
+ return 1
+ if g1_pos < 0.0:
+ return 2
// B2(IR_I2F 全局源,scaled → apx):负号全局经转换后判真 ⇒ 错
- d : dex, apx = g2;
- if d > 0.0 { return 3; }
+ d : dex, apx = g2
+ if d > 0.0:
+ return 3
// B4(IR_SLICE 数组指针 + 低界,两端皆全局):g4[lo..3] 首元素 = 20
- s := g4[lo..3];
- if s[0] != 20 { return 4; }
+ s := g4[lo..3]
+ if s[0] != 20:
+ return 4
// B5(IR_AWAIT 全局源):运行期赋值 9 ⇒ 读回 9(不可折叠)
- g5 = 9;
- x := await g5;
- if x != 9 { return 5; }
- return 0;
-}
+ g5 = 9
+ x := await g5
+ if x != 9:
+ return 5
+ return 0
diff --git a/tests/suite/go_e2e_test.cr b/tests/suite/go_e2e_test.cr
index 14c8b25d..ec6d6868 100644
--- a/tests/suite/go_e2e_test.cr
+++ b/tests/suite/go_e2e_test.cr
@@ -8,15 +8,14 @@
import io
import sched
-fn square(n: int) -> int {
- return n * n;
-}
+fn square(n: int) -> int:
+ return n * n
-fn main() -> int {
- sched_init();
- ch := go square(21);
- result := chan_recv(ch);
- if result != 441 { return 1; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ sched_init()
+ ch := go square(21)
+ result := chan_recv(ch)
+ if result != 441:
+ return 1
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/go_final_test.cr b/tests/suite/go_final_test.cr
index 880cdaa7..eb2dc3f9 100644
--- a/tests/suite/go_final_test.cr
+++ b/tests/suite/go_final_test.cr
@@ -7,15 +7,16 @@ import io
import sched
import chan
-fn square(n: int) -> int {
- return n * n;
-}
+fn square(n: int) -> int:
+ return n * n
-fn main() -> int {
- sched_init();
- ch := go square(21);
- result := chan_recv(ch);
- if result != 441 { print("FAIL: "); println(int_str(result)); return 1; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ sched_init()
+ ch := go square(21)
+ result := chan_recv(ch)
+ if result != 441:
+ print("FAIL: ")
+ println(int_str(result))
+ return 1
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/go_parallel_test.cr b/tests/suite/go_parallel_test.cr
index 2244f14c..8e38bcdc 100644
--- a/tests/suite/go_parallel_test.cr
+++ b/tests/suite/go_parallel_test.cr
@@ -8,19 +8,23 @@ import io
import sched
import chan
-fn compute(n: int) -> int {
- yield; // give others a chance
- return n + 1;
-}
+fn compute(n: int) -> int:
+ yield // give others a chance
+ return n + 1
-fn main() -> int {
- sched_init();
- c1 := go compute(1);
- c2 := go compute(2);
- r1 := chan_recv(c1);
- r2 := chan_recv(c2);
- if r1 != 2 { print("FAIL r1="); println(int_str(r1)); return 1; }
- if r2 != 3 { print("FAIL r2="); println(int_str(r2)); return 2; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ sched_init()
+ c1 := go compute(1)
+ c2 := go compute(2)
+ r1 := chan_recv(c1)
+ r2 := chan_recv(c2)
+ if r1 != 2:
+ print("FAIL r1=")
+ println(int_str(r1))
+ return 1
+ if r2 != 3:
+ print("FAIL r2=")
+ println(int_str(r2))
+ return 2
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/go_test.cr b/tests/suite/go_test.cr
index f5af8765..f082c9eb 100644
--- a/tests/suite/go_test.cr
+++ b/tests/suite/go_test.cr
@@ -1,14 +1,15 @@
import io
-fn test_go_basic() -> int {
+fn test_go_basic() -> int:
// Just verify go compiles
- go 42; // minimal go expression
- return 0;
-}
+ go 42 // minimal go expression
+ return 0
-fn main() -> int {
- r1 := test_go_basic();
- if r1 != 0 { print("FAIL: "); println(int_str(r1)); return r1; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_go_basic()
+ if r1 != 0:
+ print("FAIL: ")
+ println(int_str(r1))
+ return r1
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/hotpatch_test.cr b/tests/suite/hotpatch_test.cr
index abb27db7..72d7578b 100644
--- a/tests/suite/hotpatch_test.cr
+++ b/tests/suite/hotpatch_test.cr
@@ -6,64 +6,53 @@ import toml
// Test: basic @hotpatch(ver=1) annotation compiles
@hotpatch(ver=1)
-fn test_hotpatch_ver1() -> int {
- return 42;
-}
+fn test_hotpatch_ver1() -> int:
+ return 42
// Test: @hotpatch(ver=2) with different version
@hotpatch(ver=2)
-fn test_hotpatch_ver2() -> int {
- return 99;
-}
+fn test_hotpatch_ver2() -> int:
+ return 99
// Test: @hotpatch shorthand (defaults to ver=1)
@hotpatch
-fn test_hotpatch_shorthand() -> int {
- return 7;
-}
+fn test_hotpatch_shorthand() -> int:
+ return 7
// Test: hotpatch config loading via toml
-fn test_hotpatch_config() -> int {
- cfg := read_file(".hotpatch.toml");
- if str_len(cfg) > 0 {
+fn test_hotpatch_config() -> int:
+ cfg := read_file(".hotpatch.toml")
+ if str_len(cfg) > 0:
// Try to read a known field
- ver_str := toml_get_str(cfg, "version");
- if str_len(ver_str) > 0 {
- return 0; // config loaded and has a version field
- }
- }
- return 0; // no .hotpatch.toml is acceptable
-}
-
-fn main() -> int {
- r1 := test_hotpatch_ver1();
- if r1 != 42 {
- print("FAIL: test_hotpatch_ver1 returned ");
- println(int_str(r1));
- return 1;
- }
-
- r2 := test_hotpatch_ver2();
- if r2 != 99 {
- print("FAIL: test_hotpatch_ver2 returned ");
- println(int_str(r2));
- return 2;
- }
-
- r3 := test_hotpatch_shorthand();
- if r3 != 7 {
- print("FAIL: test_hotpatch_shorthand returned ");
- println(int_str(r3));
- return 3;
- }
-
- r4 := test_hotpatch_config();
- if r4 != 0 {
- print("FAIL: test_hotpatch_config returned ");
- println(int_str(r4));
- return 4;
- }
-
- println("ALL PASS");
- return 0;
-}
+ ver_str := toml_get_str(cfg, "version")
+ if str_len(ver_str) > 0:
+ return 0 // config loaded and has a version field
+ return 0 // no .hotpatch.toml is acceptable
+
+fn main() -> int:
+ r1 := test_hotpatch_ver1()
+ if r1 != 42:
+ print("FAIL: test_hotpatch_ver1 returned ")
+ println(int_str(r1))
+ return 1
+
+ r2 := test_hotpatch_ver2()
+ if r2 != 99:
+ print("FAIL: test_hotpatch_ver2 returned ")
+ println(int_str(r2))
+ return 2
+
+ r3 := test_hotpatch_shorthand()
+ if r3 != 7:
+ print("FAIL: test_hotpatch_shorthand returned ")
+ println(int_str(r3))
+ return 3
+
+ r4 := test_hotpatch_config()
+ if r4 != 0:
+ print("FAIL: test_hotpatch_config returned ")
+ println(int_str(r4))
+ return 4
+
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/lazy_test.cr b/tests/suite/lazy_test.cr
index 0e4434f3..e1664112 100644
--- a/tests/suite/lazy_test.cr
+++ b/tests/suite/lazy_test.cr
@@ -1,20 +1,21 @@
import io
-fn expensive(n: int) -> int {
+fn expensive(n: int) -> int:
// Side-effect-free pure function
- return n * n;
-}
+ return n * n
-fn test_lazy_basic() -> int {
+fn test_lazy_basic() -> int:
// expensive() is pure → compiler may defer it
- x := expensive(42);
- if x != 1764 { return 1; }
- return 0;
-}
+ x := expensive(42)
+ if x != 1764:
+ return 1
+ return 0
-fn main() -> int {
- r1 := test_lazy_basic();
- if r1 != 0 { print("FAIL: "); println(int_str(r1)); return r1; }
- println("ALL PASS");
- return 0;
-}
+fn main() -> int:
+ r1 := test_lazy_basic()
+ if r1 != 0:
+ print("FAIL: ")
+ println(int_str(r1))
+ return r1
+ println("ALL PASS")
+ return 0
diff --git a/tests/suite/opt_dex_test.cr b/tests/suite/opt_dex_test.cr
index 76446eeb..ce6c3dc2 100644
--- a/tests/suite/opt_dex_test.cr
+++ b/tests/suite/opt_dex_test.cr
@@ -13,122 +13,171 @@
//
// 返回码约定:0 = 全过;非 0 = **首个失败面的编号**(便于定位;逐个面独立成函数)。
-g : dex?, mut = None;
-
-struct SOpt { f: dex? }
-
-enum EOpt { V(dex?) }
-
-fn four_bare_bits() -> int {
- d : dex, apx = 7.0;
- x : dex? = d;
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn four_bare_scaled() -> int {
- e : dex = 7.0;
- x : dex? = e;
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn four_boxed_bits() -> int {
- d : dex, apx = 7.0;
- x : dex? = Some(d);
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn four_boxed_scaled() -> int {
- e : dex = 7.0;
- x : dex? = Some(e);
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn assign_bits() -> int {
- d : dex, apx = 7.0;
- x : dex?, mut = None;
- x = d;
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn ptr_write_bits() -> int {
- d : dex, apx = 7.0;
- x : dex?, mut = None;
- p := &x;
- *p = d;
- return match *p { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn addr_taken_bits() -> int {
- d : dex, apx = 7.0;
- x : dex? = d;
- p := &x;
- return match *p { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn ret_bits() -> int {
- d : dex, apx = 7.0;
- x : dex? = d;
- y := x?;
- return @raw_int(y) / 1000000;
-}
-
-fn field_lit_bits() -> int {
- d : dex, apx = 7.0;
- s : ., mut = SOpt { f = d };
- return match s.f { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn field_assign_bits() -> int {
- d : dex, apx = 7.0;
- s : ., mut = SOpt { f = None };
- s.f = d;
- return match s.f { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn global_bits() -> int {
- d : dex, apx = 7.0;
- g = d;
- return match g { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn enum_payload_bits() -> int {
- d : dex, apx = 7.0;
- e := V(d);
- return match e {
- V(x) => { return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } }; }
- };
-}
-
-fn param_scaled_ctl() -> int {
- e : dex = 7.0;
- return take_opt(e);
-}
-
-fn take_opt(x: dex?) -> int {
- return match x { Some(v) => { return @raw_int(v) / 1000000; } None => { return 0; } };
-}
-
-fn nonopt_direct_bits() -> int {
- d : dex, apx = 7.0;
- return take_plain(d);
-}
-
-fn take_plain(x: dex) -> int { return @raw_int(x) / 1000000; }
-
-fn main() -> int {
- if four_bare_bits() != 7 { return 1; }
- if four_bare_scaled() != 7 { return 2; }
- if four_boxed_bits() != 7 { return 3; }
- if four_boxed_scaled() != 7 { return 4; }
- if assign_bits() != 7 { return 5; }
- if ptr_write_bits() != 7 { return 6; }
- if addr_taken_bits() != 7 { return 7; }
- if ret_bits() != 7 { return 8; }
- if field_lit_bits() != 7 { return 9; }
- if field_assign_bits() != 7 { return 10; }
- if global_bits() != 7 { return 11; }
- if enum_payload_bits() != 7 { return 12; }
- if param_scaled_ctl() != 7 { return 13; }
- if nonopt_direct_bits() != 7 { return 14; }
- return 0;
-}
+g : dex?, mut = none
+
+struct SOpt:
+ f: dex?
+
+enum EOpt:
+ V(dex?)
+
+fn four_bare_bits() -> int:
+ d : dex, apx = 7.0
+ x : dex? = d
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn four_bare_scaled() -> int:
+ e : dex = 7.0
+ x : dex? = e
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn four_boxed_bits() -> int:
+ d : dex, apx = 7.0
+ x : dex? = Some(d)
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn four_boxed_scaled() -> int:
+ e : dex = 7.0
+ x : dex? = Some(e)
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn assign_bits() -> int:
+ d : dex, apx = 7.0
+ x : dex?, mut = none
+ x = d
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn ptr_write_bits() -> int:
+ d : dex, apx = 7.0
+ x : dex?, mut = none
+ p := &x
+ *p = d
+ return match *p:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn addr_taken_bits() -> int:
+ d : dex, apx = 7.0
+ x : dex? = d
+ p := &x
+ return match *p:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn ret_bits() -> int:
+ d : dex, apx = 7.0
+ x : dex? = d
+ y := x?
+ return @raw_int(y) / 1000000
+
+fn field_lit_bits() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = SOpt { f = d }
+ return match s.f:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn field_assign_bits() -> int:
+ d : dex, apx = 7.0
+ s : ., mut = SOpt { f = none }
+ s.f = d
+ return match s.f:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn global_bits() -> int:
+ d : dex, apx = 7.0
+ g = d
+ return match g:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn enum_payload_bits() -> int:
+ d : dex, apx = 7.0
+ e := V(d)
+ return match e:
+ V(x) =>:
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn param_scaled_ctl() -> int:
+ e : dex = 7.0
+ return take_opt(e)
+
+fn take_opt(x: dex?) -> int:
+ return match x:
+ Some(v) =>:
+ return @raw_int(v) / 1000000
+ none =>:
+ return 0
+
+fn nonopt_direct_bits() -> int:
+ d : dex, apx = 7.0
+ return take_plain(d)
+
+fn take_plain(x: dex) -> int:
+ return @raw_int(x) / 1000000
+
+fn main() -> int:
+ if four_bare_bits() != 7:
+ return 1
+ if four_bare_scaled() != 7:
+ return 2
+ if four_boxed_bits() != 7:
+ return 3
+ if four_boxed_scaled() != 7:
+ return 4
+ if assign_bits() != 7:
+ return 5
+ if ptr_write_bits() != 7:
+ return 6
+ if addr_taken_bits() != 7:
+ return 7
+ if ret_bits() != 7:
+ return 8
+ if field_lit_bits() != 7:
+ return 9
+ if field_assign_bits() != 7:
+ return 10
+ if global_bits() != 7:
+ return 11
+ if enum_payload_bits() != 7:
+ return 12
+ if param_scaled_ctl() != 7:
+ return 13
+ if nonopt_direct_bits() != 7:
+ return 14
+ return 0
diff --git a/tests/suite/params_many.cr b/tests/suite/params_many.cr
index 9631be3b..5d052d97 100644
--- a/tests/suite/params_many.cr
+++ b/tests/suite/params_many.cr
@@ -12,58 +12,97 @@
// 判据:main rc=0(逐形参值全对;任一错位返回该参数序号+1 便于定位)。
// 运行:./build/corec build tests/suite/params_many.cr -o /tmp/pm --static && /tmp/pm
-fn check18(a0: int, a1: int, a2: int, a3: int, a4: int, a5: int, a6: int, a7: int, a8: int, a9: int, a10: int, a11: int, a12: int, a13: int, a14: int, a15: int, a16: int, a17: int) -> int {
- if a0 != 1 { return 1; }
- if a1 != 2 { return 2; }
- if a2 != 3 { return 3; }
- if a3 != 4 { return 4; }
- if a4 != 5 { return 5; }
- if a5 != 6 { return 6; }
- if a6 != 7 { return 7; }
- if a7 != 8 { return 8; }
- if a8 != 9 { return 9; }
- if a9 != 10 { return 10; }
- if a10 != 11 { return 11; }
- if a11 != 12 { return 12; }
- if a12 != 13 { return 13; }
- if a13 != 14 { return 14; }
- if a14 != 15 { return 15; }
- if a15 != 16 { return 16; }
- if a16 != 17 { return 17; }
- if a17 != 18 { return 18; }
- return 0;
-}
+fn check18(a0: int, a1: int, a2: int, a3: int, a4: int, a5: int, a6: int, a7: int, a8: int, a9: int, a10: int, a11: int, a12: int, a13: int, a14: int, a15: int, a16: int, a17: int) -> int:
+ if a0 != 1:
+ return 1
+ if a1 != 2:
+ return 2
+ if a2 != 3:
+ return 3
+ if a3 != 4:
+ return 4
+ if a4 != 5:
+ return 5
+ if a5 != 6:
+ return 6
+ if a6 != 7:
+ return 7
+ if a7 != 8:
+ return 8
+ if a8 != 9:
+ return 9
+ if a9 != 10:
+ return 10
+ if a10 != 11:
+ return 11
+ if a11 != 12:
+ return 12
+ if a12 != 13:
+ return 13
+ if a13 != 14:
+ return 14
+ if a14 != 15:
+ return 15
+ if a15 != 16:
+ return 16
+ if a16 != 17:
+ return 17
+ if a17 != 18:
+ return 18
+ return 0
-fn check22(a0: int, a1: int, a2: int, a3: int, a4: int, a5: int, a6: int, a7: int, a8: int, a9: int, a10: int, a11: int, a12: int, a13: int, a14: int, a15: int, a16: int, a17: int, a18: int, a19: int, a20: int, a21: int) -> int {
- if a0 != 1 { return 1; }
- if a1 != 2 { return 2; }
- if a2 != 3 { return 3; }
- if a3 != 4 { return 4; }
- if a4 != 5 { return 5; }
- if a5 != 6 { return 6; }
- if a6 != 7 { return 7; }
- if a7 != 8 { return 8; }
- if a8 != 9 { return 9; }
- if a9 != 10 { return 10; }
- if a10 != 11 { return 11; }
- if a11 != 12 { return 12; }
- if a12 != 13 { return 13; }
- if a13 != 14 { return 14; }
- if a14 != 15 { return 15; }
- if a15 != 16 { return 16; }
- if a16 != 17 { return 17; }
- if a17 != 18 { return 18; }
- if a18 != 19 { return 19; }
- if a19 != 20 { return 20; }
- if a20 != 21 { return 21; }
- if a21 != 22 { return 22; }
- return 0;
-}
+fn check22(a0: int, a1: int, a2: int, a3: int, a4: int, a5: int, a6: int, a7: int, a8: int, a9: int, a10: int, a11: int, a12: int, a13: int, a14: int, a15: int, a16: int, a17: int, a18: int, a19: int, a20: int, a21: int) -> int:
+ if a0 != 1:
+ return 1
+ if a1 != 2:
+ return 2
+ if a2 != 3:
+ return 3
+ if a3 != 4:
+ return 4
+ if a4 != 5:
+ return 5
+ if a5 != 6:
+ return 6
+ if a6 != 7:
+ return 7
+ if a7 != 8:
+ return 8
+ if a8 != 9:
+ return 9
+ if a9 != 10:
+ return 10
+ if a10 != 11:
+ return 11
+ if a11 != 12:
+ return 12
+ if a12 != 13:
+ return 13
+ if a13 != 14:
+ return 14
+ if a14 != 15:
+ return 15
+ if a15 != 16:
+ return 16
+ if a16 != 17:
+ return 17
+ if a17 != 18:
+ return 18
+ if a18 != 19:
+ return 19
+ if a19 != 20:
+ return 20
+ if a20 != 21:
+ return 21
+ if a21 != 22:
+ return 22
+ return 0
-fn main() -> int {
- r18 := check18(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18);
- if r18 != 0 { return r18; }
- r22 := check22(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22);
- if r22 != 0 { return 40 + r22; }
- return 0;
-}
+fn main() -> int:
+ r18 := check18(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
+ if r18 != 0:
+ return r18
+ r22 := check22(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)
+ if r22 != 0:
+ return 40 + r22
+ return 0
diff --git a/tests/suite/ptr_arith.cr b/tests/suite/ptr_arith.cr
index ae25b4dd..83fe18eb 100644
--- a/tests/suite/ptr_arith.cr
+++ b/tests/suite/ptr_arith.cr
@@ -1,15 +1,16 @@
-fn main() -> int {
- arr := [10, 20, 30, 40, 50];
+fn main() -> int:
+ arr := [10, 20, 30, 40, 50]
// &arr[i] and deref
- p := &arr[2];
- if *p != 30 { return 1; }
+ p := &arr[2]
+ if *p != 30:
+ return 1
// &x and deref
- x : ., mut = 42;
- q := &x;
- *q = 99;
- if x != 99 { return 2; }
+ x : ., mut = 42
+ q := &x
+ *q = 99
+ if x != 99:
+ return 2
- return 0;
-}
+ return 0
diff --git a/tests/suite/ptr_ref_first.cr b/tests/suite/ptr_ref_first.cr
index 38970923..68a2b60f 100644
--- a/tests/suite/ptr_ref_first.cr
+++ b/tests/suite/ptr_ref_first.cr
@@ -3,10 +3,10 @@
// → p+1 退化为字节加(&x + 1)→ 地址差为 1 而非 8。
// 修复后:占位表项占住下标 8,&int 从 9 起 → PTR_ADD 按 8 字节元素缩放。
// 断言用 @raw_int 取地址原值求字节差(确定性;不依赖局部槽布局)。
-fn main() -> int {
- x : ., mut = 42;
- p := &x;
- q := p + 1; // 必须 = &x + 8(一个 int 元素),而非 &x + 1 字节
- if @raw_int(q) - @raw_int(p) != 8 { return 1; }
- return 0;
-}
+fn main() -> int:
+ x : ., mut = 42
+ p := &x
+ q := p + 1 // 必须 = &x + 8(一个 int 元素),而非 &x + 1 字节
+ if @raw_int(q) - @raw_int(p) != 8:
+ return 1
+ return 0
diff --git a/tests/suite/syscall4_test.cr b/tests/suite/syscall4_test.cr
index 7ca9aef9..8f4116f2 100644
--- a/tests/suite/syscall4_test.cr
+++ b/tests/suite/syscall4_test.cr
@@ -14,20 +14,17 @@
import io
import os
-fn main() -> int {
- rc := system("exit 3");
- if rc != 3 {
- print("FAIL: system(\"exit 3\") rc=");
- println_i(rc);
- return 1;
- }
+fn main() -> int:
+ rc := system("exit 3")
+ if rc != 3:
+ print("FAIL: system(\"exit 3\") rc=")
+ println_i(rc)
+ return 1
// 第二探针换一个值:区分「常量/陈旧缓冲区回传」与真实状态位解码。
- rc2 := system("exit 42");
- if rc2 != 42 {
- print("FAIL: system(\"exit 42\") rc=");
- println_i(rc2);
- return 2;
- }
- println("ALL PASS");
- return 0;
-}
+ rc2 := system("exit 42")
+ if rc2 != 42:
+ print("FAIL: system(\"exit 42\") rc=")
+ println_i(rc2)
+ return 2
+ println("ALL PASS")
+ return 0
diff --git a/tests/test_flow.cr b/tests/test_flow.cr
index a923fd89..68b3b3fc 100644
--- a/tests/test_flow.cr
+++ b/tests/test_flow.cr
@@ -1,16 +1,14 @@
// Test flow and yield keywords
// Counter yields 0,1,2,3,4 then exits
-flow counter() {
- i : ., mut = 0;
- loop {
- yield i;
- i = i + 1;
- if i >= 5 { break; }
- }
-}
+flow counter():
+ i : ., mut = 0
+ loop:
+ yield i
+ i = i + 1
+ if i >= 5:
+ break
-fn main() {
- go counter();
- return;
-}
+fn main():
+ go counter()
+ return
diff --git a/tests/test_go.cr b/tests/test_go.cr
index 30853806..09f7dc2d 100644
--- a/tests/test_go.cr
+++ b/tests/test_go.cr
@@ -1,15 +1,13 @@
// Minimal test for `go` keyword concurrency support
-fn worker(id: int) {
- return;
-}
+fn worker(id: int):
+ return
-fn main() {
+fn main():
// Test 1: go without count
- go worker(1);
+ go worker(1)
// Test 2: go with batch spawn
- go 4 worker(2);
+ go 4 worker(2)
- return;
-}
+ return
diff --git a/tests/test_go_range.cr b/tests/test_go_range.cr
index 6f64a303..2a56d349 100644
--- a/tests/test_go_range.cr
+++ b/tests/test_go_range.cr
@@ -1,19 +1,17 @@
// Test go range syntax: go var start end expr
// Desugars to: for var in start..end { go expr; }
-fn worker(id: int) {
- return;
-}
+fn worker(id: int):
+ return
-fn main() {
+fn main():
// Range spawn: go i 1 8 worker(i)
- go i 1 8 worker(i);
+ go i 1 8 worker(i)
// Old-style: go 4 worker(0)
- go 4 worker(0);
+ go 4 worker(0)
// Single: go worker(42)
- go worker(42);
+ go worker(42)
- return;
-}
+ return
diff --git a/tools/baseline/REBUILD.md b/tools/baseline/REBUILD.md
index 1d5d2817..30333272 100644
--- a/tools/baseline/REBUILD.md
+++ b/tools/baseline/REBUILD.md
@@ -1,6 +1,6 @@
# 冻结基线:重建配方 + sha 白名单(R2 P6 Task 1 / 交接包 E-13)
-## 这是什么
+## 定义
「**冻结基线**」= 判定面回归网**腿 ①(冻结基线同源对拍)** 里的那个「pre-批」编译器二进制:
拿它乘**当前源**,与**当前二进制**乘**当前源**逐档比(**76 档** `check` 的 rc + 日志;档数=**实读枚举**:
@@ -32,21 +32,26 @@ bash tools/baseline/rebuild.sh /tmp/p6-baseline # 产物:/tmp/p6-baseline
| 二进制 | sha256 | 源修订 |
|---|---|---|
-| `corec` | `ae01de7534ea8428e3e062fccbc5fef5d45abfc5d3dafb90b3c85e08f354cce2` | `97f4394f`(R2 P6 终态 / P6 Task 6 收官) |
-| `corearch` | `228f82e948cfaf8170ada982d80f1ebddfd3847e71cdf04ca4b42d9226373d2e` | 同上 |
-| `corelsp` | `90eb19c6d3bd4e3234b4328d8b8f3284cca6d1644d3959bb83f07b7e71473032` | 同上 |
-
-> `PINNED_REV` = `97f4394f`(**P6 终态**)——容量批(CAP:E-2 表示面聚合 / E-3 `MAX_*` 解除 /
-> E-4 收回可选程序 `.cir` 缓存)的「pre-批」侧。换代自证:重跑本配方 ⇒ 三 sha = 上表 +
-> 冒烟 42 + 确定性 ×2(rebuilt 两次逐字节同);且 `jj diff --from 97f4394f --to <本批起点树>`
-> 证明其后仅有计划文档新增(无构建输入变化)⇒ 与直接构建产物同 sha。
+| `corec` | `701a319f52696e9b098eac03b0e85ecbd6514e8d2ad05c9c30f662f62e402cdc` | `25e70197`(v4 语法迁移 T6 收官 / T7 起点) |
+| `corearch` | `bd6b1c6af5e64d20eca120e3188f05d02ee4a6f6de510516b19d47861f522e30` | 同上 |
+| `corelsp` | `2c1da86fc5c0044fb059d8d759a20a6167be18645eea43101948594949703661` | 同上 |
+
+> `PINNED_REV` = `25e70197`(**v4 迁移 T6 收官**)——**首枚可读 v4 形的基线**。与历次换代不同,
+> 本代的**换代依据是硬约束而非批次节奏**:`97f4394f` 是 v4 **之前**的修订,其 corec 只认 v3 形,
+> 而本脚本第 71 行起的冒烟已改 **v4 形**(T6b)⇒ 旧 rev 下该步必红(已知窗口态)。
+> 换代自证(2026-10-11,T7 实跑):重跑本配方 ⇒ 三 sha = 上表 + 冒烟 42 + 三 sha 与**当前工作树
+> 自建二进制**(`build/corec|corearch|corelsp`)**逐字节同**(= 输出路径无关性的直接证据)。
+> ⚠ **启用条件(见 `rebuild.sh:17` 同批注)**:源修订须**在仓内可达**——若本批经 develop
+> **squash 合入**,`25e70197` 不进 develop 历史 ⇒ 换人/换机重建失败;彼时须把 `PINNED_REV`
+> 重指到 develop 上含 v4 工作的提交并**同批重锁三 sha**(旧值留痕 = 本表 + `rebuild.sh` 注)。
## 白名单历史(**旧值不删**——换代纪律 2;本表 = 历次换代清单)
| 代 | 源修订 | `corec` | `corearch` | `corelsp` | 理由 / 出处 |
|---|---|---|---|---|---|
| 初代 | `9bcb7083`(R2 P4 收官 / P4 Task 7) | `5d2b15ad746018619b01143cce400e6f3489ae72a962e12283a7afd3dcdb41e7` | `493dc490dfaed7774b46b74ccf1cfeca9fe5f61620e34229afb8991b1628a2a7` | `18b94bd955fa204accf0753095a28f6499871566254d846333a7496c99109d49` | P5 批的 pre-侧(P6 T0 §1.4:与本配方产物逐字节 IDENTICAL ×3,白名单自洽) |
-| **2 代(现行)** | `97f4394f`(R2 P6 终态) | `ae01de75…`(全值见上表) | `228f82e9…`(全值见上表) | `90eb19c6…`(全值见上表) | 容量批 CAP 的 pre-侧;换代依据 = 换代纪律 1(下一批以本批收官为 pre-侧);自证见「现行代」注与 `cap-task1-report.md` |
+| 2 代 | `97f4394f`(R2 P6 终态) | `ae01de75…`(全值见本行原值注) | `228f82e9…` | `90eb19c6…` | 容量批 CAP 的 pre-侧;换代依据 = 换代纪律 1(下一批以本批收官为 pre-侧);自证见 `cap-task1-report.md`。**2026-10-11(T7)换代后降为历史代**——旧全值留痕:corec `ae01de7534ea8428e3e062fccbc5fef5d45abfc5d3dafb90b3c85e08f354cce2` · corearch `228f82e948cfaf8170ada982d80f1ebddfd3847e71cdf04ca4b42d9226373d2e` · corelsp `90eb19c6d3bd4e3234b4328d8b8f3284cca6d1644d3959bb83f07b7e71473032` |
+| **3 代(现行)** | `25e70197`(v4 迁移 T6 收官) | `701a319f…`(全值见上表) | `bd6b1c6a…`(全值见上表) | `2c1da86f…`(全值见上表) | **v4 基线**:首枚可读 v4 形的 pre-侧;换代依据 = **v4 可读性硬约束**(见「现行代」注)。自证(2026-10-11 实跑)= 重建三 sha = 上表 + 冒烟 42 + 与工作树自建二进制逐字节同 |
## 用法
@@ -74,12 +79,14 @@ bash tools/baseline/warm_run.sh ./build/corec /tmp/warm_now # 牙齿层(语
- **广度层**:`parity_run.sh` / `probes_run.sh` 默认附带(清单单一依据 = `/corpus.tsv`;
结果落 `/warm/`,**`logs/` 格式不变** ⇒ 历史对拍可比性保持)。`WARM_LEG=0` 关闭。
- 对 **pre-fix 冻结基线预期绿**(既有 75/29 语料不含 `as *T` 形态;实测 M1 二进制 75 档 FAIL=0)。
+ 对 **pre-fix 冻结基线预期绿**(既有 **75/29 语料**不含 `as *T` 形态;实测 M1 二进制 **75 档** FAIL=0)。
+ **〔2026-10-11 补正〕**本行「75 档」= **当时值**;parity 语料现为 **76 档**(`tests/suite/*.cr` **36** + …,
+ 见本档 §定义与 `parity_run.sh:32` 的 `CORPUS_TOTAL=76` 硬断言)——**不得当当前语料数**。
- **牙齿层**:`tests/probes/warm/`(**定路径**是该语料的设计要点;拷到唯一 temp 路径 ⇒ 判据恒绿而
空洞 —— 突变 M3 实证)。**pre-fix 二进制在本层必红**(缺陷本体)⇒ 对**冻结基线**调用
`warm_run.sh` 时预期 rc=1,**不是**基线不合规(判据 = 突变 M1,见 `warm-task3-report.md`)。
- 时长实测(2026-09-15,本机):牙齿层 **0.9s** · probes 广度层 **+3.5s** · parity 广度层
- **+125s**(**75 档** ×2 次 `ccr`,大文件为主;**⚠ 该值对含 `src/compiler/main.cr` 的大文件档不成立**——
+ **+125s**(**75 档**〔**当时值;现 76 档**〕×2 次 `ccr`,大文件为主;**⚠ 该值对含 `src/compiler/main.cr` 的大文件档不成立**——
见 `TODO #2026-09-17-8`:实测该层在含大文件的清单上 ≥7× 且未跑完)⇒ **CI 只挂最小面**(`tests/selfhost/test_warm_cache_gate.py`,0.5s),
广度层留手工判据。
- **判据本体不进 CI**(维护者裁定 2026-09-15):与套件**同语料**、覆盖重叠,收益仅「校验 runner 自身」。
@@ -127,13 +134,20 @@ bash tools/baseline/warm_run.sh ./build/corec /tmp/warm_now # 牙齿层(语
- **CI 内不跑**:`.github/workflows/core-ci.yml` 用 `actions/checkout` + `fetch-depth: 2`(浅检出,
无 `jj`)⇒ pinned revision 在 CI 环境**不可得**。本判据为**手工判据**(每任务/每批收尾跑),
故入仓的是**可复现性**而非 CI 挂钩(R2 P6 Task 1 §Step 4 评估结论)。
-- **75 档语料的既有 rc=1 不是回归**(2026-09-17 批 6 T6 **实测**:`36×0 / 39×1`):
+- **75 档语料〔**当时值;现 76 档**,见下行注〕的既有 rc=1 不是回归**(2026-09-17 批 6 T6 **实测**:`36×0 / 39×1`):
**〔2026-09-24 加注(原文保留)〕语料已增至 76 档**(#132 加 `tests/suite/cli_view_test.cr`)⇒ 本行的
`36×0 / 39×1` 是 **75 档时**的实测值;**76 档的分布与划界**须在下次采基线时重采。
**本批实测(2026-09-24)**:用 `core-ctfeas-ws` 的二进制(**2026-09-23 07:49 构建 ⇒ 不是 develop 当前二进制**)
跑计数腿 ⇒ **PASS,76 档 · rc 分布 `44×0 / 32×1`**。⚠ **该分布属于那枚二进制,不得当基线**;
与上行旧值的差(rc=0 从 36 升到 44、rc=1 从 39 降到 32,语料净 +1)⇒ **7 档由 rc=1 翻为 rc=0**(能力变更,非回归),
**划界清单须用 develop 自建二进制重划后才能当「既有失败」用**。
+ **〔2026-10-11 T7 采基线·v4〕**用**本代冻结基线**(`25e70197` 自建,`corec` sha `701a319f…`)
+ 重划 76 档计数腿 ⇒ **PASS · rc 分布 `43×0 / 33×1`**(分层 rc=1:t1 **7** · t2 **1** · t3 **13** ·
+ t4 **10** · t5 **2** = 33)。t1 的 7 档 = `apx_conversion_test` · `at_test_mini4` · `at_test_mini6`
+ (`*_mini*` ⇒ CI `suite` job 跳过)· `opt_dex_test` · `ptr_arith`(**B04** borrow)· `test_control_flow` ·
+ `test_generics`(空 fixture `cannot read`)。⚠ 与上行 2026-09-24 那枚二进制的 `44×0 / 32×1` **差 1 档(0→1)**
+ ——**归属未定**:跨二进制(且那枚非 develop 自建)⇒ 须以 **代 0 基线**(批外冻结,见 v4 计划 §二.1)逐档
+ 码集对拍方能判是否回归;**本条不作回归声明**(本批 rc 等价口径 = 代 0 逐档码集,§二.2 B1/B2)。
**⇒ 本文档他处出现的「75 档」同属 76 档之前的实测值**(牙齿层的「既有 75/29 语料」`+125s(75 档 ×2 次 ccr)`)——
**不得当当前语料数**;`src/ci/run.sh` 里那处同款引用已于 2026-09-24 一并补正。
空 fixture ×2(`tests/suite/{test_control_flow,test_generics}.cr`,日志 = `error: cannot read`)·
diff --git a/tools/baseline/canary_values.tsv b/tools/baseline/canary_values.tsv
index 8207c9ad..a175a946 100644
--- a/tools/baseline/canary_values.tsv
+++ b/tools/baseline/canary_values.tsv
@@ -226,3 +226,38 @@ gt_static_ccr gt_st.bin.ccr bbfe47897c8fb97f9cc38ffbfe6043577604ef86595760db55cd
# pa_ccr `f06bf45bcd9de1951190ec8ccee6f28684390beee5d3ccca811a8079add988f3` 96945
# pa_static_ccr `76df0adf92d63a7fe986af2f0c6bd3149ec512287ab936a7159e35013a5dd15d` 97088
# **出处**:PR #153 · 提交 `dff1c93d`(S1+S3,**引起**)· `6045d1e6`(S2+S6,**无增**)· 本表重锁与其同批。
+
+# ── 【T7 复验 2026-10-11】v4 语法迁移收尾——**结论 = 本表五值不动(无变化 ⇒ 无重锁)** ──
+# **这不是「跳过重锁」,是一次实测为「零变化」的重锁检查**(本文件两级纪律:**禁止的不是变化,
+# 是无声变化**;没有变化时,正确动作就是**不动值表**,并在此**留痕这次检查**)。
+# **实测环境(钉在 binary sha + 语料 rev 上,勿凭字面量复用)**:
+# 编译器 = 工作树自建 `build/corec` sha256 `701a319f52696e9b098eac03b0e85ecbd6514e8d2ad05c9c30f662f62e402cdc`
+# (= 由 `tools/baseline/rebuild.sh` 从 `25e70197` 重建产物,**逐字节印证**;见 `REBUILD.md` 现行代注);
+# 语料 rev = `25e70197`(v4 迁移 T6 收官;工作树 = 该提交 + T7 未提交改动);口径 = `canary_check.sh`(冷态 + 空 HOME 归一化)。
+# **D1 确定性闸门(重锁前置,硬要求):5/5 PASS**——canary_elf / pa_ccr / pa_static_ccr / gt_ccr / gt_static_ccr
+# 各自两次构建 `cmp` 逐字节相同。⇒ 前置门绿,具备重锁资格。
+# **F3 逐条比对本表:5/5 PASS,逐条 sha256 **与** size 全同**(无一项变化):
+# canary_elf `f1137275…4dde` 28854(不变)
+# pa_ccr `d6ebe3d1…1b10` 96985(不变)
+# pa_static_ccr `041b6e3e…5f62` 97128(不变)
+# gt_ccr `edfd8e98…9dd22` 143687(不变)
+# gt_static_ccr `bbfe4789…0c97` 143830(不变)
+# **归因(为什么 v4 大改而产物零变化——必须写清,否则「不变」本身可疑)**:
+# ① 本批是**前端形状迁移**(`{}`→layout region、`;`→换行、`None`→`none` 拼写、`@` 前导化),
+# **不动发射器/后端的码生成路径**(T4/T5 逐字只改前端读法与 corpus 形状);
+# ② STR 段 = 编译器在**编译入料时**的 intern 表,其**内容/次序由被编译程序驱动**,不由**编译器
+# 自身源文本的排版**驱动 ⇒ 源从 braces 改 layout **不新增/不重排** intern 串(字符串字面量的
+# **集合**未变,只是它们的**书写形状**变了);
+# ③ 两档入料(`ptr_arith.cr` 零 import;`generics_test.cr`)未含 `None`/`dyn`/`never` 等**拼写被改的
+# 关键字**到足以改变 tag 串的程度(实测五值与 v3 末代逐字节同 ⇒ 该语料面无拼写足迹)。
+# ⇒ 结论 = **v4 迁移在两档 canary 语料上「发射面 + 序列化面」零足迹**——对 canary ELF 这条
+# 「发射面零泄漏检测器」而言,这是**最强结果**(预期即「不该变」,实测「不变」)。
+# **反向对照(证明本闸门不是恒绿)**:见下方「T7 反向对照」实测记录。
+# **出处**:本批 T7 施工;`canary_check.sh` 采集日志(D1×5 PASS + F3×5 PASS)。
+#
+# ── T7 反向对照(2026-10-11 实测)──────────────────────────────────────────────
+# 取本表副本 `CANARY_VALUES=` 将 `pa_ccr` 的 sha 换回 **2026-09-20 旧代值**
+# `f06bf45bcd9de1951190ec8ccee6f28684390beee5d3ccca811a8079add988f3`(size 96945 亦改),
+# 对**同一采集目录**跑 `--verify-only` ⇒ **F3 必红**(sha + size 双向不符)。
+# ⇒ 「值表与本表不一致时闸门必红」成立(本闸门非恒绿;此即 J-T7-1 反向对照在本「零变化」
+# 结论下的等价形态——**没有重锁就没有「改回旧值」**,故以「植入旧值即红」代之)。
diff --git a/tools/baseline/rebuild.sh b/tools/baseline/rebuild.sh
index 64ba4c4c..e291dd9c 100644
--- a/tools/baseline/rebuild.sh
+++ b/tools/baseline/rebuild.sh
@@ -14,12 +14,24 @@ set -euo pipefail
# 换代(2026-09-14,容量批 CAP Task 1):PINNED_REV 9bcb7083(P4 收官)→ 97f4394f(P6 终态 /
# 本批起点)。依据 = `REBUILD.md`「换代纪律」1/2(下一批以本批收官为 pre-侧;旧值留痕)。
# 旧代三 sha(9bcb7083):corec 5d2b15ad… · corearch 493dc490… · corelsp 18b94bd9…(全值见 REBUILD.md 历史表)。
-PINNED_REV="97f4394f" # P6 终态(R2 P6 Task 6 收官)/ 容量批起点
+#
+# 换代(2026-10-11,v4 语法迁移 T7):PINNED_REV 97f4394f → **25e70197**(v4 迁移 T6 收官 / T7 起点)。
+# **依据 = v4 可读性硬约束**(本批与历次换代不同,必须写清):`97f4394f` 是 **v4 之前**的修订,
+# 其 corec **只认 v3 形**;而本脚本第 71 行起的冒烟已改 **v4 形**(T6b)⇒ 换代前该步**必红**(已知窗口态)。
+# 新 rev 的唯一硬要求 = **含本批 v4 工作的提交**(能读 v4 形)。取 `25e70197`(= 迁移批 T6 收官,
+# = 本 T7 的起点)承接「下一批以本批收官为 pre-侧」的既有口径。
+# ⚠ **启用条件(换代纪律 3)**:本条生效时其源修订须**在仓内可达**——本批经 develop 合入时**若为
+# squash**,`25e70197` 这条 jj 提交不进 develop 历史(仅本地 object store 暂存)⇒ 换人/换机重建会失败。
+# 故合入方式若非「保留提交」(merge commit / rebase-merge),须**同批把 PINNED_REV 重指到 develop 上
+# 含 v4 工作的提交**并同批重锁三 sha(**留痕**:本条即旧值出处)。
+# 旧代三 sha(97f4394f = v3 末代):corec `ae01de75…` · corearch `228f82e9…` · corelsp `90eb19c6…`
+# (全值见 `REBUILD.md` 历史表)。
+PINNED_REV="25e70197" # v4 迁移 T6 收官 / T7 起点(**首枚可读 v4 形的基线**)
WS_NAME="p6-baseline-build" # 临时 workspace 名(收工 forget)
-WHITELIST_COREC="ae01de7534ea8428e3e062fccbc5fef5d45abfc5d3dafb90b3c85e08f354cce2"
-WHITELIST_COREARCH="228f82e948cfaf8170ada982d80f1ebddfd3847e71cdf04ca4b42d9226373d2e"
-WHITELIST_CORELSP="90eb19c6d3bd4e3234b4328d8b8f3284cca6d1644d3959bb83f07b7e71473032"
+WHITELIST_COREC="701a319f52696e9b098eac03b0e85ecbd6514e8d2ad05c9c30f662f62e402cdc"
+WHITELIST_COREARCH="bd6b1c6af5e64d20eca120e3188f05d02ee4a6f6de510516b19d47861f522e30"
+WHITELIST_CORELSP="2c1da86fc5c0044fb059d8d759a20a6167be18645eea43101948594949703661"
usage() { echo "usage: bash tools/baseline/rebuild.sh " >&2; exit 2; }
[ $# -eq 1 ] || usage
@@ -68,7 +80,14 @@ mkdir -p "$OUTDIR"
cp "$WS_DIR/build/corec" "$WS_DIR/build/corearch" "$WS_DIR/build/corelsp" "$OUTDIR/"
set +e
-nice -n 19 "$OUTDIR/corec" run 'fn main()->int{return 42;}' >"$TMPBASE/smoke.out" 2>&1
+# v4 迁移 T6b:内联 Core 冒烟改 v4 形(`:` + layout 缩进 + 换行分隔)。旧形
+# `fn main()->int{return 42;}` 在 v4 前端下是 `error[P03]`(`{` 只作结构体字面量定界符)。
+# ⚠ 与 `PINNED_REV` 的**换代耦合**:白名单里的三 sha 出自 `97f4394f`(2026-09-14,
+# **v4 之前**)⇒ 那枚 corec 只认 v3 形。本行改 v4 后,**必须**由 T7 把 `PINNED_REV`
+# 一并换到 v4 可读的修订(计划 §九 J-T7-2/J-T7-3 的重锁对象 #4),否则重建的冒烟步会红。
+nice -n 19 "$OUTDIR/corec" run 'fn main() -> int:
+ return 42
+' >"$TMPBASE/smoke.out" 2>&1
smoke_rc=$?
set -e
if [ "$smoke_rc" -ne 42 ]; then
diff --git a/tools/cir-str-domain/probes/label_collision.cr b/tools/cir-str-domain/probes/label_collision.cr
index 82d7904b..97dc3057 100644
--- a/tools/cir-str-domain/probes/label_collision.cr
+++ b/tools/cir-str-domain/probes/label_collision.cr
@@ -1,79 +1,90 @@
import io
-fn f1(n: int) -> int {
- s : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- if i % 3 == 0 { s = s + i * 2; } else { s = s + 1; }
- i = i + 1;
- }
- return s;
-}
+fn f1(n: int) -> int:
+ s : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ if i % 3 == 0:
+ s = s + i * 2
+ else:
+ s = s + 1
+ i = i + 1
+ return s
-fn f2(n: int) -> int {
- s : ., mut = 1;
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- if i % 2 == 0 { s = s * 2; } else { s = s + 3; }
- i = i + 1;
- }
- return s;
-}
+fn f2(n: int) -> int:
+ s : ., mut = 1
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ if i % 2 == 0:
+ s = s * 2
+ else:
+ s = s + 3
+ i = i + 1
+ return s
-fn f3(n: int) -> int {
- s : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- if i % 5 == 0 { s = s + 7; } else { s = s - 2; }
- i = i + 1;
- }
- return s;
-}
+fn f3(n: int) -> int:
+ s : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ if i % 5 == 0:
+ s = s + 7
+ else:
+ s = s - 2
+ i = i + 1
+ return s
-fn f4(n: int) -> int {
- s : ., mut = 3;
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- if i > 3 { s = s + i; } else { s = s * 2; }
- i = i + 1;
- }
- return s;
-}
+fn f4(n: int) -> int:
+ s : ., mut = 3
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ if i > 3:
+ s = s + i
+ else:
+ s = s * 2
+ i = i + 1
+ return s
-fn f5(n: int) -> int {
- s : ., mut = 0;
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- if i % 4 == 1 { s = s + 11; } else { s = s - 5; }
- i = i + 1;
- }
- return s;
-}
+fn f5(n: int) -> int:
+ s : ., mut = 0
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ if i % 4 == 1:
+ s = s + 11
+ else:
+ s = s - 5
+ i = i + 1
+ return s
-fn f6(n: int) -> int {
- s : ., mut = 2;
- i : ., mut = 0;
- loop {
- if i >= n { break; }
- if i % 3 == 2 { s = s - 6; } else { s = s + 13; }
- i = i + 1;
- }
- return s;
-}
+fn f6(n: int) -> int:
+ s : ., mut = 2
+ i : ., mut = 0
+ loop:
+ if i >= n:
+ break
+ if i % 3 == 2:
+ s = s - 6
+ else:
+ s = s + 13
+ i = i + 1
+ return s
-fn main() -> int {
- a := f1(10);
- b := f2(9);
- c := f3(8);
- d := f4(7);
- e := f5(6);
- f := f6(5);
- print("R=");
- println(int_str(a + b + c + d + e + f));
- return 0;
-}
+fn main() -> int:
+ a := f1(10)
+ b := f2(9)
+ c := f3(8)
+ d := f4(7)
+ e := f5(6)
+ f := f6(5)
+ print("R=")
+ println(int_str(a + b + c + d + e + f))
+ return 0
diff --git a/tools/cir-str-domain/probes/repro_6line.cr b/tools/cir-str-domain/probes/repro_6line.cr
index ee2fe7fe..b6114519 100644
--- a/tools/cir-str-domain/probes/repro_6line.cr
+++ b/tools/cir-str-domain/probes/repro_6line.cr
@@ -1,19 +1,19 @@
import io
-struct Point { x: int, y: int }
+struct Point:
+ x: int, y: int
-fn test_fields_basic() -> int {
- flds := @fields(Point);
- print("fields=[");
- print(flds);
- print("] len=");
- println(int_str(str_len(flds)));
- if str_len(flds) != 3 { return 1; }
- return 0;
-}
+fn test_fields_basic() -> int:
+ flds := @fields(Point)
+ print("fields=[")
+ print(flds)
+ print("] len=")
+ println(int_str(str_len(flds)))
+ if str_len(flds) != 3:
+ return 1
+ return 0
-fn main() -> int {
- r := test_fields_basic();
- println(int_str(r));
- return r;
-}
+fn main() -> int:
+ r := test_fields_basic()
+ println(int_str(r))
+ return r
diff --git a/tools/cir-str-domain/probes/scope_concat.cr b/tools/cir-str-domain/probes/scope_concat.cr
index eace3827..ecafed3b 100644
--- a/tools/cir-str-domain/probes/scope_concat.cr
+++ b/tools/cir-str-domain/probes/scope_concat.cr
@@ -1,11 +1,10 @@
import io
-fn concat_helper() -> int {
- print("C_AB="); println("AA" + "BB");
- return 0;
-}
+fn concat_helper() -> int:
+ print("C_AB=")
+ println("AA" + "BB")
+ return 0
-fn main() -> int {
- concat_helper();
- return 0;
-}
+fn main() -> int:
+ concat_helper()
+ return 0
diff --git a/tools/cir-str-domain/probes/scope_fields.cr b/tools/cir-str-domain/probes/scope_fields.cr
index d3849c4a..af697e81 100644
--- a/tools/cir-str-domain/probes/scope_fields.cr
+++ b/tools/cir-str-domain/probes/scope_fields.cr
@@ -1,16 +1,19 @@
import io
-struct Point { x: int, y: int }
-struct Pair { a: int, b: str }
+struct Point:
+ x: int, y: int
+struct Pair:
+ a: int, b: str
-fn fields_helper() -> int {
- print("F_POINT="); println(@fields(Point));
- print("F_PAIR="); println(@fields(Pair));
- return 0;
-}
+fn fields_helper() -> int:
+ print("F_POINT=")
+ println(@fields(Point))
+ print("F_PAIR=")
+ println(@fields(Pair))
+ return 0
-fn main() -> int {
- print("F_MAIN="); println(@fields(Point));
- fields_helper();
- return 0;
-}
+fn main() -> int:
+ print("F_MAIN=")
+ println(@fields(Point))
+ fields_helper()
+ return 0
diff --git a/tools/cir-str-domain/probes/scope_firstintern.cr b/tools/cir-str-domain/probes/scope_firstintern.cr
index a716edb1..b51b2ca7 100644
--- a/tools/cir-str-domain/probes/scope_firstintern.cr
+++ b/tools/cir-str-domain/probes/scope_firstintern.cr
@@ -1,10 +1,13 @@
import io
-struct One { x: int }
-struct Two { x: int, y: int }
+struct One:
+ x: int
+struct Two:
+ x: int, y: int
-fn main() -> int {
- print("ONE="); println(@fields(One));
- print("TWO="); println(@fields(Two));
- return 0;
-}
+fn main() -> int:
+ print("ONE=")
+ println(@fields(One))
+ print("TWO=")
+ println(@fields(Two))
+ return 0
diff --git a/tools/cir-str-domain/probes/scope_interp.cr b/tools/cir-str-domain/probes/scope_interp.cr
index 626e7599..92426284 100644
--- a/tools/cir-str-domain/probes/scope_interp.cr
+++ b/tools/cir-str-domain/probes/scope_interp.cr
@@ -1,12 +1,11 @@
import io
-fn interp_helper() -> int {
- n := 7;
- print("I_V="); println("n=${n}");
- return 0;
-}
+fn interp_helper() -> int:
+ n := 7
+ print("I_V=")
+ println("n=${n}")
+ return 0
-fn main() -> int {
- interp_helper();
- return 0;
-}
+fn main() -> int:
+ interp_helper()
+ return 0
diff --git a/tools/cir-str-domain/probes/scope_lit.cr b/tools/cir-str-domain/probes/scope_lit.cr
index c8a11283..7c0e3eab 100644
--- a/tools/cir-str-domain/probes/scope_lit.cr
+++ b/tools/cir-str-domain/probes/scope_lit.cr
@@ -1,12 +1,10 @@
import io
-fn helper() -> int {
- println("HELPER_LITERAL");
- return 0;
-}
+fn helper() -> int:
+ println("HELPER_LITERAL")
+ return 0
-fn main() -> int {
- println("MAIN_LITERAL");
- helper();
- return 0;
-}
+fn main() -> int:
+ println("MAIN_LITERAL")
+ helper()
+ return 0
diff --git a/tools/cir-str-domain/probes/scope_partial.cr b/tools/cir-str-domain/probes/scope_partial.cr
index afdd18bb..374f8cd6 100644
--- a/tools/cir-str-domain/probes/scope_partial.cr
+++ b/tools/cir-str-domain/probes/scope_partial.cr
@@ -1,8 +1,9 @@
import io
-struct Two { x: int, y: int }
+struct Two:
+ x: int, y: int
-fn main() -> int {
- print("TWO="); println(@fields(Two));
- return 0;
-}
+fn main() -> int:
+ print("TWO=")
+ println(@fields(Two))
+ return 0
diff --git a/tools/cir-str-domain/probes/scope_typeinfo.cr b/tools/cir-str-domain/probes/scope_typeinfo.cr
index fd0e8b1f..2eb0e8f5 100644
--- a/tools/cir-str-domain/probes/scope_typeinfo.cr
+++ b/tools/cir-str-domain/probes/scope_typeinfo.cr
@@ -1,14 +1,15 @@
import io
-struct Point { x: int, y: int }
+struct Point:
+ x: int, y: int
-fn tinfo_helper() -> int {
- print("T_POINT="); println(@typeInfo(Point));
- print("T_INT="); println(@typeInfo(int));
- return 0;
-}
+fn tinfo_helper() -> int:
+ print("T_POINT=")
+ println(@typeInfo(Point))
+ print("T_INT=")
+ println(@typeInfo(int))
+ return 0
-fn main() -> int {
- tinfo_helper();
- return 0;
-}
+fn main() -> int:
+ tinfo_helper()
+ return 0
diff --git a/tools/cir-str-domain/probes/undefined_name.cr b/tools/cir-str-domain/probes/undefined_name.cr
index 21ad320c..93d9b491 100644
--- a/tools/cir-str-domain/probes/undefined_name.cr
+++ b/tools/cir-str-domain/probes/undefined_name.cr
@@ -1,14 +1,12 @@
import io
-fn a(x: int, y: int) -> int {
- return x + y;
-}
+fn a(x: int, y: int) -> int:
+ return x + y
-fn b() -> int {
- return zzz;
-}
+fn b() -> int:
+ return zzz
-fn main() -> int {
- print("A="); println(int_str(a(1, 2)));
- return b();
-}
+fn main() -> int:
+ print("A=")
+ println(int_str(a(1, 2)))
+ return b()
diff --git a/tools/mctt_ref/README.md b/tools/mctt_ref/README.md
index a9fbaedd..c7fc2806 100644
--- a/tools/mctt_ref/README.md
+++ b/tools/mctt_ref/README.md
@@ -1,13 +1,13 @@
# McTT 参考侧(Task 1:参考侧构建记录)
-McTT(ICFP'25,Beluga-lang)——首个经 Coq 验证的 MLTT 类型检查器。本目录记录参考侧的构建与验证信息,供后续差分测试(Task 3+)harness 使用。
+McTT(ICFP'25,Beluga-lang)是首个经 Coq 验证的 MLTT 类型检查器。本目录记录参考侧的构建与验证信息,供后续差分测试(Task 3+)的 harness 使用。
## 位置与版本
-- 源码:`~/mctt`(**仓库外**,不提交 McTT 源码进本仓库)
-- 分支:`icfp25`,头 `a3d97e9c427d311566ba25540292d55be4adfdba`(gh api 确认)
-- 获取方式:curl tarball(`https://github.com/Beluga-lang/McTT/archive/refs/heads/icfp25.tar.gz`)。
- git clone 因本机到 github.com 网络不稳超时失败;tarball 亦间歇失败,重试成功。
+- 源码:`~/mctt`(**仓库外**,McTT 源码不提交进本仓库)
+- 分支:`icfp25`,头 `a3d97e9c427d311566ba25540292d55be4adfdba`(经 `gh api` 确认)
+- 获取方式为 curl tarball(`https://github.com/Beluga-lang/McTT/archive/refs/heads/icfp25.tar.gz`)。
+ `git clone` 因本机到 github.com 网络不稳超时失败;tarball 亦间歇失败,重试后成功。
## 构建配方(实际执行,已成功)
@@ -22,29 +22,29 @@ opam install -y menhir coq-equations coq-menhirlib ppx_inline_test ppx_expect
cd ~/mctt && make # theories(Coq 证明 + extraction)→ dune build(driver)
```
-**实际执行脚本:`~/mctt/build_ref.sh`**(set -e,可续跑:已建 switch/已装包一律跳过),
+**实际执行脚本:`~/mctt/build_ref.sh`**(`set -e`,可续跑:已建 switch/已装包一律跳过),
配套 `~/mctt/curl_gh.sh`(见「网络问题与修复」)。
### 对官方配方的必要修正
-1. `opam install` 显式补装 `dune`——官方配方漏列,新建 switch 无 dune 则 `dune build` 必失败。
-2. **ppx_inline_test/ppx_expect 保留不跳**——检查结论:driver/dune 的 McttLib 库有**库级**
- `(preprocess (pps ppx_expect))`,而 mctt.exe 链接 McttLib,故主构建在 dune 编译期需要
- ppx_expect 可执行文件(ppx 虽是 Test.ml inline-tests 的测试框架,但预处理指令作用于整个库)。
- 结论:主构建**依赖** ppx,不能跳过;已安装成功(ppxlib.0.35.0 / ppx_inline_test.v0.16.1 /
+1. `opam install` 须显式补装 `dune`:官方配方漏列该项,新建 switch 若无 dune,`dune build` 必然失败。
+2. **ppx_inline_test/ppx_expect 须保留,不得跳过**:检查结论为 driver/dune 的 McttLib 库存在**库级**
+ `(preprocess (pps ppx_expect))` 指令,而 `mctt.exe` 链接 McttLib,故主构建在 dune 编译期需要
+ ppx_expect 可执行文件(ppx 虽为 Test.ml inline-tests 的测试框架,但预处理指令作用于整个库)。
+ 结论为主构建**依赖** ppx,不能跳过;已安装成功(ppxlib.0.35.0 / ppx_inline_test.v0.16.1 /
ppx_expect.v0.16.2)。
-3. CPU 限制(仓库铁律 #6):外层 `nice -n 19` + `OPAMJOBS=2`(opam 内 OCaml/Coq 编译)
- + `make -C theories J=2` + `dune build -j 2`。本机 4 核,全量构建约 2-3 小时。
+3. CPU 限制(仓库铁律 #6)为外层 `nice -n 19` 配合 `OPAMJOBS=2`(opam 内 OCaml/Coq 编译)、
+ `make -C theories J=2` 与 `dune build -j 2`。本机 4 核,全量构建约 2-3 小时。
### 网络问题与修复(github.com 主域 TLS 间歇重置)
-- 现象:github.com 主域(默认 DNS 20.205.243.166)TLS 连接间歇重置(curl exit 35),
- 且各 IP 不同时坏;重试 15 次仍可能全灭(曾两次卡在源码拉取、一次卡在 ppx 拉取)。
-- 修复:`OPAMCURL="$HOME/mctt/curl_gh.sh"`——包装 curl 对 github.com:443 做**多 IP 轮换**
+- 现象为 github.com 主域(默认 DNS 20.205.243.166)TLS 连接间歇重置(curl exit 35),
+ 且各 IP 不同时失效;重试 15 次仍可能全部失败(曾两次停在源码拉取、一次停在 ppx 拉取)。
+- 修复方式为 `OPAMCURL="$HOME/mctt/curl_gh.sh"`:包装 curl 对 github.com:443 做**多 IP 轮换**
(140.82.114.3 / 140.82.112.3 / 140.82.113.3 / 140.82.116.3 / 140.82.121.3 / 20.205.243.166),
- 成功者 stdout 原样透传(opam 解析 --write-out 的 http 码)。配 `OPAMRETRIES=15` 兜底。
+ 成功者 stdout 原样透传(opam 解析 `--write-out` 的 http 码),并配 `OPAMRETRIES=15` 兜底。
- codeload.github.com / raw.githubusercontent.com / release-assets.githubusercontent.com
- 走正常 DNS 无问题。
+ 走正常 DNS,无此问题。
## 构建状态:**COMPLETE**(2026-08-16 00:12)
@@ -56,9 +56,9 @@ cd ~/mctt && make # theories(Coq 证明 + extraction)→ dune build
## 用法(以源码为准,已实测)
-- 可执行文件:`~/mctt/_build/default/driver/mctt.exe`(**带 driver/ 段**;不是 `Main.exe`——
- driver/dune 中 executable 为 `name mctt`、模块 `Mctt.ml`,`Main.ml` 在 McttLib 库内)。
-- 用法(Mctt.ml 源码确认,单参数 ``;缺参打印 usage 并 exit 7):
+- 可执行文件为 `~/mctt/_build/default/driver/mctt.exe`(**含 driver/ 段**;不是 `Main.exe`,因
+ driver/dune 中 executable 为 `name mctt`、模块为 `Mctt.ml`,`Main.ml` 在 McttLib 库内)。
+- 用法(经 Mctt.ml 源码确认,单参数 ``;缺参时打印 usage 并 exit 7):
```bash
cd ~/mctt
@@ -66,7 +66,7 @@ cd ~/mctt
opam exec --switch=coq-8.20.0 -- dune exec mctt -- examples/simple_nat.mctt # 或经 dune
```
-- exit 0 = 类型检查通过。注意:dune 必须在 coq-8.20.0 switch 环境跑(default switch 无 ppx_expect,
+- exit 0 表示类型检查通过。注意 dune 必须在 coq-8.20.0 switch 环境运行(default switch 无 ppx_expect,
会报 "Library ppx_expect not found")。
## 冒烟测试结果(2026-08-16,已验证)
@@ -84,7 +84,7 @@ $ echo $? # 0
## extracted 模块清单(构建完成,`ls driver/extracted/*.mli` 实测 40 个)
-提取代码由构建期生成(**McTT 仓库的 driver/extracted/ 本身不含任何 .ml/.mli**——icfp25 与
+提取代码由构建期生成(**McTT 仓库的 `driver/extracted/` 本身不含任何 `.ml`/`.mli`**:icfp25 与
icfp25-artifact 标签树均已核对,只有 dune/.gitignore/.ocamlformat 三个文件)。
**McTT 核心(Task 3 harness 的差分对拍目标):**
@@ -100,7 +100,7 @@ icfp25-artifact 标签树均已核对,只有 dune/.gitignore/.ocamlformat 三
## 环境备注
- switch `coq-8.20.0`(OCaml 4.14.2,独立于 default switch 5.4.1)。
-- 本仓库禁止 git(hook 机械拦截);McTT 克隆/构建为第三方仓库操作,git/curl 均只作用于 ~/mctt。
+- 本仓库禁止 git(hook 机械拦截);McTT 的克隆与构建属第三方仓库操作,git/curl 均只作用于 `~/mctt`。
## Task 3 补充:harness 入口签名(侦查实测,以提取 .mli 为准)
@@ -121,23 +121,23 @@ harness 接线用到的真实模块与签名(`driver/extracted/*.mli`,均位
1. **提取库是 wrapped**:`(library (name McttExtracted) (public_name mctt.extracted))`
无 `wrapped false`;外部必须写 `McttExtracted.TypeCheck` 等(driver/Main.ml 即
`module Parser = McttExtracted.Parser` 的写法)。
-2. **`type_check` 参数序是 (ctx, 类型, 项)**——协议行 `check <项> <类型>`
- 接线时必须交换实参(踩坑:不交换时 `check (ctx) (zero) (nat)` 会因
+2. **`type_check` 的参数序是 (ctx, 类型, 项)**:协议行 `check <项> <类型>`
+ 接线时必须交换实参(实测不交换时 `check (ctx) (zero) (nat)` 会因
`nbe_ty (zero)` 触发 Readback.ml:60 assert 崩溃)。
3. **语义总化**:提取代码对前提不满足的输入触发 `assert false`
(Readback.ml:17/27/28/60、Evaluation.ml:33/45/46);harness 统一捕获
- Assert_failure 按拒绝态处理(协议 §5)。`type_infer` 对任意语法良构输入
+ `Assert_failure` 并按拒绝态处理(协议 §5)。`type_infer` 对任意语法良构输入
为全函数(逐分支核实,无 assert 可达)。
4. **顶层 `(sub …)` 恒推断失败**:TypeCheck.ml 的 `Coq_a_sub (_, _) -> None`
- (即使语义良型);`check (sub …)` 一律 reject,但 `convert` 经 nbe 可处理
- sub 项——均为 McTT 实际行为,语料以此为准。
+ (即使语义良型亦然);`check (sub …)` 一律 reject,但 `convert` 经 nbe 可处理
+ sub 项。以上均为 McTT 的实际行为,语料以此为准。
## Task 3 补充:harness 构建与运行
-- 源文件:本目录 `harness.ml` + `dune`(dune 内容 = `(executable (name harness)
+- 源文件:本目录 `harness.ml` 与 `dune`(dune 内容为 `(executable (name harness)
(libraries McttExtracted))`;brief 假设的 `mctt_driver` 库名不存在,实际为
`McttExtracted`)。
-- 构建(需要 opam switch 环境;~ 不在 switch 下的命令请用
+- 构建(需要 opam switch 环境;不在 switch 下的命令须用
`opam exec --switch=coq-8.20.0 --` 前缀):
```bash
@@ -147,8 +147,8 @@ cd ~/mctt && nice -n 19 opam exec --switch=coq-8.20.0 -- dune build driver/harne
# 产物:~/mctt/_build/default/driver/harness/harness.exe(可直接运行,无需 switch)
```
-- 运行:`harness.exe QUERY_FILE...`;`#` 注释行/空行跳过;malformed 行 → stderr
- 诊断 + 退出码 1(无 stdout 输出)。
+- 运行:`harness.exe QUERY_FILE...`;`#` 注释行与空行跳过;malformed 行输出 stderr
+ 诊断并返回退出码 1(无 stdout 输出)。
- 冒烟:`harness.exe tools/mctt_ref/smoke.txt` 应与 `smoke.expected` 逐行一致
(7/7,见下节)。
@@ -164,12 +164,12 @@ subtype: yes # subtype (ctx) (typ 0) (typ 1)
check: reject # check (ctx) (app (fn (nat) (var 0)) (zero)) (typ 0)
```
-brief 标注「第 7 行预期 reject 存在不确定性」——实测 **reject 确认无误**
+brief 标注「第 7 行预期 reject 存在不确定性」,实测 **reject 确认无误**
(app 推断类型为 (nat),(nat) 与 (typ 0) 不可比)。
## Task 3 补充:全量语料验证(2026-08-16)
-三个语料文件全部跑通(无 stderr、exit 0;输出行数 = 查询行数 - `#` 注释行):
+三个语料文件全部通过(无 stderr、exit 0;输出行数 = 查询行数 - `#` 注释行):
| 语料 | 查询行 | 注释行 | 输出行 | 耗时 |
|------|--------|--------|--------|------|
@@ -179,6 +179,6 @@ brief 标注「第 7 行预期 reject 存在不确定性」——实测 **reject
抽查核验(manual 案卷 25 条全部人工对过语义):natrec 的 succ 分支按 McTT 规则
`MS ⟸ A[Wk∘Wk,,succ #1]`(Definitions.v:29)——动机为 (nat) 时分支须为 nat
-形态,(fn (nat) (succ (var 0))) 推断为 Πℕℕ 故 reject(McTT 实际判定,非 harness 错误);
-`check (ctx (nat) (nat)) (sub (var 0) (compose (weaken) (id))) (nat)` 因顶层 sub
-恒 None 而 reject,亦为 McTT 实际行为。
+形态,(fn (nat) (succ (var 0))) 推断为 Πℕℕ 故 reject(McTT 的实际判定,非 harness
+错误);`check (ctx (nat) (nat)) (sub (var 0) (compose (weaken) (id))) (nat)` 因顶层 sub
+恒 None 而 reject,亦为 McTT 的实际行为。
diff --git a/tools/mctt_ref/protocol.md b/tools/mctt_ref/protocol.md
index 0d3325f1..77a1fa41 100644
--- a/tools/mctt_ref/protocol.md
+++ b/tools/mctt_ref/protocol.md
@@ -1,6 +1,6 @@
# 共享格式协议(McTT→Core 内核移植 M1 术语级差分)
-> 本协议由 Task 3 定死,是 Task 4(语料生成器 `tests/kernel/gen_corpus.py`)、
+> 本协议由 Task 3 确定,是 Task 4(语料生成器 `tests/kernel/gen_corpus.py`)、
> Task 5(`src/kernel/term_io.cr`)、Task 6(Core 内核移植)与 Task 7(差分)
> 的唯一格式基准。任何实现与本文不符即为协议违反。
> 语义基准 = McTT 提取代码(`~/mctt/driver/extracted/`,icfp25 分支),
@@ -10,7 +10,7 @@
- 每行一条查询;**`#` 开头的行(允许前导空白)是注释行,读取时必须跳过**,
不产生输出。空行同样跳过。
-- 每行由命令名 + 若干 S-表达式组成,空白分隔:
+- 每行由命令名与若干 S-表达式组成,以空白分隔:
- `check ` 判定第二项 : 第三项(项在前、类型在后)
- `infer ` 推断类型
- `convert ` 第二、三项在第四项类型下可转换性
@@ -58,7 +58,7 @@ subtype: yes | no
## 5. 语义约定(总化规则)
-判定语义 = **McTT 提取算法直译**(`TypeCheck.type_check/type_infer`、
+判定语义为 **McTT 提取算法的直译**(`TypeCheck.type_check/type_infer`、
`Subtyping.subtyping_impl`、`NbE.nbe_impl` + `Syntax.nf_eq_dec`),并约定
「判定前提不满足」的处理:
diff --git a/tools/v4_frontend_probe.py b/tools/v4_frontend_probe.py
new file mode 100644
index 00000000..9fdc867a
--- /dev/null
+++ b/tools/v4_frontend_probe.py
@@ -0,0 +1,1283 @@
+#!/usr/bin/env python3
+"""T1/T2 判据载体 —— Python bootstrap 前端的 v4 语法面(**零构建**)。
+
+出处(权威):`docs/superpowers/plans/2026-09-24-v4-syntax-migration.md` §四(T1/T2)
+· `docs/maintainer/design/v4-layout-spec.md`(T0 布局规格,五条判定)。
+本探针是 T0 探针 `tools/v4_layout_probe.py` 的**姊妹档**(同一批,同款纪律):
+T0 探针判「规格自洽」,本探针判「**实现与规格相符**」+ J-T1-1/J-T1-2 两条冻结/一致判据。
+
+用法(从仓库根跑):
+ python3 tools/v4_frontend_probe.py features # v4 语料过全管线(LEX→…→解释器)
+ python3 tools/v4_frontend_probe.py layout # INDENT/DEDENT/NEWLINE 流 + 判定 ① 三格
+ python3 tools/v4_frontend_probe.py colon # 裁定 ②(J-T0-2b 的 bootstrap 侧,含 §2.3 四格)
+ python3 tools/v4_frontend_probe.py structlit # 判定 ④:`=` 收 / `:` 响亮拒绝(P030)
+ python3 tools/v4_frontend_probe.py typenames # v4 关键字化类型名的解析面
+ python3 tools/v4_frontend_probe.py semi # J-T0-2:A4 正控 + C 类存活面
+ python3 tools/v4_frontend_probe.py ast-freeze [--rev R] # J-T1-1
+ python3 tools/v4_frontend_probe.py keywords # J-T1-2
+ python3 tools/v4_frontend_probe.py mutations # 反向对照(改坏一处 ⇒ 必红)
+ python3 tools/v4_frontend_probe.py all
+
+**当前预期(T1/T2 落地时点,不得粉饰)**:
+ - `features` / `layout` / `colon` / `structlit` / `typenames` / `semi` / `ast-freeze` / `mutations` ⇒ **rc=0**;
+ - `keywords` ⇒ **rc=1**(J-T1-2 是**批末**判据:自源侧 36 → 39 属 T5,本步只改
+ bootstrap 侧 ⇒ 差集非空是**设计使然**,实报见该子命令的输出)。
+
+反向对照纪律(本仓既有):每条判据都要有一条「改坏一处 ⇒ 必红」的机械证据;
+`mutations` 子命令即为此而设(内存内突变,不落盘、不改 runner 计数)。
+"""
+import dataclasses
+import inspect
+import io
+import json
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+
+BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert(0, os.path.join(BASE, 'bootstrap'))
+
+from corec.frontend.lexer import Lexer # noqa: E402
+from corec.frontend.parser import Parser # noqa: E402
+from corec.frontend.name_resolver import NameResolver # noqa: E402
+from corec.frontend.desugar import MatchDesugarer # noqa: E402
+from corec.frontend.type_checker import TypeChecker # noqa: E402
+from corec.frontend.ir_gen import IRGen # noqa: E402
+from corec.backend.interpreter import Interpreter # noqa: E402
+from corec.syntax.tokens import KEYWORDS, TokenType # noqa: E402
+from corec.syntax.ast import Block # noqa: E402
+
+FAILS = []
+CHECKS = 0
+
+
+def check(cond, label, detail=''):
+ """记一次判据。**空转防护**:`main` 收尾断言 `CHECKS` 有下限 ——
+ 判据面若因夹具/抽取变空而「0 == 0 通过」,等于没判(本仓 2026-09-24 #174 在
+ 姊妹档 `tools/v4_layout_probe.py` 里实测到过这一形态,故本档把它写成机械闸)。"""
+ global CHECKS
+ CHECKS += 1
+ if cond:
+ print(' PASS %s' % label)
+ else:
+ print(' FAIL %s%s' % (label, (' —— ' + detail) if detail else ''))
+ FAILS.append(label)
+ return cond
+
+
+# 判据条数下限(**非空转下限**,不是「跑到就够了」的计数):逐子命令留余量、不追平。
+# 触发场景:夹具列表被删空 / 抽取正则失配 ⇒ 判据跑了 0 条却「全绿」。
+CHECK_FLOOR = {
+ 'features': 25, 'layout': 8, 'colon': 17, 'structlit': 3, 'typenames': 7,
+ 'semi': 5, 'ast-freeze': 5, 'keywords': 5, 'mutations': 4,
+ 'positions': 48, 'all': 140,
+}
+
+
+# ── 全管线(与 tests/bootstrap/test_pipeline.py 同体例)────────────────────
+
+def run_pipeline(src):
+ """v4 源 → lex → parse → resolve → desugar → check → ir_gen → 解释器。
+
+ 返回 `(kind, value)`:`('OK', 值)` / `('ERR', 诊断列表)`;语法错**不捕获**(由调用方处理)。
+ """
+ ast = Parser(Lexer(src).tokenize()).parse_compilation_unit()
+ res = NameResolver()
+ res.resolve(ast)
+ ast = MatchDesugarer(res.symtab).desugar(ast)
+ chk = TypeChecker(res.symtab)
+ chk.check(ast)
+ if res.errors or chk.errors:
+ return ('ERR', res.errors + chk.errors)
+ mod = IRGen(res.symtab).gen_module(ast)
+ return ('OK', Interpreter(mod).run('main', []))
+
+
+# ── features:v4 语料逐例 ────────────────────────────────────────────────
+# 每例给「源 · 期望」;期望 = 解释器 main 的返回值(int)。
+FEATURES = [
+ ('fn + 调用', '''
+fn add(a: int, b: int) -> int:
+ return a + b
+
+fn main() -> int:
+ return add(3, 4)
+''', 7),
+ ('if / else', '''
+fn main() -> int:
+ a := 3
+ if a > 2:
+ return 10
+ else:
+ return 20
+''', 10),
+ ('if 无 else', '''
+fn main() -> int:
+ a := 1
+ if a > 2:
+ return 10
+ return 20
+''', 20),
+ ('loop / break', '''
+fn main() -> int:
+ i : ., mut = 0
+ s : ., mut = 0
+ loop:
+ if i >= 5:
+ break
+ s = s + i
+ i = i + 1
+ return s
+''', 10),
+ ('while', '''
+fn main() -> int:
+ i : ., mut = 0
+ while i < 4:
+ i = i + 1
+ return i
+''', 4),
+ ('for + range', '''
+fn main() -> int:
+ s : ., mut = 0
+ for x in 0..5:
+ s = s + x
+ return s
+''', 10),
+ ('struct 声明 + 字面量(`=` 形)', '''
+struct Point:
+ x: int
+ y: int
+
+fn main() -> int:
+ p := Point { x = 3, y = 4 }
+ return p.x + p.y
+''', 7),
+ ('enum + match(`|` 臂,v4 目标形)', '''
+enum Mode:
+ Off
+ On(int)
+
+fn main() -> int:
+ m := On(7)
+ match m:
+ | Off => 0
+ | On(n) => n
+''', 7),
+ ('enum + match(无 `|` 臂 —— v3 形,T4 机械改写会产出此形)', '''
+enum Mode:
+ Off
+ On(int)
+
+fn main() -> int:
+ m := On(7)
+ match m:
+ Off => 0
+ On(n) => n
+''', 7),
+ ('标签 `mut`', '''
+fn main() -> int:
+ x : int, mut = 1
+ x = x + 41
+ return x
+''', 42),
+ ('批量声明', '''
+fn main() -> int:
+ a, b : int = 1, 2
+ return a + b
+''', 3),
+ ('数组下标', '''
+fn main() -> int:
+ xs := [1, 2, 3]
+ return xs[0] + xs[2]
+''', 4),
+ ('重复数组 [v; N](`;` 存活面 C2)', '''
+fn main() -> int:
+ xs := [7; 3]
+ return xs[0] + xs[1] + xs[2]
+''', 21),
+ ('数组类型 [T; N] + 具名常量(A4 正控:非 0)', '''
+M : int = 3
+
+fn main() -> int:
+ a : [int; M] = [0; 3]
+ return 1
+''', 1),
+ ('泛型 fn + 泛型 struct', '''
+struct Box[T]:
+ v: T
+
+fn id[T](x: T) -> T:
+ return x
+
+fn main() -> int:
+ return id(42)
+''', 42),
+ ('嵌套 region + 空行 + 注释行(判定 ① ①-1/①-2)', '''
+// 顶层注释
+
+fn main() -> int:
+ x := 1
+ // 空行与注释行都是 no-op
+
+ if x > 0:
+ // 内层注释
+ y := 2
+ return x + y
+ return 0
+''', 3),
+ ('形参表跨行(隐式续行:括号内不参与 layout)', '''
+fn add(a: int,
+ b: int) -> int:
+ return a + b
+
+fn main() -> int:
+ return add(1, 2)
+''', 3),
+ ('行尾块注释后开 region(判定 ② §2.3 第 3 格)', '''
+fn main() -> int: /* note */
+ return 5
+''', 5),
+ ('unsafe region', '''
+fn main() -> int:
+ unsafe:
+ return 42
+''', 42),
+ ('impl + 方法 + self', '''
+struct P:
+ x: int
+
+impl P:
+ fn get(&self) -> int:
+ return self.x
+
+fn main() -> int:
+ p := P { x = 9 }
+ return p.get()
+''', 9),
+ ('interface + impl for', '''
+interface Get:
+ fn get(&self) -> int
+
+struct Q:
+ y: int
+
+impl Get for Q:
+ fn get(&self) -> int:
+ return self.y
+
+fn main() -> int:
+ return 0
+''', 0),
+ ('fileid + import 别名(D7)', '''
+fileid "probe"
+import math : m
+
+fn main() -> int:
+ return 1
+''', 1),
+ ('type 别名声明(声明面 + 行边界;注:别名**用在标注位**另有既有缺口,见 typenames)', '''
+type Size = int
+
+fn main() -> int:
+ return 1
+''', 1),
+ ('多行 struct 字面量(字面量内不参与 layout,判定 ④)', '''
+struct M:
+ a: int
+ b: int
+ c: int
+
+fn main() -> int:
+ m := M {
+ a = 1,
+ b = 2,
+ c = 3,
+ }
+ return m.a + m.b + m.c
+''', 6),
+ # 下面三例把**被 v3 语料挡住的语义面**用 v4 形再走一遍
+ # (对应 `tests/bootstrap/` 的 dex_arith / borrow / apx_tag 三套件;
+ # 它们今天整档红,红因是**自身语料是 v3 形**,不是这些语义面坏了)。
+ ('dex 定点算术(对应 test_dex_arith)', '''
+fn main() -> int:
+ a : dex = 1.5
+ b : dex = 2.25
+ if a + b == 3.75:
+ return 1
+ return 0
+''', 1),
+ ('apx 标签不改语义(对应 test_apx_tag)', '''
+fn main() -> int:
+ x : int, apx = 42
+ y : int = 84
+ z : int, apx, mut = 126
+ return x + y + z
+''', 252),
+ ('借用检查仍在(对应 test_borrow:多重不可变借用允许)', '''
+fn main() -> int:
+ x := 10
+ r1 := &x
+ r2 := &x
+ return *r1 + *r2
+''', 20),
+]
+
+# 必须**响亮失败**的负例(改前静默接受的形,改后必须红)
+FEATURES_NEG = [
+ ('v3 花括号函数体必须响亮拒绝', 'fn main() -> int { return 1; }'),
+ ('表达式位裸 `{` 必须响亮拒绝', 'fn main() -> int:\n x := { 1 }\n return 0\n'),
+ ('struct 字面量 `:` 分隔符必须响亮拒绝(P030)', '''
+struct P:
+ x: int
+
+fn main() -> int:
+ p := P { x: 1 }
+ return p.x
+'''),
+]
+
+# 必须**被下游拒绝**的语义负例(v4 形;证明管线不是「一律放行」)
+FEATURES_SEMNEG = [
+ ('借用:不可变借用后又用原变量 ⇒ 必报错(test_borrow 同款,v4 形)', '''
+fn main() -> int:
+ x := 10
+ r := &x
+ return x
+'''),
+ ('可变借用后又用原变量 ⇒ 必报错(test_borrow 同款,v4 形)', '''
+fn main() -> int:
+ x : ., mut = 10
+ rm := &mut x
+ return x
+'''),
+]
+
+
+def cmd_features():
+ print('[features] v4 语料过全管线(%d 例 + %d 负例)' % (len(FEATURES), len(FEATURES_NEG)))
+ for name, src, want in FEATURES:
+ try:
+ kind, got = run_pipeline(src)
+ except SyntaxError as e:
+ check(False, name, 'SyntaxError: %s' % e)
+ continue
+ if kind == 'ERR':
+ check(False, name, '诊断: %s' % got)
+ else:
+ check(got == want, name, '期望 %r 得 %r' % (want, got))
+ for name, src in FEATURES_NEG:
+ try:
+ kind, got = run_pipeline(src)
+ check(False, name, '**未拒绝**(得 %s %r)' % (kind, got))
+ except SyntaxError as e:
+ check(True, '%s(%s)' % (name, str(e).split(': ', 1)[-1][:60]))
+ for name, src in FEATURES_SEMNEG:
+ kind, got = run_pipeline(src)
+ check(kind == 'ERR' and bool(got), name, '**未报错**(得 %s %r)' % (kind, got))
+ return not FAILS
+
+
+# ── layout:token 流形状 ────────────────────────────────────────────────
+
+def kinds(src):
+ return [t.type.name for t in Lexer(src).tokenize()]
+
+
+def cmd_layout():
+ print('[layout] INDENT/DEDENT/NEWLINE 流 + 判定 ① 三格')
+
+ # 1) 基本流:region 头 → NEWLINE → INDENT … DEDENT
+ k = kinds('fn f() -> int:\n return 1\n')
+ check(k == ['FN', 'IDENT', 'LPAREN', 'RPAREN', 'ARROW', 'IDENT', 'COLON_BLOCK',
+ 'NEWLINE', 'INDENT', 'RETURN', 'INT_LIT', 'NEWLINE', 'DEDENT', 'EOF'],
+ '基本流:COLON_BLOCK → NEWLINE → INDENT → … → NEWLINE → DEDENT',
+ repr(k))
+
+ # 2) 顶层两声明之间无 INDENT(基准层不发 INDENT —— ①-1 第 3 条)
+ k = kinds('fn a() -> int:\n return 1\n\nfn b() -> int:\n return 2\n')
+ check(k.count('INDENT') == 2 and k.count('DEDENT') == 2,
+ '顶层两函数 ⇒ 恰 2 INDENT / 2 DEDENT(基准层不计层)',
+ 'INDENT=%d DEDENT=%d' % (k.count('INDENT'), k.count('DEDENT')))
+
+ # 3) ①-1 空行是 no-op:插入空行不改变流(逐 token 相同)
+ a = kinds('fn a() -> int:\n return 1\n')
+ b = kinds('fn a() -> int:\n\n\n return 1\n\n')
+ check(a == b, '①-1 空行不产生任何 token、不改变 anchor',
+ '加空行后流变了: %r vs %r' % (a, b))
+
+ # 4) ①-2 只含注释的行完全等同于空行
+ c = kinds('fn a() -> int:\n // note\n /* block */\n return 1\n')
+ check(a == c, '①-2 只含注释的行完全等同于空行',
+ '加注释行后流变了: %r vs %r' % (a, c))
+
+ # 5) ①-3 行尾注释不改变 anchor 列
+ k = kinds('fn a() -> int: // trailing\n return 1\n')
+ check(k == a, '①-3 行尾注释不改变 anchor 列', repr(k))
+
+ # 6) ①-2 行首注释 + 更深缩进的 code 行:anchor 取**首个 token** 的列
+ # `if x:` 在列 1、body 在列 5 且前面有注释 ⇒ 仍恰 1 层 INDENT
+ k = kinds('fn a() -> int:\n // c\n return 1\n')
+ check(k.count('INDENT') == 1 and k.count('DEDENT') == 1, '①-2/①-3 注释不参与 anchor 计数', repr(k))
+
+ # 7) 括号内不参与 layout(隐式续行)
+ k = kinds('fn a(x: int,\n y: int) -> int:\n return x\n')
+ head = k[:k.index('COLON_BLOCK')]
+ check('NEWLINE' not in head and 'INDENT' not in head,
+ '括号内换行不产生 NEWLINE/INDENT(隐式续行,D6)', repr(head))
+
+ # 8) `{ }` 内不参与 layout(字面量定界,判定 ④)
+ k = kinds('fn a() -> int:\n m := M {\n x = 1,\n }\n return m.x\n')
+ check(k.count('INDENT') == 1, 'struct 字面量内部不产生 layout(判定 ④ §4.1)', repr(k))
+
+ # 9) 反向对照:缩进列**不匹配任何外层列**(≠ 比基准更浅那一格)⇒ 必红。
+ # 构造:基准 1 → INDENT 5 → INDENT 9 → 列 7(弹掉 9 之后 5≠7,且栈里还有外层)
+ try:
+ kinds('fn a() -> int:\n if x > 0:\n loop:\n return 1\n')
+ check(False, '[反向] 不匹配任何外层列的缩进必须响亮报错')
+ except SyntaxError as e:
+ check('matches no open indent level' in str(e),
+ '[反向] 不匹配任何外层列的缩进 ⇒ 响亮报错(%s)' % str(e).split(': ', 1)[-1][:50])
+
+ # 10) 反向对照:比单元基准更浅 ⇒ 必红(T0 §6.1 A2 定义的那个 layout 错误)
+ try:
+ kinds('fn a() -> int:\n return 1\n return 2\n')
+ check(False, '[反向] 比基准锚点更浅的行必须响亮报错')
+ except SyntaxError as e:
+ check('shallower' in str(e) or 'dedent' in str(e),
+ '[反向] 比基准锚点更浅 ⇒ 响亮报错(%s)' % str(e).split(': ', 1)[-1][:50])
+ return not FAILS
+
+
+# ── colon:裁定 ②(J-T0-2b 的 bootstrap 侧)─────────────────────────────
+
+# 夹具:源 → 每个 `:` 的期望标签('DECL' = 行内 / 'BLOCK' = 行尾)。覆盖 T0 规格 §2.2 的
+# D1–D13 全部形 + §2.3 的四格。
+COLON_FIXTURES = [
+ ('D1 变量标注', 'x : int = 5\n', ['DECL']),
+ ('D2 标签形', 'count : int, mut = 0\n', ['DECL']),
+ ('D3 批量形', 'a, b : int = 1, 2\n', ['DECL']),
+ ('D4 字段形', 'struct S:\n id: int\n', ['BLOCK', 'DECL']),
+ ('D5 形参形', 'fn f(a: int) -> int:\n', ['DECL', 'BLOCK']),
+ ('D6 形参表跨行(终结 `:` 在续行行尾)', 'fn f(a: int,\n b: int):\n', ['DECL', 'DECL', 'BLOCK']),
+ ('D7 import 别名', 'import math : m\n', ['DECL']),
+ ('D8 mod 路径(`::` 不是 T_COLON)', 'mod examples::pi\n', []),
+ ('D9 函数体开启', 'fn add(a: int, b: int) -> int:\n', ['DECL', 'DECL', 'BLOCK']),
+ ('D11 接口方法(方法**终结**无 `:`;`o: &Self` 是 D5 形参标注 ⇒ 仍 DECL)',
+ 'interface I:\n fn eq(&self, o: &Self) -> bool\n', ['BLOCK', 'DECL']),
+ ('D12 lambda 形', 'f := fn(x: int) -> int:\n', ['DECL', 'BLOCK']),
+ ('D13 region 开启', 'match x:\n A => 1\n', ['BLOCK']),
+ ('§2.3 第 1 格:`fn f(): // note` ⇒ 行尾', 'fn f(): // note\n', ['BLOCK']),
+ ('§2.3 第 2 格:`x : int = 5 // note` ⇒ 行内', 'x : int = 5 // note\n', ['DECL']),
+ ('§2.3 第 3 格:`fn f(): /* note */` ⇒ 行尾', 'fn f(): /* note */\n', ['BLOCK']),
+ ('§2.3 第 4 格:跨行块注释 ⇒ 行尾', 'fn f(): /* note\n still note */\n', ['BLOCK']),
+ # §2.2 那个「lexer 判不出」的形态:形参标注断行 ⇒ lexer 必发 BLOCK,
+ # 由语法面(parser 期望 DECL)响亮拒绝。此处只断言**标签**(lexer 层的唯一可判事实)。
+ ('§2.2 盲点:形参标注断行 ⇒ lexer 判 BLOCK', 'fn f(a:\n int):\n', ['BLOCK', 'BLOCK']),
+]
+
+
+def cmd_colon():
+ print('[colon] 裁定 ②(词法位置决定):行内 `:` ⇒ COLON_DECL · 行尾 `:` ⇒ COLON_BLOCK')
+ for label, src, want in COLON_FIXTURES:
+ got = [t.type.name.replace('COLON_', '') for t in Lexer(src).tokenize()
+ if t.type in (TokenType.COLON_DECL, TokenType.COLON_BLOCK)]
+ check(got == want, label, '期望 %r 得 %r' % (want, got))
+
+ # 反向对照族一:把「行尾标注」当合法 ⇒ 该形必须**由 parser 响亮拒绝**(不是静默改判)
+ try:
+ run_pipeline('fn f(x:\n int) -> int:\n return 0\n')
+ check(False, '[反向·族一] 形参标注断行必须响亮拒绝')
+ except SyntaxError:
+ check(True, '[反向·族一] 形参标注断行 ⇒ 响亮拒绝(§2.2 的兜住点)')
+
+ # 反向对照族二:把行尾判定改成「注释也算 token」⇒ `fn f(): // note` 应被误判行内。
+ # 判据 = 通过**唯一扫描器** `_scan_blank_comment` 注入「不跳注释」行为,断言标签翻转。
+ src2 = 'fn f(): // note\n'
+ real = Lexer._scan_blank_comment
+
+ def no_comment(self, idx):
+ # 突变体:不识别注释 ⇒ `//` 的 `/` 成为「真字符」 ⇒ 判行内
+ n = len(self.source)
+ while idx < n and self.source[idx] in ' \t\r':
+ idx += 1
+ saw = False
+ while idx < n and self.source[idx] == '\n':
+ saw = True
+ idx += 1
+ while idx < n and self.source[idx] in ' \t\r':
+ idx += 1
+ return idx, saw
+
+ try:
+ Lexer._scan_blank_comment = no_comment
+ mut = [t.type.name for t in Lexer(src2).tokenize()
+ if t.type in (TokenType.COLON_DECL, TokenType.COLON_BLOCK)]
+ finally:
+ Lexer._scan_blank_comment = real
+ check(mut == ['COLON_DECL'], '[反向·族二] 扫描器若不跳注释 ⇒ `fn f(): // note` 翻成行内'
+ '(证明本格的绿来自那条注释规则)', repr(mut))
+ good = [t.type.name for t in Lexer(src2).tokenize()
+ if t.type in (TokenType.COLON_DECL, TokenType.COLON_BLOCK)]
+ check(good == ['COLON_BLOCK'], '[反向·族二] 正控:还原扫描器 ⇒ 判行尾', repr(good))
+ return not FAILS
+
+
+# ── structlit:判定 ④(J-T0-4 反向零构建半)─────────────────────────────
+
+def cmd_structlit():
+ print('[structlit] 判定 ④:`=` 形收 · `:` 形响亮拒绝(P030)')
+ ok = 'struct P:\n x: int\n\nfn main() -> int:\n p := P { x = 1 }\n return p.x\n'
+ try:
+ kind, got = run_pipeline(ok)
+ check(kind == 'OK' and got == 1, '`=` 形(选定形)收下且语义正确', repr((kind, got)))
+ except SyntaxError as e:
+ check(False, '`=` 形(选定形)收下', 'SyntaxError: %s' % e)
+
+ bad = 'struct P:\n x: int\n\nfn main() -> int:\n p := P { x: 1 }\n return p.x\n'
+ try:
+ run_pipeline(bad)
+ check(False, '`:` 形(未选定形)必须响亮拒绝', '**两形都收** —— 判据无鉴别力')
+ except SyntaxError as e:
+ check('P030' in str(e), '`:` 形响亮拒绝且点名 P030', str(e))
+
+ # 反向对照:把守卫去掉(还原成改前的盲跳)⇒ 该格必红
+ orig = Parser.parse_primary
+ try:
+ # 内存内把守卫替换成盲跳:模拟改前实现
+ def blind(self):
+ if self.check(TokenType.IDENT):
+ name = self.advance().lexeme
+ if name[0].isupper() and self.check(TokenType.LBRACE):
+ self.advance()
+ fields = []
+ while not self.check(TokenType.RBRACE):
+ fn = self.expect(TokenType.IDENT).lexeme
+ if self.check(TokenType.EQ) or self.check(TokenType.COLON_DECL):
+ self.advance()
+ v = self.parse_expr()
+ fields.append((fn, v))
+ if self.check(TokenType.COMMA):
+ self.advance()
+ self.expect(TokenType.RBRACE)
+ return self._struct_alias(fields)
+ return self._ident_alias(name)
+ return orig(self)
+ from corec.syntax.ast import StructLit, Ident
+ Parser._struct_alias = staticmethod(lambda f: StructLit(['P'], f))
+ Parser._ident_alias = staticmethod(lambda n: Ident(n))
+ Parser.parse_primary = blind
+ try:
+ run_pipeline(bad)
+ check(True, '[反向] 还原成盲跳(改前实现)⇒ `:` 形**被静默收下** '
+ '(证明本判据的鉴别力来自那条守卫)')
+ except SyntaxError:
+ check(False, '[反向] 还原成盲跳后仍报错 ⇒ 红的不是那条守卫(判据无鉴别力)')
+ finally:
+ Parser.parse_primary = orig
+ return not FAILS
+
+
+# ── typenames:v4 关键字化的类型名(**只判解析面**)──────────────────────
+# T1 对 `never`/`dyn` 的可交付面 = 「它们是**关键字**且 `parse_type` 有产生式」
+# (计划 §一.5 注 1 / §7.1 项 8)——这是**解析层**事实,不夹带语义主张。
+# `Self` 反向:v4 把它移出关键字表 ⇒ 它以 IDENT 到达,仍须解到原生名 `Self` 而非泛型形参。
+
+TYPENAME_CASES = [
+ ('`never` 作返回型', 'fn f() -> never:\n return f()\n'),
+ ('`dyn` 作变量标注型', 'fn f() -> int:\n x : dyn = 5\n return 1\n'),
+ ('`never` 作形参型', 'fn f(x: never) -> int:\n return 1\n'),
+ ('`&Self` 作形参型(v4 移出关键字后仍解到原生名)', 'fn f(o: &Self) -> int:\n return 1\n'),
+]
+
+
+def cmd_typenames():
+ print('[typenames] v4 关键字化的类型名 —— 只判**解析**面(不夹带语义主张)')
+ for label, src in TYPENAME_CASES:
+ try:
+ ast = Parser(Lexer(src).tokenize()).parse_compilation_unit()
+ check(len(ast.declarations) == 1, label)
+ except SyntaxError as e:
+ check(False, label, 'SyntaxError: %s' % e)
+
+ # 语义面:`Self` 必须解成 BaseType('Self'),**不得**掉进 PathType(会被 _is_generic_type
+ # 当成泛型形参 ⇒ 静默错判)。做法:直接看 parse_type 的产物。
+ p = Parser(Lexer('&Self').tokenize())
+ t = p.parse_type()
+ check(type(t).__name__ == 'RefType' and type(t.inner).__name__ == 'BaseType'
+ and t.inner.name == 'Self',
+ '`&Self` ⇒ RefType(BaseType(Self)),不是 PathType(防泛型形参误判)', repr(t))
+ p = Parser(Lexer('never').tokenize())
+ check(type(p.parse_type()).__name__ == 'BaseType', '`never` ⇒ BaseType(原生名)')
+ p = Parser(Lexer('dyn').tokenize())
+ check(type(p.parse_type()).__name__ == 'BaseType', '`dyn` ⇒ BaseType(原生名,同自源原生名表)')
+
+ # 已登记的**既有**缺口(非本步引入,只登记不改):别名/点路径在标注位不可用
+ print(' 登记(既有缺口,非本步引入,未改):')
+ print(' · `type Size = int` 的别名用在**标注位** ⇒ PathType 不被解成 int(bootstrap 无覆盖)')
+ print(' · 点路径枚举构造子 `E.V(x)` 与点路径模式 `E.V` ⇒ bootstrap 无产生式(src/** 零 `=>`,零影响)')
+ return not FAILS
+
+
+# ── semi:J-T0-2 的两条(A4 静默面 + C 类存活面)─────────────────────────
+
+def _find_array_size(src):
+ """取 main 里第一个 `x : [int; N] = …` 声明的**声明面数组长度**。"""
+ ast = Parser(Lexer(src).tokenize()).parse_compilation_unit()
+ for d in ast.declarations:
+ if type(d).__name__ != 'FunctionDecl':
+ continue
+ for st in getattr(d.body, 'stmts', []):
+ if type(st).__name__ == 'LetStmt':
+ return getattr(st.type_, 'size', None)
+ return None
+
+
+def cmd_semi():
+ print('[semi] J-T0-2:A4 的静默面(正控)+ C 类存活面(`;` 只在 `[T; N]` / `[v; N]`)')
+ src = 'M : int = 3\n\nfn main() -> int:\n a : [int; M] = [0; 3]\n return 1\n'
+ n = _find_array_size(src)
+ # A4 的「漏改即静默错答案」正控:`M` 必须**真的取到 3**(不是兜底的 0)
+ check(n == 3, 'A4 正控:具名常量 `M` 真取到 3(不是 `.get(name, 0)` 兜底的 0)', 'size=%r' % n)
+
+ # 反向对照:把常量预扫的终止元改回 `;`(= 改前形态)⇒ 扫描落空 ⇒ M 解成 0
+ # 注意 `;` 在 v4 只在 `[T;N]` 存活 ⇒ 改前形态在新语法下**扫不到任何常量**。
+ real = Parser._scan_constants
+ try:
+ Parser._scan_constants = lambda self: None # 突变体:预扫整体失效
+ n2 = _find_array_size(src)
+ finally:
+ Parser._scan_constants = real
+ check(n2 == 0, '[反向] 预扫失效 ⇒ `M` 静默解成 0(**且不报错** —— 这就是 A4 的危险形态)',
+ 'size=%r' % n2)
+ check(n != n2, '[反向] 正控与突变体读数不同 ⇒ 本格真有鉴别力(不是恒 3)')
+
+ # C 类存活面:`;` 在 `[v; N]` 仍然合法
+ k = kinds('fn f() -> int:\n a := [0; 3]\n return 1\n')
+ check('SEMI' in k, 'C2 存活:`[v; N]` 的 `;` 仍是 SEMI token', repr([x for x in k if x == 'SEMI']))
+ k = kinds('fn f() -> int:\n a : [int; 3] = [0; 3]\n return 1\n')
+ check(k.count('SEMI') == 2, 'C1+C2 存活:`[T; N]` 与 `[v; N]` 各一个 `;`',
+ repr(k.count('SEMI')))
+ return not FAILS
+
+
+# ── ast-freeze:J-T1-1 ──────────────────────────────────────────────────
+
+CLASS_RE = re.compile(r'^class\s+([A-Za-z_]\w*)', re.M)
+
+
+def ast_classes(text):
+ return sorted(CLASS_RE.findall(text))
+
+
+def read_file(rel, rev=None):
+ if rev:
+ r = subprocess.run(['jj', '--ignore-working-copy', 'file', 'show', '-r', rev, rel],
+ cwd=BASE, capture_output=True, text=True)
+ if r.returncode != 0:
+ raise SystemExit('jj file show -r %s %s 失败: %s' % (rev, rel, r.stderr))
+ return r.stdout
+ with io.open(os.path.join(BASE, rel), encoding='utf-8') as fh:
+ return fh.read()
+
+
+def cmd_ast_freeze(rev):
+ print('[ast-freeze] J-T1-1:`bootstrap/corec/syntax/ast.py` 的节点类集合冻结')
+ cur = ast_classes(read_file('bootstrap/corec/syntax/ast.py'))
+ base = ast_classes(read_file('bootstrap/corec/syntax/ast.py', rev))
+ # **空转闸**:抽取若变空,`∅ == ∅` 会假绿(#174 在姊妹档实测到的正是这一形态)
+ check(len(base) >= 50 and len(cur) >= 50,
+ '抽取非空转:两侧各 ≥ 50 个 class(防 ∅==∅ 假绿)',
+ 'base=%d cur=%d' % (len(base), len(cur)))
+ check('Ident' in base and 'Literal' in base,
+ '抽取哨兵:已知节点 `Ident`/`Literal` 在集合里(防正则失配后的空集)')
+ print(' 基线 %s:%d 个 class' % (rev, len(base)))
+ print(' 工作副本 :%d 个 class' % len(cur))
+ check(cur == base, '类集合逐元素相同(迁移前后 cmp 为空)',
+ '差集 cur-base=%r base-cur=%r' % (sorted(set(cur) - set(base)), sorted(set(base) - set(cur))))
+
+ # 反向对照:故意加一个 class ⇒ 必红
+ mutated = ast_classes(read_file('bootstrap/corec/syntax/ast.py') + '\nclass ZzProbeAdded:\n pass\n')
+ check(mutated != base, '[反向] 故意加一个 class ⇒ 判据当场红(差集 = %r)'
+ % sorted(set(mutated) - set(base)))
+ # 反向对照 2:删一个 class ⇒ 必红
+ dropped = [c for c in base if c != base[0]]
+ check(dropped != base, '[反向] 删一个 class(%s)⇒ 判据当场红' % base[0])
+ return not FAILS
+
+
+# ── keywords:J-T1-2 ────────────────────────────────────────────────────
+
+V4_KEYWORDS = set("""
+fn mut return if else loop while for break continue true false struct enum extern impl match
+import pub go await unsafe flow yield interface type mod as auto fileid self in none unit never dyn catch fail spec
+""".split())
+
+
+def selfhost_keywords(text):
+ """自源 `src/compiler/lexer.cr` 的 `lookup_keyword` 表(抽法沿用施工计划 §十二 的脚本)。
+
+ ⚠ T4 后该档已是 **v4 形**:函数体以 DEDENT 收尾、**没有列 0 的 `}`**。故块边界
+ 改判「下一个列 0 的顶层 `fn `」——原 `blk.index('\\n}\\n')` 在 v4 文本上找不到,
+ 会当场 ValueError(T4 落地时实测撞上)。
+ """
+ blk = text[text.index('fn lookup_keyword'):]
+ nxt = re.search(r'\nfn ', blk)
+ if nxt:
+ blk = blk[:nxt.start()]
+ return set(re.findall(r'if s == "([^"]+)"', blk))
+
+
+def bootstrap_keywords(text):
+ blk = text[text.index('KEYWORDS = {'):]
+ blk = blk[:blk.index('\n}')]
+ return set(re.findall(r'^\s*"([^"]+)":', blk, re.M))
+
+
+def cmd_keywords(rev=None):
+ print('[keywords] J-T1-2:两套前端关键字表逐元素一致(**批末**判据)')
+ boot = bootstrap_keywords(read_file('bootstrap/corec/syntax/tokens.py', rev))
+ sh = selfhost_keywords(read_file('src/compiler/lexer.cr', rev))
+ # **空转闸**:两侧抽取若同时变空,差集也空 ⇒ J-T1-2 会假绿
+ check(len(boot) >= 30 and len(sh) >= 30,
+ '抽取非空转:两侧各 ≥ 30 个关键字(防 ∅==∅ 假绿)',
+ 'bootstrap=%d 自源=%d' % (len(boot), len(sh)))
+ check('fn' in boot and 'struct' in boot and 'fn' in sh and 'struct' in sh,
+ '抽取哨兵:已知关键字 `fn`/`struct` 在两侧集合里(防截取失配后的空集)')
+ print(' bootstrap tokens.py KEYWORDS : %d' % len(boot))
+ print(' 自源 lexer.cr lookup_keyword : %d' % len(sh))
+ print(' v4 目标集 : %d' % len(V4_KEYWORDS))
+
+ check(boot == V4_KEYWORDS, 'bootstrap 侧 == v4 的 39(T1 的可交付面)',
+ '差集 boot-v4=%r v4-boot=%r' % (sorted(boot - V4_KEYWORDS), sorted(V4_KEYWORDS - boot)))
+ check(len(V4_KEYWORDS) == 39, 'v4 目标集计数 == 39', str(len(V4_KEYWORDS)))
+ # 两法互证:文本抽取(正则)↔ 运行时 `KEYWORDS` 字典键。两条独立路径须吻合,
+ # 否则「抽出来的集合」只是正则的产物,不是表本身(本仓纪律:两份独立方法吻合才可信)。
+ check(boot == set(KEYWORDS.keys()), '文本抽取 == 运行时 `KEYWORDS` 字典键(两法互证)',
+ '差集 %r' % sorted(boot ^ set(KEYWORDS.keys())))
+
+ d1, d2 = sorted(boot - sh), sorted(sh - boot)
+ print(' 差集 bootstrap−自源: %r' % d1)
+ print(' 差集 自源−bootstrap: %r' % d2)
+ ok = check(not d1 and not d2, '两表逐元素相同(J-T1-2 的目标形)',
+ '**当前差集非空是设计使然**:自源侧 36 → 39 属 T5(本步只改 bootstrap 侧)')
+
+ # 反向对照:往任一侧加一个 ⇒ 必红(内存内)
+ check((boot | {'zzprobe'}) != sh and (sh | {'zzprobe'}) != boot,
+ '[反向] 往任一侧加一个关键字 ⇒ 必红')
+ # 反向对照 2:把一侧还原成改前的 40 / 36 ⇒ 必红
+ boot_old = (boot - {'catch', 'dyn', 'fail', 'never', 'none', 'spec'}) | {
+ 'None', 'Self', 'Some', 'ensures', 'move', 'requires', 'result'}
+ check(len(boot_old) == 40 and boot_old != sh,
+ '[反向] 还原 bootstrap 表到改前的 40 ⇒ 必红(count=%d)' % len(boot_old))
+ return ok
+
+
+# ── positions:位置语义(语句位尾值 vs 语句)──────────────────────────────
+#
+# **本组判据的存在理由**:v4 无 `;` ⇒ 语句末的裸表达式一度被一律当 region 尾值
+# (`Block.expr`)⇒ 块类型由 unit 变 int ⇒ 全量构建刷出 **758 条**类型告警
+# (`expected return type` 450 + `If branches` 308),而**当时全部既有判据都是绿的**——
+# token 级判据(`layout`/`colon`/`semi`)天然看不见 AST 位置语义。漂移已修(见
+# `bootstrap/corec/frontend/parser.py` 的 `want_value` 位置标志 ∧ `_is_block_like` 节点种类),
+# 但该修复此前只活在代码注释里 ⇒ 本组是它的机械看门人。
+#
+# 口径(v3 逐形等价,维护者裁定):**位置标志 ∧ 节点种类** ——
+# · 语句位 region 的块状尾项(`If`/`Match`/`Loop`/`For`/`Unsafe`/`Flow`)⇒ 保 `Block.expr`;
+# · 语句位 region 的其余尾项(赋值/调用/二元/字面量/`Ident`/索引…)⇒ 包 `ExprStmt`;
+# · 表达式位 region(`x := if …` 等)⇒ 一律保尾值。
+# 依据:v3 的 `;` **只终止普通表达式语句**,块状语句在 v3 里从不带 `;` ⇒ 本来就是尾值。
+
+# v3 前端锚点 = T1/T2 提交 `03884bb8d56b` 的父(最后一份 `{`/`;` 前端)。commit id 不可变。
+POSITION_V3_REV = 'bb8cb3537584'
+
+# 夹具:(名, v3 源, v4 源, 期望块清单)。**两侧源必须表达同一程序** ⇒ 块清单须逐行相同。
+# 期望块清单 = 逐个 `Block` 一行 `路径 | 语句种类表 | 尾值种类`(`-` = 无尾值/空语句表)。
+# ⚠ 期望值是**按口径手写的判据**,不是「跑出来是什么就记什么」——若实现与之不符,那是
+# 要上报的发现,不许改判据去附和实现。
+POSITION_FIXTURES = [
+ # ── ① 语句位 · 块状尾项 ⇒ 保尾值 ──
+ ('语句位尾随 `if` ⇒ 保尾值(两臂各自成 region)', '''
+fn main() -> int { if 1 > 0 { return 1; } else { return 2; } }
+''', '''
+fn main() -> int:
+ if 1 > 0:
+ return 1
+ else:
+ return 2
+''', [
+ 'main.body | - | If',
+ 'main.body.expr.else_branch | ReturnStmt | -',
+ 'main.body.expr.then_branch | ReturnStmt | -',
+ ]),
+ ('语句位尾随 `loop` ⇒ 保尾值', '''
+fn f() -> int { loop { break; } }
+''', '''
+fn f() -> int:
+ loop:
+ break
+''', [
+ 'f.body | - | Loop',
+ 'f.body.expr.block | BreakStmt | -',
+ ]),
+ ('语句位尾随 `for` ⇒ 保尾值', '''
+fn f() -> int { x : ., mut = 0; for i in 0..3 { x = x + 1; } }
+''', '''
+fn f() -> int:
+ x : ., mut = 0
+ for i in 0..3:
+ x = x + 1
+''', [
+ 'f.body | LetStmt | For',
+ 'f.body.expr.block | ExprStmt | -',
+ ]),
+ ('语句位尾随 `unsafe` ⇒ 保尾值', '''
+fn f() -> int { unsafe { return 1; } }
+''', '''
+fn f() -> int:
+ unsafe:
+ return 1
+''', [
+ 'f.body | - | Unsafe',
+ 'f.body.expr.block | ReturnStmt | -',
+ ]),
+ ('语句位尾随 `match` ⇒ 保尾值(臂体是表达式,非 region)', '''
+enum Mode { Off, On(int) }
+
+fn main() -> int { m := On(7); match m { Off => 0, On(n) => n } }
+''', '''
+enum Mode:
+ Off
+ On(int)
+
+fn main() -> int:
+ m := On(7)
+ match m:
+ Off => 0
+ On(n) => n
+''', [
+ 'main.body | LetStmt | Match',
+ ]),
+ ('语句位尾随 `flow` ⇒ 保尾值(裁定 1:`Flow` 与其余块状形同列)', '''
+fn f() -> int { flow { 1; } }
+''', '''
+fn f() -> int:
+ flow:
+ 1
+''', [
+ 'f.body | - | Flow',
+ 'f.body.expr.block | ExprStmt | -',
+ ]),
+ # ── ② 语句位 · 普通尾项 ⇒ 包 ExprStmt(region 无值)──
+ ('语句位尾随赋值 ⇒ 包 `ExprStmt`(region 无值)', '''
+fn f(x: int) -> int { y := x; y = y + 1; }
+''', '''
+fn f(x: int) -> int:
+ y := x
+ y = y + 1
+''', [
+ 'f.body | LetStmt,ExprStmt | -',
+ ]),
+ ('语句位尾随调用 ⇒ 包 `ExprStmt`', '''
+fn f() -> unit { println("x"); }
+''', '''
+fn f():
+ println("x")
+''', [
+ 'f.body | ExprStmt | -',
+ ]),
+ ('语句位尾随字面量 ⇒ 包 `ExprStmt`', '''
+fn f() -> int { 1; }
+''', '''
+fn f() -> int:
+ 1
+''', [
+ 'f.body | ExprStmt | -',
+ ]),
+ ('语句位尾随二元 ⇒ 包 `ExprStmt`', '''
+fn f() -> int { x : ., mut = 0; x + 1; }
+''', '''
+fn f() -> int:
+ x : ., mut = 0
+ x + 1
+''', [
+ 'f.body | LetStmt,ExprStmt | -',
+ ]),
+ # ── ③ 表达式位 ⇒ 一律保尾值 ──
+ ('表达式位 `x := if …` ⇒ 两臂保尾值(值必须取到)', '''
+fn pick(c: bool) -> int { x := if c { 1 } else { 2 }; return x; }
+''', '''
+fn pick(c: bool) -> int:
+ x := if c:
+ 1
+ else:
+ 2
+ return x
+''', [
+ 'pick.body | LetStmt,ReturnStmt | -',
+ 'pick.body.stmts[0].values[0].else_branch | - | Literal',
+ 'pick.body.stmts[0].values[0].then_branch | - | Literal',
+ ]),
+ ('表达式位 `t := unsafe …` ⇒ 保尾值', '''
+fn f() -> int { t := unsafe { 7 }; return t; }
+''', '''
+fn f() -> int:
+ t := unsafe:
+ 7
+ return t
+''', [
+ 'f.body | LetStmt,ReturnStmt | -',
+ 'f.body.stmts[0].values[0].block | - | Literal',
+ ]),
+ # ── ④ 既有逻辑不动 + 规则 ③ 递归 ──
+ ('非末项裸表达式 ⇒ 仍包 `ExprStmt`(既有「还有下一项」逻辑不动)', '''
+fn f() -> int { println("a"); return 1; }
+''', '''
+fn f() -> int:
+ println("a")
+ return 1
+''', [
+ 'f.body | ExprStmt,ReturnStmt | -',
+ ]),
+ ('规则 ③ 递归:语句位 `if` 的体内再嵌语句位 `if`', '''
+fn f() -> int { x : ., mut = 0; if true { x = 1; if false { x = 2; } } return x; }
+''', '''
+fn f() -> int:
+ x : ., mut = 0
+ if true:
+ x = 1
+ if false:
+ x = 2
+ return x
+''', [
+ # 外层 `if` 是语句位 ⇒ 其 then 体是语句位 region;体内 `x = 1` 非末项 ⇒ 包 ExprStmt,
+ # 内层 `if false` 是**末项且块状** ⇒ 保尾值(规则 ① + 规则 ③ 递归)。
+ 'f.body | LetStmt,ExprStmt,ReturnStmt | -',
+ 'f.body.stmts[1].expr.then_branch | ExprStmt | If',
+ 'f.body.stmts[1].expr.then_branch.expr.then_branch | ExprStmt | -',
+ ]),
+]
+
+
+def position_lines(unit, block_cls):
+ """〈位置语义〉块清单:AST 里**每个 `Block`** 一行 `路径 | 语句种类表 | 尾值种类`。
+
+ 路径 = `声明名.字段链`(含 `stmts[i]`/`values[i]` 下标);尾值种类 `-` = 无尾值。
+ **签名不多不少正好是这一层**:位置语义的全部可观测量就是「每个 region 的尾值去留」。
+
+ 通用 dataclass 遍历(不写死字段名);v3/v4 两份 `ast.py` 的类名与字段名逐字相同
+ (实测:Block/If/Loop/For/Unsafe/Flow/ExprStmt/FunctionDecl/CompilationUnit 全同),
+ 故同一份函数两侧通用。⚠ **本函数经 `inspect.getsource` 注入 v3 侧 runner 脚本**
+ ⇒ 必须自包含(只依赖入参 + `dataclasses`),不许引用本档其它符号。
+ """
+ lines = []
+
+ def walk(node, path):
+ if node is None:
+ return
+ if isinstance(node, (list, tuple)):
+ for i, x in enumerate(node):
+ walk(x, '%s[%d]' % (path, i))
+ return
+ if isinstance(node, block_cls):
+ kinds = ','.join(type(s).__name__ for s in node.stmts)
+ tail = type(node.expr).__name__ if node.expr is not None else '-'
+ lines.append('%s | %s | %s' % (path, kinds or '-', tail))
+ walk(node.stmts, path + '.stmts')
+ walk(node.expr, path + '.expr')
+ return
+ try:
+ names = [f.name for f in dataclasses.fields(node)]
+ except TypeError:
+ return
+ for n in names:
+ walk(getattr(node, n), '%s.%s' % (path, n))
+
+ for i, d in enumerate(getattr(unit, 'declarations', None) or []):
+ walk(d, getattr(d, 'name', None) or 'decl[%d]' % i)
+ return sorted(lines)
+
+
+def v4_position_lines(src):
+ """v4 侧:当前前端解析 → 块清单。"""
+ return position_lines(Parser(Lexer(src).tokenize()).parse_compilation_unit(), Block)
+
+
+def _v3_tree(err):
+ """把 v3 前端树抽到临时目录(按 rev 缓存——rev 不可变 ⇒ 缓存恒有效)。
+
+ 返回 `<临时目录>/bootstrap`(可直接进 `sys.path`);失败返回 `None` 并把原因写进 `err`
+ (调用方转成**响亮的 FAIL**,不静默跳过 —— 静默跳过等于等价面变空还报绿)。
+ """
+ cache = os.path.join(tempfile.gettempdir(), 'core-v4probe-v3tree-%s' % POSITION_V3_REV)
+ probe_file = os.path.join(cache, 'bootstrap', 'corec', 'frontend', 'parser.py')
+ if not os.path.exists(probe_file):
+ tmp = cache + '.tmp'
+ if os.path.isdir(tmp):
+ shutil.rmtree(tmp)
+ try:
+ r = subprocess.run(['jj', 'file', 'list', '-r', POSITION_V3_REV, 'bootstrap/'],
+ cwd=BASE, capture_output=True, text=True)
+ except OSError as e:
+ err.append('调用 jj 失败(本机无 jj / 不在 PATH?): %s' % e)
+ return None
+ if r.returncode != 0:
+ err.append('jj file list -r %s 失败(浅检出无 jj / rev 不可达?): %s'
+ % (POSITION_V3_REV, r.stderr.strip()[:200]))
+ return None
+ files = [x for x in r.stdout.splitlines() if x.strip()]
+ if not files:
+ err.append('jj file list 返回空 ⇒ v3 基线不可得(等价面会退化成 vacuous)')
+ return None
+ for f in files:
+ try:
+ rr = subprocess.run(['jj', '--ignore-working-copy', 'file', 'show',
+ '-r', POSITION_V3_REV, f],
+ cwd=BASE, capture_output=True, text=True)
+ except OSError as e:
+ err.append('调用 jj 失败: %s' % e)
+ return None
+ if rr.returncode != 0:
+ err.append('jj file show -r %s %s 失败: %s'
+ % (POSITION_V3_REV, f, rr.stderr.strip()[:200]))
+ return None
+ dst = os.path.join(tmp, f)
+ os.makedirs(os.path.dirname(dst), exist_ok=True)
+ with io.open(dst, 'w', encoding='utf-8') as fh:
+ fh.write(rr.stdout)
+ if os.path.isdir(cache):
+ shutil.rmtree(cache)
+ shutil.move(tmp, cache)
+ return os.path.join(cache, 'bootstrap')
+
+
+def v3_position_lines(tree, srcs, err):
+ """v3 侧:`{夹具名: v3 源}` → `{夹具名: 块清单}`(逐夹具,失败记 `'ERROR: …'` 文本)。
+
+ 跑法 = 在临时目录里起**新解释器 + 独立 `sys.path`** 的自包含 runner:已导入的 v4
+ `corec.*` 不能被换掉,而同进程里换不了模块树 ⇒ 只能换进程。编码器经
+ `inspect.getsource(position_lines)` **注入**(不是复制)⇒ 两侧单真源,不会各自漂移。
+ """
+ script = os.path.join(os.path.dirname(tree), '_positions_runner.py')
+ body = '\n'.join([
+ 'import dataclasses',
+ 'import json',
+ 'import sys',
+ 'sys.path.insert(0, %r)' % tree,
+ 'from corec.frontend.lexer import Lexer',
+ 'from corec.frontend.parser import Parser',
+ 'from corec.syntax.ast import Block',
+ inspect.getsource(position_lines),
+ 'SRCS = %r' % srcs,
+ 'out = {}',
+ 'for _name, _src in SRCS.items():',
+ # 逐夹具兜错:单个夹具的 v3 源解析失败不该拖垮整个等价面(转成可见的 FAIL 文本)
+ ' try:',
+ ' out[_name] = position_lines(',
+ ' Parser(Lexer(_src).tokenize()).parse_compilation_unit(), Block)',
+ ' except Exception as _e:',
+ ' out[_name] = "ERROR: %s: %s" % (type(_e).__name__, _e)',
+ 'print(json.dumps(out))',
+ '',
+ ])
+ with io.open(script, 'w', encoding='utf-8') as fh:
+ fh.write(body)
+ r = subprocess.run([sys.executable, script], cwd=os.path.dirname(tree),
+ capture_output=True, text=True)
+ if r.returncode != 0:
+ err.append('v3 runner 退出码 %d: %s' % (r.returncode, r.stderr.strip()[-400:]))
+ return None
+ try:
+ return json.loads(r.stdout)
+ except ValueError as e:
+ err.append('v3 runner 输出非 JSON: %s' % e)
+ return None
+
+
+def cmd_positions():
+ print('[positions] 位置语义:语句位尾值 vs 语句(含 v3 前端逐形对拍)')
+ v3_err = []
+ tree = _v3_tree(v3_err)
+
+ # **非空转闸 ①**:夹具面本身要有鉴别力(两侧判定类都要出现),否则「全绿」是空绿。
+ check(len(POSITION_FIXTURES) >= 12,
+ '夹具面非空转:≥ 12 组(实得 %d)' % len(POSITION_FIXTURES))
+ tails = set()
+ for _n, _v3, _v4, gold in POSITION_FIXTURES:
+ for line in gold:
+ tails.add(line.rsplit(' | ', 1)[-1])
+ check('-' in tails and len(tails) >= 4,
+ '期望面非空转:既有无尾值(`-`)也有多种尾值种类(实得 %r)' % sorted(tails))
+
+ # **非空转闸 ②**:v3 基线必须**真是 v3**,否则等价面退化成 v4-vs-v4 的空绿。
+ if tree:
+ with io.open(os.path.join(tree, 'corec', 'frontend', 'parser.py'),
+ encoding='utf-8') as fh:
+ v3_src = fh.read()
+ check('RBRACE' in v3_src and 'want_value' not in v3_src,
+ 'v3 基线哨兵:`%s` 的 parser.py 含 `RBRACE` 且不含 `want_value`(防 v4-vs-v4 空绿)'
+ % POSITION_V3_REV)
+ # 反向:同一哨兵判据作用到**当前 v4** 的 parser.py 上 ⇒ 必假(证明哨兵不是恒真)
+ with io.open(os.path.join(BASE, 'bootstrap', 'corec', 'frontend', 'parser.py'),
+ encoding='utf-8') as fh:
+ v4_txt = fh.read()
+ check(not ('RBRACE' in v4_txt and 'want_value' not in v4_txt),
+ '[反向] 同一哨兵判据作用在 v4 的 parser.py 上 ⇒ 假(哨兵能识破「基线其实是 v4」)',
+ 'v4 文本: 含 RBRACE=%r / 不含 want_value=%r'
+ % ('RBRACE' in v4_txt, 'want_value' not in v4_txt))
+
+ v3_inv = None
+ if tree:
+ v3_inv = v3_position_lines(
+ tree, {n: v3 for n, v3, _v4, _g in POSITION_FIXTURES}, v3_err)
+ if tree and v3_inv is None:
+ check(False, 'v3 侧对拍可用(抽取/运行成功)', ';'.join(v3_err)[:300])
+ elif tree:
+ check(True, 'v3 侧对拍可用(抽取/运行成功)')
+ else:
+ check(False, 'v3 侧对拍可用(抽取/运行成功)', ';'.join(v3_err)[:300])
+
+ n_blocks = 0
+ for name, _v3_src, v4_src, gold in POSITION_FIXTURES:
+ try:
+ v4_lines = v4_position_lines(v4_src)
+ except SyntaxError as e:
+ check(False, name, 'v4 解析失败: %s' % e)
+ continue
+ n_blocks += len(v4_lines)
+ ok_shape = check(v4_lines == list(gold), '%s —— v4 形状与手写判据相符' % name,
+ '期望 %r 得 %r' % (list(gold), v4_lines))
+ if v3_inv is not None:
+ got3 = v3_inv.get(name)
+ if isinstance(got3, str):
+ check(False, '%s —— v3 侧解析失败' % name, got3[:200])
+ continue
+ check(got3 == list(gold), '%s —— v3 前端同判(逐形等价)' % name,
+ 'v3 %r vs 判据 %r' % (got3, list(gold)))
+ check(got3 == v4_lines, '%s —— v3/v4 两侧块清单逐行相同(直対拍)' % name,
+ 'v3 %r vs v4 %r' % (got3, v4_lines))
+ if not ok_shape:
+ continue
+
+ # **非空转闸 ③**:逐块断言数下限(夹具被删空 ⇒ 条数掉下来必红)。
+ check(n_blocks >= 25, '逐块断言数非空转:≥ 25 个 Block(实得 %d)' % n_blocks)
+ # **抽取哨兵**:已知块路径必须在清单里(防走查/抽取整体失配后的空表)。
+ probe_sig = v4_position_lines('fn f() -> int:\n y := 1\n')
+ check('f.body | LetStmt | -' in probe_sig,
+ '抽取哨兵:已知块路径 `f.body` 出现在清单里', repr(probe_sig))
+
+ # ── 反向对照(**必须有牙**)──
+ # ⚠ `_is_block_like` 是 staticmethod ⇒ 必须取**描述符**再还原,否则还原成普通函数后
+ # 会被当实例方法调用(`takes 1 positional argument but 2 were given`,本档实测撞过)。
+ real_block_like = Parser.__dict__['_is_block_like']
+ real_want = Parser._want_value_expr
+
+ def _mutate_lines(src, attr, value):
+ Parser._is_block_like = value
+ try:
+ return v4_position_lines(src)
+ finally:
+ Parser._is_block_like = real_block_like
+
+ if_src = POSITION_FIXTURES[0][2]
+ asg_src = [f for f in POSITION_FIXTURES if '语句位尾随赋值' in f[0]][0][2]
+ expr_src = [f for f in POSITION_FIXTURES if 'x := if' in f[0]][0][2]
+
+ # R1(**那次的真回归**):收尾判据改回「一律包 ExprStmt」⇒ 尾随 `if` 的尾值消失 ⇒ 必红
+ got = _mutate_lines(if_src, '_is_block_like', staticmethod(lambda expr: False))
+ check(got != list(POSITION_FIXTURES[0][3]),
+ '[反向] 把收尾判据改回「一律包 ExprStmt」⇒ 尾随 `if` 的尾值消失 ⇒ 判据当场红',
+ '得 %r' % got)
+ # R2:反方向——块状判定恒真 ⇒ 普通尾项不再包 ExprStmt ⇒ 必红
+ got = _mutate_lines(asg_src, '_is_block_like', staticmethod(lambda expr: True))
+ check(got != list([f for f in POSITION_FIXTURES if '语句位尾随赋值' in f[0]][0][3]),
+ '[反向] 块状判定恒真 ⇒ 尾随赋值不再包 `ExprStmt` ⇒ 判据当场红', '得 %r' % got)
+ # R3:表达式位标志失效(`_want_value_expr` 退回语句位)⇒ 声明右值的 region 丢尾值 ⇒ 必红
+ gold_expr = list([f for f in POSITION_FIXTURES if 'x := if' in f[0]][0][3])
+ try:
+ Parser._want_value_expr = lambda self: self.parse_expr()
+ got = v4_position_lines(expr_src)
+ finally:
+ Parser._want_value_expr = real_want
+ check(got != gold_expr,
+ '[反向] 表达式位标志失效 ⇒ `x := if …` 两臂丢尾值 ⇒ 判据当场红', '得 %r' % got)
+
+ return not FAILS
+
+
+# ── mutations:反向对照汇总 ─────────────────────────────────────────────
+
+def cmd_mutations():
+ print('[mutations] 反向对照:每条判据「改坏一处 ⇒ 必红」的机械证据')
+ # 1) colon:把行尾判定短路成「永远行内」⇒ D9 那格必翻
+ got = []
+ for t in Lexer('fn add(a: int) -> int:\n').tokenize():
+ if t.type in (TokenType.COLON_DECL, TokenType.COLON_BLOCK):
+ got.append('BLOCK' if t.type == TokenType.COLON_BLOCK else 'DECL')
+ check(got == ['DECL', 'BLOCK'], '正控:D9 两 `:` 的标签', repr(got))
+ check(got != ['DECL', 'DECL'], '[反向] 行尾判定若失效 ⇒ D9 变 [DECL, DECL](判据红)')
+
+ # 2) layout:把「首个非空行建立 anchor」改成「固定列 1」⇒ 深缩进开头的源必红
+ src = ' fn f() -> int:\n return 1\n'
+ try:
+ k = kinds(src)
+ check(k.count('INDENT') == 1, '正控:首行缩进 2 建立基准 ⇒ 只有内层 1 个 INDENT', repr(k))
+ except SyntaxError as e:
+ check(False, '正控:首行缩进 2 建立基准', str(e))
+
+ # 3) features 负例:v3 花括号形必须红
+ try:
+ run_pipeline('fn main() -> int { return 1; }')
+ check(False, '[反向] v3 花括号形必须红')
+ except SyntaxError:
+ check(True, '[反向] v3 花括号形 ⇒ 红(T4 未做时自源必断,见报告)')
+ return not FAILS
+
+
+def main(argv):
+ rev = 'develop@origin'
+ sub = argv[1] if len(argv) > 1 else 'all'
+ if '--rev' in argv:
+ rev = argv[argv.index('--rev') + 1]
+
+ ok = True
+ if sub in ('features', 'all'):
+ ok = cmd_features() and ok
+ if sub in ('layout', 'all'):
+ ok = cmd_layout() and ok
+ if sub in ('colon', 'all'):
+ ok = cmd_colon() and ok
+ if sub in ('structlit', 'all'):
+ ok = cmd_structlit() and ok
+ if sub in ('typenames', 'all'):
+ ok = cmd_typenames() and ok
+ if sub in ('semi', 'all'):
+ ok = cmd_semi() and ok
+ if sub in ('ast-freeze', 'all'):
+ ok = cmd_ast_freeze(rev) and ok
+ if sub in ('keywords', 'all'):
+ kw = cmd_keywords()
+ ok = kw and ok
+ if sub in ('positions', 'all'):
+ ok = cmd_positions() and ok
+ if sub in ('mutations', 'all'):
+ ok = cmd_mutations() and ok
+
+ print()
+ floor = CHECK_FLOOR.get(sub, 0)
+ if CHECKS < floor:
+ print('VACUOUS: 判据只跑了 %d 条(`%s` 的下限 %d)—— 判据面变空了,本轮的绿不算数'
+ % (CHECKS, sub, floor))
+ return 1
+ print('判据条数 = %d(`%s` 下限 %d)' % (CHECKS, sub, floor))
+ if ok:
+ print('ALL PASS')
+ return 0
+ print('FAILURES (%d): %s' % (len(FAILS), '; '.join(FAILS)))
+ return 1
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/tools/v4_migrate.py b/tools/v4_migrate.py
new file mode 100644
index 00000000..7f8fdfc4
--- /dev/null
+++ b/tools/v4_migrate.py
@@ -0,0 +1,1116 @@
+#!/usr/bin/env python3
+"""v4 语法迁移 T4 —— `src/**/*.cr` 语料(92 档)的一次性机械改写工具。
+
+出处(规格):
+ - docs/superpowers/plans/2026-09-24-v4-syntax-migration.md §六(T4)与 §二(判据纪律)
+ - docs/maintainer/design/v4-layout-spec.md(T0 布局规格:空行/注释行/行尾注释的 anchor 规则)
+ - docs/core-language-syntax_v4.md(目标语法)
+
+用途:把 v3 写法(`{}` 块 + `;` 分隔)**机械改写成** v4 写法(`:` 结尾 + layout 缩进 + 换行分隔)。
+形状只有两类(计划 §6.1):`{}` → `:` + 缩进、`;` → 换行。**不做任何语义改动**。
+
+⚠ **本工具是一次性迁移工具,不是常设判据。**
+ 迁移收尾后它就该被冻结/删除;不得把它接进 CI,也不得让任何常设门依赖它。
+ 它自带的三项读数(V1 解析 / V2 token 对拍 / V3 计数 / V4 注释计数)是**当时那一刻**的
+ 迁移验收读数,不是回归网(回归网见计划 §二 的代 0/代 1/代 2 代表)。
+
+用法:
+ python3 tools/v4_migrate.py transform --dry-run FILE.cr # 只打印改写结果
+ python3 tools/v4_migrate.py transform --all-under src # 原地改写 src/** 全部 92 档
+ python3 tools/v4_migrate.py check FILE.cr ... # V1/V2/V3/V4 读数
+ python3 tools/v4_migrate.py check --all-under src --baseline DIR # 与改前快照对拍
+
+`--baseline DIR`:改前的原文快照目录(同相对路径)。给 `check` 时它做 V2/V3/V4 的对照读数。
+"""
+
+import argparse
+import os
+import re
+import sys
+
+_HERE = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, _HERE)
+sys.path.insert(0, os.path.join(os.path.dirname(_HERE), 'bootstrap'))
+
+import v4_migrate_v3lex as V3 # noqa: E402 (vendored v3 扫描器)
+
+# 改写面 = **`src/**` 下全部 `.cr`(92 档)**(协调者 2026-10-11 更正:计划 §6.1 的
+# 「七目录面 74 档」会漏掉四棵同样进编译单元的子树 —— `src/lattice`(1) ·
+# `src/lsp`(7) · `src/kernel`(9) · `src/scheduler`(1);逐目录 = compiler 38 ·
+# stdlib 19 · kernel 9 · lsp 7 · arch/x86_64 5 · os/linux 3 · format/elf 3 ·
+# targets/x86_64-linux 2 · runtime 2 · arch/hit 2 · scheduler 1 · lattice 1)。
+# `tests/`·`docs/`·`examples/`·`tools/`·`legacy_asm_backend/` 下的 `.cr` 属 T6,**不动**。
+SRC_ROOT = 'src'
+
+# ── token 集合 ────────────────────────────────────────────────────────────────
+T = V3.TokenType
+
+# 行尾是这些 ⇒ 下一物理行的首个 token 是本行的续行(必须并成一行,v4 无括号外续行)
+BINOP_END = {
+ T.PLUS, T.MINUS, T.STAR, T.SLASH, T.PERCENT,
+ T.AND_AND, T.PIPE_PIPE, T.EQ_EQ, T.NOT_EQ, T.LT, T.GT, T.LT_EQ, T.GT_EQ,
+ T.PIPE, T.AMPERSAND, T.DOT_DOT, T.EQ, T.ARROW, T.FAT_ARROW,
+}
+# 行首是这些 ⇒ 它是上一条语句的续行(必须并成一行)。
+# **不含** MINUS/STAR/AMPERSAND —— 它们能起一条新语句(取负/解引用/取引用);
+# 也不含 LT/GT(泛型尖括号在行首语义不明)。这组取法会在 V1 上被复核。
+BINOP_START = {
+ T.PLUS, T.SLASH, T.PERCENT, T.AND_AND, T.PIPE_PIPE,
+ T.EQ_EQ, T.NOT_EQ, T.LT_EQ, T.GT_EQ, T.PIPE, T.DOT_DOT, T.FAT_ARROW,
+}
+
+INDENT_UNIT = ' '
+
+
+class MigrateError(Exception):
+ pass
+
+
+# ── 分类 ──────────────────────────────────────────────────────────────────────
+def _is_struct_lit(toks, brace_pos):
+ """**逐字复刻** v3 parser(`/tmp/v3boot/corec/frontend/parser.py:_is_struct_lit`)的启发式。
+
+ brace 后首个 token 是 IDENT 且再下一个是 `=` 或 `:`,且**内部顶层没有 `;`**
+ (含空 `{}` ⇒ True)⇒ 字面量。
+ """
+ pos = brace_pos + 1
+ if pos >= len(toks):
+ return False
+ if toks[pos].type == T.RBRACE:
+ return True
+ if toks[pos].type != T.IDENT:
+ return False
+ if pos + 1 >= len(toks):
+ return False
+ nxt = toks[pos + 1].type
+ if nxt != T.EQ and nxt != T.COLON:
+ return False
+ depth = 1
+ limit = min(brace_pos + 100, len(toks))
+ for i in range(brace_pos + 1, limit):
+ tt = toks[i].type
+ if tt == T.LBRACE:
+ depth += 1
+ elif tt == T.RBRACE:
+ depth -= 1
+ elif tt in (T.LBRACK, T.LPAREN):
+ depth += 1
+ elif tt in (T.RBRACK, T.RPAREN):
+ depth -= 1
+ if depth == 0:
+ break
+ if tt == T.SEMI and depth == 1:
+ return False
+ return True
+
+
+def classify(toks):
+ """给每个 token 下标标上:LBRACE/RBRACE 的 kind、SEMI 的 kind。
+
+ 返回 `(brace_kind: dict[i]->'block'|'struct', semi_kind: dict[i]->'array'|'stmt', notes)`。
+ """
+ brace_kind = {}
+ semi_kind = {}
+ match = {} # LBRACE 下标 -> 配对 RBRACE 下标
+ notes = []
+ stack = [] # 未闭合的括号:(下标, 种类)
+ decl_brace_pending = False # `struct`/`enum`/`impl`/`interface` 之后的首个 `{` = 声明体
+ for i, tk in enumerate(toks):
+ t = tk.type
+ if t in (T.STRUCT, T.ENUM, T.IMPL, T.INTERFACE):
+ decl_brace_pending = True
+ elif t == T.LBRACE:
+ prev = toks[i - 1] if i > 0 else None
+ is_struct = (not decl_brace_pending
+ and prev is not None and prev.type == T.IDENT
+ and prev.lexeme[:1].isupper()
+ and _is_struct_lit(toks, i))
+ decl_brace_pending = False
+ if is_struct:
+ brace_kind[i] = 'struct'
+ stack.append((i, 'struct{'))
+ else:
+ brace_kind[i] = 'block'
+ stack.append((i, 'block{'))
+ elif t == T.RBRACE:
+ # 与最近的未闭合 `{` 配对
+ if not stack or not stack[-1][1].endswith('{'):
+ raise MigrateError('unbalanced } at offset %d' % tk.start)
+ oi, kind = stack.pop()
+ match[oi] = i
+ brace_kind[i] = 'struct' if kind == 'struct{' else 'block'
+ elif t == T.LPAREN:
+ stack.append((i, '('))
+ elif t == T.RPAREN:
+ if stack and stack[-1][1] == '(':
+ stack.pop()
+ elif t == T.LBRACK:
+ stack.append((i, '['))
+ elif t == T.RBRACK:
+ if stack and stack[-1][1] == '[':
+ stack.pop()
+ elif t == T.SEMI:
+ semi_kind[i] = 'array' if stack and stack[-1][1] == '[' else 'stmt'
+ if stack:
+ raise MigrateError('unbalanced brackets at EOF')
+ return brace_kind, semi_kind, match, notes
+
+
+# ── 空 region 的逐处裁定表(协调者 2026-10-11 裁定 1;**逐处判定,不扩语法面**)──────
+# 键 = (相对路径, `{` 所在行号);值 = 处理。
+# 'delete-if' —— 无 else、条件无副作用(不含函数调用/赋值)的 `if` ⇒ **整条删掉**;
+# 块内注释**保留**为同位置的独立注释行(V4「注释不得下降」+ 不丢信息)。
+# 'return' —— 函数体只含注释 ⇒ 保留注释,补一条与**声明返回类型**匹配的显式 return。
+# 本表里唯一一例的声明无 `-> T` ⇒ unit ⇒ 裸 `return`。
+# ⚠ 表外的空 region ⇒ **fail-closed 中止**(不猜、不静默跳过)。
+EMPTY_ACTIONS = {
+ # —— 裁定 1 规则 A:无 else + 条件纯局部量比较 ⇒ 删整条 if ——
+ ('src/compiler/interp.cr', 337): 'delete-if', # if op2 == 33 { } // IR_ARENA_RESET
+ ('src/compiler/interp.cr', 394): 'delete-if', # if op2 == 51 { } // IR_APPROX
+ ('src/compiler/interp.cr', 722): 'delete-if', # if op == 33 { } // IR_ARENA_RESET
+ ('src/compiler/parser.cr', 1743): 'delete-if', # if is_flow != 0 { /*2 行注释*/ }
+ # —— 协调者 2026-10-11 二裁(7 处全批)——
+ # 理由行:条件是局部量(tf / cv / then_node / else_node)的纯比较(无调用、无赋值),
+ # 链的净效果 = 按序读这些局部量若干次,无可观察行为 ⇒ 整条链删;块内注释逐字保留。
+ ('src/compiler/interp.cr', 97): 'delete-if-chain', # if tf == 1||tf == 3 { } else if tf == 2||tf == 3 { }
+ ('src/compiler/interp.cr', 98): 'delete-if-chain', # 同链第二分支(按 statement 起点去重,只处置一次)
+ ('src/compiler/opt.cr', 99): 'delete-if-chain', # if cv != 0 && then_node >= 0 { } else if cv == 0 && else_node >= 0 { }
+ ('src/compiler/opt.cr', 103): 'delete-if-chain', # 同链第二分支
+ # 理由行(协调者实核 `str_len` = `src/stdlib/fmt.cr:4-8` 纯读取:`load64(s,-8)` + 分支,
+ # 无写、无调用、无副作用;调用结果未被使用)⇒ 整条删。**已知偏差见报告**:条件里那一次
+ # 内存读被一并去掉(良构程序无差异;`source`/`content` 若是无效指针,原式会陷阱而删后不会)。
+ ('src/compiler/main.cr', 21): 'delete-if', # if str_len(source) > 0 { }
+ ('src/compiler/module.cr', 172): 'delete-if', # if str_len(content) > 0 { }
+ # 理由行:空 `else { }` 本身是 no-op;其所在 if/else-if 链的**非空分支一律不动** ⇒
+ # 只摘掉这截 `else { … }`,2 行注释降为同位置独立注释行。
+ ('src/compiler/provenance_verify.cr', 121): 'delete-else', # } else { /*2 行注释*/ }
+ # —— 裁定 1 规则 B:函数体只含注释 ⇒ 补显式 return(声明无 -> T ⇒ unit)——
+ ('src/compiler/dyn_arr.cr', 259): 'return', # fn _grow(...) { /*2 行注释*/ }
+}
+
+
+def _chain_ranges(toks, i, brace_kind, brace_match):
+ """`if … { } else if … { } …` 链的删除区间表(**只吃空块分支**)。
+
+ `i` = 链首那个空块的 `{` 下标。返回 `[(start, end), …]`(删 header 的 `… {` 与配对 `}`)。
+ 若链上遇到**非空**分支 ⇒ 停下抛 `MigrateError`(不猜)。
+ """
+ s = _statement_start(toks, i)
+ if toks[s].type != T.IF:
+ raise MigrateError('chain: statement does not start with `if` (offset %d)' % toks[i].start)
+ ranges = [(toks[s].start, toks[i].end), # `if cond {`
+ (toks[brace_match[i]].start, toks[brace_match[i]].end)] # 配对 `}`
+ n = brace_match[i] + 1
+ while n < len(toks) and toks[n].type == T.ELSE:
+ m = n + 1
+ while m < len(toks) and toks[m].type != T.LBRACE:
+ m += 1
+ if m >= len(toks) or brace_match.get(m) != m + 1:
+ raise MigrateError('chain: non-empty branch at offset %d' % toks[n].start)
+ cl = brace_match[m]
+ ranges.append((toks[n].start, toks[m].end)) # `else [if cond] {`
+ ranges.append((toks[cl].start, toks[cl].end)) # 配对 `}`
+ n = cl + 1
+ return ranges
+
+# ── unsafe-in-parens 上提(裁定 2)────────────────────────────────────────────
+# 描述性名(不是 t1/t2):按站点语义给基名;同名冲突再加 `_2`/`_3`。
+UNSAFE_TMP_NAMES = {
+ ('src/compiler/parser.cr', 921): 'name_str',
+ ('src/compiler/parser.cr', 1311): 'name_str',
+ ('src/format/elf/ld.cr', 140): 'so_path_str',
+ ('src/format/elf/ld.cr', 343): 'plt_name_str',
+ ('src/format/elf/ld.cr', 363): 'path_ptr',
+ ('src/format/elf/ld.cr', 365): 'name_ptr',
+ ('src/format/elf/ld.cr', 454): 'sp_str',
+ ('src/format/elf/ld.cr', 455): 'sp_str',
+ ('src/stdlib/cli.cr', 305): 'cmd_name_str',
+ ('src/stdlib/cli.cr', 328): 'cmd_name_str',
+}
+
+
+def _enclosing_blocks(toks, idx):
+ """返回下标 `idx` 的 token 所处的**块 `{`** 下标链(外 → 内)。
+
+ 只统计块花括号(结构体字面量的 `{` 不计),故与本工具的 `classify` 同判。
+ """
+ bk, _sk, _bm, _n = classify(toks)
+ stack = []
+ for i in range(idx):
+ if toks[i].type == T.LBRACE and bk.get(i) == 'block':
+ stack.append(i)
+ elif toks[i].type == T.RBRACE and bk.get(i) == 'block':
+ if stack:
+ stack.pop()
+ return stack
+
+
+def _statement_start(toks, idx):
+ """`idx` 所在**语句**的首 token 下标:向前退到最近的语句边界之后。
+
+ 边界 = 语句 `;` / 块 `{` / 块 `}`。`else` 起头**不支持**(会响亮报错,不猜)。
+ """
+ k = idx - 1
+ while k >= 0:
+ t = toks[k].type
+ if t == T.SEMI or t == T.LBRACE or t == T.RBRACE:
+ break
+ k -= 1
+ s = k + 1
+ if s < len(toks) and toks[s].type == T.ELSE:
+ raise MigrateError('hoist: statement starts with `else` at offset %d' % toks[idx].start)
+ return s
+
+
+# ── T6a:`src/` 之外语料的追加改写(**逐条记进报告**)────────────────────────
+# 背景:T4 的改写面是 `src/**`,那份语料**没有** match / enum 臂体块 / 规约标注独立行 /
+# `@hotpatch` 独立行,且 struct 字面量全部是 `=` 形(计划 §6.1/§6.2 实核)。`tests/`·`examples/`
+# 四条面各有这些形态 ⇒ 需要三条**纯形状**追加规则(都不是语义改动):
+# E1 struct 字面量分隔符 `:` → `=`:T0 §3.4 裁定 (a),v4 唯一合法形是 `T { f = v }`;
+# E2 规约标注 `#check`/`#ensure` 独立行 ⇒ 并入签名行尾:v4 `parse_spec_annotations`
+# 只在**签名行内**可见(parser.cr:1799 `check(T_HASH)`),独立行会被当顶层 token
+# ⇒ `error[P25]` + `error[V02]`(实测);
+# E3 `@hotpatch(...)` 独立行 ⇒ 并入其后声明行:`parse_declaration`(parser.cr:1860)
+# 要求注解与声明**同行**(`parse_expr()` 之后立刻 `check(T_FN)`),独立行 ⇒ `error[P25]`。
+#
+# ⚠ 三条都**按行形精确匹配**,命中不了就**原样不动**(负例语料里的错位标注因此不被误改),
+# 只有「看起来是要改、但形态不在口径内」才进 `unresolved`(fail-closed)。
+_ANNOT_LINE_RE = re.compile(r'^#(check|ensure)\s*\(')
+_HOTPATCH_LINE_RE = re.compile(r'^@hotpatch(\(.*\))?$')
+
+
+def _line_offsets(src):
+ offs, p = [], 0
+ for ln in src.split('\n'):
+ offs.append(p)
+ p += len(ln) + 1
+ return offs
+
+
+def _t6_extra_ops(toks, brace_kind, brace_match, src, filename, recs, unresolved, ops):
+ """E1/E2/E3 的文本编辑(追加到 `ops`)。arm 块的多语句面另在 E4 里查。"""
+ # ── E1:struct 字面量分隔符 `:` → `=` ──
+ for i, tk in enumerate(toks):
+ if brace_kind.get(i) != 'struct':
+ continue
+ m = brace_match.get(i)
+ if m is None:
+ continue
+ depth = 0
+ for j in range(i + 1, m):
+ t = toks[j].type
+ if t in (T.LBRACE, T.LPAREN, T.LBRACK):
+ depth += 1
+ elif t in (T.RBRACE, T.RPAREN, T.RBRACK):
+ depth -= 1
+ elif t == T.COLON and depth == 0 and j > 0 and toks[j - 1].type == T.IDENT:
+ ops.append((toks[j].start, toks[j].end, '='))
+ recs.setdefault('struct_lit_eq', []).append('%s:%d' % (filename, tk.line))
+
+ # ── E5:`None` → `none`(v4 关键字拼写;**本批唯一的非形状改写**)──
+ # 依据:v4 关键字表(docs/core-language-syntax_v4.md:38)含 `none`,无 `None`;
+ # 实测 `z : int? = None` ⇒ `error[N01] Undefined name 'None'`,`= none` ⇒ rc=0。
+ # T4 工具头注 R3 明写「`none` ↔ `None` 的关键字化不参与本变换」——那是因为 `src/**`
+ # **零处**使用(实核:`grep -n '\bNone\b' src/**/*.cr` 只命中注释),T4 面从不需要它。
+ # T6a 面有 2 档使用 ⇒ 必须同批改,否则这两档的 `T?` 语义面在 v4 下当场 N01。
+ # 只改**裸 IDENT token**(字符串/注释不是 token,天然不误伤)。
+ for tk in toks:
+ if tk.type in (T.NONE,) or (tk.type == T.IDENT and tk.lexeme == 'None'):
+ ops.append((tk.start, tk.end, 'none'))
+ recs.setdefault('none_rename', []).append('%s:%d' % (filename, tk.line))
+
+ # ── E2:规约标注独立行 ⇒ 并入签名行尾 ──
+ lines = src.split('\n')
+ offs = _line_offsets(src)
+ i = 1
+ while i < len(lines):
+ if not _ANNOT_LINE_RE.match(lines[i].strip()):
+ i += 1
+ continue
+ j = i
+ anns = []
+ while j < len(lines) and _ANNOT_LINE_RE.match(lines[j].strip()):
+ anns.append(lines[j].strip())
+ j += 1
+ prev = lines[i - 1].strip()
+ nxt = lines[j].strip() if j < len(lines) else ''
+ if prev.startswith('fn ') and nxt == '{':
+ ops.append((offs[i - 1] + len(lines[i - 1]), offs[j],
+ ' ' + ' '.join(anns) + ' '))
+ recs.setdefault('annot_inline', []).append('%s:%d' % (filename, i))
+ i = j
+
+ # ── E3:`@hotpatch(...)` 独立行 ⇒ 并入其后声明行 ──
+ for i in range(len(lines) - 1):
+ if not _HOTPATCH_LINE_RE.match(lines[i].strip()):
+ continue
+ if lines[i].strip() == '' or not lines[i + 1].strip():
+ continue
+ nxt = lines[i + 1].strip()
+ if not (nxt.startswith('fn ') or nxt.startswith('pub fn ')):
+ unresolved.append('%s:%d (@hotpatch 独立行,后随非 fn 声明)' % (filename, i + 1))
+ continue
+ ops.append((offs[i] + len(lines[i]), offs[i + 1], ' '))
+ recs.setdefault('hotpatch_inline', []).append('%s:%d' % (filename, i + 1))
+
+
+def pre_transform(src, filename):
+ """裁定 1/2 的**逐处**预处理(纯文本层),返回 `(new_src, records, unresolved)`。
+
+ - 裁定 1:按 `EMPTY_ACTIONS` 处理空 region(表外 ⇒ 进 `unresolved`,由上层 fail-closed);
+ - 裁定 2:把「括号内 `unsafe { E }`」机械上提为临时量。`E` 必须是**单个表达式**,
+ 否则进 `unresolved`(不自行判断)。
+ """
+ toks = [t for t in V3.Lexer(src, filename).tokenize()]
+ if toks and toks[-1].type == T.EOF:
+ toks[-1].start = len(src)
+ toks[-1].end = len(src)
+ brace_kind, semi_kind, brace_match, _ = classify(toks)
+ recs = {'deleted_if': [], 'deleted_else': [], 'return_filled': [], 'hoisted': [], 'blank_collapsed': []}
+ unresolved = []
+
+ # ── 裁定 1:空 region ──
+ ops = [] # (start, end, replacement) —— 所有裁定 1/2 的文本编辑统一走这里
+ seams = [] # 裁定 1 的**删除缝**起点(供末尾那段「≥2 空行收成 1」定位)
+ chain_done = set() # 链只需处置一次(同一 `if` 的每个空分支都指向同一 statement 起点)
+ for i, tk in enumerate(toks):
+ if brace_kind.get(i) != 'block' or brace_match.get(i) != i + 1:
+ continue
+ act = EMPTY_ACTIONS.get((filename, tk.line))
+ if act is None:
+ unresolved.append('%s:%d (empty region, 无裁定)' % (filename, tk.line))
+ continue
+ if act in ('delete-if', 'delete-if-chain'):
+ if act == 'delete-if-chain':
+ # 链的**第二及以后**分支:其 statement 起点落在 `else` 上 ⇒ `_statement_start`
+ # 会响亮拒绝。这不是错误,而是「本分支属链的续段、由链首那次处置」的信号。
+ # 真出错时链首也处置不了 ⇒ 空 region 残留 ⇒ 发射期 fail-closed 中止(不静默)。
+ try:
+ stmt = _statement_start(toks, i)
+ except MigrateError:
+ continue
+ else:
+ try:
+ stmt = _statement_start(toks, i)
+ except MigrateError as e:
+ unresolved.append('%s:%d (%s)' % (filename, tk.line, e))
+ continue
+ if act == 'delete-if':
+ ifs = i - 1
+ while ifs >= 0 and toks[ifs].type not in (T.IF, T.ELSE, T.SEMI, T.LBRACE, T.RBRACE):
+ ifs -= 1
+ if ifs < 0 or toks[ifs].type != T.IF:
+ unresolved.append('%s:%d (delete-if 找不到起头 `if`)' % (filename, tk.line))
+ continue
+ nxt = brace_match[i] + 1
+ if nxt < len(toks) and toks[nxt].type == T.ELSE:
+ unresolved.append('%s:%d (delete-if 但语句带 else ⇒ 改判 delete-if-chain)'
+ % (filename, tk.line))
+ continue
+ ops.append((toks[ifs].start, tk.end, '')) # 删 `if … {`
+ ops.append((toks[i + 1].start, toks[i + 1].end, '')) # 删配对 `}`
+ seams.append(toks[ifs].start)
+ recs['deleted_if'].append('%s:%d' % (filename, tk.line))
+ else:
+ if stmt in chain_done:
+ continue # 同链的第二分支:已随首分支处置
+ try:
+ rngs = _chain_ranges(toks, i, brace_kind, brace_match)
+ except MigrateError as e:
+ unresolved.append('%s:%d (%s)' % (filename, tk.line, e))
+ continue
+ chain_done.add(stmt)
+ for a, b in rngs:
+ ops.append((a, b, ''))
+ seams.append(rngs[0][0])
+ recs['deleted_if'].append('%s:%d (整条 if/else-if 链,%d 段)'
+ % (filename, tk.line, len(rngs)))
+ elif act == 'delete-else':
+ e = i - 1
+ while e >= 0 and toks[e].type not in (T.ELSE, T.IF, T.SEMI, T.LBRACE, T.RBRACE):
+ e -= 1
+ if e < 0 or toks[e].type != T.ELSE:
+ unresolved.append('%s:%d (delete-else 找不到起头 `else`)' % (filename, tk.line))
+ continue
+ ops.append((toks[e].start, tk.end, '')) # 删 `else … {`
+ ops.append((toks[i + 1].start, toks[i + 1].end, '')) # 删配对 `}`
+ seams.append(toks[e].start)
+ recs.setdefault('deleted_else', []).append('%s:%d' % (filename, tk.line))
+ elif act == 'return':
+ ops.append((tk.end, tk.end, ' return; ')) # `{` 之后补 `return;`
+ recs['return_filled'].append('%s:%d -> `return` (声明无 -> T ⇒ unit)'
+ % (filename, tk.line))
+ else:
+ unresolved.append('%s:%d (未知裁定 %r)' % (filename, tk.line, act))
+
+ # ── 裁定 2:括号内 `unsafe { E }` 上提 ──
+ used_names = {} # 块下标 -> 已用名集合(同名冲突判定用)
+ for i, tk in enumerate(toks):
+ if tk.type != T.UNSAFE:
+ continue
+ if i + 1 >= len(toks) or toks[i + 1].type != T.LBRACE:
+ continue
+ if brace_kind.get(i + 1) != 'block':
+ continue
+ # 是否在**括号内**(`(` 未闭合)—— 用 `_enclosing_blocks` 之外的括号栈判
+ stack = []
+ for j in range(i):
+ t = toks[j].type
+ if t in (T.LPAREN, T.LBRACK):
+ stack.append(t)
+ elif t == T.LBRACE and brace_kind.get(j) != 'struct':
+ stack.append(t)
+ elif t in (T.RPAREN, T.RBRACK, T.RBRACE):
+ if stack:
+ stack.pop()
+ if not stack or stack[-1] != T.LPAREN:
+ continue # 不在括号内 ⇒ 正常 region,无需上提
+ close = brace_match[i + 1]
+ inner = toks[i + 2:close]
+ if any(x.type == T.SEMI or x.type == T.LBRACE or x.type == T.RBRACE for x in inner):
+ unresolved.append('%s:%d (unsafe 体内非单个表达式)' % (filename, tk.line))
+ continue
+ # 命名:基名 + 同 scope 冲突则加后缀
+ base = UNSAFE_TMP_NAMES.get((filename, tk.line))
+ if base is None:
+ unresolved.append('%s:%d (unsafe 上提站点无名字表项)' % (filename, tk.line))
+ continue
+ anc = _enclosing_blocks(toks, i)
+ taken = set()
+ for b in anc:
+ taken |= used_names.get(b, set())
+ name, n = base, 1
+ while name in taken or re.search(r'\b%s\b' % re.escape(name),
+ src[toks[_statement_start(toks, i)].start:
+ toks[close].end]):
+ n += 1
+ name = '%s_%d' % (base, n)
+ used_names.setdefault(anc[-1] if anc else -1, set()).add(name)
+ stmt = _statement_start(toks, i)
+ inner_txt = src[toks[i + 1].end:toks[close].start]
+ ops.append((tk.start, toks[close].end, name)) # `unsafe {E}` → 名
+ ops.append((toks[stmt].start, toks[stmt].start,
+ '%s := unsafe {%s}; ' % (name, inner_txt))) # 语句前插声明
+ recs['hoisted'].append('%s:%d -> `%s`' % (filename, tk.line, name))
+
+ # ── T6a 追加三条规则(E1/E2/E3)与 E4 守卫 ──
+ _t6_extra_ops(toks, brace_kind, brace_match, src, filename, recs, unresolved, ops)
+
+ # 统一**降序**下沉:所有替换/插入一次性按起点从大到小落,
+ # 保证先落的(更靠后)不会挪动后落的(更靠前)的偏移。
+ for start, end, rep in sorted(ops, key=lambda e: -e[0]):
+ src = src[:start] + rep + src[end:]
+
+ # ── 收拢「被删整条语句」在**同一 region 内**留下的**连续 ≥2 个空行**(协调者 2026-10-11 答 Q1)──
+ # 只收**裁定 1 的删除缝**处那一段;**不做全档「≥2 空行 → 1」的全局收拢**
+ # ——语料里本来就有大量「连续 2 空行」的原有写法(实测 11 档:corearch/ast/checker/
+ # fmt/frame/regalloc/instr/ld/term_io/elf/opt),全局收拢会**平白吃掉原文的空行**、
+ # 让 V4b 假性下降。⇒ 只在删除缝那一处收,且只在缝本身确实≥2 时才收。
+ if seams:
+ src, collapsed = _collapse_blank_runs_at(
+ src, [_map_pos(x, ops) for x in seams])
+ recs['blank_collapsed'] = collapsed
+ return src, recs, unresolved
+
+
+def _map_pos(x, ops):
+ """把**编辑前**的偏移 `x` 映射到**编辑后**的偏移(`ops` = 全部 (start,end,rep))。"""
+ shift = 0
+ for s, e, r in sorted(ops, key=lambda o: o[0]):
+ if s >= x:
+ break
+ if e <= x:
+ shift += len(r) - (e - s)
+ return x + shift
+
+
+def _collapse_blank_runs_at(text, positions):
+ """把 `positions` 各自所在的那一段**连续空行**(长度 ≥2 时)收成 1 行。
+
+ 返回 `(新文本, 收拢点行号表)`。**只在这些位置收**——不动别处的原有空行。
+ """
+ lines = text.split('\n')
+ sentinel = len(lines) - 1 if lines and lines[-1] == '' else len(lines)
+ starts, pos = [], 0
+ for l in lines:
+ starts.append(pos)
+ pos += len(l) + 1
+ import bisect
+ touched, drop = set(), set()
+ for p in positions:
+ i = bisect.bisect_right(starts, p) - 1
+ j = i
+ if not (0 <= j < sentinel) or lines[j].strip():
+ j = i - 1 # 缝落在非空行上 ⇒ 看它前面那一行
+ if not (0 <= j < sentinel) or lines[j].strip():
+ continue
+ a = j
+ while a > 0 and a - 1 < sentinel and not lines[a - 1].strip():
+ a -= 1
+ b = j
+ while b + 1 < sentinel and not lines[b + 1].strip():
+ b += 1
+ if b in touched:
+ continue
+ for k in range(a, b + 1):
+ touched.add(k)
+ if b - a + 1 >= 2: # ≥2 才收;孤立的 1 行不动
+ for k in range(a + 1, b + 1):
+ drop.add(k)
+ kept = [l for k, l in enumerate(lines) if k not in drop]
+ return '\n'.join(kept), ['line %d' % (k + 1) for k in sorted(drop)]
+
+
+# ── 改写 ──────────────────────────────────────────────────────────────────────
+def transform_text(src, filename='', empty_policy='table'):
+ """v3 文本 → v4 文本。返回 `(out, report)`;不可机械改写时抛 `MigrateError`。"""
+ report = {'file': filename, 'notes': [], 'merges': [], 'aborted': None}
+ if empty_policy == 'table':
+ src, recs, unresolved = pre_transform(src, filename)
+ for k, v in recs.items():
+ report[k] = v
+ if unresolved:
+ report['aborted'] = 'unresolved: ' + '; '.join(unresolved)
+ return None, report
+
+ toks = [t for t in V3.Lexer(src, filename).tokenize()]
+ if toks and toks[-1].type == T.EOF:
+ toks[-1].start = len(src)
+ toks[-1].end = len(src)
+ brace_kind, semi_kind, brace_match, notes = classify(toks)
+ report['notes'] = notes
+
+ # 空 region 是 v4 的表达盲区(region 不能为空:`if x:` 之后必须有一个更深列的真 token)。
+ # 注意:**只含注释的 region 与真空 region 在 token 面上不可区分**(注释不是 token)
+ # ⇒ 两者由同一条判定抓住(`brace_match[i] == i+1`)。
+ # `table` 策略下这一轮应已由 `pre_transform` 清空;仍有残留 ⇒ fail-closed 中止。
+ empty_braces = set()
+ for i, tk in enumerate(toks):
+ if brace_kind.get(i) == 'block' and brace_match.get(i) == i + 1:
+ empty_braces.add(i)
+ report.setdefault('empty_regions', []).append(
+ 'offset %d (line %d)' % (tk.start, tk.line))
+ if empty_braces and empty_policy != 'unit':
+ report['aborted'] = ('empty region(s): %s' % '; '.join(report['empty_regions']))
+ return None, report
+
+ out = []
+ cur = ''
+ indent = 0
+ depth = 0 # 括号/结构体字面量深度(>0 ⇒ 隐式续行,layout 关闭)
+ line_base = 0 # **本行起始时**的 bracket depth —— 见 flush() 的注释
+ region_stack = []
+ split_pending = False
+ prev_end = 0
+ prev_tok = None
+
+ def flush():
+ nonlocal line_base
+ # 行的缩进取「**本行起始时**的 bracket depth」(`line_base`),不是 flush 时的 `depth`。
+ # 理由(实测撞出的真缺陷):`foo(a,\n b)` 这类括号内续行的**首行**,
+ # 若按 flush 时的 depth 缩进,会得到比语句基准更深的列;而 v4 lexer 在**该行首个
+ # token** 处 bracket_depth 还是 0 ⇒ 它会发一个 INDENT ⇒ parser 在表达式位看到 INDENT
+ # 而响亮报错(hit.cr:1103 就是这样红的)。续行的第二行起,lexer 的 bracket_depth>0
+ # ⇒ 不发 layout,缩进深浅无所谓;把它排在更深列只为可读性。
+ nonlocal cur
+ if cur.strip():
+ out.append(INDENT_UNIT * (indent + line_base) + cur.strip())
+ cur = ''
+ line_base = depth
+
+ def emit_gap(gap, force, merge):
+ nonlocal cur
+ if merge:
+ i1 = gap.index('\n')
+ if '//' in gap[:i1] or '/*' in gap[:i1]:
+ report['merges'].append(
+ 'COMMENT-BLOCKED merge at offset ~%d: %r' % (prev_end, gap[:i1]))
+ # 不并(保留行断),V1 会把它抓出来
+ _plain_gap(gap, force)
+ return
+ cur += ' '
+ report['merges'].append('merged continuation near offset %d' % prev_end)
+ return
+ _plain_gap(gap, force)
+
+ def _plain_gap(gap, force):
+ nonlocal cur, line_base
+ if '\n' not in gap:
+ cur += gap
+ if force:
+ flush()
+ return
+ # **按物理行拆,不按「首尾换行下标之间的切片」拆**。
+ # 修复前的写法 `mid = gap[i1+1:ilast]` + `if mid:` 在**连续换行**时把空行吞掉:
+ # gap == '\n\n'(= 一个空行)时 mid == '' ⇒ 不产出任何行 ⇒ 空行消失。
+ # 后果实测:`}` 行被删除后、其后那个空行一起没了 ⇒ 全语料「函数紧贴函数」
+ # (`src/stdlib/fmt.cr` 空行 18 → 7,协调者抽检抓到)。
+ # 正确拆法:`gap.split('\n')` 的 `[1:-1]` 恰是「夹在首尾换行之间的整行」,
+ # k 个换行 ⇒ k-1 个整行(空行按原样留成空串)。T0 §1.1 ①-1:空行不参与 layout ⇒ 保留零风险。
+ parts = gap.split('\n')
+ cur += parts[0]
+ flush()
+ out.extend(parts[1:-1])
+ tail = parts[-1]
+ if tail.strip():
+ # 收尾那截(下一个 token 所在行的行首缩进)里**可能有块注释**(`/* … */ fn`):
+ # 有内容就不能丢,降为独立行;纯空白则丢弃(缩进由本工具自算)。
+ out.append(tail)
+ cur = ''
+ line_base = depth
+
+ for idx, tk in enumerate(toks):
+ if tk.type == T.EOF:
+ emit_gap(src[prev_end:tk.start], force=split_pending, merge=False)
+ flush()
+ break
+ gap = src[prev_end:tk.start]
+ force = split_pending
+ split_pending = False
+ merge = False
+ if '\n' in gap and depth == 0 and not force:
+ if prev_tok is not None and prev_tok.type in BINOP_END:
+ merge = True
+ elif tk.type in BINOP_START and prev_tok is not None \
+ and prev_tok.type not in (T.SEMI, T.LBRACE, T.RBRACE):
+ merge = True
+ emit_gap(gap, force, merge)
+
+ t = tk.type
+ if t == T.SEMI:
+ if semi_kind.get(idx) == 'array':
+ cur += ';'
+ else:
+ split_pending = True
+ elif t == T.LBRACE:
+ if brace_kind[idx] == 'block':
+ # ── Allman 形(块 `{` 独占行首)修复(协调者 2026-10-11 裁定 2)──────────
+ # 修复前:`cur` 为空时也 `cur = '' + ':'` ⇒ 发射出一行**孤零零的 `:`**,
+ # 该行既不接上文、也不开 region(实测 `tests/spec/t2_pos_check.cr` 等 9 档
+ # 变成 `fn f() -> int` / `#check(1 >= 0)` / `:` 三行 ⇒ 自源报 {P02,P25,V02})。
+ # 修复后:`{` 独占行首 ⇒ `:` 落到**上一个非空输出行**末尾(该行本就是它
+ # 逻辑上的头部行),`{` 那一行随之消失。纯 layout、零 token 变更。
+ # ⚠ 边界:若该行是注释行,追加 `:` 会被注释吞掉 ⇒ 不追加,退化为独立 `:` 行,
+ # 并**响亮登记**(不静默)。
+ if cur.strip():
+ cur = cur.rstrip() + ':'
+ flush()
+ else:
+ j = len(out) - 1
+ while j >= 0 and not out[j].strip():
+ j -= 1
+ if j >= 0 and not out[j].lstrip().startswith('//') \
+ and '//' not in out[j]:
+ out[j] = out[j].rstrip() + ':'
+ report.setdefault('allman_join', []).append('line %d' % tk.line)
+ else:
+ out.append(':')
+ report.setdefault('allman_orphan_colon', []).append('line %d' % tk.line)
+ region_stack.append(indent)
+ indent += 1
+ if idx in empty_braces:
+ # 策略 `unit`:空 region 里补一个 `unit` 表达式(v4 唯一的空值字面量;
+ # **`()` 在 v4 前端不可用**——`parse_primary` 的 LPAREN 分支不容空括号)。
+ # ⚠ 这是**唯一会新增 token 的改写**,逐处登记在报告的 `unit_filled` 里。
+ cur = 'unit'
+ split_pending = True
+ report.setdefault('unit_filled', []).append('line %d' % tk.line)
+ else:
+ cur += '{'
+ depth += 1
+ elif t == T.RBRACE:
+ if brace_kind[idx] == 'block':
+ flush()
+ indent = region_stack.pop()
+ else:
+ depth -= 1
+ cur += '}'
+ elif t == T.LPAREN:
+ cur += '('
+ depth += 1
+ elif t == T.RPAREN:
+ depth = max(0, depth - 1)
+ cur += ')'
+ elif t == T.LBRACK:
+ cur += '['
+ depth += 1
+ elif t == T.RBRACK:
+ depth = max(0, depth - 1)
+ cur += ']'
+ else:
+ # **原文切片**,不用 `tk.lexeme` —— 字符串/字符字面量的 lexeme 是**解码后**的
+ # 内容(`""` 会变成空串、`"\n"` 会变成真换行),十六进制整数字面量的 lexeme
+ # 是十进制值。取源切片才能逐字保留。
+ cur += src[tk.start:tk.end]
+ prev_end = tk.end
+ prev_tok = tk
+ if split_pending and t != T.SEMI:
+ # 兜底:非 `;` 的 token 也可能置位(不会发生),保守清掉
+ pass
+
+ # 行尾空白清理:注释行/空行是**逐字搬运**的,被删掉的 `if … {` 会留下「只有空格」的行;
+ # 统一 `rstrip` 每行(行尾空白对任何判据都无意义)⇒ 产物 = `transform(基线)` 的确定函数。
+ #
+ # 末尾换行**恒补一个**(`'\n'.join(out) + '\n'`):`out` 的每一项是「一行」,
+ # 于是 `out = […, 'X', '']` 必须落成 `…X\n\n`(= X 之后**一个空行**),
+ # 而 `'\n'.join` 单独用只会落成 `…X\n`(空行被 join 吃掉)——实测后果:
+ # 语料里以 `}\n\n` 收尾的档会少掉 EOF 那个空行(`src/kernel/term_io.cr` 因此 V4b 降 1)。
+ text = ('\n'.join(l.rstrip() for l in out) + '\n') if out else ''
+ return text, report
+
+
+# ── V1:v4 前端解析 ───────────────────────────────────────────────────────────
+V1_ENGINE = 'py' # 由 --v1-engine 覆盖(T6a 追加,见下)
+REPO_ROOT = os.path.dirname(_HERE)
+
+
+def _v4_parse_ok_native(text, filename):
+ """用**本仓自源编译器**(`build/corec check`)做 v4 解析读数。
+
+ T6a 追加的理由(实测,逐条可复现):`bootstrap/` 的 Python 前端**落后于**自源前端,
+ 在本批语料上至少四处误报(自源 rc=0 而 Python 前端语法错):
+ · 语句位 `as` 转换(`n := d as int`)——Python 前端「expected end of line, got 'as'」;
+ · `extern fn` 顶层声明;· `go i 0..3 f(i)`(并行 for);· `*T` 作结构体字段类型 / 元组类型。
+ ⇒ 对 `src/` 之外这批语料,**判据的目标前端是自源编译器**(T5 已落地);Python 前端只作补充。
+ 临时落盘路径保留相对路径(import 解析靠文件所在目录),cwd = 仓根(prelude 取自 `src/stdlib/`)。
+ """
+ import subprocess
+ import shutil
+ rel = filename if not os.path.isabs(filename) else os.path.basename(filename)
+ tmp = os.path.join('/tmp/v4_migrate_v1', rel)
+ os.makedirs(os.path.dirname(tmp), exist_ok=True)
+ with open(tmp, 'w', encoding='utf-8') as fh:
+ fh.write(text)
+ cc = os.path.join(REPO_ROOT, 'build', 'corec')
+ if not os.path.exists(cc):
+ return None, 'native engine unavailable (no build/corec)'
+ p = subprocess.run(['nice', '-n', '19', cc, 'check', tmp],
+ cwd=REPO_ROOT, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ out = p.stdout.decode('utf-8', 'replace')
+ if p.returncode == 0:
+ return True, None
+ # **只把 parse 相([3/5] 与 [4/5] 之间)的 error 算 V1 失败**。
+ # 理由:本批一半语料是**负例**(probes/spec/suite 的 rc=1 是**预期**),`check` 的 rc
+ # 把「解析失败」与「语义/负例报错」混在一个数里 ⇒ 直接拿 rc 当 V1 会把负例全部误判。
+ # 空文件(`cannot read`,出现在 [1/5] 之前)不计失败(T6a 面有 4 档 0 字节档)。
+ lines = out.splitlines()
+ i0 = next((k for k, l in enumerate(lines) if l.startswith('[3/5]')), len(lines))
+ i1 = next((k for k, l in enumerate(lines) if l.startswith('[4/5]')), len(lines))
+ errs = [l for l in lines[i0:i1] if l.startswith('error')]
+ if errs:
+ return False, ('native parse error (rc=%d): %s' % (p.returncode, '; '.join(errs[:3])))
+ return True, None
+
+
+def v4_parse_ok(text, filename=''):
+ eng = V1_ENGINE
+ if eng in ('both', 'native'):
+ ok, err = _v4_parse_ok_native(text, filename)
+ if err is not None and err.startswith('native engine unavailable'):
+ if eng == 'native':
+ return ok, err
+ elif ok:
+ return True, None
+ elif eng == 'native':
+ return False, err
+ from corec.frontend.lexer import Lexer
+ from corec.frontend.parser import Parser
+ try:
+ Parser(Lexer(text, filename).tokenize()).parse_compilation_unit()
+ return True, None
+ except Exception as e: # SyntaxError / 其它
+ return False, '%s: %s' % (type(e).__name__, e)
+
+
+# ── V2:token 序列对拍 ────────────────────────────────────────────────────────
+_V3_DROP = {T.SEMI, T.LBRACE, T.RBRACE}
+# v4 面:NEWLINE/INDENT/DEDENT 是 layout 发射;COLON_BLOCK 是 `{` 的**结构替身**
+# (v3 的 LBRACE 已被丢弃 ⇒ COLON_BLOCK 也必须丢,否则每一处块开都成假差异)。
+_V4_DROP = {'NEWLINE', 'INDENT', 'DEDENT', 'COLON_BLOCK'}
+_V4_RENAME = {'COLON_DECL': 'COLON'}
+
+
+def v2_tokens_v3(src):
+ """v3 侧可对拍 token 序列。
+
+ 丢弃面**按分类**取,不是按 token 种类一把抓:
+ - `SEMI`:只丢**语句分隔**的(`stmt`),**数组形的 `;`(`[T; N]` / `[v; N]`)保留**;
+ - `LBRACE`/`RBRACE`:只丢**块**的,**结构体字面量的花括号保留**(v4 里它们是原形)。
+ 若一把抓全丢,则 `[N; 4]` 与 `MemLayout { … }` 会与 v4 侧错位(首轮实测:collections.cr
+ 差 701 项、toml.cr 差 38 项 —— 全是这个错位的后果)。
+ """
+ toks = V3.Lexer(src).tokenize()
+ brace_kind, semi_kind, _bm, _n = classify(toks)
+ seq = []
+ for i, tk in enumerate(toks):
+ if tk.type == T.EOF:
+ continue
+ if tk.type == T.SEMI and semi_kind.get(i) == 'stmt':
+ continue
+ if tk.type in (T.LBRACE, T.RBRACE) and brace_kind.get(i) == 'block':
+ continue
+ seq.append((tk.type.name, tk.lexeme))
+ return seq
+
+
+def v2_tokens_v4(text):
+ from corec.frontend.lexer import Lexer
+ seq = []
+ for tk in Lexer(text).tokenize():
+ name = tk.type.name
+ if name in _V4_DROP or name == 'EOF':
+ continue
+ seq.append((_V4_RENAME.get(name, name), tk.lexeme))
+ return seq
+
+
+def v2_diff(old_src, new_text):
+ """按**最长公共子序列**对齐两侧 token,返回真正的增删项。
+
+ 位置对齐(`a[i] != b[i]`)在**有一处增删**时会把其后全部标成差异(相位错位)
+ —— 那不可读也不可审。⇒ 用 `difflib.SequenceMatcher` 取 edit script。
+ """
+ import difflib
+ a = v2_tokens_v3(old_src)
+ b = v2_tokens_v4(new_text)
+ sm = difflib.SequenceMatcher(a=a, b=b, autojunk=False)
+ diffs = []
+ for tag, i1, i2, j1, j2 in sm.get_opcodes():
+ if tag == 'equal':
+ continue
+ diffs.append((tag, a[i1:i2], b[j1:j2]))
+ return a, b, diffs
+
+
+# ── V3 / V4 计数 ──────────────────────────────────────────────────────────────
+def brace_counts(text):
+ """(裸字符花括号计数, 代码面花括号 token 计数)。"""
+ raw_open = text.count('{')
+ raw_close = text.count('}')
+ return raw_open, raw_close
+
+
+def comment_counts(text):
+ """粗算注释条数:`//` 行数与 `/* */` 块数(够用于「不得下降」的判据)。"""
+ line_c = 0
+ for ln in text.split('\n'):
+ s = ln.lstrip()
+ if s.startswith('//'):
+ line_c += 1
+ line_c += len(re.findall(r'(? int #check(1 >= 0):` +
+ **缩进被吃的** `return 1`。⇒ **无 v3 形状标记却会改动文本 ⇒ 拒写**(fail-closed)。
+ `[T; N]` 的 `;` 与 struct 字面量的 `{}` **不算标记**(它们 v3/v4 同形)。
+ """
+ try:
+ toks = [t for t in V3.Lexer(src, '').tokenize()]
+ bk, sk, _bm, _n = classify(toks)
+ except MigrateError:
+ return True # 读不动 ⇒ 交正常路径响亮报错
+ return any(v == 'block' for v in bk.values()) or any(v == 'stmt' for v in sk.values())
+
+
+# ── CLI ───────────────────────────────────────────────────────────────────────
+def gather(paths, all_under):
+ out = []
+ for p in paths:
+ out.append(p)
+ for d in all_under or []:
+ for root, _, fs in os.walk(d):
+ for f in fs:
+ if f.endswith('.cr'):
+ out.append(os.path.join(root, f))
+ return sorted(set(out))
+
+
+def cmd_transform(args):
+ files = gather(args.files, args.all_under)
+ if not files:
+ print('no files', file=sys.stderr)
+ return 2
+ n_ok = n_abort = n_fail = n_forced = n_refuse = 0
+ for p in files:
+ src = open(p, encoding='utf-8').read()
+ try:
+ out, rep = transform_text(src, p, args.empty_policy)
+ except MigrateError as e:
+ print('ABORT %-45s %s' % (p, e))
+ n_fail += 1
+ continue
+ if out is None:
+ print('SKIP %-45s %s' % (p, rep['aborted']))
+ n_abort += 1
+ continue
+ ok, err = v4_parse_ok(out, p)
+ if out != src and not _has_v3_markers(src):
+ print('REFUSE %-45s 输入无 v3 形状标记(已是 v4?)⇒ 拒写;重跑本工具会 mangle' % p)
+ n_refuse += 1
+ continue
+ if not ok and not args.force:
+ print('V1FAIL %-45s %s' % (p, err))
+ n_fail += 1
+ if args.dry_run:
+ print(out)
+ continue
+ if not ok:
+ print('V1FAIL(force) %-45s %s' % (p, err))
+ n_forced += 1
+ if args.dry_run:
+ sys.stdout.write(out)
+ print('--- %s OK ---' % p, file=sys.stderr)
+ else:
+ with open(p, 'w', encoding='utf-8') as fh:
+ fh.write(out)
+ extra = ''
+ for k in ('deleted_if', 'return_filled', 'hoisted'):
+ if rep.get(k):
+ extra += ' | %s=%s' % (k, ','.join(rep[k]))
+ print('OK %-45s%s' % (p, extra))
+ n_ok += 1
+ print('=== transform: ok=%d skip=%d fail=%d forced=%d refuse=%d ==='
+ % (n_ok, n_abort, n_fail, n_forced, n_refuse))
+ return 1 if n_fail else 0
+
+
+def cmd_check(args):
+ files = gather(args.files, args.all_under)
+ tot = {'brace_open': 0, 'brace_close': 0, 'semi': 0,
+ 'comment_lines': 0, 'blank_lines': 0}
+ v1_fail = v2_fail = v4a_fail = v4b_fail = 0
+ print('%-40s %5s %5s %6s | %-13s | %-13s | %s' %
+ ('file', '{', '}', ';', 'V4a // b->a', 'V4b blank b->a', 'V1/V2'))
+ for p in files:
+ new = open(p, encoding='utf-8').read()
+ m = file_metrics(new)
+ for k in tot:
+ tot[k] += m[k]
+ bp = os.path.join(args.baseline, p) if args.baseline else None
+ old = open(bp, encoding='utf-8').read() if (bp and os.path.exists(bp)) else None
+ # 与基线**逐字节相同** ⇒ 本档未迁移(不是「迁移失败」)。它的 V1 仍会红
+ # (还是 v3 文本),V2 也会「差」(v3 侧块花括号被丢、v4 侧没丢)。
+ # ⇒ 显式标 UNCHANGED 且**不计入失败**,否则报告把「跳过」读成「改坏」。
+ if old is not None and old == new:
+ print('%-40s %5d %5d %6d | %-13s | %-13s | UNCHANGED (未迁移)' %
+ (p, m['brace_open'], m['brace_close'], m['semi'], '-', '-'))
+ continue
+ ok, err = v4_parse_ok(new, p)
+ v1s = 'V1ok' if ok else 'V1FAIL'
+ if not ok:
+ v1_fail += 1
+ v2s = v4as = v4bs = ''
+ if old is not None:
+ om = file_metrics(old)
+ v4as = '%d->%d' % (om['comment_lines'], m['comment_lines'])
+ v4bs = '%d->%d' % (om['blank_lines'], m['blank_lines'])
+ if m['comment_lines'] < om['comment_lines']:
+ v4a_fail += 1
+ v4as += ' FAIL'
+ if m['blank_lines'] < om['blank_lines']:
+ if p in V4B_BLANK_DROP_EXEMPT:
+ v4bs += ' DROP(裁定删语句·已归因)'
+ else:
+ v4b_fail += 1
+ v4bs += ' FAIL'
+ try:
+ a, b, diffs = v2_diff(old, new)
+ if diffs:
+ v2_fail += 1
+ v2s = 'V2DIFF(%d)' % len(diffs)
+ else:
+ v2s = 'V2ok'
+ except MigrateError as e:
+ v2s = 'V2skip(%s)' % e
+ print('%-40s %5d %5d %6d | %-13s | %-13s | %s %s %s' %
+ (p, m['brace_open'], m['brace_close'], m['semi'],
+ v4as, v4bs, v1s, v2s, (err or '')[:40]))
+ print('%-40s %5d %5d %6d | %-13s | %-13s' %
+ ('TOTAL', tot['brace_open'], tot['brace_close'], tot['semi'],
+ str(tot['comment_lines']), str(tot['blank_lines'])))
+ print('V1 failures: %d | V2 mismatching files: %d | V4a (comment) drops: %d | V4b (blank) drops: %d'
+ % (v1_fail, v2_fail, v4a_fail, v4b_fail))
+ return 1 if (v1_fail or v4a_fail or v4b_fail) else 0
+
+
+def main():
+ ap = argparse.ArgumentParser(description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ sub = ap.add_subparsers(dest='cmd', required=True)
+
+ t = sub.add_parser('transform')
+ t.add_argument('files', nargs='*')
+ t.add_argument('--all-under', nargs='*', default=None)
+ t.add_argument('--dry-run', action='store_true')
+ t.add_argument('--force', action='store_true',
+ help='T6a 追加:V1 失败仍写盘。**只对「解析失败是预期结果」的负例语料用**'
+ '(tests/spec/t2_neg_* 等);正例档用它是掩盖回归,不得使用。')
+ t.add_argument('--v1-engine', default='py', choices=['py', 'native', 'both'],
+ help='V1 解析读数用哪个前端(T6a 追加):py=bootstrap Python 前端(原行为)· '
+ 'native=本仓 build/corec · both=优先 native')
+ t.add_argument('--empty-policy', default='table',
+ choices=['table', 'skip', 'unit'],
+ help='空 region 的处置:table=逐处裁定表(默认) · skip=中止 · unit=补 unit 占位(调试用)')
+ t.set_defaults(func=cmd_transform)
+
+ c = sub.add_parser('check')
+ c.add_argument('files', nargs='*')
+ c.add_argument('--all-under', nargs='*', default=None)
+ c.add_argument('--v1-engine', default='py', choices=['py', 'native', 'both'])
+ c.add_argument('--baseline', default=None,
+ help='改前原文快照目录(同相对路径)')
+ c.set_defaults(func=cmd_check)
+
+ args = ap.parse_args()
+ global V1_ENGINE
+ V1_ENGINE = getattr(args, 'v1_engine', 'py')
+ return args.func(args)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/tools/v4_migrate_inline.py b/tools/v4_migrate_inline.py
new file mode 100644
index 00000000..f576cbd9
--- /dev/null
+++ b/tools/v4_migrate_inline.py
@@ -0,0 +1,702 @@
+#!/usr/bin/env python3
+"""v4 迁移 T6b —— **内嵌 Core 源**的机械改写工具(T4 工具 `tools/v4_migrate.py` 的「内嵌版」)。
+
+存在理由:T4 的 `v4_migrate.py` 处理的是**整档 `.cr`**(整篇就是 Core)。T6b 的语料是
+**嵌在别的语言里**的 Core 片段——`.py` 的三引号字符串 / `.md` 的 ``` 围栏块 / `rebuild.sh`
+的单引号内联命令。这些宿主文件里**只有那几段**是 Core,其余字节(缩进、引号风格、fence
+标记、行尾空白)**必须一字不动**。
+
+转换核心 = `import v4_migrate`(**不复制实现**——两份必然漂)。本文件只负责:
+ ① 判定「哪几段是 Core 源」(`is_core`);
+ ② 逐字节安全地抽取/回填(`migrate_py` / `migrate_md`),宿主非 Core 面零改动。
+
+判据(双轨,见 T6b 任务书):
+ - 机械轨:每个被改写的段做 V2(与改前**逐 token 相同**)+ V4a/V4b(注释行/空行**不下降**);
+ - 真实轨:`tests/bootstrap/*.py` 必须全绿、`tests/selfhost/*.py` 能跑的必须绿。
+
+用法:
+ python3 tools/v4_migrate_inline.py report # 逐档列出被判定为 Core 的段(不动盘)
+ python3 tools/v4_migrate_inline.py apply FILE... # 原地改写(.py / .md / .sh)
+"""
+import argparse
+import ast
+import os
+import re
+import sys
+
+_HERE = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, _HERE)
+sys.path.insert(0, os.path.join(os.path.dirname(_HERE), 'bootstrap'))
+
+import v4_migrate as M # noqa: E402
+
+T = M.T
+
+# ── 「是 Core 源」的判定 ──────────────────────────────────────────────────────
+# **不用「改完能 v4 解析」当判据**:语料里有大量**故意写坏**的负例夹具(未知标签 /
+# 嵌套 fn / 非穷尽 match / 语法错),它们的 v4 解析**本就必须失败**。用解析成功当判据
+# 会把这一类整批漏掉(实测:734 过 / 461 漏,漏的几乎全是负例夹具)。
+#
+# 改判据:**声明头 / 语句形态**正则 + v3 词法可切(`transform_text` 不抛)双条件。
+# 前者抓 Core 的形态,后者排除散文(散文的括号/花括号通常不平衡 ⇒ transform 抛)。
+CORE_DECL_RE = re.compile(
+ r'\bfn\s+(?:[A-Za-z_]\w*\s*[\[\(]|[A-Za-z_]\w*\s*->)' # fn f(...) / fn f[T](...) / fn f() -> T
+ r'|\bstruct\s+[A-Za-z_]\w*'
+ r'|\benum\s+[A-Za-z_]\w*'
+ r'|\bimpl\s+[A-Za-z_\[]'
+ r'|\biface\s+[A-Za-z_]\w*'
+ r'|\binterface\s+[A-Za-z_]\w*'
+ r'|\bextern\s+fn\s'
+ r'|\bimport\s+[A-Za-z_@]'
+)
+# 语句/表达式**片段**(无声明头):`x := e;` / `x : T = e;` / `x : T, mut = e;`
+CORE_STMT_RE = re.compile(r'^[ \t]*[A-Za-z_]\w*\s*(?::[^=]*)?:=')
+CORE_STMT2_RE = re.compile(r'^[ \t]*[A-Za-z_]\w*\s*:[^=;]*=')
+
+
+def is_core(s):
+ """字符串 `s` 是否为内嵌 Core 源(形状判定;不做解析)。"""
+ if not s.strip():
+ return False
+ # **v3 的两个记号必居其一**:v3 Core 的块 `{` 或语句 `;`。这条同时是**散文过滤器**
+ # (`"[PASS] import module : alias ..."` 这类散文会被 `import\s+\w` 误抓 ⇒ 此处挡掉)。
+ if '{' not in s and ';' not in s:
+ return False
+ if not (CORE_DECL_RE.search(s) or CORE_STMT_RE.search(s) or CORE_STMT2_RE.search(s)):
+ return False
+ if s.lstrip().startswith('#'):
+ return False # Python 注释行(非字符串内容)
+ return True
+
+
+def already_v4(s):
+ """判「已经是我形、无可转换」的两条独立依据(取或):
+
+ ① **形状**:v3 的两个记号(块 `{` / 语句 `;`)都不在 ⇒ 没有可转换的东西。
+ 这条专门兜住「v4 形但**故意写坏**的负例」(未知标签等)与带 `#check` 契约的行
+ ——它们 `v4_parse_ok` 必然 False,却已是我形。
+ ② **解析**:`v4_parse_ok(s)`(兜住「v4 形 + 含结构体字面量 `{`」这类混合形,
+ 例如 `struct Point:` 与 `Point { x = 20 }` 同档)。
+ """
+ if '{' not in s and ';' not in s:
+ return True
+ return M.v4_parse_ok(s)[0]
+
+
+# 两侧词法器的**已知分歧**(非迁移引入,V2 对拍须归一化):同一个词素在 vendored v3
+# 扫描器里是 IDENT、在 v4 前端里是**关键字**(`Some`/`None`/`never`/`dyn`/…)。迁移**从不
+# 改词素** ⇒ 对**词素形如标识符**的 token 一律折叠成同一类,词素本身仍逐字比对。
+_IDLIKE = re.compile(r'^[A-Za-z_]\w*$')
+
+
+def _v2_norm(tok):
+ t, lx = tok
+ if lx == 'None': # E5:v4 关键字拼写(`None` ⇒ `none`)——**本批唯一的非形状改写**
+ lx = 'none'
+ return ('ID', lx) if _IDLIKE.match(lx) else (t, lx)
+
+
+def _v3_tokens(old):
+ """v3 侧可对拍 token 序列(`v4_migrate.v2_tokens_v3` 的**本工具版**)。
+
+ 差别只有一条:**臂体块的花括号也丢**。`v4_migrate` 只丢 `brace_kind == 'block'` 的,
+ 而 `classify` 把 `=> {` 标成 `arm`(T6a 追加)⇒ 臂体花括号留在 v3 侧、v4 侧却是
+ `=>:` + region ⇒ 每处臂体一个假 V2 差异(实测)。本工具已把臂体改写成文档形
+ (`=>:` + region)⇒ v3 侧那对花括号同样是**结构替身**,必须一并丢。
+ """
+ toks = M.V3.Lexer(old).tokenize()
+ bk, sk, _bm, _n = M.classify(toks)
+ seq = []
+ for i, tk in enumerate(toks):
+ if tk.type == M.T.EOF:
+ continue
+ if tk.type == M.T.SEMI and sk.get(i) == 'stmt':
+ continue
+ if tk.type in (M.T.LBRACE, M.T.RBRACE) and bk.get(i) in ('block', 'arm'):
+ continue
+ seq.append((tk.type.name, tk.lexeme))
+ return seq
+
+
+def v2_check(old, new):
+ """V2:与改前**逐 token 相同**。返回 diffs(归一化后)。"""
+ import difflib
+ a = _v3_tokens(old)
+ b = M.v2_tokens_v4(new)
+ diffs = []
+ for tag, i1, i2, j1, j2 in difflib.SequenceMatcher(a=a, b=b, autojunk=False).get_opcodes():
+ if tag != 'equal':
+ diffs.append((tag, a[i1:i2], b[j1:j2]))
+ norm = []
+ for tag, x, y in diffs:
+ x = [_v2_norm(t) for t in x]
+ y = [_v2_norm(t) for t in y]
+ if x != y:
+ norm.append((tag, x, y))
+ return norm
+
+
+def _encode_literal(text, quote):
+ """把 `text` 重新编成用 `quote` 定界的字面量**体**(保留宿主的转义风格)。"""
+ out = []
+ for ch in text:
+ if ch == '\\':
+ out.append('\\\\')
+ elif ch == '\n':
+ out.append('\n' if len(quote) == 3 else '\\n')
+ elif ch == '\r':
+ out.append('\\r')
+ elif ch == '\t':
+ out.append('\\t')
+ elif ch in ('"', "'") and quote[0] == ch and len(quote) == 1:
+ out.append('\\' + ch)
+ else:
+ out.append(ch)
+ return ''.join(out)
+
+
+# ── 片段的重缩进 ──────────────────────────────────────────────────────────────
+# `transform_text` 按 **region 嵌套深度**重算缩进,深度 0 ⇒ 输出一律顶格。这对
+# 「整档」是对的,对**片段**(例如插入到函数体里的 ` xv := x0 + 7;`)会**丢掉缩进**。
+# ⇒ 取原文非空行的**最小缩进**当基准,改写后逐行补回。
+def struct_colon_to_eq(src):
+ """**v4 判定 ④**(`v4-layout-spec.md` §4):struct 字面量的字段分隔符必须是 `=`,
+ `:` 形在整个语言里不存在(parser 在分隔符位点响亮拒绝 `P030`)。v3 两形都收
+ (`v4_migrate._is_struct_lit`:花括号后首 token 是 IDENT 且再下一个是 `=` **或** `:`)
+ ⇒ 这是 T4 的形状改写**没覆盖**的一类(T4 逐字保留字面量内部),本工具补上。
+
+ 只动**结构体类的花括号**内、**相对深度 0** 的 `:` token,逐字节安全。
+ """
+ toks = [t for t in M.V3.Lexer(src).tokenize()]
+ if toks and toks[-1].type == T.EOF:
+ toks[-1].start = len(src)
+ toks[-1].end = len(src)
+ # ⚠ **不能直接用 `v4_migrate.classify`**:它的 `decl_brace_pending` 假定「`struct`/`enum`/
+ # `impl`/`interface` 之后的首个 `{` = 声明体」(v3 事实)。v4 的声明体是 `:` + region、
+ # **没有** `{` ⇒ 该标志会一直挂到**后面第一个结构体字面量**上,把它误判成 block
+ # (实测:`struct P:` … `P{b: 11}` 的 `{` 被判 block ⇒ 分隔符一处也不改)。
+ # ⇒ 本处自带一份:遇到 `:`(v4 声明体的 region 头)即**清掉** pending。
+ brace_kind, brace_match = {}, {}
+ stack = []
+ pending = False
+ for i, tk in enumerate(toks):
+ t = tk.type
+ if t in (T.STRUCT, T.ENUM, T.IMPL, T.INTERFACE):
+ pending = True
+ elif t == T.COLON:
+ pending = False
+ elif t == T.LBRACE:
+ prev = toks[i - 1] if i > 0 else None
+ is_arm = prev is not None and prev.type == T.FAT_ARROW
+ is_struct = (not is_arm and not pending and prev is not None
+ and prev.type == T.IDENT and prev.lexeme[:1].isupper()
+ and M._is_struct_lit(toks, i))
+ pending = False
+ brace_kind[i] = 'struct' if is_struct else ('arm' if is_arm else 'block')
+ stack.append(('{', i))
+ elif t == T.RBRACE:
+ if stack and stack[-1][0] == '{':
+ _k, oi = stack.pop()
+ brace_match[oi] = i
+ brace_kind[i] = brace_kind.get(oi, 'block')
+ elif t == T.LPAREN:
+ stack.append(('(', i))
+ elif t == T.LBRACK:
+ stack.append(('[', i))
+ elif t == T.RPAREN:
+ if stack and stack[-1][0] == '(':
+ stack.pop()
+ elif t == T.RBRACK:
+ if stack and stack[-1][0] == '[':
+ stack.pop()
+ edits = []
+ for i, tk in enumerate(toks):
+ if tk.type != T.LBRACE or brace_kind.get(i) != 'struct':
+ continue
+ m = brace_match.get(i)
+ if m is None:
+ continue
+ depth = 0
+ for j in range(i + 1, m):
+ t = toks[j].type
+ if t in (T.LBRACE, T.LBRACK, T.LPAREN):
+ depth += 1
+ elif t in (T.RBRACE, T.RBRACK, T.RPAREN):
+ depth -= 1
+ elif t == T.COLON and depth == 0 and j > i + 1 \
+ and toks[j - 1].type == T.IDENT:
+ edits.append((toks[j].start, toks[j].end))
+ for a, b in sorted(edits, reverse=True):
+ src = src[:a] + '=' + src[b:]
+ return src, len(edits)
+
+
+def none_rename(src):
+ """v4 关键字拼写:`None` ⇒ `none`(`docs/core-language-syntax_v4.md:38` 关键字表含
+ `none`、无 `None`;实测 `x : int? = None` ⇒ `error[N01] Undefined name 'None'`)。
+
+ 主路径由 `v4_migrate._t6_extra_ops` 的 E5 负责;此处的副本只服务**短路路径**
+ (「已是 v4 形、只差 struct 字面量分隔符」的段——那条路不走 `transform_text`)。
+ """
+ toks = [t for t in M.V3.Lexer(src).tokenize()]
+ edits = [(t.start, t.end) for t in toks
+ if src[t.start:t.end] == 'None'
+ and (t.type == T.NONE or t.type == T.IDENT)]
+ for a, b in sorted(edits, reverse=True):
+ src = src[:a] + 'none' + src[b:]
+ return src, len(edits)
+
+
+# 空 region 的**目标形**(维护者 2026-10-11 裁定「规格化」:region 可为空 ⇒ `:` 后不跟 items)。
+# 实现法:先给每个空块塞一个**哨兵语句**让 `v4_migrate` 的改写走通(它对空 region fail-closed
+# 中止),产物里哨兵会单独占一行 ⇒ 逐行删掉 ⇒ 得 `:` 后无 items 的目标形。
+# 这**不是绕过**:产物就是裁定要求的形;哨兵只活在改写过程里,不落盘。
+_EMPTY_SENTINEL = '__V4_EMPTY_REGION__'
+
+
+def _fill_empty_regions(src):
+ """把 `{ }` / `{\\n}` 这类**空块**填成 `{ __V4_EMPTY_REGION__; }`;返回 `(新文本, 处数)`。"""
+ toks = [t for t in M.V3.Lexer(src).tokenize()]
+ if toks and toks[-1].type == T.EOF:
+ toks[-1].start = len(src)
+ toks[-1].end = len(src)
+ try:
+ bk, _sk, bm, _n = M.classify(toks)
+ except M.MigrateError:
+ return src, 0
+ spots = [i for i, t in enumerate(toks)
+ if t.type == T.LBRACE and bk.get(i) == 'block' and bm.get(i) == i + 1]
+ for i in sorted(spots, reverse=True):
+ # `{` 的 end 与 `}` 的 start 之间就是空块体(可能含空白/注释)
+ pos = toks[i].end
+ src = src[:pos] + ' %s;' % _EMPTY_SENTINEL + src[pos:]
+ return src, len(spots)
+
+
+def _strip_sentinels(text):
+ keep = [ln for ln in text.split('\n') if ln.strip() != _EMPTY_SENTINEL]
+ return '\n'.join(keep)
+
+
+# ── 臂体块 → **文档形**(`Pat => { BODY }` ⇒ `Pat =>` + region)──────────────────
+# 维护者 2026-10-11 裁定(协调者转述):v4 的臂体 region 形 = `=>` 后接 region(T5 第 4(b)
+# 项,`P02` 缺口即此);**`=> return E` 不是文档形,不得用「消 `return`」绕**。
+#
+# 实现:`v4_migrate.classify` 把 `=> {` 标成 `arm`(整对花括号抹掉 ⇒ 单行 `=> stmt`),
+# 那不是文档形。⇒ 在调用它之前,把一个**良性占位 token** 插进 `=>` 与 `{` 之间,
+# 让 `{` 的前驱不再是 `=>` ⇒ 回落成 **block** 分支 ⇒ 得 `=>` + `:` + region。
+# 产物里再把占位去掉 ⇒ **`Pat =>:` + region**。
+# ⚠ 只在 `=>` **紧跟** `{` 时插入:那种 `{` 恒是臂体块(结构体字面量须写成 `Foo {`)。
+_ARM_BLOCK_RE = re.compile(r'=>([ \t]*)\{')
+_ARM_PLACEHOLDER = '(0)'
+
+
+def arm_block_to_region_src(src):
+ return _ARM_BLOCK_RE.sub(lambda m: '=> %s {%s' % (_ARM_PLACEHOLDER, m.group(1)), src)
+
+
+def arm_region_post(out):
+ return out.replace('=> %s:' % _ARM_PLACEHOLDER, '=>:')
+
+
+def _restore_leading_blank(s, out):
+ """把**首行空行**补回来(`transform_text` 的行模型必然丢一条:首行的换行被读作
+ 「转到下一行」而不是「产出一个空行」)。⇒ 原文以 `\\n` 起头而产物不以 ⇒ 补一个。"""
+ if s.startswith('\n') and not out.startswith('\n'):
+ return '\n' + out
+ return out
+
+
+def _min_indent(s):
+ best = None
+ for ln in s.split('\n'):
+ if not ln.strip():
+ continue
+ n = len(ln) - len(ln.lstrip(' \t'))
+ best = n if best is None else min(best, n)
+ return best or 0
+
+
+def _reindent(text, prefix):
+ if prefix == '':
+ return text
+ out = []
+ for ln in text.split('\n'):
+ out.append(prefix + ln if ln.strip() else ln)
+ return '\n'.join(out)
+
+
+# ── 单段改写 ──────────────────────────────────────────────────────────────────
+def migrate_segment(s, label):
+ """Core 段 `s` → v4。返回 `(new, rec)`;`new is None` ⇒ 未改写(`rec['skip']` 有理由)。"""
+ rec = {'label': label, 'skip': None, 'changed': False}
+ if already_v4(s):
+ rec['skip'] = 'already-v4'
+ return None, rec
+ # 先做**与形状无关**的那一步(struct 字面量分隔符 `:` → `=`);若这一步之后就已是
+ # 合法 v4 ⇒ 本段只需该步(语料里大量「已迁移的 v4 + 遗留 `P{a: 1}`」正是此类)。
+ try:
+ s2, ncolon = struct_colon_to_eq(s)
+ except Exception as e:
+ rec['skip'] = 'colonfix-error: %s' % e
+ return None, rec
+ rec['colon_fixed'] = ncolon
+ if ncolon:
+ s3, nnone = none_rename(s2)
+ rec['none_renamed'] = nnone
+ if M.v4_parse_ok(s3)[0]:
+ rec['changed'] = s3 != s
+ rec['v4_parses'] = True
+ return s3, rec
+ # ⚠ 必须用 `table` 策略:`skip` 会**整段跳过 `pre_transform`**,而 T6a 在 `pre_transform`
+ # 的 `_t6_extra_ops` 里实现的三件改写(E1 struct 字面量 `:`→`=` · E5 `None`→`none` ·
+ # E6 `return match` 臂体块去内层 `return`)**都挂在那里**(实测教训:用 `skip` 跑出来的
+ # 臂体是 `Pat =>: ` + region —— 两个前端**都不吃**,见 parser.cr `parse_match_expr`:
+ # 臂体恒为 `parse_expr()`)。
+ # 空 region:`EMPTY_ACTIONS` 的键是 `(文件路径, 行号)`,内嵌段的行号与宿主文件不同 ⇒
+ # 永不命中表 ⇒ 一律进 `unresolved` ⇒ 本工具按「停下上报」处置(正是 T4 口径要的)。
+ # 臂体块 ⇒ 文档形(`Pat =>:` + region)。先做,再进 `transform_text`:
+ # 否则 `v4_migrate.classify` 把它当 `arm` ⇒ 单行 `=> return E`(非文档形)。
+ arm_in = arm_block_to_region_src(s2)
+ arm_hit = arm_in != s2
+ filled = None
+ try:
+ out, rep = M.transform_text(arm_in if arm_hit else s2, label, 'table')
+ except Exception as e:
+ rec['skip'] = 'transform-error: %s' % e
+ return None, rec
+ if out is None and 'empty region' in str(rep.get('aborted', '')):
+ # 空 region ⇒ 走**目标形**路径(`:` 后不跟 items;维护者 2026-10-11 规格化裁定)
+ filled, nspots = _fill_empty_regions(s2)
+ if not nspots:
+ rec['skip'] = 'empty-region: %s' % rep.get('aborted', '')
+ return None, rec
+ try:
+ out, rep = M.transform_text(filled, label, 'skip')
+ except Exception as e:
+ rec['skip'] = 'empty-region+transform-error: %s' % e
+ return None, rec
+ if out is None:
+ rec['skip'] = 'empty-region: %s' % rep.get('aborted', '')
+ return None, rec
+ out = _strip_sentinels(out)
+ rec['empty_regions_kept'] = nspots
+ elif out is None:
+ rec['skip'] = 'empty-region: %s' % rep.get('aborted', '')
+ return None, rec
+ if arm_hit:
+ out = arm_region_post(out)
+ prefix = ' ' * _min_indent(s2)
+ out = _reindent(out, prefix)
+ out = _restore_leading_blank(s2, out)
+ # 机械轨:V2 + V4a + V4b
+ try:
+ diffs = v2_check(s2, out)
+ except Exception as e:
+ rec['skip'] = 'v2-error: %s' % e
+ return None, rec
+ if diffs:
+ rec['skip'] = 'V2DIFF(%d)' % len(diffs)
+ rec['v2diffs'] = diffs
+ return None, rec
+ ob, nb = M.comment_counts(s2), M.comment_counts(out)
+ if nb['comment_lines'] + nb['block_comments'] < ob['comment_lines'] + ob['block_comments']:
+ rec['skip'] = 'V4a-drop'
+ return None, rec
+ if M.file_metrics(out)['blank_lines'] < M.file_metrics(s2)['blank_lines']:
+ rec['skip'] = 'V4b-drop'
+ return None, rec
+ rec['changed'] = out != s
+ rec['v4_parses'] = M.v4_parse_ok(out)[0]
+ rec['v3_parsed'] = M.v4_parse_ok(s)[0]
+ return out, rec
+
+
+# ── `.py` 宿主 ────────────────────────────────────────────────────────────────
+def _offsets(src):
+ lines = src.splitlines(keepends=True)
+ starts = []
+ p = 0
+ for l in lines:
+ starts.append(p)
+ p += len(l)
+ starts.append(p)
+
+ def off(lineno, col):
+ return starts[lineno - 1] + col
+ return off
+
+
+_LIT_RE = re.compile(r'^(?P[A-Za-z]*)'
+ r'(?P"""|\'\'\'|"|\')')
+
+
+def py_segments(path):
+ """列出 `.py` 里**判定为 Core** 的字符串字面量:`(offset_start, offset_end, content, label)`。"""
+ src = open(path, encoding='utf-8').read()
+ off = _offsets(src)
+ tree = ast.parse(src)
+ # **文档字符串不是 Core 源**(哪怕它引用了 `fn f(...)` 形态)——整棵文档串节点排除。
+ docstrings = set()
+ for n in ast.walk(tree):
+ if isinstance(n, (ast.Module, ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
+ if n.body and isinstance(n.body[0], ast.Expr) \
+ and isinstance(n.body[0].value, ast.Constant) \
+ and isinstance(n.body[0].value.value, str):
+ docstrings.add(id(n.body[0].value))
+ out = []
+ for n in ast.walk(tree):
+ if not (isinstance(n, ast.Constant) and isinstance(n.value, str)):
+ continue
+ if id(n) in docstrings:
+ continue
+ if not is_core(n.value):
+ continue
+ a, b = off(n.lineno, n.col_offset), off(n.end_lineno, n.end_col_offset)
+ raw = src[a:b]
+ m = _LIT_RE.match(raw)
+ if not m:
+ out.append((a, b, n.value, 'line %d' % n.lineno, '', '', 'unsupported'))
+ continue
+ q = m.group('q')
+ inner = raw[len(m.group('pre')) + len(q):-len(q)]
+ style = 'esc' if inner != n.value else 'plain'
+ out.append((a, b, n.value, 'line %d' % n.lineno, m.group('pre'), q, style))
+ return out
+
+
+def migrate_py(path, apply=False):
+ src = open(path, encoding='utf-8').read()
+ segs = py_segments(path)
+ edits = []
+ recs = []
+ for a, b, content, label, pre, q, style in segs:
+ if style == 'unsupported':
+ recs.append({'label': label, 'skip': 'unparsed-literal-form'})
+ continue
+ new, rec = migrate_segment(content, label)
+ recs.append(rec)
+ if new is None or not rec['changed']:
+ continue
+ # 单引号形(`"…"` / `'…'`)**必须保持单行** ⇒ 产物里的真换行要编成 `\n`。
+ # 三引号形只有当原文本身用了转义时才重编(否则逐字保留,避免无谓 diff)。
+ if style == 'plain' and len(q) == 3:
+ body = new
+ else:
+ body = _encode_literal(new, q)
+ edits.append((a, b, pre + q + body + q))
+ if apply and edits:
+ for a, b, rep in sorted(edits, key=lambda e: -e[0]):
+ src = src[:a] + rep + src[b:]
+ open(path, 'w', encoding='utf-8').write(src)
+ return recs, len(edits)
+
+
+# ── `.md` 宿主 ────────────────────────────────────────────────────────────────
+_FENCE_RE = re.compile(r'^(?P[ \t]*)(?P```+|~~~+)(?P[^\n]*)$')
+
+
+def md_segments(path):
+ """列出 `.md` 里**判定为 Core** 的围栏块:`(start, end, content, label)`。
+
+ `start/end` = 块体在文件里的**字符偏移**(不含围栏行本身)。
+ """
+ text = open(path, encoding='utf-8').read()
+ lines = text.split('\n')
+ starts, pos = [], 0
+ for l in lines:
+ starts.append(pos)
+ pos += len(l) + 1
+ segs = []
+ i = 0
+ while i < len(lines):
+ m = _FENCE_RE.match(lines[i])
+ if not m:
+ i += 1
+ continue
+ fence = m.group('f')
+ info = m.group('info').strip()
+ j = i + 1
+ while j < len(lines):
+ m2 = _FENCE_RE.match(lines[j])
+ if m2 and m2.group('f')[0] == fence[0] and len(m2.group('f')) >= len(fence) \
+ and m2.group('info').strip() == '':
+ break
+ j += 1
+ body_start = starts[i] + len(lines[i]) + 1 if i + 1 < len(lines) else len(text)
+ body_end = starts[j] if j < len(lines) else len(text)
+ content = text[body_start:body_end]
+ label = 'lines %d-%d (info=%r)' % (i + 2, j, info)
+ # `core` 标记者恒收;**无标记**的围栏仅当块体带 Core 声明形(`fn`/`struct`/…)
+ # 且确有 v3 记号(`is_core` 已含此闸)时收——否则散文块会被误判。
+ if (info.startswith('core') or (not info and CORE_DECL_RE.search(content))) \
+ and is_core(content):
+ segs.append((body_start, body_end, content, label))
+ i = j + 1
+ return segs
+
+
+def _iter_string_spans(path):
+ """`(start, end, value, kind)`:文件里**全部**字符串常量与 f-string 字面块的源跨度。"""
+ src = open(path, encoding='utf-8').read()
+ off = _offsets(src)
+ tree = ast.parse(src)
+ out = []
+ for n in ast.walk(tree):
+ if isinstance(n, ast.JoinedStr):
+ for v in n.values:
+ if isinstance(v, ast.Constant) and isinstance(v.value, str):
+ out.append((off(v.lineno, v.col_offset),
+ off(v.end_lineno, v.end_col_offset), v.value, 'fstr'))
+ elif isinstance(n, ast.Constant) and isinstance(n.value, str):
+ out.append((off(n.lineno, n.col_offset),
+ off(n.end_lineno, n.end_col_offset), n.value, 'str'))
+ return src, out
+
+
+def none_rename_py(path, apply=False):
+ """把**所有 Core 形字符串**里的 `None` 改成 `none`(v4 关键字拼写)。
+
+ 单独成一步的理由:`is_core` 要求 v3 的两个记号(`{` / `;`)之一,而**已是 v4 形**的
+ 片段(`fn g() -> int?:` + `return None`)一个都没有 ⇒ 那些片段会漏过主流程的 E5。
+ """
+ src, spans = _iter_string_spans(path)
+ edits = []
+ for a, b, v, kind in spans:
+ if 'None' not in v:
+ continue
+ if not (CORE_DECL_RE.search(v) or is_core(v)):
+ continue
+ if v.lstrip().startswith('#'):
+ continue
+ raw = src[a:b]
+ # 只动**字面量体**:跳过前缀与引号
+ m = _LIT_RE.match(raw) if kind == 'str' else None
+ if m:
+ head = len(m.group('pre')) + len(m.group('q'))
+ body = raw[head:-len(m.group('q'))]
+ else:
+ body = raw
+ new_body = re.sub(r'\bNone\b', 'none', body)
+ if new_body == body:
+ continue
+ edits.append((a, b, raw.replace(body, new_body, 1)))
+ if apply and edits:
+ for a, b, rep in sorted(edits, key=lambda e: -e[0]):
+ src = src[:a] + rep + src[b:]
+ open(path, 'w', encoding='utf-8').write(src)
+ return len(edits)
+
+
+def cr_segments(path):
+ """列出 `.cr` 里**判定为 Core** 的字符串字面量:`(start, end, value, label, line)`。
+
+ 宿主是 Core 源(不是 Python)⇒ 用 vendored v3 扫描器切 `STRING_LIT`。
+ **额外闸**(吸取实测假阳):正文形态的字面量必须含换行或行尾 `;` ——
+ 否则形如 `'{' is only valid as a struct literal delimiter …'` 的诊断文案会被
+ `\\bstruct\\s+\\w`("struct literal")误抓。
+ """
+ src = open(path, encoding='utf-8').read()
+ toks = [t for t in M.V3.Lexer(src, path).tokenize()]
+ out = []
+ for t in toks:
+ if t.type.name != 'STRING_LIT':
+ continue
+ v = t.lexeme
+ if '\n' not in v and not v.rstrip().endswith(';'):
+ continue
+ if not is_core(v):
+ continue
+ out.append((t.start, t.end, v, 'line %d' % t.line, t.line))
+ return src, out
+
+
+def migrate_cr(path, apply=False):
+ src, segs = cr_segments(path)
+ edits, recs = [], []
+ for a, b, content, label, _ln in segs:
+ if already_v4(content):
+ recs.append({'label': label, 'skip': 'already-v4'})
+ continue
+ new, rec = migrate_segment(content, label)
+ recs.append(rec)
+ if new is None or not rec['changed']:
+ continue
+ raw = src[a:b]
+ q = raw[0] if raw[:1] in ('"', "'") else '"'
+ edits.append((a, b, q + _encode_literal(new, q * 1) + q))
+ if apply and edits:
+ for a, b, rep in sorted(edits, key=lambda e: -e[0]):
+ src = src[:a] + rep + src[b:]
+ open(path, 'w', encoding='utf-8').write(src)
+ return recs, len(edits)
+
+
+def migrate_md(path, apply=False):
+ text = open(path, encoding='utf-8').read()
+ segs = md_segments(path)
+ edits, recs = [], []
+ for a, b, content, label in segs:
+ new, rec = migrate_segment(content, label)
+ recs.append(rec)
+ if new is None or not rec['changed']:
+ continue
+ edits.append((a, b, new))
+ if apply and edits:
+ for a, b, rep in sorted(edits, key=lambda e: -e[0]):
+ text = text[:a] + rep + text[b:]
+ open(path, 'w', encoding='utf-8').write(text)
+ return recs, len(edits)
+
+
+# ── CLI ───────────────────────────────────────────────────────────────────────
+def do_file(path, apply):
+ if path.endswith('.py'):
+ return migrate_py(path, apply)
+ if path.endswith('.md'):
+ return migrate_md(path, apply)
+ if path.endswith('.cr'):
+ return migrate_cr(path, apply)
+ raise SystemExit('unsupported host: %s' % path)
+
+
+def main():
+ ap = argparse.ArgumentParser()
+ sub = ap.add_subparsers(dest='cmd', required=True)
+ r = sub.add_parser('report')
+ r.add_argument('files', nargs='+')
+ a = sub.add_parser('apply')
+ a.add_argument('files', nargs='+')
+ n = sub.add_parser('none-rename')
+ n.add_argument('files', nargs='+')
+ args = ap.parse_args()
+ if args.cmd == 'none-rename':
+ tot = 0
+ for p in args.files:
+ k = none_rename_py(p, apply=True)
+ if k:
+ print('%-60s None->none = %d' % (p, k))
+ tot += k
+ print('TOTAL None->none: %d (in %d files)' % (tot, len(args.files)))
+ return 0
+ apply = args.cmd == 'apply'
+ nch = nskip = 0
+ for p in args.files:
+ recs, n = do_file(p, apply)
+ nch += n
+ print('=== %s' % p)
+ for rec in recs:
+ if rec.get('skip'):
+ nskip += 1
+ print(' [skip] %-28s %s' % (rec['label'], rec['skip']))
+ else:
+ print(' [%s] %-28s v4parse=%s wasv4parse=%s' %
+ ('EDIT' if rec['changed'] else 'same', rec['label'],
+ rec.get('v4_parses'), rec.get('v3_parsed')))
+ print(' -> %d segment(s) %s' % (n, 'rewritten' if apply else 'rewritable'))
+ print('TOTAL: %d rewritten, %d skipped' % (nch, nskip))
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/tools/v4_migrate_v3lex.py b/tools/v4_migrate_v3lex.py
new file mode 100644
index 00000000..89d60eed
--- /dev/null
+++ b/tools/v4_migrate_v3lex.py
@@ -0,0 +1,477 @@
+"""vendored v3 前端扫描器(一次性迁移工具的内部件;非判据)。
+
+出处:develop 版 v3 frontend(`bootstrap/corec/frontend/lexer.py` + `syntax/tokens.py`
+的等价副本,2026-09-24 v4 迁移 T4 时点)。**本档不含 v4 布局**(无 INDENT/DEDENT/NEWLINE),
+它只做 v3 词法,供 `tools/v4_migrate.py` 取 token 位置与做 V2 对拍。
+
+与本仓 `bootstrap/corec/frontend/lexer.py`(v4)的分工:
+ - 本档 = v3 面(`{`/`}`/`;` 仍是 token;`:` 是单一 COLON);
+ - v4 面由 `bootstrap/corec/frontend/lexer.py` 提供。
+两档**必须保持各自语义**,不得互改。
+
+对 vendored 源做的唯一改动:每个 token 增记 `start`/`end`(字符偏移)——
+`tokenize()` 每轮在 skip_whitespace 之后记 `self._iter_start = self.pos`,
+`_emit()` 落 `start=_iter_start, end=self.pos`。**其余逐字保持 vendored 原样。**
+(v3 原档的 `line`/`col` 对 ident 与单字符 token 的基准不同一 —— 见 T4 报告 ——
+ 故偏移只取自 `start`/`end`,不从 line/col 反推。)
+"""
+
+from enum import Enum, auto
+from dataclasses import dataclass
+
+class TokenType(Enum):
+ # 字面量
+ INT_LIT = auto()
+ FLOAT_LIT = auto()
+ STRING_LIT = auto()
+ CHAR_LIT = auto()
+ BOOL_LIT = auto()
+ UNIT_LIT = auto()
+
+ # 标识符
+ IDENT = auto()
+
+ # 关键字
+ FN = auto()
+ STRUCT = auto()
+ ENUM = auto()
+ INTERFACE = auto()
+ IMPL = auto()
+ TYPE = auto()
+ MUT = auto()
+ MOVE = auto()
+ GO = auto()
+ AWAIT = auto()
+ FLOW = auto()
+ YIELD = auto()
+ IF = auto()
+ ELSE = auto()
+ MATCH = auto()
+ FOR = auto()
+ IN = auto()
+ LOOP = auto()
+ WHILE = auto()
+ RETURN = auto()
+ BREAK = auto()
+ CONTINUE = auto()
+ PUB = auto()
+ MOD = auto()
+ IMPORT = auto()
+ FILEID = auto()
+ AS = auto()
+ AUTO = auto()
+ UNSAFE = auto()
+ REQUIRES = auto()
+ ENSURES = auto()
+ RESULT = auto()
+ SELF = auto()
+ SELF_TYPE = auto()
+ TRUE = auto()
+ FALSE = auto()
+ UNIT = auto()
+ NONE = auto()
+ SOME = auto()
+ EXTERN = auto()
+
+ # 符号
+ FAT_ARROW = auto()
+ PLUS = auto()
+ MINUS = auto()
+ STAR = auto()
+ SLASH = auto()
+ PERCENT = auto()
+ EQ_EQ = auto()
+ NOT_EQ = auto()
+ LT = auto()
+ GT = auto()
+ LT_EQ = auto()
+ GT_EQ = auto()
+ AND_AND = auto()
+ PIPE = auto()
+ PIPE_PIPE = auto()
+ BANG = auto()
+ EQ = auto()
+ ARROW = auto()
+ PATH_SEP = auto()
+ DOT = auto()
+ DOT_DOT = auto()
+ DOT_DOT_DOT = auto()
+ COMMA = auto()
+ SEMI = auto()
+ COLON = auto()
+ COLON_EQ = auto()
+ LPAREN = auto()
+ RPAREN = auto()
+ LBRACK = auto()
+ RBRACK = auto()
+ LBRACE = auto()
+ RBRACE = auto()
+ AMPERSAND = auto()
+ AT = auto()
+ QUESTION = auto()
+ UNDERSCORE = auto()
+ # 批 6(裁-S7,bounded):规约标注 sigil `#`(`#check(...)` / `#ensure(...)`)。
+ # bootstrap 侧只做「**接受并跳过**」(零语义):能词法化、不报错、**不影响产物**;
+ # **不**实现 VC/三态(完整 bootstrap 规约面登记后续)。对应 self-hosted 的 `T_HASH = 101`。
+ HASH = auto()
+
+ EOF = auto()
+
+KEYWORDS = {
+ "fn": TokenType.FN,
+ "struct": TokenType.STRUCT,
+ "enum": TokenType.ENUM,
+ "interface": TokenType.INTERFACE,
+ "impl": TokenType.IMPL,
+ "type": TokenType.TYPE,
+ "mut": TokenType.MUT,
+ "move": TokenType.MOVE,
+ "go": TokenType.GO,
+ "await": TokenType.AWAIT,
+ "flow": TokenType.FLOW,
+ "yield": TokenType.YIELD,
+ "if": TokenType.IF,
+ "else": TokenType.ELSE,
+ "match": TokenType.MATCH,
+ "for": TokenType.FOR,
+ "in": TokenType.IN,
+ "loop": TokenType.LOOP,
+ "while": TokenType.WHILE,
+ "return": TokenType.RETURN,
+ "break": TokenType.BREAK,
+ "continue": TokenType.CONTINUE,
+ "pub": TokenType.PUB,
+ "mod": TokenType.MOD,
+ "import": TokenType.IMPORT,
+ "fileid": TokenType.FILEID,
+ "as": TokenType.AS,
+ "unsafe": TokenType.UNSAFE,
+ "requires": TokenType.REQUIRES,
+ "ensures": TokenType.ENSURES,
+ "result": TokenType.RESULT,
+ "self": TokenType.SELF,
+ "Self": TokenType.SELF_TYPE,
+ "auto": TokenType.AUTO,
+ "true": TokenType.TRUE,
+ "false": TokenType.FALSE,
+ "extern": TokenType.EXTERN,
+ "unit": TokenType.UNIT,
+ "None": TokenType.NONE,
+ "Some": TokenType.SOME,
+}
+
+@dataclass
+class Token:
+ type: TokenType
+ lexeme: str
+ line: int
+ col: int
+ start: int = -1
+ end: int = -1
+
+ def __repr__(self):
+ return f"Token({self.type}, '{self.lexeme}', {self.line}:{self.col})"
+
+
+
+class Lexer:
+ def __init__(self, source: str, filename: str = ""):
+ self.source = source
+ self.filename = filename
+ self.pos = 0
+ self.line = 1
+ self.col = 1
+ self.tokens = []
+
+ def current(self) -> str:
+ if self.pos < len(self.source):
+ return self.source[self.pos]
+ return '\0'
+
+ def advance(self):
+ ch = self.current()
+ self.pos += 1
+ if ch == '\n':
+ self.line += 1
+ self.col = 1
+ else:
+ self.col += 1
+ return ch
+
+ def peek(self, offset: int = 1) -> str:
+ idx = self.pos + offset
+ if idx < len(self.source):
+ return self.source[idx]
+ return '\0'
+
+ def skip_whitespace_and_comments(self):
+ while self.pos < len(self.source):
+ ch = self.current()
+ if ch in ' \t\n\r':
+ self.advance()
+ elif ch == '/' and self.peek() == '/':
+ while self.current() != '\n' and self.current() != '\0':
+ self.advance()
+ elif ch == '/' and self.peek() == '*':
+ self.advance(); self.advance()
+ while not (self.current() == '*' and self.peek() == '/') and self.current() != '\0':
+ self.advance()
+ self.advance(); self.advance()
+ else:
+ break
+
+ def read_string(self, quote: str) -> Token:
+ start_line, start_col = self.line, self.col
+ self.advance()
+ s = ""
+ while self.current() != quote and self.current() != '\0':
+ if self.current() == '\\':
+ self.advance()
+ esc = self.advance()
+ if esc == 'n': s += '\n'
+ elif esc == 't': s += '\t'
+ elif esc == 'r': s += '\r'
+ elif esc == '0': s += '\0'
+ elif esc == '\\': s += '\\'
+ elif esc == '"': s += '"'
+ elif esc == '\'': s += '\''
+ elif esc == 'x':
+ h = self.advance() + self.advance()
+ s += chr(int(h, 16))
+ else:
+ s += esc
+ else:
+ s += self.advance()
+ if self.current() == '\0':
+ self.error("Unterminated string literal")
+ self.advance()
+ tok_type = TokenType.STRING_LIT if quote == '"' else TokenType.CHAR_LIT
+ return Token(tok_type, s, start_line, start_col)
+
+ def read_number(self, first: str) -> Token:
+ start_line, start_col = self.line, self.col
+ n = first
+ base = 10
+ is_prefixed = False
+ if first == '0' and self.current() in 'xXoObB':
+ prefix = self.advance()
+ n += prefix
+ base = {'x': 16, 'X': 16, 'o': 8, 'O': 8,
+ 'b': 2, 'B': 2}[prefix]
+ is_prefixed = True
+ is_float = False
+ if is_prefixed:
+ digits = '0123456789abcdefABCDEF' if base == 16 else (
+ '01234567' if base == 8 else '01')
+ while self.current() in digits:
+ c = self.current()
+ if c in digits:
+ n += self.advance()
+ else:
+ break
+ # 数字词法收窄(2026-09-10 语言面收窄 §2):'_' 分隔符不支持——响亮报错,
+ # 不再消费(与 self-hosted lexer 同款;修复前被静默并入词素)。
+ if self.current() == '_':
+ self.error("invalid character '_' in numeric literal (digit separators not supported)")
+ if n[-1] in 'xXoObB' or not any(c != '_' for c in n[2:]):
+ self.error("invalid integer literal")
+ if self.current().isalnum() or self.current() == '_':
+ self.error("invalid digit in integer literal")
+ else:
+ while self.current().isdigit():
+ n += self.advance()
+ if self.current() == '_':
+ self.error("invalid character '_' in numeric literal (digit separators not supported)")
+ if self.current() == '.' and self.peek().isdigit():
+ is_float = True
+ n += self.advance()
+ while self.current().isdigit():
+ n += self.advance()
+ if self.current() == '_':
+ self.error("invalid character '_' in numeric literal (digit separators not supported)")
+ if self.current().isalpha():
+ # 宽度后缀退役(2026-09-10 语言面收窄 §2)——与 self-hosted lexer 同款
+ # 响亮报错;此前后缀被并入词素('10f32')→ parser int() 抛 ValueError。
+ self.error("invalid suffix on numeric literal (width suffixes retired 2026-09-10)")
+ n = n.replace('_', '')
+ # 前缀进制(0x/0o/0b)整数字面量超形状拒绝——与 self-hosted lexer 的
+ # base 校准守卫一致(P2)。层语义(int-unbounded-semantics 定稿):
+ # 语言 int = 无上限数学整数,本守卫是编码层限制错误(本编译器内部
+ # 表示 = 经典 64 位机器字投影;超形状 = 该投影无载体),非语义溢出。
+ # 十进制保持原样词法(Python int 任意精度 = 同语义的另一份投影实例):
+ # self-hosted 对十进制幅值边界有既有处理(-9223372036854775808),
+ # 不一致处理——两编译器差异 = 各自投影形状差异,非语义分歧。
+ if is_prefixed:
+ val = int(n[2:], base)
+ if val > 9223372036854775807:
+ self.error("integer literal overflow")
+ return Token(TokenType.INT_LIT, str(val), start_line, start_col)
+ if is_float:
+ return Token(TokenType.FLOAT_LIT, n, start_line, start_col)
+ return Token(TokenType.INT_LIT, n, start_line, start_col)
+
+ def read_ident(self, first: str) -> Token:
+ start_line, start_col = self.line, self.col
+ ident = first
+ while self.current().isalnum() or self.current() == '_' or self.current() == '\'':
+ ident += self.advance()
+ if ident in KEYWORDS:
+ return Token(KEYWORDS[ident], ident, start_line, start_col)
+ return Token(TokenType.IDENT, ident, start_line, start_col)
+
+ def _emit(self, tok: Token):
+ tok.start = self._iter_start
+ tok.end = self.pos
+ self.tokens.append(tok)
+
+ def error(self, msg: str):
+ raise SyntaxError(f"{self.filename}:{self.line}:{self.col}: {msg}")
+
+ def tokenize(self) -> list:
+ self.tokens = []
+ self._iter_start = 0
+ while self.pos < len(self.source):
+ self.skip_whitespace_and_comments()
+ if self.pos >= len(self.source):
+ break
+ self._iter_start = self.pos
+
+ ch = self.current()
+ start_line, start_col = self.line, self.col
+
+ # 单字符 token
+ # 批 6(裁-S7,bounded):`#` = 规约标注 sigil(`#check(...)` / `#ensure(...)`)。
+ # 修复前 `#` 走末尾 `self.error("Unexpected character")`(**响亮拒收**)——
+ # 而 self-hosted 侧是**静默丢弃**(`lexer.cr` Unknown 分支)⇒ 两前端分歧;
+ # 现两侧同判:都产出一个 `#` token,语义面由各自的 parser 消费(**接受并跳过**)。
+ # 注:`:287` 的未知字符报错**保留**——`#` 之外仍需它做最后一道响亮防线。
+ single_char_map = {
+ '+': TokenType.PLUS, '-': TokenType.MINUS,
+ '*': TokenType.STAR, '/': TokenType.SLASH,
+ '%': TokenType.PERCENT, ',': TokenType.COMMA,
+ ';': TokenType.SEMI, '@': TokenType.AT,
+ '#': TokenType.HASH,
+ '(': TokenType.LPAREN, ')': TokenType.RPAREN,
+ '[': TokenType.LBRACK, ']': TokenType.RBRACK,
+ '{': TokenType.LBRACE, '}': TokenType.RBRACE,
+ }
+
+ if ch in single_char_map:
+ self.advance()
+
+ # 检查 ->
+ if ch == '-' and self.current() == '>':
+ self.advance()
+ self._emit(Token(TokenType.ARROW, '->', start_line, start_col))
+ continue
+
+ self._emit(Token(single_char_map[ch], ch, start_line, start_col))
+ continue
+
+ # 双字符
+ if ch == '=':
+ self.advance()
+ if self.current() == '=':
+ self.advance()
+ self._emit(Token(TokenType.EQ_EQ, '==', start_line, start_col))
+ elif self.current() == '>':
+ self.advance()
+ self._emit(Token(TokenType.FAT_ARROW, '=>', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.EQ, '=', start_line, start_col))
+ continue
+
+ if ch == '!':
+ self.advance()
+ if self.current() == '=':
+ self.advance()
+ self._emit(Token(TokenType.NOT_EQ, '!=', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.BANG, '!', start_line, start_col))
+ continue
+
+ if ch == '<':
+ self.advance()
+ if self.current() == '=':
+ self.advance()
+ self._emit(Token(TokenType.LT_EQ, '<=', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.LT, '<', start_line, start_col))
+ continue
+
+ if ch == '>':
+ self.advance()
+ if self.current() == '=':
+ self.advance()
+ self._emit(Token(TokenType.GT_EQ, '>=', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.GT, '>', start_line, start_col))
+ continue
+
+ if ch == '&':
+ self.advance()
+ if self.current() == '&':
+ self.advance()
+ self._emit(Token(TokenType.AND_AND, '&&', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.AMPERSAND, '&', start_line, start_col))
+ continue
+
+ if ch == '|':
+ self.advance()
+ if self.current() == '|':
+ self.advance()
+ self._emit(Token(TokenType.PIPE_PIPE, '||', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.PIPE, '|', start_line, start_col))
+ continue
+
+ if ch == ':':
+ self.advance()
+ if self.current() == '=':
+ self.advance()
+ self._emit(Token(TokenType.COLON_EQ, ':=', start_line, start_col))
+ elif self.current() == ':':
+ self.advance()
+ self._emit(Token(TokenType.PATH_SEP, '::', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.COLON, ':', start_line, start_col))
+ continue
+
+ if ch == '.':
+ self.advance()
+ if self.current() == '.':
+ self.advance()
+ if self.current() == '.':
+ self.advance()
+ self._emit(Token(TokenType.DOT_DOT_DOT, '...', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.DOT_DOT, '..', start_line, start_col))
+ else:
+ self._emit(Token(TokenType.DOT, '.', start_line, start_col))
+ continue
+
+ if ch == '?':
+ self.advance()
+ self._emit(Token(TokenType.QUESTION, '?', start_line, start_col))
+ continue
+
+ # 字符串
+ if ch in ('"', '\''):
+ self._emit(self.read_string(ch))
+ continue
+
+ # 数字
+ if ch.isdigit():
+ self._emit(self.read_number(self.advance()))
+ continue
+
+ # 标识符
+ if ch.isalpha() or ch == '_':
+ self._emit(self.read_ident(self.advance()))
+ continue
+
+ self.error(f"Unexpected character: '{ch}'")
+
+ self._emit(Token(TokenType.EOF, '', self.line, self.col))
+ return self.tokens