From 93f13beba6ad167ae9b556c84d8180a8fd24256f Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Thu, 24 Sep 2026 11:15:54 +0800 Subject: [PATCH 01/15] =?UTF-8?q?v4=20=E8=BF=81=E7=A7=BB=EF=BC=88=E6=89=B9?= =?UTF-8?q?=E5=86=85=C2=B7=E7=AC=AC=E4=B8=80=E7=AC=94=EF=BC=89=EF=BC=9A?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E5=A0=86=20rebase=20=E5=88=B0=20develop=20+?= =?UTF-8?q?=20=E5=89=8D=E7=AB=AF=E5=8F=96=E8=AE=A1=E5=88=92=E7=89=88=20T1/?= =?UTF-8?q?T2=20+=20T3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 基底问题(本轮探明的根因):本地那堆 v4 改动原在 dbadb8d6 上(落后 develop 24 提交、 缺 104 档文件——其中恰含 develop 已合入的施工计划与 T0 布局规格),所以「改了一大半 v4 语法」却看不到计划。本笔把堆 rebase 到 develop(920b1cbb)。 - 前端(T1/T2):bootstrap/corec 取 feature/v4-migration-t1t2 的**计划版**实现—— 39 关键字 + NEWLINE/INDENT/DEDENT 发射 + parser 吃 INDENT…DEDENT(取代 {}), 随附判据载体 tools/v4_frontend_probe.py(94 条,含正反两态);唯一 FAIL 是 J-T1-2「两套前端关键字一致」= 批末判据(自源侧属 T5)。 本地那套「双形并存」实现退居 bookmark wip/v4-local-stale-base(bb8cb353)备查。 - 自源面:src/compiler 恢复 develop 版(本地双形自源改动按计划留待 T5 重做)。 - T3:build_selfhost_native.py 的 wrapper 与 tests/selfhost/test_compile.py 的内联源 改 v4 形(`:` + layout)。(tools/build_stdlib.py 无 wrapper 行,计划该格不适用。) - 文档:48 档冲突逐档合(事实/结构/引用以 develop 为准,本地较新的事实与风格保留) ⇒ 0 冲突;另恢复被堆清空的 docs/superpowers/plans/2026-07-30-lazy-eval.md(develop 186 行) 并删两枚 .tmp 原子写残骸。 - 判据现状:T1/T2 探针 94 条(93 PASS);tests/bootstrap 全红 = (乙) 预期 (料语料仍 v3);src/** 语料未动(花括号 14,962 / `;` 18,663)⇒ T4 起点。 --- .github/CONTRIBUTING.md | 38 +- .github/SECURITY.md | 6 +- .github/pull_request_template.md | 8 +- CHANGELOG.md | 16 +- CLAUDE.md | 136 +- DEBUG_REPORT.md | 68 +- README.md | 3 +- README.zh-CN.md | 3 +- bootstrap/corec/frontend/lexer.py | 151 +- bootstrap/corec/frontend/parser.py | 330 ++-- bootstrap/corec/frontend/type_checker.py | 6 + bootstrap/corec/syntax/tokens.py | 55 +- build_selfhost_native.py | 4 +- docs/README.md | 70 +- docs/academic/cache-semantics.md | 133 +- docs/academic/lattice-theory.md | 78 +- docs/academic/verifier-kernel.md | 8 +- docs/coq/README.md | 32 +- docs/core-language-syntax_v4.md | 1410 +++++++++++++++++ docs/developer/at-intrinsics.md | 2 +- docs/developer/concepts.md | 16 +- docs/developer/concepts/deploy.md | 28 +- docs/developer/concepts/graph.md | 18 +- docs/developer/concepts/memory.md | 24 +- docs/developer/concepts/spec.md | 32 +- docs/developer/editors.md | 6 +- docs/developer/errors.md | 18 +- docs/developer/examples.md | 20 +- docs/developer/faq.md | 52 +- docs/developer/quickstart.md | 28 +- docs/developer/syntax.md | 40 +- docs/developer/tutorial.md | 60 +- docs/glossary.md | 22 +- docs/ir-schema/corespecir-schema.md | 4 +- docs/maintainer/adr/README.md | 8 +- .../adr/adr-0001-corespec-crasm-retired.md | 16 +- .../adr/adr-0002-ccr-v6-segment-table.md | 22 +- .../adr/adr-0003-selfhost-elf-direct-emit.md | 26 +- .../adr/adr-0004-corec-corearch-split.md | 18 +- .../adr/adr-0005-memory-model-layers-v4.md | 8 +- .../adr/adr-0006-cache-semantics.md | 6 +- .../adr/adr-0007-graph-anchored-regions.md | 8 +- .../adr/adr-0008-execution-model-regions.md | 10 +- .../maintainer/adr/adr-0009-spec-system-v2.md | 16 +- .../adr/adr-0010-numeric-dex-apx.md | 16 +- .../adr/adr-0011-platform-abstract.md | 8 +- docs/maintainer/adr/adr-0012-int-unbounded.md | 18 +- .../adr/adr-0013-type-system-direction.md | 8 +- .../adr/adr-0014-lazy-compile-time.md | 12 +- .../adr-0015-hit-hardware-interface-table.md | 14 +- docs/maintainer/adr/adr-0016-arena-model.md | 18 +- .../adr/adr-0017-concurrency-gmp.md | 18 +- .../adr/adr-0018-repo-governance.md | 16 +- .../adr/adr-0019-bootstrap-route.md | 18 +- docs/maintainer/adr/adr-0020-ir-dual-form.md | 18 +- docs/maintainer/design/corelsp.md | 10 +- docs/maintainer/design/crasm.md | 12 +- docs/maintainer/design/dataflow-design.md | 40 +- docs/maintainer/design/execution-model.md | 209 +-- docs/maintainer/design/existence-structure.md | 18 +- docs/maintainer/design/ir-op-semantics.md | 124 +- docs/maintainer/design/memory-model.md | 6 +- docs/maintainer/design/pointer-model.md | 20 +- .../design/regalloc-cache-mapping.md | 8 +- docs/maintainer/design/region-model.md | 27 +- docs/maintainer/design/spec-design.md | 60 +- docs/maintainer/onboarding.md | 32 +- docs/maintainer/proposals/comptime.md | 14 +- docs/maintainer/proposals/concurrency.md | 14 +- docs/maintainer/proposals/distributed.md | 26 +- docs/maintainer/proposals/dynamic-typing.md | 20 +- docs/maintainer/proposals/ffi.md | 10 +- docs/maintainer/proposals/generics.md | 8 +- docs/maintainer/proposals/lazy.md | 19 +- docs/maintainer/proposals/probabilistic.md | 26 +- docs/project-book.md | 34 +- .../plans/2026-07-28-arena-model.md | 266 ++-- ...026-09-10-language-surface-narrowing-r1.md | 114 +- .../plans/2026-09-10-r2-p0-type-engine.md | 132 +- .../plans/2026-09-10-r2-p1-shadow-parity.md | 23 +- .../plans/2026-09-11-r2-p3-capabilities.md | 280 ++-- .../plans/2026-09-13-r2-p5-cleanup.md | 57 +- .../2026-09-15-fail-closed-diagnostics.md | 121 +- .../plans/2026-09-16-agg-read-type.md | 300 ++-- .../plans/2026-09-16-criteria-harden.md | 48 +- .../specs/2026-07-28-arena-model-design.md | 24 +- .../specs/2026-07-28-at-intrinsics-design.md | 12 +- .../specs/2026-07-29-hotpatch-design.md | 4 +- .../2026-07-29-incremental-cache-design.md | 4 +- .../specs/2026-07-30-concurrency-design.md | 20 +- .../specs/2026-07-30-dynamic-typing-design.md | 24 +- .../specs/2026-07-30-ffi-design.md | 24 +- .../specs/2026-07-30-generics-design.md | 24 +- .../specs/2026-07-30-lazy-eval-design.md | 22 +- .../2026-07-30-probabilistic-pass-design.md | 32 +- .../specs/2026-08-08-crasm-design.md | 36 +- .../specs/2026-08-08-error-codes-design.md | 50 +- .../specs/2026-08-08-lsp-design.md | 99 +- .../specs/2026-08-08-pseudocode-tdd-design.md | 18 +- ...ocode-tdd-design.md.tmp.48271.a358599c902c | 160 ++ .../specs/2026-08-08-region-cfg-design.md | 56 +- .../2026-08-09-repo-governance-design.md | 42 +- ...026-08-13-graph-anchored-regions-design.md | 28 +- .../2026-08-15-cache-semantics-design.md | 30 +- .../2026-08-16-platform-abstract-design.md | 14 +- .../specs/2026-08-23-hw-map-design.md | 54 +- .../2026-08-27-lattice-form-ir-design.md | 24 +- ...026-08-27-regalloc-cache-mapping-design.md | 58 +- .../specs/2026-08-28-lsp-production-design.md | 40 +- .../2026-09-01-syntax-doc-rewrite-design.md | 2 +- .../2026-09-06-int-unbounded-semantics.md | 2 +- .../2026-09-07-regalloc-backend-design.md | 36 +- .../specs/2026-09-09-lattice-ir-v7-format.md | 26 +- ...09-10-language-surface-narrowing-design.md | 30 +- .../specs/2026-09-10-x86-instance-design.md | 52 +- ...9-11-explain-predict-incremental-design.md | 30 +- ...1-performance-without-commitment-design.md | 24 +- .../2026-09-11-policy-authorization-design.md | 14 +- .../2026-09-11-policy-injection-design.md | 32 +- ...9-11-policy-resource-confinement-design.md | 10 +- ...9-11-policy-state-version-toctou-design.md | 8 +- ...9-11-semantic-safety-obligations-design.md | 48 +- .../2026-09-11-semantic-safety-roadmap.md | 2 +- .../2026-09-16-agg-read-type-batch-report.md | 34 +- .../specs/2026-09-16-apx-conversion-audit.md | 36 +- .../2026-09-16-apx-conversion-batch-report.md | 4 +- .../2026-09-16-arg-inference-batch-report.md | 16 +- .../specs/2026-09-16-compile-time-theorems.md | 9 +- .../2026-09-16-criteria-strength-audit.md | 66 +- .../specs/2026-09-16-opt-rep-batch-report.md | 2 +- ...026-09-28-doc-tone-normalization-design.md | 86 + docs/z-vision.md | 28 +- editor/README.md | 6 +- grammar/core.ebnf | 84 +- tests/bootstrap/test_pipeline.py | 59 + tests/fixtures/so_index/README.md | 6 +- tests/kernel/README.md | 16 +- tests/probes/README.md | 6 +- tests/probes/warm/README.md | 6 +- tests/selfhost/test_compile.py | 35 +- tools/baseline/REBUILD.md | 2 +- tools/mctt_ref/README.md | 76 +- tools/mctt_ref/protocol.md | 6 +- tools/v4_frontend_probe.py | 835 ++++++++++ 144 files changed, 5541 insertions(+), 2397 deletions(-) create mode 100644 docs/core-language-syntax_v4.md create mode 100644 docs/superpowers/specs/2026-08-08-pseudocode-tdd-design.md.tmp.48271.a358599c902c create mode 100644 docs/superpowers/specs/2026-09-28-doc-tone-normalization-design.md create mode 100644 tools/v4_frontend_probe.py 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 `)不走该门,其对应门 = `tests/selfhost/test_backend_bootstrap.py` 的 + `run_checked`(rc=0 时仍扫 stdout+stderr 的 `error[`)——**两门互补,改一处须同步另一处**。 + +### 本地复现 CI(首选入口:与 CI 跑的是同一条命令) + +CI 与本地**唯一真源 = `src/ci/run.sh`**(按 `CI_JOB_NAME` 的 case 分发,逐档带计数注); +workflow 只负责事件分层与 matrix 派发(`.github/workflows/core-ci.yml`): +PR 层 = `check`/`bootstrap-tests`/`selfhost-tests`,完整层 = `suite`/`full-bootstrap` +(merge queue 因免费计划降级,完整层目前经 `workflow_dispatch` 手动派发)。 -**Bootstrap pipeline tests** (`tests/bootstrap/`): ```bash -python3 tests/bootstrap/test_pipeline.py # core pipeline: lex → parse → check → ir → interp -python3 tests/bootstrap/test_borrow.py # Borrow checker error detection -python3 tests/bootstrap/test_generics.py # Generic function + generic struct +CI_JOB_NAME=check src/ci/run.sh # 构建 + ./build/corec check src/compiler(最快) +CI_JOB_NAME=bootstrap-tests src/ci/run.sh # 纯 python:bootstrap 套件 + harness 机械门 + canary 载体牙 +CI_JOB_NAME=selfhost-tests src/ci/run.sh # 最长档:构建 + 40+ 档套件/闸门调用(含 canary) +CI_JOB_NAME=suite src/ci/run.sh # tests/suite/*.cr 逐个编译成 ELF 并运行(rc=0 为过) +CI_JOB_NAME=full-bootstrap src/ci/run.sh # 三阶段自举:corec2 与 corec3 必须 cmp 逐字节同 ``` -**Self-hosted compiler tests** (`tests/selfhost/`): +> 判据口径:改 `src/compiler/**` ⇒ 至少 `selfhost-tests` + `full-bootstrap`;只动文档/注释 ⇒ `check` 够。 +> 长编译遵守铁律 #6。 + +### Test suites + +`tests/` 共 8 个目录,职责不同——**只有前三个是「测试套件」**: + +| 目录 | 形态 | 说明 | +|------|------|------| +| `bootstrap/` | 7 个 `.py` | 纯 Python 驱动,import `bootstrap/corec` 走全管线后解释执行。**不需要构建** | +| `selfhost/` | 59 个 `.py` | 驱动原生 `build/corec` 子进程;**前置**:先跑 `build_selfhost_native.py`(缺则报 `[FAIL] missing native compiler`) | +| `suite/` | `.cr` 源码 | 端到端集成:逐个编译成 ELF 并运行,main 返回 0 为通过;`*_mini*.cr` 被 CI 跳过 | +| `harness/` | 5 个 `.py` | **判据的判据**(元测试):git 拦截、CI 挂点覆盖、判据突变自证、canary 载体牙、TODO 标识迁移 | +| `probes/` | 29 档 `.cr` | 行为探针语料(`check` 面负例为主),**非编译单元**;runner = `tools/baseline/probes_run.sh` | +| `fixtures/` | 夹具 | 判据自带夹具(如 `so_index/` 两态索引) | +| `kernel/` | 语料 + 驱动 | McTT→Core 内核差分测试;**需仓外 OCaml 参考侧 `~/mctt`**(见 `tools/mctt_ref/`)⇒ 不入 CI | +| `hit/` | `.cr` + `.ccr` | HIT 表冒烟语料 | + +**跑单个套件** = 直接跑那个 `.py`(多数套件**不支持过滤参数**,用例表写在文件内的 +`CASES` / `CHECK_CASES` 列表里 ⇒ 跑「单个用例」= 改列表或临时注释): + ```bash -python3 tests/selfhost/test_compile.py # Self-compilation pipeline test +python3 tests/bootstrap/test_pipeline.py # core pipeline: lex → parse → check → ir → interp python3 tests/selfhost/test_impl.py # Impl/method tests python3 tests/selfhost/test_borrow.py # Self-hosted borrow checker (7 rules) ``` @@ -102,6 +150,38 @@ Integration tests in `tests/suite/` are `.cr` source files — run through `./bu **行为探针语料**(`tests/probes/`,29 档 `check` 面负例为主,**非编译单元**)与**回归网配方**(`tools/baseline/`:冻结基线重建 + sha 白名单 + 两条 runner)见 `tools/baseline/REBUILD.md`——判定面回归网 = 冻结基线同源对拍 + 行为探针 + 突变控制 + 三态纪律(R2 P6 Task 1 起;影子通道已下线,不得引用其计数)。 +**改单档 suite 语料**: + +```bash +./build/corec build tests/suite/at_test.cr -o /tmp/bin --static && chmod +x /tmp/bin && /tmp/bin +``` + +> ⚠ **新增测试文件 = 必须同时登记,否则 CI 变红**(`test_ci_hook_coverage.py` 机械判): +> 新建 `tests/{selfhost,bootstrap,harness}/*.py` 后,**要么**在 `src/ci/run.sh` 加挂点, +> **要么**在 `tests/harness/ci_hook_allowlist.txt` 逐条登记一行理由(`路径理由`)。 +> 双向都查:已挂/已删条目留在白名单里也会 FAIL。该门存在的原因见 `run.sh:71-79` +> (曾因「自称已挂而 run.sh 零命中」致 `error[N06]` 跨 5 任务漏检 33 次)。 + +### 判据网(回归网四要素 + canary 闸门) + +判定面回归网 = **① 冻结基线同源对拍** + **② 行为探针** + **③ 突变控制** + **④ 三态纪律** +(R2 P6 Task 1 起;**影子通道已下线,不得引用其计数/摘要**)。 + +- **①** 冻结基线(二进制**不入库**)由 `bash tools/baseline/rebuild.sh ` 从 pinned revision + 重建,配方 + 三 sha 白名单 = `tools/baseline/REBUILD.md`;对拍 runner = `tools/baseline/parity_run.sh` + (逐档 `clean-cache`)。CI 内不跑(浅检出无 jj)。 +- **②** 探针语料 `tests/probes/`(29 档,**非编译单元**)+ 行为套件;runner = `tools/baseline/probes_run.sh`。 +- **③** 改坏派生面 ⇒ 探针/对拍必须转红(`tests/harness/test_criteria_mutations.py` 是这条的机械形态)。 +- **④** 引擎 -1 ⇒ ICE04 硬错(`main.cr` 硬名单)。 + +**ELF canary + `.ccr` 四条闸门**(CI `selfhost-tests` 内,`bash tools/baseline/canary_check.sh` + +`tests/harness/test_canary_carrier.py --require-compiler`):锁定值**单一真源** = +`tools/baseline/canary_values.tsv`。契约分两级——canary ELF = 发射面零泄漏检测器(**变 = 越界 ⇒ 停下上报**); +`.ccr` 四条 = 格式+形状检测器(值变 ≠ 必然回归,但**必须「显式归因 + 同批重锁 + 旧值留痕」**)。 +> ⚠ **换代纪律**:跑出来不符时**先归因**,归因不出按回归处理并停下上报——**不得改值表去对齐输出**。 +> 详见 `docs/superpowers/plans/2026-09-16-criteria-carrier.md` §6。另注:`.ccr` 四条为**冷态**锁定, +> 且 `.so` 索引面须环境归一化(载体已把 `HOME` 钉到采集目录内空 `home/`)。 + ## Architecture ### Python Bootstrap Compiler @@ -121,7 +201,7 @@ bootstrap/corec/frontend/type_checker.py → Type inference + checking + borrow bootstrap/corec/frontend/ir_gen.py → AST → Core IR bootstrap/corec/ir/cir.py → Dataflow graph IR definitions -bootstrap/corec/ir/ccr.py → 格形态 IR(注:该文件实际不存在——.ccr 仅由 self-hosted ccr_io.cr 读写;现行 = v8 八段段表,见 specs/2026-09-09-lattice-ir-v7-format.md;v6 版历史设计见 specs/2026-09-05-lattice-ir-v6-format.md) +bootstrap/corec/ir/ccr.py → 格形态 IR(注:该文件实际不存在——.ccr 仅由 self-hosted ccr_io.cr 读写;现行 = v9 八段段表(NOD 40B),见 specs/2026-09-09-lattice-ir-v7-format.md;v6 版历史设计见 specs/2026-09-05-lattice-ir-v6-format.md) bootstrap/corec/ir/base.py → IRNode base class, IRVar, VarKind bootstrap/corec/ir/symbol_table.py → Scoped symbol table @@ -185,6 +265,20 @@ src/compiler/ (**全 38 个 .cr**;2026-09-16 文档审计修订:原清 └── type_terms.cr → R2 P0 类型项表(集合语义 DAG)(backend_support+corec+corelsp) ``` +### 其余 src 子树(**不在 `src/compiler/`,易漏**) + +``` +src/lattice/ent_kernel.cr → 语义内核(范式无关),corec 与 corearch **双 concat 共享**(`kernel_files`) +src/arch/hit/ → HIT 表**引擎**(hit.cr + lower_to_core.cr)——与架构轴的**表数据** `core-x86.toml` 分工 +src/kernel/ → McTT→Core **验证内核**移植(bytes/term_io/mctt/subst/nbe/subtype/check/kernel_main) + · 由根目录 **`build_kernel.py`** 单独构建出 `build/kernel`(复用 bootstrap 管线的 + `concat`/`compile_and_assemble`,**不在** build_selfhost_native.py 的任何清单内) + · 差分语料 `tests/kernel/`(需仓外 OCaml 参考侧 `~/mctt`,不入 CI) +src/lsp/ → corelsp:json.cr · rpc.cr · lsp.cr · analysis.cr · main.cr(+ `_import.cr`) + · 由自举脚本的 `corelsp_files` 清单构建成 `build/corelsp` +src/scheduler/ → sched.s + example.cr(调度器汇编侧原型) +``` + ### Backend(x86 实例化三轴布局:架构 × 格式 × OS;`src/arch/linux/ld/` 已退役) Direct ELF binary output for x86-64, used by `corearch`. 三轴目录 = 跨轴 import 的 @@ -313,10 +407,28 @@ Design documents (Chinese): - File extensions: `.cr` (source), `.cir` (dataflow graph IR / 图形态), `.ccr`(格形态 IR,**v9 = 段表架构 8 段**:STR/SYM/NOD/ENT/REG/EDG + TYPE(7)/IFACE(8)(R2 P4 载体批起;R2 P6 T3 起 **v9**——NOD 40B 承载 TYPE 段项索引;版本以 `src/compiler/ccr_io.cr::CCR_VERSION` 为准;文件名/测试名保留「v7」= 段表架构代号,见 specs/2026-09-09-lattice-ir-v7-format.md)。**2026-09-16 审计修订:原文写 v8(陈旧)**), `.corespec`(已退役 2026-09-06——规约并入 .cr 语法,见 grammar/core.ebnf 迁移事项) - Tests in `tests/bootstrap/` and `tests/selfhost/` define inline Core source strings and compare output - Python bootstrap: `sys.path.insert(0, 'bootstrap')` to import compiler modules -- VS Code extension in `vscode-core/` +- Editor integrations under **`editor/`**(不是仓库根的 `vscode-core/`):`vscode-core/`(VS Code 扩展)· + `nvim/`(Neovim:syntax/ftdetect/ftplugin/snippets)· `core.mtsx`(Zed 用 grammar)· `corecheck`(脚本) - Spec files in `spec/`(.corespec 已退役——规约语法并入 .cr,图即验证承载于 TagNode/.csr) - Examples in `examples/` ## Known Issues & TODO -See [TODO.md](TODO.md) for current status. +See [TODO.md](TODO.md) for current status——**371 KB / 1300+ 行,别整读**,用 `rg`/`grep` 定位条目。 + +### TODO 标识约定(**机械门,写错即 CI 红**) + +新条目标识 = **`#YYYY-MM-DD-N`**(日期 = 创建日期;`N` = 当天序号,按标题行行号升序,取「当天最大 +1」)。 +**旧「全局单调号 `#NN`」已永久封存**(不复用、不重编号)——历史 commit/文档里的旧号经 TODO.md 头部 +「编号迁移对照表」解析。由 `tests/harness/test_todo_id_migration.py` 机械执行: +J1 全仓无旧形态残留 · J2 新 id ↔ TODO.md 标题双向一致(无悬空)· J3 映射完备 · J4 突变自证。 +> ⚠ J4 的突变样本**就取自本文件**——`elf.cr` 死文件条目的 `TODO #2026-09-10-3` 引用是那个载体, +> 删/改它会让 J4 失去自证能力(跑 `python3 tests/harness/test_todo_id_migration.py` 可立即确认)。 + +### 会话级铁律的机械执行面(别绕,绕不过) + +- **铁律 #2(禁 git)**:`.claude/settings.json` 的 PreToolUse hook → `.claude/hooks/block-git.py`, + 拦截**任意位置**的 git 调用(分隔符后 / 命令替换 / `bash -c` / 前缀命令后),引号内文本与 + heredoc 体不误伤,`jj git push` 放行。回归 = `tests/harness/test_block_git.py`。 + **hook 自身异常一律放行(宁可漏拦不卡会话)**⇒ 不要依赖它做安全边界,依赖它做习惯约束。 +- **铁律 #3(文件永久不允许还原)**:`jj restore` / `jj abandon` / 覆盖回退既有文件均**须先取得明确许可**。 diff --git a/DEBUG_REPORT.md b/DEBUG_REPORT.md index 34f0fba3..8d7f2189 100644 --- a/DEBUG_REPORT.md +++ b/DEBUG_REPORT.md @@ -1,17 +1,17 @@ -# Core 自举调试报告:corec2 → corec3 +# Core 自举调试报告:`corec2` → `corec3` -> 日期: 2026-07-06 -> PR: https://github.com/dslsdzc/core/compare/main...RhineIris:core:main +> 日期:2026-07-06 +> PR:https://github.com/dslsdzc/core/compare/main...RhineIris:core:main > -> ** 历史存档**:本报告描述的问题均已在后续修复中解决—— -> 文中 3 个已修复 Bug 已合并(PR #9/#16 时期);"仍未解决的根本性 Bug" +> **历史存档**:本报告描述的问题均已在后续修复中解决—— +> 文中 3 个已修复 Bug 已合并(PR #9/#16 时期);「仍未解决的根本性 Bug」 > (rip_patch 位置错位)已由 2026-07-23 P0 全量修复(`emit_instr()` disp32 -> 写入补上当前指令基址)解决,corec2 → corec3 自举现已全程通过。 +> 写入补上当前指令基址)解决,`corec2` → `corec3` 自举现已全程通过。 > 本文档仅作调试过程记录保留。 ## 目标 -用 corec2 (Stage 1,由 Python bootstrap 编译) 编译自身源码,产生 corec3 (Stage 2)。 +用 `corec2`(Stage 1,由 Python bootstrap 编译)编译自身源码,产生 `corec3`(Stage 2)。 构建命令: ``` @@ -23,13 +23,13 @@ ## 已修复的 Bug(3 个,已包含在 PR 中) -### Bug 1: `alloc_registers()` 在 O1 损坏字符串引用 +### Bug 1:`alloc_registers()` 在 O1 损坏字符串引用 -**文件:** `src/compiler/main.cr` 第 374-380 行 +**文件:** `src/compiler/main.cr` 第 374-380 行 -**问题:** `alloc_registers()` 在 O1 被调用,污染了 `g_opt_meta`,导致 ELF 后端生成的二进制中字符串引用(LEA rip-relative)指向错误地址。`println` 的字符串参数使 `str_len` 无限扫描内存——表现为死循环。 +**问题:** `alloc_registers()` 在 O1 被调用,污染了 `g_opt_meta`,导致 ELF 后端生成的二进制中字符串引用(LEA rip-relative)指向错误地址。`println` 的字符串参数使 `str_len` 无限扫描内存——表现为死循环。 -**修复:** +**修复:** ```diff - if g_opt_level >= 1 { - pass_cse(); @@ -42,13 +42,13 @@ --- -### Bug 2: Type-check 诊断 fatal 导致自举中断 +### Bug 2:Type-check 诊断 fatal 导致自举中断 -**文件:** `src/compiler/main.cr` 第 123-128 行 +**文件:** `src/compiler/main.cr` 第 123-128 行 -**问题:** Self-hosted 编译器在类型检查后将所有诊断(包括 `TC_IF_BRANCH` "if branches have different types")当致命错误处理。但 Python bootstrap 将这些视为 warning。源码 `opt.cr` 中的 `if...else if` 链产生大量 TC02 警告,导致自举编译中止。 +**问题:** Self-hosted 编译器在类型检查后将所有诊断(包括 `TC_IF_BRANCH` "if branches have different types")当致命错误处理。但 Python bootstrap 将这些视为 warning。源码 `opt.cr` 中的 `if...else if` 链产生大量 TC02 警告,导致自举编译中止。 -**修复:** +**修复:** ```diff check_all(); - if g_diag_count > 0 { print_diagnostics(); return 1; } @@ -58,13 +58,13 @@ --- -### Bug 3: `cur_char()` / `peek()` 中 `g_source_len` 读取不一致 +### Bug 3:`cur_char()` / `peek()` 中 `g_source_len` 读取不一致 -**文件:** `src/compiler/lexer.cr` 第 33-47 行 +**文件:** `src/compiler/lexer.cr` 第 33-47 行 -**问题:** 全局变量 `g_source_len` 在 `tokenize()` 中写入的 BSS 地址与 `cur_char()` 中读取的 BSS 地址不同——写入去了地址 A,读取从地址 B(未被写入,始终为 0)。`cur_char()` 永远判定 "past end of source",返回 0(EOF),tokenizer 不产生任何 token。 +**问题:** 全局变量 `g_source_len` 在 `tokenize()` 中写入的 BSS 地址与 `cur_char()` 中读取的 BSS 地址不同——写入去了地址 A,读取从地址 B(未被写入,始终为 0)。`cur_char()` 永远判定 "past end of source",返回 0(EOF),tokenizer 不产生任何 token。 -**修复:** +**修复:** ```diff fn cur_char() -> int { - if g_pos >= g_source_len { return 0; } @@ -89,9 +89,9 @@ ### 症状 -即使上述 3 个修复全部应用,corec2 在 O0 下仍然一进入 `tokenize()` 就死循环。死循环的原因:`advance()` 写入 `g_pos` 的 BSS 地址与 tokenize 循环条件 `g_pos >= g_source_len` 读取 `g_pos` 的地址不同。`advance()` 将递增后的值写入地址 A,但循环条件始终从地址 B 读取(值永远为初始值 0)。 +即使上述 3 个修复全部应用,`corec2` 在 O0 下仍然一进入 `tokenize()` 就死循环。死循环的原因:`advance()` 写入 `g_pos` 的 BSS 地址与 `tokenize` 循环条件 `g_pos >= g_source_len` 读取 `g_pos` 的地址不同。`advance()` 将递增后的值写入地址 A,但循环条件始终从地址 B 读取(值永远为初始值 0)。 -**空函数 tokenize 验证:** +**空函数 `tokenize` 验证:** ```core fn tokenize() { g_token_count = 0; @@ -100,15 +100,15 @@ fn tokenize() { return; } ``` -将 tokenize 替换为空函数后,corec2 **完全正常工作**——tokenize → parse → check → IRgen 全部通过,exit 0。确认问题仅在 tokenize 循环体内。 +将 `tokenize` 替换为空函数后,`corec2` **完全正常工作**——`tokenize` → `parse` → `check` → `IRgen` 全部通过,exit 0。确认问题仅在 `tokenize` 循环体内。 ### 调试过程 -#### 1. 排除 rip_patch 计算错误(已验证正确) +#### 1. rip_patch 计算错误的排除(已验证正确) 在 `elf_gen()` 的 rip_patch 循环中添加调试:对每个 `g_pos`(var_idx=698)的 patch 条目打印 `ppos`、`g_x86_global_off`、`target_va`、`rel`。 -**结果:全部 16 个 `g_pos` patch 计算正确:** +**结果:全部 16 个 `g_pos` patch 计算正确** ``` PATCH gvi=698 ppos=74669 off=5584 target=4736480 rel=467503 @@ -121,7 +121,7 @@ PATCH gvi=698 ppos=74845 off=5584 target=4736480 rel=467327 - `target_va=4736480` (= bss_va + 16 + 5584) → 全部一致 - rip_patch 计算 `target_va - lea_end_va` 的公式正确 -#### 2. 排除函数调用 patching 失败(已验证正确) +#### 2. 函数调用 patching 失败的排除(已验证正确) ```diff // ── Patch forward calls ── @@ -133,13 +133,13 @@ PATCH gvi=698 ppos=74845 off=5584 target=4736480 rel=467327 **结果:`CALLS: patched=4390 missed=0`** —— 全部 4390 个函数调用正确 patch,0 个失败。 -#### 3. 排除 ELF 结构错误(已验证正确) +#### 3. ELF 结构错误的排除(已验证正确) - ELF program headers: code segment (r-x), data segment (rw-, 256MB) - BSS 在 rw- 段内,地址范围正确 - 内置函数(load64=35, store8=29, syscall3=11, w64=126)全部正确注册 -#### 4. 发现:w32 写入后 read-back 正确,但最终文件不正确 +#### 4. `w32` 写入后 read-back 正确,但最终文件不正确(发现) 在 rip_patch 循环中添加即时验证: @@ -166,7 +166,7 @@ file offset 74893 (176+74717): [0xff, 0x48, 0x89, 0x45] 第一个字节 `0xff`(255) 正确,后三个字节 `0x48 0x89 0x45` 是指令代码(`mov [rbp+...], rax`)。 -#### 5. 确认:w32 写入到错误的位置 +#### 5. `w32` 写入位置错误(确认) 在 `elf_gen` 末尾(`return` 之前)加入验证标记: @@ -194,7 +194,7 @@ syscall3(1, fd, g_elf_buf, sz); - 标记 1(位置 500000)→ **保留成功**,说明 buffer 在 elf_gen 返回后没有被整体污染 - 标记 2(位置 74717)和标记 3(位置 74717)→ **都被覆盖**,最终值是原始指令代码 -#### 6. 反汇编确认:ppos 不指向 LEA displacement +#### 6. `ppos` 不指向 LEA displacement(反汇编确认) ``` 文件偏移 0x1245d (176+74717): @@ -204,7 +204,7 @@ syscall3(1, fd, g_elf_buf, sz); **ppos=74717 处于 CALL 指令的 4 字节位移字段内**(CALL 指令第 1-4 字节),而非 LEA(`4C 8D 1D ...`)的 displacement 字段。 -真正的 LEA 指令在位置 74704(`4C 8D 1D 4A 21 07 00`),其 displacement 字段在 74707。但 rip_patch 注册的 ppos 是 74717,差了 10 字节。 +真正的 LEA 指令在位置 74704(`4C 8D 1D 4A 21 07 00`),其 displacement 字段在 74707。但 rip_patch 注册的 `ppos` 是 74717,差了 10 字节。 ### 根因分析 @@ -255,7 +255,7 @@ cp = cp + e2_lr(buf, pos+cp, 0); ## 环境 -- 平台: WSL2 (Ubuntu, x86-64) -- Core 仓库: https://github.com/dslsdzc/core -- Fork: https://github.com/RhineIris/core -- 构建: `python3 build_selfhost_native.py` → `./build/corec build build/all.cr --static -O 0` +- 平台:WSL2 (Ubuntu, x86-64) +- Core 仓库:https://github.com/dslsdzc/core +- Fork:https://github.com/RhineIris/core +- 构建:`python3 build_selfhost_native.py` → `./build/corec build build/all.cr --static -O 0` diff --git a/README.md b/README.md index c25842dc..e04e2d1e 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,8 @@ This produces `build/corec` (frontend) and `build/corearch` (backend). - [Project Book](docs/project-book.md) — design and rationale - [Developer documentation](docs/developer/) — syntax reference and internals -- [Execution Model](docs/maintainer/design/execution-model.md) · [Memory Model](docs/maintainer/design/memory-model.md) +- [Execution Model](docs/maintainer/design/execution-model.md) +- [Memory Model](docs/maintainer/design/memory-model.md) - [Error codes](docs/developer/errors.md) ## Contributing diff --git a/README.zh-CN.md b/README.zh-CN.md index 5c7e64d9..82b11e7b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -88,7 +88,8 @@ python3 build_selfhost_native.py - [Project Book](docs/project-book.md) —— 设计与理由 - [开发者文档](docs/developer/) —— 语法参考与内部实现 -- [Execution Model](docs/maintainer/design/execution-model.md) · [Memory Model](docs/maintainer/design/memory-model.md) +- [Execution Model](docs/maintainer/design/execution-model.md) +- [Memory Model](docs/maintainer/design/memory-model.md) - [错误码](docs/developer/errors.md) ## 贡献 diff --git a/bootstrap/corec/frontend/lexer.py b/bootstrap/corec/frontend/lexer.py index 8305fc8a..160ee95d 100644 --- a/bootstrap/corec/frontend/lexer.py +++ b/bootstrap/corec/frontend/lexer.py @@ -8,6 +8,17 @@ def __init__(self, source: str, filename: str = ""): self.line = 1 self.col = 1 self.tokens = [] + # ── v4 布局状态(施工计划 §四.1 项 3;判定出处 = T0 布局规格 §1/§2)── + # 缩进栈:**空栈起**,由首个非空行的首个 token 建立基准 anchor(规格 §1.1 ①-1 第 3 条) + # —— 基准层不出 INDENT/DEDENT,故它不在栈里占一层。 + self.indent_stack = [] + # 括号/花括号深度:>0 时**不参与布局**(隐式续行)。`{ }` 一并计入 ⇒ + # 结构体字面量内部不产生 layout(规格 §4.1「字面量内部不参与 layout region」)。 + self.bracket_depth = 0 + # 当前逻辑行是否已产出 token(决定换行时是否发 NEWLINE;纯空行/纯注释行不发)。 + self.line_has_token = False + # 上一个「属于某个 token」的物理行号 —— 换行判定用(比跨行空白标志更稳)。 + self.last_tok_line = 0 def current(self) -> str: if self.pos < len(self.source): @@ -30,21 +41,102 @@ def peek(self, offset: int = 1) -> str: 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() + # ── v4 布局(layout):共享扫描器 + 发射 ────────────────────────────── + # 实现约束(T0 布局规格 §2.3,写死):判定 ① 的 anchor 计算与判定 ② 的 + # 行尾判定**必须共用同一个**注释/字符串感知扫描器——两处各写一份必然漂。 + # ⇒ 本类里注释/空白的跳过**只有** `_scan_blank_comment` 一个实现: + # `skip_whitespace_and_comments`(改写 self.pos)与 `_colon_is_line_end` + # (只读前瞻,不动状态)都建在它之上。 + def _scan_blank_comment(self, idx: int): + """从 idx 起跳过空白与注释(`//` 行注释 · `/* */` 块注释,**可跨行**)。 + + 不识别字符串字面量 —— 字符串是 **token**,两个调用方都在「遇真字符即停」的 + 语义下使用本函数,故无需(也不应)在此吞掉字符串。 + 返回 `(新下标, 是否跨过至少一个物理行边界)`。**纯函数**:不读不写实例状态。 + """ + src = self.source + n = len(src) + saw_nl = False + while idx < n: + ch = src[idx] + if ch in ' \t\r': + idx += 1 + elif ch == '\n': + saw_nl = True + idx += 1 + elif ch == '/' and idx + 1 < n and src[idx + 1] == '/': + while idx < n and src[idx] != '\n': + idx += 1 + elif ch == '/' and idx + 1 < n and src[idx + 1] == '*': + idx += 2 + while idx < n and not (src[idx] == '*' and idx + 1 < n and src[idx + 1] == '/'): + if src[idx] == '\n': + saw_nl = True + idx += 1 + idx = min(idx + 2, n) else: break + return idx, saw_nl + + def skip_whitespace_and_comments(self): + target, _ = self._scan_blank_comment(self.pos) + while self.pos < target: + self.advance() + + def _colon_is_line_end(self) -> bool: + """裁定 ②(词法位置决定,T0 布局规格 §2.1/§2.3): + + `:` **是行尾的** ⟺ 该 `:` 之后、到该物理行行尾为止,**不存在任何 token** + (空白不计 · 注释不计 ⇒ §2.3 的四格:`// note` / `/* note */` / 跨行块注释 + 都判**行尾**;`x : int = 5 // note` 判**行内**)。 + 调用点保证 `self.pos` 正好在 `:` 之后。 + """ + idx, saw_nl = self._scan_blank_comment(self.pos) + if saw_nl: + # 跨过行边界(含跨行块注释)⇒ 本物理行 `:` 之后已无余物 + return True + # 未跨行 ⇒ 要么撞上真字符(行内),要么到了源尾(行尾) + return idx >= len(self.source) + + def _layout_break(self): + """越过物理行边界(且不在括号内)时,发出 NEWLINE 与 INDENT/DEDENT。 + + 判定出处(T0 布局规格):§1.1 ①-1/①-2 —— 空行与只含注释的行**不产生 token**、 + 不改变 anchor(故本函数只在「上一逻辑行确实产出了 token」时被调用,见 `tokenize`); + §1.1 ①-3 —— anchor 列 ≡ 该行**首个 token** 的列(不是注释的列,也不是行首空白宽度); + ①-1 第 3 条 —— **首个非空行建立 anchor**(故本层不发 INDENT,基准由首行给定, + 与 `tools/v4_layout_probe.py` 的布局模型逐条同构:栈空 ⇒ 建基)。 + """ + self.tokens.append(Token(TokenType.NEWLINE, '', self.line, self.col)) + self.line_has_token = False + col = self.col + top = self.indent_stack[-1] + if col > top: + self.indent_stack.append(col) + self.tokens.append(Token(TokenType.INDENT, '', self.line, col)) + elif col < top: + while len(self.indent_stack) > 1 and self.indent_stack[-1] > col: + self.indent_stack.pop() + self.tokens.append(Token(TokenType.DEDENT, '', self.line, col)) + if self.indent_stack[-1] != col: + if len(self.indent_stack) == 1: + # 「比单元基准锚点更浅」——正是 T0 §6.1 A2 定义的那个 layout 错误 + self.error("layout anchor %d is shallower than the unit base anchor %d" + % (col, self.indent_stack[-1])) + # 不匹配任何外层列 ⇒ 响亮报错(**不得**静默对齐到最近一层——那是猜) + self.error("inconsistent dedent: column %d matches no open indent level" % col) + + def _finish_layout(self): + """源尾收尾:补发最后一个 NEWLINE,并弹出全部未闭合的缩进层(各发一个 DEDENT)。 + + 基准层(栈底 = 首行 anchor)**不发 DEDENT** —— 它没有对应的 INDENT。 + """ + if self.line_has_token: + self.tokens.append(Token(TokenType.NEWLINE, '', self.line, self.col)) + self.line_has_token = False + while len(self.indent_stack) > 1: + self.indent_stack.pop() + self.tokens.append(Token(TokenType.DEDENT, '', self.line, self.col)) def read_string(self, quote: str) -> Token: start_line, start_col = self.line, self.col @@ -150,11 +242,29 @@ def error(self, msg: str): def tokenize(self) -> list: self.tokens = [] + self.indent_stack = [] + self.bracket_depth = 0 + self.line_has_token = False + self.last_tok_line = 0 while self.pos < len(self.source): self.skip_whitespace_and_comments() if self.pos >= len(self.source): break + # 布局发射(判定出处 = T0 布局规格 §1/§2): + # - 只在括号外(`()`/`[]`/`{}` 内是隐式续行,不参与 layout); + # - 只在「上一逻辑行确实产出过 token」时发 NEWLINE ⇒ 纯空行与纯注释行 + # 天然成为 no-op(规格 ①-1/①-2,**不需要**另写一份「本行是否只有注释」的判定); + # - anchor 列 = 本 token 的列(规格 ①-3),由 `advance()` 的既有列维护给出。 + if self.bracket_depth == 0 and self.line_has_token and self.line != self.last_tok_line: + self._layout_break() + self.line_has_token = True + self.last_tok_line = self.line + if not self.indent_stack: + # ①-1 第 3 条:**首个非空行建立 anchor**(该行的首个 token 即基准列)。 + # 基准层不发 INDENT —— 否则顶层代码会整体被多包一层。 + self.indent_stack.append(self.col) + ch = self.current() start_line, start_col = self.line, self.col @@ -178,6 +288,14 @@ def tokenize(self) -> list: if ch in single_char_map: self.advance() + # 括号深度:`{}` 一并计入 ⇒ 结构体字面量内部不产生 layout + # (规格 §4.1「字面量内部不参与 layout region」) + if ch in '([{': + self.bracket_depth += 1 + elif ch in ')]}': + if self.bracket_depth > 0: + self.bracket_depth -= 1 + # 检查 -> if ch == '-' and self.current() == '>': self.advance() @@ -253,8 +371,12 @@ def tokenize(self) -> list: elif self.current() == ':': self.advance() self.tokens.append(Token(TokenType.PATH_SEP, '::', start_line, start_col)) + elif self._colon_is_line_end(): + # 裁定 ②:行尾 `:` = region 开启(唯一措辞见 T0 布局规格 §2.1) + self.tokens.append(Token(TokenType.COLON_BLOCK, ':', start_line, start_col)) else: - self.tokens.append(Token(TokenType.COLON, ':', start_line, start_col)) + # 行内 `:` = 类型标注 / import 别名 / 字段 / 形参分隔符 + self.tokens.append(Token(TokenType.COLON_DECL, ':', start_line, start_col)) continue if ch == '.': @@ -292,5 +414,6 @@ def tokenize(self) -> list: self.error(f"Unexpected character: '{ch}'") + self._finish_layout() self.tokens.append(Token(TokenType.EOF, '', self.line, self.col)) return self.tokens diff --git a/bootstrap/corec/frontend/parser.py b/bootstrap/corec/frontend/parser.py index 309472ae..a3e85355 100644 --- a/bootstrap/corec/frontend/parser.py +++ b/bootstrap/corec/frontend/parser.py @@ -39,27 +39,66 @@ def __init__(self, tokens: list): self.const_values = {} def _scan_constants(self): - """Pre-scan for 'NAME: TYPE = VALUE;' declarations to resolve array sizes.""" + """Pre-scan for 'NAME: TYPE = VALUE' declarations to resolve array sizes. + + v4 改判(T0 布局规格 §6.2 A4):终止元由 `;` 改为**行边界** ⇒ 六元组收为五元组。 + ⚠ **漏改即静默错答案**:具名长度会落到 `parse_type` 的 `.get(name, 0)` 兜底 + (解成 0),既不报错也不可辨。⇒ 判据必须含**正控**(真取到非 0 的值)。 + """ save = self.pos while not self.check(TokenType.EOF): matched = False - # New syntax: NAME: TYPE = VALUE; (starts with IDENT) + # v4: NAME : TYPE = VALUE 〈行边界〉 if (self.check(TokenType.IDENT) and - self._check_seq([TokenType.IDENT, TokenType.COLON, - TokenType.IDENT, TokenType.EQ, TokenType.INT_LIT, - TokenType.SEMI])): + self._check_seq([TokenType.IDENT, TokenType.COLON_DECL, + TokenType.IDENT, TokenType.EQ, TokenType.INT_LIT])): name = self.advance().lexeme # NAME self.advance() # : - type_name = self.advance().lexeme # int/dex/bool + self.advance() # TYPE name (int/dex/bool) self.advance() # = val = int(self.advance().lexeme) # VALUE - self.const_values[name] = val - self.advance() # ; (skip to keep pos consistent) + if self._at_line_end(): + self.const_values[name] = val matched = True if not matched: self.advance() self.pos = save + # ── v4 行边界(`;` 退场后的统一终止面)────────────────────────────── + # 出处 = T0 布局规格 §2.5(`;` 只在 `[T; N]` / `[v; N]` 存活)+ §6.2 的 A/B 两类逐点判定。 + def _at_line_end(self): + """当前位置是否处于行边界:NEWLINE / DEDENT / EOF。 + + `DEDENT` 与 `EOF` **不消费**——它们是 region 收尾信号,由块产生式处理。 + """ + return (self.check(TokenType.NEWLINE) or self.check(TokenType.DEDENT) + or self.check(TokenType.EOF)) + + def _consume_newlines(self): + while self.check(TokenType.NEWLINE): + self.advance() + + def _end_decl(self): + """消费语句/声明的行边界;**非行边界即响亮报错**。 + + 本函数取代原 `expect(SEMI)`(T0 布局规格 §6.2 B 类 8 处)——保留其**严格性**: + 少了这条,「同行两条声明」会被静默接受(与 `;` 时代行为不一致)。 + """ + if not self._at_line_end(): + self.error(f"expected end of line, got '{self.cur().lexeme}'") + self._consume_newlines() + + def _expect_region(self): + """吃 region 头:`COLON_BLOCK` 行尾冒号 + 其后的 NEWLINE + `INDENT`。 + + token 次序由 lexer 的 `_layout_break` 决定:NEWLINE 先于 INDENT/DEDENT。 + **行内 `:`(`COLON_DECL`)在此被响亮拒绝** —— 这正是 T0 布局规格 §2.2 要的 + 「行尾类型标注不是合法文本」的兜住点。 + """ + self.expect(TokenType.COLON_BLOCK) + self._consume_newlines() + self.expect(TokenType.INDENT) + def _check_seq(self, types): """Check if the next tokens match the given type sequence.""" if self.pos + len(types) > len(self.tokens): @@ -93,7 +132,12 @@ def check(self, typ: TokenType) -> bool: return self.cur().type == typ def _is_var_decl_start(self): - """Check if current position starts a new-style variable declaration (no 'let' keyword).""" + """Check if current position starts a new-style variable declaration (no 'let' keyword). + + v4 改判(T0 布局规格 §6.2 A3):本消解器**不读 `;`**(今天也不读),但 `:` 改判 + `COLON_DECL`——裁定 ② 使两种 `:` 互斥且穷尽 ⇒ 本处**零前瞻**, + `COLON_BLOCK` 不进声明分支(进不去 ⇒ 在语句位会响亮报错,正是 §2.2 要的)。 + """ if not self.check(TokenType.IDENT): return False save = self.pos @@ -104,11 +148,11 @@ def _is_var_decl_start(self): self.advance() if self.check(TokenType.IDENT): self.advance() - if self.check(TokenType.COLON): + if self.check(TokenType.COLON_DECL): result = True elif self.check(TokenType.COLON_EQ): result = True - elif self.check(TokenType.COLON): + elif self.check(TokenType.COLON_DECL): result = True # x : type ... — commit to declaration self.pos = save return result @@ -126,7 +170,7 @@ def _parse_var_decl_names_tags_type(self): self.advance() values = [self.parse_expr()] return names, tags, None, values - self.expect(TokenType.COLON) + self.expect(TokenType.COLON_DECL) if self.check(TokenType.AUTO) or self.check(TokenType.DOT): typ = None # auto-deduced self.advance() @@ -134,17 +178,18 @@ def _parse_var_decl_names_tags_type(self): typ = self.parse_type() if self.check(TokenType.COMMA): self.advance() - while not self.check(TokenType.EQ) and not self.check(TokenType.SEMI) and not self.check(TokenType.EOF): - # Accept IDENT or any keyword as a tag (anything that's not a structural token) - tt = self.cur().type - if tt not in (TokenType.EQ, TokenType.SEMI, TokenType.COMMA, TokenType.COLON, TokenType.EOF): - tag = self.advance().lexeme - # 已知标签:mut / pub / apx(与自举编译器一致,未知标签报错) - if tag not in ('mut', 'pub', 'apx'): - self.error(f"unknown declaration tag '{tag}'") - tags.append(tag) - else: - break + # 标签表终止面(T0 布局规格 §6.2 A8 + A9 的对齐目标): + # **行边界** + `EQ`(`x : int, mut, pub = e` 的 `=` 仍保留)。 + # ⚠ A9:自源 `parser.cr:871` 今天的终止符集 = EQ/SEMI/EOF, + # 而本侧曾是 EQ/SEMI/COMMA/COLON/EOF —— **两套前端此处不同形**。 + # v4 下两侧一律取「行边界 + EQ」⇒ 本步把 COMMA/COLON 从终止符集移除 + # (COMMA 仍是标签**分隔符**,见下方 advance;收进终止符集是过去的兜底)。 + while not self._at_line_end() and not self.check(TokenType.EQ): + tag = self.advance().lexeme + # 已知标签:mut / pub / apx(与自举编译器一致,未知标签报错) + if tag not in ('mut', 'pub', 'apx'): + self.error(f"unknown declaration tag '{tag}'") + tags.append(tag) if self.check(TokenType.COMMA): self.advance() else: @@ -165,6 +210,11 @@ def parse_compilation_unit(self) -> CompilationUnit: modules, imports = self._parse_module_and_imports() declarations = [] while not self.check(TokenType.EOF): + self._consume_newlines() + if self.check(TokenType.EOF): + break + if self.check(TokenType.DEDENT): + self.error("unexpected dedent at top level") declarations.append(self.parse_top_level_decl()) return CompilationUnit(modules, imports, declarations, fileid) @@ -172,7 +222,7 @@ def _parse_fileid(self): if self.check(TokenType.FILEID): self.advance() name = self.expect(TokenType.STRING_LIT).lexeme - self.expect(TokenType.SEMI) + self._end_decl() return name return None @@ -188,7 +238,7 @@ def _parse_module_and_imports(self): def parse_module_decl(self): self.expect(TokenType.MOD) path = self.parse_path() - self.expect(TokenType.SEMI) + self._end_decl() return ModuleDecl(path) def parse_import_decl(self): @@ -199,10 +249,11 @@ def parse_import_decl(self): project = self.expect(TokenType.IDENT).lexeme file_id = self.expect(TokenType.IDENT).lexeme alias = None - if self.check(TokenType.AS) or self.check(TokenType.COLON): + # D7(T0 布局规格 §2.2):`import math : m` 的别名 `:` 后**必有**后继 token ⇒ COLON_DECL + if self.check(TokenType.AS) or self.check(TokenType.COLON_DECL): self.advance() alias = self.expect(TokenType.IDENT).lexeme - self.expect(TokenType.SEMI) + self._end_decl() return ImportDecl([file_id], alias, project) def parse_path(self): @@ -256,8 +307,12 @@ def parse_function_decl(self, is_pub, is_flow=False): if self.check(TokenType.EQ): self.advance() body = self.parse_expr() - self.expect(TokenType.SEMI) + self._end_decl() return FunctionDecl(is_pub, name, generics, params, ret, body) + # D9/D10(T0 布局规格 §2.2):有体 ⇒ 行尾 `:`(COLON_BLOCK)开 region; + # 无体(`extern fn read(fd: int) -> int`)⇒ 行边界,无 `:`。 + if self._at_line_end(): + return FunctionDecl(is_pub, name, generics, params, ret, None) body = self.parse_block() if is_flow: body = Flow(body) @@ -297,7 +352,7 @@ def _parse_generics(self): self.expect(TokenType.COMMA) first = False names.append(self.expect(TokenType.IDENT).lexeme) - if self.check(TokenType.COLON): + if self.check(TokenType.COLON_DECL): self.advance() # : self.expect(TokenType.IDENT) # constraint name (skip) self.expect(TokenType.RBRACK) @@ -327,7 +382,7 @@ def _parse_param(self): if self.check(TokenType.SELF): name = self.advance().lexeme typ = None - if self.check(TokenType.COLON): + if self.check(TokenType.COLON_DECL): self.advance() typ = self.parse_type() return (name, typ) @@ -335,11 +390,11 @@ def _parse_param(self): if self.check(TokenType.DOT_DOT_DOT): self.advance() name = self.expect(TokenType.IDENT).lexeme - self.expect(TokenType.COLON) + self.expect(TokenType.COLON_DECL) typ = self.parse_type() return (name, typ) name = self.expect(TokenType.IDENT).lexeme - self.expect(TokenType.COLON) + self.expect(TokenType.COLON_DECL) typ = self.parse_type() return (name, typ) @@ -385,10 +440,21 @@ def parse_type(self): self.advance() return RefType(mut, self.parse_type()) # dex = 精确小数(数值迁移 Task 5:float 类型名已移除,与自举侧同步) - base_types = {'int','dex','bool','string','char','unit','never'} - if self.check(TokenType.SELF_TYPE): + # v4:`never` / `dyn` 从「词素比对」**提升为关键字**(计划 §一.5 注 1 / §7.1 项 8) + # ⇒ 必须在此显式收下,否则它们会掉进 `parse_path()` 的 `expect(IDENT)` 而响亮报错。 + # 语义与自源原生名表一致(`checker.cr:1186` 的 8 个基类型名含 never/dyn ⇒ TY_NEVER / TI_DYN)。 + if self.check(TokenType.NEVER): + self.advance() + return BaseType('never') + if self.check(TokenType.DYN): self.advance() - return BaseType('Self') + return BaseType('dyn') + # v4:`Self` 不再进关键字表(计划 §一.5 的 `bootstrap − v4` 差集含 `Self`) + # ⇒ 它以 IDENT 到达;保留「`&Self` 是原生名不是泛型形参」的既有行为 + # (先例:`never` 今天也走这条 base_types 路径)。**若漏掉本格**, + # `&Self` 会变成 `PathType(['Self'])`,而 type_checker 的 `_is_generic_type` + # 把「单元素 PathType」当泛型形参 ⇒ 静默错判(不是报错)。 + base_types = {'int','dex','bool','string','char','unit','never','Self'} if self.check(TokenType.IDENT) and self.cur().lexeme in base_types: return BaseType(self.advance().lexeme) if self.check(TokenType.UNIT): @@ -418,12 +484,8 @@ def parse_expr(self): return left def parse_assignment(self): - if self.check(TokenType.MOVE): - self.advance() - name = self.expect(TokenType.IDENT).lexeme - self.expect(TokenType.EQ) - val = self.parse_expr() - return Move(name, val) + # `move` 已退役(计划 §一.5:bootstrap − v4 差集含 `move`)⇒ 原 MOVE 分支删除。 + # v4 下 `move x = e` 会响亮报错(`move` 落 T_IDENT ⇒ 变成两条语句/未知名),不静默。 left = self.parse_logical_or() if self.check(TokenType.EQ): self.advance() @@ -578,7 +640,7 @@ def parse_primary(self) -> Expr: symbol = self.expect(TokenType.IDENT).lexeme return Ident(f"@{first}.{file_id}::{symbol}") return Builtin(first, []) - if self.check(TokenType.SOME) or self.check(TokenType.NONE) or self.check(TokenType.SELF): + if self.check(TokenType.NONE) or self.check(TokenType.SELF): return Ident(self.advance().lexeme) if self.check(TokenType.INT_LIT): return Literal(int(self.advance().lexeme), 'int') @@ -598,17 +660,18 @@ def parse_primary(self) -> Expr: self.advance(); return Literal(None, 'unit') if self.check(TokenType.IDENT): ident_name = self.advance().lexeme - if ident_name[0].isupper() and self.check(TokenType.LBRACE) and self._is_struct_lit(self.pos): + # v4(T0 布局规格 §4.5):块花括号不存在 ⇒ `Name {` 之后**必**是字面量, + # 原 `_is_struct_lit` 消解器整体退场(它靠「深度 1 的 `;`」判块)。 + if ident_name[0].isupper() and self.check(TokenType.LBRACE): self.advance() # consume { fields = [] while not self.check(TokenType.RBRACE): fname = self.expect(TokenType.IDENT).lexeme - if self.check(TokenType.EQ): - self.advance() - elif self.check(TokenType.COLON): - self.advance() - else: - self.expect(TokenType.EQ) + # §4.2 写死:分隔符必须是 `=`;未选定的 `:` 形**响亮拒绝**(码 P030)。 + # 修复前是**盲跳**(`elif check(COLON): advance()`)⇒ 两形同收 = 判据无鉴别力。 + if not self.check(TokenType.EQ): + self.error("struct literal field separator must be '=' [P030]") + self.advance() val = self.parse_expr() fields.append((fname, val)) if self.check(TokenType.COMMA): @@ -641,7 +704,9 @@ def parse_primary(self) -> Expr: self.expect(TokenType.RPAREN) return e if self.check(TokenType.LBRACE): - return self.parse_block() + # v4:`{ }` 只作结构体字面量定界符(`{` 的唯一合法位置,T0 布局规格 §4.3), + # 块结构由 `:` + 缩进取代 ⇒ 表达式位的裸 `{` 无产生式,响亮报错。 + self.error("'{' is only valid as a struct literal delimiter in v4 (blocks use ':' + indent)") if self.check(TokenType.IF): return self.parse_if_expr() if self.check(TokenType.MATCH): @@ -681,45 +746,20 @@ def parse_primary(self) -> Expr: self.advance(); return Unsafe(self.parse_block()) self.error(f"Unexpected token: {self.cur().lexeme}") - def _is_struct_lit(self, brace_pos): - """Check if at brace_pos we have a struct literal rather than a block. - - Scans for ';' inside the braces — a semicolon at depth 1 means block, - not struct literal. Also requires first field to start with IDENT =/:.""" - pos = brace_pos + 1 - if pos >= len(self.tokens): - return False - # Empty braces {} - if self.tokens[pos].type == TokenType.RBRACE: - return True - # Must start with IDENT = or IDENT : - if self.tokens[pos].type != TokenType.IDENT: - return False - if pos + 1 >= len(self.tokens): - return False - nxt = self.tokens[pos + 1].type - if nxt != TokenType.EQ and nxt != TokenType.COLON: - return False - # Scan for ; at depth 1 (top level), tracking all bracket types - depth = 1 - limit = min(brace_pos + 100, len(self.tokens)) - for i in range(brace_pos + 1, limit): - tt = self.tokens[i].type - if tt in (TokenType.LBRACE,): depth += 1 - elif tt in (TokenType.RBRACE,): depth -= 1 - elif tt in (TokenType.LBRACK, TokenType.LPAREN): depth += 1 - elif tt in (TokenType.RBRACK, TokenType.RPAREN): depth -= 1 - if depth == 0: - break - if tt == TokenType.SEMI and depth == 1: - return False # ; at top level -> block - return True - def parse_block(self) -> Block: - self.expect(TokenType.LBRACE) + """v4 region:吃 `INDENT` … `DEDENT`(取代原 `{` … `}`)。 + + 尾表达式判定(T0 布局规格 §6.2 A1):**region 的最后一项 = 该 region 的值**, + 其余各项按语句处理 —— 即原 `parse_block` 的「暂定尾表达式」逻辑原样保留, + 只是「还有下一项」的判据由「不是 `}`」变成「不是 DEDENT」。 + """ + self._expect_region() stmts = [] expr = None - while not self.check(TokenType.RBRACE) and not self.check(TokenType.EOF): + while True: + self._consume_newlines() + if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): + break item = self.parse_stmt() if isinstance(item, Stmt): if expr is not None: @@ -732,38 +772,34 @@ def parse_block(self) -> Block: if expr is not None: stmts.append(ExprStmt(expr)) expr = item - self.expect(TokenType.RBRACE) + self.expect(TokenType.DEDENT) return Block(stmts, expr) def parse_stmt(self): if self.check(TokenType.IDENT) and self._is_var_decl_start(): names, tags, typ, values = self._parse_var_decl_names_tags_type() - self.expect(TokenType.SEMI) + self._end_decl() return LetStmt(names=names, tags=tags, type_=typ, values=values) elif self.check(TokenType.RETURN): self.advance() val = None - if not self.check(TokenType.SEMI) and not self.check(TokenType.RBRACE): + # A6:关键字之后**同一逻辑行内**无 token ⇒ 无值(行边界取代 `;`/`}`) + if not self._at_line_end(): val = self.parse_expr() - if self.check(TokenType.SEMI): - self.advance() + self._consume_newlines() return ReturnStmt(val) elif self.check(TokenType.BREAK): self.advance() - if self.check(TokenType.SEMI): - self.advance() + self._consume_newlines() return BreakStmt() elif self.check(TokenType.CONTINUE): self.advance() - if self.check(TokenType.SEMI): - self.advance() + self._consume_newlines() return ContinueStmt() else: - e = self.parse_expr() - if self.check(TokenType.SEMI): - self.advance() - return ExprStmt(e) - return e + # A1:裸表达式**暂定**为 region 尾值;块循环在「后面还有一项」时再包成 ExprStmt。 + # v4 无 `;` ⇒ 不再有「显式语句」形态(原 `if check(SEMI): return ExprStmt(e)` 分支淘汰)。 + return self.parse_expr() def parse_if_expr(self): self.expect(TokenType.IF) @@ -781,18 +817,33 @@ def parse_if_expr(self): def parse_match_expr(self): self.expect(TokenType.MATCH) expr = self.parse_expr() - self.expect(TokenType.LBRACE) + self._expect_region() arms = [] - while not self.check(TokenType.RBRACE) and not self.check(TokenType.EOF): + while True: + self._consume_newlines() + if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): + break + # 臂前缀 `|`(v4 目标形,维护者原话 `/tmp/briefs/v4-syntax-raw.md:81,119-138`: + # `|` = alternative / pattern arm,且同组臂必须**列对齐**)。 + # **本侧接受「有 `|`」与「无 `|`」两形**,理由写实(不是偷懒): + # ① v3 语料的臂**没有** `|`(`tests/suite/apx_conversion_test.cr:89` + # 逐字 `match e { V(x) => …, None => … }`),而 T4 是**机械改写** + # (计划 §六.1:形状只有 `{}`→缩进、`;`→换行两类)⇒ 它**不会**补 `|` + # ⇒ 本批自己的产物必须仍可解析; + # ② v4 目标形有 `|` ⇒ 不收它就解析不了维护者原话里的 match 例。 + # ⚠ 二者**不是「两形都收」的静默歧义**:改前 `|` 在臂首是**解析错误**, + # 故本放宽**不改变任何既有可解析程序的含义**(纯增量)。 + # 「`|` 是否**强制**」留待 T5 决定(先例:struct 字面量分隔符守卫,T0 §4.2)。 + if self.check(TokenType.PIPE): + self.advance() pat = self.parse_pattern() self.expect(TokenType.FAT_ARROW) # 使用 => body = self.parse_expr() arms.append(MatchArm(pat, body)) if self.check(TokenType.COMMA): self.advance() - self.expect(TokenType.RBRACE) + self.expect(TokenType.DEDENT) return Match(expr, arms) - def parse_pattern(self) -> Pattern: if self.check(TokenType.UNDERSCORE) or self.cur().lexeme == '_': self.advance(); return Wildcard() @@ -810,8 +861,18 @@ def parse_pattern(self) -> Pattern: pats.append(self.parse_pattern()) self.expect(TokenType.RPAREN) return TuplePattern(pats) - # 标识符或关键字作为模式 - if self.check(TokenType.IDENT) or self.check(TokenType.SOME) or self.check(TokenType.NONE): + # v4 的 `none`(小写,v4 关键字)与既有 canonical 变体名 `None` 指**同一个**变体。 + # ⚠ canonical 名此处仍写 `None`:改它 = 全局重命名,属 **T5** 的 `None`→`none` 语义面 + # (计划 §2.3 R3 逐字「`none` ↔ `None` … 是语义面,见 T1/T5」), + # 与 T4 的机械形状改写不同批。`EnumPattern` 的 path[-1] 会被 desugar 直接当 + # `__variant` 的**标签串**比较(`desugar.py:86-92`)⇒ 必须与枚举声明的变体名一致。 + # **漏掉本格** ⇒ 小写 `none` 会掉进下方的 IdentPattern(那是**变量绑定**,不是匹配) + # ⇒ 语义静默改变(模式永远命中)——正是要防的形态。 + if self.check(TokenType.NONE): + self.advance() + return EnumPattern(['None'], None) + # 标识符或关键字作为模式(v4:`Some` 已是普通 IDENT,走下行) + if self.check(TokenType.IDENT): name = self.advance().lexeme path = [name] if self.check(TokenType.LPAREN): @@ -871,25 +932,29 @@ def parse_struct_decl(self, is_pub): self.expect(TokenType.STRUCT) name = self.expect(TokenType.IDENT).lexeme generics = self._parse_generics() - self.expect(TokenType.LBRACE) + self._expect_region() fields = [] - while not self.check(TokenType.RBRACE): + while True: + self._consume_newlines() + if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): + break fname = None if self.check(TokenType.IDENT): fname = self.advance().lexeme elif self.cur().type in (TokenType.TYPE, TokenType.MUT, TokenType.PUB, TokenType.MOD, TokenType.STRUCT, TokenType.ENUM, - TokenType.IMPL, TokenType.SELF, TokenType.SELF_TYPE, + TokenType.IMPL, TokenType.SELF, TokenType.MATCH, TokenType.FOR, TokenType.LOOP, TokenType.WHILE, TokenType.IF, TokenType.ELSE, TokenType.RETURN, TokenType.BREAK, TokenType.CONTINUE, - TokenType.GO, TokenType.AWAIT, TokenType.MOVE, + TokenType.GO, TokenType.AWAIT, TokenType.TRUE, TokenType.FALSE, TokenType.UNIT, TokenType.AUTO, TokenType.INTERFACE, TokenType.AS): fname = self.advance().lexeme # keyword as field name else: fname = self.expect(TokenType.IDENT).lexeme - self.expect(TokenType.COLON) + # D4(T0 布局规格 §2.2):字段形 `id: int` 的 `:` 后必有类型 ⇒ COLON_DECL + self.expect(TokenType.COLON_DECL) ftype = self.parse_type() # field tags: consume optional tags like `, mut`, `, pub` after type while self.check(TokenType.COMMA) and self.peek().type in (TokenType.MUT, TokenType.PUB): @@ -898,18 +963,22 @@ def parse_struct_decl(self, is_pub): fields.append((fname, ftype)) if self.check(TokenType.COMMA): self.advance() - self.expect(TokenType.RBRACE) + self.expect(TokenType.DEDENT) return StructDecl(is_pub, name, generics, fields) def parse_enum_decl(self, is_pub): self.expect(TokenType.ENUM) name = self.expect(TokenType.IDENT).lexeme generics = self._parse_generics() - self.expect(TokenType.LBRACE) + self._expect_region() variants = [] - while not self.check(TokenType.RBRACE): - vname = None - if self.check(TokenType.SOME) or self.check(TokenType.NONE): + while True: + self._consume_newlines() + if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): + break + # `None` ⇒ `none` 是关键字 ⇒ 变体名仍收 NONE(保留今日「以 None 为变体名」的接受面); + # `Some` 已退休成 IDENT ⇒ 走 expect(IDENT)。 + if self.check(TokenType.NONE): vname = self.advance().lexeme else: vname = self.expect(TokenType.IDENT).lexeme @@ -925,16 +994,19 @@ def parse_enum_decl(self, is_pub): variants.append((vname, types)) if self.check(TokenType.COMMA): self.advance() - self.expect(TokenType.RBRACE) + self.expect(TokenType.DEDENT) return EnumDecl(is_pub, name, generics, variants) def parse_interface_decl(self, is_pub): self.expect(TokenType.INTERFACE) name = self.expect(TokenType.IDENT).lexeme generics = self._parse_generics() - self.expect(TokenType.LBRACE) + self._expect_region() methods = [] - while not self.check(TokenType.RBRACE): + while True: + self._consume_newlines() + if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): + break self.expect(TokenType.FN) mname = self.expect(TokenType.IDENT).lexeme self.expect(TokenType.LPAREN) @@ -942,9 +1014,12 @@ def parse_interface_decl(self, is_pub): self.expect(TokenType.RPAREN) self.expect(TokenType.ARROW) ret = self.parse_type() - self.expect(TokenType.SEMI) + # D11(T0 布局规格 §2.2):接口方法**无 `:`** ⇒ 行边界收尾。 + # ⚠ 带默认体的接口方法**本批不支持**:它要在 `InterfaceDecl.methods` 的 + # 三元组里加一个 body 槽 ⇒ 动 `ast.py` ⇒ 违 J-T1-1 冻结。此处**响亮报错**(不静默吞体)。 + self._end_decl() methods.append((mname, params, ret)) - self.expect(TokenType.RBRACE) + self.expect(TokenType.DEDENT) return InterfaceDecl(is_pub, name, generics, methods) def parse_impl_decl(self): @@ -956,11 +1031,14 @@ def parse_impl_decl(self): self.advance() trait = for_type for_type = self.parse_path() - self.expect(TokenType.LBRACE) + self._expect_region() methods = [] - while not self.check(TokenType.RBRACE): + while True: + self._consume_newlines() + if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): + break methods.append(self.parse_function_decl(False)) - self.expect(TokenType.RBRACE) + self.expect(TokenType.DEDENT) return ImplDecl(generics, trait, for_type, methods) def parse_type_alias(self): @@ -968,11 +1046,11 @@ def parse_type_alias(self): name = self.expect(TokenType.IDENT).lexeme self.expect(TokenType.EQ) typ = self.parse_type() - self.expect(TokenType.SEMI) + self._end_decl() return TypeAliasDecl(name, typ) def _parse_new_let_decl(self): from corec.syntax.ast import LetDecl names, tags, typ, values = self._parse_var_decl_names_tags_type() - self.expect(TokenType.SEMI) + self._end_decl() return LetDecl(names=names, tags=tags, type_=typ, values=values) diff --git a/bootstrap/corec/frontend/type_checker.py b/bootstrap/corec/frontend/type_checker.py index acb4399a..5a734ba6 100644 --- a/bootstrap/corec/frontend/type_checker.py +++ b/bootstrap/corec/frontend/type_checker.py @@ -130,6 +130,12 @@ def _declare_builtins(self): opt = EnumDecl(True, 'Option', ['T'], [('Some', [PathType(['T'])]), ('None', [])]) self._declare_enum(opt) + # ⚠ v4 的 `none` 拼写**不在此注册**(曾经试过,已撤):本函数的符号表注册 + # **不可达** —— 裸 `none` 在表达式位会先被 `NameResolver` 以 `Undefined name` 拦下 + # (`name_resolver.py:98`,其内建表里没有 none/None)。半接线 = 「看着支持、其实永不生效」 + # 的空壳,比不接线更坏。⇒ 拼写面(`None`→`none`)是 **T5** 的重命名面; + # 今日现状(改前改后一致):裸 `none`/`None` 作**值**未实现,**响亮失败**。 + # 语料影响 = 0:`src/**` 的 74 处 `None` 全在注释/字符串里,无代码面裸 None。 if not self.symtab.lookup('Result'): res = EnumDecl(True, 'Result', ['T', 'E'], [('Ok', [PathType(['T'])]), ('Err', [PathType(['E'])])]) diff --git a/bootstrap/corec/syntax/tokens.py b/bootstrap/corec/syntax/tokens.py index fb07398d..5a0b0b5b 100644 --- a/bootstrap/corec/syntax/tokens.py +++ b/bootstrap/corec/syntax/tokens.py @@ -21,7 +21,6 @@ class TokenType(Enum): IMPL = auto() TYPE = auto() MUT = auto() - MOVE = auto() GO = auto() AWAIT = auto() FLOW = auto() @@ -43,16 +42,19 @@ class TokenType(Enum): AS = auto() AUTO = auto() UNSAFE = auto() - REQUIRES = auto() - ENSURES = auto() - RESULT = auto() SELF = auto() - SELF_TYPE = auto() TRUE = auto() FALSE = auto() UNIT = auto() + # v4 新增关键字(目标集 39;出处 = 施工计划 §一.5 的三表差集)。 + # `none` 复用 NONE(v4 是小写 `none`;`None`/`Some` 已退役为普通标识符—— + # `Some(x)` 仍可解,走 `parse_call_or_field` 的「首字母大写 ⇒ EnumConstructor」分支)。 NONE = auto() - SOME = auto() + NEVER = auto() + DYN = auto() + CATCH = auto() + FAIL = auto() + SPEC = auto() EXTERN = auto() # 符号 @@ -80,7 +82,14 @@ class TokenType(Enum): DOT_DOT_DOT = auto() COMMA = auto() SEMI = auto() - COLON = auto() + # v4 裁定 ②(词法位置决定,T0 布局规格 §2.1):原单个 COLON 由此二者取代, + # **互斥且穷尽** ⇒ parser 侧零前瞻。 + # `:` 之后到该物理行行尾**无任何 token**(空白与注释不计,§2.3)⇒ COLON_BLOCK(region 开启) + # 否则 ⇒ COLON_DECL(类型标注 / import 别名 / 字段 / 形参分隔符) + # ⚠ 行尾类型标注**不是合法文本**:lexer 必发 COLON_BLOCK,而该位置不是合法 region 头 + # ⇒ parser 必须响亮拒绝(§2.2),不得静默改判成声明。 + COLON_DECL = auto() + COLON_BLOCK = auto() COLON_EQ = auto() LPAREN = auto() RPAREN = auto() @@ -97,8 +106,27 @@ class TokenType(Enum): # **不**实现 VC/三态(完整 bootstrap 规约面登记后续)。对应 self-hosted 的 `T_HASH = 101`。 HASH = auto() + # v4 布局(layout)token —— 施工计划 §四.1 项 2;逐条判定出处 = T0 布局规格 §1/§2。 + # NEWLINE:一个「有 token 的逻辑行」结束时发出(纯空行/纯注释行**不发**,§1.1 ①-1/①-2)。 + # INDENT :换行后首个 token 的列**深于**缩进栈顶 ⇒ 压栈并发出。 + # DEDENT :更浅 ⇒ 逐层弹出并各发一个;不匹配任何外层列 ⇒ **响亮报错**(不静默对齐)。 + # 括号 `( ) [ ] { }` 内不参与布局(隐式续行;`{ }` 是字面量定界符,规格 §4.1)。 + NEWLINE = auto() + INDENT = auto() + DEDENT = auto() + EOF = auto() +# v4 关键字表 —— **目标集 39**(施工计划 §四.1 项 1)。 +# 出处 = 计划 §一.5 的三表机械差集(脚本算,非目测),逐条: +# 去(bootstrap − v4,7):`None` `Self` `Some` `ensures` `move` `requires` `result` +# 加(v4 − bootstrap,6):`catch` `dyn` `fail` `never` `none` `spec` +# ⚠ 本表必须与自源 `src/compiler/lexer.cr` 的 `lookup_keyword` **逐元素相同** +# (判据 J-T1-2)。自源侧 36 → 39 属 **T5**,本步(T1/T2)只改本侧 +# ⇒ **现阶段两侧预期仍不一致**,差集 = 本侧独有 6(`catch` `dyn` `fail` `never` `none` `spec`) +# + 自源独有 3(`None` `Some` `move`);T5 落地后应双双为空。 +# **不得把这条预期红说成绿** —— 实报走 `python3 tools/v4_frontend_probe.py keywords`。 +# 计数:40 − 7 + 6 = 39。 KEYWORDS = { "fn": TokenType.FN, "struct": TokenType.STRUCT, @@ -107,7 +135,6 @@ class TokenType(Enum): "impl": TokenType.IMPL, "type": TokenType.TYPE, "mut": TokenType.MUT, - "move": TokenType.MOVE, "go": TokenType.GO, "await": TokenType.AWAIT, "flow": TokenType.FLOW, @@ -128,18 +155,18 @@ class TokenType(Enum): "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, + "none": TokenType.NONE, + "never": TokenType.NEVER, + "dyn": TokenType.DYN, + "catch": TokenType.CATCH, + "fail": TokenType.FAIL, + "spec": TokenType.SPEC, } @dataclass diff --git a/build_selfhost_native.py b/build_selfhost_native.py index 723d545b..3ebaebd1 100644 --- a/build_selfhost_native.py +++ b/build_selfhost_native.py @@ -154,7 +154,9 @@ def concat(files, wrapper_fn=None): parts.append(f"// === {f} ===\n{content}") src = '\n\n'.join(parts) if wrapper_fn: - src += f'\n\nfn main() -> int {{ return {wrapper_fn}(); }}\n' + # v4(T3):wrapper 必须用目标语法形——`: ` + layout region,不用花括号。 + # 这行是承重面:不改它,T1/T2 翻到 v4 后整个自举链在第一步就断。 + src += f'\n\nfn main() -> int:\n return {wrapper_fn}()\n' return src diff --git a/docs/README.md b/docs/README.md index 99e61d0e..9bd20d2a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,53 +1,53 @@ # Core 文档中心 -> 定位:受众 = 所有读者(入口);状态 = active。 -> 分类规则:一级 = **受众**(developer/maintainer/academic),二级 = 主题;每份文档头部有定位声明(受众/状态/出处)。 +> 定位:受众 = 所有读者(入口);状态 = active。 +> 分类规则:一级 = **受众**(developer/maintainer/academic),二级 = 主题;每份文档头部有定位声明(受众/状态/出处)。 > 一份文档一个职责。 -> **判据层级(计划优先,代码兜底)**:设计定稿与计划(specs/plans)优先于代码——实现未跟上设计时文档保持定稿、标注"设计态/按计划推进";仅在计划未覆盖的细节(记号/关键字等实现层细节)以源码为准。 -> **演进义务**:语言或实现变化时,相关文档头部状态与正文随之更新(active 变 superseded、设计态转已实现等);开发者文档随语言演进迭代。 +> **判据层级(计划优先,代码兜底)**:设计定稿与计划(specs/plans)优先于代码——实现未跟上设计时文档保持定稿、标注"设计态/按计划推进";仅在计划未覆盖的细节(记号/关键字等实现层细节)以源码为准。 +> **演进义务**:语言或实现变化时,相关文档头部状态与正文随之更新(active 变 superseded、设计态转已实现等);开发者文档随语言演进迭代。 -## 开发者(developer/)——用 Core 写程序 +## 开发者(developer/)——用 Core 写程序 -- [quickstart.md](developer/quickstart.md)— 快速开始(构建/第一个程序) -- [tutorial.md](developer/tutorial.md)— 渐进学习路径 -- [concepts.md](developer/concepts.md)— 核心概念导览(分篇:[graph](developer/concepts/graph.md)/[memory](developer/concepts/memory.md)/[deploy](developer/concepts/deploy.md)/[spec](developer/concepts/spec.md)) -- [syntax.md](developer/syntax.md)— 语言语法参考 -- [examples.md](developer/examples.md)— 示例集 -- [faq.md](developer/faq.md)— 常见问题 -- [errors.md](developer/errors.md)— 错误码参考 -- [editors.md](developer/editors.md)— 编辑器与 LSP 配置 -- [at-intrinsics.md](developer/at-intrinsics.md)— @ 内建原语 +- [quickstart.md](developer/quickstart.md) — 快速开始(构建/第一个程序) +- [tutorial.md](developer/tutorial.md) — 渐进学习路径 +- [concepts.md](developer/concepts.md) — 核心概念导览(分篇:[graph](developer/concepts/graph.md)/[memory](developer/concepts/memory.md)/[deploy](developer/concepts/deploy.md)/[spec](developer/concepts/spec.md)) +- [syntax.md](developer/syntax.md) — 语言语法参考 +- [examples.md](developer/examples.md) — 示例集 +- [faq.md](developer/faq.md) — 常见问题 +- [errors.md](developer/errors.md) — 错误码参考 +- [editors.md](developer/editors.md) — 编辑器与 LSP 配置 +- [at-intrinsics.md](developer/at-intrinsics.md) — @ 内建原语 -## 维护者(maintainer/)——改编译器 +## 维护者(maintainer/)——改编译器 -**上手**:[onboarding.md](maintainer/onboarding.md)(先读)→ [testing.md](maintainer/testing.md)(回归操作) +**上手**:[onboarding.md](maintainer/onboarding.md)(先读)→ [testing.md](maintainer/testing.md)(回归操作) -**设计参考**(maintainer/design/): -- 执行模型 / 图与 region:[execution-model.md](maintainer/design/execution-model.md)、[dataflow-design.md](maintainer/design/dataflow-design.md)(早期稿,已被取代,留档) -- 存储语义:[materialization-space.md](maintainer/design/materialization-space.md)(**层定义 = 存在格 / Materialization Space**)、[memory-model.md](maintainer/design/memory-model.md)(总览)、[cache-semantics.md](academic/cache-semantics.md)(条款 1–7 以该文为准;缓存映射一类,该层的一个实例)、[existence-structure.md](maintainer/design/existence-structure.md)(v6 承载)、[region-model.md](maintainer/design/region-model.md)(经典映射) -- 指针与验证 pass:[pointer-model.md](maintainer/design/pointer-model.md)、[regalloc-cache-mapping.md](maintainer/design/regalloc-cache-mapping.md) -- 规约系统:[spec-design.md](maintainer/design/spec-design.md);IR 操作语义:[ir-op-semantics.md](maintainer/design/ir-op-semantics.md);corelsp:[corelsp.md](maintainer/design/corelsp.md);已废弃:[crasm.md](maintainer/design/crasm.md) +**设计参考**(maintainer/design/): +- 执行模型 / 图与 region:[execution-model.md](maintainer/design/execution-model.md)、[dataflow-design.md](maintainer/design/dataflow-design.md)(早期稿,已被取代,留档) +- 存储语义:[materialization-space.md](maintainer/design/materialization-space.md)(**层定义 = 存在格 / Materialization Space**)、[memory-model.md](maintainer/design/memory-model.md)(总览)、[cache-semantics.md](academic/cache-semantics.md)(条款 1–7 以该文为准;缓存映射一类,该层的一个实例)、[existence-structure.md](maintainer/design/existence-structure.md)(v6 承载)、[region-model.md](maintainer/design/region-model.md)(经典映射) +- 指针与验证 pass:[pointer-model.md](maintainer/design/pointer-model.md)、[regalloc-cache-mapping.md](maintainer/design/regalloc-cache-mapping.md) +- 规约系统:[spec-design.md](maintainer/design/spec-design.md);IR 操作语义:[ir-op-semantics.md](maintainer/design/ir-op-semantics.md);corelsp:[corelsp.md](maintainer/design/corelsp.md);已废弃:[crasm.md](maintainer/design/crasm.md) -**决策记录**:[adr/](maintainer/adr/README.md)— ADR-0001 起 +**决策记录**:[adr/](maintainer/adr/README.md) — ADR-0001 起 -**特性提案**(maintainer/proposals/):generics/concurrency/dynamic-typing/comptime/ffi/lazy/distributed/probabilistic(状态见各文件头注) +**特性提案**(maintainer/proposals/):generics/concurrency/dynamic-typing/comptime/ffi/lazy/distributed/probabilistic(状态见各文件头注) -## 学术(academic/)——验证/理论读者 +## 学术(academic/)——验证/理论读者 -- [cache-semantics.md](academic/cache-semantics.md)— 条款 1–7(以该文为准;**缓存映射一类**;层本体 = 存在格,见 [maintainer/design/materialization-space.md](maintainer/design/materialization-space.md)) -- [lattice-theory.md](academic/lattice-theory.md)— 三层映射理论定稿(图 → 格 → 编码) -- [verifier-kernel.md](academic/verifier-kernel.md)— 验证内核选型(CIC 信任根) +- [cache-semantics.md](academic/cache-semantics.md) — 条款 1–7(以该文为准;**缓存映射一类**;层本体 = 存在格,见 [maintainer/design/materialization-space.md](maintainer/design/materialization-space.md)) +- [lattice-theory.md](academic/lattice-theory.md) — 三层映射理论定稿(图 → 格 → 编码) +- [verifier-kernel.md](academic/verifier-kernel.md) — 验证内核选型(CIC 信任根) ## 顶层 -- [project-book.md](project-book.md)— 项目定位导航 -- [glossary.md](glossary.md)— 架构术语表(跨受众) -- [z-vision.md](z-vision.md)— 愿景 +- [project-book.md](project-book.md) — 项目定位导航 +- [glossary.md](glossary.md) — 架构术语表(跨受众) +- [z-vision.md](z-vision.md) — 愿景 -## 档案与工具链目录(不参与受众分类) +## 档案与工具链目录(不参与受众分类) -- archive/(任务产物):[compcert-reference.md](archive/compcert-reference.md)、[compcert-round4-findings.md](archive/compcert-round4-findings.md)、[numeric-migration-inventory.md](archive/numeric-migration-inventory.md)、[memory-model-capability-lattice.md](archive/memory-model-capability-lattice.md) -- [pseudocode/](pseudocode/README.md)(TDD 交付物)、[superpowers/](superpowers/)(specs + plans 工作目录;2026-09-16 新增:[compile-time-theorems](superpowers/specs/2026-09-16-compile-time-theorems.md)、[verification-slice](superpowers/plans/2026-09-16-verification-slice.md)、[preexisting-bug-ledger](superpowers/specs/2026-09-16-preexisting-bug-ledger.md)) +- archive/(任务产物):[compcert-reference.md](archive/compcert-reference.md)、[compcert-round4-findings.md](archive/compcert-round4-findings.md)、[numeric-migration-inventory.md](archive/numeric-migration-inventory.md)、[memory-model-capability-lattice.md](archive/memory-model-capability-lattice.md) +- [pseudocode/](pseudocode/README.md)(TDD 交付物)、[superpowers/](superpowers/)(specs + plans 工作目录;2026-09-16 新增:[compile-time-theorems](superpowers/specs/2026-09-16-compile-time-theorems.md)、[verification-slice](superpowers/plans/2026-09-16-verification-slice.md)、[preexisting-bug-ledger](superpowers/specs/2026-09-16-preexisting-bug-ledger.md)) - **文档 vs 现实审计(2026-09-16)**:[specs/2026-09-16-doc-reality-audit.md](superpowers/specs/2026-09-16-doc-reality-audit.md)——「声称了但不成立」的文档断言全表(35 条:危险 7/陈旧 6/成立 20/无法判定 2)+ 逐条**修订去向**;**改文档或照文档设计前先查此表** -- [ir-schema/](ir-schema/):[coreir-schema.md](ir-schema/coreir-schema.md)、[corespecir-schema.md](ir-schema/corespecir-schema.md) -- [verifier/](verifier/):[kernel-spec.md](verifier/kernel-spec.md);[coq/](coq/README.md):Coq 验证 stdlib 纯函数 +- [ir-schema/](ir-schema/):[coreir-schema.md](ir-schema/coreir-schema.md)、[corespecir-schema.md](ir-schema/corespecir-schema.md) +- [verifier/](verifier/):[kernel-spec.md](verifier/kernel-spec.md);[coq/](coq/README.md):Coq 验证 stdlib 纯函数 diff --git a/docs/academic/cache-semantics.md b/docs/academic/cache-semantics.md index 6bc6486b..a61fe3ed 100644 --- a/docs/academic/cache-semantics.md +++ b/docs/academic/cache-semantics.md @@ -1,114 +1,115 @@ -# 存储语义条款 1–7(权威条款;缓存映射一类) +# 存储语义条款 1–7(权威条款;缓存映射一类) -> 定位:受众 = 学术(条款消费方:验证器实现者/维护者);状态 = active。 -> 本文件是 Core 存储语义**条款 1–7 的权威**——七条为定义性条款,将来供验证器(翻译桥/CIC 内核)消费;实现与文档冲突时以本文档为准(设计文档优先于代码)。 -> 设计依据:2026-08-15-cache-semantics-design;v4 晋升与归档讨论见 docs/archive/memory-model-capability-lattice.md。 -> **2026-09-20 层定义修订(ADR-0021)**:本文件的**条款内容不变**;变的是它们的位置—— -> 格层本体 = **存在格 / Materialization Space**(层定义 = docs/maintainer/design/materialization-space.md), -> **缓存语义是该层最直接的一类映射实例,不是本体的名字**。「缓存」一词原先偷带的 -> 复制/驱逐/backing-store 假设并非对全部合法物化成立(MMIO、线性资源、事务态反例见该文件 §三)。 -> 分层位置:三层映射链(图 → 格 → 编码)的「格」层规则;存在结构载体(IR 编码)见 docs/maintainer/design/existence-structure.md;经典映射(区域/字节)见 docs/maintainer/design/region-model.md;总览导航见 docs/maintainer/design/memory-model.md。 +> 定位:受众 = 学术(条款消费方:验证器实现者/维护者);状态 = active。 +> 本文件是 Core 存储语义**条款 1–7 的权威**——七条为定义性条款,将来供验证器(翻译桥/CIC 内核)消费;实现与文档冲突时以本文档为准(设计文档优先于代码)。 +> 设计依据:2026-08-15-cache-semantics-design;v4 晋升与归档讨论见 `docs/archive/memory-model-capability-lattice.md`。 +> **2026-09-20 层定义修订(ADR-0021)**:本文件的**条款内容不变**;变的是它们的位置—— +> 格层本体 = **存在格 / Materialization Space**(层定义 = `docs/maintainer/design/materialization-space.md`), +> **缓存语义是该层最直接的一类映射实例,不是本体的名字**。「缓存」一词原先偷带的 +> 复制/驱逐/backing-store 假设并非对全部合法物化成立(MMIO、线性资源、事务态反例见该文件 §三)。 +> 分层位置:三层映射链(图 → 格 → 编码)的「格」层规则;存在结构载体(IR 编码)见 `docs/maintainer/design/existence-structure.md`;经典映射(区域/字节)见 `docs/maintainer/design/region-model.md`;总览导航见 `docs/maintainer/design/memory-model.md`。 --- ## 零、为什么是缓存——以及它是哪一类 -Core 的存储语义本体是**存在格(Materialization / Existence Space)**——范式无关的存储抽象,不是字节内存,也不是寄存器。它回答:哪些 materialization 合法、哪些可以共存、哪些代表同一 Entry/version、哪些转换保持语义(四问主套见 materialization-space.md §2.1;维护者原话另有**同义表述**「如何'存在'、在哪里存在、哪些存在形式可同时成立、哪些可被替换或重新构造」——其中「在哪里存在」= `location` 字段,是否入格层**待裁**,见该档 §九-C)。 +Core 的存储语义本体是**存在格(Materialization / Existence Space)**——范式无关的存储抽象,不是字节内存,也不是寄存器。它回答:哪些 materialization 合法、哪些可以共存、哪些代表同一 Entry/version、哪些转换保持语义(四问主套见 `materialization-space.md` §2.1;维护者原话另有**同义表述**「如何'存在'、在哪里存在、哪些存在形式可同时成立、哪些可被替换或重新构造」——其中「在哪里存在」= `location` 字段,是否入格层**待裁**,见该档 §九-C)。 -**缓存是这个层里最直接的一类映射实例,不是这个层的名字:** +**缓存是这个层里最直接的一类映射实例,不是这个层的名字:** -- 传统编译器的内存模型从机器出发(字节寻址 + 权限),范式绑死 -- 缓存映射从"值如何产生与保留"出发:值 = 配方(可重算),存储 = 配方结果的保留(可驱逐) -- 机器内存、寄存器、VRAM 都是缓存映射的实例;量子存储、持久映射是其他实例——范式映射表由此成立 +- 传统编译器的内存模型从机器出发(字节寻址 + 权限),范式绑死。 +- 缓存映射从"值如何产生与保留"出发:值 = 配方(可重算),存储 = 配方结果的保留(可驱逐)。 +- 机器内存、寄存器、VRAM 都是缓存映射的实例;量子存储、持久映射是其他实例——范式映射表由此成立。 -**边界(2026-09-20 修订补)**:缓存一词偷带的假设——有一个权威值、可以复制、可以驱逐、可以重新物化、存在 backing store、不同副本表示同一值——**只对 可再生且可复制 的那一类成立**。MMIO 读、随机数、一次性 token、线性资源、事务临时状态、分布式唯一 authority 落在同一层内但**不满足这些假设**(逐条卡点见 materialization-space.md §三),因此不能用「缓存」给整个层命名。 +**边界(2026-09-20 修订补)**:缓存一词偷带的假设——有一个权威值、可以复制、可以驱逐、可以重新物化、存在 backing store、不同副本表示同一值——**只对 可再生且可复制 的那一类成立**。MMIO 读、随机数、一次性 token、线性资源、事务临时状态、分布式唯一 authority 落在同一层内但**不满足这些假设**(逐条卡点见 `materialization-space.md` §三),因此不能用「缓存」给整个层命名。 -实现从来就是这张存在格(HDFG):节点 = 配方(值的产生方式),边 = 值流,state edges = 顺序约束,驱逐/再生 = 丢令牌/重跑节点。此前的文档层错误是把 CompCert v2 字节模型当语义本体——已纠偏(2026-08-15,零代码改动)。 +实现从来就是这张存在格(HDFG):节点 = 配方(值的产生方式),边 = 值流,state edges = 顺序约束,驱逐/再生 = 丢令牌/重跑节点。此前的文档层错误是把 CompCert v2 字节模型当语义本体——已纠偏(2026-08-15,零代码改动)。 --- -## 一、七条条款(权威) +## 一、七条条款(权威) -> 这七条是**存在格这一层**的规则,不是「缓存这一类」的私产——缓存映射是最直接实现它们的一类实例 -> (见 §零)。条款 1–7 的**层定义上下文**(四问/七字段/归类表/划界)见 docs/maintainer/design/materialization-space.md。 +> 这七条是**存在格这一层**的规则,不是「缓存这一类」的私产——缓存映射是最直接实现它们的一类实例 +> (见 §零)。条款 1–7 的**层定义上下文**(四问/七字段/归类表/划界)见 `docs/maintainer/design/materialization-space.md`。 1. **值 = 配方**。条目的语义 = (产生它的图节点, 输入边)。不存在独立于配方的"存储事实"。 -2. **驱逐不变量**。**对可再生条目**(recipe = recomputable)驱逐图内任意条目(丢弃存储物、保留配方)不改变可观测语义——只影响性能,不影响正确性。形式化目标:⟦G ∖ storage(e)⟧ = ⟦G⟧。这是**缓存映射这一类**的定义性质;层的一般判据见 2′。 -3. **再生等价**。重跑配方节点产生的值与原条目可观测等价。这是条款 2 的机制保证,也是"任何范式都能换映射"的语义依据。 -4. **边界公理**。图边界输入(MMIO/FFI/输入/测量)是无配方条目(边界类),语义上是符号常量。语法层叫 `unsafe`(边界标注),语义层只叫"边界"。边界之外才需要 state,边界之内全是可重算的。 -4b. **图内不可重算(v4 并入,M4 输入)**。执行标注空间(神谕 / BSS 实数 / FIXPT 声明 / 模糊融合,见 docs/maintainer/design/dataflow-design.md §8)存在**图内**无配方条目——非边界、不可重算。驱逐不变量/再生等价对其不成立(重跑神谕 ≠ 原结果):其存储必须持久(home 保有材料),驱逐必须写回;身份 = 产生节点(图节点身份)。边界条目与图内不可重算条目统一为「无配方条目」规则,一视同仁、不按范式枚举。 -5. **赋值 = 版本化**。`x = x + 1` 在语义上 = "x₁ 创建、x₀ 失效、绑定移动",不是修改内存单元。顺序约束由 state edges 表达。"可变"不是内存单元的属性,是绑定可移动的许可。 -6. **地址 = 映射**。`&x` = (条目标识, 偏移),字节地址只是经典投影,不是语义对象。指针算术合法性由条目标识 + 偏移域验证(现有 provenance 三 pass 保留不动)。 -7. **映射实例正确性**。区域/arena/字节权限(CompCert v2)是经典映射实例,其正确性标准 = 保持条款 1–6 的可观测语义。 +2. **驱逐不变量**。**对可再生条目**(`recipe = recomputable`)驱逐图内任意条目(丢弃存储物、保留配方)不改变可观测语义——只影响性能,不影响正确性。形式化目标:⟦G ∖ storage(e)⟧ = ⟦G⟧。这是**缓存映射这一类**的定义性质;层的一般判据见 2′。 +3. **再生等价**。重跑配方节点产生的值与原条目可观测等价。这是条款 2 的机制保证,也是"任何范式都能换映射"的语义依据。 +4. **边界公理**。图边界输入(MMIO/FFI/输入/测量)是无配方条目(边界类),语义上是符号常量。语法层叫 `unsafe`(边界标注),语义层只叫"边界"。边界之外才需要 state,边界之内全是可重算的。 +4b. **图内不可重算(v4 并入,M4 输入)**。执行标注空间(神谕 / BSS 实数 / FIXPT 声明 / 模糊融合,见 `docs/maintainer/design/dataflow-design.md` §8)存在**图内**无配方条目——非边界、不可重算。驱逐不变量/再生等价对其不成立(重跑神谕 ≠ 原结果):其存储必须持久(home 保有材料),驱逐必须写回;身份 = 产生节点(图节点身份)。边界条目与图内不可重算条目统一为「无配方条目」规则,一视同仁、不按范式枚举。 +5. **赋值 = 版本化**。`x = x + 1` 在语义上 = "x₁ 创建、x₀ 失效、绑定移动",不是修改内存单元。顺序约束由 state edges 表达。"可变"不是内存单元的属性,是绑定可移动的许可。 +6. **地址 = 映射**。`&x` = (条目标识, 偏移),字节地址只是经典投影,不是语义对象。指针算术合法性由条目标识 + 偏移域验证(现有 provenance 三 pass 保留不动)。 +7. **映射实例正确性**。区域/arena/字节权限(CompCert v2)是经典映射实例,其正确性标准 = 保持条款 1–6 的可观测语义。 -**2′. 驱逐的完整判据(2026-09-20 补;把条款 4b 从「例外」并入同一条判据)** +**2′. 驱逐的完整判据(2026-09-20 补;把条款 4b 从「例外」并入同一条判据)** -> 📌 **本式为主副本(2026-09-20 定)**。另四处引用——`adr-0021:31` · `materialization-space.md §4.2/§4.5` · -> `regalloc-cache-mapping.md §三.1` · `glossary.md:46`——**均以本处为准**; -> 改式先改本处,其余各处仅作引用,不另立措辞。 +> 📌 **本式为主副本(2026-09-20 定)**。另四处引用——`adr-0021:31` · `materialization-space.md §4.2/§4.5` · +> `regalloc-cache-mapping.md §三.1` · `glossary.md:46`——**均以本处为准**; +> 改式先改本处,其余各处仅作引用,不另立措辞。 ``` Evictable(x) ⟺ Recoverable(x) ∨ PreserveRequiredState(x) ``` -一个 materialization 可以消失,当且仅当:**之后能重新得到等价状态**(Recoverable);**或者消失前已把必须保留的状态转移到其他合法 materialization**(PreserveRequiredState)。 +一个 materialization 可以消失,当且仅当:**之后能重新得到等价状态**(Recoverable);**或者消失前已把必须保留的状态转移到其他合法 materialization**(PreserveRequiredState)。 -条款 2 是 x 落在 Recoverable 侧时的情形;条款 4/4b 是 x 落在 PreserveRequiredState 侧时的情形——**二者本是同一条判据的两支**,此前写成「规则 + 例外」,现并为一条。两点必须同时遵守: +条款 2 是 x 落在 Recoverable 侧时的情形;条款 4/4b 是 x 落在 PreserveRequiredState 侧时的情形——**二者本是同一条判据的两支**,此前写成「规则 + 例外」,现并为一条。两点必须同时遵守: -- **Recoverable 是语义判据,不是语法判据**:配方存在 ≠ 可重算。volatile MMIO 读有"地址意义上的配方",但重读一次 ≠ 原值且有副作用,故 `Recoverable = false`。 -- **判不出 ⇒ 不可驱逐(fail-closed)**:归属判定返回「未知」时判为不可驱逐,而不是可驱逐——否则「义务未满足」与「义务未被检查」在观测上不可区分,就是静默语义破坏。 +- **Recoverable 是语义判据,不是语法判据**:配方存在 ≠ 可重算。volatile MMIO 读有"地址意义上的配方",但重读一次 ≠ 原值且有副作用,故 `Recoverable = false`。 +- **判不出 ⇒ 不可驱逐(fail-closed)**:归属判定返回「未知」时判为不可驱逐,而不是可驱逐——否则「义务未满足」与「义务未被检查」在观测上不可区分,就是静默语义破坏。 -展开、反例形态(含 `recipe = no` 的义务面)与判据形状见 docs/maintainer/design/materialization-space.md §四。 +展开、反例形态(含 `recipe = no` 的义务面)与判据形状见 `docs/maintainer/design/materialization-space.md` §四。 --- ## 二、条款细读 -### 条款 1:值 = 配方 +### 条款 1:值 = 配方 -"条目"是存储的一项,它的语义完全由产生方式决定。不存在"内存单元里存了什么"这种脱离产生方式的存储事实——问"这个值是什么"永远可以还原为"它是哪个图节点、用什么输入产生的"。这对验证的含义:验证器不需要为存储建模,只需要为配方(图)建模。 +"条目"是存储的一项,它的语义完全由产生方式决定。不存在"内存单元里存了什么"这种脱离产生方式的存储事实——问"这个值是什么"永远可以还原为"它是哪个图节点、用什么输入产生的"。这对验证的含义:验证器不需要为存储建模,只需要为配方(图)建模。 -### 条款 2 + 3:驱逐与再生(缓存的两面) +### 条款 2 + 3:驱逐与再生(缓存的两面) -驱逐不变量**在可再生的那一类上是**定义性质:凡配方还在的物化都可以被丢弃。再生等价是机制保证:重跑配方得到可观测等价的值。 +驱逐不变量**在可再生的那一类上是**定义性质:凡配方还在的物化都可以被丢弃。再生等价是机制保证:重跑配方得到可观测等价的值。 -**对无配方条目(条款 4/4b)这一支不成立**——它走 2′ 的 `PreserveRequiredState` 侧:材料必须保有或被合法转移,不得靠"重算"覆盖。 +**对无配方条目(条款 4/4b)这一支不成立**——它走 2′ 的 `PreserveRequiredState` 侧:材料必须保有或被合法转移,不得靠"重算"覆盖。 -二者合起来给出编译器优化的正确性依据: -- 寄存器分配中把值溢出到 home(材料移走)= 驱逐 + 按需再生 -- rematerialization(重算代替装载)= 条款 3 的直接应用 -- 任何映射实例层(缓存/寄存器/持久)的动作都不改变语义——性能是唯一代价维度 +二者合起来给出编译器优化的正确性依据: -### 条款 4 + 4b:无配方条目(`recipe = unrecomputable`;2′ 的 PreserveRequiredState 侧) +- 寄存器分配中把值溢出到 home(材料移走)= 驱逐 + 按需再生。 +- rematerialization(重算代替装载)= 条款 3 的直接应用。 +- 任何映射实例层(缓存/寄存器/持久)的动作都不改变语义——性能是唯一代价维度。 -两类条目没有配方,驱逐必须写回、不可再生(即 `Evictable` 只能经 2′ 的第二支成立): +### 条款 4 + 4b:无配方条目(`recipe = unrecomputable`;2′ 的 PreserveRequiredState 侧) + +两类条目没有配方,驱逐必须写回、不可再生(即 `Evictable` 只能经 2′ 的第二支成立): | 类别 | 例子 | 语法层标注 | |---|---|---| | 边界(图外输入) | MMIO、FFI 返回值、输入、测量 | unsafe(边界标注) | | 图内不可重算 | 神谕、BSS 实数、FIXPT 声明、模糊融合 | 执行标注(见 dataflow-design §8) | -统一规则:无配方条目必须有 home(持久位置),驱逐必写回;身份 = 产生节点。不按范式枚举——新增范式时无配方规则不变。 +统一规则:无配方条目必须有 home(持久位置),驱逐必写回;身份 = 产生节点。不按范式枚举——新增范式时无配方规则不变。 -### 条款 5:赋值 = 版本化 +### 条款 5:赋值 = 版本化 -非 SSA 语言中变量的多次赋值在语义上是版本序列:x₁ 创建、x₀ 失效、绑定移动。这解释了三件事: +非 SSA 语言中变量的多次赋值在语义上是版本序列:x₁ 创建、x₀ 失效、绑定移动。这解释了三件事: -- "可变"不是内存单元的属性,是绑定可移动的许可(语义层不承诺任何内存单元) -- 顺序约束不属于存储,属于 state edges(副作用链) -- 存在区间(live range)是版本级别的——每条版本有自己的定值点与最后使用点(IR 载体见 existence-structure.md) +- "可变"不是内存单元的属性,是绑定可移动的许可(语义层不承诺任何内存单元)。 +- 顺序约束不属于存储,属于 state edges(副作用链)。 +- 存在区间(live range)是版本级别的——每条版本有自己的定值点与最后使用点(IR 载体见 `existence-structure.md`)。 -### 条款 6:地址 = 映射 +### 条款 6:地址 = 映射 -`&x` 在语义层是 (条目标识, 偏移)——字节地址是经典投影(编码层对象)。由此指针算术的合法性 = 条目标识 + 偏移域验证,与类型无关;provenance(归属)与 offset 是图上本有的信息(推论 C,见 region-model.md)。 +`&x` 在语义层是 (条目标识, 偏移)——字节地址是经典投影(编码层对象)。由此指针算术的合法性 = 条目标识 + 偏移域验证,与类型无关;provenance(归属)与 offset 是图上本有的信息(推论 C,见 `region-model.md`)。 -### 条款 7:映射实例正确性 +### 条款 7:映射实例正确性 -任何映射实例(区域/arena/字节权限/寄存器)的正确性标准是同一个:保持条款 1–6 的可观测语义。由此"范式映射表"= 映射正确性定理表——经典行 = 证明条款 1–6 ⊇ 字节内存实现(CompCert 式语义保鲜);量子行 = 将来证明条款 1–6 ⊇ 量子存储实现。语义保鲜从"编译正确性定理"升级为"映射正确性定理"。 +任何映射实例(区域/arena/字节权限/寄存器)的正确性标准是同一个:保持条款 1–6 的可观测语义。由此"范式映射表"= 映射正确性定理表——经典行 = 证明条款 1–6 ⊇ 字节内存实现(CompCert 式语义保鲜);量子行 = 将来证明条款 1–6 ⊇ 量子存储实现。语义保鲜从"编译正确性定理"升级为"映射正确性定理"。 --- -## 三、推论:范式映射表 +## 三、推论:范式映射表 | 行 | 映射实例 | 正确性定理 | |---|---|---| @@ -116,17 +117,17 @@ Evictable(x) ⟺ Recoverable(x) ∨ PreserveRequiredState(x) | 寄存器 | 寄存器缓存 + home(栈槽) | 判定四条(见 regalloc-cache-mapping.md) | | 量子(将来) | 量子存储 | 条款 1–6 ⊇ 量子存储实现 | -每行定理共享条款 1–6——新范式不需要新的存储语义,只需要新映射与新证明。 +每行定理共享条款 1–6——新范式不需要新的存储语义,只需要新映射与新证明。 --- ## 四、关联 -- **层定义(存在格 / 七字段 / 归类 / 划界)**:docs/maintainer/design/materialization-space.md -- 存储语义总览:docs/maintainer/design/memory-model.md -- 层定义修订决策:docs/maintainer/adr/adr-0021-existence-space-layer-definition.md -- IR 载体:v6 存在结构(ENT/NOD/REG)— docs/maintainer/design/existence-structure.md -- 经典映射:docs/maintainer/design/region-model.md(区域/arena/权限) -- 寄存器实例:docs/maintainer/design/regalloc-cache-mapping.md(判定四条) -- 设计依据:docs/superpowers/specs/2026-08-15-cache-semantics-design.md -- 术语索引:docs/glossary.md §四(缓存语义术语) +- **层定义(存在格 / 七字段 / 归类 / 划界)**:`docs/maintainer/design/materialization-space.md` +- 存储语义总览:`docs/maintainer/design/memory-model.md` +- 层定义修订决策:`docs/maintainer/adr/adr-0021-existence-space-layer-definition.md` +- IR 载体:v6 存在结构(ENT/NOD/REG)— `docs/maintainer/design/existence-structure.md` +- 经典映射:`docs/maintainer/design/region-model.md`(区域/arena/权限) +- 寄存器实例:`docs/maintainer/design/regalloc-cache-mapping.md`(判定四条) +- 设计依据:`docs/superpowers/specs/2026-08-15-cache-semantics-design.md` +- 术语索引:`docs/glossary.md` §四(缓存语义术语) diff --git a/docs/academic/lattice-theory.md b/docs/academic/lattice-theory.md index 3fe3882e..9f69b8e5 100644 --- a/docs/academic/lattice-theory.md +++ b/docs/academic/lattice-theory.md @@ -1,7 +1,7 @@ -# 三层映射理论:图 → 格 → 编码(定稿) +# 三层映射理论:图 → 格 → 编码(定稿) -> 定位:受众 = 学术(验证/理论读者,兼维护者);状态 = active(v3 立、v4 晋升定稿,2026-08-27 第三层更名)。 -> 本文件 = 三层映射理论的**定稿提炼**;原始论证与演进(抽象升华系列/v1-v4 讨论)见 docs/archive/memory-model-capability-lattice.md;存储半边的**层定义**(存在格 / Materialization Space)见 docs/maintainer/design/materialization-space.md、**条款 1–7** 见 docs/academic/cache-semantics.md;执行标注空间见 docs/maintainer/design/dataflow-design.md §8。 +> 定位:受众 = 学术(验证/理论读者,兼维护者);状态 = active(v3 立、v4 晋升定稿,2026-08-27 第三层更名)。 +> 本文件 = 三层映射理论的**定稿提炼**;原始论证与演进(抽象升华系列/v1-v4 讨论)见 `docs/archive/memory-model-capability-lattice.md`;存储半边的**层定义**(存在格 / Materialization Space)见 `docs/maintainer/design/materialization-space.md`、**条款 1–7** 见 `docs/academic/cache-semantics.md`;执行标注空间见 `docs/maintainer/design/dataflow-design.md` §8。 --- @@ -17,24 +17,24 @@ 编码 —— 物理编码空间:如何实现 ``` -### 为什么需要格这一层 +### 格这一层的必要性 -图回答"这个计算世界中有什么关系、什么可能发生";格回答"这些东西如何成为具有状态和位置的可实现存在"。若图 → 编码直连,大量"如何存在"的问题(节点是什么内存对象、关系怎么保存状态、两个可能分支的状态怎么共存、非因果怎么落地址、节点生命周期)都会被迫塞进一个万能的图 → 机器码映射器。 +图回答"这个计算世界中有什么关系、什么可能发生";格回答"这些东西如何成为具有状态和位置的可实现存在"。若图 → 编码直连,大量"如何存在"的问题(节点是什么内存对象、关系怎么保存状态、两个可能分支的状态怎么共存、非因果怎么落地址、节点生命周期)都会被迫塞进一个万能的图 → 机器码映射器。 ### 三层的数学定位 -- **图 = 关系空间**:表达可超越经典图灵机执行模型的语义(非因果、模糊、超图灵)——**超图灵性属于图,不属于格** -- **格 = 状态/存储空间**:提供足够一般的状态模型使图能被映射下来;格不需要理解超图灵,只需让可被当前执行环境实现的部分拥有状态/位置/关系/可访问性 -- **编码 = 物理编码空间**:把格编码成具体机器的地址、字节、指令、位模式(2026-08-27 更名:原"二进制"硬编码经典惯例,违反零硬件惯例——量子/模拟/光学皆非二进制) -- **格不重新引入程序顺序**:传统 IR(SSA/LLVM)本质上仍是"另一种程序"——按执行路径组织;格 = 中间存在空间,不必重新引入程序顺序 +- **图 = 关系空间**:表达可超越经典图灵机执行模型的语义(非因果、模糊、超图灵)——**超图灵性属于图,不属于格**。 +- **格 = 状态/存储空间**:提供足够一般的状态模型使图能被映射下来;格不需要理解超图灵,只需让可被当前执行环境实现的部分拥有状态/位置/关系/可访问性。 +- **编码 = 物理编码空间**:把格编码成具体机器的地址、字节、指令、位模式(2026-08-27 更名:原"二进制"硬编码经典惯例,违反零硬件惯例——量子/模拟/光学皆非二进制)。 +- **格不重新引入程序顺序**:传统 IR(SSA/LLVM)本质上仍是"另一种程序"——按执行路径组织;格 = 中间存在空间,不必重新引入程序顺序。 -### 跨范式自由度(格的价值) +### 跨范式自由度(格的价值) -- 不同范式(命令式/函数式/数据流/并发/事件驱动/非确定/模糊/超图灵)的差异首先被图吸收(图层标注空间) -- 格不被某个有限、固定的传统计算范式预先封顶——可构造表达空间无界 -- 真正的问题是"C 的语义能否找到一个格映射",而不是"格能不能表示 C"——**格本身不需要知道范式是什么** +- 不同范式(命令式/函数式/数据流/并发/事件驱动/非确定/模糊/超图灵)的差异首先被图吸收(图层标注空间)。 +- 格不被某个有限、固定的传统计算范式预先封顶——可构造表达空间无界。 +- 真正的问题是"C 的语义能否找到一个格映射",而不是"格能不能表示 C"——**格本身不需要知道范式是什么**。 -## 二、术语澄清:格的两义 +## 二、术语澄清:格的两义 | 术语 | 含义 | |---|---| @@ -43,31 +43,31 @@ ## 三、定稿原则 -### 规则封闭、对象开放(v4 定稿) +### 规则封闭、对象开放(v4 定稿) -- **规则(封闭,永不新建)**:条款 1–7 + 最弱理论(关系层面)。新范式出现时层本体一字不改——**规则封闭 = 维护有界**(2026-09-20 层定义修订只换了层名与框定词:本体 = 存在格,缓存 = 该类映射实例;条款数不变、规则不增) -- **对象(开放,无界)**:条目、配方、标注。任何范式的值都装得下(量子振幅、FIXPT 不动点、模糊隶属度)——**对象开放 = 表达无界** -- 一切结构是图层导出或映射参数:共存关系是图层导出(图活性),不是格层承诺;格代数、区域、字节、寄存器都是映射实例 +- **规则(封闭,永不新建)**:条款 1–7 + 最弱理论(关系层面)。新范式出现时层本体一字不改——**规则封闭 = 维护有界**(2026-09-20 层定义修订只换了层名与框定词:本体 = 存在格,缓存 = 该类映射实例;条款数不变、规则不增)。 +- **对象(开放,无界)**:条目、配方、标注。任何范式的值都装得下(量子振幅、FIXPT 不动点、模糊隶属度)——**对象开放 = 表达无界**。 +- 一切结构是图层导出或映射参数:共存关系是图层导出(图活性),不是格层承诺;格代数、区域、字节、寄存器都是映射实例。 -### 无格承诺(v4 定稿) +### 无格承诺(v4 定稿) -- 任何具体格 = 签名 + 恒等式 → 恒等式封顶表达空间。解法不是选更宽的格,而是**把语义写在比格更弱的理论里**——最弱理论 = 最多模型 = 无界 -- 存储判定需要的最弱结构 = 共存关系(对称关系,无传递性——a 与 b 共存、b 与 c 共存,a 与 c 不必共存),连预序公理都不需要 -- 格(Lattice 代数)降级为**映射实例的组织参数**:经典行用乘积格、量子行用别的、未来范式用未知格——每范式引入自己的代数都是参数 -- 数学原则:**用函子式/普适构造定义层,不用情形分析**;对象由普适性质定义(直到同构唯一),不选具体结构 -- 验证视角:判定/定理写在最弱理论里,对一切格成立;CIC 内核里任何具体格都是该理论的一个模型——健全性对理论成立,就对所有模型成立 +- 任何具体格 = 签名 + 恒等式 → 恒等式封顶表达空间。解法不是选更宽的格,而是**把语义写在比格更弱的理论里**——最弱理论 = 最多模型 = 无界。 +- 存储判定需要的最弱结构 = 共存关系(对称关系,无传递性——a 与 b 共存、b 与 c 共存,a 与 c 不必共存),连预序公理都不需要。 +- 格(Lattice 代数)降级为**映射实例的组织参数**:经典行用乘积格、量子行用别的、未来范式用未知格——每范式引入自己的代数都是参数。 +- 数学原则:**用函子式/普适构造定义层,不用情形分析**;对象由普适性质定义(直到同构唯一),不选具体结构。 +- 验证视角:判定/定理写在最弱理论里,对一切格成立;CIC 内核里任何具体格都是该理论的一个模型——健全性对理论成立,就对所有模型成立。 -## 四、新范式只需三件事(不是"新建格") +## 四、新范式只需三件事(不是"新建格") -1. **图标注空间加标签**——统一空间,加标签不是新机制(FUZZY/FIXPT/Oracle/CORE 已是标签) -2. **CIC 内部定义新结构**——一个逻辑,健全性继承 -3. **硬件映射**——不可避免的工程,但是映射工作,不是层工作 +1. **图标注空间加标签**——统一空间,加标签不是新机制(FUZZY/FIXPT/Oracle/CORE 已是标签)。 +2. **CIC 内部定义新结构**——一个逻辑,健全性继承。 +3. **硬件映射**——不可避免的工程,但是映射工作,不是层工作。 -判定规则是**条目泛型**的:操作"条目"这个类别(位置 + 配方 + 存在),不读值的内容——新条目种类不需要新判定规则。 +判定规则是**条目泛型**的:操作"条目"这个类别(位置 + 配方 + 存在),不读值的内容——新条目种类不需要新判定规则。 -## 五、范式映射表(推论) +## 五、范式映射表(推论) -范式映射表 = 映射正确性定理表(条款 7 的推论): +范式映射表 = 映射正确性定理表(条款 7 的推论): | 行 | 映射实例 | 正确性定理 | |---|---|---| @@ -75,17 +75,17 @@ | 寄存器 | 寄存器缓存 + home | 判定四条(regalloc-cache-mapping) | | 量子(将来) | 量子存储 | 条款 1–6 ⊇ 量子存储实现 | -每行定理共享七条——新范式不需要新的存储语义,只需要新映射与新证明。 +每行定理共享七条——新范式不需要新的存储语义,只需要新映射与新证明。 ## 六、验证主线 -Graph → Lattice 映射通用性清单(每项通过 = 三层链成立的证据;原始清单见 archive 备忘 §十二):寄存器分配判定以纯格对象写出(无路径结构)= "格不重引入顺序"判据的实例化;存储半边(条款 1–7)已定稿,执行半边(执行标注空间 = dataflow-design §8)为对应物。 +Graph → Lattice 映射通用性清单(每项通过 = 三层链成立的证据;原始清单见 archive 备忘 §十二):寄存器分配判定以纯格对象写出(无路径结构)= "格不重引入顺序"判据的实例化;存储半边(条款 1–7)已定稿,执行半边(执行标注空间 = dataflow-design §8)为对应物。 ## 七、关联 -- 原始论证与演进:docs/archive/memory-model-capability-lattice.md(v1-v4 备忘,讨论过程档案) -- 存储半边**层定义**:docs/maintainer/design/materialization-space.md(存在格 / Materialization Space / 七字段) -- 存储半边条款:docs/academic/cache-semantics.md(条款 1–7 权威) -- 执行标注空间:docs/maintainer/design/dataflow-design.md §8(仍权威) -- IR 载体:docs/maintainer/design/existence-structure.md(v6 ENT/NOD/REG) -- 映射实例:docs/maintainer/design/region-model.md(经典映射)、regalloc-cache-mapping.md(寄存器行) +- 原始论证与演进:`docs/archive/memory-model-capability-lattice.md`(v1-v4 备忘,讨论过程档案) +- 存储半边**层定义**:`docs/maintainer/design/materialization-space.md`(存在格 / Materialization Space / 七字段) +- 存储半边条款:`docs/academic/cache-semantics.md`(条款 1–7 权威) +- 执行标注空间:`docs/maintainer/design/dataflow-design.md` §8(仍权威) +- IR 载体:`docs/maintainer/design/existence-structure.md`(v6 ENT/NOD/REG) +- 映射实例:`docs/maintainer/design/region-model.md`(经典映射)、`regalloc-cache-mapping.md`(寄存器行) diff --git a/docs/academic/verifier-kernel.md b/docs/academic/verifier-kernel.md index cf6ecdef..3b983edf 100644 --- a/docs/academic/verifier-kernel.md +++ b/docs/academic/verifier-kernel.md @@ -1,9 +1,9 @@ # 验证内核选型与融合架构(Verifier Kernel) -> 定位:受众 = 学术(兼维护者);状态 = active +> 定位:受众 = 学术(兼维护者);状态 = active。 > 信任根 = CIC 内核。表达力 = CIC + 公理 + HoTT 库。自动化 = 证书形态(计算在外、健全性在内)。 -> 融合各家之长,不选边——每个维度取最优,其他体系全部变成方法贡献。 +> 融合各家之长,不偏向单一体系——每个维度取最优,其他体系全部变成方法贡献。 ## 一、问题 @@ -38,7 +38,7 @@ ## 四、融合架构(决策,2026-08-10) -不选边——**每个维度取最优,其他体系降级为方法贡献**: +不偏向单一体系——**每个维度取最优,其他体系降级为方法贡献**: ``` ┌─ 内核层(信任根)───────────────────────────────────┐ @@ -66,7 +66,7 @@ | 表达力 | CIC + 公理 + HoTT 库(不换理论,挂载) | 数学完备性用库层拿,内核零增长 | | 自动化 | 证书形态(SMTCoq + Andromeda 同构) | 计算在外、健全性在内——与自举/验证路线天然兼容 | -### 为什么 HoTT 不换内核:用 CIC 证明 HoTT +### HoTT 不换内核的依据:用 CIC 证明 HoTT - HoTT/Coq 与 UniMath 的先例:标准 CIC 内核 + Univalence 公理(Voevodsky 模型证明一致) - 公理化 UA 不可计算(含 UA 消除的证明项归一化会 stuck)——但**日常规约验证不用 UA**,它只在数学库层需要——工程分层天然隔离 diff --git a/docs/coq/README.md b/docs/coq/README.md index 43fd9734..2d50d552 100644 --- a/docs/coq/README.md +++ b/docs/coq/README.md @@ -1,19 +1,19 @@ # 用 Coq 验证 Core stdlib 纯函数 -> 定位:受众 = 维护者/验证者;状态 = active(方向与入口);本文件即入口(coq/ 证明待建)。 +> 定位:受众 = 维护者/验证者;状态 = active(方向与入口);本文件即入口(`coq/` 证明待建)。 -> 目标:用 Coq(Rocq)做**程序验证**——验证 Core 系统里**几乎永远不会改**的部分(stdlib 纯函数)。 -> 注意:这不是规约系统(`.corespec` / 翻译桥那套基础设施),是直接用 Coq 验证程序本身的性质。 +> 目标:用 Coq(Rocq)做**程序验证**——验证 Core 系统里**几乎不随语言演进而改动**的部分(stdlib 纯函数)。 +> 注意:这不是规约系统(`.corespec` / 翻译桥那套基础设施),而是直接用 Coq 验证程序本身的性质。 -## 为什么选 stdlib 纯函数 +## 选取 stdlib 纯函数的依据 -- **几乎永不变**:`int_str`(数字→字符串)、`str_eq` 等是语言无关的经典算法,语言怎么演进都不变。验证是长期投入,选会变动的代码证明就过时了。 +- **几乎永不变**:`int_str`(数字→字符串)、`str_eq` 等是语言无关的经典算法,不随语言演进变动。验证是长期投入,选取会变动的代码作证明对象会随之过时。 - **纯函数**:无副作用,语义干净,Coq 里建模没有状态/内存干扰。 -- **规模适中**:每个函数几十行,翻译 + 证明一晚上一个闭环。 +- **规模适中**:每个函数几十行,翻译与证明可在一日内完成一个闭环。 -## 第一刀目标:`int_str` ↔ `str_int` 互逆 +## 首个目标:`int_str` ↔ `str_int` 互逆 -源码:`src/stdlib/fmt.cr:96`(int_str)、`src/stdlib/fmt.cr:134`(str_int)。 +源码:`src/stdlib/fmt.cr:96`(`int_str`)、`src/stdlib/fmt.cr:134`(`str_int`)。 **要证明的性质(非负情形)**: @@ -21,7 +21,7 @@ 对任意非负整数 n:str_int(int_str(n)) == n ``` -即:数字转成字符串,再解析回来,等于原数。这是 fmt.cr 的灵魂性质(数字转换正确性)。 +即:数字转成字符串,再解析回来,等于原数。这是 `fmt.cr` 的核心性质(数字转换正确性)。 ## 验证工作流(5 步) @@ -37,9 +37,9 @@ ## 第 ① 步:建模约定(已完成) -**关键概念:验证不是逐行翻译代码,而是用 Coq 的语言重新表达同一个算法语义。** 要回答的问题:"int_str 的语义是什么?"——不是"它怎么操作内存",而是"它把一个数字变成了什么"。 +**关键概念:验证不是逐行翻译代码,而是用 Coq 的语言重新表达同一个算法语义。** 需要回答的问题是 `int_str` 的语义,即它把一个数字变成了什么,而不是它如何操作内存。 -对照 `fmt.cr:96` 的 int_str,逐项消去: +对照 `fmt.cr:96` 的 `int_str`,逐项消去: | Core 里的东西 | 为什么能消去 | Coq 里的表达 | |---|---|---| @@ -48,21 +48,21 @@ | `+ 48` / `- 48`(ASCII 转换) | 字符编码是实现细节,语义 = "数字的十进制位" | 数字 `0..9` | | `int`(64 位机器整数) | **先只验证非负情形**,负数/溢出留到后面 | `nat` | -**消去后 int_str 的算法语义**: +**消去后 `int_str` 的算法语义**: ``` int_str(n) = n 的十进制 digits 序列 比如 int_str(123) = [1, 2, 3] ``` -**str_int 的语义**(`fmt.cr:134`): +**`str_int` 的语义**(`fmt.cr:134`): ``` str_int(s) = 从左往右读 digits,每读一位 res = res*10 + d [1,2,3] → ((0*10+1)*10+2)*10+3 = 123 ``` -**待确认点**:int_str 里有两个循环(数位数的循环 + 填位的循环)——翻译成 Coq 时两个循环会合体成一个递归函数。 +**待确认点**:`int_str` 里有两个循环(数位数的循环 + 填位的循环)——翻译成 Coq 时两个循环会合并为一个递归函数。 ## 进度 @@ -81,10 +81,10 @@ str_int(s) = 从左往右读 digits,每读一位 res = res*10 + d - `parse_fwd_snoc` / `parse_fwd_rev` — 桥引理:正序解析 = 逆序解析 - 终止性义务:`n/10 < n`(Function measure 证明) -## 过程中踩的坑(Rocq 9.1 实测) +## 实现过程中遇到的问题(Rocq 9.1 实测) 1. **除法递归不被 Fixpoint 接受**(guard condition)——`n / 10` 不是结构子项,需 `Function` + measure -2. **`Function f (n : nat) {measure n}` 语法在 Rocq 9.1 坏了**——报 "Illegal application: n cannot be applied to n";须写 `{measure (fun x => x) n}` +2. **`Function f (n : nat) {measure n}` 语法在 Rocq 9.1 失效**——报 "Illegal application: n cannot be applied to n";须写 `{measure (fun x => x) n}` 3. **`simpl` 会展开 wf 包装 / divmod / 乘法**——`Function` 定义展开带证明项,`mod`/`div` 内部是 `divmod` fix,`10 * x` 展开成加法链。解法:`Opaque Nat.div Nat.modulo Nat.mul` + 用 `digits_rev_equation` 精确展开 4. **`rewrite` 替换所有匹配**——`rewrite (Nat.div_mod (S m) 10) at 1` 限定只替换最外层 5. **归纳需要泛化累加器**——`induction l in acc |- *`,否则 IH 里的 acc 与目标不匹配 diff --git a/docs/core-language-syntax_v4.md b/docs/core-language-syntax_v4.md new file mode 100644 index 00000000..a547ed54 --- /dev/null +++ b/docs/core-language-syntax_v4.md @@ -0,0 +1,1410 @@ +# Core 语言语法 + +> 定位:受众 = 开发者;状态 = active +> 基线:`develop` @ `7cf724f6c1577e29879c37493b87e90ad061af57` +> 版本:v4 目标语法 + +本文档记录 Core 语言本体的目标语法。v4 正在从现有 `develop` 实现迁移;迁移期间,编译器源码可能暂时接受旧语法,但新增代码与语法实现以本文档为目标。 + +--- + +## 一、词法与布局 + +### 1.1 注释 + +```core +// 单行注释 +/* 多行注释 */ +``` + +多行注释可以嵌套。 + +### 1.2 标识符 + +```text +IDENT = LETTER (LETTER | DIGIT | '_' | '\'')* +``` + +字母(a-z / A-Z / `_`)开头,后续可含字母、数字、下划线与单引号。`_` 本身是通配符。 + +### 1.3 关键字 + +v4 目标语法使用下列核心关键字: + +```text +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 +``` + +- `self` 用于方法接收者(`self` / `&self` / `&mut self`)。 +- `Self` 是接口/实现上下文中的类型名。 +- `@comptime` 等 `@` 形式属于内建原语,不作为普通关键字处理。 +- `#check` / `#ensure` / `#invariant` / `#variant` 属于规约指令;`#smt`、`#induct`、`#simp`、`#tag` 等属于证明战术标签。它们都不占用普通代码的全局关键字。 +- `forall`、`exists`、`result`、`old` 只在规约上下文中具有特殊含义,不作为普通代码的全局保留字。 +- v4 不使用 `move` 关键字。 + +### 1.4 字面量 + +| 字面量 | 示例 | 说明 | +|--------|------|------| +| 整数 | `42` `0` `-7` | 十进制;机器位宽由编码层按目标决定 | +| 小数 | `3.14` `.5` | 精确小数,默认 `dex` 语义 | +| 字符串 | `"Core"` `"a\nb"` | 不可变 UTF-8 | +| 字符 | `'x'` `'\n'` `'\x41'` | Unicode 标量值 | +| 布尔 | `true` `false` | | +| 单元 | `()` | `unit` 的唯一值 | +| 空可选值 | `none` | `T?` 的无值形态 | + +普通 `T` 值可以作为 `T?` 的有值形态,不需要 `Some(...)` 包装。 + +### 1.5 运算符与结构记号 + +| 记号 | 含义 | +|------|------| +| `:` | 类型标注;在完整语法头部末尾开启 layout region | +| `:=` | 变量声明与绑定 | +| `=` | 赋值 / 显式初始化 | +| `+=` `-=` `*=` `/=` | 复合赋值 | +| `->` | 显式返回类型 / 函数类型结果 | +| `=>` | match / catch 臂映射到结果;规约量词体分隔 | +| `==>` | 规约蕴含,右结合 | +| `|` | alternative / pattern arm | +| `|>` | 管道阶段连接;只用于真实 pipeline | +| `...` | 变参前缀 | +| `*` | 乘 / 解引用 / 裸指针类型前缀 | +| `&` `&mut` | 引用 | +| `+ - / %` | 算术 | +| `== != < > <= >=` | 比较 | +| `&& \|\| !` | 逻辑 | +| `.` | 字段访问 / 类型推断占位 | +| `::` | 路径分隔符 | +| `,` | 分隔 | +| `?` | 可选类型标记 | +| `..` | 范围 | +| `@` | 内建原语前缀 | +| `_` | 通配符 | + +`?` 不用于错误传播。错误传播由错误边与 `catch` 语法处理。 + +### 1.6 Layout region + +v4 不使用 `{ ... }` 作为语言块结构。块由 `:` 与相对缩进建立。 + +```core +fn add(a: int, b: int) -> int: + return a + b +``` + +缩进宽度本身没有语义。解析器只比较相对列关系: + +```text +更深 = 当前结构的从属内容 +同列 = 当前 region 的 sibling +更浅 = 退出一个或多个 region +``` + +同一 sibling group 必须对齐。第一个子项建立该 group 的 layout anchor。 + +下面两段结构等价: + +```core +match x: + | A => a + | B => b +``` + +```core +match x: + | A => a + | B => b +``` + +但同一个 arm group 内不得错位: + +```core +match x: + | A => a + | B => b // error: sibling 未对齐 +``` + +空行与只含注释的行不改变 layout。格式化器可以按语法角色使用不同的视觉缩进宽度,但不能改变 anchor 关系。 + +换行是通常的语句分隔方式。`;` 不要求用于普通源码布局。 + +--- + +## 二、模块与导入 + +模块系统基于**文件标识符**与**项目标识符**,不使用文件物理路径。 + +### 2.1 文件标识符 + +默认使用文件名(不含 `.cr`)作为标识符,可在文件头部覆盖: + +```core +fileid "my_helper" + +fn greet(name: string) -> string: + return "hi " + name +``` + +同一项目内标识符必须唯一。 + +### 2.2 模块声明 + +```core +mod examples::pi +``` + +`::` 是文件内路径分隔符。 + +### 2.3 导入 + +```core +import math +import math : m +import @acme math +import @acme math : m +``` + +`@项目名` 前缀区分本地符号与外部项目符号。项目名在项目根的 `Core.toml` 中声明。 + +### 2.4 符号访问 + +```core +import math : m + +result := m.add(3, 5) +``` + +未导入时可用完整路径 `math::add(3, 5)` 直接访问。 + +### 2.5 目录级批量导入 + +目录下的 `_import.cr` 自动应用于该目录及子目录: + +```core +// _import.cr +import @acme math : m +import @std io +``` + +`_import.cr` 本身不生成代码,只起导入声明作用。 + +--- + +## 三、类型标注与自动类型关系 + +类型语法只保留用户需要主动表达的区别;能够由程序关系唯一恢复的信息由编译器推导。 + +### 3.1 类型表达式 + +目标语法: + +```text +Type = BaseType + | PathType + | RefType + | PtrType + | OptionalType + | FunctionType + | TupleType + | ArrayType + | SliceType + | InferredType + | TypeOf + +RefType = '&' ['mut'] Type +PtrType = '*' Type +OptionalType = Type '?' +FunctionType = 'fn' '(' [Type (',' Type)*] ')' '->' Type +TupleType = '(' [Type (',' Type)*] ')' +ArrayType = '[' Type ';' INT_LIT ']' +SliceType = '[' Type ']' +InferredType = '.' +TypeOf = 'typeof' '(' Expr ')' +``` + +`PtrType` 是可用的显式边界类型形式,不表示普通裸指针必须标注类型;由 `&`、指针算术或其他可追踪关系产生的指针默认自动推断。 + +基础类型: + +| 类型 | 说明 | +|------|------| +| `int` | 精确整数 | +| `dex` | 精确小数 | +| `bool` | `true` / `false` | +| `string` | 不可变 UTF-8 字符串 | +| `char` | Unicode 标量值 | +| `unit` | 空值 `()` | +| `never` | 发散类型 | +| `dyn` | 运行时开放值域 | +| `Self` | 当前接口或实现类型 | + +复合类型示例: + +```core +coords : (int, int) +zeros : [int; 16] +view : [int] +parent : User? +cb : fn(int) -> int +``` + +引用与裸指针通常不需要显式类型标注。`&`、解引用、指针算术以及数据流关系足以确定其指向类型、来源与偏移;只有外部地址、FFI、固定 ABI 等无法由程序关系恢复的边界才需要显式写出指针类型。 + +### 3.2 可选类型 `T?` + +`?` 表示该位置允许“有值”或“无值”。 + +```core +parent : User? = none +value : int? = 5 +``` + +普通值直接构成有值分支,不使用 `Some(...)` 包装。 + +函数体能够唯一推出可选返回时,返回标注可以省略: + +```core +fn find_user(id: int): + if exists(id): + return load_user(id) + + return none +``` + +显式 `-> User?` 仍可用于 API 契约。 + +### 3.3 引用、裸指针与动态值域 + +引用与裸指针的具体类型由表达式和 HDFG 自动推断,不要求为普通指针值重复写 `&T` / `*T` 标注: + +```core +p := &arr[0] +q := p + n +x := *q +value : dyn = x +``` + +编译器从取地址对象、指针算术、解引用和数据流中恢复指向类型,并同时维护 provenance、offset 与可用区域。 + +`&T` / `&mut T` 仍可在函数边界等位置显式表达“引用既有实体”的接口关系;`*T` 是低层裸指针的显式类型形式,主要用于外部地址、FFI、固定 ABI 或显式转换等无法从安全程序关系唯一恢复类型的边界。`dyn` 表达运行时开放值域。 + +### 3.4 推断占位 `.` 与 `auto` + +`.` 和 `auto` 表示由上下文和程序关系确定的类型。 + +```core +x : auto = 42 +y : . = 3.14 +z : ., mut = 20 +``` + +`.` 可用于参数、字段、枚举 payload、切片元素与函数类型: + +```core +fn identity(x: .): + return x + +struct Event: + name: string + payload: . + +extern fn transform(fn(.) -> .) -> . +``` + +每个独立的 `.` 初始表示独立未知类型;只有程序关系要求时才建立等式或其他约束。 + +### 3.5 同一类型关系 `typeof(...)` + +当声明本身需要显式表达同型关系、且没有实现可供推导时,可以引用已有位置的类型: + +```core +extern fn clone_value(x: .) -> typeof(x) +``` + +不引入类型参数。 + +### 3.6 无显式泛型参数与泛型应用 + +v4 不包含 ``、`[T]` 或其他显式泛型参数 / 类型实参语法。 + +```core +fn identity(x: .): + return x +``` + +编译器可以从该实现得到参数与返回值的同型关系并自动泛化。 + +### 3.7 结构语义与物理布局分离 + +递归结构可以直接写出: + +```core +struct Node: + value: int + next: Node? +``` + +普通类型语法不要求 `Box`、`Rc`、`Arc`、`Owned`、`Heap` 等存储或所有权包装。 + +### 3.8 标签 + +变量与字段可带 `mut`、`pub`、`apx` 等标签: + +```core +count : int, mut = 0 +pub_val : int, pub = 42 +speed : dex, apx = 3.14 +``` + +--- + +## 四、变量声明与赋值 + +无 `let` 关键字。`:=` 进行声明与绑定,`: Type =` 显式标注: + +```core +x := 42 +name : string = "Core" +count : int, mut = 0 +shared : auto, pub, mut = 42 +a, b : int = 1, 2 +``` + +赋值使用 `=`: + +```core +count = count + 1 +count += 1 +``` + +v4 不使用显式 `move`。region、借用有效性、escape、capture 与存储 realization 由程序关系推导。 + +--- + +## 五、表达式与运算符 + +### 5.1 基本优先级 + +从低到高: + +```text +Assignment +Pipeline +LogicalOr +LogicalAnd +Equality +Comparison +Addition +Multiplication +Unary +CallOrField +Primary +``` + +`|>` 是独立的 pipeline 关系,不是普通函数调用的替代写法。其语义检查见 5.6。 + +### 5.2 基本表达式 + +```core +42 +3.14 +"Core" +'x' +true +() +none +(1 + 2) * 3 +``` + +### 5.3 调用、字段与下标 + +```core +result := m.add(3, 5) +p.x +arr[0] +``` + +直接命名函数与 callable 值使用同一调用语法: + +```core +f := fn.square +y := f(10) +``` + +### 5.4 函数引用与 Lambda + +命名函数作为值使用 `fn.name`: + +```core +fn square(x: int) -> int: + return x * x + +f : fn(int) -> int = fn.square +``` + +`fn.square` 是有类型 callable;`@addr(square)` 是低层机器地址。 + +表达式 lambda: + +```core +double := fn(x: int) => x * 2 +``` + +多行 lambda 使用 layout,并要求显式 `return`: + +```core +f := fn(x: int) -> int: + y := x * 2 + return y + 1 +``` + +expected type 已知时参数类型可以省略: + +```core +f : fn(int) -> int = fn(x) => x * 2 +``` + +### 5.5 转换 `as` + +```core +x : int = 3 +d : dex = x as dex +ptr : *int = addr as *int +``` + +### 5.6 管道 `|>` + +`|>` 只连接真实 pipeline 的 source / stage / sink。它不是 `f(x)` 的语法糖,也不用于普通值连续调用。 + +纵向形式: + +```core +records(path) +|> valid +|> normalize +|> store +``` + +连续形式: + +```core +records(path) |> valid |> normalize |> store +``` + +两种形式语义相同。 + +下面的写法不是 pipeline,用普通函数调用表达: + +```core +name := normalize_text(trim(user.name)) + +text := read_file(path) +cfg := parse_config(text) +``` + +不能仅因为类型首尾可连接就使用 `|>`。类型可接不等于存在 pipeline relation。HDFG 必须能够确认各端构成管道关系。 + +### 5.7 @ 内建调用 + +```core +n := @sizeOf(Point) +``` + +--- + +## 六、错误与恢复 + +错误不通过 `Result`、`Ok(...)`、`Err(...)` 或后缀 `?` 表达。可失败计算具有独立错误边;未处理错误自动向调用方传播。 + +### 6.1 产生错误 + +```core +fn parse(text: string) -> Config: + if text == "": + fail "empty input" + + return parse_impl(text) +``` + +`fail expr` 产生错误值。错误值不要求继承统一的 `Error` / `Exception` 基类。 + +### 6.2 `catch` 后置子句 + +`catch:` 位于被处理语句的下一行,与该语句处于同一 layout 层级: + +```core +fn load_config(path: string) -> Config: + text := read_file(path) + catch: + | FileNotFound => fail "config not found" + + cfg := parse_config(text) + catch: + | ParseError => fail "invalid config" + + validate_config(cfg) + return cfg +``` + +`catch` 绑定到紧邻其前的可失败表达式或语句。 + +恢复分支可以产生替代值: + +```core +cfg := parse_config(text) +catch: + | ParseError => default_config() +``` + +未匹配的错误继续自动传播: + +```core +cfg := load(path) +catch: + | FileNotFound => default_config() +``` + +如果 `load(path)` 还可能产生其他错误,它们不会被该 `catch` 吞掉。 + +`_` 可以匹配任意错误;标识符模式可以绑定错误值: + +```core +value := operation() +catch: + | KnownError => recover() + | e => log_and_fail(e) +``` + +v4 不提供 `try` 关键字,也不提供错误传播用的 `?`。 + +--- + +## 七、语句与控制流 + +### 7.1 条件 + +```core +if x > 0: + println("positive") +else if x < 0: + println("negative") +else: + println("zero") +``` + +### 7.2 循环 + +```core +for i in 0..10: + println(i) + +for item in items: + println(item) + +loop: + if done: + break + +while condition: + work() +``` + +### 7.3 匹配 + +```core +match value: + | none => println("nothing") + | x => println(x) +``` + +字符串常量分支: + +```core +match cmd: + | "start" => start_server() + | "stop" => stop_server() + | "restart" => restart_server() + | _ => println("unknown command") +``` + +`match` 臂使用 `| Pattern => Expr`。需要多行 arm body 时,`=>` 后换行并进入更深 layout: + +```core +match cmd: + | "start" => + prepare() + start_server() + | _ => println("unknown command") +``` + +### 7.4 返回 + +函数没有 implicit tail return。函数返回值必须由 `return` 明确产生。 + +```core +fn add(a: int, b: int) -> int: + return a + b +``` + +下面的写法不是返回: + +```core +fn add(a: int, b: int) -> int: + a + b +``` + +如果函数声明了非 `unit` 结果但所有可达路径没有显式 `return`,属于静态错误。 + +返回类型仍可以由所有显式 `return` 路径推导: + +```core +fn same(x: .): + return x +``` + +### 7.5 不安全区域 + +```core +unsafe: + ptr : *int = addr as *int + *ptr = 42 +``` + +--- + +## 八、函数与方法 + +### 8.1 函数定义 + +目标语法: + +```text +FunctionDecl = ['pub'] 'fn' IDENT + '(' [ParamList] ')' + ['->' Type] + ':' Layout +``` + +函数体统一由 `:` 开启,不使用 `=`、`:=`、`in` 或 `{ ... }` 作为函数体分隔符。 + +```core +fn add(a: int, b: int) -> int: + return a + b + +fn add_inferred(a: int, b: int): + return a + b + +fn identity(x: .): + return x +``` + +只有签名、没有函数体的声明不写末尾 `:`: + +```core +extern fn read(fd: int, buf: *char, len: int) -> int +``` + +接口中的方法声明同样只写签名。 + +### 8.2 方法 + +```core +impl Point: + fn norm(&self) -> dex: + return sqrt(self.x * self.x + self.y * self.y) + + fn move_by(&mut self, dx: dex, dy: dex): + self.x += dx + self.y += dy +``` + +接收者形式:`self` / `&self` / `&mut self`。 + +--- + +## 九、结构、枚举与接口 + +### 9.1 结构体 + +```core +struct User: + id: int + name: string + parent: User? +``` + +字段属于结构体 layout region,不使用逗号结束字段。 + +### 9.2 枚举 + +枚举分支使用 `|`: + +```core +enum Mode: + | Server + | Client +``` + +带 payload 的分支: + +```core +enum Message: + | Text(string) + | Data([char]) + | Closed +``` + +### 9.3 接口声明与实现 + +```core +interface Eq: + fn eq(&self, other: &Self) -> bool + +impl Eq for Point: + fn eq(&self, other: &Self) -> bool: + return self.x == other.x && self.y == other.y +``` + +接口签名中的 `Self` 指实现类型本身。 + +### 9.4 自动多态 + +```core +fn first(list: &[.]): + if list.len() > 0: + return list[0] + + return none +``` + +函数体产生的接口需求直接形成约束: + +```core +fn output(x: .): + x.print() +``` + +无需显式类型参数或泛型约束列表。 + +### 9.5 类型别名 + +```core +type Point3 = (dex, dex, dex) +``` + +类型别名只提供名称,不引入泛型参数。 + +--- + +## 十、规约 + +规约直接写在 `.cr` 中,不存在独立的 `.corespec` / `.csp` 源语言。规约只描述不能从实现唯一恢复、或需要主动保证的性质;能够从 HDFG 自动推导的性质不要求用户重复标注。`#` 同时承载规约指令与证明战术标签:前者产生证明目标,后者向证明引擎提供能力、领域知识与搜索约束。`#tag` 用于定义可复用的证明策略,不建立第二套宏语言。 + +### 10.1 `#check` / `#ensure` + +函数规约位于函数 layout region 的开头: + +```core +fn divide(a: int, b: int) -> int?: + #check(b != 0) + #ensure(result != none) + + if b == 0: + return none + + return a / b +``` + +- `#check(...)`:调用方必须满足的前提条件。 +- `#ensure(...)`:函数保证的后置条件。 +- `result` 指当前规约所描述函数的返回值。 +- `old(expr)` 指函数入口时表达式的值。 + +```core +fn transfer(from: &mut Account, to: &mut Account, amount: int): + #check(amount >= 0) + #ensure(from.balance + to.balance == old(from.balance + to.balance)) + + from.balance -= amount + to.balance += amount +``` + +### 10.2 循环规约 `#invariant` / `#variant` + +循环不变量和终止度量写在循环 region 开头: + +```core +i : int, mut = 0 + +loop: + #invariant(i >= 0 && i <= count) + #variant(count - i) + + if i == count: + break + + consume(items[i]) + i += 1 +``` + +- `#invariant(expr)`:每次进入循环与完成一次迭代后都必须保持的性质。 +- `#variant(expr)`:用于终止性证明的递减度量。 + +### 10.3 `spec fn` + +```core +spec fn valid(x: int) -> bool: + return x >= 0 +``` + +`spec fn` 使用与普通函数相同的 layout 和显式 `return` 规则,可以被 `#check`、`#ensure`、`#invariant` 等规约表达式调用。 + +### 10.4 量词与蕴含 + +规约表达式支持全称、存在量词和逻辑蕴含: + +```core +#ensure(forall(i: int) => i >= 0 ==> valid(i)) +#check(exists(i: int) => table[i] == target) +``` + +量词形式: + +```text +forall(name: Type) => SpecExpr +exists(name: Type) => SpecExpr +``` + +`==>` 是规约层蕴含运算符,优先级低于 `||`,右结合: + +```text +A ==> B ==> C +``` + +等价于: + +```text +A ==> (B ==> C) +``` + +### 10.5 证明自动化与复杂度边界 + +`spec fn` 描述**要证明什么**;证明战术标签描述证明引擎**可以使用什么能力、知识或搜索约束**。普通情况下不要求用户手写战术:验证器先根据目标结构自动选择适用能力,只有无法低成本唯一决定策略、需要缩小搜索空间或需要显式授权昂贵证明时才写标签。 + +```core +spec fn distributive(a: int, b: int, c: int) -> bool: + return a * (b + c) == a * b + a * c +``` + +若目标可被代数正规化直接关闭,验证器可以自动使用对应战术;用户不需要重复写 `#ring`。 + +Core 对自动化有一条硬复杂度边界: + +```text +ONLINE + 允许普通 corec build 隐式执行 + 必须具有已知的最坏情况 O(N) 或图上的 O(V + E) 上界 + +VERIFY + 不要求线性最坏情况保证 + 只能在显式验证阶段执行 +``` + +其中 `N` 表示当前处理对象的线性表示规模,`V` / `E` 表示 HDFG 的节点数与边数。普通构建不得因为某个规约或战术标签启动 SMT、归纳搜索、定理搜索或其他没有线性最坏情况保证的过程。 + +因此: + +```text +corec build + source + ↓ + 仅 ONLINE 分析 + ↓ + HDFG / CIR / codegen + +corec verify + 已生成的语义对象 + spec fn + ↓ + ONLINE + VERIFY 战术 + ↓ + proof / certificate + ↓ + CIC kernel +``` + +已经验证的证明结果可以作为带依赖身份的 proof artifact 缓存;后续普通构建可以读取和校验其身份,但不能为了重新得到该结果而隐式启动 VERIFY 搜索。 + +### 10.6 证明战术标签 + +证明战术标签不是命令式 proof script。它们向证明引擎提供**候选能力、领域提示或搜索限制**;证明引擎仍可以根据目标结构选择实际执行顺序,并可以在更便宜的方法已经关闭目标时忽略未使用的提示。 + +例如: + +```core +spec fn append_nil(xs: List) -> bool: + #induct(xs) + return append(xs, Nil) == xs +``` + +`#induct(xs)` 的含义是:如果当前证明需要归纳,将 `xs` 作为明确的归纳对象;它不要求验证器在读取该行时立刻执行归纳。如果化简或已有定理已经关闭目标,则不需要实际执行归纳。 + +基础战术库可以提供: + +```text +#intro +#exact(...) +#apply(...) +#cases(...) +#induct(...) +#rewrite(...) +#simp +#unfold(...) +#constructor +#split +#exists(...) +#contradiction +#auto +``` + +专用判定与求解战术可以提供: + +```text +#ring +#field +#lia +#lra +#nia +#nra +#bitvec +#congruence +#sat +#smt +``` + +这些名字描述 proof capability,不意味着它们都能进入 ONLINE。每个战术必须登记自己的执行等级、适用目标、证据形式和成本信息。 + +`#smt` 因此不再被定义为普通编译阶段的“证明通道开关”,而是一个 VERIFY 战术标签: + +```core +#smt +spec fn bounded(x: int, lo: int, hi: int) -> bool: + return x >= lo && x <= hi +``` + +它表示当前目标允许或优先使用 SMT 证明能力;`corec build` 仍不会因此启动 SMT。 + +### 10.7 Core 语义战术 + +Core 的战术库不仅包含传统逻辑战术,还可以直接读取编译器已经拥有的 HDFG 语义信息。语义战术只能**读取、裁剪和分析** HDFG,并产生子目标、可验证事实或证书;不能通过证明标签修改源程序、HDFG 或 backend mapping。 + +典型能力: + +```text +#graph.provenance(...) +#graph.dependencies(...) +#graph.reachability(...) +#graph.scc(...) +#graph.region(...) +#graph.effects(...) +#graph.alias(...) +#graph.state(...) +#graph.dataflow(...) +#graph.slice(...) + +#derive(bounds) +#derive(pure) +#derive(deterministic) +#derive(terminating) +#derive(no_alias) +#derive(noninterference) +``` + +例如: + +```core +spec fn output_independent(secret: ., output: .) -> bool: + #graph.dependencies(secret, output) + return no_dependency(secret, output) +``` + +如果相应分析属于已证明最坏情况线性的 ONLINE 能力,它可以在普通构建中生成语义事实;如果其证明过程需要非线性搜索,则只能在 VERIFY 阶段消费这些事实。 + +编译器自动推导的 `pure`、`deterministic`、`terminating`、`no_alloc`、`safe_index` 等性质首先属于内部 FactDB / 验证结果,不要求用户在普通源码中重复书写同名标签。只有需要给证明引擎增加无法自动恢复的信息时才使用显式战术标签。 + +### 10.8 `#tag` 战术策略 + +`#tag` 定义一个可复用的**证明策略(proof strategy)**。它不是宏,不进行源码文本展开、AST 替换或 hygienic substitution;标签体声明的是该策略可提供的战术能力和搜索约束。 + +无参数策略: + +```core +#tag arithmetic: + #simp + #ring + #lia + #smt +``` + +参数化策略: + +```core +#tag structural(x): + #induct(x) + #simp + #auto +``` + +使用: + +```core +spec fn append_nil(xs: List) -> bool: + #structural(xs) + return append(xs, Nil) == xs +``` + +`#tag` 的标签体是**能力集合**,不是严格的命令序列。对某个多项式恒等式,`#arithmetic` 可能只实际运行 `ring`;对另一个目标可能先化简再进入 SMT。验证器依据目标分类、适用条件、确定性与成本模型选择实际路径。 + +目标语法: + +```text +TagDecl = '#tag' IDENT ['(' [TagParamList] ')'] ':' Layout +TagParamList = IDENT (',' IDENT)* +TagUse = '#' TagPath ['(' [ArgList] ')'] +``` + +`#tag` 参数不写普通 Core 运行时类型。参数的 proof-semantic role 由其在组成战术中的使用方式推导;这些内部角色不形成 `Goal`、`Proof`、`InductionSubject` 等用户可见类型。 + +例如: + +```core +#tag structural(x): + #induct(x) + #simp +``` + +`#induct(x)` 约束 `x` 必须能够作为归纳对象;该要求在策略使用位置进行静态检查。 + +`#tag` 的硬规则: + +- 只允许出现在顶层;标签名位于独立的 tactic/tag namespace。 +- 内建战术名不能被用户 `#tag` 覆盖。 +- 标签体只能引用证明战术、证明提示或其他 `#tag` 策略。 +- `#check`、`#ensure`、`#invariant`、`#variant` 不允许进入 `#tag`;命题复用使用 `spec fn`。 +- 会改变信任边界的 `axiom`、`assume`、`admit` 一类能力不得被 `#tag` 隐藏。 +- 编译/优化/映射操作不属于 `#tag`;这类能力继续由普通语言或 `@` 编译/映射控制承担。 +- 自定义策略可以引用其他自定义策略;直接或间接形成递归环时属于静态错误。 +- 策略不产生运行时指令,不单独生成 HDFG 节点。 +- 策略不能把未证明命题变成已证明事实;所有最终结论仍必须具有 CIC 内核可复验的 proof / certificate,或显式受信机制所要求的证据。 + +### 10.9 战术执行等级与成本传播 + +每个战术至少登记: + +```text +name +applicability +execution_class ONLINE | VERIFY +complexity 已知上界或未承诺 +cost cheap | medium | expensive | unbounded +required_context +produced_evidence +``` + +组合策略的执行等级由其成员自动传播: + +```text +class(strategy) = max(class(member tactics)) +``` + +例如: + +```core +#tag memory_linear: + #graph.provenance + #graph.region +``` + +如果两个组成战术都满足 ONLINE 要求,则整个策略仍是 ONLINE。 + +```core +#tag algebra: + #simp + #ring + #smt +``` + +只要其中存在 VERIFY 战术,则整个策略是 VERIFY;它不能被伪装成普通构建中的线性自动分析。 + +VERIFY 阶段仍按照成本模型优先选择高适用性、低成本、高确定性的战术,不默认穷举所有候选。 + +必要时可以提供验证预算提示: + +```text +#budget(fast) +#budget(normal) +#budget(deep) +``` + +预算只约束 VERIFY 搜索,不改变普通 `corec build` 的线性复杂度边界。 + +### 10.10 战术库与扩展 + +战术库可以包含: + +```text +primitive tactics +semantic tactics +decision procedures +strategy tags +lemma / rewrite databases +goal classifiers +reflection procedures +``` + +标准库可以按领域组织,例如: + +```text +std::proof::logic +std::proof::arithmetic +std::proof::algebra +std::proof::collections +std::proof::graph +std::proof::memory +std::proof::concurrency +``` + +第三方战术库继续使用普通 Core 模块与包管理机制,不建立独立的 proof package manager。可见 theorem / lemma 数据库由普通 `import` 范围限制,避免默认把整个生态的规则都送入 proof search。 + + +### 10.11 元编程与证明对象不形成用户类型 + +Core 不引入 `Fragment<...>`、`Relation`、`Goal<...>`、`Proof<...>`、`Rewrite<...>` 等用户可见元对象类型。证明状态、战术参数角色、证明项、语义切片与重写对象可以存在于验证器内部,但源码仍使用普通 Core 语法、`spec fn`、`#` 战术标签和 `@` 编译/映射控制表达。 + + + +--- + +## 十一、并发与执行流 + +### 11.1 异步启动 `go` + +```core +handle := go some_work(arg1, arg2) +``` + +### 11.2 等待 `await` + +```core +result := await handle +``` + +等待关系可以由值依赖自动推导;`await` 保留为显式控制点。 + +### 11.3 长期执行流 `flow` / `yield` + +```core +flow counter(start: int) -> int: + n : int, mut = start + + loop: + yield n + n += 1 +``` + +`flow` 与普通 `fn` 一样使用 `:` 开启 layout region。 + +### 11.4 Pipeline + +`flow`、channel、stream 或其他能够形成管道关系的实体可以通过 `|>` 组合: + +```core +records(path) +|> valid +|> normalize +|> store +``` + +或者: + +```core +records(path) |> valid |> normalize |> store +``` + +是否构成合法 pipeline 由语义关系判定,不由“函数签名刚好能接上”决定。 + +--- + +## 十二、指针与 unsafe + +### 12.1 裸指针自动推断 + +普通裸指针操作不需要显式指针类型声明: + +```core +p := &arr[0] // 自动推断指向类型,并记录来源与初始偏移 +p = p + n // 指针算术继续传播 provenance / offset 关系 +x := *p // 解引用时由编译器验证可访问范围 +``` + +指针和 C 一样允许直接取地址、算术与解引用;安全性不依赖用户写生命周期、所有权类型或裸指针类型标注。PointerAnalysis、RegionCheck 与 ProvenanceVerify 从 HDFG 自动恢复并验证这些关系。 + +显式 `*T` 不是普通指针代码的必需标注。它只在类型无法从程序关系恢复时作为边界类型使用,例如整数机器地址、FFI 或固定 ABI: + +```core +unsafe: + ptr := addr as *int + *ptr = 42 +``` + +这里写 `*int` 是因为 `addr` 本身只有机器地址信息,编译器无法从来源关系推出被指向对象的类型。 + +### 12.2 unsafe region + +普通硬件能力优先通过 HIT 表达;具体机器 realization 与 HIT 实现层由 `.crasm` / backend 负责。 + +### 12.3 固定地址放置 `alloc_at` + +固定物理地址、MMIO 页或其他由外部世界给出的地址事实使用声明式放置: + +```core +mmio := alloc_at(0x7fff0000, 4096, align(4096)) +``` + +`alloc_at(addr, size, align)` 将地址、大小和对齐作为一个可追踪的分配关系送入图中;之后的 provenance、offset、边界和生命周期继续由普通指针分析处理。它不是显式区域/回收语法。 + +--- + +## 十三、@ 内建原语 + +`@` 开头的标识符是编译器能力入口,不通过标准库实现。`@` 只用于查询、编译/映射控制和低层边界;它不建立独立的元编程语言。 + +### 13.1 元数据与语义查询 + +```core +@sizeOf(Point) +@alignOf(Point) +@fields(Point) +@field(Point, "x") +@hasField(Point, "x") +@typeInfo(Point) +``` + +这些结果可以在普通 Core 的编译期执行环境中使用,不要求 `Fragment`、`Relation` 等专用元类型。 + +### 13.2 编译控制 + +```core +@inline(fn.square) +@unroll(4) +@section("text.hot") +@comptime(expr) +@fast +``` + +块形式使用普通 layout: + +```core +@comptime: + for field in @fields(User): + inspect(field) +``` + +`@fast` 是优化提示;忽略它不能改变程序语义。允许结果近似使用 `apx`,不由 `@fast` 授权。 + +### 13.3 函数地址 + +```core +@addr(square) +``` + +`@addr(square)` 返回机器地址;普通函数值使用 `fn.square`。 + +### 13.4 安全检查 + +```core +@NoBoundsCheck +``` + +`@NoBoundsCheck` 只用于调用方明确承担边界安全责任的低层区域。 + +### 13.5 FFI + +C ABI 是 `extern fn` 的默认外部接口;需要指定其他运行时互操作方式时使用 `@ffi(...)`: + +```core +extern fn write(fd: int, buf: *char, len: int) -> int + +@ffi("Python") +extern fn py_call(obj: dyn, method: string) -> dyn + +@ffi("Java") +extern fn java_call(env: dyn, obj: dyn, method: string) -> dyn +``` + +`@ffi` 描述外部调用边界的编组/ABI 方式,不引入另一种 Core 类型系统。 + +### 13.6 Hotpatch + +函数多版本共存使用 `@hotpatch(...)`: + +```core +@hotpatch(ver=1) +fn handle(x: dyn) -> dyn: + return handle_v1(x) + +@hotpatch(ver=2) +fn handle(x: dyn) -> dyn: + return handle_v2(x) +``` + +所有同名 hotpatch 版本必须保持兼容签名;版本选择与 rollout 属于运行时映射,不改变调用处的源语言类型。 + +### 13.7 异构执行域 + +异构执行默认完全自动:没有注解时,编译器根据 HDFG、HIT 能力、拓扑、数据驻留和代价模型选择执行域。源码只在确实需要约束映射时写注解。 + +软偏好: + +```core +@preferredDomain(gpu) +fn transform(data: [dex]) -> [dex]: + return compute(data) +``` + +`@preferredDomain(name)` 表示优先映射到该逻辑执行域;不可用或代价不合适时允许回退。 + +硬约束: + +```core +@executionDomain(fpgaA) +flow encode(input: Frame) -> Packet: + yield encode_frame(input) +``` + +`@executionDomain(name)` 要求映射到指定逻辑执行域;目标不存在或不能满足该 region 的语义要求时必须报错,不得静默回退。 + +注解也可以约束局部执行 region: + +```core +@preferredDomain(gpu) +loop: + process_batch() +``` + +执行域名由部署环境提供,不是语言内建类型。`gpu`、`fastCpu`、`fpgaA`、`remoteNode7` 等都只是逻辑 domain 名称。Core 不提供 CUDA 风格 kernel 语法,也不要求显式 memcpy/host-device transfer;数据 residency、materialization 和传输由 Execution Mapping 与 HIT 决定。 + +映射模式只有三种: + +```text +无注解 AUTO +@preferredDomain(name) PREFER +@executionDomain(name) REQUIRE +``` + +这些注解只约束 realization/mapping,不改变函数、flow、loop 或 region 在 HDFG 中的语义身份。 diff --git a/docs/developer/at-intrinsics.md b/docs/developer/at-intrinsics.md index 0f2d9470..0a200bed 100644 --- a/docs/developer/at-intrinsics.md +++ b/docs/developer/at-intrinsics.md @@ -1,6 +1,6 @@ # Core @ 内建原语 -> 定位:受众 = 开发者;状态 = active(12 个内建已实现,2026-07-28 完整落地;语义契约见 docs/maintainer/design/ir-op-semantics.md §2.8/§4)。 +> 定位:受众 = 开发者;状态 = active(12 个内建已实现,2026-07-28 完整落地;语义契约见 `docs/maintainer/design/ir-op-semantics.md` §2.8/§4)。 `@` 是编译器提供的能力入口,不通过标准库实现。分三类: diff --git a/docs/developer/concepts.md b/docs/developer/concepts.md index 9a318ce1..e7b241ad 100644 --- a/docs/developer/concepts.md +++ b/docs/developer/concepts.md @@ -1,7 +1,7 @@ # 核心概念导览 -> 定位:受众 = 开发者(理解 Core 的设计思维);状态 = active。 -> 四篇分篇各讲一个概念(每篇末有深入链接);本文是入口与一句话总览。 +> 定位:受众 = 开发者(理解 Core 的设计思维);状态 = active。 +> 四篇分篇各讲一个概念(每篇末有深入链接);本文是入口与一句话总览。 ## 四个概念 @@ -12,13 +12,13 @@ | 部署与代码分离 | 物理世界(内存策略/OS/时间源)进部署配置,不进代码 | [concepts/deploy.md](concepts/deploy.md) | | 规约内联验证 | #check/#ensure 写在函数上,验证不用学第二门语言 | [concepts/spec.md](concepts/spec.md) | -## 为什么这些概念成立:语义保鲜 +## 共同基础:语义保鲜 -编译中间表示(IR)保留全部类型与语义信息,不逐级降格为机器指令——验证器消费 IR 即获得完整语义模型。这是 Core 支持形式化验证、跨平台行为一致、范式可迁移(经典/量子/…)的共同基础。 +编译中间表示(IR)保留全部类型与语义信息,不逐级降格为机器指令——验证器消费 IR 即获得完整语义模型。这是 Core 支持形式化验证、跨平台行为一致、范式可迁移(经典/量子/…)的共同基础。 ## 阅读建议 -- 第一次接触:先 [tutorial.md](tutorial.md) 上手,概念随阶段展开 -- 想理解设计:读四个分篇 -- 语法细节:[syntax.md](syntax.md) -- 术语表:`../glossary.md`(一般不需要查——本文只用开发者术语) +- 初次接触:先读 [tutorial.md](tutorial.md) 上手,概念随阶段展开 +- 设计理解:读四个分篇 +- 语法细节:[syntax.md](syntax.md) +- 术语表:`../glossary.md`(一般不需要查——本文只用开发者术语) diff --git a/docs/developer/concepts/deploy.md b/docs/developer/concepts/deploy.md index 505fc5e5..c7cfc7fb 100644 --- a/docs/developer/concepts/deploy.md +++ b/docs/developer/concepts/deploy.md @@ -1,12 +1,12 @@ -# 概念:部署配置与代码分离 +# 概念:部署配置与代码分离 -> 定位:受众 = 开发者;状态 = active(部分落地,见注)。 +> 定位:受众 = 开发者;状态 = active(部分落地,见注)。 ## 一条原则 -**代码描述计算;物理世界不进代码。** +**代码描述计算;物理世界不进代码。** -内存能否动态分配、有几个核、有没有 OS——这些不属于程序语义,属于部署目标。Core 用部署配置(TOML)声明它们: +内存能否动态分配、有几个核、有没有 OS——这些不属于程序语义,属于部署目标。Core 用部署配置(TOML)声明它们: ```toml [deploy.mcu] @@ -18,24 +18,24 @@ target = "x86-64-linux" allocation = "dynamic" ``` -同一份代码: +同一份代码: -- 教学环境 → 解释执行,可单步 -- 桌面 → 原生二进制(ELF) -- 裸机 → 静态分配,零运行时 -- (设计态)集群 → 图跨机部署 +- 教学环境 → 解释执行,可单步 +- 桌面 → 原生二进制(ELF) +- 裸机 → 静态分配,零运行时 +- (设计态)集群 → 图跨机部署 代码不改。语义不变。部署配置不同。 -## 平台接口同理 +## 平台接口的同一原则 -I/O、时钟、随机、哈希在语言层是**语义接口**——程序的 I/O 语义是"流变换"(输入流 → 输出流),系统调用是后端按部署目标实现的物理细节。验证意义上 I/O 是一等公民,不是黑洞。 +I/O、时钟、随机、哈希在语言层是**语义接口**——程序的 I/O 语义是「流变换」(输入流 → 输出流),系统调用是后端按部署目标实现的物理细节。验证意义上 I/O 是一等公民,不是黑洞。 ## 现状注记 -部署配置文件的消费范围与平台桥(IO/时钟语义接口)落地按 TODO 推进——当前以源码行为为准,`deploy.toml` 的字段语义见各示例与维护者文档。 +部署配置文件的消费范围与平台桥(IO/时钟语义接口)落地按 TODO 推进——当前以源码行为为准,`deploy.toml` 的字段语义见各示例与维护者文档。 ## 延伸 -- `../../maintainer/design/execution-model.md` §五(设计定稿) -- examples/pi(deploy.toml 示例) +- `../../maintainer/design/execution-model.md` §五(设计定稿) +- examples/pi(deploy.toml 示例) diff --git a/docs/developer/concepts/graph.md b/docs/developer/concepts/graph.md index b09dfe8f..783392d7 100644 --- a/docs/developer/concepts/graph.md +++ b/docs/developer/concepts/graph.md @@ -1,10 +1,10 @@ -# 概念:程序 = 一张图 +# 概念:程序 = 一张图 -> 定位:受众 = 开发者;状态 = active。 +> 定位:受众 = 开发者;状态 = active。 -## 图是什么 +## 图的结构 -Core 编译后的程序不是"指令序列",而是一张**数据流图**:节点是操作(取址、解引用、算术、调用),边是值的流动。控制流不是另加的机制,而是图的结构: +Core 编译后的程序不是「指令序列」,而是一张**数据流图**:节点是操作(取址、解引用、算术、调用),边是值的流动。控制流不是另加的机制,而是图的结构: | 代码 | 图上 | |---|---| @@ -13,9 +13,9 @@ Core 编译后的程序不是"指令序列",而是一张**数据流图**:节点 | loop/for | 一条环:值绕环流动,每圈=一次迭代 | | go | 运行时从当前节点长出并行子图 | -## 对写代码意味着什么 +## 对编码的影响 -**不需要"模式"概念。** 没有 debug/release/并发模式切换——代码写了什么,图就反映什么。学习、单步、并发是同一张图的不同看法: +**不需要「模式」概念。** 没有 debug/release/并发模式切换——代码写了什么,图就反映什么。学习、单步、并发是同一张图的不同看法: - 单步调试 = 沿图走值 - 并发 = 图上有并行的子图 @@ -23,9 +23,9 @@ Core 编译后的程序不是"指令序列",而是一张**数据流图**:节点 ## 表达力上限 -图的表达不限于经典机器能执行的顺序:非因果/概率/模糊语义在图上都有标注位置(设计态,超出本文范围;术语见 `../../glossary.md`)。 +图的表达不限于经典机器能执行的顺序:非因果/概率/模糊语义在图上都有标注位置(设计态,超出本文范围;术语见 `../../glossary.md`)。 ## 延伸 -- 图的执行与并发细节:`../../maintainer/design/execution-model.md`(维护者视角,可选) -- 语法如何映射到图:tutorial 各阶段"图模型"栏 +- 图的执行与并发细节:`../../maintainer/design/execution-model.md`(维护者视角,可选) +- 语法到图的映射:tutorial 各阶段「图模型」栏 diff --git a/docs/developer/concepts/memory.md b/docs/developer/concepts/memory.md index f9bf10f7..99ba21e9 100644 --- a/docs/developer/concepts/memory.md +++ b/docs/developer/concepts/memory.md @@ -1,18 +1,18 @@ -# 概念:内存——自动、无 GC、无标注 +# 概念:内存——自动、无 GC、无标注 -> 定位:受众 = 开发者;状态 = active(arena 已实现;区域机制设计态见注)。 +> 定位:受众 = 开发者;状态 = active(arena 已实现;区域机制设计态见注)。 -## 不用学 borrow checker +## 内存安全:无须 borrow checker -Core 的内存管理与 Rust 不同路:Rust 用类型层的借用规则(需要你学与标注),Core 由编译器在图上自动验证指针安全。你写指针和 C 一样自由,编译器负责:越界、悬垂、生命周期。 +Core 的内存管理与 Rust 不同路:Rust 用类型层的借用规则(需要学习与标注),Core 由编译器在图上自动验证指针安全。指针的写法与 C 一样自由,编译器负责越界、悬垂、生命周期。 -## 内存怎么回收:子图区域 +## 回收机制:子图区域 -内存按**子图区域**管理: +内存按**子图区域**管理: - 每个函数/循环有独立内存区域 -- 区域内分配 = 指针碰撞,O(1) -- 子图结束 → 区域整体重置回收,O(1),无 GC 停顿 +- 区域内分配 = 指针碰撞,O(1) +- 子图结束 → 区域整体重置回收,O(1),无 GC 停顿 ```core fn process_batch(items: [int]) -> int { @@ -24,16 +24,16 @@ fn process_batch(items: [int]) -> int { } ``` -`go` 启动的并发子图各有独立区域,退出整块回收。 +`go` 启动的并发子图各有独立区域,退出整块回收。 ## 长期服务的内存上限 -内存上限 = 并发子图数 × 区域容量——可预测,无 GC 停顿。区域复用/清零策略(敏感数据)为部署配置控制(非默认)。 +内存上限 = 并发子图数 × 区域容量——可预测,无 GC 停顿。区域复用/清零策略(敏感数据)为部署配置控制(非默认)。 ## 现状注记 -子图 arena 已实现;区域机制的扩展形态(split/merge/size class 等)为设计态,按 TODO 推进——当前以源码行为为准。 +子图 arena 已实现;区域机制的扩展形态(split/merge/size class 等)为设计态,按 TODO 推进——当前以源码行为为准。 ## 延伸 -- 实现与理论:`../../maintainer/design/region-model.md`、`../../academic/cache-semantics.md`(学术,可选) +- 实现与理论:`../../maintainer/design/region-model.md`、`../../academic/cache-semantics.md`(学术,可选) diff --git a/docs/developer/concepts/spec.md b/docs/developer/concepts/spec.md index ffdbb02a..25b33ff3 100644 --- a/docs/developer/concepts/spec.md +++ b/docs/developer/concepts/spec.md @@ -1,10 +1,10 @@ -# 概念:规约——验证不换语言 +# 概念:规约——验证不换语言 -> 定位:受众 = 开发者;状态 = 设计定稿(未实现——见注)。 +> 定位:受众 = 开发者;状态 = 设计定稿(未实现——见注)。 -## 写性质,不用学逻辑语言 +## 性质表达:不引入独立逻辑语言 -Core 的验证入口写在函数上,表达式就是 Core 表达式: +Core 的验证入口写在函数上,表达式就是 Core 表达式: ```core fn divide(a: int, b: int) -> int? @@ -16,27 +16,27 @@ fn divide(a: int, b: int) -> int? } ``` -- `#check(...)`:调用方义务 -- `#ensure(...)`:实现方保证;`result` = 返回值,`old(x)` = 入口时的值 -- `spec fn`:表达复杂性质用纯 Core 写的检查函数(验证的标准) +- `#check(...)`:调用方义务 +- `#ensure(...)`:实现方保证;`result` = 返回值,`old(x)` = 入口时的值 +- `spec fn`:表达复杂性质用纯 Core 写的检查函数(验证的标准) ## 三层自动化的哲学 -1. 编译器自动推导能推导的一切(`#pure`/`#terminating` 等标签——不用你写) -2. 推导不出的简单性质:一行 `#check`/`#ensure` -3. 复杂性质:`spec fn`——还是 Core,不是公式 +1. 编译器自动推导能推导的一切(`#pure`/`#terminating` 等标签——无须手写) +2. 推导不出的简单性质:一行 `#check`/`#ensure` +3. 复杂性质:`spec fn`——仍是 Core,不是公式 -验证的回报不只是安全:证明过的性质可流回优化器(证明驱动优化,设计态)——写的证明越多,优化越狠。 +验证的回报不只是安全:证明过的性质可流回优化器(证明驱动优化,设计态)——写的证明越多,优化越强。 -## 为什么可行:语义保鲜 +## 可行性:语义保鲜 -编译中间表示保留全部语义——验证器消费 IR 即获得完整程序语义模型,不需要你为验证重写一遍程序,也不需要验证器自己猜语义。 +编译中间表示保留全部语义——验证器消费 IR 即获得完整程序语义模型,不需要为验证重写程序,也不需要验证器自行推测语义。 ## 现状注记 -规约语法(#check/#ensure/.cr 内联)为 2026-09 设计定稿;**语法与验证管线均未实现**——当前标注不改变运行行为。推进见 TODO 与 `../../maintainer/design/spec-design.md`。 +规约语法(`#check`/`#ensure`/`.cr` 内联)为 2026-09 设计定稿;**语法与验证管线均未实现**——当前标注不改变运行行为。推进见 TODO 与 `../../maintainer/design/spec-design.md`。 ## 延伸 -- 语法参考:`../syntax.md` 第十章 -- 系统设计:`../../maintainer/design/spec-design.md` +- 语法参考:`../syntax.md` 第十章 +- 系统设计:`../../maintainer/design/spec-design.md` diff --git a/docs/developer/editors.md b/docs/developer/editors.md index 3580393a..4dd19068 100644 --- a/docs/developer/editors.md +++ b/docs/developer/editors.md @@ -1,7 +1,7 @@ # 编辑器接入配置(corelsp) > 定位:受众 = 开发者;状态 = active;corelsp 行为以 [maintainer/design/corelsp.md](../maintainer/design/corelsp.md) 为准(实现与文档冲突时以源码为准);仓库内编辑器素材见 [editor/](../../editor/)(扩展源码与说明)。 -> 本文是纯用户向接入指南——各编辑器怎么接 corelsp;corelsp 的架构(检查管线/诊断通道/能力契约)见 [maintainer/design/corelsp.md](../maintainer/design/corelsp.md)。 +> 本文是纯用户向接入指南——各编辑器的 corelsp 接入步骤;corelsp 的架构(检查管线/诊断通道/能力契约)见 [maintainer/design/corelsp.md](../maintainer/design/corelsp.md)。 corelsp 是 Core 语言的语言服务器(标准 LSP 协议,stdio 管道)。接入后编辑器可获得: @@ -32,7 +32,7 @@ vim.lsp.start({ }) ``` -### 健壮版(任意 cwd,自动定位项目根) +### 健壮形态(任意 cwd,自动定位项目根) ```lua -- after/ftplugin/core.lua @@ -79,7 +79,7 @@ code --install-extension editor/vscode-core/ 1. Zed → Extensions(扩展)面板 → **Install Dev Extension(安装开发扩展)** → 选择 `~/core-plugin-zed` 2. 打开 `.cr` 文件:语法高亮 + 诊断 + 悬停 + F12 跳转 + `@` 补全 + 语义着色全部生效 -扩展结构:`extension.toml`(`[lib]` + `language_servers` 段)、`src/lib.rs`(`language_server_command` → corelsp 绝对路径)、`languages/core/config.toml`(`language_servers = ["corelsp"]`)、`grammars/`(语法)。**命令路径在 Rust 代码里**(`~/core-plugin-zed/src/lib.rs`)——纯 TOML 无法指定,这是 Zed 扩展的机制约束。构建:`cargo build --release --target wasm32-wasip1` → `extension.wasm`。 +扩展结构:`extension.toml`(`[lib]` + `language_servers` 段)、`src/lib.rs`(`language_server_command` → corelsp 绝对路径)、`languages/core/config.toml`(`language_servers = ["corelsp"]`)、`grammars/`(语法)。**命令路径位于 Rust 代码中**(`~/core-plugin-zed/src/lib.rs`)——纯 TOML 无法指定,这是 Zed 扩展的机制约束。构建:`cargo build --release --target wasm32-wasip1` → `extension.wasm`。 ### 方式二:settings.json(无扩展时的 LSP 兜底) diff --git a/docs/developer/errors.md b/docs/developer/errors.md index 0a3abed7..80f5eede 100644 --- a/docs/developer/errors.md +++ b/docs/developer/errors.md @@ -1,7 +1,7 @@ # Core 错误码参考 -> 定位:受众 = 开发者;状态 = active。 -> 出处:错误码数值与注释名 = src/compiler/ast.cr 的 EC_* 常量(每码唯一检查点,注释带本文编号,如 `EC_P_EXPECTED = 1001 // P001`);**词法族(L 族)例外**——lexer.cr 的 add_error 只传消息文本不带码,L 码为本文档侧编号,以消息文本为准。改码须同步 ast.cr 注释与本文。 +> 定位:受众 = 开发者;状态 = active。 +> 出处:错误码数值与注释名 = `src/compiler/ast.cr` 的 `EC_*` 常量(每码唯一检查点,注释带本文编号,如 `EC_P_EXPECTED = 1001 // P001`);**词法族(L 族)例外**——`lexer.cr` 的 `add_error` 只传消息文本不带码,L 码为本文档侧编号,以消息文本为准。改码须同步 `ast.cr` 注释与本文。 > **fail-closed 语义(2026-09-15,FC 批 T2 起)**:**默认阻断**——任何**不在豁免登记表**内的 > 类型面诊断 ⇒ `rc=1` + **零产物**(不落目标 ELF、不落本次 `.ccr`)。豁免表 = @@ -14,9 +14,9 @@ --- -## L0xx — 词法 (Lexer) +## L0xx — 词法(Lexer) -> 注:本族码无数值常量(lexer add_error 不带码)——以消息模板为准,码为文档侧编号。 +> 注:本族码无数值常量(lexer 的 `add_error` 不带码)——以消息模板为准,码为文档侧编号。 | 码 | 检查点 | 消息模板 | 触发条件 | |----|--------|---------|---------| @@ -32,7 +32,7 @@ | L010 | 小数后缀非法(f32/f64 = apx 的 CPU 位宽标注) | `Invalid float suffix: {suffix}` | 非 f32/f64 后缀 | | L011 | 无法识别的字符 | `Unknown character: '{c}'` | 源码中出现 ASCII 控制字符或全角空格等 | -## P0xx — 语法 (Parser) +## P0xx — 语法(Parser) | 码 | 检查点 | 消息模板 | |----|--------|---------| @@ -67,7 +67,7 @@ > (打印器取 `码 % 1000`)。三者均属**语法族(P 族)** ⇒ 按本文件开头的 fail-closed 语义:**前端任一即 `rc=1` + 零产物** > (不进入 lower / 不写 `.ccr` / 不产 ELF)。出处(本轮实读,`develop` = `662ff87d`):`ast.cr` 常量三行 + `parser.cr` 三处 `check_error` 调用点。 -## N0xx — 名字解析 (Name Resolution) +## N0xx — 名字解析(Name Resolution) | 码 | 检查点 | 消息模板 | |----|--------|---------| @@ -93,7 +93,7 @@ | N020 | 导入文件读取失败 | `Failed to read import '{id}'` | | N021 | 符号重导出冲突 | `Name '{name}' re-exported from multiple modules` | -## I0xx — 类型推断 (Inference) +## I0xx — 类型推断(Inference) | 码 | 检查点 | 消息模板 | |----|--------|---------| @@ -106,7 +106,7 @@ ## TA0xx — 类型检查:赋值与绑定 -> TA02 自 2026-09-13(R2 P5 Task 6 / TODO #2026-09-11-14)起**实现**并列入 run_frontend 硬错误名单 +> TA02 自 2026-09-13(R2 P5 Task 6 / TODO #2026-09-11-14)起**实现**并列入 `run_frontend` 硬错误名单 > (rc=1 且不产出产物):修复前 `EXPR_LET` 站点**无任何兼容检查**(符号取注解行、后端按注解 > 行发射 = 静默错产物;`EC_TA_DECL` 定义零 raise)。判定点 = `checker.cr::check_let_annot_compat` > (局部 `EXPR_LET` + 全局 `check_global_let` 两调用点共用),组合函数 = `type_compat_strict` @@ -209,7 +209,7 @@ ## TS0xx — 类型检查:结构体字面量 -> 四码自 2026-09-11(TODO #2026-09-11-11)起**全部实现**并列入 run_frontend 硬错误名单(rc=1 且不产出 +> 四码自 2026-09-11(TODO #2026-09-11-11)起**全部实现**并列入 `run_frontend` 硬错误名单(rc=1 且不产出 > 产物):修复前字段名被丢弃(值按声明位序绑定 = 静默错值),四校验均不存在。字段值现按 > **名字**绑定(与 Python bootstrap 的 gen_struct_lit 同语义;求值顺序仍为源序)。 diff --git a/docs/developer/examples.md b/docs/developer/examples.md index 5fa33e99..83cf6c61 100644 --- a/docs/developer/examples.md +++ b/docs/developer/examples.md @@ -1,6 +1,6 @@ # 示例集 -> 定位:受众 = 开发者;状态 = active。仓库 examples/ 的可跑程序,按复杂度排列。 +> 定位:受众 = 开发者;状态 = active。仓库 `examples/` 的可跑程序,按复杂度排列。 ## 运行方式 @@ -9,7 +9,7 @@ /tmp/ ``` -或先检查:`./build/corec check examples//main.cr` +或先检查:`./build/corec check examples//main.cr` ## 示例清单 @@ -20,11 +20,11 @@ | [pi](../../examples/pi/main.cr) | 圆周率计算 | 数值循环(带 deploy.toml 的部署配置示例) | | [load_balancer](../../examples/load_balancer/main.cr) | 负载均衡器 | 并发/任务分发方向(含 spec/ 规约骨架) | -> 注:examples/hello/ 目前是空骨架(未填 main)——忽略或用 add/ 起步。 +> 注:`examples/hello/` 目前是空骨架(未填 `main`)——忽略或用 `add/` 起步。 -## 更多示例:测试套件(tests/suite/) +## 更多示例:测试套件(tests/suite/) -仓库测试套件的 .cr 文件是按主题组织的可跑示例(覆盖更广): +仓库测试套件的 `.cr` 文件是按主题组织的可跑示例(覆盖更广): | 主题 | 文件 | |---|---| @@ -35,14 +35,14 @@ | 内存/指针 | ptr_arith.cr、ptr_ref_first.cr、arena_test.cr | | FFI/热补丁/惰性 | ffi_test.cr、hotpatch_test.cr、lazy_test.cr | -> 注:套件文件可能依赖测试驱动(检查点/期望输出)——作示例阅读时关注语言用法,运行请走测试入口(见 `../maintainer/testing.md`)。 +> 注:套件文件可能依赖测试驱动(检查点/期望输出)——作示例阅读时关注语言用法,运行请走测试入口(见 `../maintainer/testing.md`)。 ## 配套 -- 每个示例目录可能带 `.cir`/`.ccr`/`.s`/`prog`——构建副产物,手工分步调试时对照用 -- 完整编译产物链:`.cr` →(corec)→ `.cir`(图形态)+ `.ccr`(格形态)→(corearch)→ ELF +- 每个示例目录可能带 `.cir`/`.ccr`/`.s`/`prog`——构建副产物,手工分步调试时对照用 +- 完整编译产物链:`.cr` →(corec)→ `.cir`(图形态)+ `.ccr`(格形态)→(corearch)→ ELF ## 建议下一步 -写自己的程序时:类型检查循环(`check`)先行,`run` 试小段,`build` 出产物。 -语法速查见 [syntax.md](syntax.md);构建与命令见 [quickstart.md](quickstart.md)。 +写自己的程序时:类型检查循环(`check`)先行,`run` 试小段,`build` 出产物。 +语法速查见 [syntax.md](syntax.md);构建与命令见 [quickstart.md](quickstart.md)。 diff --git a/docs/developer/faq.md b/docs/developer/faq.md index 57cc7a9b..55c2396a 100644 --- a/docs/developer/faq.md +++ b/docs/developer/faq.md @@ -1,50 +1,50 @@ -# 常见问题(FAQ) +# 常见问题(FAQ) -> 定位:受众 = 开发者;状态 = active。答案以当前实现为准;标注"设计态"的条目尚未落地。 +> 定位:受众 = 开发者;状态 = active。答案以当前实现为准;标注「设计态」的条目尚未落地。 ## 语言与设计 -**Core 和 Rust 什么关系?为什么没有 borrow checker?** -Rust 用借用检查在类型层保证内存安全,代价是学习曲线与表达力约束。Core 的指针安全由编译器在数据流图上自动验证(来源追踪 + 边界核对)——你不需要标注生命周期。Rust 是启发,不是基础:语言从图模型独立设计。 +**与 Rust 的关系及无 borrow checker 的原因** +Rust 用借用检查在类型层保证内存安全,代价是学习曲线与表达力约束。Core 的指针安全由编译器在数据流图上自动验证(来源追踪 + 边界核对)——不需要标注生命周期。Rust 是启发,不是基础:语言从图模型独立设计。 -**"语义保鲜"是什么?** -编译中间表示(IR)保留全部类型与语义信息,不逐级降格为机器指令。验证器消费 IR 即获得完整语义模型——这是 Core 支持形式化验证、跨平台行为一致、范式可迁移(经典/量子/…)的共同基础。通俗说:编译器不把"程序是什么"丢掉。 +**语义保鲜的含义** +编译中间表示(IR)保留全部类型与语义信息,不逐级降格为机器指令。验证器消费 IR 即获得完整语义模型——这是 Core 支持形式化验证、跨平台行为一致、范式可迁移(经典/量子/…)的共同基础。换言之,编译器不丢弃「程序是什么」。 -**没有 GC,内存谁回收?** -子图区域(arena):函数/循环结束,它的内存区域整块回收——O(1) 重置游标,无停顿。长期服务的内存上限 = 并发子图数 × 区域容量。 +**无 GC 的内存回收** +子图区域(arena):函数/循环结束,其内存区域整块回收——O(1) 重置游标,无停顿。长期服务的内存上限 = 并发子图数 × 区域容量。 -**部署配置里 allocation = "static"/"dynamic" 是什么?** -代码不决定内存策略;部署目标声明。static 目标(裸机)要求所有大小编译期可定;dynamic 目标允许运行时分配。同一份代码两种部署都成立时,它就两头都能跑。 +**部署配置中的 allocation = "static"/"dynamic"** +代码不决定内存策略;部署目标声明。static 目标(裸机)要求所有大小编译期可定;dynamic 目标允许运行时分配。同一份代码在两种部署下都成立时,它即可在两类目标上运行。 ## 使用 -**怎么跑第一个程序?** -见 [quickstart.md](quickstart.md)——`python3 build_selfhost_native.py` 构建,`./build/corec build` 编译,`run` 内联执行。 +**第一个程序的运行** +见 [quickstart.md](quickstart.md)——`python3 build_selfhost_native.py` 构建,`./build/corec build` 编译,`run` 内联执行。 -**check / build / run / cir / ccr 什么区别?** -`check` 只做类型检查;`run` 解释器内联执行(不产文件);`build` 全链到 ELF;`cir`/`ccr` 输出中间 IR(研究/调试)。 +**check / build / run / cir / ccr 的区别** +`check` 只做类型检查;`run` 解释器内联执行(不产文件);`build` 全链到 ELF;`cir`/`ccr` 输出中间 IR(研究/调试)。 -**为什么我打印不出东西?** -先确认用了标准库的 print/println(实现在 src/stdlib/io.cr;模块导入与目录级批量导入规则见 syntax.md 模块章)。注意:裸 `fn main()->int{return 42;}` 没有输出是**正常的**——main 返回值 = 进程退出码,不是打印。 +**print 无输出的排查** +先确认使用了标准库的 print/println(实现在 `src/stdlib/io.cr`;模块导入与目录级批量导入规则见 `syntax.md` 模块章)。注意:裸 `fn main()->int{return 42;}` 没有输出属**正常**——main 返回值 = 进程退出码,不是打印。 -**编译很慢/风扇很响?** -自举编译是 CPU 密集任务;长时间构建(无人值守)建议 `nice -n 19` 或 `cpulimit -l 10` 限速——交互式短任务不必。 +**编译耗时与资源占用** +自举编译是 CPU 密集任务;长时间构建(无人值守)建议 `nice -n 19` 或 `cpulimit -l 10` 限速——交互式短任务不必。 -**corec2 是什么?为什么我 check 会卡住?** -corec2 = 自举的第二代前端产物(自编译验证用)。它曾有 tokenizer 死循环已知问题(全局变量注册缺陷,见 TODO)——日常开发请用 `./build/corec`,不要用 corec2。 +**corec2 及其 check 卡顿问题** +corec2 = 自举的第二代前端产物(自编译验证用)。它曾有 tokenizer 死循环已知问题(全局变量注册缺陷,见 TODO)——日常开发请用 `./build/corec`,不要用 corec2。 > 修订(2026-09-24):该问题**不再作为阻塞项**——`corec2` 链可跑通且逐字节稳定(`corec2 == corec3` IDENTICAL;由 `src/ci/run.sh` 的 `full-bootstrap` job 覆盖)。原文保留供追溯。 ## 状态相关 -**哪些功能还没实现?** -语言与编译器在活跃自举期。已知设计态/挂账:验证管线(规约证明)、平台桥(IO/时钟语义接口落地)、惰性求值、分布式、部署配置完整消费、.ccr 内容随 v9 段表推进(版本以 `src/compiler/ccr_io.cr` 的 `CCR_VERSION` 为准)。最新状态看仓库 TODO.md 与各文档头部"状态"。 +**未实现功能** +语言与编译器在活跃自举期。已知设计态/挂账:验证管线(规约证明)、平台桥(IO/时钟语义接口落地)、惰性求值、分布式、部署配置完整消费、.ccr 内容随 v9 段表推进(版本以 `src/compiler/ccr_io.cr` 的 `CCR_VERSION` 为准)。最新状态见仓库 `TODO.md` 与各文档头部「状态」。 -**float 呢?** -float 已退役(2026-08,dex/apx 定案)——精确小数用 `dex`,近似授权用 `apx`。历史遗留的 float 代码需迁移(见 ADR-0010)。 +**float 的现状** +`float` 已退役(2026-08,dex/apx 定案)——精确小数用 `dex`,近似授权用 `apx`。历史遗留的 `float` 代码需迁移(见 ADR-0010)。 -**.corespec 文件还有用吗?** -没有——独立规约格式 2026-09 退役,规约写成 .cr 内联 #check/#ensure(设计态,见 ADR-0001)。 +**.corespec 文件的现状** +无用途——独立规约格式 2026-09 退役,规约写成 `.cr` 内联 `#check`/`#ensure`(设计态,见 ADR-0001)。 ## 相关 diff --git a/docs/developer/quickstart.md b/docs/developer/quickstart.md index 9c5aef94..ce7976b5 100644 --- a/docs/developer/quickstart.md +++ b/docs/developer/quickstart.md @@ -1,24 +1,24 @@ # 快速开始 -> 定位:受众 = 开发者(第一次接触 Core);状态 = active。 -> 前提:Linux(x86-64)、Python 3、一个终端。构建与运行的全部命令以仓库 CLAUDE.md 为准。 +> 定位:受众 = 开发者(第一次接触 Core);状态 = active。 +> 前提:Linux(x86-64)、Python 3、一个终端。构建与运行的全部命令以仓库 `CLAUDE.md` 为准。 ## 一、构建编译器 -Core 编译器由 Core 自身编写(自举),用 Python bootstrap 构建出原生二进制: +Core 编译器由 Core 自身编写(自举),用 Python bootstrap 构建出原生二进制: ```bash # 在仓库根目录 python3 build_selfhost_native.py ``` -产物:`build/corec`(前端:源码 → IR)→ `build/corearch`(后端:IR → ELF)。 +产物:`build/corec`(前端:源码 → IR)→ `build/corearch`(后端:IR → ELF)。 -> 提示:构建是编译密集型任务,慢机器上可用 `nice -n 19` 降优先级。产物尚不随仓库分发——需要自己构建(发行打包见 PKGBUILD 方向)。 +> 提示:构建是编译密集型任务,慢机器上可用 `nice -n 19` 降优先级。产物尚未随仓库分发——需自行构建(发行打包见 PKGBUILD 方向)。 ## 二、第一个程序 -`examples/add/main.cr` 是最小完整程序: +`examples/add/main.cr` 是最小完整程序: ```core fn add(a: int, b: int) -> int { @@ -29,7 +29,7 @@ fn main() -> int { } ``` -`main` 的返回值 = 进程退出码(所以这个程序"运行成功" = 退出码 7)。 +`main` 的返回值 = 进程退出码(因此该程序「运行成功」 = 退出码 7)。 ## 三、三种运行方式 @@ -45,7 +45,7 @@ fn main() -> int { /tmp/add; echo $? # 打印退出码 7 ``` -`build` 会自动调用后端产出 ELF;也可手工分步:`./build/corec ccr file.cr` 出中间 IR,`./build/corearch file.ccr --elf --static -o out` 出二进制(调试后端时有用)。 +`build` 会自动调用后端产出 ELF;也可手工分步:`./build/corec ccr file.cr` 出中间 IR,`./build/corearch file.ccr --elf --static -o out` 出二进制(调试后端时有用)。 ## 四、目录导览 @@ -57,12 +57,12 @@ fn main() -> int { | examples/ | 示例程序(add/complex/pi/load_balancer 等,见 examples.md) | | tests/ | 测试三套(bootstrap/selfhost/suite) | -> 注:examples/hello/ 目前是空骨架——用 add/ 或自建文件开始。 -> 注:`src/arch/linux/ld/`(原来的 ELF 后端)**已退役**,后端现在按三轴分目录,组合根在 `src/targets/x86_64-linux/`(2026-09-24 更正)。 +> 注:`examples/hello/` 目前是空骨架——用 `add/` 或自建文件开始。 +> 注:`src/arch/linux/ld/`(原来的 ELF 后端)**已退役**,后端现在按三轴分目录,组合根在 `src/targets/x86_64-linux/`(2026-09-24 更正)。 ## 五、下一步 -- [tutorial.md](tutorial.md)— 渐进学习路径(从基础到系统编程) -- [syntax.md](syntax.md)— 语法参考 -- [examples.md](examples.md)— 可跑示例 -- [concepts.md](concepts.md)— 图模型等核心概念导览 +- [tutorial.md](tutorial.md)——渐进学习路径(从基础到系统编程) +- [syntax.md](syntax.md)——语法参考 +- [examples.md](examples.md)——可跑示例 +- [concepts.md](concepts.md)——图模型等核心概念导览 diff --git a/docs/developer/syntax.md b/docs/developer/syntax.md index 50bb581e..8f888841 100644 --- a/docs/developer/syntax.md +++ b/docs/developer/syntax.md @@ -2,25 +2,25 @@ > 定位:受众 = 开发者;状态 = active -本文档是 Core 语言**本体**的语法参考:词法、类型标注、声明、表达式、控制流、接口与泛型、规约、并发。语法形式以 `grammar/core.ebnf` 与 `src/compiler/` 源码为准(冲突时以源码为准)。设计理念与术语见 [concepts.md](concepts.md);深入(IR/验证/理论)从 concepts 的链接走。 +本文档是 Core 语言**本体**的语法参考:词法、类型标注、声明、表达式、控制流、接口与泛型、规约、并发。语法形式以 `grammar/core.ebnf` 与 `src/compiler/` 源码为准(冲突时以源码为准)。设计理念与术语见 [concepts.md](concepts.md);深入(IR/验证/理论)从 concepts 的链接走。 --- ## 一、设计要点 -Core 是"数据流图 + 语义保鲜"的语言——代码编译为图,图保留全部语义(形式验证直接消费)。给语法带来的要点: +Core 是「数据流图 + 语义保鲜」的语言——代码编译为图,图保留全部语义(形式验证直接消费)。给语法带来的要点: - **无 `let` 关键字**:变量用 `:=` 或 `: Type =` 声明。 - **无生命周期标注**:引用有效性由编译器自动验证。 -- **一切自动推断,零标注负担**: - - **类型推断**:`:=` / `auto` / `.` 推断,标注可选 - - **所有权**:默认借用,显式 `move` 转移 - - **编译时执行**:全常量输入自动求值,`@comptime` 兜底 - - **惰性分支**:控制流自动惰性(未走路径不求值),无 `lazy()` 关键字 - - **指针安全**:裸指针自由,超出范围的访问/悬垂引用由编译器自动拦截 +- **一切自动推断,零标注负担**: + - **类型推断**:`:=` / `auto` / `.` 推断,标注可选 + - **所有权**:默认借用,显式 `move` 转移 + - **编译时执行**:全常量输入自动求值,`@comptime` 兜底 + - **惰性分支**:控制流自动惰性(未走路径不求值),无 `lazy()` 关键字 + - **指针安全**:裸指针自由,超出范围的访问/悬垂引用由编译器自动拦截 - **动态类型**:`dyn` 边界自动转换 - **并发 = 流的构造**:`go` / `await` / `flow` / `yield` 构成数据流网络。 -- **规约内联**:`#check`/`#ensure` 写在函数上(设计态,见第 10 章)。 +- **规约内联**:`#check`/`#ensure` 写在函数上(设计态,见第 10 章)。 --- @@ -45,7 +45,7 @@ IDENT = LETTER { LETTER | DIGIT | '_' | '\'' } ### 2.3 关键字 -共 36 个(以 `src/compiler/lexer.cr lookup_keyword()` 为准,2026-09 核对): +共 36 个(以 `src/compiler/lexer.cr lookup_keyword()` 为准,2026-09 核对): ``` fn mut return if else loop while for break continue @@ -55,9 +55,9 @@ auto fileid move self in None Some unit ``` - `self` 是词法关键字,用于方法接收者(`self` / `&self` / `&mut self`)。 -- `Self` 不是词法关键字——它是接口/方法签名中的上下文类型名,按标识符解析,由编译器按上下文处理。 +- `Self` 不是词法关键字——它是接口/方法签名中的上下文类型名,按标识符解析,由编译器按上下文处理。 - `comptime` 不是关键字(`@comptime` 是 @ 内建原语)。 -- `#check`/`#ensure`/`#tag`/`spec fn` 不是词法关键字——规约是标注层语法(第 10 章;设计定稿 = maintainer/design/spec-design.md;实现态:parser 未支持)。 +- `#check`/`#ensure`/`#tag`/`spec fn` 不是词法关键字——规约是标注层语法(第 10 章;设计定稿 = maintainer/design/spec-design.md;实现态:parser 未支持)。 ### 2.4 字面量 @@ -199,11 +199,11 @@ ref : &Point; // 引用 mutr : &mut Point; // 可变引用 ``` -> 类型形态以 2026-09-01 语法重写定稿为准(计划优先);切片类型的运行时边界完整化(high 界进值)按 TODO 推进,当前编译器的切片操作语义以源码为准。 +> 类型形态以 2026-09-01 语法重写定稿为准(计划优先);切片类型的运行时边界完整化(high 界进值)按 TODO 推进,当前编译器的切片操作语义以源码为准。 **接口作类型**:任何接口名可作为类型标注(`PathType`),见第 9 章。 -**机器形状不在语言内**:整数位宽、浮点格式等机器形状由目标平台决定,不进入类型/标签体系。 +**机器形状不在语言内**:整数位宽、浮点格式等机器形状由目标平台决定,不进入类型/标签体系。 ### 4.2 标注位置 @@ -504,7 +504,7 @@ type Point3 = (dex, dex, dex); ## 十、规约 -规约(#check/#ensure 标注,2026-09 语法定稿——与 #pure/#terminating 自动推导标签同族)与函数体并列,可选编写。设计定稿见 docs/maintainer/design/spec-design.md;语法归口 grammar/core.ebnf(并入为迁移事项;.corespec 独立格式已退役,见 docs/maintainer/adr/adr-0001-corespec-crasm-retired.md)。**实现状态:设计态——lexer/parser 尚未实现规约语法**,示例为定稿形态。 +规约(`#check`/`#ensure` 标注,2026-09 语法定稿——与 #pure/#terminating 自动推导标签同族)与函数体并列,可选编写。设计定稿见 docs/maintainer/design/spec-design.md;语法归口 grammar/core.ebnf(并入为迁移事项;.corespec 独立格式已退役,见 docs/maintainer/adr/adr-0001-corespec-crasm-retired.md)。**实现状态:设计态——lexer/parser 尚未实现规约语法**,示例为定稿形态。 ### 10.1 #check / #ensure @@ -521,12 +521,12 @@ fn divide(a: int, b: int) -> int? ``` - `#check(...)` —— 调用方必须满足的前提条件 -- `#ensure(...)` —— 保证的后置条件;`result` 指返回值,`old(expr)` 指函数入口时表达式的值 -- `spec fn` —— 用 Core 写的纯检查函数(验证标准,见 maintainer/design/spec-design.md §七) +- `#ensure(...)` —— 保证的后置条件;`result` 指返回值,`old(expr)` 指函数入口时表达式的值 +- `spec fn` —— 用 Core 写的纯检查函数(验证标准,见 maintainer/design/spec-design.md §七) ### 10.2 where 值约束 -`where` 实现内联轻量前置条件(行内形态,与 #check 同层;定稿形态以 spec-design 为准): +`where` 实现内联轻量前置条件(行内形态,与 #check 同层;定稿形态以 spec-design 为准): ```core fn sqrt(x: dex) -> dex where x >= 0 { @@ -534,7 +534,7 @@ fn sqrt(x: dex) -> dex where x >= 0 { } ``` -值约束按表达式形态分三档语义(编译期求值 / 生成验证义务 / 运行时检查): +值约束按表达式形态分三档语义(编译期求值 / 生成验证义务 / 运行时检查): | 约束形态 | 语义 | |----------|------| @@ -542,7 +542,7 @@ fn sqrt(x: dex) -> dex where x >= 0 { | 符号约束 | 生成 VC(验证义务),由验证管线消费 | | 动态约束 | 运行时检查——「证明不了也不静默」 | -与规约前置条件互相映射(规约 = .cr 语法内约束,独立 .corespec 格式已退役,见 ADR-0001)。 +与规约前置条件互相映射(规约 = .cr 语法内约束,独立 .corespec 格式已退役,见 ADR-0001)。 --- diff --git a/docs/developer/tutorial.md b/docs/developer/tutorial.md index 37e56229..57fc9d83 100644 --- a/docs/developer/tutorial.md +++ b/docs/developer/tutorial.md @@ -2,15 +2,15 @@ > 定位:受众 = 开发者;状态 = active -Core 是少数不能归入"第一门语言"或"第 N 门语言"二元分类的设计。它的结构使得同一个语言可以陪伴程序员从零基础走到编写操作系统内核。 +Core 是少数不能归入「第一门语言」或「第 N 门语言」二元分类的设计。其结构使同一门语言可以陪伴程序员从零基础走到编写操作系统内核。 -学习路径自然展开——每个阶段的图结构复杂度递增,概念逐级累积,**没有换过语言,没有切换过"模式",没有需要遗忘的概念**。 +学习路径自然展开——每个阶段的图结构复杂度递增,概念逐级累积,**没有换过语言,没有切换过「模式」,没有需要遗忘的概念**。 --- ## 第一阶段:基础 -**目标**:写出第一个程序——"输入 → 计算 → 输出"的纯计算。 +**目标**:写出第一个程序——「输入 → 计算 → 输出」的纯计算。 **引入的概念**: - 变量声明:`x := expr`(推断)、`x : Type = expr`(显式)、`x : ., mut`(可变) @@ -20,7 +20,7 @@ Core 是少数不能归入"第一门语言"或"第 N 门语言"二元分类的 - 循环:`for x in arr`、`for i in 0..n` - 数组 `[T]`、结构体 `struct` -**图模型**:DAG——无环,值按依赖顺序流动;不依赖同一份数据的部分互不干扰。 +**图模型**:DAG——无环,值按依赖顺序流动;不依赖同一份数据的部分互不干扰。 **心智模型**:顺序执行——执行的每一步严格按文本顺序,所有变量值完全可观测、可单步。 @@ -39,22 +39,22 @@ fn sum(a: [int]) -> int { } ``` -**关联**:`docs/developer/syntax.md`、`docs/maintainer/design/execution-model.md` §一(唯一执行模型:HDFG) +**关联**:`docs/developer/syntax.md`、`docs/maintainer/design/execution-model.md` §一(唯一执行模型:HDFG) --- ## 第二阶段:结构化控制流 -**目标**:理解"持续运行"——程序不再是一次性计算,而是有状态地运行。 +**目标**:理解「持续运行」——程序不再是一次性计算,而是有状态地运行。 **引入的概念**: - `loop { ... }` + `break` / `continue` - `while` 条件循环 - 状态保持:可变变量跨迭代存活 -**图模型**:带环的静态图——loop/for 让值流绕圈,循环的"再次执行"由图的环表达。 +**图模型**:带环的静态图——loop/for 让值流绕圈,循环的「再次执行」由图的环表达。 -**心智模型**:循环 = 图中的环——每轮迭代值沿环流动一周;程序开始出现时间维度(状态跨迭代存活)。 +**心智模型**:循环 = 图中的环——每轮迭代值沿环流动一周;程序开始出现时间维度(状态跨迭代存活)。 **里程碑**:能写计数器、状态机雏形、轮询循环。 @@ -75,23 +75,23 @@ fn counter() -> int { } ``` -**关联**:`docs/maintainer/design/execution-model.md` §三(深入:执行模型与图的实现) +**关联**:`docs/maintainer/design/execution-model.md` §三(深入:执行模型与图的实现) --- ## 第三阶段:指针与内存 -**目标**:理解"字节级控制"——程序从"值的运算"进入"内存的操作"。 +**目标**:理解「字节级控制」——程序从「值的运算」进入「内存的操作」。 **引入的概念**: - 裸指针:`*T` 类型、`&x` 取址、`*p` 解引用、`cast(p)` 转换 -- `unsafe` 块:图边界入口(外部地址、FFI 返回值、无法自动追踪来源的场景) +- `unsafe` 块:图边界入口(外部地址、FFI 返回值、无法自动追踪来源的场景) - @ 内建:`@sizeOf(T)`、`@alignOf(T)`、`@fields(T)`、`@comptime`、`@inline` - 内存控制:`alloc_at(addr, size, align)` 声明式放置 -**图模型**:每个指针自带来源(它来自哪次分配/取址)与偏移;解引用时编译器自动核对边界——不需要你标注任何生命周期。 +**图模型**:每个指针自带来源(它来自哪次分配/取址)与偏移;解引用时编译器自动核对边界——不需要你标注任何生命周期。 -**心智模型**:指针和 C 一样自由;安全由编译器自动验证(来源追踪 + 边界核对)。unsafe 不是"关掉验证",是"声明此处是图边界入口"——一进图内,编译器重新获得追踪权。 +**心智模型**:指针和 C 一样自由;安全由编译器自动验证(来源追踪 + 边界核对)。unsafe 不是「关掉验证」,是「声明此处是图边界入口」——一进图内,编译器重新获得追踪权。 **里程碑**:能安全地做指针算术、类型双关、外部地址访问——不需要学 borrow checker。 @@ -119,18 +119,18 @@ unsafe { ## 第四阶段:并发与通信 -**目标**:理解"数据驱动"——程序是一张图,节点可以并发运行,数据在边上流动。 +**目标**:理解「数据驱动」——程序是一张图,节点可以并发运行,数据在边上流动。 **引入的概念**: -- `go f(args)`:启动一段并发计算(与主流程并行流动) +- `go f(args)`:启动一段并发计算(与主流程并行流动) - `h := go f(...)`:返回句柄 - `await h`:等待结果 - `flow`:可激活的命名子图模板;`yield`:暂停并输出值 - 通道(chan):跨执行流传递数据 -**图模型**:动态图——go 在运行时长出新的子图,与启动它的代码并行流动。 +**图模型**:动态图——go 在运行时长出新的子图,与启动它的代码并行流动。 -**心智模型**:节点、边、令牌——从"一行一行执行"平滑过渡到"数据驱动":执行顺序由数据可用性驱动,而非文本顺序。 +**心智模型**:节点、边、令牌——从「一行一行执行」平滑过渡到「数据驱动」:执行顺序由数据可用性驱动,而非文本顺序。 **里程碑**:能写生产者-消费者、并发管道(扇出/扇入)。 @@ -152,15 +152,15 @@ fn main() -> int { } ``` -**关联**:`docs/maintainer/proposals/concurrency.md`、`docs/maintainer/design/execution-model.md` §三(并发 GMP) +**关联**:`docs/maintainer/proposals/concurrency.md`、`docs/maintainer/design/execution-model.md` §三(并发 GMP) --- ## 形式规约(横切能力) -> [注意] **未实现**:本节为设计预览。规约形态 2026-09 定稿为 `#check`/`#ensure` 标注(与 #pure/#terminating 标签同族,见 `docs/developer/syntax.md` 第十章与 `docs/maintainer/design/spec-design.md`;独立 `.corespec` 格式已退役,见 adr/adr-0001),但**规约语法与验证管线均未实现**——当前编译器不消费规约。实现推进见 maintainer/design/spec-design.md 与 TODO.md。 +> [注意] **未实现**:本节为设计预览。规约形态 2026-09 定稿为 `#check`/`#ensure` 标注(与 #pure/#terminating 标签同族,见 `docs/developer/syntax.md` 第十章与 `docs/maintainer/design/spec-design.md`;独立 `.corespec` 格式已退役,见 adr/adr-0001),但**规约语法与验证管线均未实现**——当前编译器不消费规约。实现推进见 maintainer/design/spec-design.md 与 TODO.md。 -**目标**:理解"行为契约"——程序 = 实现 + 保证。 +**目标**:理解「行为契约」——程序 = 实现 + 保证。 **位置**:横切能力——任何阶段的代码都可配规约,不依赖特定能力层;推荐在掌握函数签名和类型系统后引入。 @@ -168,11 +168,11 @@ fn main() -> int { - `#check(...)`:前置条件 - `#ensure(...)`:后置条件(可引用 `result`、`old(x)`) - `spec fn`:检查函数(用 Core 写的纯逻辑函数) -- 函数内规约(`#check`/`#ensure` 标注,.cr 内表达——独立规约格式已退役) +- 函数内规约(`#check`/`#ensure` 标注,.cr 内表达——独立规约格式已退役) -**图模型**:规约约束挂载在图上(设计态)——性质与代码同源,验证器直接消费同一张图。 +**图模型**:规约约束挂载在图上(设计态)——性质与代码同源,验证器直接消费同一张图。 -**心智模型**:函数不只"做什么",还"保证什么"——意图成为代码的一等公民,验证器可消费。 +**心智模型**:函数不只「做什么」,还「保证什么」——意图成为代码的一等公民,验证器可消费。 **里程碑**:能给函数写前置/后置条件,用检查函数表达性质(有序性、排列性、不变量)。 @@ -185,7 +185,7 @@ fn divide(a: int, b: int) -> int } ``` -**关联**:`docs/maintainer/design/spec-design.md`、`docs/developer/syntax.md` 第十章、`docs/maintainer/adr/adr-0001-corespec-crasm-retired.md`(格式退役决策)、`docs/superpowers/specs/`(验证管线设计稿) +**关联**:`docs/maintainer/design/spec-design.md`、`docs/developer/syntax.md` 第十章、`docs/maintainer/adr/adr-0001-corespec-crasm-retired.md`(格式退役决策)、`docs/superpowers/specs/`(验证管线设计稿) --- @@ -209,12 +209,12 @@ fn divide(a: int, b: int) -> int **新增概念**: - 裸指针:`*T` 类型、`&x` 取址、`*p` 解引用、`cast(p)` 转换 -- `unsafe` 块:图边界入口(外部地址、FFI 返回值、无法自动追踪来源的场景) +- `unsafe` 块:图边界入口(外部地址、FFI 返回值、无法自动追踪来源的场景) - @ 内建:`@sizeOf(T)`、`@alignOf(T)`、`@fields(T)`、`@comptime`、`@inline` - 内存控制:`alloc_at(addr, size, align)` 声明式放置、布局控制 -- 硬件接口(HIT):MMIO/特权/中断经 unsafe + HIT extern 事件(独立汇编格式 .crasm 已废弃,见 maintainer/adr/adr-0001) +- 硬件接口(HIT):MMIO/特权/中断经 unsafe + HIT extern 事件(独立汇编格式 .crasm 已废弃,见 maintainer/adr/adr-0001) -**心智模型**:字节级控制 + 图边界——指针和 C 一样自由,安全由编译器自动验证;unsafe 是"声明图边界入口",不是"关掉验证"。 +**心智模型**:字节级控制 + 图边界——指针和 C 一样自由,安全由编译器自动验证;unsafe 是「声明图边界入口」,不是「关掉验证」。 ```core unsafe { @@ -223,13 +223,13 @@ unsafe { } ``` -**关联**:`docs/maintainer/design/pointer-model.md`、`docs/maintainer/design/memory-model.md`、`docs/maintainer/adr/adr-0001-corespec-crasm-retired.md`(crasm 废弃决策) +**关联**:`docs/maintainer/design/pointer-model.md`、`docs/maintainer/design/memory-model.md`、`docs/maintainer/adr/adr-0001-corespec-crasm-retired.md`(crasm 废弃决策) ### 示例:嵌入式与实时 无 MMU 目标、确定性延迟——图锚定区域(静态路径纯 bump 零碎片、无 GC 停顿)+ 部署配置(`allocation = "static"`)是核心卖点。 -**关联**:`docs/maintainer/design/execution-model.md` §五(部署配置与时间)、`docs/maintainer/design/memory-model.md` +**关联**:`docs/maintainer/design/execution-model.md` §五(部署配置与时间)、`docs/maintainer/design/memory-model.md` --- @@ -243,4 +243,4 @@ unsafe { | ④ 并发与通信 | go、await、flow、yield、chan | 动态图 | 数据驱动 | | 横切:形式规约 | #check/#ensure/spec fn | 图上约束 | 行为契约 | -整个过程中,概念只增不减——每个能力层学到的都留在下一个应用领域中继续使用,最终形成一个从"第一个程序"到"编译器与内核"的连续路径:**同一门语言,从零基础走到任何领域**。 +整个过程中,概念只增不减——每个能力层学到的都留在下一个应用领域中继续使用,最终形成一个从「第一个程序」到「编译器与内核」的连续路径:**同一门语言,从零基础走到任何领域**。 diff --git a/docs/glossary.md b/docs/glossary.md index 63645ca6..b6ef6c1f 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -1,9 +1,9 @@ -# 术语表(Glossary)——Core 架构术语 +# 术语表(Glossary)——Core 架构术语 -> 定位:受众 = maintainers(兼 contributors);状态 = active;出处 = 各术语「出处」列的文档与 -> `src/compiler/lexer.cr`(语言关键字只以它为准,本表不重复);实现与文档冲突时以源码为准(既有惯例)。 -> 规则:本表只收**架构级术语**,实现细节与设计论证在出处文档,不在本表展开。 -> 演进:2026-08-27 v3 全量扩充 → 2026-09-06 v4 校准(去 .corespec 退役残留、出处链接对齐、重复表压缩)。 +> 定位:受众 = maintainers(兼 contributors);状态 = active;出处 = 各术语「出处」列的文档与 +> `src/compiler/lexer.cr`(语言关键字只以它为准,本表不重复);实现与文档冲突时以源码为准(既有惯例)。 +> 规则:本表只收**架构级术语**,实现细节与设计论证在出处文档,不在本表展开。 +> 演进:2026-08-27 v3 全量扩充 → 2026-09-06 v4 校准(去 `.corespec` 退役残留、出处链接对齐、重复表压缩)。 ## 一、设计出发点 @@ -34,7 +34,7 @@ | 线性投影 | v5 格形态 = 从图线性化的投影;v6 升级为存在结构本体 | specs/lattice-ir-v6-format | | 部署配置 | 执行方式由部署配置声明决定,图语义不变 | maintainer/design/execution-model.md | -> 注:.corespec/.csr 独立规约形态已退役(2026-09-06)——规约 = .cr 语法内约束,见 maintainer/adr/adr-0001。 +> 注:`.corespec`/`.csr` 独立规约形态已退役(2026-09-06)——规约 = `.cr` 语法内约束,见 `maintainer/adr/adr-0001`。 ## 四、存在格条款(1–7 + 2′)+ 边界 @@ -51,14 +51,14 @@ | 地址 = 映射 | `&x` = (条目标识, 偏移);字节地址只是经典投影 | 6 | | 映射实例正确性 | 映射实例保持条款 1-6 = 范式映射表的行定理 | 7 | -> 完整条款 + 字节权限层/home/存在区间/驱逐配对等扩展术语:maintainer/design/memory-model.md。 -> **层本体 = 存在格**(四问/七字段/归类表/划界):maintainer/design/materialization-space.md。 +> 完整条款 + 字节权限层/home/存在区间/驱逐配对等扩展术语:`maintainer/design/memory-model.md`。 +> **层本体 = 存在格**(四问/七字段/归类表/划界):`maintainer/design/materialization-space.md`。 ## 五、寄存器分配(缓存语义映射实例) 一致性判定/共存互斥/读点无陈旧/调用点失效契约/remat/共存偏序 width/order-free/ 上下文贪心 CAG/spill/栈槽/装载存储/写回——全部术语定义与论证见 -maintainer/design/regalloc-cache-mapping.md(正式参考),本表不重复。 +`maintainer/design/regalloc-cache-mapping.md`(正式参考),本表不重复。 ## 六、执行标注空间 @@ -86,5 +86,5 @@ maintainer/design/regalloc-cache-mapping.md(正式参考),本表不重复。 ## 九、讨论判据与术语演进 -- 判据(何时一个新词值得进本表):跨文档引用 ≥2 处且语义唯一;否则留在出处文档 -- v3(2026-08-27)全量扩充 → v4(2026-09-06)校准;历史演进细节见 git 历史,不设演进记录节 +- 判据(何时一个新词值得进本表):跨文档引用 ≥2 处且语义唯一;否则留在出处文档。 +- v3(2026-08-27)全量扩充 → v4(2026-09-06)校准;历史演进细节见 git 历史,不设演进记录节。 diff --git a/docs/ir-schema/corespecir-schema.md b/docs/ir-schema/corespecir-schema.md index 37e63704..c75b247a 100644 --- a/docs/ir-schema/corespecir-schema.md +++ b/docs/ir-schema/corespecir-schema.md @@ -1,6 +1,6 @@ -# Core Spec IR Schema — 规约约束层 (.csr) +# Core Spec IR Schema — 规约约束层(`.csr`) -> 定位:受众 = 维护者(规约约束层实现者);**状态 = 设计态(未实现)**;出处 = **(拟)`src/compiler/ccr_io.cr`(.csr 读写)——⚠ 当前零实现** + maintainer/design/spec-design.md。 +> 定位:受众 = 维护者(规约约束层实现者);**状态 = 设计态(未实现)**;出处 = **(拟)`src/compiler/ccr_io.cr`(.csr 读写)——⚠ 当前零实现** + `maintainer/design/spec-design.md`。 > > ⚠ **修订(2026-09-16 文档审计)**:原文写「状态 = active;真源 = `src/compiler/ccr_io.cr`(.csr 读写)」—— > **不成立**:全仓 `grep -rn 'csr\|CSR1\|TagNode' --include='*.cr' src/` = **0 命中**;`ccr_io.cr` 亦零命中 diff --git a/docs/maintainer/adr/README.md b/docs/maintainer/adr/README.md index 20ab8094..19079102 100644 --- a/docs/maintainer/adr/README.md +++ b/docs/maintainer/adr/README.md @@ -1,12 +1,12 @@ # 决策记录(ADR) -> 定位:受众 = maintainers;状态 = active;真源 = 各 ADR 正文(与 git 历史一致时以历史为准)。 -> 规则:每份 ADR 记录一个已做决策的"为什么";设计细节不重复,见正文"关联"指向的文档。 +> 定位:受众 = maintainers;状态 = active;真源 = 各 ADR 正文(与 git 历史一致时以历史为准)。 +> 规则:每份 ADR 记录一个已做决策的「为什么」;设计细节不重复,见正文「关联」指向的文档。 ## 编号规则 -- 从 0001 起递增;新决策落地时追加,不修改已 accepted 的历史记录 -- 状态:accepted(已采纳)/ superseded by ADR-000N(被取代)——被取代的保留原文,新决策另起新号 +- 从 0001 起递增;新决策落地时追加,不修改已 `accepted` 的历史记录 +- 状态:`accepted`(已采纳)/ `superseded by ADR-000N`(被取代)——被取代的保留原文,新决策另起新号 - 模板: ```markdown diff --git a/docs/maintainer/adr/adr-0001-corespec-crasm-retired.md b/docs/maintainer/adr/adr-0001-corespec-crasm-retired.md index 3f178ee2..5593ddd1 100644 --- a/docs/maintainer/adr/adr-0001-corespec-crasm-retired.md +++ b/docs/maintainer/adr/adr-0001-corespec-crasm-retired.md @@ -8,21 +8,21 @@ ## 背景 仓库一度存在两套独立格式:`.corespec`(规约/契约文件)与 `.crasm`(统一汇编抽象层)。二者 -同构于同一思路——为特定职责发明独立文件格式与语法。代价:格式越多,真源越散(lexer/parser/ -ebnf/后端各要维护一套),且独立格式绑定经典硬件过深(寄存器/寻址/ISA 助记符/私有平台映射表)。 +同构于同一思路——为特定职责发明独立文件格式与语法。代价:格式越多,真源越散(`lexer`/`parser`/ +`ebnf`/后端各要维护一套),且独立格式绑定经典硬件过深(寄存器/寻址/ISA 助记符/私有平台映射表)。 ## 决策 -- **.corespec 退役**(2026-09-06,提交 582a1e1):独立规约格式取消——规约 = .cr 语法唯一表达 -- **.crasm 废弃**(2026-09-05):独立汇编格式取消,能力由硬件接口表(HIT)吸收——跨平台 = HIT +- **`.corespec` 退役**(2026-09-06,提交 `582a1e1`):独立规约格式取消——规约 = `.cr` 语法唯一表达 +- **`.crasm` 废弃**(2026-09-05):独立汇编格式取消,能力由硬件接口表(HIT)吸收——跨平台 = HIT 事件 + 投影表;MMIO/特权/中断 = `.cr` unsafe + HIT extern 接口事件 -- 语法责任并入 `grammar/core.ebnf`;`.corespec` 文件标注退役,CLAUDE.md 同步 +- 语法责任并入 `grammar/core.ebnf`;`.corespec` 文件标注退役,`CLAUDE.md` 同步 ## 后果 -- 正面:真源收敛——语言语法只有一个表达(.cr);维护面缩小(无私有格式链) -- 负面:core.ebnf 与 CLAUDE.md 需挂账清理残余 .corespec 引用;spec/ 目录残留 7 行占位文件待清; - 既有 .corespec 资产(regalloc-consistency 已迁 .cr 注释契约)需按新形态改写 +- 正面:真源收敛——语言语法只有一个表达(`.cr`);维护面缩小(无私有格式链) +- 负面:`core.ebnf` 与 `CLAUDE.md` 需挂账清理残余 `.corespec` 引用;`spec/` 目录残留 7 行占位文件待清; + 既有 `.corespec` 资产(`regalloc-consistency` 已迁 `.cr` 注释契约)需按新形态改写 ## 关联 diff --git a/docs/maintainer/adr/adr-0002-ccr-v6-segment-table.md b/docs/maintainer/adr/adr-0002-ccr-v6-segment-table.md index 976e7d8b..66206e05 100644 --- a/docs/maintainer/adr/adr-0002-ccr-v6-segment-table.md +++ b/docs/maintainer/adr/adr-0002-ccr-v6-segment-table.md @@ -7,24 +7,24 @@ ## 背景 -.ccr(格形态 IR)早期为线性指令投影(v5 前),全局变量/函数记录/寄存器信息分散,缺乏 -结构化承载。v6 的目标形状(spec §3.2/§3.5):全局数据段带类型、函数记录声明区并入 vars、 -寄存器以"坐标"描述生命周期。 +`.ccr`(格形态 IR)早期为线性指令投影(v5 前),全局变量/函数记录/寄存器信息分散,缺乏 +结构化承载。v6 的目标形状(spec §3.2/§3.5):全局数据段带类型、函数记录声明区并入 `vars`、 +寄存器以「坐标」描述生命周期。 ## 决策 -- **v6 = 段表架构**:.ccr 按段组织(存在结构段 ENT、数据段、函数记录段等),段表为格式骨架 -- **ENT 存在结构段**:声明"什么东西存在"于后续各段,loader 侧有 entries_coexist 上界校验等 +- **v6 = 段表架构**:`.ccr` 按段组织(存在结构段 ENT、数据段、函数记录段等),段表为格式骨架 +- **ENT 存在结构段**:声明「存在哪些对象」供后续各段使用,loader 侧有 `entries_coexist` 上界校验等 一致性守卫(GC 批) -- **REG 坐标化**:REG 记录带 kind/parent/enter/exit/first/last;root_region span 派生函数边界 -- **SYM 归并**:vars 并入函数记录声明区,globals 带 type -- 写读双端(ccr_io.cr)与格式 spec 同步演进 +- **REG 坐标化**:REG 记录带 `kind`/`parent`/`enter`/`exit`/`first`/`last`;`root_region` span 派生函数边界 +- **SYM 归并**:`vars` 并入函数记录声明区,`globals` 带 type +- 写读双端(`ccr_io.cr`)与格式 spec 同步演进 ## 后果 -- 正面:v5 前 .ccr 的线性形态被结构化段表取代——dump/验证/loader 都有明确格式锚点; - REG 坐标让寄存器分配元数据可序列化、可对照验证(regalloc-consistency 三层定位) -- 负面:v5 前 .ccr 文件不兼容(格式边界硬切);ELF 发射层需保持零变化前提下适配 +- 正面:v5 前 `.ccr` 的线性形态被结构化段表取代——dump/验证/loader 都有明确格式锚点; + REG 坐标让寄存器分配元数据可序列化、可对照验证(`regalloc-consistency` 三层定位) +- 负面:v5 前 `.ccr` 文件不兼容(格式边界硬切);ELF 发射层需保持零变化前提下适配 (v6 落地时已验证发射零变化) ## 关联 diff --git a/docs/maintainer/adr/adr-0003-selfhost-elf-direct-emit.md b/docs/maintainer/adr/adr-0003-selfhost-elf-direct-emit.md index 6399234b..6b68ca1c 100644 --- a/docs/maintainer/adr/adr-0003-selfhost-elf-direct-emit.md +++ b/docs/maintainer/adr/adr-0003-selfhost-elf-direct-emit.md @@ -6,25 +6,29 @@ ## 背景 -自举需要编译器自身编译自身。若后端产出 `.s` 汇编再经外部 `as`/`ld` 汇编链接,则: -(1) 依赖外部工具链,自举链脆弱;(2) 汇编器行为差异导致构建不可复现;(3) 无法做 -字节级一致性验证。早期 Python 后端(StackAsmGen/arm64_asm)走 .s 路线,自举阶段发现 +自举要求编译器编译自身。若后端产出 `.s` 汇编再经外部 `as`/`ld` 汇编链接,则存在三项代价: + +1. 依赖外部工具链,自举链脆弱 +2. 汇编器行为差异导致构建不可复现 +3. 无法做字节级一致性验证 + +早期 Python 后端(`StackAsmGen`/`arm64_asm`)采用 `.s` 路线,自举阶段发现 需要 ELF 直出能力。 ## 决策 -- 后端直接发射 **x86-64 ELF 二进制**(`src/arch/linux/ld/`:elf.cr/instr.cr/sizes.cr/ - resolve.cr/ld.cr),跳过 `.s` 中介 -- 动态链接能力保留(PLT/GOT、.so 加载,ld.cr),静态链接为默认路径 -- corec/corearch 拆分(见 ADR-0004)后由 corearch 承担发射;rt.s 手工汇编保留为运行时种子 -- legacy_asm_backend/ 移出主链,Python 后端仅用于 bootstrap 构建 +- 后端直接发射 **x86-64 ELF 二进制**(`src/arch/linux/ld/`:`elf.cr`/`instr.cr`/`sizes.cr`/ + `resolve.cr`/`ld.cr`),跳过 `.s` 中介 +- 动态链接能力保留(PLT/GOT、.so 加载,`ld.cr`),静态链接为默认路径 +- `corec`/`corearch` 拆分(见 ADR-0004)后由 `corearch` 承担发射;`rt.s` 手工汇编保留为运行时种子 +- `legacy_asm_backend/` 移出主链,Python 后端仅用于 bootstrap 构建 ## 后果 -- 正面:三阶段自举(corec→corec2→corec3)可连续发射且**二进制逐字节一致**(2026-07-27 贯通); +- 正面:三阶段自举(`corec→corec2→corec3`)可连续发射且**二进制逐字节一致**(2026-07-27 贯通); 无外部 as/ld 依赖;O0/O2 寄存器分配元数据可序列化并由自举后端读取 -- 负面:指令编码(REX/ModRM/SIB)全部自维护——每修一个编码 bug 都是全链回归; - 新平台支持成本高(需重写发射器,ARM64 仍走 .s) +- 负面:指令编码(`REX`/`ModRM`/`SIB`)全部自维护——每修复一处编码缺陷均触发全链回归; + 新平台支持成本高(需重写发射器,ARM64 仍沿用 `.s`) ## 关联 diff --git a/docs/maintainer/adr/adr-0004-corec-corearch-split.md b/docs/maintainer/adr/adr-0004-corec-corearch-split.md index c77c46f5..c84e438e 100644 --- a/docs/maintainer/adr/adr-0004-corec-corearch-split.md +++ b/docs/maintainer/adr/adr-0004-corec-corearch-split.md @@ -7,22 +7,22 @@ ## 背景 -2026-05-28 将单编译器拆为前后端(.core → .cr 更名同期);自举管线进一步要求"前端编译 .cr → 中间产物 → 后端发射 ELF"两步可独立驱动:corec2 自我编译 -时,前端需反复调用后端;若前后端同体,则无法单独验证后端对同一 .ccr 的发射一致性, +2026-05-28 将单编译器拆为前后端(`.core` → `.cr` 更名同期);自举管线进一步要求「前端编译 `.cr` → 中间产物 → 后端发射 ELF」两步可独立驱动:`corec2` 自我编译 +时,前端需反复调用后端;若前后端同体,则无法单独验证后端对同一 `.ccr` 的发射一致性, 也无法分离调试(前端死循环与后端 SIGFPE 会互相掩盖)。 ## 决策 -- 拆为两个二进制:**corec**(前端:lex→parse→check→ir→ccr 写出)与 **corearch**(后端: - .ccr 读入 → ELF 发射),corearch 亦可单独跑 `--elf --static` -- **.ccr 文件 = 前后端接口契约**:v5 线性指令/变量段(后演进为 v6 段表,见 ADR-0002) -- corec `build` 子命令内部自动调用 corearch;用户也可手工分步(如逐字节对比发射) +- 拆为两个二进制:**`corec`**(前端:lex→parse→check→ir→ccr 写出)与 **`corearch`**(后端: + `.ccr` 读入 → ELF 发射),`corearch` 亦可单独跑 `--elf --static` +- **`.ccr` 文件 = 前后端接口契约**:v5 线性指令/变量段(后演进为 v6 段表,见 ADR-0002) +- `corec` 的 `build` 子命令内部自动调用 `corearch`;用户也可手工分步(如逐字节对比发射) ## 后果 -- 正面:三阶段自举可逐字节验证(corec→corec2→corec3 发射一致);后端可独立回归 - (O0/O1/O2 CCR 与原生 ELF 运行验证);.ccr 成为稳定的格式边界与 dump 载体 -- 负面:两二进制分发的复杂度(CLI 入口两份);.ccr 格式稳定性成为硬约束—— +- 正面:三阶段自举可逐字节验证(`corec→corec2→corec3` 发射一致);后端可独立回归 + (O0/O1/O2 CCR 与原生 ELF 运行验证);`.ccr` 成为稳定的格式边界与 dump 载体 +- 负面:两二进制分发的复杂度(CLI 入口两份);`.ccr` 格式稳定性成为硬约束—— 格式一变,前后端必须同步(版本耦合) ## 关联 diff --git a/docs/maintainer/adr/adr-0005-memory-model-layers-v4.md b/docs/maintainer/adr/adr-0005-memory-model-layers-v4.md index b6d4b709..9a5a23f9 100644 --- a/docs/maintainer/adr/adr-0005-memory-model-layers-v4.md +++ b/docs/maintainer/adr/adr-0005-memory-model-layers-v4.md @@ -5,9 +5,11 @@ - 决策者:DslsDZC ## 背景 -内存模型讨论备忘演进多版(v1 位置抽象 → v3 三层映射总纲 → v4 定稿)。需要回答:语义保鲜的存储本体是什么、能力(能力安全概念)是否是一等公民。 + +内存模型讨论备忘演进多版(v1 位置抽象 → v3 三层映射总纲 → v4 定稿)。需要回答的问题:语义保鲜的存储本体是什么、能力(能力安全概念)是否为一等公民。 ## 决策 + - **三层映射**:图 = 关系空间(发生什么)、格 = 状态/存储空间(如何存在)、编码 = 物理编码空间(如何实现;2026-08-27 由「二进制」更名,违反零硬件惯例) - **超图灵性属于图不属于格**;格不重新引入程序顺序;跨范式发生在图层 - **规则封闭、对象开放**:层规则 = 缓存语义七条,永不新建;对象(条目/配方/标注)无界 @@ -15,9 +17,11 @@ - **能力不提升一等公民**(可逆):身份 = 图节点、无配方 = 标注、授权归治理层(consult/assume/measure/pass = 可能关系标注) ## 后果 -- 正面:新范式只需三件事(图标注加标签/CIC 定义新结构/硬件映射),不新建格;判定对一切格成立 + +- 正面:新范式只需三项工作(图标注加标签/CIC 定义新结构/硬件映射),不新建格;判定对一切格成立 - 负面:能力作为独立语义概念被否决——治理层授权机制待实现 ## 关联 + - 文档:docs/academic/lattice-theory.md(定稿提炼)、docs/archive/memory-model-capability-lattice.md(v1-v4 备忘) - 相关 ADR:ADR-0006(缓存语义) diff --git a/docs/maintainer/adr/adr-0006-cache-semantics.md b/docs/maintainer/adr/adr-0006-cache-semantics.md index 4dd0aa2b..5491dd21 100644 --- a/docs/maintainer/adr/adr-0006-cache-semantics.md +++ b/docs/maintainer/adr/adr-0006-cache-semantics.md @@ -5,17 +5,21 @@ - 决策者:DslsDZC ## 背景 -memory-model 文档此前把 CompCert v2 字节模型(块 + 字节偏移 + 每字节权限)描述为语义本体。文档层错误——实现(HDFG)从来就是缓存语义:节点 = 配方、边 = 值流、驱逐/再生 = 丢令牌/重跑节点。 + +memory-model 文档此前把 CompCert v2 字节模型(块 + 字节偏移 + 每字节权限)描述为语义本体。文档层错误——实现(HDFG)始终为缓存语义:节点 = 配方、边 = 值流、驱逐/再生 = 丢令牌/重跑节点。 ## 决策 + - 语义本体 = **缓存语义七条**(值 = 配方/驱逐不变量/再生等价/边界公理 + 4b 图内不可重算/赋值 = 版本化/地址 = 映射/映射实例正确性) - CompCert 字节模型降级为**经典映射实例**(权限面,条款 7) - 零代码改动——本次只纠偏文档 ## 后果 + - 正面:范式映射表成立(经典行/寄存器行/未来量子行共享七条);验证器条款单一权威 - 负面:无(文档纠偏) ## 关联 + - 文档:docs/academic/cache-semantics.md(七条权威)、docs/superpowers/specs/2026-08-15-cache-semantics-design.md - 相关 ADR:ADR-0005(v4 分层)、ADR-0007(区域映射) diff --git a/docs/maintainer/adr/adr-0007-graph-anchored-regions.md b/docs/maintainer/adr/adr-0007-graph-anchored-regions.md index 25f900a1..5e8aaeca 100644 --- a/docs/maintainer/adr/adr-0007-graph-anchored-regions.md +++ b/docs/maintainer/adr/adr-0007-graph-anchored-regions.md @@ -5,19 +5,23 @@ - 决策者:DslsDZC ## 背景 -多 Arena 模型(2026-07-28)把 arena 绑定子图;进一步问题是内存区域与图的关系、跨区域引用策略、栈的角色。早期方案逃逸规则四条一刀切禁止跨区域。 + +多 Arena 模型(2026-07-28)把 arena 绑定子图;进一步问题是内存区域与图的关系、跨区域引用策略、栈的角色。早期方案的逃逸规则四条一律禁止跨区域。 ## 决策 + - **区域锚定图**:区域 = 子图节点的字节域,非词法作用域影子;生命周期 = 图活性(非 LIFO) - **Arena 降级为分配器面实现**(区域 = arena slot 语义升级) -- **逃逸四条坍缩为一条 outlives 顺序判定**:引用者使用区间 ⊆ 被引用区域存活区间(RegionCheck cur_seq < exit_seq 即该判定);全局 = 程序级虚拟区域 +- **逃逸四条坍缩为一条 outlives 顺序判定**:引用者使用区间 ⊆ 被引用区域存活区间(`RegionCheck` `cur_seq` < `exit_seq` 即该判定);全局 = 程序级虚拟区域 - **栈 = 区域仅语义层**(栈上对象有 provenance;硬件栈保留,防双栈) - 外部世界接口(FFI/IO)与硬件描述表同构(后演化为 HIT,见 ADR-0015) ## 后果 + - 正面:go/flow 非 LIFO 生命周期可行;跨区域引用合法化(顺序判定);验证判据 = 图活性 - 负面:split/merge/share、IR 层回收点、size class 策略待实现(M1-M3) ## 关联 + - 文档:docs/maintainer/design/region-model.md、pointer-model.md;specs/2026-08-13-graph-anchored-regions-design.md - 相关 ADR:ADR-0006(缓存语义条款 7 = 正确性标准) diff --git a/docs/maintainer/adr/adr-0008-execution-model-regions.md b/docs/maintainer/adr/adr-0008-execution-model-regions.md index dc2cb394..3885b5d2 100644 --- a/docs/maintainer/adr/adr-0008-execution-model-regions.md +++ b/docs/maintainer/adr/adr-0008-execution-model-regions.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 + 早期 HDFG 文档的图是平面概念(节点/边/子图),控制流与副作用顺序的表达依赖标签跳转与全局位置表;验证与 region 迭代需要结构化边界。 ## 决策 -- 控制流 = **region 嵌套**(SG_FUNC/LOOP/FOR/FLOW/UNSAFE + 新增 SG_IF),region = 存在结构段(kind/enter/exit/parent/nstart/ncount) -- **state edges(边 kind=1)** 两条来源:副作用链(STORE 族/非纯 CALL 按指令序)+ 循环终止依赖(loop/for exit 连边——循环不终止则图不终止) + +- 控制流 = **region 嵌套**(`SG_FUNC/LOOP/FOR/FLOW/UNSAFE` + 新增 `SG_IF`),region = 存在结构段(`kind`/`enter`/`exit`/`parent`/`nstart`/`ncount`) +- **state edges(边 `kind=1`)** 两条来源:副作用链(`STORE` 族/非纯 `CALL` 按指令序)+ 循环终止依赖(loop/for exit 连边——循环不终止则图不终止) - 解释器循环按 region enter/exit 迭代(break/continue = region 语义操作),摆脱全局标签位置表 -- g_df_node_region 显式映射(O(1) 归属查询) +- `g_df_node_region` 显式映射(O(1) 归属查询) ## 后果 + - 正面:终止性依赖显式化可证;验证 pass/解释器/DOT 共享 region 结构;v6 REG 段承载(坐标升级) - 负面:早期平面图文档(dataflow-design)整体被取代(留档,§8 环标注仍权威) ## 关联 + - 文档:docs/maintainer/design/execution-model.md §二;specs/2026-08-08-region-cfg-design.md - 相关 ADR:ADR-0002(v6 REG 段) diff --git a/docs/maintainer/adr/adr-0009-spec-system-v2.md b/docs/maintainer/adr/adr-0009-spec-system-v2.md index 388f251c..f88b726f 100644 --- a/docs/maintainer/adr/adr-0009-spec-system-v2.md +++ b/docs/maintainer/adr/adr-0009-spec-system-v2.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 -规约系统早期形态未定验证后端与表达力上限。需要:规约表达力、验证健全性、平民化三者的平衡。 + +规约系统早期形态未定验证后端与表达力上限。待定问题:规约表达力、验证健全性、平民化三者的平衡。 ## 决策 + - 规约语言编译为 **CIC 项**(归纳构造演算):量词/归纳/高阶全在内核,表达力无上限 -- **SMT 证书外包**:目标一阶化 → SMT 求解 → 证书 → 翻译成 CIC 证明项 → 内核重验——健全性唯一来源是 CIC 内核(SMTCoq 模式);SMT 只当搜索器 -- 平民化分层:编译器自动推导 → #check/#ensure → spec fn(Core 写的纯检查函数)→ 用户入口分层(#induct/#lemma/证明项逃逸) -- 语法形态 2026-09 定稿:#check/#ensure 标注,.cr 内联(见 ADR-0001 退役同步) +- **SMT 证书外包**:目标一阶化 → SMT 求解 → 证书 → 翻译成 CIC 证明项 → 内核重验——健全性唯一来源是 CIC 内核(SMTCoq 模式);SMT 仅承担搜索器角色 +- 平民化分层:编译器自动推导 → `#check`/`#ensure` → `spec fn`(Core 写的纯检查函数)→ 用户入口分层(`#induct`/`#lemma`/证明项逃逸) +- 语法形态 2026-09 定稿:`#check`/`#ensure` 标注,`.cr` 内联(见 ADR-0001 退役同步) ## 后果 -- 正面:表达力与健全性解耦(内核最小信任根);证明驱动优化(已证性质门控喂优化器) -- 负面:全链未实现(解析/翻译桥/SMT 通道/内核绑定);CIC 内核选择挂起(Rocq vs Lean 4,等社区) + +- 正面:表达力与健全性解耦(内核最小信任根);证明驱动优化(已证性质门控输入优化器) +- 负面:全链未实现(解析/翻译桥/SMT 通道/内核绑定);CIC 内核选择挂起(Rocq vs Lean 4,待社区结论) ## 关联 + - 文档:docs/maintainer/design/spec-design.md、docs/academic/verifier-kernel.md(选型论证) - 相关 ADR:ADR-0001(规约格式退役) diff --git a/docs/maintainer/adr/adr-0010-numeric-dex-apx.md b/docs/maintainer/adr/adr-0010-numeric-dex-apx.md index d5b7338e..497b4aa5 100644 --- a/docs/maintainer/adr/adr-0010-numeric-dex-apx.md +++ b/docs/maintainer/adr/adr-0010-numeric-dex-apx.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 -float 的 IEEE 754 语义与"语义保鲜 + 范式普适"冲突(NaN/±0/舍入是机器惯例);需要精确数值的范式无关表达 + 性能快路径。 + +`float` 的 IEEE 754 语义与「语义保鲜 + 范式普适」冲突(NaN/±0/舍入是机器惯例);需要精确数值的范式无关表达 + 性能快路径。 ## 决策 -- **dex** = 精确小数(定点缩放整数,S = 10⁶ 契约决策):全序、无 NaN/±0/无穷,数学实数语义 -- **apx** = 近似授权(变量级标签):CPU 兑现 = binary64 快路径;仅授权后近似 -- IR_I2F/IR_F2I 迁移为 int↔dex 转换(浮点形态退役);TI_FLOAT 路径 = apx 前身 -- 宽度类型(f32/f64 后缀)= 编码层标注,移出语言定案(2026-08-30 随类型系统方向) + +- **`dex`** = 精确小数(定点缩放整数,S = 10⁶ 契约决策):全序、无 NaN/±0/无穷,数学实数语义 +- **`apx`** = 近似授权(变量级标签):CPU 兑现 = binary64 快路径;仅授权后近似 +- `IR_I2F`/`IR_F2I` 迁移为 `int`↔`dex` 转换(浮点形态退役);`TI_FLOAT` 路径 = `apx` 前身 +- 宽度类型(`f32`/`f64` 后缀)= 编码层标注,移出语言定案(2026-08-30 随类型系统方向) ## 后果 -- 正面:精确默认、近似显式授权;验证无 NaN 陷阱;契约表(ir-op-semantics §4)有显式缩放决策 + +- 正面:精确默认、近似显式授权;验证无 NaN 陷阱;契约表(`ir-op-semantics` §4)有显式缩放决策 - 负面:溢出/除零/有损转换需要错误码检查点(R001/R003/R004);128 位中间积处理 ## 关联 + - 文档:specs/2026-08-16-numeric-types-design.md、docs/maintainer/design/ir-op-semantics.md §4 - 相关 ADR:ADR-0012(int 无上限) diff --git a/docs/maintainer/adr/adr-0011-platform-abstract.md b/docs/maintainer/adr/adr-0011-platform-abstract.md index 37a6bd21..b9d956c0 100644 --- a/docs/maintainer/adr/adr-0011-platform-abstract.md +++ b/docs/maintainer/adr/adr-0011-platform-abstract.md @@ -5,16 +5,20 @@ - 决策者:DslsDZC ## 背景 + I/O 与时间等系统接口若直接暴露系统调用,程序语义被平台绑定,验证无法覆盖;部署配置分离原则要求物理实现在后端。 ## 决策 -- 程序 I/O 语义 = **流变换**(转导器:(输入流)→(输出流));read/write 系统调用 = 物理实现,后端按部署目标隔离 + +- 程序 I/O 语义 = **流变换**(转导器:(输入流)→(输出流));`read`/`write` 系统调用 = 物理实现,后端按部署目标隔离 - 四个语义抽象:I/O 流 / 随机(概率分布)/ 哈希(散列函数)/ 时钟(单调时间序)——语言层语义接口,熵源/算法/系统调用在后端 -- 验证意义上 I/O 是一等公民(流性质可规约),非验证黑洞 +- 验证意义上 I/O 是一等公民(流性质可规约),非验证盲区 ## 后果 + - 正面:程序语义平台无关;规约可描述输入流性质 → 输出流性质 - 负面:平台桥实现未落地(语义接口待接线) ## 关联 + - 文档:specs/2026-08-16-platform-abstract-design.md;docs/maintainer/design/execution-model.md §五 diff --git a/docs/maintainer/adr/adr-0012-int-unbounded.md b/docs/maintainer/adr/adr-0012-int-unbounded.md index 0add8a4c..24946bde 100644 --- a/docs/maintainer/adr/adr-0012-int-unbounded.md +++ b/docs/maintainer/adr/adr-0012-int-unbounded.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 -int 若为 64 位机器整数,规约验证在无界域证明的结论与实际运行(溢出回绕)可能不一致(int-unbounded 问题);同时性能需要 64 位快路径。 + +`int` 若为 64 位机器整数,规约验证在无界域证明的结论与实际运行(溢出回绕)可能不一致(`int-unbounded` 问题);同时性能需要 64 位快路径。 ## 决策 -- **语义层:int = 无上限数学整数**(公理化接口,无溢出概念——溢出非语义事件) -- **编码层:64 位机器字 = 快路径投影**;超界 = 编码层事务(静态区间证明免检;推导不出才检查提升;表示策略归 hw-map 远期,后端策略 B:64 快路径 + 溢出扩展 2-limb) -- 溢出类错误(lexer 字面量守卫/CCR i32 字段校验)= 编码层限制错误,重新归位 -- int 公理可被 .cr 规约对照验证(CompCert 精神推广到原语层);与 dex 精确两线不混(int = 语义无上限、dex = 表示层工程) + +- **语义层:`int` = 无上限数学整数**(公理化接口,无溢出概念——溢出非语义事件) +- **编码层:64 位机器字 = 快路径投影**;超界 = 编码层事务(静态区间证明免检;推导不出才检查提升;表示策略归 `hw-map` 远期,后端策略 B:64 快路径 + 溢出扩展 2-limb) +- 溢出类错误(`lexer` 字面量守卫/CCR `i32` 字段校验)= 编码层限制错误,重新归位 +- `int` 公理可被 `.cr` 规约对照验证(CompCert 精神推广到原语层);与 `dex` 精确两线互不混同(`int` = 语义无上限、`dex` = 表示层工程) ## 后果 -- 正面:验证结论与运行语义一致(#ensure(x + y > x) 无条件成立);快路径性能保留 -- 负面:多字表示/溢出升级实现推进中(M1/M2,见 plans/2026-09-06-int-multiword-m1);IR 契约表以编码层为基准需持续注记(ir-op-semantics) + +- 正面:验证结论与运行语义一致(`#ensure(x + y > x)` 无条件成立);快路径性能保留 +- 负面:多字表示/溢出升级实现推进中(M1/M2,见 `plans/2026-09-06-int-multiword-m1`);IR 契约表以编码层为基准需持续注记(`ir-op-semantics`) ## 关联 + - 文档:docs/maintainer/design/ir-op-semantics.md §1/D1;specs(int-unbounded-semantics、plans/int-multiword-m1) - 相关 ADR:ADR-0010(dex/apx) diff --git a/docs/maintainer/adr/adr-0013-type-system-direction.md b/docs/maintainer/adr/adr-0013-type-system-direction.md index 087a6226..f33175f7 100644 --- a/docs/maintainer/adr/adr-0013-type-system-direction.md +++ b/docs/maintainer/adr/adr-0013-type-system-direction.md @@ -5,17 +5,21 @@ - 决策者:DslsDZC ## 背景 -类型系统需要总体方向:类型推断强度、借用/可变性语义、显式边界语法的取舍长期有分叉讨论(图本体 vs 传统类型层)。 + +类型系统需要总体方向:类型推断强度、借用/可变性语义、显式边界语法的取舍长期存在分叉讨论(图本体 vs 传统类型层)。 ## 决策 + - 方向总纲:**图本体 + 接口统一**——类型推导建立在图结构上 - 14 条定案要点:自动推导全量(用户零标注默认)+ 借用收缩(borrow 语义收窄)+ 声明式边界(显式边界语法按需) -- **宽度类型移出语言定案**:位宽/后缀为编码层概念,不进语言本体(与 dex/apx 归位一致) +- **宽度类型移出语言定案**:位宽/后缀为编码层概念,不进语言本体(与 `dex`/`apx` 归位一致) ## 后果 + - 正面:类型标注成本趋向零;语言本体与编码层职责清晰 - 负面:自动推导全量在复杂场景的检查器实现工作量;借用收缩细节待落地 ## 关联 + - 文档:specs/2026-08-30-type-system-direction-design.md、docs/archive/(类型方向备忘) - 相关 ADR:ADR-0010(宽度类型移出) diff --git a/docs/maintainer/adr/adr-0014-lazy-compile-time.md b/docs/maintainer/adr/adr-0014-lazy-compile-time.md index 3e50812a..232e176b 100644 --- a/docs/maintainer/adr/adr-0014-lazy-compile-time.md +++ b/docs/maintainer/adr/adr-0014-lazy-compile-time.md @@ -5,15 +5,19 @@ - 决策者:DslsDZC ## 背景 -图模型天然可表达惰性(节点不在边上游等待时不执行),但 IR 生成策略是 eager。惰性求值若做成运行时机制将引入新执行语义。 + +图模型天然可表达惰性(节点不在边上游等待时不执行),但 IR 生成策略是 `eager`。惰性求值若做成运行时机制将引入新执行语义。 ## 决策 -- **惰性控制流 = 编译期下沉**:if 分支/循环体内的条件性使用经图分析延迟执行(编译期变换),非运行时 thunk 语义 -- IR 保留显式 thunk 形态(IR_LAZY_THUNK/FORCE)作为迁移载体,当前 eager 近似 + +- **惰性控制流 = 编译期下沉**:`if` 分支/循环体内的条件性使用经图分析延迟执行(编译期变换),非运行时 `thunk` 语义 +- IR 保留显式 `thunk` 形态(`IR_LAZY_THUNK`/`FORCE`)作为迁移载体,当前 `eager` 近似 ## 后果 + - 正面:执行模型不新增惰性运行时语义;图分析统一处理 -- 负面:控制流级惰性未实现(自动升级 eager 在实现中体现为使用点 force) +- 负面:控制流级惰性未实现(自动升级 `eager` 在实现中体现为使用点 `force`) ## 关联 + - 文档:docs/maintainer/proposals/lazy.md;docs/maintainer/design/ir-op-semantics.md §2.7 diff --git a/docs/maintainer/adr/adr-0015-hit-hardware-interface-table.md b/docs/maintainer/adr/adr-0015-hit-hardware-interface-table.md index 9ba236cd..d1ffb3ac 100644 --- a/docs/maintainer/adr/adr-0015-hit-hardware-interface-table.md +++ b/docs/maintainer/adr/adr-0015-hit-hardware-interface-table.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 -.crasm 独立汇编层废弃(ADR-0001)后,内核路线的 MMIO/特权/中断访问需要受控入口:跨平台统一 + 可验证 + 与 .cr 语义衔接。 + +`.crasm` 独立汇编层废弃(ADR-0001)后,内核路线的 MMIO/特权/中断访问需要受控入口:跨平台统一 + 可验证 + 与 `.cr` 语义衔接。 ## 决策 + - **HIT = 表驱动硬件接口**:最小核 4 事件契约 {sub, nand, load, store} + 投影表——换表即换平台 -- 跨平台 = HIT 事件 + 投影表;MMIO/特权/中断 = .cr unsafe + HIT extern 接口事件 -- 事件可读形态 = v6 NOD 文本 dump;NOD op ↔ HIT event_id 对齐为实施期事项 -- 硬件访问进图获得 provenance(声明式进图路径,与 alloc_at 同构) +- 跨平台 = HIT 事件 + 投影表;MMIO/特权/中断 = `.cr` unsafe + HIT extern 接口事件 +- 事件可读形态 = v6 NOD 文本 dump;`NOD op` ↔ HIT `event_id` 对齐为实施期事项 +- 硬件访问进图获得 `provenance`(声明式进图路径,与 `alloc_at` 同构) ## 后果 -- 正面:硬件层统一契约,表驱动换平台;事件级可验证;取代 .crasm 的私有映射表 + +- 正面:硬件层统一契约,表驱动换平台;事件级可验证;取代 `.crasm` 的私有映射表 - 负面:标准硬件表(寄存器/MMIO 区域)工程量;表外硬件行为 unsafe 人工保证 ## 关联 + - 文档:specs/2026-09-05-hardware-interface-table.md;docs/maintainer/design/crasm.md(废弃收尾) - 相关 ADR:ADR-0001(.crasm 退役)、ADR-0002(v6 NOD) diff --git a/docs/maintainer/adr/adr-0016-arena-model.md b/docs/maintainer/adr/adr-0016-arena-model.md index faea5c26..1b588749 100644 --- a/docs/maintainer/adr/adr-0016-arena-model.md +++ b/docs/maintainer/adr/adr-0016-arena-model.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 -早期运行时用单一全局 bump 分配器(BSS + mmap 扩展)。问题:内存生命周期与子图脱节——函数/循环产生的数据只能等到程序结束统一回收,长期服务内存无界;回收时机无法与执行结构对齐。 + +早期运行时采用单一全局 `bump` 分配器(BSS + mmap 扩展)。问题 = 内存生命周期与子图脱节——函数/循环产生的数据只能等到程序结束统一回收,长期服务内存无界;回收时机无法与执行结构对齐。 ## 决策 -- **每个子图(function/loop/for/unsafe)自己的 arena**:子图入口 arena_new、出口 arena_reset(游标重置,格式化清空) -- 新 IR opcode:IR_ARENA_NEW = 32 / IR_ARENA_RESET = 33(编译期大小预计算) -- ELF 后端双路径 alloc:arena 感知(g_current_arena)+ 全局 bump 回退;mmap 堆扩展 -- stdlib arena.cr 完整生命周期(init/new/reset)、动态元数据、free list、嵌套 + +- **每个子图(function/loop/for/unsafe)自己的 arena**:子图入口 `arena_new`、出口 `arena_reset`(游标重置,格式化清空) +- 新 IR opcode:`IR_ARENA_NEW` = 32 / `IR_ARENA_RESET` = 33(编译期大小预计算) +- ELF 后端双路径 `alloc`:arena 感知(`g_current_arena`)+ 全局 `bump` 回退;mmap 堆扩展 +- stdlib `arena.cr` 完整生命周期(init/new/reset)、动态元数据、free list、嵌套 ## 后果 -- 正面:子图退出即整块回收;分配 O(1) bump;无 GC -- 负面:arena 绑定子图 = 数据不能逃逸子图(跨子图引用受约束,后续由 outlives 修订放宽——ADR-0007);07-28 后遇 bump 死循环等实现 bug(已修) + +- 正面:子图退出即整块回收;分配 O(1) `bump`;无 GC +- 负面:arena 绑定子图 = 数据不能逃逸子图(跨子图引用受约束,后续由 `outlives` 修订放宽——ADR-0007);07-28 后出现 `bump` 死循环等实现缺陷(已修) ## 关联 + - 文档:docs/maintainer/design/region-model.md §四(arena = 区域机制的分配器面);specs/2026-07-28-arena-model-design.md - 相关 ADR:ADR-0007(图锚定区域,arena 的语义升级) diff --git a/docs/maintainer/adr/adr-0017-concurrency-gmp.md b/docs/maintainer/adr/adr-0017-concurrency-gmp.md index cb21cffc..299ea74f 100644 --- a/docs/maintainer/adr/adr-0017-concurrency-gmp.md +++ b/docs/maintainer/adr/adr-0017-concurrency-gmp.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 -早期执行模型文档设想"有 OS 用 OS 线程 / 无 OS 用时间片抢占"。实现 go 并发时发现:OS 线程模型把并发绑定平台线程与内核调度,无 OS 抢占在用户态成本高且与数据流图协作模型不匹配。 + +早期执行模型文档设想「有 OS 用 OS 线程 / 无 OS 用时间片抢占」。实现 go 并发时发现:OS 线程模型把并发绑定平台线程与内核调度,无 OS 抢占在用户态成本高且与数据流图协作模型不匹配。 ## 决策 -- 采用 **Go runtime 同构的 GMP 简化模型**:G = goroutine(fiber,16KB 栈,独立 arena)、M = machine、**P 不分离合并到 M**;无 GOMAXPROCS,M 数 = CPU 核 -- G 状态机(_Gidle/_Grunnable/_Grunning/_Gwaiting/_Gdead);local run queue + global 偷取;切换 = 用户态 fiber_switch(协作) -- channel 通信(环形缓冲 + send_wait/recv_wait 链表,值拷贝语义);go 返回 result_ch -- 早期"OS 线程/抢占式"设计废弃(文档层,2026-09 全量重写时清除) + +- 采用 **Go runtime 同构的 GMP 简化模型**:G = `goroutine`(`fiber`,16KB 栈,独立 arena)、M = machine、**P 不分离合并到 M**;无 `GOMAXPROCS`,M 数 = CPU 核 +- G 状态机(`_Gidle`/`_Grunnable`/`_Grunning`/`_Gwaiting`/`_Gdead`);local run queue + global 队列偷取;切换 = 用户态 `fiber_switch`(协作) +- channel 通信(环形缓冲 + `send_wait`/`recv_wait` 链表,值拷贝语义);go 返回 `result_ch` +- 早期「OS 线程/抢占式」设计废弃(文档层,2026-09 全量重写时清除) ## 后果 -- 正面:协作调度无内核介入;每 G arena 生命周期对齐(goroutine 栈 + G 结构同生共死);与图模型一致(yield/recv = 图节点操作) -- 负面:多 M 并行、global queue、阻塞链完整化推进中;并发执行器语义(IR_SPAWN eager 近似)与调度模型的差距持续注记(ir-op-semantics §2.7) + +- 正面:协作调度无内核介入;每 G arena 生命周期对齐(`goroutine` 栈 + G 结构同生共死);与图模型一致(yield/recv = 图节点操作) +- 负面:多 M 并行、global queue、阻塞链完整化推进中;并发执行器语义(`IR_SPAWN` eager 近似)与调度模型的差距持续注记(`ir-op-semantics` §2.7) ## 关联 + - 文档:docs/maintainer/design/execution-model.md §三(GMP);specs/2026-07-30-concurrency-design.md;stdlib sched.cr/goroutine.cr/chan.cr - 相关 ADR:ADR-0007(每 G 独立区域) diff --git a/docs/maintainer/adr/adr-0018-repo-governance.md b/docs/maintainer/adr/adr-0018-repo-governance.md index 727a6d7a..f1e5aad2 100644 --- a/docs/maintainer/adr/adr-0018-repo-governance.md +++ b/docs/maintainer/adr/adr-0018-repo-governance.md @@ -5,16 +5,20 @@ - 决策者:DslsDZC(维护者) ## 背景 -自举进入协作期(第二维护者 RhineIris 参与 PR #9/#2026-09-10-10),需要分支保护、审批流与 CI;早期直接提交 main 的流程不可持续。 + +自举进入协作期(第二维护者 RhineIris 参与 PR #9/#2026-09-10-10),需要分支保护、审批流与 CI;早期直接提交 `main` 的流程不可持续。 ## 决策 -- **分支模型 feature → develop → main**:main = 正式版线(仅维护者可合入,update 规则 + 无管理员绕过);develop = 集成分支(PR + 审批 + merge queue + CI 门槛);feature 分支每改动独立 -- 仓库治理四件套:CODE_OF_CONDUCT/CONTRIBUTING/SECURITY/PR 模板 + CI(core-ci.yml) -- 版本控制工具 = jj(禁 git 写操作,仓库约定);合并 = 手动 squash 合入 develop(merge queue 因免费计划降级) + +- **分支模型 `feature` → `develop` → `main`**:`main` = 正式版线(仅维护者可合入,update 规则 + 无管理员绕过);`develop` = 集成分支(PR + 审批 + merge queue + CI 门槛);`feature` 分支每改动独立 +- 仓库治理四项:`CODE_OF_CONDUCT`/`CONTRIBUTING`/`SECURITY`/PR 模板 + CI(`core-ci.yml`) +- 版本控制工具 = `jj`(禁止 `git` 写操作,仓库约定);合并 = 手动 `squash` 合入 `develop`(merge queue 因免费计划降级) ## 后果 -- 正面:合入门槛(审批 + CI 绿)防回归;main 稳定线;协作并行(PR 通道) -- 负面:多会话共享工作副本互踩风险(后续用独立 jj workspace 根治);squash 合入丢失分支粒度 + +- 正面:合入门槛(审批 + CI 绿)防回归;`main` 稳定线;协作并行(PR 通道) +- 负面:多会话共享工作副本相互覆盖的风险(后续用独立 `jj` workspace 根治);`squash` 合入丢失分支粒度 ## 关联 + - 文档:CLAUDE.md(版本控制流程);specs/2026-08-09-repo-governance-design.md diff --git a/docs/maintainer/adr/adr-0019-bootstrap-route.md b/docs/maintainer/adr/adr-0019-bootstrap-route.md index 3ba8f5e0..f631e8bf 100644 --- a/docs/maintainer/adr/adr-0019-bootstrap-route.md +++ b/docs/maintainer/adr/adr-0019-bootstrap-route.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 -全新语言无编译器可用。早期提交(2026-04-24 init)同时出现:语言核心(lexer/parser/checker)、编辑器支持与后端起步。关键路线问题:用什么写第一个编译器、目标产物怎么验证。 + +全新语言无编译器可用。早期提交(2026-04-24 init)同时出现:语言核心(`lexer`/`parser`/`checker`)、编辑器支持与后端起步。关键路线问题:第一个编译器的实现语言与目标产物的验证方式。 ## 决策 -- **Python bootstrap 先行**(bootstrap/corec/):纯 Python 单遍管线,无外部依赖——作为 stage 0 构建自托管编译器 -- **自托管为目标**:编译器用 Core 自身编写(src/compiler/),Python bootstrap 编译它出原生二进制 -- 三级自举:stage 0(Python)→ stage 1(corec)→ stage 2(corec2);2026-07-26 corec2→corec10 全线贯通 -- 扩展名 .core → .cr(2026-05-28,与前后端拆分同期) + +- **Python bootstrap 先行**(`bootstrap/corec/`):纯 Python 单遍管线,无外部依赖——作为 stage 0 构建自托管编译器 +- **自托管为目标**:编译器用 Core 自身编写(`src/compiler/`),Python bootstrap 编译它出原生二进制 +- 三级自举:stage 0(Python)→ stage 1(`corec`)→ stage 2(`corec2`);2026-07-26 `corec2`→`corec10` 全线贯通 +- 扩展名 `.core` → `.cr`(2026-05-28,与前后端拆分同期) ## 后果 -- 正面:自举闭环(语言写自己 = 最强验证);Python bootstrap 简单可审计 -- 负面:Python/自托管双实现需保持一致(bootstrap 解释器截断方向等 bug 曾致发散——ir-op-semantics BC2);bootstrap 后期只作构建工具保留 + +- 正面:自举闭环(语言编译自身 = 最强验证);Python bootstrap 简单可审计 +- 负面:Python/自托管双实现需保持一致(bootstrap 解释器截断方向等缺陷曾致发散——`ir-op-semantics` BC2);bootstrap 后期只作构建工具保留 ## 关联 + - 文档:CLAUDE.md(构建与自举);docs/maintainer/onboarding.md - 相关 ADR:ADR-0003(ELF 直出)、ADR-0004(前后端拆分) diff --git a/docs/maintainer/adr/adr-0020-ir-dual-form.md b/docs/maintainer/adr/adr-0020-ir-dual-form.md index 04a1c0ca..eba4c299 100644 --- a/docs/maintainer/adr/adr-0020-ir-dual-form.md +++ b/docs/maintainer/adr/adr-0020-ir-dual-form.md @@ -5,18 +5,22 @@ - 决策者:DslsDZC ## 背景 -自托管编译器需要中间产物格式承载"语义保鲜":单一 IR 要么偏图(验证友好)要么偏线性(后端友好)。早期(2026-05-28)确立双产物:数据流图描述(.cir)与二进制格式(.ccr)。 + +自托管编译器需要中间产物格式承载「语义保鲜」:单一 IR 要么偏图(验证友好)要么偏线性(后端友好)。早期(2026-05-28)确立双产物:数据流图描述(`.cir`)与二进制格式(`.ccr`)。 ## 决策 -- **.cir** = 数据流图格式描述(图形态——验证/分析消费) -- **.ccr** = 二进制格式(格形态线性投影——后端消费;早期版本含变量/指令段) -- corec 产出两者,corearch 消费 .ccr(前后端以 .ccr 为契约——ADR-0004) -- v6(2026-09)将 .ccr 升级为存在结构主体(段表 + ENT/NOD/REG),.cir 语义为图坐标真源 + +- **`.cir`** = 数据流图格式描述(图形态——验证/分析消费) +- **`.ccr`** = 二进制格式(格形态线性投影——后端消费;早期版本含变量/指令段) +- `corec` 产出两者,`corearch` 消费 `.ccr`(前后端以 `.ccr` 为契约——ADR-0004) +- v6(2026-09)将 `.ccr` 升级为存在结构主体(段表 + ENT/NOD/REG),`.cir` 语义为图坐标真源 ## 后果 -- 正面:验证面(.cir)与执行面(.ccr)分离;格式演进有 spec 文档与 schema(ir-schema/) -- 负面:双格式同步成本(.cir/.ccr 表述需一致);v5→v6 不兼容(中间产物零持久生态,可接受) + +- 正面:验证面(`.cir`)与执行面(`.ccr`)分离;格式演进有 spec 文档与 schema(`ir-schema/`) +- 负面:双格式同步成本(`.cir`/`.ccr` 表述需一致);v5→v6 不兼容(中间产物零持久生态,可接受) ## 关联 + - 文档:docs/ir-schema/(schema);docs/maintainer/design/existence-structure.md(v6);docs/superpowers/specs/2026-08-27-lattice-form-ir-design.md(方向) - 相关 ADR:ADR-0002、ADR-0004 diff --git a/docs/maintainer/design/corelsp.md b/docs/maintainer/design/corelsp.md index 4bacaa6b..c893181d 100644 --- a/docs/maintainer/design/corelsp.md +++ b/docs/maintainer/design/corelsp.md @@ -4,9 +4,9 @@ > 用户接入(Neovim/VS Code/Zed 配置步骤)见 [developer/editors.md](../../developer/editors.md)。 > 早期设计稿(历史,细节以源码为准):2026-08-08 [lsp-design](../../superpowers/specs/2026-08-08-lsp-design.md)、2026-08-28 [lsp-production-design](../../superpowers/specs/2026-08-28-lsp-production-design.md)。 -## 一、是什么 +## 一、定位与组成 -corelsp = 用 Core 自举编译器**前端子集**拼接出的语言服务器:LSP over stdio,rpc 循环收请求、按请求跑一次静默检查、回协议帧。与 corec 共享 lexer/parser/checker/diag/module/globals 等前端模块;**不含** corec 的 main.cr/entry.cr(corec_main 不参与 corelsp 构建)。 +corelsp 由 Core 自举编译器的**前端子集**拼接而成:LSP over stdio,rpc 循环接收请求,每次请求执行一次静默检查并回协议帧。与 corec 共享 lexer/parser/checker/diag/module/globals 等前端模块;**不含** corec 的 main.cr/entry.cr(corec_main 不参与 corelsp 构建)。 `src/lsp/` 文件职责: @@ -21,13 +21,13 @@ corelsp = 用 Core 自举编译器**前端子集**拼接出的语言服务器: ## 二、构建接线 -`build_selfhost_native.py` 的「corelsp」段:前端依赖子集(lexer/parser/checker/diag/module/globals 及其依赖链)+ `src/lsp/` 六文件,按依赖序 concat 后包装为 `lsp_main`,产出 `build/corelsp`。拼接顺序约束(json → rpc → lsp 同翻译单元内可见)见 lsp.cr 头部注释;给 src/lsp/ 加新文件时需同步该 concat 列表。 +`build_selfhost_native.py` 的「corelsp」段由前端依赖子集(lexer/parser/checker/diag/module/globals 及其依赖链)与 `src/lsp/` 六文件构成,按依赖序 concat 后包装为 `lsp_main`,产出 `build/corelsp`。拼接顺序约束(json → rpc → lsp 同翻译单元内可见)见 lsp.cr 头部注释;在 `src/lsp/` 新增文件时须同步该 concat 列表。 ## 三、检查管线与诊断通道 -管线(lsp.cr 注释实录,改动前先读源码): +管线(lsp.cr 注释实录;改动前须先读源码): -- **禁止 `run_frontend()`**——它含 `println("[1/5]...")` 进度输出,会污染 stdout 协议通道。检查固定走 `lsp_check_file`。 +- **禁止 `run_frontend()`**——它含 `println("[1/5]...")` 进度输出,会污染 stdout 协议通道;检查统一走 `lsp_check_file`。 - `lsp_check_file(path, src)`:`g_source` 置源文本 → `reset_frontend_state()` → tokenize → `res_imports` → parse_all →(parse 阶段有诊断则跳过 check_all,AST 可能不完整)→ check_all → publishDiagnostics。 - **publishDiagnostics**:主文件(`g_files[0]`,当前检查文档)无条件发布——无诊断也发空数组以清旧;其余有诊断的文件(file_id 去重)逐个发布。`file_id → 路径` 经 g_files 路径表,`uri = "file://" + path`。诊断字段:range 1-based → 0-based 减 1、severity=1、message 做 JSON 转义(含引号/反斜杠/控制符时保证合法 JSON)。 diff --git a/docs/maintainer/design/crasm.md b/docs/maintainer/design/crasm.md index d826395a..7bd57654 100644 --- a/docs/maintainer/design/crasm.md +++ b/docs/maintainer/design/crasm.md @@ -1,23 +1,23 @@ # .crasm 统一汇编抽象层(已废弃) -> 定位:受众 = maintainers;状态 = **deprecated**(2026-09-05);出处 = 本页 + 下方链接。 -> 本文为废弃收尾页——是什么/为什么废弃/去向;设计细节(统一指令集、特权固定集、 +> 定位:受众 = maintainers;状态 = **deprecated**(2026-09-05);出处 = 本页 + 下方链接。 +> 本文为废弃收尾页,覆盖废弃对象、废弃原因与能力去向;设计细节(统一指令集、特权固定集、 > 寄存器生命周期规则、硬件描述表、里程碑)不再保留,历史正文见 git 历史。 -## 是什么 +## 废弃对象 `.crasm` 曾是 Core 的汇编层设计:跨平台统一指令集 + 无限虚拟寄存器(`%0/%1`)+ 平台映射表, -为内核路线(MMIO、特权指令、中断)提供受控汇编入口,并刻意"难写"以限制汇编程序规模、 +为内核路线(MMIO、特权指令、中断)提供受控汇编入口,并刻意做成"难写"的形态,以限制汇编程序规模、 保障可验证性。设计于 2026-08-08,2026-08-09 定稿,从未实现。 -## 为什么废弃(2026-09-05) +## 废弃原因(2026-09-05) - **绑定经典硬件过深**:寄存器/寻址/ISA 助记符/私有平台映射表——把"汇编"概念做成了 新格式,但汇编本质是机器码的文本投影,不值得一套独立语法 - **与 .corespec 同构问题**:独立格式 = 定义散在多处(lexer/parser/ebnf/后端各维护一套), 与同期 .corespec 退役(见 ADR-0001)是同一个决策模式 -## 去向(能力被谁吸收) +## 能力去向(承接机制) - 跨平台 = 硬件接口表(HIT)事件 + 投影表 - MMIO/特权/中断 = `.cr` unsafe + HIT extern 接口事件 diff --git a/docs/maintainer/design/dataflow-design.md b/docs/maintainer/design/dataflow-design.md index 4874eec1..65ae4b94 100644 --- a/docs/maintainer/design/dataflow-design.md +++ b/docs/maintainer/design/dataflow-design.md @@ -1,6 +1,6 @@ # Core HDFG 设计 -> 定位:受众 = 维护者;状态 = superseded(由 execution-model.md 取代,留档) +> 定位:受众 = 维护者;状态 = superseded(由 execution-model.md 取代,留档)。 > **注(2026-08-15)**:本文档为 HDFG 的早期设计(07-22 前);v2 执行模型已演进为 region 嵌套 + state edges(RVSDG 风格结构化控制流,见 [execution-model.md](execution-model.md) 与 docs/superpowers/specs/2026-08-08-region-cfg-design.md)。本文档的 HDFG 基本结构(节点/边/子图)仍成立,region 化细节以 v2 为准。 > **留档范围(2026-09)**:§1-7 与 §结论 = 早期设计稿(§7 指针安全已由 [pointer-model.md](pointer-model.md) 取代);**§8 环语义标注(ITER/FIXPT/超图灵/模糊/共归纳)= 仍权威**——执行标注空间是 `docs/academic/cache-semantics.md` 条款 4b「图内不可重算」(`recipe = unrecomputable`)与 glossary 的出处,修改需先改条款。 @@ -9,8 +9,8 @@ ## 1. 核心抽象 -Core 将一切执行抽象为HDFG。 -程序员编写顺序的函数调用与并发启动,编译器自动构建并优化对应的HDFG。 +Core 将一切执行抽象为 HDFG。 +程序员编写顺序的函数调用与并发启动,编译器自动构建并优化对应的 HDFG。 | 编程概念 | HDFG映射 | |----------|--------------| @@ -31,12 +31,12 @@ Core 将一切执行抽象为HDFG。 --- -## 2. 静态与动态HDFG +## 2. 静态与动态 HDFG ### 2.1 静态图 -编译时已知:函数调用关系、模块连接。 -等价于传统的数据流程序图。 +编译期已知的信息 = 函数调用关系、模块连接。 +该图等价于传统的数据流程序图。 ```core fn transform(x: int) -> int { x * 2 } @@ -51,12 +51,12 @@ fn main() { ``` 图结构:data → transform 节点(多个实例) → display 节点(多个实例)。 -for 展开为扇出,go 为每个实例创建执行流节点。 +`for` 展开为扇出;`go` 为每个实例创建执行流节点。 ### 2.2 动态图 运行时图拓扑可变:产生新节点、删除节点、重新连线。 -这是 Core 应对长期运行服务和自适应系统的关键能力。 +该能力是 Core 应对长期运行服务与自适应系统的关键。 ```core flow load_balancer() { @@ -74,22 +74,22 @@ flow load_balancer() { } ``` -load_balancer 节点不断创建/移除 worker 节点,HDFG在运行时动态演化。 +`load_balancer` 节点不断创建与移除 `worker` 节点,HDFG 在运行时动态演化。 --- ## 3. 执行流与数据流节点的统一视图 -一个 flow 实例既是: +一个 `flow` 实例同时具备三种身份: - 执行流:拥有自己的栈和指令指针。 -- 数据流节点:通过 recv 消费输入,通过 yield 或 return 产出输出。 +- 数据流节点:通过 `recv` 消费输入,通过 `yield` 或 `return` 产出输出。 - 图中的顶点:可以连接到其他节点(通道/句柄)。 -这种统一性使得: +统一性带来两点结果: - 并发推理无需关心线程/协程的底层差异。 -- 静态分析工具可以提取完整的数据依赖图用于形式化验证。 +- 静态分析工具可以提取完整的数据依赖图,用于形式化验证。 --- @@ -137,16 +137,16 @@ fn main() { 图结构: -- 8 个 worker 节点,每个独立运行,产出 dex 令牌。 -- orchestrator 节点通过 recv() 从 8 条边收集令牌,累加后输出。 -- 所有边是缓冲通道,允许生产者/消费者异步执行。 -- 循环构成反馈:worker 每次 yield 后继续计算下一块。 +- 8 个 worker 节点各自独立运行,产出 `dex` 令牌。 +- `orchestrator` 节点通过 `recv()` 从 8 条边收集令牌,累加后输出。 +- 所有边是缓冲通道,允许生产者与消费者异步执行。 +- 循环构成反馈:worker 每次 `yield` 后继续计算下一块。 --- ## 6. 形式化验证视角 -从这张HDFG可以直接导出: +从这张 HDFG 可以直接导出四类结论: - 数据依赖:边定义了节点间的偏序关系。 - 吞吐量/延迟分析:节点执行时间 + 通道缓冲。 @@ -157,7 +157,7 @@ fn main() { ## 7. 与硬件执行模型的映射 -Core 的HDFG可以高效映射到多种底层硬件: +Core 的 HDFG 可以高效映射到多种底层硬件: - 多核 CPU:节点映射为线程/协程,边用无锁队列或共享内存。 - GPU:节点映射为 kernel,边映射为 global memory + 同步。 @@ -174,7 +174,7 @@ Core 的 HDFG 将并发原语(go、await、flow、recv、yield)统一为图 ## 7. 指针安全 -HDFG的另一个消费端是指针安全验证。图中每个值的出生节点记录了它的来源(provenance)。 +HDFG 的另一个消费端是指针安全验证。图中每个值的出生节点记录了它的来源(provenance)。 ``` ALLOC(arr[16]) ──→ ADDR(&arr[0]) ──→ ADD(p + n) ──→ DEREF(*p) diff --git a/docs/maintainer/design/execution-model.md b/docs/maintainer/design/execution-model.md index 5dfc3c55..85042c22 100644 --- a/docs/maintainer/design/execution-model.md +++ b/docs/maintainer/design/execution-model.md @@ -1,86 +1,67 @@ # Core 执行模型 -> 定位:受众 = 维护者/贡献者/用户;状态 = active。 -> 语义设计以本文件为准;实现以源码为准——图/region:src/compiler/dataflow.cr;并发:src/stdlib/sched.cr、goroutine.cr、chan.cr;执行器:src/compiler/interp.cr;语法:grammar/core.ebnf。 -> 本文 2026-09 全量重写:并发部分废弃旧"OS 线程/抢占式"设计,改为与实现一致的 Go 风格 GMP 简化模型;实现与设计的差距以"设计态/已实现"标注,不删设计意图。 +> 定位:受众 = 维护者/贡献者/用户;状态 = active。 +> 语义设计以本文件为准;实现以源码为准——图与 region 见 `src/compiler/dataflow.cr`,并发见 `src/stdlib/sched.cr`、`goroutine.cr`、`chan.cr`,执行器见 `src/compiler/interp.cr`,语法见 `grammar/core.ebnf`。 +> 修订(2026-09):并发一节重写。早期设计中的「OS 线程 / 抢占式」已被废弃,改用与实现一致的 Go 风格 GMP 简化模型。实现与设计的差距在各节以「已实现」或「设计态」标注,不删设计意图。 ---- +## 执行模型:HDFG -## 一、唯一执行模型(HDFG) +Core 只有一种执行语义,即 HDFG(全息数据流图)。源码经语义 IR 翻译后构成一张有向图,节点是操作,边是数据依赖,图的拓扑结构承载执行语义: -Core 只有一种执行语义:HDFG(全息数据流图)。代码经语义 IR 翻译后构成一张有向图—— -节点是操作,边是数据依赖。图的拓扑承载执行语义: - -| 图结构 | 承载语义 | +| 图结构 | 承载的语义 | |---|---| -| 有向无环图(DAG) | 依赖偏序——无反馈,确定性 | -| 带环静态图 | 迭代——region 表达迭代与终止 | -| 动态图 | 并发——节点运行时创建、生命周期动态管理 | - -程序员不需要声明"模式":代码写了什么,图就反映什么。执行方式(串行/并行/调度)属于 -部署层,图语义不变。 +| 有向无环图(DAG) | 依赖偏序。无反馈,确定性 | +| 带环静态图 | 迭代。region 表达迭代与终止 | +| 动态图 | 并发。节点在运行时创建,生命周期动态管理 | -三层映射(术语见 docs/glossary.md):**图**表达计算(关系空间)、**格**承载计算 -(存在空间,条目/配方)、**编码**实现计算(物理空间,ELF)。本文只讲图这一层。 +程序员不需要声明「模式」,图由代码直接决定。执行方式(串行、并行、调度)属于部署层,不改变图语义。 ---- +三层映射(术语见 `docs/glossary.md`):图表达计算,对应关系空间;格承载计算,对应存在空间,内容是条目与配方;编码实现计算,对应物理空间,即 ELF。本文只讲图这一层。 -## 二、图的落地形状:region 嵌套与 state edges +## 图的结构:region 嵌套与 state edge -图不是一张摊平的网络——控制流以 **region(存在结构段 SG)嵌套**表达,副作用与终止以 -**state edges** 表达。实现于 dataflow.cr(DFNode/DFEdge + sg 段表)。 +图不是摊平的网络。控制流以 region(存在结构段,SG)嵌套表达,副作用与终止以 state edge 表达。实现在 `dataflow.cr`,数据结构为 DFNode/DFEdge 加 sg 段表。 -### 2.1 节点与边 +### 节点与边 -- DFNode:操作节点,图结构携带类型与语义信息(不降格为指令) -- DFEdge:值流边;其中 **state edge**(边 kind=1)表达顺序约束——副作用链与循环终止依赖 +DFNode 是操作节点,图结构本身携带类型与语义信息,不降格为指令。DFEdge 是值流边,其中 kind=1 的边称为 state edge,表达顺序约束,用于副作用链与循环终止依赖。 -### 2.2 region(SG 段) +### region(SG 段) -region 是子图的字节域锚定:每个 region 记录 kind/enter/exit/parent/nstart/ncount -(sg_push/sg_pop,见 dataflow.cr;设计定稿 = region-cfg-design)。kind 取值: +region 是子图的字节域锚定。每个 region 记录 kind/enter/exit/parent/nstart/ncount,由 `sg_push`/`sg_pop` 管理(见 `dataflow.cr`;设计定稿见 region-cfg-design)。kind 的取值: | 值 | kind | 对应语法 | 语义 | |---|---|---|---| -| 0 | SG_FUNC | 函数 | 函数体域(根 region) | -| 1 | SG_LOOP | loop | 迭代域(break/continue 为 region 语义操作) | +| 0 | SG_FUNC | 函数 | 函数体域,根 region | +| 1 | SG_LOOP | loop | 迭代域。break/continue 是 region 语义操作 | | 2 | SG_FOR | for 循环 | 有界迭代域 | | 3 | SG_FLOW | flow | 可激活命名子图域 | -| 4 | SG_UNSAFE | unsafe | 图边界入口域(provenance 边界) | -| 5 | SG_IF | if/else | 条件分支域(条件求值前 push,区间覆盖 [条件, 汇合);match 展开为 if 链,不单独建 region) | +| 4 | SG_UNSAFE | unsafe | 图边界入口域,provenance 边界 | +| 5 | SG_IF | if/else | 条件分支域。条件求值前 push,区间覆盖 [条件, 汇合)。match 展开为 if 链,不单独建 region | -显式映射:`g_df_node_region[]` 并行数组——df_create_node 时写入当前 open region id, -O(1) 归属查询(解释器 region 迭代/验证 pass/DOT 分组免线性扫描)。 +节点与 region 的归属由 `g_df_node_region[]` 记录。该数组与节点数组并行,在 `df_create_node` 时写入当前打开的 region id,使归属查询为 O(1)——解释器的 region 迭代、验证 pass 与 DOT 分组都不必线性扫描。 -### 2.3 终止依赖与副作用链 +### 终止依赖与副作用链 -state edge = DFEdge 的 kind=1 边(0=data,1=state;边结构设计定稿 = region-cfg-design)。 -两条来源: +state edge 是 DFEdge 中 kind=1 的边,kind=0 为普通的 data 边(边结构设计定稿见 region-cfg-design)。它有两个来源: -1. **副作用链**:每个函数维护一条 state 链——STORE/STORE_FIELD/STORE_INDEX/非纯 CALL - 按指令序连 state 边(prev → cur),构建于 df_connect_srcs(emit 同步建图),df_end_func 闭合 -2. **循环终止依赖**:SG_LOOP/SG_FOR 的 exit 节点,从循环体最后一条副作用指令连一条 - state 边到 exit——"循环不终止则图不终止",终止性依赖显式化后可证循环终止与顺序性质 +一是副作用链。每个函数维护一条 state 链,STORE、STORE_FIELD、STORE_INDEX 与非纯 CALL 按指令序连成 state 边(prev → cur)。链条在 `df_connect_srcs` 中随 emit 同步建立,由 `df_end_func` 闭合。 -### 2.4 执行投影:顺序即拓扑 +二是循环终止依赖。SG_LOOP 与 SG_FOR 的 exit 节点各有一条 state 边,从循环体最后一条副作用指令连向 exit。这条边把「循环不终止则图不终止」显式化,使循环终止与顺序性质可证。 -- **解释器**(interp.cr):按 IR 顺序执行节点——对直线代码,文本顺序即合法拓扑序 - (源码注释明言);region 表按 SG_LOOP/SG_FOR 的 enter/exit 驱动循环(globals.cr) -- **原生**:ELF 直出 x86-64 机器码(编码层投影,见 adr/adr-0003);arena 生命周期见 §四 +### 执行投影 -图是执行语义的载体,不是执行方式的决定者——物理执行由编码层决定,图只约束语义。 +解释器(`interp.cr`)按 IR 顺序执行节点。对直线代码,文本顺序就是一个合法的拓扑序,这一点源码注释中已有说明;region 表按 SG_LOOP/SG_FOR 的 enter/exit 驱动循环(见 `globals.cr`)。 ---- +原生执行走 ELF 直出 x86-64 机器码,属于编码层投影(见 `adr/adr-0003`)。arena 生命周期见「内存生命周期」一节。 -## 三、并发:Go 风格 GMP 模型(G 并入 M 的简化) +图约束的是执行语义,物理执行方式由编码层决定。 -> 2026-09 定稿(设计 = concurrency-design,2026-07-30):并发执行采用 **Go runtime 同构的 -> GMP 简化模型**——G = goroutine(fiber),M = machine(OS 线程),**P 不分离,合并到 M**; -> 无全局 GOMAXPROCS,M 数量 = CPU 核数(运行时配置)。 -> 废弃早期设计的"有 OS 用线程 / 无 OS 时间片抢占"。实现:src/stdlib/sched.cr(调度)、 -> goroutine.cr(G 生命周期)、chan.cr(通信);ir_gen.cr 发射 go 调用。 +## 并发:Go 风格 GMP 模型 -### 3.1 并发原语 +此模型于 2026-09 定稿(原设计见 concurrency-design,2026-07-30)。并发执行采用与 Go runtime 同构的 GMP 简化模型:G 是 goroutine(fiber),M 是 machine(OS 线程),P 不单独分离,合并进 M。运行时没有全局 GOMAXPROCS,M 的数量等于 CPU 核数,由运行时配置决定。早期设计中「有 OS 时用线程、无 OS 时用时间片抢占」的方案已废弃。实现分布在 `src/stdlib/sched.cr`(调度)、`goroutine.cr`(G 生命周期)与 `chan.cr`(通信),`ir_gen.cr` 负责发射 go 调用。 + +### 并发原语 ```core ch := make(chan int, 10); // 缓冲 channel,容量 10 @@ -91,12 +72,11 @@ val := recv(ch); // 接收 close(ch); // 关闭 ``` -- 语法层与 stdlib chan_* 的对应见 docs/developer/syntax.md 第十一章与 chan.cr -- go 也支持范围批量形态(go var start..end expr,parser.cr desugar) +这些语法与 stdlib 中 `chan_*` 函数的对应关系见 `docs/developer/syntax.md` 第十一章与 `chan.cr`。go 还支持范围批量形态(`go var start..end expr`,在 `parser.cr` 中 desugar)。 -### 3.2 G:goroutine(fiber) +### G:goroutine(fiber) -每个 G = 一个用户态协程,固定 16KB 栈,绑定独立 arena: +每个 G 是一个用户态协程,栈固定为 16KB,绑定独立的 arena: ```core struct Goroutine { @@ -105,21 +85,19 @@ struct Goroutine { } ``` -G 状态机:_Gidle(未启动)/ _Grunnable(队列中)/ _Grunning(执行中)/ -_Gwaiting(阻塞在 chan send/recv)/ _Gdead(退出待回收)。 +G 的状态机有五个状态:`_Gidle`(未启动)、`_Grunnable`(在队列中)、`_Grunning`(执行中)、`_Gwaiting`(阻塞在 chan 的 send 或 recv)、`_Gdead`(已退出,待回收)。 + +`go f(args)` 的语义(设计定稿)是: -`go f(args)` 语义(设计定稿): -1. 分配 G 结构 + 16KB 栈 -2. 复制参数到新 arena +1. 分配 G 结构与 16KB 栈 +2. 把参数复制到新 arena 3. 创建新 arena -4. 状态置 _Grunnable,投递到 M 的 local run queue -5. 返回(不等待;若用作句柄则返回 result channel) +4. 状态置为 `_Grunnable`,投递到 M 的 local run queue +5. 返回,不等待;若该表达式用作句柄,则返回 result channel -实现(goroutine.cr):g_new 先建 G 的 arena,再 fiber_init 初始化协程栈;entry 恒为 -goroutine_entry_wrapper,saved_fn/result_ch 存 G 结构体;sched_go = g_new + sched_enqueue; -wrapper 经 saved_fn 调用户函数,结果经 result_ch 回传;g_free = reset arena 整块回收。 +实现见 `goroutine.cr`:`g_new` 先建立 G 的 arena,再用 `fiber_init` 初始化协程栈;入口固定为 `goroutine_entry_wrapper`,`saved_fn` 与 `result_ch` 存放在 G 结构体中;`sched_go` 等于 `g_new` 加 `sched_enqueue`;wrapper 经 `saved_fn` 调用用户函数,结果经 `result_ch` 回传;`g_free` 通过 reset arena 整块回收。 -### 3.3 M:machine(OS 线程) +### M:machine(OS 线程) ```core struct Machine { @@ -127,15 +105,15 @@ struct Machine { } ``` -- sched_init 注册主线程(G0 = 主流程的 G);sched_spawn_workers(n) 派生多 M(m_idx 标识) -- 切换 = 用户态 fiber_switch(保存旧 G 寄存器到栈、装入新 G 栈指针)——无内核介入 -- 调度循环(local run queue):取一个 G 运行;local 空 → 从 global run queue 偷; - global 也空 → idle(OS 线程休眠) -- 切换点:send 遇满 chan / recv 遇空 chan → G 阻塞入等待链表,schedule();yield() 主动让出 +`sched_init` 注册主线程,主流程的 G 记为 G0;`sched_spawn_workers(n)` 派生多个 M,以 m_idx 标识。 -### 3.4 Channel 与通信 +切换走用户态的 `fiber_switch`:保存旧 G 的寄存器到栈,装入新 G 的栈指针,全程无内核介入。 -channel = 环形缓冲 + 等待链表: +调度循环以 local run queue 为中心:取一个 G 运行;local 为空时从 global run queue 偷取;两者皆空则 idle,OS 线程休眠。切换点有两处:send 遇到已满的 chan 或 recv 遇到空的 chan 时,G 阻塞并进入等待链表,调用 `schedule()`;`yield()` 用于主动让出。 + +### channel 与通信 + +channel 由环形缓冲与等待链表组成: ```core struct Channel { @@ -144,78 +122,59 @@ struct Channel { } ``` -- send:已关闭 → panic;有等待接收的 G → 直拷给接收者并唤醒;buf 未满 → 入缓冲; - buf 满 → 当前 G 阻塞入 send_wait -- recv:有等待发送的 G → 直收并唤醒发送者;buf 非空 → 取缓冲;已关闭且空 → 零值; - 空且未关 → G 阻塞入 recv_wait -- **值拷贝语义**:channel 边界永远拷贝值,不传引用;发送方的值发送后不变 +send 的行为分四种情况:channel 已关闭则 panic;有等待接收的 G 则直接拷贝给接收者并唤醒它;缓冲未满则写入缓冲;缓冲已满则当前 G 阻塞,进入 send_wait。 + +recv 的行为同样分四种情况:有等待发送的 G 则直接接收并唤醒发送者;缓冲非空则取缓冲;已关闭且缓冲为空则返回零值;缓冲为空且未关闭则 G 阻塞,进入 recv_wait。 -实现:chan.cr 的 chan_make/chan_send/chan_recv/chan_close;go 句柄本身即 result channel。 +channel 边界永远拷贝值,不传引用。发送方的值在发送后不再改变。 -### 3.5 实现现状与设计态 +实现在 `chan.cr`,函数为 `chan_make`/`chan_send`/`chan_recv`/`chan_close`。go 语句返回的句柄本身就是一个 result channel。 -已实现(2026-07-31 go 端到端):go 单发、chan 同步、result 回传、G0 = 主线程、 -协作切换(单 M 起)。设计态/推进中:多 M worker 并行、global run queue 偷取、 -G 状态机完整化(_Gwaiting 阻塞链)、range go 批量、select 聚合、语言层 await 收尾语法。 -推进记录见 docs/superpowers/plans/2026-07-30-concurrency.md。 +### 实现现状 ---- +截至 2026-07-31,go 已端到端可用,包括 go 单发、chan 同步、结果回传、G0 为主线程,以及从单 M 起步的协作切换。 -## 四、内存生命周期:arena +以下仍在设计态:多 M worker 并行、global run queue 偷取、G 状态机完整化(`_Gwaiting` 阻塞链)、range go 批量、select 聚合、语言层的 await 收尾语法。推进记录见 `docs/superpowers/plans/2026-07-30-concurrency.md`。 -分配以 **arena** 为单元——arena 是"图锚定区域"内存模型的当前实现形态 -(区域 = 子图节点,生命周期 = 图活性;概念设计见 2026-08-13-graph-anchored-regions-design, -映射实例层见 docs/maintainer/design/region-model.md): +## 内存生命周期:arena -- 函数/loop/for/unsafe 等子图自动获得 arena 生命周期(ir_gen.cr 在子图边界发射 - IR_ARENA_NEW=32/IR_ARENA_RESET=33,含编译期大小预计算;ELF 后端双路径 alloc: - arena 感知 + 全局 bump 回退,见 arch/linux/ld/elf.cr;实现计划 = arena-model) -- 每个 go 的 G 在创建时独立建 arena,fiber 栈与 G 结构体同生共死,g_free = reset 整块回收 -- 静态已知大小路径 = 纯 bump 零碎片;动态路径分档;物理约束(配额等)由部署配置声明(§五) +分配以 arena 为单元。arena 是「图锚定区域」内存模型的当前实现形态:区域对应子图节点,生命周期对应图活性。概念设计见 `2026-08-13-graph-anchored-regions-design`,映射实例层见 `docs/maintainer/design/region-model.md`。 ---- +函数、loop、for、unsafe 等子图自动获得 arena 生命周期。`ir_gen.cr` 在子图边界发射 `IR_ARENA_NEW=32` 与 `IR_ARENA_RESET=33`,并做编译期大小预计算;ELF 后端有两条分配路径,arena 感知路径与全局 bump 回退,见 `arch/linux/ld/elf.cr`。实现计划见 arena-model。 -## 五、部署配置与时间语义(设计态) +每个 go 创建 G 时独立建立 arena,fiber 栈与 G 结构体同生共死,`g_free` 通过 reset 整块回收。 -> 以下为设计意图,部分未落地——落地状态以平台桥设计与 plans/ 为准。 +大小在静态已知时走纯 bump 路径,零碎片;动态大小则分档处理。物理约束(例如配额)由部署配置声明,见「部署配置与时间语义」一节。 -### 5.1 代码不规定分配策略 +## 部署配置与时间语义 -Core 代码只描述计算逻辑与数据结构,不规定内存从哪来。语义 IR 保留类型/边界/编译期上限 -信息,但不固定分配策略。物理约束在部署配置中声明(TOML,如 allocation = "static"/"dynamic"), -编译器据此检查兼容性并生成适配代码。 +> 本节为设计意图,部分尚未落地。落地状态以平台桥设计文档与 `plans/` 为准。 -### 5.2 时间语义 +### 代码不规定分配策略 -时钟语义 = 单调时间序(数学):代码不区分零时间/物理实时/仿真时间,只要求单调。 -时间源由部署上下文与后端决定(平台桥语义接口 now_monotonic/sleep_ms;系统调用隔离在后端) -——裸机用硬件时钟、普通 OS 用系统时钟、仿真器可控。部署配置决定时间源,程序语义不变。 +Core 代码只描述计算逻辑与数据结构,不规定内存的来源。语义 IR 保留类型、边界与编译期上限信息,但不固定分配策略。物理约束在部署配置中声明(TOML,例如 `allocation = "static"` 或 `"dynamic"`),编译器按该声明检查兼容性并生成适配代码。 -I/O 同理:程序语义 = 流变换(转导器:(输入流)→(输出流));系统调用是物理实现,由后端按 -部署目标隔离,不进入程序语义。 +### 时间语义 -### 5.3 资源配额 +时钟语义是数学意义上的单调时间序。代码不区分零时间、物理实时与仿真时间,只要求单调。时间源由部署上下文与后端决定:平台桥提供 `now_monotonic`/`sleep_ms` 两个语义接口,系统调用隔离在后端。裸机用硬件时钟,普通 OS 用系统时钟,仿真器可以自行控制。部署配置决定时间源,程序语义不变。 -配额(CPU/内存/速率)属运营策略,在部署配置中可选声明,不声明即无限制;代码不变。 +I/O 同理。程序语义是流变换,即转导器 `(输入流) → (输出流)`。系统调用是物理实现,由后端按部署目标隔离,不进入程序语义。 ---- +### 资源配额 -## 六、代码与部署分离 +配额(CPU、内存、速率)属于运营策略,可在部署配置中声明,不声明即无限制。代码不变。 -同一份代码: +## 代码与部署分离 -- 教学环境 → 解释器逐步执行,可单步 -- 桌面 → AOT 编译原生执行(ELF 直出) -- 嵌入/裸机 → 静态分配 + arena,零运行时依赖 -- 集群 → 图可远程部署(分布式为设计态,见 docs/maintainer/proposals/distributed.md) +同一份代码可以部署到不同环境: -代码不改。图语义唯一。部署配置不同。 +- 教学环境 → 解释器逐步执行,可单步 +- 桌面 → AOT 编译为原生代码执行(ELF 直出) +- 嵌入与裸机 → 静态分配加 arena,零运行时依赖 +- 集群 → 图可远程部署(分布式为设计态,见 `docs/maintainer/proposals/distributed.md`) ---- +这四种情况的代码相同,图的语义相同,只有部署配置不同。 -## 七、结论 +## 小结 -代码生成图结构,图承载执行语义;region 嵌套与 state edges 表达控制流与副作用; -并发 = Go 风格 GMP 模型(go/fiber/chan,协作调度);内存 = arena 生命周期; -执行方式与物理约束归部署层。拓扑简单则执行简单,拓扑复杂则执行复杂—— -不需要人为命名任何"模式"。 +代码生成图结构,图承载执行语义。region 嵌套与 state edge 表达控制流与副作用。并发是 Go 风格 GMP 模型,由 go、fiber 与 chan 构成,采用协作调度。内存以 arena 管理生命周期。执行方式与物理约束归部署层,拓扑简单则执行简单,拓扑复杂则执行复杂,不需要人为命名任何模式。 diff --git a/docs/maintainer/design/existence-structure.md b/docs/maintainer/design/existence-structure.md index a72851e5..0aaaec6f 100644 --- a/docs/maintainer/design/existence-structure.md +++ b/docs/maintainer/design/existence-structure.md @@ -1,7 +1,7 @@ # 存在结构:v6 格形态 IR 的语义承载(ENT/NOD/REG) -> 定位:受众 = 维护者(ccr_io/分配器/验证器实现者);状态 = active(设计定稿,实现推进中)。 -> 本文件从**语义视角**讲 v6 存在结构——条款 1–7(权威 = docs/academic/cache-semantics.md)如何在 .ccr 中落成 IR 一等结构;字节级布局(段表/字段宽/对齐)的最终规格在 docs/ir-schema/coreir-schema.md(实现期并入),格式设计草案与实施状态以 docs/superpowers/specs/2026-09-05-lattice-ir-v6-format.md 与实施计划为准。 +> 定位:受众 = 维护者(ccr_io/分配器/验证器实现者);状态 = active(设计定稿,实现推进中)。 +> 本文件从**语义视角**讲 v6 存在结构——条款 1–7(权威 = docs/academic/cache-semantics.md)如何在 `.ccr` 中落成 IR 一等结构。字节级布局(段表/字段宽/对齐)的最终规格在 docs/ir-schema/coreir-schema.md(实现期并入);格式设计草案与实施状态以 docs/superpowers/specs/2026-09-05-lattice-ir-v6-format.md 与实施计划为准。 > **2026-09-20 层定义修订(ADR-0021)**:条款所属的层本体 = **存在格 / Materialization Space**(层定义与七字段模型 = docs/maintainer/design/materialization-space.md)——本文件的载体结构不变,变的只是条款的层归属称谓。 > 决策:adr/adr-0002(.ccr v6 段表架构)。 @@ -9,11 +9,11 @@ ## 一、设计原则(v6 与 v5 的分野) -1. **存在为主体,执行为投影**:v5 文件描述"按什么顺序执行什么"(线性指令数组);v6 描述"什么存在(条目 × 版本)、存在多久(区间)、由什么产生(配方)、嵌套在哪(region)"——执行序是可重建的投影,不再是文件主干。 -2. **图节点坐标(D1)**:存在区间端点、region 边界、条目定值点全部以 NOD id(图节点序)为坐标——与 .cir(图形态)同坐标系,兑现"图 = 唯一真相层"。 +1. **存在为主体,执行为投影**:v5 文件描述"按什么顺序执行什么"(线性指令数组);v6 描述"什么存在(条目 × 版本)、存在多久(区间)、由什么产生(配方)、嵌套在哪(region)"。执行序是可重建的投影,不再是文件主干。 +2. **图节点坐标(D1)**:存在区间端点、region 边界、条目定值点全部以 NOD id(图节点序)为坐标——与 `.cir`(图形态)同坐标系,兑现"图 = 唯一真相层"。 3. **执行序重建(D2)**:corearch 从 NOD + REG 重建线性投影——图节点文件序即合法拓扑序,重建 = 文件序直出 + region 边界标注,无排序成本。 4. **共存不落盘(D3)**:判定消费时从存在区间推导,sweep O(n log n),不超线性、不冗余存储。 -5. **v6-only**:不兼容 v5、无转换工具(.ccr 为管线中间产物,零持久生态)。 +5. **v6-only**:不兼容 v5、无转换工具(`.ccr` 为管线中间产物,零持久生态)。 6. **格层 vs 编码层**:ENT/NOD/REG 的语义(条目数学结构/版本/区间/共存)属格层,范式无关;字节宽/段表布局是编码层投影,可按编码空间调整。 --- @@ -94,7 +94,7 @@ REG 记录 = v5 sgs 坐标升级: | enter_nod / exit_nod | 入口/出口节点(NOD id) | | first_ent / last_ent | 区内条目范围(-1 = 无) | -REG 的 first_ent/last_ent 使"子图边界 = 存在域边界"成为直接查询——图锚定区域内存模型(region-model.md)的语义锚点:区域生命周期由 region 的存在结构推导,而非词法作用域。 +REG 的 first_ent/last_ent 使"子图边界 = 存在域边界"成为直接查询——图锚定区域内存模型(region-model.md)的语义锚点。区域生命周期由 region 的存在结构推导,而非词法作用域。 --- @@ -122,7 +122,11 @@ REG 的 first_ent/last_ent 使"子图边界 = 存在域边界"成为直接查询 | 共存 | 无 | 不落盘,sweep 推导 | | 兼容 | — | v6-only,无转换工具 | -消费方:corec 前端产 NOD+REG + 条目重建;corearch 段表寻址 → 投影重建 → 发射;判定(分配器/一致性自检)消费 ENT;证书等判定产物独立于 .ccr,不落本文件。 +消费方: +- corec:前端产 NOD+REG + 条目重建 +- corearch:段表寻址 → 投影重建 → 发射 +- 判定(分配器/一致性自检):消费 ENT +- 证书等判定产物独立于 `.ccr`,不落本文件。 --- diff --git a/docs/maintainer/design/ir-op-semantics.md b/docs/maintainer/design/ir-op-semantics.md index 69cb69fd..a4eb48d5 100644 --- a/docs/maintainer/design/ir-op-semantics.md +++ b/docs/maintainer/design/ir-op-semantics.md @@ -1,6 +1,6 @@ # Core IR 操作语义表(对照 CompCert x86/Op.v + Asm.v) -> 定位:受众 = 维护者;状态 = active +> 定位:受众 = 维护者;状态 = active。 > 用途:CompCert 对照审查第四轮(2026-08-16)的**契约文档**——Task 2 后端审查逐 opcode 三方对照 > (本表定义语义 vs `src/arch/linux/ld/instr.cr` ELF 编码 vs `src/compiler/interp.cr` 解释执行)以本表为准。 @@ -57,69 +57,69 @@ Core 侧只读来源:`src/compiler/ast.cr`(opcode 常量,L527-580)、`sr | # | 名称 | 分组 | 发射方 | ELF 后端 | 解释器 | 本节 | |---|---|---|---|---|---|---| -| 0 | IR_NOP | 控制流 | — | ✓ 空 | ✓ 空 | 2.5 | -| 1 | IR_CONST | 常量 | ir_gen | ✓ | ✓ | 2.1 | -| 2 | IR_BINARY | 算术 | ir_gen | ✓ | ✓(部分) | 2.2 | -| 3 | IR_UNARY | 算术 | ir_gen | ✓ | ✓ | 2.2 | -| 4 | IR_CALL | 调用 | ir_gen | ✓ | ✓(单层内联) | 2.5 | -| 5 | IR_RETURN | 调用 | ir_gen | ✓ | ✓ | 2.5 | -| 6 | IR_ALLOC | 内存 | ir_gen(标量槽标记) | ✓ 空 | ✓ 置 0 | 2.4 | -| 7 | IR_ALLOC_STRUCT | 内存 | ir_gen | ✓ | ✓ | 2.4 | -| 8 | IR_ALLOC_ARRAY | 内存 | ir_gen | ✓ | ✓ | 2.4 | -| 9 | IR_STORE | 拷贝(命名误导) | ir_gen | ✓ | ✓ | 2.1 | -| 10 | IR_LOAD | 拷贝 | ir_gen | ✓ | ✓ | 2.1 | -| 11 | IR_LOAD_FIELD | 内存 | ir_gen | ✓ | ✓ | 2.4 | -| 12 | IR_STORE_FIELD | 内存 | ir_gen | ✓ | ✓ | 2.4 | -| 13 | IR_LOAD_INDEX | 内存 | ir_gen | ✓ | ✓ | 2.4 | -| 14 | IR_STORE_INDEX | 内存 | ir_gen | ✓ | ✓ | 2.4 | -| 15 | IR_LOAD_INDEX_VAR | 内存 | ir_gen | ✓ | ✓ | 2.4 | -| 16 | IR_STORE_INDEX_VAR | 内存 | ir_gen | ✓ | ✓ | 2.4 | -| 17 | IR_MAKE_ENUM | 枚举 | ir_gen | ✓ | ✓(近似) | 2.6 | -| 18 | IR_REF | 地址 | ir_gen | ✓ | ✓(近似) | 2.4 | -| 19 | IR_BRANCH | 控制流 | ir_gen | ✓ | ✓ | 2.5 | -| 20 | IR_JUMP | 控制流 | ir_gen | ✓ | ✓ | 2.5 | -| 21 | IR_LABEL | 控制流 | ir_gen | ✓ | ✓ | 2.5 | -| 22 | IR_PHI | 控制流 | **无**(保留) | ✗ | ✗ | 2.5 | -| 23 | IR_LOAD_ENUM_TAG | 枚举 | ir_gen | ✓ | ✓(近似) | 2.6 | -| 24 | IR_SLICE | 内存 | ir_gen | ✓ | ✓(BC11 已修补实现) | 2.4 | -| 25 | IR_DEREF | 内存 | ir_gen | ✓ | ✓(近似) | 2.4 | -| 26 | IR_STORE_PTR | 内存 | ir_gen | ✓ | ✓(近似) | 2.4 | -| 27 | IR_SPAWN | 并发 | ir_gen | ✓(单线程近似) | ✓(单层) | 2.7 | -| 28 | IR_YIELD | 并发 | ir_gen | ✓(eager 值传递近似,BC8/F5 已修) | ✓ | 2.7 | -| 29 | IR_AWAIT | 并发 | ir_gen | ✓(eager) | ✓(eager) | 2.7 | -| 30 | IR_BOUNDS_CHECK | 内存/安全 | ext_safety | ✓ | ✓(BC11 已修补实现) | 2.4 | -| 31 | IR_ADDR_INDEX | 地址 | ir_gen | ✓ | ✓(BC11 已修补实现) | 2.4 | -| 32 | IR_ARENA_NEW | 内存 | ir_gen | ✓ | ✓(no-op 近似,BC11 已修) | 2.4 | -| 33 | IR_ARENA_RESET | 内存 | ir_gen(作用域退出) | ✓ | ✓(no-op 近似,BC11 已修) | 2.4 | -| 34 | IR_INLINE | 注解 | ir_gen | 空 | 空 | 2.9 | -| 35 | IR_NO_BOUNDS_CHECK | 注解 | ir_gen | 空 | 空 | 2.9 | -| 36 | IR_FAST | 注解 | ir_gen | 空 | 空 | 2.9 | -| 37 | IR_UNROLL | 注解 | ir_gen | 空 | 空 | 2.9 | -| 38 | IR_SECTION | 注解 | ir_gen | 空 | 空 | 2.9 | -| 39 | IR_HOTPATCH_ROUTE | 调用 | ir_gen | ✓ | ✗ | 2.5 | +| 0 | `IR_NOP` | 控制流 | — | ✓ 空 | ✓ 空 | 2.5 | +| 1 | `IR_CONST` | 常量 | `ir_gen` | ✓ | ✓ | 2.1 | +| 2 | `IR_BINARY` | 算术 | `ir_gen` | ✓ | ✓(部分) | 2.2 | +| 3 | `IR_UNARY` | 算术 | `ir_gen` | ✓ | ✓ | 2.2 | +| 4 | `IR_CALL` | 调用 | `ir_gen` | ✓ | ✓(单层内联) | 2.5 | +| 5 | `IR_RETURN` | 调用 | `ir_gen` | ✓ | ✓ | 2.5 | +| 6 | `IR_ALLOC` | 内存 | `ir_gen`(标量槽标记) | ✓ 空 | ✓ 置 0 | 2.4 | +| 7 | `IR_ALLOC_STRUCT` | 内存 | `ir_gen` | ✓ | ✓ | 2.4 | +| 8 | `IR_ALLOC_ARRAY` | 内存 | `ir_gen` | ✓ | ✓ | 2.4 | +| 9 | `IR_STORE` | 拷贝(命名误导) | `ir_gen` | ✓ | ✓ | 2.1 | +| 10 | `IR_LOAD` | 拷贝 | `ir_gen` | ✓ | ✓ | 2.1 | +| 11 | `IR_LOAD_FIELD` | 内存 | `ir_gen` | ✓ | ✓ | 2.4 | +| 12 | `IR_STORE_FIELD` | 内存 | `ir_gen` | ✓ | ✓ | 2.4 | +| 13 | `IR_LOAD_INDEX` | 内存 | `ir_gen` | ✓ | ✓ | 2.4 | +| 14 | `IR_STORE_INDEX` | 内存 | `ir_gen` | ✓ | ✓ | 2.4 | +| 15 | `IR_LOAD_INDEX_VAR` | 内存 | `ir_gen` | ✓ | ✓ | 2.4 | +| 16 | `IR_STORE_INDEX_VAR` | 内存 | `ir_gen` | ✓ | ✓ | 2.4 | +| 17 | `IR_MAKE_ENUM` | 枚举 | `ir_gen` | ✓ | ✓(近似) | 2.6 | +| 18 | `IR_REF` | 地址 | `ir_gen` | ✓ | ✓(近似) | 2.4 | +| 19 | `IR_BRANCH` | 控制流 | `ir_gen` | ✓ | ✓ | 2.5 | +| 20 | `IR_JUMP` | 控制流 | `ir_gen` | ✓ | ✓ | 2.5 | +| 21 | `IR_LABEL` | 控制流 | `ir_gen` | ✓ | ✓ | 2.5 | +| 22 | `IR_PHI` | 控制流 | **无**(保留) | ✗ | ✗ | 2.5 | +| 23 | `IR_LOAD_ENUM_TAG` | 枚举 | `ir_gen` | ✓ | ✓(近似) | 2.6 | +| 24 | `IR_SLICE` | 内存 | `ir_gen` | ✓ | ✓(BC11 已修补实现) | 2.4 | +| 25 | `IR_DEREF` | 内存 | `ir_gen` | ✓ | ✓(近似) | 2.4 | +| 26 | `IR_STORE_PTR` | 内存 | `ir_gen` | ✓ | ✓(近似) | 2.4 | +| 27 | `IR_SPAWN` | 并发 | `ir_gen` | ✓(单线程近似) | ✓(单层) | 2.7 | +| 28 | `IR_YIELD` | 并发 | `ir_gen` | ✓(eager 值传递近似,BC8/F5 已修) | ✓ | 2.7 | +| 29 | `IR_AWAIT` | 并发 | `ir_gen` | ✓(eager) | ✓(eager) | 2.7 | +| 30 | `IR_BOUNDS_CHECK` | 内存/安全 | `ext_safety` | ✓ | ✓(BC11 已修补实现) | 2.4 | +| 31 | `IR_ADDR_INDEX` | 地址 | `ir_gen` | ✓ | ✓(BC11 已修补实现) | 2.4 | +| 32 | `IR_ARENA_NEW` | 内存 | `ir_gen` | ✓ | ✓(no-op 近似,BC11 已修) | 2.4 | +| 33 | `IR_ARENA_RESET` | 内存 | `ir_gen`(作用域退出) | ✓ | ✓(no-op 近似,BC11 已修) | 2.4 | +| 34 | `IR_INLINE` | 注解 | `ir_gen` | 空 | 空 | 2.9 | +| 35 | `IR_NO_BOUNDS_CHECK` | 注解 | `ir_gen` | 空 | 空 | 2.9 | +| 36 | `IR_FAST` | 注解 | `ir_gen` | 空 | 空 | 2.9 | +| 37 | `IR_UNROLL` | 注解 | `ir_gen` | 空 | 空 | 2.9 | +| 38 | `IR_SECTION` | 注解 | `ir_gen` | 空 | 空 | 2.9 | +| 39 | `IR_HOTPATCH_ROUTE` | 调用 | `ir_gen` | ✓ | ✗ | 2.5 | | 40 | *(未定义)* | — | — | — | — | — | -| 41 | IR_DYN_TAG | 动态 | ir_gen | ✓ | ✗ | 2.6 | -| 42 | IR_DYN_VAL | 动态 | ir_gen | ✓ | ✗ | 2.6 | -| 43 | IR_DYN_PACK | 动态 | ir_gen | ✓ | ✗ | 2.6 | -| 44 | IR_DYN_DISPATCH | 动态 | ir_gen | ✓(占位) | ✗ | 2.6 | -| 45 | IR_CALL_EXTERN | 调用 | ir_gen | ✓ | ✗ | 2.5 | -| 46 | IR_LAZY_THUNK | 惰性 | ir_gen | ✓(eager) | ✓(eager) | 2.7 | -| 47 | IR_LAZY_FORCE | 惰性 | ir_gen | ✓(eager) | ✓(eager) | 2.7 | -| 48 | IR_FNADDR | 地址 | ir_gen | ✓ | ✓(d=0) | 2.5 | -| 49 | IR_I2F | 转换 | ir_gen | ✓([注意] 见 BC-I2F) | ✗ | 2.3 | -| 50 | IR_F2I | 转换 | ir_gen | ✓ | ✗ | 2.3 | -| 51 | IR_APPROX | 注解 | —(**零发射点**;`ast.cr:568` 已定义) | — | — | 2.9 | +| 41 | `IR_DYN_TAG` | 动态 | `ir_gen` | ✓ | ✗ | 2.6 | +| 42 | `IR_DYN_VAL` | 动态 | `ir_gen` | ✓ | ✗ | 2.6 | +| 43 | `IR_DYN_PACK` | 动态 | `ir_gen` | ✓ | ✗ | 2.6 | +| 44 | `IR_DYN_DISPATCH` | 动态 | `ir_gen` | ✓(占位) | ✗ | 2.6 | +| 45 | `IR_CALL_EXTERN` | 调用 | `ir_gen` | ✓ | ✗ | 2.5 | +| 46 | `IR_LAZY_THUNK` | 惰性 | `ir_gen` | ✓(eager) | ✓(eager) | 2.7 | +| 47 | `IR_LAZY_FORCE` | 惰性 | `ir_gen` | ✓(eager) | ✓(eager) | 2.7 | +| 48 | `IR_FNADDR` | 地址 | `ir_gen` | ✓ | ✓(d=0) | 2.5 | +| 49 | `IR_I2F` | 转换 | `ir_gen` | ✓([注意] 见 BC-I2F) | ✗ | 2.3 | +| 50 | `IR_F2I` | 转换 | `ir_gen` | ✓ | ✗ | 2.3 | +| 51 | `IR_APPROX` | 注解 | —(**零发射点**;`ast.cr:568` 已定义) | — | — | 2.9 | 对照 CompCert:Core 的「opcode + 操作数槽(dest/src1/src2/src3/type_kind)」形态对应 RTL 的 `Iop`(3 地址) -与 Asm 的 `instruction` 之间的中间层——语义表以 Asm.v 的机器语义为基准(opcode 最终由机器指令兑现), -算术层语义以 Op.v 的 `eval_operation` 为基准。 +与 Asm 的 `instruction` 之间的中间层——语义表以 `Asm.v` 的机器语义为基准(opcode 最终由机器指令兑现), +算术层语义以 `Op.v` 的 `eval_operation` 为基准。 ## 3. 分组语义定义 记法:`a` = `ρ(s1)`、`b` = `ρ(s2)`(变量取值);`d` = dest 变量;`M[x]` = 内存 `x` 处 8 字节; `→` = 状态变换;`⊥` = 中止(陷阱)。 -### 2.1 常量与拷贝(对照 Op.v 常量/Omove) +### 2.1 常量与拷贝(对照 `Op.v` 常量/`Omove`) - **IR_CONST**(1):`d := s1`(立即数)。`type_kind` 决定解释:`TI_STR` → `d` = rodata 字符串基址 (ELF 经 `lea r10,[rip+disp]` 补丁;对照 CompCert `Pmov_rs` Asm.v:L619-620 / `Oindirectsymbol` Op.v:L352); @@ -131,7 +131,7 @@ Core 侧只读来源:`src/compiler/ast.cr`(opcode 常量,L527-580)、`sr > 组注:`IR_LOAD`/`IR_STORE` 在 Core 中是「槽间拷贝」,真正的内存操作是 FIELD/INDEX/DEREF 族—— > 与 CompCert 的 load/store 命名不同,属 Core 的 IR 形态设计(D:扁平槽模型,全局/局部统一)。 -### 2.2 算术(对照 Op.v eval_operation + Asm.v 整数算术) +### 2.2 算术(对照 `Op.v` `eval_operation` + `Asm.v` 整数算术) `IR_BINARY`(2)按 `s3 = OP_*` 分派;`IR_UNARY`(3)按 `s3 = UOP_*` 分派。`type_kind = TI_FLOAT` 时走浮点路径(见下)。 @@ -171,16 +171,16 @@ Core 侧只读来源:`src/compiler/ast.cr`(opcode 常量,L527-580)、`sr **BC2 [ok] 已修复(2026-08-17,第四轮 F10)——整数除/模截断方向三方已统一为向零截断**: - ELF 后端:`idiv` → 向零截断(与 CompCert `Z.quot` 一致)✓ - Python bootstrap 解释器(`bootstrap/corec/backend/interpreter.py`):**已修**——`//` 改 abs+符号向零截断、`%` 余数符号随被除数(修复前 Python `//` = 向下取整(-7/3 = -3,C 为 -2)、`%` 余数符号随除数——与 Core 的 C 语义不一致);`tests/bootstrap/test_pipeline.py` 补四组负操作数回归用例(-7/3、7/-3、-7%3、7%-3) -- 自托管 interp.cr 的 `lv / rv` 行为取决于承载二进制:经 ELF 构建 → 向零;经 Python bootstrap 跑测试 → 向下(修复后一致)。 +- 自托管 interp.cr 的 `lv / rv` 行为取决于承载二进制:经 ELF 构建 → 向零;经 Python bootstrap 执行测试 → 向下(修复后一致)。 - 契约定为:**向零截断**(对照 CompCert)。 -### 2.3 转换(对照 Op.v 转换族) +### 2.3 转换(对照 `Op.v` 转换族) - **IR_I2F**(49):`d := float(int64(a))`。对照 `Ofloatoflong`(Op.v:L169, L438)→ `Val.floatoflong` = `Float.of_long`(Floats.v:L318-320:`BofZ` 53 位二进制浮点,就近舍入)。ELF 编码现状:`F2 48 0F 2A`(`cvtsi2sd`,**REX.W 已补——BC-I2F [ok] 已修复(2026-08-17,第四轮 F7)**,`e2_sd_cvt` instr.cr L378-389)。修复前为 `F2 0F 2A`(32 位操作数)只转换低 32 位符号扩展,`|a| ≥ 2³¹` 时结果错误(如 `2⁴⁰ → 0.0`),与 `IR_F2I` 的 `cvttsd2si` `F2 48 0F 2C`(REX.W ✓)不对称。迁移后语义:int→dex = `d := a·10⁶`(精确,无舍入)。 - **IR_F2I**(50):`d := trunc(f)`(向零截断)。对照 `Olongoffloat`(Op.v:L167, L437)→ `Val.longoffloat` = `Float.to_long`(Floats.v:L308-309:`ZofB_range` 向零截断,**越界 → None**)。当前 ELF 用 `cvttsd2si`:向零截断 ✓,但**越界结果是硬件返回的特殊值 0x8000000000000000**(Intel SDM:异常掩码默认下越界 `cvttsd2si` 返回不定值 INT64_MIN——文档化行为)——CompCert 定义为 `None`(Stuck)。**BC-F2I(死路径已确认,第四轮 §2):IR_F2I 无发射方(语言级 float→int 转换不存在),当前不可触发**;若将来启用需定越界语义。迁移后语义:dex→int = `d := trunc(a/10⁶)`(有损转换,`EC_R_LOSSY_CONVERT` R004 检查点)。 - interp:op 49/50 **已实现**(`i64_to_f64`/`f64_to_i64`,f64.cr 软件路径,BC11 已修)——原「静默跳过」见 BC11(已修复)。 -### 2.4 内存与地址(对照 Memory.v 模型 + Asm.v 访问指令) +### 2.4 内存与地址(对照 `Memory.v` 模型 + `Asm.v` 访问指令) 分配(对照 CompCert `Pallocframe`(Asm.v:L948-958)/`Mem.alloc`(Memory.v:L348)——L531 是 `store`,勿误引): @@ -220,7 +220,7 @@ load/store(对照 `Mem.load`/`Mem.store` Memory.v:L428/L531 + `valid_access` L - **IR_CALL_EXTERN**(45):外部符号调用——`s1`=函数名 ni、`s2`=首参、`s3`=参数个数(**注意:约定与 IR_CALL 不同,名字在 s1**)。ELF:外部重定位 `call rel32`。对照 CompCert `exec_step_external`(Asm.v:L1120-1127)。 - **IR_HOTPATCH_ROUTE**(39):热补丁路由调用(s1=名字、s2=首参、s3=参数数,同 CALL_EXTERN 约定)。ELF:call patch 同 CALL。对照无(CompCert 无热补丁)——D。 - **IR_FNADDR**(48):`d := &f`(`s1`=函数名 ni;`movabs` imm64 + 链接期补丁)。对照 `Oindirectsymbol`(Op.v:L79, L352)→ `Genv.symbol_address`。interp:`d := 0`(无地址概念,已知局限)。 -- **IR_SPAWN**(27):创建并发执行单元——`d`=future/结果、`s1`=首参、`s2`=参数个数、`s3`=函数名 ni(**按 ir_gen.cr L871 实际发射**)。**BC1 [ok] 已修复(2026-08-17,第四轮 F4)**:操作数约定统一为 s3=函数名,并补 SysV 参数装载(修复前 ast.cr 注释/instr.cr(`name_ni := s1`)与发射方/interp 四方错位——ELF 拿参数变量索引当函数名查表、且从不装载参数 → SIGSEGV)。ELF 现为单线程近似(直接 call 存结果);interp 单层内联。对照:CompCert 无并发——D。 +- **IR_SPAWN**(27):创建并发执行单元——`d`=future/结果、`s1`=首参、`s2`=参数个数、`s3`=函数名 ni(**按 ir_gen.cr L871 实际发射**)。**BC1 [ok] 已修复(2026-08-17,第四轮 F4)**:操作数约定统一为 s3=函数名,并补 SysV 参数装载(修复前 ast.cr 注释/instr.cr(`name_ni := s1`)与发射方/interp 四方错位——ELF 以参数变量索引作函数名查表、且从不装载参数 → SIGSEGV)。ELF 现为单线程近似(直接 call 存结果);interp 单层内联。对照:CompCert 无并发——D。 ### 2.6 枚举与动态类型 @@ -234,7 +234,7 @@ load/store(对照 `Mem.load`/`Mem.store` Memory.v:L428/L531 + `valid_access` L ### 2.7 并发 / 流 / 惰性(对照:CompCert 无,全部为 D 设计差异) - **IR_SPAWN**:见 2.5。 -- **IR_YIELD**(28):语义 = **向 flow 消费者通道发射 `ρ(s1)`**(ast.cr L557)。**BC8 [ok] 已修复(2026-08-17,第四轮 F5)**:ELF 改 **eager 值传递近似**(`d := ρ(s1)`,不再 `call sched_yield()`——修复前实现与定义语义不符且未导入符号 rel32=0 崩溃);interp 补 `d >= 0` 守卫(修复前发射恒 dest=-1 → `g_ir_vals[-8]` 堆下溢写,静默 UB)。三方一致为 eager 近似(D:单线程模式既定近似——完整 go/G-M 调度见 docs/maintainer/design/execution-model.md §三);flow fn 语法已修(parser 不再把 T_FN 当函数名)。 +- **IR_YIELD**(28):语义 = **向 flow 消费者通道发射 `ρ(s1)`**(ast.cr L557)。**BC8 [ok] 已修复(2026-08-17,第四轮 F5)**:ELF 改 **eager 值传递近似**(`d := ρ(s1)`,不再 `call sched_yield()`——修复前实现与定义语义不符且未导入符号 rel32=0 崩溃);interp 补 `d >= 0` 守卫(修复前发射恒 dest=-1 → `g_ir_vals[-8]` 堆下溢写,静默 UB)。三方一致为 eager 近似(D:单线程模式既定近似——完整 go/G-M 调度见 docs/maintainer/design/execution-model.md §三);flow fn 语法已修(parser 不再将 T_FN 视作函数名)。 - **IR_AWAIT**(29):语义 = 阻塞直到 future 就绪,`d` = 结果。ELF/interp 均为值复制(eager 近似,已文档化)——D:单线程模式的既定近似。 - **IR_LAZY_THUNK**(46):`d` = 惰性包装(s1 = 表达式求值)。**IR_LAZY_FORCE**(47):`d` = 强求结果。两者当前均 eager 近似(值传递,ELF/interp 一致)——D:惰性求值尚未落地(lazy 设计文档),IR 保留显式 thunk 形态以便迁移。 @@ -287,7 +287,7 @@ load/store(对照 `Mem.load`/`Mem.store` Memory.v:L428/L531 + `valid_access` L | # | 位置 | 现象 | 依据 | 状态(2026-08-17) | |---|---|---|---|---| | **BC-I2F** | instr.cr L352-363 | **IR_I2F 的 `cvtsi2sd` 缺 REX.W**:`F2 0F 2A`(32 位操作数)→ `\|a\|≥2³¹` 的 int64→float 截断为低 32 位符号扩展(如 2⁴⁰ → 0.0)。IR_F2I 有 `F2 48 0F 2C` 对照可见遗漏 | 本表 2.3;CompCert `Ofloatoflong`(Op.v:L438)语义对照 | [ok] 已修复(2026-08-17,第四轮 F7:`e2_sd_cvt` 补 REX.W) | -| BC1 | instr.cr L825-836(IR_SPAWN `name_ni := s1`) | SPAWN 操作数约定错位:发射方/interp 用 `s3`=函数名、`s1`=首参;ELF 拿 `s1`(参数变量索引)当函数名查表;ast.cr L556 注释与二者皆不同 | 本表 2.5;ir_gen.cr L871 vs instr.cr L828 | [ok] 已修复(2026-08-17,第四轮 F4:统一 s3=函数名 + SysV 参数装载) | +| BC1 | instr.cr L825-836(IR_SPAWN `name_ni := s1`) | SPAWN 操作数约定错位:发射方/interp 用 `s3`=函数名、`s1`=首参;ELF 以 `s1`(参数变量索引)作函数名查表;ast.cr L556 注释与二者皆不同 | 本表 2.5;ir_gen.cr L871 vs instr.cr L828 | [ok] 已修复(2026-08-17,第四轮 F4:统一 s3=函数名 + SysV 参数装载) | | BC2 | bootstrap/corec/backend/interpreter.py L108 | 整数除/模截断方向:Python `//` 向下取整 vs 契约向零截断(ELF `idiv` ✓,CompCert `Z.quot` ✓)——负除数程序在 bootstrap 与 ELF 下结果不同 | 本表 2.2;Values.v L727 / Integers.v L193 | [ok] 已修复(2026-08-17,第四轮 F10:abs+符号向零截断,补四组负操作数回归) | | BC3 | ast.cr L282-283 + instr.cr L495-512 | OP_SHL/OP_SHR 无发射方(死路径);若启用,OP_SHR 用 `shr`(逻辑)而契约方向未定(CompCert `Oshrl` 为算术) | 本表 2.2 | 死路径已确认(第四轮 §2)——启用时按契约补语义 | | BC4 | interp.cr L96-123 | 解释器对 TI_FLOAT 无分支:float 算术按整数位模式运算(结果错误);op 24/30/31/32/33/41-45/49/50 未实现(静默跳过);`IR_STORE_PTR` 槽拷贝错位(BC12 细化) | 本表 2.2/2.3/2.4 | [ok] 已修复(2026-08-17,第四轮 F9:TI_FLOAT 走 f64.cr 软件实现;其余 opcode 随 BC11 补齐) | diff --git a/docs/maintainer/design/memory-model.md b/docs/maintainer/design/memory-model.md index d40d65a5..753ca7d4 100644 --- a/docs/maintainer/design/memory-model.md +++ b/docs/maintainer/design/memory-model.md @@ -1,6 +1,6 @@ # 存储语义总览:存在格 → 存在结构 → 经典映射 -> 定位:受众 = 维护者/贡献者;状态 = active。 +> 定位:受众 = 维护者/贡献者;状态 = active。 > 本文件是存储语义三层结构的**导航总览**——细节各归其位:**层定义 = materialization-space.md**(存在格 / Materialization Space);条款权威 = cache-semantics.md;IR 载体 = existence-structure.md;经典映射 = region-model.md。 > 分层:三层映射链(图 → 格 → 编码)中「格」层的内容;术语权威见 docs/glossary.md。 > **2026-09-20 层定义修订**(ADR-0021):「格 = 缓存语义」降级为特例——格层本体 = **存在格**,缓存是该层的一类映射实例。本文各处的框定词已同步。 @@ -17,7 +17,7 @@ | [region-model.md](region-model.md) | 经典映射:图锚定区域/Arena/字节权限/逃逸规则 | 内存管理实现者 | | 本文件 | 三层关系、阅读路径、关联 | 所有读者(入口) | -## 二、一张图看懂三层 +## 二、三层结构总览 ``` 层定义 = 存在格 存在结构(existence-structure.md) 经典映射(region-model.md) @@ -35,7 +35,7 @@ ## 三、术语定位 -"内存"在仓库里有三层含义,阅读时先判定语境(详见 glossary): +"内存"在仓库中有三层含义,阅读前需先判定语境(详见 glossary): | 术语 | 含义 | 文档 | |---|---|---| diff --git a/docs/maintainer/design/pointer-model.md b/docs/maintainer/design/pointer-model.md index 47ae18da..c34e736a 100644 --- a/docs/maintainer/design/pointer-model.md +++ b/docs/maintainer/design/pointer-model.md @@ -1,6 +1,6 @@ # Core 指针模型:图上的三点验证 pass -> 定位:受众 = 维护者(改/验证三点 pass 的人);状态 = active;出处 = 源码(src/compiler/ptr_analysis.cr、region_check.cr、provenance_verify.cr)——本文描述的是已实现行为,文档与源码冲突时以源码为准,并请更新本文。 +> 定位:受众 = 维护者(改/验证三点 pass 的人);状态 = active;出处 = 源码(src/compiler/ptr_analysis.cr、region_check.cr、provenance_verify.cr)——本文描述的是已实现行为,文档与源码冲突时以源码为准,并请更新本文。 > 语义定位:指针安全建立在 HDFG 上,不引入 borrow checker/生命周期标注。地址语义(条目标识 + 偏移)见条款 6(docs/academic/cache-semantics.md);层本体 = 存在格(docs/maintainer/design/materialization-space.md);经典映射见 docs/maintainer/design/region-model.md。 > 本文 2026-09 重写:三 pass 描述与实现对齐(Andersen 约束求解、逃逸三点检查、双路径边界验证)。 @@ -8,7 +8,7 @@ ## 一、问题与方案 -C 风格裸指针表达力强但无保障;Rust 用 borrow checker 换安全,代价是学习曲线与表达力。Core 的目标:**指针和 C 一样自由,安全保障不依赖用户标注**——编译器维护完整 HDFG,图中每个值的出生节点记录来源(provenance),每个解引用是 DEREF/STORE_PTR 节点;三点 pass 在图上验证,与类型系统解耦: +C 风格裸指针表达力强但无保障;Rust 用 borrow checker 换安全,代价是学习曲线与表达力。Core 的目标:**指针和 C 一样自由,安全保障不依赖用户标注**。编译器维护完整 HDFG:图中每个值的出生节点记录来源(provenance),每个解引用是 DEREF/STORE_PTR 节点;三点 pass 在图上验证,与类型系统解耦: | Pass | 文件 | 功能 | |---|---|---| @@ -28,7 +28,7 @@ C 风格裸指针表达力强但无保障;Rust 用 borrow checker 换安全,代 | 子图/SG region | 图锚定的执行域(函数/loop/for/flow/unsafe,见 execution-model.md §二) | | 图边界 | 编译器无 provenance 的入口(外部地址、FFI 返回、inline asm)→ unsafe | -## 三、用户可见语法(开发者的形状) +## 三、用户可见语法(开发者视角) 开发者视角的语法与保证见 docs/developer/syntax.md 指针节;此处只列 pass 输入形状: @@ -45,11 +45,11 @@ unsafe { } ``` -类型双关(`*(dex*)&i`)不需要 unsafe——地址语义是条目标识 + 偏移(条款 6),经典映射是"字节序列 + 宽度 + 边界",provenance/offset/alloc_size 与类型无关;cast 保留值流,provenance 边不断。判据 = 边界 + 宽度。 +类型双关(`*(dex*)&i`)不需要 unsafe——地址语义是条目标识 + 偏移(条款 6),经典映射是"字节序列 + 宽度 + 边界",provenance/offset/alloc_size 与类型无关;`cast` 保留值流,provenance 边不断。判据 = 边界 + 宽度。 ## 四、Pass 1:PointerAnalysis(ptr_analysis.cr) -**算法**:interprocedural Andersen-style 约束求解(参考 SVF, Sui & Xue CC 2016——inclusion constraints + interprocedural function summaries),在数据流图上跑。规则(源码注释): +**算法**:在数据流图上跑 interprocedural Andersen-style 约束求解(参考 SVF, Sui & Xue CC 2016——inclusion constraints + interprocedural function summaries)。规则(源码注释): | 规则 | 触发 | 动作 | |---|---|---| @@ -60,15 +60,15 @@ unsafe { | Call | 调用 | 函数摘要传播 + 参数保守处理(interprocedural) | 实现要点: -- pts 为**位图**(pa_set_bit 等,grow_pa_alloc_nodes 动态扩容)——非逐对象列表 -- **alloc content 跟踪**:g_alloc_pts[alloc_id] 记录"存进该分配块的值集合",DEREF 读它——pointer-induced flow 的实现形态(不是图上物理加边,是位图数据) -- unsafe 感知:pa_in_unsafe 使 unsafe 域内指针不参与正常约束 +- pts 为**位图**(`pa_set_bit` 等,`grow_pa_alloc_nodes` 动态扩容)——非逐对象列表 +- **alloc content 跟踪**:`g_alloc_pts[alloc_id]` 记录"存进该分配块的值集合",DEREF 读它——pointer-induced flow 的实现形态(不是图上物理加边,是位图数据) +- unsafe 感知:`pa_in_unsafe` 使 unsafe 域内指针不参与正常约束 按子图独立分析 + 函数摘要跨子图——不需要全程序统一求解。 ## 五、Pass 2:RegionCheck(region_check.cr) -**功能**:逃逸检查——子图 A 分配的内存不能逃逸出 A 的存活域。判定基准 = SG region 区间(enter/nstart/ncount/exit,dataflow.cr 的 sg 表)。 +**功能**:逃逸检查——子图 A 分配的内存不能逃逸出 A 的存活域。判定基准 = SG region 区间(`enter`/`nstart`/`ncount`/`exit`,dataflow.cr 的 sg 表)。 四点判定(2026-09-20 修订为与实现一致;实现见 `region_check.cr`,共用单源判定 `rc_var_dead`): @@ -87,7 +87,7 @@ unsafe { **功能**:DEREF/STORE_PTR 越界检查——偏移 + 访问宽度 vs 分配大小。 -处理(per DEREF/STORE_PTR,per 函数 provenance_verify_func): +处理(per DEREF/STORE_PTR,per 函数 `provenance_verify_func`): 1. 从 s1(指针变量)取 pts 目标集合;经 g_offsets 取累计偏移 2. 对每个目标 alloc:get_alloc_size(编译期已知大小)且偏移可静态定 → `0 <= off && off + width <= alloc_size`?通过则**编译期证明**;越界 → 编译错误(EC_TU_DEREF 错误码) 3. 未知大小或动态偏移 → **运行时检查**:编码 allocation base/size/width,`sub+cmp+jae+ud2` 序列(panic);多 pts 目标时按目标定位实际 base(runtime_targets),不再用页内偏移近似(2026-08-16 落地) diff --git a/docs/maintainer/design/regalloc-cache-mapping.md b/docs/maintainer/design/regalloc-cache-mapping.md index eefaba5e..77d91fef 100644 --- a/docs/maintainer/design/regalloc-cache-mapping.md +++ b/docs/maintainer/design/regalloc-cache-mapping.md @@ -1,6 +1,6 @@ # 寄存器分配:缓存语义映射实例 -> 定位:受众 = 维护者(分配器/opt.cr/一致性自检);状态 = active。 +> 定位:受众 = 维护者(分配器/opt.cr/一致性自检);状态 = active。 > 本文是寄存器分配在 Core 架构中的正式参考文档——缓存语义(条款权威 = docs/academic/cache-semantics.md;层定义 = docs/maintainer/design/materialization-space.md)的寄存器映射实例;存在区间载体 = v6 ENT(docs/maintainer/design/existence-structure.md)。 > 设计决策记录(日期/排除方向/讨论):docs/superpowers/specs/2026-08-27-regalloc-cache-mapping-design.md;分配器逻辑契约文档 = src/compiler/regalloc-consistency.cr(v6 分支)。 > 本文 2026-09 重写:v6 对齐(ENT 区间/home/sweep 共存)+ 实现状态分线(develop vs lattice-ir-v6)。 @@ -20,7 +20,7 @@ | 共存 | 两条目存在区间相交(对称、无传递性;v6 sweep 推导,不落盘) | | 寄存器映射实例 | 寄存器文件 = 缓存层、home = 栈槽(条款 7) | -## 一、定位:分配是映射实例,不是编译器 pass +## 一、定位:映射实例而非编译器 pass 寄存器分配与区域/arena/字节权限同族,是格 → 编码的映射实例(条款 7): @@ -36,12 +36,12 @@ - 正确性 **order-free**:对全部可能执行陈述,不对某条线性化路径 - 范式映射表 = 映射正确性定理表——寄存器实例是其中一行(经典行),与字节内存行同构:证明缓存语义 ⊇ 该实现 -## 二、语义基座:驱逐不变量 = 语义保持定理 +## 二、语义基座:驱逐不变量与语义保持定理 公理 = 条款 1–7(docs/academic/cache-semantics.md)。其中: - **驱逐不变量(条款 2)**:⟦G ∖ storage(e)⟧ = ⟦G⟧——驱逐任意条目不改变可观测语义 -- 分配器放寄存器还是栈、放多久 = 放置/替换策略——**算法零证明**,语义保持不依赖具体贪心(生成器 + 验证器分离;VeriLocc 同构先例) +- 分配器选寄存器还是栈、保留时长 = 放置/替换策略——**算法零证明**,语义保持不依赖具体贪心(生成器 + 验证器分离;VeriLocc 同构先例) - **无格承诺**:判定/定理只在关系层面陈述——共存无传递性(最弱理论);对一切格成立 ## 三、对象与 v6 载体 diff --git a/docs/maintainer/design/region-model.md b/docs/maintainer/design/region-model.md index df77055f..24254ac3 100644 --- a/docs/maintainer/design/region-model.md +++ b/docs/maintainer/design/region-model.md @@ -1,6 +1,6 @@ # 图锚定区域:存在格语义的经典映射(区域/Arena/权限) -> 定位:受众 = 维护者/贡献者(内存管理实现与验证);状态 = active(arena 层已实现;区域机制部分设计态,状态见 §六)。 +> 定位:受众 = 维护者/贡献者(内存管理实现与验证);状态 = active(arena 层已实现;区域机制部分设计态,状态见 §六)。 > 本文件 = **存在格 / Materialization Space**(层定义 = docs/maintainer/design/materialization-space.md;条款权威 = docs/academic/cache-semantics.md)在经典字节硬件上的**映射实例**详细设计——正确性标准 = 保持条款 1–6 的可观测语义(条款 7)。 > 设计谱系:2026-07-28 多 Arena(已实现,分配器面)→ 2026-08-13 图锚定区域(语义面升级,本文档);设计依据 specs 见 §七。 @@ -8,11 +8,11 @@ ## 一、方案概述 -Core 采用**图锚定区域**的统一内存管理:区域(Region)锚定在 HDFG 上——**区域是子图节点的字节域**,不是词法作用域的影子。堆按 HDFG 子图划分独立区域,区域内线性指针碰撞分配(bump allocation),回收 = 游标重置(格式化清空)。 +Core 采用**图锚定区域**的统一内存管理:区域(Region)锚定在 HDFG 上——**区域是子图节点的字节域**,不是词法作用域的影子。堆按 HDFG 子图划分独立区域;区域内做线性指针碰撞分配(bump allocation),回收 = 游标重置(格式化清空)。 -传统区域内存管理(Tofte-Talpin 区域栈、Cyclone、Verona)锚定词法作用域(LIFO 嵌套);Core 的执行模型是 HDFG,区域与图同构——这是与经典区域模型的分野,也是非 LIFO 生命周期(go/flow)可行的原因。 +传统区域内存管理(Tofte-Talpin 区域栈、Cyclone、Verona)锚定词法作用域(LIFO 嵌套)。Core 的执行模型是 HDFG,区域与图同构——这是与经典区域模型的分野,也是非 LIFO 生命周期(go/flow)可行的原因。 -不可放弃的两个核心价值: +两个不可放弃的核心价值: 1. **无碎片**——静态已知大小的分配路径保持纯 bump,零碎片 2. **动态模式下工程可控的极低碎片**——动态大小分配路径走分档子区域,浪费上界由 size class 表决定(档位越细上界越低:pow2 档约 50%,细分档约 12.5%) @@ -21,7 +21,7 @@ Core 采用**图锚定区域**的统一内存管理:区域(Region)锚定在 HDFG --- -## 二、设计动机(为什么区域) +## 二、设计动机(区域方案) | 方案 | 问题 | |---|---| @@ -30,7 +30,12 @@ Core 采用**图锚定区域**的统一内存管理:区域(Region)锚定在 HDFG | 跟踪式 GC | 停顿不可预测、内存开销不确定、不适合硬实时 | | RAII + 所有权(Rust) | 静态正确,但复杂数据结构需精细设计借用关系,运行期开销 | -区域方案优势:分配 O(1)(指针碰撞)、回收 O(1)(整体重置)、区域内无碎片、可预测(无 GC 停顿)、cache 友好(同子图数据同区域,空间局部性好)。 +区域方案的优势: +- 分配 O(1)(指针碰撞) +- 回收 O(1)(整体重置) +- 区域内无碎片 +- 可预测(无 GC 停顿) +- cache 友好(同子图数据同区域,空间局部性好) 论文依据:Tofte & Talpin 区域推断(POPL'94,泄漏弱点需显式提前释放)、Gay & Aiken 显式区域(PLDI'98,提前释放工程可用)、Verona/snmalloc(Oopsla'24,size class 分档)、CompCert v2(每字节权限层 = 经典映射的权限面)。细节见 graph-anchored-regions-design。 @@ -88,10 +93,10 @@ Core 采用**图锚定区域**的统一内存管理:区域(Region)锚定在 HDFG 实现要点(已落地): - stdlib arena.cr 完整生命周期(init/new/reset)、动态元数据、free list、嵌套 - IR 子图绑定:函数/loop/for/unsafe 自动 arena lifecycle + 编译期大小预计算(ir_gen.cr) -- ELF 后端双路径 alloc:arena 感知(g_current_arena 检查)+ 全局 bump 回退;mmap 堆扩展(BSS 打满自动 mmap) -- emit_alloc_body 零初始化 + 链式扩容 +- ELF 后端双路径 alloc:arena 感知(`g_current_arena` 检查)+ 全局 bump 回退;mmap 堆扩展(BSS 打满自动 mmap) +- `emit_alloc_body` 零初始化 + 链式扩容 -运行时:每区域单线程访问,bump pointer 无需原子操作(无锁分配);go 创建独立区域(G 的 arena),返回值拷贝到父区域;区域池制——活跃区域数 = 当前并发子图数,上限 = MAX_CONCURRENCY,耗尽时新 go/flow 阻塞等待;无 GC。 +运行时:每区域单线程访问,`bump pointer` 无需原子操作(无锁分配);go 创建独立区域(G 的 arena),返回值拷贝到父区域;区域池制——活跃区域数 = 当前并发子图数,上限 = `MAX_CONCURRENCY`,耗尽时新 go/flow 阻塞等待;无 GC。 --- @@ -101,7 +106,7 @@ Core 采用**图锚定区域**的统一内存管理:区域(Region)锚定在 HDFG 经典映射 = 图 + 字节权限层(CompCert v2):权限层不是语义本体,是缓存语义在字节寻址机器上的权限投影(条款 7)。每字节权限序:**Freeable > Writable > Readable > Nonempty > Empty**。 -- 区域树 = 图的子图结构;布局元数据、ALLOC_AT 边界、outlives 结论全部从图导出——验证器消费图即消费全部内存语义 +- 区域树 = 图的子图结构;布局元数据、`ALLOC_AT` 边界、`outlives` 结论全部从图导出——验证器消费图即消费全部内存语义 ### 5.2 布局与放置(用户面,零管理负担) @@ -129,7 +134,7 @@ mmio := alloc_at(0x7fff0000, 4096, align(4096)); ``` - 不提供显式区域/回收语法(YAGNI) -- 0x 字面量仍是 unsafe 外部入口;alloc_at 是声明式进图(获得 provenance 的节点)——声明是唯一信任点,之后全图追踪 +- 0x 字面量仍是 unsafe 外部入口;`alloc_at` 是声明式进图(获得 provenance 的节点)——声明是唯一信任点,之后全图追踪 --- diff --git a/docs/maintainer/design/spec-design.md b/docs/maintainer/design/spec-design.md index f6ba5908..57d11469 100644 --- a/docs/maintainer/design/spec-design.md +++ b/docs/maintainer/design/spec-design.md @@ -1,13 +1,13 @@ # Core 规约系统设计(v2 — CIC 内核 + SMT 证书架构) -> 定位:受众 = 维护者(主,实现规约系统)+ 学术(验证架构);状态 = active(设计定稿,未实现——实现状态以 TODO.md 与 plans/ 为准)。理论侧重(验证器架构/信任根/自举)见 docs/academic/verifier-kernel.md,本文件不重复其论证。 -> 语法形态 2026-09 定稿:#check/#ensure 标注(与 #pure 标签同族),.cr 内联书写——本文 .csp 段落均为自动生成物方向的设计稿。 +> 定位:受众 = 维护者(主,实现规约系统)+ 学术(验证架构);状态 = active(设计定稿,未实现——实现状态以 TODO.md 与 plans/ 为准)。理论侧重(验证器架构/信任根/自举)见 docs/academic/verifier-kernel.md,本文件不重复其论证。 +> 语法形态 2026-09 定稿:`#check`/`#ensure` 标注(与 `#pure` 标签同族),`.cr` 内联书写——本文 `.csp` 段落均为自动生成物方向的设计稿。 > 规约 = 图上的约束。表达力 = CIC(归纳构造演算)。自动化 = SMT 证书外包。 ## 一、哲学 -Core 的语义中间表示是HDFG(`.cir`),图穷尽了程序的全部语义。规约不是对代码的"另一套描述",而是**图上的约束标注**。 +Core 的语义中间表示是 HDFG(`.cir`),图穷尽了程序的全部语义。规约不是对代码的"另一套描述",而是**图上的约束标注**。 ``` # 正常编译(无规约) @@ -33,7 +33,7 @@ CIC 项(归纳构造演算——一切表达力:量词/归纳/依赖类型/ └─ 归纳/高阶 → CIC 内核直接处理 ``` -**健全性唯一来源是 CIC 内核。** SMT 是证明搜索器(可以凭启发式甚至不健全地猜),其输出必须经内核验证才被接受——证书校验失败即拒绝,绝不引入不健全。这是 SMTCoq 模式(CAV'17,先例)。 +**健全性唯一来源是 CIC 内核。** SMT 是证明搜索器(可依赖启发式,甚至可能不健全),其输出必须经内核验证才被接受——证书校验失败即拒绝,绝不引入不健全。这是 SMTCoq 模式(CAV'17,先例)。 ### 表达力边界 @@ -48,7 +48,7 @@ CIC 提供 Coq 级别的全部表达力,逐项对应: | 依赖类型(`Vec n`) | 内核有,**但 Core 不需要** | 被图验证替代:边界安全由图保证,长度性质由谓词表达(`#ensure(result.len() == |a|)`) | | 引理/定理复用 | 证明项可组合 | 见 §12 用户入口 | -**Core 对依赖类型的替代**:Coq 用 `Vec n` 在类型层面保证索引不越界/长度匹配;Core 里这两个需求已被其他机制消化——索引越界由指针模型图验证保证(已实现),长度性质由谓词表达。安全性由图承担,性质由谓词承担——这就是 Core 不用付出依赖类型学习成本的根源。 +**Core 对依赖类型的替代**:Coq 用 `Vec n` 在类型层面保证索引不越界/长度匹配;Core 里这两个需求已被其他机制消化——索引越界由指针模型图验证保证(已实现),长度性质由谓词表达。安全性由图承担,性质由谓词承担——这是 Core 不需要付出依赖类型学习成本的根源。 ## 三、平民化原理 @@ -141,7 +141,7 @@ spec fn vec_invariant[T](v: Vec[T]) -> bool { ## 五、编译器自动推导(零门槛的核心) -编译器从 `.cir` 图结构中自动推导性质(标签),输出进约束 IR(.csr),不需要用户写任何东西。 +编译器从 `.cir` 图结构中自动推导性质(标签),输出进约束 IR(`.csr`),无需用户书写。 ### 自动推导的标签 @@ -158,7 +158,7 @@ spec fn vec_invariant[T](v: Vec[T]) -> bool { ### 自动生成的检查函数(骨架) -编译器识别常见图模式,自动生成检查函数代码。用户可以在规约区(.cr 内联或编译器生成的规约骨架)中 `#use` 或忽略(生成物形态见 §四 注记)。 +编译器识别常见图模式,自动生成检查函数代码。用户可以在规约区(`.cr` 内联或编译器生成的规约骨架)中 `#use` 或忽略(生成物形态见 §四 注记)。 ``` fn sort(a: [int]) -> [int] @@ -206,13 +206,13 @@ fn foo() -> int ``` `#` 风格: -- 更干净,视觉上区分于代码逻辑 +- 形态简洁,视觉上与代码逻辑区分 - 不占用 `@`(后者保留给 `import @project`) -- 语义清晰:`#` 标记的东西不影响运行时语义 +- 语义清晰:`#` 标记的内容不影响运行时语义 ## 七、检查函数(规约的主力) -检查函数是用 Core 语言写的纯函数,返回值是 `bool`。它们被编译为 `.cir` 图,然后与实现函数的 `.cir` 并列供验证器消费。 +检查函数是用 Core 语言写的纯函数,返回值是 `bool`。它们被编译为 `.cir` 图,与实现函数的 `.cir` 并列供验证器消费。 ```core // 检查函数的语法特征: @@ -254,7 +254,7 @@ spec fn all_nonneg(arr: [int]) -> bool ## 八、量词(v2 新增) -`forall x: int => P(x)` 必须是规约语言的一等构造(**不是** for 循环的翻译)——int 域无限,遍历不了;for 循环只是有限域的便利糖(§7 纯公式支持的 `forall x in arr` 是有限域情形)。 +`forall x: int => P(x)` 必须是规约语言的一等构造(**不是** for 循环的翻译)——int 域无限,无法用遍历表达;for 循环只是有限域的便利糖(§7 纯公式支持的 `forall x in arr` 是有限域情形)。 ```core // ⚠ 修订(2026-09-16 文档审计):**EBNF 尚未定义**——原写「EBNF 已定义(2026-09 起归口 @@ -273,7 +273,7 @@ exists (i: int) => a[i] == target spec fn 用 Core 书写——命令式:变量重复赋值、循环、数组、`return`。CIC 是纯函数式逻辑:lambda 演算、递归定义、归纳类型、没有赋值没有循环。翻译桥把前者确定性变换为后者,**不丢语义、不加语义**。 -可行的根本保障:spec fn 是纯的(project-book:"规约表达式限于纯逻辑运算"——无副作用、无 IO、无 unsafe、无外部调用)。纯命令式程序与函数式程序的翻译是经典确定性问题。 +可行的根本保障:`spec fn` 是纯的(project-book:"规约表达式限于纯逻辑运算"——无副作用、无 IO、无 unsafe、无外部调用)。纯命令式程序与函数式程序的翻译是经典确定性问题。 ### 9.2 结构翻译表(Core 构造 → CIC 构造) @@ -303,7 +303,7 @@ f(acc, i) = if i >= n then acc CIC 只接受**良基递归**(递归参数严格递减)——非终止的"递归"在 CIC 里无法定义。因此: -- 每个循环/递归翻译必须携带**变体**(loop variant,**EBNF 尚未定义——待实现**;2026-09-16 文档审计修订,原写「EBNF 已有」不成立)——递减度量 +- 每个循环/递归翻译必须携带**变体**(`loop variant`,**EBNF 尚未定义——待实现**;2026-09-16 文档审计修订,原写「EBNF 已有」不成立)——递减度量 - 编译器自动推导(§五 的 `#terminating` 图模式)优先;推导不出的要求用户标注 - 无变体的循环 → 翻译失败(编译错误),或降级为未解释函数(用户确认语义) @@ -317,19 +317,19 @@ Core 的 `int` 是无上限数学整数(2026-08-23 修订:i64 快路径 + | 机器整数(位向量) | 精确匹配运行语义(SMTCoq 已支持位向量理论) | 复杂;需要位向量 + 溢出模式建模,证明义务更繁 | | 混合 | 默认数学整数;位宽相关性质用显式位向量类型标注 | 平衡;用户只对溢出敏感的性质声明位宽 | -**已决(2026-08-16,随数值类型设计 dex/apx 落定)**:默认数学语义(精确——规约性质在无界整数上证明)+ **显式授权机器语义**:`apx` 标签授权后端/验证器采用机器语义(CPU 后端兑现为 binary64 FPU 快路径;验证器据此知道用户允许近似)。原「与内核选择(§十七)一并决策」的捆绑随之解除。 +**已决(2026-08-16,随数值类型设计 dex/apx 落定)**:默认数学语义(精确——规约性质在无界整数上证明)+ **显式授权机器语义**:`apx` 标签授权后端/验证器采用机器语义(CPU 后端兑现为 binary64 FPU 快路径;验证器由此可知用户允许近似)。原「与内核选择(§十七)一并决策」的捆绑随之解除。 **修订(2026-08-23,随 int 无上限化)**:语言层 `int` 已为无界数学整数(i64 快路径 + 溢出自动升级 BigInt),「机器整数 vs 数学整数」分歧对 int 消解——`#ensure(x + y > x)` 在整数上无条件成立,与规约证明一致;`apx` 的机器语义授权仍适用于 `dex` 及其余显式位宽场合。 ### 9.5 实现函数进规约的身份 -`#ensure(f(x) == y)` 引用实现函数 f——f 不是 spec fn,是运行时代码。它的 CIC 身份是**语义模型**: +`#ensure(f(x) == y)` 引用实现函数 f——f 不是 `spec fn`,是运行时代码。它的 CIC 身份是**语义模型**: - 函数式子集(纯、可翻译)→ 翻译为递归定义(与 spec fn 同路径) - 其余(有副作用/未翻译)→ **未解释函数**(Uninterpreted Function):CIC 只知道签名,不知道定义——性质只能由用户另行声明 - 有副作用/非纯的实现函数不能进规约(project-book 规定) -### 9.6 失败情形(翻译不了怎么办) +### 9.6 失败情形(无法翻译时的处理) | 情形 | 处理 | |---|---| @@ -340,7 +340,7 @@ Core 的 `int` 是无上限数学整数(2026-08-23 修订:i64 快路径 + ## 十、函数类型归属(v2 决策:规约专属) -函数类型在两个层面是两个不同的东西,**必须拆分决策**: +函数类型在两个层面是两个不同的对象,**必须拆分决策**: | | 规约层 | 实现层 | |---|---|---| @@ -348,7 +348,7 @@ Core 的 `int` 是无上限数学整数(2026-08-23 修订:i64 快路径 + | 机制 | 箭头类型 `int -> int` → CIC 原生 | TYP_FN + 闭包/捕获/调用约定 | | 需求 | 高阶量词 `forall f: int -> int => P(f)` | 函数值编程(map/filter 传函数、回调表) | -**决策:规约专属函数类型。** `int -> int` 只存在于规约语言(规约类型宇宙的一部分——独立源格式已退役,类型机制不受影响),直接映射 CIC 箭头;量化的是数学函数,不需要实现层有函数值。零污染 Core 语言(checker/ir_gen/后端/内存模型不动)。 +**决策:规约专属函数类型。** `int -> int` 只存在于规约语言(规约类型宇宙的一部分——独立源格式已退役,类型机制不受影响),直接映射 CIC 箭头;量化的是数学函数,不需要实现层有函数值。零污染 Core 语言(`checker`/`ir_gen`/后端/内存模型不动)。 **实现层函数值(TYP_FN/闭包)按 YAGNI 挂起**:现状 `@addr(f)` + int 能表达函数地址(内核函数表、中断向量表);闭包与 arena 内存模型(捕获变量归属)交互复杂,无真实用例不做。 @@ -371,13 +371,13 @@ CIC 类型检查器(Coq 内核级别:约数千行的信任根)。初期绑 → CIC 内核重新验证 ← 健全性唯一来源 ``` -- SMT 不求信任:可以跑不健全启发式,证书校验失败即拒绝 +- SMT 不求信任:可运行不健全启发式,证书校验失败即拒绝 - 用户可**主动选择** SMT:目标标注 `#smt`(hammer 的手动挡) - 覆盖范围:线性算术、数组边界、位向量、UF——"绝大多数";SMT 表达不了的目标(归纳/高阶)直接走内核——**表达力边界由 CIC 决定,SMT 只是加速器** ### 反例调试 -SMT 解不出时返回**反例模型**(哪个输入违反性质)——开发期黄金能力:`#check(b != 0)` 被违反 → SMT 给出 `b = 0` 的具体反例。验证报告区分三种状态:**绿**(证明)/ **黄**(部分)/ **红**(反例或未证明)。 +SMT 解不出时返回**反例模型**(哪个输入违反性质)——开发期核心能力:`#check(b != 0)` 被违反 → SMT 给出 `b = 0` 的具体反例。验证报告区分三种状态:**绿**(证明)/ **黄**(部分)/ **红**(反例或未证明)。 ## 十二、约束的验证与用户入口 @@ -389,7 +389,7 @@ SMT 解不出时返回**反例模型**(哪个输入违反性质)——开发 4. 对 `spec fn`:检查实现函数的图是否蕴含检查函数的图 5. 输出:每条约束绿(证明)/ 黄(部分证明)/ 红(反例或未证明) -约束可以同时在开发期插桩运行时 assert 检查,验证器到位前也有保障。 +约束可以同时在开发期插桩运行时 `assert` 检查,验证器到位前也有保障。 ### 用户入口分层(自动化失败时降级,v2 新增) @@ -405,7 +405,7 @@ SMT 解不出时返回**反例模型**(哪个输入违反性质)——开发 ### .csr 状态 -`.csr` 的 status 字段(0=unproven, 1=auto_proven, 2=user_proven)承接验证结果: +`.csr` 的 `status` 字段(0=unproven, 1=auto_proven, 2=user_proven)承接验证结果: | 来源 | status | |---|---| @@ -416,7 +416,7 @@ SMT 解不出时返回**反例模型**(哪个输入违反性质)——开发 ## 十三、规约的回报:证明驱动的优化(v2 新增) -**写的证明越多,编译器优化越狠。** 规约不只是验证负担——证明过的性质流入优化器,成为激进变换的前提。这是"语义保鲜"的闭环:用户注入的语义(规约)流经验证变成**可证明的事实**,再流进优化器,验证的回报不只是安全,还有性能。 +**证明越多,编译器可做的优化越激进。** 规约不只是验证负担——证明过的性质流入优化器,成为激进变换的前提。这是"语义保鲜"的闭环:用户注入的语义(规约)流经验证变成**可证明的事实**,再流进优化器;验证的回报不只是安全,还有性能。 ### 机制:证明状态门控的优化信息流 @@ -427,7 +427,7 @@ SMT 解不出时返回**反例模型**(哪个输入违反性质)——开发 unproven 的性质 ──→ 丢弃(绝不喂优化器) ``` -**关键:只有被证明的性质才进优化器。** `.csr` 的证明状态(auto_proven / user_proven)就是优化器的许可证——unproven 的性质可能为假,喂给优化器 = 优化器引入 bug。**证明错误 = 优化错误,门控是机制核心。** +**关键:只有被证明的性质才进优化器。** `.csr` 的证明状态(auto_proven / user_proven)就是优化器的许可证——unproven 的性质可能为假,送入优化器 = 优化器引入 bug。**证明错误 = 优化错误,门控是机制核心。** ### 收益清单(证明 → 优化映射) @@ -443,7 +443,7 @@ SMT 解不出时返回**反例模型**(哪个输入违反性质)——开发 ### 动机闭环 -**规约从"验证负担"变成"性能投资"**——普通程序员为性能写 `#check`/`#ensure`,验证顺手完成。这解决了"为什么要写规约"的动机问题。先例:LLVM 的 `llvm.assume`(用户声明的事实喂优化器)。 +**规约从"验证负担"变成"性能投资"**——普通程序员为性能写 `#check`/`#ensure`,验证在同一次书写中完成。这解决了"为什么要写规约"的动机问题。先例:LLVM 的 `llvm.assume`(用户声明的事实送入优化器)。 ### 两个注意点 @@ -476,9 +476,9 @@ verify file.csr ``` 编译器输出的 `.csr` 包含: -- 编译器自动推导的全部标签(status=auto_proven) -- 用户写的 `#check/#ensure/#invariant`(status=pending) -- `spec fn` 编译为 spec 图节点(status=pending) +- 编译器自动推导的全部标签(`status=auto_proven`) +- 用户写的 `#check/#ensure/#invariant`(`status=pending`) +- `spec fn` 编译为 spec 图节点(`status=pending`) ## 十五、信任根与自举路线(v2 新增) @@ -519,9 +519,9 @@ fn map_page(pt: &mut PageTable, virt: Addr, phys: Addr, flags: u64) #ensure(pagetable_invariant(pt)) ``` -即使在这里,规约还是 Core 代码——变量、循环、分支。不是公式,是你能读也能写的代码。 +即使在内核场景,规约仍是 Core 代码——变量、循环、分支。不是公式,是既能读也能写的代码。 -内核的量词(`for all mappings`)写成了 `for` 循环,编译器把它编译成纯逻辑约束。纯公式语法糖(`forall`)也存在,但只是编译器的展开。 +内核的量词(`for all mappings`)写成了 `for` 循环,编译器将其编译为纯逻辑约束。纯公式语法糖(`forall`)也存在,但只是编译器的展开。 ## 十七、实现里程碑(建议) diff --git a/docs/maintainer/onboarding.md b/docs/maintainer/onboarding.md index 6ce6a555..b223a566 100644 --- a/docs/maintainer/onboarding.md +++ b/docs/maintainer/onboarding.md @@ -1,16 +1,16 @@ # 新维护者入门手册(onboarding) > 定位:受众 = maintainers;状态 = active;出处 = 源码 + [CLAUDE.md](../../CLAUDE.md)(实现与文档冲突时以源码为准,既有惯例)。 -> 文档导航见 [docs/README.md](../README.md)(分类规则:主题 × 读者 × 状态)。本文档聚焦仓库结构、构建、工作流与雷区。 +> 文档导航见 [docs/README.md](../README.md)(分类规则:主题 × 读者 × 状态)。本文档聚焦仓库结构、构建、工作流与已知陷阱。 ## 一、仓库地图 -**仓库协作约定**(人类维护者视角;CLAUDE.md 的"铁律"是面向 AI 助手的会话规则,不直接约束人——但下述约定人机一致): +**仓库协作约定**(人类维护者视角;`CLAUDE.md` 的「铁律」是面向 AI 助手的会话规则,不直接约束人——但下述约定人机一致): -- **版本控制只用 jj,不用 git 写操作**——仓库工具链统一(jj 分支模型见 §四) -- **不随意还原/回滚文件**——改坏了向前修,不回头抹历史(有争议先讨论) -- **修问题找 root cause**,不绕过、不掩盖、不加临时开关了事 -- **长构建/测试注意机器负载**:无人值守或共享机器上建议 `cpulimit -l 10` / `nice -n 19`(减风扇噪音与卡顿;交互式短任务不必) +- **版本控制只用 `jj`,不用 `git` 写操作**——仓库工具链统一(`jj` 分支模型见 §四) +- **不随意还原/回滚文件**——改坏了向前修,不回头抹历史(有争议先讨论) +- **修问题找 root cause**,不绕过、不掩盖、不加临时开关了事 +- **长构建/测试注意机器负载**:无人值守或共享机器上建议 `cpulimit -l 10` / `nice -n 19`(减风扇噪音与卡顿;交互式短任务不必) ``` src/compiler/ → 自举编译器主体(corec 前端 + corearch 后端共用) @@ -73,11 +73,11 @@ python3 build_selfhost_native.py # Stage 0:Python bootstrap → build/co 三级自举(回归必验): -- **Stage 0** — Python bootstrap 编译 `src/compiler/*.cr` → corec(第一代原生编译器) -- **Stage 1** — corec 编译 `src/compiler/*.cr` → corec2 -- **Stage 2** — corec2 编译 `src/compiler/*.cr` → corec3;闭环判据 = corec2/corec3 输出逐字节一致(可加 O1,历史 O0/O1 均已贯通) +- **Stage 0** — Python bootstrap 编译 `src/compiler/*.cr` → `corec`(第一代原生编译器) +- **Stage 1** — `corec` 编译 `src/compiler/*.cr` → `corec2` +- **Stage 2** — `corec2` 编译 `src/compiler/*.cr` → `corec3`;闭环判据 = `corec2`/`corec3` 输出逐字节一致(可加 O1,历史 O0/O1 均已贯通) -任何长时间构建/测试任务建议 `cpulimit -l 10` 或 `nice -n 19`(机器负载与噪音考虑;交互式短任务不必)。 +任何长时间构建/测试任务建议 `cpulimit -l 10` 或 `nice -n 19`(机器负载与噪音考虑;交互式短任务不必)。 ## 三、分支模型与 jj 速查 @@ -87,7 +87,7 @@ python3 build_selfhost_native.py # Stage 0:Python bootstrap → build/co - **develop** = 集成分支:日常 PR 目标(ruleset:PR 通道 + 审批 + merge queue + CI 门槛) - 日常开发 feature 分支 base = develop;PR 一律指向 develop -jj 速查(仓库 hook 机械拦截 git;提交经 SSH 自动签名,无需人工操作): +`jj` 速查(仓库 hook 机械拦截 `git`;提交经 SSH 自动签名,无需人工操作): ```bash jj bookmark create feature/xxx # 每个改动独立分支 @@ -100,12 +100,12 @@ jj git fetch && jj bookmark move develop -r develop@origin # 同步远端 deve 发布(develop → main,仅维护者):`jj git push -b develop` → `gh pr create --base main --fill` → 合入后 `jj git fetch && jj bookmark move main -r main@origin`。 -## 四、已知雷区 +## 四、已知陷阱 -- **corec2 tokenizer 死循环**:约 9 个全局变量(`g_tok_cap`/`g_tokens`/`g_str_count`/`g_line`/`g_source_len` 等)未被 parser 注册到 `g_ir_globals` 时,赋值语句被静默丢弃 → tokenizer 卡死。曾以 tokenizer 参数化(PR #9)规避 `g_source` 依赖,残留项待根治。机理全文见 [CLAUDE.md Known Issues](../../CLAUDE.md);遇 tokenizer 卡住先查 `g_pos`/`g_tok_cap` 是否递增。 -- **O1 不稳定**:`--opt-level 1`(pass_cse 与 alloc_registers 元数据交互)在自举编译大函数时可能崩溃;遇崩降 O0 定位,详见 [CLAUDE.md Known Issues](../../CLAUDE.md)。 -- **core dump 挂起(桌面环境)**:trap 类测试进程 SIGILL 后,内核写 core 经 systemd-coredump 管道唤醒服务,拥堵时进程挂起。2026-09-05 起 `src/ci/run.sh` 全局 `ulimit -c 0`、trap 测试内置 `RLIMIT_CORE=0`;根治方向 = 图推导边界判定 pass。详见 [TODO.md](../../TODO.md)。 -- **测试总览与回归流程**:命令与跑法见 [CLAUDE.md Build & Test](../../CLAUDE.md),历史修复记录在 [TODO.md](../../TODO.md)。 +- **`corec2` tokenizer 死循环**:约 9 个全局变量(`g_tok_cap`/`g_tokens`/`g_str_count`/`g_line`/`g_source_len` 等)未被 `parser` 注册到 `g_ir_globals` 时,赋值语句被静默丢弃 → tokenizer 停滞。曾以 tokenizer 参数化(PR #9)规避 `g_source` 依赖,残留项待根治。机理全文见 [CLAUDE.md Known Issues](../../CLAUDE.md);遇 tokenizer 停滞时首先检查 `g_pos`/`g_tok_cap` 是否递增。 +- **O1 不稳定**:`--opt-level 1`(`pass_cse` 与 `alloc_registers` 元数据交互)在自举编译大函数时可能崩溃;遇崩溃时降至 O0 定位,详见 [CLAUDE.md Known Issues](../../CLAUDE.md)。 +- **core dump 挂起(桌面环境)**:`trap` 类测试进程 SIGILL 后,内核写 core 经 systemd-coredump 管道唤醒服务,拥堵时进程挂起。2026-09-05 起 `src/ci/run.sh` 全局 `ulimit -c 0`、`trap` 测试内置 `RLIMIT_CORE=0`;根治方向 = 图推导边界判定 pass。详见 [TODO.md](../../TODO.md)。 +- **测试总览与回归流程**:命令与运行方式见 [CLAUDE.md Build & Test](../../CLAUDE.md),历史修复记录在 [TODO.md](../../TODO.md)。 ## 五、贡献清单(检查列表) diff --git a/docs/maintainer/proposals/comptime.md b/docs/maintainer/proposals/comptime.md index 49939502..122774ae 100644 --- a/docs/maintainer/proposals/comptime.md +++ b/docs/maintainer/proposals/comptime.md @@ -1,12 +1,12 @@ # Core 编译时能力 -> 定位:受众 = 维护者/贡献者;状态 = **active(部分实现)**——@ 内建原语与编译期机制见 docs/developer/at-intrinsics.md;本设计文档为推导策略蓝图,多数单元格未落地 +> 定位:受众 = 维护者/贡献者;状态 = **active(部分实现)**——@ 内建原语与编译期机制见 docs/developer/at-intrinsics.md;本设计文档为推导策略蓝图,多数单元格未落地。 ## 设计原则 -- **90% 的编译时执行由HDFG自动推导,用户不需要任何关键字。** +- **90% 的编译时执行由 HDFG 自动推导,用户不需要任何关键字。** - **用户只需在"必须编译时执行,算不了就报错"时表态。** -- `@` 只负责查询和控制——不负责触发执行。 +- `@` 只负责查询和控制,不负责触发执行。 ## 三种场景 @@ -18,7 +18,7 @@ ## 自动推导 -编译器从HDFG上判定:子图的所有输入来自 CONST 或已执行的编译时子图,且子图内无副作用——则自动在编译时执行。 +编译器在 HDFG 上判定:子图的所有输入来自 CONST 或已执行的编译时子图,且子图内无副作用,即自动在编译时执行。 ```core // 全部自动,不需要任何关键字 @@ -33,7 +33,7 @@ w := fibonacci(user_input); // 参数运行时才确定 → 留给运行时 ## @comptime -自动推导不能表达"算不了就报错"的意图。`@comptime` 提供这个保证: +自动推导不能表达"算不了就报错"的意图;`@comptime` 为此提供保证: ```core @comptime { @@ -44,11 +44,11 @@ w := fibonacci(user_input); // 参数运行时才确定 → 留给运行时 } ``` -`@comptime` 不改变语义——只改变报错时机。 +`@comptime` 不改变语义,只改变报错时机。 ## 编译时函数(comptime fn) -标记为 `comptime fn` 的函数要求所有调用点在编译时可求值: +标记为 `comptime fn` 的函数,要求所有调用点在编译时可求值: ```core comptime fn fibonacci(n: int) -> int { diff --git a/docs/maintainer/proposals/concurrency.md b/docs/maintainer/proposals/concurrency.md index ed4ede6a..2598ce55 100644 --- a/docs/maintainer/proposals/concurrency.md +++ b/docs/maintainer/proposals/concurrency.md @@ -1,11 +1,11 @@ # Core 并发原语 -> 定位:受众 = 维护者/贡献者;状态 = **active(已实现)**——go/chan 端到端可用(2026-07-31);细节见 src/stdlib/goroutine.cr、chan.cr、src/scheduler/;本设计文档的 flow/yield/await 扩展为演进方向 +> 定位:受众 = 维护者/贡献者;状态 = **active(已实现)**——go/chan 端到端可用(2026-07-31);细节见 src/stdlib/goroutine.cr、chan.cr、src/scheduler/;本设计文档的 flow/yield/await 扩展为演进方向。 ## 设计原则 -- **只有一张图。** go/flow/yield/await/walk 都是图上的节点和边,不是额外的运行时概念。 -- **有 OS 用 OS 线程,无 OS 抢占式时间片。** 没有 actor、没有 CSP、没有 async/await 关键字。 +- **只有一张图。** go/flow/yield/await/walk 均为图上的节点和边,不是额外的运行时概念。 +- **有 OS 用 OS 线程,无 OS 抢占式时间片。** 不引入 actor、CSP、async/await 关键字。 ## 原语 @@ -53,7 +53,7 @@ flow numbers() { `yield` 在图上是一个暂停点:当前节点的执行暂停,值沿输出边传递给消费者。消费者通过 `await` 接收。 -多个 `yield` 的 flow 类似生成器——每次 `yield` 后可以继续执行到下一个 `yield`。 +含多个 `yield` 的 flow 类似生成器:每次 `yield` 后可继续执行至下一个 `yield`。 ### await @@ -83,11 +83,11 @@ walker process(data: [int]) { } ``` -`walk` 激活一个 walker 实例。walker 不是在新节点上启动新执行——而是将当前执行上下文(栈、局部变量)序列化后传输到目标节点继续执行。 +`walk` 激活一个 walker 实例。walker 不在新节点上启动新执行,而是将当前执行上下文(栈、局部变量)序列化后传输到目标节点继续执行。 `step` 暂停当前 walker,将状态传输到目标节点,在目标节点上恢复执行。 -走完的 walker 和 flow 一样可以被 `await`。 +执行完毕的 walker 与 flow 一样可被 `await`。 ## 图上的表示 @@ -134,4 +134,4 @@ step @("n") → 序列化当前上下文,传输到目标节点,恢复 g_new 存 saved_fn/saved_arg → ELF 后端内联发射 fiber_init/fiber_switch/goroutine_entry_wrapper → wrapper 调用 saved_fn(saved_arg) → 结果经 result_ch 回传。主线程注册为 G 0, 可经 channel 阻塞/唤醒;sched_yield 不再重排 Gwaiting。 -`walker` / `step` 尚未实现;多 M worker 线程的完整验证待补(见 `TODO.md` 预存 bug 第 2 条)。 +`walker` / `step` 未实现;多 M worker 线程的完整验证待补(见 `TODO.md` 预存 bug 第 2 条)。 diff --git a/docs/maintainer/proposals/distributed.md b/docs/maintainer/proposals/distributed.md index 6f036c9a..b1db7586 100644 --- a/docs/maintainer/proposals/distributed.md +++ b/docs/maintainer/proposals/distributed.md @@ -1,12 +1,12 @@ # Core 分布式 -> 定位:受众 = 维护者/贡献者;状态 = **proposal(核心已备,运行时未实现)**——go/await/子图边界就位;跨机器传输/QUIC/认证/重试未实现 +> 定位:受众 = 维护者/贡献者;状态 = **proposal(核心已备,运行时未实现)**——go/await/子图边界就位;跨机器传输/QUIC/认证/重试未实现。 ## 设计原则 -- **图跨机器。** `go` 本来就在本地创建节点,加上 `@("node")` 目标就是远程节点。 -- **编译时决定,运行时只执行。** 图上哪些边是远程的,编译时就全知道了。编译器生成序列化、认证、重试代码。运行时只管跑。 -- **接口兼容够用。** 版本号是人的事,接口签名编译器自己会看。 +- **图跨机器。** `go` 默认在本地创建节点,加上 `@("node")` 目标即为远程节点。 +- **编译时决定,运行时只执行。** 图上哪些边是远程的,编译期即已确定;序列化、认证、重试代码由编译器生成,运行时只负责执行。 +- **接口兼容够用。** 版本号由人维护,编译器只检查接口签名。 ## 语法 @@ -48,7 +48,7 @@ go @("server2") fn() 断线重连由 QUIC connection migration 处理 ``` -QUIC 提供的: +QUIC 提供的能力: | 需求 | QUIC 的应对 | |------|-----------| @@ -68,7 +68,7 @@ big_data := read_file("1gb.bin"); result := go @("server2") process(big_data); ``` -编译器看图知道 `data` 跨节点。大块数据不直接走网络——编译器生成共享存储读写的代码(由部署配置指定): +编译器看图即知 `data` 跨节点。大块数据不直接走网络:编译器生成共享存储读写的代码(由部署配置指定): ```toml [data] @@ -76,9 +76,9 @@ backend = "s3" # 也可以在部署配置中声明共享存储路径 cache = "/mnt/shared" ``` -代码不感知数据在本地还是远程——编译器在边界插了读共享存储的逻辑,不走网络。 +代码不感知数据在本地还是远程:编译器在边界插入读共享存储的逻辑,不走网络。 -这也是平台桥抽象在分布式场景的体现:`read_file` 的语义是读取文件流(字节序列),物理存储后端(本地文件系统、共享存储 s3、网络)是后端实现,由部署配置决定——代码只见流语义,不见物理实现。 +这也是平台桥抽象在分布式场景的体现。`read_file` 的语义是读取文件流(字节序列),物理存储后端(本地文件系统、共享存储 s3、网络)是后端实现,由部署配置决定;代码只见流语义,不见物理实现。 ## 接口兼容 @@ -86,7 +86,7 @@ cache = "/mnt/shared" go @("server2") worker(1); ``` -编译器看 server2 上暴露的接口签名和调用处的签名是否匹配: +编译器检查 server2 上暴露的接口签名与调用处的签名是否匹配: | 调用处 | 远端接口 | 结果 | |--------|---------|------| @@ -94,11 +94,11 @@ go @("server2") worker(1); | `fn(x: int) -> int` | `fn(x: int) -> string` | 不匹配 | | `fn(x: int) -> int` | `fn(x: dyn) -> int` | dyn 兼容 | -不需要版本号。接口签名一致就能跑。版本号是人控制的,编译器只看接口类型。 +不需要版本号。接口签名一致即可运行;版本号由人控制,编译器只检查接口类型。 ## 不安全与恢复 -远程节点挂断时: +远程节点断开时: ``` go @("server2") worker(1) @@ -118,7 +118,7 @@ retry = 3 timeout = "5s" ``` -不超时代码自己感知不到远端挂了——超时由 QUIC 的心跳和编译器生成的远程 await 超时逻辑共同保证。 +未设置超时时,代码无法感知远端失效;超时由 QUIC 的心跳与编译器生成的远程 await 超时逻辑共同保证。 ## 认证 @@ -126,7 +126,7 @@ timeout = "5s" go @("server2") read_file("/etc/passwd"); ``` -远程节点不接受来自其他节点的未授权请求。认证模型如同 FFI——编译器在生成的 QUIC 连接建立时插入认证 token。 +远程节点不接受来自其他节点的未授权请求。认证模型与 FFI 一致:编译器在生成的 QUIC 连接建立时插入认证 token。 ``` 首次连接:token 交换(由部署配置提供) diff --git a/docs/maintainer/proposals/dynamic-typing.md b/docs/maintainer/proposals/dynamic-typing.md index 920eb7d0..63ccf1dc 100644 --- a/docs/maintainer/proposals/dynamic-typing.md +++ b/docs/maintainer/proposals/dynamic-typing.md @@ -1,12 +1,12 @@ # Core 动态类型 -> 定位:受众 = 维护者/贡献者;状态 = **active(部分实现)**——dyn 类型(2026-07-30)+ @hotpatch 基础(2026-07-29)已实现;滚动更新/参数化分流为设计态(未实现);细节见 src/stdlib/dex.cr +> 定位:受众 = 维护者/贡献者;状态 = **active(部分实现)**——dyn 类型(2026-07-30)+ @hotpatch 基础(2026-07-29)已实现;滚动更新/参数化分流为设计态(未实现);细节见 src/stdlib/dex.cr。 ## 设计原则 - **弱动态风格,编译器在图知道的范围内做到强动态的保证。** -- **动态值不是胖结构。** 图在 90% 的路径上知道确切类型,变量就是裸值,零开销。 -- **全生命流图已知所有分支可能。** 没有"不确定",只有"可能取值集合",编译器为每种可能生成一条处理路径。 +- **动态值不是胖结构。** 图在 90% 的路径上知道确切类型,变量即裸值,零开销。 +- **全生命流图已知所有分支可能。** 不存在"不确定",只有"可能取值集合";编译器为每种可能生成一条处理路径。 ## 声明 @@ -18,7 +18,7 @@ y : int = 42; // 静态类型,不能变 z : auto = 42; // 自动推导,仍然是静态 ``` -`dyn` 是类型关键字,和 `int`、`string` 平级。 +`dyn` 是类型关键字,与 `int`、`string` 平级。 ## 图上的表示 @@ -35,11 +35,11 @@ y := x + 1; // 路径 B: 直接加法 ``` -没有"运行时才知道"——编译器已知全量分支。 +不存在"运行时才知道":编译器已知全量分支。 ## 边界转换 -编译器看图知道两边的类型,在边界自动插入转换代码。 +编译器看图可知两边的类型,在边界自动插入转换代码。 ```core x := "42"; @@ -77,7 +77,7 @@ x.len(); // 部分路径有 → 编译错误(动态类型不隐藏不存在的方法) ``` -动态类型不隐藏不存在的方法——任何路径上都没有的方法在编译期报错。 +动态类型不隐藏不存在的方法:任何路径上都不存在的方法在编译期报错。 ## 运行时表示 @@ -92,11 +92,11 @@ x : dyn = cond ? 42 : "hello"; // 后续代码根据 tag 分派 ``` -这个开销不是全局的——只在图发现多路径歧义的那个变量上。单路径的 `dyn` 变量就是裸值,零开销。 +这个开销不是全局的,只作用于图发现多路径歧义的那个变量。单路径的 `dyn` 变量即裸值,零开销。 ## 滚动更新 -热补丁(原子替换)是滚动更新的特例。滚动更新是新旧版本共存、流量逐渐迁移,Core 的子图边界天然支持: +热补丁(原子替换)是滚动更新的特例。滚动更新指新旧版本共存、流量逐渐迁移,Core 的子图边界天然支持该模式: ### 声明 @@ -137,7 +137,7 @@ x : dyn = cond ? 42 : "hello"; | 排水 | 旧子图保留到请求完成,然后回收 | | 回滚 | 路由比例退回旧版本 | -这比热补丁轻——不需要接口契约编译、不需要图链接器验证。滚动更新就是一个会按比例分流的路由节点,子图的隔离性是 HDFG 自带的。热补丁是 `rollout="100%"` 后 `drain="true"` 的特例。 +该机制比热补丁轻:不需要接口契约编译,也不需要图链接器验证。滚动更新即一个按比例分流的路由节点,子图的隔离性由 HDFG 自带。热补丁是 `rollout="100%"` 后 `drain="true"` 的特例。 --- diff --git a/docs/maintainer/proposals/ffi.md b/docs/maintainer/proposals/ffi.md index 4a3a3fc2..e6f003bf 100644 --- a/docs/maintainer/proposals/ffi.md +++ b/docs/maintainer/proposals/ffi.md @@ -1,11 +1,11 @@ # Core FFI -> 定位:受众 = 维护者/贡献者;状态 = **partial(仅 extern fn)**——@ffi 统一入口为设计态未实现;当前 C ABI 走 extern fn(IR_CALL/syscall);细节见 src/stdlib/io.cr extern 声明 +> 定位:受众 = 维护者/贡献者;状态 = **partial(仅 extern fn)**——`@ffi` 统一入口为设计态未实现;当前 C ABI 走 `extern fn`(`IR_CALL`/syscall);细节见 src/stdlib/io.cr extern 声明。 ## 设计原则 - **所有语言统一走 `@ffi`,参数描述运行时特征。** -- `@ffi` 是编译控制,不改变语义,只改变编译方式——和 `@inline` 在同一分类。 +- `@ffi` 是编译控制,不改变语义,只改变编译方式,与 `@inline` 属同一分类。 - C ABI 是默认接口,所有其他语言最终也通过 C ABI 对接。 - **平台接口隔离在后端。** 常规 I/O 走标准库流语义接口(print/println/read_file/write_file 保持),read/write 等系统调用是平台桥后端的实现细节;`extern fn` 直接声明系统接口是绕过语义层的例外入口,属 unsafe 范畴。 @@ -37,7 +37,7 @@ extern fn read_file(path: *const u8) -> *mut u8; // 显式指定,和省略时一样 ``` -## 编译器的应对 +## 编译器行为 | @ffi 参数 | 编译器的行为 | 开销 | |-----------|------------|------| @@ -56,8 +56,8 @@ extern fn read_file(path: *const u8) -> *mut u8; └─ 安全检查 → @NoBoundsCheck ``` -`@ffi` 是编译控制——不改变语义,只改变编译方式。 +`@ffi` 属编译控制:不改变语义,只改变编译方式。 ## 当前状态 -设计完成,未实现。当前编译器只支持 `extern fn` 的 C ABI 调用(通过 `IR_CALL` 和 syscall 实现)。 +设计完成,未实现。当前编译器只支持 `extern fn` 的 C ABI 调用,实现路径为 `IR_CALL` 与 syscall。 diff --git a/docs/maintainer/proposals/generics.md b/docs/maintainer/proposals/generics.md index 61d5adf7..399714ee 100644 --- a/docs/maintainer/proposals/generics.md +++ b/docs/maintainer/proposals/generics.md @@ -1,12 +1,12 @@ # Core 泛型 -> 定位:受众 = 维护者/贡献者;状态 = **active(已实现)**——泛型函数/struct + 跨模块实例化(monomorph.cr)已纳入自举;本设计文档留作机制参考,细节见 checker.cr/monomorph.cr/tests/suite/generics_test.cr +> 定位:受众 = 维护者/贡献者;状态 = **active(已实现)**——泛型函数/struct + 跨模块实例化(monomorph.cr)已纳入自举;本设计文档留作机制参考,细节见 checker.cr/monomorph.cr/tests/suite/generics_test.cr。 ## 设计原则 - **尽量靠图推导,不需要用户标注约束。** - 泛型函数的每次实例化在图上产生独立子图,互不干扰。 -- 学习成本:用户只需要会写 ``,不需要学 trait bounds、where 子句、关联类型。 +- 学习成本:用户只需掌握 `` 写法,不需要学 trait bounds、where 子句、关联类型。 ## 语法 @@ -56,7 +56,7 @@ print_size("hello"); // string 有 .len(),编译器推导约束匹配 ### 隐式约束推导 -尝试使用泛型类型时,编译器关注实际传入的类型是否满足函数内部的操作。规则是从使用点推导约束,而不是在定义点声明约束。 +使用泛型类型时,编译器检查实际传入的类型是否满足函数内部的操作。约束从使用点推导,不在定义点声明。 ```core fn add(a: T, b: T) -> T { @@ -162,6 +162,6 @@ make_array(); // 编译错误:泛型参数 N 需要编译 ## 当前状态 -泛型函数和泛型 struct 已在 checker 和 ir_gen 中实现(`infer_gen_call`、`fi_generic_count`)。 +泛型函数和泛型 struct 已在 `checker` 和 `ir_gen` 中实现(`infer_gen_call`、`fi_generic_count`)。 跨模块泛型实例化由 `src/compiler/monomorph.cr` 承担(已纳入自举构建)。 具体实现进度以 `TODO.md` 与源码为准。已知局限:解释器不支持泛型函数(类型检查通过但返回 255,见 TODO.md 预存 bug 3)。 diff --git a/docs/maintainer/proposals/lazy.md b/docs/maintainer/proposals/lazy.md index f866619d..50a8ed6e 100644 --- a/docs/maintainer/proposals/lazy.md +++ b/docs/maintainer/proposals/lazy.md @@ -1,10 +1,10 @@ # Core 惰性求值 -> 定位:受众 = 维护者/贡献者;状态 = **proposal(未实现)**——图天然惰性论点成立,eager 为当前策略;使用点 force 机制与设计语义一致(部分),控制流级惰性未做 +> 定位:受众 = 维护者/贡献者;状态 = **proposal(未实现)**——图天然惰性论点成立,eager 为当前策略;使用点 force 机制与设计语义一致(部分),控制流级惰性未做。 ## 设计原则 -- **图本来就是惰性的。** 节点不在边上游等待时就不执行。当前的 IR 生成策略是 eager——节点一出现就执行。这不是图的限制,是策略的选择。 +- **图本来就是惰性的。** 节点不在边上游等待时就不执行。当前 IR 生成策略是 eager:节点一出现就执行。这是策略选择,不是图的限制。 ## 自动惰性推导 @@ -28,7 +28,7 @@ print(result); ## 无关键字 -惰性推导和之前的指针验证、编译期求值、概率推导一样——编译器看图自动做,不引入 `lazy` 关键字。 +惰性推导与此前的指针验证、编译期求值、概率推导一致:由编译器看图自动完成,不引入 `lazy` 关键字。 ```core x := expensive(); // 编译器 auto: eager 或 lazy @@ -46,7 +46,7 @@ y := cond ? x : 0; // 如果 x 只用在这里且无副作用 → 自动惰 | volatile 内存操作 | 不可惰性 | | FFI 调用 | 默认不可惰性 | -## 被推导但是用了怎么办 +## 惰性节点被多处使用 ```core x := expensive(); // 编译器决定惰性 @@ -54,9 +54,9 @@ y := cond ? x : 0; z := x + 1; // x 这里也被用了 → 必须求值 ``` -如果编译器发现惰性标注的节点实际上有多条路径需要它——自动升级为 eager。用户不感知。 +若编译器发现标注为惰性的节点实际有多条路径需要它,则自动升级为 eager;用户不感知。 -## 惰性不改变语义 +## 惰性对语义无影响 无论编译器选择惰性还是 eager,程序输出一致。惰性只是策略选择,不影响正确性。 @@ -64,7 +64,12 @@ z := x + 1; // x 这里也被用了 → 必须求值 ## 当前实现状态 -**更新(2026-08-09)**:控制流级惰性方向定为**编译期指令下沉路线**——纯调用移到唯一消费点(分支内),无运行时 thunk/flag/9 字节结构,interp / ELF 后端零改动;见 TODO.md「控制流自动惰性」。同时核实现状两点:THUNK/FORCE 当前为纯值搬运(IR_CALL 在 THUNK 前已急切发射,ELF/interp 均按值传递降级,无实际延迟);`use_count <= 1` 判定存在时序问题(`compute_usage_counts()` 在全部 ir_gen 之后运行,判定时读到的恒为 0/未初始化,"单次使用"条件名存实亡)。 +**更新(2026-08-09)**:控制流级惰性方向定为**编译期指令下沉路线**——纯调用移到唯一消费点(分支内),无运行时 thunk/flag/9 字节结构,interp / ELF 后端零改动;见 TODO.md「控制流自动惰性」。 + +现状实核两点: + +- THUNK/FORCE 当前为纯值搬运:`IR_CALL` 在 THUNK 前已急切发射,ELF/interp 均按值传递降级,无实际延迟。 +- `use_count <= 1` 判定存在时序问题:`compute_usage_counts()` 在全部 ir_gen 之后运行,判定时读到的恒为 0/未初始化,"单次使用"条件名存实亡。 **更新(2026-08-08)**:惰性求值已部分实现,范围为调用级(文档设计的子集): diff --git a/docs/maintainer/proposals/probabilistic.md b/docs/maintainer/proposals/probabilistic.md index 7648caa2..6d8a0c05 100644 --- a/docs/maintainer/proposals/probabilistic.md +++ b/docs/maintainer/proposals/probabilistic.md @@ -1,16 +1,16 @@ # Core 概率编程 -> 定位:受众 = 维护者/贡献者;状态 = **proposal(讨论中)**——概率 = pass 的论点未落地,无实现痕迹 +> 定位:受众 = 维护者/贡献者;状态 = **proposal(讨论中)**——概率 = pass 的论点未落地,无实现痕迹。 ## 设计原则 -- **概率不是新特性——是一个 pass。** +- **概率不是新特性,而是一个 pass。** - `@` 不参与概率。抽样是库函数,观测是图上的约束,分支概率图自动推导。 -- 不需要运行时概率系统。全部信息在编译期走完。 +- 不需要运行时概率系统,全部信息在编译期处理完毕。 -## 分支概率——自动推导 +## 分支概率的自动推导 -图上 `random() < p` 模式被 pass 认出,在分支边上标注概率权重。 +图上 `random() < p` 模式由 pass 识别,在分支边上标注概率权重。 ```core if random() < 0.3 { @@ -20,7 +20,7 @@ if random() < 0.3 { } ``` -pass 沿值流传播权重——任何变量的分布信息自动推导。 +pass 沿值流传播权重,任何变量的分布信息均自动推导。 ```core result := if random() < 0.05 { @@ -33,9 +33,9 @@ result := if random() < 0.05 { // result 是 {5% "rare", 95% "common"} ``` -## 抽样——库函数 +## 抽样(库函数) -`random()` 接受一个分布参数,返回样本。等价于 `read_file()`——编译器不用特殊对待,库函数。 +`random()` 接受一个分布参数并返回样本。它与 `read_file()` 等价:编译器不做特殊对待,属库函数。 ```core x := random(normal(0, 1)); // 标准正态分布 @@ -43,11 +43,11 @@ y := random(uniform(0, 10)); // 均匀分布 z := random(binomial(10, 0.5)); // 二项分布 ``` -运行时 `random(normal(0, 1))` 返回一个 double。编译期的概率 pass 看到 `random(...)` 的返回值的后续使用,但不影响运行时。 +运行时 `random(normal(0, 1))` 返回一个 double。编译期的概率 pass 观察 `random(...)` 返回值的后续使用,但不影响运行时。 -## 观测——图上的约束 +## 观测(图上的约束) -观测是贝叶斯更新。在 Core 上不发生在运行时——发生在编译期的图分析。约束可以写在规约中(.cr 内联,独立 `.corespec` 格式已退役,见 ADR-0001),也可以直接在条件分支中表达: +观测是贝叶斯更新。在 Core 中它不发生在运行时,而发生在编译期的图分析。约束可以写在规约中(.cr 内联,独立 `.corespec` 格式已退役,见 ADR-0001),也可以直接在条件分支中表达: ```core sensor := random(normal(true_temp, 0.1)); @@ -58,7 +58,7 @@ if sensor > 30 { } ``` -没有 `@observe`,没有新语法。就是条件分支 + 规约。 +不引入 `@observe`,也不引入新语法,只用条件分支 + 规约。 ## ProbabilityPass @@ -82,7 +82,7 @@ if sensor > 30 { | 代码生成 | 冷热路径分离 | | 验证器 | 统计性质检验 | -运行时不需要改动——概率信息是编译期的,不走 `@`,不产生运行时开销。 +运行时不需要改动:概率信息属于编译期,不走 `@`,不产生运行时开销。 ## 与现有机制的关系 diff --git a/docs/project-book.md b/docs/project-book.md index 8edbf1cd..0949f2d6 100644 --- a/docs/project-book.md +++ b/docs/project-book.md @@ -59,7 +59,7 @@ Core IR 与传统编译器 IR 的区别在于保留语义信息而非逐步丢 具体而言,实现层 IR 保留以下信息: -- 结构化类型与接口作为一等结构(struct/enum/impl/interface),完整保留成员签名、实现关系与方法解析,不降级为无类型的数据块 +- 结构化类型与接口作为一等结构(`struct`/`enum`/`impl`/`interface`),完整保留成员签名、实现关系与方法解析,不降级为无类型的数据块 - 泛型参数保留,不擦除类型实参 - 名字解析为包含模块路径的限定名 - 语法糖归一化为标准语义节点 @@ -100,11 +100,11 @@ Core IR 与传统编译器 IR 的区别在于保留语义信息而非逐步丢 Core 只有一种执行语义:HDFG(Holographic Dataflow Graph,全息数据流图——从数据流图演化的语义承载图:任何消费者——执行后端、验证器、AI——都能从图中读取全部语义,无信息丢失)。 -所有代码经语义 IR 翻译后构成一张有向图——节点是操作,边是数据依赖。图承载程序的全部执行语义——代码写了什么(函数调用、loop、go),图就反映什么: +所有代码经语义 IR 翻译后构成一张有向图——节点是操作,边是数据依赖。图承载程序的全部执行语义——代码写了什么(函数调用、`loop`、`go`),图就反映什么: -- 纯函数、分支、for 循环 → 有向无环图(DAG)——依赖偏序,无反馈。 -- loop、recv → 带反馈环的图——迭代语义,region 边界表达迭代与终止。 -- flow、go、yield、select → 运行时动态图——节点创建与并发语义。 +- 纯函数、分支、`for` 循环 → 有向无环图(DAG)——依赖偏序,无反馈。 +- `loop`、`recv` → 带反馈环的图——迭代语义,region 边界表达迭代与终止。 +- `flow`、`go`、`yield`、`select` → 运行时动态图——节点创建与并发语义。 图是执行语义的载体,**不是执行方式的决定者**:执行方式(串行、并行、调度策略)由部署配置决定——同一张 DAG,单核串行、多核并行、无 OS 抢占式时间片。图只约束语义(依赖、迭代、并发结构),不决定物理执行。同样,图也是存储语义的载体——值即条目(配方可重算),存储 = 语义对象在**存在格(Materialization / Existence Space)**中的物化(范式无关),缓存与字节内存都只是该层的映射实例(见 `docs/maintainer/design/materialization-space.md`)。 @@ -168,7 +168,7 @@ graph TD 实现层 IR 是程序执行语义的完备编码。它包含: - 类型定义节点:结构体、枚举、接口、代数数据类型。每个节点完整记录实现关系、成员签名、可见性。具体内存布局由后端决定,但做出布局决策所需的所有语义信息均被保留。 -- 函数与方法的执行结构:region 嵌套(SG 段 = 图锚定存在结构)+ 格形态 .ccr(v6:段表 + ENT 存在结构段,v6-only——存在区间/共存/驱逐承载,见 `specs/2026-09-05-lattice-ir-v6-format.md` + `2026-08-27-lattice-form-ir-design.md`)。指令为高级语义原语——静态调用、对象分配、字段读写、数组读写、分支、循环。每一条指令的源操作数和目标操作数均为完全解析的符号引用。 +- 函数与方法的执行结构:region 嵌套(SG 段 = 图锚定存在结构)+ 格形态 `.ccr`(v6:段表 + ENT 存在结构段,v6-only——存在区间/共存/驱逐承载,见 `specs/2026-09-05-lattice-ir-v6-format.md` + `2026-08-27-lattice-form-ir-design.md`)。指令为高级语义原语——静态调用、对象分配、字段读写、数组读写、分支、循环。每一条指令的源操作数和目标操作数均为完全解析的符号引用。 - 图拓扑元数据:标注每个子图的结构特征(DAG、静态循环、动态生长),为后端选择执行策略提供依据。 - 全局符号表:模块间引用全部解析为直接索引。无重复、无歧义。 @@ -183,9 +183,9 @@ graph TD - 边界条件:证明循环终止所需的递减度量(变体)。 - 抽象规约:接口或抽象类对其所有实现方施加的契约。 -规约公式可引用:程序的可见实体(通过限定名)、特殊逻辑符号(如 result 表示返回值、old(x) 表示调用前的值)、纯逻辑函数和谓词。 +规约公式可引用:程序的可见实体(通过限定名)、特殊逻辑符号(如 `result` 表示返回值、`old(x)` 表示调用前的值)、纯逻辑函数和谓词。 -规约层 IR 不被任何代码生成后端触及。它被形式化验证工具消费(验证工作流见 docs/spec-design.md——规约经翻译桥进入 CIC 内核 + SMT 证书验证);已证性质可回流入优化器(证明驱动优化,见 spec-design §13)。 +规约层 IR 不被任何代码生成后端触及。它被形式化验证工具消费(验证工作流见 `docs/spec-design.md`——规约经翻译桥进入 CIC 内核 + SMT 证书验证);已证性质可回流入优化器(证明驱动优化,见 spec-design §13)。 ### 4.4 代码生成后端 @@ -193,13 +193,13 @@ graph TD 每个后端维护一张指令映射表,将实现层 IR 中的每一条高级指令映射为目标平台的指令序列。后端根据 IR 中的图拓扑元数据自动选择执行调度策略——DAG 用串行、静态循环用固定节奏、动态图用协作式或多核并行。程序员不指定策略,编译器也不要求程序员指定。 -后端的平台特有职责仅限于指令选择、寄存器分配、调用约定。每个后端是机械翻译器(现有 x86-64 ELF 后端见 src/arch/linux/ld/,直接发射 ELF,不依赖外部 as/ld)。 +后端的平台特有职责仅限于指令选择、寄存器分配、调用约定。每个后端是机械翻译器(现有 x86-64 ELF 后端见 `src/arch/linux/ld/`,直接发射 ELF,不依赖外部 `as`/`ld`)。 ### 4.5 部署配置 物理世界的约束——内存模型、核心数量、操作系统支持——不属于程序语义,属于部署目标的属性。 -这些属性在部署配置文件中声明(如 .toml 格式),而不是在代码中。编译时,编译器读取部署配置,与实现层 IR 进行兼容性检查: +这些属性在部署配置文件中声明(如 `.toml` 格式),而不是在代码中。编译时,编译器读取部署配置,与实现层 IR 进行兼容性检查: - 目标不支持动态分配 → 编译器检查所有数据结构大小是否编译期可确定。不可确定则拒绝编译,给出明确错误及位置。 - 目标支持动态分配 → 生成使用目标分配器的代码。 @@ -207,11 +207,11 @@ graph TD 同一份实现层 IR,搭配不同的部署配置,即可适配不同的目标平台。代码不变。 -I/O 等平台接口与部署目标属性同属物理层,遵循同一原则线:程序语义是流变换——程序 = 流转导器 (输入流) → (输出流),输入输出是同一数学对象(流)的两端,输出即对世界的输入。read_file/write_file/print/println 等 API 是语义接口(现有 API 保持不变),read/write 等系统调用是物理实现,由后端按部署目标隔离;验证意义上,I/O 程序语义 = 流变换,规约可描述「输入流性质 → 输出流性质」,I/O 是一等公民语义而非验证黑洞。随机(概率分布)、哈希(散列函数)、时钟(单调时间序)同理:语义接口在语言层,熵源、算法、系统调用在后端实现。 +I/O 等平台接口与部署目标属性同属物理层,遵循同一原则线:程序语义是流变换——程序 = 流转导器 (输入流) → (输出流),输入输出是同一数学对象(流)的两端,输出即对世界的输入。`read_file`/`write_file`/`print`/`println` 等 API 是语义接口(现有 API 保持不变),`read`/`write` 等系统调用是物理实现,由后端按部署目标隔离;验证意义上,I/O 程序语义 = 流变换,规约可描述「输入流性质 → 输出流性质」,I/O 是一等公民语义而非验证黑洞。随机(概率分布)、哈希(散列函数)、时钟(单调时间序)同理:语义接口在语言层,熵源、算法、系统调用在后端实现。 ### 4.6 指针安全 -Core 的指针安全完全建立在HDFG上,不引入 borrow checker、Arena tag、RawRef 等独立概念层。编译器从图中推导每个指针的来源(provenance)和偏移,在解引用点自动验证。详见 `docs/maintainer/design/pointer-model.md`。 +Core 的指针安全完全建立在 HDFG 上,不引入 `borrow checker`、`Arena tag`、`RawRef` 等独立概念层。编译器从图中推导每个指针的来源(provenance)和偏移,在解引用点自动验证。详见 `docs/maintainer/design/pointer-model.md`。 存储语义本体为**存在格 / Materialization Space**——格层回答四问:哪些 materialization 合法、哪些可以共存、哪些代表同一 Entry/version、哪些转换保持语义(主套见 `docs/maintainer/design/materialization-space.md` §2.1);**缓存语义是该层的一类映射实例**(最直接实现条款 1–7 的那一类),不是本体的名字。层定义与七字段模型(recipe/identity/version/authority/location/persistence/replicability)见 `docs/maintainer/design/materialization-space.md`;条款 1–7 见 `docs/academic/cache-semantics.md`;字节内存是经典映射实例——总览见 `docs/maintainer/design/memory-model.md`。 @@ -231,7 +231,7 @@ Core 的执行模型可以完整描述为一句话:程序即 HDFG——图承 ### 5.1 DAG:确定性的顺序执行 -最简单的程序——变量绑定、算术运算、函数调用、条件分支、for 循环——编译后产生有向无环图。图中每个节点在其全部输入就绪后恰好执行一次,产生输出令牌。 +最简单的程序——变量绑定、算术运算、函数调用、条件分支、`for` 循环——编译后产生有向无环图。图中每个节点在其全部输入就绪后恰好执行一次,产生输出令牌。 执行器按拓扑序遍历节点。在任何时刻,只有一个节点在执行,程序的全部状态完全可观测、完全可预测。单步调试就是逐步走图。 @@ -239,14 +239,14 @@ Core 的执行模型可以完整描述为一句话:程序即 HDFG——图承 ### 5.2 带环静态图:有节奏的循环 -当代码中出现 loop 构造,图中引入带环结构:编译为嵌套 region(loop/for 结构节点 +当代码中出现 `loop` 构造,图中引入带环结构:编译为嵌套 region(`loop`/`for` 结构节点 含子区域,region 嵌套的层次无环图)。执行器按迭代周期调度:每个周期内循环体子 region 按拓扑序执行;周期结束回到 region 头部触发下一轮迭代。循环不变量和变体标注于 region 边界,供验证工具证明终止性和循环正确性(终止性依赖经 state edge 显式表达)。 ### 5.3 动态图:并发与自适应 -当代码中使用 flow、go、yield、select,图的拓扑可在运行时变化。新节点通过 go 动态创建,节点间的流通过 yield/recv 传递令牌,select 在多个输入边之间等待最先到达的令牌。 +当代码中使用 `flow`、`go`、`yield`、`select`,图的拓扑可在运行时变化。新节点通过 `go` 动态创建,节点间的流通过 `yield`/`recv` 传递令牌,`select` 在多个输入边之间等待最先到达的令牌。 多核目标上,各节点被分配到独立线程并行执行。单核目标上,使用协作式调度。同一份语义 IR,编译器根据部署配置中的目标信息自动选择调度方案。 @@ -268,7 +268,7 @@ fn main() { - 部署为单核嵌入式 → 编译器生成串行机器码,静态分配,零运行时。 - 部署为多核服务器 → 编译器可并行化不相关的计算路径。 - 部署到教学环境 → 解释器按拓扑序逐步执行,每步展示变量值。 -- 部署为分布式系统 → add 节点可远程执行,输入输出为网络消息。 +- 部署为分布式系统 → `add` 节点可远程执行,输入输出为网络消息。 代码不改。图语义唯一。部署配置不同。 @@ -276,6 +276,6 @@ fn main() { ## 八、总结 -Core 要回答的问题是:如果在语言设计之初就将语法检查、语义 IR 和规约 IR 纳入统一框架——实现层 IR 承载程序语义,规约层 IR 承载行为约束,两者分立但通过符号精确关联——那么编译速度、跨平台能力和形式化验证的门槛可以降低到什么程度? +Core 要回答的问题是:如果在语言设计之初就将语法检查、语义 IR 和规约 IR 纳入统一框架——实现层 IR 承载程序语义,规约层 IR 承载行为约束,两者分立但通过符号精确关联——那么编译速度、跨平台能力和形式化验证的门槛可以降低到什么程度。 Core 项目将用实际可运行的代码来回答这个问题。 diff --git a/docs/superpowers/plans/2026-07-28-arena-model.md b/docs/superpowers/plans/2026-07-28-arena-model.md index 0fdb78a2..170f3df6 100644 --- a/docs/superpowers/plans/2026-07-28-arena-model.md +++ b/docs/superpowers/plans/2026-07-28-arena-model.md @@ -1,36 +1,36 @@ -# Arena 内存模型 Implementation Plan +# Arena 内存模型实现计划 -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. +> **受众**:执行本计划的 agentic worker。**必需子技能**:`superpowers:subagent-driven-development`(推荐)或 `superpowers:executing-plans`,按任务逐项实施。进度以复选框(`- [ ]`)跟踪。 -**Goal:** Replace the single global bump allocator with a multi-arena system where each subgraph (function/loop/for/unsafe) gets its own arena, allocation automatically uses the current arena, and subgraph exit resets the arena cursor. +**目标**:将单一全局 bump 分配器替换为多 arena 系统——每个子图(function/loop/for/unsafe)持有独立 arena,分配自动使用当前 arena,子图退出时重置 arena 游标。 -**Architecture:** Three layers — (1) stdlib arena lifecycle in Core (`arena.cr`), (2) compiler emits `IR_ARENA_NEW`/`IR_ARENA_RESET` at subgraph boundaries with compile-time size estimation, (3) ELF backend `emit_alloc_body` checks `g_current_arena` and allocates from the arena chunk when set, falling back to global bump when not. +**架构**:三层结构——(1)Core 侧的 stdlib arena 生命周期(`arena.cr`);(2)编译器在子图边界发射 `IR_ARENA_NEW`/`IR_ARENA_RESET`,并做编译期尺寸估算;(3)ELF 后端 `emit_alloc_body` 检查 `g_current_arena`,已设置时从 arena chunk 分配,未设置时回退到全局 bump。 -**Tech Stack:** Core language (self-hosted compiler), x86-64 ELF backend, GNU as (rt.s) +**技术栈**:Core 语言(自举编译器)、x86-64 ELF 后端、GNU as(rt.s) -## Global Constraints +## 全局约束 -- No fixed MAX_ARENAS limit — metadata arrays are dynamic (like `g_df_nodes`) -- `alloc()` API unchanged — arena awareness is transparent -- `g_current_arena = -1` preserves existing global bump behavior -- All lifecycle management in Core code (`arena.cr`); only bump path is in assembly -- New IR opcodes: `IR_ARENA_NEW = 32`, `IR_ARENA_RESET = 33` -- ESZ_IRINSTR = 48 bytes (6 fields × 8 bytes). `iri_set_s1(idx, val)` patches instruction field. -- Chain expansion: arena OOM allocates overflow block from global heap +- 无固定 `MAX_ARENAS` 上限——元数据数组为动态数组(与 `g_df_nodes` 同机制) +- `alloc()` API 不变——arena 感知对调用方透明 +- `g_current_arena = -1` 保留既有全局 bump 行为 +- 生命周期管理全部位于 Core 代码(`arena.cr`);汇编仅承担 bump 路径 +- 新增 IR opcode:`IR_ARENA_NEW = 32`、`IR_ARENA_RESET = 33` +- `ESZ_IRINSTR = 48` 字节(6 字段 × 8 字节)。`iri_set_s1(idx, val)` 用于回填指令字段。 +- 链式扩展:arena OOM 时从全局堆分配溢出块 --- -### Task 1: BSS Extension (rt.s) +### 任务 1:BSS 扩展(rt.s) -**Files:** -- Modify: `src/runtime/rt.s` +**涉及文件:** +- 修改:`src/runtime/rt.s` -**Interfaces:** -- Produces: `g_current_arena` (BSS, 8B), `g_arena_pool_data` (BSS, 8B), `g_arena_free_list` (BSS, 8B) +**接口:** +- 产出:`g_current_arena`(BSS,8 字节)、`g_arena_pool_data`(BSS,8 字节)、`g_arena_free_list`(BSS,8 字节) -- [ ] **Step 1: Add arena BSS variables** +- [ ] **步骤 1:新增 arena BSS 变量** -In `src/runtime/rt.s`, find the `.bss` section. Add after `.balign 4096` and before `heap_ptr`: +在 `src/runtime/rt.s` 中定位 `.bss` 段,在 `.balign 4096` 之后、`heap_ptr` 之前新增: ```asm .section .bss @@ -43,9 +43,9 @@ heap_start: .space 1024 * 1024 * 1024 heap_end: ``` -- [ ] **Step 2: Initialize new globals in _start** +- [ ] **步骤 2:在 _start 中初始化新增全局变量** -In `_start`, after the existing `heap_ptr` init (`lea rax, [rip + heap_start]; lea r10, [rip + heap_ptr]; mov [r10], rax`), add: +在 `_start` 中既有 `heap_ptr` 初始化(`lea rax, [rip + heap_start]; lea r10, [rip + heap_ptr]; mov [r10], rax`)之后新增: ```asm # Initialize g_current_arena = -1 (no arena active) @@ -59,12 +59,12 @@ In `_start`, after the existing `heap_ptr` init (`lea rax, [rip + heap_start]; l mov [r10], rax ``` -- [ ] **Step 3: Verify assembly** +- [ ] **步骤 3:校验汇编** -Run: `as -o /tmp/rt.o src/runtime/rt.s` -Expected: No errors. +命令:`as -o /tmp/rt.o src/runtime/rt.s` +预期:无错误。 -- [ ] **Step 4: Commit** +- [ ] **步骤 4:提交** ```bash git add src/runtime/rt.s @@ -73,55 +73,55 @@ git commit -m "feat: add arena BSS globals (g_current_arena, g_arena_pool_data, --- -### Task 2: New IR Opcodes (ast.cr, dataflow.cr, opt.cr) +### 任务 2:新增 IR Opcode(ast.cr、dataflow.cr、opt.cr) -**Files:** -- Modify: `src/compiler/ast.cr` -- Modify: `src/compiler/dataflow.cr` -- Modify: `src/compiler/opt.cr` +**涉及文件:** +- 修改:`src/compiler/ast.cr` +- 修改:`src/compiler/dataflow.cr` +- 修改:`src/compiler/opt.cr` -**Interfaces:** -- Produces: `IR_ARENA_NEW = 32`, `IR_ARENA_RESET = 33` +**接口:** +- 产出:`IR_ARENA_NEW = 32`、`IR_ARENA_RESET = 33` -- [ ] **Step 1: Add opcode constants to ast.cr** +- [ ] **步骤 1:向 ast.cr 添加 opcode 常量** -Find the IR opcode section (around line 526-530), add after `IR_YIELD`: +定位 IR opcode 段(约第 526-530 行),在 `IR_YIELD` 之后新增: ```core IR_ARENA_NEW : int = 32; // dest=arena_var, src1=size_estimate IR_ARENA_RESET : int = 33; // src1=arena_id (dest=-1) ``` -- [ ] **Step 2: Register in dataflow.cr df_opcode_name** +- [ ] **步骤 2:在 dataflow.cr 的 df_opcode_name 中登记** -Find `fn df_opcode_name`, add after the `IR_YIELD` entry (around line 349): +定位 `fn df_opcode_name`,在 `IR_YIELD` 条目之后(约第 349 行)新增: ```core if opcode == IR_ARENA_NEW { return "arena_new"; } if opcode == IR_ARENA_RESET { return "arena_reset"; } ``` -- [ ] **Step 3: Register in dataflow.cr df_connect_srcs** +- [ ] **步骤 3:在 dataflow.cr 的 df_connect_srcs 中登记** -Find `fn df_connect_srcs` (search for `df_connect_srcs` definition). Add at the end, before the function's closing: +定位 `fn df_connect_srcs`(搜索其定义)。在函数结尾之前追加: ```core if opcode == IR_ARENA_NEW { df_use_var(nid, s1); return; } if opcode == IR_ARENA_RESET { df_use_var(nid, s1); return; } ``` -- [ ] **Step 4: Skip in opt.cr optimization loops** +- [ ] **步骤 4:在 opt.cr 优化循环中跳过** -Find the main optimization loop in `opt.cr` (search for `if op == IR_` blocks). Add: +定位 `opt.cr` 的主优化循环(搜索 `if op == IR_` 分支)。新增: ```core if op == IR_ARENA_NEW { continue; } if op == IR_ARENA_RESET { continue; } ``` -Also check `resolve.cr` for any opcode switch — add skip cases if found. +同时检查 `resolve.cr` 中是否存在 opcode 分支;若存在则补充跳过分支。 -- [ ] **Step 5: Commit** +- [ ] **步骤 5:提交** ```bash git add src/compiler/ast.cr src/compiler/dataflow.cr src/compiler/opt.cr @@ -130,14 +130,14 @@ git commit -m "feat: add IR_ARENA_NEW(32) and IR_ARENA_RESET(33) opcodes" --- -### Task 3: CCR Serialization (ccr_io.cr) +### 任务 3:CCR 序列化(ccr_io.cr) -**Files:** -- Modify: `src/compiler/ccr_io.cr` +**涉及文件:** +- 修改:`src/compiler/ccr_io.cr` -- [ ] **Step 1: Add save_ccr handling** +- [ ] **步骤 1:添加 save_ccr 分支** -Find `fn save_ccr`. Find the instruction-writing loop (where opcodes are dispatched). Add after the YIELD case: +定位 `fn save_ccr` 中的指令写入循环(opcode 分发处),在 YIELD 分支之后新增: ```core if op == IR_ARENA_NEW { @@ -162,9 +162,9 @@ Find `fn save_ccr`. Find the instruction-writing loop (where opcodes are dispatc } ``` -- [ ] **Step 2: Add load_ccr handling** +- [ ] **步骤 2:添加 load_ccr 分支** -Find `fn load_ccr`. Find the instruction-reading loop. Add after the YIELD case: +定位 `fn load_ccr` 中的指令读取循环,在 YIELD 分支之后新增: ```core if op == IR_ARENA_NEW { @@ -189,7 +189,7 @@ Find `fn load_ccr`. Find the instruction-reading loop. Add after the YIELD case: } ``` -- [ ] **Step 3: Commit** +- [ ] **步骤 3:提交** ```bash git add src/compiler/ccr_io.cr @@ -198,16 +198,16 @@ git commit -m "feat: save/load IR_ARENA_NEW and IR_ARENA_RESET in ccr_io" --- -### Task 4: Stdlib — arena.cr +### 任务 4:Stdlib——arena.cr -**Files:** -- Rewrite: `src/stdlib/arena.cr` +**涉及文件:** +- 重写:`src/stdlib/arena.cr` -**Interfaces:** -- Globals: `g_current_arena`, `g_arena_cursors`, `g_arena_sizes`, `g_arena_parents`, `g_arena_pool_data`, `g_arena_max_size`, `g_arena_free_list`, `g_arena_count`, `g_arena_cap` -- Functions: `arena_init(pool_size, arena_size)`, `arena_new() -> int`, `arena_reset(ai)`, `arena_avail(ai) -> int` +**接口:** +- 全局变量:`g_current_arena`、`g_arena_cursors`、`g_arena_sizes`、`g_arena_parents`、`g_arena_pool_data`、`g_arena_max_size`、`g_arena_free_list`、`g_arena_count`、`g_arena_cap` +- 函数:`arena_init(pool_size, arena_size)`、`arena_new() -> int`、`arena_reset(ai)`、`arena_avail(ai) -> int` -- [ ] **Step 1: Write arena.cr** +- [ ] **步骤 1:编写 arena.cr** ```core // Arena memory model — per-subgraph bump allocator. @@ -316,14 +316,14 @@ fn arena_avail(ai: int) -> int { } ``` -- [ ] **Step 2: Type-check** +- [ ] **步骤 2:类型检查** -Run: `./build/corec check src/stdlib/arena.cr` -Expected: No compilation errors. (If errors about globals, ensure arena.cr globals are registered — see Known Issues in CLAUDE.md about unregistered globals.) +命令:`./build/corec check src/stdlib/arena.cr` +预期:无编译错误。(若报全局变量相关错误,确认 `arena.cr` 的全局变量已注册——参见 CLAUDE.md 的 Known Issues 中关于未注册全局变量的记录。) -If there are errors about global registration, add arena globals to the parser's global registration list (similar fix to the tokenizer global registration issue documented in CLAUDE.md). +若出现全局变量注册相关错误,将 arena 全局变量加入 parser 的全局注册表(做法与 CLAUDE.md 记录的 tokenizer 全局注册问题相同)。 -- [ ] **Step 3: Commit** +- [ ] **步骤 3:提交** ```bash git add src/stdlib/arena.cr @@ -332,14 +332,14 @@ git commit -m "feat: arena lifecycle allocator — init/new/reset with dynamic m --- -### Task 5: IR Gen Integration (ir_gen.cr) +### 任务 5:IR Gen 集成(ir_gen.cr) -**Files:** -- Modify: `src/compiler/ir_gen.cr` +**涉及文件:** +- 修改:`src/compiler/ir_gen.cr` -- [ ] **Step 1: Add per-subgraph arena tracking globals** +- [ ] **步骤 1:添加子图级 arena 跟踪全局变量** -At the top of `ir_gen.cr` (after the comment block), add: +在 `ir_gen.cr` 顶部(注释块之后)新增: ```core // Subgraph-level arena tracking for compile-time size estimation @@ -359,7 +359,7 @@ fn grow_sg_arena_var(needed: int) { nb := alloc(nc * 8); _dyncpy(g_sg_arena_var, g_sg_arena_var_cap * 8, nb); g_sg_arena_var = nb; g_sg_arena_var_cap = nc; } ``` -- [ ] **Step 2: Add sg_alloc_push/pop and track_alloc_size** +- [ ] **步骤 2:添加 sg_alloc_push/pop 与 track_alloc_size** ```core fn sg_alloc_push(kind: int) { @@ -384,11 +384,11 @@ fn track_alloc_size(size: int) { } ``` -- [ ] **Step 3: Wire arena at function entry/exit in ir_gen_func** +- [ ] **步骤 3:在 ir_gen_func 的函数入口与出口接入 arena** -In `ir_gen_func`, find the start of body generation. Replace `sg_push(kind)` call pattern. The function currently doesn't call `sg_push` directly — `df_begin_func` does that. But we need to add arena lifecycle around the function body. +在 `ir_gen_func` 中定位 body 生成的起点,替换 `sg_push(kind)` 的调用模式。该函数本身不直接调用 `sg_push`(由 `df_begin_func` 调用),arena 生命周期需加在函数 body 外围。 -Find `if body >= 0 { gen_expr(body); }`. Replace with: +定位 `if body >= 0 { gen_expr(body); }`,替换为: ```core // Function-level arena @@ -402,7 +402,7 @@ Find `if body >= 0 { gen_expr(body); }`. Replace with: sg_alloc_pop(); ``` -Wait, this has an ordering issue — we need the total before we create IR_ARENA_NEW, but we need the arena_var before body gen. Let me restructure: +该顺序存在问题:`IR_ARENA_NEW` 需要 `total`,而 `total` 须在 body 生成之后才可得;`arena_var` 则须在 body 生成之前确定。调整顺序如下: ```core // Function-level arena @@ -423,11 +423,11 @@ Wait, this has an ordering issue — we need the total before we create IR_ARENA sg_alloc_pop(); ``` -- [ ] **Step 4: Wire arena at loop/for/unsafe boundaries** +- [ ] **步骤 4:在 loop/for/unsafe 边界接入 arena** -Find the existing `sg_push`/`sg_pop` calls in ir_gen.cr: +定位 `ir_gen.cr` 中既有的 `sg_push`/`sg_pop` 调用点。 -For **LOOP** (around line 659): +LOOP(约第 659 行): ```core sg_alloc_push(SG_LOOP); arena_var := new_ir_var("_arena", TI_INT); @@ -440,7 +440,7 @@ For **LOOP** (around line 659): sg_alloc_pop(); ``` -For **FOR** (around line 724): +FOR(约第 724 行): ```core sg_alloc_push(SG_FOR); arena_var := new_ir_var("_arena", TI_INT); @@ -453,7 +453,7 @@ For **FOR** (around line 724): sg_alloc_pop(); ``` -For **UNSAFE** (around line 1005): +UNSAFE(约第 1005 行): ```core sg_alloc_push(SG_UNSAFE); arena_var := new_ir_var("_arena", TI_INT); @@ -466,11 +466,11 @@ For **UNSAFE** (around line 1005): sg_alloc_pop(); ``` -- [ ] **Step 5: Wire track_alloc_size into ALLOC instruction emission** +- [ ] **步骤 5:将 track_alloc_size 接入全部 ALLOC 指令发射点** -In `emit()` or at each ALLOC emit site, call `track_alloc_size`. The cleanest location: in `emit()` itself, after writing the instruction, check if opcode is an ALLOC variant and track the size. +`track_alloc_size` 可在各 ALLOC 发射点分别调用,也可在 `emit()` 内统一调用。选定位置为 `emit()` 内部:写入指令之后判断 opcode 是否为 ALLOC 变体,是则记录尺寸。 -At the end of `emit()` (after `g_ir_instr_count = idx + 1;` and `df_create_node(...);`), add: +在 `emit()` 末尾(`g_ir_instr_count = idx + 1;` 与 `df_create_node(...);` 之后)新增: ```core // Track allocation size for subgraph arena size estimation @@ -483,7 +483,7 @@ At the end of `emit()` (after `g_ir_instr_count = idx + 1;` and `df_create_node( if opcode == IR_ALLOC_ARRAY && src1 > 0 { track_alloc_size(src1 * 8); } ``` -- [ ] **Step 6: Commit** +- [ ] **步骤 6:提交** ```bash git add src/compiler/ir_gen.cr @@ -492,23 +492,23 @@ git commit -m "feat: ir_gen arena lifecycle — sg_alloc_push/pop, size estimati --- -### Task 6: ELF Backend — emit_alloc_body Dual Path (elf.cr) +### 任务 6:ELF 后端——emit_alloc_body 双路径(elf.cr) -**Files:** -- Modify: `src/arch/linux/ld/elf.cr` +**涉及文件:** +- 修改:`src/arch/linux/ld/elf.cr` -- [ ] **Step 1: Read current emit_alloc_body** +- [ ] **步骤 1:阅读现有 emit_alloc_body** -Read the current `emit_alloc_body` function (around line 23-84 in elf.cr) and understand its structure: -- It emits `_start` initialization code -- Has bounds check (cmp rdi, 64MB) -- Bumps `heap_ptr` from BSS -- Zeroes memory with `rep stosb` -- Stores length header, returns data ptr +阅读 `emit_alloc_body` 现有实现(`elf.cr` 中约第 23-84 行),其结构如下: +- 发射 `_start` 初始化代码 +- 含边界检查(`cmp rdi, 64MB`) +- 从 BSS 递增 `heap_ptr` +- 以 `rep stosb` 清零内存 +- 写入长度头,返回数据指针 -- [ ] **Step 2: Modify emit_alloc_body for dual-path** +- [ ] **步骤 2:改写 emit_alloc_body 为双路径** -Replace the body of `emit_alloc_body` to check `g_current_arena` at entry. New logic: +改写 `emit_alloc_body` 函数体,在入口处检查 `g_current_arena`。新逻辑如下: ```asm emit_alloc_body: @@ -613,23 +613,23 @@ emit_alloc_body: ret ``` -Note: The assembly above is a sketch. The actual implementation needs to be precise x86-64 machine code emission compatible with the existing `emit_alloc_body` interface. Key points: -1. Function entry is the same (`rdi = size`) -2. Function exit is the same (`rax = pointer` or 0) -3. The arena path loads globals via RIP-relative addressing -4. Chain expansion falls through to global bump path +注:上述汇编为示意。实际实现须为与既有 `emit_alloc_body` 接口兼容的精确 x86-64 机器码发射。要点如下: +1. 函数入口不变(`rdi = size`) +2. 函数出口不变(`rax = pointer` 或 0) +3. arena 路径通过 RIP 相对寻址读取全局变量 +4. 链式扩展落至全局 bump 路径 -The actual code emission uses `w8(buf, pos+cp, byte)` etc. — follow the existing pattern. +实际发射使用 `w8(buf, pos+cp, byte)` 等原语,遵循既有模式。 -- [ ] **Step 3: Update emit_alloc_body return signature in phase 2 sizing** +- [ ] **步骤 3:更新阶段 2 尺寸估算中 emit_alloc_body 的返回签名** -In the `elf_gen` function where `emit_alloc_body` size is pre-calculated (currently hardcoded as 84 bytes), update the estimated size to accommodate the expanded function (approximately double, ~160-180 bytes). +在 `elf_gen` 中预计算 `emit_alloc_body` 尺寸的位置(现为硬编码 84 字节),上调估算尺寸以容纳扩展后的函数(约为原值的两倍,约 160-180 字节)。 ```core total_code = total_code + 180; // arena-aware alloc body ``` -- [ ] **Step 4: Commit** +- [ ] **步骤 4:提交** ```bash git add src/arch/linux/ld/elf.cr @@ -638,16 +638,16 @@ git commit -m "feat: emit_alloc_body dual-path arena alloc + chain expansion fal --- -### Task 7: ELF Backend — Arena NEW/RESET Encoding (instr.cr, resolve.cr) +### 任务 7:ELF 后端——arena NEW/RESET 编码(instr.cr、resolve.cr) -**Files:** -- Modify: `src/arch/linux/ld/instr.cr` -- Modify: `src/arch/linux/ld/elf.cr` (add arena_new_impl / arena_reset_impl emit) -- Modify: `src/arch/linux/ld/resolve.cr` +**涉及文件:** +- 修改:`src/arch/linux/ld/instr.cr` +- 修改:`src/arch/linux/ld/elf.cr`(新增 `arena_new_impl` / `arena_reset_impl` 发射) +- 修改:`src/arch/linux/ld/resolve.cr` -- [ ] **Step 1: Add IR_ARENA_NEW encoding to instr.cr** +- [ ] **步骤 1:向 instr.cr 添加 IR_ARENA_NEW 编码** -Find the main instruction encoding function in `instr.cr` (where IR opcodes are dispatched, around the `if op == IR_ALLOC` section). Add before the `return cp` at the end: +定位 `instr.cr` 的主指令编码函数(IR opcode 分发处,约 `if op == IR_ALLOC` 段),在末尾 `return cp` 之前新增: ```core if op == IR_ARENA_NEW { @@ -666,7 +666,7 @@ Find the main instruction encoding function in `instr.cr` (where IR opcodes are } ``` -- [ ] **Step 2: Add IR_ARENA_RESET encoding to instr.cr** +- [ ] **步骤 2:向 instr.cr 添加 IR_ARENA_RESET 编码** ```core if op == IR_ARENA_RESET { @@ -681,11 +681,11 @@ Find the main instruction encoding function in `instr.cr` (where IR opcodes are } ``` -Note: `e2_load_var(buf, pos+cp, 7, s1)` loads the IR variable `s1` into register rdi (= 7 for `edi`). Check the register numbering convention in `instr.cr` — the emitted code needs to match the calling convention (`rdi` = first arg). +注:`e2_load_var(buf, pos+cp, 7, s1)` 将 IR 变量 `s1` 载入 rdi(`edi` 的编号为 7)。寄存器编号约定以 `instr.cr` 为准,发射代码须匹配调用约定(`rdi` = 第一个参数)。 -- [ ] **Step 3: Add label size estimation for new opcodes in sizes.cr** +- [ ] **步骤 3:在 sizes.cr 中为新 opcode 添加尺寸估算** -Find the instruction size function in `src/arch/linux/ld/sizes.cr`. Add size cases: +定位 `src/arch/linux/ld/sizes.cr` 的指令尺寸函数,新增尺寸分支: ```core if op == IR_ARENA_NEW { @@ -698,9 +698,9 @@ Find the instruction size function in `src/arch/linux/ld/sizes.cr`. Add size cas } ``` -- [ ] **Step 4: Add arena_new_impl / arena_reset_impl to elf.cr** +- [ ] **步骤 4:向 elf.cr 添加 arena_new_impl / arena_reset_impl** -In `elf.cr` (after `emit_alloc_body`), add two new emitter functions: +在 `elf.cr` 中(`emit_alloc_body` 之后)新增两个发射函数: ```core // Emit arena_new_impl — creates a new arena slot. @@ -737,9 +737,9 @@ fn emit_arena_reset_impl(buf: string, pos: int) -> int { } ``` -- [ ] **Step 5: Register arena_new_impl/arena_reset_impl in elf_gen** +- [ ] **步骤 5:在 elf_gen 中登记 arena_new_impl / arena_reset_impl** -In `elf_gen`, after emitting the alloc body and its offset registration, add: +在 `elf_gen` 中,alloc body 发射及其偏移登记之后新增: ```core // arena_new_impl @@ -757,7 +757,7 @@ In `elf_gen`, after emitting the alloc body and its offset registration, add: total_code = total_code + 6; // emit_arena_reset_impl size ``` -And in Phase 3 (emit), after calling `emit_alloc_body`, call the new emitters: +Phase 3(发射)中,在调用 `emit_alloc_body` 之后调用新增的发射函数: ```core // arena_new_impl @@ -766,11 +766,11 @@ And in Phase 3 (emit), after calling `emit_alloc_body`, call the new emitters: cp = cp + emit_arena_reset_impl(buf, cp); ``` -- [ ] **Step 6: Handle new opcodes in resolve.cr label resolution** +- [ ] **步骤 6:在 resolve.cr 标签解析中处理新 opcode** -In `resolve.cr`, ensure any label-related passes skip new opcodes (they don't use labels). +在 `resolve.cr` 中确认各标签相关 pass 跳过新增 opcode(新增 opcode 不使用标签)。 -- [ ] **Step 7: Commit** +- [ ] **步骤 7:提交** ```bash git add src/arch/linux/ld/instr.cr src/arch/linux/ld/elf.cr src/arch/linux/ld/sizes.cr src/arch/linux/ld/resolve.cr @@ -779,12 +779,12 @@ git commit -m "feat: ELF backend arena_new/reset opcode encoding + impl stubs" --- -### Task 8: Tests +### 任务 8:测试 -**Files:** -- Create: `tests/suite/arena_test.cr` +**涉及文件:** +- 创建:`tests/suite/arena_test.cr` -- [ ] **Step 1: Write arena lifecycle test** +- [ ] **步骤 1:编写 arena 生命周期测试** ```core // Arena memory model test suite @@ -869,33 +869,33 @@ fn main() -> int { } ``` -- [ ] **Step 2: Run test via interpreter** +- [ ] **步骤 2:以解释器运行测试** ```bash ./build/corec run -f tests/suite/arena_test.cr ``` -(Note: `-f` flag may not exist — use `run` subcommand with file path or inline. Check `./build/corec --help` for the correct syntax.) +(注:`-f` 标志可能不存在——`run` 子命令接受文件路径或内联代码,正确语法以 `./build/corec --help` 为准。) -If the `run` command doesn't support importing stdlib files, try: +若 `run` 命令不支持导入 stdlib 文件,改用: ```bash ./build/corec build tests/suite/arena_test.cr -o /tmp/arena_test --static /tmp/arena_test echo $? ``` -Or inline the arena code directly in the test file without the `import` and test with the interpreter directly. +或将 arena 代码直接内联进测试文件(不使用 `import`),直接以解释器测试。 -- [ ] **Step 3: Run existing tests to verify no regression** +- [ ] **步骤 3:运行既有测试确认无回归** ```bash python3 tests/bootstrap/test_pipeline.py python3 tests/selfhost/test_compile.py ``` -Expected: All existing tests pass (arena code path not triggered for non-arena tests). +预期:既有测试全部通过(非 arena 测试不会触发 arena 代码路径)。 -- [ ] **Step 4: Commit** +- [ ] **步骤 4:提交** ```bash git add tests/suite/arena_test.cr diff --git a/docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md b/docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md index f026f59a..9ee995b5 100644 --- a/docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md +++ b/docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md @@ -2,43 +2,54 @@ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. -**Goal:** 落实 `docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md` 的波 R1 三项:定长数组「表示层概念」注记、宽度死条目移除 + 词法面对齐(`1_000` / 宽度后缀退役)、全局初始化修复(定长数组全局 SIGSEGV + 静默丢初始化)。 +**Goal:** 本文落实 `docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md` 的波 R1 三项。第一项为定长数组的「表示层概念」注记。第二项为宽度死条目移除加词法面对齐,其中 `1_000` 与宽度后缀一并退役。第三项为全局初始化修复,覆盖定长数组全局 SIGSEGV 与静默丢初始化两种表现。 -**Architecture:** 三类正交改动——(a) **注释层**(零行为,Task 1);(b) **词法/语法面收窄**(死 token kind 与死分支移除 + 两编译器对齐 + grammar 同步,Task 2/3);(c) **全局初始化修复**(前端把当前被静默丢弃/崩溃的全局初始化降级为运行期 IR 序列、解释器补「标量常量初始化」阶段,Task 4)。 +**Architecture:** 本批改动共三类,彼此正交。 -**Tech Stack:** Core 自举栈 —— Python bootstrap(`bootstrap/corec/`,构建工具链)+ self-hosted 编译器(`src/compiler/`,用户面编译器)+ x86-64 ELF 后端(`src/arch/x86_64/` × `src/format/elf/` × `src/os/linux/`)+ 解释器(`src/compiler/interp.cr`)。 +- (a) **注释层**:零行为,对应 Task 1。 +- (b) **词法/语法面收窄**:死 token kind 与死分支移除,两编译器对齐并同步 grammar,对应 Task 2 与 Task 3。 +- (c) **全局初始化修复**:前端把当前被静默丢弃或崩溃的全局初始化降级为运行期 IR 序列,解释器补「标量常量初始化」阶段,对应 Task 4。 + +**Tech Stack:** Core 自举栈,由四部分组成。 + +- Python bootstrap(`bootstrap/corec/`):构建工具链。 +- self-hosted 编译器(`src/compiler/`):用户面编译器。 +- x86-64 ELF 后端:由 `src/arch/x86_64/`、`src/format/elf/`、`src/os/linux/` 三轴组成。 +- 解释器(`src/compiler/interp.cr`)。 ## Global Constraints -- **jj only**:版本控制一律 `jj`(git 被 hook 机械拦截);提交 = `jj commit -m '...'`。禁止 `git` 命令。 -- **CPU 限速**:所有编译/测试命令必须 `nice -n 19` 前缀(CLAUDE.md 铁律 #6)。 -- **文件永久不允许还原**:任何回滚须用户明确许可(铁律 #3)。 -- **根因修复**:不得用绕过/变通掩盖问题(铁律 #1/#4)。 -- **勿重编号**:`src/compiler/ast.cr` 常量编号空间稳定——删除条目**留墓碑注释**,绝不重排后续编号(先例:`// T_FLOAT_TYPE 91 已删除…`)。 -- **行为零变化面**:Task 1(注释)、Task 2(死代码移除)必须输出等价——判据 = 同命令前后输出逐字节相同。 -- **行为变化面仅限两处**:Task 3(`_` 分隔符与宽度后缀**均由静默改为响亮报错**——用户裁决 2026-09-10:数字字面量不支持 `_`)、Task 4(原先 SIGSEGV / 静默 0 的全局初始化场景)。**其余一切行为不得变化**。 -- **自举守护**:`nice -n 19 python3 tests/selfhost/test_backend_bootstrap.py` 必须 stage 链全 `[PASS]` + `corec2`/`corec3` `cmp` IDENTICAL + N06 = 0。 -- **run 门**:任何 `run`/`build` 输出中 `error[` 计数 = 0(不许「rc=0 就算过」)。 -- **提交粒度**:每任务一次提交,中文提交信息,前缀 `docs:` / `refactor:` / `fix:` / `test:`。 -- **diff 校验命令(Task 1 实现者实测教训,2026-09-10)**:本机 `jj diff` 默认 color-words 输出**新增行不带 `+` 前缀**,任何 `jj diff | grep '^+'` 形式的校验**恒真空通过、零校验力**;且本机 `grep` = ugrep,`'^+ *//'` 这类式样会直接报错(rc=2)。规范式样: +- **jj only**:版本控制一律使用 `jj`,`git` 被 hook 机械拦截;提交命令为 `jj commit -m '...'`。禁止执行 `git` 命令。 +- **CPU 限速**:所有编译与测试命令必须加 `nice -n 19` 前缀(CLAUDE.md 铁律 #6)。 +- **文件永久不允许还原**:任何回滚均须取得用户明确许可(铁律 #3)。 +- **根因修复**:不得用绕过或变通手段掩盖问题(铁律 #1/#4)。 +- **勿重编号**:`src/compiler/ast.cr` 的常量编号空间稳定。删除条目时**留墓碑注释**,绝不重排后续编号(先例:`// T_FLOAT_TYPE 91 已删除…`)。 +- **行为零变化面**:Task 1(注释)与 Task 2(死代码移除)必须输出等价。判据为同命令前后输出逐字节相同。 +- **行为变化面仅限两处**:其一为 Task 3(`_` 分隔符与宽度后缀**均由静默改为响亮报错**,用户裁决 2026-09-10:数字字面量不支持 `_`);其二为 Task 4(原先 SIGSEGV 或静默 0 的全局初始化场景)。**其余一切行为不得变化**。 +- **自举守护**:`nice -n 19 python3 tests/selfhost/test_backend_bootstrap.py` 必须 stage 链全 `[PASS]`,且 `corec2`/`corec3` 的 `cmp` 结果为 IDENTICAL、N06 = 0。 +- **run 门**:任何 `run`/`build` 输出中的 `error[` 计数必须为 0,不允许以「rc=0 就算过」充当判据。 +- **提交粒度**:每任务一次提交,提交信息用中文,前缀取 `docs:` / `refactor:` / `fix:` / `test:` 之一。 +- **diff 校验命令(Task 1 实现者实测教训,2026-09-10)**:本机 `jj diff` 默认 color-words 输出中,**新增行不带 `+` 前缀**,因此任何 `jj diff | grep '^+'` 形式的校验**恒真空通过、零校验力**。本机 `grep` 等于 ugrep,`'^+ *//'` 这类式样会直接报错(rc=2)。规范式样如下: + ```bash jj diff --git | grep '^[+]' | grep -v -e '^[+][+][+]' -e '^[+][[:space:]]*//' -e '^[+][[:space:]]*$' # 期望空 jj diff --git | grep -c '^[-]' # 期望 0(无删除行) ``` - 并按需加**非真空控制组**(故意构造一条应命中的输入验证该命令真会报)。fish 环境另有 noclobber(`>` 覆盖已存在文件会静默失败)——重定向用 `>|` 或先删目标文件。 + + 校验时按需加入**非真空控制组**,即故意构造一条应命中的输入,用于验证该命令确实会报出结果。fish 环境另有 noclobber 行为(`>` 覆盖已存在文件会静默失败),因此重定向须用 `>|`,或先删除目标文件。 --- ## 背景与判据(侦查已定,实现者不需要重新论证) -### 定长数组全局崩溃 — root cause(2026-09-10 全链侦查结论) +### 定长数组全局崩溃的 root cause(2026-09-10 全链侦查结论) -**类别 = 初始化缺失(storage/pointer 未生成),不是尺寸算错。** 证据链: +结论:**类别 = 初始化缺失(storage/pointer 未生成),不是尺寸算错**。证据链如下。 -1. `src/compiler/ir_gen.cr:2349`(`gtype : ., mut = TI_INT;`)+ `:2365`(`new_ir_var(name, gtype)`)—— 全局一律登记为 `TI_INT`,数组类型/长度不进 IR;`:2336`(`global_init_val` 尾部 `return 0`)对数组字面量静默返回 0(初值丢弃)。 -2. `src/os/linux/entry.cr:72-98` `_start` 常量初始化循环只写「`init_val != 0` 的标量」;数组 init_val = 0 → 不发射。全局槽 = BSS 零。 -3. `src/arch/x86_64/instr.cr:428-438` `e2_load_var` global 分支 = `lea r11,[rip+slot]; mov reg,[r11]`(取槽**内容**当基指针)→ 槽为 0 时后续 `[r10+idx*8]` 解引用 NULL → SIGSEGV。 -4. `src/compiler/interp.cr:67-93` `ir_interpret()` 只跑 main 的 node 区间,**无任何全局初始化阶段**(全文零引用 `g_ir_globals`)→ 解释器同因崩溃;且**可变标量全局也丢初始化**(`x : int, mut = 5` 读回 0)。 +1. `src/compiler/ir_gen.cr:2349`(`gtype : ., mut = TI_INT;`)与 `:2365`(`new_ir_var(name, gtype)`)把全局一律登记为 `TI_INT`,数组类型与长度均不进 IR;`:2336`(`global_init_val` 尾部 `return 0`)对数组字面量静默返回 0,初值就此丢弃。 +2. `src/os/linux/entry.cr:72-98` 的 `_start` 常量初始化循环只写「`init_val != 0` 的标量」;数组的 init_val 等于 0,因此不发射,全局槽保持 BSS 零。 +3. `src/arch/x86_64/instr.cr:428-438` 的 `e2_load_var` global 分支为 `lea r11,[rip+slot]; mov reg,[r11]`,即取槽**内容**当基指针;槽为 0 时,后续 `[r10+idx*8]` 解引用 NULL,导致 SIGSEGV。 +4. `src/compiler/interp.cr:67-93` 的 `ir_interpret()` 只跑 main 的 node 区间,**无任何全局初始化阶段**(全文零引用 `g_ir_globals`),解释器因此同样崩溃;此外,**可变标量全局也丢初始化**(`x : int, mut = 5` 读回 0)。 ### 修复前行为基线(实现者须复现确认,作为 TDD 的「红」) @@ -61,16 +72,17 @@ | `0x1_0` | 16 ✓(十六进制路径早已吃 `_`) | 16 ✓ | | `10f32` / `1.5f32` | 静默:后缀消费 + dex 路由 hack(`suffix == "f32"` → 走 T_DEX),宽度值从不落地(`W_F32` 分支不可达) | 后缀并入词素(`INT_LIT '10f32'`)→ parser `int()` 抛 `ValueError` | -**裁决(2026-09-10 用户拍板,本批落实)**:数字字面量**不支持 `_` 分隔符**——两编译器**统一响亮报错**(现状双向皆错:self-hosted 静默 0、bootstrap 静默接受;grammar 原注记「以实现为准取不支持」方向正确但两实现均未落实);**宽度后缀(`f32`/`f64`/`i8..u8`…)退出语言面**,同样**响亮报错**(grammar 早已注明它是「apx CPU 位宽标注」= 机器形状,且全仓 `src/`+`tests/` 零使用)。 +**裁决(2026-09-10 用户拍板,本批落实)**:数字字面量**不支持 `_` 分隔符**,两编译器**统一响亮报错**。现状双向皆错:self-hosted 静默 0,bootstrap 静默接受;grammar 原注记「以实现为准取不支持」方向正确,但两实现均未落实。**宽度后缀(`f32`/`f64`/`i8..u8`…)退出语言面**,同样**响亮报错**;grammar 早已注明它是「apx CPU 位宽标注」即机器形状,且全仓 `src/` 与 `tests/` 零使用。 -全仓数字下划线使用点(精确 grep:`(^|[^A-Za-z0-9_.])[0-9]+_[0-9]+`)**仅一处**:`tests/bootstrap/test_pipeline.py:329` `check_integer_literals`(bootstrap lexer 测试断言 `1_000`→1000)——随裁决改为断言报错。`src/` 与 `tests/` 其余为零,(自举构建不依赖该形态)。 +按精确 grep 式 `(^|[^A-Za-z0-9_.])[0-9]+_[0-9]+` 检索,全仓数字下划线的使用点**仅一处**:`tests/bootstrap/test_pipeline.py:329` 的 `check_integer_literals`(bootstrap lexer 测试断言 `1_000`→1000)。该断言随裁决改为断言报错。`src/` 与 `tests/` 其余位置为零,自举构建不依赖该形态。 ### 关键既有机制(Task 4 复用,不新造) -- `IR_ALLOC_ARRAY(8)`:ELF 侧 `src/arch/x86_64/instr.cr:939-957` → 调运行期 `alloc`;解释器侧 `src/compiler/interp.cr:176-186` → `alloc` + 显式清零。运行期 `alloc`(`src/runtime/rt.s:72-98`)**自带 `rep stosb` 清零** → 两路径语义一致(分配即零初始化)。 -- `IR_STORE(9)`:`interp.cr:187` —— `s1`(目标 var) ← `s2`(值 var);数组字面量 lowering = `src/compiler/ir_gen.cr:2107-2127`(`IR_ALLOC_ARRAY` + 逐元素 `IR_STORE_INDEX` + `irv_set_type(v, alloc_type(TYP_ARRAY, elem_ti, n))`)。 -- 全局 var 注册 = `ir_gen_globals()`(`ir_gen.cr:2390`),调用点 `src/compiler/main.cr:408`(**先于**逐函数生成 `main.cr:480 ir_gen_func(fi)` → 序言注入时 `g_ir_globals` 已就绪)。 -- 手工验证过的等价形态(可作 oracle):把初始化写进 main 体内——`fn main()->int{ g = [10,20,30,40]; return g[2]; }` → 现网 rc=30(两路径均正常)。本任务 = 把这段序列**自动化地**搬到序言。 +- `IR_ALLOC_ARRAY(8)`:ELF 侧位于 `src/arch/x86_64/instr.cr:939-957`,实现为调运行期 `alloc`;解释器侧位于 `src/compiler/interp.cr:176-186`,实现为 `alloc` 加显式清零。 +- 运行期 `alloc`(`src/runtime/rt.s:72-98`)**自带 `rep stosb` 清零**,因此两路径语义一致(分配即零初始化)。 +- `IR_STORE(9)`:定义在 `interp.cr:187`,语义为 `s1`(目标 var)← `s2`(值 var)。数组字面量的 lowering 位于 `src/compiler/ir_gen.cr:2107-2127`,由 `IR_ALLOC_ARRAY`、逐元素 `IR_STORE_INDEX` 与 `irv_set_type(v, alloc_type(TYP_ARRAY, elem_ti, n))` 组成。 +- 全局 var 注册由 `ir_gen_globals()`(`ir_gen.cr:2390`)承担,调用点在 `src/compiler/main.cr:408`,**先于**逐函数生成(`main.cr:480 ir_gen_func(fi)`);因此序言注入时 `g_ir_globals` 已就绪。 +- 手工验证过的等价形态可作 oracle:把初始化写进 main 体内,即 `fn main()->int{ g = [10,20,30,40]; return g[2]; }`,现网 rc=30,两路径均正常。本任务就是把这段序列**自动化地**搬到序言。 --- @@ -82,8 +94,8 @@ - Modify: `src/compiler/parser.cr:44-58`(`parse_type` 的 `[T; N]` / `[T]` 分支) **Interfaces:** -- Consumes: 无(纯注释) -- Produces: 无(零行为);注记短语供后续 R2(接口化)检索:关键字 `表示层概念` +- Consumes:无(纯注释) +- Produces:无(零行为)。注记短语供后续 R2(接口化)检索,关键字为 `表示层概念` - [x] **Step 1: 捕获基线输出** @@ -98,7 +110,7 @@ Expected: `check` 输出 `ok`(rc=0);`build` rc=0;`/tmp/r1t1_bin_before` - [x] **Step 2: 逐处贴入注记** -在下列每个位置各贴一段(紧邻被标注代码,同一文件内可共用一次完整注记 + 其余位置一行式引用): +注记贴入下列每个位置。贴入时紧邻被标注代码;同一文件内可共用一次完整注记,其余位置用一行式引用: ```core // 表示层概念(2026-09-10 语言面收窄裁决 §1):`[T; N]` 的类型构造器身份已退役—— @@ -124,7 +136,7 @@ nice -n 19 ./build/corec check /tmp/r1t1_sample.cr > /tmp/r1t1_check_after.txt 2 nice -n 19 ./build/corec cir /tmp/r1t1_sample.cr > /tmp/r1t1_cir_after.txt 2>&1 diff /tmp/r1t1_check_before.txt /tmp/r1t1_check_after.txt && diff /tmp/r1t1_cir_before.txt /tmp/r1t1_cir_after.txt && echo IDENTICAL ``` -Expected: `IDENTICAL`(`build`/`bin` 不必重跑——注释不进二进制;如需,比对 `cmp /tmp/r1t1_bin_before <新产物>`)。 +Expected: `IDENTICAL`。`build`/`bin` 不必重跑,因为注释不进二进制;如需比对,执行 `cmp /tmp/r1t1_bin_before <新产物>`。 - [x] **Step 5: 提交** @@ -142,15 +154,15 @@ jj commit -m 'docs: 语言面收窄 R1 Task 1——定长数组「表示层概 - Modify: `src/compiler/parser.cr:392-403`、`:406-411`、`:897-908`(唯一引用面 = 死分支) **Interfaces:** -- Consumes: 无 -- Produces: 无(lexer 从不发射这些 token kind——`parser.cr` 的 `kn == T_INT_I8 …` 链与 `tok_k(t) >= T_INT_I8 && tok_k(t) <= T_INT_U64` 判定**永不可达**;`W_*` 仅被这些链引用) +- Consumes:无 +- Produces:无(lexer 从不发射这些 token kind,`parser.cr` 的 `kn == T_INT_I8 …` 链与 `tok_k(t) >= T_INT_I8 && tok_k(t) <= T_INT_U64` 判定**永不可达**;`W_*` 仅被这些链引用) - [x] **Step 1: 引用面核实(必须只有 parser.cr 死分支)** ```bash nice -n 19 grep -rn "T_INT_I8\|T_INT_I16\|T_INT_I32\|T_INT_I64\|T_INT_U8\|T_INT_U16\|T_INT_U32\|T_INT_U64\|T_FLOAT_F32\|T_FLOAT_F64\|W_I8\|W_I16\|W_I32\|W_I64\|W_U8\|W_U16\|W_U32\|W_U64\|W_F32\|W_F64" src/ --include='*.cr' | grep -v '^src/compiler/ast.cr' ``` -Expected: 命中仅 `src/compiler/parser.cr` 第 392-411 / 897-908 行(若出现其它文件/行号 → **停下并上报**,不得继续)。 +Expected: 命中仅 `src/compiler/parser.cr` 第 392-411 / 897-908 行。若出现其它文件或行号,则**停下并上报**,不得继续。 - [x] **Step 2: parser.cr 死分支移除** @@ -202,7 +214,7 @@ Expected: 命中仅 `src/compiler/parser.cr` 第 392-411 / 897-908 行(若出 nice -n 19 grep -rn "T_INT_I8\|T_INT_I16\|T_INT_I32\|T_INT_I64\|T_INT_U8\|T_INT_U16\|T_INT_U32\|T_INT_U64\|T_FLOAT_F32\|T_FLOAT_F64\|W_I8\|W_I16\|W_I32\|W_I64\|W_U8\|W_U16\|W_U32\|W_U64\|W_F32\|W_F64" src/ --include='*.cr' nice -n 19 grep -n "T_INT_I64\|W_I64" bootstrap/ -r ``` -Expected: **过滤注释行后**零命中(**代码引用面**归零)——注意墓碑注释正文本身含这些标识符字样,故原始 grep 不会全空(Task 2 实现者实测指出此点,判据按「代码引用零命中」执行):`grep ... | grep -v '^[^:]*:[0-9]*: *//'` 或等价过滤后 rc=1/无输出。 +Expected: **过滤注释行后**零命中(**代码引用面**归零)。注意墓碑注释正文本身含这些标识符字样,故原始 grep 不会全空(Task 2 实现者实测指出此点,判据按「代码引用零命中」执行):`grep ... | grep -v '^[^:]*:[0-9]*: *//'` 或等价过滤后 rc=1/无输出。 - [x] **Step 5: 重建 + 冒烟 + 回归** @@ -230,8 +242,8 @@ jj commit -m 'refactor: 语言面收窄 R1 Task 2——宽度死条目移除(a - Create: `tests/selfhost/test_lexer_parity.py` **Interfaces:** -- Consumes: Task 2 已删掉宽度 token kind(本任务不再产生它们) -- Produces: 词法契约——数字字面量**不接受** `_` 分隔符、**不接受**任何字母后缀,二者均**响亮报错**;合法形态(十进制/小数/`0x`/`0o`/`0b`/负号)行为不变 +- Consumes:Task 2 已删掉宽度 token kind,本任务不再产生它们 +- Produces:词法契约——数字字面量**不接受** `_` 分隔符、**不接受**任何字母后缀,二者均**响亮报错**;合法形态(十进制/小数/`0x`/`0o`/`0b`/负号)行为不变 - [x] **Step 1: 写失败测试 `tests/selfhost/test_lexer_parity.py`** @@ -286,11 +298,11 @@ if __name__ == '__main__': ```bash nice -n 19 python3 tests/selfhost/test_lexer_parity.py ``` -Expected: 两条 FAIL + 一条对照 PASS —— `test_bootstrap_rejects`(bootstrap 接受 `1_000`)/ `test_selfhost_rejects`(无我们的诊断文本,只有既有 TF01)/ `test_legal_forms_unchanged`(PASS,对照组)。记录实际输出到报告。 +Expected: 两条 FAIL + 一条对照 PASS。`test_bootstrap_rejects` 因 bootstrap 接受 `1_000` 而失败;`test_selfhost_rejects` 因无我们的诊断文本、只有既有 TF01 而失败;`test_legal_forms_unchanged` 作对照组 PASS。记录实际输出到报告。 - [x] **Step 3: self-hosted lexer 改造(`src/compiler/lexer.cr`)** -(a) 十进制数码循环(`:421-423`)与小数部分循环(`:445`)**保持只吃 digit**(不加 `_`);hex/oct/bin 三条循环(`:428-430`)各**删除** `|| hc == 95`、`|| oc == 95`、`|| bc == 95`(不再接受 `_`)。 +(a) 十进制数码循环(`:421-423`)与小数部分循环(`:445`)**保持只吃 digit**,不加 `_`。hex/oct/bin 三条循环(`:428-430`)各**删除** `|| hc == 95`、`|| oc == 95`、`|| bc == 95`,不再接受 `_`。 (b) 后缀段落(`:452-468`)整段替换为: @@ -409,12 +421,12 @@ jj commit -m 'fix: 语言面收窄 R1 Task 3——数字词法收窄(_ 分隔 - Create: `tests/selfhost/test_global_init.py` **Interfaces:** -- Consumes: `g_global_lets`(`{a=name_idx, b=type_node, c=value_node, int_val=apx 位模式|null}`);`g_ir_globals`(每 24B:`+0 name_idx`、`+8 ir_var`、`+16 init_val`,已由 `main.cr:408 ir_gen_globals()` 填充);`IR_ALLOC_ARRAY(8)`、`IR_STORE(9)`、`IR_STORE_INDEX`;`gen_expr(node)`、`new_ir_var`、`irv_set_type`、`emit` -- Produces: 全局初始化语义——(1) 聚合全局(`[T;N]`/`[T]`)无论有无初值都在运行期分配 + 写槽(存储持久,`alloc` 语义);(2) 非常量初值的全局在运行期求值并写槽;(3) 编译期标量常量初始化保持既有通道(ELF `_start` 常量循环),解释器补同语义阶段 +- Consumes:`g_global_lets`(`{a=name_idx, b=type_node, c=value_node, int_val=apx 位模式|null}`);`g_ir_globals`(每 24B:`+0 name_idx`、`+8 ir_var`、`+16 init_val`,已由 `main.cr:408 ir_gen_globals()` 填充);`IR_ALLOC_ARRAY(8)`、`IR_STORE(9)`、`IR_STORE_INDEX`;`gen_expr(node)`、`new_ir_var`、`irv_set_type`、`emit` +- Produces:全局初始化语义,含三点:(1) 聚合全局(`[T;N]`/`[T]`)无论有无初值都在运行期分配并写槽,存储持久,遵循 `alloc` 语义;(2) 非常量初值的全局在运行期求值并写槽;(3) 编译期标量常量初始化保持既有通道(ELF `_start` 常量循环),解释器补同语义阶段。 - [x] **Step 1: 写失败测试 `tests/selfhost/test_global_init.py`** -覆盖下表(解释器 `run` 与 ELF `build --static` + 运行二进制**双路径**;ELF 调用模式照抄 `tests/selfhost/test_native_memory.py:110-130`): +覆盖下表,解释器 `run` 与 ELF `build --static` 加运行二进制**双路径**均在内;ELF 调用模式照抄 `tests/selfhost/test_native_memory.py:110-130`: | # | 源 | 期望 rc | |---|---|---| @@ -427,11 +439,11 @@ jj commit -m 'fix: 语言面收窄 R1 Task 3——数字词法收窄(_ 分隔 | 7 | `g : [int;2] = [3,4];\nfn get()->int{return g[1];}\nfn main()->int{return get();}`(跨函数访问) | 4 | | 8 | `a : [int;2] = [8,9];\nb : [int;2] = a;\nfn main()->int{return a[0]+b[1];}` | 17 | -每例两条断言:**无 `error[`** + rc 精确值。 +每例两条断言:**无 `error[`**,且 rc 为精确值。 - [x] **Step 2: 运行确认「红」(两路径)** -**前置(必须先做)——清增量缓存**:`inject_global_inits` 的注入点在 `ir_gen_func` 内(`main.cr:480` 调用),而**函数命中 cir 缓存时根本不走 `ir_gen_func`**(`main.cr:483` 的 cache-hit 分支)——叠加已知缺陷 TODO #2026-09-10-1(缓存键不含编译器身份,跨重建不失效),**旧缓存会让本次修复看起来"没生效"**。故每次判据前: +**前置步骤(必须先做)为清增量缓存。** `inject_global_inits` 的注入点在 `ir_gen_func` 内(`main.cr:480` 调用),而**函数命中 cir 缓存时根本不走 `ir_gen_func`**(`main.cr:483` 的 cache-hit 分支)。叠加已知缺陷 TODO #2026-09-10-1(缓存键不含编译器身份,跨重建不失效),**旧缓存会让本次修复看起来「没生效」**。故每次判据前执行: ```bash nice -n 19 ./build/corec clean-cache # 若子命令不可用:rm -rf .core/cache(先 ls 确认路径) @@ -454,7 +466,7 @@ sha256sum /tmp/r1t4_base_bin | tee /tmp/r1t4_base_sha - [x] **Step 4: 前端修复(`src/compiler/ir_gen.cr`)** -新增(建议置于 `global_init_val` 之后): +新增下列三个函数,建议置于 `global_init_val` 之后: ```core // 文件级 let 是否需要「运行期初始化」(2026-09-10 语言面收窄 §1.3 / R1 ②)。 @@ -571,7 +583,7 @@ cmp /tmp/r1t4_base_bin /tmp/r1t4_head_bin && echo BYTE-IDENTICAL nice -n 19 python3 tests/selfhost/test_compile.py nice -n 19 python3 tests/bootstrap/test_pipeline.py ``` -Expected: `BYTE-IDENTICAL`(无运行期初始化全局的程序 ELF 产物逐字节不变)。 +Expected: `BYTE-IDENTICAL`,即无运行期初始化全局的程序 ELF 产物逐字节不变。 - [x] **Step 7: 提交** @@ -641,11 +653,11 @@ nice -n 19 ./build/corec run 'fn main()->int{return 42;}' # rc=42 - [x] **Step 5: 测试清单陈旧路径核对(`tests/selfhost/test_compile.py:20-38`)** -`concat_sources()` 的 `if os.path.exists(path)` 会**静默跳过**缺失文件——现清单含三条已搬迁路径(`src/compiler/backend/x86_64.cr`、`src/compiler/backend/x86_64/instr.cr`、`src/compiler/backend/resolve.cr` 均已不存在;波 1 三轴搬迁后为 `src/arch/x86_64/*.cr` + `src/format/elf/*.cr` + `src/os/linux/*.cr`)。 +`concat_sources()` 的 `if os.path.exists(path)` 会**静默跳过**缺失文件。现清单含三条已搬迁路径(`src/compiler/backend/x86_64.cr`、`src/compiler/backend/x86_64/instr.cr`、`src/compiler/backend/resolve.cr` 均已不存在;波 1 三轴搬迁后为 `src/arch/x86_64/*.cr` + `src/format/elf/*.cr` + `src/os/linux/*.cr`)。 -处理:把条目更新为三轴现状路径(对照 `build_selfhost_native.py` 的 `corearch_files`/`arch_x86_64_files`/`format_elf_files`/`os_linux_files`),并把 `exists` 静默跳过改为**存在性断言**(`build_selfhost_native.py:144-152 guard_manifest` 同款)。复跑 `test_compile.py` 必须仍全绿。 +处理方式:把条目更新为三轴现状路径(对照 `build_selfhost_native.py` 的 `corearch_files`/`arch_x86_64_files`/`format_elf_files`/`os_linux_files`),并把 `exists` 静默跳过改为**存在性断言**(`build_selfhost_native.py:144-152 guard_manifest` 同款)。复跑 `test_compile.py` 必须仍全绿。 -若补入后测试失败 → 说明原清单是刻意裁剪:改为在原处加**显式注释**说明裁剪意图(保 `exists` 语义)+ 在 `TODO.md` 登记本次发现——**不得**用还原/静默跳过掩盖。 +若补入后测试失败,则说明原清单是刻意裁剪:改为在原处加**显式注释**说明裁剪意图(保 `exists` 语义),并在 `TODO.md` 登记本次发现。**不得**用还原/静默跳过掩盖。 - [x] **Step 6: 提交** @@ -657,7 +669,7 @@ jj commit -m 'docs: 语言面收窄 R1 收官——全量回归 + 自举守护 ## 自检记录(写完计划后复核) -- **spec 覆盖**:§1(定长裁决)→ Task 1(注记)+ Task 4(全局路径修复);§1.3「checker 落实时点 = R2」→ 明确不在本批;§2(宽度三项)→ Task 2(死条目)+ Task 3(后缀/`1_000`);§3 波 R1 判据 → Task 5。**无遗漏,无越界**(表示提示机制留 R3、checker 类型判定重构留 R2)。 +- **spec 覆盖**:§1(定长裁决)对应 Task 1(注记)与 Task 4(全局路径修复);§1.3「checker 落实时点 = R2」明确不在本批;§2(宽度三项)对应 Task 2(死条目)与 Task 3(后缀/`1_000`);§3 波 R1 判据对应 Task 5。**无遗漏,无越界**(表示提示机制留 R3、checker 类型判定重构留 R2)。 - **占位符扫描**:无 TBD/TODO;所有代码块为可落地的具体代码;所有命令带期望输出。 - **类型/命名一致性**:`global_needs_runtime_init` / `global_var_of` / `inject_global_inits` 三名在 Task 4 内自洽;`IR_ALLOC_ARRAY`=8、`IR_STORE`=9 与 `interp.cr:176-187` 一致;`emit(IR_STORE, d, s1, s2, …)` 参数序与 `interp.cr:187` 一致(`s1` 目标、`s2` 值)。 -- **风险注记**:Task 4 的序言注入只对「需要运行期初始化」的全局生效 → 其余程序 IR 不变(Step 3/6 的 byte-identical 判据即此保证);注入点选择 main 序言的理由(无新 IR 函数/无 .ccr 段变更/无 `_start` 字节扰动)已写明,若未来出现非 main 入口或库形态,需迁移到独立 init 区(已记入 TODO)。 +- **风险注记**:Task 4 的序言注入只对「需要运行期初始化」的全局生效,其余程序 IR 不变(Step 3/6 的 byte-identical 判据即此保证);注入点选择 main 序言的理由(无新 IR 函数、无 .ccr 段变更、无 `_start` 字节扰动)已写明,若未来出现非 main 入口或库形态,需迁移到独立 init 区(已记入 TODO)。 diff --git a/docs/superpowers/plans/2026-09-10-r2-p0-type-engine.md b/docs/superpowers/plans/2026-09-10-r2-p0-type-engine.md index 9ca99061..15ed543a 100644 --- a/docs/superpowers/plans/2026-09-10-r2-p0-type-engine.md +++ b/docs/superpowers/plans/2026-09-10-r2-p0-type-engine.md @@ -1,35 +1,47 @@ # R2 P0(建层)实施计划:类型项表 + 语义包含引擎 + 判定用例表 -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. +> **受众**:执行本计划的 agentic worker。**必需子技能**:`superpowers:subagent-driven-development`(推荐)或 `superpowers:executing-plans`,按任务逐项实施。进度以复选框(`- [ ]`)跟踪。 -**Goal:** 为 R2 建「类型项层 + 语义包含引擎」的地基:集合语义的类型项 DAG 表、NNF/DNF 规范化、包含/等价/不相交/可空/反例判定 API(三态 + 预算守卫)、数据驱动判定用例表与 `corec selftest-types` 自测通道——**checker 零改动、产物零变化**。 +**目标**:为 R2 建立「类型项层 + 语义包含引擎」的地基,内容包括集合语义的类型项 DAG 表、NNF/DNF 规范化、包含/等价/不相交/可空/反例判定 API(三态 + 预算守卫)、数据驱动判定用例表,以及 `corec selftest-types` 自测通道(**checker 零改动、产物零变化**)。 -**Architecture:** 三个新文件分工:`type_terms.cr`(类型项表 + 构造/去重 + 规范化)、`type_engine.cr`(判定 API + 原子互斥公理 + μ memo + 预算守卫)、`type_selftest.cr`(用例表 + 自测驱动)。引擎自带原子类 id(`AK_*`)与 `g_types` 行解耦,natives 用 1:1 映射,结构/命名原子挂 `g_types` 行(`-1` = 类级)。**不改 checker / ir_gen / 后端 / 解释器**——P0 不改判据行为,只建能力。 +**架构**:本计划新增三个文件,其分工如下: -**Tech Stack:** Core 自举栈(self-hosted 编译器 `src/compiler/`);扁平字节缓冲表(`string` + `w64/r64` + `grow_*` + `ESZ_*/OFF_*` 常量,先例 `g_types`/`g_ifaces`);CLI 通道(`cli_cmd` + `corec_main` 分派);Python 测试包装(`tests/selfhost/test_*.py` 风格,subprocess 调 `./build/corec`)。 +- `type_terms.cr` 负责类型项表、构造与去重,以及规范化。 +- `type_engine.cr` 负责判定 API、原子互斥公理、μ memo 与预算守卫。 +- `type_selftest.cr` 负责用例表与自测驱动。 -**Spec:** `docs/superpowers/specs/2026-09-10-type-interface-unification-design.md`(§0 裁决 / §1 语义基座 / §3 类型项层与引擎 / §4 步 1 建层 / §9 P0)。 +引擎自带原子类 id(`AK_*`),与 `g_types` 行解耦;natives 采用 1:1 映射;结构原子与命名原子挂 `g_types` 行(`-1` 表示类级)。**不改 checker / ir_gen / 后端 / 解释器**:P0 不改判据行为,只建能力。 -## Global Constraints +**技术栈**:本计划涉及四个技术面,列举如下: -- **jj only**:版本控制一律 `jj`(git 被 hook 机械拦截);**提交必须路径限定**(多 agent 共用工作副本): +- Core 自举栈,即 self-hosted 编译器 `src/compiler/`。 +- 扁平字节缓冲表,由 `string` 加 `w64/r64` 与 `grow_*` 构成,常量族为 `ESZ_*/OFF_*`;先例为 `g_types` 与 `g_ifaces`。 +- CLI 通道,由 `cli_cmd` 加 `corec_main` 分派。 +- Python 测试包装,沿用 `tests/selfhost/test_*.py` 风格,经 subprocess 调用 `./build/corec`。 + +**设计 spec**:`docs/superpowers/specs/2026-09-10-type-interface-unification-design.md`(§0 裁决、§1 语义基座、§3 类型项层与引擎、§4 步 1 建层、§9 P0)。 + +## 全局约束 + +- **仅用 `jj`**:版本控制一律使用 `jj`,`git` 由 hook 机械拦截。 +- **提交必须路径限定**(多 agent 共用工作副本): `jj commit <本次改动的精确文件...> -m '<中文,前缀 feat:/docs:/test:>'` -- **CPU 限速**:所有编译/测试命令必须 `nice -n 19` 前缀(铁律 #6)。 -- **文件永久不允许还原**;不得绕过/变通;根因修复。 -- **P0 零行为改动**:`checker.cr` / `ir_gen.cr` / `interp.cr` / 后端与内核文件**一行不动**;现有程序的编译产物 **byte-identical**(判据见 Task 5)。 -- **diff 校验规范式样**(本机 `jj diff` 默认 color-words 无 `+` 前缀,`grep '^+'` 恒真空通过;grep 实为 ugrep): +- **CPU 限速**:所有编译与测试命令必须加 `nice -n 19` 前缀(铁律 #6)。 +- **文件永久不允许还原**。不得绕过问题,不得变通,一律做根因修复。 +- **P0 零行为改动**:`checker.cr`、`ir_gen.cr`、`interp.cr` 与后端、内核文件**一行不动**;现有程序的编译产物必须 **byte-identical**(判据见 Task 5)。 +- **diff 校验规范式样**:本机 `jj diff` 默认使用 color-words,输出无 `+` 前缀,因此 `grep '^+'` 恒真空通过;本机 `grep` 实为 ugrep。式样如下: ```bash jj diff --git | grep '^[+]' | grep -v -e '^[+][+][+]' # 逐行核新增 jj diff --git | grep -c '^[-]' # 期望 0(除计划性替换) ``` -- 环境陷阱:noclobber(`>` 覆盖已存在文件失败 → 用 `>|` 或先删);变量展开不分词。 -- **新文件必须注册三处**(否则构建静默缺件): - 1. `src/compiler/_import.cr`(project-mode 解析链) - 2. `build_selfhost_native.py` 的 **corec 清单**(`corec_files`,顺序 = 行为定义面:置于 `src/compiler/checker.cr` 之后、`ir_gen.cr` 之前) - 3. `tests/selfhost/test_compile.py` 的 `concat_sources()` 清单(同位置) - (`corelsp` / `corearch` 清单 P0 **不加**:引擎尚无消费者。) -- **判据铁律**:`corec selftest-types` 全 PASS + 末行计数断言 + 无 `FAIL` 行;全回归绿;自举 `corec2/corec3` `cmp` IDENTICAL + N06=0。 -- **附加验证纪律(Task 1 实证教训,2026-09-10)**:白盒/压力验证**必须限时**——禁止 `sleep` 式长等待(用短超时或直接看日志);同一缺陷最多迭代 **2 轮**(≥3 轮说明假设错了,改为最小化失败用例 + BLOCKED 上报);**计划代码不是免检的**(本次 `h - (h/cap)*cap` 负哈希取模越界即为计划缺陷,由压力测试抓出)。 +- 环境陷阱:noclobber 下用 `>` 覆盖已存在文件会失败,须改用 `>|` 或先删;变量展开不分词。 +- **新文件必须注册三处**,否则构建静默缺件: + 1. `src/compiler/_import.cr`,即 project-mode 解析链。 + 2. `build_selfhost_native.py` 的 **corec 清单**(`corec_files`)。其顺序即行为定义面:置于 `src/compiler/checker.cr` 之后、`ir_gen.cr` 之前。 + 3. `tests/selfhost/test_compile.py` 的 `concat_sources()` 清单,位置同上。 + (`corelsp` 与 `corearch` 清单 P0 **不加**:引擎尚无消费者。) +- **判据铁律**:`corec selftest-types` 全 PASS,末行有计数断言,且无 `FAIL` 行;全回归绿;自举 `corec2/corec3` 的 `cmp` 结果为 IDENTICAL,且 N06=0。 +- **附加验证纪律(Task 1 实证教训,2026-09-10)**:白盒与压力验证**必须限时**,禁止 `sleep` 式长等待,改用短超时或直接看日志。同一缺陷最多迭代 **2 轮**;达到 3 轮以上说明假设错了,须改为最小化失败用例并作 BLOCKED 上报。**计划代码不是免检的**:本次 `h - (h/cap)*cap` 的负哈希取模越界即为计划缺陷,由压力测试发现。 --- @@ -52,14 +64,14 @@ ## Task 1: 类型项表 + 构造 API + 自测通道骨架 -**Files:** -- Create: `src/compiler/type_terms.cr` -- Create: `src/compiler/type_selftest.cr` -- Modify: `src/compiler/globals.cr`(表全局声明)、`src/compiler/main.cr`(CLI)、`src/compiler/_import.cr`、`build_selfhost_native.py`、`tests/selfhost/test_compile.py` - (**不含 `dyn_arr.cr`**——扩容函数放 `type_terms.cr` 自持,理由见「文件结构」表注) -- Create: `tests/selfhost/test_type_engine.py` +**涉及文件:** +- 新建 `src/compiler/type_terms.cr` +- 新建 `src/compiler/type_selftest.cr` +- 修改 `src/compiler/globals.cr`(表全局声明)、`src/compiler/main.cr`(CLI)、`src/compiler/_import.cr`、`build_selfhost_native.py`、`tests/selfhost/test_compile.py` + (**不含 `dyn_arr.cr`**:扩容函数放在 `type_terms.cr` 自持,理由见「文件结构」表注) +- 新建 `tests/selfhost/test_type_engine.py` -**Interfaces(本任务产出,后续任务依赖,签名不可改):** +**接口(本任务产出,后续任务依赖,签名不可改):** ``` // —— 标签常量(type_terms.cr)—— @@ -144,11 +156,11 @@ if __name__ == "__main__": ```bash nice -n 19 python3 tests/selfhost/test_type_engine.py ``` -Expected: FAIL —— `selftest-types` 未注册(`corec` 打印未知子命令/无 `N/M ... passed` 行)。 +预期:FAIL,因为 `selftest-types` 未注册(`corec` 打印未知子命令,或无 `N/M ... passed` 行)。 - [ ] **Step 3: 表全局声明(`src/compiler/globals.cr`)** -追加(与既有表声明同风格): +追加内容与既有表声明同风格: ```core // R2 P0 类型项引擎:类型项 DAG 表 + 结构哈希索引 + 判定 memo + 预算守卫 @@ -164,9 +176,9 @@ g_ty_uncovered : int, mut; // 未覆盖面命中位(如 AK_NAMED 具 - [ ] **Step 4: 扩容函数(**落在 `src/compiler/type_terms.cr`,不放 `dyn_arr.cr`**)** -> **位置修正(Task 1 实测 D5)**:照 `grow_types` 先例放 `dyn_arr.cr` 会让 **corearch 解析期硬失败**(`Undefined name: ESZ_TYPE_TERM / tt_reindex`)——`dyn_arr.cr` 是双 concat 共享面。引擎自持扩容与常量(Step 5 代码块内),共享面零改动。 +> **位置修正(Task 1 实测 D5)**:若照 `grow_types` 先例放进 `dyn_arr.cr`,会让 **corearch 解析期硬失败**(`Undefined name: ESZ_TYPE_TERM / tt_reindex`),因为 `dyn_arr.cr` 是双 concat 共享面。引擎自持扩容与常量,代码见 Step 5 代码块;共享面零改动。 -追加(照 `grow_types` 先例): +追加内容照 `grow_types` 先例: ```core fn grow_type_terms(needed: int) { @@ -198,9 +210,9 @@ fn grow_tt_index(needed: int) { - [ ] **Step 5: 类型项表 + 构造 API(`src/compiler/type_terms.cr`)** > **Task 1 落地确认的三条实现约定(Task 2/3/4 必须沿用,勿回退)**: -> ① **键 = 五字段全比,哈希不入键**(哈希只负责槽位定位)——「存储哈希 == 重算哈希」只在 i64 回绕下成立,而 bootstrap 解释器为任意精度整数 ⇒ 该等式恒假、引擎静默退化为「只插不查」(Task 1 实证)。 -> ② **惰性 memo 用零初值 + ready 位**(`g_tt_top_ok`/`g_tt_nil_ok`)——全局 `= -1` 初值被 bootstrap 后端降级为 0(`bootstrap/corec/frontend/ir_gen.py:68-74`:`constant_value` 只对 `Literal` 赋值 → 其余 `.quad 0`;见 TODO #2026-09-10-10)。 -> ③ **本语言无位异或算子** → 哈希用 FNV-1 加法折叠(照 `dyn_arr.cr` 的 `hash_bytes` 家族),不用 FNV-1a 的 `^`。 +> ① **键 = 五字段全比,哈希不入键**,哈希只负责槽位定位。理由:「存储哈希 == 重算哈希」只在 i64 回绕下成立,而 bootstrap 解释器为任意精度整数,因此该等式恒假,引擎静默退化为「只插不查」(Task 1 实证)。 +> ② **惰性 memo 用零初值加 ready 位**(`g_tt_top_ok` 与 `g_tt_nil_ok`)。理由:全局 `= -1` 初值被 bootstrap 后端降级为 0(`bootstrap/corec/frontend/ir_gen.py:68-74` 中 `constant_value` 只对 `Literal` 赋值,其余写 `.quad 0`;见 TODO #2026-09-10-10)。 +> ③ **本语言无位异或算子**,因此哈希采用 FNV-1 加法折叠(照 `dyn_arr.cr` 的 `hash_bytes` 家族),不用 FNV-1a 的 `^`。 ```core // R2 P0:类型项表(集合语义的类型项 DAG) @@ -399,13 +411,13 @@ fn ty_sub(a: int, b: int) -> int { // 桩:Task 3 替换为真判定(三态 - [ ] **Step 8: CLI 注册(`src/compiler/main.cr`)** -在 `corec_main()` 的子命令注册段(`cli_cmd("clean-cache", ...)` 之后)追加: +在 `corec_main()` 的子命令注册段中追加,位置在 `cli_cmd("clean-cache", ...)` 之后: ```core cli_cmd("selftest-types", "Run type-engine self tests (R2 P0)"); ``` -并在命令分派区(与 `cli_eq(cmd, "run")` 等同级)追加: +并在命令分派区追加,位置与 `cli_eq(cmd, "run")` 等同级: ```core if cli_eq(cmd, "selftest-types") { return type_selftest_run(); } @@ -413,9 +425,9 @@ fn ty_sub(a: int, b: int) -> int { // 桩:Task 3 替换为真判定(三态 - [ ] **Step 9: 清单注册(三处)** -1. `src/compiler/_import.cr`:在 `import checker` 之后加 `import type_terms` / `import type_engine` / `import type_selftest` -2. `build_selfhost_native.py`:`corec_files` 列表在 `'src/compiler/checker.cr',` 之后插入三行 -3. `tests/selfhost/test_compile.py`:`concat_sources()` 的 `files` 列表同样位置插入三行 +1. `src/compiler/_import.cr`:在 `import checker` 之后加入 `import type_terms`、`import type_engine`、`import type_selftest`。 +2. `build_selfhost_native.py`:在 `corec_files` 列表的 `'src/compiler/checker.cr',` 之后插入三行。 +3. `tests/selfhost/test_compile.py`:在 `concat_sources()` 的 `files` 列表的同样位置插入三行。 - [ ] **Step 10: 重建 + 跑测试** @@ -425,7 +437,7 @@ nice -n 19 ./build/corec selftest-types # 期望 5/5 ... passed、rc=0 nice -n 19 python3 tests/selfhost/test_type_engine.py # 期望 PASS nice -n 19 ./build/corec run 'fn main()->int{return 42;}' # 期望 rc=42(既有行为不动) ``` -Expected: 全绿。 +预期:全绿。 - [ ] **Step 11: 提交(路径限定)** @@ -435,19 +447,19 @@ jj commit src/compiler/type_terms.cr src/compiler/type_engine.cr src/compiler/ty build_selfhost_native.py tests/selfhost/test_compile.py tests/selfhost/test_type_engine.py \ -m 'feat: R2 P0 Task 1——类型项表(DAG + 哈希去重)+ 构造 API + selftest-types 自测通道骨架(checker 零改动)' ``` -(**不含 `dyn_arr.cr`**——扩容自持于 `type_terms.cr`,见「文件结构」表注。) +(**不含 `dyn_arr.cr`**:扩容自持于 `type_terms.cr`,见「文件结构」表注。) --- ## Task 2: NNF + DNF 规范化 -**Files:** -- Modify: `src/compiler/type_terms.cr` -- Modify: `src/compiler/type_selftest.cr`(加用例) +**涉及文件:** +- 修改 `src/compiler/type_terms.cr` +- 修改 `src/compiler/type_selftest.cr`(加用例) -**Interfaces:** -- Consumes: Task 1 的构造 API -- Produces: +**接口:** +- 消费:Task 1 的构造 API +- 产出: ``` fn tt_nnf(i: int) -> int // 否定下推:¬(∪) → ∩(¬)、¬(∩) → ∪(¬)、¬¬ 消、¬ATOM/¬VAR/¬μ 保留为字面 fn tt_norm(i: int) -> int // 规范化到 DNF:UNION of INTER-of-literals(literals = ATOM/¬ATOM/VAR/¬VAR/TOP_K) @@ -464,14 +476,14 @@ fn tt_is_dnf(i: int) -> int // 自测辅助:检查项是否已是 DNF total = total + 1; fails = fails + ts_check("norm.union_inter_dist", ty_equiv(tt_inter(tt_union(a_int, a_str), a_int), a_int), 1); ``` -(`tt_intersect_union_probe()` = 构造 `(int ∪ string) ∩ bool` 的探针函数,Task 2 一并加上——它测的是「∩ 分配到 ∪ 后 DNF 不丢项」。) +(`tt_intersect_union_probe()` 是构造 `(int ∪ string) ∩ bool` 的探针函数,Task 2 一并加上;它测的是「∩ 分配到 ∪ 后 DNF 不丢项」。) - [ ] **Step 2: 运行确认「红」** ```bash nice -n 19 python3 build_selfhost_native.py && nice -n 19 ./build/corec selftest-types ``` -Expected: FAIL(`tt_norm`/`tt_is_dnf`/`tt_equiv` 未实现或桩返回 0)。 +预期:FAIL(`tt_norm`、`tt_is_dnf`、`tt_equiv` 未实现,或桩返回 0)。 - [ ] **Step 3: 实现 NNF(`type_terms.cr`)** @@ -501,7 +513,7 @@ fn tt_nnf_neg(i: int) -> int { // 计算 ¬i 的 NNF(负位置) return tt_not(i); // 字面取反:¬ATOM / ¬VAR } ``` -(`tt_nnf_list`:对 CONS 链逐元素 `tt_nnf`——新加的小工具函数。) +(`tt_nnf_list` 是新增的小工具函数,对 CONS 链逐元素调用 `tt_nnf`。) - [ ] **Step 4: 实现 DNF(`type_terms.cr`)** @@ -552,7 +564,7 @@ fn tt_is_product_chain(i: int) -> int { return tt_is_literal(i); } ``` -(`tt_is_literal` 已在 Task 3 Step 3 定义——**依赖顺序**:Task 2 落地时先补一个最小 `tt_is_literal`(语义同 Task 3 版本),Task 3 再替换为最终版;两版语义必须一致。) +(`tt_is_literal` 已在 Task 3 Step 3 定义,**依赖顺序**如下:Task 2 落地时先补一个最小 `tt_is_literal`,其语义同 Task 3 版本;Task 3 再替换为最终版。两版语义必须一致。) - [ ] **Step 5: 跑测试确认变绿** @@ -560,7 +572,7 @@ fn tt_is_product_chain(i: int) -> int { nice -n 19 python3 build_selfhost_native.py && nice -n 19 ./build/corec selftest-types nice -n 19 python3 tests/selfhost/test_type_engine.py ``` -Expected: 全部 PASS(计数行 ≥ 8)。 +预期:全部 PASS,计数行 ≥ 8。 - [ ] **Step 6: 提交** @@ -572,13 +584,13 @@ jj commit src/compiler/type_terms.cr src/compiler/type_selftest.cr -m 'feat: R2 ## Task 3: 判定引擎(三态 + 原子互斥 + μ memo + 预算守卫) -**Files:** -- Modify: `src/compiler/type_engine.cr`(替换 Task 1 的桩) -- Modify: `src/compiler/type_selftest.cr`(加用例) +**涉及文件:** +- 修改 `src/compiler/type_engine.cr`(替换 Task 1 的桩) +- 修改 `src/compiler/type_selftest.cr`(加用例) -**Interfaces:** -- Consumes: Task 1/2 的 API -- Produces(**API 稳定,Task 4/后续 P 期依赖**): +**接口:** +- 消费:Task 1/2 的 API +- 产出(**API 稳定,Task 4/后续 P 期依赖**): ``` // 三态:1 = 成立;0 = 不成立;-1 = 预算耗尽/不可判定(禁止当 0 用) fn ty_sub(a: int, b: int) -> int @@ -633,7 +645,7 @@ fn ak_disjoint(x: int, y: int) -> int ty_budget_reset(200000); ``` -- [ ] **Step 2: 运行确认「红」**(桩返回 0,断言 1/-1 的用例必挂) +- [ ] **Step 2: 运行确认「红」**(桩返回 0,断言 1 或 -1 的用例必然失败) - [ ] **Step 3: 实现互斥公理 + 逐字面覆盖(`type_engine.cr`)** @@ -671,7 +683,7 @@ fn lit_covers(p: int, q: int) -> int { return 0; // 其余一律不覆盖(⊥ 早退由调用方 lits_contradictory 处理) } ``` -(`ty_ak_of(lit)`:ATOM → `tt_a(lit)`;`¬ATOM` → `tt_a(tt_a(lit))`。) +(`ty_ak_of(lit)` 的规则:ATOM 取 `tt_a(lit)`;`¬ATOM` 取 `tt_a(tt_a(lit))`。) - [ ] **Step 4: 实现判定的 product 覆盖 + μ 展开 + memo + 预算(`type_engine.cr`)** @@ -708,7 +720,7 @@ fn prod_covered(p: int, b: int) -> int { return 1; } ``` -(实现者按此语义实现:`lit_collect` 把 product 拆成字面数组(µ 展开点见下),`lit_set_covers` 用 `lit_covers` 扫描,`lits_contradictory` 检查 `ATOM(k1)` 与 `ATOM(k2)`(k1≠k2 且互斥)或 `X` 与 `¬X`。) +(实现者按此语义实现:`lit_collect` 把 product 拆成字面数组,µ 展开点见下;`lit_set_covers` 用 `lit_covers` 扫描;`lits_contradictory` 检查 `ATOM(k1)` 与 `ATOM(k2)`(k1≠k2 且互斥),或检查 `X` 与 `¬X`。) ```core // μ 展开 + memo(假设-判定,最大不动点):遇到 MU 单步展开,并在假设集中登记 (子项对) diff --git a/docs/superpowers/plans/2026-09-10-r2-p1-shadow-parity.md b/docs/superpowers/plans/2026-09-10-r2-p1-shadow-parity.md index 9a54ccf5..82b870a7 100644 --- a/docs/superpowers/plans/2026-09-10-r2-p1-shadow-parity.md +++ b/docs/superpowers/plans/2026-09-10-r2-p1-shadow-parity.md @@ -2,9 +2,14 @@ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. -**Goal:** 把 P0 的类型项引擎以**影子模式**挂到检查器的类型判定上(旧判定照常生效),对真实语料并跑两套判定、产出**分类差异清单**——收紧面(旧接受→新拒绝 / 旧拒绝→新接受)在 P1 暴露,而不改任何行为。 +**Goal:** 把 P0 的类型项引擎以**影子模式**挂到检查器的类型判定上,旧判定照常生效。对真实语料并跑两套判定,产出**分类差异清单**,使收紧面(旧接受→新拒绝 / 旧拒绝→新接受)在 P1 暴露,而不改任何行为。 -**Architecture:** 三件新东西 + 一处包装:① 判定衔接层 `ty_shadow.cr`(checker 的 `ti` → 引擎类型项);② 影子判定核心(翻译 → `ty_equiv` → 分类:`AGREE` / `OLD_STRICTER`(旧拒新受)/ `OLD_LOOSER`(旧受新拒)/ `UNKNOWN`(引擎 -1,单列不计差异));③ 通道(CLI `--type-shadow` 开关 + 摘要行 + 转储文件);挂点 = `type_equal` 包装(原函数改名 `type_equal_core` 供内部递归,外部 8 个决策点经包装自动覆盖)。 +**Architecture:** 本批共三件新东西加一处包装。 + +- ① 判定衔接层 `ty_shadow.cr`,负责把 checker 的 `ti` 翻译为引擎类型项。 +- ② 影子判定核心,流程为翻译 → `ty_equiv` → 分类,分类取值为 `AGREE` / `OLD_STRICTER`(旧拒新受)/ `OLD_LOOSER`(旧受新拒)/ `UNKNOWN`(引擎 -1,单列不计差异)。 +- ③ 通道,由 CLI `--type-shadow` 开关、摘要行与转储文件组成。 +- 挂点 = `type_equal` 包装:原函数改名 `type_equal_core` 供内部递归,外部 8 个决策点经包装自动覆盖。 **Tech Stack:** Core 自举栈;P0 引擎(`src/compiler/type_terms.cr` / `type_engine.cr` / `type_selftest.cr`);检查器 `src/compiler/checker.cr`;CLI `src/compiler/main.cr`。 @@ -12,13 +17,13 @@ ## Global Constraints -- **jj only**;**提交必须路径限定**(多 agent 共用工作副本)。 -- 所有编译/测试命令 `nice -n 19` 前缀;改编译器源码后**必须重建**。 -- **P1 行为零变化(强判据)**:`--type-shadow` **关**(默认)= 产物与 P0 基线逐字节相同;**开** = 产物**同样**逐字节相同(影子只观察、不改判定、不写产物)。两态都要过。 -- **判据前清缓存**:`nice -n 19 ./build/corec clean-cache`(TODO #2026-09-10-1),且 cwd = 仓库根。 +- **jj only**。**提交必须路径限定**(多 agent 共用工作副本)。 +- 所有编译/测试命令加 `nice -n 19` 前缀。改编译器源码后**必须重建**。 +- **P1 行为零变化(强判据)**:`--type-shadow` **关**(默认)时,产物与 P0 基线逐字节相同;**开**时产物**同样**逐字节相同(影子只观察、不改判定、不写产物)。两态都要过。 +- **判据前清缓存**:执行 `nice -n 19 ./build/corec clean-cache`(TODO #2026-09-10-1),且 cwd = 仓库根。 - 文件永久不允许还原;不得绕过;**引擎 UNKNOWN(-1)不得计入差异**(未覆盖面 ≠ 收紧面,单列统计)。 -- diff 校验式样:`jj diff --git | grep '^[+]' | grep -v -e '^[+][+][+]'`;环境陷阱:noclobber(用 `>|`)、变量不分词。 -- 新文件三处注册(`src/compiler/_import.cr` / `build_selfhost_native.py` 的 **corec 清单**(checker 段后)/ `tests/selfhost/test_compile.py`)。 +- diff 校验式样:`jj diff --git | grep '^[+]' | grep -v -e '^[+][+][+]'`。环境陷阱:noclobber(用 `>|`)、变量不分词。 +- 新文件三处注册:`src/compiler/_import.cr`、`build_selfhost_native.py` 的 **corec 清单**(checker 段后)、`tests/selfhost/test_compile.py`。 --- @@ -257,7 +262,7 @@ fn type_equal(t1: int, t2: int) -> bool { ``` (`r ? 1 : 0`:**本语言无三元运算符**——用 `ok : ., mut = 0; if r { ok = 1; }` 显式写。) -- [ ] **Step 2: 站点标注**:在 8 个外部调用点(`checker.cr:711/947/959/973/1212/1405/1796/2127`)调用前 `sh_site_begin()`。 +- [ ] **Step 2: 站点标注**:在 8 个外部调用点(`checker.cr:711/947/959/973/1212/1405/1796/2127`)调用前执行 `sh_site_begin()`。 **实读修正(Task 2 落地,取代初稿标签)**:8 个外部点**无一是 match 路径**;站点 4 = 泛型匹配(pattern 侧恒 `TI_UNIT` → 难产差异);站点 6 = `EXPR_BINARY+OP_ASSIGN` 遗留路径(**当前不可达**——parser 已把 `=` 统一降为 `EXPR_ASSIGN`,挂点保留但永不产样本,去留待 P2 裁决);站点 8 = `EXPR_ASSIGN` 节点(**非「索引」**)。站点 ↔ 语义以 `ty_shadow.cr` 头注(实读表)为准。 - [ ] **Step 3: 分类核心(`ty_shadow.cr`)** diff --git a/docs/superpowers/plans/2026-09-11-r2-p3-capabilities.md b/docs/superpowers/plans/2026-09-11-r2-p3-capabilities.md index aaf38226..a501936c 100644 --- a/docs/superpowers/plans/2026-09-11-r2-p3-capabilities.md +++ b/docs/superpowers/plans/2026-09-11-r2-p3-capabilities.md @@ -1,70 +1,84 @@ -# R2 P3(能力落地)实施计划:定长退役 + 序列接口/长度约束 + 穷尽性/联合/可选 + 泛型约束 + impl 契约 +# R2 P3(能力落地)实施计划:定长退役、序列接口与长度约束、穷尽性/联合/可选、泛型约束、impl 契约 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. -**Goal:** 把 P0/P1/P2a 建成的「类型项层 + 语义包含引擎 + 判定接线」从**判定替换**推进到**能力落地**——五项目标能力(定长退役、序列接口/长度约束、穷尽性/联合/可选、泛型约束、impl 契约)各自在引擎/桥接/checker 三层接通,每项带正负控、边界例与不变量双锁定。 +**Goal:** 本计划把 P0/P1/P2a 建成的「类型项层 + 语义包含引擎 + 判定接线」从**判定替换**推进到**能力落地**。五项目标能力(定长退役、序列接口/长度约束、穷尽性/联合/可选、泛型约束、impl 契约)各自在引擎层、桥接层与 checker 层接通,每项能力均配正负控、边界例与不变量双锁定。 -**Architecture:** 三条主线:① **引擎展开层**(Task 0:named/struct/enum/generic-apply → 结构项;**仅**服务满足判定与域查询,等价判定保持原子名义)——它是穷尽性/联合/可选/泛型约束/impl 四项的共同前提,也是 P2a 登记的「P5 引擎命名展开」前移;② **不依赖 P2b 的能力**(Task 1 定长/变型、Task 3 穷尽性、Task 4 联合/可选、Task 5 的非接口半边)= **P3a**;③ **依赖 P2b 注册表的接口面**(Task 2 横切接口、Task 6 impl 契约、Task 5 的 `T: I` 满足半边)= **P3b**(P2b 计划落地后接,接口契约见下节)。 +**Architecture:** 本计划分三条主线。 +① **引擎展开层**:Task 0 把 named/struct/enum/generic-apply 展开为结构项。该层**仅**服务满足判定与域查询,等价判定保持原子名义。它既是穷尽性、联合/可选、泛型约束、impl 四项能力的共同前提,也是 P2a 登记的「P5 引擎命名展开」的前移。 +② **不依赖 P2b 的能力** = **P3a**,含 Task 1(定长/变型)、Task 3(穷尽性)、Task 4(联合/可选),以及 Task 5 的非接口半边。 +③ **依赖 P2b 注册表的接口面** = **P3b**,含 Task 2(横切接口)、Task 6(impl 契约),以及 Task 5 的 `T: I` 满足半边。该线在 P2b 计划落地后接入,接口契约见下节。 -**Tech Stack:** Core 自举栈。`src/compiler/type_terms.cr`(类型项 DAG)· `type_engine.cr`(三态判定)· `ty_shadow.cr`(ti→term 桥接 + 10 站点 + 计数)· `checker.cr`(判定点/公理区/泛型/接口)· `monomorph.cr`(实例化)· `ir_gen.cr`(表示层读 N 的两处)。判据通道:`corec selftest-types`、`--type-shadow`、`tests/selfhost/test_type_engine.py`。 +**Tech Stack:** Core 自举栈。涉及文件与各自职责如下。 +- `src/compiler/type_terms.cr`:类型项 DAG。 +- `src/compiler/type_engine.cr`:三态判定。 +- `src/compiler/ty_shadow.cr`:ti→term 桥接、10 站点与计数。 +- `src/compiler/checker.cr`:判定点、公理区、泛型与接口。 +- `src/compiler/monomorph.cr`:实例化。 +- `src/compiler/ir_gen.cr`:表示层读 N 的两处。 +判据通道 = `corec selftest-types`、`--type-shadow` 与 `tests/selfhost/test_type_engine.py`。 -**Spec:** `docs/superpowers/specs/2026-09-10-type-interface-unification-design.md` §5(能力落点:§5.1 定长/序列/长度约束、§5.2 泛型、§5.3 impl、§5.4 穷尽性/联合/可选)+ §1/§2(语义基座/双轴注册表)+ §9 P3 行;方向定案 `docs/superpowers/specs/2026-08-30-type-system-direction-design.md` 条目 8;定长裁决 `docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md` §1 + TODO.md `fixed-array-retire`(TODO.md:446)。**前置状态(已实测,非本计划目标)**:P0 引擎 + **95 例**(`selftest-types` 95/95);P1 影子(开/关两态产物逐字节同);P2a 判定替换(`type_equal` → `ty_equiv`)+ 语料对拍归零。 +**Spec:** 本计划的规约来源如下。 +- `docs/superpowers/specs/2026-09-10-type-interface-unification-design.md` §5 给出能力落点:§5.1 定长/序列/长度约束、§5.2 泛型、§5.3 impl、§5.4 穷尽性/联合/可选;该文档的 §1/§2 给出语义基座与双轴注册表;§9 的 P3 行给出阶段划分。 +- `docs/superpowers/specs/2026-08-30-type-system-direction-design.md` 条目 8 为方向定案。 +- `docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md` §1 与 `TODO.md` 的 `fixed-array-retire` 条目(TODO.md:446)为定长裁决。 +**前置状态(已实测,非本计划目标)**:P0 引擎已落地并含 **95 例**(`selftest-types` 95/95);P1 影子层已落地(开/关两态产物逐字节相同);P2a 已完成判定替换(`type_equal` → `ty_equiv`),语料对拍归零。 ## Global Constraints -- **jj only(禁 git 含只读/复合)**;**提交路径限定**;所有命令 `nice -n 19`;判据前 `clean-cache`、cwd = 仓库根(比较任何 `.ccr`/缓存态产物前必须 clean-cache——TODO #2026-09-10-1 末条/#26)。 -- **ELF canary 本计划全任务预期不变**:`clean-cache` → `build tests/suite/ptr_arith.cr --static -o /tmp/…` → sha256 `95084e7bc68d6550d21d3d96fa3afd89c67a5d89edce5656a3d2e74fc923d475`(即 `/tmp/r1t4_base_bin`)。**任一任务 ELF 变 → 停下上报**(类型层改动泄进发射面)。⚠ canary 语料(`tests/suite/ptr_arith.cr`:一个数组字面量 + 取址/解引用,**无切片/联合/match**)对类型层改动**不敏感**——它是「发射面零泄漏」证据,**不得**当新语义正确性证据;新语义一律由**行为探针**承担(各任务判据步单列)。 -- **`.ccr` 预期与实测**:Task 0/1/2/3 预期不变(类型表行序不动);**Task 4(退役内建 Option 注册)/ Task 5(实例键类型项化)预期会变**(命名行编号 / SYM 中 mangled 实例名)→ **允许但必须实测报告**;判据按 TODO #2026-09-11-9 = **结构性断言**(`tests/selfhost/test_ccr_v7.py` 全绿)+ 语义零变化 + 自举稳定(`corec2/corec3` `cmp` IDENTICAL + N06=0 + 冒烟 42),不以「与旧版逐字节同」为准。ELF 同时变 → 停下上报。 -- **三态纪律(P0/P1/P2a 继承)**:引擎 -1(预算耗尽/未覆盖面)**不得**当 0/1 用;判定路径回落(`type_equal_legacy`)必须计数(`g_replace_unknown`/`g_replace_bridge`)并单列。新引擎查询自带预算前后隔离(照 `type_equal_engine`,checker.cr:500-502)。 -- **影子对拍门(每任务复跑)**(**R2 P5 Task 5 起作废**:影子通道已整体下线 ⇒ 改由 **冻结基线同源对拍 + 行为探针 + 突变控制** 承担,见 `TODO.md` #48 与 findings §15;本行余下语义——「零差异 ≠ 面收敛」与站点覆盖范围——**继续有效**,只是证据载体从对拍换为行为探针):基线 = 71 候选 / **67 有效文件 / 26,989 判定全 agree / `old_stricter=0` / `old_looser=0` / `unknown=0` / `replace_*=0`**(findings §11)。**必须与站点覆盖同报**(站点 1/2/4/6 语料零命中、3 仅 2 次)——「零差异」≠「面收敛」;新能力面(match/切片/泛型约束/impl)语料零命中 ⇒ 由定向探针承担。 -- **收紧处置(spec §0 裁决 6)**:新判定若「旧接受 → 新拒绝」,逐条记录(文件/用例/旧判定/新判定/处置);涉及自举源码先跑全语料清单再改;**语义争议停下上报**。 -- **新硬错误先报告后开门**:任何把新检查升为 rc=1 门的步骤(穷尽性、长度方向、可选面)必须先在**全语料**(`src/compiler/_import.cr` 自指 + `tests/suite` + `tests/selfhost` 内联源 + `src/stdlib` + `examples`)report-only 跑一遍,清单审查后再入 `run_frontend` 硬错误名单(main.cr:146-158;照 #29 先例)。语料排除项见 TODO #2026-09-11-6(`src/compiler/elf.cr` 陈旧 2 parse error;`tests/suite/test_control_flow.cr`/`test_generics.cr` 0 字节)。 -- **不得回退既有收纳**:TS01-04/TK02 硬错误门(#29)、F2 常量档拒绝语义与「N 不回身份」(#19/#24)、F5 槽位契约(#25/#28)、效应/纯度判据(#26/#27)本计划一律不动;冲突 → 停下上报。 -- 本语言无三元运算符;取模须非负;键比较不得依赖 i64 回绕;noclobber(`>|`);自测用例**只增不减**(`test_type_engine.py:MIN_CASES=32` 为下限,逐任务下限见各任务判据)。 - -## 侦查底座(2026-09-11 实读 + 定向实测,file:line = 当前工作树) - -**引擎/桥接(能力落点现状)** -- 三态 API:`ty_sub`/`ty_equiv`/`ty_disjoint`/`ty_inhabited`/`tt_witness`/`ty_exhaustive`(type_engine.cr:390/405/479/414/448/471);`tt_norm`(type_terms.cr:326);预算 `ty_budget_reset`(type_engine.cr:301)。 -- P0 显式未覆盖面(type_engine.cr:10-13):① 参数化原子**仅同形判等**(变型 = P3);② `AK_NAMED` **不展开**;③ 空递归保守 -1。变型现状证据 = 同类参数不同形 → `-1`(type_engine.cr:175-182)+ `tt_list_same` 结构相等(:187-193)。 -- 桥接(ty_shadow.cr:194-246):`TYP_ARRAY`/`TYP_SLICE` **同归** `AK_SEQUENCE(elem)`(:217-220,固定性与 N 均不入项);`TYP_REF` 的 mut 标记**不入参数链**(:224-227,注记自认「引擎无只读/可写区分 = P3 条目化面」);`TYP_NAMED`/`TYP_GENERIC_PARAM`/`TYP_GENERIC_APPLY` → `AK_NAMED`(:230-231);`TYP_TUPLE` → `AK_PRODUCT`(:178-191)。桥接缓存随 `init_types()` 失效(:98-102)。 - -**判定点/长度约束(P2a 现状)** -- `type_equal_engine`(checker.cr:492-508)+ 包装(:515-523);`type_equal_legacy`(:419-477,对照物 + 回落,P5 删);10 站点表(ty_shadow.cr:252-269)。 -- `array_len_constraint_ok`(checker.cr:346-386)= **常量档**、下钻 6 位(数组/指针/引用/切片/元组字段/泛型实参);**异 kind → 返回 1(无约束)**;`type_compat_strict`(:394-398)= 身份 ∧ 长度;判定点 10 处(:1088/1455/1468/1483/1732/1927/2320/2654/2780/2845)。 -- **实测(2026-09-11,探针 `/tmp/r2p3_probe/`,cwd=探针目录,`build/corec` = 20:39 构建)**: - - pA `fn g() -> [int;3] { b:[int;4]=[1,2,3,4]; return b[0..2]; }` → **rc=0、零诊断**(切片值当 `[int;3]` 用 = **静默放宽**;读码:legacy 数组分支要求两侧同为 `TYP_ARRAY`(:432-434),跨 kind 判 false ⇒ 此为 P2a 替换后的**现行语义洞**。P2a 前为 `error[TF01]`——此「前值」为读码结论,**未实测**)。 - - pB `fn h() -> [int] { c:[int;3]=[1,2,3]; return c; }` → rc=0(符合 spec §5.1 `[T;N] <: [T]`)。 - - pC 异长(`[int;4]` 在返回位给 `[int;3]`)→ rc=1 `error[TF01]: Array length constraint not satisfied`(常量档拒绝仍在)。 - - pD `fn f(x: int?) -> int` + `v := Some(3)`(无用户 `enum Option`)→ rc=1 `error[N01]: Undefined enum constructor 'Some'`。 - -**定长退役「未办面」枚举(读码逐条,非猜)** -1. **array/slice 判等过度合并**:桥接同译 `AK_SEQUENCE(elem)`(ty_shadow.cr:217-220)+ `array_len_constraint_ok` 异 kind 返回 1(checker.cr:349)⇒ 方向不设防(实测 pA)。 -2. **变型规则缺位**:参数链不携带「固定长/视图」「只读/可写」维度(ty_shadow.cr:220/225-227)⇒ `[T;N] <: [T]`、`[T;N] ≢ [T]`、`&T` vs `&mut T` 均无法表达。 -3. **长度档位**:常量档已有(:346-386);**符号档/动态档未实现**(:343-344 自注「P3 面」)。本次裁定:动态档 = 既有运行期检查(`g_ir_slice_lens` 侧表 + `IR_BOUNDS_CHECK`,R1 已落、TODO F11 划销)+ checker 字面量界检查(:2586-2602);**符号档 = VC 义务,本计划不实现,显式登记**。 -4. **N 读取面边界**:`get_type_extra(TYP_ARRAY)` 仍被读 5 处——常量档(:351)、F11 字面量切片界(:2589)、F2 字面量索引界(:2609)、表示层 `ir_gen.cr:120-131 arr_len_lit_of` / `:476-483 type_size`(+`type_align`)。退役后的**不变式** = 「N 只许被常量档检查与表示层读,身份/子类型路径零 N」——Task 1 为它加守门用例。 -5. 自举源码 10 处 `[T; N]` 零改造(R1 裁决)——Task 1 判据复验。 +- **版本控制限定为 jj**(禁用 git,含只读与复合调用);**提交路径限定**;所有命令一律加 `nice -n 19`;判据执行前先 `clean-cache`,cwd 固定为仓库根。比较任何 `.ccr` 或缓存态产物之前必须 clean-cache(TODO #2026-09-10-1 末条/#26)。 +- **ELF canary 在本计划全任务预期不变**:命令序列为 `clean-cache` → `build tests/suite/ptr_arith.cr --static -o /tmp/…` → sha256 `95084e7bc68d6550d21d3d96fa3afd89c67a5d89edce5656a3d2e74fc923d475`(即 `/tmp/r1t4_base_bin`)。任一任务出现 ELF 变化**即停下上报**,其含义为类型层改动泄进发射面。⚠ canary 语料(`tests/suite/ptr_arith.cr`:一个数组字面量加取址/解引用,**无切片/联合/match**)对类型层改动**不敏感**。它是「发射面零泄漏」的证据,**不得**当作新语义正确性的证据;新语义一律由**行为探针**承担(各任务判据步单列)。 +- **`.ccr` 的预期与实测分档**:Task 0/1/2/3 预期不变(类型表行序不动);**Task 4(退役内建 Option 注册)与 Task 5(实例键类型项化)预期会变**(命名行编号或 SYM 中 mangled 实例名),**允许变化但必须实测报告**。判据按 TODO #2026-09-11-9 = **结构性断言**(`tests/selfhost/test_ccr_v7.py` 全绿)加语义零变化加自举稳定(`corec2/corec3` `cmp` IDENTICAL + N06=0 + 冒烟 42),不以「与旧版逐字节同」为准。ELF 同时变化**即停下上报**。 +- **三态纪律(继承 P0/P1/P2a)**:引擎返回 -1(预算耗尽或未覆盖面)时**不得**当 0/1 使用;判定路径的回落(`type_equal_legacy`)必须计数(`g_replace_unknown`/`g_replace_bridge`)并单列。新引擎查询自带预算前后隔离(照 `type_equal_engine`,checker.cr:500-502)。 +- **影子对拍门(每任务复跑)**(**R2 P5 Task 5 起作废**:影子通道已整体下线,改由**冻结基线同源对拍 + 行为探针 + 突变控制**承担,见 `TODO.md` #48 与 findings §15;本行余下语义——「零差异 ≠ 面收敛」与站点覆盖范围——**继续有效**,只是证据载体从对拍换为行为探针):基线 = 71 候选,其中 **67 有效文件、26,989 判定全 agree、`old_stricter=0`、`old_looser=0`、`unknown=0`、`replace_*=0`**(findings §11)。该结果**必须与站点覆盖同报**(站点 1/2/4/6 语料零命中、3 仅 2 次),因为「零差异」不等于「面收敛」;新能力面(match/切片/泛型约束/impl)语料零命中,其正确性由定向探针承担。 +- **收紧处置(spec §0 裁决 6)**:新判定若出现「旧接受 → 新拒绝」,须逐条记录(文件、用例、旧判定、新判定、处置)。涉及自举源码时先跑全语料清单再改;**语义争议停下上报**。 +- **新硬错误先报告后开门**:任何把新检查升为 rc=1 门的步骤(穷尽性、长度方向、可选面)必须先在**全语料**上以 report-only 跑一遍,清单审查后再入 `run_frontend` 硬错误名单(main.cr:146-158;照 #29 先例)。全语料 = `src/compiler/_import.cr` 自指、`tests/suite`、`tests/selfhost` 内联源、`src/stdlib` 与 `examples`。语料排除项见 TODO #2026-09-11-6(`src/compiler/elf.cr` 陈旧 2 parse error;`tests/suite/test_control_flow.cr`/`test_generics.cr` 0 字节)。 +- **不得回退既有收纳**:TS01-04/TK02 硬错误门(#29)、F2 常量档拒绝语义与「N 不回身份」(#19/#24)、F5 槽位契约(#25/#28)、效应/纯度判据(#26/#27)在本计划中一律不动;出现冲突**即停下上报**。 +- 本语言无三元运算符;取模须非负;键比较不得依赖 i64 回绕;重定向使用 noclobber(`>|`)。自测用例**只增不减**(`test_type_engine.py:MIN_CASES=32` 为下限,逐任务下限见各任务判据)。 + +## 侦查底座(2026-09-11 实读与定向实测,file:line 均为当前工作树) + +**引擎与桥接(能力落点现状)** +- 三态 API:`ty_sub`、`ty_equiv`、`ty_disjoint`、`ty_inhabited`、`tt_witness`、`ty_exhaustive`(type_engine.cr:390/405/479/414/448/471);`tt_norm`(type_terms.cr:326);预算重置为 `ty_budget_reset`(type_engine.cr:301)。 +- P0 显式未覆盖面(type_engine.cr:10-13):① 参数化原子**仅同形判等**(变型 = P3);② `AK_NAMED` **不展开**;③ 空递归保守 -1。变型现状的证据 = 同类参数不同形返回 `-1`(type_engine.cr:175-182),加 `tt_list_same` 的结构相等(:187-193)。 +- 桥接现状(ty_shadow.cr:194-246):`TYP_ARRAY` 与 `TYP_SLICE` **同归** `AK_SEQUENCE(elem)`(:217-220,固定性与 N 均不入项);`TYP_REF` 的 mut 标记**不入参数链**(:224-227,注记自认「引擎无只读/可写区分 = P3 条目化面」);`TYP_NAMED`、`TYP_GENERIC_PARAM` 与 `TYP_GENERIC_APPLY` 归 `AK_NAMED`(:230-231);`TYP_TUPLE` 归 `AK_PRODUCT`(:178-191)。桥接缓存随 `init_types()` 失效(:98-102)。 + +**判定点与长度约束(P2a 现状)** +- `type_equal_engine`(checker.cr:492-508)与其包装(:515-523);`type_equal_legacy`(:419-477,兼作对照物与回落实现,P5 删除);10 站点表在 ty_shadow.cr:252-269。 +- `array_len_constraint_ok`(checker.cr:346-386)= **常量档**,下钻 6 位(数组、指针、引用、切片、元组字段、泛型实参);**异 kind 时返回 1(无约束)**。`type_compat_strict`(:394-398)= 身份 ∧ 长度。判定点共 10 处(:1088/1455/1468/1483/1732/1927/2320/2654/2780/2845)。 +- **实测(2026-09-11,探针目录 `/tmp/r2p3_probe/`,cwd = 探针目录,`build/corec` = 20:39 构建)**: + - pA `fn g() -> [int;3] { b:[int;4]=[1,2,3,4]; return b[0..2]; }` → **rc=0、零诊断**。切片值当 `[int;3]` 用构成**静默放宽**。读码结论:legacy 数组分支要求两侧同为 `TYP_ARRAY`(:432-434),跨 kind 判 false,因此这是 P2a 替换后的**现行语义洞**。P2a 前为 `error[TF01]`;该「前值」为读码结论,**未实测**。 + - pB `fn h() -> [int] { c:[int;3]=[1,2,3]; return c; }` → rc=0(符合 spec §5.1 的 `[T;N] <: [T]`)。 + - pC 异长(返回位以 `[int;4]` 给 `[int;3]`)→ rc=1 `error[TF01]: Array length constraint not satisfied`(常量档拒绝仍在)。 + - pD `fn f(x: int?) -> int` 配合 `v := Some(3)`(无用户 `enum Option`)→ rc=1 `error[N01]: Undefined enum constructor 'Some'`。 + +**定长退役「未办面」枚举(逐条读码所得,非推测)** +1. **array/slice 判等过度合并**:桥接把两者同译为 `AK_SEQUENCE(elem)`(ty_shadow.cr:217-220),且 `array_len_constraint_ok` 在异 kind 时返回 1(checker.cr:349),因此方向不设防(实测 pA)。 +2. **变型规则缺位**:参数链不携带「固定长/视图」与「只读/可写」维度(ty_shadow.cr:220/225-227),因此 `[T;N] <: [T]`、`[T;N] ≢ [T]` 与 `&T` vs `&mut T` 均无法表达。 +3. **长度档位**:常量档已有(:346-386);**符号档与动态档均未实现**(:343-344 自注「P3 面」)。本次裁定:动态档 = 既有运行期检查(`g_ir_slice_lens` 侧表与 `IR_BOUNDS_CHECK`,R1 已落、TODO F11 划销)加 checker 字面量界检查(:2586-2602);**符号档 = VC 义务,本计划不实现,显式登记**。 +4. **N 读取面边界**:`get_type_extra(TYP_ARRAY)` 仍被读 5 处,分别为常量档(:351)、F11 字面量切片界(:2589)、F2 字面量索引界(:2609),以及表示层 `ir_gen.cr:120-131 arr_len_lit_of` 与 `:476-483 type_size`(连同 `type_align`)。退役后的**不变式** = 「N 只许被常量档检查与表示层读,身份/子类型路径零 N」;Task 1 为它加守门用例。 +5. 自举源码的 10 处 `[T; N]` 零改造(R1 裁决),由 Task 1 判据复验。 **穷尽性/联合/可选(现状)** -- match **零检查**:`EC_TM_*` 仅定义(ast.cr:443-451),`checker.cr` 零 raise;`EXPR_MATCH` 只推臂体(:2407-2451),模式绑定变量**恒 `TI_INT`**(:2431/:2439);臂类型一致性、模式 vs scrutinee、穷尽性、冗余臂全无。模式形态(parser.cr:1020-1040):通配 / 字面量(int/string/char/bool)/ 绑定 ident / 枚举 / struct 模式。 -- enum:变体构造器注册为「返回枚举 named 类型的函数」(checker.cr:977-993);`EXPR_ENUM_CONSTRUCTOR` 只解析名字(:2489-2507,载荷类型不校验);表访问器 dyn_arr.cr:393-399;`MAX_ENUM_VARIANTS=16`(ast.cr:117)。 -- 可选:`T?` 降级为 `Option[T]`(parser.cr:139-143);`Option` 仅在用户未声明时被注册为**一个 named 类型**(checker.cr:962-975);`Some`/`None` 走 `EXPR_ENUM_CONSTRUCTOR`(parser.cr:418-431)⇒ 无用户 `enum Option` 时 `Some(3)` 报 N01(实测 pD);`EXPR_TRY` 按**基名字符串** `"Option"`/`"Result"` 解包(checker.cr:2871-2888)。 -- 语料:`src/compiler/**` 与 `tests/suite/**` **零 `match` 表达式**、零 `enum` 声明(全仓 grep 仅注记命中)⇒ 穷尽性收紧的**自举风险 ≈ 0**;enum/match 仅出现在 `tests/selfhost/test_interp_float.py:34-35`、`test_interp_parity.py:54-74`、`test_native_memory.py:68`、`test_lsp.py:137-145` 内联 fixture(均为全变体覆盖的 3 变体枚举)。 +- match **零检查**:`EC_TM_*` 仅有定义(ast.cr:443-451),`checker.cr` 零 raise;`EXPR_MATCH` 只推臂体(:2407-2451),模式绑定变量**恒为 `TI_INT`**(:2431/:2439);臂类型一致性、模式 vs scrutinee、穷尽性与冗余臂四项全无。模式形态(parser.cr:1020-1040)包含通配、字面量(int/string/char/bool)、绑定 ident、枚举与 struct 模式。 +- enum:变体构造器注册为「返回枚举 named 类型的函数」(checker.cr:977-993);`EXPR_ENUM_CONSTRUCTOR` 只解析名字(:2489-2507,载荷类型不校验);表访问器在 dyn_arr.cr:393-399;`MAX_ENUM_VARIANTS=16`(ast.cr:117)。 +- 可选:`T?` 降级为 `Option[T]`(parser.cr:139-143);`Option` 仅在用户未声明时被注册为**一个 named 类型**(checker.cr:962-975);`Some` 与 `None` 走 `EXPR_ENUM_CONSTRUCTOR`(parser.cr:418-431),因此无用户 `enum Option` 时 `Some(3)` 报 N01(实测 pD);`EXPR_TRY` 按**基名字符串** `"Option"`/`"Result"` 解包(checker.cr:2871-2888)。 +- 语料:`src/compiler/**` 与 `tests/suite/**` **零 `match` 表达式**、零 `enum` 声明(全仓 grep 仅注记命中),因此穷尽性收紧的**自举风险 ≈ 0**;enum/match 仅出现在 `tests/selfhost/test_interp_float.py:34-35`、`test_interp_parity.py:54-74`、`test_native_memory.py:68` 与 `test_lsp.py:137-145` 的内联 fixture,且均为全变体覆盖的 3 变体枚举。 **泛型约束(现状)** -- 约束语法仅**函数**泛型有:`parse_generics_into` 收 `T: I`(parser.cr:1184-1188)→ `save_func_gen_constrs`(:1210-1222,索引 `fi * MAX_GENERICS + gi`);**结构/枚举/接口泛型把约束写进 dummy 缓冲后丢弃**(parser.cr:1533/:1575/:1628)⇒ `struct S[T: I]` 静默无约束。 -- 调用点检查 = 名字拼接 + `check_iface`(checker.cr:1562-1598 → :1588);泛型体内经约束的方法调用同样走名拼接(:2103-2144)。 -- monomorph:实例键 = **逗号分隔类型名字符串**,由 `ir_gen` 从**调用实参**的 `irv_type` 生成(ir_gen.cr:1497-1513),**非原生类型一律兜底 `"int"`**(:1511;读码 ⇒ 不同类型实参可折叠到同一实例,**未实测**);去重 `istr_eq`(monomorph.cr:443-456);替换 = 名字文本替换(:64-89);`MAX_GENERICS=4`(ast.cr:115)。 +- 约束语法仅**函数**泛型具有:`parse_generics_into` 收 `T: I`(parser.cr:1184-1188),转入 `save_func_gen_constrs`(:1210-1222,索引为 `fi * MAX_GENERICS + gi`);**结构/枚举/接口泛型把约束写进 dummy 缓冲后丢弃**(parser.cr:1533/:1575/:1628),因此 `struct S[T: I]` 静默无约束。 +- 调用点检查 = 名字拼接加 `check_iface`(checker.cr:1562-1598 → :1588);泛型体内经约束的方法调用同样走名拼接(:2103-2144)。 +- monomorph:实例键 = **逗号分隔类型名字符串**,由 `ir_gen` 从**调用实参**的 `irv_type` 生成(ir_gen.cr:1497-1513),**非原生类型一律兜底 `"int"`**(:1511;读码结论 ⇒ 不同类型实参可折叠到同一实例,**未实测**)。去重用 `istr_eq`(monomorph.cr:443-456);替换用名字文本替换(:64-89);`MAX_GENERICS=4`(ast.cr:115)。 **impl/interface(现状)** -- 表:`g_ifaces` 1432B/条(16 方法 × 88B、方法参数 ≤8;dyn_arr.cr:143-149);签名存**裸 `TY_*`**(parser.cr:1671/1685 `unpack_type`)⇒ 签名**无法表达命名/泛型类型**。`g_impl_for` 16B 存两名字 ni(parser.cr:1763-1767)。 -- 判定:`find_iface`(checker.cr:844-852)/`type_has_method`(:873-879,名字拼接 `Type.method`)/`check_iface`(:881-904)/`check_impl_for`(:1746-1807,param/ret 裸 TY 比较)。 -- **ir_gen 零消费、.ccr 零序列化**(spec §11 已核);覆盖 = `tests/selfhost/test_impl.py` 5 check + 2 native 例,**全为固有方法**(`impl Vec { … }`),`interface`/`impl I for T` 零命中(实读)。 +- 表:`g_ifaces` 为 1432B/条(16 方法 × 88B、方法参数 ≤8;dyn_arr.cr:143-149);签名存**裸 `TY_*`**(parser.cr:1671/1685 的 `unpack_type`),因此签名**无法表达命名/泛型类型**。`g_impl_for` 16B,存两个名字 ni(parser.cr:1763-1767)。 +- 判定:`find_iface`(checker.cr:844-852)、`type_has_method`(:873-879,名字拼接 `Type.method`)、`check_iface`(:881-904)与 `check_impl_for`(:1746-1807,param/ret 按裸 TY 比较)。 +- **ir_gen 零消费、.ccr 零序列化**(spec §11 已核);覆盖 = `tests/selfhost/test_impl.py` 的 5 个 check 例加 2 个 native 例,**全为固有方法**(`impl Vec { … }`),`interface`/`impl I for T` 零命中(实读)。 **产物面(判据依据)** -- ELF 无符号表(`src/format/elf/elf.cr` 全文件 `symtab` 零命中)⇒ 函数名/mangled 名**不入 ELF**;`.ccr` 函数记录含 `name_idx`、NOD/var 含类型行号(ccr_io.cr:39-47/129-130)⇒ 命名行编号或实例名变化 → `.ccr` 字节变(允许、须报告)。 +- ELF 无符号表(`src/format/elf/elf.cr` 全文件 `symtab` 零命中),因此函数名与 mangled 名**不入 ELF**。`.ccr` 函数记录含 `name_idx`,NOD/var 含类型行号(ccr_io.cr:39-47/129-130),因此命名行编号或实例名变化会导致 `.ccr` 字节变化(允许,须报告)。 -## 与 P2b 的交接面(阻塞 / 非阻塞) +## 与 P2b 的交接面(阻塞项与非阻塞项) | P3 项 | 阻塞于 P2b? | 说明 | |---|---|---| @@ -75,13 +89,19 @@ | 序列接口 / 横切接口 | **是** | 横切轴条目(`sequence<⊤>`、只读/可写两形状)属注册表;P3 增量 = 形状条目内容 + 消费点(索引/切片/迭代)接线 | | impl 契约(用户轴) | **是** | 条目升级(形状项引用 + 满足关系)+ `g_ifaces` 布局 + mangling 退役归 P2b;P3 增量 = 签名类型项化 + 覆盖集 | -**交接契约(要求 P2b 落点提供;若落地形态与此不符 → 停下上报后重定 Task 2/6)**:① `iface_satisfies(t_ti: int, iface_ni: int) -> int`(三态 1/0/-1,不得静默当 0);② 本质条目留可扩展字段——`操作许可`(P2b 落)与**变型规则**(P3 落;引擎侧表可先在 Task 1 落,条目字段后续挂引用);③ `res_type_node` 单一化后 `TYP_ARRAY`/`TYP_SLICE`/`TYP_NAMED` 构造语义不得变化(Task 0/1 依赖)。 +**交接契约(要求 P2b 落点提供;若落地形态与此不符,则停下上报后重定 Task 2/6)**: +① `iface_satisfies(t_ti: int, iface_ni: int) -> int`,三态取值 1/0/-1,不得静默当 0。 +② 本质条目留可扩展字段——`操作许可`(P2b 落)与**变型规则**(P3 落;引擎侧表可先在 Task 1 落,条目字段后续挂引用)。 +③ `res_type_node` 单一化后,`TYP_ARRAY`/`TYP_SLICE`/`TYP_NAMED` 的构造语义不得变化(Task 0/1 依赖)。 -> **P2b 已落地(2026-09-11,提交链 `7f520dce`→`30545da7`)——本条契约按 P2b 实际交付面重定,实施前必读附录 A;⚠ 其后的 ① 已被 P3b Task 0 关闭(2026-09-12,见附录 B.1 首注)**:① **`iface_satisfies` 未交付**(P2b 范围明标「零调用者,P3 落地 impl 语义时才有对象」,见附录 A.3-①)⇒ Task 2/6 与 Task 5 的 `T: I` 满足半边**开工前先补条目 + 满足判定**;② 条目表已落 5 字段 `{ak, ti_row, name_ni, lit_code, ops}`(40B/条,无变型规则字段;`name_ni` 现为 `-1`——.ccr STR 段硬判据,见 A.3-②)⇒ 变型规则无处挂,Task 1 按「引擎侧表先行」约定落地(本计划原文已备此路);③ 已满足:`res_type_node`/`res_call_type` 经单表 `ty_code_to_ti`,`TYP_ARRAY`/`TYP_SLICE`/`TYP_NAMED` 三构造语义零变化(P2b 全判据 = 零行为变化)。 +> **P2b 已落地(2026-09-11,提交链 `7f520dce`→`30545da7`)——本条契约按 P2b 实际交付面重定,实施前必读附录 A。⚠ 上述第 ① 项已被 P3b Task 0 关闭(2026-09-12,见附录 B.1 首注)**: +> ① **`iface_satisfies` 未交付**(P2b 范围明标「零调用者,P3 落地 impl 语义时才有对象」,见附录 A.3-①),因此 Task 2/6 与 Task 5 的 `T: I` 满足半边**开工前先补条目与满足判定**。 +> ② 条目表已落 5 字段 `{ak, ti_row, name_ni, lit_code, ops}`(40B/条,无变型规则字段;`name_ni` 现为 `-1`——.ccr STR 段硬判据,见 A.3-②),因此变型规则无处挂,Task 1 按「引擎侧表先行」约定落地(本计划原文已备此路)。 +> ③ 已满足:`res_type_node`/`res_call_type` 经单表 `ty_code_to_ti`,`TYP_ARRAY`/`TYP_SLICE`/`TYP_NAMED` 三构造语义零变化(P2b 全判据 = 零行为变化)。 --- -## Task 0(P3a,前置):引擎展开层——named/struct/enum/generic-apply → 结构项 +## Task 0(P3a,前置):引擎展开层(named/struct/enum/generic-apply → 结构项) **Files:** Modify `src/compiler/ty_shadow.cr`(新增展开查询,**不改**既有分支语义)· `src/compiler/checker.cr`(暴露 名字→struct/enum 行 查询)· `src/compiler/type_engine.cr`(满足判定入口占位)· `src/compiler/type_selftest.cr` @@ -93,11 +113,12 @@ fn sh_enum_domain_term(ti: int) -> int // enum named → AK_SUM 变体项之 fn sh_variant_term(ti: int, name_ni: int) -> int // 变体名 → 变体项(穷尽性模式项用) fn sh_iface_shape_term(iface_ni: int) -> int // 接口 → 形状项(方法集 product of fn;P2b 条目就绪前返回 -1) ``` -**语义边界(实施须遵守)**:展开**只服务** ① 满足判定 `T <: 形状` ② 穷尽性域/模式项。**等价/包含判定(`type_equal` 路径)保持原子名义,不展开**——否则同形不同名类型被判等价 = 语义漂移,且推翻 P2a 对拍归零基线。一层深度不足 → 按引擎既有规则 -1 上抛。 +**语义边界(实施须遵守)**:展开**只服务** ① 满足判定 `T <: 形状` 与 ② 穷尽性域/模式项。**等价/包含判定(`type_equal` 路径)保持原子名义,不展开**,否则同形不同名类型会被判等价,构成语义漂移,并推翻 P2a 的对拍归零基线。一层深度不足时,按引擎既有规则 -1 上抛。 -- [ ] **Step 1: 用例(红)6 例**(`type_selftest.cr`):struct → product 字段序;enum → sum 变体数;`Box[int]` 域展开含实参代入;**名义不漂移**(两个同形不同名 struct:`ty_equiv` 仍 **-1**、`type_equal` 仍 false);行号越界 → -1;展开缓存命中计数。**为何 6 例**:四个正向形态 + 一条名义不变量双锁定 + 一条缺口上抛。 -- [ ] **Step 2: 实现 + 缓存**(照 `sh_map_*` 先例:装填守卫 / 重建重放 / 回写重探;`find_struct`/`find_enum`/`find_iface`(checker.cr:824-852)为名字入口)。 -- [ ] **Step 3: 判据**:`selftest-types` **95 → ≥101**;影子对拍复跑(**预期零变化**——展开未接入 `type_equal` 路径;`unknown`/`replace_*` 若变 → 逐条归因登记);ELF canary IDENTICAL(clean-cache);`test_compile`/`test_purity`/`test_ccr_v7` 绿。 +- [ ] **Step 1: 用例(红)6 例**(`type_selftest.cr`):struct → product 字段序;enum → sum 变体数;`Box[int]` 域展开含实参代入;**名义不漂移**(两个同形不同名 struct:`ty_equiv` 仍 **-1**、`type_equal` 仍 false);行号越界 → -1;展开缓存命中计数。 + **为何 6 例**:四个正向形态,加一条名义不变量双锁定,加一条缺口上抛。 +- [ ] **Step 2: 实现 + 缓存**(照 `sh_map_*` 先例:装填守卫、重建重放、回写重探;名字入口为 `find_struct`/`find_enum`/`find_iface`(checker.cr:824-852))。 +- [ ] **Step 3: 判据**:`selftest-types` 由 **95 增至 ≥101**;影子对拍复跑(**预期零变化**,因为展开未接入 `type_equal` 路径;`unknown`/`replace_*` 若变则逐条归因登记);ELF canary IDENTICAL(clean-cache);`test_compile`/`test_purity`/`test_ccr_v7` 绿。 - [ ] **Step 4: 提交**:`feat: R2 P3 Task 0——引擎展开层(struct→product / enum→sum / generic-apply 代入;仅满足判定与域查询用,等价判定保持原子名义)` ## Task 1(P3a):定长退役收尾——array/slice 方向 + 变型 + 长度档位 @@ -112,10 +133,11 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 ``` **语义(spec §5.1)**:`[T;N] <: [T]`(更强长度约束 = 子类型);`[T] ⊄ [T;N]`(除非证 len==N);只读序列视图**协变**、可写视图**不变**;`&T`/`&mut T` 进参数链(mut 标记成为判定维度,替代 ty_shadow.cr:224-227 的「不入链」)。 -- [ ] **Step 1: 用例(红)8 例**:方向 4(`[int;3] <: [int]` = 1 / `[int] <: [int;3]` = 0 / `[int;3]` vs `[int;4]`:等价判 1(N 不入身份)+ 常量档拒 0 / slice vs slice 同元素 = 1);变型 2(只读协变通过、可写不变拒绝);**N 读取面守门 1**(身份路径零 N:`type_equal` 对异长同结构仍 true,且 `array_len_constraint_ok` 是唯一拒绝来源);**动态档登记 1**(切片运行期长度不可证 ⇒ 视图→固定拒绝,不给 -1 当 0)。**为何 8 例**:每条方向/变型规则正负控成对 + N 边界双锁定 + 三态纪律。 +- [ ] **Step 1: 用例(红)8 例**:方向 4 例(`[int;3] <: [int]` = 1;`[int] <: [int;3]` = 0;`[int;3]` vs `[int;4]` 的等价判 1(N 不入身份)加常量档拒 0;slice vs slice 同元素 = 1);变型 2 例(只读协变通过、可写不变拒绝);**N 读取面守门 1 例**(身份路径零 N:`type_equal` 对异长同结构仍 true,且 `array_len_constraint_ok` 是唯一拒绝来源);**动态档登记 1 例**(切片运行期长度不可证 ⇒ 视图→固定拒绝,不给 -1 当 0)。 + **为何 8 例**:每条方向/变型规则的正负控成对,加 N 边界双锁定,加三态纪律。 - [ ] **Step 2: 实现**(变型表首版仅含 `AK_SEQUENCE`/`AK_REF`/`AK_PTR` 三构造子,其余默认不变;`tt_list_same` 改为按 `ty_variance_of` 递归,**不得**改变同形时的既有结果——同形判定仍是 1)。 -- [ ] **Step 3: 行为探针(本任务主判据)**:pA 必须由 rc=0 翻为 **rc=1 + 专属措辞**(收紧清单第 1 条);pB/pC 语义保持(pB rc=0、pC rc=1 TF01);新增 pE(`&mut T` 形参接 `&T` 实参拒绝 / 反向拒绝);嵌套位沿用 f2.* 探针形态(`[[int;3];2]`、`G<[int;3]>`、`*[int;3]`、`(int,[int;3])`)。 -- [ ] **Step 4: 判据**:`selftest-types` 101 → **≥109**;影子对拍复跑(预期零差异——N 面影子已失明,**不得**以对拍充当 N 面证据,findings §11);全语料 report-only(收紧面清单)→ 自举源码 10 处 `[T;N]` 复验零改造;ELF canary IDENTICAL;全回归 + 自举链。 +- [ ] **Step 3: 行为探针(本任务主判据)**:pA 必须由 rc=0 翻为 **rc=1 + 专属措辞**(收紧清单第 1 条);pB/pC 语义保持(pB rc=0、pC rc=1 TF01);新增 pE(`&mut T` 形参接 `&T` 实参拒绝,反向亦拒绝);嵌套位沿用 f2.* 探针形态(`[[int;3];2]`、`G<[int;3]>`、`*[int;3]`、`(int,[int;3])`)。 +- [ ] **Step 4: 判据**:`selftest-types` 由 101 增至 **≥109**;影子对拍复跑(预期零差异——N 面影子已失明,**不得**以对拍充当 N 面证据,findings §11);全语料 report-only(收紧面清单)→ 自举源码 10 处 `[T;N]` 复验零改造;ELF canary IDENTICAL;全回归加自举链。 - [ ] **Step 5: 提交**:`feat: R2 P3 Task 1——定长退役收尾(array<:slice 方向规则 + 只读协变/可写不变变型表 + N 读取面守门;修 slice→数组 静默放宽)` ## Task 2(P3b,P2b 后置):横切接口——序列/可索引/可迭代/product 形状判定接线 @@ -124,10 +146,14 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 **依赖**:P2b 注册表的 `iface_satisfies` 与横切轴条目(交接契约 ①)。若 P2b 只落本质轴操作许可(lead 描述的窄版本),本任务 Step 1 先补横切轴条目再接线,并在报告登记范围扩大。 -- [x] **Step 1: 形状条目细化(spec §2.2 的「待细化」)**:`序列接口` ⟺ `sequence<⊤>`;**只读/可写两形状**(只读 = 协变、可写 = 不变,与 Task 1 变型表同源);`可索引`/`可迭代`/`product` 三条目首版(形状项 = 对应 AK 的 ⊤ 实例化)。——**已交付(2026-09-12)**:六条形状项 = `iface_registry.cr` 横切形状段(`sh_shape_seq` / `sh_shape_seq_ro` / `sh_shape_seq_rw` / `sh_shape_indexable` / `sh_shape_iterable` / `sh_shape_product`)。**两处按实测重定**:① 「`sequence<⊤>`」按 Task 0 §1.3 勘误落 **`⊤ₖ` 类别形**(不变槽遇 ⊤ 落 -1);② 只读形状 = 序列本体 ∪ **只读视图**(`&[⊤ₖ(SEQ)]`,协变槽判定)——「只读 = 协变」在**视图面**兑现,可写形状 = 本体面 + 拒绝只读视图,可写**视图**形状不可表达(-1,登记)。**名字面**:生产路径不注册(注册名 = 驻留 ni,初始化路径 `str_intern` 会动 `.ccr` STR 段 = A.3-② 硬约束)⇒ 消费者走无名字入口 `iface_satisfies_term`;命名消费语法待裁决。 -- [x] **Step 2: 用例(红)6 例**:数组/切片满足序列接口(正);int 不满足(负);只读形状接受数组与切片、可写形状拒绝只读视图;`可索引` 对字符串(TI_STR 索引已支持,checker.cr:2619-2633)正控;接口形状项不可展开 → -1(不得当 0)。——**已交付**:15 例(`x2.*`,两路咬合:形状判定 + 两条**全类型行枚举**等价;含非同一比较断言防快路径冒充判定、零 `str_intern` 守门、注册/复位泄漏守门)。 -- [x] **Step 3: 消费点接线**:索引(checker.cr:2581-2636)/切片(:2586-2602)的 `get_type_kind` 直比改为「形状满足 + 元素项取出」;**行为保持**(既有接受/拒绝集合不变,仅来源换位——如出现差异按收紧清单登记)。——**已交付**:索引兜底门 → 可索引形状(-1 回落许可表);range 分支 → 序列形状 ∧ 固定性位(取自序列项 b 槽,`sh_seq_fixed_len_of_ti`)。结果三分支原地保留(A.2 #16-18)。**差异 = 0**(收紧/放宽皆 0;12 例老/新两二进制逐例同 + 全语料 check 面零差异)。 -- [x] **Step 4: 判据**:`selftest-types` ≥109 → **≥115**;影子对拍复跑(站点 8/5/7 主流量:**判定数应不变**,agree 全绿);行为探针:数组/切片/字符串索引全部正例 + 负例(`int` 索引拒绝);ELF canary IDENTICAL;全回归。——**已交付(按 P3a/P3b-T0 后基线重定阈值)**:`selftest-types` 304 → **319/319**;影子对拍全计数 0(判定数变化逐条归因 = 新源码行自身站点);新套件 12 例挂 `run.sh`;ELF canary `95084e7b…d475` + `.ccr` 逐字节同;全回归 + 自举链 + 突变控制。 +- [x] **Step 1: 形状条目细化(spec §2.2 的「待细化」)**:`序列接口` ⟺ `sequence<⊤>`;**只读/可写两形状**(只读 = 协变、可写 = 不变,与 Task 1 变型表同源);`可索引`/`可迭代`/`product` 三条目首版(形状项 = 对应 AK 的 ⊤ 实例化)。 + ——**已交付(2026-09-12)**:六条形状项 = `iface_registry.cr` 横切形状段(`sh_shape_seq` / `sh_shape_seq_ro` / `sh_shape_seq_rw` / `sh_shape_indexable` / `sh_shape_iterable` / `sh_shape_product`)。**两处按实测重定**:① 「`sequence<⊤>`」按 Task 0 §1.3 勘误落 **`⊤ₖ` 类别形**(不变槽遇 ⊤ 落 -1);② 只读形状 = 序列本体 ∪ **只读视图**(`&[⊤ₖ(SEQ)]`,协变槽判定)——「只读 = 协变」在**视图面**兑现;可写形状 = 本体面 + 拒绝只读视图,可写**视图**形状不可表达(-1,登记)。**名字面**:生产路径不注册(注册名 = 驻留 ni,初始化路径 `str_intern` 会动 `.ccr` STR 段 = A.3-② 硬约束),因此消费者走无名字入口 `iface_satisfies_term`;命名消费语法待裁决。 +- [x] **Step 2: 用例(红)6 例**:数组/切片满足序列接口(正);int 不满足(负);只读形状接受数组与切片、可写形状拒绝只读视图;`可索引` 对字符串成立(TI_STR 索引已支持,checker.cr:2619-2633)为正控;接口形状项不可展开时返回 -1(不得当 0)。 + ——**已交付**:15 例(`x2.*`),两路咬合——形状判定,加两条**全类型行枚举**等价;含非同一比较断言(防快路径冒充判定)、零 `str_intern` 守门与注册/复位泄漏守门。 +- [x] **Step 3: 消费点接线**:索引(checker.cr:2581-2636)与切片(:2586-2602)的 `get_type_kind` 直比改为「形状满足 + 元素项取出」;**行为保持**(既有接受/拒绝集合不变,仅来源换位——如出现差异按收紧清单登记)。 + ——**已交付**:索引兜底门 → 可索引形状(-1 回落许可表);range 分支 → 序列形状 ∧ 固定性位(取自序列项 b 槽,`sh_seq_fixed_len_of_ti`)。结果三分支原地保留(A.2 #16-18)。**差异 = 0**(收紧与放宽皆 0;12 例老/新两二进制逐例同,加全语料 check 面零差异)。 +- [x] **Step 4: 判据**:`selftest-types` 由 ≥109 增至 **≥115**;影子对拍复跑(站点 8/5/7 主流量:**判定数应不变**,agree 全绿);行为探针:数组/切片/字符串索引全部正例加负例(`int` 索引拒绝);ELF canary IDENTICAL;全回归。 + ——**已交付(按 P3a/P3b-T0 后基线重定阈值)**:`selftest-types` 由 304 增至 **319/319**;影子对拍全计数 0(判定数变化逐条归因 = 新源码行自身站点);新套件 12 例挂 `run.sh`;ELF canary `95084e7b…d475` 加 `.ccr` 逐字节同;全回归加自举链加突变控制。 - [x] **Step 5: 提交**:`feat: R2 P3 Task 2——横切接口接线(序列/可索引/可迭代/product 形状满足判定取代 TYP_* 直比;只读协变/可写不变两形状)` ## Task 3(P3a):穷尽性真判定——match 补集空性 + 反例值 @@ -137,32 +163,37 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 **语义(spec §5.4)**:穷尽性 = 补集空性 ⇒ `ty_exhaustive(domain, patterns)`;反例给**具体值**(未被覆盖的变体名)。**域限定**:仅枚举 scrutinee 判穷尽(域 = 变体集);int/string/bool/char 字面量模式与通配的域不判穷尽(**显式登记**:非枚举域不判,不得假装穷尽或假装不穷尽);`-1`(未知)**不得**升为「不穷尽」硬错误。 - [ ] **Step 1: 模式项收集**:臂模式 → 项(枚举模式 = `sh_variant_term`;绑定 ident = 通配但**不绑定值域**;通配 = ⊤);scrutinee 类型 → 域项(`sh_enum_domain_term`,Task 0)。 -- [ ] **Step 2: 用例(红)8 例**(引擎层,`type_selftest.cr`):全变体覆盖 = 1 / 缺一变体 = 0 + witness = 该变体 / 通配吸收 = 1 / 单变体枚举 = 1(无臂 = 0)/ 域不可展开(`AK_NAMED` 不展开)= -1(不得当 0)/ 空枚举域 = 0(无值可覆盖,登记语义)/ 重复臂 → 补集已空(`EC_TM_REDUNDANT` 同源判据)/ payload 变体与 tag 变体混合。**「非枚举域不判穷尽」是 checker 侧登记项**(不调引擎),验证在 Step 4 行为集,不占引擎用例。 -- [ ] **Step 3: 硬错误门(report-only 先行)**:`EC_TM_EXHAUST`(9003)入 `run_frontend` 硬名单前,全语料 report-only;清单若空 → 开门(main.cr:146-158 追加一行)。**冗余臂(9004)同期评估**(同族判据,可同批)。 -- [ ] **Step 4: 行为覆盖集**:新增 `tests/selfhost/test_match_exhaust.py`(≥8 例:穷尽过 / 缺臂拒 + 码 + **无产物** / 通配过 / 嵌套枚举 / payload 变体 / 空枚举边界 / 非枚举域不报穷尽 / 泛型枚举实例),挂钩 `src/ci/run.sh` selfhost-tests。 -- [ ] **Step 5: 判据**:`selftest-types` ≥115 → **≥123**;镜像回归:`test_interp_float.py`(3 变体全列)、`test_interp_parity.py`、`test_native_memory.py` 全绿(**这些是唯一既有 match 语料**);ELF canary IDENTICAL;全回归 + 自举链。 +- [ ] **Step 2: 用例(红)8 例**(引擎层,`type_selftest.cr`):全变体覆盖 = 1;缺一变体 = 0 且 witness = 该变体;通配吸收 = 1;单变体枚举 = 1(无臂 = 0);域不可展开(`AK_NAMED` 不展开)= -1(不得当 0);空枚举域 = 0(无值可覆盖,登记语义);重复臂 → 补集已空(`EC_TM_REDUNDANT` 同源判据);payload 变体与 tag 变体混合。 + **「非枚举域不判穷尽」是 checker 侧登记项**(不调引擎),验证在 Step 4 行为集,不占引擎用例。 +- [ ] **Step 3: 硬错误门(report-only 先行)**:`EC_TM_EXHAUST`(9003)入 `run_frontend` 硬名单前,先跑全语料 report-only;清单若空 → 开门(main.cr:146-158 追加一行)。**冗余臂(9004)同期评估**(同族判据,可同批)。 +- [ ] **Step 4: 行为覆盖集**:新增 `tests/selfhost/test_match_exhaust.py`(≥8 例:穷尽过;缺臂拒加码加**无产物**;通配过;嵌套枚举;payload 变体;空枚举边界;非枚举域不报穷尽;泛型枚举实例),挂钩 `src/ci/run.sh` 的 selfhost-tests。 +- [ ] **Step 5: 判据**:`selftest-types` 由 ≥115 增至 **≥123**;镜像回归:`test_interp_float.py`(3 变体全列)、`test_interp_parity.py`、`test_native_memory.py` 全绿(**这些是唯一既有 match 语料**);ELF canary IDENTICAL;全回归加自举链。 - [ ] **Step 6: 提交**:`feat: R2 P3 Task 3——match 穷尽性真判定(补集空性 + 具体变体反例;仅枚举域,非枚举显式登记)+ TM03 硬门 + 覆盖集` ## Task 4(P3a):联合/可选——enum = sum 项、`T?` = T ∪ null、退役内建 Option 注册 **Files:** Modify `src/compiler/checker.cr`(:962-975 退役;`EXPR_TRY` :2871-2888 去名字依赖)· `src/compiler/parser.cr`(`T?` 目标形态)· `src/compiler/ty_shadow.cr`(null 项)· `src/compiler/type_selftest.cr` · New `tests/selfhost/test_optional.py` -**决策点(实施前须定,语义争议 → 停下上报,spec 裁决 6)**:`null` 的类型承载。spec §5.4 写「`T?` = `T ∪ null`」,但 §1.2 原生八员**无 `null`**。候选:**(a) 新增原生原子 `AK_NULL`(原生九员,值域单点)**——推荐(`None` 值、`T ∪ null` 直接成立、与 AK_UNIT 不相交);(b) `null` 归 `AK_UNIT`(值域混淆,不推荐);(c) 仅保留枚举形态(= 不做此项,与 spec 相悖)。**裁定前不实施本任务 Step 2+**。 +**决策点(实施前须定;语义争议时停下上报,spec 裁决 6)**:`null` 的类型承载。spec §5.4 写「`T?` = `T ∪ null`」,但 §1.2 的原生八员中**无 `null`**。候选方案如下。 +- **(a) 新增原生原子 `AK_NULL`(原生九员,值域单点)**——推荐:`None` 值可用、`T ∪ null` 直接成立、与 AK_UNIT 不相交。 +- **(b) `null` 归 `AK_UNIT`**(值域混淆,不推荐)。 +- **(c) 仅保留枚举形态**(= 不做此项,与 spec 相悖)。 +**裁定前不实施本任务 Step 2+**。 -- [ ] **Step 1: 用例(红)6 例**:`T?` 的项 = `T ∪ null`(`ty_equiv`)/ `None` 满足 `T?`(子类型)/ `Some(1)` 满足 `int?` / `null` 与 `int` 不相交(`ty_disjoint`)/ 联合在 match 域上的穷尽性(`T?` 两分支:有值 + None)/ 退役后 `Option` 名字不再被 bultin 注册(行数对照)。 +- [ ] **Step 1: 用例(红)6 例**:`T?` 的项 = `T ∪ null`(`ty_equiv`);`None` 满足 `T?`(子类型);`Some(1)` 满足 `int?`;`null` 与 `int` 不相交(`ty_disjoint`);联合在 match 域上的穷尽性(`T?` 两分支:有值加 None);退役后 `Option` 名字不再被 bultin 注册(行数对照)。 - [ ] **Step 2: 实现**:`Some`/`None` 在无用户 `enum Option` 时仍可解析(parser.cr:418-431 的名字路径接 `T?` 的联合项);`EXPR_TRY` 改按**类型项结构**(`AK_SUM`/联合含 null)解包,废掉基名字符串 `"Option"`/`"Result"`(checker.cr:2879 的 `base_name ==` 判断)。 -- [ ] **Step 3: 判据**:`selftest-types` ≥123 → **≥129**;`.ccr` **预期变**(退役一个命名行 → 行号位移)→ 实测报告 + `test_ccr_v7` 结构性断言全绿 + 冷缓存对比;ELF canary IDENTICAL(若变 → 停下上报);`test_optional.py` ≥8 例(含解释器/ELF 双路径 rc);全回归。 +- [ ] **Step 3: 判据**:`selftest-types` 由 ≥123 增至 **≥129**;`.ccr` **预期变**(退役一个命名行 → 行号位移)→ 实测报告,加 `test_ccr_v7` 结构性断言全绿,加冷缓存对比;ELF canary IDENTICAL(若变**即停下上报**);`test_optional.py` ≥8 例(含解释器/ELF 双路径 rc);全回归。 - [ ] **Step 4: 提交**:`feat: R2 P3 Task 4——可选 = 联合(T? = T ∪ null;退役内建 Option 注册与 EXPR_TRY 名字解包)` ## Task 5(P3a 主 + P3b 半):泛型约束——保留/实例化判定/monomorph 类型项化 **Files:** Modify `src/compiler/parser.cr`(:1533/:1575 结构/枚举泛型约束不再丢)· `src/compiler/checker.cr`(声明处约束登记 + `ty_sub(实参, 约束)` 实例化判定)· `src/compiler/monomorph.cr` + `src/compiler/ir_gen.cr:1497-1513`(实例键类型项化)· `src/compiler/type_selftest.cr` -- [ ] **Step 1: F4 同族复核(TODO #2026-09-11-4)**:`infer_gen_call` 的形参链导航(`ast_data(pn)`)在后续形参上取到 `gparam(T)` 而非声明类型——本任务先修此(否则实例化判定拿不到正确的实参类型);用例正/负控各一。 +- [ ] **Step 1: F4 同族复核(TODO #2026-09-11-4)**:`infer_gen_call` 的形参链导航(`ast_data(pn)`)在后续形参上取到 `gparam(T)` 而非声明类型。本任务先修此(否则实例化判定拿不到正确的实参类型);用例正/负控各一。 - [ ] **Step 2: 结构/枚举泛型约束落地**:`parse_generics_into` 的约束不再写 dummy(parser.cr:1533/1575),登记到结构/枚举侧表(照 `g_generic_constr` 先例,索引空间分家);声明处检查 = 实例化点(`Box[T: I]` 的 `Box[P]`)。 - [ ] **Step 3: 实例化判定引擎化**:`T: I` 检查 = `ty_sub(实参项, 约束项)`(约束为**类型项**;本质轴形状用引擎、用户接口形状待 P2b 的 `iface_satisfies` ⇒ **本步本质轴部分 P3a 可做,用户接口部分 P3b**);失败给**非空反例**(`tt_witness`),诊断含反例值;`-1` 不得当 0。 - [ ] **Step 4: monomorph 类型项化**:实例键由「调用实参名串(非原生 → `"int"` 兜底)」改为「**类型项结构哈希**(含命名/泛型应用实参真身份)」;`gen_build_subst` 名字替换升级为类型项替换(或按项哈希生成规范名)。**产物面**:实例 mangled 名若变 → SYM/`.ccr` 变(允许、实测报告;ELF 无 symtab ⇒ 预期不变);去重正确性探针:两个**不同结构体类型**实参调用同一泛型函数 → 必须是两个实例(今天可能折叠——**未实测**,本步实测并登记)。 -- [ ] **Step 5: 判据**:`selftest-types` ≥129 → **≥137**;`MAX_GENERICS=4`(ast.cr:115)解除或显式登记(二选一,记录理由);行为探针:约束满足/违反(含反例文本)/结构泛型约束/双类型实参实例分离;影子对拍复跑 + 全回归 + ELF canary IDENTICAL + `.ccr` 实测报告 + 自举链。 +- [ ] **Step 5: 判据**:`selftest-types` 由 ≥129 增至 **≥137**;`MAX_GENERICS=4`(ast.cr:115)解除或显式登记(二选一,记录理由);行为探针:约束满足/违反(含反例文本)/结构泛型约束/双类型实参实例分离;影子对拍复跑,加全回归,加 ELF canary IDENTICAL,加 `.ccr` 实测报告,加自举链。 - [ ] **Step 6: 提交**:`feat: R2 P3 Task 5——泛型约束(结构/枚举约束不再丢 + 实例化 ty_sub 判定 + 反例;monomorph 实例键类型项化)+ F4 形参链修复` ## Task 6(P3b,P2b 后置):impl 契约——签名类型项化 + 满足判定接引擎 + mangling 退役 + 覆盖集 @@ -172,15 +203,17 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 **依赖**:P2b 注册表(条目 + 满足关系 + `iface_satisfies`)。**mangling 废弃**(spec §2.3/§5.3,无兼容窗口 = 裁决 5)。 - [x] **Step 1: 签名类型项化**:`interface I { fn m(a: T) -> U; }` 的 T/U 从裸 `TY_*` 改为类型节点解析(`res_type_node`)——**现状只能写基类型**(parser.cr:1671/1685);方法上限 16 / 参数上限 8(dyn_arr.cr:143-149)**解除或显式登记**。——**已交付(2026-09-12)**:方法条目新增类型**节点**槽(`OFF_IFM_PARAM_NODES` / `OFF_IFM_RET_NODE` / `OFF_IFM_SELF_MODE`;`ESZ_IFMETHOD` 88→168、`ESZ_IFACEINFO` 1432→2712——**不入 `.ccr` 序列化**,实测逐字节同)+ parser 写点;**裸码槽保留**(S6 站点返回型映射值域 = 映射层编码,P2b Task 6 已锁定);参数裸码槽自本批起**零读者**(登记)。**上限显式登记保留**(`MAX_IFACE_METHODS=16` / `MAX_IFACE_METHOD_PARAMS=8` 单源常量;超限 = **硬错 rc=1** 非静默截断,新套件两例固定;解除面 = 方法表迁侧表,按 B.4-7 约定「先加护栏、再评估解除」)。 -- [x] **Step 2: 覆盖集(spec §5.3 要求新建)**:`test_impl_iface.py` ≥10 例——正向(满足)/ 反向(缺方法、参数数不符、参数类型不符、返回类型不符)/ 多接口 / 与泛型约束交互(`fn f[T: I]`)/ 错误例(未定义接口)/ 固有方法不受影响(`test_impl.py` 7 例保持绿)。——**已交付**:**20 例**(正向 **双站点**同证(实例化点注解 + 函数调用点)7 + 泛型体内方法调用运行面 2 + 反向签名五面 7 + 错误例 1 + 登记面 1 + 上限硬错 2)。**双站点是硬要求**(Task 0 M4 教训实测):只走实例化点的正例在突变下不咬合(本轮一度空转,已修)。解释器面登记:泛型体内方法调用 `corec run` 解析不支持(旧二进制同 rc=1)⇒ 该 2 例走 check + ELF。 -- [x] **Step 3: 满足判定接引擎**:`check_iface`/`check_impl_for` 改走 `iface_satisfies`(形状项包含判定);方法解析(`type_has_method` 名字拼接,checker.cr:873-879)改「类型项 + 条目」查表;泛型约束的方法调用路径(:2103-2144)同步。——**已交付(按实测重定两处)**:① 形状项 `sh_iface_shape_term` = 方法集(product of fn,b 槽 = 方法名)**已建**;判定 = **逐成员包含**(方法名表查询 + 接收者模式显式比较 + 签名 fn 项经引擎结构比较原语 `tt_list_same`)。**整形状 `ty_sub` 路由不可用**(实测两条:引擎对 AK_NAMED 不展开 ⇒ 命名行实参恒 -1;product 比较是结构相等非子集包含 ⇒ 带额外方法的实现方误拒)——登记为未覆盖面。**逐成员签名比较不得用 `ty_sub`**:引擎把不变槽的「确定不同」上抛 **-1** ⇒ 签名不符退化「不判」= 静默通过面复活(突变 M3b 实证 8 自测 + 3 行为例红);签名项为规范形(N 不入项 / 泛型应用展开 / 命名行按名)⇒ `tt_list_same`(0/1 全域)即正确判据。② `check_iface` = 与 `iface_user_satisfies` **同一核心**(`iface_user_satisfies_ii`,同源由构造保证);`check_impl_for` 逐参/返回比较**同改签名项**(诊断码/措辞保留);泛型约束方法调用路径 → **实例化时查表解析**(`CALL_FLAG_IFACE_METHOD` + monomorph 克隆分支)——**旧态产物运行 rc=139**(合成 "T.m" 串 + 文本替换 ⇒ 调用目标悬空),本批修。 +- [x] **Step 2: 覆盖集(spec §5.3 要求新建)**:`test_impl_iface.py` ≥10 例——正向(满足)/ 反向(缺方法、参数数不符、参数类型不符、返回类型不符)/ 多接口 / 与泛型约束交互(`fn f[T: I]`)/ 错误例(未定义接口)/ 固有方法不受影响(`test_impl.py` 7 例保持绿)。 + ——**已交付**:**20 例**(正向 **双站点**同证(实例化点注解 + 函数调用点)7 例;泛型体内方法调用运行面 2 例;反向签名五面 7 例;错误例 1 例;登记面 1 例;上限硬错 2 例)。**双站点是硬要求**(Task 0 M4 教训实测):只走实例化点的正例在突变下不咬合(本轮一度空转,已修)。解释器面登记:泛型体内方法调用 `corec run` 解析不支持(旧二进制同 rc=1),因此该 2 例走 check 加 ELF。 +- [x] **Step 3: 满足判定接引擎**:`check_iface`/`check_impl_for` 改走 `iface_satisfies`(形状项包含判定);方法解析(`type_has_method` 名字拼接,checker.cr:873-879)改「类型项 + 条目」查表;泛型约束的方法调用路径(:2103-2144)同步。 + ——**已交付(按实测重定两处)**:① 形状项 `sh_iface_shape_term` = 方法集(product of fn,b 槽 = 方法名)**已建**;判定 = **逐成员包含**(方法名表查询 + 接收者模式显式比较 + 签名 fn 项经引擎结构比较原语 `tt_list_same`)。**整形状 `ty_sub` 路由不可用**(实测两条:引擎对 AK_NAMED 不展开 ⇒ 命名行实参恒 -1;product 比较是结构相等非子集包含 ⇒ 带额外方法的实现方误拒),登记为未覆盖面。**逐成员签名比较不得用 `ty_sub`**:引擎把不变槽的「确定不同」上抛 **-1** ⇒ 签名不符退化为「不判」= 静默通过面复活(突变 M3b 实证 8 自测加 3 行为例红);签名项为规范形(N 不入项 / 泛型应用展开 / 命名行按名)⇒ `tt_list_same`(0/1 全域)即正确判据。② `check_iface` = 与 `iface_user_satisfies` **同一核心**(`iface_user_satisfies_ii`,同源由构造保证);`check_impl_for` 逐参/返回比较**同改签名项**(诊断码/措辞保留);泛型约束方法调用路径 → **实例化时查表解析**(`CALL_FLAG_IFACE_METHOD` + monomorph 克隆分支)——**旧态产物运行 rc=139**(合成 "T.m" 串 + 文本替换 ⇒ 调用目标悬空),本批修。 - [x] **Step 4: 判据**:`selftest-types` ≥137 → **≥141**;`test_impl.py` 7/7 不回归 + 新套件全绿 + `src/ci/run.sh` 挂钩;影子对拍复跑;全回归;ELF canary IDENTICAL;`.ccr` 实测报告(接口目前零序列化 ⇒ 预期不变)。——**已交付(阈值按 P3a/P3b 后基线重定)**:`selftest-types` 319 → **333/333**(+14 `ifc.*`);新套件 **20/20** 挂 `run.sh`;`test_impl` 7/7 + 六套件全绿(`test_iface_satisfies` 按清单改 1 例后 17/17);ELF canary `95084e7b…d475` IDENTICAL + `.ccr` 逐字节同(88943B/130974B——接口零序列化 + 零新 `str_intern`);影子 30628/30628(全计数 0,站点同报);同源对拍 72 档零差异;五 CI job;更宽 selfhost 45/45 + `test_backend_bootstrap` rc=0;突变控制 4 条(M4 = 行为级独有牙,登记)。 - [x] **Step 5: 提交**:`feat: R2 P3 Task 6——impl 契约(接口签名类型项化 + iface_satisfies 接引擎 + mangling 退役)+ 覆盖集`(提交见 §11 / 本批报告) ## Task 7:收官(回归 + 判据 + 收紧清单 + 文档) - [ ] **Step 1: 全量回归**(`src/ci/run.sh` selfhost + bootstrap 全档) -- [ ] **Step 2: 零变化复验**:ELF canary IDENTICAL(clean-cache,开/关两态)+ `.ccr` 变更面实测报告(逐任务列)+ 影子对拍终态(差异/站点覆盖/回落计数同报) +- [ ] **Step 2: 零变化复验**:ELF canary IDENTICAL(clean-cache,开/关两态)加 `.ccr` 变更面实测报告(逐任务列)加影子对拍终态(差异/站点覆盖/回落计数同报) - [ ] **Step 3: 自举链**:`corec2/corec3` `cmp` IDENTICAL + N06=0 + 冒烟 `run 'fn main()->int{return 42;}'` = 42 - [ ] **Step 4: 收紧清单汇总**:本批「旧接受 → 新拒绝」逐条(预期 ≥1 条:pA 切片→数组;标「P2a 引入的静默放宽在本批关闭」) - [ ] **Step 5: 文档**:spec §9 P3 行标 ✅ + 未覆盖面更新(符号档登记);TODO:`fixed-array-retire`(TODO.md:446)未办句划销、#19 的「P3 面遗留」收尾、#26 判据继承、新增登记(非枚举域不判穷尽 / 空递归保守 / MAX_* 上限处置);findings 文档追加「P3 后复跑」节 @@ -195,7 +228,7 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 > P3b = Task 0(契约回补 `9aa1786c`)/ Task 2(横切接口 `44100ba4`)/ Task 6(impl 契约 `e838f18b`)三件;本 Task = 三份任务报告(`.superpowers/sdd/p3b-task{0,2,6}-report.md`)之上的**阶段收官**——全量回归 + 判据复验 + 清单统一 + P4 交接包(附录 C)。判据标准继承:**本轮实跑 vs 继承基线逐条标注**(收官报告 §1/§2)。 -- [x] **Step 1: 全量回归**——五 CI job(selfhost-tests / bootstrap-tests / suite / full-bootstrap / check)rc + 逐档计数;全枚举 selfhost 45 档 + bootstrap 7 档逐档 rc;`check` job rc=1 = **既有 red 划界**(恰 2 条 TF01 误报 `lits_copy`/`ty_memo_slot_no_grow`,非本批引入)。✅ 实测见收官报告 §1。【**2026-09-13 更新**:两条已修(TODO #2026-09-13-1)⇒ `check src/compiler` rc=0,该划界约定作废(行保留为当期实跑记录)。】 +- [x] **Step 1: 全量回归**——五 CI job(selfhost-tests / bootstrap-tests / suite / full-bootstrap / check)rc 加逐档计数;全枚举 selfhost 45 档 + bootstrap 7 档逐档 rc;`check` job rc=1 = **既有 red 划界**(恰 2 条 TF01 误报 `lits_copy`/`ty_memo_slot_no_grow`,非本批引入)。✅ 实测见收官报告 §1。【**2026-09-13 更新**:两条已修(TODO #2026-09-13-1)⇒ `check src/compiler` rc=0,该划界约定作废(行保留为当期实跑记录)。】 - [x] **Step 2: 判据复验**——`clean-cache` → ELF canary `95084e7b…d475` IDENTICAL;`corec2/corec3` `cmp` IDENTICAL + N06=0 + 冒烟 42 + `corec3 --help` rc=1(既有约定);`.ccr` 面(`ptr_arith`/`generics_test`)。✅ 实测见收官报告 §2。 - [x] **Step 3: 统一清单**(P3b 三件聚合;下表 = 收紧 **10** / 放宽 **0** / 崩溃修复 **1**;全语料零命中,逐任务同源对拍零差异) - [x] **Step 4: P3 总状态 + 未开工清单**(见本节末) @@ -237,29 +270,43 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 | T2 | check 面 `diff -r` **空**(rc 分布 33×0 / 39×1 两侧同) | 30400 / 30400;**旧×新同值** | 形状面零命中(行为保持批) | | T6 | check 面 `diff -r` **空**;shadow dump 空 | 30628 / 30628;**旧×新同值** | `interface`/`impl I for T`/`T: I` 生产用法零命中 | -> 影子判定数逐任务增量(30128 → 30271 → 30400 → 30628)**均为新增源码自身的站点**(旧二进制跑同一新源得完全相同的数)——「零差异」≠「面收敛」的声明继承 P3a(B.3);P3b 新能力面正确性由各任务的定向探针(T0 17 例 / T2 12 例 / T6 20 例)+ 用例表(+45 `isat.*`/`x2.*`/`ifc.*`)+ 突变控制(4+3+4 条)承担。 +> 影子判定数的逐任务增量(30128 → 30271 → 30400 → 30628)**均为新增源码自身的站点**(旧二进制跑同一新源得到完全相同的数)。「零差异」不等于「面收敛」的声明继承 P3a(B.3);P3b 新能力面的正确性由各任务的定向探针(T0 17 例 / T2 12 例 / T6 20 例)、用例表(+45 `isat.*`/`x2.*`/`ifc.*`)与突变控制(4+3+4 条)承担。 ### P3 阶段总状态(P3a + P3b) -- **交付面**:五项目标能力**全部接通**——定长退役(T1)· 序列接口/长度约束(T2)· 穷尽性/联合/可选(T3/T4)· 泛型约束(T5 + T0b 的 `T: I` 半边)· impl 契约(T6)。`selftest-types` **95 → 333**;新套件 **6 个**(P3a 3 + P3b 3)= `test_match_exhaust` 16 · `test_optional` 12 · `test_generic_constr` 15 · `test_iface_satisfies` 17 · `test_xcut_iface` 12 · `test_impl_iface` 20(全挂 `run.sh`)。 -- **收紧/放宽总账**:P3a 收紧 **18** / 放宽 **8** / 诊断面新增 1(TM04 软)/ 实例名忠实化 6 / 挂死修复 2 端;P3b 收紧 **10** / 放宽 **0** / 崩溃修复 1 ⇒ **P3 合计:收紧 28 · 放宽 8 · 软诊断面 +1 · 挂死与崩溃修复 3 端**(全语料零命中;自举源码零改造)。 -- **判据面**:ELF canary `95084e7b…d475` **全阶段 IDENTICAL**(类型层改动零泄漏发射面);`.ccr` 变更面 = T4 `ptr_arith` STR 段 −10B + T5 `generics_test` +370B(反折叠),P3b 三件**零变更**;自举链 `corec2/corec3` `cmp` IDENTICAL + N06=0 + 冒烟 42 全程稳定。 +- **交付面**:五项目标能力**全部接通**——定长退役(T1)、序列接口/长度约束(T2)、穷尽性/联合/可选(T3/T4)、泛型约束(T5 加 T0b 的 `T: I` 半边)、impl 契约(T6)。`selftest-types` 由 **95 增至 333**;新套件 **6 个**(P3a 3 个 + P3b 3 个)= `test_match_exhaust` 16、`test_optional` 12、`test_generic_constr` 15、`test_iface_satisfies` 17、`test_xcut_iface` 12、`test_impl_iface` 20(全部挂 `run.sh`)。 +- **收紧/放宽总账**:P3a 收紧 **18**、放宽 **8**、诊断面新增 1(TM04 软)、实例名忠实化 6、挂死修复 2 端;P3b 收紧 **10**、放宽 **0**、崩溃修复 1。⇒ **P3 合计:收紧 28、放宽 8、软诊断面 +1、挂死与崩溃修复 3 端**(全语料零命中;自举源码零改造)。 +- **判据面**:ELF canary `95084e7b…d475` **全阶段 IDENTICAL**(类型层改动零泄漏发射面);`.ccr` 变更面 = T4 的 `ptr_arith` STR 段 −10B,加 T5 的 `generics_test` +370B(反折叠),P3b 三件**零变更**;自举链 `corec2/corec3` `cmp` IDENTICAL + N06=0 + 冒烟 42 全程稳定。 **未开工 / 未实现清单(显式;P3 未覆盖面终态)** -1. **iterable 面接线**:`EXPR_FOR` 现状**零类型检查**(`checker.cr:2810-2821`——`infer_expr(iter)` 返回值被丢弃、循环变量恒 `TI_INT`;T2 登记项④)⇒ 接线 = 新判定 + 可能的新硬门,须 report-only 专批。 -2. **形状命名消费语法**(`T: 可索引`)+ **`.ccr` STR 段增长裁决**(A.3-② 后续;两者同一裁决的两面,见附录 C.6-①)。 -3. **整形状 `ty_sub` 路由**(T6 实测不可用:引擎 `AK_NAMED` 不展开 ⇒ 命名行恒 -1;product 比较 = 结构相等非子集包含)⇒ 形状项作**签名载体**由逐成员判定消费(`tt_list_same`)。 -4. **上限族保留**:`MAX_GENERICS=4`(ast.cr:115)· `MAX_IFACE_METHODS=16` / `MAX_IFACE_METHOD_PARAMS=8`(dyn_arr.cr:162/167,硬错护栏已立 = 非静默截断)· `MAX_ENUM_VARIANTS`/`MAX_VARIANT_TYPES=16`(TODO #2026-09-12-2)——「先加护栏、再评估解除」。 -5. **TODO #2026-09-12-5 名义 vs 结构裁决**(用户轴约定;维护者裁——采纳会翻转 5+ 既有锁定,见 C.6-②)。 -6. **运行期可选表示统一**(B.7 一等条目:`Some` 臂双路径 SIGSEGV rc=139,check/build rc=0 零诊断)——P3b 未动;修法与 P4 的 TYPE 段同批裁(C.6-⑤)。 -7. **TODO #2026-09-11-14**(`EXPR_LET` 无任何兼容检查;实测 `x: [int;4] = [1,2,3]` / `y: int = x`(x 为 `int?`)rc=0)。 -8. **TODO #2026-09-12-2**(前端枚举表写入侧无护栏:≥17 变体越界写;check 静默 rc=0 / build rc=1 在读回闸)。 -9. **其余未覆盖面(登记,非漏放)**:可写视图形状不可表达(不变槽遇 ⊤ 落 -1)· 索引侧「须 int」位缺失(A.3-⑧)· dyn 与字段面未接线(A.2 #23/#28)· 符号档长度约束 = **VC 义务,不实现** · `Box[S]` 命名实参 vs 原生约束 = -1 不判(B.4-3)· 接口泛型形参 `interface I[T]` 被 parser 丢弃 · 变参签名不可表达 · `save_func_gen_constrs` 稀疏零初值(B.4-1,未触发)· bootstrap `&&`/`||` 不短路根因(B.4-12)· 空递归保守 -1 · 非枚举域不判穷尽 · 空枚举域 = 空洞穷尽 · `never` 语义裁决(B.4-2)· 性能面 `(ak → entry)` 快表无必要(实测)。 +1. **iterable 面接线**:`EXPR_FOR` 现状**零类型检查**(`checker.cr:2810-2821`——`infer_expr(iter)` 的返回值被丢弃,循环变量恒 `TI_INT`;T2 登记项④)。⇒ 接线 = 新判定加可能的新硬门,须 report-only 专批。 +2. **形状命名消费语法**(`T: 可索引`)与 **`.ccr` STR 段增长裁决**(A.3-② 后续;两者为同一裁决的两面,见附录 C.6-①)。 +3. **整形状 `ty_sub` 路由**(T6 实测不可用:引擎 `AK_NAMED` 不展开 ⇒ 命名行恒 -1;product 比较 = 结构相等非子集包含)。⇒ 形状项作为**签名载体**,由逐成员判定消费(`tt_list_same`)。 +4. **上限族保留**:`MAX_GENERICS=4`(ast.cr:115)、`MAX_IFACE_METHODS=16` 与 `MAX_IFACE_METHOD_PARAMS=8`(dyn_arr.cr:162/167,硬错护栏已立 = 非静默截断)、`MAX_ENUM_VARIANTS`/`MAX_VARIANT_TYPES=16`(TODO #2026-09-12-2)——统一口径为「先加护栏、再评估解除」。 +5. **TODO #2026-09-12-5 名义 vs 结构裁决**(用户轴约定,由维护者裁定;采纳会翻转 5+ 既有锁定,见 C.6-②)。 +6. **运行期可选表示统一**(B.7 一等条目:`Some` 臂双路径 SIGSEGV rc=139,而 check/build rc=0 零诊断)——P3b 未动;修法与 P4 的 TYPE 段同批裁定(C.6-⑤)。 +7. **TODO #2026-09-11-14**(`EXPR_LET` 无任何兼容检查;实测 `x: [int;4] = [1,2,3]` 与 `y: int = x`(x 为 `int?`)均 rc=0)。 +8. **TODO #2026-09-12-2**(前端枚举表写入侧无护栏:≥17 变体越界写;check 静默 rc=0,build 在读回闸处 rc=1)。 +9. **其余未覆盖面(登记,非漏放)**:逐条如下。 + - 可写视图形状不可表达(不变槽遇 ⊤ 落 -1)。 + - 索引侧「须 int」位缺失(A.3-⑧)。 + - dyn 与字段面未接线(A.2 #23/#28)。 + - 符号档长度约束 = **VC 义务,不实现**。 + - `Box[S]` 命名实参 vs 原生约束 = -1 不判(B.4-3)。 + - 接口泛型形参 `interface I[T]` 被 parser 丢弃。 + - 变参签名不可表达。 + - `save_func_gen_constrs` 稀疏零初值(B.4-1,未触发)。 + - bootstrap `&&`/`||` 不短路根因(B.4-12)。 + - 空递归保守 -1。 + - 非枚举域不判穷尽。 + - 空枚举域 = 空洞穷尽。 + - `never` 语义裁决(B.4-2)。 + - 性能面 `(ak → entry)` 快表无必要(实测)。 ## 实施状态总表(2026-09-12,P3b 收官更新) -> **P3a = Task 0/1/3/4/5 已交付**(提交链 `61d3a8b4`→`ef61f002`→`e9818d62`→`c8c7731b`→`9c0a83ec` + 收官提交);**P3b = Task 0/2/6 已交付**(提交链 `9aa1786c`→`44100ba4`→`e838f18b` + Task 7b 收官提交)⇒ **P3 全阶段(P3a + P3b)收官**。P3b 开工期阻塞/接线/登记面 = **附录 B**;P4 开工必读 = **附录 C**(载体交接包)。 +> **P3a = Task 0/1/3/4/5 已交付**(提交链 `61d3a8b4`→`ef61f002`→`e9818d62`→`c8c7731b`→`9c0a83ec` 加收官提交);**P3b = Task 0/2/6 已交付**(提交链 `9aa1786c`→`44100ba4`→`e838f18b` 加 Task 7b 收官提交)。⇒ **P3 全阶段(P3a + P3b)收官**。P3b 开工期的阻塞/接线/登记面 = **附录 B**;P4 开工必读 = **附录 C**(载体交接包)。 | 任务 | 状态 | 提交 | 判据要点 | 报告 | |---|---|---|---|---| @@ -276,19 +323,24 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 ## 自检记录 -- **spec 覆盖**:§5.1 定长/序列/长度约束 → Task 0/1/2;§5.2 泛型 → Task 5;§5.3 impl → Task 6;§5.4 穷尽性/联合/可选 → Task 3/4;§9 P3 行五项目标能力逐项有落点;`TODO.md:446` fixed-array-retire 的「未办 = 类型身份退役本身」由 Task 1 收尾(枚举了 5 条读码事实,非猜)。 -- **占位符扫描**:无 TBD;两处**决策点显式登记**(Task 4 的 `null` 原子承载、Task 5 的 MAX_GENERICS 解除或登记)——均为"实施前须定",非「稍后填」。 -- **命名一致性**:`sh_struct_term`/`sh_enum_domain_term`/`sh_variant_term`/`sh_iface_shape_term`/`ty_variance_of`/`sh_seq_term`/`iface_satisfies` 在任务间一致;`iface_satisfies` 为 P2b 交接契约名。 -- **数字约定**:95 = 实测(`grep -c "fails = fails + ts_check("` = 95);26,989/67 文件 = findings §11 实测;pA-pD 四探针 = 本计划实测(2026-09-11);其余「≥N 例」为计划下限(可增不可减)。 -- **风险面**:① **展开层裁定**(Task 0 的「仅满足判定展开、等价不展开」边界)——裁错 → 判定全面漂移 + 推翻 P2a 基线(缓解:影子对拍逐任务归零 + 名义不变量用例);② **pA 类静默放宽**(已实测在库:切片→数组)——本批收紧即修,须走收紧清单 + report-only;③ 穷尽性硬错误影响用户 rc(缓解:语料零 match + report-only 先行);④ monomorph 实例键变更(`.ccr`/SYM 变化 + 折叠缺陷修复可能改变既有实例数——实测报告);⑤ **P2b 依赖项阻塞**(Task 2/6 + Task 5 半)——分批交付(P3a 先行、P3b 待 P2b)。 +- **spec 覆盖**:§5.1 定长/序列/长度约束 → Task 0/1/2;§5.2 泛型 → Task 5;§5.3 impl → Task 6;§5.4 穷尽性/联合/可选 → Task 3/4;§9 P3 行的五项目标能力逐项有落点。`TODO.md:446` 的 fixed-array-retire「未办 = 类型身份退役本身」由 Task 1 收尾(枚举了 5 条读码事实,非推测)。 +- **占位符扫描**:无 TBD;两处**决策点显式登记**(Task 4 的 `null` 原子承载、Task 5 的 MAX_GENERICS 解除或登记)——两者均为「实施前须定」,非「稍后填」。 +- **命名一致性**:`sh_struct_term`、`sh_enum_domain_term`、`sh_variant_term`、`sh_iface_shape_term`、`ty_variance_of`、`sh_seq_term` 与 `iface_satisfies` 在任务间一致;其中 `iface_satisfies` 为 P2b 交接契约名。 +- **数字约定**:95 = 实测(`grep -c "fails = fails + ts_check("` = 95);26,989 与 67 文件 = findings §11 实测;pA-pD 四探针 = 本计划实测(2026-09-11);其余「≥N 例」为计划下限(可增不可减)。 +- **风险面**:本计划的风险项与缓解措施如下。 + - ① **展开层裁定**(Task 0 的「仅满足判定展开、等价不展开」边界):裁错会导致判定全面漂移并推翻 P2a 基线;缓解 = 影子对拍逐任务归零加名义不变量用例。 + - ② **pA 类静默放宽**(已实测在库:切片→数组):本批收紧即修,须走收紧清单加 report-only。 + - ③ 穷尽性硬错误影响用户 rc;缓解 = 语料零 match 加 report-only 先行。 + - ④ monomorph 实例键变更:`.ccr`/SYM 随之变化,且折叠缺陷修复可能改变既有实例数,须实测报告。 + - ⑤ **P2b 依赖项阻塞**(Task 2/6 加 Task 5 半):分批交付(P3a 先行、P3b 待 P2b)。 --- ## 附录 A:R2 P2b 交接包(2026-09-11 收官实测;P3 实施前必读) -**来源**:R2 P2b Task 1~6 报告(`.superpowers/sdd/p2b-task{1..6}-report.md`)+ 收官复验(提交链 `7f520dce`→`31143cd0`→`6d2790cd`→`a99ee825`→`7145eea5`→`30545da7` + 本附录所在收官提交)。P2b 的硬约定 = **保语义接线(零行为变化)**:同源双编译器对拍逐任务空(旧二进制 × 新源 == 新二进制 × 新源:21 档语料 + 自源 + 影子 + `.ccr` 四面)。⇒ 本附录的每一条「不接线」= **在该约定下不可能接线**,理由均为实测(探针/突变/全行枚举),不是判断。 +**来源**:R2 P2b 的 Task 1~6 报告(`.superpowers/sdd/p2b-task{1..6}-report.md`)加收官复验(提交链 `7f520dce`→`31143cd0`→`6d2790cd`→`a99ee825`→`7145eea5`→`30545da7`,加本附录所在的收官提交)。P2b 的硬约定 = **保语义接线(零行为变化)**,即同源双编译器对拍逐任务为空(旧二进制 × 新源 == 新二进制 × 新源,覆盖 21 档语料、自源、影子与 `.ccr` 四面)。⇒ 本附录的每一条「不接线」都意味着**在该约定下不可能接线**,其理由均为实测所得(探针、突变、全行枚举),不是判断。 -**行号约定**:本附录行号 = P2b 末提交 `30545da7` 实测(`checker.cr` 3422 行);括注「←T4/T5 报告号」= 该任务报告的**接线前**行号(两报告间有 +10~+21 增行位移,勿混;定位请按内容)。 +**行号约定**:本附录的行号取自 P2b 末提交 `30545da7` 的实测(`checker.cr` 3422 行);括注「←T4/T5 报告号」表示该任务报告的**接线前**行号(两份报告之间存在 +10~+21 的增行位移,不可混用;定位请按内容)。 ### A.1 P2b 实际接线面(P3 的「已就位」清单) @@ -304,7 +356,7 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 ### A.2 未接线站点清单(31 条 = T4 的 14 + T5 的 17) -> 「不接线」的三种实测理由分类:**结果规则**(该分支同时决定结果类型,非许可判定)、**无拒绝路径**(现状恒真,换成门 = 空转)、**谓词非类级位**(类级位表达不了逐行/逐名判定)。 +> 「不接线」的实测理由分三类:**结果规则**(该分支同时决定结果类型,非许可判定)、**无拒绝路径**(现状恒真,换成门等于空转)、**谓词非类级位**(类级位表达不了逐行/逐名判定)。 #### A.2.1 二元 / 一元 / 条件面(T4:18 站点 − 4 接线 = 14) @@ -349,30 +401,30 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 ### A.3 P3 裁决点登记(实施前须定 / 须先补) -① **`iface_satisfies` 未交付**:P2b 范围明标「零调用者,P3 落地 impl 语义时才有对象」(spec §2.5)。⇒ 本计划 Task 2/6 与 Task 5 的 `T: I` 半边**开工前先补条目 + 满足判定**(三态 1/0/-1,不得静默当 0);已就位底座 = `iface_of_term`(类型项 → AK,单原子/-1)、`iface_kind_of`(行 → AK)、条目表 13 类。 -② **`name_ni` 列 = `-1`**(T1 登记偏差):`.ccr` 的 STR 段 = 编译期 `g_strs` **全量**(`ccr_io.cr:537`)⇒ 在 `iface_registry_init`(`init_types` 尾部、每编译一次)里 `str_intern("product")` 之类会把 13 个新串追加进 `g_strs` ⇒ `.ccr` 逐字节变(控制组实测:未用标识符 `zzz_probe_unused_ident` 确实进 STR 段)。⇒ **首个消费者(P3 诊断/显示)落地时裁决**「是否接受 .ccr STR 段增长」;此前在本表初始化路径加 `str_intern` = 打破 P2b 硬判据。 -③ **`TY_DEX_S`(码 8)不入 `ty_code_to_ti`**(T6 §6.1):两处基型分支现状对码 8 落 `TI_UNIT`;入表 = 若该码可达即行为变化(selftest `t6.R_dex_s_unit`/`t6.C_dex_s_unit` 把现状锁定红)⇒ 需 8 个站点各加排除,净收益负。实测:`TY_DEX_S` 仅现于 `init_types` 位置公理(`checker.cr:253`)+ 定义 + 注释;parser 只产 7 个类型名码。 -④ **`never` 单元格:调用位点 = unit,类型位点 = never**(T6 §5,插桩实测**可达**):`res_call_type` 侧显式保留 `|| tv == TY_NEVER`(`checker.cr:1394-1398`);`fn g[T](a: T) -> never` 的调用结果按 unit 参与检查(`@raw_int` → TF07 实测;32 档语料 + 自源命中 0 次——真实源码无 `never` 类型位)⇒ **语义裁决**(never 形参/返回在调用位点应如何参与),P2b 按 spec §4 裁决 6 停下上报、未顺手改。 -⑤ **「全许可列」= 11 个 op 位 × 13 类 = 143 格**(比较 6 + `NEG`/`NOT`/`REF`/`DEREF` + `AS`):现状**无拒绝路径**(T4/T5 探针 32+44 例零拒绝)⇒ 表位已置 1、无门可换(本批不接线)。每位收紧建议见 findings §12。⚠ 任务简报记「20 个全许可列站点」——**本报告无法复现该计数**:实测约定 = 11 位(比较 6 / 一元 4 / 转换 1)、未接线站点合计 **31**(A.2 逐条)。 -⑥ **字段面 / 转换面:无任何拒绝路径**:`EXPR_FIELD` 全形 rc=0 零诊断(落空 `return TI_UNIT`,`checker.cr:2613`)、`EXPR_AS` 除 PTR 结果规则外恒等透传(`checker.cr:2953`)⇒ `IP_FIELD`/`IP_AS` 现为**恒真门**;P3 加诊断后才是可推翻判定(A.2 #23/#25)。 +① **`iface_satisfies` 未交付**:P2b 范围明标「零调用者,P3 落地 impl 语义时才有对象」(spec §2.5)。⇒ 本计划 Task 2/6 与 Task 5 的 `T: I` 半边**开工前先补条目与满足判定**(三态 1/0/-1,不得静默当 0);已就位的底座 = `iface_of_term`(类型项 → AK,单原子或 -1)、`iface_kind_of`(行 → AK)、条目表 13 类。 +② **`name_ni` 列 = `-1`**(T1 登记偏差):`.ccr` 的 STR 段等于编译期 `g_strs` 的**全量**(`ccr_io.cr:537`)。⇒ 在 `iface_registry_init`(`init_types` 尾部,每编译一次)里调用 `str_intern("product")` 之类的写法会把 13 个新串追加进 `g_strs`,导致 `.ccr` 逐字节变化(控制组实测:未用标识符 `zzz_probe_unused_ident` 确实进 STR 段)。⇒ **首个消费者(P3 诊断/显示)落地时再裁决**「是否接受 .ccr STR 段增长」;此前在本表初始化路径加 `str_intern` = 打破 P2b 硬判据。 +③ **`TY_DEX_S`(码 8)不入 `ty_code_to_ti`**(T6 §6.1):两处基型分支现状对码 8 落 `TI_UNIT`;入表意味着若该码可达即产生行为变化(selftest `t6.R_dex_s_unit`/`t6.C_dex_s_unit` 把现状锁定红),且需 8 个站点各加排除,净收益为负。实测:`TY_DEX_S` 仅现于 `init_types` 位置公理(`checker.cr:253`)、定义与注释;parser 只产 7 个类型名码。 +④ **`never` 单元格:调用位点 = unit,类型位点 = never**(T6 §5,插桩实测**可达**):`res_call_type` 侧显式保留 `|| tv == TY_NEVER`(`checker.cr:1394-1398`);`fn g[T](a: T) -> never` 的调用结果按 unit 参与检查(`@raw_int` → TF07 实测;32 档语料加自源命中 0 次——真实源码无 `never` 类型位)。⇒ 此项属**语义裁决**(never 形参/返回在调用位点应如何参与),P2b 按 spec §4 裁决 6 停下上报,未顺手改。 +⑤ **「全许可列」= 11 个 op 位 × 13 类 = 143 格**(比较 6 位,加 `NEG`/`NOT`/`REF`/`DEREF`,加 `AS`):现状**无拒绝路径**(T4/T5 探针 32+44 例零拒绝),因此表位已置 1、无门可换(本批不接线)。每位收紧建议见 findings §12。⚠ 任务简报记「20 个全许可列站点」——**本报告无法复现该计数**:实测约定 = 11 位(比较 6、一元 4、转换 1),未接线站点合计 **31**(A.2 逐条)。 +⑥ **字段面 / 转换面:无任何拒绝路径**:`EXPR_FIELD` 全形 rc=0 零诊断(落空 `return TI_UNIT`,`checker.cr:2613`);`EXPR_AS` 除 PTR 结果规则外恒等透传(`checker.cr:2953`)。⇒ `IP_FIELD`/`IP_AS` 现为**恒真门**,P3 加诊断后才是可推翻判定(A.2 #23/#25)。 ⑦ **dyn 面:谓词非类级位**(A.2 #28/#29);另有 **dyn 位图 64 上限**(`union_bitmaps` 与 `validate_dyn_method` 的 `ti >= 64` 钳位;spec §3.3 已登记)。 -⑧ **索引侧「须 int」位缺失**:`idx_ti`(`checker.cr:2618`)推断后**无消费者** ⇒ `a[true]` rc=0。`IP_INDEX` 是**容器侧**位(ANY 语义),不能兼职索引侧(须 ALL 语义的「indexee」位)⇒ 新位 + 新门属 P3 设计面。 -⑨ **枚举域无条目**:注册表 13 类**无 `AK_SUM`/`AK_FN`**(checker 侧 enum 类型行 = `TYP_NAMED`;`iface_kind_of` 对全部 NAMED 行回 `AK_NAMED`)⇒ 本计划 Task 3/4(穷尽性/联合)经 `sh_enum_domain_term` 走桥接展开,**不要**在注册表查「sum 原子」;若要在条目层表达 sum,须先扩 `iface_kind_of` 的命名行分派(需要行→声明的查询,即 Task 0 Step 2 的 `find_enum`)。 -⑩ **性能面(如实登记)**:单次判定 = `iface_kind_of` + `iface_entry`(13 条线性扫)+ 位构造循环;三处登记(T3/T4/T5 报告)均判「无编译耗时回归证据」。P3 若把判定面扩到热路径(索引/迭代/字段),先看编译耗时再考虑 `(ak → entry)` 快表。 +⑧ **索引侧「须 int」位缺失**:`idx_ti`(`checker.cr:2618`)推断后**无消费者**,因此 `a[true]` rc=0。`IP_INDEX` 是**容器侧**位(ANY 语义),不能兼职索引侧(须 ALL 语义的「indexee」位)。⇒ 新位加新门属 P3 设计面。 +⑨ **枚举域无条目**:注册表 13 类中**无 `AK_SUM`/`AK_FN`**(checker 侧 enum 类型行 = `TYP_NAMED`;`iface_kind_of` 对全部 NAMED 行回 `AK_NAMED`)。⇒ 本计划 Task 3/4(穷尽性/联合)经 `sh_enum_domain_term` 走桥接展开,**不要**在注册表查「sum 原子」;若要在条目层表达 sum,须先扩 `iface_kind_of` 的命名行分派(需要行到声明的查询,即 Task 0 Step 2 的 `find_enum`)。 +⑩ **性能面(如实登记)**:单次判定 = `iface_kind_of` 加 `iface_entry`(13 条线性扫)加位构造循环;三处登记(T3/T4/T5 报告)均判「无编译耗时回归证据」。P3 若把判定面扩到热路径(索引/迭代/字段),须先看编译耗时再考虑 `(ak → entry)` 快表。 ### A.4 表 / 注册表结构事实(P3 扩展前必知) -- **条目布局** 40B/条 × 5 字段 `{ak, ti_row, name_ni, lit_code, ops}`(`iface_registry.cr:44-48`);`ti_row` 仅 8 原生有值,**结构/命名类 = -1 = 类级**(类级/行级不得混同——selftest 有专例);`lit_code` = AST 字面量 kind 的字典;`ops` = 许可位集。 -- **位下标**:`OP_*` 直用(1..19)、`UOP_*` **+20 偏置**、`IP_INDEX=25`/`IP_INDEX_RANGE=26`/`IP_FIELD=27`/`IP_METHOD=28`/`IP_AS=29`/`IP_COND=30`/`IP_COND_BOOL=31`。常量在 **`globals.cr:254-271`**(**必须在 globals.cr**:变量/常量跨文件按声明序可见,`checker.cr` 在 `iface_registry.cr` 之前;函数不受限)。`iface_bit` = 乘 2 循环(本语言无移位);`iface_permits(op<0 || op>62)` → 0(不回绕;≥63 会把 i64 推负 = 全位命中)。 -- **三态纪律**:`iface_ops(未知/-1)` = 0、`iface_kind_of(负/越界)` = -1、`iface_lit_ti(非字面量 kind)` = -1;`iface_of_term` 仅 `TT_ATOM`/`TT_TOP_K` 回 AK,其余 -1。 -- **初始化**:挂 `init_types()` 尾部(`checker.cr:257` 区)——幂等 + **不缓存行号**(长驻 corelsp 每请求 `init_types`)⇒ P3 新字段照此;**不得**在初始化路径 `str_intern`(见 A.3-②)。 +- **条目布局**:40B/条 × 5 字段 `{ak, ti_row, name_ni, lit_code, ops}`(`iface_registry.cr:44-48`);`ti_row` 仅 8 个原生条目有值,**结构/命名类 = -1 = 类级**(类级与行级不得混同——selftest 有专例);`lit_code` = AST 字面量 kind 的字典;`ops` = 许可位集。 +- **位下标**:`OP_*` 直接使用(1..19),`UOP_*` 加 **+20 偏置**,`IP_INDEX=25`、`IP_INDEX_RANGE=26`、`IP_FIELD=27`、`IP_METHOD=28`、`IP_AS=29`、`IP_COND=30`、`IP_COND_BOOL=31`。常量位于 **`globals.cr:254-271`**(**必须在 globals.cr**:变量与常量跨文件按声明序可见,而 `checker.cr` 在 `iface_registry.cr` 之前;函数不受此限)。`iface_bit` 用乘 2 循环实现(本语言无移位);`iface_permits(op<0 || op>62)` → 0(不回绕;≥63 会把 i64 推负,导致全位命中)。 +- **三态纪律**:`iface_ops(未知/-1)` = 0、`iface_kind_of(负/越界)` = -1、`iface_lit_ti(非字面量 kind)` = -1;`iface_of_term` 仅对 `TT_ATOM`/`TT_TOP_K` 回 AK,其余 -1。 +- **初始化**:挂在 `init_types()` 尾部(`checker.cr:257` 区),要求幂等且**不缓存行号**(长驻 corelsp 每请求执行 `init_types`);P3 新字段照此办理,且**不得**在初始化路径 `str_intern`(见 A.3-②)。 - **桥接单源化**:`sh_base_ak`/`sh_native_ak` 委托 `iface_by_ty_code`(唯一实现;`ty_shadow.cr:72-89`);`sh_native_ak` **保留** `get_type_kind != TYP_BASE → -1` 门(`sh_native_ak(TI_DYN) == -1`——DYN 行经 `sh_term_of_ti` 的另一分支;**不得**直接换成 `iface_kind_of`);`sh_*_ak_legacy` 为对拍对照物(P5 删,TODO #2026-09-11-8-④)。 -- **单表 `ty_code_to_ti`**(`iface_registry.cr:259-270`):8 码逐项 + 域外 -1;**码 7 格 = 现状数值撞车原样保留**(`TY_GENERIC_PARAM=7` 与 `TI_DYN=7`;`parser.cr:98` 对 `dyn` 正产码 7 ⇒ 可达、N08 判据依赖)——归 P4/P5 命名空间分家,**P3 不得改**。 -- **语义分派守卫**(P1 血泪:AK/TI 下标不 1:1):AK↔TI 一律按语义逐项写死(`AK_STRING↔TI_STR`、`AK_BOOL↔TI_BOOL` 错位书写);守卫用例 `iface.dispatch_no_index_shortcut`——**任何新映射不得按数值直传**。 +- **单表 `ty_code_to_ti`**(`iface_registry.cr:259-270`):8 码逐项,域外 -1;**码 7 格 = 现状数值撞车,原样保留**(`TY_GENERIC_PARAM=7` 与 `TI_DYN=7`;`parser.cr:98` 对 `dyn` 正产码 7 ⇒ 可达,且 N08 判据依赖此事实)——归 P4/P5 命名空间分家,**P3 不得改**。 +- **语义分派守卫**(P1 的教训:AK/TI 下标不 1:1):AK↔TI 一律按语义逐项写死(`AK_STRING↔TI_STR`、`AK_BOOL↔TI_BOOL` 属错位书写);守卫用例 `iface.dispatch_no_index_shortcut`——**任何新映射不得按数值直传**。 ### A.5 事实表指针 -侦查 §2 九条现状宽松面 → 表中格 → 现状诊断 → P3 收紧建议:**findings 文档 §12「P2b 后:公理区事实表」**(本附录所在提交同批新增);P3 各任务的「旧接受 → 新拒绝」登记表照其约定逐条填。 +侦查 §2 的九条现状宽松面按「表中格 → 现状诊断 → P3 收紧建议」的链条记录于 **findings 文档 §12「P2b 后:公理区事实表」**(与本附录所在提交同批新增);P3 各任务的「旧接受 → 新拒绝」登记表照其约定逐条填写。 --- diff --git a/docs/superpowers/plans/2026-09-13-r2-p5-cleanup.md b/docs/superpowers/plans/2026-09-13-r2-p5-cleanup.md index f439ffed..1a6d308c 100644 --- a/docs/superpowers/plans/2026-09-13-r2-p5-cleanup.md +++ b/docs/superpowers/plans/2026-09-13-r2-p5-cleanup.md @@ -2,15 +2,15 @@ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. -**Goal:** 兑现统一设计 spec §9 的 P5 行(**收尾**)+ §3.4「收尾:单槽 = 类型项引用 + `atom_of(term)` 取原子(后端改动面 ≈ 20 处比较点,收尾批一并改)」:① **单槽化**——把 DFNode 的**类型面**从「迁移期双槽(`OFF_DF_TK` 混用码 + `OFF_DF_TK_TERM` 项引用)」收拢为**项引用唯一依据 + 派生码**,并把混用码里的**非类型辅码**(旗标/宽度)显式分离(`OFF_DF_AUX`);② **大步删旧路径(路线 3)**——删 `type_equal_legacy` 与全部回落面、删判定衔接层 legacy 副本、删站点 6 与不可达死分支、**影子判定对拍层下线**,并把「判定面回归网」切换为**冻结基线同源对拍 + 行为探针 + 突变控制**;③ **文档/清单**——spec 行标 / findings 终态 / TODO 划销链 / **P6 交接包(附录 E)**。**边界纪律(本批为收尾批)**:任何「新能力」(盘面项索引、corearch `atom_of` 读回承接面、对象布局表示位、`MAX_*` 解除、可选程序收回 `.cir` 缓存、命名消费语法、iterable 接线)**一律转 P6**,本批只做**删除 / 收尾 / 零行为变化的单源化**。 +**Goal:** 本计划兑现统一设计 spec §9 的 P5 行(**收尾**)与 §3.4「收尾:单槽 = 类型项引用 + `atom_of(term)` 取原子(后端改动面 ≈ 20 处比较点,收尾批一并改)」。目标分三项:① **单槽化** —— 把 DFNode 的**类型面**从「迁移期双槽(`OFF_DF_TK` 混用码 + `OFF_DF_TK_TERM` 项引用)」收拢为**项引用唯一依据 + 派生码**,并把混用码里的**非类型辅码**(旗标/宽度)显式分离到 `OFF_DF_AUX`;② **大步删旧路径(路线 3)** —— 删 `type_equal_legacy` 与全部回落面、删判定衔接层 legacy 副本、删站点 6 与不可达死分支、**影子判定对拍层下线**,并把「判定面回归网」切换为**冻结基线同源对拍 + 行为探针 + 突变控制**;③ **文档/清单** —— spec 行标 / findings 终态 / TODO 划销链 / **P6 交接包(附录 E)**。**边界纪律(本批为收尾批)**:任何「新能力」(盘面项索引、corearch `atom_of` 读回承接面、对象布局表示位、`MAX_*` 解除、可选程序收回 `.cir` 缓存、命名消费语法、iterable 接线)**一律转 P6**,本批只做**删除 / 收尾 / 零行为变化的单源化**。 -**Architecture:** 六条主线:① **前置侦查与基线冻结**(Task 0:全 op `tk` 语义分类表 + 站点评级表 + -1 面清点 + 冻结基线二进制;**源码零改动**);② **预存缺陷**(Task 1:`.cir` 暖态 SIGSEGV 根因修复——它是单槽化 `.cir` 面的地基,且属「响亮失败」级预存面);③ **单槽化**(Task 2:槽语义对调 + 辅码分离 + `atom_of` 契约 + **派生码不变量**「新派生值 ≡ 旧 `tk`」);④ **unknown 清零**(Task 3:命名面判定化——**身份链 + 可判定面加强**,不是结构性展开);⑤ **删除批**(Task 4 删 legacy + 回落 + 副本 + 死分支;Task 5 并行的对照实现下线 + 回归网切换);⑥ **独立收尾与收官**(Task 6:TODO #2026-09-11-14 `EXPR_LET` 判定点;Task 7:收官)。 +**Architecture:** 本计划分六条主线。① **前置侦查与基线冻结**(Task 0:全 op `tk` 语义分类表 + 站点评级表 + -1 面清点 + 冻结基线二进制;**源码零改动**)。② **预存缺陷**(Task 1:`.cir` 暖态 SIGSEGV 根因修复,它是单槽化 `.cir` 面的地基,且属「响亮失败」级预存面)。③ **单槽化**(Task 2:槽语义对调 + 辅码分离 + `atom_of` 契约 + **派生码不变量**「新派生值 ≡ 旧 `tk`」)。④ **unknown 清零**(Task 3:命名面判定化,即**身份链 + 可判定面加强**,不是结构性展开)。⑤ **删除批**(Task 4 删 legacy + 回落 + 副本 + 死分支;Task 5 并行的对照实现下线 + 回归网切换)。⑥ **独立收尾与收官**(Task 6:TODO #2026-09-11-14 `EXPR_LET` 判定点;Task 7:收官)。 -**Tech Stack:** Core 自举栈。`src/compiler/checker.cr`(`type_equal_legacy` :504 / `type_equal_engine` / `type_equal` 包装 / `type_compat_strict` :442 / `EXPR_LET` 分支 :3079)· `src/compiler/ty_shadow.cr`(桥接 `sh_term_of_ti` :275 / `sh_tk_term_of_code` :377 / 影子挂点与站点表 :472-538 / 展开层 :678 / `sh_*_ak_legacy` :101/:109)· `src/compiler/type_engine.cr`(判定核 `lit_implies` :165 / 变型表 :264 / `tt_list_variance_at` :291)· `src/compiler/dyn_arr.cr`(DFNode 布局 :103-121)· `src/compiler/dataflow.cr`(`df_create_node` / `df_rebuild_ir` :455)· `src/compiler/ir_gen.cr`(`emit` / :129 / :338)· `src/compiler/cir_cache.cr`(`:48` `CIR_CACHE_VER=17` / 装载重派生 :448-453)· `src/arch/x86_64/instr.cr` :460 · `regalloc.cr` :457 · `lower_to_core.cr` :250/:574 · `dump.cr` :125 · `ccr_io.cr`(NOD 盘记录 :143 / :511 / :768)。 +**Tech Stack:** Core 自举栈。涉及文件与位置:`src/compiler/checker.cr`(`type_equal_legacy` :504 / `type_equal_engine` / `type_equal` 包装 / `type_compat_strict` :442 / `EXPR_LET` 分支 :3079)· `src/compiler/ty_shadow.cr`(桥接 `sh_term_of_ti` :275 / `sh_tk_term_of_code` :377 / 影子挂点与站点表 :472-538 / 展开层 :678 / `sh_*_ak_legacy` :101/:109)· `src/compiler/type_engine.cr`(判定核 `lit_implies` :165 / 变型表 :264 / `tt_list_variance_at` :291)· `src/compiler/dyn_arr.cr`(DFNode 布局 :103-121)· `src/compiler/dataflow.cr`(`df_create_node` / `df_rebuild_ir` :455)· `src/compiler/ir_gen.cr`(`emit` / :129 / :338)· `src/compiler/cir_cache.cr`(`:48` `CIR_CACHE_VER=17` / 装载重派生 :448-453)· `src/arch/x86_64/instr.cr` :460 · `regalloc.cr` :457 · `lower_to_core.cr` :250/:574 · `dump.cr` :125 · `ccr_io.cr`(NOD 盘记录 :143 / :511 / :768)。 -**Spec:** `docs/superpowers/specs/2026-09-10-type-interface-unification-design.md` **§3.4**(迁移期双槽 → 收尾单槽)、**§4 步 4**(收尾 = 删旧分支/旧映射/双槽,单源化)、**§6.2**(DFNode.TK 升格落地记录 + 「收尾(单槽化)归 P5」)、**§9 P5 行**;风险表 **R5**(双槽期漂移:**term 为准,atom 由 `atom_of(term)` 派生**——本批的单源化约定即此句)。**P5 起点文档 = P4 计划附录 D**(`docs/superpowers/plans/2026-09-12-r2-p4-carrier.md:345-405`;D-1 约定表 / D-2 任务面 / D-3 十四项 / D-4 检查单)。 +**Spec:** 规格依据为 `docs/superpowers/specs/2026-09-10-type-interface-unification-design.md` 的 **§3.4**(迁移期双槽 → 收尾单槽)、**§4 步 4**(收尾 = 删旧分支/旧映射/双槽,单源化)、**§6.2**(DFNode.TK 升格落地记录 + 「收尾(单槽化)归 P5」)与 **§9 P5 行**。风险表 **R5** 规定双槽期漂移的约定:**term 为准,atom 由 `atom_of(term)` 派生**——本批的单源化约定即此句。**P5 起点文档 = P4 计划附录 D**(`docs/superpowers/plans/2026-09-12-r2-p4-carrier.md:345-405`;含 D-1 约定表 / D-2 任务面 / D-3 十四项 / D-4 检查单)。 -**前置状态(已实测,非本计划目标)**:P4 全阶段收官于 `9bcb7083`(工作副本 `8d1885df`,`jj status` 干净、无空描述改动);`selftest-types` **355/355**(`src/ci/run.sh:71`);ELF canary `95084e7bc68d6550d21d3d96fa3afd89c67a5d89edce5656a3d2e74fc923d475` 全批 IDENTICAL;自举链 `corec2==corec3` cmp IDENTICAL + N06=0 + 冒烟 42;全枚举 **55/55**(48 selfhost + 7 bootstrap);`CIR_CACHE_VER=17`(`cir_cache.cr:48`,P4 T4 实测后**保持不 bump**);`ESZ_DFNODE=72`(9 槽,`dyn_arr.cr:119-121`);DFNode 项槽(`OFF_DF_TK_TERM`)**无生产消费者**(P4 T4 §7-②)。 +**前置状态(已实测,非本计划目标)**:P4 全阶段收官于 `9bcb7083`(工作副本 `8d1885df`,`jj status` 干净、无空描述改动)。`selftest-types` 实测 **355/355**(`src/ci/run.sh:71`)。ELF canary `95084e7bc68d6550d21d3d96fa3afd89c67a5d89edce5656a3d2e74fc923d475` 全批 IDENTICAL。自举链 `corec2==corec3` cmp IDENTICAL + N06=0 + 冒烟 42。全枚举 **55/55**(48 selfhost + 7 bootstrap)。`CIR_CACHE_VER=17`(`cir_cache.cr:48`,P4 T4 实测后**保持不 bump**)。`ESZ_DFNODE=72`(9 槽,`dyn_arr.cr:119-121`)。DFNode 项槽(`OFF_DF_TK_TERM`)**无生产消费者**(P4 T4 §7-②)。 --- @@ -34,7 +34,7 @@ ## 收官总述:类型接口化工作流的终态(一页;维护者先读) -**单一权威(现在谁说最后一句)** +**单一权威(各面的最终权威)** | 面 | 权威 | 位置 | |---|---|---| @@ -82,13 +82,13 @@ ## Global Constraints -- **jj only(禁 git 含只读/复合)**;**提交路径限定**(多 agent 在场:一律 `jj commit -m … `);所有命令 `nice -n 19`;一构建一编译**串行**;cwd = 仓库根(`/tmp` cwd 触发 import 解析假失败)。 -- **基线纪律**:每任务开工先取**同任务起点**基线(binary sha + 语料计数),**不得沿用 P4 计数**(P4 期间源码多次变更,`decisions`/`.ccr` 记录值跨提交不可比——T4 §7-⑧ 约定)。 -- **ELF canary(硬闸,全批)**:`clean-cache` → `build tests/suite/ptr_arith.cr --static -o /tmp/…` → sha256 `95084e7bc68d6550d21d3d96fa3afd89c67a5d89edce5656a3d2e74fc923d475`。**任一任务变即停下上报**。⚠ 该语料对类型层不敏感——它是「发射面零泄漏」证据,**不得**当新语义正确性证据(P3 附录 C.5-6 约定继承)。 -- **三态纪律(不得稀释)**:引擎 -1(预算耗尽/未覆盖面)不得当 0/1 用;载入失败/段缺失/行不可译/项不可建 ⇒ **拒绝**(不得静默当空表当 0);save 侧装填遇不可译行/签名项 ⇒ **save 拒绝**。 +- **jj only(禁 git 含只读/复合)**。**提交路径限定**(多 agent 在场:一律 `jj commit -m … `)。所有命令加 `nice -n 19`。一构建一编译**串行**。cwd = 仓库根(`/tmp` cwd 触发 import 解析假失败)。 +- **基线纪律**:每任务开工先取**同任务起点**基线,内容为 binary sha 与语料计数。**不得沿用 P4 计数**:P4 期间源码多次变更,`decisions`/`.ccr` 记录值跨提交不可比(T4 §7-⑧ 约定)。 +- **ELF canary(硬闸,全批)**:流程为 `clean-cache` → `build tests/suite/ptr_arith.cr --static -o /tmp/…` → sha256 `95084e7bc68d6550d21d3d96fa3afd89c67a5d89edce5656a3d2e74fc923d475`。**任一任务出现变化即停下上报**。⚠ 该语料对类型层不敏感——它是「发射面零泄漏」证据,**不得**当新语义正确性证据(P3 附录 C.5-6 约定继承)。 +- **三态纪律(不得稀释)**:引擎 -1(预算耗尽/未覆盖面)不得当 0/1 用。载入失败/段缺失/行不可译/项不可建 ⇒ **拒绝**(不得静默当空表当 0)。save 侧装填遇不可译行/签名项 ⇒ **save 拒绝**。 - **新硬错先 report-only**:本批新增的任何 rc=1 门(含 Task 6 的 `EXPR_LET` 判定、Task 3 若引入的残留 -1 政策)必须先在**全语料**(`src/compiler/_import.cr` 自指 + `tests/suite` + `tests/selfhost` 内联源 + `src/stdlib` + `examples`)report-only 跑一遍,清单审查后才开门(硬门 = `main.cr` parse 阶段 `g_diag_count > 0` 硬名单闸,本轮实读 ≈:149-170;照 #29/TM03 先例)。 -- **清单双注册面(B.6,硬性)**:任何清单/段表改动必须**三面同核**——`build_selfhost_native.py`(`corec_files`/`corearch_files`/`corelsp_files`)↔ `src/targets/x86_64-linux/_import.cr`(project-mode)↔ `src/compiler/_import.cr`;每任务回归面**必含** `tests/selfhost/test_backend_bootstrap.py`(rc=0 + 构建日志 `error[` = 0)。 -- **回归网(本批切换;D26)**:Task 5 之前 = 影子对拍每任务复跑(**站点覆盖与差异数同报**;载体面零覆盖声明继承);Task 5 之后 = **冻结基线同源对拍**(Task 0 冻结的 pre-P5 二进制 × 当前源 vs 当前二进制 × 当前源,72 档 `check` 日志 + rc 逐档 diff)+ 行为探针全集中跑 + 突变控制。**载体正确性证据**(段/读回/TK/表示)**一律** = 结构性断言 + corearch 读回对拍 + 定向探针(影子通道对其零覆盖,继承声明)。 +- **清单双注册面(B.6,硬性)**:任何清单/段表改动必须**三面同核**——`build_selfhost_native.py`(`corec_files`/`corearch_files`/`corelsp_files`)↔ `src/targets/x86_64-linux/_import.cr`(project-mode)↔ `src/compiler/_import.cr`。每任务回归面**必含** `tests/selfhost/test_backend_bootstrap.py`(rc=0 + 构建日志 `error[` = 0)。 +- **回归网(本批切换;D26)**:Task 5 之前 = 影子对拍每任务复跑(**站点覆盖与差异数同报**;载体面零覆盖声明继承)。Task 5 之后 = **冻结基线同源对拍**(Task 0 冻结的 pre-P5 二进制 × 当前源 vs 当前二进制 × 当前源,72 档 `check` 日志 + rc 逐档 diff)+ 行为探针全集中跑 + 突变控制。**载体正确性证据**(段/读回/TK/表示)**一律** = 结构性断言 + corearch 读回对拍 + 定向探针(影子通道对其零覆盖,继承声明)。 - **`.cir` 缓存面**:`CIR_CACHE_VER` 手工 bump 是格式/语义代变更的既定配方;**DF 记录布局/语义一变即必须 bump**(v16 教训)。本批 D19 下**布局零变化 ⇒ 不 bump**(实施时以「盘记录逐字段对照 + `test_cache_identity.py:VER_EXPECTED` 不动」复证并登记)。 - **不得回退既有收纳**:TS01-04/TK02 硬门(#29)、TM03/TG02 门(#31/#33)、F2 常量档拒绝语义与「N 不回身份」、F5 槽位契约(#25/#28)、效应/纯度判据(#26/#27)、`iface_satisfies` 轴序 A>C>B、逐成员判定、P4 全批(段机制/确定性装填/允许清单制/可选表示)——本计划一律不动;冲突 → 停下上报。 - **本语言无三元运算符**;取模须非负;键比较不得依赖 i64 回绕;noclobber(`>|`);自测用例**只增不减**;判据「≥N 例」= 下限(可增不可减)。 @@ -96,19 +96,21 @@ --- -## 侦查底座(2026-09-13 实读;file:line = 当前工作树(父提交 `9bcb7083` = P4 收官,侦查时工作副本为空、无未描述改动;工作副本 id 随编辑变动,不作为锚点);未标注者为本轮实读实核) +## 侦查底座(2026-09-13 实读;`file:line` = 当前工作树;父提交 `9bcb7083` = P4 收官,侦查时工作副本为空、无未描述改动;工作副本 id 随编辑变动,不作为锚点;未标注者为本轮实读实核) **判定面(删除对象)** -- `type_equal_legacy`:定义 `checker.cr:504`(降级注记 :495-503);**内部递归自调 7 处**(:518 数组 / :528 元组 / :534 引用 / :537 指针 / :540 切片 / :547 可选 / :560 泛型应用);**回落调用 2 处**(:590 桥接缺口→`g_replace_bridge`;:599 引擎 -1→`g_replace_unknown`);**影子对照 1 处**(:612 `if type_equal_legacy(t1, t2) { ok = 1; }`)。判定入口链 = `type_equal`(:604-615)→ `type_equal_engine`(:573-601)→ `ty_equiv`。 -- `g_replace_unknown`/`g_replace_bridge`:声明 `globals.cr:421`;复位 `checker.cr:246`;摘要打印 `ty_shadow.cr:628/:630`。 + +- `type_equal_legacy`:定义于 `checker.cr:504`(降级注记 :495-503)。**内部递归自调 7 处**,分别在 :518 数组、:528 元组、:534 引用、:537 指针、:540 切片、:547 可选、:560 泛型应用。**回落调用 2 处**::590 桥接缺口 → `g_replace_bridge`,:599 引擎 -1 → `g_replace_unknown`。**影子对照 1 处**::612 的 `if type_equal_legacy(t1, t2) { ok = 1; }`。判定入口链 = `type_equal`(:604-615)→ `type_equal_engine`(:573-601)→ `ty_equiv`。 +- `g_replace_unknown`/`g_replace_bridge`:声明于 `globals.cr:421`,复位于 `checker.cr:246`,摘要打印于 `ty_shadow.cr:628/:630`。 - 锁定回落语义的自测例 **5 处**(删 legacy 时必须重新锁定):`t3.unknown_fallback_legacy`(`type_selftest.cr:1814`)· `t3.bridge_fallback_legacy`(:1821)· `unf.nominal_equiv_atomic_unknown`(:2487,断言 `ty_equiv(命名项, 命名项) == -1`)· `unf.nominal_type_equal_false`(:2492,断言回落 +1)· `t1.n_face_gate_nested`(:2691,断言**不**回落)。 -- 判定衔接层 legacy 副本:`sh_native_ak_legacy`(`ty_shadow.cr:101`)/`sh_base_ak_legacy`(:109);零生产调用,仅 `type_selftest.cr:1957/:1966/:1977` 三例引用。 -- 并行的对照实现:站点表 `ty_shadow.cr:472-483`(10 站点;**站点 6** = `checker.cr:2454-2463` 的 `EXPR_BINARY+OP_ASSIGN`,:479 注「当前 parser 已无生产点 = 遗留路径,无样本」——**本轮独立复核成立**:`tok2op`(`parser.cr:170-184`)零 `OP_ASSIGN`、`T_EQ` → `EXPR_ASSIGN`(:227)、`+=` 族(:216-224)显式包裹且 op ∈ {ADD,SUB,MUL,DIV};对侧 `ir_gen.cr:927-929` 同分支);`sh_site_begin`(:504,关态早退 + 10 槽直方图);环缓冲 `sh_record`(:519 起)/`sh_compare`(:539)/`sh_site_name`(:574)/`sh_kind_name`(:588)/`sh_report`(:607)/`sh_dump_write`(:651);`sh_finish`/`sh_dump_write` 调用点(`main.cr:212-216`);CLI:`--type-shadow`(`main.cr:236`)、`--type-shadow-dump`(:237)、`g_shadow_on`(:244)、`--verify-named-dedup`(:182/:238)。 +- 判定衔接层 legacy 副本:`sh_native_ak_legacy`(`ty_shadow.cr:101`)与 `sh_base_ak_legacy`(:109);零生产调用,仅 `type_selftest.cr:1957/:1966/:1977` 三例引用。 +- 并行的对照实现:站点表 `ty_shadow.cr:472-483`(10 站点;**站点 6** = `checker.cr:2454-2463` 的 `EXPR_BINARY+OP_ASSIGN`,:479 注「当前 parser 已无生产点 = 遗留路径,无样本」——**本轮独立复核成立**:`tok2op`(`parser.cr:170-184`)零 `OP_ASSIGN`、`T_EQ` → `EXPR_ASSIGN`(:227)、`+=` 族(:216-224)显式包裹且 op ∈ {ADD,SUB,MUL,DIV};对侧 `ir_gen.cr:927-929` 同分支)。其余部件:`sh_site_begin`(:504,关态早退 + 10 槽直方图);环缓冲 `sh_record`(:519 起)/`sh_compare`(:539)/`sh_site_name`(:574)/`sh_kind_name`(:588)/`sh_report`(:607)/`sh_dump_write`(:651);`sh_finish`/`sh_dump_write` 调用点(`main.cr:212-216`);CLI:`--type-shadow`(`main.cr:236`)、`--type-shadow-dump`(:237)、`g_shadow_on`(:244)、`--verify-named-dedup`(:182/:238)。 - **桥接缓存(生产面,**不删**)**:`g_shadow_map`(16B/条 {ti, term})+ `g_shadow_entries/hits`(`ty_shadow.cr:56-62`);重置钩子 `sh_map_reset`(:130-133)经 `init_types()` 调用(`checker.cr:240`,P2a 评审 Critical 修复)+ `sh_unf_map_reset`(:243)+ `tt_layer_reset`(`type_terms.cr:144`,`ccr_types.cr:57-59` 亦调)。**登记**:计数在生产路径(`ty_shadow.cr:48` 注「影子关时也读写」)⇒ `sh_tk_term_of_code` 须存-复原 `g_shadow_hits`(:383-386 区域)——D26-③ 删除对象。 -- 引擎命名面(清零对象):`lit_implies` 两处 `AK_NAMED ⇒ g_ty_uncovered=1; return -1`(`type_engine.cr:192` 否定面 / :198 正原子面);`ak_disjoint` 对 NAMED **不断言互斥**(:76-78,P0 终审 Important B 实证);变型表 `ty_variance_of`(:264-277)表外构造子一律**不变**(含 AK_NAMED);不变槽 mismatch ⇒ `g_ty_uncovered=1; return -1`(`tt_list_variance_at` :305-307);`tt_type_elem_same`(:231)+ 其登记注(:219-230:**「确定不等价 ⇒ 0」加强须先有「链元素皆类型项」不变量**)。桥接命名构造点**两处**:`sh_term_of_ti`(`ty_shadow.cr:328`/`:330`)+ `sh_sig_term_of_ti`(:951)——**两处必须同步**(双构造点契约,照域/模式项先例)。 -- 展开层(**本批不动**):边界声明 + 反证 `ty_shadow.cr:678-700`(只在满足判定/域查询;等价面一律不经;「把展开项接进等价判定」= 同形不同名 struct 判等 + 推翻 P2a 归零基线);实现 `sh_struct_term`(:833)/`sh_variant_term`(:874)/`sh_enum_domain_term`(:887)。**注意**:`sh_unf_map_reset` 等缓存不得 `str_intern` 面新增(留给 P6)。 +- 引擎命名面(清零对象):`lit_implies` 两处 `AK_NAMED ⇒ g_ty_uncovered=1; return -1`(`type_engine.cr:192` 否定面 / :198 正原子面);`ak_disjoint` 对 NAMED **不断言互斥**(:76-78,P0 终审 Important B 实证);变型表 `ty_variance_of`(:264-277)表外构造子一律**不变**(含 AK_NAMED);不变槽 mismatch ⇒ `g_ty_uncovered=1; return -1`(`tt_list_variance_at` :305-307);`tt_type_elem_same`(:231)及其登记注(:219-230:**「确定不等价 ⇒ 0」加强须先有「链元素皆类型项」不变量**)。桥接命名构造点**两处**:`sh_term_of_ti`(`ty_shadow.cr:328`/`:330`)与 `sh_sig_term_of_ti`(:951),**两处必须同步**(双构造点契约,照域/模式项先例)。 +- 展开层(**本批不动**):边界声明与反证见 `ty_shadow.cr:678-700`(只在满足判定/域查询;等价面一律不经;「把展开项接进等价判定」= 同形不同名 struct 判等 + 推翻 P2a 归零基线);实现为 `sh_struct_term`(:833)/`sh_variant_term`(:874)/`sh_enum_domain_term`(:887)。**注意**:`sh_unf_map_reset` 等缓存不得 `str_intern` 面新增(留给 P6)。 **DFNode / 载体面(单槽化对象)** + - 布局:`ESZ_DFNODE=72`、`OFF_DF_TK=40`(混用码)、`OFF_DF_TK_TERM=64`(项引用;P4 新增)——`dyn_arr.cr:103-121`(含三条契约注:① `OFF_DF_TK` 语义/字节零变化;② 项槽只在 **emit 期**派生(时点不得后移);③ 唯一写点 = `df_create_node` + `.cir` 装载重派生)。 - 写点:`df_create_node`(定义 `dataflow.cr:98`;tk 写 :108、项槽写 :109);**唯一调用点 = `emit`**(定义 `ir_gen.cr:329`,调用 :345——本轮 grep 全仓仅此一处调用);派生函数 `sh_tk_term_of_code`(`ty_shadow.cr:377`,**允许清单 = {IR_CONST, IR_BINARY}**,另有 4 处排除说明含「IR_ALLOC/IR_CALL/IR_I2F/IR_F2I/IR_LOAD 传类型行但后端不按 ti 分派 ⇒ 暂不入清单,**留待 P5 单槽化时按需再裁**」;hack = 存-复原 `g_shadow_hits`,:384-386)。 - 派生链:`df_rebuild_ir`(`dataflow.cr:448-455`,tk → `iri_set_tk`)· `ir_gen.cr:338`(`iri_set_tk(idx, type_kind)`)。 @@ -117,6 +119,7 @@ - 冷/暖面:DF 节点装载 loop(`cir_cache.cr:431-453`)+ IRI 装载 loop(:530-545)**两路对称**;快照入场闸 = 版本 `:383` / 编译器身份 `:389-391` / 指纹 `:396`;P4 ㉙ 用例锁「冷/暖 (op,tk,term) 逐行同」。 **TODO / 未收尾面** + - `#32`(`EXPR_LET` 无检查):`checker.cr:3079-3097` 的 `EXPR_LET` 分支——`val_ti := infer_expr(val_c)` 后 `ti := val_ti; if type_node >= 0 { ti = res_type_node(type_node); }`(:3096-3097)**无任何兼容检查**;可复用判定 = `type_compat_strict`(:442)+ `diag_type_incompatible`(:486)。姊妹面 = #20(F3 调用位点无诊断:`unify_types`(定义 :1905)的返回值在 :2017 被丢弃——**TODO #2026-09-11-14 记录的旧锚 `:1053` 已随行漂移**,以本次实读 :2017 为准)。**全局声明面同形**(`checker.cr:1614-1620` 全局 let 注册亦无比对——#32 的修法须显式划界是否覆盖)。 - `#35` **已由 P4 T6 划销**(`test_enum_limit.py` 13 例);`#43` = P4 T5 落地(其「登记面」= 可选程序关缓存 + 暖态 SIGSEGV,本计划 Task 1/D27 处理);`#44` = P4 收官(本计划 Task 7 接续)。 - 判据面:`src/ci/run.sh:68-90`(selfhost-tests 挂点,含 `test_ccr_types`/`test_optional`/`test_enum_limit` 等);72 档同源对拍 runner `/tmp/p3t0_run.sh`(**本轮实查存在**,2026-09-12 版)。 @@ -128,7 +131,8 @@ **Files:** 无源码改动。产物 = 报告 `.superpowers/sdd/p5-task0-report.md`(工作区,不入提交)+ 冻结基线二进制 `/tmp/p5t0/base/{corec,corearch,corelsp}` + 直方图/清点原始输出留档(`/tmp/p5t0/`)。 **Interfaces(产物四表,全部落报告;数字一律实测,未实测标「待实测」):** -- **表 A:全 op `tk` 语义分类表**(单槽化 Step 1 的输入)——逐 op:`{类型行 / 旗标 / 宽度 / 无}` + 后端消费者(`instr.cr:460` 的 5 分派点 / `regalloc.cr:457` / `lower_to_core.cr:250·574` / `dump.cr:125`)+ 是否入项槽 + 依据(P4 T4 §2 方法扩面:`instr.cr` 分支逐条审计 + `ir_gen.cr` 全 `emit(` 调用点逐 op 静态审计 + 全语料 NOD (op,tk) 直方图)。**必须显式再裁 P4 排除项**:`IR_ALLOC`/`IR_CALL`/`IR_I2F`/`IR_F2I`/`IR_LOAD`/`IR_LOAD_ENUM_TAG`(P4 T4 §2 注明「留待 P5」)。 + +- **表 A:全 op `tk` 语义分类表**(单槽化 Step 1 的输入)——逐 op 记录 `{类型行 / 旗标 / 宽度 / 无}` + 后端消费者(`instr.cr:460` 的 5 分派点 / `regalloc.cr:457` / `lower_to_core.cr:250·574` / `dump.cr:125`)+ 是否入项槽 + 依据(P4 T4 §2 方法扩面:`instr.cr` 分支逐条审计 + `ir_gen.cr` 全 `emit(` 调用点逐 op 静态审计 + 全语料 NOD (op,tk) 直方图)。**必须显式再裁 P4 排除项**:`IR_ALLOC`/`IR_CALL`/`IR_I2F`/`IR_F2I`/`IR_LOAD`/`IR_LOAD_ENUM_TAG`(P4 T4 §2 注明「留待 P5」)。 - **表 B:站点评级表**(D-3-6 / D25)——站点 1..10 逐条 `{语义 / 可达性证明 / 语料命中 / 判定点保留? / 挂点去留}`;站点 6 附不可达三面证明(`parser.cr:170-184` / `:227` / `:216-224`)。 - **表 C:P5 起点基线**——冻结二进制三 sha + 冒烟;72 档 × {`check`, `shadow`} 的 `decisions`/`agree`/全计数/站点覆盖/rc 分布(**以此为新基线**,P4 的 32620 等值不得直接沿用)。 - **表 D:-1 面清点(report-only)**——探针语料逐形态记录的 `ty_equiv`/`ty_sub` 负值计数 + `g_ty_uncovered`/`g_ty_exhausted` 归因(Task 3 的输入清单)。 @@ -153,9 +157,9 @@ ## Task 1:`.cir` 暖态 SIGSEGV 根因修复(预存缺陷;D-3-9-(ii),独立可做) -**Files:** Modify `src/compiler/cir_cache.cr`(根因处)· 可能 `src/compiler/main.cr`(cache 使能面)/ `src/stdlib/fmt.cr`(`str_len` 消费面——**只在根因确证涉及时**)· New/Modify `tests/selfhost/test_cache_identity.py`(或新套件 `test_cir_warm_path.py`)。 +**Files:** Modify `src/compiler/cir_cache.cr`(根因处)· 可能 Modify `src/compiler/main.cr`(cache 使能面)/ `src/stdlib/fmt.cr`(`str_len` 消费面——**只在根因确证涉及时**)· New/Modify `tests/selfhost/test_cache_identity.py`(或新套件 `test_cir_warm_path.py`)。 -**背景(登记值,实施时**先复现**,不得引用为已证)**:`corec build src/compiler/main.cr -O 0` **冷 rc=0 / 暖 rc=139**;gdb 栈 = `load_cir_cache`(`cir_cache.cr:373`)→ `str_len`(`fmt.cr:4`)← `load64`;**基线二进制同病**(P4 T5 §7-5 实测,非 P4 引入)。P4 T5 的「可选面关 `.cir` 缓存」只**顺带规避可选程序**,非本缺陷的修法。 +**背景(登记值;实施时**先复现**,不得引用为已证)**:`corec build src/compiler/main.cr -O 0` **冷 rc=0 / 暖 rc=139**;gdb 栈 = `load_cir_cache`(`cir_cache.cr:373`)→ `str_len`(`fmt.cr:4`)← `load64`;**基线二进制同病**(P4 T5 §7-5 实测,非 P4 引入)。P4 T5 的「可选面关 `.cir` 缓存」只**顺带规避可选程序**,非本缺陷的修法。 - [x] **Step 1: 红态复现(本任务自跑)**:`clean-cache` → 冷运行 rc=0 → **第二次**运行 rc=139(复现记录 = 命令 + rc + 是否稳定可重复);gdb 栈复现并落报告;用 `/tmp/p5t0/base/corec`(Task 0 冻结)复证「预存、非本批引入」。⚠ 复现时注意 TODO #2026-09-10-1 家族的 clean-cache 约定(跨重建必须 clean,相对 cwd)。 - [x] **Step 2: 归因(写读对称表)**:把快照的写侧(`cir_cache.cr` 写点)与读侧(:430-560 两个装载 loop + 入场闸 版本 `:383` / 身份 `:389-391` / 指纹 `:396`)逐字段列成**对称表**(字段 / 写偏移 / 读偏移 / 长度来源),核 `pos` 推进与长度域;**定位根因**(候选:长度字段读偏/越界、0 长与空串混淆、函数计数与实际记录数不一致、身份闸后的残余旧条目),**不得**先加守卫吞异常(若最终只能加守卫,必须在报告里说明根因不可达的实测证据 + 停下上报)。 @@ -163,13 +167,13 @@ - [x] **Step 4: 判据**:新套件全绿;**ELF canary IDENTICAL**;五 CI job rc=0;全枚举 55/55;`corec2==corec3` cmp IDENTICAL + N06=0 + 冒烟 42;`.ccr` 记录值(两套形式)冷态复测;`test_backend_bootstrap.py` rc=0 + `error[`=0;自源 `check src/compiler` rc=0。 - [x] **Step 5: 提交**:`fix: R2 P5 Task 1——.cir 暖态 SIGSEGV 根因修复(...根因一句话...);冷/暖两态产物一致回归` -**停条件**:若归因指向格式缺陷(需 `CIR_CACHE_VER` bump)或更深的缓存设计 ⇒ **停下上报**(bump 是允许面但须单独裁决 + 记失效面);若暖态 SIGSEGV 与「快照面语义」纠缠到无法在本任务内隔离 ⇒ 上报转独立批(不硬塞进 P5)。 +**停条件**:若归因指向格式缺陷(需 `CIR_CACHE_VER` bump)或更深的缓存设计 ⇒ **停下上报**(bump 是允许面,但须单独裁决并记失效面);若暖态 SIGSEGV 与「快照面语义」纠缠到无法在本任务内隔离 ⇒ 上报转独立批(不硬塞进 P5)。 ### Task 1 实施记录(2026-09-13;报告 `.superpowers/sdd/p5-task1-report.md`;证据 `/tmp/p5t1b/`) **根因(实测,非引用)**:装载侧**逐函数** `read_file(path)` = `alloc(fsize+1)`,而 bump 分配器(`rt.s alloc`)**不回收** ⇒ 946 个快照读缓冲**累计 1.1674 GiB > 1 GiB 堆**(`rt.s heap_start: .space 1024*1024*1024`;单条目 max 3,987,879B = 3.80MiB,因快照含**全程序边表** ⇒ 尺寸 O(程序) 而非 O(函数))⇒ `alloc` 耗尽返回 0(`.Lalloc_oom`)⇒ `load_cir_cache` 首行 `str_len(0)` → `load64(0,-8)` = **暖态 SIGSEGV**(gdb 三跑同栈 `load64(rdi=0,rsi=-8) ← str_len ← load_cir_cache`;冷态不读快照 ⇒ rc=0)。**停条件核**:写读对称表逐字段核(字段/写偏移/读偏移/长度来源 + `pos` 推进)⇒ **无长度域/格式缺陷 ⇒ 不 bump `CIR_CACHE_VER`**(保持 17)。 -**修法(根因级,非加钳位)**:`cir_cache.cr::cir_read_snapshot`(新增 30 行)= **单一复用读缓冲** `g_cir_read_buf/g_cir_read_cap`(峰值 = 最大单条目;读侧自此与写侧既有 `g_cir_write_buf/g_cir_write_cap` **同构**——读侧原是唯一逐调用新分配方);`w64(buf,-8,fsize+1)` 保住 `str_len` 约定 ⇒ **消费面(r64/str_sub 四点)零改动**;载入失败(open 失败 / `fsize<=0` / 短读 / 缓冲不可得=read EFAULT / 长度<56)⇒ `-1` = **cache miss**(三态纪律:载入失败 ⇒ 拒绝,miss = 无害重建,绝不静默当空表)。刻意**不写** `buf == 0` 形态空判(该 string-int 混比在 bootstrap 侧 `x86_64_stack_asm.py:164` 编成 `str_eq(buf,0)` ⇒ `str_len(0)` 自崩溃;**建议另单**,登记于报告 §6-①)。 +**修法(根因级,非加钳位)**:`cir_cache.cr::cir_read_snapshot`(新增 30 行)= **单一复用读缓冲** `g_cir_read_buf/g_cir_read_cap`(峰值 = 最大单条目;读侧自此与写侧既有 `g_cir_write_buf/g_cir_write_cap` **同构**——读侧原是唯一逐调用新分配方);`w64(buf,-8,fsize+1)` 保住 `str_len` 约定 ⇒ **消费面(r64/str_sub 四点)零改动**;载入失败(open 失败 / `fsize<=0` / 短读 / 缓冲不可得=read EFAULT / 长度<56)⇒ `-1` = **cache miss**(三态纪律:载入失败 ⇒ 拒绝,miss = 无害重建,绝不静默当空表)。刻意**不写** `buf == 0` 形态空判(该 `string-int` 混比在 bootstrap 侧 `x86_64_stack_asm.py:164` 编成 `str_eq(buf,0)` ⇒ `str_len(0)` 自崩溃;**建议另单**,登记于报告 §6-①)。 **判据(全部本实例实跑)**:新套件 **19/19**(`COREC_WARM_SELF=1` ⇒ **21/21**;RED 对照:冻结基线 × 同套件 = **15 PASS/1 FAIL**(D3 rc=-11))· `build_selfhost_native.py` rc=0(`corec` `8edb967f…` 两次构建逐字节同;`corearch`/`corelsp` = T0 记录值)· `check src/compiler` rc=0 · `test_backend_bootstrap` rc=0 + `error[`=0 · `selftest-types` **355/355** · 全枚举 **56/56**(48+1 selfhost + 7 bootstrap;+1 = 本套件)· ELF canary `95084e7b…d475` **IDENTICAL** · **暖≡冷(自源)**:冷 + 暖×2 三跑 ELF 同 sha `13230542f79da591c4ea…`(`cmp` IDENTICAL)、`.ccr` **八段冷==暖1==暖2**、946 条目戳三跑全等(**真命中**)、冻结基线冷产物亦同 sha(零发射面漂移)· 自举链 `corec2==corec3` `cmp` **IDENTICAL**(双 `13230542…`)+ N06=**0** + 冒烟 **42** + `--help` rc=1 · **突变控制**(M1:`load_cir_cache` 回灌修复前读路径 ⇒ 套件 **15 PASS/1 FAIL** 转红;精确回滚 ⇒ 源 sha `1220742f…` 复原 + 三二进制**逐字节回原值**)· 语料既有失败面无新增。 @@ -180,6 +184,7 @@ **Files:** Modify `src/compiler/dyn_arr.cr`(槽语义/偏移改名 + 布局注)· `src/compiler/dataflow.cr`(`df_create_node` 签名 + 存储 + `df_rebuild_ir` 派生)· `src/compiler/ir_gen.cr`(`emit` 分流;:129 消费点)· `src/compiler/ty_shadow.cr`(分类表驱动 + `sh_atom_of_term`;`sh_tk_term_of_code` 改造)· `src/compiler/cir_cache.cr`(装载侧重派生;**布局零变化**)· `src/compiler/dump.cr`(`--dump-tk-terms` 扩展)· `src/compiler/type_selftest.cr`(`t4.tk_*` 重新锁定 + 新例)· `tests/selfhost/test_ccr_types.py`(T4 节扩展)· New `tests/selfhost/test_single_slot.py`(或并入既有套件)。 **Interfaces:** + ``` ESZ_DFNODE : int = 72; // 字节数不变(D19) OFF_DF_TK : int = 40; // ★语义变更:类型项引用(g_type_terms 行号;-1 = 无项)= 类型面唯一真源 @@ -192,6 +197,7 @@ fn sh_atom_of_term(term: int) -> int // D21:TT_ATOM ∧ b ≥ fn df_create_node(opcode, dest, src1, src2, src3, tk_term: int, tk_aux: int) -> int // 存储:OFF_DF_TK ← tk_term;OFF_DF_AUX ← tk_aux(互斥不变量 D22-②) ``` + - [x] **Step 1: 用例(红)≥10 例**:① **类型面**:分类表为「类型行」的每类 op 各一正控(项槽 = `sh_term_of_ti(tk)` 同项);② **辅码面**:`IR_BOUNDS_CHECK`(旗标 1)/`IR_DEREF`/`IR_STORE_PTR`(宽度 8/4/2/1)三负控——项槽 **-1** ∧ 辅码槽 = 原码;③ **数值陷阱负控**(P4 同款):旗标 `1` 与宽度 `8` **不得**被当类型行建项(`TI_DEX`/`TI_DEX_S` 行);④ **无类型面**:`tk` 恒 0 的 op ⇒ 两槽皆空;⑤ **派生码不变量**:全语料 `iri_tk` 逐节点 == 旧值(对拍脚本 + (op,tk) 直方图 diff 空);⑥ **互斥不变量**:任一节点两槽不同时非空;⑦ **不可译拒绝**(D23):构造行越界/桥接缺口的类型面 op ⇒ `save_ccr` 拒绝 rc=1 + 诊断 + 无产物;⑧ **冷/暖**:项槽与辅码槽两态同值同索引;⑨ **`.ccr`/`--dump-objects` 逐字节同**(发射面零泄漏);⑩ **版本不动**:`CIR_CACHE_VER == 17` ∧ `test_cache_identity.py:VER_EXPECTED` 不动。 - [x] **Step 2: 写点分流**:`emit` 按 `sh_tk_face_of_code(opcode, type_kind)` 分流:类型行 ⇒ `tk_term = sh_term_of_ti(tk)`、`tk_aux = 0`;辅码 ⇒ `tk_term = -1`、`tk_aux = tk`;无 ⇒ 皆空。`df_create_node` 签名同步(**唯一调用点 = `emit`**,逐处核);`dataflow.cr` 保持「仅存储、零前端符号引用」纪律(注记落文件头)。 - [x] **Step 3: 派生面**:`df_rebuild_ir` 由 `(tk_term, tk_aux)` 派生 `iri_tk`:`tk_aux != 0 ⇒ tk_aux`;否则 `atom_of(tk_term)`;否则 0。**逐节点对拍旧值**(Step 1-⑤)。`.cir` 装载侧(`cir_cache.cr:448-453`)保持「重派生项槽」并把辅码槽按盘上码重派生(盘面仍 8 槽;DF 节点装载 loop 内两槽皆**重派生**,不得读盘项槽——P4 时点纪律)。 @@ -222,6 +228,7 @@ fn df_create_node(opcode, dest, src1, src2, src3, tk_term: int, tk_aux: int) -> **Files:** Modify `src/compiler/ty_shadow.cr`(`sh_term_of_ti` 命名分支 :328/:330 + `sh_sig_term_of_ti` :951 **两处同步**;新增身份链构造)· `src/compiler/type_engine.cr`(AK_NAMED 可判定面规则 + 不变槽加强的**适用域**与守卫)· `src/compiler/type_selftest.cr`(`unf.nominal_*` 两例重新锁定 + 新例)· `src/compiler/globals.cr`(如需新归因计数)· New `tests/selfhost/test_named_face.py`(**行为断言形态**——它必须能在 shadow 下线后独立存活)。 **Interfaces:** + ``` // ── 桥接侧:命名面身份链(取代空链 + b=行号 当身份)── // TYP_NAMED / TYP_GENERIC_PARAM : c = [sh_name_token(name_ni)] @@ -232,6 +239,7 @@ fn sh_named_identity_term(ti: int) -> int // -1 = 不可构造(⇒ 清零 // 两条规则(适用域见下):① 同链(逐元素同一性)⇒ 1;② 链异且**两侧链元素皆为类型项/身份令牌** ⇒ 0 // 边界:union/μ/未范化面**不适用**(保持三态 -1,登记)——加强须先满足「链元素皆类型项」不变量 ``` + - [x] **Step 1: 用例(红)**:命名面探针逐条断言 **`ty_equiv` ∈ {0,1}(非 -1)** 且**与 legacy 同值**:同/异名命名、两次实例化同实参的泛型应用(行不同 ⇒ 必须判等)、异实参泛型应用(判不等)、递归命名(`Node` vs `Node`;`*Node` vs `*Node`)、`[Named;N]`/`Named?`/元组含命名、别名一层、泛型形参位(`T` vs `T` / `T` vs `int`)、`AK_NAMED` vs 非命名(product/tuple/原生)。**同时用例必须落「负控」**:union/μ 未范化面**仍** -1(不得被加强误判为 0)。 - [x] **Step 2: 清零清点(report-only,**删除前置**)**:全语料 + 探针语料跑 {`check`, `shadow`} → `g_replace_unknown` = **0** ∧ `g_replace_bridge` = **0**(逐档表;同时报站点覆盖)。**判据 = 0;非 0 ⇒ 停下上报**(逐条裁决:收紧/放宽/未覆盖面)。 - [x] **Step 3: 实现**:① 桥接:两处命名构造点改为身份链(`sh_name_token` 复用,`ty_shadow.cr:244`);泛型应用实参项走 `sh_term_of_ti`(**不展开**,只用既有身份语义)。② 引擎:`lit_implies` 的 AK_NAMED 守卫(:192/:198)改为「链比较(同一性)→ 1 / 链异且链元素皆为类型项或身份令牌 → 0」;`ak_disjoint` 的 NAMED 行**不动**(仍不断言互斥)。③ **适用域守卫**:加强**只**用于「链元素集合 ⊆ {类型项, 身份令牌}」的原子(实现为一个显式判定函数 + 注释),其余面保持 -1(含 `tt_list_variance_at` 的不变槽面——**该面本任务不动**,除非探针证明残留 -1 来自该面;动则须逐面出「链元素皆类型项」证据)。 @@ -261,6 +269,7 @@ fn sh_named_identity_term(ti: int) -> int // -1 = 不可构造(⇒ 清零 **三件证据(协调者裁定)**:① **适用域证明** = 逐构造点**排序表**(令牌位:AK_REF 槽 0 / AK_SUM 槽 0,1 / AK_NAMED 槽 0〔不经本函数,走 `te_named_pair`〕;类型项位:SEQUENCE/PTR/PRODUCT/FN 全槽 + AK_REF 槽 1 + NAMED 实参位)⇒ 同 (ak, slot) **不存在排序混排**;域外面(μ 变元/¬/⊤ₖ)**保持 -1**(牙齿 = 突变 M3 + 自测 `t3b.elem_out_of_domain_stays_minus1`)。**AK_UNIT 形态二义**(原生 unit 项 = `tt_atom(AK_UNIT, 行号, -1)` 与令牌同形)**登记**:令牌先判是**失效方向**要求(若先判类型项 ⇒ token × unit 走 `ty_equiv` 判**等** = 假等 = P3-T1 令牌碰撞类);可达性 = 无构造点在同一槽混排两排序(负控 §③)。② **全语料对拍** = 上(**零翻转**)。③ **突变控制 4 条**:M1 令牌面中和(4 FAIL)/ M2 类型项面中和(7 FAIL + **残留探针复红 1/1**)/ M3 域外守卫去掉(3 FAIL)/ **M4 分派次序倒置**(3 FAIL,**复现 P3-T1 令牌碰撞 `unf.enum_variant_identity_scoped` 红** = 负控有牙)——逐条转红 + 源 sha/二进制 sha **精确回滚**(回滚后 `build/corec` 逐字节复原)。 **翻转与登记(收紧面清单)**:① `param.unknown_p0` → `param.elem_class_diff_zero`(`[int]` vs `[str]` 元素位)由 **-1 变 0**——语义加强(异原生类元素确定不同);与 spec §2.2 的 `sequence<⊤>` 正向面**无关**(后者走 `⊤ₖ` 分支),legacy 同结论(替换门一致);② `t3.counterexample_named_variant` 的 `ty_equiv(w, B)` 由 **-1 变 0**:空析取支里的**异变体令牌**比较由 -1(旧)变 0 ⇒ 撤掉原先掩盖 `sub_cover(B, B∩¬R) = 0` 的 -1 ⇒ **揭开预存过判**(¬ 面同类别名规则把 `B ⊆ ¬R` 判 0,值集语义应 1)——影响面实测 = 仅 witness 项(生产 `ty_exhaustive` 走 `tt_norm`+`ty_inhabited`、`gen_constr_witness_str` 走 `tt_display`;全语料零翻转)⇒ **登记为后续步**(¬ 面「异身份原子 ⇒ 不交」加强),本步不修、不近似。 + **停条件② 状态**:**已关闭**;D24 的「回落计数归零 → 删 legacy」前置对本面成立(残留探针 0/0 = 硬证据)。 ## Task 4:删 `type_equal_legacy` 与全部回落面(+ 桥接 legacy 副本 + 死分支/站点 6) diff --git a/docs/superpowers/plans/2026-09-15-fail-closed-diagnostics.md b/docs/superpowers/plans/2026-09-15-fail-closed-diagnostics.md index 67fabe6b..2e3637b4 100644 --- a/docs/superpowers/plans/2026-09-15-fail-closed-diagnostics.md +++ b/docs/superpowers/plans/2026-09-15-fail-closed-diagnostics.md @@ -2,27 +2,61 @@ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. -**Goal:** 兑现**维护者已裁「要改」的方向 = fail-closed**:把编译器语义收敛到「**报出错误 ⇒ `rc=1` 且不产生产物**」,消灭「诊断照打、二进制照出」的静默错产物类。机制 = 把 `src/compiler/main.cr` 的**硬名单闸反转为「默认全阻断 + 已知命中面豁免登记表」**(现行正向名单 ⇒ 默认 `hard = 1`,豁免表 = 白名单:码 + 语料位点 + 理由 + 生效范围)。**全批纪律:新面 report-only 先行、命中清单审查后才开门;命中面过大 ⇒ 转独立批(停条件)。** - -**Architecture:** 六条主线:① **前置侦查 + 冻结基线重建 + 锚点实核**(T0,源码零改动);② **全语料 report-only 基线(核心产物)**(T1:用**现有二进制**在 build 面语料上采全量命中清单——现有 `check` 面已是 fail-closed 闸,是天然仪器,**零源码改动**即可产出清单);③ **分诊表定稿 + 裁决门取裁**(T2,零代码);④ **闸门机制实现 + report-only 开关**(T3:反转 + 豁免表 + 隐藏旗标 + 采集器);⑤ **命中面处置**(T4:逐条归因——修根因 / 修语料 / 登记豁免);⑥ **开门 + 零产物语义 + 回归收官**(T5/T6)。 - -**Tech Stack / 锚点(本实例实读,行号 = 当前工作树):** 闸门三处 + 一处已收紧面——① **语法面闸**:`src/compiler/main.cr:134`(`parse_all()` 后 `g_diag_count > 0 ⇒ print_diagnostics(); return 1`)+ `:135`(`g_error_count > 0 ⇒ print_parse_errors(); return 1`);② **类型面闸(本批的对象)**:`main.cr:146-179`(`if g_diag_count > 0 { 硬名单扫描 }`;**6 条语句行** `:152`/`:153`/`:154`/`:160`/`:166`/`:174` 覆盖 **11 个码常量**;`if hard != 0 { return 1; }` 在 **`:178`**);③ **安全检查面闸(已 fail-closed)**:`main.cr:594-603`(`base_diags` 快照 → `ptr_analysis_all()` / `region_check_all()` / `provenance_verify_all()` → `g_diag_count > base_diags ⇒ return 1`,**无码过滤 = 任意诊断阻断**);④ **`check` 面闸(已 fail-closed)**:`main.cr:443-451`(`if g_diag_count > 0 { return 1; }`)。 -其余落点:`main.cr:399-402`(`run` 走同一 `run_frontend` 闸)· `:431-438`(`--static` 前置 `rt.cr`)· `:440-441`(`fe_rc` 唯一入口)· `:473`(`make_cir_cache_dir`)· `:565-591`(`cir`,**不过**安全检查面)· `:620-662`(`ccr`)· `:665-703`(`build`:`:671` `.ccr` 路径 / `:674-679` `save_ccr` / `:682-702` 拼 `corearch` 命令行并 `system()` / `:702` `return exit_code`)· `diag.cr:122-150`(`print_diagnostics`,码面 = `cat = ec/1000` + `num = ec%1000`,`diag.cr:86-104` 前缀表 + `:106-110` 补零)· `checker.cr:820-828`(`check_error` 唯一写入器,记录 40B = `globals.cr:182` `DIAG_REC_SIZE`)· `checker.cr:490-495`(`diag_type_incompatible` 组合判定)· `globals.cr:463-500`(`reset_frontend_state` 清 `g_diag_count`;`check_all` 自身亦在 `checker.cr:3805` 清零)· `src/ci/run.sh:31-33`(check job)/`:36-54`(suite job:`:44` `*_mini*.cr` SKIP、`:46` 空文件 SKIP)/`:119-130`(full-bootstrap)· `tools/baseline/parity_run.sh:30`(`CORPUS_TOTAL=72`)/`:32-40`(逐档 `clean-cache` + `check`)/`:68-71`(计数硬断言)· `tools/baseline/probes_run.sh`(`PROBE_TOTAL=29`)。 - -**Spec / 依据:** ① **维护者 2026-09-14 裁定「要改、方向 = fail-closed」**(本批成立的前提;裁定文本经协调者转述,**无独立文件载体 —— 须 T0 向维护者核一句原文并落报告**);② **P6 裁决门 裁-P6-2 的 (b)(c) 两问**(`docs/superpowers/plans/2026-09-14-r2-p6-tail.md:58`:**(b)** 非硬名单诊断是否收紧到 `build` 面;**(c)** 新硬错入闸判据是否成文化为「判定继续 ⇒ 产出静默错产物」)——**本批 = 该两问的最强形式,未取裁前的方向性背书不成立**;③ **P5 已落政策**:P-A(ICE04 硬错,`plans/2026-09-13-r2-p5-cleanup.md` + `main.cr:161-166` 注)、TA02(TODO #2026-09-11-14 + `main.cr:167-174` 注)——**本批不得回退这两条**;④ **`docs/error-codes.md`**(码族/消息模板/统计);⑤ **E-14 的活证据**(P6 T0 报告 §6-5:`tests/suite/ptr_arith.cr` `check` rc=1(B04 `12:8`)而 `build --static` rc=0 且产出 canary ELF)。 +**Goal:** 兑现**维护者已裁「要改」的方向 = fail-closed**。本批把编译器语义收敛到「**报出错误 ⇒ `rc=1` 且不产生产物**」,消灭「诊断照打、二进制照出」的静默错产物类。机制 = 把 `src/compiler/main.cr` 的**硬名单闸反转为「默认全阻断 + 已知命中面豁免登记表」**:现行名单为正向名单,反转后**默认 `hard = 1`**;豁免表充当白名单,条目 = 码 + 语料位点 + 理由 + 生效范围。**全批纪律:新面 report-only 先行、命中清单审查后才开门;命中面过大 ⇒ 转独立批(停条件)。** + +**Architecture:** 本批共六条主线。 + +- ① **前置侦查 + 冻结基线重建 + 锚点实核**(T0,源码零改动)。 +- ② **全语料 report-only 基线(核心产物)**(T1:用**现有二进制**在 build 面语料上采全量命中清单;现有 `check` 面已是 fail-closed 闸,是天然仪器,**零源码改动**即可产出清单)。 +- ③ **分诊表定稿 + 裁决门取裁**(T2,零代码)。 +- ④ **闸门机制实现 + report-only 开关**(T3:反转 + 豁免表 + 隐藏旗标 + 采集器)。 +- ⑤ **命中面处置**(T4:逐条归因——修根因 / 修语料 / 登记豁免)。 +- ⑥ **开门 + 零产物语义 + 回归收官**(T5/T6)。 + +**Tech Stack / 锚点(本实例实读,行号 = 当前工作树):** 闸门共三处,另有一处为已收紧面。 + +- ① **语法面闸**:`src/compiler/main.cr:134`(`parse_all()` 后 `g_diag_count > 0 ⇒ print_diagnostics(); return 1`)+ `:135`(`g_error_count > 0 ⇒ print_parse_errors(); return 1`)。 +- ② **类型面闸(本批的对象)**:`main.cr:146-179`(`if g_diag_count > 0 { 硬名单扫描 }`)。其中 **6 条语句行** `:152`/`:153`/`:154`/`:160`/`:166`/`:174` 覆盖 **11 个码常量**;`if hard != 0 { return 1; }` 在 **`:178`**。 +- ③ **安全检查面闸(已 fail-closed)**:`main.cr:594-603`(`base_diags` 快照 → `ptr_analysis_all()` / `region_check_all()` / `provenance_verify_all()` → `g_diag_count > base_diags ⇒ return 1`,**无码过滤 = 任意诊断阻断**)。 +- ④ **`check` 面闸(已 fail-closed)**:`main.cr:443-451`(`if g_diag_count > 0 { return 1; }`)。 + +其余落点逐条如下。 + +- `main.cr:399-402`:`run` 走同一 `run_frontend` 闸。 +- `main.cr:431-438`:`--static` 前置 `rt.cr`。 +- `main.cr:440-441`:`fe_rc` 唯一入口。 +- `main.cr:473`:`make_cir_cache_dir`。 +- `main.cr:565-591`:`cir`,**不过**安全检查面。 +- `main.cr:620-662`:`ccr`。 +- `main.cr:665-703`:`build`——`:671` 为 `.ccr` 路径,`:674-679` 为 `save_ccr`,`:682-702` 拼 `corearch` 命令行并调用 `system()`,`:702` 为 `return exit_code`。 +- `diag.cr:122-150`:`print_diagnostics`,码面 = `cat = ec/1000` + `num = ec%1000`;`diag.cr:86-104` 为前缀表,`:106-110` 为补零。 +- `checker.cr:820-828`:`check_error` 唯一写入器,记录 40B = `globals.cr:182` `DIAG_REC_SIZE`。 +- `checker.cr:490-495`:`diag_type_incompatible` 组合判定。 +- `globals.cr:463-500`:`reset_frontend_state` 清 `g_diag_count`;`check_all` 自身亦在 `checker.cr:3805` 清零。 +- `src/ci/run.sh:31-33`:check job;`:36-54`:suite job(`:44` 为 `*_mini*.cr` SKIP、`:46` 为空文件 SKIP);`:119-130`:full-bootstrap。 +- `tools/baseline/parity_run.sh:30`:`CORPUS_TOTAL=72`;`:32-40`:逐档 `clean-cache` + `check`;`:68-71`:计数硬断言。 +- `tools/baseline/probes_run.sh`:`PROBE_TOTAL=29`。 + +**Spec / 依据:** + +- ① **维护者 2026-09-14 裁定「要改、方向 = fail-closed」**,本批成立的前提即此。该裁定文本经协调者转述,**无独立文件载体 —— 须 T0 向维护者核一句原文并落报告**。 +- ② **P6 裁决门 裁-P6-2 的 (b)(c) 两问**(`docs/superpowers/plans/2026-09-14-r2-p6-tail.md:58`):**(b)** 非硬名单诊断是否收紧到 `build` 面;**(c)** 新硬错入闸判据是否成文化为「判定继续 ⇒ 产出静默错产物」。**本批 = 该两问的最强形式,未取裁前的方向性背书不成立**。 +- ③ **P5 已落政策**:P-A(ICE04 硬错,`plans/2026-09-13-r2-p5-cleanup.md` + `main.cr:161-166` 注)、TA02(TODO #2026-09-11-14 + `main.cr:167-174` 注)。**本批不得回退这两条**。 +- ④ **`docs/error-codes.md`**(码族 / 消息模板 / 统计)。 +- ⑤ **E-14 的活证据**(P6 T0 报告 §6-5:`tests/suite/ptr_arith.cr` 的 `check` rc=1(B04 `12:8`),而 `build --static` rc=0 且产出 canary ELF)。 --- ## 前置状态(**本计划未跑任何构建/测试**;下列全部为实读源码/文档或既有报告记录值,出处逐条标注) - **工作树 = `/tmp/p7wt`,基线 = P6 终态提交 `97f4394f`**(协调者给定)。**本实例 `jj` 命令零执行**(纪律:统一由协调者提交);`ps` 实查无并发编译进程的步骤留给实施任务。 -- **诊断通道实读 = 5 条**(全仓 `check_error(` / `g_diags` 写入点 grep 实证): - 1. **词法/语法消息通道**:`lexer.cr:39-43` `add_error()`(`g_errors` = 驻留串下标)+ `parser.cr` 同族 `add_error` —— **20 个调用点**(`lexer.cr` 10:`:147/:226/:233/:236/:238/:240/:246/:436/:454/:456`;`parser.cr` 10:`:468/:591/:704/:1472/:1474/:1477/:1479/:1482/:1531/:1580`)。无码,打印形 `error: `(`diag.cr:154-162`)。**已 fail-closed**(`main.cr:135`)。 - 2. **语法诊断码通道**:`parser.cr` 直接写 `g_diags`(15 处写入 / **8 个码**):`EC_P_EXPECTED`(`:121`/`:130`)、`EC_P_FIELD_SYNTAX`(`:1828`)、`EC_P_PARAM_TYPE`(`:1847`)、`EC_TA_UNKNOWN_TAG`(`:829`)、`EC_P_NESTED_FN`(`:927`)、`EC_P_TOO_MANY_PARAMS`(`:1453`)、`EC_P_STRUCT_LIMIT`(`:1647`)、`EC_P_ENUM_LIMIT`(`:1723`/`:1728`)。**已 fail-closed**(`main.cr:134`)。 - 3. **类型诊断码通道(`check_all` 内,**本批反转对象**)**:`checker.cr` 的 `check_error` 调用面 = **55 处 / 32 个码**(清单见「表 1」)。`check` 面已 fail-closed(`main.cr:448`);**`build` 面只拦 11 码**(`main.cr:152-174`)⇒ **本批的唯一缺口面**。 - 4. **安全检查面通道(build/ccr 专属)**:`region_check.cr:83`/`:134`(`EC_B_LIFETIME`/B11)、`provenance_verify.cr:68`(`EC_TU_DEREF`/TU03)、`:91`/`:99`/`:126`(`EC_TK_INDEX`/TK01 复用)。**已 fail-closed**(`main.cr:600`,任意新诊断阻断)——**注意:`check` 面不跑该面(`main.cr:451` 提前返回)⇒ 该面是「check rc=0 / build rc=1」的**反向不一致**存在性证据**(与 `ptr_arith` 的正向不一致成对;本实例未构造具体语料,**须 T1 实测登记**)。 - 5. **非 `g_diags` 的 `error:` 打印通道**:`main.cr`(`:32`/`:94`/`:421`/`:434`/`:640`/`:675`/`:679`、写入失败 `:650-652`/`corearch.cr:510`/`:586`/`:596`)、`corearch.cr`(装载/链接失败全分支)、`interp.cr:408`/`:413`/`:738`/`:743`。**已 fail-closed**(各自 `return 1`)。 -- **码面实读统计**:`ast.cr` 定义码 ≈ **146**(`docs/error-codes.md:275-287` 统计表自述「总计 ~146」);**可达码(有 raise 点)= 42**(本实例用 `check_error(EC_*` / `diag_type_incompatible(…, EC_*` / `DIAG_REC_SIZE, EC_*` 三形态全仓 grep 去重实得 43 项,其中 `EC_SIZE` 为 `DIAG_REC_SIZE` 的子串假命中,扣 1)⇒ **其余 ≈104 个码「定义零 raise」(本批不动,登记)**。**码名两式约定**(照 P6 T0 表 D-6):常量名 `EC_P_ENUM_LIMIT=1022`(`ast.cr:372`)而**用户面实印 `error[P22]`**(`diag.cr:132-136` 的 `num = ec%1000 = 22`)——**本计划一律「常量名(用户面码)」双写**。 +- **诊断通道实读 = 5 条**(全仓 `check_error(` / `g_diags` 写入点 grep 实证)。逐条如下。 + 1. **词法/语法消息通道**:`lexer.cr:39-43` 的 `add_error()`(`g_errors` = 驻留串下标),加 `parser.cr` 的同族 `add_error`。该通道共 **20 个调用点**(`lexer.cr` 10 处,即 `:147`/`:226`/`:233`/`:236`/`:238`/`:240`/`:246`/`:436`/`:454`/`:456`;`parser.cr` 10 处,即 `:468`/`:591`/`:704`/`:1472`/`:1474`/`:1477`/`:1479`/`:1482`/`:1531`/`:1580`)。该通道无码,打印形为 `error: `(`diag.cr:154-162`)。**已 fail-closed**(`main.cr:135`)。 + 2. **语法诊断码通道**:`parser.cr` 直接写 `g_diags`,共 15 处写入 / **8 个码**:`EC_P_EXPECTED`(`:121`/`:130`)、`EC_P_FIELD_SYNTAX`(`:1828`)、`EC_P_PARAM_TYPE`(`:1847`)、`EC_TA_UNKNOWN_TAG`(`:829`)、`EC_P_NESTED_FN`(`:927`)、`EC_P_TOO_MANY_PARAMS`(`:1453`)、`EC_P_STRUCT_LIMIT`(`:1647`)、`EC_P_ENUM_LIMIT`(`:1723`/`:1728`)。**已 fail-closed**(`main.cr:134`)。 + 3. **类型诊断码通道(`check_all` 内,本批反转对象)**:`checker.cr` 的 `check_error` 调用面 = **55 处 / 32 个码**(清单见「表 1」)。`check` 面已 fail-closed(`main.cr:448`);**`build` 面只拦 11 码**(`main.cr:152-174`)⇒ **本批的唯一缺口面**。 + 4. **安全检查面通道(build/ccr 专属)**:`region_check.cr:83`/`:134`(`EC_B_LIFETIME`/B11)、`provenance_verify.cr:68`(`EC_TU_DEREF`/TU03)、`:91`/`:99`/`:126`(`EC_TK_INDEX`/TK01 复用)。**已 fail-closed**(`main.cr:600`,任意新诊断阻断)。**注意:`check` 面不跑该面(`main.cr:451` 提前返回)⇒ 该面是「check rc=0 / build rc=1」的反向不一致存在性证据**(与 `ptr_arith` 的正向不一致成对;本实例未构造具体语料,**须 T1 实测登记**)。 + 5. **非 `g_diags` 的 `error:` 打印通道**:`main.cr`(`:32`/`:94`/`:421`/`:434`/`:640`/`:675`/`:679`,写入失败为 `:650-652`/`corearch.cr:510`/`:586`/`:596`)、`corearch.cr`(装载/链接失败全分支)、`interp.cr:408`/`:413`/`:738`/`:743`。**已 fail-closed**(各自 `return 1`)。 +- **码面实读统计**:`ast.cr` 定义码 ≈ **146**(`docs/error-codes.md:275-287` 统计表自述「总计 ~146」);**可达码(有 raise 点)= 42**(本实例用 `check_error(EC_*` / `diag_type_incompatible(…, EC_*` / `DIAG_REC_SIZE, EC_*` 三形态全仓 grep 去重实得 43 项,其中 `EC_SIZE` 为 `DIAG_REC_SIZE` 的子串假命中,扣 1)⇒ **其余 ≈104 个码「定义零 raise」,本批不动,登记**。**码名两式约定**(照 P6 T0 表 D-6):常量名写作 `EC_P_ENUM_LIMIT=1022`(`ast.cr:372`),而**用户面实印 `error[P22]`**(`diag.cr:132-136` 的 `num = ec%1000 = 22`)——**本计划一律「常量名(用户面码)」双写**。 - **现行 11 码硬名单**(`main.cr:152-174` 逐行实读):`EC_R_OOB`(R002)· `EC_TK_SLICE_BOUNDS`(TK05)· `EC_TK_SLICE_LEN`(TK06)· `EC_TS_MISSING_FIELD`/`EC_TS_UNKNOWN_FIELD`/`EC_TS_FIELD_TYPE`/`EC_TS_FIELD_DUP`(TS01-04)· `EC_TK_ELEM_TYPE`(TK02)· `EC_TM_EXHAUST`(TM03)· `EC_ICE_TY_INDET`(ICE04)· `EC_TA_DECL`(TA02)。 - **已知非硬名单诊断**(`ast.cr:487-489` 定义、`main.cr` 名单外):`EC_TG_ARG_COUNT`(TG01,**零 raise**)· `EC_TG_BOUND`(TG02,raise 于 `checker.cr:1227`/`:1233`/`:2059`)· 族内其余(N/TF/TB/TC/TM/TK/B 面)。 - **`check` 面不产生产物**(实读:`main.cr:444-451` 在 `:467` `optrep_begin()`/`:473` `make_cir_cache_dir()` 之前返回)⇒ 「零产物」的缺口**只在 `build`/`ccr`/`cir` 面**。 @@ -41,7 +75,7 @@ | `selftest-types` / `selftest-purity` | — | — | — | 自测通道,不读源文件 | 无 | **不改** | | LSP(`src/lsp/lsp.cr`) | — | — | — | 编辑器诊断推送(不产生产物) | 无 | **不改**(登记:非产物面,fail-closed 不适用) | -**判定面定义(本批语义)**:**error = 阻断**(`rc=1` + 零产物);本仓**现行无 warning 通道**(全仓无 `warning[` 打印面;`TM04`(`EC_TM_REDUNDANT`)在 `main.cr:159` 注中记为「软面登记(同 Rust unreachable-pattern 的警告约定)」但**打印仍是 `error[TM04]`**)⇒ **本批要么把软面码降级为真 warning,要么登记为豁免**(见裁-FC-2)。 +**判定面定义(本批语义)**:**error = 阻断**(`rc=1` + 零产物);本仓**现行无 warning 通道**(全仓无 `warning[` 打印面)。`TM04`(`EC_TM_REDUNDANT`)在 `main.cr:159` 注中记为「软面登记(同 Rust unreachable-pattern 的警告约定)」,**但打印仍是 `error[TM04]`** ⇒ **本批要么把软面码降级为真 warning,要么登记为豁免**(见裁-FC-2)。 --- @@ -86,7 +120,7 @@ **表 1 计数:① 必须阻断 = 25 码**(TA01/TA02/TF08/TF09/TF10/TB01/TC01/TC02/TC04/TM03/TK01/TK02/TK05/TK06/R002/N008/N009/TG02/B001/B002/ICE04/TS01/TS02/TS03/TS04)**② 必须豁免 = 7 码**(TF01 · TF07 · TM04 · N001 · N006 · N011 · B004)**③ 本批不动 = 表 0 的七行作用域外命令 + ≈104 个「定义零 raise」码 + 5 条通道里已 fail-closed 的 4 条**。 -**表 1-补:已 fail-closed 的 10 个可达码(本批不改,清点收编)**:`EC_P_EXPECTED`/`EC_P_FIELD_SYNTAX`/`EC_P_PARAM_TYPE`/`EC_P_NESTED_FN`/`EC_P_TOO_MANY_PARAMS`/`EC_P_STRUCT_LIMIT`/`EC_P_ENUM_LIMIT`/`EC_TA_UNKNOWN_TAG`(语法面 8,`main.cr:134`)· `EC_B_LIFETIME`(B11,`region_check.cr:83`/`:134`)· `EC_TU_DEREF`(TU03,`provenance_verify.cr:68`)(安全检查面 2,`main.cr:600`)。⇒ **可达码 42 = 25 + 7 + 10。** +**表 1-补:已 fail-closed 的 10 个可达码(本批不改,清点收编)**:`EC_P_EXPECTED`/`EC_P_FIELD_SYNTAX`/`EC_P_PARAM_TYPE`/`EC_P_NESTED_FN`/`EC_P_TOO_MANY_PARAMS`/`EC_P_STRUCT_LIMIT`/`EC_P_ENUM_LIMIT`/`EC_TA_UNKNOWN_TAG`(语法面 8 个,落 `main.cr:134`)· `EC_B_LIFETIME`(B11,`region_check.cr:83`/`:134`)· `EC_TU_DEREF`(TU03,`provenance_verify.cr:68`)(安全检查面 2 个,落 `main.cr:600`)。⇒ **可达码 42 = 25 + 7 + 10。** --- @@ -104,7 +138,7 @@ | 探针语料 | `tests/probes/*.cr` 29 档 | `check` | **17×0 / 12×1**(12 档为**故意的负例**) | **零变化**(check 面不改 ⇒ 两态对拍仍为零差异) | `tests/probes/README.md:58` | | `examples/*.cr` | 4 档 | `check` | 2 档解析错(既有) | 零变化(check 面) | P6 T0 §3.1 | -**转红面预估方法(**硬要求,T1 落地**)**:① **不靠猜**:T1 用**现有二进制**对「build 面语料全集」逐档跑 `build`(`-o /tmp/fc1/out/`,**保留产物供二次比对**),采集 `rc` + 日志中全部 `error[XX]` 行的(码, `file:line`)二元组 ⇒ 产出 `hits.tsv`;② **逐档归因表**:每档给「码 → 归因(真错 / 假阳性 / 语境缺失 / 政策软面)→ 处置(修根因 / 修语料 / 登记豁免)」;③ **分批开门办法**:批次 1 = 全反转 + 豁免表覆盖 T1 全清单(**先保 CI 绿**);批次 2..n = 逐条撤销豁免(每条以「根因已修 / 语料已正」为撤除判据),**只减不增**。 +**转红面预估方法(硬要求,T1 落地)**:① **不靠猜**——T1 用**现有二进制**对「build 面语料全集」逐档跑 `build`(`-o /tmp/fc1/out/`,**保留产物供二次比对**),采集 `rc` 与日志中全部 `error[XX]` 行的(码, `file:line`)二元组 ⇒ 产出 `hits.tsv`。② **逐档归因表**——每档给出「码 → 归因(真错 / 假阳性 / 语境缺失 / 政策软面)→ 处置(修根因 / 修语料 / 登记豁免)」。③ **分批开门办法**——批次 1 = 全反转 + 豁免表覆盖 T1 全清单(**先保 CI 绿**);批次 2..n = 逐条撤销豁免(每条以「根因已修 / 语料已正」为撤除判据),**只减不增**。 --- @@ -141,16 +175,16 @@ ## Global Constraints(照 P6 简版) -- **jj only(禁 git 含只读/复合)**;**提交路径限定**(多 agent 在场:一律 `jj commit -m … `);所有命令 `nice -n 19`;一构建一编译**串行**(每段前 `ps` 实查);cwd = 仓库根(`/tmp` cwd 触发 import 解析假失败)。 -- **基线纪律**:每任务开工先取**同任务起点**基线(binary sha + 语料 rc 表 + 探针 rc 表),**不得沿用上一任务的计数**。冻结基线 = 由 `tools/baseline/rebuild.sh`(配方 `tools/baseline/REBUILD.md`;pinned revision + 三 sha 白名单)重建;**P6 终态的白名单值须 T0 实核后落表**(P6 期的白名单 = P4 收官 `9bcb7083` 产物,**不是**本批基线 ⇒ 本批须以 P6 终态 revision 重建并**新锁白名单**)。 -- **ELF canary(硬闸,全批)**:`clean-cache` → `build tests/suite/ptr_arith.cr --static` → sha256 `95084e7bc68d6550d21d3d96fa3afd89c67a5d89edce5656a3d2e74fc923d475`(28822B)。**本批的 canary 语义有变体**:T5 开门后若 B04 豁免生效,canary 应**逐字节同**(豁免 = 不阻断,发射面零变化);**若 canary 不可产 ⇒ 立即停下**(= 裁-FC-3 未取裁或取 (i)/(iii) 的信号)。 -- **发射面声明(本批必须显式声明)**:**本批声明发射面零变更**(闸门 = 前端 rc 语义;不触 `ir_gen`/`lower_to_ccr`/`emit`)。任何 canary/`--dump-objects`/`.ccr` 逐字节差异 ⇒ 停下(越界信号)。 -- **`.ccr` 记录值引用约定(D28 继承)**:一律带**命令形式**(`corec ccr F -o O` vs `corec build F -o O --static`,差恒 143B)+ **缓存态**(冷/热;非可选程序冷≠热为**预存**豁免);比较任何 `.ccr`/缓存态产物前 `clean-cache`。 -- **判据标准按 TODO #2026-09-11-9**:不采用「与旧版逐字节同」当语义证据;结构性断言 + 语义零变化 + 自举稳定为本仓主判据;「≥N 例」= 下限(可增不可减);**自测用例只增不减**(重新锁定/改名允许,删除须给死亡证据)。 -- **三态纪律(不得稀释)**:引擎 -1 不得当 0/1 用;载入失败/段缺失/行不可译/项不可建 ⇒ **拒绝**。**新硬错先 report-only**:本批新增的任何 rc=1 门(含闸门反转本身)必须先在**全语料**(72 档 + `tests/selfhost` **内联源** + `src/stdlib` + `examples` + `src/compiler` 自指 + **58 套件全枚举**)report-only 跑一遍,清单审查后才开门。 -- **清单三面同核(B.6,硬性)**:任何清单/段表改动必须三面同核——`build_selfhost_native.py`(`corec_files`/`corearch_files`/`corelsp_files`)↔ `src/targets/x86_64-linux/_import.cr` ↔ `src/compiler/_import.cr`;每任务回归面**必含** `tests/selfhost/test_backend_bootstrap.py`(rc=0 + 构建日志 `error[` = 0)。本批新增的 runner/语料(`tools/baseline/*`、`tests/probes/*`)**不进**任何编译清单。 -- **不得回退既有收纳**:TS01-04/TK02 硬门(#29)、TM03/TG02 门(#31/#33)、F2 常量档拒绝语义与「N 不回身份」、F5 槽位契约(#25/#28)、效应/纯度判据(#26/#27)、`iface_satisfies` 轴序 A>C>B、P4 全批、P5 全批(ICE04/TA02/影子下线)、P6 全批(β/¬ 面/never/文档)——**一律不动**;冲突 → 停下上报。 -- **本语言无三元运算符**;取模须非负;键比较不得依赖 i64 回绕;noclobber(`>|`);**不写 `buf == 0` 形态的空判**(string-int 混比在 bootstrap 侧编成 `str_eq` ⇒ 自崩);bootstrap 构建的 corec 对 **`&&`/`||` 两侧无条件求值** ⇒ **不得写 `guard && 表读`**(`p6-task4-report.md` §3 先例:须嵌套 `if`)。 +- **版本控制与提交**:一律使用 `jj`,**禁 git(含只读调用与复合调用)**。**提交路径限定**(多 agent 在场时,一律以 `jj commit -m … ` 形式提交)。所有命令以 `nice -n 19` 运行。构建与编译**串行**执行,每段之前以 `ps` 实查。cwd 恒为仓库根(`/tmp` 作为 cwd 会触发 import 解析假失败)。 +- **基线纪律**:每个任务开工前先取**同任务起点**基线(binary sha + 语料 rc 表 + 探针 rc 表),**不得沿用上一任务的计数**。冻结基线由 `tools/baseline/rebuild.sh` 重建,配方见 `tools/baseline/REBUILD.md`,内容为 pinned revision + 三 sha 白名单。**P6 终态的白名单值须由 T0 实核后落表**:P6 期的白名单 = P4 收官 `9bcb7083` 的产物,**不是**本批基线 ⇒ 本批须以 P6 终态 revision 重建并**新锁白名单**。 +- **ELF canary(硬闸,全批)**:命令序列 = `clean-cache` → `build tests/suite/ptr_arith.cr --static`,判据值 = sha256 `95084e7bc68d6550d21d3d96fa3afd89c67a5d89edce5656a3d2e74fc923d475`(28822B)。**本批的 canary 语义有变体**:T5 开门后若 B04 豁免生效,canary 应**逐字节同**(豁免 = 不阻断,发射面零变化)。**若 canary 不可产 ⇒ 立即停下**,该信号等价于裁-FC-3 未取裁或取 (i)/(iii)。 +- **发射面声明(本批必须显式声明)**:**本批声明发射面零变更**(闸门 = 前端 rc 语义,不触 `ir_gen`/`lower_to_ccr`/`emit`)。任何 canary/`--dump-objects`/`.ccr` 逐字节差异 ⇒ 停下(越界信号)。 +- **`.ccr` 记录值引用约定(D28 继承)**:引用记录值一律带**命令形式**(`corec ccr F -o O` vs `corec build F -o O --static`,差恒 143B),并带**缓存态**(冷/热;非可选程序的冷态不等于热态属**预存**豁免)。比较任何 `.ccr`/缓存态产物之前先执行 `clean-cache`。 +- **判据标准按 TODO #2026-09-11-9**:不采用「与旧版逐字节同」当语义证据;本仓主判据 = 结构性断言 + 语义零变化 + 自举稳定。「≥N 例」表示下限(可增不可减);**自测用例只增不减**(重新锁定/改名允许,删除须给死亡证据)。 +- **三态纪律(不得稀释)**:引擎 -1 不得当 0/1 用;载入失败/段缺失/行不可译/项不可建 ⇒ **拒绝**。**新硬错先 report-only**:本批新增的任何 rc=1 门(含闸门反转本身)必须先在**全语料**上 report-only 跑一遍,清单审查后才开门;全语料 = 72 档 + `tests/selfhost` **内联源** + `src/stdlib` + `examples` + `src/compiler` 自指 + **58 套件全枚举**。 +- **清单三面同核(B.6,硬性)**:任何清单/段表改动必须三面同核,即 `build_selfhost_native.py`(`corec_files`/`corearch_files`/`corelsp_files`)↔ `src/targets/x86_64-linux/_import.cr` ↔ `src/compiler/_import.cr`。每任务回归面**必含** `tests/selfhost/test_backend_bootstrap.py`(判据 = rc=0 + 构建日志 `error[` = 0)。本批新增的 runner/语料(`tools/baseline/*`、`tests/probes/*`)**不进**任何编译清单。 +- **不得回退既有收纳**:TS01-04/TK02 硬门(#29)、TM03/TG02 门(#31/#33)、F2 常量档拒绝语义与「N 不回身份」、F5 槽位契约(#25/#28)、效应/纯度判据(#26/#27)、`iface_satisfies` 轴序 A>C>B、P4 全批、P5 全批(ICE04/TA02/影子下线)、P6 全批(β/¬ 面/never/文档)——**一律不动**;冲突时停下上报。 +- **语言面约束**:本语言无三元运算符;取模须非负;键比较不得依赖 i64 回绕;启用 noclobber(`>|`);**不写 `buf == 0` 形态的空判**(string-int 混比在 bootstrap 侧编成 `str_eq` ⇒ 自崩)。bootstrap 构建的 corec 对 **`&&`/`||` 两侧无条件求值** ⇒ **不得写 `guard && 表读`**(先例见 `p6-task4-report.md` §3:须嵌套 `if`)。 - **多 agent 纪律**:不并发构建;提交路径限定;实施时逐任务串行;突变控制一律在**仓库外实拷贝**(`tests/` 必须**实拷贝**而非软链)。 --- @@ -178,11 +212,12 @@ **Files:** 无源码改动。产物 = 报告 `.superpowers/sdd/fc-task0-report.md`(工作区,不入提交)+ 重建的冻结基线 `/tmp/fc0/base/{corec,corearch,corelsp}` + 清点原始输出(`/tmp/fc0/`)。 **Interfaces(产物四表,数字一律实测;未实测标「待实测」):** -- **表 A:冻结基线重建**——`tools/baseline/rebuild.sh`(或等价手跑配方:`jj workspace add --revision 97f4394f` → `nice -n 19 python3 build_selfhost_native.py`)→ 三 sha **新锁白名单**(写入本任务产出的 `REBUILD.md` 换代记录);构建 ×2 取确定性;冒烟 42。 -- **表 B:本批起点判据基线**——起点基线值表 1–11 项**逐条复跑**(五 CI job / 全枚举 / `check src/compiler` / `selftest-types` / 构建确定性 ×2 / 自举链 / canary / `.ccr` 四条 / `--dump-objects` / `.cir` DOT)。 -- **表 C:语料清点(**本批的新增面**)**——① 72 档逐档清单 + rc;② **build 面语料全集**:`tests/suite` 实 build 档(`run.sh:36-54` 语义实跑逐档计数)、`src/compiler/main.cr --static -O 0`、canary 档、`.ccr` 两档、`tests/selfhost/*.py` 内 `build` 调用逐处清点(含内联源去重)、`examples/*.cr`;③ 探针 29 档。 -- **表 D:锚点实核**——本计划「Tech Stack」「表 0/1/2」的每个 `file:line` 逐条实读复核(**行号漂移以本轮实读为准**,漂移逐条写进文档)。 -- **表 E:裁定原文核录**——向维护者核一句「fail-closed 方向已裁」的原文/出处(来源 = 协调者转述);**无原文 ⇒ 本批章程不成立 ⇒ 停**。 + +- **表 A:冻结基线重建**。做法 = `tools/baseline/rebuild.sh`(或等价手跑配方:`jj workspace add --revision 97f4394f` → `nice -n 19 python3 build_selfhost_native.py`),产出三 sha 的**新锁白名单**(写入本任务产出的 `REBUILD.md` 换代记录)。同时做构建 ×2 取确定性,并做冒烟 42。 +- **表 B:本批起点判据基线**。起点基线值表 1–11 项**逐条复跑**(五 CI job / 全枚举 / `check src/compiler` / `selftest-types` / 构建确定性 ×2 / 自举链 / canary / `.ccr` 四条 / `--dump-objects` / `.cir` DOT)。 +- **表 C:语料清点(本批的新增面)**。含三项:① 72 档逐档清单 + rc;② **build 面语料全集**——`tests/suite` 实 build 档(`run.sh:36-54` 语义实跑逐档计数)、`src/compiler/main.cr --static -O 0`、canary 档、`.ccr` 两档、`tests/selfhost/*.py` 内 `build` 调用逐处清点(含内联源去重)、`examples/*.cr`;③ 探针 29 档。 +- **表 D:锚点实核**。本计划「Tech Stack」「表 0/1/2」的每个 `file:line` 逐条实读复核(**行号漂移以本轮实读为准**,漂移逐条写进文档)。 +- **表 E:裁定原文核录**。向维护者核一句「fail-closed 方向已裁」的原文/出处(来源 = 协调者转述);**无原文 ⇒ 本批章程不成立 ⇒ 停**。 - [ ] **Step 1: 基线重建**。判据:三 sha 与**新白名单**逐条同 + 冒烟 42 + 构建确定性 ×2(日志逐字节同)。**不符 ⇒ 停下上报**。 - [ ] **Step 2: 起点判据**(表 B;cwd = 仓库根、逐段 `ps` 实查无并发、比较前 `clean-cache`)。 @@ -229,7 +264,7 @@ tools/baseline/build_gate_run.sh **Files:** Modify 本计划(把 T1 实测值回填表 1/表 2 + 落「豁免表草案」节)· 报告 `.superpowers/sdd/fc-task2-report.md`。 -**Interfaces(豁免表草案的**逐条字段**,本任务定稿后交维护者):** +**Interfaces(豁免表草案的逐条字段,本任务定稿后交维护者):** ``` { code, // 码常量(如 EC_B_USE_WHILE_BORROWED) scope, // build | check | both(裁-FC-1) @@ -335,21 +370,21 @@ tools/baseline/build_gate_run.sh ## 未决项与登记(**不猜**) -- **U-1(维护者裁定原文)**:本批的章程前提 = 「要改、方向 = fail-closed」,来源 = 协调者转述,**无独立文件载体** ⇒ T0 表 E 核录;**无原文则本批停在 T2**。 -- **U-2(`测试面 `check` rc 分布 vs `build` 面)**:72 档 runner 只跑 `check`(`parity_run.sh:36`),**build 面无既有 runner** ⇒ T1 必须新建(`build_gate_run.sh`);「命中面」的完整定义**在本批首次建立**。 -- **U-3(安全检查面的反向不一致)**:`region_check`/`provenance_verify` 只在 build/ccr 面跑 ⇒ 存在「check rc=0 / build rc=1」档(本实例**未构造具体语料**)⇒ T1 实测登记(不得当已知事实引用)。 -- **U-4(TM04 的打印前缀)**:现行以 `error[TM04]` 打印但语义声明为软面(`main.cr:159`)⇒ 「报错即拒」与「软面」字面冲突 ⇒ 裁-FC-2(d)。 -- **U-5(≈104 个「定义零 raise」码)**:`ast.cr` 定义 ≈146 / 可达 42 ⇒ 其余为**死码面**(本批不删、不改、登记;删除属独立决定,照 `tools/module_to_ccr.py` 的「只标废弃不删」先例)。 +- **U-1(维护者裁定原文)**:本批的章程前提 = 「要改、方向 = fail-closed」,来源 = 协调者转述,**无独立文件载体** ⇒ 由 T0 表 E 核录;**无原文则本批停在 T2**。 +- **U-2(测试面 `check` rc 分布 vs `build` 面)**:72 档 runner 只跑 `check`(`parity_run.sh:36`),**build 面无既有 runner** ⇒ T1 必须新建(`build_gate_run.sh`);「命中面」的完整定义**在本批首次建立**。 +- **U-3(安全检查面的反向不一致)**:`region_check`/`provenance_verify` 只在 build/ccr 面跑 ⇒ 存在「check rc=0 / build rc=1」档(本实例**未构造具体语料**)⇒ 由 T1 实测登记(不得当已知事实引用)。 +- **U-4(TM04 的打印前缀)**:现行以 `error[TM04]` 打印但语义声明为软面(`main.cr:159`)⇒ 「报错即拒」与「软面」字面冲突 ⇒ 交裁-FC-2(d) 处置。 +- **U-5(≈104 个「定义零 raise」码)**:`ast.cr` 定义 ≈146、可达 42 ⇒ 其余为**死码面**(本批不删、不改、登记;删除属独立决定,照 `tools/module_to_ccr.py` 的「只标废弃不删」先例)。 - **U-6(LSP 面)**:`src/lsp/lsp.cr` 消费 `g_diag_count` 但**不产生产物** ⇒ fail-closed 不适用(表 0 登记)。 -- **登记维持(不做,理由写死)**:`EXPR_FOR` 元素类型恒 int(E-6/裁-P6-4)· `.csr`/TagNode(验证切片轮)· 容量批(E-2/E-3/E-4)· `string == int` 混比(裁-P6-3)· `--verify-named-dedup` 保留(裁-P6-2(e))——**本批一律不动**。 +- **登记维持(不做,理由写死)**:`EXPR_FOR` 元素类型恒 int(E-6/裁-P6-4)· `.csr`/TagNode(验证切片轮)· 容量批(E-2/E-3/E-4)· `string == int` 混比(裁-P6-3)· `--verify-named-dedup` 保留(裁-P6-2(e))。以上各项**本批一律不动**。 --- ## 自检记录 -- **本计划的自我限制(诚实登记)**:**本计划未跑任何构建/测试/`jj` 命令**;所有「现状值」= 实读源码/文档或既有报告记录值(出处逐条标注);需实测的数字(基线重建 sha、build 面命中清单、套件面命中档数、转红面逐 job 计数)一律留给 T0/T1 的实测步。 -- **判定面清点的诚实性**:「42 可达码」= 全仓 grep 三形态(`check_error(EC_*` / `diag_type_incompatible(…, EC_*` / `DIAG_REC_SIZE, EC_*`)去重实得 43 减 1 个假命中(`EC_SIZE` 为 `DIAG_REC_SIZE` 子串);**未**用「源码注释/文档统计」冒充实测(`docs/error-codes.md` 的 ~146 为文档自述值,已标出处)。分诊的 7 条豁免**全部带命中证据或政策出处**;其余 25 条阻断**全部按「判定继续 ⇒ 静默错产物 / 不可信」判据成文**(裁-P6-2(c) 约定),未用一个「大概/应该」。 -- **根因 vs 止血**:闸门反转直达根因(**默认允许**是缺口本身,不是名单不全);豁免表被明确设计为**临时面**(每条带 `exit`)+ 只减不增 + 每次开新面重跑 report-only(防退化成语义黑洞)。 +- **本计划的自我限制(诚实登记)**:**本计划未跑任何构建/测试/`jj` 命令**。所有「现状值」= 实读源码/文档或既有报告记录值(出处逐条标注)。需实测的数字(基线重建 sha、build 面命中清单、套件面命中档数、转红面逐 job 计数)一律留给 T0/T1 的实测步。 +- **判定面清点的诚实性**:「42 可达码」的得出方式 = 全仓 grep 三形态(`check_error(EC_*` / `diag_type_incompatible(…, EC_*` / `DIAG_REC_SIZE, EC_*`)去重实得 43,再减 1 个假命中(`EC_SIZE` 为 `DIAG_REC_SIZE` 子串);**未**用「源码注释/文档统计」冒充实测(`docs/error-codes.md` 的 ~146 为文档自述值,已标出处)。分诊的 7 条豁免**全部带命中证据或政策出处**;其余 25 条阻断**全部按「判定继续 ⇒ 静默错产物 / 不可信」判据成文**(裁-P6-2(c) 约定),未用一个「大概/应该」。 +- **根因 vs 止血**:闸门反转直达根因(**默认允许**是缺口本身,不是名单不全)。豁免表被明确设计为**临时面**(每条带 `exit`),配合只减不增与每次开新面重跑 report-only,防止其退化成语义黑洞。 - **与既有裁决的一致性复核**:不回退 TM03/TG02(#31/#33)、TS01-04/TK02(#29)、ICE04(P-A)、TA02(#32)、F2/R002(先例即入闸依据);TM04 的「软面」裁定经裁-FC-2(d) 显式处置(**不得**由实施者私自改判)。 - **占位符扫描**:无 TBD;「须 T1 实测」逐处给出测量命令或产物格式;六条裁决门**逐条点名问句**,未用「推荐」冒充裁定。 - **本批最大风险(一句话)**:**一次反转会让 CI `suite` job 至少 7 档(TF01×5/TF07×1/B04×1)与 ELF canary 载体同时转红——而 canary 载体 `ptr_arith.cr` 自身就是 check rc=1 档 ⇒ 不先取裁-FC-3,本批无法开门。** diff --git a/docs/superpowers/plans/2026-09-16-agg-read-type.md b/docs/superpowers/plans/2026-09-16-agg-read-type.md index cd60588a..9ec45d38 100644 --- a/docs/superpowers/plans/2026-09-16-agg-read-type.md +++ b/docs/superpowers/plans/2026-09-16-agg-read-type.md @@ -1,45 +1,46 @@ -# 聚合读丢型(TODO #2026-09-16-16 · 总闸级)—— 批 2 计划(**只读侦查 + 裁决门**,2026-09-16) +# 聚合读丢型(TODO #2026-09-16-16 · 总闸级)批 2 计划(**只读侦查 + 裁决门**,2026-09-16) -**批名**:**聚合读丢型**(TODO #2026-09-16-16)· **批次位置**:用户排序的**第 2 批**(维护者 2026-09-16 派单) -**起点**:`develop = 2cfa2646`(PR #86 合入后;分支 `feature/agg-read-type`,写本文件时零源码改动) +**批名**:**聚合读丢型**(TODO #2026-09-16-16)。 +**批次位置**:用户排序的**第 2 批**,由维护者于 2026-09-16 派单。 +**起点**:**`develop = 2cfa2646`**(PR #86 合入后)。分支为 `feature/agg-read-type`,写本文件时零源码改动。 **性质**:`只读侦查 → 写进文档 → 取裁 → (裁后)实施`。**本轮零源码改动、零构建**。 -**输入**:`TODO.md` #78(含 apx 批交叉引用裁-APX-8)· `docs/superpowers/specs/2026-09-16-apx-conversion-audit.md` §1 ③b/④b/⑤/⑥b/⑧ + §2 表 B + §errata · apx 批报告(`docs/superpowers/specs/2026-09-16-apx-conversion-batch-report.md`) -**本文件约定**:所有 `file:line` 均为 **`develop 2cfa2646` 现状**(亲自读过;与 TODO/审计中的旧行号有偏移 ⇒ 见 §0.4 坐标校正表)。凡标 **预判** 者 = 读码推断、**待 T1 实测**;凡标 **实核** 者 = 本轮直接读到的代码行。 +**输入**:`TODO.md` #78(含 apx 批交叉引用裁-APX-8)、`docs/superpowers/specs/2026-09-16-apx-conversion-audit.md` §1 ③b/④b/⑤/⑥b/⑧ 与 §2 表 B 与 §errata、apx 批报告(`docs/superpowers/specs/2026-09-16-apx-conversion-batch-report.md`)。 +**本文件约定**:所有 `file:line` 均为 **`develop 2cfa2646` 现状**,由本代理亲自读过。这些行号与 TODO、审计中的旧行号存在偏移,见 §0.4 坐标校正表。凡标「**预判**」者,为读码推断、**待 T1 实测**;凡标「**实核**」者,为本轮直接读到的代码行。 --- ## 0. 现状与根因 -### 0.1 四个读点 + 一个结果槽(实核) +### 0.1 四个读点与一个结果槽(实核) -| 读点 | 现状坐标 | 今天怎么定型 | 声明面在哪 | 节点级零 alloc 可得? | +| 读点 | 现状坐标 | 当前定型方式 | 声明面位置 | 节点级零 `alloc` 可得性 | |---|---|---|---|---| -| **结构体字段读** | `ir_gen.cr:2590`(`v := new_ir_var("field", TI_INT)`)· 发射 `:2597 IR_LOAD_FIELD` | 硬定 `TI_INT` | `si_field_type_node(si, fi)`(字段类型节点) | **✓**(先例 `dex_decl_form_of_expr:1075-1083`:`find_struct(ast_c(node))` + 节点判 `ast_type_val == TY_DEX`) | -| **数组/切片元素读** | `:2655`(`new_ir_var("elem", TI_INT)`)· 发射 `:2660 IR_LOAD_INDEX` / `:2668 IR_LOAD_INDEX_VAR` | 硬定 `TI_INT` | 数组 var 的 IR 型(`TYP_ARRAY/TYP_SLICE` 行 ⇒ `get_type_data` = 元素 ti) | **✓ 局部/字面量形**(`:2780 irv_set_type(v, alloc_type(TYP_ARRAY, elem_ti, N))` 已把元素 ti 写进数组型;`elem_ti_of_decl:343-349` 是纯表读)· **全局形**另有节点级先例(`dex_decl_form_of_expr:1085-1103` 扫 `g_global_lets`) | -| **match 臂载荷绑定** | `:2393`(`fv := new_ir_var("fld", TI_INT)`)· 发射 `:2395`/`:2412 IR_LOAD_FIELD` | 硬定 `TI_INT` | `ei_variant_type_node(ei, vi, pos)`(变体载荷类型节点;`enum_payload_ti:389-403` 同源) | **✓**(照 `:389-403` 去掉 `res_type_node` 即可) | -| **match 结果槽** | `:2299`(`new_ir_var("match_res", TI_INT)` + `:2300 emit(IR_ALLOC, …, TI_INT)`) | 硬定 `TI_INT`(含 `IR_ALLOC` 的 tk) | 无单一声明面——型由**各臂**决定,多臂可异型 | **✗ 未覆盖面**(见 §0.3;建议本批**不碰**,登记) | +| **结构体字段读** | `ir_gen.cr:2590`(`v := new_ir_var("field", TI_INT)`)、发射点 `:2597 IR_LOAD_FIELD` | 硬定 `TI_INT` | `si_field_type_node(si, fi)`(字段类型节点) | **✓**(先例 `dex_decl_form_of_expr:1075-1083`:`find_struct(ast_c(node))` 与节点判 `ast_type_val == TY_DEX`) | +| **数组/切片元素读** | `:2655`(`new_ir_var("elem", TI_INT)`)、发射点 `:2660 IR_LOAD_INDEX` 与 `:2668 IR_LOAD_INDEX_VAR` | 硬定 `TI_INT` | 数组 var 的 IR 型(`TYP_ARRAY/TYP_SLICE` 行,`get_type_data` 即元素 ti) | **✓ 局部/字面量形**(`:2780 irv_set_type(v, alloc_type(TYP_ARRAY, elem_ti, N))` 已把元素 ti 写进数组型;`elem_ti_of_decl:343-349` 是纯表读)。**全局形**另有节点级先例(`dex_decl_form_of_expr:1085-1103` 扫 `g_global_lets`) | +| **match 臂载荷绑定** | `:2393`(`fv := new_ir_var("fld", TI_INT)`)、发射点 `:2395` 与 `:2412 IR_LOAD_FIELD` | 硬定 `TI_INT` | `ei_variant_type_node(ei, vi, pos)`(变体载荷类型节点;`enum_payload_ti:389-403` 同源) | **✓**(照 `:389-403` 去掉 `res_type_node` 即可) | +| **match 结果槽** | `:2299`(`new_ir_var("match_res", TI_INT)`)与 `:2300 emit(IR_ALLOC, …, TI_INT)` | 硬定 `TI_INT`(含 `IR_ALLOC` 的 tk) | 无单一声明面,型由**各臂**决定,多臂可异型 | **✗ 未覆盖面**(见 §0.3;建议本批**不碰**,登记) | -> 补充事实:**元组元素读走 `:2590` 同形**(`EXPR_FIELD` 且 `ast_type_val > 0` = 数字下标记法)——元组**无声明面**(`field_ti_of_node:360` 显式 `return -1`)⇒ 本批的节点级通道**取不到元组元素的声明型**(见 §0.3 未覆盖面 U2)。 +> 补充事实:**元组元素读走 `:2590` 的同形路径**(`EXPR_FIELD` 且 `ast_type_val > 0`,即数字下标记法)。元组**无声明面**(`field_ti_of_node:360` 显式 `return -1`),因此本批的节点级通道**取不到元组元素的声明型**(见 §0.3 未覆盖面 U2)。 -### 0.2 「丢型」为什么是**总闸**(读码实核的连锁面) +### 0.2 「丢型」的**总闸**性质(读码实核的连锁面) -读点结果槽 `irv_type` 恒 `TI_INT` ⇒ 一切**按 IR 值型触发**的下游在「经聚合读入的值」上失明。本轮实核的**收益面**(修好后**自动**变正确,且无需改这些点): +读点结果槽的 `irv_type` 恒为 `TI_INT`,因此一切**按 IR 值型触发**的下游在「经聚合读入的值」上失明。下表列出本轮实核的**收益面**,这些点在修好后**自动**变正确,且无需改动这些点: -| 点位 | 今天为什么失明 | 修好后 | +| 点位 | 当前失明原因 | 修好后 | |---|---|---| -| `dex_store_adjust:1046-1049` | `vt := irv_type(val)` = `TI_INT` ⇒ 两条转换支都不进 ⇒ **scaled 值直接写进 apx(binary64)槽** | `vt == TI_DEX_S` ⇒ 走 `dex_scaled_to_bits` | -| `dex_scale_int:1034`(精确路径 int 对齐) | 门 `!= TI_INT` 早退 ⇒ 读槽被当 int ⇒ 再 ×S | 原样参与(已是 scaled) | -| 二元分流 `:1311/1331/1334` | 读槽落「通用整数路径」 | 进 `TI_DEX_S` 精确路径 | -| extern 实参边界 `:1902` | 门 `irv_type(av) == TI_DEX_S` ⇒ 读槽不匹配 ⇒ scaled 当 binary64 位模式传出 | 触发 `:1905` scaled→bits | -| LET 继承 `:2503-2505` / `:2518-2519` | 无注解 LET 的槽型 = `irv_type(初值)` ⇒ 继承到 `TI_INT`(**类型经一次绑定即永久丢失**) | 继承 `TI_DEX_S` | -| 泛型实例键回落路径 `:1970-1976` | 键名串由实参 IR 型拼 ⇒ 读槽贡献 `"int"` | 贡献 `"dex"`(**与 #93 批的 TODO #2026-09-16-35 同面**,见 §5) | +| `dex_store_adjust:1046-1049` | `vt := irv_type(val)` 取到 `TI_INT`,两条转换支都不进,**scaled 值直接写进 apx(binary64)槽** | `vt == TI_DEX_S` 时走 `dex_scaled_to_bits` | +| `dex_scale_int:1034`(精确路径 int 对齐) | 门 `!= TI_INT` 时早退,读槽被当作 int,于是再乘 S | 原样参与(已是 scaled) | +| 二元分流 `:1311/1331/1334` | 读槽落入「通用整数路径」 | 进 `TI_DEX_S` 精确路径 | +| extern 实参边界 `:1902` | 门 `irv_type(av) == TI_DEX_S` 不匹配读槽,scaled 被当作 binary64 位模式传出 | 触发 `:1905` 的 scaled→bits | +| LET 继承 `:2503-2505` / `:2518-2519` | 无注解 LET 的槽型取自 `irv_type(初值)`,于是继承到 `TI_INT`(**类型经一次绑定即永久丢失**) | 继承 `TI_DEX_S` | +| 泛型实例键回落路径 `:1970-1976` | 键名串由实参 IR 型拼成,读槽贡献 `"int"` | 贡献 `"dex"`(**与 #93 批的 TODO #2026-09-16-35 同面**,见 §5) | | apx 批的**比较/运算点 hack** `dex_decl_form_of_expr:1072`(调用点 `:1285-1286`) | 该函数存在的唯一理由(注释 `:1065-1071` 自陈「#78 未修」) | **可退役**(但须先证明通用机制覆盖它,见 §4.4 突变控制) | -### 0.3 今天**仍是静默错值**的面(apx 批 hack 够不着)= 本批 RED 候选(**预判,待 T1 实测**) +### 0.3 仍为**静默错值**且 apx 批 hack 未覆盖的面 —— 本批 RED 候选(**预判,待 T1 实测**) -apx 批 T3 的 hack **只作用于二元分流点**(`:1280-1286`,且要求**操作数节点本身**是 `EXPR_FIELD` 或**全局** ident 数组下标)。因此下列形态**今天仍是静默错值**: +apx 批 T3 的 hack **只作用于二元分流点**(`:1280-1286`),且要求**操作数节点本身**是 `EXPR_FIELD` 或**全局** ident 数组下标。因此下列形态**当前仍是静默错值**: -| # | 形态(最小探针,全部显式形) | 为什么 hack 够不着 | 预判 | +| # | 形态(最小探针,全部显式形) | hack 未覆盖的原因 | 预判 | |---|---|---|---| | **R1** | `x := s.f; x * 2.0`(**LET 中转**) | hack 按**操作数节点**判;`x` 是 ident,`dex_decl_form_of_expr(ident) = 0`,且 `x` 的槽型已在 LET 处丢成 `TI_INT` | 静默错值 | | **R2** | `enum E { V(dex) } … match e { V(x) => x * 2.0 }` | match 臂绑定是 `new_ir_var("fld", TI_INT)`,不在 hack 的两种节点形内 | 静默错值 | @@ -47,31 +48,31 @@ apx 批 T3 的 hack **只作用于二元分流点**(`:1280-1286`,且要求** | **R4** | 元组 `t := (d, 1.0); t . 0 * 2.0` | 元组无声明面(同 U2) | 静默错值 | | **R5** | `g : dex, apx, mut = 1.0; g = s.f;`(**写 apx 槽**) | hack 只在二元分流点;`dex_store_adjust` 看 `irv_type(val)` | 静默错值(scaled 位模式写进 binary64 槽) | | **R6** | `extern fn c_dex(x: dex) -> dex; … c_dex(s.f)`(**extern 实参**) | 门 `:1902` 看 `irv_type(av)` | 静默错值 · **需实证**(extern 面另有历史语义,见 §10 U4) | -| **R7** | `fn f(x: dex) -> int {…} … f(s.f)`(**Core 调用实参**) | 环 `:1810-1848` 按**形参声明**转,但转的前提是看得见实参型 | **需实证**(T1 必须先把环读清) | -| **N1**(**非回归断言**) | `s.f == d` / `@raw_int(s.f)`(apx 批已转正的 B-3/B-4/B-5/B-6/B-8 形) | — | **今天绿,修后须仍绿**(防「修法把正确的搞坏」) | +| **R7** | `fn f(x: dex) -> int {…} … f(s.f)`(**Core 调用实参**) | 环 `:1810-1848` 按**形参声明**转换,但转换的前提是看得见实参型 | **需实证**(T1 必须先把环读清) | +| **N1**(**非回归断言**) | `s.f == d` / `@raw_int(s.f)`(apx 批已转正的 B-3/B-4/B-5/B-6/B-8 形) | — | **当前绿,修后须仍绿**(防「修法改坏正确面」) | -### 0.4 坐标校正表(TODO #2026-09-16-16 / 审计的旧行号 → 现状) +### 0.4 坐标校正表(TODO #2026-09-16-16 与审计的旧行号 → 现状) | TODO/审计写法 | 现状(`2cfa2646`) | 说明 | |---|---|---| -| `ir_gen.cr:2513`(字段读) | **`:2590`**(`new_ir_var`)/ `:2597`(emit) | apx 批 + 容量批位移 | +| `ir_gen.cr:2513`(字段读) | **`:2590`**(`new_ir_var`)/ `:2597`(emit) | apx 批与容量批的位移 | | `:2578`(元素读) | **`:2655`** / 发射 `:2660`·`:2668` | 同上 | | `:2591`(`IR_LOAD_INDEX_VAR`) | **`:2668`** | 同上 | | `:2316`(match 绑定) | **`:2393`**(`fv` 定型)/ `:2395`·`:2412`(emit) | 同上 | -| `:2222`(match 结果槽,apx 批 T2 补) | **`:2299`**(+ `:2300` 的 `IR_ALLOC` tk) | 同上 | +| `:2222`(match 结果槽,apx 批 T2 补) | **`:2299`**(含 `:2300` 的 `IR_ALLOC` tk) | 同上 | | 审计 `:2520` / `:2583` / `:2556-2560` | 同上表 | — | --- -## 1. 硬约束复核与既有先例(**先例都是零 alloc 的**) +## 1. 硬约束复核与既有先例(**既有先例均为零 `alloc`**) -### 1.1 GC12 的真实边界(实核,比条目原文更窄——**须向维护者交代**) +### 1.1 GC12 的真实边界(实核;比条目原文更窄,**须向维护者交代**) -- `ir_gen.cr:2455`:**带注解的 LET** 无条件调 `res_type_node(type_node)`——即 **ir_gen 里今天已有非 optrep 门控的 `res_type_node` 站点**。 +- `ir_gen.cr:2455`:**带注解的 LET** 无条件调用 `res_type_node(type_node)`。也就是说,**ir_gen 中当前已有非 optrep 门控的 `res_type_node` 站点**。 - `checker.cr:957-967`:`res_type_node` 对**基类型节点**(`ast_kind == 0`)走 `ty_code_to_ti`(`iface_registry.cr:274-284`:**纯 if 链查表,零 alloc**);对命名类型走 `alloc_named_type`(**alloc**);对 `EXPR_ARRAY/EXPR_REFTYPE/EXPR_PTRTYPE` 走 `alloc_type`(**alloc**)。 -- ⇒ **GC12 的准确表述**(建议本批写入 Global Constraints):**ir_gen 路径不得新增「可能 alloc 的」`alloc_type`/`alloc_named_type` 站点**;「节点是基类型节点」的 `res_type_node` 是**纯查表**,但**本批一律不用它**——改用更窄的**节点判**(`ast_kind(tn) == 0 && ast_type_val(tn) == TY_DEX`),因为我们要的只是 **dex 轴**(二值),不是完整类型。 +- 因此 **GC12 的准确表述**(建议本批写入 Global Constraints)为:**ir_gen 路径不得新增「可能 alloc 的」`alloc_type`/`alloc_named_type` 站点**。「节点是基类型节点」的 `res_type_node` 是**纯查表**,但**本批一律不用它**,改用更窄的**节点判**(`ast_kind(tn) == 0 && ast_type_val(tn) == TY_DEX`),因为本批要的只是 **dex 轴**(二值),不是完整类型。 -### 1.2 零 alloc 先例(三处,全在同一仓、同一文件群) +### 1.2 零 `alloc` 先例(三处,均在同一仓、同一文件群) | 先例 | 坐标 | 手法 | |---|---|---| @@ -79,11 +80,11 @@ apx 批 T3 的 hack **只作用于二元分流点**(`:1280-1286`,且要求** | 比较点声明面查表 | `dex_decl_form_of_expr:1072-1106` | 同上判 + `si_field_type_node` / `g_global_lets` 扫描 | | 元素型(纯表读) | `elem_ti_of_decl:343-349` → `get_type_kind/get_type_data` | 无 alloc、无 AST 扫描 | -**声明面侧表**(`irv_decl_ti:315` / `irv_set_decl_ti:321` / `slot_decl_ti:336`)也是零布局变更的进程内表:**不进 `.ccr`/`.cir`**(注释 `:305`),今天写点 5 处(`:2458`·`:2528`·`:2640`·`:2784`·`:2955`,其中 4 处带 `g_optrep_on` 门),读点 4 处(`:353`·`:412`·`:443`·`:1530`)。 +**声明面侧表**(`irv_decl_ti:315`、`irv_set_decl_ti:321`、`slot_decl_ti:336`)也是零布局变更的进程内表,**不进 `.ccr`/`.cir`**(注释 `:305`)。该表当前的写点有 5 处(`:2458`·`:2528`·`:2640`·`:2784`·`:2955`,其中 4 处带 `g_optrep_on` 门),读点有 4 处(`:353`·`:412`·`:443`·`:1530`)。 --- -## 2. 候选方案(逐案:改动面 / 风险 / 判据 / 足迹) +## 2. 候选方案(逐案列出改动面、风险、判据与足迹) ### 候选 ① **读点定型改「声明面 dex 形式」**(推荐主体) @@ -94,32 +95,32 @@ form_of_read(node_or_ctx) = TI_DEX_S 若 声明面为 dex(TY_DEX) = TI_INT 否则(**保持逐字节不变**) ``` -**要动的点**(4 处定型 + 若需 `IR_ALLOC` tk 同步):`:2590` · `:2655` · `:2393` ·(本批**建议不动** `:2299`,见 §0.3/§10 U1)。 +**要动的点**(4 处定型;若需则同步 `IR_ALLOC` 的 tk):`:2590` · `:2655` · `:2393`;本批**建议不动** `:2299`(见 §0.3/§10 U1)。 -**改动面**:`ir_gen.cr` 一处新判定函数(照 `dex_decl_form_of_expr` 的零 alloc 手法,但**返回「元素/字段/载荷的声明形式」**而非布尔),3 个读点各 1 行;元素读复用 `elem_ti_of_decl(irv_type(arr_var))`(纯表读)。 +**改动面**:`ir_gen.cr` 新增一处判定函数(照 `dex_decl_form_of_expr` 的零 alloc 手法,但**返回「元素/字段/载荷的声明形式」**而非布尔),3 个读点各改 1 行;元素读复用 `elem_ti_of_decl(irv_type(arr_var))`(纯表读)。 **风险**(**全部为「仅 dex 聚合读程序」的足迹**,逐条见 §3): -- `regalloc.cr:680-681`:`TI_DEX_S` **不参与寄存器分配** ⇒ 读槽恒栈驻留(功能等价、代码密度/性能变化)。 -- `tag2l.cr:117/126/128/135/137`:只对 `TI_INT` 生效 ⇒ 读槽出 tag 闭包 ⇒ 帧尺寸与少量指令字节变(**仅当该槽今天真的带 tag**——需实证,见 §3.2)。 -- `.ccr` SYM `ccr_io.cr:631/690` + `.cir` `cir_cache.cr:259`:per-var 型落盘 ⇒ 含 dex 聚合读的程序产字节变。 +- `regalloc.cr:680-681`:`TI_DEX_S` **不参与寄存器分配**,读槽恒栈驻留(功能等价,代码密度与性能变化)。 +- `tag2l.cr:117/126/128/135/137`:只对 `TI_INT` 生效,读槽因而出 tag 闭包,帧尺寸与少量指令字节变化(**仅当该槽当前真的带 tag**,需实证,见 §3.2)。 +- `.ccr` SYM `ccr_io.cr:631/690` 与 `.cir` `cir_cache.cr:259`:per-var 型落盘,含 dex 聚合读的程序产字节变化。 - **判据**:R1–R7 转精确值(腿 A)· `irv_type` 断言(腿 B)· N1 保持绿 · 锁定 5 条 IDENTICAL。 ### 候选 ② **只补登记声明面侧表**(`irv_set_decl_ti` 先例;零后端足迹) -**做法**:读点不改 `irv_type`;改为在读点 `irv_set_decl_ti(v, TI_DEX_S)`(**存的是预置常量 `TI_DEX_S`,不 alloc**),并把 §0.2 的 6 个判定点的取型来源由 `irv_type(x)` 改成 `slot_decl_ti(x)`。 +**做法**:读点不改 `irv_type`,改为在读点调用 `irv_set_decl_ti(v, TI_DEX_S)`(**存的是预置常量 `TI_DEX_S`,不 alloc**),并把 §0.2 的 6 个判定点的取型来源由 `irv_type(x)` 改成 `slot_decl_ti(x)`。 -**改动面**:读点 3–4 行 + **6 个判定点各 1 行**(`dex_store_adjust`/`dex_scale_int`/二元分流 3 处/extern 边界/LET 继承)。`slot_decl_ti` 的既有消费者已核**无副作用**:`ti_is_optional(TI_DEX_S) = 0`(`:328-333`)· `elem_ti_of_decl(TI_DEX_S) = -1`(`:343-349`)· `is_ptr_var:626-636` 早退。 +**改动面**:读点 3–4 行,加 **6 个判定点各 1 行**(`dex_store_adjust`/`dex_scale_int`/二元分流 3 处/extern 边界/LET 继承)。`slot_decl_ti` 的既有消费者已核**无副作用**:`ti_is_optional(TI_DEX_S) = 0`(`:328-333`)· `elem_ti_of_decl(TI_DEX_S) = -1`(`:343-349`)· `is_ptr_var:626-636` 早退。 -**优点**:**零后端足迹、零序列化足迹**(regalloc/tag2l/`.ccr`/`.cir` 全不看侧表)⇒ ELF 与 5 条锁定产物**逐字节不变**(比候选 ① 更保守)。 -**缺点**:`irv_type` 仍是 `TI_INT` ⇒ **未来任何新的按值型分派消费者仍会失明**(「总闸」只堵了一半);且**判据③(`irv_type` 断言)无法满足**——TODO #2026-09-16-16 的验收条款明写「聚合读的 `irv_type` 断言进自测」。 +**优点**:**零后端足迹、零序列化足迹**(regalloc/tag2l/`.ccr`/`.cir` 全不看侧表),ELF 与 5 条锁定产物**逐字节不变**(比候选 ① 更保守)。 +**缺点**:`irv_type` 仍是 `TI_INT`,**未来任何新的按值型分派消费者仍会失明**(「总闸」只堵了一半);且**判据③(`irv_type` 断言)无法满足**,因为 TODO #2026-09-16-16 的验收条款明写「聚合读的 `irv_type` 断言进自测」。 -### 候选 ③ **混合**(① + 侧表同时登记) +### 候选 ③ **混合**(① 与侧表同时登记) -① 为主,另在 LET(`:2458`)与读点补登记,使 `slot_decl_ti` 与 `irv_type` 两种形式**一致**。代价 = ① 的足迹 + 侧表一致性维护;收益 = 消除「两种形式不一致」的隐性坑。**推荐序:① → ③(若实施中发现 `slot_decl_ti` 约定有人依赖)**。 +以 ① 为主,另在 LET(`:2458`)与读点补登记,使 `slot_decl_ti` 与 `irv_type` 两种形式**一致**。代价 = ① 的足迹 + 侧表一致性维护;收益 = 消除「两种形式不一致」的隐性缺陷。**推荐序:① → ③(若实施中发现 `slot_decl_ti` 约定有人依赖)**。 ### 候选 ④ **只扩 hack 覆盖面**(不做,仅记录其爆炸半径) -把 `dex_decl_form_of_expr` 的节点形扩到 match 载荷/局部数组/元组 ⇒ 能救 R2/R3 的部分形态,但**救不了 R1(LET 中转)与 R5(写 apx 槽)**(它们不在二元分流点),且每加一个消费面就要复制一次 hack —— 与 #78「总闸」定性相悖。**登记为不做**。 +把 `dex_decl_form_of_expr` 的节点形扩到 match 载荷/局部数组/元组,能救 R2/R3 的部分形态,但**救不了 R1(LET 中转)与 R5(写 apx 槽)**(它们不在二元分流点),且每加一个消费面就要复制一次 hack,与 #78「总闸」定性相悖。**登记为不做**。 --- @@ -127,40 +128,61 @@ form_of_read(node_or_ctx) = TI_DEX_S 若 声明面为 dex(TY_DEX) ### 3.1 前端(`src/compiler/`) -**会变**(候选 ① 下):`ir_gen.cr:339`(`slot_decl_ti` 兜底)· `:1017`(`dex_scaled_to_bits` 门首次通过)· `:1034`(`dex_scale_int` 早退消失)· `:1046-1049`(`dex_store_adjust` 新支)· `:1233-1234`(二元取型)· `:1315/1321/1331/1334`(各自分流转正)· `:1407`+`:2509`(`IR_DYN_PACK` 的 tag 由 0 变 8)· `:1568`(一元负结果型)· `:1902`(extern 边界)· `:1970-1976`(泛型键名串)· `:2503-2505`/`:2518-2519`(LET 继承)· `:2764`(数组字面量 `elem_ti` 取自元素值型)。 +**会变**(候选 ① 下): +- `ir_gen.cr:339`(`slot_decl_ti` 兜底) +- `:1017`(`dex_scaled_to_bits` 门首次通过) +- `:1034`(`dex_scale_int` 早退消失) +- `:1046-1049`(`dex_store_adjust` 新支) +- `:1233-1234`(二元取型) +- `:1315/1321/1331/1334`(各自分流转正) +- `:1407` 与 `:2509`(`IR_DYN_PACK` 的 tag 由 0 变 8) +- `:1568`(一元负结果型) +- `:1902`(extern 边界) +- `:1970-1976`(泛型键名串) +- `:2503-2505`/`:2518-2519`(LET 继承) +- `:2764`(数组字面量 `elem_ti` 取自元素值型) + **不会变**(逐条已核,理由见侦查表):`:122`·`:140/149`·`:353`·`:412/443`·`:626/636`·`:654`·`:846`·`:961`·`:983`·`:1061`·`:1241/1247`·`:1305-1306`·`:1405`·`:1510`·`:1767`·`:2033`·`:2092`·`:2571`·`:2834`·`:2856`。 -**需实证**:`:1530-1531→1550`(`&v` 的 pointee 型行身份)· `:2023-2024`(`_arg` 打包槽)· `:2527-2528`(侧表继承——取决于是否选候选 ③)。 -**其它文件**:`opt.cr`(零类型读,纯 opcode/CSE)· `ptr_analysis.cr`(零 `irv_type`,Andersen 按 opcode)· `dataflow.cr`(零类型;`:464` 明注 `iri_tk` 是派生码)· `region_check.cr:62/98/118` 与 `provenance_verify.cr:66`(皆判 `TYP_PTR`;`TI_DEX_S` 与 `TI_INT` 同 kind ⇒ **不会变**)· `monomorph.cr`/`checker.cr`/`src/targets/*`(零命中)。 -**解释器**:`interp.cr:293/298/304/310/609/616/624/632`——**全部只判容器是否 `TI_STR`**,与结果槽无关 ⇒ **不会变**;`ir_interp_binary:37-49` 按 opcode 分派、不读型 ⇒ 零消费点。 -### 3.2 后端(`src/arch/x86_64/` · `src/os/linux/` · `src/format/elf/`)——**只有两个真变化点** +**需实证**:`:1530-1531→1550`(`&v` 的 pointee 型行身份)· `:2023-2024`(`_arg` 打包槽)· `:2527-2528`(侧表继承,取决于是否选候选 ③)。 + +**其它文件**: +- `opt.cr`(零类型读,纯 opcode/CSE) +- `ptr_analysis.cr`(零 `irv_type`,Andersen 按 opcode) +- `dataflow.cr`(零类型;`:464` 明注 `iri_tk` 是派生码) +- `region_check.cr:62/98/118` 与 `provenance_verify.cr:66`(皆判 `TYP_PTR`;`TI_DEX_S` 与 `TI_INT` 同 kind,因此**不会变**) +- `monomorph.cr`/`checker.cr`/`src/targets/*`(零命中) + +**解释器**:`interp.cr:293/298/304/310/609/616/624/632` **全部只判容器是否 `TI_STR`**,与结果槽无关,因此**不会变**;`ir_interp_binary:37-49` 按 opcode 分派、不读型,因此零消费点。 + +### 3.2 后端(`src/arch/x86_64/` · `src/os/linux/` · `src/format/elf/`)—— **只有两个真变化点** | 点 | 判定 | 依据 | |---|---|---| -| **`regalloc.cr:680-681`** | **会变** | `ty == TI_DEX \|\| TI_DEX_S \|\| TI_DYN \|\| TI_UNIT ⇒ continue`(不建候选)。`TI_INT` 今天可分配 ⇒ 读槽由「可能驻寄存器」变「恒栈驻留」;同窗口其它 var 的分配可连带变 | -| **`tag2l.cr:117 / :126 / :128 / :135 / :137`** | **会变** | 规则 A/B/B′ 全部窄门 `irv_type(...) == TI_INT` ⇒ 读槽出入 tag 闭包;`g_x86_mw_tag_count`(`:157`)进 `pf_frame_size`(`frame.cr:51-67`)⇒ 帧尺寸与 `sub rsp` 立即数可能变(`elf.cr:998/1116`) | +| **`regalloc.cr:680-681`** | **会变** | `ty == TI_DEX \|\| TI_DEX_S \|\| TI_DYN \|\| TI_UNIT ⇒ continue`(不建候选)。`TI_INT` 当前可分配,因此读槽由「可能驻寄存器」变「恒栈驻留」;同窗口其它 var 的分配可连带变 | +| **`tag2l.cr:117 / :126 / :128 / :135 / :137`** | **会变** | 规则 A/B/B′ 全部窄门 `irv_type(...) == TI_INT`,读槽因而出入 tag 闭包;`g_x86_mw_tag_count`(`:157`)进 `pf_frame_size`(`frame.cr:51-67`),因此帧尺寸与 `sub rsp` 立即数可能变(`elf.cr:998/1116`) | | `callseq.cr:70/97/101/127/167/179` | **不会变** | 7 处全是 `== TI_DEX`;`TI_DEX_S` 与 `TI_INT` **同落整数类**(binary64 走 XMM、scaled 走整数寄存器——**本批不改变这一分工**) | | `instr.cr` | **不会变** | 全文 `TI_DEX_S` 出现 **0** 次;`e2_load_var`/`e2_sd_*`/`IR_LOAD_FIELD:1137`/`IR_LOAD_INDEX:1313`/`IR_LOAD_INDEX_VAR:1349` 均无类型分支;`:386`·`:963` 只判 `== TI_DEX` | -| `frame.cr:51-67/119-168` | 间接 | 帧公式类型无关但含 tag 计数;`:160-168` 的「形参行清 tag」只覆盖形参 ⇒ 读槽本就不吃它 | +| `frame.cr:51-67/119-168` | 间接 | 帧公式类型无关但含 tag 计数;`:160-168` 的「形参行清 tag」只覆盖形参,因此读槽本就不吃它 | | `sizes.cr` | **不会变** | `instr_size(op)` 无类型入参 | | `elf.cr` / `syscall.cr` / `entry.cr` / `ld.cr` / `resolve.cr` | **不会变** | 零类型分派(`elf.cr` 的 `TI_` 命中全是注释) | -**需实证**(缺证据,T1 必做):① 读槽**今天是否真的带 tag**(若从不带 ⇒ tag2l/frame 零足迹);② 读槽今天**是否真的被分配了寄存器**(若窗口冲突/带 hazard 位 ⇒ regalloc 零足迹)。 +**需实证**(缺证据,T1 必做):① 读槽**当前是否真的带 tag**(若从不带,则 tag2l/frame 零足迹);② 读槽当前**是否真的被分配了寄存器**(若窗口冲突/带 hazard 位,则 regalloc 零足迹)。 ### 3.3 序列化面(**本批足迹的出处**) | 产物 | 坐标 | 事实 | |---|---|---| -| `.ccr` | `ccr_io.cr:631`(SYM 全局:`irv_type(gi)`)· **`:690`(SYM 函数 var 声明:`irv_type(row)`)** | **per-IR-var 型落盘** ⇒ 候选 ① 下,含 dex 聚合读的程序的 `.ccr` **字节变**(记录定长 ⇒ size 不变、sha 变) | -| `.ccr` 版本 | `CCR_VERSION = 9`(`ccr_io.cr:135`) | 本批**不改段结构** ⇒ 不 bump(但若最终方案触发落盘字节变化,按「禁的不是变化是无声变化」原则在报告里显式归因) | -| `.ccr` TYPE/IFACE 段 | `ccr_io.cr:380-390` · `ccr_types.cr:160-163` | 独立类型项表,**不承载 per-var 型** ⇒ 候选 ①(只给预置常量 `TI_DEX_S`,不 alloc)**不动 TYPE 段尺寸** | -| `.cir` | `cir_cache.cr:259`(`w64_cir(irv_type(v_idx))`)· `CIR_CACHE_VER = 17`(`:51`) | `.cir` 快照含 var 型 ⇒ 候选 ① 下暖/冷快照字节变(**语义一致**,两侧同源);**`.cir` 不在 5 条 canary 内** | +| `.ccr` | `ccr_io.cr:631`(SYM 全局:`irv_type(gi)`)· **`:690`(SYM 函数 var 声明:`irv_type(row)`)** | **per-IR-var 型落盘**,因此候选 ① 下,含 dex 聚合读的程序的 `.ccr` **字节变**(记录定长,故 size 不变、sha 变) | +| `.ccr` 版本 | `CCR_VERSION = 9`(`ccr_io.cr:135`) | 本批**不改段结构**,因此不 bump(但若最终方案触发落盘字节变化,按「禁的不是变化是无声变化」原则在报告里显式归因) | +| `.ccr` TYPE/IFACE 段 | `ccr_io.cr:380-390` · `ccr_types.cr:160-163` | 独立类型项表,**不承载 per-var 型**,因此候选 ①(只给预置常量 `TI_DEX_S`,不 alloc)**不动 TYPE 段尺寸** | +| `.cir` | `cir_cache.cr:259`(`w64_cir(irv_type(v_idx))`)· `CIR_CACHE_VER = 17`(`:51`) | `.cir` 快照含 var 型,因此候选 ① 下暖/冷快照字节变(**语义一致**,两侧同源);**`.cir` 不在 5 条 canary 内** | | ELF | `elf.cr:55` | 无 IR 型面;但 §3.2 的两点会通过指令流间接改 ELF | ### 3.4 语料覆盖(**结论:锁定语料覆盖不到本批面**) - **锁定 5 条**(`canary_values.tsv:88-92` / `test_canary_carrier.py:42`):`canary_elf`+`pa_ccr`(`tests/suite/ptr_arith.cr`)· `pa_static_ccr` · `gt_ccr`/`gt_static_ccr`(`tests/suite/generics_test.cr`)。 -- `ptr_arith.cr`:唯一聚合访问是 `&arr[2]`(`IR_ADDR_INDEX`,**不是** `:2655`)+ `*p`;**无 dex**。 +- `ptr_arith.cr`:唯一聚合访问是 `&arr[2]`(`IR_ADDR_INDEX`,**不是** `:2655`)与 `*p`;**无 dex**。 - `generics_test.cr`:**有**聚合读(`:24`/`:58`/`:60`/`:67`/`:69` 的 `b.val` 等,声明型 = 泛型 `T` 实例化为 `int`/`str`),**但全档 `dex` 零出现**(`grep -n dex` 无命中)。 - ⇒ **预期:候选 ① 下 5 条 canary 全 IDENTICAL**(无 dex ⇒ `form = TI_INT` ⇒ 逐字节不变)。 - ⇒ ⚠ **同时必须写明的反面**:**锁定 5 条对本批目标面零区分力**(这正是上一批「`.ccr` 没变 ≠ 生成面没变」教训的镜像)。真正覆盖本批面的语料是**未锁定**的 `tests/suite/apx_conversion_test.cr`(`:15` dex 字段 · `:42/:44` 字段读 · `:47/:48/:51` 数组/切片元素读 · `:55` 元组元素读 · `:73` 比较 · `:85/:89` 枚举载荷)+ **本批新增探针**。 @@ -168,7 +190,7 @@ form_of_read(node_or_ctx) = TI_DEX_S 若 声明面为 dex(TY_DEX) --- -## 4. 判据设计(**本批最容易搞错的地方**) +## 4. 判据设计(**本批最易出错之处**) ### 4.1 预期足迹总表 @@ -178,38 +200,38 @@ form_of_read(node_or_ctx) = TI_DEX_S 若 声明面为 dex(TY_DEX) | `.ccr` 四条(96015/96158/142765/142908) | **IDENTICAL** | 停,查约定(极可能是「无条件施加」) | | 74 档 parity `check` rc | **逐档全同** | 逐档归因 | | 29 行为探针 rc | **全同**(`p_spawn` rc=0) | 停 | -| `p_dex`/`apx_conversion_test.cr` 等 dex 档 | **产物字节可变**(预期内)⇒ 按「旧值+新值+归因+出处」重锁或留痕 | — | +| `p_dex`/`apx_conversion_test.cr` 等 dex 档 | **产物字节可变**(预期内),按「旧值+新值+归因+出处」重锁或留痕 | — | | 新探针(腿 A/B) | 全绿 | 停 | ### 4.2 探针设计表(**本批必须自建判据网**,canary 帮不上忙) | 判据 | 内容 | 判据形态 | |---|---|---| -| **腿 A(语义值)** | R1 `x := s.f; x * 2.0` · R2 match 载荷 · R3 局部数组元素 · R4 元组元素 · R5 `g_apx = s.f` · R6 extern 实参 · R7 Core 调用实参 | `build --static` + **运行值**断言(期望值 = scaled 语义下的精确值);**双路径**(`run` + ELF) | -| **腿 B(界面断言,**TODO #2026-09-16-16 判据③**)** | 同一批源,`cir`/`ccr` 转储断言**读槽 `irv_type` = `TI_DEX_S`**(≥6 例,逐读点:字段/元素/切片/载荷/嵌套/LET 中转) | 机制面正据(**不依赖运行值**——能在语义面还没接线时先红) | +| **腿 A(语义值)** | R1 `x := s.f; x * 2.0` · R2 match 载荷 · R3 局部数组元素 · R4 元组元素 · R5 `g_apx = s.f` · R6 extern 实参 · R7 Core 调用实参 | `build --static` 加**运行值**断言(期望值 = scaled 语义下的精确值);**双路径**(`run` + ELF) | +| **腿 B(界面断言,**TODO #2026-09-16-16 判据③**)** | 同一批源,`cir`/`ccr` 转储断言**读槽 `irv_type` = `TI_DEX_S`**(≥6 例,逐读点:字段/元素/切片/载荷/嵌套/LET 中转) | 机制面正据(**不依赖运行值**,能在语义面还没接线时先红) | | **腿 C(回归)** | 74 档 + 29 探针 + 锁定 5 条 + `interp_parity` + `selftest-types` | rc/sha 对拍 | -| **腿 D(突变控制)** | ① **关掉 apx hack**(`:1285-1286` 注释掉)⇒ 腿 A/B **仍须全绿**(证明通用机制独立成立);② **把读点改成无条件 `TI_DEX_S`** ⇒ 锁定 5 条**必红**(证明 canary 判别器有效、约定不是摆设) | 两条突变都必须按预期红/绿 | +| **腿 D(突变控制)** | ① **关掉 apx hack**(`:1285-1286` 注释掉),腿 A/B **仍须全绿**(证明通用机制独立成立);② **把读点改成无条件 `TI_DEX_S`**,锁定 5 条**必红**(证明 canary 判别器有效、约定不是摆设) | 两条突变都必须按预期红/绿 | | **腿 E(适用范围)** | 非 dex 聚合读(`int` 字段/数组)**必须零足迹**:产物与改前逐字节相同 | 逐字节 `cmp` | -### 4.3 「今天绿」的非回归断言(N1) +### 4.3 当前已绿的非回归断言(N1) -apx 批已转正的 B-3/B-4/B-5/B-6/B-8 探针(`tests/selfhost/test_apx_conversion.py` + `tests/suite/apx_conversion_test.cr`)**本批不得回退**;且它们**必须继续在「关掉 hack」下成立**(腿 D①)。 +apx 批已转正的 B-3/B-4/B-5/B-6/B-8 探针(`tests/selfhost/test_apx_conversion.py` 与 `tests/suite/apx_conversion_test.cr`)**本批不得回退**;且它们**必须继续在「关掉 hack」下成立**(腿 D①)。 -### 4.4 hack 退役约定(**建议:本批只验证、不删**) +### 4.4 hack 退役约定(**建议本批只验证、不删**) -`dex_decl_form_of_expr` 在候选 ① 落地后对**其覆盖面内的形态**成为冗余。**建议**:本批**保留**该函数并加注释说明「通用机制已覆盖,退役候选」;**退役动作**留待腿 D① 连续两批绿之后(与 `elf.cr` 死文件教训同族:删之前要有独立判据证明无依赖)。 +`dex_decl_form_of_expr` 在候选 ① 落地后,对**其覆盖面内的形态**成为冗余。**建议**:本批**保留**该函数并加注释说明「通用机制已覆盖,退役候选」;**退役动作**留待腿 D① 连续两批绿之后(与 `elf.cr` 死文件教训同族:删之前要有独立判据证明无依赖)。 --- -## 5. 与 #93 批的交互(预判 + 可证伪探针) +## 5. 与 #93 批的交互(预判与可证伪探针) -1. **#97(实参位泛型退化实例键)**:读点定型改变实参 IR 型 ⇒ `:1970-1976` 的**回落键名串**由 `"int"` 变 `"dex"` ⇒ `idf(s.f)` 的实例键变化。**这是「键更精确」的顺向修复**,但会**新增实例**(`.ccr` 里实例名/NOD 数变)⇒ 走「显式归因 + 同批留痕」。**探针**:`idf(s.f)` 与 `idf(x_dex_local)` 的实例名必须一致(照腿 D 手法)。 -2. **#93 的 19 例 + 腿 D/E**:必须保持全绿(腿 C 已含)。特别注意 #93 的腿 B(`g(nosuchfn(1))` ⇒ `error[N06]`)与 `infer_call_args` 的 fail-closed 护栏——**本批不动 checker**,但若实施中确实需要动 checker 侧(不预期),**停下报维护者**。 -3. **新暴露预判**:读点定型后,**此前被 `TI_INT` 掩盖的静默面**会开始「正确地报错或正确地算」——若哪一档从 rc=0 变 rc=1,按 #93 批纪律**默认回归嫌疑**逐条归因,**不许把「新增诊断」当修好**(`2026-09-16-criteria-strength-audit.md` §0quater)。 +1. **#97(实参位泛型退化实例键)**:读点定型改变实参 IR 型,因此 `:1970-1976` 的**回落键名串**由 `"int"` 变 `"dex"`,`idf(s.f)` 的实例键随之变化。**这是「键更精确」的顺向修复**,但会**新增实例**(`.ccr` 里实例名/NOD 数变),须走「显式归因 + 同批留痕」。**探针**:`idf(s.f)` 与 `idf(x_dex_local)` 的实例名必须一致(照腿 D 手法)。 +2. **#93 的 19 例与腿 D/E**:必须保持全绿(腿 C 已含)。特别注意 #93 的腿 B(`g(nosuchfn(1))` ⇒ `error[N06]`)与 `infer_call_args` 的 fail-closed 护栏。**本批不动 checker**,但若实施中确实需要动 checker 侧(不预期),**停下报维护者**。 +3. **新暴露预判**:读点定型后,**此前被 `TI_INT` 掩盖的静默面**会开始「正确地报错或正确地算」。若哪一档从 rc=0 变 rc=1,按 #93 批纪律**默认回归嫌疑**逐条归因,**不许把「新增诊断」当修好**(`2026-09-16-criteria-strength-audit.md` §0quater)。 --- -## 6. 裁决门(逐条:问句 / 影响 / 推荐 / 未取裁时行为) +## 6. 裁决门(逐条列出问句、影响、推荐与未取裁时行为) | # | 问句 | 影响 | 推荐 | 未取裁时行为 | |---|---|---|---|---| @@ -219,8 +241,8 @@ apx 批已转正的 B-3/B-4/B-5/B-6/B-8 探针(`tests/selfhost/test_apx_conver | **裁-AGG-4** | 泛型字段/元素(`Box[T].val`,声明型 = 类型参数)? | `TY_DEX` 判定对类型参数为假 ⇒ 泛型实例化为 dex 时本批**不覆盖** | **登记未覆盖**(U3),与 #97 交互面单列 | 登记 | | **裁-AGG-5** | hack(`dex_decl_form_of_expr`)本批删不删? | 删 = 少一处 hack;不删 = 冗余但安全 | **不删**,加「退役候选」注释;删除留待腿 D① 两批绿 | 不删 | | **裁-AGG-6** | `IR_ALLOC` 的 tk(`ir_gen.cr:2300`)与 `IR_DYN_PACK` 的 tag(`:1407/:2509`)是否同批拉齐? | 拉齐 = 更一致;不拉 = 保持改面最小 | **只改结果槽型,不主动改 tk/tag**(让它们随值型自然变;变了要归因) | 不动 | -| **裁-AGG-7** | `.ccr`/`.cir` 若如预期**不变**(锁定语料零 dex),是否仍要 bump 版本号? | 不 bump = 旧产物仍被命中(**语义一致**,因为变化只发生在 dex 聚合读程序——它们的旧 `.ccr`/`.cir` 与新版**不等价**!) | **需你裁**:建议 **bump `.cir`(`CIR_CACHE_VER` 17→18)+ 对 `.ccr` 按「同版本号但语义变了」的风险给结论**。§10 U5 给出两种约定的代价 | 停,等裁 | -| **裁-AGG-8** | 腿 D②(无条件突变)导致锁定 5 条必红——是否把该突变固化为常驻判据(照判据批 22/22 先例)? | 固化 = 防「约定被改宽」;代价 = CI 时间 | **固化**(一行开关 + 期望必红) | 不固化 | +| **裁-AGG-7** | `.ccr`/`.cir` 若如预期**不变**(锁定语料零 dex),是否仍要 bump 版本号? | 不 bump = 旧产物仍被命中(**语义一致**,因为变化只发生在 dex 聚合读程序,它们的旧 `.ccr`/`.cir` 与新版**不等价**) | **需你裁**:建议 **bump `.cir`(`CIR_CACHE_VER` 17→18)+ 对 `.ccr` 按「同版本号但语义变了」的风险给结论**。§10 U5 给出两种约定的代价 | 停,等裁 | +| **裁-AGG-8** | 腿 D②(无条件突变)导致锁定 5 条必红,是否把该突变固化为常驻判据(照判据批 22/22 先例)? | 固化 = 防「约定被改宽」;代价 = CI 时间 | **固化**(一行开关 + 期望必红) | 不固化 | --- @@ -228,9 +250,9 @@ apx 批已转正的 B-3/B-4/B-5/B-6/B-8 探针(`tests/selfhost/test_apx_conver | 任务 | 内容 | 出口判据 | |---|---|---| -| **T1** | **零构建侦查复核**:① 逐条实核 §3.2 的两个「需实证」(读槽今天是否带 tag / 是否分到寄存器);② 实读调用环 `:1810-1848` 定 R7;③ 把 R1–R7 写成探针源并跑**改前基线**(预期:静默错值/139) | 每条 RED 都有「改前实测值」(不许只写预判) | +| **T1** | **零构建侦查复核**:① 逐条实核 §3.2 的两个「需实证」(读槽当前是否带 tag / 是否分到寄存器);② 实读调用环 `:1810-1848` 定 R7;③ 把 R1–R7 写成探针源并跑**改前基线**(预期:静默错值/139) | 每条 RED 都有「改前实测值」(不许只写预判) | | **T2** | **先裁写进文档**(八门结论)+ 探针入库(RED 状态,白名单登记) | 门逐条有裁决 | -| **T3** | **实施**:声明形式判定函数 + 3 读点定型(+ 若裁-AGG-1 选②,则 6 判定点改取型) | 腿 A/B 转绿;腿 E 零足迹 | +| **T3** | **实施**:声明形式判定函数 + 3 读点定型(若裁-AGG-1 选②,则 6 判定点改取型) | 腿 A/B 转绿;腿 E 零足迹 | | **T4** | **判据复验**:腿 C 全量 + 腿 D 突变 + 腿 E + 锁定 5 条 + 重锁判定(若有 dex 档产物变) | 全绿 + 逐条归因 | | **T5** | **收官**:TODO #2026-09-16-16 状态 + 批报告 + 未覆盖面登记(U1–U4)+ 交叉引用(#97/#93/审计表 B) | `jj status` 干净 + 五 CI job | @@ -240,10 +262,10 @@ apx 批已转正的 B-3/B-4/B-5/B-6/B-8 探针(`tests/selfhost/test_apx_conver 1. **GC12′**(本批重述,见 §1.1):ir_gen 路径**不得新增可能 alloc 的类型站点**;本批一律用**节点判**(`ast_kind(tn)==0 && ast_type_val(tn)==TY_DEX`)与**纯表读**(`get_type_kind/get_type_data`),**不调** `res_type_node`/`alloc_type`/`alloc_named_type`。 2. **约定门**:定型**只对声明面为 dex** 生效;**非 dex 聚合读逐字节不变**(腿 E 是这一条的判据)。 -3. **canary 判别器**:锁定 5 条**必须 IDENTICAL**;同时报告必须写明「本批 canary 对目标面零区分力」——**不得**用 canary 绿代替本批判据。 +3. **canary 判别器**:锁定 5 条**必须 IDENTICAL**;同时报告必须写明「本批 canary 对目标面零区分力」,**不得**用 canary 绿代替本批判据。 4. **无名变化禁止**:任何 `.ccr`/`.cir`/ELF 字节变化必须**逐档归因 + 旧值/新值/出处**(含 dex 档);**若出现预期外变化 ⇒ 停**(停条件 2)。 5. **不许把「新增诊断/新增失败」当修好**(判据批 §0quater)。 -6. **毒丸守卫**:改动若需动 `checker.cr`(不预期)⇒ **停下报维护者**。 +6. **毒丸守卫**:改动若需动 `checker.cr`(不预期),**停下报维护者**。 --- @@ -251,34 +273,34 @@ apx 批已转正的 B-3/B-4/B-5/B-6/B-8 探针(`tests/selfhost/test_apx_conver 1. 锁定 5 条 canary 出现**任何非预期变化**。 2. **任何非 dex 聚合读**程序的产物字节变化(= 约定泄漏)。 -3. 腿 D①(关 hack)下腿 A 出现红 ⇒ 说明通用机制**覆盖面不足**(不是「hack 冗余」)。 +3. 腿 D①(关 hack)下腿 A 出现红,说明通用机制**覆盖面不足**(不是「hack 冗余」)。 4. 74 档出现 rc 由 0→1 的档且**归因不清**。 5. 实施中发现必须复用「那 5 个声明面 API」(GC12 原约定)才能推进。 -6. `.cir`/`.ccr` 版本号 bump 的裁决(裁-AGG-7)未取裁之前,涉及产物锁定的 T4 步骤不得开工。 +6. 裁-AGG-7 的 `.cir`/`.ccr` 版本号 bump 裁决未取裁之前,涉及产物锁定的 T4 步骤不得开工。 --- ## 10. 未决项(U) - **U1**:match **结果槽** `:2299`(多臂异型,需臂分析)——本批登记不修。 -- **U2**:**元组**元素(无声明面;`field_ti_of_node:360` 显式返回 -1)——登记;其「比较形」今天靠 hack 兜(`dex_decl_form_of_expr` 对 `ast_type_val > 0` 也返回 0 ⇒ **其实连 hack 也没覆盖**,R4 的 RED 属性待 T1 实测确认)。 +- **U2**:**元组**元素(无声明面;`field_ti_of_node:360` 显式返回 -1)——登记;其「比较形」当前靠 hack 兜(`dex_decl_form_of_expr` 对 `ast_type_val > 0` 也返回 0,因此**连 hack 也未覆盖该形**,R4 的 RED 属性待 T1 实测确认)。 - **U3**:**泛型**字段/元素(声明型 = 类型参数 T)——本批不覆盖;与 `TODO #2026-09-16-35`(退化实例键)**同面**,建议后续批合并处理。 -- **U4**:**extern 实参**(R6)——extern 的 dex 语义有历史契约(①b「apx 实参原样保留恰合 C ABI」)⇒ 本批改动是否**应当**影响 extern 形**需维护者确认**(否则 R6 应从腿 A 移除、改列「语义待定」)。 -- **U5**:**`.cir`/`.ccr` 是否 bump**(裁-AGG-7):约定 A = 不 bump(理由:锁定 5 条不变、且变化只落在 dex 聚合读程序);约定 B = bump `.cir` 17→18(理由:旧 `.cir` 快照里读槽型是 `TI_INT`,与新建的 `TI_DEX_S` **不等价** ⇒ 同一源文件在修复前后会命中不同语义的旧快照,**这正是 #8 缓存事故的同族**)。**建议约定 B**(bump `.cir`)+ **`.ccr` 侧**同步给出结论(`.ccr` 无「快照复用」语义 ⇒ 可只留痕不 bump,但须写成显式声明)。 -- **U6**:**超大 scaled 值的 tag 语义**(§3.2):读槽掉出 tag 闭包后,若该值参与 2L(多字)路径的算术,语义是否仍正确 —— 需一条**边界探针**(构造 |scaled| 接近 2⁶² 的 dex 字段值 + ADD/MUL)实证;不成立 ⇒ tag2l 需要把 `TI_DEX_S` 纳入闭包(届时**改面扩大**,须回取裁)。 +- **U4**:**extern 实参**(R6)——extern 的 dex 语义有历史契约(①b「apx 实参原样保留恰合 C ABI」),因此本批改动是否**应当**影响 extern 形**需维护者确认**(否则 R6 应从腿 A 移除、改列「语义待定」)。 +- **U5**:**`.cir`/`.ccr` 是否 bump**(裁-AGG-7):约定 A = 不 bump(理由:锁定 5 条不变、且变化只落在 dex 聚合读程序);约定 B = bump `.cir` 17→18(理由:旧 `.cir` 快照里读槽型是 `TI_INT`,与新建的 `TI_DEX_S` **不等价**,同一源文件在修复前后会命中不同语义的旧快照,**这正是 #8 缓存事故的同族**)。**建议约定 B**(bump `.cir`)加 **`.ccr` 侧**同步给出结论(`.ccr` 无「快照复用」语义,可只留痕不 bump,但须写成显式声明)。 +- **U6**:**超大 scaled 值的 tag 语义**(§3.2):读槽掉出 tag 闭包后,若该值参与 2L(多字)路径的算术,语义是否仍正确,需一条**边界探针**(构造 |scaled| 接近 2⁶² 的 dex 字段值 + ADD/MUL)实证;不成立则 tag2l 需要把 `TI_DEX_S` 纳入闭包(届时**改面扩大**,须回取裁)。 --- -## 11. §T1 记录(2026-09-16 —— 前置 + 冻结基线 + R1–R7 **改前实测**) +## 11. §T1 记录(2026-09-16:前置、冻结基线与 R1–R7 **改前实测**) -> 维护者裁决(2026-09-16):八门**全按推荐**(裁-AGG-1=① · -2/-3/-4 登记 · -5 hack 不删(退役判据=腿 D① 连绿两批)· -6 不改 `IR_ALLOC` tk/`IR_DYN_PACK` tag · -7 **bump `CIR_CACHE_VER` 17→18** 且四要素齐 · -8 突变固化)· **U4 裁:extern 边界 = 规范化成 ABI binary64**(⇒ R6 进腿 A,期望 = 转换)。 +> 维护者裁决(2026-09-16):八门**全按推荐**(裁-AGG-1=① · -2/-3/-4 登记 · -5 hack 不删(退役判据=腿 D① 连绿两批)· -6 不改 `IR_ALLOC` tk/`IR_DYN_PACK` tag · -7 **bump `CIR_CACHE_VER` 17→18** 且四要素齐 · -8 突变固化)· **U4 裁:extern 边界 = 规范化成 ABI binary64**(因此 R6 进腿 A,期望 = 转换)。 ### 11.1 前置与冻结基线(实核) - 起点 `develop = 99ae6bdd`;分支 `feature/agg-read-type`(本记录 = 该链首个提交)。 -- **冻结基线(改前二进制)** = 现成 `build/corec` + `build/corearch`;**同源证明**:`jj diff --from e7243955 --to develop --stat -- src/compiler src/arch src/os src/format build_selfhost_native.py` = **0 files changed**(该二进制所建源面与 `develop 99ae6bdd` 逐字节同)⇒ 即「改前基线」。 +- **冻结基线(改前二进制)** = 现成 `build/corec` + `build/corearch`。**同源证明**:`jj diff --from e7243955 --to develop --stat -- src/compiler src/arch src/os src/format build_selfhost_native.py` = **0 files changed**(该二进制所建源面与 `develop 99ae6bdd` 逐字节同),因此即为「改前基线」。 - 备份 + sha256:`/tmp/agg-t1/pre/corec` = `a689de9a205a2c1f…` · `/tmp/agg-t1/pre/corearch` = `8dd89647971f6af3…`。 -- **命令纪律(本轮踩到,留痕)**:① `corec build` 必须在**仓库根**跑(否则 `error: cannot locate src/runtime/rt.cr`);② 重定向到**已存在**日志文件被 noclobber 拦 ⇒ 命令根本没跑、读到的是上一轮旧日志 ⇒ **假红**(本轮首轮 8/8「失败」即此)⇒ 改用 `>|` + 新路径。 +- **命令纪律(本轮踩到,留痕)**:① `corec build` 必须在**仓库根**跑(否则 `error: cannot locate src/runtime/rt.cr`);② 重定向到**已存在**日志文件被 noclobber 拦,命令根本没跑、读到的是上一轮旧日志,表现为**假红**(本轮首轮 8/8「失败」即此),因此改用 `>|` + 新路径。 ### 11.2 探针源(8 档 · T1 实测稿;入仓/挂点见 T2) @@ -373,32 +395,32 @@ fn main() -> int { | R7 Core 实参(断言) | 7 | **7** | **绿**(与读码判定一致 ⇒ 归类修正,§11.6) | | N1 apx 批已转正形(断言) | 7 | **7** | **绿** | -全部 8 档 `check` = 0 error(**无诊断**:这正是「静默」的实测证据)。 +全部 8 档 `check` = 0 error(**无诊断**,这正是「静默」的实测证据)。 ### 11.4 IR 级机理正据(比 rc 更强的断言) | 探针 | cir 证据(改前) | 读法 | |---|---|---| -| **R1** | `load_field field = s.0` → `const _dsc = 1000000` → `binary _dxt = x * _dsc` → `binary _dxm = _dxt * dex` | **读槽被当 int 二次缩放**(`dex_scale_int` 的 ×S)⇒ 值放大 10⁶ | +| **R1** | `load_field field = s.0` → `const _dsc = 1000000` → `binary _dxt = x * _dsc` → `binary _dxm = _dxt * dex` | **读槽被当 int 二次缩放**(`dex_scale_int` 的 ×S),值放大 10⁶ | | **R3** | `--dump-entries`:`var 40 name=elem kind=LOAD_INDEX` 之后依次 `_dsc`(1e6 常量) → `_dxt`(BINARY) → `_dxm`(BINARY) | 同上,另一读点 | -| **R6** | `load_field field = s.0` → `call_extern dest=call s1=6 s2=36 s3=1` ——**中间零转换**(既无 scaled→bits,亦无位模式常量重发射) | extern 契约破坏的**正据**(今天为空序列) | -| **R7**(断言) | `load_field field = s.0` → `call dbl(field)` ——零转换**且正确** | Core 形参物化 scaled ↔ 读值 scaled **同形** ⇒ 直传正确 | +| **R6** | `load_field field = s.0` → `call_extern dest=call s1=6 s2=36 s3=1`,**中间零转换**(既无 scaled→bits,亦无位模式常量重发射) | extern 契约破坏的**正据**(当前为空序列) | +| **R7**(断言) | `load_field field = s.0` → `call dbl(field)`,零转换**且正确** | Core 形参物化 scaled 与读值 scaled **同形**,因此直传正确 | ### 11.5 两条「需实证」的实核结论 -1. **tag 面(§3.2 ①)——收窄(T1 结论)**:读槽**从不作 `IR_BINARY ADD/SUB` 的 dest**(dest 恒是新槽 `bin`/`_dx*`),而 tag 规则 A(`tag2l.cr:117`)只标 ADD/SUB **dest**;且精确路径的结果槽 `_dxm`/`bin` 在**改前/改后同为 `TI_DEX_S`**(`ir_gen.cr:1338/1342` 硬编码)⇒ **R1/R3/R4 预期无 tag 差异**;tag 足迹只可能出现在「非 dex 聚合读」的整数路径,而那条路径被声明面门控 ⇒ **预期零 tag 足迹**。最终以 T3/T4 改前/改后对拍为准(帧尺寸 + `.ccr` 尺寸)。 -2. **regalloc 面(§3.2 ②)——读码确证、足迹待对拍**:`regalloc.cr:680-681` 对 `TI_DEX_S` 不建候选(读码确证);读槽今天 `TI_INT` ⇒ 有资格进候选(是否真命中窗口/无 hazard 位需 T3 对拍)。**预期足迹** = 该槽由「可能驻寄存器」变「恒栈驻留」。 +1. **tag 面(§3.2 ①)——收窄(T1 结论)**:读槽**从不作 `IR_BINARY ADD/SUB` 的 dest**(dest 恒是新槽 `bin`/`_dx*`),而 tag 规则 A(`tag2l.cr:117`)只标 ADD/SUB **dest**;且精确路径的结果槽 `_dxm`/`bin` 在**改前/改后同为 `TI_DEX_S`**(`ir_gen.cr:1338/1342` 硬编码),因此 **R1/R3/R4 预期无 tag 差异**。tag 足迹只可能出现在「非 dex 聚合读」的整数路径,而那条路径被声明面门控,因此**预期零 tag 足迹**。最终以 T3/T4 改前/改后对拍为准(帧尺寸 + `.ccr` 尺寸)。 +2. **regalloc 面(§3.2 ②)——读码确证、足迹待对拍**:`regalloc.cr:680-681` 对 `TI_DEX_S` 不建候选(读码确证);读槽当前为 `TI_INT`,因此有资格进候选(是否真命中窗口、是否无 hazard 位需 T3 对拍)。**预期足迹** = 该槽由「可能驻寄存器」变「恒栈驻留」。 ### 11.6 归类修正(T1 实测结论 ⇒ 改约定) -- **R7:「RED 候选」→「非回归断言」**(读码 + 实测双证:今日 rc=7)。**修后必须仍绿**。 -- **R6:判定形态「运行值」→「IR 级断言」**:extern dex 调用的**静态链运行路径既有崩溃**(`tests/suite/ffi_test.cr:8-11` 头注明载「运行时 FFI 被 corearch `--link` 静态路径既有崩溃阻塞」⇒ 该档只声明不调用),实测 `run_rc = 139`。⇒ 照既有先例 `tests/selfhost/test_dex_arith.py::test_extern_dex_arg_cir` 用 **cir 断言**判定;本批断言 = 「`load_field` 与 `call_extern` 之间**必须出现**转换序列」(**改前为空 ⇒ RED 正据已取,见 §11.4**)。 -- **U4 裁后约定**:extern 边界 = **规范化成 ABI binary64**(`ir_gen.cr:1900-1907` 只做 `TI_DEX_S → bits`)⇒ R6 期望 = **转换**(不是「不变」、也不是「转 scaled」)。 +- **R7:「RED 候选」→「非回归断言」**(读码 + 实测双证:当前 rc=7)。**修后必须仍绿**。 +- **R6:判定形态「运行值」→「IR 级断言」**:extern dex 调用的**静态链运行路径既有崩溃**(`tests/suite/ffi_test.cr:8-11` 头注明载「运行时 FFI 被 corearch `--link` 静态路径既有崩溃阻塞」,该档只声明不调用),实测 `run_rc = 139`。因此照既有先例 `tests/selfhost/test_dex_arith.py::test_extern_dex_arg_cir` 用 **cir 断言**判定;本批断言 = 「`load_field` 与 `call_extern` 之间**必须出现**转换序列」(**改前为空,因此 RED 正据已取**,见 §11.4)。 +- **U4 裁后约定**:extern 边界 = **规范化成 ABI binary64**(`ir_gen.cr:1900-1907` 只做 `TI_DEX_S → bits`),因此 R6 期望 = **转换**(不是「不变」、也不是「转 scaled」)。 ### 11.7 批报告必写条目(维护者指定;T5 不得遗漏) -1. **镜像教训**:「`.ccr` 没变 ≠ 生成面没变」(#93 批)↔「**`.ccr` 没变 ≠ 这个面被覆盖了**」(本批)——两句合起来才完整:**判据的「绿」只在它的覆盖域内有意义**。 -2. **GC12 的自我修正顺序**:先查出 `res_type_node` 对**基类型节点**是纯查表零 alloc、把规则**改准**,再决定**不用它**(本批一律不调)——「先把规则改准,再决定用不用」。 +1. **镜像教训**:「`.ccr` 没变 ≠ 生成面没变」(#93 批)与「**`.ccr` 没变 ≠ 这个面被覆盖了**」(本批)——两句合起来才完整:**判据的「绿」只在它的覆盖域内有意义**。 +2. **GC12 的自我修正顺序**:先查出 `res_type_node` 对**基类型节点**是纯查表零 alloc、把规则**改准**,再决定**不用它**(本批一律不调),即「先把规则改准,再决定用不用」。 ### 11.8 T1 未决(转 T2/T3) @@ -408,9 +430,9 @@ fn main() -> int { --- -## 12. §T2 记录(2026-09-16 —— 探针入仓 + 白名单 + 两条陷阱落仓 + T3 验收形状) +## 12. §T2 记录(2026-09-16:探针入仓、白名单、两条陷阱落仓与 T3 验收形状) -> 维护者 T2 放行(2026-09-16):① R7/R6 归类修正**确认**;② 两条陷阱**必须落仓级文档**(不能只活在报告里, +> 维护者 T2 放行(2026-09-16)包含三项:① R7/R6 归类修正**确认**;② 两条陷阱**必须落仓级文档**(不能只活在报告里, > 判据 = 下一个人搜「noclobber」能在仓里搜到);③ T3 判据补「**槽型正确 + 无重复转换**两条都要」。 ### 12.1 探针入仓(RED 语料) @@ -422,15 +444,15 @@ fn main() -> int { - **腿 B(界面见证,见 12.3)**:B1/B2 反方向(无 `_dxt`)· B3 正方向(`_dxdiv` 恰好 1)· B4 extern 调用点前须有转换。 - **改前实测(`build/corec` = 冻结基线 `a689de9a…`)**:腿 A **5/5 红**(`elf=1`,`check` 0 error) - · 腿 C **2/2 绿**(`elf=7`)· 腿 B **4/4 红**(`_dxt`×1 / `_dxt`×1 / `_dxdiv`=0 / 无转换) - ⇒ **整档 9 项失败**,与 §11 的 T1 实测一致。 -- **白名单条目**(`tests/harness/ci_hook_allowlist.txt`):写明「RED 语料,勿挂」+ 修复批三件套 + · 腿 C **2/2 绿**(`elf=7`)· 腿 B **4/4 红**(`_dxt`×1 / `_dxt`×1 / `_dxdiv`=0 / 无转换), + 即**整档 9 项失败**,与 §11 的 T1 实测一致。 +- **白名单条目**(`tests/harness/ci_hook_allowlist.txt`):写明「RED 语料,勿挂」与修复批三件套 (删条目 + 挂 `run.sh` + 改头注)。 ### 12.2 两条陷阱落仓级文档(维护者要求) - **落点**:`tools/baseline/REBUILD.md` 新增 **`### 命令层陷阱(假红)`**(置于「换代纪律」之前, - 与既有「适用范围限制 / 已知限制」同区)——① `noclobber`:重定向到已存在日志 ⇒ **命令根本没跑**、 + 与既有「适用范围限制 / 已知限制」同区)。两条为:① `noclobber`:重定向到已存在日志时**命令根本没跑**、 读到上一轮旧日志;② `corec build` 必须在**仓库根**跑(否则 `cannot locate src/runtime/rt.cr`)。 两条**叠加**时表现为「整批探针全失败」(#78 T1 首轮 8/8 假红)。 - **判据**:`grep -rn noclobber tools/` **命中该文件**(仓级可搜)。批报告(T5)另单列一节。 @@ -440,7 +462,7 @@ fn main() -> int { R1 的 IR 证据(§11.4)给出**判据形状**: > 修后 `load_field` 的**结果槽类型**必须是 `TI_DEX_S`(而非 `TI_INT`),且**下游不得再出现那次多余的 -> `× _dsc`**——后者是**「转换不重复」**的判据(**既不能漏转,也不能转两遍**)。 +> `× _dsc`**。后者是**「转换不重复」**的判据(**既不能漏转,也不能转两遍**)。 **落进套件的形态**(= 腿 B,已实现,**两个方向都取门控忠实的见证**): @@ -453,7 +475,7 @@ R1 的 IR 证据(§11.4)给出**判据形状**: > **为何用「门控忠实见证」而不是直接读槽型**:`.cir` 文本转储**不打印普通 IR 变量的类型** > (`dump.cr:50-60` 的 `type_kind_name` 只在 `alloc`/`const` 行输出,且 `TI_DEX`(1) 与 `TI_DEX_S`(8) > **同名 "dex"、不可区分**);权威通道 = `.ccr` SYM 的 per-var 型字节(`ccr_io.cr:690`),但那要写 -> 二进制解析。⇒ 本批先用**门控见证**(其门**恰好**是我们要断言的类型谓词 ⇒ 忠实), +> 二进制解析。因此本批先用**门控见证**(其门**恰好**是我们要断言的类型谓词,因此忠实), > `.ccr` SYM 解析列为 **T3 可选加固**(若 T3 顺手,加一条直接断言更佳)。 ### 12.4 裁-AGG-7 的落点(bump 文案与 `.ccr` 结论) @@ -462,9 +484,9 @@ R1 的 IR 证据(§11.4)给出**判据形状**: > `// 18:TODO #2026-09-16-16「聚合读丢型」——聚合读结果槽型由 TI_INT 改为声明面形式(dex 声明 ⇒ TI_DEX_S)。 > // 旧快照里读槽型 = TI_INT,与修复后语义**不等价** ⇒ 命中旧条目会复活「丢型」的坏 IR。 > // 与 TODO #2026-09-10-4(缓存键缺编译器身份)**同族**:cache miss = 无害重建。` -- **`.ccr`:不 bump**,但**报告须写明**「**dex 程序的 `.ccr` 内容会变**(格式不变、内容变)」—— - 防后来人把「版本没 bump」读成「内容没变」。落点 = 批报告 §判据 + `.ccr` 段。 -- **判据**:cache miss ⇒ 无害重建(照 TODO #2026-09-10-4 收尾约定);canary/五条**不受影响**(无 dex)—— +- **`.ccr`:不 bump**,但**报告须写明**「**dex 程序的 `.ccr` 内容会变**(格式不变、内容变)」, + 以防后来人把「版本没 bump」读成「内容没变」。落点 = 批报告 §判据 + `.ccr` 段。 +- **判据**:cache miss ⇒ 无害重建(照 TODO #2026-09-10-4 收尾约定);canary/五条**不受影响**(无 dex), 与**停条件①**(非 dex 聚合读任何字节变化 ⇒ 停)**互为印证**。 ### 12.5 T2 未决(转 T3) @@ -475,9 +497,9 @@ R1 的 IR 证据(§11.4)给出**判据形状**: --- -## 13. §T3 记录(2026-09-16 —— 实施 + 判据 + 突变 + 换代重锁) +## 13. §T3 记录(2026-09-16:实施、判据、突变与换代重锁) -> 维护者 T3 放行(2026-09-16):① 事故「我担一半」+ 正确配方入派单约定;② 门控见证设计获肯定(「先确认工具链能不能表达 X」); +> 维护者 T3 放行(2026-09-16)包含三项:① 事故「我担一半」与正确配方入派单约定;② 门控见证设计获肯定(「先确认工具链能不能表达 X」); > ③ 实施约定 = 声明面形式判定 + 3 读点定型 + `CIR_CACHE_VER` 17→18 + 腿 A/B 转绿 + 挂点三件套;判据 = 腿 A 5/5(**见 §13.4 冲突**)· > 腿 B 四条见证 · 腿 C 断言 · **停条件①**(非 dex 任何字节变化 ⇒ 停)· **停条件②**(关 hack 后腿 A 红 ⇒ 停)。 @@ -485,40 +507,40 @@ R1 的 IR 证据(§11.4)给出**判据形状**: | # | 位置 | 改动 | |---|---|---| -| ① | `ir_gen.cr`(`enum_payload_ti` 之后新增)| **4 个节点级 helper**:`agg_read_form_is_dex`(`ast_kind(tn)==0 && ast_type_val(tn)==TY_DEX`——**不调** `res_type_node`)· `agg_field_read_form`(`si_field_type_node` + 节点判;数字元组下标 `ast_type_val>0` ⇒ `TI_INT`)· `agg_elem_read_form`(`elem_ti_of_decl(slot_decl_ti(arr))` **纯表读**;`TI_DEX`/`TI_DEX_S` 都归一到 `TI_DEX_S`——聚合存储恒 scaled)· `agg_payload_read_form`(`find_gsym`+`find_enum_row_of`+`ei_variant_type_node` + 节点判)| -| ② | 字段读(`:2647` 邻域)| `irv_set_type(v, agg_field_read_form(node, fi))`——**在 `fi` 解出之后**(位序无关,但语义要 fi);非 dex ⇒ `TI_INT` = 原值 ⇒ **零足迹** | +| ① | `ir_gen.cr`(`enum_payload_ti` 之后新增)| **4 个节点级 helper**:`agg_read_form_is_dex`(`ast_kind(tn)==0 && ast_type_val(tn)==TY_DEX`,**不调** `res_type_node`)· `agg_field_read_form`(`si_field_type_node` + 节点判;数字元组下标 `ast_type_val>0` ⇒ `TI_INT`)· `agg_elem_read_form`(`elem_ti_of_decl(slot_decl_ti(arr))` **纯表读**;`TI_DEX`/`TI_DEX_S` 都归一到 `TI_DEX_S`,因为聚合存储恒 scaled)· `agg_payload_read_form`(`find_gsym`+`find_enum_row_of`+`ei_variant_type_node` + 节点判)| +| ② | 字段读(`:2647` 邻域)| `irv_set_type(v, agg_field_read_form(node, fi))`,**在 `fi` 解出之后**(位序无关,但语义要 fi);非 dex ⇒ `TI_INT` = 原值 ⇒ **零足迹** | | ③ | 元素读(`:2717` 邻域)| `irv_set_type(v, agg_elem_read_form(arr_var))` | | ④ | match 载荷绑定(`:2450` 邻域)| `irv_set_type(fv, agg_payload_read_form(arm_pat, fi))`(`EXPR_ENUMPAT`:`a`=变体名 ni)| -| ⑤ | `cir_cache.cr:51` | `CIR_CACHE_VER` **17 → 18** + 注释(旧快照读槽型 `TI_INT` 与新语义**不等价** ⇒ 命中旧条目会复活坏 IR;与 TODO #2026-09-10-4 同族;cache miss = 无害重建);并把历史条目「v18(不 bump——R2 P4 Task 4…)」改标题为「**[曾议 v18 而未 bump]**」避免与本次撞号 | +| ⑤ | `cir_cache.cr:51` | `CIR_CACHE_VER` **17 → 18** + 注释(旧快照读槽型 `TI_INT` 与新语义**不等价**,命中旧条目会复活坏 IR;与 TODO #2026-09-10-4 同族;cache miss = 无害重建);并把历史条目「v18(不 bump——R2 P4 Task 4…)」改标题为「**[曾议 v18 而未 bump]**」避免与本次撞号 | | ⑥ | 挂点三件套 | `run.sh` `selfhost-tests` **+1 行** · `ci_hook_allowlist.txt` **−1 条** · 套件头注转「已修」 | ### 13.2 判据(终态全绿) | 判据 | 结果 | |---|---| -| **腿 A**(语义值) | R1 LET 中转 · R2 match 载荷 · R3 局部数组元素 · R5 写回 apx 槽 —— **elf=7 全绿**(改前全 = 1)· R4 见 §13.4 | -| **腿 B**(界面见证) | B1 反方向 `_dxt`=**0** · B2 反方向 `_dxt`=**0** · B3 正方向 `_dxdiv`=**恰好 1** · B4 extern `load_field…call_extern` 之间有转换 —— **四条全绿**(改前四条全红)| +| **腿 A**(语义值) | R1 LET 中转 · R2 match 载荷 · R3 局部数组元素 · R5 写回 apx 槽,**elf=7 全绿**(改前全 = 1)· R4 见 §13.4 | +| **腿 B**(界面见证) | B1 反方向 `_dxt`=**0** · B2 反方向 `_dxt`=**0** · B3 正方向 `_dxdiv`=**恰好 1** · B4 extern `load_field…call_extern` 之间有转换,**四条全绿**(改前四条全红)| | **腿 C**(断言) | R7(Core 实参)· N1(apx 已转正形)**全绿** | -| **停条件①**(非 dex 零足迹) | canary **5/5 IDENTICAL**(ELF `95084e7b…d475` 28822B + `.ccr` 四条)——`generics_test` 含 int/str 字段读而**零 dex** ⇒ 这条同时是「非 dex 读槽恒 `TI_INT`」的**行为证据** | +| **停条件①**(非 dex 零足迹) | canary **5/5 IDENTICAL**(ELF `95084e7b…d475` 28822B + `.ccr` 四条);`generics_test` 含 int/str 字段读而**零 dex**,因此这条同时是「非 dex 读槽恒 `TI_INT`」的**行为证据** | | 74 档 parity | rc **逐档全同**(35×0 / 39×1)· 暖态腿 **FAIL=0**(41 档真命中)| | 29 行为探针 | rc **与基线全同** | | 挂点 harness | `test_ci_hook_coverage.py` **PASS**(scope=69 hooked=48 unhooked=21)| | 五 CI job / 自举链 | §13.5 | -| **二进制同一性论证** | 注释/测试改动后**重建 = `64c8a7d6…` 与判据二进制逐字节同** ⇒ 已跑的 canary/parity/probes 结论对**终态**成立(不是「大概没变」)| +| **二进制同一性论证** | 注释/测试改动后**重建 = `64c8a7d6…` 与判据二进制逐字节同**,因此已跑的 canary/parity/probes 结论对**终态**成立(不是「大概没变」)| -### 13.3 腿 D① 突变(**关掉 apx hack**)——**通过** +### 13.3 腿 D① 突变(**关掉 apx hack**)—— **通过** -把 `:1342-1343` 两行 hack 注释化 → 重建 → 跑判据:**apx 批套件 23 例全绿 + 本批 6 例 + 腿 B 全绿** -⇒ **通用机制独立成立**(hack 的覆盖面被声明面机制完全接管)⇒ **hack 冗余确认**(退役判据「腿 D① 连绿两批」第一步达成); +把 `:1342-1343` 两行 hack 注释化 → 重建 → 跑判据:**apx 批套件 23 例全绿 + 本批 6 例 + 腿 B 全绿**, +因此**通用机制独立成立**(hack 的覆盖面被声明面机制完全接管),**hack 冗余确认**(退役判据「腿 D① 连绿两批」第一步达成); 随后恢复源码 + 重建 + 复验(全绿)。 ### 13.4 ⚠ R4(元组)与 T3 约定的**冲突**(须你裁) - 你的 T3 约定写「腿 A **5/5** 转绿(R1–R5)」,但 **裁-AGG-3** 已裁「**元组**(无声明面)**登记,不纳入本批**」。 -- 实测事实:元组构造(`ir_gen.cr` 的 `EXPR_TUPLE` 分支)给元组 var 定型 `TI_INT`、**不携带元素 ti** ⇒ 数字下标读(`t . 0`)**取不到声明面** ⇒ 本批的通道覆盖不到它(R4 修后仍 = 1)。 -- **我的处置(按裁-AGG-3 执行,不静默)**:3 读点实施**不含元组**;套件把 R4 移入 **`[GAP]` 组**——**只观测、不计入判据**(打印期望值与实测值,注明裁决与出处);后续批修复时须把它移回 `CASES`。 -- **若要现在就覆盖元组**(最小机制,供你裁):在元组构造点按「**全元素同形**」把该形式登记进**既有声明侧表**(`irv_set_decl_ti(tv, TI_DEX_S)`,2 行、零 alloc);数字下标读再查 `slot_decl_ti(obj_var)`。 - **代价/风险**:`slot_decl_ti(tv)` 变 `TI_DEX_S` 会波及唯一取址面 `ir_gen.cr:1530`(`&tuple` 的 pointee 型行身份:`TYP_PTR(TI_INT)` → `TYP_PTR(TI_DEX_S)`)⇒ 需一条实证;且这是**新机制**,与「最小改动」约定相抵。**推荐:维持裁-AGG-3(登记)**。 +- 实测事实:元组构造(`ir_gen.cr` 的 `EXPR_TUPLE` 分支)给元组 var 定型 `TI_INT`、**不携带元素 ti**,因此数字下标读(`t . 0`)**取不到声明面**,本批的通道覆盖不到它(R4 修后仍 = 1)。 +- **本代理的处置(按裁-AGG-3 执行,不静默)**:3 读点实施**不含元组**;套件把 R4 移入 **`[GAP]` 组**,**只观测、不计入判据**(打印期望值与实测值,注明裁决与出处);后续批修复时须把它移回 `CASES`。 +- **若要现在即覆盖元组**(最小机制,供你裁):在元组构造点按「**全元素同形**」把该形式登记进**既有声明侧表**(`irv_set_decl_ti(tv, TI_DEX_S)`,2 行、零 alloc);数字下标读再查 `slot_decl_ti(obj_var)`。 + **代价与风险**:`slot_decl_ti(tv)` 变 `TI_DEX_S` 会波及唯一取址面 `ir_gen.cr:1530`(`&tuple` 的 pointee 型行身份:`TYP_PTR(TI_INT)` → `TYP_PTR(TI_DEX_S)`),需一条实证;且这是**新机制**,与「最小改动」约定相抵。**推荐:维持裁-AGG-3(登记)**。 ### 13.5 五 CI job / 自举链(回填 · 全部 rc=0) @@ -532,7 +554,7 @@ R1 的 IR 证据(§11.4)给出**判据形状**: > 命令形式:`CI_JOB_NAME= bash src/ci/run.sh`(**argv 写法 = 假红**,见 `tools/baseline/REBUILD.md` 的命令层陷阱段)。 -**二进制同一性论证**(§13.2 末行):终态源码(注释/测试改动后)重建 = `64c8a7d6…` 与判据二进制**逐字节同** ⇒ 已在 T3 中期跑出的 canary/parity/probes 三组结论**对终态继续成立**(不是「大概没变」)。 +**二进制同一性论证**(§13.2 末行):终态源码(注释/测试改动后)重建 = `64c8a7d6…` 与判据二进制**逐字节同**,因此已在 T3 中期跑出的 canary/parity/probes 三组结论**对终态继续成立**(不是「大概没变」)。 ### 13.6 换代重锁清单(**裁-AGG-7 的四要素**:旧值 · 新值 · 归因 · 出处) @@ -540,27 +562,27 @@ R1 的 IR 证据(§11.4)给出**判据形状**: |---|---|---| | `cir_cache.cr:51` | `CIR_CACHE_VER` 17 → **18** | 改常量 + 注释(归因写清)| | `tests/selfhost/test_ccr_types.py` ㉛/㊲ + 模块头注 | 断言 `ver == 17` → **18** | 断言改 18 + 三处注释写明「旧值 17 / 新值 18 / 归因 / 出处」| -| `tests/selfhost/test_cache_identity.py` | `VER_EXPECTED` 17 → **18** | 同上(**布局未变** ⇒ `layout()` 的 v17 分支按 `VER_EXPECTED` 复用,无需新分支)| +| `tests/selfhost/test_cache_identity.py` | `VER_EXPECTED` 17 → **18** | 同上(**布局未变**,因此 `layout()` 的 v17 分支按 `VER_EXPECTED` 复用,无需新分支)| | `src/compiler/dyn_arr.cr:112` · `src/compiler/ccr_io.cr:137` | 陈旧注释「CIR_CACHE_VER=17 不 bump」 | 注释更新 + 指向本批(**注释-only,零行为**)| | `.ccr`(`CCR_VERSION=9`) | **不 bump** | 交付格式、无快照复用语义;但**报告须写明「dex 程序的 `.ccr` 内容会变」**(防「版本没 bump」被读成「内容没变」)| -> **重锁过程留痕**:首轮 `selfhost-tests` **rc=1**,两例因版本位(`test_p4t4_cir_snapshot_layout_unbumped` / `test_p5t2_snapshot_disk_code_preserved`);重锁后**复跑又红**——但那次是**环境 flake**(同套件在干净缓存下 49/49 通过;改前二进制对照跑 47/49 = 恰为该两例版本断言,属预期);第三次红 = `test_cache_identity.py` 的 `VER_EXPECTED` 未同步(本表第 3 行)⇒ 一并重锁后 **rc=0**。 +> **重锁过程留痕**:首轮 `selfhost-tests` **rc=1**,两例因版本位(`test_p4t4_cir_snapshot_layout_unbumped` / `test_p5t2_snapshot_disk_code_preserved`);重锁后**复跑又红**,但那次是**环境 flake**(同套件在干净缓存下 49/49 通过;改前二进制对照跑 47/49 = 恰为该两例版本断言,属预期);第三次红 = `test_cache_identity.py` 的 `VER_EXPECTED` 未同步(本表第 3 行),一并重锁后 **rc=0**。 ### 13.7 未覆盖面(本批登记,供后续批) -- **U7 · `IR_SLICE` 产物的元素读**:切片 var 的 IR 型恒 `TI_INT`(且 `is_ptr_var:627` 对 `TI_DEX_S` **早退 0** ⇒ 改切片 var 型会改指针判断,**不可**用「给切片 var 定型」的办法)⇒ 切片元素的声明形式**无处寄存**(若要覆盖需新增侧表或换寄存面)。 -- **U1** match 结果槽(裁-AGG-2)· **U2/U4 元组与泛型**(裁-AGG-3/-4)——已在 §10 登记,本批未动。 +- **U7 · `IR_SLICE` 产物的元素读**:切片 var 的 IR 型恒 `TI_INT`(且 `is_ptr_var:627` 对 `TI_DEX_S` **早退 0**,因此改切片 var 型会改指针判断,**不可**用「给切片 var 定型」的办法),切片元素的声明形式**无处寄存**(若要覆盖需新增侧表或换寄存面)。 +- **U1** match 结果槽(裁-AGG-2)· **U2/U4 元组与泛型**(裁-AGG-3/-4)已在 §10 登记,本批未动。 ### 13.8 T3 未决(转 T4/T5) - T3-1:`.ccr` SYM per-var 型的直接断言(可选加固;本批用门控见证 + canary/parity 覆盖)。 - T3-2:R4 的取裁(§13.4)。 -- T3-3:腿 D①「连绿两批」的第二次(下批复跑本套件 + apx 套件且 hack 仍关)⇒ 达成后可删 hack(TODO #2026-09-16-16 追记)。 +- T3-3:腿 D①「连绿两批」的第二次(下批复跑本套件 + apx 套件且 hack 仍关),达成后可删 hack(TODO #2026-09-16-16 追记)。 - T3-4:`.cn`/`.cir` 之外是否有第三处落 per-var 型的产物(本轮扫描:`ccr_io.cr:631/:690` 与 `cir_cache.cr:259` 两处,未见第三处)。 --- -## 14. §T5 记录(2026-09-16 —— 收官) +## 14. §T5 记录(2026-09-16:收官) ### 14.1 交付 @@ -583,10 +605,10 @@ R1 的 IR 证据(§11.4)给出**判据形状**: | `selfhost-tests` | rc=0(含本批套件已挂点 · 49/49 ccr_types · 23/23 interp_parity)| | `suite` | rc=0(23 档 ALL PASS)| | `full-bootstrap` | rc=0(`cmp corec2 corec3` **恒等** 2904726 B)| -| **二进制同一性** | T5 重建 = `64c8a7d6…` 与判据二进制**逐字节同** ⇒ canary/parity/probes 结论对终态成立(§5 论证)| +| **二进制同一性** | T5 重建 = `64c8a7d6…` 与判据二进制**逐字节同**,因此 canary/parity/probes 结论对终态成立(§5 论证)| ### 14.3 批终态一行结论 -**修好**(同报告 §0):聚合读结果槽硬定 `TI_INT` ⇒ 总闸级连锁失明 —— 读点定型改**声明面形式**(零 alloc 节点判)+ +**修好**(同报告 §0):聚合读结果槽硬定 `TI_INT`,造成总闸级连锁失明,读点定型改**声明面形式**(零 alloc 节点判)+ `CIR_CACHE_VER` 17→18;**腿 A 4/5 转绿(R4 按裁-AGG-3 登记 `[GAP]`)· 腿 B 四条见证 · 腿 C 断言 · canary 5/5 IDENTICAL · 74 档/29 探针 rc 全同 · 五 CI job rc=0 · 自举链恒等 · 腿 D① 突变通过(hack 冗余确认)**。 diff --git a/docs/superpowers/plans/2026-09-16-criteria-harden.md b/docs/superpowers/plans/2026-09-16-criteria-harden.md index 4e2c661d..3a3ae625 100644 --- a/docs/superpowers/plans/2026-09-16-criteria-harden.md +++ b/docs/superpowers/plans/2026-09-16-criteria-harden.md @@ -1,11 +1,16 @@ -# 判据网加固批(criteria-harden):挂点扩容(+6 档)+ 六条弱判据改强 +# 判据网加固批(criteria-harden):挂点扩容(+6 档)与六条弱判据改强 + +**范围**:本批只改动判据与挂点,改动面为 `tests/`、`tests/harness/ci_hook_allowlist.txt`、`src/ci/run.sh`、`TODO.md` 与文档。 + +**零源码语义改动**:该结论由 `jj diff` 实证,diff 输出中无 `src/compiler` / `src/arch` / `src/format` / `src/runtime` / `src/stdlib` / `src/targets` 命中。 + +**输入**:判据强度审计(`docs/superpowers/specs/2026-09-16-criteria-strength-audit.md` 表 B / §4)与 `TODO.md` #84–#88/#90。 -**范围**:**只动判据/挂点**——`tests/`、`tests/harness/ci_hook_allowlist.txt`、`src/ci/run.sh`、`TODO.md`、文档。 -**零源码语义改动**(`jj diff` 实证:无 `src/compiler` / `src/arch` / `src/format` / `src/runtime` / `src/stdlib` / `src/targets` 命中)。 -**输入**:判据强度审计(`docs/superpowers/specs/2026-09-16-criteria-strength-audit.md` 表 B / §4)· `TODO.md` #84–#88/#90。 **基点**:develop `f7798197`(工作区 `/home/DslsDZC/core-crit-ws`;bookmark `feature/criteria-harden`)。 -## 1. T1 挂点扩容(审计 §4 成本序;**时长 = 本机实测**,逐条与 `run.sh` 行注一致) +## 1. T1 挂点扩容 + +本节按审计 §4 的成本序排列。表中的时长列为本机实测值,逐条与 `run.sh` 的行注一致。 | 档 | 时长实测 | 结果 | job | 依据 | |---|---|---|---|---| @@ -17,12 +22,14 @@ | **`test_backend_bootstrap.py`** | **22.5s** | PASS(stage0/1/2 + O2 元数据) | `selfhost-tests` | **高**:allowlist 自标「最高危」= **N06 唯一门**(rc=0 但日志带 `error[` 判红;曾致 P3a 33×N06 漏检)。审计只担心「构建面成本」,**实测 22.5s ⇒ 可挂** | | `test_criteria_mutations.py`(**本批新增**) | <1s | 22/22 | `bootstrap-tests` | 突变自证载体(§3) | -- `tests/harness/ci_hook_allowlist.txt` 同步删除 6 条(纪律:删条目 = 已挂)+ 头注重算(`scope 66 / hooked 45 / 差集 21`)。 -- **未挂登记**:`test_mw_task1-6`(**标准换代**:零 diff 基线须在**改动前**编译器上产 ⇒ CI 参照物结构性不可得;机器化需「基线入仓」取裁或改约定)· `test_lsp`(进程级,未实测)· 其余历史缺口档(差集逐条带理由)。 -- **过程证据(覆盖判据的牙)**:先挂 `run.sh`、未删白名单条目时,`test_ci_hook_coverage.py` **当场转红**并逐条指名 5 个「已挂但白名单未删」;新增 harness 档未挂时同样转红。⇒ 该判据不是纸面机制(本仓曾因「自称已挂」吃 33×N06 漏检)。 +- `tests/harness/ci_hook_allowlist.txt` 同步删除 6 条,遵循的纪律为「删条目 = 已挂」;头注同步重算(`scope 66 / hooked 45 / 差集 21`)。 +- **未挂登记**:`test_mw_task1-6` 属标准换代(零 diff 基线须在**改动前**的编译器上产出,因此 CI 参照物在结构上不可得;机器化需「基线入仓」取裁或改约定);`test_lsp` 属进程级,未实测;其余历史缺口档在差集中逐条附理由。 +- **过程证据(覆盖判据的牙)**:先挂 `run.sh`、未删白名单条目时,`test_ci_hook_coverage.py` 当场转红,并逐条指名 5 个「已挂但白名单未删」的条目;新增 harness 档未挂时同样转红。该表现说明该判据不是纸面机制(本仓曾因「自称已挂」吃 33×N06 漏检)。 - **终态**:`[PASS] ci_hook_coverage: scope=66 hooked=45 unhooked(allowlisted)=21`(含内存内「摘挂点必红」自证)。 -## 2. T2 六条弱判据改强(**新断言形态**;每条含「反例自检 + 探针触发自检」注释) +## 2. T2 六条弱判据改强 + +六条判据均改换为新断言形态;每条含「反例自检 + 探针触发自检」注释。 | # | 旧形态(弱因) | **新断言形态** | |---|---|---| @@ -33,20 +40,25 @@ | **#90** `test_mw_task2` E8 盲窗 | 遇 `0xE8` 字节即跳 5B | 判据侧**独立 x86-64 长度解码器**(fail-closed:未登记形态 ⇒ 判红)+ `region_equal_mask_calls` **指令边界锁步**(两侧边界序列逐条一致;非 call 全字节比;call 仅放行 4B rel32 且目标断言落在本 text 内) | | **#85** `test_mw_task2` 块体 | 2B 前缀锚 + 目标序 | `parse_slow_block` **逐指令模板**(除 alloc 位移/dest 槽偏移/回跳位移三字段外全字节固定)+ `tag 立即数 == 1` + 回跳落**真指令边界** + 块间**连续** + 各站点 alloc 目标**唯一** | -**真跑证据(全部本机实测)**:`test_hit_table` 24/24 · `test_ccr_types` 49/49 · `test_cir_warm_path` 19/19 · `test_mw_task2` ALL PASS(z 用例零 diff 9/9、豁免面计数 1/1/2、t3 250 站点、新增 `t4_sub_overflow` 三档);解码器与 `objdump --insn-width=16` 对拍 17 个真实 region(含 t3 3272 条指令)**逐指令边界一致**。 +**真跑证据(全部本机实测)**:`test_hit_table` 24/24;`test_ccr_types` 49/49;`test_cir_warm_path` 19/19;`test_mw_task2` ALL PASS,其中 z 用例零 diff 9/9、豁免面计数 1/1/2、t3 250 站点、新增 `t4_sub_overflow` 三档。解码器与 `objdump --insn-width=16` 对拍 17 个真实 region(含 t3 3272 条指令),逐指令边界一致。 + +## 3. 突变自证 -## 3. 突变自证(≥3 条要求 ⇒ 实交 **22/22**,已固化入仓) +本批的突变条目要求为 ≥3 条,实交 22/22 条,且已固化入仓。 -`tests/harness/test_criteria_mutations.py`(纯 python、内存内、零副作用;挂 `bootstrap-tests`):**19 突变体 + 3 正控**,每例判据 = **「旧形态骗得过(绿)∧ 新形态咬住(红)」**—— -M1 #84(角色换向/opcode 尾加 1B/rm_mode)· M2 #86(1 / 0xFE / 0xFFFFFFFF / `00` / 行尾随字段)· M3 #87(同尺寸改内容/中间漏条/暖态多一条)· M4 #88(多印未计数行/非 dump 处混入/同数量换行)· M5 #90(**改 `48 C7 45 E8 …` 的 imm32——0xE8 是数据字节,旧盲窗吞掉 ⇒ 旧绿新红**)· M6 #85(tag 1→0 / 插 `0x90` / `4C 89 10`→`18`)。 +`tests/harness/test_criteria_mutations.py`(纯 python、内存内、零副作用;挂 `bootstrap-tests`)含 19 突变体与 3 正控;每例的判据为「旧形态骗得过(绿)∧ 新形态咬住(红)」——M1 #84(角色换向/opcode 尾加 1B/rm_mode)· M2 #86(1 / 0xFE / 0xFFFFFFFF / `00` / 行尾随字段)· M3 #87(同尺寸改内容/中间漏条/暖态多一条)· M4 #88(多印未计数行/非 dump 处混入/同数量换行)· M5 #90(**改 `48 C7 45 E8 …` 的 imm32——0xE8 是数据字节,旧盲窗吞掉 ⇒ 旧绿新红**)· M6 #85(tag 1→0 / 插 `0x90` / `4C 89 10`→`18`)。 -## 4. 本批抓到的两条**新假绿**(已追加进审计 spec §0bis,附判别法) +## 4. 本批抓到的新假绿 + +本批抓到两条新假绿,已追加进审计 spec §0bis,并附判别法。 1. **`t4_sub_overflow`:判据内部 `sub` 分支从未被走到**——块体模板的 `is_sub` 分支断言(`not r11`)在原三例(全 add)下**从未执行** ⇒ 属 §0bis 第二类假绿(探针不触发)。判别法 = **逐分支覆盖检查**(判据每个条件分支问「哪条语料走到它」)。 -2. **解码器 fail-closed 当场抓到未登记 opcode `0x19`**(慢路径块首 `4D 19 DB` = `sbb r11,r11`)⇒ 「宁可红不静默」的现场实证;若当初写成「未知 ⇒ 跳过」则缺口静默留存。 +2. **解码器 fail-closed 当场抓到未登记 opcode `0x19`**(慢路径块首 `4D 19 DB` = `sbb r11,r11`)⇒ 这是「宁可红不静默」的现场实证;若当初写成「未知 ⇒ 跳过」,则该缺口会静默留存。 ## 5. 全量判据(T3) +下表逐项列出本批的全量判据与结果。 + | 判据 | 结果 | |---|---| | ELF canary + `.ccr` **四条** | **5/5 PASS**(值源 `tools/baseline/canary_values.tsv`):`95084e7b…d475`(28822B) · `680a6f98…cd7a`(96015) · `76f36e6a…f329c`(96158) · `d92a2727…2c95`(142765) · `a1f7b99c…82ea`(142908) | @@ -58,8 +70,8 @@ M1 #84(角色换向/opcode 尾加 1B/rm_mode)· M2 #86(1 / 0xFE / 0xFFFFFF | 挂点覆盖判据 | `[PASS] scope=66 hooked=45 unhooked(allowlisted)=21` | | 枚举(实读) | `tests/selfhost/test_*.py` **55** · `tests/bootstrap/*.py` **7** · `tests/harness/test_*.py` **4** · `tests/probes/*.cr` **29** · `tests/suite/*.cr` **33** | -## 6. 未覆盖面 / 交接 +## 6. 未覆盖面与交接 - `test_mw_task1-6` 仍**未挂**(标准换代,需取裁);`#90` 的判据虽已改强,但该条判据仍靠手工跑(同因)。 -- 本批新增 `t4_sub_overflow` 为**行为覆盖用例**(不改源码语义);`t3` 的 250 站点块体模板断言随语料规模线性增长(实测可接受)。 -- 判据侧解码器(`x86_insn_len`)为**判据专用**:发射器新增指令形态时它会**判红**(fail-closed),需按新形态登记——这是有意的维护点,勿改回「未知即跳过」。 +- 本批新增的 `t4_sub_overflow` 为**行为覆盖用例**(不改源码语义);`t3` 的 250 站点块体模板断言随语料规模线性增长(实测可接受)。 +- 判据侧解码器(`x86_insn_len`)为**判据专用**:发射器新增指令形态时它会**判红**(fail-closed),需按新形态登记——这是有意的维护点,不得改回「未知即跳过」。 diff --git a/docs/superpowers/specs/2026-07-28-arena-model-design.md b/docs/superpowers/specs/2026-07-28-arena-model-design.md index 3265317d..b260e331 100644 --- a/docs/superpowers/specs/2026-07-28-arena-model-design.md +++ b/docs/superpowers/specs/2026-07-28-arena-model-design.md @@ -2,7 +2,7 @@ ## 概述 -Core 语言基于 Arena 的内存管理方案。本设计将现有的 1GB 全局 bump allocator 升级为多 Arena 池,每个子图(函数/loop/for/unsafe)关联独立 Arena,分配自动从当前 Arena 的 bump pointer 分配,子图退出时整体重置游标。 +Core 语言基于 Arena 的内存管理方案。本设计将现有的 1GB 全局 bump allocator 升级为多 Arena 池,每个子图(函数 / `loop` / `for` / `unsafe`)关联独立 Arena,分配自动从当前 Arena 的 bump pointer 分配,子图退出时整体重置游标。 ### 核心原则 @@ -25,7 +25,7 @@ BSS 段布局(新增字段用 + 标记): heap_end ``` -> **设计决策**:arena metadata 数组(`cursors`、`sizes`、`parents`)作为 Core 全局变量动态分配(`g_arena_cursors = alloc(N * 8)`),不使用 BSS 静态数组。原因是固定上限(MAX_ARENAS)会在深层嵌套或大量并发子图时导致运行时错误——metadata 需要像 `g_df_nodes` 一样可扩容。性能代价:`emit_alloc_body` 多一次间接访存(加载指针值),在分配热路径上可接受。 +> **设计决策**:arena metadata 数组(`cursors`、`sizes`、`parents`)作为 Core 全局变量动态分配(`g_arena_cursors = alloc(N * 8)`),不使用 BSS 静态数组。原因是固定上限(`MAX_ARENAS`)会在深层嵌套或大量并发子图时导致运行时错误——metadata 需要像 `g_df_nodes` 一样可扩容。性能代价:`emit_alloc_body` 多一次间接访存(加载指针值),在分配热路径上可接受。 ### Arena slot 模型 @@ -129,7 +129,7 @@ fn arena_avail(ai: int) -> int { ### 2. 运行时(`src/runtime/rt.s`)— BSS 扩展 -BSS 段新增 emit_alloc_body 热路径直接访问的字段: +BSS 段新增 `emit_alloc_body` 热路径直接访问的字段: ```asm .section .bss @@ -183,7 +183,7 @@ IR_ARENA_RESET : int = 31; // arena_reset src1 | SG_FLOW | `sg_push(SG_FLOW)` 之前(编译器插桩点预留) | `sg_pop()` 之后 | | SG_GO | `sg_push(SG_GO)` 之前(编译器插桩点预留) | `sg_pop()` 之后 | -> `SG_FLOW` 和 `SG_GO` 的 arena 插桩点已预留。当前编译器未实现 `go`/`flow` 原语,但 arena 层已准备好——`sg_push(SG_FLOW)` 时自动 `arena_new()` 创建独立 arena,`sg_pop()` 时自动 `arena_reset()` 回收。flow/go 的结果跨 arena 拷贝机制在对应原语实现时加入即可。 +> `SG_FLOW` 和 `SG_GO` 的 arena 插桩点已预留。当前编译器未实现 `go`/`flow` 原语,但 arena 层已准备好——`sg_push(SG_FLOW)` 时自动 `arena_new()` 创建独立 arena,`sg_pop()` 时自动 `arena_reset()` 回收。`flow`/`go` 的结果跨 arena 拷贝机制在对应原语实现时加入即可。 每次 `arena_new` 创建一个新的 IR 变量 `_arena_N` 存储 arena ID。 @@ -193,9 +193,9 @@ IR_ARENA_RESET : int = 31; // arena_reset src1 `IR_ARENA_RESET` → emit 调用 `arena_reset` -**实现选择**:arena_new/arena_reset 作为外部函数(通过 `ctx_add_plt("arena_new", ...)` 机制)还是内联 emit? +**实现选择**:`arena_new`/`arena_reset` 存在两种实现路径——作为外部函数(通过 `ctx_add_plt("arena_new", ...)` 机制)或内联 emit,需在两者之间取舍。 -选择**外部函数**方式:与现有 `alloc` 类似,`arena_new`/`arena_reset` 实现为 `emit_alloc_body` 附近的代码片段,通过 call+relocation 跳转。这使得 Core stdlib 可以定义 API,后端提供实现。 +本设计选择**外部函数**方式:与现有 `alloc` 类似,`arena_new`/`arena_reset` 实现为 `emit_alloc_body` 附近的代码片段,通过 call+relocation 跳转。这使得 Core stdlib 可以定义 API,后端提供实现。 ### 5. 其他文件修改 @@ -210,7 +210,7 @@ IR_ARENA_RESET : int = 31; // arena_reset src1 ### 6. 编译期 Arena 大小预计算 -memory-model.md 要求编译器为每个子图计算最大内存需求,作为 `arena_new` 的 size 参数。实现在 `ir_gen.cr` 中。 +`memory-model.md` 要求编译器为每个子图计算最大内存需求,作为 `arena_new` 的 size 参数。实现在 `ir_gen.cr` 中。 **算法**:在 IR gen 阶段,为每个子图维护一个累计 `alloc_total`: @@ -222,7 +222,7 @@ memory-model.md 要求编译器为每个子图计算最大内存需求,作为 6. 子图结束时(`sg_pop` 前),累计值为 `estimated_size` 7. 如果 `estimated_size == 0`(全动态,无可推大小),使用默认值(如 64KB) -实现位置:在 `emit()` 函数入口处检查 opcode,若是 ALLOC 系列则累加一个子图级计数器。 +实现位置:在 `emit()` 函数入口处检查 opcode,若属于 `ALLOC` 系列则累加一个子图级计数器。 ```core // ir_gen.cr 新增 @@ -252,9 +252,9 @@ fn track_alloc_size(size: int) { `track_alloc_size` 在每个 `emit(IR_ALLOC_X, ...)` 处调用。 -## IR_ALLOC 指令无变化 +## `IR_ALLOC` 指令的零改动 -关键设计决定:**IR_ALLOC、IR_ALLOC_STRUCT、IR_ALLOC_ARRAY 指令本身不需要修改**。它们都 emit `call alloc`,而 `alloc()` 函数本身已经是 arena-aware。这使得编译器改动最小化。 +关键设计决定:**`IR_ALLOC`、`IR_ALLOC_STRUCT`、`IR_ALLOC_ARRAY` 指令本身不需要修改**。它们都 emit `call alloc`,而 `alloc()` 函数本身已经是 arena-aware。这使得编译器改动最小化。 ## 错误处理 @@ -266,7 +266,7 @@ fn track_alloc_size(size: int) { ### 链式扩容(Chunk Overflow) -当 `arena_alloc` 在当前 chunk 中空间不足时,不是返回 0,而是: +当 `arena_alloc` 在当前 chunk 中空间不足时,处理路径不是返回 0,而是执行以下步骤: 1. 通过全局 alloc(此时 `g_current_arena` 暂存为 -1)分配一个新 chunk 2. 新 chunk 挂在当前 arena 的链表末尾 @@ -291,7 +291,7 @@ reset 时只回收第一个 chunk 的 cursor(O(1) 重置),overflow chunks ## 不包含的功能 -以下功能属于 memory-model.md 设计但依赖其他未实现的原语,不在本次实现中: +以下功能属于 `memory-model.md` 设计但依赖其他未实现的原语,不在本次实现中: - **Flow/Go 并发 arena**:编译器的 `go`/`flow` 原语尚未实现。待这些原语就绪后,每个 `go`/`flow` 调用在 `sg_push(SG_FLOW/GO)` 处自然获得独立 arena - **敏感数据清零选项**:部署配置控制的 optional 行为,不影响 Arena 模型核心语义 diff --git a/docs/superpowers/specs/2026-07-28-at-intrinsics-design.md b/docs/superpowers/specs/2026-07-28-at-intrinsics-design.md index 3b324232..8c968aee 100644 --- a/docs/superpowers/specs/2026-07-28-at-intrinsics-design.md +++ b/docs/superpowers/specs/2026-07-28-at-intrinsics-design.md @@ -8,9 +8,9 @@ ## 核心原则 -- **每个 @ 有对应 IR 语义节点**(IR_CONST 带 provenance 标注),验证工具能从 IR 图看到原始操作 -- **元数据查询在 IR gen 时已算出值**,emit 为 IR_CONST,不引入运行时指令 -- **@comptime 在编译期调解释器执行**,不留任何运行时痕迹 +- **每个 `@` 有对应 IR 语义节点**(`IR_CONST` 带 provenance 标注),验证工具能从 IR 图看到原始操作 +- **元数据查询在 IR gen 时已算出值**,emit 为 `IR_CONST`,不引入运行时指令 +- **`@comptime` 在编译期调解释器执行**,不留任何运行时痕迹 - **编译控制/安全检查 emit 标注指令**,被 pass 或后端消费 ## IR 指令 @@ -50,7 +50,7 @@ T_AT → advance ## 类型检查器 -在 checker 中识别 `EXPR_AT`,根据 `name_ni` 分发: +在 `checker` 中识别 `EXPR_AT`,根据 `name_ni` 分发: ```core fn check_expr_at(node): @@ -161,7 +161,7 @@ TY_TYPEINFO : int = ...; // struct { name: string, size: int, align: int, field TY_FIELDINFO : int = ...; // struct { name: string, offset: int, type: int } ``` -具体实现方案:在 checker/ir_gen 中使用编译期已知的 struct layout 来构造返回值。因为 @typeInfo 和 @field 返回的结构体在编译期构造,不需要运行时定义。 +具体实现方案:在 `checker`/`ir_gen` 中使用编译期已知的 struct layout 来构造返回值。`@typeInfo` 和 `@field` 返回的结构体在编译期构造,不需要运行时定义。 ## @comptime 实现 @@ -187,7 +187,7 @@ TY_FIELDINFO : int = ...; // struct { name: string, offset: int, type: int } | 7 | `src/arch/linux/ld/instr.cr` | IR_INLINE 等(仅标注,emit NOP) | | 8 | `tests/suite/at_test.cr` | 测试 @ 内建 | -## 不包含 +## 不包含的功能 - walk/step(属于并发模型) - `@unroll` / `@section`(编译控制后续扩展) diff --git a/docs/superpowers/specs/2026-07-29-hotpatch-design.md b/docs/superpowers/specs/2026-07-29-hotpatch-design.md index 23febd98..d59b2075 100644 --- a/docs/superpowers/specs/2026-07-29-hotpatch-design.md +++ b/docs/superpowers/specs/2026-07-29-hotpatch-design.md @@ -11,7 +11,7 @@ Core 编译器的滚动更新(hotpatch)机制。通过 `@hotpatch` 注解支 - **同名函数多版本共存**:`@hotpatch(ver=N)` 标记的函数允许同名,签名必须一致 - **编译期路由节点**:调用点 emit `IR_HOTPATCH_ROUTE`,运行时根据配置选择版本 - **运行时配置**:`.hotpatch.toml` 配置文件,SIGHUP 信号重读 -- **排水安全**:in_flight 计数追踪进行中请求,drain 完成后回收旧版本 +- **排水安全**:`in_flight` 计数追踪进行中请求,drain 完成后回收旧版本 ## IR 指令 @@ -69,7 +69,7 @@ g_hp_config : string, mut; // 序列化配置表 g_hp_inflight : string, mut; // in_flight 计数数组 ``` -### 配置格式(.hotpatch.toml) +### 配置格式(`.hotpatch.toml`) ```toml [hotpatch.handle] diff --git a/docs/superpowers/specs/2026-07-29-incremental-cache-design.md b/docs/superpowers/specs/2026-07-29-incremental-cache-design.md index 45716b1f..a97996e7 100644 --- a/docs/superpowers/specs/2026-07-29-incremental-cache-design.md +++ b/docs/superpowers/specs/2026-07-29-incremental-cache-design.md @@ -1,7 +1,7 @@ # 增量缓存设计 -> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 docs/project-book.md。正文保留历史原样。 +> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 `docs/project-book.md`。正文保留历史原样。 ## 概述 @@ -66,7 +66,7 @@ fn function_fingerprint(func_node: int) -> int { } ``` -使用现有 `str_hash` 函数(Fowler-Noll-Vo 或类似),已经存在于 `dyn_arr.cr`。 +使用现有 `str_hash` 函数(Fowler-Noll-Vo 或同类算法),该函数已存在于 `dyn_arr.cr`。 ### 签名指纹 diff --git a/docs/superpowers/specs/2026-07-30-concurrency-design.md b/docs/superpowers/specs/2026-07-30-concurrency-design.md index ee2301cc..383696bb 100644 --- a/docs/superpowers/specs/2026-07-30-concurrency-design.md +++ b/docs/superpowers/specs/2026-07-30-concurrency-design.md @@ -6,10 +6,10 @@ ## 核心原则 -- **不共享内存。** goroutine 之间不共享变量。所有通信通过 channel 传值。 -- **"像图一样"。** 每个 goroutine 是图上的一个节点,channel 是边。 -- **Arena 隔离。** 每个 goroutine 有自己的 arena。`go f()` 时创建新 arena。 -- **Cooperative 调度。** 只在 channel send/recv 和显式 `yield` 时切换。 +- **不共享内存**:goroutine 之间不共享变量。所有通信通过 channel 传值。 +- **「像图一样」**:每个 goroutine 是图上的一个节点,channel 是边。 +- **Arena 隔离**:每个 goroutine 有自己的 arena。`go f()` 时创建新 arena。 +- **Cooperative 调度**:只在 channel `send`/`recv` 和显式 `yield` 时切换。 ## GMP 模型(简化) @@ -85,7 +85,7 @@ struct Channel { ### Channel 操作 -**send(ch, val)**: +**`send(ch, val)`**: ``` 1. 如果 ch 已关闭 → panic 2. 如果有等待接收的 G → 直接拷贝给接收者,唤醒 G @@ -93,7 +93,7 @@ struct Channel { 4. 如果 buf 已满 → 当前 G 阻塞,加入 send_wait 链表 ``` -**recv(ch)**: +**`recv(ch)`**: ``` 1. 如果有等待发送的 G → 从发送者直接接收,唤醒发送者 2. 如果 buf 非空 → 从缓冲区读取 @@ -103,7 +103,7 @@ struct Channel { **值拷贝语义**:channel 边界永远拷贝值,不传引用。发送方的值在发送后不变。 -## go f() 语义 +## `go f()` 语义 ```core go f(args); @@ -112,11 +112,11 @@ go f(args); 1. 分配 G 结构 + 16KB 栈 2. 复制参数到新 arena 3. 创建新 arena(`arena_new()`) -4. 设置 G 状态为 _Grunnable +4. 设置 G 状态为 `_Grunnable` 5. 投递到 M 的 local run queue 6. 返回(不等待 f 完成) -**返回值**:`go f()` 返回一个 channel,用于接收 f 的返回值: +**返回值**:`go f()` 返回一个 channel,用于接收 `f` 的返回值: ```core ch := go f(args); @@ -168,7 +168,7 @@ IR_SPAWN : int = 27; // 已有: dest=chan, s1=fn_ni, s2=first_arg, s3=arg_count IR_YIELD : int = 28; // 已有: s1=value_var ``` -保持不变。`IR_SPAWN` 在后端编译为 fiber 创建 + 队列投递。`IR_YIELD` 编译为 fiber 切换。 +上列编号保持不变。`IR_SPAWN` 在后端编译为 fiber 创建 + 队列投递。`IR_YIELD` 编译为 fiber 切换。 ## 实现清单 diff --git a/docs/superpowers/specs/2026-07-30-dynamic-typing-design.md b/docs/superpowers/specs/2026-07-30-dynamic-typing-design.md index 6cefd69e..6a1eff5a 100644 --- a/docs/superpowers/specs/2026-07-30-dynamic-typing-design.md +++ b/docs/superpowers/specs/2026-07-30-dynamic-typing-design.md @@ -1,17 +1,17 @@ # 动态类型实现设计 -> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 docs/project-book.md。正文保留历史原样。 +> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 `docs/project-book.md`。正文保留历史原样。 ## 概述 在 Core 中实现 `dyn` 动态类型。声明为 `dyn` 的变量可以在不同路径中持有不同类型的值,编译器从数据流图中推导所有可能的类型,在汇合点生成 `(tag, value)` 对,后续代码根据 tag 分派不同的执行路径。 -**核心原则:** -- 动态值不是胖结构,没有装箱 -- 单路径 `dyn` 变量 = 裸值,零运行时开销 -- 多路径 `dyn` 变量 = 编译期确定的 `(tag, value)` 对 -- 编译器全量知道所有分支的可能类型集合 +**核心原则**: +- 动态值不是胖结构,没有装箱。 +- 单路径 `dyn` 变量 = 裸值,零运行时开销。 +- 多路径 `dyn` 变量 = 编译期确定的 `(tag, value)` 对。 +- 编译器全量知道所有分支的可能类型集合。 ## 类型系统 @@ -49,7 +49,7 @@ g_type_set : string, mut; // 每变量: int[] 可能类型索引 T_DYN : int = 48; ``` -### parse_type 中处理 +### `parse_type` 中处理 ```core // 在 parse_type 中,当遇到 `dyn` 关键字时返回类型节点 @@ -116,8 +116,8 @@ IR_DYN_DISPATCH : int = 44; // s1=dyn_var, s2=type_list_ni — 按 tag 分派执 ### 变量宽度 -- 单路径 `dyn`:编译期已知确切类型 → 变量宽度 = 该类型宽度(8 字节,零开销) -- 多路径 `dyn`:编译期已知所有可能类型 → 变量宽度 = 16 字节(`{ tag: int, value: [8]byte }`) +- 单路径 `dyn`:编译期已知确切类型 → 变量宽度 = 该类型宽度(8 字节,零开销)。 +- 多路径 `dyn`:编译期已知所有可能类型 → 变量宽度 = 16 字节(`{ tag: int, value: [8]byte }`)。 ```core // 在 IR 变量表中新增字段 @@ -144,7 +144,7 @@ y := x + 1; ## IR 生成 -### EXPR_DYN 处理 +### `EXPR_DYN` 处理 ```core // 在 gen_expr 中: @@ -189,7 +189,7 @@ x.len(); ## 后端(ELF) -### IR_DYN_TAG / IR_DYN_VAL / IR_DYN_PACK / IR_DYN_DISPATCH +### `IR_DYN_TAG` / `IR_DYN_VAL` / `IR_DYN_PACK` / `IR_DYN_DISPATCH` | 指令 | 编码 | |------|------| @@ -248,7 +248,7 @@ y := x + 1; // string + int → str_to_int + 加法(自动插转换) | int → float | `int_to_float()` | | float → int | `float_to_int()` | -跨 `dyn` 边界访问时,编译器如果发现"期望类型 ≠ 实际类型"且存在转换路径,自动插入转换代码;不存在转换路径时报编译错误。 +跨 `dyn` 边界访问时,编译器如果发现「期望类型 ≠ 实际类型」且存在转换路径,自动插入转换代码;不存在转换路径时报编译错误。 ## 实现清单 diff --git a/docs/superpowers/specs/2026-07-30-ffi-design.md b/docs/superpowers/specs/2026-07-30-ffi-design.md index d5610cb8..82b198f3 100644 --- a/docs/superpowers/specs/2026-07-30-ffi-design.md +++ b/docs/superpowers/specs/2026-07-30-ffi-design.md @@ -6,14 +6,14 @@ ## 核心原则 -- **C ABI 是默认接口**。所有语言最终通过 C ABI 对接。 -- **`@ffi` 是编译控制**。不改变语义,只改变调用方式的生成。 -- **类型编组在 IR gen 时静态插入**。`@ffi("Python")` 在每个调用点插入 PyObject* 转换代码。 -- **`.so` 链接已有基础设施**。`ctx_add_plt`/`g_x86_ext_rel` 等直接复用。 +- **C ABI 是默认接口**:所有语言最终通过 C ABI 对接。 +- **`@ffi` 是编译控制**:不改变语义,只改变调用方式的生成。 +- **类型编组在 IR gen 时静态插入**:`@ffi("Python")` 在每个调用点插入 `PyObject*` 转换代码。 +- **`.so` 链接已有基础设施**:`ctx_add_plt`/`g_x86_ext_rel` 等直接复用。 ## 语法 -### extern fn 声明 +### `extern fn` 声明 ```core extern fn read_file(path: *const u8) -> *mut u8; @@ -21,7 +21,7 @@ extern fn write(fd: i32, buf: *const u8, len: i32) -> i32; extern fn getchar() -> i32; ``` -### @ffi 多语言注解 +### `@ffi` 多语言注解 ```core @ffi("C") extern fn printf(fmt: *const u8, ...) -> i32; @@ -73,7 +73,7 @@ extern fn getchar() -> i32; T_EXTERN : int = 100; // extern 关键字 ``` -**parse_extern_fn**:在 `parse_declaration` 中处理 `extern fn`: +**`parse_extern_fn`**:在 `parse_declaration` 中处理 `extern fn`: ```core if tok_k(cur_tok()) == T_EXTERN { @@ -95,13 +95,13 @@ if tok_k(cur_tok()) == T_EXTERN { ### 2. 检查器 -- `extern fn` 不需要函数体,只做签名检查 -- 参数类型和返回类型校验(是否可编组) -- `@ffi("Python")` 的参数类型校验(`dyn` 类型是否合理) +- `extern fn` 不需要函数体,只做签名检查。 +- 参数类型和返回类型校验(是否可编组)。 +- `@ffi("Python")` 的参数类型校验(`dyn` 类型是否合理)。 ### 3. IR 生成 -**extern 调用点的代码生成**: +**`extern` 调用点的代码生成**: ```core if is_extern_func(func_ni) { @@ -121,7 +121,7 @@ if is_extern_func(func_ni) { ### 4. 链接器集成 -在链接阶段,extern 函数自动触发 `.so` 加载: +在链接阶段,`extern` 函数自动触发 `.so` 加载: ```core // 在 ldd.cr 中处理 extern 函数 diff --git a/docs/superpowers/specs/2026-07-30-generics-design.md b/docs/superpowers/specs/2026-07-30-generics-design.md index f2189cf2..5e248345 100644 --- a/docs/superpowers/specs/2026-07-30-generics-design.md +++ b/docs/superpowers/specs/2026-07-30-generics-design.md @@ -6,10 +6,10 @@ ## 核心原则 -- **不需要 trait bounds / where 子句 / 关联类型**。类型检查不通过的用法在 monomorphization 时报错,和普通函数一样自然。 -- **自动推导**。`identity(42)` → `T = int`,不需要写 `identity(42)`。 -- **Monomorphization 是编译期展开**。每次实例化产生独立函数/结构体,后端不感知泛型。 -- **零运行时开销**。特化后的代码和手写具体类型版本完全一样。 +- **不需要 trait bounds / where 子句 / 关联类型**:类型检查不通过的用法在 monomorphization 时报错,报错路径与普通函数一致。 +- **自动推导**:`identity(42)` → `T = int`,不需要写 `identity(42)`。 +- **Monomorphization 是编译期展开**:每次实例化产生独立函数/结构体,后端不感知泛型。 +- **零运行时开销**:特化后的代码和手写具体类型版本完全一样。 ## 用户语法 @@ -59,7 +59,7 @@ x := b.get(); // T = int | `ir_gen.cr` | 调用特化版本 | ~20 行 | | 测试 | 泛型函数/结构体/方法/多参数 | ~80 行 | -### 1. 解析器(parser.cr) +### 1. 解析器(`parser.cr`) 在 `parse_fn` 中识别 `fn name(...)`: @@ -76,15 +76,15 @@ x := b.get(); // T = int 解析类型名 → cur_tok 为 < → 解析类型参数列表 → 创建 TYP_GENERIC_APPLY ``` -### 2. 类型检查器(checker.cr) +### 2. 类型检查器(`checker.cr`) **泛型参数注册**:遇到 `` 时注册 `T` 为 `TYP_GENERIC_PARAM`,存储在符号表中。 **实例化**:当检测到 `identity(42)` 调用时: -1. 检查函数是否有泛型参数 -2. 从参数类型推导具体类型(`42` 是 `int` → `T = int`) -3. 检查 `g_gen_instances` 缓存中是否已有 `identity` -4. 如果没有,注册新实例,触发 monomorphization +1. 检查函数是否有泛型参数。 +2. 从参数类型推导具体类型(`42` 是 `int` → `T = int`)。 +3. 检查 `g_gen_instances` 缓存中是否已有 `identity`。 +4. 如果没有,注册新实例,触发 monomorphization。 **类型替换**:在实例化时将函数/结构体定义中所有 `T` 替换为具体类型。 @@ -94,7 +94,7 @@ x := b.get(); // T = int // 特化: fn identity$int(x: int) -> int { return x; } ``` -### 3. Monomorphization(monomorph.cr)— 新文件 +### 3. Monomorphization(`monomorph.cr`)— 新文件 ```core // 实例表 @@ -117,7 +117,7 @@ fn gen_monomorphize(func_ni: int, type_args: string) -> int { } ``` -### 4. IR 生成(ir_gen.cr) +### 4. IR 生成(`ir_gen.cr`) 在 `gen_expr` 的 `EXPR_CALL` 处理中: diff --git a/docs/superpowers/specs/2026-07-30-lazy-eval-design.md b/docs/superpowers/specs/2026-07-30-lazy-eval-design.md index 6331cf9a..91a5ac62 100644 --- a/docs/superpowers/specs/2026-07-30-lazy-eval-design.md +++ b/docs/superpowers/specs/2026-07-30-lazy-eval-design.md @@ -1,9 +1,9 @@ # 惰性求值实现设计 -> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 docs/project-book.md。正文保留历史原样。 +> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 `docs/project-book.md`。正文保留历史原样。 -状态:调用级子集已实现(2026-08-08);控制流级方向 2026-08-09 定为**编译期指令下沉路线**(不做运行时 thunk),详见 `docs/lazy.md` 与 TODO.md「控制流自动惰性」——本 spec 的运行时 thunk 设计(flag + 9 字节结构 + asm 草案)已被取代,IR_LAZY_THUNK/IR_LAZY_FORCE 编号保留。 +状态:调用级子集已实现(2026-08-08);控制流级方向 2026-08-09 定为**编译期指令下沉路线**(不做运行时 thunk),详见 `docs/lazy.md` 与 `TODO.md`「控制流自动惰性」——本 spec 的运行时 thunk 设计(flag + 9 字节结构 + asm 草案)已被取代,`IR_LAZY_THUNK`/`IR_LAZY_FORCE` 编号保留。 ## 概述 @@ -11,16 +11,16 @@ ## 核心原则 -- **无关键字**。编译器自动推导,用户不感知。 -- **图本来就是惰性的**。节点不在边上游等待时就不执行。当前 IR 是 eager 策略,不是图的限制。 -- **惰性不改变语义**。纯编译器优化,输出一致。 -- **副作用标记决定策略**。有副作用的调用永远 eager。 +- **无关键字**:编译器自动推导,用户不感知。 +- **图本来就是惰性的**:节点不在边上游等待时就不执行。当前 IR 是 eager 策略,不是图的限制。 +- **惰性不改变语义**:纯编译器优化,输出一致。 +- **副作用标记决定策略**:有副作用的调用永远 eager。 ## 副作用分析 ### 纯函数判定 -一个函数是"纯"的(可惰性)当且仅当: +一个函数是「纯」的(可惰性)当且仅当: | 条件 | 说明 | |------|------| @@ -60,11 +60,11 @@ OFF_FN_ISPURE : int = 32; // 新字段,1=纯函数 ESZ_FN 增长为 40 ``` -或者更简单:在 IR gen 时惰性分析,不修改 g_funcs。 +或者采用更简单的方案:在 IR gen 时惰性分析,不修改 `g_funcs`。 ## 使用计数分析 -在 IR gen 阶段(或作为一个单独 pass),统计每个 IR 变量的"使用次数": +在 IR gen 阶段(或作为一个单独 pass),统计每个 IR 变量的「使用次数」: ```core // 对每个 IR 变量 v: @@ -112,9 +112,9 @@ v := IR_LAZY_FORCE v, t // 如果执行到该分支则求值 ## 后端(ELF) -`IR_LAZY_THUNK`: 分配 9 字节的 thunk 结构(1 byte flag + 8 byte value)。flag 初始为 0。 +`IR_LAZY_THUNK`:分配 9 字节的 thunk 结构(1 byte flag + 8 byte value)。flag 初始为 0。 -`IR_LAZY_FORCE`: 检查 flag,为 0 则执行表达式并设置 flag=1。为 1 则直接返回 value。 +`IR_LAZY_FORCE`:检查 flag,为 0 则执行表达式并设置 flag=1。flag 为 1 时直接返回 value。 ```asm ; IR_LAZY_FORCE: diff --git a/docs/superpowers/specs/2026-07-30-probabilistic-pass-design.md b/docs/superpowers/specs/2026-07-30-probabilistic-pass-design.md index 37661eb4..7f3a3dea 100644 --- a/docs/superpowers/specs/2026-07-30-probabilistic-pass-design.md +++ b/docs/superpowers/specs/2026-07-30-probabilistic-pass-design.md @@ -1,20 +1,20 @@ # 概率编程 pass 实现设计 -> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 docs/project-book.md。正文保留历史原样。 +> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 `docs/project-book.md`。正文保留历史原样。 ## 概述 -在 Core 编译器中实现 ProbabilityPass——一个在数据流图上运行的概率推导 pass。不需要新语法、不需要运行时系统、不需要 CPS 变换。全部在编译期完成。 +在 Core 编译器中实现 ProbabilityPass——一个在数据流图上运行的概率推导 pass。该 pass 不需要新语法、不需要运行时系统、不需要 CPS 变换,全部工作在编译期完成。 -参考 Mappl (PLDI 2024) 的变量消元编译方法,但利用 Core 已有数据流图简化实现。 +参考 Mappl (PLDI 2024) 的变量消元编译方法,并利用 Core 已有的数据流图简化实现。 ## 核心原则 -- **概率不是新特性——是一个 pass。** -- **数据流图天然记录了所有依赖关系。** Mappl 用信息流类型系统+CPS 变换才能分析的东西,Core 的图上已经有了。 -- **`random()` 是库函数。** 编译器不特殊对待——pass 看到的是 `IR_CALL random` 节点。 -- **观测是条件分支。** `if sensor > 30` — pass 在这条边上标注观察约束。 +- **概率以 pass 形态实现,而非新增语言特性。** +- **数据流图天然记录了所有依赖关系。** Mappl 需借助信息流类型系统与 CPS 变换才能分析的信息,Core 的数据流图上已经具备。 +- **`random()` 是库函数。** 编译器不做特殊对待——pass 看到的是 `IR_CALL random` 节点。 +- **观测即条件分支。** `if sensor > 30` — pass 在该分支边上标注观察约束。 ## ProbabilityPass 架构 @@ -38,7 +38,7 @@ pass 流程: 无运行时开销: 全部信息在编译期走完。 ``` -## Step 1: 识别 random() 节点 +## Step 1:`random()` 节点识别 ```core fn scan_random_calls() { @@ -59,9 +59,9 @@ fn scan_random_calls() { } ``` -## Step 2: 分支概率标注 +## Step 2:分支概率标注 -`random() < p` 模式在图中是 `IR_BRANCH s1=condition`。如果 condition 的上游是 `IR_BINARY(OP_LT, random_call, IR_CONST(p))`,则: +`random() < p` 模式在图中是 `IR_BRANCH s1=condition`。如果 `condition` 的上游是 `IR_BINARY(OP_LT, random_call, IR_CONST(p))`,则: ```core fn tag_branch_weights() { @@ -83,9 +83,9 @@ random() ──→ IR_CONST(0.3) → false_edge (weight=0.7) ``` -## Step 3: 权重传播 +## Step 3:权重传播 -沿值流传播概率权重。原理和数据流分析一样——每个值的"可能概率"从分支边沿数据边传播: +沿值流传播概率权重。原理与数据流分析相同——每个值的"可能概率"沿分支边与数据边传播: ```core fn propagate_weights() { @@ -108,9 +108,9 @@ fn propagate_weights() { } ``` -## Step 4: 观测约束 +## Step 4:观测约束 -`if sensor > 30 { ... }` — 条件分支同时也是一个观测。pass 在这里标注: +`if sensor > 30 { ... }` — 条件分支同时也是一个观测。pass 在该处标注: ```core fn apply_observations() { @@ -121,7 +121,7 @@ fn apply_observations() { } ``` -## Step 5: 图标注 +## Step 5:图标注 概率信息附加到 DF 节点上供优化器和验证器消费: @@ -131,7 +131,7 @@ fn apply_observations() { // EXTENDED_ESZ_DFNODE: int = 72 (原本 64 + 8) ``` -或更简单:用独立的 `g_node_probs[]` 数组(8 bytes per node),不修改 DFNODE 结构。 +替代方案:使用独立的 `g_node_probs[]` 数组(8 bytes per node),不修改 `DFNODE` 结构。 ## 与 Mappl 的对比 diff --git a/docs/superpowers/specs/2026-08-08-crasm-design.md b/docs/superpowers/specs/2026-08-08-crasm-design.md index 1e1465bf..c5b38cb1 100644 --- a/docs/superpowers/specs/2026-08-08-crasm-design.md +++ b/docs/superpowers/specs/2026-08-08-crasm-design.md @@ -1,42 +1,42 @@ -# .crasm 统一汇编抽象层设计 +# `.crasm` 统一汇编抽象层设计 日期:2026-08-08 状态:已批准(brainstorming 会话,五节逐节确认);2026-08-09 整理为正式文档 → `docs/crasm.md`(本 spec 保留为批准记录) -> **2026-09-05 退役**:独立 .crasm 格式取消——绑定经典硬件过深;诉求被硬件接口表(HIT)吸收(见 `docs/superpowers/specs/2026-09-05-hardware-interface-table.md`)。本文保留为历史批准记录。 +> **2026-09-05 退役**:独立 `.crasm` 格式取消——该格式与经典硬件绑定过深;诉求被硬件接口表(HIT)吸收(见 `docs/superpowers/specs/2026-09-05-hardware-interface-table.md`)。本文保留为历史批准记录。 ## 1. 背景与动机 -Core 的内核路线(project-book 第五阶段)需要汇编级能力(MMIO、特权指令、中断), -但当前无任何汇编层(lexer/parser 无 asm 语法;汇编只存在于 rt.s 手工汇编与 ELF +Core 的内核路线(`project-book` 第五阶段)需要汇编级能力(MMIO、特权指令、中断), +但当前无任何汇编层(`lexer`/`parser` 无 asm 语法;汇编只存在于 `rt.s` 手工汇编与 ELF 后端机器码发射)。设计目标(用户原话): - **不安全隔离**:特权操作隔离在受控区域 -- **能够验证绝大多数**:普通级指令全部 + 特权级用法可自动验证 -- **跨平台统一**:不同平台指令不同——统一指令集 + 平台映射表解决 +- **能够验证绝大多数**:普通级指令全部可自动验证,特权级用法亦可自动验证 +- **跨平台统一**:平台间指令不同——以统一指令集 + 平台映射表解决 ## 2. 设计原则 ### 2.1 统一指令集 + 无限虚拟寄存器 -- `.crasm` 是**新生态**(无旧代码兼容义务)——统一指令集可用 -- 虚拟寄存器 `%0, %1, ...` 无上限——写的人不管平台寄存器数,ISA 后端自动分配 +- `.crasm` 是**新生态**(无旧代码兼容义务)——统一指令集因此可用 +- 虚拟寄存器 `%0, %1, ...` 无上限——书写者无需关心平台寄存器数量,由 ISA 后端自动分配 (复用现有 `opt.cr alloc_registers` 线性扫描分配器) -- 平台映射表(普通 + 特权指令)翻译到真实 ISA +- 平台映射表(普通 + 特权指令)负责翻译到真实 ISA ### 2.2 难写原则(刻意限制) -`.crasm` 刻意保持"不好写"——这是特性不是缺陷: +`.crasm` 刻意保持"不好写"——这是特性而非缺陷: -- 寄存器强制 `%0/%1` 编号(不命名)——代码难维护 → 自然阻止长汇编程序 -- 复杂逻辑写不出也写不进——复杂逻辑属于 Core 层 +- 寄存器强制 `%0/%1` 编号(不命名)——代码难以维护 → 自然阻止长汇编程序 +- 复杂逻辑既写不出也写不进——复杂逻辑属于 Core 层 - 汇编层保持薄:意图纯粹、滥用防护、验证聚焦 -- **代码越简单越容易验证**——限制可写性就是保障可验证性 +- **代码越简单越容易验证**——限制可写性即保障可验证性 ### 2.3 生态边界 - `.crasm` 新代码按统一指令集写,无兼容义务 -- 旧 .c/汇编代码原样保留(不迁移)——互不干扰 +- 旧 `.c`/汇编代码原样保留(不迁移)——互不干扰 ## 3. 架构 @@ -89,7 +89,7 @@ extern fn port_read(addr: u64) fn port_read(addr: u64) -> u8 { | 普通级 | 数据传输/算术/分支/内存操作/地址计算 | **自动验证**:寄存器生命周期 + 地址 provenance/边界(复用现有指针模型 pass)——"绝大多数可验证" | | 特权级 | mmio/barrier/irq/swap_context/halt | **用法验证**(自动):参数类型/宽度、放置规则、指令间约束(固定集 → 可形式化);**副作用隔离**(unsafe 边界):硬件行为/时序超出编译期验证范围,人工保证 | -### 5.2 寄存器生命周期规则(新 pass,.crasm 专用) +### 5.2 寄存器生命周期规则(新 pass,`.crasm` 专用) | 规则 | 检查内容 | 违反示例 | |---|---|---| @@ -119,7 +119,7 @@ unsafe fn port_write(addr: u64, val: u8) { ## 6. 交互接口 -### 6.1 .cr ↔ .crasm +### 6.1 `.cr` ↔ `.crasm` ```cr extern fn port_read(addr: u64) -> u8; // .cr 侧:C ABI 先例 @@ -137,7 +137,7 @@ src/arch/ └── riscv/ → 同接口,不同映射 ``` -映射表 = 每平台一份"统一指令 → 真实指令"翻译表(编译器后端的一部分,机械翻译——与现有 `src/arch/linux/ld/` 后端同构)。特权指令映射在表内固定(mmio_read → x86 mov / arm ldr)——映射正确性由固定表保证。 +映射表 = 每平台一份"统一指令 → 真实指令"翻译表(编译器后端的一部分,机械翻译——与现有 `src/arch/linux/ld/` 后端同构)。特权指令映射在表内固定(`mmio_read` → x86 `mov` / arm `ldr`)——映射正确性由固定表保证。 ### 6.3 编译流程 @@ -164,7 +164,7 @@ src/arch/ 2. 寄存器生命周期 pass + 测试 3. 特权约束表 + 用法验证 + unsafe 隔离 4. x86-64 映射表(翻译器)+ 字节级测试 -5. .cr extern 接口接线 + 端到端 +5. `.cr` extern 接口接线 + 端到端 6. (后补)ARM64/RISC-V 映射表 ### 7.3 明确不做(YAGNI) diff --git a/docs/superpowers/specs/2026-08-08-error-codes-design.md b/docs/superpowers/specs/2026-08-08-error-codes-design.md index eae1f5aa..8919aa1f 100644 --- a/docs/superpowers/specs/2026-08-08-error-codes-design.md +++ b/docs/superpowers/specs/2026-08-08-error-codes-design.md @@ -7,10 +7,10 @@ ### 1.1 现状问题 -- 错误码 145 条平铺分段(L/P/N/I/TA/TF/TB/TU/TC/TM/TK/TS/TG/B/R/E/ICE),**维度混杂无层级**:L/P/N/I 是编译阶段,TA/TF 是类型子系统,B 是借用,R 是运行时 -- **同性质分散**:"类型不匹配"因上下文不同分裂在 TA01/TF07/TS03/TM07 四个段 +- 错误码 145 条平铺分段(`L`/`P`/`N`/`I`/`TA`/`TF`/`TB`/`TU`/`TC`/`TM`/`TK`/`TS`/`TG`/`B`/`R`/`E`/`ICE`),**维度混杂无层级**:`L`/`P`/`N`/`I` 是编译阶段,`TA`/`TF` 是类型子系统,`B` 是借用,`R` 是运行时 +- **同性质分散**:"类型不匹配"因上下文不同分裂在 `TA01`/`TF07`/`TS03`/`TM07` 四个段 - **无严重度维度**:无法支撑致命/警告决策(PR #23 诊断致命化争论的根源) -- 编译器自身源码有数百条类型检查诊断(dyn_arr.cr 156 条等),致命化会让自举失败 +- 编译器自身源码有数百条类型检查诊断(`dyn_arr.cr` 156 条等),致命化会让自举失败 ### 1.2 心理学/人因研究依据 @@ -23,9 +23,9 @@ ### 1.3 设计原则(brainstorming 定稿) 1. **人机双读分离**:码值给机器(唯一、稳定、可解析),渲染给人(快速锁定、可读)——两层独立设计 -2. **severity 可靠编码 = 词**:error/warning/note 词是唯一可靠编码(终端变色、色弱不影响);颜色仅增强 +2. **severity 可靠编码 = 词**:`error`/`warning`/`note` 词是唯一可靠编码(终端变色、色弱不影响);颜色仅增强 3. **类别单字母快速锁定**:码的字母段只表达类别(第一性原理:锁类别,理解靠消息);子类信息在消息里 -4. **同性质聚合**:类型系 8 段合并为 T 类 +4. **同性质聚合**:类型系 8 段合并为 `T` 类 ## 2. 码值结构(机器层) @@ -53,7 +53,7 @@ ### 2.2 序号 -- 类别内唯一,5 位(00001-99999)——为未来图分析提示(匹配度/业务逻辑建议,大量 N 类提示)留足空间 +- 类别内唯一,5 位(00001-99999)——为未来图分析提示(匹配度/业务逻辑建议,大量 `N` 类提示)留足空间 - 序号无语义(不编码检查点),检查点信息在消息文本中 ### 2.3 severity 不在码内 @@ -84,7 +84,7 @@ error[T00001] cannot assign string to int - 颜色仅增强:词按 severity 着色(红/黄/蓝);类别位可加粗(与序号区分,形态主题免疫) - 位置行 `--> file:line:col` 灰色(现有格式延续) - 源码上下文行 + `^^^` 标注(现有格式延续) -- 消息简短(可读性四因素:短、无行话、建设性措辞;不用 illegal/offending/fatal 语气词) +- 消息简短(可读性四因素:短、无行话、建设性措辞;不用 `illegal`/`offending`/`fatal` 语气词) ### 3.2 示例 @@ -110,12 +110,12 @@ note[F00001] loop condition always true (match 100%) - 语法/语义正确性错误 → Error(编译必须失败) - 设计警告/可运行代码的风格性问题 → Warning -- 编译器自身源码现存数百条诊断(TC02 等)→ Warning(否则自举失败) +- 编译器自身源码现存数百条诊断(`TC02` 等)→ Warning(否则自举失败) - 提示类(未来图分析)→ Note ### 5.2 逐条归属(原码 → 新码 → severity) -**L 词法(→ L 类)**——全部 Error: +**`L` 词法(→ `L` 类)**——全部 Error: | 原码 | 新码 | 消息 | |---|---|---| | L001 | L00001 | Unterminated string literal | @@ -130,11 +130,11 @@ note[F00001] loop condition always true (match 100%) | L010 | L00010 | Invalid float suffix | | L011 | L00011 | Unknown character | -**S 语法(→ S 类)**——全部 Error:P001-019 → S00001-00019(按原序) -**U 名字(→ U 类)**——全部 Error:N001-021 → U00001-00021(按原序) -**I 推断(→ T 类)**——全部 Error:I001-006 → T00001-00006(接在 TA 系前) +**`S` 语法(→ `S` 类)**——全部 Error:`P001-019` → `S00001-00019`(按原序) +**`U` 名字(→ `U` 类)**——全部 Error:`N001-021` → `U00001-00021`(按原序) +**`I` 推断(→ `T` 类)**——全部 Error:`I001-006` → `T00001-00006`(接在 TA 系前) -**T 类型(→ T 类)**: +**`T` 类型(→ `T` 类)**: | 原段 | severity | 新码 | |---|---|---| | TA01-07 | Error | T00007-00013 | @@ -146,9 +146,9 @@ note[F00001] loop condition always true (match 100%) | TK01-08 | Error | T00056-00063 | | I001-006 | Error | T00001-00006 | -**G 泛型(→ G 类)**——全部 Error:TG01-02 → G00001-00002 -**B 借用(→ B 类)**——全部 Error:B001-004/B010-011/B020-022 → B00001-00010(按原序) -**F 控制流(→ F 类)**: +**`G` 泛型(→ `G` 类)**——全部 Error:`TG01-02` → `G00001-00002` +**`B` 借用(→ `B` 类)**——全部 Error:`B001-004`/`B010-011`/`B020-022` → `B00001-00010`(按原序) +**`F` 控制流(→ `F` 类)**: | 原码 | severity | 新码 | 理由 | |---|---|---|---| | TC01 | Error | F00001 | if 条件非 bool——真错误 | @@ -159,7 +159,7 @@ note[F00001] loop condition always true (match 100%) | TC06 | Error | F00006 | break 在循环外 | | TC07 | Error | F00007 | continue 在循环外 | -**R 运行时(→ R 类)**: +**`R` 运行时(→ `R` 类)**: | 原码 | severity | 新码 | 理由 | |---|---|---|---| | R001 | Error | R00001 | 编译期除零 | @@ -167,20 +167,20 @@ note[F00001] loop condition always true (match 100%) | R003 | Error | R00003 | 编译期溢出 | | R004 | Warning | R00004 | 数值转换损失精度——警告性质 | -**O IO(→ O 类)**——全部 Error:E001-004 → O00001-00004 -**I 内部(→ I 类)**——全部 Error:ICE01-03 → I00001-00003 +**`O` IO(→ `O` 类)**——全部 Error:`E001-004` → `O00001-00004` +**`I` 内部(→ `I` 类)**——全部 Error:`ICE01-03` → `I00001-00003` ### 5.3 自举可行性 -编译器自身源码现有诊断(dyn_arr.cr 156 条等)在归属表下均为 Warning(TC02 类)→ `check` 不失败 → 自举不阻塞。PR #23 的"诊断致命化"以"severity 字段 + 退出码判定"替代(N001 类 Undefined name → U 类 Error → 致命,测试断言成立)。 +编译器自身源码现有诊断(`dyn_arr.cr` 156 条等)在归属表下均为 Warning(`TC02` 类)→ `check` 不失败 → 自举不阻塞。PR #23 的"诊断致命化"以"severity 字段 + 退出码判定"替代(`N001` 类 Undefined name → `U` 类 Error → 致命,测试断言成立)。 ## 6. 迁移路径 -1. 诊断记录 32→40B:+severity 字段、+file_id 字段(corelsp 需求) +1. 诊断记录 32→40B:+severity 字段、+`file_id` 字段(`corelsp` 需求) 2. `check_error(code, msg, line, col)` → 新签名 `check_error(sev, code, msg, line, col)`(调用点机械替换) -3. 错误码常量重命名:`EC_N_UNDEFINED` → `EC_U_UNDEFINED` 等(以 ast.cr/diag.cr 实际常量名为准) -4. print_diagnostics 输出格式:`error[L001]:` → `error[T00001]:` -5. error-codes.md 重写为本规格的映射表 +3. 错误码常量重命名:`EC_N_UNDEFINED` → `EC_U_UNDEFINED` 等(以 `ast.cr`/`diag.cr` 实际常量名为准) +4. `print_diagnostics` 输出格式:`error[L001]:` → `error[T00001]:` +5. `error-codes.md` 重写为本规格的映射表 6. `--fatal-warnings` flag 7. 全量回归 + 自举 O0/O1 @@ -189,4 +189,4 @@ note[F00001] loop condition always true (match 100%) - 消息模板参数化/本地化(保留现有英文消息,仅换码) - LLM 生成解释(研究显示[效果不一致](https://searchworks-lb.stanford.edu/articles/edsarx__edsarx.2409.18661),专家手写结构最佳) - 修复建议/quick-fix 数据(未来图分析提示阶段) -- LSP 的 severity 渲染(corelsp 消费端自映射) +- LSP 的 severity 渲染(`corelsp` 消费端自映射) diff --git a/docs/superpowers/specs/2026-08-08-lsp-design.md b/docs/superpowers/specs/2026-08-08-lsp-design.md index 407a8341..ddad4522 100644 --- a/docs/superpowers/specs/2026-08-08-lsp-design.md +++ b/docs/superpowers/specs/2026-08-08-lsp-design.md @@ -5,20 +5,21 @@ ## 1. 背景与目标 -Core 语言的前端(自举编译器 corec)已具备完整的 lexer / parser / type checker, -诊断数据结构(g_diags:错误码、消息、行、列)健全,类型检查错误非致命。 -当前编辑器支持仅为"浅层":nvim 保存时 shell 调 corec 解析输出进 quickfix、 -VS Code 只有 tmLanguage 高亮、Zed 只有 tree-sitter。无 LSP。 +Core 语言的前端(自举编译器 `corec`)已具备完整的 `lexer` / `parser` / `type checker`, +诊断数据结构(`g_diags`:错误码、消息、行、列)健全,类型检查错误非致命。 +当前编辑器支持仅为"浅层":`nvim` 在保存时以 shell 调用 `corec` 并将解析输出送进 `quickfix`、 +`VS Code` 仅有 `tmLanguage` 高亮、`Zed` 仅有 `tree-sitter`。当前无 LSP 支持。 -目标:写一个 **Core 自举的 LSP 服务器**(吃自己的狗粮)——用 Core 语言本身实现, -直接复用自举编译器的前端模块。v1 覆盖全家桶功能: -diagnostics / hover / go-to-definition / completion / documentSymbol / semanticTokens。 +目标:实现一个 **Core 自举的 LSP 服务器**(以 Core 语言实现自身的编辑器工具链), +用 Core 语言本身编写,直接复用自举编译器的前端模块。 +v1 覆盖全部功能项: +`diagnostics` / `hover` / `go-to-definition` / `completion` / `documentSymbol` / `semanticTokens`。 已确认的决策: -- **实现语言**:Core 自举(复用 src/compiler/ 前端模块) -- **二进制形态**:独立 corelsp 二进制(与 corearch 同模式),非 corec 子命令 +- **实现语言**:Core 自举(复用 `src/compiler/` 前端模块) +- **二进制形态**:独立 `corelsp` 二进制(与 `corearch` 同模式),非 `corec` 子命令 - **进程模型**:长期进程,进程内重跑前端检查(非 spawn 子进程) -- **客户端**:只做服务器,VS Code / nvim 客户端配置后补 +- **客户端**:本设计仅实现服务器端,`VS Code` / `nvim` 客户端配置后补 ## 2. 架构 @@ -36,57 +37,57 @@ src/lsp/ ### 2.2 构建 -`build_selfhost_native.py` 加第三段 build 调用(复用现有 build 函数, -`wrapper_fn='lsp_main'`),产出 `build/corelsp`。与 corearch 完全相同的先例。 +`build_selfhost_native.py` 增加第三段 build 调用(复用现有 build 函数, +`wrapper_fn='lsp_main'`),产出 `build/corelsp`。该方式沿用与 `corearch` 完全相同的先例。 ### 2.3 关键约束 -- **stdout 是协议通道**:检查管线必须走"静默版"——直接调 +- **stdout 是协议通道**:检查管线必须走"静默版",即直接调用 `tokenize → res_imports → parse_all → check_all`,不能复用 `run_frontend()` - (其含 `println("[1/5]...")` 进度输出)。日志走 stderr。 -- **只跑前端**:到 `check_all` 为止,不生成 IR(`corec check` 命令已验证此路径)。 + (其含 `println("[1/5]...")` 进度输出)。日志输出到 stderr。 +- **只跑前端**:检查到 `check_all` 为止,不生成 IR(`corec check` 命令已验证此路径)。 ## 3. 生命周期与全局状态重置 -进程内重跑检查是唯一硬骨头。 +进程内重跑检查是本设计唯一的难点。 ### 3.1 重置策略 每轮检查前调用 `reset_frontend_state()`(新增,集中列出全部清零项): -- **重置(清 count,保留 cap)**:`g_tokens` / `g_ast` / `g_errors` / `g_diags` / +- **重置(清除 count,保留 cap)**:`g_tokens` / `g_ast` / `g_errors` / `g_diags` / `g_block_stmts`、符号表(`g_funcs` / `g_structs` / `g_enums` / `g_syms` / `g_types` / `g_ifaces` / `g_methods` / `g_type_aliases` / `g_generic_constr` / `g_gen_params` 等)、检查器临时状态(`g_scope_bounds` / `g_borrow_*` / `g_alloc_pts` 等)、`g_files` / `g_mods` - **不重置**:字符串驻留表 `g_strs` / `g_str_hash`(跨检查存活,内容去重,内存收敛) -清 count 保留 cap:缓冲容量复用,避免每轮重新分配。 -`reset_frontend_state()` 放 globals.cr 旁边,一处管理,避免漏网。 +清除 count 而保留 cap:缓冲容量得以复用,避免每轮重新分配。 +`reset_frontend_state()` 置于 `globals.cr` 旁边,集中管理,避免遗漏。 ### 3.2 已知代价 -bump allocator 不回收,字符串内容泄漏到进程退出;内存上限 ≈ -会话内唯一字符串总量 + 各缓冲峰值。数小时编辑会话量级几十 MB,可接受。 +`bump allocator` 不回收内存,字符串内容泄漏至进程退出;内存上限 ≈ +会话内唯一字符串总量 + 各缓冲峰值。数小时编辑会话的量级为几十 MB,可以接受。 ### 3.3 验证手段 -集成测试连续两次检查——第二次故意改出错误,断言诊断被更新 -(专门抓"重置漏项 → 幽灵诊断")。 +集成测试执行连续两次检查,第二次故意改出错误,断言诊断被更新 +(专门检测"重置漏项 → 幽灵诊断")。 ## 4. 诊断记录扩展 -diag 记录当前为 32 字节(error_code / msg_ptr / line / col),**无文件 ID**。 -多文件项目诊断无法按文件分发 → 需给 `g_diags` 记录加 file_id 字段 -(32→40 字节),与已有的 `g_files` 文件表(module.cr)配套。 +`diag` 记录当前为 32 字节(`error_code` / `msg_ptr` / `line` / `col`),**无文件 ID**。 +多文件项目的诊断无法按文件分发,因此需给 `g_diags` 记录增加 `file_id` 字段 +(32→40 字节),与已有的 `g_files` 文件表(`module.cr`)配套。 `print_diagnostics()` 同步适配(保持现有输出格式不变)。 ## 5. 协议层与文档状态 -### 5.1 帧循环(rpc.cr) +### 5.1 帧循环(`rpc.cr`) - 读:`read(0, buf, 4096)` 循环 → 解析 `Content-Length: N\r\n\r\n` 头 → 读满 N 字节 - (`syscall3(0, 0, buf, n)`,rt.s 零改动) + (`syscall3(0, 0, buf, n)`,`rt.s` 零改动) - 写:`syscall3(1, 1, s, len)` 组装帧写出 - 分发:方法名 → 处理器映射 @@ -101,10 +102,10 @@ diag 记录当前为 32 字节(error_code / msg_ptr / line / col),**无文 ### 5.3 文档状态与检查触发 - `g_open_docs`:路径 → 最新缓冲区内容;`textDocumentSync = 1`(全量同步,v1 不做增量 diff) -- **didChange 同步重跑检查**(~100ms,在请求处理内完成),随后 `publishDiagnostics` - 发布**所有有诊断的文件**(检查是整项目的;编辑 A 文件可能影响导入它的 B 文件—— +- **`didChange` 同步重跑检查**(~100ms,在请求处理内完成),随后由 `publishDiagnostics` + 发布**所有有诊断的文件**(检查是整项目的;编辑 A 文件可能影响导入它的 B 文件, 全量发布最简单且正确) -- 打开文件的源文本**从缓冲区取,不走磁盘**:module.cr 导入读取路径加 helper—— +- 打开文件的源文本**从缓冲区取,不走磁盘**:`module.cr` 导入读取路径增加 helper, 先查 `g_open_docs`,未打开才读盘。支持多文件同时编辑 - 检查产物只保留:诊断(带 file ID)、符号表(`g_funcs`/`g_structs`/`g_syms`/...)、 令牌流(`g_tokens`,带 line/col/kind)。查询全部基于这三者,不依赖 IR @@ -116,7 +117,7 @@ diag 记录当前为 32 字节(error_code / msg_ptr / line / col),**无文 ## 6. 查询功能 -五个功能全部走同一模式:**位置 → 令牌查找 → 符号表查询**(analysis.cr 一个模块)。 +五个功能全部采用同一模式:**位置 → 令牌查找 → 符号表查询**(`analysis.cr` 单个模块)。 | 功能 | 逻辑 | |------|------| @@ -127,16 +128,16 @@ diag 记录当前为 32 字节(error_code / msg_ptr / line / col),**无文 | `semanticTokens` | 令牌流 → tokenType 映射(keyword/type/function/variable/comment/string)→ 差分编码(相对行/列/长度)。**tokenType 分类以实际 token kind 为准**,不以语言文档为准 | **所有查询查"最后一次成功检查"的快照,查询本身不触发检查** -(检查只由 didChange/didOpen 驱动)——LSP 标准异步模型,hover 延迟稳定在个位数毫秒。 +(检查只由 `didChange`/`didOpen` 驱动),符合 LSP 标准异步模型,`hover` 延迟稳定在个位数毫秒。 ## 7. 错误处理 - JSON-RPC 错误码按规范:`-32700` 解析错误 / `-32601` 方法不存在 / `-32602` 参数无效 - (如 hover 缺 position) + (如 `hover` 缺少 `position`) - `initialize` 之前收到其他请求:回 `-32602` 并继续 -- 服务器崩溃(编译器自身 bug):v1 不设防——客户端自动重启 LSP 进程 - (VS Code/nvim 内置行为)。panic handler 是否接 stderr 日志放实现阶段定 -- 文件读不到/解析失败:按编译器现有行为(`g_diags` 非致命)继续,不崩 +- 服务器崩溃(编译器自身 bug):v1 不设防,由客户端自动重启 LSP 进程 + (`VS Code`/`nvim` 内置行为)。panic handler 是否接 stderr 日志放实现阶段定 +- 文件读不到或解析失败:按编译器现有行为(`g_diags` 非致命)继续,不崩溃 ## 8. 测试(三层) @@ -146,7 +147,7 @@ diag 记录当前为 32 字节(error_code / msg_ptr / line / col),**无文 | 重置回归 | 集成测试内嵌 | 连续两次检查,第二次故意改错,断言诊断更新(抓幽灵诊断) | | LSP 集成 | `tests/selfhost/test_lsp.py` | Python 模拟客户端:spawn `build/corelsp`,按协议发 initialize → didOpen → hover/definition/completion/documentSymbol/semanticTokens,断言响应 JSON 字段 | -集成测试是标准做法(LSP 服务器都这么测),同时即协议级文档。 +集成测试是 LSP 服务器的标准做法,同时兼作协议级文档。 ## 9. v1 明确不做(YAGNI) @@ -154,24 +155,24 @@ diag 记录当前为 32 字节(error_code / msg_ptr / line / col),**无文 - 代码格式化 - rename / 重构 - workspace 级符号搜索 -- 跨文件 goto-def 的精确类型解析(v1 符号表按名字查,同名符号可能跳错——TODO 注明,后补作用域精确化) +- 跨文件 goto-def 的精确类型解析(v1 符号表按名字查,同名符号可能跳错,TODO 注明,后补作用域精确化) - UTF-16 列偏移(字节近似,TODO) ## 10. 里程碑 -1. json.cr + JSON 单元测试 -2. rpc.cr 帧循环 + 生命周期握手(initialize/shutdown/exit) -3. 静默检查管线 + `reset_frontend_state()` + diag file_id + publishDiagnostics -4. hover + go-to-definition -5. completion + documentSymbol -6. semanticTokens -7. 集成测试套件 + 构建脚本第三段(corelsp 二进制) -8. (后补)VS Code / nvim 客户端配置 +1. `json.cr` + JSON 单元测试 +2. `rpc.cr` 帧循环 + 生命周期握手(`initialize`/`shutdown`/`exit`) +3. 静默检查管线 + `reset_frontend_state()` + `diag` file_id + `publishDiagnostics` +4. `hover` + go-to-definition +5. `completion` + `documentSymbol` +6. `semanticTokens` +7. 集成测试套件 + 构建脚本第三段(`corelsp` 二进制) +8. (后补)`VS Code` / `nvim` 客户端配置 ## 11. 风险与 TODO 清单 -- [ ] 全局重置遗漏 → 幽灵诊断(缓解:reset 集中管理 + 重置回归测试) +- [ ] 全局重置遗漏 → 幽灵诊断(缓解:`reset` 集中管理 + 重置回归测试) - [ ] 驻留表内存增长(接受,上限 ≈ 会话唯一字符串总量) - [ ] 中文注释错误列偏移(UTF-16 转换后补) - [ ] 同名符号跨文件跳转可能不准(作用域精确化后补) -- [ ] **仓库文档部分已过时**(CHANGELOG 止于 2026-06-21、DEBUG_REPORT 止于 2026-07-06、grammar/tokens.ebnf 关键字表与 lexer.cr 不符且无 @ 内建覆盖、pointer-model 等"当前状态"段与实现不符)——实现时以源码为准(关键字表唯一依据 `lexer.cr lookup_keyword()`;@ 内建名单唯一依据 `checker.cr` EXPR_AT 分发),文档仅作设计参考 +- [ ] **仓库文档部分已过时**(`CHANGELOG` 止于 2026-06-21、`DEBUG_REPORT` 止于 2026-07-06、`grammar/tokens.ebnf` 关键字表与 `lexer.cr` 不符且无 `@` 内建覆盖、`pointer-model` 等"当前状态"段与实现不符)——实现时以源码为准(关键字表唯一依据 `lexer.cr lookup_keyword()`;`@` 内建名单唯一依据 `checker.cr` EXPR_AT 分发),文档仅作设计参考 diff --git a/docs/superpowers/specs/2026-08-08-pseudocode-tdd-design.md b/docs/superpowers/specs/2026-08-08-pseudocode-tdd-design.md index 36e2ac4f..cd58387d 100644 --- a/docs/superpowers/specs/2026-08-08-pseudocode-tdd-design.md +++ b/docs/superpowers/specs/2026-08-08-pseudocode-tdd-design.md @@ -9,7 +9,7 @@ 用途(按优先级): 1. **TDD 主导**:伪代码内嵌每个函数的「测试要点」,作为后续编写测试的行为依据 -2. **形式化基础**(远期):伪代码必须信息完整、无歧义,之后要支撑完全形式化(.csp/.csr/.corespec 方向) +2. **形式化基础**(远期):伪代码必须信息完整、无歧义,之后要支撑完全形式化(`.csp`/`.csr`/`.corespec` 方向) ## 二、范围 @@ -17,7 +17,7 @@ - `src/compiler/*.cr`(29 个) - `src/stdlib/*.cr`(18 个) -- `src/runtime/*.cr`(2 个:rt.cr、arena_globals.cr) +- `src/runtime/*.cr`(2 个:`rt.cr`、`arena_globals.cr`) - `src/arch/linux/ld/*.cr`(7 个) **明确排除**(在 README 中注明):`rt.s`(汇编)、`rt.ccr`(编译产物)、`bootstrap.c`/`compiler_rt.c`(C 代码)、`tests/`、`examples/` —— 均非 Core 语言源码。 @@ -34,7 +34,7 @@ docs/pseudocode/ └── arch/linux/ld/ ← 7 个源文件 → 11 个 .md ``` -**大文件拆分规则**(用户补充要求,2026-08-08):源文件 ≥800 行时,其伪代码拆为多个部分文档 `<源名>-<序号>.md`(序号从 1 连续),每部分覆盖一个逻辑相关的函数组,伪代码量约 400-600 行;每部分独立使用下方骨架;拆分不改变全量逐语句要求。命中拆分:parser(4 部分)、checker(5 部分)、ir_gen(4 部分)、arch/elf(4 部分)、instr(3 部分)。文档总数:56 源文件 → 71 个 .md。 +**大文件拆分规则**(用户补充要求,2026-08-08):源文件 ≥800 行时,其伪代码拆为多个部分文档 `<源名>-<序号>.md`(序号从 1 连续),每部分覆盖一个逻辑相关的函数组,伪代码量约 400-600 行;每部分独立使用下方骨架;拆分不改变全量逐语句要求。命中拆分:`parser`(4 部分)、`checker`(5 部分)、`ir_gen`(4 部分)、`arch/elf`(4 部分)、`instr`(3 部分)。文档总数:56 源文件 → 71 个 .md。 **每个文件文档的骨架**: @@ -84,7 +84,7 @@ docs/pseudocode/ - 所有标识符(全局、函数、结构、枚举、字段、局部变量)译成中文语义名;**首次出现**写作 `中文名(原名)`,之后只用中文名 - 共享标识符(`g_*` 全局、公开函数、结构名)必须以《标识符对照表》为准,**禁止自造** -- 内置类型:整数(int)、字符串(string)、布尔(bool)、字节(byte)、浮点数(float);自定义类型按标识符规则 +- 内置类型:整数(`int`)、字符串(`string`)、布尔(`bool`)、字节(`byte`)、浮点数(`float`);自定义类型按标识符规则 ### 4.3 格式约定 @@ -113,7 +113,7 @@ docs/pseudocode/ ## 五、详细程度与测试要点 -**全量逐语句翻译**(用户修订,2026-08-08):所有函数均逐语句展开为缩进式伪代码,不做概括;仅空文件与纯引入文件(entry.cr、_import.cr、linker.cr 等)可两三句话带过。理由:之后要做完全形式化,信息不可省略。 +**全量逐语句翻译**(用户修订,2026-08-08):所有函数均逐语句展开为缩进式伪代码,不做概括;仅空文件与纯引入文件(`entry.cr`、`_import.cr`、`linker.cr` 等)可两三句话带过。理由:之后要做完全形式化,信息不可省略。 **作用说明**(用户补充要求,2026-08-08):每个函数节除伪代码与测试要点外,必须有 `### 作用` 小节——用自然语言说明该函数的职责、在编译管线/模块中的位置、输入输出语义。与逐语句「逻辑」区分:作用是"为什么和干什么",逻辑是"怎么做"。 @@ -145,16 +145,16 @@ docs/pseudocode/ | 9 | arch/linux/ld 全部 7 个文件 | 3,640 | | 10 | runtime 2 个文件 + README.md 总索引 | 18 | -约束:每个 agent 只读自己的源文件 + 术语表,只写自己的 .md,不碰其他文件。 +约束:每个 agent 只读自己的源文件 + 术语表,只写自己的 `.md`,不碰其他文件。 ## 八、质量控制与完成标准 -1. **机械校验**:grep 检查全部 .md —— 伪代码正文禁止 `{` `}` `;` 及英文关键字独立词(`if`/`while`/`return`/`fn` 等) +1. **机械校验**:`grep` 检查全部 `.md` —— 伪代码正文禁止 `{` `}` `;` 及英文关键字独立词(`if`/`while`/`return`/`fn` 等) 2. **术语一致性**:脚本比对每个文件的对照表与全局术语表(共享标识符必须一致) 3. **测试要点抽查**:每个函数节都有「测试要点」;抽查 20% 的边界条件合理性 -4. **完成标准**:71 个 .md 全产出(56 源文件全覆盖,含 5 个大文件拆分)+ 上述校验通过 +4. **完成标准**:71 个 `.md` 全产出(56 源文件全覆盖,含 5 个大文件拆分)+ 上述校验通过 ## 九、后续阶段(不在本次范围) - 从伪代码推导正式测试用例(TDD 落地) -- 伪代码 → 形式化规约(.csp/.csr/.corespec)转换,伪代码作为人类可读的规约层 +- 伪代码 → 形式化规约(`.csp`/`.csr`/`.corespec`)转换,伪代码作为人类可读的规约层 diff --git a/docs/superpowers/specs/2026-08-08-pseudocode-tdd-design.md.tmp.48271.a358599c902c b/docs/superpowers/specs/2026-08-08-pseudocode-tdd-design.md.tmp.48271.a358599c902c new file mode 100644 index 00000000..5bc61534 --- /dev/null +++ b/docs/superpowers/specs/2026-08-08-pseudocode-tdd-design.md.tmp.48271.a358599c902c @@ -0,0 +1,160 @@ +# Core 源码全量伪代码翻译设计(TDD + 形式化基础) + +日期:2026-08-08 +状态:已获用户逐节认可 + +## 一、背景与目标 + +将 Core 语言全部 `.cr` 源码(56 个文件,19,749 行)翻译为**无任何编程语言关键字的汉语伪代码**,每个文件对应一份 Markdown 文档,镜像源码目录结构。 + +用途(按优先级): +1. **TDD 主导**:伪代码内嵌每个函数的「测试要点」,作为后续编写测试的行为依据 +2. **形式化基础**(远期):伪代码必须信息完整、无歧义,之后要支撑完全形式化(`.csp`/`.csr`/`.corespec` 方向) + +## 二、范围 + +**翻译对象**(`src/` 下全部 `.cr` 文件,共 56 个): + +- `src/compiler/*.cr`(29 个) +- `src/stdlib/*.cr`(18 个) +- `src/runtime/*.cr`(2 个:rt.cr、arena_globals.cr) +- `src/arch/linux/ld/*.cr`(7 个) + +**明确排除**(在 `README` 中注明):`rt.s`(汇编)、`rt.ccr`(编译产物)、`bootstrap.c`/`compiler_rt.c`(C 代码)、`tests/`、`examples/`,上述各项均非 Core 语言源码。 + +## 三、目录结构 + +``` +docs/pseudocode/ +├── README.md ← 总索引 + 约定速查 + 范围说明 +├── 标识符对照表.md ← 全局术语表(共享标识符中英对照) +├── compiler/ ← 29 个源文件 → 39 个 .md +├── stdlib/ ← 18 个 .md +├── runtime/ ← 2 个 .md +└── arch/linux/ld/ ← 7 个源文件 → 11 个 .md +``` + +**大文件拆分规则**(用户补充要求,2026-08-08):源文件 ≥800 行时,其伪代码拆为多个部分文档 `<源名>-<序号>.md`(序号从 1 连续),每部分覆盖一个逻辑相关的函数组,伪代码量约 400-600 行;每部分独立使用下方骨架;拆分不改变全量逐语句要求。命中拆分:`parser`(4 部分)、`checker`(5 部分)、`ir_gen`(4 部分)、`arch/elf`(4 部分)、`instr`(3 部分)。文档总数:56 源文件 → 71 个 `.md`。 + +**每个文件文档的骨架**: + +```markdown +# <文件名> 伪代码 +> 源文件:src/…/<文件名>(N 行) +> 功能概要:两句话说明该文件干什么 + +## 标识符对照表 +(表格:中文名 | 原名 | 首次出现函数) + +## 全局状态 +(该文件涉及的全局变量,逐条说明含义与初始值) + +## 函数 <中文名(原名)> +### 作用 +(自然语言解释:该函数在编译管线/模块中的职责、为什么存在、输入输出的语义) +### 逻辑 +(缩进式伪代码,见第四节) +### 测试要点 +1. (编号列表,见第五节) +``` + +## 四、翻译约定 + +### 4.1 关键字替换表 + +| 源码 | 伪代码 | +|------|--------| +| `if` / `else` | 如果 条件,那么:… / 否则:… | +| `else if` | 否则如果 条件,那么:… | +| `while` | 循环(当 条件 成立时):… | +| `for` | 对 集合 遍历(每次取 元素):… | +| `break` / `continue` | 跳出循环 / 继续下一次循环 | +| `return` | 返回 | +| `match` | 匹配 值:… 分支 值,那么:… | +| `fn` / `struct` / `enum` | 函数 / 结构 / 枚举 | +| `:=` / `: type =` | 令 名字 = 值(声明) | +| `mut` / `pub` / `import` | 可变 / 公开 / 引入 | +| `true` / `false` / `None` | 真 / 假 / 无值(None) | +| `and` / `or` / `not` | 且 / 或 / 非 | +| `==` `!=` `<` `<=` `>` `>=` | 等于 / 不等于 / 小于 / 不大于 / 大于 / 不小于 | +| `+ - * / %` 及位运算 | **保留符号**(语言中性的通用符号) | +| 源码注释 | 译成中文,保留在对应位置 | + +### 4.2 标识符规则(首次中英对照) + +- 所有标识符(全局、函数、结构、枚举、字段、局部变量)译成中文语义名;**首次出现**写作 `中文名(原名)`,之后只用中文名 +- 共享标识符(`g_*` 全局、公开函数、结构名)必须以《标识符对照表》为准,**禁止自造** +- 内置类型:整数(`int`)、字符串(`string`)、布尔(`bool`)、字节(`byte`)、浮点数(`float`);自定义类型按标识符规则 + +### 4.3 格式约定 + +- 4 空格缩进,嵌套层级与源码一一对应 +- 条件块:`如果 条件,那么:` 后换行缩进;`否则:` 同层 +- 循环:`循环(当 条件 成立时):` 或 `对 列表 遍历:` +- 解引用/取地址 → `解引用(*ptr)` / `取地址(&x)` +- 赋值 → `令 名字 = 值` +- **禁止模糊词**("适当地"、"相应地"、"处理"等无信息量表述);每个分支/循环条件必须写全,包括边界情况 +- 伪代码正文禁用英文关键字与 `{` `}` `;` + +### 4.4 示例 + +``` +函数 检查赋值(check_assign): + 如果 目标 是全局变量,那么: + 返回 + 否则: + 如果 目标 是局部变量 且 目标 未声明,那么: + 报告错误(报错位置:"未声明的变量") + 返回 假 + 否则如果 目标 已冻结,那么: + 报告错误(报错位置:"试图给不可变变量赋值") + 返回 假 +``` + +## 五、详细程度与测试要点 + +**全量逐语句翻译**(用户修订,2026-08-08):所有函数均逐语句展开为缩进式伪代码,不做概括;仅空文件与纯引入文件(`entry.cr`、`_import.cr`、`linker.cr` 等)可两三句话带过。理由:之后要做完全形式化,信息不可省略。 + +**作用说明**(用户补充要求,2026-08-08):每个函数节除伪代码与测试要点外,必须有 `### 作用` 小节,用自然语言说明该函数的职责、在编译管线/模块中的位置、输入输出语义。与逐语句「逻辑」区分:作用是"为什么和干什么",逻辑是"怎么做"。 + +**测试要点**:每个函数下方 `### 测试要点`,编号列表(不用 emoji),内容包括: +- 边界条件(空输入、最大/最小值、溢出、未初始化) +- 代表性输入 → 预期输出 +- 错误路径(报错位置、返回值、部分结果) +- 状态转换(全局变量的变化) +- 简单函数 1-2 条,复杂函数可到 5-8 条 + +## 六、术语表构建(翻译前必做) + +1. 脚本提取全部共享标识符:所有 `g_*` 全局变量、`fn` 函数名、`struct`/`enum` 类型名 +2. 统一分配中文语义名,产出 `docs/pseudocode/标识符对照表.md` +3. 局部变量归各翻译 agent 自行命名(首次出现对照即可) + +## 七、并行分组(10 个 agent 同时开工) + +| Agent | 文件 | 行数 | +|-------|------|------| +| 1 | lexer.cr + parser.cr | 2,084 | +| 2 | checker.cr + ast.cr | 3,033 | +| 3 | ir_gen.cr | 2,032 | +| 4 | dataflow.cr + ccr_io.cr + cir_cache.cr | 1,429 | +| 5 | opt.cr + pass.cr + dyn_arr.cr + interp.cr + dump.cr | 2,053 | +| 6 | main.cr + corearch.cr + module.cr + project.cr + diag.cr + globals.cr + entry.cr + _import.cr + elf.cr + linker.cr | 2,282 | +| 7 | ext_mgr.cr + ext_safety.cr + monomorph.cr + provenance_verify.cr + ptr_analysis.cr + region_check.cr | 1,097 | +| 8 | stdlib 全部 18 个文件 | 2,081 | +| 9 | arch/linux/ld 全部 7 个文件 | 3,640 | +| 10 | runtime 2 个文件 + README.md 总索引 | 18 | + +约束:每个 agent 只读自己的源文件与术语表,只写自己的 `.md`,不修改其他文件。 + +## 八、质量控制与完成标准 + +1. **机械校验**:以 `grep` 检查全部 `.md`,伪代码正文禁止 `{` `}` `;` 及英文关键字独立词(`if`/`while`/`return`/`fn` 等) +2. **术语一致性**:脚本比对每个文件的对照表与全局术语表(共享标识符必须一致) +3. **测试要点抽查**:每个函数节都有「测试要点」;抽查 20% 的边界条件合理性 +4. **完成标准**:71 个 `.md` 全产出(56 源文件全覆盖,含 5 个大文件拆分)+ 上述校验通过 + +## 九、后续阶段(不在本次范围) + +- 从伪代码推导正式测试用例(TDD 落地) +- 伪代码 → 形式化规约(`.csp`/`.csr`/`.corespec`)转换,伪代码作为人类可读的规约层 diff --git a/docs/superpowers/specs/2026-08-08-region-cfg-design.md b/docs/superpowers/specs/2026-08-08-region-cfg-design.md index 135b9824..834f2277 100644 --- a/docs/superpowers/specs/2026-08-08-region-cfg-design.md +++ b/docs/superpowers/specs/2026-08-08-region-cfg-design.md @@ -1,6 +1,6 @@ # RVSDG 式 Region 化控制流设计 -> **术语注记(2026-08-15)**:本规格中的"RVSDG 式"为当时设计路线的真实记录(参考 RVSDG 的嵌套 region 特征);该结构后定名为 **HDFG(Holographic Dataflow Graph)**,术语演进见 docs/project-book.md。正文保留历史原样。 +> **术语注记(2026-08-15)**:本规格中的"RVSDG 式"为当时设计路线的真实记录(参考 RVSDG 的嵌套 region 特征);该结构后定名为 **HDFG(Holographic Dataflow Graph)**,术语演进见 `docs/project-book.md`。正文保留历史原样。 日期:2026-08-08 状态:已批准(brainstorming 会话,五节逐节确认) @@ -11,10 +11,10 @@ 当前控制流是线性 CFG 形态: -- 循环/分支编译为 `IR_LABEL` / `IR_JUMP` / `IR_BRANCH` 指令序列(ir_gen.cr:1147-1268) -- 数据流图(DFNode)只有数据依赖边;label/jump/branch 在图上是孤立节点(ir-schema:无变量输入 → 无边) -- 解释器按图执行(ip 走 `g_df_nodes`),循环靠 `g_label_poses` 位置表跳转——与图执行不兼容,即 TODO.md 预存 bug 第 3 条(for 循环 label/branch 问题) -- 嵌套 region 树已存在(`sg_push/sg_pop`,dataflow.cr:36-64,随 arena 机制生成):SG_FUNC/SG_LOOP/SG_FOR/SG_FLOW/SG_UNSAFE,含 parent/enter/exit/nstart/ncount,但未语义化使用 +- 循环/分支编译为 `IR_LABEL` / `IR_JUMP` / `IR_BRANCH` 指令序列(`ir_gen.cr:1147-1268`) +- 数据流图(`DFNode`)只有数据依赖边;`label`/`jump`/`branch` 在图上是孤立节点(`ir-schema`:无变量输入 → 无边) +- 解释器按图执行(`ip` 走 `g_df_nodes`),循环靠 `g_label_poses` 位置表跳转——与图执行不兼容,即 TODO.md 预存 bug 第 3 条(for 循环 `label`/`branch` 问题) +- 嵌套 region 树已存在(`sg_push/sg_pop`,`dataflow.cr:36-64`,随 arena 机制生成):`SG_FUNC`/`SG_LOOP`/`SG_FOR`/`SG_FLOW`/`SG_UNSAFE`,含 `parent`/`enter`/`exit`/`nstart`/`ncount`,但未语义化使用 ### 1.2 论文依据 @@ -30,19 +30,19 @@ 把现有 SG 子图树升级为 RVSDG 式嵌套 region: 1. 新增 `SG_IF`(条件 region) -2. `g_df_node_region[]` 显式 DFNode→region 映射 +2. `g_df_node_region[]` 显式 `DFNode`→region 映射 3. 解释器循环按 region 迭代执行(根治 TODO #2026-07-25-1) 4. state edges(副作用链 + 循环终止依赖) -5. 序列化 v2(SG 段 + edge kind 进 .cir/.ccr,v1 兼容) +5. 序列化 v2(`SG` 段 + edge `kind` 进 `.cir`/`.ccr`,v1 兼容) 6. RegionCheck 迁移到显式映射;三 pass 回归 -**ELF 后端零改动**——label/jump 保留给后端线性化(res_labels),region 是语义层。 +**ELF 后端零改动**——`label`/`jump` 保留给后端线性化(`res_labels`),region 是语义层。 ## 2. Region 模型 ### 2.1 Region 类型 -现有(dataflow.cr:104-106)+ 新增: +现有(`dataflow.cr:104-106`)+ 新增: | 值 | 名称 | 现有/新增 | |----|------|-----------| @@ -53,28 +53,28 @@ | 4 | SG_UNSAFE | 现有 | | 5 | SG_IF | **新增** | -`SG_IF`:if/else 在条件求值前、if 节点开头 `sg_push(SG_IF)`(ir_gen.cr:1138,push 先于 `gen_expr(cond)`),merge label 处 `sg_pop()`。区间覆盖 `[条件, 汇合)`。match 不单独建 region(展开为 if 链/跳转表)。 +`SG_IF`:if/else 在条件求值前、if 节点开头 `sg_push(SG_IF)`(`ir_gen.cr:1138`,push 先于 `gen_expr(cond)`),merge `label` 处 `sg_pop()`。区间覆盖 `[条件, 汇合)`。match 不单独建 region(展开为 if 链/跳转表)。 ### 2.2 显式映射 -新增并行数组 `g_df_node_region[]`(每 DFNode 一个 region id,跟随 `g_df_node_cap` 增长,照 `g_df_var_producer` 模式): +新增并行数组 `g_df_node_region[]`(每 `DFNode` 一个 region id,跟随 `g_df_node_cap` 增长,照 `g_df_var_producer` 模式): - `df_create_node` 时写入当前 open region id(`sg_push` 维护的栈顶) - O(1) 归属查询——解释器 region 迭代、验证 pass、DOT 分组免线性扫描 ## 3. 解释器 region 迭代(P2) -现状:`ip` 走 DFNode 数组,`IR_BRANCH`/`IR_JUMP` 查 `g_label_poses` 跳转(interp.cr:187-197)。 +现状:`ip` 走 `DFNode` 数组,`IR_BRANCH`/`IR_JUMP` 查 `g_label_poses` 跳转(`interp.cr:187-197`)。 改为 region 边界判定: -- 执行到 SG_LOOP/SG_FOR region 的 enter 节点 → 进入迭代模式(记录 region id 与 enter/exit 序号) -- 循环体按序执行;`IR_BREAK`(label 目标 == 当前 region exit)→ 跳出 region,继续 region 外下一节点 -- `IR_JUMP` 回跳(label 目标 == region header)→ 重新开始迭代(回到 region enter) -- `IR_BRANCH`(for/while 条件)照旧按 label 跳转,但目标被识别为"区域内"或"region 出口"→ 判定迭代是否继续 +- 执行到 `SG_LOOP`/`SG_FOR` region 的 enter 节点 → 进入迭代模式(记录 region id 与 enter/exit 序号) +- 循环体按序执行;`IR_BREAK`(`label` 目标 == 当前 region exit)→ 跳出 region,继续 region 外下一节点 +- `IR_JUMP` 回跳(`label` 目标 == region header)→ 重新开始迭代(回到 region enter) +- `IR_BRANCH`(for/while 条件)照旧按 `label` 跳转,但目标被识别为"区域内"或"region 出口"→ 判定迭代是否继续 - region exit 序号 → 正常结束迭代 -效果:循环场景不再依赖全局 `g_label_poses` 位置表;`break`/`continue` 成为 region 语义操作;嵌套时 break 跳出多层(label 目标属于外层 region → 直接跳该 region exit);early return / 异常路径不受影响。 +效果:循环场景不再依赖全局 `g_label_poses` 位置表;`break`/`continue` 成为 region 语义操作;嵌套时 `break` 跳出多层(`label` 目标属于外层 region → 直接跳该 region exit);early return / 异常路径不受影响。 ## 4. State Edges(P3) @@ -85,9 +85,9 @@ ### 4.2 两条来源 1. **副作用链**:每个函数维护一条 state 链——`STORE`/`STORE_FIELD`/`STORE_INDEX`/非纯 `CALL` 按指令序连 state 边(prev → cur) -2. **循环终止依赖**:SG_LOOP/SG_FOR 的 exit 节点,从循环体最后一条副作用指令连一条 state 边到 exit——保证"循环不终止则图不终止" +2. **循环终止依赖**:`SG_LOOP`/`SG_FOR` 的 exit 节点,从循环体最后一条副作用指令连一条 state 边到 exit——保证"循环不终止则图不终止" -构建位置:`df_connect_srcs` 内(emit 同步建图处),按 opcode 判定副作用;`df_end_func` 闭合链。 +构建位置:`df_connect_srcs` 内(emit 同步建图处),按 `opcode` 判定副作用;`df_end_func` 闭合链。 ### 4.3 影响 @@ -97,11 +97,11 @@ ## 5. 序列化 v2(P4) -- 文件头版本号 v1→v2(.cir 文本 + .ccr 二进制) -- 新增 SG 段:`sg_count × 24B`(6×i32:kind/enter/exit/parent/nstart/ncount,内存格式 48B 与线格式 24B 区分——`ESZ_SG_DISK`) -- DFEdge 序列化带 kind +- 文件头版本号 v1→v2(`.cir` 文本 + `.ccr` 二进制) +- 新增 `SG` 段:`sg_count × 24B`(6×i32:`kind`/`enter`/`exit`/`parent`/`nstart`/`ncount`,内存格式 48B 与线格式 24B 区分——`ESZ_SG_DISK`) +- `DFEdge` 序列化带 `kind` - v1 兼容:加载 v1 文件按旧格式解析,region 树退化为单 FUNC region -- 影响面:ccr_io.cr(save/load)、ir-schema 文档 +- 影响面:`ccr_io.cr`(save/load)、`ir-schema` 文档 ## 6. 验证 Pass 迁移(P5) @@ -121,8 +121,8 @@ ## 8. 测试策略 - 每阶段 TDD:先写失败测试(`.cir` dump 文本断言 / `corec run` 运行断言) -- 回归重点:`tests/suite/` 循环/嵌套/break-continue 用例;解释器;自举三阶段(corec→corec2→corec3,O0/O1) -- 新增用例:嵌套 region(if 内 loop、loop 内 if、双循环)、break 跳出多层、for 的 ivar 跨迭代保持 +- 回归重点:`tests/suite/` 循环/嵌套/`break`-`continue` 用例;解释器;自举三阶段(`corec`→`corec2`→`corec3`,O0/O1) +- 新增用例:嵌套 region(if 内 loop、loop 内 if、双循环)、`break` 跳出多层、for 的 `ivar` 跨迭代保持 ## 9. 风险与对策 @@ -135,10 +135,10 @@ ## 10. 明确不做(YAGNI) -- ELF 后端零改动(label 保留给线性化) -- 任意 goto +- ELF 后端零改动(`label` 保留给线性化) +- 任意 `goto` - 验证工具消费(外部组件,等格式定型) -- SG_IF 的 then/else 独立子 region(分支内结构由嵌套 region 表达) +- `SG_IF` 的 `then`/`else` 独立子 region(分支内结构由嵌套 region 表达) ## 11. 文档同步(随各阶段) diff --git a/docs/superpowers/specs/2026-08-09-repo-governance-design.md b/docs/superpowers/specs/2026-08-09-repo-governance-design.md index 59528b62..ea3b32c9 100644 --- a/docs/superpowers/specs/2026-08-09-repo-governance-design.md +++ b/docs/superpowers/specs/2026-08-09-repo-governance-design.md @@ -5,7 +5,7 @@ ## 1. 概述 -Core 的愿景是成为严肃系统语言(语义保鲜、内核路线、形式验证)——开发流程按**最终形态**立规,执行按**现状规模**宽松。治理模型参考 Rust/Linux:main 即 mainline,**任何人(含维护者)不得直推**,全部改动经 PR + 审查 + 合入门槛进入 main。 +Core 的愿景是成为严肃系统语言(语义保鲜、内核路线、形式验证)——开发流程按**最终形态**立规,执行按**现状规模**宽松。治理模型参考 Rust/Linux:`main` 即 mainline,**任何人(含维护者)不得直推**,全部改动经 PR + 审查 + 合入门槛进入 `main`。 | 事实 | 值 | |---|---| @@ -20,11 +20,11 @@ Core 的愿景是成为严肃系统语言(语义保鲜、内核路线、形式 - **非对称**:唯一实际审查 = 你对 RhineIris PR 的单向把关;你的改动走 PR,合入经 **B 流程**(临时豁免,见 §3.3) - **愿景结构 + 现状执行**:规则按最终形态全立(将来贡献者增多规则自动生效);执行上互审约定优先(**实测修正 2026-08-09**:GitHub 原生禁止作者批准自己的 PR——"自批兜底"不成立,维护者自有 PR 合入经 B 流程临时豁免,见 §3.3) - **机制限制(如实记录)**:GitHub 无原生"禁止以 main 为 base 创建 PR"开关——"PR 不能指向 main"由 **main 规则组合强制**(restrict pushes 仅 DslsDZC + required reviewers 仅 DslsDZC:指向 main 的 PR 无维护者批准无法合入)+ CONTRIBUTING 约定(PR 一律指向 develop)实现 -- **铁律机械执行**:CLAUDE.md 第 2 条(禁止 git、全面 jj)用 hook 硬拦截 +- **铁律机械执行**:`CLAUDE.md` 第 2 条(禁止 `git`、全面 `jj`)用 hook 硬拦截 -## 3. GitHub 侧:ruleset 最终清单(main / develop 两个 ruleset) +## 3. GitHub 侧:ruleset 最终清单(`main` / `develop` 两个 ruleset) -### 3.1 main ruleset(目标:main)——只有维护者能触碰 +### 3.1 `main` ruleset(目标:`main`):维护者独占 | # | 规则 | 配置 | |---|---|---| @@ -36,7 +36,7 @@ Core 的愿景是成为严肃系统语言(语义保鲜、内核路线、形式 | M6 | 管理员无绕过 | 规则对仓库管理员同样生效(关闭 admin bypass——否则 M1 形同虚设) | | M7 | Protected tags | `release/*` 标签禁强推、禁删除 | -### 3.2 develop ruleset(目标:develop 集成分支)——日常开发入口 +### 3.2 `develop` ruleset(目标:`develop` 集成分支):日常开发入口 | # | 规则 | 配置 | |---|---|---| @@ -54,18 +54,18 @@ Core 的愿景是成为严肃系统语言(语义保鲜、内核路线、形式 ### 3.3 机制限制与过渡 -- **GitHub 无原生"禁止以 main 为 base 创建 PR"开关**:M4(required reviewers 仅 DslsDZC)使指向 main 的 PR 无法被非你合入——"PR 不能指向 main"以规则兜底 + CONTRIBUTING 约定(PR 一律指向 develop)实现 +- **GitHub 无原生"禁止以 main 为 base 创建 PR"开关**:`M4`(`required reviewers` 仅 DslsDZC)使指向 `main` 的 PR 无法由维护者以外者合入——"PR 不能指向 `main`"以规则兜底 + `CONTRIBUTING` 约定(PR 一律指向 `develop`)实现 - **落地过渡**:两个 ruleset 先以 **evaluate(试运行)模式**启用,观察确认无干扰后转 active - **2026-08-09 落地偏差(免费计划限制,已实测)**: - `enforcement: evaluate` 仅 Enterprise 可用——免费计划已直接以 **active** 创建(无试运行期,规则即刻生效) - `merge_queue` 规则被 API 拒绝("Invalid rule 'merge_queue'" 空原因)——**降级为手动合入**:审批 + CI 状态检查门槛保留(D1/D3/D8 的自动化串行部分由人工点击合入替代) - - pull_request 参数 schema 实测:5 个必填布尔(含 `require_code_owner_review`)、`allowed_merge_methods: ["squash"]` 强制 squash-only + - `pull_request` 参数 schema 实测:5 个必填布尔(含 `require_code_owner_review`)、`allowed_merge_methods: ["squash"]` 强制 squash-only - `required_status_checks` 参数数组字段名是 `required_status_checks`(非 `checks`) - **2026-08-09 实测(流程验证)**: - GitHub **原生禁止作者批准自己的 PR**("Can not approve your own pull request")——"自批兜底"前提不成立;管理员强制合并亦被 bypass_actors 空集拦截 - **B 流程**(既定路径):维护者自有 PR 合入 = 临时禁用对应 ruleset → squash 合并 → 恢复 active(PR #26 首次执行,2026-08-09) - RhineIris 的审批要计入 required approvals 需 write 权限(fork 贡献者审批不满足要求)——待决策是否授予 collaborator - - CI 工作流注册冻结持续(GitHub 侧,注册表含已删文件/缺新文件)——develop 的 required_status_checks 暂移除,注册自愈后回填 + - CI 工作流注册冻结持续(GitHub 侧,注册表含已删文件/缺新文件)——`develop` 的 `required_status_checks` 暂移除,注册自愈后回填 - M7(release/* 标签保护)与 D7(文件路径限制)未落地:脚本与已建 ruleset 均未含(免费计划可用但暂缓),列入后续项 ## 4. GitHub 侧:落地方式 @@ -86,9 +86,9 @@ src/ci/scripts/run-build-from-ci.sh ← GHA 入口 src/ci/scripts/setup-environment.sh ← 环境转储 ``` -- 双层触发:`pull_request`(PR 快速层:check / bootstrap-tests / selfhost-tests)+ `merge_group`(完整层:suite / full-bootstrap)——PR 层 job 在 merge 下也运行(Rust 的 PR-jobs-auto-register 语义) -- 砍掉:citool(静态矩阵内联)、全部 install-*.sh(Core 零工具链依赖)、docker/、artifacts -- 已知风险(如实标记):`full-bootstrap` 撞 corec2 tokenizer 死循环(TODO 自举阻塞项)+ 预存 bug 1(1GiB bump heap 峰值)——完整层按 TODO 逐个点亮;`opt-regress`(O0/O1 回归)留位 +- 双层触发:`pull_request`(PR 快速层:`check` / `bootstrap-tests` / `selfhost-tests`)+ `merge_group`(完整层:`suite` / `full-bootstrap`)——PR 层 job 在 merge 下也运行(Rust 的 PR-jobs-auto-register 语义) +- 移除:`citool`(静态矩阵内联)、全部 `install-*.sh`(Core 零工具链依赖)、`docker/`、`artifacts` +- 已知风险(如实标记):`full-bootstrap` 触及 `corec2` tokenizer 死循环(TODO 自举阻塞项)+ 预存 bug 1(1GiB bump heap 峰值)——完整层按 TODO 逐个点亮;`opt-regress`(O0/O1 回归)留位 - 本地验证:`CI_JOB_NAME=bootstrap-tests src/ci/run.sh` 端到端通过 ## 6. 本地配置 @@ -101,7 +101,7 @@ src/ci/scripts/setup-environment.sh ← 环境转储 | settings.local.json 清理 | 移除 `Bash(git *)` 允许项 | 权限模型与 hook 一致 | | CLAUDE.md | 新增"版本控制流程"段(下述命令序列) | 文档与机制一致 | -## 7. 新工作流(你) +## 7. 新工作流(维护者) ``` 日常开发(feature → develop): @@ -121,15 +121,15 @@ gh pr create --base main --fill # develop→main PR(required reviewers = ## 8. 验证清单(合入后端到端) -- [ ] 直推 main 被拒(403);推 feature 分支成功 -- [ ] 指向 main 的 PR(非你创建)无法被批准合入——required reviewers 仅 DslsDZC -- [ ] develop→main 合并只有你执行成功 -- [ ] 你的 feature PR:B 流程(临时豁免)→ squash 合入 develop → 源分支自动删除 -- [ ] RhineIris fork PR:base=develop,完整流程,你审批后合入 develop +- [ ] 直推 `main` 被拒(403);推 `feature` 分支成功 +- [ ] 指向 `main` 的 PR(非维护者创建)无法被批准合入——`required reviewers` 仅 DslsDZC +- [ ] `develop`→`main` 合并只有维护者执行成功 +- [ ] 维护者自有 `feature` PR:B 流程(临时豁免)→ squash 合入 `develop` → 源分支自动删除 +- [ ] RhineIris fork PR:`base=develop`,完整流程,维护者审批后合入 `develop` - [ ] 未签名提交的 PR 被拒(签名规则生效);`jj log --no-graph -T 'signature'` 可见签名 -- [ ] 管理员账号直推 main 同样被拒(绕过已关闭) +- [ ] 管理员账号直推 `main` 同样被拒(绕过已关闭) - [ ] `git` 命令被 hook 硬拦截;`jj` 一切正常 -- [ ] jj main protect 生效(rebase 移不动 main) +- [ ] `jj` main protect 生效(rebase 移不动 `main`) - [ ] PR 层 CI 绿;完整层 job 状态如实标记 ## 9. 社区协作基础设施(2026-08-09 补充) @@ -158,8 +158,8 @@ gh pr create --base main --fill # develop→main PR(required reviewers = ## 12. 当前状态 - CI 骨架:已实现(2026-08-09),本地验证通过,随首个 PR 上线 -- 社区四件套:PR 模板 / CONTRIBUTING / SECURITY / CODE_OF_CONDUCT 已写(2026-08-09),随本 spec 首 PR 上线 +- 社区四件套:PR 模板 / `CONTRIBUTING` / `SECURITY` / `CODE_OF_CONDUCT` 已写(2026-08-09),随本 spec 首 PR 上线 - 本地配置:jj protect / jj 签名(behavior=own)/ hook / settings 清理 / CLAUDE.md——全部落地(2026-08-09) - `develop` 集成分支已创建并承载 PR #25 -- GitHub ruleset:**main-only-maintainer**(id 20601201)+ **develop-integration**(id 20601189)已创建并 active(2026-08-09);gh TLS 间歇性故障期间以重试创建成功;squash-only(allowed_merge_methods=['squash'])已应用于双 ruleset;delete_branch_on_merge=True 已设 +- GitHub ruleset:`main-only-maintainer`(id 20601201)+ `develop-integration`(id 20601189)已创建并 active(2026-08-09);`gh` TLS 间歇性故障期间以重试创建成功;squash-only(`allowed_merge_methods=['squash']`)已应用于双 ruleset;`delete_branch_on_merge=True` 已设 - 首个 PR(#25 → develop)与发布 PR(#26 → main,B 流程)已完成;治理全流程端到端验证 diff --git a/docs/superpowers/specs/2026-08-13-graph-anchored-regions-design.md b/docs/superpowers/specs/2026-08-13-graph-anchored-regions-design.md index ac33580e..8adf859b 100644 --- a/docs/superpowers/specs/2026-08-13-graph-anchored-regions-design.md +++ b/docs/superpowers/specs/2026-08-13-graph-anchored-regions-design.md @@ -1,7 +1,7 @@ # 图锚定区域内存模型设计(Graph-Anchored Regions) -> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 docs/project-book.md。正文保留历史原样。 +> **术语注记(2026-08-15)**:本规格为历史设计记录,其中「数据流图」(及「RVSDG 式」)为当时术语;该结构后定名为 **HDFG(Holographic Dataflow Graph,全息数据流图)**,术语演进见 `docs/project-book.md`。正文保留历史原样。 ## 概述 @@ -43,31 +43,31 @@ fn f() { ┌─ SG_IF ─┐ ## 核心概念:图锚定区域 -区域 = 子图节点(DFNode)的字节域。现有设计的「每个 DFNode 可关联一个 Arena」「子图绑定」「Arena 嵌套」原样继承,概念升级为区域。 +区域 = 子图节点(`DFNode`)的字节域。现有设计的「每个 `DFNode` 可关联一个 Arena」「子图绑定」「Arena 嵌套」原样继承,概念升级为区域。 -### 推论 A:生命周期 = 图活性,不是 LIFO +### 推论 A:生命周期 = 图活性(非 LIFO) -RegionCheck 的 `cur_seq < exit_seq` 判定(pointer-model.md Pass 2)就是图版本的生命周期定义。这天然支持 flow/go 的独立区域(区域栈做不到非 LIFO 生命周期),也天然给出跨区域引用的合法性判据(outlives 的图形式)。 +RegionCheck 的 `cur_seq < exit_seq` 判定(`pointer-model.md` Pass 2)就是图版本的生命周期定义。这天然支持 `flow`/`go` 的独立区域(区域栈做不到非 LIFO 生命周期),也天然给出跨区域引用的合法性判据(`outlives` 的图形式)。 -### 推论 B:区域操作沿图边 +### 推论 B:沿图边的区域操作 区域不仅嵌套(树),还能沿数据流边操作: -- **split**:一块字节沿边划给子消费者(= 字节块独立回收;子区域 = 图边的子块,自己的游标 + 自己的重置点) -- **merge**:汇合点两个子区域的数据汇入(拷贝或区域合并) -- **share**:分叉点一个区域被多个消费者只读共享(共享者必须 outlive 引用) +- **`split`**:一块字节沿边划给子消费者(= 字节块独立回收;子区域 = 图边的子块,自己的游标 + 自己的重置点) +- **`merge`**:汇合点两个子区域的数据汇入(拷贝或区域合并) +- **`share`**:分叉点一个区域被多个消费者只读共享(共享者必须 `outlive` 引用) -### 推论 C:每字节归属 = 图的 provenance 边 +### 推论 C:每字节归属 = 图的 `provenance` 边 -pointer-model.md 已定义记忆模型为「字节序列 + 宽度 + 边界」,provenance(归属)、offset(字节偏移)、alloc_size(字节大小)全部与类型无关。"控制每一个字节"不是新语法,是图上本来就有的信息。 +`pointer-model.md` 已定义记忆模型为「字节序列 + 宽度 + 边界」,`provenance`(归属)、`offset`(字节偏移)、`alloc_size`(字节大小)全部与类型无关。"控制每一个字节"不是新语法,是图上本来就有的信息。 ### 与传统的关系 区域树是图区域的特例(无汇合/分叉的图 = 树 = 词法嵌套);Tofte-Talpin 的区域栈是更窄的特例(树 + LIFO)。本设计是推广,不是发明。 -### 术语注意 +### 术语注记 -dataflow 模块已有「region」一词指控制流嵌套(SG_IF/LOOP/FOR/FLOW/UNSAFE)。本文的「区域」指**内存字节域**。文档中按上下文区分;若需精确,内存区域全称「内存区域」。 +`dataflow` 模块已有「region」一词指控制流嵌套(`SG_IF`/`LOOP`/`FOR`/`FLOW`/`UNSAFE`)。本文的「区域」指**内存字节域**。文档中按上下文区分;若需精确,内存区域全称「内存区域」。 ## 机制总图 @@ -115,7 +115,7 @@ mmio := alloc_at(0x7fff0000, 4096, align(4096)); ``` - v1 **不提供**显式区域/回收语法(YAGNI)。「指定回收」是编译器内部机制(IR 层生成回收点 = Cyclone early deallocation 的自动版)。 -- 与 pointer-model.md 2026-08-10 定论的关系:0x 字面量仍是 unsafe 外部入口;`alloc_at` 是**声明式进图**(获得 provenance 的节点),不冲突——声明是唯一信任点,之后全图追踪。 +- 与 `pointer-model.md` 2026-08-10 定论的关系:0x 字面量仍是 `unsafe` 外部入口;`alloc_at` 是**声明式进图**(获得 `provenance` 的节点),不冲突——声明是唯一信任点,之后全图追踪。 ## 语义面(验证器) @@ -123,7 +123,7 @@ mmio := alloc_at(0x7fff0000, 4096, align(4096)); - 每字节内容 = 字节序列(已有) - 每字节权限 = **Freeable > Writable > Readable > Nonempty > Empty**(新加) -- 区域树 = 图的子图结构;布局元数据、ALLOC_AT 边界、outlives 结论全部从图导出——**验证器消费图即消费全部内存语义** +- 区域树 = 图的子图结构;布局元数据、`ALLOC_AT` 边界、`outlives` 结论全部从图导出——**验证器消费图即消费全部内存语义** - 前置缺口:宽度检查(`off + width <= alloc_size`)待补(对应 TODO 预存 bug 7) ## 分配器面(实现) diff --git a/docs/superpowers/specs/2026-08-15-cache-semantics-design.md b/docs/superpowers/specs/2026-08-15-cache-semantics-design.md index 3f199aa0..79868fb9 100644 --- a/docs/superpowers/specs/2026-08-15-cache-semantics-design.md +++ b/docs/superpowers/specs/2026-08-15-cache-semantics-design.md @@ -7,15 +7,15 @@ ### 1.1 现状 -- z-vision 目标一(语义保鲜):HDFG 保留全部语义信息,与执行硬件解耦;范式迁移时"语义不动,只换后端映射"。其中**范式映射表未做**(设计上每范式一张表)。 +- `z-vision` 目标一(语义保鲜):HDFG 保留全部语义信息,与执行硬件解耦;范式迁移时"语义不动,只换后端映射"。其中**范式映射表未做**(设计上每范式一张表)。 - 存储侧现状:`docs/memory-model.md` 的语义本体 = CompCert v2 字节模型(块 + (块 ID, 字节偏移) + 每字节权限)。**字节寻址本身是经典范式概念**——存储语义仍然绑死经典硬件。 -- 执行侧已范式无关(HDFG + region/state edge/provenance 已实现),存储侧没有跟上:这正是"范式映射表"的**存储半边**缺口。 +- 执行侧已范式无关(HDFG + `region`/`state edge`/`provenance` 已实现),存储侧没有跟上:这正是"范式映射表"的**存储半边**缺口。 ### 1.2 关键观察 -**实现早已是缓存语义**:HDFG 节点 = 配方(值的产生方式),边 = 值流,state edges = 顺序约束,驱逐/再生 = 丢令牌/重跑节点。IR(.cir/.ccr)从来不是字节内存——它是数据流。 +**实现早已是缓存语义**:HDFG 节点 = 配方(值的产生方式),边 = 值流,`state edges` = 顺序约束,驱逐/再生 = 丢令牌/重跑节点。IR(`.cir`/`.ccr`)从来不是字节内存——它是数据流。 -落后的不是实现,是**文档层**:`memory-model.md` 在描述一个实现里不存在的本体(字节内存为语义根基)。本次工作是语义层面的文档纠偏,与"文档大量过时、实现以源码为准"是同一个病,只是病在语义层。 +落后的不是实现,是**文档层**:`memory-model.md` 在描述一个实现里不存在的本体(字节内存为语义根基)。本次工作是语义层面的文档纠偏,与"文档大量过时、实现以源码为准"属于同一类问题,只是问题出在语义层。 ### 1.3 目标 @@ -27,7 +27,7 @@ ## 2. 核心模型:语义本体(七条条款) -以下条款是 memory-model.md 上部的正文,写成可形式化的陈述,将来供验证器(翻译桥/CIC 内核)消费: +以下条款是 `memory-model.md` 上部的正文,写成可形式化的陈述,将来供验证器(翻译桥/CIC 内核)消费: 1. **值 = 配方**。条目的语义 = (产生它的图节点, 输入边)。不存在独立于配方的"存储事实"。 @@ -37,9 +37,9 @@ 4. **边界公理**。图边界输入(MMIO/FFI/输入/测量)是唯一无配方条目,语义上是符号常量。语法层叫 `unsafe`(边界标注),语义层只叫"边界"。边界之外才需要 state,边界之内全是可重算的。 -5. **赋值 = 版本化**。`x = x + 1` 在语义上 = "x₁ 创建、x₀ 失效、绑定移动",不是修改内存单元。顺序约束由 state edges 表达。"可变"不是内存单元的属性,是绑定可移动的许可。 +5. **赋值 = 版本化**。`x = x + 1` 在语义上 = "x₁ 创建、x₀ 失效、绑定移动",不是修改内存单元。顺序约束由 `state edges` 表达。"可变"不是内存单元的属性,是绑定可移动的许可。 -6. **地址 = 映射**。`&x` = (条目标识, 偏移),字节地址只是经典投影,不是语义对象。指针算术合法性由条目标识 + 偏移域验证(现有 provenance 三 pass 保留不动)。 +6. **地址 = 映射**。`&x` = (条目标识, 偏移),字节地址只是经典投影,不是语义对象。指针算术合法性由条目标识 + 偏移域验证(现有 `provenance` 三 pass 保留不动)。 7. **映射实例正确性**。区域/arena/字节权限(CompCert v2)是经典映射实例,其正确性标准 = 保持条款 1–6 的可观测语义。 @@ -62,7 +62,7 @@ ## 5. 术语对照表 -"内存"的三层含义(放 memory-model.md 开头,防术语歧义): +"内存"的三层含义(放 `memory-model.md` 开头,防术语歧义): | 术语 | 含义 | 例子 | |------|------|------| @@ -72,20 +72,20 @@ ## 6. 范围边界(YAGNI) -- ❌ 零代码改动:无 sem_ver 字段、无 IR 变更、无后端变更(图本身就是缓存语义) +- ❌ 零代码改动:无 `sem_ver` 字段、无 IR 变更、无后端变更(图本身就是缓存语义) - ❌ 不做后端映射改造、不做量子映射实现 - ❌ 不改语言表面(命令式行不动) - ❌ 不碰规约/验证器实现(仍设计态) -- ✅ 唯一产出:docs/ 下文档改动 + 全仓库术语一致性扫描 +- ✅ 唯一产出:`docs/` 下文档改动 + 全仓库术语一致性扫描 ## 7. 落地顺序 1. 术语对照表定稿 -2. memory-model.md 重构(核心交付物) -3. pointer-model.md 更新 -4. z-vision.md 更新 -5. project-book.md / execution-model.md 一致性 -6. 全仓库术语扫描(grep 找出所有把字节模型当语义本体的残留表述,逐个修正) +2. `memory-model.md` 重构(核心交付物) +3. `pointer-model.md` 更新 +4. `z-vision.md` 更新 +5. `project-book.md` / `execution-model.md` 一致性 +6. 全仓库术语扫描(`grep` 找出所有把字节模型当语义本体的残留表述,逐个修正) ## 8. 验收标准 diff --git a/docs/superpowers/specs/2026-08-16-platform-abstract-design.md b/docs/superpowers/specs/2026-08-16-platform-abstract-design.md index 7fb98aeb..4f069259 100644 --- a/docs/superpowers/specs/2026-08-16-platform-abstract-design.md +++ b/docs/superpowers/specs/2026-08-16-platform-abstract-design.md @@ -1,12 +1,12 @@ # 平台桥抽象设计:I/O 流 / 随机 / 哈希 / 时钟 日期:2026-08-16 -状态:已批准(brainstorming-lite——模式无新决策,直接定稿) +状态:已批准(brainstorming-lite;模式无新决策,直接定稿) ## 一、原则 -1. **语义接口(数学)+ 后端实现(惯例隔离)**:语言层只见数学语义接口,系统调用/熵源/算法选择全部隔离到后端实现 -2. **现有 API 零变化**(「不敢自动」兼容原则):print/println/read_file/write_file/str_hash 等保持原样,抽象是新增接口层 +1. **语义接口(数学)+ 后端实现(惯例隔离)**:语言层只呈现数学语义接口,系统调用/熵源/算法选择全部隔离到后端实现 +2. **现有 API 零变化**(「不敢自动」兼容原则):`print`/`println`/`read_file`/`write_file`/`str_hash` 等保持原样,抽象是新增接口层 3. **小而准**:四个抽象各一个语义接口 + 一个后端实现,不做非阻塞 IO/加密级随机/异步流(YAGNI) ## 二、四个抽象 @@ -61,10 +61,10 @@ - 非阻塞/异步 I/O、事件循环 - 加密级随机(密码学另议) - 跨平台文件系统抽象(目录遍历/路径——更大的议题,后议) -- 流组合子库(map/filter 流变换——用户层可做) +- 流组合子库(`map`/`filter` 流变换——用户层可做) ## 四、验证 -- 现有测试全部不破(test_pipeline/test_compile 等回归) -- 新接口冒烟:流读写往返、uniform_int 分布范围、hash 确定性、时钟单调 -- 与 LSP 并行(tests/selfhost/test_lsp.py 不回归) +- 现有测试全部保持通过(`test_pipeline`/`test_compile` 等回归) +- 新接口冒烟:流读写往返、`uniform_int` 分布范围、`hash` 确定性、时钟单调 +- 与 LSP 并行(`tests/selfhost/test_lsp.py` 不回归) diff --git a/docs/superpowers/specs/2026-08-23-hw-map-design.md b/docs/superpowers/specs/2026-08-23-hw-map-design.md index 53d7be83..d0a1af11 100644 --- a/docs/superpowers/specs/2026-08-23-hw-map-design.md +++ b/docs/superpowers/specs/2026-08-23-hw-map-design.md @@ -5,25 +5,25 @@ ## 一、背景与动机 -内核路线(project-book 第五阶段)需要汇编级/硬件级能力——MMIO 是第一步。标准化问题:x86 有 +内核路线(`project-book` 第五阶段)需要汇编级/硬件级能力——MMIO 是第一步。标准化问题:x86 有 标准手册可循,而 **arm64 SoC 外设各写各的、手册不统一**(内存映射因芯片而异)。结论:后端需要 一个**能直接编译的具体硬件目标**——参考机(固定 MMIO 映射的虚拟标准机),真实硬件走平台投影。 先例(均已批准): -- **crasm**(2026-08-08):统一汇编层 + 特权指令固定集(mmio_read/mmio_write/barrier/...)+ 平台映射表 -- **alloc_at**(2026-08-13):MMIO 页声明式进图获得 provenance(pointer-model.md) +- **`crasm`**(2026-08-08):统一汇编层 + 特权指令固定集(`mmio_read`/`mmio_write`/`barrier`/...)+ 平台映射表 +- **`alloc_at`**(2026-08-13):MMIO 页声明式进图获得 `provenance`(`pointer-model.md`) - **平台桥抽象**(2026-08-16):语义接口(数学)+ 后端实现(惯例隔离) - **地址 = 映射**(2026-08-15 语义定稿):字节地址不是语义对象,只是经典投影实例 ## 二、决策记录(2026-08-23 brainstorming 确认) 1. **参考机 + 裸机输出**:后端直接编译到固定 MMIO 映射的参考机,产出裸机镜像(无 OS) -2. **全局生效接入检查**:每次 MMIO 访问对照映射表验证——存在性与地址、宽度匹配、读写权限、volatile 顺序性(全面) +2. **全局生效接入检查**:每次 MMIO 访问对照映射表验证——存在性与地址、宽度匹配、读写权限、`volatile` 顺序性(全面) 3. **描述形态两者结合**:语言内声明(主)+ 外部数据文件(真实 SoC) 4. **双方都生效**:语言层与 crasm 层共用同一全局映射表与检查 5. **落地顺序**:先定义表描述格式 → 再完成 x64 映射表 6. **范式无关**:设备声明不绑定物理地址——地址绑定下沉到投影层(与「地址 = 映射」定稿一致) -7. **暂不接入能力模型**:能力格 v4(memory-model-capability-lattice.md)已发布——M1 定论:能力不提升一等公民(语义还原图上,授权归治理层);本设计不绑定,与 v4 定位一致 +7. **暂不接入能力模型**:能力格 v4(`memory-model-capability-lattice.md`)已发布——M1 定论:能力不提升一等公民(语义还原图上,授权归治理层);本设计不绑定,与 v4 定位一致 ## 三、架构:三层结构(描述 → 检查 → 发射) @@ -39,10 +39,10 @@ g_hw_sem ├── name / offset(设备内逻辑偏移)/ width(8|16|32|64) / perm(ro|wo|rw) ``` -没有 base、没有绝对地址——设备 = 逻辑身份 + 寄存器结构,量子/分布式/GPU 范式下照常可用。 +没有 `base`、没有绝对地址——设备 = 逻辑身份 + 寄存器结构,量子/分布式/GPU 范式下照常可用。 语言声明与数据文件编译进**同一张表**,形式不同、语义同一。 -**语言内声明**(声明式进图,alloc_at 同路径): +**语言内声明**(声明式进图,`alloc_at` 同路径): ```core device UART { // 无 @ 基址——不绑定任何硬件 @@ -51,7 +51,7 @@ device UART { // 无 @ 基址——不绑定任何硬件 } ``` -**数据文件**(真实 SoC 用,复用 stdlib/toml.cr 解析器): +**数据文件**(真实 SoC 用,复用 `stdlib/toml.cr` 解析器): ```toml [[device]] @@ -60,7 +60,7 @@ name = "uart" # 无 base 字段 name = "data"; offset = 0x00; width = 8; perm = "rw" ``` -**投影表(经典地址绑定 = 后端实现选择)**——device id → 物理基址: +**投影表(经典地址绑定 = 后端实现选择)**——`device` id → 物理基址: ``` uart → 0x3F200000 (x64 参考机,编译器内置) @@ -69,12 +69,12 @@ uart → 0x09000000 (真实平台:QEMU virt,数据文件导入) ``` x64 映射表 = 投影表的第一份实例。同一份语义表 + 不同投影表 = 同一程序编译到不同硬件。 -访问 `UART.DATA` 语义上是「逻辑设备内的逻辑寄存器」;只有发射时才解析为 基址+偏移 的经典 load/store。 +访问 `UART.DATA` 语义上是「逻辑设备内的逻辑寄存器」;只有发射时才解析为 基址+偏移 的经典 `load`/`store`。 ### 2. 检查层 -**hw_check pass**:在 HDFG 上运行(与 ptr_analysis / region_check / provenance_verify 并列), -消费 `g_hw_sem`。访问形式:语言层 `UART.DATA` 下降为携带 device+reg 引用的 IR 节点 +**`hw_check` pass**:在 HDFG 上运行(与 `ptr_analysis` / `region_check` / `provenance_verify` 并列), +消费 `g_hw_sem`。访问形式:语言层 `UART.DATA` 下降为携带 `device`+`reg` 引用的 IR 节点 (`IR_MMIO_READ/WRITE`)。 | 检查 | 规则 | 违反示例 | @@ -86,26 +86,26 @@ x64 映射表 = 投影表的第一份实例。同一份语义表 + 不同投影 全部编译期,零运行期开销。 -**crasm 双方都生效——「可解析即检查」**:crasm 的 `mmio_read(addr)` / `mmio_write(addr, val)` -中,地址若经投影表**静态解析**回语义寄存器 → 四项检查照常;解析不到(动态地址)→ unsafe -外部入口(与 0x 字面量同角色,见 pointer-model.md)。 +**`crasm` 双方都生效——「可解析即检查」**:`crasm` 的 `mmio_read(addr)` / `mmio_write(addr, val)` +中,地址若经投影表**静态解析**回语义寄存器 → 四项检查照常;解析不到(动态地址)→ `unsafe` +外部入口(与 0x 字面量同角色,见 `pointer-model.md`)。 ``` mmio_read(0x3F200000) → 投影解析 → UART.DATA → 四项检查 mmio_read(addr_var) → 解析不到 → unsafe 边界(检查不适用) ``` -**volatile 实现**:IR 节点带 volatile 标记;`pass.cr`(常量折叠)、`opt.cr`(CSE/regalloc/调度) +**`volatile` 实现**:IR 节点带 `volatile` 标记;`pass.cr`(常量折叠)、`opt.cr`(CSE/regalloc/调度) 一律不消除、不重排、不合并 MMIO 读写——每个 MMIO 读都是副作用,读后不用也必须保留。 -发射为普通 load/store 到解析地址;跨核/硬件的顺序保障是 crasm `barrier` 的职责,不混入。 +发射为普通 `load`/`store` 到解析地址;跨核/硬件的顺序保障是 `crasm` `barrier` 的职责,不混入。 -**错误报告**:走现有 diag 体系,新错误码(E_MMIO_UNKNOWN_REG / E_MMIO_WIDTH_MISMATCH / -E_MMIO_PERM / E_MMIO_VOLATILE),实现时在 error-codes 规格里定归属。 +**错误报告**:走现有 `diag` 体系,新错误码(`E_MMIO_UNKNOWN_REG` / `E_MMIO_WIDTH_MISMATCH` / +`E_MMIO_PERM` / `E_MMIO_VOLATILE`),实现时在 `error-codes` 规格里定归属。 ### 3. 发射层 **参考机定义**(x64 投影表第一份实例):编译器内置投影表(如 `src/arch/x86_64/hw_ref.toml`), -第一版外设范围**只有 UART**(能打印 = 最小验证闭环);timer / 中断控制器 / GPIO 后续扩展。 +第一版外设范围**只有 UART**(能打印 = 最小验证闭环);`timer` / 中断控制器 / GPIO 后续扩展。 **发射流程**: @@ -128,23 +128,23 @@ IR_MMIO_READ/WRITE(语义引用 device+reg) ## 四、边界 -- crasm `mmio_read(addr)` 显式地址 = unsafe 外部入口(不可静态解析时),与 0x 字面量同角色, +- `crasm` `mmio_read(addr)` 显式地址 = `unsafe` 外部入口(不可静态解析时),与 0x 字面量同角色, 不与语义层混淆 - 检查全部编译期,零运行期开销 - 语言层 `device` 是声明不是运行时对象——映射表只活在编译期 ## 五、测试与里程碑 -1. 语义表构建:`device` 声明解析 + toml 导入 → 同一张表(单测) -2. hw_check pass + 四项检查测试(tests/selfhost 载体) +1. 语义表构建:`device` 声明解析 + `toml` 导入 → 同一张表(单测) +2. `hw_check` pass + 四项检查测试(`tests/selfhost` 载体) 3. 投影表 + 地址解析(可解析即检查路径测试) -4. x64 参考机投影表 + IR_MMIO 发射 +4. x64 参考机投影表 + `IR_MMIO` 发射 5. `corearch --bare` 裸机输出 -6. 端到端:`.cr`(device UART 声明 + 打印)→ `--bare` → QEMU 运行 → 断言串口输出 +6. 端到端:`.cr`(`device` UART 声明 + 打印)→ `--bare` → QEMU 运行 → 断言串口输出 (无 QEMU 环境时跳过) 7. (后补)真实平台投影表数据文件(树莓派 / QEMU virt) -回归:现有测试全部不破(test_pipeline / test_compile / test_pointer_safety 等)。 +回归:现有测试全部保持通过(`test_pipeline` / `test_compile` / `test_pointer_safety` 等)。 ## 六、明确不做(YAGNI) @@ -156,6 +156,6 @@ IR_MMIO_READ/WRITE(语义引用 device+reg) ## 七、参考 - `docs/crasm.md`、`docs/superpowers/specs/2026-08-08-crasm-design.md`(特权指令固定集、平台映射表) -- `docs/pointer-model.md`(alloc_at 声明式进图、unsafe 边界、地址 = 映射) +- `docs/pointer-model.md`(`alloc_at` 声明式进图、`unsafe` 边界、地址 = 映射) - `docs/superpowers/specs/2026-08-16-platform-abstract-design.md`(语义接口 + 后端实现原则) - `docs/memory-model-capability-lattice.md`(能力格 v4,已发布——能力不提升一等公民) diff --git a/docs/superpowers/specs/2026-08-27-lattice-form-ir-design.md b/docs/superpowers/specs/2026-08-27-lattice-form-ir-design.md index 4695a878..e820c463 100644 --- a/docs/superpowers/specs/2026-08-27-lattice-form-ir-design.md +++ b/docs/superpowers/specs/2026-08-27-lattice-form-ir-design.md @@ -1,7 +1,7 @@ -# 格形态 IR 设计:.ccr 升级为格形态(C 路线) +# 格形态 IR 设计:`.ccr` 升级为格形态(C 路线) 日期:2026-08-27 -状态:**方向定稿 → 已实质化实施(2026-09)**——v6 格式与数据面落地(`specs/2026-09-05-lattice-ir-v6-format.md` 格式定稿 + `plans/2026-09-05-lattice-ir-v6.md` 实施计划 Task 1-5 完成:存在区间/条目版本化/共存推导/段表 IO/判定自检);v5→v6 一次性转换按定稿取消(.ccr 中间产物零生态,v6-only)。关联:`docs/regalloc-cache-mapping.md`、`docs/memory-model-capability-lattice.md` v4。 +状态:**方向定稿 → 已实质化实施(2026-09)**——v6 格式与数据面落地(`specs/2026-09-05-lattice-ir-v6-format.md` 格式定稿 + `plans/2026-09-05-lattice-ir-v6.md` 实施计划 Task 1-5 完成:存在区间/条目版本化/共存推导/段表 IO/判定自检);v5→v6 一次性转换按定稿取消(`.ccr` 中间产物零生态,v6-only)。关联:`docs/regalloc-cache-mapping.md`、`docs/memory-model-capability-lattice.md` v4。 ## 1. 背景与动机 @@ -15,15 +15,15 @@ | **格形态** | 格 = 存在空间 | `.ccr`(**本设计对象**) | 承载存在(状态/条目/共存/驱逐) | | 编码形态 | 编码 = 物理编码空间 | ELF | 运行 | -### 1.2 .ccr 的名实不符 +### 1.2 `.ccr` 的名实不符 -- 缩写:`.ccr` = Core **Control-flow** Representation(`docs/ir-schema/coreir-schema.md`)——名字写着 CFG +- 缩写:`.ccr` = Core **Control-flow** Representation(`docs/ir-schema/coreir-schema.md`)——名称写的是 CFG - 内容:v5 格式已是 **SG region 段**(`sg_count × 24B`:kind/enter/exit/parent/nstart/ncount)——内容早已是区域结构(图锚定存在结构),不再是「基本块控制流」 -- 语义:CFG 即将淘汰变成格(正确性不再按 CFG 路径陈述,而是对全部可能执行成立)——「控制流表示」的定位描述全部过时 +- 语义:CFG 即将被格取代(正确性不再按 CFG 路径陈述,而是对全部可能执行成立)——「控制流表示」的定位描述全部过时 -### 1.3 时机:趁程序生态小 +### 1.3 时机:程序生态规模小 -格形态马上要出;当前 `.cr`/`.ccr` 程序生态很小。**改名与格式升级现在定案 = O(仓库);以后定案 = O(仓库 + 生态 + 产物/缓存)**。C 路线:改名与格式升级合一,**一次迁移**。 +格形态即将落地;当前 `.cr`/`.ccr` 程序生态规模很小。**改名与格式升级现在定案 = O(仓库);以后定案 = O(仓库 + 生态 + 产物/缓存)**。C 路线:改名与格式升级合一,**一次迁移**。 ## 2. 定位 @@ -40,9 +40,9 @@ | **A(已定案)** | 扩展名 `.ccr` 保留,缩写展开改为 **Core Region Representation**;格式 v6 内部升级 | 零生态成本:扩展名 / magic(`CCR1`)/ CLI / 文件路径全不动 | | B | 新扩展名(`.rir` / `.cer` / `.exr`)+ 新 magic + CLI 子命令 | 全链改名(代码/测试/文档),与 v6 升级同一迁移批次 | -**推荐 A**:改名(语义)与格式升级合一的关键是「一次迁移」——扩展名不动则迁移面最小;region 一词准确反映 v5 已落地的 SG region 段与图锚定存在结构。若未来需要显式区分「格形态」与「线性投影」两种格式,再引入 B 不迟。 +**推荐 A**:改名(语义)与格式升级合一的关键是「一次迁移」——扩展名不动则迁移面最小;region 一词准确反映 v5 已落地的 SG region 段与图锚定存在结构。若未来需要显式区分「格形态」与「线性投影」两种格式,届时再引入 B 即可。 -**已定案(2026-08-27 拍板):方案 A**——扩展名 `.ccr` 保留,缩写展开 = Core Region Representation;扩展名 / magic(`CCR1`)/ CLI / 文件路径全不动,零生态成本。 +**已定案(2026-08-27 确定):方案 A**——扩展名 `.ccr` 保留,缩写展开 = Core Region Representation;扩展名 / magic(`CCR1`)/ CLI / 文件路径全不动,零生态成本。 ## 4. 格式设计方向(v6) @@ -54,7 +54,7 @@ ### 4.2 v6 增量(存在结构段) -**不做格式兼容**:v6 与 v5 是数学结构大改(线性程序 → 存在结构)——条目/存在区间/共存/驱逐不是「追加段」能表达的(v4→v5 的 SG 段只是尾部超集扩展,先例不适用)。提供 **v5 → v6 一次性转换**(从线性投影重建存在结构:图活性推导 + 版本化重建),趁程序生态小转换成本最低: +**不做格式兼容**:v6 与 v5 是数学结构大改(线性程序 → 存在结构)——条目/存在区间/共存/驱逐不是「追加段」能表达的(v4→v5 的 SG 段只是尾部超集扩展,先例不适用)。提供 **v5 → v6 一次性转换**(从线性投影重建存在结构:图活性推导 + 版本化重建),程序生态规模小时转换成本最低: 1. **条目版本段**:版本化条目(变量 × 版本)→ 存在区间 [start, end](图活性,RegionCheck 语义) 2. **共存关系**:存在区间相交的显式标注,或推导规则(从图活性派生,避免冗余存储) @@ -85,13 +85,13 @@ - ❌ 不做 `.cir` 改名(图形态不变) - ❌ 不做 ELF 改名(编码形态不变) -- ❌ 本会话不做任何代码改动(执行交第二维护者) +- ❌ 本会话不做任何代码改动(执行交由第二维护者) - ✅ 做:命名定案、格式 v6 设计细化、迁移清单(→ TODO.md) ## 7. 验收标准 - 格式 v6 可序列化/反序列化(自身闭环,不承诺 v5 后向兼容——数学结构大改) -- v5 → v6 一次性转换工具(趁程序生态小;不承诺双向兼容) +- v5 → v6 一次性转换工具(程序生态规模小时进行;不承诺双向兼容) - 存在结构段携带:条目版本、存在区间、共存、home、无配方标记 - 分配判定从格形态直接消费(无 CFG 路径结构) - 命名体系三形态一致:图 = `.cir` / 格 = `.ccr`(或定案名)/ 编码 = ELF diff --git a/docs/superpowers/specs/2026-08-27-regalloc-cache-mapping-design.md b/docs/superpowers/specs/2026-08-27-regalloc-cache-mapping-design.md index 186457e5..bbc571fd 100644 --- a/docs/superpowers/specs/2026-08-27-regalloc-cache-mapping-design.md +++ b/docs/superpowers/specs/2026-08-27-regalloc-cache-mapping-design.md @@ -7,15 +7,15 @@ ### 1.1 问题 -寄存器分配如何**完全形式化验证**?候选算法空间(图着色 / 线性扫描 / SSA 弦图 / SPL 语法分解)都存在同一障碍:**正确性绑定在 CFG 结构上**——验证要么证明算法机制(CompCert 式,随算法变、贵),要么在运行时再跑一遍检查(双重验证)。 +寄存器分配的**完全形式化验证**需在候选算法空间(图着色 / 线性扫描 / SSA 弦图 / SPL 语法分解)中取舍;该空间内各方案都存在同一障碍:**正确性绑定在 CFG 结构上**——验证要么证明算法机制(CompCert 式,随算法变、贵),要么在运行时再跑一遍检查(双重验证)。 ### 1.2 关键转向:缓存语义视角 -在 Core 的框架里,寄存器分配不是「编译器 pass」,而是**格 → 编码的映射实例**——与区域 / arena / 字节权限同族(缓存语义条款 7)。寄存器文件 = 缓存层,home(栈槽)= 经典映射。由此: +在 Core 的框架里,寄存器分配不是「编译器 `pass`」,而是**格 → 编码的映射实例**——与区域 / `arena` / 字节权限同族(缓存语义条款 7)。寄存器文件 = 缓存层,`home`(栈槽)= 经典映射。由此: -- **驱逐不变量(条款 2)就是现成的语义保持定理**——驱逐任意条目不改变可观测语义。分配器把哪个条目放寄存器、放多久,只是放置/替换策略(与 LRU 无需证明同理),**算法零证明** +- **驱逐不变量(条款 2)就是现成的语义保持定理**——驱逐任意条目不改变可观测语义。分配器把哪个条目放寄存器、放多久,只是放置/替换策略(与 `LRU` 无需证明同理),**算法零证明** - **验证义务收敛为映射实例的一致性判定**——单层、可判定、局部 -- **CFG 算法(线性扫描/图着色/SPL)都是线性化退化实例**——不进入语义本体;「CFG 即将淘汰变成格」对分配的正确含义:正确性不再对某条线性化路径陈述,而是对**全部可能执行**成立(order-free) +- **`CFG` 算法(线性扫描/图着色/`SPL`)都是线性化退化实例**——不进入语义本体;「`CFG` 即将淘汰变成格」对分配的正确含义:正确性不再对某条线性化路径陈述,而是对**全部可能执行**成立(`order-free`) ### 1.3 已排除的方向(讨论记录) @@ -27,9 +27,9 @@ ## 2. 语义基座(律) -- **公理 = 缓存语义七条**(memory-model.md §一)——零签名、无格承诺(能力+格备忘 v4 §4.6) -- **驱逐不变量 = 语义保持定理**:⟦G ∖ storage(e)⟧ = ⟦G⟧——分配正确性与执行顺序无关,对全部可能执行成立(强于任何 CFG 正确性:CFG 只对一个线性化成立) -- 判定/定理只在**关系层面**陈述(共存关系连预序公理都不需要——共存无传递性,是对称关系);对一切格成立,CIC 内核中任何具体格都是该理论的一个模型 +- **公理 = 缓存语义七条**(`memory-model.md` §一)——零签名、无格承诺(能力+格备忘 v4 §4.6) +- **驱逐不变量 = 语义保持定理**:⟦G ∖ storage(e)⟧ = ⟦G⟧——分配正确性与执行顺序无关,对全部可能执行成立(强于任何 `CFG` 正确性:`CFG` 只对一个线性化成立) +- 判定/定理只在**关系层面**陈述(共存关系连预序公理都不需要——共存无传递性,是对称关系);对一切格成立,`CIC` 内核中任何具体格都是该理论的一个模型 ## 3. 对象(物) @@ -41,7 +41,7 @@ | 共存 | 两个条目的存在区间相交(对称关系;互斥分支中的条目永不共存——无路径结构,由状态空间直接给出) | | home | 条目的持久位置(经典映射 = 栈槽) | -**无配方条目**(边界 + 图内不可重算,能力+格备忘 v4 §5.3)一条通用规则:**必须有 home,驱逐必写回**——驱逐不变量/再生等价对它们不成立(重跑神谕 ≠ 原结果)。对所有无配方条目一视同仁,不按范式枚举。 +**无配方条目**(边界 + 图内不可重算,能力+格备忘 v4 §5.3)一条通用规则:**必须有 `home`,驱逐必写回**——驱逐不变量/再生等价对它们不成立(重跑神谕 ≠ 原结果)。对所有无配方条目一视同仁,不按范式枚举。 ## 4. 判定(验证,单层) @@ -49,23 +49,23 @@ 1. **共存互斥**:每时刻每寄存器至多一个条目的材料(共存 = 存在区间相交) 2. **读点无陈旧**:读到的材料与条目的当前版本对齐(条款 5 版本化) -3. **驱逐配对**:驱逐(寄存器回收)时材料不丢——写回 home,或配方可再生(条款 3 再生等价 = rematerialization);无配方条目必写回(§3) -4. **调用点失效契约**:调用点 = 缓存失效边界——caller-saved 失效(材料归 home),callee-saved 保留(ABI 即缓存保留契约) +3. **驱逐配对**:驱逐(寄存器回收)时材料不丢——写回 `home`,或配方可再生(条款 3 再生等价 = `rematerialization`);无配方条目必写回(§3) +4. **调用点失效契约**:调用点 = 缓存失效边界——`caller-saved` 失效(材料归 `home`),`callee-saved` 保留(`ABI` 即缓存保留契约) -**算法零证明**:正确性由判定保证,与分配算法选择无关(生成器 + 验证器分离——2025 年 LLM 分配器 VeriLocc 同构先例)。分配算法定案 = 上下文贪心(§5)。 +**算法零证明**:正确性由判定保证,与分配算法选择无关(生成器 + 验证器分离——2025 年 `LLM` 分配器 `VeriLocc` 同构先例)。分配算法定案 = 上下文贪心(§5)。 **落点**(双层消费同一规约): -- `.corespec` 契约——「寄存器映射实例合法」判定写成规约(spec-design.md §2.7 体系:翻译桥 → CIC 内核,健全性由内核保证) -- 编译器内 checker——实现期自检(每编译一次,失败 = 分配器 bug 即时暴露) +- `.corespec` 契约——「寄存器映射实例合法」判定写成规约(`spec-design.md` §2.7 体系:翻译桥 → `CIC` 内核,健全性由内核保证) +- 编译器内 `checker`——实现期自检(每编译一次,失败 = 分配器 bug 即时暴露) ## 5. 分配器(定案:上下文贪心) -**共存偏序上的贪心放置**:上下文 = 共存关系 + 再生成本(配方)+ region 生命周期 + 调用点。**定案(2026-08-27):上下文贪心为唯一分配算法**;判定不依赖算法选择(算法规格见 `docs/regalloc-cache-mapping.md` §五)。 +**共存偏序上的贪心放置**:上下文 = 共存关系 + 再生成本(配方)+ `region` 生命周期 + 调用点。**定案(2026-08-27):上下文贪心为唯一分配算法**;判定不依赖算法选择(算法规格见 `docs/regalloc-cache-mapping.md` §五)。 -- 版本区间(IR_STORE 切分)——对应条款 5 版本化,比 first/last 全函数区间精确 -- spill = 驱逐写回 home;remat = 配方重算(成本 = 产生节点重算代价) -- 调用点感知:解锁 caller-saved 寄存器(x86-64 通用寄存器 16 个 + XMM,现实现仅用 5 个 callee-saved) -- **CFG 退化情形 = 区间序 First Fit = 最优**(Dilworth:最小寄存器数 = 共存偏序的 width;区间图 = 完美图,χ = ω)——数学闭合 +- 版本区间(`IR_STORE` 切分)——对应条款 5 版本化,比 `first`/`last` 全函数区间精确 +- `spill` = 驱逐写回 `home`;`remat` = 配方重算(成本 = 产生节点重算代价) +- 调用点感知:解锁 `caller-saved` 寄存器(x86-64 通用寄存器 16 个 + `XMM`,现实现仅用 5 个 `callee-saved`) +- **`CFG` 退化情形 = 区间序 `First Fit` = 最优**(`Dilworth`:最小寄存器数 = 共存偏序的 width;区间图 = 完美图,χ = ω)——数学闭合 ## 6. 数学支撑(文献) @@ -77,26 +77,26 @@ ## 7. 范围边界(YAGNI) -- ❌ 不做 SSA 转换(版本化语义已在,§3 条目 = 版本;IR 不需要 SSA 化) -- ❌ 不做图着色机制、不做 SPL 分解实现(CFG 系,方向已弃) +- ❌ 不做 `SSA` 转换(版本化语义已在,§3 条目 = 版本;IR 不需要 `SSA` 化) +- ❌ 不做图着色机制、不做 `SPL` 分解实现(`CFG` 系,方向已弃) - ❌ 不做格代数承诺(§2:关系层面陈述;格 = 映射参数,将来挂接) -- ❌ 不做 spill 指令级插入(后端映射细节,判定先行) -- ✅ 做:共存关系定义落定 → `.corespec` 判定规约 → 贪心放置实现 → checker 自检 +- ❌ 不做 `spill` 指令级插入(后端映射细节,判定先行) +- ✅ 做:共存关系定义落定 → `.corespec` 判定规约 → 贪心放置实现 → `checker` 自检 ## 8. 落地顺序 -1. **共存关系落定**:图活性存活区间相交(复用 RegionCheck 的 cur_seq/exit_seq 机制),确认条目版本的图表示 +1. **共存关系落定**:图活性存活区间相交(复用 `RegionCheck` 的 `cur_seq`/`exit_seq` 机制),确认条目版本的图表示 2. **判定规约**:一致性四条写成 `.corespec`(先规格后实现) -3. **贪心放置策略**:版本区间 + 共存检查 + 驱逐写回(现 `opt.cr` alloc_registers 增量升级) -4. **checker**:编译期一致性自检(debug 模式全开,release 可选) -5. **(远期)证书层**:最优性证书(DP 表重放或 ILP 对偶)——验证「最优」而不只是「一致」 +3. **贪心放置策略**:版本区间 + 共存检查 + 驱逐写回(现 `opt.cr` `alloc_registers` 增量升级) +4. **`checker`**:编译期一致性自检(`debug` 模式全开,`release` 可选) +5. **(远期)证书层**:最优性证书(`DP` 表重放或 `ILP` 对偶)——验证「最优」而不只是「一致」 ## 9. 验收标准 - 判定:可判定、局部、条目泛型;对一切格成立(关系层面陈述) - 分配器:任意替换/升级贪心策略,判定与语义保持不受影响 -- 语义保持:驱逐不变量成立(order-free,对所有可能执行) -- 无配方条目:统一规则(有 home、驱逐必写回),无范式枚举 +- 语义保持:驱逐不变量成立(`order-free`,对所有可能执行) +- 无配方条目:统一规则(有 `home`、驱逐必写回),无范式枚举 - 与 #10 判据联动:判定以纯格对象写出(无路径结构)=「格不重引入顺序」的实证 ## 10. 关联 @@ -106,4 +106,4 @@ - `docs/dataflow-design.md` §8(执行标注空间——无配方条目的来源) - `docs/pointer-model.md`(RegionCheck:存在区间的现有实现) - `docs/spec-design.md`(.corespec 规约体系) -- 实现现状:`src/compiler/opt.cr`(alloc_registers 朴素线性扫描 + g_opt_meta 映射 + pass_stack_share) +- 实现现状:`src/compiler/opt.cr`(`alloc_registers` 朴素线性扫描 + `g_opt_meta` 映射 + `pass_stack_share`) diff --git a/docs/superpowers/specs/2026-08-28-lsp-production-design.md b/docs/superpowers/specs/2026-08-28-lsp-production-design.md index 938b7329..39fff333 100644 --- a/docs/superpowers/specs/2026-08-28-lsp-production-design.md +++ b/docs/superpowers/specs/2026-08-28-lsp-production-design.md @@ -6,15 +6,15 @@ ## 一、背景与动机 -corelsp 已端到端跑通(Zed 扩展 wasm 机制 + 诊断/补全/悬停/跳转/符号/语义令牌,2026-08-28 验证)。但存在生产级缺口:单文件检查(跨文件符号未解析 → 假错误)、无增量、无错误恢复边界。同时 Core 拥有其他语言 LSP 没有的语义数据矿藏(HDFG 图、指针三 pass、缓存语义、范式标注、验证内核)——生产化的目标不仅是「补缺口」,更是「语义保鲜进 IDE」的差异化兑现。 +`corelsp` 已端到端跑通(Zed 扩展 `wasm` 机制 + 诊断/补全/悬停/跳转/符号/语义令牌,2026-08-28 验证)。现状存在生产级缺口:单文件检查(跨文件符号未解析 → 假错误)、无增量、无错误恢复边界。Core 另拥有其他语言 LSP 不具备的语义数据矿藏(`HDFG` 图、指针三 `pass`、缓存语义、范式标注、验证内核)——生产化的目标不仅是「补缺口」,更是「语义保鲜进 IDE」的差异化兑现。 ## 二、决策链(2026-08-28 brainstorming 五问定案) -1. **编辑器覆盖面**:Zed 优先,VS Code 后置——LSP 协议层保持编辑器无关,客户端(渲染)先在 Zed 写一套 -2. **数据通道**:混合——标准 LSP 承载一切可渲染的(hover 富内容 / inlay hints / 诊断增强 / 语义令牌);重 UI(图视图/管线探索器)为独立查看器(coreview,读 .cir/.ccr dump)——Zed 扩展 API 无面板/WebView,全屏 UI 无宿主 -3. **检查架构**:分阶段——P0 import 闭包级,P1 项目级分析服务(rust-analyzer 式);架构预留策略接口 -4. **查看器形态**:Web 应用(coreview:静态 + 图渲染库;VS Code 后置时可作 Webview 嵌入) -5. **代码库演进**:corelsp 增量演进(方案 A)——检查会话抽象为策略,不推倒重写 +1. **编辑器覆盖面**:Zed 优先,VS Code 后置——`LSP` 协议层保持编辑器无关,客户端(渲染)先在 Zed 写一套 +2. **数据通道**:混合——标准 LSP 承载一切可渲染的(`hover` 富内容 / `inlay hints` / 诊断增强 / 语义令牌);重 UI(图视图/管线探索器)为独立查看器(`coreview`,读 `.cir`/`.ccr` dump)——Zed 扩展 API 无面板/WebView,全屏 UI 无宿主 +3. **检查架构**:分阶段——P0 `import` 闭包级,P1 项目级分析服务(`rust-analyzer` 式);架构预留策略接口 +4. **查看器形态**:Web 应用(`coreview`:静态 + 图渲染库;VS Code 后置时可作 Webview 嵌入) +5. **代码库演进**:`corelsp` 增量演进(方案 A)——检查会话抽象为策略,不推倒重写 ## 三、架构总览 @@ -27,7 +27,7 @@ src/lsp/(corelsp 增量) coreview/ 新增:Web 查看器(解析 .cir/.ccr dump,图渲染 + 管线分屏) ``` -原则:数据源全部来自编译器既有产物(三 pass / 图 / dump / 验证内核),LSP 只做「接线 + 呈现」,不重复实现分析。 +原则:数据源全部来自编译器既有产物(三 `pass` / 图 / dump / 验证内核),LSP 只做「接线 + 呈现」,不重复实现分析。 ## 四、能力矩阵与分期 @@ -45,28 +45,28 @@ coreview/ 新增:Web 查看器(解析 .cir/.ccr dump,图渲染 + // 三实现共用同一接口;rpc/lsp 层只面对接口,不感知粒度 ``` -- P0 实现 ClosureSession:复用 `module.cr res_imports` 解析闭包,闭包一起过 checker;pts 等按闭包近似(interprocedural 精度 P1 解决) -- P1 实现 ProjectSession:全项目编译一次进内存,变更重编译受影响文件(增量/缓存/失效传播) +- P0 实现 `ClosureSession`:复用 `module.cr` 的 `res_imports` 解析闭包,闭包一起过 `checker`;`pts` 等按闭包近似(`interprocedural` 精度 P1 解决) +- P1 实现 `ProjectSession`:全项目编译一次进内存,变更重编译受影响文件(增量/缓存/失效传播) ## 六、富内容格式(全部标准 LSP,零协议扩展) -- hover:结构化 markdown(代码块 + 表格)——指针 points-to 集合、配方、范式标注、证明状态(P1+) -- inlay hints:版本链(x₀→x₁→x₂)、惰性标注(P2)、寄存器映射(P2) -- 诊断:code 分类(CORE-E001…),unsafe/例外入口区域标记 +- `hover`:结构化 `markdown`(代码块 + 表格)——指针 `points-to` 集合、配方、范式标注、证明状态(P1+) +- `inlay hints`:版本链(x₀→x₁→x₂)、惰性标注(P2)、寄存器映射(P2) +- 诊断:`code` 分类(`CORE-E001`…),`unsafe`/例外入口区域标记 - 语义令牌:现有(keyword/type/function/variable/…) ## 七、coreview(独立查看器) -- 形态:静态 Web 应用(HTML + JS + cytoscape.js),无后端依赖 +- 形态:静态 Web 应用(`HTML` + `JS` + `cytoscape.js`),无后端依赖 - 数据源:`corec cir` / `corec ccr` dump(现有命令输出) -- 功能 v1:HDFG 图视图(DFNode/DFEdge + region 嵌套 + state edges)、管线探索器(源码 ↔ AST ↔ HDFG ↔ 格形态 IR ↔ 汇编分屏) +- 功能 v1:`HDFG` 图视图(`DFNode`/`DFEdge` + `region` 嵌套 + `state edges`)、管线探索器(源码 ↔ `AST` ↔ `HDFG` ↔ 格形态 IR ↔ 汇编分屏) - 联动(P1+):与 LSP 双向高亮(代码 ↔ 图)——文件轮询或小服务 ## 八、测试与验收 -- LSP 协议测试扩展:富内容/inlay/诊断 code 的协议用例(现有 test_lsp.py 体系) -- coreview:dump 文件快照测试(图结构断言) -- 验收线:P0 = Zed 日常写 Core 无假错误 + 指针 hover 可用;P1 = 项目级精度 + 完整 IDE 体验;P2 = 差异化全兑现 +- LSP 协议测试扩展:富内容/`inlay`/诊断 `code` 的协议用例(现有 `test_lsp.py` 体系) +- `coreview`:dump 文件快照测试(图结构断言) +- 验收线:P0 = Zed 日常写 Core 无假错误 + 指针 `hover` 可用;P1 = 项目级精度 + 完整 IDE 体验;P2 = 差异化全兑现 ## 九、依赖与风险 @@ -82,9 +82,9 @@ coreview/ 新增:Web 查看器(解析 .cir/.ccr dump,图渲染 + ## 十、落地顺序 -1. P0:session.cr 策略接口 + ClosureSession(import 闭包)→ 错误恢复 → hover 富内容 v1 → inlay v1 → 诊断增强 → 协议测试 → Zed 验证(验收线) -2. P1:coreview v1 → 项目级会话 → 增量 sync=2 → rename/references → 完整 IDE 体验 -3. P2:随主线(惰性/寄存器/验证管线各就位后接线)+ coreview 联动 + VS Code 客户端 +1. P0:`session.cr` 策略接口 + `ClosureSession`(`import` 闭包)→ 错误恢复 → `hover` 富内容 v1 → `inlay` v1 → 诊断增强 → 协议测试 → Zed 验证(验收线) +2. P1:`coreview` v1 → 项目级会话 → 增量 `sync=2` → `rename`/`references` → 完整 IDE 体验 +3. P2:随主线(惰性/寄存器/验证管线各就位后接线)+ `coreview` 联动 + VS Code 客户端 ## 十一、关联 diff --git a/docs/superpowers/specs/2026-09-01-syntax-doc-rewrite-design.md b/docs/superpowers/specs/2026-09-01-syntax-doc-rewrite-design.md index 12af2a99..cf447e60 100644 --- a/docs/superpowers/specs/2026-09-01-syntax-doc-rewrite-design.md +++ b/docs/superpowers/specs/2026-09-01-syntax-doc-rewrite-design.md @@ -1,4 +1,4 @@ -# 语法文档重写设计(language-syntax.md) +# 语法文档重写设计(`language-syntax.md`) 日期:2026-09-01 状态:已批准(brainstorming 逐节确认) diff --git a/docs/superpowers/specs/2026-09-06-int-unbounded-semantics.md b/docs/superpowers/specs/2026-09-06-int-unbounded-semantics.md index 80465c09..68b935da 100644 --- a/docs/superpowers/specs/2026-09-06-int-unbounded-semantics.md +++ b/docs/superpowers/specs/2026-09-06-int-unbounded-semantics.md @@ -11,7 +11,7 @@ - `docs/superpowers/specs/2026-08-16-numeric-types-design.md`(2026-08-23 修订:int = 无上限数学整数)+ `docs/superpowers/specs/2026-08-23-hw-map-design.md`(hw-map = 语义表 + 投影表) - TODO `dex-precision`(dex 任意精度精确小数挂账) -> 一句话:**int 在语义层 = 数学整数的公理化接口(无溢出概念);「64 位」「i64 上限」「环绕」全部是编码层(hw-map 域)的经典投影实例形状——溢出不是语义事件,溢出错也不是语义错误。** +> 要点:**int 在语义层 = 数学整数的公理化接口(无溢出概念);「64 位」「i64 上限」「环绕」全部是编码层(hw-map 域)的经典投影实例形状——溢出不是语义事件,溢出错也不是语义错误。** ## 一、语义层定稿:int = 数学整数公理化接口 diff --git a/docs/superpowers/specs/2026-09-07-regalloc-backend-design.md b/docs/superpowers/specs/2026-09-07-regalloc-backend-design.md index 95e67918..1bf13fb6 100644 --- a/docs/superpowers/specs/2026-09-07-regalloc-backend-design.md +++ b/docs/superpowers/specs/2026-09-07-regalloc-backend-design.md @@ -1,13 +1,12 @@ # 寄存器分配移后端设计(编码层资源决策归位) 日期:2026-09-07 -状态:**设计定稿 + 实施完成(2026-09-07——R1-R5 全部拍板落地,见 §6 决策记录与 -实施计划执行记录)** +状态:**设计定稿 + 实施完成(2026-09-07——R1-R5 全部拍板落地,见 §6 决策记录与实施计划执行记录)** 关联:`docs/regalloc-cache-mapping.md`(判定四条/上下文贪心)、`specs/2026-09-05-lattice-ir-v6-format.md`(v6 ENT home)、`specs/2026-09-06-int-multiword-backend-design.md`(多字表示 = 后端)、`specs/2026-09-05-hardware-interface-table.md`(优化不进表——判定/分配在格形态层)、compile-time-linearity 计划(corec 时间分布)。 ## 1. 归属论证 -**寄存器是物理资源——分配是编码层决策**(与 int 多字表示、指令发射同层)。现状分配器在 corec(opt.cr)纯属历史(v5 时代后端无决策能力);「g2_slot 负编码 = 纯机械翻译分配结果」的表述把后端固定成执行者——分配归位后此表述取消:后端自己做分配,g2_slot 是后端的槽解析 seam(决策的一部分),非机械翻译。 +寄存器是物理资源,分配属于编码层决策,与 int 多字表示、指令发射同层。分配器现位于 corec(`opt.cr`),属 v5 时代的历史遗留:当时后端不具备决策能力。原文以「`g2_slot` 负编码 = 纯机械翻译分配结果」的表述把后端固定成执行者,分配归位后该表述取消:后端自行完成分配,`g2_slot` 是后端的槽解析 seam(决策的一部分),不是机械翻译。 ``` 现状:corec(数据面+分配+判定)→ .ccr 传 REG_ASSIGN → corearch 机械消费负编码 @@ -17,24 +16,25 @@ ## 2. 迁移形态(决策点 R1 —— **R1a 拍板落地**) -opt.cr 相关函数(compute_live_ranges/compute_entries/共存/alloc_registers/verify)——**按层拆分(R1a)**: -- opt.cr 现既在 corec 闭包(优化 pass 含 CSE 等仍属 corec 吗?——CSE/pass_cse 是图优化=语义层?分配是编码层——opt.cr 里两类混居) -- **R1a(拍板)**:opt.cr 拆分——语义优化(AST 常量折叠 + pass_cse 留 corec)与编码决策(数据面/共存/分配/判定/注入)移 corearch(新文件 `src/arch/linux/ld/regalloc.cr`,加入 corearch 闭包)。corec 侧 opt.cr 1940→312 行(剩件 = AST 折叠 + CSE + optimize_all 死码编排入口);main.cr O2 段/`cir` 调试通道摘除 +`opt.cr` 的相关函数(compute_live_ranges/compute_entries/共存/alloc_registers/verify)按层拆分(R1a)。 + +- `opt.cr` 现既在 corec 闭包之内,其中优化 pass 含 CSE 等的归属需先判定:CSE/pass_cse 是图优化即语义层,分配是编码层,两类在 `opt.cr` 里混居 +- **R1a(拍板)**:`opt.cr` 拆分——语义优化(AST 常量折叠 + pass_cse 留 corec)与编码决策(数据面/共存/分配/判定/注入)移 corearch(新文件 `src/arch/linux/ld/regalloc.cr`,加入 corearch 闭包)。corec 侧 `opt.cr` 1940→312 行(剩件 = AST 折叠 + CSE + optimize_all 死码编排入口);`main.cr` O2 段/`cir` 调试通道摘除 - R1b(弃):整文件入 corearch 闭包——CSE 是图优化应留 corec -## 3. .ccr 简化(决策点 R2 —— **D-1=Y 拍板落地**) +## 3. `.ccr` 简化(决策点 R2 —— **D-1=Y 拍板落地**) -- opt_meta(含 REG_ASSIGN)出 .ccr——分配结果不再传输(corearch load 后自算) +- opt_meta(含 REG_ASSIGN)出 `.ccr`——分配结果不再传输,corearch load 后自算 - **ENT 段恒空(D-1=Y)**:corec save 不再落条目——SYM func/REG `first_ent/last_ent` 恒 -1、param_ents 恒 -1、ENT 段 0 条、opt_meta 子节 0 块;**格式结构保留**(loader 空表语义已支持:段缺失/0 条 + pcnt==0 ↔ -1 对照),**零 version bump**。ENT home 字段随 ENT 落盘消亡(内存表 home 字段保留——corearch 自算内存态,M1 分配不回填) -- 数据面计算单宿主 corearch:compute_live_ranges/compute_entries 随 regalloc.cr 迁入,载入 NOD 流自算(与 .ccr 载荷同坐标)——corec lower 尾/落盘直写废止 +- 数据面计算单宿主 corearch:compute_live_ranges/compute_entries 随 `regalloc.cr` 迁入,载入 NOD 流自算(与 `.ccr` 载荷同坐标)——corec lower 尾/落盘直写废止 ## 4. 判定位置(决策点 R3 —— 拍板落地) -verify_regalloc_consistency/regalloc_verify_all 随分配移 corearch(regalloc.cr):corearch O2 = load 后自算分配 + 自检(emit 前,违反 = 编译错误,成功静默)。corec build 路径判定触发移除(main.cr);corec `cir` 通道随迁 corearch 同名隐藏 flag(--dump-entries/--dump-coexist/--check-regalloc/--inject-*/--dump-regassign),红注入用例在 corearch 路径仍红(test_live_ranges 13/13)。 +verify_regalloc_consistency/regalloc_verify_all 随分配移 corearch(`regalloc.cr`):corearch O2 = load 后自算分配 + 自检(emit 前,违反 = 编译错误,成功静默)。corec build 路径判定触发移除(`main.cr`);corec `cir` 通道随迁 corearch 同名隐藏 flag(--dump-entries/--dump-coexist/--check-regalloc/--inject-*/--dump-regassign),红注入用例在 corearch 路径仍红(test_live_ranges 13/13)。 ## 5. 多字整合 -tagged 识别在 corearch(instr.cr mw_setup_tags)——分配移入后与 tagged 信息同侧(迁移前 Task 5 靠 REG_ASSIGN 元数据跨进程读取——现同进程)。判定消费 ENT(自算)+ tag 表——零通道。test_mw_task5 元断言改经 corearch `--dump-regassign`(O2 自算分配逐对输出):2L 溢出函数 tagged∩REG_ASSIGN ≠ ∅ 保持(reg 形态裁决在 corearch 自算下成立)。 +tagged 识别在 corearch(`instr.cr` mw_setup_tags)——分配移入后与 tagged 信息同侧(迁移前 Task 5 靠 REG_ASSIGN 元数据跨进程读取——现同进程)。判定消费 ENT(自算)+ tag 表——零通道。test_mw_task5 元断言改经 corearch `--dump-regassign`(O2 自算分配逐对输出):2L 溢出函数 tagged∩REG_ASSIGN ≠ ∅ 保持(reg 形态裁决在 corearch 自算下成立)。 ## 6. 决策点清单(**2026-09-07 全部拍板 + 实施**) @@ -42,15 +42,15 @@ tagged 识别在 corearch(instr.cr mw_setup_tags)——分配移入后与 ta 2. **R2** = **D-1=Y**:opt_meta 子节恒 0 + ENT 段恒空(first/last_ent/param_ents 恒 -1)——格式结构保留、loader 空表语义已支持、零 version bump;home 字段随落盘消亡(内存表保留,corearch 自算) 3. **R3**:verify 触发点 = corearch O2(load 后 alloc + verify,emit 前,违反 = 编译错误);corec 判定触发与 `cir` 通道移除(注入通道随迁同名 flag) 4. **R4**(注):编译时间分布——分配/数据面计算移 corearch 进程;compile-time-linearity 的 corec 侧减负面按实测另行记录(未列入本批) -5. **R5** = **拍板**:corec `-O` 门语义——O1 = CSE(corec 进程内,实证:对 .ccr 产物零效果——NOD O0/O1/O2 逐字节同);O2 分配在 corearch(corec build 透传 `--opt-level`;直接调 corearch 未传 -O = O0 全栈)。CLI 帮助文案已更新(corec/corearch) +5. **R5** = **拍板**:corec `-O` 门语义——O1 = CSE(corec 进程内,实证:对 `.ccr` 产物零效果——NOD O0/O1/O2 逐字节同);O2 分配在 corearch(corec build 透传 `--opt-level`;直接调 corearch 未传 -O = O0 全栈)。CLI 帮助文案已更新(corec/corearch) 6. **D-3**(附加拍板):pass_stack_share 停用摘除(产物死路径实证——g_stack_map 不落盘、corearch 恒空;恢复 = corearch 内 alloc 同 seam 实现,挂账) ## 7. 受波及面(**均已处置**) -- opt.cr 拆分(1940→312 行——语义 vs 编码切分;纯搬移提交 + 切换提交两步可独立评审) -- ccr_io.cr(ENT/opt_meta save 恒空 + func/REG first/last -1)+ 测试(test_ccr_v6 8/8 重写恒空断言;region_cfg walker 兼容零改) -- corearch 闭包(build_selfhost_native.py + regalloc.cr)+ backend_bootstrap(stage0-2 绿——分配在后端自举语义验证) -- main.cr O2 门/判定触发移除 + `cir` 调试通道摘除 -- 「纯机械映射」表述清除(regalloc.cr/instr.cr/globals.cr/regalloc-consistency.cr 注记更新) -- regalloc-consistency.cr(参考实现指针 → regalloc.cr + 停用/缺口注记更新) +- `opt.cr` 拆分(1940→312 行——语义 vs 编码切分;纯搬移提交 + 切换提交两步可独立评审) +- `ccr_io.cr`(ENT/opt_meta save 恒空 + func/REG first/last -1)+ 测试(test_ccr_v6 8/8 重写恒空断言;region_cfg walker 兼容零改) +- corearch 闭包(`build_selfhost_native.py` + `regalloc.cr`)+ backend_bootstrap(stage0-2 绿——分配在后端自举语义验证) +- `main.cr` O2 门/判定触发移除 + `cir` 调试通道摘除 +- 「纯机械映射」表述清除(`regalloc.cr`/`instr.cr`/`globals.cr`/regalloc-consistency.cr 注记更新) +- regalloc-consistency.cr(参考实现指针 → `regalloc.cr` + 停用/缺口注记更新) - 多字 mw 测试(REG_ASSIGN 元数据通道 → corearch `--dump-regassign`;test_mw_task5 标记值更新绿) diff --git a/docs/superpowers/specs/2026-09-09-lattice-ir-v7-format.md b/docs/superpowers/specs/2026-09-09-lattice-ir-v7-format.md index e6d1b4c6..de9efb0a 100644 --- a/docs/superpowers/specs/2026-09-09-lattice-ir-v7-format.md +++ b/docs/superpowers/specs/2026-09-09-lattice-ir-v7-format.md @@ -3,10 +3,10 @@ 日期:2026-09-09 状态:~~格式设计定稿(待实现)~~ → **已实施(2026-09-10,`plans/2026-09-09-lattice-ir-v7.md` Task 1-3 收官)**——v7 段表架构时代,字节状态以此为准;实施期裁决回填见 §4 规则 4 / §6 开放点 3、5。 **2026-09-12 追加(R2 P4 Task 1,D9/D10)**:**版本 7 → 8** + 段集合 +TYPE(7)/IFACE(8)(Task 1 落空壳;内容面归 Task 2/3)。文件名保留「v7」= 段表架构代号(改名引用面 40+ 处、收益为零);**v8 = v7 的加法扩展**:前六段字节布局不变,加段 + 版本 bump。旧 v7 六段文件由版本闸**整类拒收**(不静默当「两段缺席 = 空表」)——本条为现行字节权威(§1/§2/§3.7/§3.8/§4 已同步)。 -**2026-09-14 追加(R2 P5 Task 2/7)**:**版本 / 段集合 / 记录布局零变化**——单槽化只在**内存面**(DFNode `OFF_DF_TK` = 类型项引用 / `OFF_DF_AUX` = 辅码,72B 不变);`.ccr` 面 `tk` 语义定为**派生码**(§3.3 的「`tk` 字段语义」块,含 D20 稳定引用形态规范);`version` 保持 8、`CIR_CACHE_VER` 保持 17;`test_ccr_types` 34 → **40** 例。 +**2026-09-14 追加(R2 P5 Task 2/7)**:**版本 / 段集合 / 记录布局零变化**——单槽化只在**内存面**(DFNode `OFF_DF_TK` = 类型项引用 / `OFF_DF_AUX` = 辅码,72B 不变)。`.ccr` 面 `tk` 语义定为**派生码**(§3.3 的「`tk` 字段语义」块,含 D20 稳定引用形态规范);`version` 保持 8、`CIR_CACHE_VER` 保持 17;`test_ccr_types` 34 → **40** 例。 **2026-09-15 追加(#60 批 T2/T3:暖缓存静默缺陷修复 + 判据网暖态腿)**:`.cir` 快照**格式零变化**(`CIR_CACHE_VER` 保持 17)。修复落在**保存侧策略**:生成期对「快照**不载**的共享面」(实锤面 = `g_types` 类型行表;`checker.cr:10-19` 只追加不去重、快照只载 var 的 `type` 行号)有副作用的函数**不写条目** ⇒ 下跑必 miss ⇒ 重放全部生成期副作用(「宁可 miss 不可静默」);实现 = `main.cr` miss 分支 `tc0 := g_type_count` 比对。代价实测 **0.3%**(语料 101 档 989→986 条目)/ **0.9%**(编译器自源 110→109)。**§3.3 的「暖态缺行 ⇒ 写 `-1`」支因此收窄**:分配行的函数不再被命中(复合 mint 行在见证下**结构上不落盘**,实核 101 档扫描仅 `ptr_ref_first.cr` 有复合行且全缺 ⇒ 原盘面判据不可达,重新锁定见 `tests/selfhost/test_ccr_types.py` ㊲ + `/tmp/fct4/task2-report.md` §3.2)。**判据网补齐暖态腿**(本缺陷长期不可见 = 判据面对暖态零覆盖):入仓语料 `tests/probes/warm/`(7 档,**定路径**是该语料的设计要点)+ `tools/baseline/warm_leg.sh`(两层)/`warm_run.sh`(牙齿层);**实核:`check` 面写 0 条缓存条目 ⇒ 暖态腿必须走 `ccr` 面**。约定/预期值/时长见 `tools/baseline/REBUILD.md`;根因链与统一清单见 `docs/superpowers/plans/2026-09-15-warm-cache-diagnostics.md` §8-9 与 `.superpowers/sdd/warm-task4-report.md`。 -**2026-09-14 追加(R2 P6 Task 3,D20-② 兑现 = β)**:**版本 8 → 9** + **NOD 记录 36 → 40B**(语义区 28 → 32B:+28 新增 `item i32` = **TYPE 段文件空间项索引**,-1 = 无项;邻接域顺移 +32/+36)——前六段其余字段布局与 `tk` 槽语义/字节零变化;旧 v8 及更早文件由版本闸**整类拒收**(D10 先例)。`.cir` 快照面**零改动**(`CIR_CACHE_VER` 保持 17——项索引只在 TYPE 段重建后的文件空间成立,`.cir` 写点早于该空间 ⇒ 落盘只能得到进程内索引 = D20-③ 禁令;保存期由派生码重派生即得)。写侧装填 = `ccr_types.cr:ccr_nod_item_populate`(保存期单遍);读侧 = `load_ccr` 的 TYPE 段后**一致性硬校验**(域外 / `atom_of(项) ≠ 盘上码` ⇒ 拒绝)+ corearch `--dump-nod-items` 读回通道。`test_ccr_types` 40 → **48** 例。 -性质:两段式第二段(字节格式);语义定义 = `2026-09-09-lattice-ir-v7-carrier-design.md`(权威);本文件 = 字节怎么排。 +**2026-09-14 追加(R2 P6 Task 3,D20-② 兑现 = β)**:**版本 8 → 9** + **NOD 记录 36 → 40B**(语义区 28 → 32B:+28 新增 `item i32` = **TYPE 段文件空间项索引**,-1 = 无项;邻接域顺移 +32/+36)——前六段其余字段布局与 `tk` 槽语义/字节零变化。旧 v8 及更早文件由版本闸**整类拒收**(D10 先例)。`.cir` 快照面**零改动**(`CIR_CACHE_VER` 保持 17——项索引只在 TYPE 段重建后的文件空间成立,`.cir` 写点早于该空间 ⇒ 落盘只能得到进程内索引 = D20-③ 禁令;保存期由派生码重派生即得)。写侧装填 = `ccr_types.cr:ccr_nod_item_populate`(保存期单遍);读侧 = `load_ccr` 的 TYPE 段后**一致性硬校验**(域外 / `atom_of(项) ≠ 盘上码` ⇒ 拒绝)+ corearch `--dump-nod-items` 读回通道。`test_ccr_types` 40 → **48** 例。 +性质:两段式第二段(字节格式);语义定义 = `2026-09-09-lattice-ir-v7-carrier-design.md`(权威);本文件 = 字节布局定义。 关联: - `docs/superpowers/specs/2026-09-09-lattice-ir-v7-carrier-design.md`(v7 载体设计——语义权威:边必落/ENT 主干化/调度 = 投影/op 字典显式遗留) @@ -17,7 +17,7 @@ --- -## 1. 与 v6 的差异(先读总表) +## 1. 与 v6 的差异(总表先行) | 面 | v6 | v7 | v8(R2 P4 Task 1 起) | **v9**(R2 P6 Task 3 起 = 现行版本) | |---|---|---|---|---| @@ -47,7 +47,7 @@ v6 其余字节惯例沿用:小端、i32/u32、offset/size u32、`ccr_i32_fits └─────────────────────────────────────────────┘ ``` -段 tag 常量:`1=STR 2=SYM 3=NOD 4=ENT 5=REG 6=EDG` + **`7=TYPE 8=IFACE`**(R2 P4 Task 1,D9——两段必备,D11;`9+` 预留顺移:驱逐标注段 v6.1 延续、证书段)。corec 写侧用**规范序**(tag = 行号 1..8、offset = 前段尾、段体紧随段表连续);loader 仍按规范序校验(`tg == ri+1` + 段体连续两闸形状自 v7 不变)。 +段 tag 常量:`1=STR 2=SYM 3=NOD 4=ENT 5=REG 6=EDG` + **`7=TYPE 8=IFACE`**(R2 P4 Task 1,D9——两段必备,D11;`9+` 预留顺移:驱逐标注段 v6.1 延续、证书段)。corec 写侧用**规范序**(tag = 行号 1..8、offset = 前段尾、段体紧随段表连续)。loader 仍按规范序校验(`tg == ri+1` + 段体连续两闸形状自 v7 不变)。 ## 3. 段定义 @@ -59,7 +59,7 @@ v6 其余字节惯例沿用:小端、i32/u32、offset/size u32、`ccr_i32_fits 同 v6(函数/全局/结构/枚举)。函数 `param_ents` = 条目 id——v7 ENT 实记录后解析到真实条目。 -### 3.3 NOD — 节点表(40B)〔格层语义 + 编码层字节;first_edge/count = 邻接索引〕 +### 3.3 NOD — 节点表(40B)〔格层语义 + 编码层字节;`first_edge`/`edge_count` = 邻接索引〕 `nod_count u32` + `nod_count × 40B`(R2 P6 Task 3 起;v8 及更早 = 36B,版本闸整类拒收): @@ -75,11 +75,11 @@ v6 其余字节惯例沿用:小端、i32/u32、offset/size u32、`ccr_i32_fits | first_edge | u32 | 出边在 EDG 段的起始下标(+32) | | edge_count | u32 | 出边数(+36) | -邻接约定:节点出边在 EDG 段**连续**(节点 i+1 的 first_edge = 节点 i 的 first_edge + edge_count)——重建流式零索引(cir_cache v13 同款)。文件序 = 节点 id 序 = 生产者选择的合法拓扑调度。 +邻接约定:节点出边在 EDG 段**连续**(节点 i+1 的 `first_edge` = 节点 i 的 `first_edge` + `edge_count`)——重建流式零索引(`cir_cache` v13 同款)。文件序 = 节点 id 序 = 生产者选择的合法拓扑调度。 -**`item` 字段语义(R2 P6 Task 3 起 = β 兑现;`tk` 槽字节零变化)**:`item` = **TYPE 段文件空间项索引**(D20-② 唯一许可跨边界形态;D13 确定性装填 ⇒ 文件内索引稳定)。写侧 = `ccr_types.cr:ccr_nod_item_populate`(**保存期**由盘上派生码经判定衔接层 `sh_tk_face_of_code`/`sh_term_of_ti` 重派生——**不得**沿用 emit 期活表索引:`ccr_type_populate` 的 `tt_layer_reset` 在 save 前作废活表引用,D20-③/`bad_term=329`)。读侧 = `load_ccr` 的TYPE 段后**一致性硬校验**(`item < -1` / `≥ tt_count()` / `atom_of(项) ≠ tk` ⇒ 拒绝 rc=1,**不得**静默当无项)+ corearch `--dump-nod-items` 读回通道。暖态缺行(缓存命中跳过 ir_gen)⇒ 写 `-1`(码仍由 `tk` 保真;暖态项面登记为部分)。 +**`item` 字段语义(R2 P6 Task 3 起 = β 兑现;`tk` 槽字节零变化)**:`item` = **TYPE 段文件空间项索引**(D20-② 唯一许可跨边界形态;D13 确定性装填 ⇒ 文件内索引稳定)。写侧 = `ccr_types.cr:ccr_nod_item_populate`(**保存期**由盘上派生码经判定衔接层 `sh_tk_face_of_code`/`sh_term_of_ti` 重派生——**不得**沿用 emit 期活表索引:`ccr_type_populate` 的 `tt_layer_reset` 在 save 前作废活表引用,D20-③/`bad_term=329`)。读侧 = `load_ccr` 的 TYPE 段后**一致性硬校验**(`item < -1` / `≥ tt_count()` / `atom_of(项) ≠ tk` ⇒ 拒绝 rc=1,**不得**静默当无项)+ corearch `--dump-nod-items` 读回通道。暖态缺行(缓存命中跳过 ir_gen)⇒ 写 `-1`(码仍由 `tk` 保真;暖态项面登记为部分)。 -**`tk` 字段语义(R2 P5 Task 2 起 = 现行;字节/偏移零变化——R2 P6 Task 3 后仍为派生码)**:`tk` = **派生码**——类型面 op → 类型行(`IR_CONST`/`IR_BINARY` ∪ `{IR_ALLOC, IR_CALL, IR_LOAD, IR_I2F, IR_F2I}`);辅码面 op → 旗标/宽度/计数(`IR_BOUNDS_CHECK`/`IR_DEREF`/`IR_STORE_PTR`/`IR_SPAWN`/`IR_HOTPATCH_ROUTE`);其余 → 0。由 `sh_dfn_code_of_slots(类型项, 辅码)` **单源派生**(emit / `lower_to_ccr` / `.cir` 装载侧三处同源;分类表 = `ty_shadow.cr` 的 `sh_tk_face_of_code`)。**盘面不承载进程内项引用**——D20 禁令:进程内项表索引不得跨进程/跨复位边界(P4 `bad_term=329` 红证);未来跨边界唯一许可形态 = **TYPE 段文件内项索引**(**β 已兑现** = 上方 `item` 槽,R2 P6 Task 3)。P5 单槽化只在**内存面**(DFNode 72B 不变:`OFF_DF_TK` = 类型项引用 / `OFF_DF_AUX` = 辅码),NOD `.ccr` 面实测与 P4 逐字节同(`ptr_arith`/`generics_test`;`--dump-objects` 同)——详见 `plans/2026-09-13-r2-p5-cleanup.md` Task 2。 +**`tk` 字段语义(R2 P5 Task 2 起 = 现行;字节/偏移零变化——R2 P6 Task 3 后仍为派生码)**:`tk` = **派生码**——类型面 op → 类型行(`IR_CONST`/`IR_BINARY` ∪ `{IR_ALLOC, IR_CALL, IR_LOAD, IR_I2F, IR_F2I}`);辅码面 op → 旗标/宽度/计数(`IR_BOUNDS_CHECK`/`IR_DEREF`/`IR_STORE_PTR`/`IR_SPAWN`/`IR_HOTPATCH_ROUTE`);其余 → 0。由 `sh_dfn_code_of_slots(类型项, 辅码)` **单源派生**(emit / `lower_to_ccr` / `.cir` 装载侧三处同源;分类表 = `ty_shadow.cr` 的 `sh_tk_face_of_code`)。**盘面不承载进程内项引用**——D20 禁令:进程内项表索引不得跨进程/跨复位边界(P4 `bad_term=329` 红证)。未来跨边界唯一许可形态 = **TYPE 段文件内项索引**(**β 已兑现** = 上方 `item` 槽,R2 P6 Task 3)。P5 单槽化只在**内存面**(DFNode 72B 不变:`OFF_DF_TK` = 类型项引用 / `OFF_DF_AUX` = 辅码),NOD `.ccr` 面实测与 P4 逐字节同(`ptr_arith`/`generics_test`;`--dump-objects` 同)——详见 `plans/2026-09-13-r2-p5-cleanup.md` Task 2。 ### 3.4 EDG — 边表(8B/记录,v7 新增)〔配方闭合的载体〕 @@ -90,7 +90,7 @@ v6 其余字节惯例沿用:小端、i32/u32、offset/size u32、`ccr_i32_fits | to_nod | u32 | 目标节点 id(from = 所属节点,邻接隐含) | | kind | u32 | 边类:0 = 数据(def-use 值流)、1 = state(副作用序 = VSDG 状态链);(2+ 预留) | -`edg_count` 必等于 Σ 各节点 edge_count(校验规则 ②)。 +`edg_count` 必等于 Σ 各节点 `edge_count`(校验规则 ②)。 ### 3.5 ENT — 条目表(28B,布局不变;内容恒空 → 实记录)〔格层本体〕 @@ -180,18 +180,18 @@ self_mode ∈ 0..3)+ **跨段引用域**:`name_ni`/`type_ni`/`method_ni`/`ma 1. **拓扑不变量(语义约束的字节形态)**:EDG 每条边 `所属节点 < to_nod`(数据/state 边前向——DAG 拓扑调度);违规 = 文件损坏拒绝 2. **边界声明(非边)**:branch/jump/调用目标的 NOD id 引用(可后向——回边语义)是**操作数字段,不是边**;循环语义 = REG(SG_LOOP 嵌套)+ state 链表达(VSDG 先例)——EDG 只承载数据/state 两类前向边 3. `edg_count` == Σ edge_count;NOD/ENT/REG 引用 id 界内(NOD id < nod_count 等) -4. 段表 offset/size 界、ENT home/flags 读入放行——**裁决(2026-09-10 Task 2 review R3)**:loader 对 home≠-1 / flags≠0 **接受不拒绝**——home = 实例映射注记,.ccr = corec→corearch 传输中间物,实例层(分配/缓存映射)决策不写回格式;非 -1/非 0 值不构成损坏证据(无消费方依赖恒 -1/0 前提之外的安全面)。开放点 3 保留:未来实例层选择写回(非传输中间物用途)时重议 +4. 段表 offset/size 界、ENT home/flags 读入放行——**裁决(2026-09-10 Task 2 review R3)**:loader 对 `home`≠-1 / `flags`≠0 **接受不拒绝**——`home` = 实例映射注记,`.ccr` = corec→corearch 传输中间物,实例层(分配/缓存映射)决策不写回格式。非 -1/非 0 值不构成损坏证据(无消费方依赖恒 -1/0 前提之外的安全面)。开放点 3 保留:未来实例层选择写回(非传输中间物用途)时重议 5. magic/version(**`version == 9`**——R2 P6 Task 3 起;`version ≠ 9` 整类拒收,含全部 v7 六段/v8 八段文件——D10 先例);`ccr_i32_fits` 沿用(中间产物 < 4GB) 6. **段集合完备性(R2 P4 Task 1,D11)**:`seg_cnt` 未满 / 缺任一必备段(STR/SYM/NOD/REG/EDG/**TYPE/IFACE**)⇒ 拒绝;ENT 仍可缺(v5 精神:旧段缺失 = 空表,`ccr_io.cr` 既有约定)。**「缺段 = 空表」仅适用于 ENT**——TYPE/IFACE 缺席必须响亮拒绝(可选段 = 两种 `.ccr` 在野 = 静默降级面) 7. **~~空壳期段体校验(R2 P4 Task 1)~~(已退役——R2 P4 Task 3)**:TYPE 段自 Task 2 起、IFACE 段自 Task 3 起皆为内容面,校验 = §3.7/§3.8 的逐条不变量(含跨段引用域);两段**必备**(规则 6)不变 ## 5. 消费方影响 -- **corec(产)**:图化(节点 + 数据/state 边 + 区域——dataflow.cr VSDG 机制先例;构建时机核实 = 实施计划项)→ 条目重建(载体设计 §4)→ 邻接化(first_edge/edge_count 连续布局)→ 写 v7 +- **corec(产)**:图化(节点 + 数据/state 边 + 区域——`dataflow.cr` VSDG 机制先例;构建时机核实 = 实施计划项)→ 条目重建(载体设计 §4)→ 邻接化(`first_edge`/`edge_count` 连续布局)→ 写 v7 - **corearch(载)**:段表寻址 → NOD/EDG/ENT 载入 → 校验(§4)→ 图 → 线性调度重建(载体设计 §3:文件序 + 沿边合法性校验 + REG 展开)→ 发射(现路径语义) - 判定/证书:共存 sweep(v6 §4.2)消费 ENT 区间;图语义消费(验证/优化)直接消费 NOD+EDG - **TYPE/IFACE 段(R2 P4 Task 1 起)**:Task 1 = 空壳,**零消费者**(loader 仅做存在性/空壳校验);内容面(Task 2/3)落地后由 corearch 载入**重建**类型行表/类型项表与接口表(统一设计 spec §6.3 的 `atom_of` 承接面)——纯信息面,**不参与 ELF 发射**(发射面零泄漏判据 = ELF canary 不变) -- 测试族:test_ccr_v7.py 27/27(2026-09-10 Task 3 迁移收官;2026-09-12 R2 P4 Task 1 结构断言重定 = 8 段/`HEADER_TABLE=112`/`seg_count==8`/坏版本 (8,7,6,5))+ test_ccr_types.py **48/48**(T1 新建 9 例 = 段机制/loader 负分支/旧 v7 文件拒收;T2 内容面 +10(行表/项 DAG 序列化 + 确定性装填 + corearch 读回对拍 + 拓扑/标注槽负分支);T3 IFACE 内容面 +10(五小节/扩列 16/形状命名化/签名项化/impl 边与方法表/跨段引用域);T4 DFNode.TK 项槽 +6(逐节点允许清单规则/dex 语料/NOD 36B 同序/冷·暖快照对称/dump 零产物影响/`.cir` 布局未变);**P5 T2 单槽化 +6**(复合行走辅码 / 互斥不变量 / F1 hotpatch 无面 / 复合行冷·暖对称 / 复合行 NOD 同序 / 快照盘面派生码保真);**P6 T3 项索引 +8**(版本闸 v8 拒收 / NOD 40B 字段序 / 项索引落盘读回对拍(非退化)/ 两通道面一致 / 辅码面与复合行保真 / 项索引越界与不一致 ⇒ 拒绝(三子例)/ 段界检 / D18 纯度静态;**突变 M1–M5 逐条转红**);机制面随批重定)——v6 测试族已合并退役;无版本链对照(v8-only 世界,行为判据 = 全量回归 + stage 链 byte-identical,见载体设计 §3.3 注记)。**判据标准(TODO #2026-09-11-9,T1 起)**:不以「与旧版逐字节同」为准 = 结构断言全绿 + 语义零变化 + 自举稳定。 +- 测试族:`test_ccr_v7.py` 27/27(2026-09-10 Task 3 迁移收官;2026-09-12 R2 P4 Task 1 结构断言重定 = 8 段/`HEADER_TABLE=112`/`seg_count==8`/坏版本 (8,7,6,5))+ `test_ccr_types.py` **48/48**(T1 新建 9 例 = 段机制/loader 负分支/旧 v7 文件拒收;T2 内容面 +10(行表/项 DAG 序列化 + 确定性装填 + corearch 读回对拍 + 拓扑/标注槽负分支);T3 IFACE 内容面 +10(五小节/扩列 16/形状命名化/签名项化/impl 边与方法表/跨段引用域);T4 DFNode.TK 项槽 +6(逐节点允许清单规则/dex 语料/NOD 36B 同序/冷·暖快照对称/dump 零产物影响/`.cir` 布局未变);**P5 T2 单槽化 +6**(复合行走辅码 / 互斥不变量 / F1 hotpatch 无面 / 复合行冷·暖对称 / 复合行 NOD 同序 / 快照盘面派生码保真);**P6 T3 项索引 +8**(版本闸 v8 拒收 / NOD 40B 字段序 / 项索引落盘读回对拍(非退化)/ 两通道面一致 / 辅码面与复合行保真 / 项索引越界与不一致 ⇒ 拒绝(三子例)/ 段界检 / D18 纯度静态;**突变 M1–M5 逐条转红**);机制面随批重定)——v6 测试族已合并退役;无版本链对照(v8-only 世界,行为判据 = 全量回归 + stage 链 byte-identical,见载体设计 §3.3 注记)。**判据标准(TODO #2026-09-11-9,T1 起)**:不以「与旧版逐字节同」为准 = 结构断言全绿 + 语义零变化 + 自举稳定。 ## 6. 开放点(实施期定夺) diff --git a/docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md b/docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md index 062e7c3f..bb241ac5 100644 --- a/docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md +++ b/docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md @@ -1,7 +1,7 @@ # 语言面收窄与接口化交叉执行(定长退役裁决 + 宽度清理 + 依赖序) 日期:2026-09-10 -状态:**已实施(R1)**——波 R1 语言面收窄批(计划 `docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md`)Task 1-5 于 2026-09-10 收官:定长裁决注记落位、宽度三项清理完成、全局定长/初始化路径修复;全回归 + 自举守护全绿。R2(接口化主设计轮)后启。 +状态:**已实施(R1)**——波 R1 语言面收窄批(计划 `docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md`)的 Task 1-5 于 2026-09-10 收官。定长裁决注记落位、宽度三项清理完成、全局定长/初始化路径修复;全回归与自举守护全绿。R2(接口化主设计轮)于其后启动。 性质:前端/语言面战线(根基革命 A:图本体/类型→接口)的启动裁决 + 与既有战线的交叉执行序。**本 spec 只裁方向与顺序,实施计划后立。** 关联: @@ -12,7 +12,7 @@ --- -## 1. 定长数组裁决(2026-09-10 用户拍板) +## 1. 定长数组裁决(2026-09-10 用户裁决) ### 1.1 裁决 @@ -22,8 +22,8 @@ - N 元聚合 → **product 类型**(条目 8:元组/记录 = product 自动组合) - N 长序列 → **序列接口 + 长度值约束**(条目 8:F11 长度走 where 三档) - 长度入型做验证 → **图/F11 长度来源链**(比字面量构造器强——可表达依赖长度) -- **表示层**:`[T; N]` 语法保留 = **内联容量存储的表示提示**(映射参数——与 hw-map 同层;随实例选择生效/退化;非经典范式实例可忽略或另定——"内联"在量子/光学映射中未定义是正常的) -- **自举代码**:`ast.cr` 9 处 + `kernel/term_io.cr` 1 处用法零改造(它们本就是表示提示的正当消费——编译器需内联存储) +- **表示层**:`[T; N]` 语法保留 = **内联容量存储的表示提示**(映射参数——与 hw-map 同层;随实例选择生效/退化;非经典范式实例可忽略或另定——"内联"在量子/光学映射中未定义属正常情形) +- **自举代码**:`ast.cr` 9 处 + `kernel/term_io.cr` 1 处用法零改造(二者本属表示提示的正当消费——编译器需内联存储) ### 1.2 裁决依据(用途拆解) @@ -39,11 +39,11 @@ ### 1.3 连带处置 -- **全局定长数组 SIGSEGV**(实测:check 过/build rc=0/run rc=139——含解释器路径):过渡期处置 = 按表示层语义修或先编译期拒绝;**修复归属 = 实施批**(见 §3 波 R1)。**R1 落地形态(2026-09-10 实测,与本节初稿括注不同)**:运行期分配持久存储 + 全局槽持指针(与局部数组/bootstrap 参考实现同语义);**「内联 N 格」表示未兑现**——内联容量 = 映射参数层的表示提示,属 R3 表示提示机制(对非经典范式可退化),故 R1 不建该机制 - - **✅ R1 已处置(选「按表示语义修」)**:全局(聚合 / 非常量初值)降级为运行期初始化序列——main 序言 IR 注入 + 解释器初始化阶段;落点 71cb6278;判据 `tests/selfhost/test_global_init.py` 15 例双路径(解释器 / ELF)逐例精确 rc。非编译期拒绝(保留语义,符合「表示提示」裁决)。 -- **checker 落实时点**:`[T; N]` 从类型判定中降格 = **接口化轮(R2)重做 checker 类型判定时自然完成**(届时不经类型相等/子类型);R1 只做:裁决注记(ast.cr/checker 加「表示层概念」标注)+ 全局路径处置 + 语法面文档 - - **✅ R1 三项均已做**:注记 aa76f7f5(ast/checker/parser 七处,零行为)/ 全局路径 71cb6278 / 语法面文档(本 spec + grammar 同步 51d74be3) -- **表示提示机制**(提示如何被映射层消费) = 映射侧(R3/hw-map 通道)设计时定——R1 不建机制(现状语法行为不动) +- **全局定长数组 SIGSEGV**(实测:`check` 过 / `build` rc=0 / `run` rc=139——含解释器路径):过渡期处置 = 按表示层语义修,或先编译期拒绝;**修复归属 = 实施批**(见 §3 波 R1)。**R1 落地形态(2026-09-10 实测,与本节初稿括注不同)**:运行期分配持久存储 + 全局槽持指针(与局部数组/bootstrap 参考实现同语义)。**「内联 N 格」表示未兑现**——内联容量 = 映射参数层的表示提示,属 R3 表示提示机制(对非经典范式可退化),故 R1 不建该机制 + - **✅ R1 已处置(择「按表示语义修」)**:全局(聚合 / 非常量初值)降级为运行期初始化序列——`main` 序言 IR 注入 + 解释器初始化阶段;落点 71cb6278;判据 `tests/selfhost/test_global_init.py` 15 例双路径(解释器 / ELF)逐例精确 rc。本处置非编译期拒绝(保留语义,符合「表示提示」裁决)。 +- **`checker` 落实时点**:`[T; N]` 从类型判定中降格 = **接口化轮(R2)重做 `checker` 类型判定时自然完成**(届时不经类型相等/子类型);R1 只做:裁决注记(`ast.cr`/`checker` 加「表示层概念」标注)+ 全局路径处置 + 语法面文档 + - **✅ R1 三项均已做**:注记 aa76f7f5(`ast`/`checker`/`parser` 七处,零行为)/ 全局路径 71cb6278 / 语法面文档(本 spec + `grammar` 同步 51d74be3) +- **表示提示机制**(提示如何被映射层消费)= 映射侧(R3/hw-map 通道)设计时定夺——R1 不建机制(现状语法行为不动) --- @@ -51,8 +51,8 @@ | 项 | 内容 | 裁决 | 结果 | |---|---|---|---| -| 死条目移除 | `ast.cr` `T_INT_I8..T_INT_U64`(77-84)+ `T_FLOAT_F32/F64`(85-86)——**勿重编号**(编号空间稳定) | R1 直接做(机械) | ✅ ce3e541c——ast.cr 墓碑注释(勿重编号)+ `W_*` 值域 + parser 两处死分支(lexer 从不发射,引用面归零) | -| `_f32/_f64` 后缀 | 实况:`parser.cr:414` 注「data = 宽度标注(_f32/_f64,**保留**)」——后缀现作为宽度标注随字面量存 | **R1 侦查后裁**:若承载 apx/binary64 精度语义(语言语义)→ 保留并重命名注解(精度非宽度);若纯机器宽度 → 随死条目清(或转 R3 映射通道标注) | ✅ 裁为**纯机器宽度 → 退役**(51d74be3):lexer 不再消费后缀、一律响亮报错;宽度 = 机器形状,归映射层(parser 宽度分支随死条目一并清)。侦查结论:后缀位宽信息在词法层即被丢弃(`num_str` 已剔除),data 槽恒 0——无语言语义承载 | +| 死条目移除 | `ast.cr` `T_INT_I8..T_INT_U64`(77-84)+ `T_FLOAT_F32/F64`(85-86)——**勿重编号**(编号空间稳定) | R1 直接做(机械) | ✅ ce3e541c——`ast.cr` 墓碑注释(勿重编号)+ `W_*` 值域 + `parser` 两处死分支(`lexer` 从不发射,引用面归零) | +| `_f32/_f64` 后缀 | 实况:`parser.cr:414` 注「`data` = 宽度标注(_f32/_f64,**保留**)」——后缀现作为宽度标注随字面量存 | **R1 侦查后裁**:若承载 apx/binary64 精度语义(语言语义)→ 保留并重命名注解(精度非宽度);若纯机器宽度 → 随死条目清(或转 R3 映射通道标注) | ✅ 裁为**纯机器宽度 → 退役**(51d74be3):`lexer` 不再消费后缀、一律响亮报错;宽度 = 机器形状,归映射层(`parser` 宽度分支随死条目一并清)。侦查结论:后缀位宽信息在词法层即被丢弃(`num_str` 已剔除),`data` 槽恒 0——无语言语义承载 | | `1_000` 分歧 | bootstrap vs self-hosted 两编译器解析分歧复核 | R1 做(词法对照测试) | ✅ 51d74be3——`_` 分隔符**不支持**,两编译器统一响亮报错(原双向皆错:self-hosted 静默成值 0 / bootstrap 静默成 1000);新增 `tests/selfhost/test_lexer_parity.py` | --- @@ -84,14 +84,14 @@ hw-map 宽度显式通道 + 表示提示机制(内联容量存储的映射消费)+ 实例参数化 ``` -交叉点(已核):R1③ 的词法面与 R2 的 checker 重做同文件族(parser/ast);R2 的接口条目在 R3 的映射实例上实现;R3 与实例化波 2 是同一件事(编码层参数化)两个名字。 +交叉点(已核):R1③ 的词法面与 R2 的 `checker` 重做属同一文件族(`parser`/`ast`);R2 的接口条目在 R3 的映射实例上实现;R3 与实例化波 2 是同一件事(编码层参数化)的两个名字。 ## 4. 挂账与不承诺 -- R1 不做:表示提示机制(R3)、checker 类型判定重构(R2)、F11/where 落地(R2) +- R1 不做:表示提示机制(R3)、`checker` 类型判定重构(R2)、F11/where 落地(R2) - 全局定长数组修复若改为「编译期拒绝」先行 = 过渡措施,R2/R3 后恢复完整语义 - - **R1 实际选择 = 按表示语义修**(非编译期拒绝)——不产生过渡态;R2/R3 只需在 checker/映射侧接续(已记 TODO「全局初始化机制」条目:未来非 main 入口 / 库形态需迁移到独立 init 区) + - **R1 实际选择 = 按表示语义修**(非编译期拒绝)——不产生过渡态;R2/R3 只需在 `checker`/映射侧接续(已记 TODO「全局初始化机制」条目:未来非 `main` 入口 / 库形态需迁移到独立 init 区) - 本 spec 不裁 `_f32/_f64` 最终归属(R1 侦查后裁) - **✅ R1 已裁**:退役 + 响亮报错(51d74be3)——后缀无语言语义承载(词法层即丢弃);未来若需精度/位宽标注,走 R3 映射通道 - TODO 登记:定长裁决(随 R1 提交记 TODO 划销/挂账)、宽度清理三项(随 R1 完成划销) - - **✅ 已办(Task 5)**:宽度三项划销 + 定长注记挂账(类型身份退役 = R2)+ 新登记(全局初始化机制 / lexer 诊断前缀不一致 / 枚举族 callee 内联缺口 / 嵌套类型别名一层解析 / test_compile 清单陈旧) + - **✅ 已办(Task 5)**:宽度三项划销 + 定长注记挂账(类型身份退役 = R2)+ 新登记(全局初始化机制 / `lexer` 诊断前缀不一致 / 枚举族 callee 内联缺口 / 嵌套类型别名一层解析 / `test_compile` 清单陈旧) diff --git a/docs/superpowers/specs/2026-09-10-x86-instance-design.md b/docs/superpowers/specs/2026-09-10-x86-instance-design.md index 83303287..f84e5bf8 100644 --- a/docs/superpowers/specs/2026-09-10-x86-instance-design.md +++ b/docs/superpowers/specs/2026-09-10-x86-instance-design.md @@ -2,7 +2,7 @@ 日期:2026-09-10 状态:**已实施(波 1 结构波 2026-09-10 Task 1-7 收官——plan `2026-09-10-x86-instance-wave1.md`:三轴目录搬迁 + 组合根 `src/targets/x86_64-linux/` + 序列算法文件化(entry/frame/tag2l/callseq/syscall)+ 表数据迁架构轴 + 构建清单分段守卫;判据 = 行为零变化全绿)**——波 2 参数化 / 波 3 能力未启;执行注记见 §8(步骤 3——蓝图演进序第 3 步) -性质:**实例层设计裁决**——把 x86/ELF/Linux 的全部定制内容按三轴归位到实例边界内(内核零改动——规则封闭);判据按边界 C4 = 行为等价 + 投影正确性方向。实施分波(结构波先、能力波后)。 +性质:**实例层设计裁决**——将 x86/ELF/Linux 的全部定制内容按三轴归位到实例边界内(内核零改动——规则封闭);判据按边界 C4 = 行为等价 + 投影正确性方向。实施分波(结构波先、能力波后)。 关联: - `docs/superpowers/specs/2026-09-09-corearch-rewrite-design.md`(蓝图——§1.2 实例组成/§2 裁决表/§3 演进序步骤 3 = 本设计的窗口;"实例边界内的数据化/参数化 = M2 复启的接续形态") @@ -13,15 +13,15 @@ --- -## 0. 定位与商讨结论(2026-09-10 用户拍板) +## 0. 定位与商讨结论(2026-09-10 用户裁决) -蓝图 §3 步骤 3 = 实例边界内的数据化/参数化。商讨结论: +蓝图 §3 步骤 3 = 实例边界内的数据化/参数化。商讨结论如下: -1. **实例 = 三轴组合**:架构(x86_64)× 格式(ELF)× OS(Linux)——前两个轴大体通用(架构目录跨 OS 复用、格式目录跨架构复用),OS 轴最薄。三轴皆遵循同一模式:**通用机制 + 特化参数**(与 hit 的引擎/表数据同构) +1. **实例 = 三轴组合**:架构(x86_64)× 格式(ELF)× OS(Linux)——前两个轴大体通用(架构目录跨 OS 复用、格式目录跨架构复用),OS 轴最薄。三轴皆遵循同一模式:**通用机制 + 特化参数**(与 `hit` 的引擎/表数据同构) 2. **寄存器分配切分原则**:需求推导(哪些条目要位置/窗口/可共享——语义侧)vs 物理选择/搜索/编码(机器侧)——切分表见 §4;**先结构后能力** -3. **spill/驱逐 = 独立能力波**:设计预留契约形状(needs_eviction 激活 → 判定③④ 引擎扩展 = 注册契约演进的正式演练),实施后置 +3. **spill/驱逐 = 独立能力波**:设计预留契约形状(`needs_eviction` 激活 → 判定③④ 引擎扩展 = 注册契约演进的正式演练),实施后置 -## 1. 实例 = 三轴组合 +## 1. 实例的三轴组合 ``` 架构(src/arch/x86_64/) × 格式(src/format/elf/) × OS(src/os/linux/) @@ -29,7 +29,7 @@ └── 构建设置选择组合 = 一个实例配置(x86_64 × elf × linux) ``` -- 组合选择机制:构建时(build_selfhost_native.py / Core.toml)声明三轴选择 + 交叉适配参数(如 ELF 的 machine ID / reloc 类型 = 格式层的架构特化参数位——由架构轴提供) +- 组合选择机制:构建时(`build_selfhost_native.py` / `Core.toml`)声明三轴选择 + 交叉适配参数(如 ELF 的 machine ID / reloc 类型 = 格式层的架构特化参数位——由架构轴提供) - 换实例 = 换轴组合(arm64 × elf × linux = 换架构轴;x86_64 × pe × windows = 换格式+OS 轴)——内核与其余轴零改动(规则封闭的实例级验收) - ABI = 交叉轴:机器寄存器集(架构轴)× 调用约定(OS 轴)——callseq 归 OS 轴、参数寄存器表引用架构轴 @@ -57,14 +57,14 @@ src/lattice/ / src/kernel/ ← 语义内核 / 验证内核(已落,本 src/runtime/ ← 运行时(rt.s——OS 轴补充) ``` -- **序列算法文件化** = 本设计的实质内容之一(现散在 elf.cr/instr.cr 巨型文件里的帧/调用/syscall 序列显式成文件——C2/C3"实例算法"的目录化) +- **序列算法文件化** = 本设计的实质内容之一(现散在 `elf.cr`/`instr.cr` 巨型文件里的帧/调用/syscall 序列显式成文件——C2/C3"实例算法"的目录化) - 平铺不设子目录(文件规模 10 级——concat/导入机制成本不值;文件增多再分) -- ld project-mode 入口(main.cr)随迁 OS 轴或架构轴——**实施计划定夺点**(其 flag 注册分歧 = TODO #2026-09-10-2 的处置并入本设计实施波) +- ld project-mode 入口(`main.cr`)随迁 OS 轴或架构轴——**实施计划定夺点**(其 flag 注册分歧 = TODO #2026-09-10-2 的处置并入本设计实施波) ## 3. 构建清单分段(按轴组织) -- `build_selfhost_native.py` 清单重构为分段组合:`common_files`(shared:globals/dyn_arr/ast/ccr_io 等)+ `kernel_files`(lattice 内核)+ `non_x86` 无关面(corec 前端)+ `arch_x86_64_files` + `format_elf_files` + `os_linux_files` + hit 引擎段——concat = 按确定顺序组合 -- 守卫(吸收 ld 单元静默缺陷教训):①清单文件存在性断言(防路径漂);②"目录新文件未入清单"检查(构建设置期提示);③构建日志 `error[` 计数非零 = 失败门(TODO #2026-09-10-2 建议③的落地) +- `build_selfhost_native.py` 清单重构为分段组合:`common_files`(shared:`globals`/`dyn_arr`/`ast`/`ccr_io` 等)+ `kernel_files`(lattice 内核)+ `non_x86` 无关面(corec 前端)+ `arch_x86_64_files` + `format_elf_files` + `os_linux_files` + `hit` 引擎段——concat = 按确定顺序组合 +- 守卫(吸收 ld 单元静默缺陷教训):① 清单文件存在性断言(防止路径漂移);② "目录新文件未入清单"检查(构建设置期提示);③ 构建日志 `error[` 计数非零 = 失败门(TODO #2026-09-10-2 建议③的落地) - corelsp 等其余 concat = 同一分段机制复用 ## 4. 寄存器分配切分(CAG 五阶段侧归属)与能力演进预留 @@ -79,20 +79,20 @@ src/runtime/ ← 运行时(rt.s——OS 轴补充) | 4 First Fit 搜索 | 不透明位置的搜索 | 灰区——搜索泛型、可用位置集 = 实例域 | 实施按需(YAGNI:单一实例时留实例侧) | | 5 终分配 ≤5 对/块写 meta | 块格式编码 | 实例 | 编码 | -- **实施节奏**:需求推导上收 = 原则记录 + 按需(实例 B 出现前的真收益低);本设计波次先物理侧归位/参数化 +- **实施节奏**:需求推导上收 = 原则记录 + 按需(实例 B 出现前的实际收益低);本设计波次先物理侧归位/参数化 ### 4.2 能力演进预留(spill/驱逐——契约形状预演,实施后置) - **激活点**:`needs_eviction=1` 的实例声明 → 判定③(驱逐配对)引擎扩展 - **双向契约三段形状**(定稿): - 1. **实例→内核**:登记(kern_loc_*——已立)+ 驱逐/替换事件登记(预留 API 位) + 1. **实例→内核**:登记(`kern_loc_*`——已立)+ 驱逐/替换事件登记(预留 API 位) 2. **内核→实例**:判定输出(violations/共存证据——已立)+ **持久条目 home 需求查询**(条款 4b:无配方条目必须 home 保真——预留接口位,现 IR 面无实例 = 空槽) - 3. **判定③④ 引擎实现**:needs_* = 1 时的契约演进点(现 {0,0}——静态放置无事件/callee-saved 平凡满足) + 3. **判定③④ 引擎实现**:`needs_*` = 1 时的契约演进点(现 {0,0}——静态放置无事件/callee-saved 平凡满足) - spill 引入同时解锁:判定④(调用点失效——被调用者保存集与调用点未维护条目的配对检查) ### 4.3 判据 -- 结构波(波 1-2):**行为零变化**——全回归 + backend_bootstrap stage 链 byte-identical + ccr_v7 产物 byte-identical + full-bootstrap guard(纯搬移/文件化证明) +- 结构波(波 1-2):**行为零变化**——全回归 + `backend_bootstrap` stage 链 byte-identical + `ccr_v7` 产物 byte-identical + `full-bootstrap` guard(纯搬移/文件化证明) - 能力波(波 3,后置):行为等价按边界 C4(**非逐字节复刻**——实例算法可自由设计,正确性判据 = 投影正确性方向)——M2 复启的判据修订同步落地 ## 5. 演进波次(实施另立) @@ -104,11 +104,11 @@ src/runtime/ ← 运行时(rt.s——OS 轴补充) ## 6. 挂账与风险 -- **M2 交互**:HIT 表数据迁架构轴(波 1)与 M2 挂起状态——搬迁判据 = 全回归(表路径测试 hit_table 24/24 保持);M2 复启时表定位(引擎/数据分离)已由本设计解决。**波 1 已实施**:表数据 `src/arch/x86_64/core-x86.toml` + 引擎 `src/arch/hit/` 分离落位,hit_table **24/24 保持** ✓(M2 挂起态未动——本波只搬定位面) -- **rc/cmp 判据**:文件移动不改产物(asm 后端无 .loc——评审曾实测注释变化 asm byte-identical);stage 链 run 内 byte-identical 判据保持 -- **main.cr 双入口**(TODO #2026-09-10-2):波 2 处置(注册收敛或显式分歧留档)。**波 1 已搬未收敛**——双入口之一随 Task 1 迁入组合根(`src/arch/linux/ld/main.cr` → `src/targets/x86_64-linux/main.cr`),分歧本体(ld project-mode 入口缺 HIT/表旗标注册)逐字保持、`test_backend_bootstrap` stage 链仍走该入口;按 H7 纪律——波 1 只同步注记措辞、flag 面收敛留波 2 +- **M2 交互**:HIT 表数据迁架构轴(波 1)与 M2 挂起状态——搬迁判据 = 全回归(表路径测试 `hit_table` 24/24 保持);M2 复启时表定位(引擎/数据分离)已由本设计解决。**波 1 已实施**:表数据 `src/arch/x86_64/core-x86.toml` + 引擎 `src/arch/hit/` 分离落位,`hit_table` **24/24 保持** ✓(M2 挂起态未动——本波只搬定位面) +- **rc/cmp 判据**:文件移动不改产物(asm 后端无 `.loc`——评审曾实测注释变化 asm byte-identical);stage 链 run 内 byte-identical 判据保持 +- **`main.cr` 双入口**(TODO #2026-09-10-2):波 2 处置(注册收敛或显式分歧留档)。**波 1 已搬未收敛**——双入口之一随 Task 1 迁入组合根(`src/arch/linux/ld/main.cr` → `src/targets/x86_64-linux/main.cr`),分歧本体(ld project-mode 入口缺 HIT/表旗标注册)逐字保持、`test_backend_bootstrap` stage 链仍走该入口;按 H7 纪律——波 1 只同步注记措辞、flag 面收敛留波 2 - **架构特化参数位**(格式层的 machine/reloc):波 1 仅搬迁不建参数机制;交叉适配机制 = 波 2 或实例 B 时定 -- **波 1 评审裁决遗留**(全部登记 TODO,**均不改波 1 结构面**):TODO #2026-09-10-4 = 前端 ≥18 形参静默误编译类(高优先级——根因前端参数表/AST bookkeeping,本波零接触;其 ④ 项「22 参 runtime 用例入 tests/suite」= 该项缺陷修复后才可达,**非波 1 收尾条件**);TODO #2026-09-10-5 = `IR_CALL_EXTERN` >6 int 参语义缺口(callseq.cr 指针落地——波 1 按"零变化"逐字保留预存不对称,修复 = 波 2 FFI 面);TODO #2026-09-10-6 = `src/format/elf/elf.cr` 三处手写 syscall 序列(mmap/clone/exit,syscall1/5/6 形)留在格式轴 = **实例 B「换轴零改动」承诺的证伪面**,收编 `src/os/linux/` = 波 2 / 实例 B 前置(Task 6 只抽 syscall3/4 内置体发射面,未扩面) +- **波 1 评审裁决遗留**(全部登记 TODO,**均不改波 1 结构面**):TODO #2026-09-10-4 = 前端 ≥18 形参静默误编译类(高优先级——根因前端参数表/AST bookkeeping,本波零接触;其 ④ 项「22 参 runtime 用例入 `tests/suite/`」= 该项缺陷修复后才可达,**非波 1 收尾条件**);TODO #2026-09-10-5 = `IR_CALL_EXTERN` >6 int 参语义缺口(`callseq.cr` 指针落地——波 1 按"零变化"逐字保留预存不对称,修复 = 波 2 FFI 面);TODO #2026-09-10-6 = `src/format/elf/elf.cr` 三处手写 syscall 序列(mmap/clone/exit,syscall1/5/6 形)留在格式轴 = **实例 B「换轴零改动」承诺的证伪面**,收编 `src/os/linux/` = 波 2 / 实例 B 前置(Task 6 只抽 syscall3/4 内置体发射面,未扩面) - **本设计不承诺**:需求推导上收(§4.1 内核候选——按需)、spill/驱逐实施(§4.2 预留)、格式轴跨 OS 全面参数化(PE 出现前 YAGNI) ## 7. 关联同步项 @@ -117,16 +117,16 @@ src/runtime/ ← 运行时(rt.s——OS 轴补充) - TODO #2026-09-10-2(双入口分歧)→ 波 2 处置(波 1 已搬未收敛,见 §6);TODO #2026-09-09-1/#5 不受影响 - TODO #2026-09-10-4/#9/#10(波 1 评审裁决登记)→ 全属波 2 / 后续专项,本波只登记不改结构面(见 §6 末条) - M2 计划/spec:复启时按本设计表归属 + C4 判据修订执行 -- 目录分层先例(src/lattice 搬迁 712946a0)机制复用(module.cr 回退链/清单/守卫) +- 目录分层先例(`src/lattice` 搬迁 712946a0)机制复用(`module.cr` 回退链/清单/守卫) ## 8. 执行注记(波 1 收官回填——2026-09-10 Task 1-7) > 本节约 = 设计落地确认(plan `2026-09-10-x86-instance-wave1.md` Tasks 1-7)。 > 提交落点:Task 0 盘点 327c2cf01af3(设计定稿 6694f358f376)/ Task 1 三轴搬迁 + 组合根 -> 29d177ac49a5(+ 补正 c927525baf35、docs 58e6be3a1c18)/ Task 2 entry.cr 整搬 -> b23f008000cf(+ docs 8dcfaeca52b2)/ Task 3 frame.cr 抽取 b0ba8c1c9b01 / Task 4 -> tag2l.cr 整搬 d65fc1b8f3c3(+ docs c6b6cbfe9a75)/ Task 5 callseq.cr 抽取 -> 3ab39f6eaa16(+ docs 525a872a0ba7)/ Task 6 syscall.cr 抽取 94d1cac15359(+ docs +> 29d177ac49a5(+ 补正 c927525baf35、docs 58e6be3a1c18)/ Task 2 `entry.cr` 整搬 +> b23f008000cf(+ docs 8dcfaeca52b2)/ Task 3 `frame.cr` 抽取 b0ba8c1c9b01 / Task 4 +> `tag2l.cr` 整搬 d65fc1b8f3c3(+ docs c6b6cbfe9a75)/ Task 5 `callseq.cr` 抽取 +> 3ab39f6eaa16(+ docs 525a872a0ba7)/ Task 6 `syscall.cr` 抽取 94d1cac15359(+ docs > d2f3e0968d8c)/ Task 7(本状态行随收官提交落盘)。行为零变化判据(§4.3 结构波) > 全绿——**逐任务 stage 链 byte-identical**(搬迁任务 R 重命名内容 verbatim;抽取任务 > 内容进新文件 + 调用点替换,每步独立构建验证)+ **收官全量回归逐套计数**。 @@ -142,7 +142,7 @@ src/runtime/ ← 运行时(rt.s——OS 轴补充) - **OS 轴** `src/os/linux/`:`entry.cr`(`emit_start`/`emit_start_size` 整搬)——Task 2; `callseq.cr`(`cs_args_dispatch`/`cs_arg_on_stack`/`cs_stack_count`/`cs_stack_args`/ `cs_stack_cleanup`/`cs_ret_value`/`cs_call_direct`——SysV 三处同源合流,per-slice - 字节比对核对后合并;`IR_CALL_EXTERN` 预存不对称**未合并未顺手修** = TODO #2026-09-10-5)——Task 5; + 字节比对核对后合并;`IR_CALL_EXTERN` 预存不对称**未合并、未连带修复** = TODO #2026-09-10-5)——Task 5; `syscall.cr`(`sys_syscall3_stub`/`sys_syscall4_stub`,r10 第四参约定)——Task 6。 - **组合根** `src/targets/x86_64-linux/`:`main.cr` + `_import.cr` + `Core.toml` (target triple 命名;project-mode 入口链,不入 concat)——Task 1。stage0 硬编码点 @@ -180,7 +180,7 @@ src/runtime/ ← 运行时(rt.s——OS 轴补充) 失败回 1/2)。构建日志 `error[` = 0,运行 `ALL PASS` rc=0(`build/corec` 与 stage 链 `corec3` 两工具链均绿)——覆盖 `os.cr` × `wait4` × `syscall4` r10 第四参径。 -### 8.3 本波**未**做(范围克制——波 2 起) +### 8.3 本波**未**做项(范围克制——波 2 起) - `IR_CALL_EXTERN` 栈参/栈清理不对称未修(TODO #2026-09-10-5);前端 ≥18 形参缺陷未修(TODO #2026-09-10-4)—— 两者皆预存、与结构波正交,按「零变化」纪律不混入。 diff --git a/docs/superpowers/specs/2026-09-11-explain-predict-incremental-design.md b/docs/superpowers/specs/2026-09-11-explain-predict-incremental-design.md index a1a31e18..993bd02b 100644 --- a/docs/superpowers/specs/2026-09-11-explain-predict-incremental-design.md +++ b/docs/superpowers/specs/2026-09-11-explain-predict-incremental-design.md @@ -42,7 +42,7 @@ 可解释是**人**的通道,可预测是**调度/约束**的通道,语义增量是**机器**的通道;三者共用 §4 的记录表与依赖边,不各建一套。 -**路线图 §1.4 的报告面(2026-09-11 追加)是同一机制在确定性轴族上的投影**:`D_value`…`D_mapping` 的逐项状态 = 该轴上的决定记录;**不确定性 provenance 链** = 同一条 `evidence` 闭包换个读法(从「为何选」读成「这个不确定性从哪来」)。故它是**第四条线索,不是第四个系统**(§1.7)。 +**路线图 §1.4 的报告面(2026-09-11 追加)是同一机制在确定性轴族上的投影**:`D_value`…`D_mapping` 的逐项状态 = 该轴上的决定记录;**不确定性 provenance 链** = 同一条 `evidence` 闭包的另一种读法(从「为何选」读成「这个不确定性从哪来」)。故它是**第四条线索,不是第四个系统**(§1.7)。 ### 0.3 裁决表 @@ -75,7 +75,7 @@ ### 1.1 原则:automation without opacity -编译器拿走工作,**不拿走理解**。可解释的判据不是「能打印一堆东西」,而是: +编译器拿走工作,**不拿走理解**。可解释的判据不是「能打印大量信息」,而是: 1. 用户能从一个**他能指认的锚点**(源码位置 / 符号 / 图节点)出发,问一个**他关心的问题类**,得到**编译器实际做过的决定**及其因由; 2. 答案是**产物的函数**,不是「再跑一遍编译器,这次开着日志」——同一产物两次查询必须逐字节同(与 §3 同一条纪律); @@ -85,7 +85,7 @@ ### 1.2 查询面:锚点 × 问题类 -**锚点**(用户指认得出来的东西): +**锚点**(用户指认得出的对象): | 锚点形态 | 语法(草案) | 解析路径 | |---|---|---| @@ -94,7 +94,7 @@ | 图对象 | `--node DFN` / `--instr IRN` / `--region ID` | `.cir` / `.ccr` 产物 + dump 通道 | | 记录 | `--record ID` | 决策记录表(L9 内容寻址 id) | -**问题类**=由**生产者注册的开放清单**(不是 CLI 硬编码 switch——否则每加一个 pass 就要改 CLI,退化成特判): +**问题类**=由**生产者注册的开放清单**(不是 CLI 硬编码 switch——否则每新增一个 pass 都须改 CLI,退化为特判): | 问题类 | 问什么 | 生产者(决策产出点) | 就绪度 | |---|---|---|---| @@ -178,8 +178,8 @@ ### 1.6 现状基础与缺口(诚实清单) -有:`ext_safety` 钩子 + F11 长度侧表(`g_ir_slice_lens`,编码:≥0 字面量 / ≤−2 长度变量 / −1 清除)+ `IR_BOUNDS_CHECK` + checker R002 + 7 个 dump 旗标 + 审计通道(默认关;**两态产物逐字节同**的纪律沿用——现行载体 = `--verify-named-dedup` / `--verify-evp-nodes`)+ `analysis.cr` 快照查询 + `json.cr` 读写。(原 `--type-shadow` 两态纪律的载体已随 R2 P5 Task 5 下线——R2 P6 Task 5 勘误。) -缺:统一记录表(0 实现)|内容寻址 id|因由码体系(现状无稳定规则标识符)|`unattributed` 概念|向量化决策(生产者不存在)|边界节点标注(`unsafe`/边界是语义概念,但**无查询通道**)|成本模型(S-C)|~~**效应事实不可靠(B 线 C2 登记)**~~(**已修,2026-09-11 效应/纯度批 `762bd429`+`c9099d73`**:`fi_ispure` 真计算 + `IR_CALL_EXTERN`/间接调用等全入链 ⇒ 本项移出「缺」清单;残余限定与证据见 §1.7.1 硬约束 8 修订与 TODO #2026-09-11-10;历史快照:恒 1 写入点 `checker.cr:1107`/`:1142`、`IR_CALL_EXTERN`(`ast.cr:572`=45)不入链、链每函数重置 `dataflow.cr:401`)。 +已有:`ext_safety` 钩子 + F11 长度侧表(`g_ir_slice_lens`,编码:≥0 字面量 / ≤−2 长度变量 / −1 清除)+ `IR_BOUNDS_CHECK` + checker R002 + 7 个 dump 旗标 + 审计通道(默认关;**两态产物逐字节同**的纪律沿用——现行载体 = `--verify-named-dedup` / `--verify-evp-nodes`)+ `analysis.cr` 快照查询 + `json.cr` 读写。(原 `--type-shadow` 两态纪律的载体已随 R2 P5 Task 5 下线——R2 P6 Task 5 勘误。) +缺口:统一记录表(0 实现)|内容寻址 id|因由码体系(现状无稳定规则标识符)|`unattributed` 概念|向量化决策(生产者不存在)|边界节点标注(`unsafe`/边界是语义概念,但**无查询通道**)|成本模型(S-C)|~~**效应事实不可靠(B 线 C2 登记)**~~(**已修,2026-09-11 效应/纯度批 `762bd429`+`c9099d73`**:`fi_ispure` 真计算 + `IR_CALL_EXTERN`/间接调用等全入链 ⇒ 本项移出「缺」清单;残余限定与证据见 §1.7.1 硬约束 8 修订与 TODO #2026-09-11-10;历史快照:恒 1 写入点 `checker.cr:1107`/`:1142`、`IR_CALL_EXTERN`(`ast.cr:572`=45)不入链、链每函数重置 `dataflow.cr:401`)。 ### 1.7 确定性报告面:`core analyze --determinism`(路线图 §1.4,2026-09-11 追加) @@ -290,7 +290,7 @@ cost_model_query(kind, subject, mapping_desc) -> { 三层不可混报:`explain --bounds` 的输出必须标层。**结构层上界不蕴含映射层上界**(值个数少但值大);把两层混成一个「内存上界」是本设计明确禁止的过度承诺。 -### 2.2 保证 vs 平均:状态值域(**统一承路线图 §1.4**) +### 2.2 保证与平均的区分:状态值域(**统一承路线图 §1.4**) 上界与轴族状态**共用同一个值域**(不另造一套标签——这是「三线共用一套」的直接后果): @@ -302,7 +302,7 @@ cost_model_query(kind, subject, mapping_desc) -> { | `EXPLICIT` | 语义**明文允许**该不确定(有主的不确定) | 必须指明**主人**(标注的位置与来源);不得与 `UNKNOWN` 混同 | | (`measured`) | 实测(PGO/剖析/回归数据) | **不是状态、不是保证**;只允许出现在诊断/建议语境,样式中不得与前四者同形 | -**假设是修饰不是状态**:`PROVED`/`MODELED` 都可以带假设清单(原「assumed」= `PROVED + 非空 assumptions` 的读法);假设不成立则界不成立——此约定比单列一档 `assumed` 更诚实(不会让读者以为「有假设的界」与「无条件证明」是同一类东西)。 +**假设是修饰不是状态**:`PROVED`/`MODELED` 都可以带假设清单(原「assumed」= `PROVED + 非空 assumptions` 的读法);假设不成立则界不成立——此约定比单列一档 `assumed` 更诚实(不会让读者以为「有假设的界」与「无条件证明」是同一类对象)。 这就是 §1.2 原则 3「义务不静默消失」在预测面的同构条款:**上界不静默降级**——`PROVED` 退到 `MODELED` 必须写清模型与假设;退到 `UNKNOWN` 必须显式登记。**禁止**把 `MODELED` 呈现为 WCET 证明(L13,契约硬性)。 @@ -328,7 +328,7 @@ cost_model_query(kind, subject, mapping_desc) -> { | ④ **reject** | 高安全模式下无法处置 → 拒绝编译 | policy 数据裁量 | | (② enforce **不在语言面**) | 若库 / 运行时自行实现超时动作,那是**库的语义**——语言不承诺其行为,也不得把运行期动作升格为语言保证(★D8) | — | -**明确不在 ①**:即使 someday 有成本模型,deadline 的 prove 仍依赖调度/硬件假设(路线图 §1.3 残留第 2 类)——`PROVED` 的 deadline 只可能在「声明域内 + 单核 + 无中断」这类**显式声明的封闭假设**下成立,且必须把假设挂在 `assumptions[]` 里。 +**明确不在 ①**:即使将来有成本模型,deadline 的 prove 仍依赖调度/硬件假设(路线图 §1.3 残留第 2 类)——`PROVED` 的 deadline 只可能在「声明域内 + 单核 + 无中断」这类**显式声明的封闭假设**下成立,且必须把假设挂在 `assumptions[]` 里。 **`MODELED` 的位置**:deadline 可以在**非安全关键**语境以 `MODELED`(S-C 成本模型估计 + 不确定带)呈现——但必须明标「模型估计,非证明」(L13),且**不得**作为调度/安全/适航类判据的输入。**超时动作 = 仅诊断**(已裁,★D8;O5 已闭合):报告面只呈现「该约束的 `D_timing` 状态 + 残余」,**不得**承诺任何超时行为。S-C 侧同款(其 §1 资源行 + §8 O5)。 @@ -368,7 +368,7 @@ cost_model_query(kind, subject, mapping_desc) -> { ### 3.2 与现有缓存的差距(含两个已实测缺陷) -**现状**:函数级 `.cir` 快照,`CIR_CACHE_VER = 17`(`src/compiler/cir_cache.cr:51`),头部 = magic / 版本 / **编译器身份**(v17 起引入——TODO #2026-09-10-1 修复,见 `cir_cache.cr:26` 与 `:214` 的字段序注)/ 函数体指纹 / 签名指纹 / name_len+name;命中即跳过 check + IR gen。(原记 `CIR_CACHE_VER`=14 / `cir_cache.cr` 行号 16 / magic `C1C1…` 三处双陈旧已在 R2 P6 Task 5 修正;magic 值不作承诺——`CIR_CACHE_MAGIC` 常量声明见 `cir_cache.cr:50`。) +**现状**:函数级 `.cir` 快照,`CIR_CACHE_VER = 17`(`src/compiler/cir_cache.cr:51`),头部 = magic / 版本 / **编译器身份**(v17 起引入——TODO #2026-09-10-1 修复,见 `cir_cache.cr:26` 与 `:214` 的字段序注)/ 函数体指纹 / 签名指纹 / `name_len`+name;命中即跳过 check + IR gen。(原记 `CIR_CACHE_VER`=14 / `cir_cache.cr` 行号 16 / magic `C1C1…` 三处双陈旧已在 R2 P6 Task 5 修正;magic 值不作承诺——`CIR_CACHE_MAGIC` 常量声明见 `cir_cache.cr:50`。) **差距 A(TODO #2026-09-10-1,预存)**:键**缺编译器身份分量** ⇒ 二进制重建后旧条目存活 ⇒ 旧 CIR 与新版字符串表(`g_strs` 驻留序)错位 ⇒ dump 通道变量名缺失/错位(实证:806 → 381 个 `name=` 翻转;清 cache 即复现判据)。 @@ -378,10 +378,10 @@ cost_model_query(kind, subject, mapping_desc) -> { **范围注(C4/★D25)**:差距 B 的**闭环**(命中路径产物保真:字符串驻留序 / 全局初始化注入的重放)落在「条目内容」面,**超出 S-D3 声明的范围**(S-D3 只做键的依赖集,明确不做增量后端与 `.ccr` 格式改动)⇒ 其判据② 已**降级为登记**(S-D3 表;不得按其字面读作 S-D3 的验收线)。 **差距 C(缓存 × 语义的静默交互,已有登记)**:缓存命中**跳过 `ir_gen_func(main)`** ⇒ 全局初始化注入(main 序言 IR 注入)在命中路径上**不重放**;配合差距 A ⇒ 升级编译器后旧 cache 让该修复**静默失效**(TODO「全局初始化机制」缓存交叉引用;批前该场景本就 rc=139,非回归)。 -**差距 D**:缓存与单态化的交互脆弱(`main.cr:442-446` 注释明写:缓存命中不重放 monomorph ⇒ 泛型函数存在时缓存整关)——即「性能特性」与「正确性」在现状实现里靠**关掉缓存**兜底。 +**差距 D**:缓存与单态化的交互脆弱(`main.cr:442-446` 注释明写:缓存命中不重放 monomorph ⇒ 泛型函数存在时缓存整关)——即「性能特性」与「正确性」在现状实现里以**关闭缓存**兜底。 **差距 E**:命中判据只有 <函数体, 签名> 两维——**不含**构建配置(`--static` / opt-level / target / `--table` / 实例声明)、**不含** policy 集(S-A 落地后义务集变了缓存必须失效)、**不含**依赖闭包。 -### 3.3 缓存键 = 依赖集(L6) +### 3.3 缓存键:依赖集(L6) | 分量 | 内容 | 解决 | |---|---|---| @@ -405,7 +405,7 @@ cost_model_query(kind, subject, mapping_desc) -> { | L2 记录级 | `explain` 输出(冷 vs 热两态,含 `unattributed`) | **S-D1 后可测**(依赖 L8:记录随条目存取) | | L3 义务级 | 义务/证明集合(ΔProof 后) | 待验证管线 | -**反向判据(必须同时有,否则主判据可被「永远全量重编」作弊)**:**增量必须真的生效**——命中率/复用率统计 + 一条「改动 1 个函数 ⇒ 未变更函数的 `.cir` 条目**字节未变**」的断言。只测「等价」不测「真的省了」= 把缓存删掉也能全绿。 +**反向判据(必须同时有,否则主判据可被「永远全量重编」规避)**:**增量必须真实生效**——命中率/复用率统计 + 一条「改动 1 个函数 ⇒ 未变更函数的 `.cir` 条目**字节未变**」的断言。只测「等价」而不测「确有节省」= 删除缓存也能全绿。 **负控集(失效面覆盖,每条一个断言)**:① 重建编译器(差距 A:跨重建不复用)② 改 stdlib 依赖(`deps_fp`)③ 改 policy 集(`policy_fp`,S-A 后)④ 改 `--static`/opt-level/target(`unit_fp`)⑤ 泛型/单态化路径(差距 D)⑥ 引擎版本变更(ΔProof)。 **验收升级(C4/★D25 修正)**:现状纪律「判据比较前必须 `clean-cache`」的消灭 = **整体目标(L7)**,其闭环依赖「命中路径产物保真」机制(**不属 S-D3 范围**);S-D3 的验收线改为「**差距 A 转绿 + 差距 B 仍红并附根因清单** + L7 保留为整体目标」(§5 S-D3 判据②/③)。 @@ -446,7 +446,7 @@ cost_model_query(kind, subject, mapping_desc) -> { - **落盘位置**:**先行 = 旁路文件**(S-D1 落地路径;与产物同目录或 `.core/`,命名待实施批定);**终态 = `.ccr` 决策记录段**(**已裁,★D4**:随 R2 P4 同波进段——**段 tag 空间可扩展**,`2026-09-09-lattice-ir-v7-format.md:44` 的 `7+` **未固定分配**(既有注明用途 = 驱逐标注段 / 证书段,与本段并列取号,段名随实施批定))——段化前旁路文件是唯一载体;段化后**两态产物须逐字节同**(守卫判据)。 - **守卫判据**:记录通道关 → 产物逐字节同(照**审计通道默认关 + 两态产物 sha256 同**的既有纪律;现行载体 = `--verify-named-dedup` / `--verify-evp-nodes`;迁移期 `--type-shadow` 已随 R2 P5 Task 5 下线——R2 P6 Task 5 勘误)。 -### 4.4 为什么不能各建一套(反例) +### 4.4 不得各建一套的反例 差距 B(`.ccr` 冷热两态 sha256 不同)就是「没有共用载体」的代价:**编译器的决定没有随产物走**,于是缓存命中路径「少做了一些决定」,而没有任何数据结构能告诉你少做了什么。若 §1 自建一套解释数据、§3 自建一套失效数据,则: - `explain` / `analyze --determinism` 在冷/热两态给出不同答案(因为决定没随条目走)——**直接违反本 spec §1.4 约束 1 与 §1.7.1 约束 6**; @@ -518,7 +518,7 @@ cost_model_query(kind, subject, mapping_desc) -> { | 残留 | 本 spec 的落法 | |---|---| | **错误 specification** | `explain` 报告的是「编译器**为何**这样做」,**不是**「这样做**对**」。记录的 `cause` 是因由码而非正确性证明;增量主判据(L1 逐字节同)是「同一编译器的两态一致」,**不等于语义正确**——不得当作验证证据引用。 | -| **恶意/失陷外部实体** | 决策记录的**载体是磁盘文件(旁路 + 缓存)**,可被篡改;伪造的记录能让 `explain` 撒谎、能让增量复用错误的决定。故:① `explain` 输出**不是**安全证据(它只谈编译器自己的决定);② 对抗篡改靠可复现构建/签名(路线图范围内、本 spec 范围外);③ 记录必须随缓存条目**一起**校验(分量不匹配即 miss,§3.5)。 | +| **恶意/失陷外部实体** | 决策记录的**载体是磁盘文件(旁路 + 缓存)**,可被篡改;伪造的记录可令 `explain` 给出不实结论,也可令增量复用错误的决定。故:① `explain` 输出**不是**安全证据(它只谈编译器自己的决定);② 对抗篡改靠可复现构建/签名(路线图范围内、本 spec 范围外);③ 记录必须随缓存条目**一起**校验(分量不匹配即 miss,§3.5)。 | | **需求本身允许危险行为** | 本 spec 不禁止任何能力:上界是**约束数据**,解释是**只读视图**。隔离边界(S-B 族)与上界声明是两件事——上界不构成隔离证明,反之亦然。 | **路线图 §1.4 面的同一读法**(确定性报告): diff --git a/docs/superpowers/specs/2026-09-11-performance-without-commitment-design.md b/docs/superpowers/specs/2026-09-11-performance-without-commitment-design.md index b440114e..ed90bf17 100644 --- a/docs/superpowers/specs/2026-09-11-performance-without-commitment-design.md +++ b/docs/superpowers/specs/2026-09-11-performance-without-commitment-design.md @@ -45,7 +45,7 @@ | L6 | **标注 = 开放标注/事实来源,不是新 primitive**:不新建属性轴、不新增语言关键字;显式面仅允许「可选性能提示」(可被任何目标忽略 → 退化合法)。**2026-09-11 用户裁决 ★D5 = 守零新语法**:轴 / 上界 / 局部性标注全走**既有插件标签通道**;参数级档位约束落 **policy 数据表**(不新增声明语法) | 契约 §1.2.1 | | L7 | **决策与缺席都要有理由**(§5)——「不静默」原则在本线的形态(弱承诺:可解释,非拒绝编译) | 与 S-D 的接口 | -**待论证清单**(不假装已定):成本模型的精度/量纲/校准方法论;启发式阈值(调度开销 vs 收益);PGO 数据的信任形态;决策记录规模与裁剪。逐条见 §8。(局部性显式提示的语法载体已裁 = 零新语法,★D5——见 §8 O2。) +**待论证清单**(不视作已定项):成本模型的精度/量纲/校准方法论;启发式阈值(调度开销 vs 收益);PGO 数据的信任形态;决策记录规模与裁剪。逐条见 §8。(局部性显式提示的语法载体已裁 = 零新语法,★D5——见 §8 O2。) ### 0.3 合批关系(R3 / x86 实例化波 2-3) @@ -140,10 +140,10 @@ 契约六条: 1. 事实/模型分离:成本事实 = 表条目字段(材料属性);「如何用成本事实决策」= 编译器侧可替换件(HIT §3.3「表只描述材料,不描述放置策略」保持)。 -2. 缺失 = 保守退化,**不猜**。 +2. 缺失 = 保守退化,**不作推断**。 3. 相对量纲,不承诺绝对值、不承诺最优(§7)。 4. 模型可替换:多目标/多范式各一套实例,机制不换。 -5. **模型非证明(硬性,承契约 §1.4;B 线 C1/★D24)**:估计值**不得**呈现为 WCET 证明 / 时间上界——`MODELED` 渲染必须明标「模型估计,非证明」(S-D §1.7.2);`band` 必填;模型不可用(未落地 / 预算耗尽)⇒ 消费方按 `UNKNOWN`,**不得**用"经验常数"兜底成 `MODELED`(S-D §1.7.3 禁令)。 +5. **模型非证明(硬性,承契约 §1.4;B 线 C1/★D24)**:估计值**不得**呈现为 WCET 证明 / 时间上界——`MODELED` 渲染必须明标「模型估计,非证明」(S-D §1.7.2);`band` 必填;模型不可用(未落地 / 预算耗尽)⇒ 消费方按 `UNKNOWN`,**不得**以"经验常数"回退为 `MODELED`(S-D §1.7.3 禁令)。 6. **与上界不混报(B 线 C1/★D24)**:成本估计只进 `MODELED` 层;与 S-D 结构层 `PROVED` 数字(分配次数/在飞任务数/通信量)**不得合并/覆盖/相减**——三层不可混报(S-D §2.1);同层内冲突取保守(更宽界)。`phase_ver` 含 `model_ver` ⇒ **模型换代 ⇒ 相关记录与报告自动失效**(S-D §3.3)。 ### 2.4 与义务/安全性的交互(硬条款,承 L4) @@ -180,7 +180,7 @@ 2. **源码零改动**:换目标不得要求改源码——**这是「无实现承诺」的操作性判据**(要改源码 = 机器形状漏进程序意义,违反 L1)。 3. **义务判定不变**:换目标后 S-A 的义务档位/判定结果不变(安全不因目标而弱化)。 4. **决策自由**:映射选择(内联 / 向量化 / 并行 / 布局 / placement)可完全不同——判据**只约束语义,不约束决策**。 -5. **可移植子集**:只用最小核事件的程序 = 任意表可跑(HIT §4 既有条款,本 spec 承接为可移植判据的基线)。 +5. **可移植子集**:只用最小核事件的程序 = 可在任意表下运行(HIT §4 既有条款,本 spec 承接为可移植判据的基线)。 反向(泄漏检测,用 lattice-encoding-boundary G3「可换性」判据):a) 换目标需改源码;b) 决策结果被写回图/源码语义;c) 源/图中出现机器名词——三项任一 = 违反,登记为「泄漏待归一」。 @@ -229,8 +229,8 @@ S-D 消费面(归 S-D):explain 输出契约 / 上界预测(内存/任务 **切片设计(一条标注 → 一个决策)**: - **事实**:纯度(效应集)——**本批(`762bd429`+`c9099d73`)后可直接消费真纯度**:含任何效应 opcode(§1 单一依据 `purity_op_effect`)或不可解析/未证纯调用的节点/region 一律计效应(保守方向)。**时点约束**(同 §2.2 C2):须在 `compute_all_purity` 写回后消费(IR 生成 + `df_state_finalize`),生成期旗标仍是冻结的乐观默认值。零新语法、零用户可见变化。 -- **决策(2026-09-11 收敛批 v3 重定靶对象,B 线 N3)**:**自动记忆化 safe 子集 = 「循环不变的纯节点/region」**——三条前提:① **在循环体内**且**输入不随迭代变化**(定义在循环外,或由图证明为迭代不变量);② 按真纯度判定为纯(保守方向:含任何效应 opcode 或未证纯/不可解析调用即视为有效应——§1 单一依据 `purity_op_effect`;时点见 §2.2 C2);③ 无分配 / 无 arena 交互 + 单线程。选择理由:**收益面真实存在**(每迭代重复求值 ⇒ 上提至循环外/缓存后**求值次数下降**),且合法性前提仍是最小集(无效应边 + 不变性),与自动惰性共用基础设施(TODO 原文的机制重叠);**不接线成本模型**——收益规则用平凡保守启发式,把成本模型留成可替换桩。即:切片先跑通「**合法性可判定**」,把「**收益启发式**」留白(与 §2.2 分界一致)。 -- **为何不用「≥2 次使用」(B 线 N3 实证,硬性)**:① 今日 `IR_LAZY_THUNK` / `IR_LAZY_FORCE`(46/47)在**两条路径都是 eager 直通**(`interp.cr:299-302`「Calls are currently eager, so both wrappers preserve the computed value」;`x86_64/instr.cr:1364-1375` 同义)⇒ **没有"延迟求值"可省**;② 严格 DAG 中一个值的多个消费者**本就只求值一次**(单生产者 + 槽读)⇒「≥2 次使用」的记忆化**无可省收益、判据 3 无见证**(正控会全绿空过)。**备选路线**(把「thunk 真惰性落地」列为切片前置)**不采纳**:理由 = 那会把切片从「一个标注 → 一个决策」变成**执行模型改造**(前置成本远大于收益),且与惰性批(TODO「控制流自动惰性」)重叠——两条路线的收益面不同(惰性 = 避免未使用的求值;本切片 = 避免重复求值),不应互锁。 +- **决策(2026-09-11 收敛批 v3 重定靶对象,B 线 N3)**:**自动记忆化 safe 子集 = 「循环不变的纯节点/region」**——三条前提:① **在循环体内**且**输入不随迭代变化**(定义在循环外,或由图证明为迭代不变量);② 按真纯度判定为纯(保守方向:含任何效应 opcode 或未证纯/不可解析调用即视为有效应——§1 单一依据 `purity_op_effect`;时点见 §2.2 C2);③ 无分配 / 无 arena 交互 + 单线程。选择理由:**收益面真实存在**(每迭代重复求值 ⇒ 上提至循环外/缓存后**求值次数下降**),且合法性前提仍是最小集(无效应边 + 不变性),与自动惰性共用基础设施(TODO 原文的机制重叠);**不接线成本模型**——收益规则用平凡保守启发式,把成本模型留成可替换桩。即:切片先实现「**合法性可判定**」,把「**收益启发式**」留白(与 §2.2 分界一致)。 +- **「≥2 次使用」不作为判据的理由(B 线 N3 实证,硬性)**:① 今日 `IR_LAZY_THUNK` / `IR_LAZY_FORCE`(46/47)在**两条路径都是 eager 直通**(`interp.cr:299-302`「Calls are currently eager, so both wrappers preserve the computed value」;`x86_64/instr.cr:1364-1375` 同义)⇒ **没有"延迟求值"可省**;② 严格 DAG 中一个值的多个消费者**只求值一次**(单生产者 + 槽读)⇒「≥2 次使用」的记忆化**无可省收益、判据 3 无见证**(正控将全部通过而不构成见证)。**备选路线**(把「thunk 真惰性落地」列为切片前置)**不采纳**:理由 = 该路线会把切片从「一个标注 → 一个决策」变成**执行模型改造**(前置成本远大于收益),且与惰性批(TODO「控制流自动惰性」)重叠——两条路线的收益面不同(惰性 = 避免未使用的求值;本切片 = 避免重复求值),不应互锁。 - **落点**:新增判定/memo pass(事实读取 + 选择 + §5 记录 stub;时点见前置 1)+ 解释器侧 memo 化消费点(`interp.cr`)。 - **依赖**:数据流分析的使用计数(§2.1 ① 的事实面)+ **循环归属 / 迭代不变量判定**(region 迭代序 `SG_LOOP` / `SG_FOR` + 输入的 def 位置是否在循环外——B 线 N3 重定靶对象后新增的事实面,仍是"图可判定");S-D1 的记录表 stub(判据 6,建议同批)。 - **切片前置**(不属切片、但计划须显式列出): @@ -241,7 +241,7 @@ S-D 消费面(归 S-D):explain 输出契约 / 上界预测(内存/任务 1. **零标注**:源程序不变(无新语法),切片前后源码零改动。 2. **语义等价**:全回归 + 双路径(interp / ELF)精确 rc + **效应次数不增** + **不变量前提成立**(被记忆化的节点/region:无调用、无效应、**输入不随迭代变化**——三者逐条断言,不靠"看起来纯")。 -3. **生效证据**:决策记录出现记忆化/上提选择(≥1,判据 6 通道)+ **求值规模下降**——判据 3 的**唯一可观测面 = 前置 2 自带的解释器侧最小计数**(interp-only dev 通道);**不采用**「IR 节点数 / 发射指令数下降」作备选(B 线 N6:本切片落点在**解释器侧**,其改写不减少 ELF 路径的指令数——与落点不相容);「生效」必须可观测,不能只看产物没崩。 +3. **生效证据**:决策记录出现记忆化/上提选择(≥1,判据 6 通道)+ **求值规模下降**——判据 3 的**唯一可观测面 = 前置 2 自带的解释器侧最小计数**(interp-only dev 通道);**不采用**「IR 节点数 / 发射指令数下降」作备选(B 线 N6:本切片落点在**解释器侧**,其改写不减少 ELF 路径的指令数——与落点不相容);「生效」必须可观测,不能仅以产物未崩溃为准。 4. **退化路径**:事实推导失败 / 使用计数未知 / **不变量不可判(输入随迭代变化)** / 保守条款判为有效应 → 不 memo 且记录理由(无静默)。 5. **开关**:决策 pass 可关;关态 = 现状行为(产物/rc 与基线一致)。 6. **记录通道 stub**:§5 R1/R2 的最小记录随切片落地(字段集 = S-D §1.3 + 本线补充;为 S-D 预留消费面)。 @@ -260,17 +260,17 @@ S-D 消费面(归 S-D):explain 输出契约 / 上界预测(内存/任务 本族逐条落点: -- **错误 specification**:优化器不救错算法——「忠实实现规则」包含「忠实地慢」;本线承诺的是「不把机器写回程序」,不是「程序一定快」。 +- **错误 specification**:优化器不修复错误的算法——「忠实实现规则」包含「忠实地慢」;本线承诺的是「不把机器写回程序」,不是「程序一定快」。 - **恶意/失陷外部实体**:**表与剖析数据是外部输入**——恶意/损坏的目标描述或 PGO 数据可改变性能甚至改变所选映射;用 provenance / 签名 / 最小权限**缩小**,语言语义**不证明**;信任归治理层(与 M1 定论一致)。 - **需求本身允许危险行为**:unsafe / extern 边界内手写机器相关代码(HIT extern 事件 / unsafe 外部入口)**不被禁止**——本 spec 不管理它,只保证它不污染其它部分的程序意义(机器相关区域须显式留在边界内)。 本线自有不承诺(成本模型 / 启发式): -- **模型非证明(承契约 §1.4,硬性)**——成本估计是启发式,**不得**呈现为 WCET 证明 / 时间上界;`MODELED` 数字必带 `band` + `model_id`/`model_ver` + `assumptions[]`(§2.3 契约第 5 条),且与 `PROVED` 层不混报(第 6 条);模型不可用 ⇒ `UNKNOWN`,不得用经验常数兜底。 +- **模型非证明(承契约 §1.4,硬性)**——成本估计是启发式,**不得**呈现为 WCET 证明 / 时间上界;`MODELED` 数字必带 `band` + `model_id`/`model_ver` + `assumptions[]`(§2.3 契约第 5 条),且与 `PROVED` 层不混报(第 6 条);模型不可用 ⇒ `UNKNOWN`,不得以经验常数回退。 - **成本模型不保证最优**——选择 = 启发式;最优性证书 = 远期独立项,不在本 spec。 - **启发式可退化**——退化 = 回落语义直接形态;不承诺任何程序变快,不承诺优化一定发生。 - **不承诺性能可移植**——语义可移植(§3.2)是承诺;不同目标的性能表现可完全不同(决策自由是其推论)。 -- **不承诺自动推断意图**——精度(apx)等意图类标注永远显式;推断不出的局部性事实不猜。 +- **不承诺自动推断意图**——精度(apx)等意图类标注永远显式;无法推断的局部性事实不作推断。 --- @@ -278,8 +278,8 @@ S-D 消费面(归 S-D):explain 输出契约 / 上界预测(内存/任务 **不做项**(YAGNI / 已裁): -- 自动 apx(精度意图——编译器猜不了,显式标签保留——TODO 定案); -- 数据结构自动选择(依赖意图,太远——TODO 定案); +- 自动 apx(精度意图——编译器无法推断,显式标签保留——TODO 定案); +- 数据结构自动选择(依赖意图,超出当前范围——TODO 定案); - 最优性证书 / 性能证明(远期独立项); - 非经典范式的成本模型实例(本 spec 只给接口形态;经典实例先行,范式扩展随 M3); - 手动性能标注的**语言化**(不新增关键字/属性轴——L6); diff --git a/docs/superpowers/specs/2026-09-11-policy-authorization-design.md b/docs/superpowers/specs/2026-09-11-policy-authorization-design.md index c94a1f65..252cf5df 100644 --- a/docs/superpowers/specs/2026-09-11-policy-authorization-design.md +++ b/docs/superpowers/specs/2026-09-11-policy-authorization-design.md @@ -17,7 +17,7 @@ ### 0.1 论题 -**授权的语义不是「运行时问一句能不能」,而是图上一条路径是否存在。** 判定式(路线图 §2 S-B2 定义;**带状态版本参数**,2026-09-11 裁决 D13): +**授权的语义不是「运行时的一次可否询问」,而是图上一条路径是否存在。** 判定式(路线图 §2 S-B2 定义;**带状态版本参数**,2026-09-11 裁决 D13): ``` Can(a, o, r, v) ⟺ ∃π : a ⇝ (o, r),π 合法 ∧ v 与路径边的版本见证一致 @@ -25,7 +25,7 @@ Can(a, o, r, v) ⟺ ∃π : a ⇝ (o, r),π 合法 ∧ v 与路径边的 `a` = 主体(subject)· `o` = 对象(object)· `r` = 权限(right)· `v` = **状态版本见证**(D13;κ 粒度 = **对象身份 + 版本见证**)· `π` = capability path。 -与传统做法的差别是**量的差别变成质的差别**:`if (!has_permission(...)) return error;` 的失败分支是一条**没人写的代码路径**(漏写 = 越权);`∃π` 的失败是一个**类型/图形状事实**(写不出越权,因为该 effect 生成不出来)。本族的全部工作就是让后者成立。 +与传统做法的差别是**量的差别变成质的差别**:`if (!has_permission(...)) return error;` 的失败分支是一条**未被写出的代码路径**(漏写 = 越权);`∃π` 的失败是一个**类型/图形状事实**(写不出越权,因为该 effect 生成不出来)。本族的全部工作就是让后者成立。 ### 0.2 与 capability-lattice v4 的 M1 定论对齐(**裁决:不改变,本族是 M1 的兑现**) @@ -43,7 +43,7 @@ M1 定论(v4 §六):**语义保鲜线不需要「能力」独立概念** **本族对 M1 的两点增量(补充,非修订):** 1. **不对称性的推广**:M1 说「标注可长,原语不可长」(v4 §六 架构不对称性)。本族把它推广到治理层——**策略可长(数据),判定器不可长(固定为集合包含 + 图上可达性)**。新增安全模型 = 新增授权边数据;判定算法一字不改。这是契约 §1.1 `policy` 定义(数据而非语法)在授权族的具体兑现。 -2. **M1 的证成(而非只是裁决)**:M1 断言「授权不是语义」。本族给出它**为什么不是**——因为 capability path 的语义半边(引用能否到达、生命周期是否包含)**已经在图上了**(provenance / RegionCheck / 借用逃逸,`pointer-model.md`)。缺的只有治理半边。**有引用 ≠ 有授权**;语义层给「能不能到」,治理层给「许不许」。两半分开,正是 M1 的切分点。若把治理半边塞进语义层,就等于让「谁被允许」污染「这程序算什么」——语义保鲜线立刻失守。 +2. **M1 的证成(而非只是裁决)**:M1 断言「授权不是语义」。本族给出其**不属语义的依据**——capability path 的语义半边(引用能否到达、生命周期是否包含)**已经在图上了**(provenance / RegionCheck / 借用逃逸,`pointer-model.md`)。缺的只有治理半边。**有引用 ≠ 有授权**;语义层给出「能否到达」,治理层给出「是否许可」。两半分开,正是 M1 的切分点。若把治理半边塞进语义层,就等于让「谁被允许」污染「这程序算什么」——语义保鲜线立刻失守。 ### 0.3 `unsafe` 与治理层的关系(本族最重要的一条边界裁决) @@ -52,7 +52,7 @@ M1 定论(v4 §六):**语义保鲜线不需要「能力」独立概念** > **`unsafe` 消解语义层义务,不消解治理层授权义务。** - 在 `unsafe` 块内,provenance 不可追踪 → capability path 的语义半边**不可证** → 该 effect 落 **proof-required 或 reject**(§3.3),**绝不落 prove**。**分类(2026-09-11 收敛批 v3 按 A 线 ⚠️3 拆句)**:这是 **`unknown` 面**——「**不可判定 ≠ 不合法**」(S-A §2.2 点 2)⇒ 走 ③/④,**不得写成「违法」**。 -- 治理层授权义务**独立于 unsafe 继续存在**(**第二条,与上一条分属不同档**):`unsafe` 里读同一对象仍需治理层声明覆盖,否则**硬编译错 = 违法**——缺省拒绝下 `¬Can` **确定成立**,是**判定结论为假**(属"违法",**不属于义务梯档**),不是 ④「无法处置」(S-A §2.2 点 1 分栏,§3.3 表)——出路 = 显式治理层声明(下行)。理由:若 unsafe 能顺带免掉授权检查,`unsafe` 就成了**权限提升后门**——这正是 broken access control 的经典形态,本族存在的意义就是堵它。 +- 治理层授权义务**独立于 unsafe 继续存在**(**第二条,与上一条分属不同档**):`unsafe` 里读同一对象仍需治理层声明覆盖,否则**硬编译错 = 违法**——缺省拒绝下 `¬Can` **确定成立**,是**判定结论为假**(属"违法",**不属于义务梯档**),不是 ④「无法处置」(S-A §2.2 点 1 分栏,§3.3 表)——出路 = 显式治理层声明(下行)。理由:若 unsafe 能顺带免掉授权检查,`unsafe` 就成了**权限提升后门**——这正是 broken access control 的经典形态,本族的存在意义即在于封堵这一形态。 - 唯一合法通道 = **显式治理层声明**(grant 边 / 例外条目),且**派生源必须可追踪**(capability-lattice §七:派生源 = 例外入口授权可追踪,信任链)。这是路线图 §1.1 `declassify` 在授权族的同构对应物:`¬Can → Can` 的唯一合法通道 = 带派生源的显式声明,不是 `unsafe`、不是运行时绕过。 - **收尾到统一 schema(2026-09-11 裁决 D2(a))**:本族条目 = **S-A §3.1「放行 / 声明条目」** 的 `kind = grant|deny`,字段 = 主体/身份 · 目标/范围(`(o,r)`)· 理由 · **派生源** · 义务引用;**必须落清单**(S-A §5.2b)。**形态 = 声明型边集合(`E_grant`/`E_deny`),显式豁免节点形态**——理由:授权归**治理层数据面**(M1),它是**标注/声明**而非「变换一个值」的图节点(与 `declassify` 的语义角色不同);豁免理由 + 审计字段二者缺一即**拒装**(S-A §3.6)。 @@ -66,7 +66,7 @@ M1 定论(v4 §六):**语义保鲜线不需要「能力」独立概念** | C2 | 撤销(revocation)必须**运行期强制**,且无法表达为图上状态版本 | 未触发:按 v4 §11,Core 参照 seL4 的**结构**不参照其**运行时机制**;撤销落 S-B5 状态版本族(编译期) | | C3 | 策略表达力需求超出图上正存在边 + 显式 deny(如需要运行期动态策略注入对象) | 未触发:超片段需求按 §3.3 落 proof-required/reject,不扩判定器 | -C1/C2 的**代价必须写明**(诚实账):不提升 = **无法表达「运行期授予且运行期撤销的能力」**。图是编译期的;`grant` 发生在运行时的场景(能力在程序运行中由外部授予)**不在本族可证范围**——它落 §3.3 的 proof-required 档,由治理层外部机制承担。这条代价不做隐藏。 +C1/C2 的**代价必须写明**(代价须显式记录):不提升 = **无法表达「运行期授予且运行期撤销的能力」**。图是编译期的;`grant` 发生在运行时的场景(能力在程序运行中由外部授予)**不在本族可证范围**——它落 §3.3 的 proof-required 档,由治理层外部机制承担。该代价不作隐藏。 **代价的接受(2026-09-11 裁决 D14)**:**接受**该代价(能力不提升一等公民),代价条款同时写进**路线图 §2 的 S-B2 行**。**延伸路径**(未来若确需运行期授予 / 撤销)= **D13 的能力对象 + 版本见证**(`Can(a,o,r,v)`,§1.3)——「撤销 = 版本推进 ⇒ 旧版本见证失效」,在语言面可表达,不需回溯修订 M1。触发条件仍以 §0.4 的 C1/C2/C3 为判据(当前全未触发)。 @@ -86,7 +86,7 @@ C1/C2 的**代价必须写明**(诚实账):不提升 = **无法表达「 | `SrcOK(π)` | 治理层**允许**:路径每条边的授权标注沿路径**单调收窄**(⊑ 细化,不得提权) | 治理层 `E_grant` 标注(**本族新增数据**,非新机制) | | `¬Deny(π)` | 无显式拒绝边覆盖 | 治理层 `E_deny` 标注 | -**为什么必须是三条而不是一条**:`SemOK` 是语义层的(M1 已在图上),`SrcOK`/`Deny` 是治理层的(M1 说归治理层)。缺 `SemOK` 的失败 = 「你根本到不了这东西」(UAF/逃逸类);缺 `SrcOK` 的失败 = 「你能到,但你不许」——**后者才是本族**。诊断为二者给出**不同断点**(§2.5),这是「越权」与「野指针」不被混为一谈的形式保证。 +**三条合取条件的必要性**:`SemOK` 是语义层的(M1 已在图上),`SrcOK`/`Deny` 是治理层的(M1 说归治理层)。缺 `SemOK` 的失败 = 「引用根本到不了该对象」(UAF/逃逸类);缺 `SrcOK` 的失败 = 「引用能到达,但授权不允许」——**后者属本族**。诊断为二者给出**不同断点**(§2.5),这是「越权」与「野指针」不被混为一谈的形式保证。 ### 1.2 节点与边(**设计定稿**;内部布局实施批定) @@ -121,7 +121,7 @@ Can(a,o,r,v) ⟺ r ∈ W(a,o) ∧ ¬DenyCovered(a,o,r) ∧ v 一致(版本 - **路径内取交(⋂ = 幂集格 meet)**:每条边都必须允许。 - **路径间取并(⋃ = 幂集格 join)**:**存在**一条合法路径即可。 - 这正是 capability-lattice §九 代数(授权分量 = 幂集格,`∩`/`∪` = meet/join)与保序积总序 `(r₁,a₁) ⊑ (r₂,a₂) ⟺ r₁ ⊑ r₂ ∧ a₁ ⊆ a₂` 的直接消费。 -- **可判定性(好消息)**:`W(a,o)` 是 **格上最宽路径(widest / bottleneck path)问题**。因为授权分量是**分配格**(幂集格 ⇒ 分配律成立),最宽路径良定义且**多项式时间可解**(Dijkstra 变体 / 有限主体集上迭代到不动点 = Datalog 半朴素求值)。递归能力树成环**不破坏可判定性**(格上可达性对环封闭;与 R2 引擎 μ 展开的余归纳 memo 同族处理)。 +- **可判定性(正面结论)**:`W(a,o)` 是 **格上最宽路径(widest / bottleneck path)问题**。因为授权分量是**分配格**(幂集格 ⇒ 分配律成立),最宽路径良定义且**多项式时间可解**(Dijkstra 变体 / 有限主体集上迭代到不动点 = Datalog 半朴素求值)。递归能力树成环**不破坏可判定性**(格上可达性对环封闭;与 R2 引擎 μ 展开的余归纳 memo 同族处理)。 - **与 state edges 的接口(正交,**裁决:不耦合**)**:state edges 是「先发生」顺序约束(命令式下限,定案 14 不动);capability path 是**存在性**,不是顺序——两者正交,判定**不消费顺序**。唯一的表面交叉 = **撤销**:撤销前后的能力不同,是**时间**概念 → 归 **S-B5 状态版本族**(图上两个版本),本族**只消费其版本见证**(D13:`Can(…,v)`),不定义版本机制。 - **与 provenance 的接口(`asp`)**:外部地址空间指针(`asp=1`,`pointer-model.md:221`)**没有 Core provenance** → 其 `SemOK` 恒假 → capability path 必然经例外入口 → 落 §0.3 的 unsafe 裁决。这条把「外部来源引用」自动排除出可证子集,无需特判。 diff --git a/docs/superpowers/specs/2026-09-11-policy-injection-design.md b/docs/superpowers/specs/2026-09-11-policy-injection-design.md index 9cffa9cd..5095a3c3 100644 --- a/docs/superpowers/specs/2026-09-11-policy-injection-design.md +++ b/docs/superpowers/specs/2026-09-11-policy-injection-design.md @@ -51,7 +51,7 @@ ## §1 非法边判据 -### §1.1 位置种类的操作性定义(为什么它必须由库声明) +### §1.1 位置种类的操作性定义(须由库声明的原因) > **语法位判据**:位置 π 是领域 D 的**语法位**,当且仅当**下游解释器 D 对 π 处的字节做分隔符/结构再扫描(re-scan)**——即这些字节中若出现 D 的元字符(或分隔约定),会改变 D 对结构的判定。否则 π 是**值位**。 @@ -101,11 +101,11 @@ Legal(v, π) ⟺ - **陷阱注记(本族对 S-A §3.3 的补充,实施批必读)**:单式里的 `⊓` 与 `⊥` 有一个会**架空判据**的退化路径——若 `A_trust(v)` 以**否定形式**展开(如不可信 ↦ `¬Trusted`),而左侧值项本身已含该标注(如库构造出的 `SQL` 值被标 `untrusted`),则左式 = `SQL ⊓ ¬Trusted = ⊥`,而 `⊥ ⊑ 任意 φ` **恒真** ⇒ 判定放行一个不可信值 ⇒ **静默通过**(违反原则 3)。**规范约定**:`A_trust` 只做**加约束式单调展开**(可信 ↦ `Trusted`,不可信 ↦ `⊤`=不加约束),属性要求一律写在**右侧** `Shape(π)`;实施批须配负控(N5,§6.1)锁死该约定。**并且右项与正例也要锁**(S-A §3.3.1 **C5**,2026-09-11 裁决 D11)——本式的**全部鉴别力在右项**(`trust` 不可信 ↦ `⊤` 不加约束),因此:① `Shape(π)` 在 `syntax` / `syntax_raw` 位置**不得为 `⊤`**(policy 装载期校验,违者**拒装**);② 每条轴取值须有**非退化正例**(`Trusted ⊓ string ≠ ⊥`,否则正控全灭、P1-P3 不成立);③「假 / unknown」**分因**(假 = 违法、unknown = ③/④);④ 未定义原子**取 unknown 不得取真**。四项的规范性来源 = **S-A §3.3.1 C1-C5**,本文只引用。 - **未判定不静默**(原则 3 + R2 §3.3 预算守卫):`ty_sub` 返回 unknown(预算耗尽 / 未覆盖面)时,**不得当通过**,按 S-A §2.2 决策树落 ③/④ 并登记(§5)。 -**为什么不需要流敏感分析**:判据只读 `τ(v)` 与 `trust(v)` 两处标注,与 v 的**定义路径、别名、中转(laundering)无关**。把不可信字符串存进结构体字段、经函数返回、经容器搬运,都不会改变它到不了语法位这一事实——因为**唯一的入口是库的构造器**。这是形状项判据相对污点分析的结构性优势,也是 §3「if-校验旁路」不成立的根因。 +**不需要流敏感分析的原因**:判据只读 `τ(v)` 与 `trust(v)` 两处标注,与 v 的**定义路径、别名、中转(laundering)无关**。把不可信字符串存进结构体字段、经函数返回、经容器搬运,都不会改变它到不了语法位这一事实——因为**唯一的入口是库的构造器**。这是形状项判据相对污点分析的结构性优势,也是 §3「if-校验旁路」不成立的根因。 - **该论证的前提(登记,D12)**:`trust(v)` 的传播面(S-B3 的 R1-R4 同族)与形状判据都要求「**图的边 / region 覆盖全部语义依赖**」——这是**待审计前提**,不是公理。按 **D12**,依赖完备性 = **独立侦查项**(输出「边 / region 覆盖率报告 + 缺口清单」);**覆盖率报告无缺口前**,本节论证与 S-B3 S1 一律不启动(S-B3 §6.1 前置 3 同门槛)。 -### §1.3 构造器封闭 = 非法边的第一性来源 +### §1.3 构造器封闭:非法边的第一性来源 `φ` 是**库声明的**形状类型项,其 inhabited 值只能由**声明返回 φ 的构造器**产生: @@ -113,7 +113,7 @@ Legal(v, π) ⟺ - **数值层封闭(须策略给出)**:`φ` 的某个构造器若同时接受「不可信来源可满足的类型」(如 `string`),则它是**开口**——策略必须二选一:① 给它附**档位约束**(解析式位置 = 常量档,动态实参不满足,§2.2),或 ② 把它登记为净化节点(§3,带后置条件义务)。 - **封闭性的现实缺口(已裁,2026-09-11)**:Core 今天**不强制** `pub`(`parser.cr:662` 声明 / `:697` 只写 `is_pub`,**全仓无消费**——代码级缺陷 5)⇒ 库外代码若被允许构造 `φ`,封闭性只能靠 TCB 维持。**裁决(D6(a))**:形状项 / 根声明**只在受控命名空间内有效** + **装载期校验**(S-A §3.6);「谁有权声明形状项 / 根」记入 policy 面、**对装载器可见**;**不启用 `pub` 强制**(选项 (b) 不实施)。⇒ 库外伪造 = **装载期拒绝**(不再是运行期靠约定)。 -一句话:**「不可信数据不能到达语法位」之所以是非法边,不是因为我们追踪了它,而是因为语法位的类型里没有一条从 `string` 出发的边**——唯一存在的边(构造器)由库把守,库的边要么带常量档,要么是一处显式、可审计的净化节点。 +结论:**「不可信数据不能到达语法位」之所以是非法边,其原因不在于追踪,而在于语法位的类型里没有一条从 `string` 出发的边**——唯一存在的边(构造器)由库把守,库的边要么带常量档,要么是一处显式、可审计的净化节点。 ### §1.4 与 `string` 的关系(零标注) @@ -223,7 +223,7 @@ pos syntax_raw(sh) popen:0 ## §3 净化(sanitize)与 declassify 的语义 -### §3.1 净化 = 位置化,不是「清洗」 +### §3.1 净化的语义:位置化(非「清洗」) 库的净化构造器**不做**「从字符串里删掉危险子串」的语义,而是做**位置化**:把不可信值放进下游解释器**当数据消费**的位置,并把这个事实写进**返回类型项**。 @@ -241,7 +241,7 @@ pos syntax_raw(sh) popen:0 2. **可审计**:节点进 S-A §5.2 的**三面可见**(诊断面 / 义务清单面 / 产物面)+ `core explain` 决策通道(S-D);「这个程序的不可信数据从哪进、经哪放行、到哪止步」可被一条命令答出。净化节点在清单中的记录字段 = S-A §5.2b 的义务项(轴 / 源 / 汇 / 落档 / 状态 / 图→源码映射)。 3. **产生义务而不是免单**:`declassify` 声明的是**库的后置条件**,义务是「证明该后置条件成立」——落 proof-required(VC 由验证切片消费;库体本身可作 VC 目标)。**绝不**因为「它是库给的」而当通过(原则 3;「库自己写错 sanitize」是 §7-② 的不可消残留——本族能做的是把它变成一笔**显式记在账上的债**,不是消灭它)。 -### §3.3 不允许隐式 declassify(if-校验旁路) +### §3.3 隐式 declassify 的禁止(if-校验旁路) **控制流上的校验不构成净化**: @@ -298,20 +298,20 @@ if is_valid(s) { sh_run_text(sh_text(s)) } // s 仍是 string,不是 Sh` 与 `φ` 的机制同族(形状项),边界 = 谁声明:路径**结构**的语法正确性归本族形态,**根约束**归 S-B4。重叠点登记为 S-B4 的输入(§8-开放问题 7)。 -### 4.9 与载体(.ccr v7)的关系 +### 4.9 与载体(`.ccr` v7)的关系 形状项与位置声明**随库分发**才有意义(否则跨模块/预编译库丢失策略)。v7 段表已预留 `7+`(驱逐标注/证书段)——**是否新增 `POLICY` 段**、策略随 `.ccr` 走还是随源文件走,是实施批议题(§8-开放问题 5);本族只要求「策略是数据、可随库携带、可被审计」。 @@ -321,7 +321,7 @@ if is_valid(s) { sh_run_text(sh_text(s)) } // s 仍是 string,不是 Sh` 与 `φ` 共用形状项机制,需要一条统一的分工判据(归 S-B4 输入)。 8. **未包装 API 的规模问题**:C 库/AOT/动态链接场景下裸位置数量大,策略维护成本高;是否允许(在审计档下)自动从符号/类型推断候选裸位置并生成清单供人工裁决——这仍属「策略数据生成」,不违反原则 2,但需要论证不产生「自动特判」。 9. **S-A 对齐余项**:本文已按 S-A **收敛批 v2 → v3** 对齐(状态行 + §1.2/§2.1/§3.2/§4.3/§4.6/§5/§6.3 锚点;D1(a)/D2(a)/D5(a)/D6(a)/D11 已随动;**v3 = §5 的 ④ 按 A 线 N1 限定为「已声明域内声明不完整 ⇒ unknown」,与 §0.2 裁决 9「无声明 = 无义务」并存不冲突;编号对照表见路线图 §4**)。**仍待定(归实施批 / S-A 统一分配)**:`Trusted` 判定入口名、policy 装载器实现面(S-A §3.6 已定语义)、义务清单**格式**(归 S-D 线,D29)、错误码段分配(本文 §6.1 建议的 `EC_SF_*` 段号待 S-A 统一)。 diff --git a/docs/superpowers/specs/2026-09-11-policy-resource-confinement-design.md b/docs/superpowers/specs/2026-09-11-policy-resource-confinement-design.md index c9904082..031b8a40 100644 --- a/docs/superpowers/specs/2026-09-11-policy-resource-confinement-design.md +++ b/docs/superpowers/specs/2026-09-11-policy-resource-confinement-design.md @@ -22,7 +22,7 @@ > 把目标资源从"字符串可达"改为"**无法构造目标 capability**"——路径值携带 provenance/capability,派生只能落在 capability 定义的 namespace 内。 -判据形态:不是"我们拒绝了 `..`",而是"**`..` 没有对应的构造**"——攻击面从"检查是否遗漏"变成"类型/图上是否存在这条边"。 +判据形态:不是"编译器拒绝了 `..`",而是"**`..` 没有对应的构造**"——攻击面从"检查是否遗漏"变成"类型/图上是否存在这条边"。 ### 0.2 本族覆盖 / 不覆盖 @@ -64,7 +64,7 @@ Path // Root = 根身份符号(不透明、用户不可伪造) | `Path → string` | **仅诊断渲染**(`display()` 类,单向);渲染结果拿去重建 = 重新走 `child`,不恢复 capability | | 合法性判定 | 在**命名空间的名字集合**上做成员性判定,**不做字符串重写/规范化/过滤**(L1)。"名字不合法" ≠ "字符串被清洗成合法" | -**L1 的边界说明(区分设计与待论证)**:本族与"输入校验库"的差别不在实现而在**判定对象**——校验库判"这个字符串危险吗"(可被绕过、需枚举攻击面);本族判"这个名字在命名空间的名字集合里吗"(定义即判据,无枚举)。因此本族**不承诺**任何字符串层面的安全性,只承诺构造层面无非法 capability。 +**L1 的边界说明(区分设计与待论证)**:本族与"输入校验库"的差别不在实现而在**判定对象**——校验库判"这个字符串是否危险"(可被绕过、需枚举攻击面);本族判"这个名字是否在命名空间的名字集合里"(定义即判据,无枚举)。因此本族**不承诺**任何字符串层面的安全性,只承诺构造层面无非法 capability。 ### 1.3 与 provenance / asp 的复用面(同构表) @@ -80,7 +80,7 @@ Path // Root = 根身份符号(不透明、用户不可伪造) | 判定域 = 条目标识 + 偏移,**与字节地址表示无关** | 判定域 = 根身份 + 组件序列,**与路径字符串表示无关** | **复用声明(不是类比,是同一判定形状)**: -0. **唯一 owner(2026-09-11 裁决 D22)**:图上「沿 def 链倒推」的判定**只在 S-B2 §2.1 步① 实现一次**(输入 = provenance / RegionCheck / ProvenanceVerify 的既有结果,输出 = `Cap` + 派生链见证,`g_*` 只读)。**本族只供给派生链证据**(§3 接口约定 ②),**不另写分析、不重复判定**——其 Q4(派生链合法性落点)据此关闭。 +0. **唯一 owner(2026-09-11 裁决 D22)**:图上「沿 def 链倒推」的判定**只在 S-B2 §2.1 步① 实现一次**(输入 = provenance / RegionCheck / ProvenanceVerify 的既有结果,输出 = `Cap` + 派生链见证,`g_*` 只读)。**本族只供给派生链证据**(§3 接口约定 ②),**不另写分析、不重复判定**——其 Q4(派生链合法性落点)由该裁决关闭。 1. 两者都是**沿 def 链倒推的图稀疏分析**,都不新增 pass——本族判定 = R2 引擎的类型项判定(身份判等,定案 1/4 的图验证层级)+ 图上派生链判定。**共同前提(D12)**:仓库的边 / region 必须**覆盖全部语义依赖**——**覆盖率报告无缺口**前,本族的派生链判定与 S-B3 S1 一样**不启动**(独立侦查项,S-B3 §6.1 前置 3)。 2. 两者都把"外部/未验证入口"收敛到**唯一显式信任点**(`unsafe` / 根声明),且进信任点后重获追踪权(`alloc_at` 先例:"声明是唯一信任点,之后编译器重新获得追踪权")。 3. **能力三件套的边界成分**(lattice §六表:边界 → ProvenanceVerify 已覆盖,对应物 = 域约束)在本族 = 命名空间边界;两族的"边界"都**不是**字节长度("排除:基址/长度/字节 R/W/X——经典映射实例")。 @@ -102,7 +102,7 @@ handle(身份绑定载体)出现在本族值的什么位置,只有两种 ## 2. namespace 判定 -### 2.1 命名空间 = 根 + 名字集合 + 派生运算 +### 2.1 命名空间:根 + 名字集合 + 派生运算 - **语义层固定的是判定形状**:一个根定义了一个**名字集合** `N(R)` 与一个**派生运算** `child : (R, name) ⇀ R'`(部分函数——不合法即无定义)。 - **具体命名空间算法是映射参数**(结构同 lattice §4.6 无格承诺):POSIX 目录树、对象存储前缀、URL 路径、配置键空间各自实例化自己的 `N` 与 `child`;语义层不固定哪一个,也不按范式枚举。 @@ -200,7 +200,7 @@ child(self: Path, name: string) -> Path // 失败语义见下 **边界**:本族**不实现** handle 化——切片 v0 为纯值级(§5),故 v0 的安全 claim **只覆盖 LV-1**(§2.5 判据在此重申)。两族的合并 claim(LV-1 ∧ LV-2)需要 v0 + handle 化映射同时到位。 -**S-B5 的状态(2026-09-11 收敛批 v3 按 A 线 N4 更新)**:S-B5 = **收敛批 v2/v3,已与本 spec 对齐**(原「并行起草中 / 未定稿」表述**作废**)——其 §3.2 已回接本节 §1.4 / §3 / Q7,并**给出 handle 类型表示裁定 = 并列类型**(本节 Q7 据此关闭)。本 spec 只固定上述接力点与共享不变量;若两族后续形态冲突,以**两族共同复核**为准。 +**S-B5 的状态(2026-09-11 收敛批 v3 按 A 线 N4 更新)**:S-B5 = **收敛批 v2/v3,已与本 spec 对齐**(原「并行起草中 / 未定稿」表述**作废**)——其 §3.2 已回接本节 §1.4 / §3 / Q7,并**给出 handle 类型表示裁定 = 并列类型**(本节 Q7 由该裁定关闭)。本 spec 只固定上述接力点与共享不变量;若两族后续形态冲突,以**两族共同复核**为准。 --- diff --git a/docs/superpowers/specs/2026-09-11-policy-state-version-toctou-design.md b/docs/superpowers/specs/2026-09-11-policy-state-version-toctou-design.md index 7e1ff0c0..c8dd6685 100644 --- a/docs/superpowers/specs/2026-09-11-policy-state-version-toctou-design.md +++ b/docs/superpowers/specs/2026-09-11-policy-state-version-toctou-design.md @@ -65,7 +65,7 @@ - **修链归属(2026-09-11 裁决 D7(c) + A 线评审 I4 收敛;**已闭合**)**:修链(`df_connect_state` 覆盖 `IR_CALL_EXTERN` + 更正 `fi_ispure` 写入点)= 原「独立里程碑单独立项」,**已作为 P0 插队批落地**(`762bd429`+`c9099d73`+`c7ca4251`;落地登记 = TODO #2026-09-11-10)。**门禁约定不变**:本族切片**不以其为前置**(修链落地前后同此);S-E §4.1 的「判给 S-B5 切片」表述仍**不成立**(两处约定已对齐)。判据 = 本批实测(全量回归 + `.ccr` 边集语义断言 `test_ccr_v7` 24→27 + ELF canary 逐字节 + 自举稳定)。 - **清单唯一约束(硬性)**:**外部效应 / 变更源清单只允许存在一份**(挂 S-A §1.7 的 policy 面);本族切片自带的最小面 = **对该清单的消费**(`mutates(κ)` 注解 + 未标注 extern = 变更一切 κ,§1.2 ③),**不另写一份**(否则必然漂移)。负控(§5.4)建立在该面 + 该清单之上。 - **回填记录(2026-09-11,Task 4 Step 4 = 原「待纯度批落地后回填」marker 的落点)**:上两条的「纯度标注乐观 / 外部效应无保证的序通道」**已按实测重述**为修复后状态;链覆盖范围 = 函数内 store 家族 + `purity_op_effect` 全清单 + 一切不可解析/未证纯的可解析调用(跨函数不连)。实测证据 = TODO #2026-09-11-10(回归 38/38 rc=0 · 语料级旧前端 vs 当前 ELF 逐字节 20/20 同 · canary `95084e7b…d475` IDENTICAL · 自举稳定 · `.ccr` 差异仅 chain(kind=1)边)。 -- 今日语言面事实:`syscall3/4` 是特判内置(`checker.cr:2021` 注释 / `:2024-2025` 返回点;`instr.cr:681` 内联发射),stdlib `read_file(path)` / `write_file(path, …)`(`io.cr:27/72`)是**按 pathname 重查**的形态(P3,§2.4)。 +- 语言面现状事实:`syscall3/4` 是特判内置(`checker.cr:2021` 注释 / `:2024-2025` 返回点;`instr.cr:681` 内联发射),stdlib `read_file(path)` / `write_file(path, …)`(`io.cr:27/72`)是**按 pathname 重查**的形态(P3,§2.4)。 ### 1.3 图版本 vs 世界版本(判据的诚实核心) @@ -87,7 +87,7 @@ **记号**: - check 节点 `C`:验证谓词 `P` 于身份 `κ` 的版本 `v(C)`。 - use 节点 `U`:作用于身份 `κ` 的版本 `v(U)`。 -- state 可达 `→*`:EDG `kind=1` 的传递闭包。图语义 = 约束集 ⇒ 偏序可达(v7 载体设计 §1.3);今日生产形态 = 链(`g_last_state_node`)⇒ 判定退化为区间包含(实施快路径)。 +- state 可达 `→*`:EDG `kind=1` 的传递闭包。图语义 = 约束集 ⇒ 偏序可达(v7 载体设计 §1.3);现行生产形态 = 链(`g_last_state_node`)⇒ 判定退化为区间包含(实施快路径)。 - mutator:图内变更(③ a)或带 `mutates(κ)` 的边界节点;未标注 extern = 变更一切 κ。 **TOCTOU 判据**:`U` 合法 ⟺ ∃C 使 C1 ∧ C2 ∧ C3: @@ -104,7 +104,7 @@ - **交集非空**(同一 `go` 起的节点既是图节点又是并发主体)⇒ **先本族的保守面**,**S-E 不重复报**(只出一条诊断)。 - 对应负控 = **交叉负控**(§5.4 新增:同一场景断言**恰一条**诊断)。S-E 侧的同款一行归其自身文本(B 线)。 -### 2.2 版本分离的检测(本族要检什么) +### 2.2 版本分离的检测(本族的检出对象) - **重观察 = 新版本**:`use` 若重新读同一 pathname,则产生新边界节点 → 新条目 → 新 `def_nod` ⇒ `v(U) ≠ v(C)`,C1 不成立。**这就是 `check(x); use(x)` 的图形态:两次独立观察 = 两个分离的状态版本**(论题的直接兑现)。 - 版本分离**本身不是错误**(合法:写后重读);**没有新 check 的 use 才是**——即分离出的版本上不存在同版本的 check。 @@ -150,7 +150,7 @@ op(vh, …) -> … // 操作只对 Verified 定 ### 3.2 与 S-B4 围栏的衔接(回接其 §1.4 / §3 / Q7) - **接力点(S-B4 §3 原文立场)**:S-B4 保证**名字 → capability 的构造**单步且不可回退(无"先检查字符串、再用字符串");S-B5 保证 **capability → 资源身份的绑定**是原子的(check/use 同一版本)。分工 = 命名空间判定(S-B4)∥ 时间判定(本族);**两族互不重定义**:S-B4 不定义版本,本族不定义命名空间。 -- **S-B4 交给下游的三样东西**(① 根身份 ② 派生链 ③ 可选的 handle 槽)中,本族消费 ③;① ② 归 S-B2 的 `Can` 判定。**唯一 owner(2026-09-11 裁决 D22)**:①② 的图面分析(沿 def 链倒推 / 根封闭 / 派生链合法性)**只在 S-B2 §2.1 步① 实现一次**(输出 = `Cap` + 派生链见证,`g_*` 只读)——本族**消费其输出**(κ 的可靠性上限 = 映射层 handle 化能力,见下),**不另写分析**。S-B4 只供给派生链证据(其 Q4 据此关闭)。 +- **S-B4 交给下游的三样东西**(① 根身份 ② 派生链 ③ 可选的 handle 槽)中,本族消费 ③;① ② 归 S-B2 的 `Can` 判定。**唯一 owner(2026-09-11 裁决 D22)**:①② 的图面分析(沿 def 链倒推 / 根封闭 / 派生链合法性)**只在 S-B2 §2.1 步① 实现一次**(输出 = `Cap` + 派生链见证,`g_*` 只读)——本族**消费其输出**(κ 的可靠性上限 = 映射层 handle 化能力,见下),**不另写分析**。S-B4 只供给派生链证据(其 Q4 由该裁决关闭)。 - **LV-1 / LV-2 分工(S-B4 L5 / §2.5)**:S-B4 语义层只判 LV-1(构造合法性);**LV-2(symlink / mount / hardlink = 解析身份)值级不可判,显式登记为映射层义务**。本族随之划界:**κ 的可靠性上限 = 映射层 handle 化的能力**——无 handle 化时 ④ reject(**高安全档**;S-B4 §4 同款——该行的 ④ 只在「策略禁止运行时检查 / 映射层无 handle 化」时出现,不是默认档行为),有 handle 化时 LV-2 由映射层强制(本族 C3 的身份部分据此才成立)。 - **handle 类型表示的裁定(S-B4 §1.4 把裁定权交给「S-B5 + 映射层」)——本族裁定(2026-09-11,D30 采纳本节建议):并列类型**。理由:本族需要 handle 携带版本见证 `(κ, v)`(§3.1),而"内嵌槽"方案使 `Path` 值类型随绑定状态变化(状态依赖类型,与路线图 §1.2 原则 1「属性不升格 primitive」张力更大),且要求值级也带版本(S-B4 已裁定**纯值路径无版本变化**)。故取 `Handle` 独立 + `bind(p: Path) -> Handle`:**转换点 = 唯一的 check/use 边界 = 本族 C1 的判定对象**(与 S-B4 §3 表述一致)。映射层确认项 = `bind` 的原子性由谁提供(fd / dirfd / `openat` 类;S-B4 §3「已 handle 化」行)。**S-B4 §1.4 的两种形态已由本裁定收敛为「并列类型」**(其 Q7 据此关闭)。 - **两侧的 TOCTOU 分工(S-B4 §3 表格)**:已 handle 化 ⇒ 构造即绑定身份、**无重查 ⇒ 无 TOCTOU**(S-B4 产出即本族**版本载体**);未 handle 化(纯值路径)⇒ 值级无版本变化、无 TOCTOU,**"值 → 资源身份"的转换点才产生 TOCTOU 面 = 本族判定对象**(= 本族 P3 重查模式的另一投影)。 diff --git a/docs/superpowers/specs/2026-09-11-semantic-safety-obligations-design.md b/docs/superpowers/specs/2026-09-11-semantic-safety-obligations-design.md index ecf86b19..ac6dff95 100644 --- a/docs/superpowers/specs/2026-09-11-semantic-safety-obligations-design.md +++ b/docs/superpowers/specs/2026-09-11-semantic-safety-obligations-design.md @@ -2,7 +2,7 @@ 日期:2026-09-11 状态:**设计稿(2026-09-11 收敛批 v3)**(**v3 = B 线 N2 对照表挂路线图 §4 + A 线 N1-N5 与 B 线 N2/N4/N8 的接口面收尾**:§3.1 放行条目补**第四族(S-B4,`kind=mint`)**与 `declassify 通道` 栏的投影关系(A 线 N2/⚠️2)· §1.3 首消费方改为「暂无对侧确认(登记)」+ S-B5 的 `state-version × integrity` 回引(A 线 N3)· §2.2 附补族级例外限定(A 线 N5)· §3.4 段位表述精确化(B 线 N8)· §1.7 清单唯一约定(B 线 N7)· 纯度事实留回填指引)。**正文面**:轴(§1,含共享契约 §1.4 追加裁决的 `determinism` 轴族)/ 档(§2)/ policy 接口(§3)/ enforcement 通道(§4)/ 诊断面(§5)五面定形;§9 五问已裁 4、余 1 待论证;**A 簇 ★ 裁决(D1-D3/D5-D7/D9-D11)与设计者可裁项已落实,索引见 §0.4**。实施计划后立(writing-plans),实施排在 **R2 收线之后**(共享契约 §3.3)。 -性质:语义安全线(S 族)**地基 spec**——其余 8 份(S-B×5 / S-C / S-D / S-E)的机制与术语基准。**本 spec 是设计文档,不写代码、不改产物。** +性质:语义安全线(S 族)**地基 spec**(specification,设计规约)——其余 8 份(S-B×5 / S-C / S-D / S-E)的机制与术语基准。**本 spec 是设计文档,不写代码、不改产物。** 共享契约:`docs/superpowers/specs/2026-09-11-semantic-safety-roadmap.md` §1.1 术语 / §1.2 原则 / §1.3 三类不可消——**逐字遵守,不重定义**。 关联: @@ -22,7 +22,7 @@ ## 0. 裁决与范围 -### 0.1 本 spec 定什么(六项) +### 0.1 本 spec 的定项(六项) | # | 定项 | 落点 | |---|---|---| @@ -33,10 +33,10 @@ | 5 | 未证明义务的**三面可见**(诊断 / 清单 / 产物)+「不静默」的可测判据 | §5 | | 6 | **最小可实施切片 A**(trust 轴 + 一条策略 + 正/负控 + 零产物变化判据)+ **候选切片 B**(`determinism` 族隐式竞争 reject——与 A 并列,二选一或两者) | §6(+ §6.5) | -### 0.2 本 spec 不定什么(划界,交接对象) +### 0.2 本 spec 的不定项(划界,交接对象) - **各族的流纪律语义**(注入 / 授权 / 信息流 / 围栏 / 状态版本)→ S-B1…S-B5 各自定;本 spec 只给机制、档位与接口。 -- **判定算法本体**(DNF 规范化 / memo / 预算 / 反例)→ R2 P0 已定已实施;本 spec 只**消费** API,不改引擎。 +- **判定算法本体**(DNF(disjunctive normal form,析取范式)规范化 / memo / 预算 / 反例)→ R2 P0 已定已实施;本 spec 只**消费** API,不改引擎。 - **隐式流完整判定**(branch/timing/cache 面)→ S-B3 的边界;本 spec 只在 §2.3 登记「不可强制」类并说明其落档。 - **where / requires / ensures 的语法实现** → TODO「.cr 规约语法实现」(:440)线;本 spec 的 §2.3 映射停在语义层(现状:`where` 三档**仅设计态**,parser 无 `where` 终结符——见 §2.3 注)。 - **性能无实现承诺 / 成本模型** → S-C;**可解释与语义增量** → S-D。 @@ -156,13 +156,13 @@ | 载面 | **条目 / IR 变量版本**(图上已存在)+ 产生节点(产生节点-版本的「版本对」) | | 来源 | **自动推导**(版本编号由图构造生成——零标注) | | 既有机制接口 | **state edges**(顺序约束 = 版本序的落地形态,`dataflow.cr:129,157`)+ 条目与配方(条款 1)+ 缓存语义(条款 5) | -| 首消费方 | S-B5(check/use 分离版本 = 图上两版本;TOCTOU 判定 = 版本等价判定) | +| 首消费方 | S-B5(check/use 分离版本 = 图上两版本;TOCTOU(time-of-check to time-of-use,检查-使用时间差)判定 = 版本等价判定) | ### 1.7 `effect`(副作用) | 字段 | 内容 | |---|---| -| 语义定义 | 节点/值是否产生副作用(IO / FFI / unsafe / volatile / 写内存) | +| 语义定义 | 节点/值是否产生副作用(IO / FFI(foreign function interface,外部函数接口)/ unsafe / volatile / 写内存) | | 载面 | **节点标注** + **state edges**(副作用链——顺序表达**已有**;缺的是副作用**类别**的标注面) | | 来源 | **自动推导**(ir_gen 判定:写内存 / 不纯调用 / unsafe → state edge 链;`docs/lazy.md` 判定表「有副作用 → 永远 eager」已有)+ 领域库声明(FFI 效应集) | | 既有机制接口 | state edges + 惰性/记忆化判定(TODO auto-memo「图显式纯度判定」)+ `unsafe` 边界 | @@ -182,7 +182,7 @@ | `effect` × `authority` | effectful op 须产出证明(授权面耦合) | S-B2 | | `lifetime` × `effect` | 副作用链的存活范围 = region 边界(arena reset 面) | S-B4 | -**本节的整体判断(诚实评估)**:七轴中 `lifetime`/`state-version`/`effect` 的**载体已在图上跑**(region / 条目版本 / state edges),`trust` 的传播与 provenance 同边,`authority` 载面是治理层既有形态。**S-A 的工作 = 把「标注维度」显式化 + 给判定与落档流程,不新建图机制**——这是本 spec 可小步落地(§6)的结构性理由。§1.9 的 `determinism` 族同理(`D_effect`/`D_memory` 直接复用 state edges / region)。 +**本节的整体判断(诚实评估)**:七轴中 `lifetime`/`state-version`/`effect` 的**载体已在图上运行**(region / 条目版本 / state edges),`trust` 的传播与 provenance 同边,`authority` 载面是治理层既有形态。**S-A 的工作 = 把「标注维度」显式化 + 给判定与落档流程,不新建图机制**——这是本 spec 可小步落地(§6)的结构性理由。§1.9 的 `determinism` 族同理(`D_effect`/`D_memory` 直接复用 state edges / region)。 ### 1.9 `determinism` 族(`D_*`,七轴——共享契约 §1.4 追加裁决,2026-09-11) @@ -195,9 +195,9 @@ | `D_value` | 值/结果确定性 | 节点(纯值流) | 自动推导(§1.4 现状「强」) | 值流边 + 引擎判定(无副作用边即纯) | | `D_effect` | 副作用顺序确定性 | **节点 + state edges**(副作用链) | 自动推导(§1.4「有基础(state edges 显式)」) | state edges(`dataflow.cr:129,157`);与 `effect` 轴(§1.7)**同载体、不同问题**(`effect` 问「有无副作用」,`D_effect` 问「顺序是否被固定」) | | `D_memory` | 内存行为/生命周期确定性 | region + 条目 | 自动推导(§1.4「强(region 锚定 + bump/reset)」) | region / arena / 共存关系(v4 §11.5);与 `lifetime` 轴(§1.5)同载体 | -| `D_timing` | 时间 / WCET | 节点/region 上界标注 | **三值**(§1.4 硬性) | `PROVED`(机器无关上界:分配次数/字节、在飞任务数、通信量——可从 region/图证明;接 bounds-inference)|`MODELED`(机器相关 = **成本模型估计,明确标注「模型非证明」**,复用 S-C 成本模型)|`UNKNOWN`。**禁止把 MODELED 呈现为 WCET 证明**(→ §5.2a 措辞/码可区分) | +| `D_timing` | 时间 / WCET(worst-case execution time,最坏执行时间) | 节点/region 上界标注 | **三值**(§1.4 硬性) | `PROVED`(机器无关上界:分配次数/字节、在飞任务数、通信量——可从 region/图证明;接 bounds-inference)|`MODELED`(机器相关 = **成本模型估计,明确标注「模型非证明」**,复用 S-C 成本模型)|`UNKNOWN`。**禁止把 MODELED 呈现为 WCET 证明**(→ §5.2a 措辞/码可区分) | | `D_resource` | 资源上界确定性 | 节点/region 的静态 bound | 自动推导 + 声明(§1.4「有基础(需静态 bound)」) | bounds-inference(TODO);接 S-C 成本模型 | -| `D_external` | 外部输入依赖确定性 | **边界节点**(无配方条目:MMIO/FFI/输入/测量) | 领域库/部署声明(§1.4「边界节点可归档(图上有边界)」) | 边界公理(memory-model 条款 4)+ 图内不可重算条款(v4 §5.3);与 `trust` 轴(§1.1)**同边界点、不同问题** | +| `D_external` | 外部输入依赖确定性 | **边界节点**(无配方条目:MMIO(memory-mapped I/O,内存映射 I/O)/FFI/输入/测量) | 领域库/部署声明(§1.4「边界节点可归档(图上有边界)」) | 边界公理(memory-model 条款 4)+ 图内不可重算条款(v4 §5.3);与 `trust` 轴(§1.1)**同边界点、不同问题** | | `D_mapping` | **跨机器语义确定性**(Core 特有轴) | **语义层性质**(「语义 ≥ 映射」——不是某个图对象的标注) | 自动(结构性质) | 三层映射(图→格→编码)+ v4「证明完毕不下发」;承载 = 映射实例的语义保持定理面。**唯一的非标注型轴**——本 spec 只登记,不建机制 | **执法 = 四档义务(§1.4 表 → §2.2 决策树的实例化)**: @@ -209,7 +209,7 @@ | 语义明文允许(`race` / `select_any`)**且「声明-实现一致性」证明成立** | **① prove + 报告义务**(**不是第五档**) | 显式请求 + 声明与实现一致 ⇒ 义务已被「程序说的是它想说的」处置;报告面登记归 S-D。**证明范围 = 局部**(只覆盖该汇合点本身,**不覆盖观测点**)——该未覆盖面必须在报告面**显式标注**(D10(a))。**证明不成立 ⇒ 落 ③ 登记**(不是 prove)。§1.4 明言「与 §1.1 四档同构」,故**不引入第五档** | | 既未证明也未标注(**隐式竞争**) | **④ reject** | 该族 policy 取值 = `allow_enforce=false` + `require_proof=false` + `strict=true` → §2.2 决策树**固定落到 ④**(**无需改树**——档位是 policy 数据,§3.1)。§1.4「真正的执法点」 | -- **判定侧硬约束(本 spec 给出)**:在 S-E 完成 `select` 重定之前,`select` **不得**被当作「显式顺序源」用于 prove——否则等于把现有语义缺陷(§1.4:现 `select` = 「最早到达的令牌」,把物理调度顺序泄进语义)**固化为证明前提**。迁移路径与兼容窗口归 S-E;**窗口 W1 = 默认 1 个发布周期**(§1.4,D3):窗口内本禁令不解除,窗口后强制标注。 +- **判定侧硬约束(本 spec 给出)**:在 S-E 完成 `select` 重定之前,`select` **不得**被当作「显式顺序源」用于 prove——否则等于把现有语义缺陷(§1.4:现 `select` = 「最早到达的令牌」,把物理调度顺序泄漏进语义)**固化为证明前提**。迁移路径与兼容窗口归 S-E;**窗口 W1 = 默认 1 个发布周期**(§1.4,D3):窗口内本禁令不解除,窗口后强制标注。 - **S-A ↔ S-E 接口需求**(本 spec 只提**需求与供给**,不定义其语义——§0.2 边界): 1. **需求(S-A 消费面)**:S-E 为四形态各给出**图上可判的显式标记**(判定输入)——`merge_deterministic`(汇合无关)/ `merge_ordered`(显式顺序源)/ `race` / `select_any`(显式不确定请求)。S-A 的落档规则(§2.6)**消费两面**:① **标记存在性**(不读其内部语义);② **该标记的「声明-实现一致性」证明结论**(S-E §1.3 / §1.5 第 5 步;2026-09-11 裁决 D10(a))。**`race` / `select_any` 的 ① prove 当且仅当 ② 成立**——② 不成立 ⇒ **落 ③ 登记**(不是 prove)。② 的证明**范围 = 局部**(只覆盖汇合点本身):报告面**必须**标注「该保证**未覆盖观测点**」(不覆盖性由 S-D 的报告面承担)。 2. **需求(解除条件)**:S-E 的 `select` 重定须使「显式顺序源」不再含物理调度泄漏——即本条硬约束的**解除条件**(窗口 W1 见上)。 @@ -293,7 +293,7 @@ | ③ **proof-required** | 零运行期成本;成本 = 用户/领域库的 proof/contract 撰写 + 验证管线时间 | **不可判定且不可强制**(隐式流 / 信任假设 / 规范正确性) | 默认:诊断 + 清单条目(登记,**不是通过**);strict:拒绝 | | ④ **reject** | n/a | 策略档位的后果(非判定结果) | 编译错误(响亮 + 出路建议,§5.4) | -- 预算边界(**诚实项**):引擎有判定预算守卫(R2 P0)。预算耗尽 → unknown → 按本决策树落 ②/③/④,**绝不当通过**;且诊断必须区分「预算耗尽」与「判定为假」(R2 §3.3 同款)。 +- 预算边界(**诚实项**):引擎有判定预算守卫(R2 P0)。预算耗尽 → unknown → 按本决策树落 ②/③/④,**绝不视作通过**;且诊断必须区分「预算耗尽」与「判定为假」(R2 §3.3 同款)。 ### 2.5 判定的可靠性责任(**待论证,登记**) @@ -404,7 +404,7 @@ Shape(sink) :sink 的形状项(policy 数据;语法位 / 值位的区分 ## 4. enforcement 通道(动态档落地) -### 4.1 先例(**现状事实——enforce 档的原型已经在跑**) +### 4.1 先例(**现状事实——enforce 档的原型已运行**) `IR_BOUNDS_CHECK`(`ast.cr:559`,op 30):语义 = `if ρ(s1) ≥ᵤ s2 → ud2`(`ir-op-semantics.md:196`);发射 = `ext_safety.cr:27,33`(**插件 + 钩子**形态,不是语言特判);解释器侧已实现(`interp.cr:289`);ELF 侧编码 = cmp + jb + ud2。失败语义 = **中止而非未定义值(安全优先)**;负索引由无符号比较天然捕获。 @@ -457,7 +457,7 @@ open ──strict 未满足──→ rejected(编译拒绝) open ─────────────────→ **passed 不存在**(禁令:不静默) ``` -**禁令(契约 §1.2 原则 3 的可实施形态)**:证不出 → 必落 ②/③/④ 之一,**绝不静默当通过**。③ 的「登记」状态是 **open**(未处置),**不是** passed——清单中它是待办,不是已通过项。 +**禁令(契约 §1.2 原则 3 的可实施形态)**:证不出 → 必落 ②/③/④ 之一,**绝不静默视作通过**。③ 的「登记」状态是 **open**(未处置),**不是** passed——清单中它是待办,不是已通过项。 ### 5.2 三面可见(缺一不可) @@ -467,7 +467,7 @@ open ─────────────────→ **passed 不存在** | **b) 清单面** | **义务清单**(obligations manifest):轴 / 源 / 汇 / 落档 / 状态 / 图→源码位置映射。是人类与 CI 的门槛通道(strict 档 = CI 断言清单为空)。**§3.1「放行 / 声明条目」的每一条(含豁免形态者)必须在此出现**(D2:放行必须落清单) | 落点实施批定(编译输出过渡态先行;`.ccr` 段随 §3.4 = R2 P4)。**格式归 S-D 线统一(D29)**——各族只写消费点,不写格式 | | **c) 产物面** | 义务清单 = 图数据的投影(语义保鲜兑现,R2 §6.4 同构)——验证工具直接消费,不必重跑前端 | `.csr`/TagNode 图验证线(coreir-schema「图即验证」) | -### 5.3 「不静默」的可测判据(把承诺变成断言) +### 5.3 「不静默」的可测判据(承诺的可断言化) - **负控**:故意留一条未处置义务 → 编译输出**必须**含具名诊断(轴 + 源位置 + 汇位置)+ 清单条目;测试断言二者均存在。 - **strict 负控**:同一条义务在 strict 档 → 编译**必须**拒绝(非零退出 + 错误码)。 @@ -476,7 +476,7 @@ open ─────────────────→ **passed 不存在** ### 5.4 档 ④ 的措辞要求 -拒绝必须给**出路**(否则等于死墙):补 proof/contract / 加 declassify / 显式例外入口(`unsafe` 边界——**放行记入清单**,承 v4「例外入口授权可追踪(信任链)」)。 +拒绝必须给**出路**(否则等于无出路):补 proof/contract / 加 declassify / 显式例外入口(`unsafe` 边界——**放行记入清单**,承 v4「例外入口授权可追踪(信任链)」)。 --- @@ -516,7 +516,7 @@ open ─────────────────→ **passed 不存在** ### 6.5 候选切片 B:`determinism` 族的「隐式竞争 reject」执法面(**与切片 A 并列,二选一或两者**) - **范围(以负控侧为主)**:图上「共享条目被两个并发 region 触碰 + 两 region 间无 state edge 顺序源 + 无显式请求标注」→ **reject**(§2.6 行 4)。**正控侧**(显式 `race` / `select_any` 通过 + 报告条目)**依赖 S-E 四形态语义**——若 S-E 未定稿,切片 B **先只做负控**(隐式竞争必须 reject),正控登记为 S-E 就位后的增量。 -- **为什么小**:判定输入 = **图上已有事实**(region `dataflow.cr:428-432` + state edges `:129,157` + 共享条目 / 共存关系——零新图机制);执法 = 诊断 + 拒绝(无 enforcement 节点、无新 opcode、无新 op)。 +- **规模小的理由**:判定输入 = **图上已有事实**(region `dataflow.cr:428-432` + state edges `:129,157` + 共享条目 / 共存关系——零新图机制);执法 = 诊断 + 拒绝(无 enforcement 节点、无新 opcode、无新 op)。 - **判据**: 1. **负控**:隐式竞争用例 → 编译拒绝;诊断指出**共同条目 + 两个 region 位置**(图→源码映射)。 2. **正控(S-E 就位后)**:显式 `race` / `select_any` → 通过,且报告面条目存在(S-D 接口)。 @@ -549,8 +549,8 @@ open ─────────────────→ **passed 不存在** | # | 契约 §1.3 类别 | 本族(S-A + 属性轴/义务阶梯)的落点 | |---|---|---| | 1 | **错误 specification** | 本族只能证明「**程序忠实实现了 policy**」,**不能**证明 policy 本身正确:policy 漏声明的 sink / 错形状的 source / 错误的 `A_a(v)` 映射 → 义务阶梯**结构上无法覆盖**它。故本族**不承诺**「程序安全」,只承诺「相对 policy 的忠实性 + 义务不静默」。这是第 1 类的**纯落点** | -| 2 | **恶意/失陷外部实体** | `trust` 轴提供**声明与检查**通道(untrusted 标记 + 净化节点),但**不能**证明「被声明为 trusted 的组件真的可信」——供应链 / 编译机 / 密钥 / 硬件后门不可用语言语义证明。本族贡献 = 把信任假设**显式化**(可审计、可追踪、最小权限,承 v4「可追踪信任链」),**不是消除它**。`determinism` 族的 `D_external`/`D_timing` 同落此类:外部世界的时间与环境**不可证明**,只能**归因 + 三值标注**(`PROVED`/`MODELED`/`UNKNOWN`)——不承诺消除物理不确定性,只承诺**不许撒谎**(§1.9) | -| 3 | **需求本身允许危险行为** | shell / browser / kernel / JIT 必须执行外来代码——`system(cmd)` 本身就是需求(§6.1 的 sink 不是 bug)。本族目标 = 证明**隔离边界**(形如「不可信数据不能到达解释器语法位」的流纪律),**不是禁止能力**;`declassify` / `unsafe` = 危险行为的**显式授权点**(登记可追踪) | +| 2 | **恶意/失陷外部实体** | `trust` 轴提供**声明与检查**通道(untrusted 标记 + 净化节点),但**不能**证明「被声明为 trusted 的组件真的可信」——供应链 / 编译机 / 密钥 / 硬件后门不可用语言语义证明。本族贡献 = 把信任假设**显式化**(可审计、可追踪、最小权限,承 v4「可追踪信任链」),**不是消除它**。`determinism` 族的 `D_external`/`D_timing` 同落此类:外部世界的时间与环境**不可证明**,只能**归因 + 三值标注**(`PROVED`/`MODELED`/`UNKNOWN`)——不承诺消除物理不确定性,只承诺**不虚假陈述**(§1.9) | +| 3 | **需求本身允许危险行为** | shell / browser / kernel / JIT(just-in-time 编译)必须执行外来代码——`system(cmd)` 本身就是需求(§6.1 的 sink 不是 bug)。本族目标 = 证明**隔离边界**(形如「不可信数据不能到达解释器语法位」的流纪律),**不是禁止能力**;`declassify` / `unsafe` = 危险行为的**显式授权点**(登记可追踪) | **全局禁令(原文遵守)**:**不承诺**「能自动证明所有程序安全」——判定引擎是**三态 + 预算守卫**的,unknown 是设计内的第一等结果(Rice/halting 边界,契约 §1.2 原则 3)。 @@ -572,11 +572,11 @@ open ─────────────────→ **passed 不存在** | # | 问题 | 影响面 | 裁定(2026-09-11) | |---|---|---|---| -| 1 | **档 ③ 的默认行为**(宽松档):诊断 + 清单**继续编译**,还是默认拒绝、需显式开关降级? | 「不静默」的强度 vs 上手成本 | **已裁(D3(c))**:默认 = **登记 + 继续编译**(③ 是**登记**不是通过);**strict 档拒编**;**CI 门槛从严**。规范形态见 §2.2 附 | -| 2 | **轴标注的语法载体**:走既有插件标签通道(`g_plugin_tags`,零新语法),还是给轴**独立语法**? | 语言面改动面(零关键字 vs 新语法) | **已裁(D5(a))**:**零新语法**——走**插件标签通道**(§3.5);参数级档位约束落 **policy 数据表**;缺口上报而非私自加语法 | -| 3 | **policy 档位粒度**:全局 / 每策略 / 每轴 / 每模块? | 策略表的键设计(§3.1) | **已裁(D15)**:**两级**——全局默认 + **每策略覆盖**(键 = `(ns, policy_name)`);**每轴粒度留扩展位**(不实施) | -| 4 | **义务清单载体**:编译输出先行,还是直接规划 `.ccr` POLICY 段(与 R2 P4 载体批合批)? | 实施批次划分 | **已裁(D4(a))**:**随 R2 P4 同波进 `.ccr` 新段**(政策随产物分发);载体就位前 = 编译输出过渡态(非目标形态) | -| 5 | **轴与横切接口的边界复核**(**本 spec 最大理论风险**):`trust`/`integrity` 是否可被正确表达为「横切形状类型项」(R2 §2.2 同入口)从而**根本不需要轴机制**? | 若成立,S-A 的价值收缩为「流程 + 落档」,标注机制并入 R2 注册表 | 倾向:不成立(§0.3 T1——横切形状是**单值结构判定**,轴是**来源/流向**性质,跨节点路径性质无法由单值形状表达);但**该论证未形式化 = 待论证**,须在切片 1 的语言实践中检验 | +| 1 | **档 ③ 的默认行为**(宽松档):诊断 + 清单**继续编译**与默认拒绝、需显式开关降级两种取法的取舍 | 「不静默」的强度 vs 上手成本 | **已裁(D3(c))**:默认 = **登记 + 继续编译**(③ 是**登记**不是通过);**strict 档拒编**;**CI 门槛从严**。规范形态见 §2.2 附 | +| 2 | **轴标注的语法载体**:走既有插件标签通道(`g_plugin_tags`,零新语法)与给轴**独立语法**两种取法的取舍 | 语言面改动面(零关键字 vs 新语法) | **已裁(D5(a))**:**零新语法**——走**插件标签通道**(§3.5);参数级档位约束落 **policy 数据表**;缺口上报而非私自加语法 | +| 3 | **policy 档位粒度**:全局 / 每策略 / 每轴 / 每模块四种取法的取舍 | 策略表的键设计(§3.1) | **已裁(D15)**:**两级**——全局默认 + **每策略覆盖**(键 = `(ns, policy_name)`);**每轴粒度留扩展位**(不实施) | +| 4 | **义务清单载体**:编译输出先行与直接规划 `.ccr` POLICY 段(与 R2 P4 载体批合批)两种取法的取舍 | 实施批次划分 | **已裁(D4(a))**:**随 R2 P4 同波进 `.ccr` 新段**(政策随产物分发);载体就位前 = 编译输出过渡态(非目标形态) | +| 5 | **轴与横切接口的边界复核**(**本 spec 最大理论风险**):`trust`/`integrity` 是否可被正确表达为「横切形状类型项」(R2 §2.2 同入口)从而**根本不需要轴机制** | 若成立,S-A 的价值收缩为「流程 + 落档」,标注机制并入 R2 注册表 | 倾向:不成立(§0.3 T1——横切形状是**单值结构判定**,轴是**来源/流向**性质,跨节点路径性质无法由单值形状表达);但**该论证未形式化 = 待论证**,须在切片 1 的语言实践中检验 | --- @@ -585,7 +585,7 @@ open ─────────────────→ **passed 不存在** - **共享契约合规逐条**:§1.1 术语(属性轴/义务/四档/policy/declassify/sink·source 模型)逐字引用未重定义;§1.2 五条原则逐条落点(原则 1 → A2/§0.3 T3;原则 2 → §3.2 理由 1;原则 3 → §2.2/§5.1/§5.3;原则 4 → §3.3;原则 5 → §0.3 T4/§4.5);**§1.4(2026-09-11 追加裁决)→ §1.9 承接轴族与义务落档**(含「显式不确定 = prove + 报告义务,**不是第五档**」与 `select` 的判定侧硬约束),报告面(S-D)/汇合语义(S-E)边界逐字引用;§1.3 三类 → §8 逐条引用落点。 - **占位符扫描**:无 TBD/TODO;「待论证」出现于 §0.3 T1、§2.5、§9.2 #5(**刻意保留**——性质 = 需证明或需用户裁决,非缺稿)。 - **内部一致性**:§2.2 决策树 ↔ §2.3 映射表 ↔ §2.4 成本表三表同源(同一落档语义);§5.1 状态机 ↔ §2.4 失败语义 ↔ §5.2 三面同源。 -- **范围检查**:单一实施计划?**否**——本 spec 是机制与判据定形,§6 切片 = 唯一的实施计划对象(一批);S-B×5/S-C/S-D 各自立计划。 +- **范围检查**:单一实施计划 = **否**——本 spec 是机制与判据定形,§6 切片 = 唯一的实施计划对象(一批);S-B×5/S-C/S-D 各自立计划。 - **歧义检查**:「违法」与「④ reject」已分(§2.2 点 1);「unknown」与「假」已分(§2.2 点 2);「登记(open)」与「passed」已分(§5.1 禁令);「轴」与「横切接口」已分(§0.3 T1,残余风险登记 §9.2 #5);**「族」与「轴」已分**(§1.9 定位段——`determinism` 族七轴独立标注/独立落档,禁止合并为单一标注维度)。 - **跨 spec 健全性(§3.3.1)**:S-B1 提出的「`A_a` 否定形式展开 ⇒ 左侧塌 ⊥ ⇒ `⊥ ⊑ 任意 φ` 恒真 ⇒ 静默放行」已落为**规范性约定 C1-C5**(左侧只加约束 / 要求写右侧 / ⊥ 非真 / 负控+正控四用例 / **非退化性:右项非 ⊤ + 正例非 ⊥ + 假·unknown 分因 + 未定义原子取 unknown**),并声明**本 spec 为规范性来源**(S-B1 引用,冲突以本节为准);C3 只用 P0 已有 `ty_inhabited`、C5① 走装载期数据校验,**未新增判定算子**。 - **A 簇收敛记录(2026-09-11)**:本批落实 —— A 线 C1(D1(a):§1.1 对表 + §1.3 注)、A 线 C2(D2(a):§3.1 放行/声明条目 + §3.6 装载校验 + §5.2b 清单)、A 线 C3→**C5**(D11:§3.3.1 + §3.6 + §7-#8)、A 线 I1(D10(a):§1.9 需求 1 + §2.6 行 3)、A 线 I5(§6.1 启动条件 + §6.3 三批)、A 线 M1(门禁改引 R2 §4 行)。D5/D6/D7/D9/D12-D15/D19/D22/D23/D29/D30 的裁定与落点见 §0.4 索引。 diff --git a/docs/superpowers/specs/2026-09-11-semantic-safety-roadmap.md b/docs/superpowers/specs/2026-09-11-semantic-safety-roadmap.md index 3355e21b..bce0be48 100644 --- a/docs/superpowers/specs/2026-09-11-semantic-safety-roadmap.md +++ b/docs/superpowers/specs/2026-09-11-semantic-safety-roadmap.md @@ -1,7 +1,7 @@ # 语义安全路线图与九份设计 spec 的共享契约 日期:2026-09-11 -状态:**路线图定稿(用户裁决:全部起草)+ 收敛批 v3 补 §4 编号对照表(2026-09-11)**——本文件不是设计本身,而是 9 份设计 spec 的**共享契约 + 清单 + 起草/实施节奏 + 编号对照**。 +状态:**路线图定稿(用户裁决:全部起草)+ 收敛批 v3 补 §4 编号对照表(2026-09-11)**——本文件不是设计本身,而是 9 份设计 spec(specification,设计规约)的**共享契约 + 清单 + 起草/实施节奏 + 编号对照**。 性质:战略层路线文档(用户与外部 AI 讨论收敛后的方向确认)+ 后续各 spec 的术语与边界基准。 关联: diff --git a/docs/superpowers/specs/2026-09-16-agg-read-type-batch-report.md b/docs/superpowers/specs/2026-09-16-agg-read-type-batch-report.md index 95372b40..30add4e8 100644 --- a/docs/superpowers/specs/2026-09-16-agg-read-type-batch-report.md +++ b/docs/superpowers/specs/2026-09-16-agg-read-type-batch-report.md @@ -1,7 +1,7 @@ # 聚合读丢型(TODO #2026-09-16-16)—— 批报告(#78 批 2 · 2026-09-16) **批名**:**聚合读丢型** · **批次位置**:用户排序的**第 2 批**(维护者 2026-09-16 派单) -**起点**:`develop = 99ae6bdd`(T1 时点)→ 收官 = `develop 66eb9589`(T3 合入后) +**起点**:`develop = 99ae6bdd`(T1 时点)· **收官**:`develop 66eb9589`(T3 合入后) **性质**:只读侦查 → 计划 → 取裁 → **实施** → 判据/突变 → 收官(全程**先裁后码**、**三态纪律**、**路径限定小步提交**) **输入**:`TODO.md` #78 · `docs/superpowers/specs/2026-09-16-apx-conversion-audit.md`(§1 ③b/④b/⑤/⑥b/⑧ + §2 表 B) **计划**:`docs/superpowers/plans/2026-09-16-agg-read-type.md`(§11 T1 记录 · §12 T2 记录 · §13 T3 记录) @@ -10,8 +10,8 @@ ## 0. 批终态一行结论 -**修好**:聚合读结果槽**硬定 `TI_INT`** ⇒ 「按 IR 值型触发」的下游在经聚合读入的值上**连锁失明**这一**总闸级**根因—— -读点定型改取**声明面形式**(dex 声明 ⇒ `TI_DEX_S`;**零 alloc 节点判**),并 **`CIR_CACHE_VER` 17→18** 换代。 +**修好**:聚合读结果槽**硬定 `TI_INT`** ⇒ 「按 IR 值型触发」的下游在经聚合读入的值上**连锁失明**,此为**总闸级**根因。 +修法 = 读点定型改取**声明面形式**(dex 声明 ⇒ `TI_DEX_S`;**零 alloc 节点判**),并 **`CIR_CACHE_VER` 17→18** 换代。 判据:**腿 A 4/5 转绿(R4 按裁-AGG-3 登记 `[GAP]`)· 腿 B 四条界面见证全绿 · 腿 C 断言绿** · **canary 5/5 IDENTICAL** · 74 档/29 探针 rc 全同 · **五 CI job rc=0** · 自举链 `corec2≡corec3` · **腿 D① 突变通过(apx hack 冗余确认)**。 @@ -44,7 +44,7 @@ 接线 3 读点:字段读(`fi` 解出后 `irv_set_type`)· 元素读 · match 载荷绑定。**非 dex 形态恒 `TI_INT`** ⇒ 非 dex 程序**逐字节不变**。 -**为何不直接取完整类型**:`res_type_node` 对命名/聚合/指针类型会 `alloc_type`(GC12′)⇒ 只用 **dex 轴二值**判定; +**不直接取完整类型的原因**:`res_type_node` 对命名/聚合/指针类型会 `alloc_type`(GC12′)⇒ 只用 **dex 轴二值**判定; 且 `TI_DEX_S` 是**预置常量**(非新分配的类型行)。 ## 3. 判据(全绿) @@ -64,20 +64,20 @@ (读槽被当 int **二次缩放**)⇒ 修后该 `_dsc/_dxt` 对**消失**(腿 B 的 B1/B2 即此见证);R5 改前 `load_field → call_extern` **中间零转换** ⇒ 修后出现转换(B3/B4)。 -## 4. 腿 D① 突变证据(**关掉 apx hack** ⇒ 通用机制独立成立) +## 4. 腿 D① 突变证据(**关闭 apx hack** ⇒ 通用机制独立成立) 把 `ir_gen.cr:1342-1343`(apx 批的**比较/运算点声明面 hack**)注释化 → 重建 → 跑: **apx 批套件 23 例全绿 + 本批 6 例 + 腿 B 全绿** ⇒ 声明面机制**完全接管** hack 的覆盖面 ⇒ **hack 冗余从推测变实测**。 (退役判据 = 「连绿两批」第一步;随后恢复源码+重建+复验全绿。) -## 5. 二进制同一性论证(**什么时候必须重跑**) +## 5. 二进制同一性论证(**必须重跑的条件**) T5 的改动是 **docs/TODO-only**,但「文档改动」不足以说明判据仍有效——**实测**:终态重建的 `build/corec` 与判据二进制 **逐字节相同**(sha256 `64c8a7d6…`)⇒ 已跑出的 canary / parity / probes 结论**对终态继续成立**。 > **约定**:判据结果的有效性绑定**二进制内容**而非**提交号**。凡「源码→二进制」映射未变(注释/文档/测试改动、 > 或重建后 `cmp` 相同),判据不必重跑;一旦重建产物**不同**,则**必须**重跑受其影响的面。 -> 这条把「什么时候必须重跑」从习惯变成可判定。 +> 本口径把「必须重跑的条件」从习惯判定变为可判定项。 ## 6. 方法学 · **镜像教训**(维护者指定必写) @@ -90,20 +90,20 @@ T5 的改动是 **docs/TODO-only**,但「文档改动」不足以说明判据 ## 7. 方法学 · **GC12 的自我修正顺序**(维护者指定必写) -侦查时发现:`ir_gen.cr:2455` **今天已有**非 optrep 门控的 `res_type_node`(带注解 LET),且 `res_type_node` 对 +侦查时发现:`ir_gen.cr:2455` **当前已有**非 optrep 门控的 `res_type_node`(带注解 LET),且 `res_type_node` 对 **基类型节点**走 `ty_code_to_ti`(`iface_registry.cr:274`)是**纯查表零 alloc**,只有命名/聚合/指针类型才 `alloc`。 ⇒ 把 GC12 从「不得新增 `alloc_type` 站点」**收紧为**「**不得新增可能 alloc 的类型站点**」(更准), **然后仍然不用它**(本批一律走节点判 + 纯表读)。 > **顺序本身就是方法**:**先把规则改准,再决定用不用**——若先按粗约定办事(「res_type_node 一律禁止」), -> 会误伤正确的路径;若先松后紧(「反正基类型不 alloc 就随便用」),则会漏掉聚合/命名类型的 alloc 面。 +> 会误伤正确的路径;若先松后紧(「基类型不 alloc,可任意使用」),则会漏掉聚合/命名类型的 alloc 面。 -## 8. 陷阱落仓(维护者要求:**不能只活在报告里**) +## 8. 陷阱落仓(维护者要求:**须落仓,不得仅存于报告**) `tools/baseline/REBUILD.md` 新增 **`### 命令层陷阱(假红)`**(与既有「适用范围限制 / 已知限制」同区): -- **`noclobber`**:重定向到**已存在**的日志文件 ⇒ 该重定向失败、**命令根本没跑**,`tail`/`grep` 读到的是**上一轮**旧日志 - (本批 T1 首轮 8/8「失败」全是这样来的;**同一坑第二次踩到**——首次在 #93 批的 CI job 轮询)。 +- **`noclobber`**:重定向到**已存在**的日志文件 ⇒ 该重定向失败、**命令实际未运行**,`tail`/`grep` 读到的是**上一轮**旧日志 + (本批 T1 首轮 8/8「失败」均由该原因产生;**同一陷阱为第二次命中**——首次在 #93 批的 CI job 轮询)。 - **`corec build` 必须在仓库根跑**:在 `/tmp` 下 ⇒ `error: cannot locate src/runtime/rt.cr`(与既有「cwd 决定 import 解析」同族)。 **判据**:`grep -rn noclobber tools/` **命中该文件**(仓级可搜)。 @@ -118,8 +118,8 @@ T5 的改动是 **docs/TODO-only**,但「文档改动」不足以说明判据 | `src/compiler/dyn_arr.cr:112` · `src/compiler/ccr_io.cr:137` | 陈旧注释「`CIR_CACHE_VER=17` 不 bump」 | 注释更新 + 指向本批(**注释-only,零行为**)| | **`.ccr`**(`CCR_VERSION=9`) | **不 bump** | 交付格式、**无快照复用语义**;⚠ **但报告显式写明:dex 程序的 `.ccr` 内容会变**(格式不变、内容变)——防「版本没 bump」被读成「内容没变」| -**重锁过程留痕**:首轮 `selfhost-tests` **rc=1**(两例版本位断言)→ 重锁后复跑**又红**——经隔离(干净缓存 49/49; -改前二进制对照 47/49 恰为该两例)判定为**环境 flake**,非本批引入 → 第三次红 = `VER_EXPECTED` 未同步 ⇒ 一并重锁后 **rc=0**。 +**重锁过程留痕**:首轮 `selfhost-tests` **rc=1**(两例版本位断言)→ 重锁后复跑**再次转红**——经隔离(干净缓存 49/49; +改前二进制对照 47/49 恰为该两例)判定为**环境 flake**,非本批引入 → 第三次转红 = `VER_EXPECTED` 未同步 ⇒ 一并重锁后 **rc=0**。 ## 10. R4(元组)的 `[GAP]` 处置与裁决出处(维护者指定必写) @@ -133,9 +133,9 @@ T5 的改动是 **docs/TODO-only**,但「文档改动」不足以说明判据 ⇒ 应**并成一条**处理。 - **落点**:`TODO #2026-09-16-36`(元组 + 切片产物合并条目,含最小机制/代价/待实证/同族互引)。 -## 11. 判据可行性经验(工具链能不能表达 X) +## 11. 判据可行性经验(工具链的表达能力) -**不是「想断言 X 就写 X」,而是先确认工具链能不能表达 X**:本轮想直接断言「读槽型 = `TI_DEX_S`」,实核发现 +**判据设计的前置条件 = 先确认工具链具备该表达能力**:本轮拟直接断言「读槽型 = `TI_DEX_S`」,实核发现 - `.cir` 文本转储**不打印普通 IR 变量类型**(`dump.cr:50-60` 的 `type_kind_name` 只在 `alloc`/`const` 行输出); - 且 `TI_DEX`(1) 与 `TI_DEX_S`(8) 在该表**同名 `"dex"`,不可区分**; @@ -143,7 +143,7 @@ T5 的改动是 **docs/TODO-only**,但「文档改动」不足以说明判据 ⇒ 改成**门控忠实见证**:`dex_scale_int`(门 = `irv_type(var) == TI_INT`)的唯一产物 `binary _dxt = …` 出现 ⇒ 读槽仍是 int; `dex_scaled_to_bits`(门 = `irv_type(var) == TI_DEX_S`)的非字面量产物 `binary _dxdiv = …` 出现 ⇒ 读槽已是 scaled。 -**见证的门恰好就是我们要断言的类型谓词 ⇒ 忠实**;两条合起来同时覆盖「**槽型正确**」与「**无重复转换**」(维护者指定的两条验收)。 +**见证的门恰好就是所断言的类型谓词 ⇒ 忠实**;两条合起来同时覆盖「**槽型正确**」与「**无重复转换**」(维护者指定的两条验收)。 (`.ccr` SYM 解析列为可选加固,未做。) ## 12. 未覆盖面与遗留 diff --git a/docs/superpowers/specs/2026-09-16-apx-conversion-audit.md b/docs/superpowers/specs/2026-09-16-apx-conversion-audit.md index b0b33ec6..dc48e474 100644 --- a/docs/superpowers/specs/2026-09-16-apx-conversion-audit.md +++ b/docs/superpowers/specs/2026-09-16-apx-conversion-audit.md @@ -2,7 +2,7 @@ **日期**:2026-09-16 · **性质**:**只读审计**(零构建、零测试运行、零源码改动)· **体例**:照 `2026-09-16-preexisting-bug-ledger.md` **判定约定**:本文件除标注 **【(B) 实测】** 者外,**一律为「读码判定」**(逐条 `file:line`);机理未坐实者**明写「未实证」**,不填空。 -**缘起**:(B) 批 T1 实测两条缺陷 **N-3**(方法调用 dex 实参不转换)· **N-1**(apx 作第 9 个 binary64 栈参)——本审计走查**全部边界**并回答「同族否」。 +**缘起**:(B) 批 T1 实测两条缺陷 **N-3**(方法调用 dex 实参不转换)· **N-1**(apx 作第 9 个 binary64 栈参)——本审计走查**全部边界**并对「是否同族」给出判定。 ## 0. 形式模型(读码) @@ -27,7 +27,7 @@ | ①e | 调用实参 · **>8 binary64 栈参** | 前端环转换同 ①a;**后端分类按 `irv_type`**:`callseq.cr:71`(寄存器)/`:97`(计数)/`:99`(落栈判定)/`:125`(压栈)| 前端**有**、后端**按槽型** | **未覆盖 = N-1**((B) 实测)· **机理未实证**(候选见 §3)| | ②a | 返回值 · Core `-> dex` 返 **apx 值** | 门 `:2494` `g_cur_ret_ti == TI_DEX`;而 Core `-> dex` ⇒ `fn_return_ti` 返 **`TI_DEX_S`**(`:684-690`)| **恒不触发** | **未覆盖(静默,高置信)**——(B) B7「未确证」项**读码确证可达** | | ②b | 返回值 · `return ` / 字面量 | 同 `:2494` | 不需要 | **正确** | -| ②c | 返回值 · extern 函数 | `:684-688`(extern ⇒ 保 `TI_DEX`)| 调用点结果定型 | **正确**(但结果若再被 Core 函数 `return` ⇒ 踩 ②a)| +| ②c | 返回值 · extern 函数 | `:684-688`(extern ⇒ 保 `TI_DEX`)| 调用点结果定型 | **正确**(但结果若再被 Core 函数 `return` ⇒ 触发 ②a)| | ③a | 结构体字段**写** | 字面量 `:2643-2646` / 赋值 `:1344-1346` | **无**(仅可选装箱)| **未覆盖** | | ③b | 结构体字段**读** | `:2520`(`new_ir_var("field", TI_INT)` + `IR_LOAD_FIELD`)| **无**,且**类型丢失** | **未覆盖**(类型丢失 ⇒ 下游 ①/②/⑧ 转换**均不触发**)| | ④a | 数组/切片元素**写** | 赋值 `:1362` / 字面量 `:2690-2700` / 切片形 `:2517` 后同元素路径 | **无** | **未覆盖** | @@ -41,7 +41,7 @@ | ⑧ | **比较/相等**(`==`,`<`,…)| 二元路径 `:1248-1273`:有 `TI_DEX` 操作数 ⇒ bits 对齐;否则 `TI_DEX_S` ⇒ 精确对齐 | **有**(**前提 = 操作数 IR 型完好**)| **部分**:经 ③b/④b/⑤/⑥ 读入的操作数**类型已丢失** ⇒ 不进对齐分支 ⇒ **静默错值** | | ⑨ | **`as` 类转换** | `:2749-2767`:`IR_LOAD` 纯拷贝进目标型新槽 | **无形式转换** | **未覆盖**(两侧各形态;`@raw_int`(`:1703`)是唯一显式通道)| | ⑩ | `match` 于 dex | dex 非枚举 ⇒ 无 tag 语义;`dex?` 面 = 载荷读(同 ⑥b)| **无** | **未覆盖**(同族 ⑥b)| -| ⑪ | 形参在 **callee 内**使用 | `ir_gen.cr:2863-2867`:**形参恒物化为 `TI_DEX_S`**(`if param_type == TI_DEX { = TI_DEX_S }`)| 有(统一 scaled)| **正确**(前提 = 调用点已按 ①a 转;方法调用 ⇒ 踩 ①c)| +| ⑪ | 形参在 **callee 内**使用 | `ir_gen.cr:2863-2867`:**形参恒物化为 `TI_DEX_S`**(`if param_type == TI_DEX { = TI_DEX_S }`)| 有(统一 scaled)| **正确**(前提 = 调用点已按 ①a 转;方法调用 ⇒ 触发 ①c)| **表 A 结论**:契约「存储/边界处按槽位形式转换」**只在 4 类落点兑现**(局部/全局/LET 写点 + 二元对齐 + `@raw_int` + 返回点**部分**), **聚合面(字段/元素/元组/载荷)与 `as`/引用词调用/返回的 Core 分支全部未兑现**;且聚合读**丢类型**(`:2520` 起 `TI_INT` 定型), @@ -53,7 +53,7 @@ > **探针为设计稿(未编译验证语法)**:语法按本仓既有用例形(`impl S { fn m(self: S, …) }`、结构体字面量 `S { f = v }`)——(B) 批落地时先过一遍 `check`。 > **N-4 纪律**:涉及全局的探针**必须 `mut`**(否则 `find_global_const_node` 折叠 ⇒ 读点不碰全局行)。 > -> ⚠ **errata(2026-09-16,T1 实测 —— 抄本表前必读)**:本表探针源的 `d : ., apx = 7.0`(类型位**推断**)**不产生 apx 槽** ⇒ 按其运行**全部假绿**。**一律改用显式形 `d : dex, apx = 7.0`**。详见文末 **§errata**(保留本表原文,不静默改)。 +> ⚠ **errata(2026-09-16,T1 实测 —— 引用本表前必读)**:本表探针源的 `d : ., apx = 7.0`(类型位**推断**)**不产生 apx 槽** ⇒ 按其运行**全部假绿**。**一律改用显式形 `d : dex, apx = 7.0`**。详见文末 **§errata**(保留本表原文,不静默改)。 | # | 机理一句话 | 最小探针(≤10 行)| 期望 | 可达性 | |---|---|---|---|---| @@ -66,25 +66,25 @@ | **B-7**(=⑨)| `as` 为纯 `IR_LOAD` 拷贝(`:2765`),无形式转换 | `fn main() -> int { d : ., apx = 1.5; x := d as dex; return @raw_int(x) / 1000000; }` | 1(1.5 经 6 位定点 = 1500000/1e6)| **可达**:`:2749-2767` · **⚠ 待语言定案**(「`d as dex` 恒等还是转换」由维护者问用户裁,**不进 RED 集合**)| | **B-8**(=⑧)| 聚合读丢型 ⇒ 比较不对齐(bits vs scaled 混比)| `struct S { f: dex } fn main() -> int { d : ., apx = 1.5; s : ., mut = S { f = 1.5 }; if s.f == d { return 1; } return 0; }` | 1(同值应相等)| **可达**(依赖 B-3/B-4 同因)| | **B-9**(=①e,=N-1)| 前端已转 scaled,后端分类仍按 `irv_type`(`callseq.cr:71/97/99/125`)⇒ 落位/序与 callee 期望的交互 | 见 (B) T1 探针(8 个 binary64 实参 + 局部 apx 作第 9 参)| 7 | **(B) 实测可达**;**机理未实证**(§3)| -| **B-10**(=⑪ 反证对照)| 已覆盖面**应当正确**(防「修法把正确的搞坏」)| `fn g(x: dex) -> int { return @raw_int(x) / 1000000; } fn main() -> int { d : ., apx = 7.0; return g(d); }` | 7 | 已覆盖(①a+⑪)| +| **B-10**(=⑪ 反证对照)| 已覆盖面**应当正确**(防「修法破坏正确路径」)| `fn g(x: dex) -> int { return @raw_int(x) / 1000000; } fn main() -> int { d : ., apx = 7.0; return g(d); }` | 7 | 已覆盖(①a+⑪)| ## 3. N-3 / N-1 同族判定(**本审计最重要结论**) -**结论(修订后):两条为**同一根因**——**前端转换环的覆盖面缺口**(两个**触发模式**)⇒ **下一批 = 一个批次**。** +**结论(修订后)**:两条为**同一根因**——**前端转换环的覆盖面缺口**(两个**触发模式**)⇒ **下一批 = 一个批次**。 (**修订留痕**:本文件首版按「N-3 = 门 / N-1 = 前后端约定交互」判**两条独立根因**;补齐 ⑦a 与 **callee 侧**读码后**据实改判**——理由见下,旧表述不静默抹去。) -**共同根因 = 转换环(`ir_gen.cr:1806-1839`)是「Core 函数 dex 实参」的**唯一**转换点**:全仓再无其它实参转换通道(转换调用点全集见 §0),而两个后端在调用边界**只做运输、零 dex 逻辑**(ELF:`callseq.cr:66-132` 按 `irv_type` 分类 + `frame.cr:115-140` 保存;解释器:`interp.cr:240-244` **按位置拷贝实参、无任何 dex 判断**)。⇒ **环漏转一个实参 ⇒ 双路径必同错**(同一个错 IR)——与 (B) 两条实测的「双路径同错」形态一致。 +**共同根因** = 转换环(`ir_gen.cr:1806-1839`)是「Core 函数 dex 实参」的**唯一**转换点:全仓再无其它实参转换通道(转换调用点全集见 §0),而两个后端在调用边界**只做运输、零 dex 逻辑**(ELF:`callseq.cr:66-132` 按 `irv_type` 分类 + `frame.cr:115-140` 保存;解释器:`interp.cr:240-244` **按位置拷贝实参、无任何 dex 判断**)。⇒ **环漏转一个实参 ⇒ 双路径必同错**(同一个错 IR)——与 (B) 两条实测的「双路径同错」形态一致。 **触发模式 ①(= N-3):调用形态门**。门 `:1806` 写死 `ast_kind(func_node)==EXPR_IDENT` ⇒ `EXPR_FIELD`(方法调用)整段跳过(表 A ①c)。 -**触发模式 ②(= N-1):环内逐形参的**配对/类型读取**未命中**。机理(读码判定,高置信): +**触发模式 ②(= N-1)**:环内逐形参的**配对/类型读取**未命中。机理(读码判定,高置信): 1. 环按 `ast_type_val(cpn) == TI_DEX` 决定转换(`:1821`),`cpn` 沿「下一个 `EXPR_PARAM`」前扫(`:1839-1843`,与 F4/#21 同族的形参链导航)——**若某深度的形参类型读取未命中** ⇒ **该实参不转换**; 2. 未转换的 apx 实参在**后端**按 `irv_type == TI_DEX` 被判为 **binary64 类**(`callseq.cr:71/97/99/125`)⇒ 走 XMM / **float 栈**;而 callee 形参槽恒为 `TI_DEX_S`(`:2866`)⇒ - **主错 = 值形式**:callee 拿到 **bits**(按 scaled 读)⇒ **静默错值**; - **次错(可达、未实证)= 落位公式不对称**:callee 的栈参偏移**按形参序号**算(`frame.cr:129/131`:`caller_off := 16 + (pi - 6) * 8`),caller 的落栈判定**按类型类**(`callseq.cr:89-105`)⇒ 类混合时两边对「第 7 个实参是否在栈上/第几槽」可给出**不同答案**(同一实参被放进 XMM 而 callee 从栈读)。 -3. **为何两路径同错**:主错发生在**前端已定的 IR**(值形式未转换)⇒ ELF 与 interp 一致地错 ✓。 +3. **两路径同错的机理**:主错发生在**前端已定的 IR**(值形式未转换)⇒ ELF 与 interp 一致地错 ✓。 -**必须实测才能逐一坐实(插桩点,供下一批用)**: +**须实测才能逐一坐实(插桩点,供下一批使用)**: - **插桩点 A(环内)**:`:1815-1843` 每轮打印 `cpi` / `ast_type_val(cpn)` / `irv_type(arg_vars[cpi])`(转换前后)⇒ 直接看**第 9 形参是否被环看见**:若 `ast_type_val` ≠ `TI_DEX` ⇒ **模式②坐实**;若 = `TI_DEX` 且转换发生 ⇒ 模式②证伪 ⇒ 转查落位公式(次错)。 - **插桩点 B(分类 vs 落位)**:`callseq.cr:66-105` 打印每实参 `irv_type(fa+i)` + 类计数 + 落栈判定;`frame.cr:118-140` 打印每形参 `pty` + `caller_off` ⇒ **两表对照**即判「次错」是否存在。 - **改写条件**:若插桩点 A 显示环**确已转换**第 9 实参 ⇒ N-1 根因回到「落位公式不对称」(与 N-3 不同)⇒ 本行改回「两条独立根因」(判据已给,可直接改)。 @@ -93,20 +93,20 @@ | 优先级 | 条目 | 理由 | |---|---|---| -| **P0** | B-2(返回)/ B-3(字段)/ B-4(元素)/ B-5(元组)/ B-6(载荷)| **静默错值 + 双路径同错**(本项目头号敌人);全部**普通代码可达**(无需 apx 冷门语法:B-2 只要函数返回局部 apx 值)| +| **P0** | B-2(返回)/ B-3(字段)/ B-4(元素)/ B-5(元组)/ B-6(载荷)| **静默错值 + 双路径同错**(本项目头号敌人);全部**普通代码可达**(无需 apx 生僻语法:B-2 只要函数返回局部 apx 值)| | **P0** | B-1(=N-3 方法调用)| 同上;`impl` 方法是主语法 | | **P0** | B-9(=N-1 栈参)| 同上((B) 已实测)| | P1 | B-7(`as`)| 静默;`as` 在 dex 上的语义**未定** ⇒ 需**先裁语义**(「`d as dex` 是恒等还是转换」)再修 | | P1 | B-8(比较)| 静默,但**派生自 B-3/B-4** ⇒ 修好聚合面后自然收敛;保留探针防回退 | | P2 | ⑦a 全局初值(**待核**)| 本轮未读完 `inject_global_init` 区 ⇒ **未实证**;若与 ⑦b 同源则无需修 | -**修法方向(**已获维护者背书 2026-09-16**——理由 = 「语义保鲜」哲学:判定应以**语言层语义(声明型/签名型)**为准,不该以已降级过的 IR 值型为准)**:把「按槽位形式转换」的**唯一漏斗**收敛到 `dex_store_adjust`(`:1044`),并让**所有**写点(含 4 类聚合写 + `as` + 返回)与**读点定型**(`:2520` 等处的 `TI_INT` 硬定型 ⇒ 应保留元素/字段的声明型)都过这一漏斗;转换触发**应以「声明型/签名型」而非「IR 值型」为准**(B-2/B-9 的共同教训:值型在多处丢失或被改写)。 +**修法方向**(**已获维护者背书 2026-09-16**——理由 = 「语义保鲜」哲学:判定应以**语言层语义(声明型/签名型)**为准,不该以已降级过的 IR 值型为准):把「按槽位形式转换」的**唯一漏斗**收敛到 `dex_store_adjust`(`:1044`),并让**所有**写点(含 4 类聚合写 + `as` + 返回)与**读点定型**(`:2520` 等处的 `TI_INT` 硬定型 ⇒ 应保留元素/字段的声明型)都过这一漏斗;转换触发**应以「声明型/签名型」而非「IR 值型」为准**(B-2/B-9 的共同教训:值型在多处丢失或被改写)。 ## 5. 边界清单外的新发现(补) 1. **聚合读的统一类型丢失**(`:2520` `new_ir_var("field", TI_INT)`;元素读同类)⇒ 是 B-2/B-8 类「转换不触发」的**放大器**(不止 dex:可选表示的 `rep`/声明面亦受影响 —— 与 (A) 批 T3 的「声明面登记」修法**正交**,勿混)。 -2. **`@raw_int` 是唯一显式形式通道**(`:1703`):所有探针的**期望值判据都应经 `@raw_int` 表达**(否则比较面自己就踩 B-8)。 -3. **extern 面已排除**(①b):apx 实参照传 = C ABI(binary64)**正确**;但 extern **返回值**在 Core 函数里 `return` 会踩 ②a(B-2 的变体)。 +2. **`@raw_int` 是唯一显式形式通道**(`:1703`):所有探针的**期望值判据都应经 `@raw_int` 表达**(否则比较面自身即触发 B-8)。 +3. **extern 面已排除**(①b):apx 实参照传 = C ABI(binary64)**正确**;但 extern **返回值**在 Core 函数里 `return` 会触发 ②a(B-2 的变体)。 --- @@ -114,13 +114,13 @@ > **体例**:本仓纪律「裁决被证伪要留痕」——**本文 §1/§2 的原文一律不动**(它是当时的判定快照),勘误集中在本节并**已被维护者背书**。 -### E1(**必修,会影响所有抄表 B 的人**)—— 表 B 的探针源**一律**须用**显式形** +### E1(**必修,影响所有引用表 B 者**)—— 表 B 的探针源**一律**须用**显式形** | 面 | 内容 | |---|---| | **原文(本文 §2 表 B 十条,照录不变)** | 全部写作 `d : ., apx = 7.0;`(类型位用 `.` 推断 + `apx` 标签) | | **实测结论** | **该形不产生 apx 槽**。`ir_gen.cr:2388-2393` 的 apx 分支**以 `declared_ti == TI_DEX` 为前提**;类型位写 `.`(推断)时 `type_node < 0` ⇒ `declared_ti = res_type_node` 落 **`TI_UNIT`**(`:2377-2378`)⇒ apx 分支**整段不进**,随后 `:2441-2443` 把槽型设为**初值类型 `TI_DEX_S`** ⇒ **退化为普通精确 dex 局部变量,`apx` 标签对槽形式零作用** | -| **后果** | 表 B 十条按其**原稿形**运行 ⇒ **全部假绿**(缺陷即使存在也必然显绿,因为被测路径根本没走) | +| **后果** | 表 B 十条按其**原稿形**运行 ⇒ **全部假绿**(缺陷即使存在也必然显绿,因为被测路径并未走到) | | **修正** | **一律改用显式形 `d : dex, apx = 7.0`(类型位写 `dex`)** | | **判别法(关键)** | **`.cir` 中 `const dex = ` 序列的在场性**——显式形会多出一条 binary64 位模式常量(7.0 ⇒ `4619567317775286272`)+ `_dxs`/`_dxm`/`_dxc`/`branch`/`_dxh`/`F2I` 序列;推断形只有 `const dex = 7000000` + `store`。**另有反向自证**:`corec run`(解释器)在显式形下**拒收 rc=255**(`IR_I2F/IR_F2I` 无 binary64 语义),推断形则正常取值 ⇒ **拒收本身就是「apx 槽确已建立」的证据** | | **影响范围(已核)** | 本文表 B 是**设计稿、从未运行**,故本文其余读码结论不受影响;**(B) 批已实测的 N-3/N-1(TODO #2026-09-16-17/#81)用的是显式形**(`lx : dex, apx, mut = 1.5`)⇒ **那两条实测结论不受影响** | @@ -134,12 +134,12 @@ ### E3(已落 T1 实测)—— 表 B-7 的探针**零区分力**(探针设计缺陷,与「语义未定」是两件事) -原文 B-7 探针在「`as` = 恒等」与「`as` = 转换」两种读法下**同答 1** ⇒ 答不出它要问的问题。**且原稿形(`d : ., apx`)连 apx 槽都没建**(E1),缺陷叠加。 +原文 B-7 探针在「`as` = 恒等」与「`as` = 转换」两种读法下**同答 1** ⇒ 答不出它要问的问题。**且原稿形(`d : ., apx`)未建立 apx 槽**(E1),缺陷叠加。 **替换探针**(源改**精确值**):`fn main() -> int { e : dex = 1.5; y := e as dex; return @raw_int(y) / 1000000; }` ⇒ 恒等读法答 **0**(实测)、转换读法答 **1**,**可区分**。`as` 语义仍**待语言定案**,面**冻结不动**。 ### E4(语法)—— 元组数字下标须写 **`t . 0`(带空格)** -`t.0` 会让词法器把 `.0` 读成 dex 字面量 ⇒ `check rc=1` + 3× `error: invalid integer literal`;`t . 0` 才走 `parser.cr:359-366` 的 `T_DOT` + `T_INT` 分支。**本文原稿写法是对的**(此处仅为防后人「顺手改成 `t.0`」)。 +`t.0` 会让词法器把 `.0` 读成 dex 字面量 ⇒ `check rc=1` + 3× `error: invalid integer literal`;`t . 0` 才走 `parser.cr:359-366` 的 `T_DOT` + `T_INT` 分支。**本文原稿写法是对的**(此处仅为防后人误改为 `t.0`)。 ### E5(**完整性声明 —— 表 A / 表 B 的覆盖面不完备**) diff --git a/docs/superpowers/specs/2026-09-16-apx-conversion-batch-report.md b/docs/superpowers/specs/2026-09-16-apx-conversion-batch-report.md index c5b522b6..24d4a544 100644 --- a/docs/superpowers/specs/2026-09-16-apx-conversion-batch-report.md +++ b/docs/superpowers/specs/2026-09-16-apx-conversion-batch-report.md @@ -63,7 +63,7 @@ ⇒ **预变更与当前逐档相同,差异全在「pinned rev ↔ develop」之间** ⇒ **非本批引入**。机理 = 本批之前的批(fail-closed 收紧)把这类语料由 `rc=0` 变为 `rc=1`(如 N06 硬错)⇒ **无产物 ⇒ 无缓存条目**。**判据标准**:腿① 的判据是「74 档 `check` 日志逐字节同 + 逐档 rc 同」(**已零差异**)与「暖态 FAIL=0」(**两侧均 0**);暖态**条目计数**是信息量,非判据。 -## 4. **判据分工(本批最值钱的一条 —— 覆盖域必须显式)** +## 4. **判据分工(本批最重要的一条 —— 覆盖域必须显式)** > **实测**:把 apx 面改坏两次(M1/M2),**ELF canary 与 `.ccr` 四条在两种突变下全部 IDENTICAL**。 @@ -76,7 +76,7 @@ | 腿① 74 档 | 74 档的 **check 面** | **ir_gen 及之后**(`check` 不跑 ir_gen) | | **本批套件** | **apx/dex 形式转换面** | 其余一切 | -**落地要求**:新增判据必须写明覆盖域与零覆盖域;**跨面回归由该面的判据承担**,不得以「canary 还绿着」代替。详见 `2026-09-16-criteria-strength-audit.md` **§0ter**。 +**落地要求**:新增判据必须写明覆盖域与零覆盖域;**跨面回归由该面的判据承担**,不得以「canary 仍为绿」代替。详见 `2026-09-16-criteria-strength-audit.md` **§0ter**。 ## 5. 审计校正(留痕体例:审计原文 ↔ 实读并存,不静默抹史) diff --git a/docs/superpowers/specs/2026-09-16-arg-inference-batch-report.md b/docs/superpowers/specs/2026-09-16-arg-inference-batch-report.md index 1faa017b..b4ba626b 100644 --- a/docs/superpowers/specs/2026-09-16-arg-inference-batch-report.md +++ b/docs/superpowers/specs/2026-09-16-arg-inference-batch-report.md @@ -31,7 +31,7 @@ | `c4703475` | T3/T4 实施记录(含**方法学修正**:码集对拍不得用「码+行号」做身份) | | `77d55860` | **⚠ T4 停止点**(腿 C 抓到 1 处新引入误报) | | **`43d6b598`** | **裁 (i) 落实**:补 **range-go 迭代变量绑定** + **腿 E** 直接判据 | -| `5eaab2ae` | 编号碰撞处置(我的 #94→**#96**、#95→**#97**) | +| `5eaab2ae` | 编号碰撞处置(本批编号 #94→**#96**、#95→**#97**) | | `59bd94a1` | 硬条件 3 留痕(TODO 追记)+ 方法论文档 §0quater | **收官形态 = 在最新 develop 上的单提交**(重建,非 rebase;事故经过见 §10)。理由与证据: @@ -54,7 +54,7 @@ 2. **(b) fail-closed 护栏**:`infer_call_args` 内,实参位 `EXPR_CALL` 且 callee 为 `EXPR_FIELD` 且 `ast_data <= 0` ⇒ `check_error(EC_N_FUNC, …)`。**落点偏离计划已交代**:既有 fail-closed 闸门(`main.cr:146-175`)位于 `check_all()` 之后、`ir_gen` **之前** ⇒ 在 ir_gen 报错不进闸门、须改构建控制流;改在 **checker 侧**实现同一条件(零新控制流、闸门天然覆盖)。**(a) 已修 ⇒ 恒不触发**(其价值 = 防未来同类回归);**不误伤 dyn**(dyn 方法调用的名字由 dyn 分支回填,`cir` 实测 `dyn_dispatch` 正常)。 3. **同批**:`TODO #2026-09-16-35`(实参位泛型退化键)与 **range-go 绑定**(见 §3)。 -## 3. ⚠ **本批顺带修复的既有缺陷(两条)**(硬条件 3:必须写清,否则后来人不知本批改了多少东西) +## 3. ⚠ **本批顺带修复的既有缺陷(两条)**(硬条件 3:须写明,否则后续开发者无从得知本批的改动范围) ### ① 实参位泛型调用用「退化实例键」实例化 → `TODO #2026-09-16-35`(独立条目) @@ -106,7 +106,7 @@ 机制:一次**触发面变更**会**同时**产生①真修好②新引入误报,二者在「诊断计数」上**不可区分**。 **落地要求**(已写入 `2026-09-16-criteria-strength-audit.md` **§0quater**):触发面变更批**必须**把新增诊断**默认按回归嫌疑**处理、逐条归因;**且必须有「原载体回归」判据**(本例 = 29 探针 + 已挂套件的 rc 基线)——因为**新形态的断言 ≠ 原载体的断言**。 -**方法学附带修正(防后人重踩)**:码集对拍**不能**以「码 + 行号」为身份——t2/t3 语料是**多文件拼接单元**,改动任一参与文件的行数都会让后续行号整体漂移(实测 +17)⇒ 首轮把「位移」误判为「新增 N11×38」。**正确身份 = 码 + 诊断文本**。 +**方法学附带修正(防后人重犯)**:码集对拍**不能**以「码 + 行号」为身份——t2/t3 语料是**多文件拼接单元**,改动任一参与文件的行数都会让后续行号整体漂移(实测 +17)⇒ 首轮把「位移」误判为「新增 N11×38」。**正确身份 = 码 + 诊断文本**。 ## 7. 收官判据(五 CI job + 自举链) @@ -143,13 +143,13 @@ ### ① 失败的 rebase:`jj rebase -s <链尖> -d develop` 把 16 段链压成 1 段 -- **经过**:收尾执行 `jj rebase -s feature/arg-inference-gap -d develop`(意图 = 整链移到最新 develop)。**`-s` 语义 = 「以该 revision 为根重定位它与它的后代」**;我给的却是**链尖** ⇒ 链尖被直接挂到 develop,**15 个祖先被孤立**,工作副本树 = **只剩链尖一个提交的 diff**。 +- **经过**:收尾执行 `jj rebase -s feature/arg-inference-gap -d develop`(意图 = 整链移到最新 develop)。**`-s` 语义 = 「以该 revision 为根重定位它与它的后代」**;实际传入的却是**链尖** ⇒ 链尖被直接挂到 develop,**15 个祖先被孤立**,工作副本树 = **只剩链尖一个提交的 diff**。 - **发现**:`jj status` + 8 条路径清单对照 ⇒ `src/compiler/checker.cr` 里 `infer_call_args` 不见了。 - **恢复**:`jj undo` ×2(jj 操作日志逐条记录)⇒ 完整回到 `59bd94a1`;`cmp` 逐路径复核 = **零数据损失**。 -- **正确用法(防重踩)**:整链移动用 **`jj rebase -b `**(或 `-s <链根>`);**绝不** `-s <链尖>`;单提交用 `-r`。 +- **正确用法(防重犯)**:整链移动用 **`jj rebase -b `**(或 `-s <链根>`);**绝不** `-s <链尖>`;单提交用 `-r`。 - **加固纪律(本批新增)**:破坏性 `jj` 操作(rebase / squash / abandon)**先 `jj log -r '::@'` 记链形态**,**操作后立即**以「关键标记 grep + `jj diff --stat`」复核树内容,**再**跑判据。 -### ② 两条判据命令的假红陷阱(同一晚各踩一次) +### ② 两条判据命令的假红陷阱(同一晚各命中一次) -- **`src/ci/run.sh` 不读 argv**:job 名走 **`CI_JOB_NAME` 环境变量**(`CI_JOB_NAME=check src/ci/run.sh`)。我首轮写成 `bash src/ci/run.sh check` ⇒ 五个 job **全部** `unknown CI_JOB_NAME:` rc=1——**是命令用错,不是 job 红**。 -- **重定向被 noclobber 拦住 ⇒ 读到的是上次的旧日志**:第二轮我用 `env CI_JOB_NAME=$j ... > /tmp/apx-t1/job_$j.log`,而该文件已存在、当前 shell 开了 noclobber ⇒ **重定向失败、命令根本没跑**,`tail` 展示的仍是首轮的旧内容 ⇒ 两轮「结果」看起来完全相同。**判据命令必须核对「日志时间戳/新路径」**,否则「跑过了」本身是假的。 +- **`src/ci/run.sh` 不读 argv**:job 名走 **`CI_JOB_NAME` 环境变量**(`CI_JOB_NAME=check src/ci/run.sh`)。首轮写成 `bash src/ci/run.sh check` ⇒ 五个 job **全部** `unknown CI_JOB_NAME:` rc=1——**是命令用错,不是 job 红**。 +- **重定向被 noclobber 拦住 ⇒ 读到的是上次的旧日志**:第二轮使用 `env CI_JOB_NAME=$j ... > /tmp/apx-t1/job_$j.log`,而该文件已存在、当前 shell 开了 noclobber ⇒ **重定向失败、命令实际未运行**,`tail` 展示的仍是首轮的旧内容 ⇒ 两轮「结果」呈现完全相同。**判据命令必须核对「日志时间戳/新路径」**,否则「已运行」这一判断本身不成立。 diff --git a/docs/superpowers/specs/2026-09-16-compile-time-theorems.md b/docs/superpowers/specs/2026-09-16-compile-time-theorems.md index 662090a5..4d20b993 100644 --- a/docs/superpowers/specs/2026-09-16-compile-time-theorems.md +++ b/docs/superpowers/specs/2026-09-16-compile-time-theorems.md @@ -1,9 +1,10 @@ # 编译时间上界定理清单(code review 对照) 日期:2026-09-16 -定位(受众/状态/出处):**受众 = maintainer(改编译器者)+ reviewer**;**状态 = active(计划配套,随 `plans/2026-09-04-compile-time-linearity.md` 推进而更新)**;**出处 = 本文(定理与论证要点)+ 计划 §4(原表)+ 实施期计数器证书(机器侧)**。 -性质:**人证清单**(不是测量结果)。每行一条定理:输入规模 N(按 pass 定义)下,耗时 ≤ C·N(C 为 pass 相关常数;hash 表按**期望** O(1) 时在「论证要点」注明「期望」;总量界 = 平摊严格线性)。 -用法:**改任一 pass 必须同步本表**——保持定理成立,或**先改定理并说明**(照计划 §5.3)。破坏定理的改动 = review 阻断项。 + +**定位(受众 / 状态 / 出处)**:受众 = maintainer(改编译器者)+ reviewer;状态 = active(计划配套,随 `plans/2026-09-04-compile-time-linearity.md` 推进而更新);出处 = 本文(定理与论证要点)+ 计划 §4(原表)+ 实施期计数器证书(机器侧)。 +**性质**:人证清单(非测量结果)。每行一条定理:输入规模 N(按 pass 定义)下,耗时 ≤ C·N(C 为 pass 相关常数;hash 表按**期望** O(1) 时在「论证要点」注明「期望」;总量界 = 平摊严格线性)。 +**用法**:改动任一 pass 必须同步本表——保持定理成立,或先改定理并说明(照计划 §5.3)。破坏定理的改动 = review 阻断项。 --- @@ -34,4 +35,4 @@ - `docs/superpowers/plans/2026-09-04-compile-time-linearity.md`(计划本体;§4 = 原定理表,§8 = 任务级细化与审计勘误,§9 = 裁决门) - `docs/superpowers/plans/2026-09-16-opt-rep-follows-storage.md`(同期的另一条性能相关批:可选表示,**不含时间上界承诺**) -- 审计复核来源(2026-09-16 纸面细化轮):计划 §8.1 勘误表(**8 条行漂 / 2 条位置迁移 / 后端目录退役 / 1 条已失效**——照原文开工必错) +- 审计复核来源(2026-09-16 纸面细化轮):计划 §8.1 勘误表(**8 条行漂 / 2 条位置迁移 / 后端目录退役 / 1 条已失效**——照原文施工必然出错) diff --git a/docs/superpowers/specs/2026-09-16-criteria-strength-audit.md b/docs/superpowers/specs/2026-09-16-criteria-strength-audit.md index e61da8c2..02844279 100644 --- a/docs/superpowers/specs/2026-09-16-criteria-strength-audit.md +++ b/docs/superpowers/specs/2026-09-16-criteria-strength-audit.md @@ -1,8 +1,8 @@ # 判据强度审计 —— 字节/序列级判据的系统性弱点(2026-09-16) -**性质**:只读审计(**零构建、零源码/测试改动**;全部结论来自实读 + `grep`)· **体例**:照 `2026-09-16-preexisting-bug-ledger.md` -**来源**:`criteria-strength-audit` 代理的判据强度审计全文(含 **05:54–05:58「判据载体化」批落盘后的状态修订**)+ `plan-capacity` 代理的坐标实核。 -**扫描快照**:审计者 = 今日 23:21 前后的树,**05:54–05:58 一批落盘改变了数条结论与坐标**(下文逐条标「**已修 / 仍存**」)。 +**性质**:只读审计(零构建、零源码/测试改动;全部结论来自实读 + `grep`)。**体例**:照 `2026-09-16-preexisting-bug-ledger.md`。 +**来源**:`criteria-strength-audit` 代理的判据强度审计全文(含 05:54–05:58「判据载体化」批落盘后的状态修订)+ `plan-capacity` 代理的坐标实核。 +**扫描快照**:审计对象 = 当日 23:21 前后的树;05:54–05:58 一批落盘改变了数条结论与坐标(下文逐条标「已修 / 仍存」)。 **缘起(实证)**:seam 批 sd 助手三处漏 `REX.B` —— `[r11]` 编码成 `[rbx]` ⇒ **野指针 139**;而当时的判据**各自独立 `find`**(一条查 `4c8d1d`、一条查 `f20f1003`),**中间插坏字节照样全绿** ⇒ 判据放跑了真缺陷。 ## 0. 方法论条目(核心结论) @@ -10,26 +10,26 @@ **弱点形态:片段式字节判据(disjoint-fragment matching)**——同一段期望序列被拆成**多个各自独立的 `find`/子串断言**,片段之间的字节**无任何约束**。 - 判据实际断言的命题是「这些片段各自出现过」≠「这段序列连续出现」⇒ **片段间的插入/替换**(多一字节、错一个 ModRM、换成等长异义指令)都不会变红。 - **实证**:seam 批三处 `REX.B`(现 `src/arch/x86_64/instr.cr:474/489/501` 注释:「漏它则 rm=3 变成 [rbx] ⇒ 野指针 139」);修复后 A1 判据已改为**连续序列 + 精确 4B gap + REX.B 入列**(表 A 行 A1 = 修正后的强形态)。 -- **④ 反例驱动(可操作自检问句,**本节的口味要求**)**:新增/评审任何字节判据时,**逐条问**: +- **④ 反例驱动(可操作自检问句,本节的要求)**:新增或评审任何字节判据时,逐条自问: > **「什么坏实现能骗过这条断言?」** - 答不出 ⇒ 该判据**尚未被证明有效**(不是「够强」);答得出且**真能骗过** ⇒ **弱判据**(进表 B + 登记 TODO)。 - **落地建议**:把这句话**写进判据所在测试函数的注释**(一行即可,例:`# 反例自检:改 modrm_reg_role 能否骗过本断言?`)⇒ 让「能不能被骗过」成为写判据时的**必答题**,而不是评审时才想起。 - **本日教训(维护者原话)**:判据弱**不是因为写得少,而是因为没人问过它能不能被骗过**。 + 答不出 ⇒ 该判据**尚未被证明有效**(不等价于「够强」);答得出且**真能骗过** ⇒ **弱判据**(进表 B + 登记 TODO)。 + **落地建议**:将该问句**写进判据所在测试函数的注释**(一行即可,例:`# 反例自检:改 modrm_reg_role 能否骗过本断言?`)⇒ 让「能否被坏实现骗过」成为写判据时的**必答题**,而非评审时才想起。 + **本日教训(维护者原话)**:判据弱的成因**不在写得少,而在从未有人问过它能否被坏实现骗过**。 - **强判据写法**:① **连续序列断言**(整条指令字节,含 `??` 通配位);② **带定长 gap 的正则**(`..{0,N}`,N 尽量小并写明理由——A1 即此形);③ **锚点 + 定长窗口**(长度可变段用**长度公式**,如 A2 的 `text[m+1]==0x83 and text[m+2]==0xEC → text[m+3]`);④ **反例驱动**:每条字节判据评审时须回答「**什么坏实现能骗过它**」——写不出反例 ≠ 强,写得出而判据仍绿 = 弱判据。 -## 0bis. 第二类假绿:**探针不触发**(probe-doesn't-reach)(2026-09-16,apx 转换缺口批 T1 实测) +## 0bis. 第二类假绿:探针不触发(probe-doesn't-reach)(2026-09-16,apx 转换缺口批 T1 实测) -**本文 §0 命名的是第一类:片段式判据**——判据**断言写弱了**,能被坏实现骗过(断言在骗,探针本身走到了路径)。 -**本节的第二类与之正交**:**判据本身没问题,但探针根本没走到被测路径** ⇒ 同样产出**假绿**。 +**本文 §0 命名的是第一类:片段式判据**——判据断言写弱,能被坏实现骗过(问题在断言侧,探针本身已走到路径)。 +**本节的第二类与之正交**:判据本身无问题,但探针从未走到被测路径 ⇒ 同样产出**假绿**。 | 面 | 第一类(片段式判据) | 第二类(探针不触发) | |---|---|---| | **谁坏了** | **断言** | **探针 / 语料** | -| **为什么假绿** | 断言能被坏实现骗过(片段之间无约束) | 缺陷即使存在也必然显绿(被测路径压根没执行) | +| **为什么假绿** | 断言能被坏实现骗过(片段之间无约束) | 缺陷即使存在也必然显绿(被测路径从未执行) | | **修法** | 改**断言**(连续序列 / 定长 gap / 锚点窗口) | 改**探针**(让它真走到那条路径)+ **加覆盖面自证** | | **自检问句** | 「**什么坏实现能骗过这条断言?**」 | 「**我怎么知道探针走到了那条路径?**」 | -### 实证(**决定性,2026-09-16**):apx 探针的声明形 +### 实证(决定性,2026-09-16):apx 探针的声明形 apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源**统一**写作 `d : ., apx = 7.0;`(类型位用 `.` 推断 + `apx` 标签)。而 `ir_gen.cr:2388-2393` 的 apx 槽建立**以 `declared_ti == TI_DEX` 为前提**;类型位写 `.` 时 `declared_ti = TI_UNIT`(`:2377-2378`)⇒ apx 分支**整段不进** ⇒ 槽型回落 `TI_DEX_S` ⇒ **apx 标签对槽形式零作用,探针退化为普通精确 dex**。 ⇒ 该表十条**全部假绿**:不是断言写弱,而是**探针从未走到 apx 转换面**。 @@ -39,7 +39,7 @@ apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源** 2. **反向自证**——`corec run`(解释器)在**显式形**下**拒收 rc=255**(`IR_I2F/IR_F2I` 无 binary64 语义,`interp.cr:263-266`/`:704-705`),推断形则正常取值 ⇒ **拒收本身就是「apx 槽确已建立」的证据**; 3. **正据(数值反推执行路径)**——`bits(7.0) mod 2⁸` 与实测读数的逐例吻合(T1:`4619567317775 mod 256 = 15`,9 例同值)⇒ 证出「bits 原样入槽 + 读点定型 `TI_INT` + `@raw_int` 无转换」这条链**确实被执行**。 -### 通用判别法(**写探针时的必答题,与 §0 的反例问句配对**) +### 通用判别法(写探针时的必答题,与 §0 的反例问句配对) > **「我怎么知道探针走到了那条路径?」** @@ -49,7 +49,7 @@ apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源** **登记去向**:`TODO.md` 的判据类登记面(见 §5;本小节由 apx 批 T1 追加,**不改变本文 §1/§2 的任何既有结论**)。 -## 0ter 判据覆盖域:**canary 的正交性**(2026-09-16 apx 批 T3 实测) +## 0ter 判据覆盖域:canary 的正交性(2026-09-16 apx 批 T3 实测) **事实(实测,非推断)**:apx 批 T3 做了**突变双向**(把新能力改坏两次),**两种突变下 ELF canary + `.ccr` 四条全部 IDENTICAL**——而同期的 apx 探针组全部转红。 @@ -63,25 +63,25 @@ apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源** | 行为探针 29 档 | 该 29 档 | 其余形态 | **方法论含义(与本文件 §0/§0bis 并列的第三类问题)**: -- §0 = 断言写得弱(能被骗过)· §0bis = 探针没走到(不该绿却绿)· **本节 = 判据的覆盖域没写明(绿了但管不着那一块)**。 -- **头号危险是错觉**:「我们有 canary 所以放心」——canary 只对**它那两个语料**说话。 +- §0 = 断言写得弱(能被骗过)· §0bis = 探针未走到(不该绿却绿)· **本节 = 判据的覆盖域未写明(判据绿但覆盖不到该面)**。 +- **首要危险是错觉**:「已有 canary 即可放心」——canary 只对其覆盖的两个语料负责。 - **落地要求**:新增判据时**必须写明覆盖域与零覆盖域**(一行即可);**跨面回归必须由该面的判据承担**,不得以「canary 还绿着」代替(apx 批 T3 的突变实验就是这条的反证)。 **交叉引用**:apx 批计划 `docs/superpowers/plans/2026-09-16-apx-conversion-fix.md` §8(Global Constraints 注)· 批报告判据分工节(T7 落)。 -## 0bis. 第二类假绿:**探针不触发**(probe-doesn't-reach)(2026-09-16,apx 转换缺口批 T1 实测) +## 0bis. 第二类假绿:探针不触发(probe-doesn't-reach)(2026-09-16,apx 转换缺口批 T1 实测) -**本文 §0 命名的是第一类:片段式判据**——判据**断言写弱了**,能被坏实现骗过(断言在骗,探针本身走到了路径)。 -**本节的第二类与之正交**:**判据本身没问题,但探针根本没走到被测路径** ⇒ 同样产出**假绿**。 +**本文 §0 命名的是第一类:片段式判据**——判据断言写弱,能被坏实现骗过(问题在断言侧,探针本身已走到路径)。 +**本节的第二类与之正交**:判据本身无问题,但探针从未走到被测路径 ⇒ 同样产出**假绿**。 | 面 | 第一类(片段式判据) | 第二类(探针不触发) | |---|---|---| | **谁坏了** | **断言** | **探针 / 语料** | -| **为什么假绿** | 断言能被坏实现骗过(片段之间无约束) | 缺陷即使存在也必然显绿(被测路径压根没执行) | +| **为什么假绿** | 断言能被坏实现骗过(片段之间无约束) | 缺陷即使存在也必然显绿(被测路径从未执行) | | **修法** | 改**断言**(连续序列 / 定长 gap / 锚点窗口) | 改**探针**(让它真走到那条路径)+ **加覆盖面自证** | | **自检问句** | 「**什么坏实现能骗过这条断言?**」 | 「**我怎么知道探针走到了那条路径?**」 | -### 实证(**决定性,2026-09-16**):apx 探针的声明形 +### 实证(决定性,2026-09-16):apx 探针的声明形 apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源**统一**写作 `d : ., apx = 7.0;`(类型位用 `.` 推断 + `apx` 标签)。而 `ir_gen.cr:2388-2393` 的 apx 槽建立**以 `declared_ti == TI_DEX` 为前提**;类型位写 `.` 时 `declared_ti = TI_UNIT`(`:2377-2378`)⇒ apx 分支**整段不进** ⇒ 槽型回落 `TI_DEX_S` ⇒ **apx 标签对槽形式零作用,探针退化为普通精确 dex**。 ⇒ 该表十条**全部假绿**:不是断言写弱,而是**探针从未走到 apx 转换面**。 @@ -93,19 +93,19 @@ apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源** ### 实证(追加,2026-09-16 判据网加固批):两条同族实例 -本批把 §0bis 的问句**用在了判据自身上**,当场抓到两条同族假绿(都不是推论,是改强过程里撞出来的): +本批把 §0bis 的问句**用在判据自身上**,当场识别出两条同族假绿(均非推论,而是在改强过程中实测得到): **实例 1:判据内部的 `sub` 分支从未被走到(`test_mw_task2.py` 慢路径块体模板,#85/B6)** - 事实:块体模板加了 `is_sub` 分支断言(sub 站点块内多 3B `49 F7 D3` = `not r11`),而**原三例 `t1_add`/`t2_add_overflow`/`t3_bigfunc` 全是 add**(`x + 1`/`x + x`)⇒ 该分支在语料上**从未被走到**,断言即使写错也恒绿。 - 处置:加 `t4_sub_overflow`(`x = x - -4611686018427387904` ⇒ 2^63 正溢出)——sub 版块被真走到(`@O0/@O1/@O2` 三档 + 16B stdout 数值校验)。 - **判别法(可机械执行)**:**逐分支覆盖检查**——把判据里每个条件分支(`if is_sub` / `elif name == "store"` / 事件 id 集合 / 行类型分类…)列出来,逐个问「**哪条语料/哪个用例走到它?**」;答不出的分支 = 该分支断言**未被证明**(要么补语料,要么在注释里显式登记「本分支未覆盖」)。 -**实例 2:fail-closed 解码器当场抓到「未登记指令形态」(`test_mw_task2.py` `x86_insn_len`,#90/B1)** +**实例 2:fail-closed 解码器当场识别出「未登记指令形态」(`test_mw_task2.py` `x86_insn_len`,#90/B1)** - 事实:零 diff 腿的判据侧长度解码器上线首跑即**判红**——慢路径块首 `4D 19 DB`(`sbb r11,r11`)的 opcode `0x19` 未登记(`_OP_MODRM` 漏了 `0x11/0x19` 两个 ALU 双操作数 opcode)。 - 意义:这正是「宁可红不静默」的**现场实证**——若解码器当初写成「未知 opcode ⇒ 当 1 字节放过」或「未知 ⇒ 跳过」,这条缺口会**静默留在判据里**(正是 §0bis 要消灭的形态)。fail-closed(未知形态 ⇒ 抛错 ⇒ 判红)把「未覆盖面」变成了「必须处理的显式事件」。 - **判别法(同族)**:任何判据侧的「解码/解析/分类器」都应当 **fail-closed**:未登记形态 ⇒ 红,而不是 `continue`/`pass`/默认值。判据的**未覆盖面**必须响,不得静默。 -### 通用判别法(**写探针时的必答题,与 §0 的反例问句配对**) +### 通用判别法(写探针时的必答题,与 §0 的反例问句配对) > **「我怎么知道探针走到了那条路径?」** @@ -117,7 +117,7 @@ apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源** **登记去向**:`TODO.md` 的判据类登记面(见 §5;本小节由 apx 批 T1 追加,**不改变本文 §1/§2 的任何既有结论**)。 -## 0ter 判据覆盖域:**canary 的正交性**(2026-09-16 apx 批 T3 实测) +## 0ter 判据覆盖域:canary 的正交性(2026-09-16 apx 批 T3 实测) **事实(实测,非推断)**:apx 批 T3 做了**突变双向**(把新能力改坏两次),**两种突变下 ELF canary + `.ccr` 四条全部 IDENTICAL**——而同期的 apx 探针组全部转红。 @@ -131,26 +131,26 @@ apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源** | 行为探针 29 档 | 该 29 档 | 其余形态 | **方法论含义(与本文件 §0/§0bis 并列的第三类问题)**: -- §0 = 断言写得弱(能被骗过)· §0bis = 探针没走到(不该绿却绿)· **本节 = 判据的覆盖域没写明(绿了但管不着那一块)**。 -- **头号危险是错觉**:「我们有 canary 所以放心」——canary 只对**它那两个语料**说话。 +- §0 = 断言写得弱(能被骗过)· §0bis = 探针未走到(不该绿却绿)· **本节 = 判据的覆盖域未写明(判据绿但覆盖不到该面)**。 +- **首要危险是错觉**:「已有 canary 即可放心」——canary 只对其覆盖的两个语料负责。 - **落地要求**:新增判据时**必须写明覆盖域与零覆盖域**(一行即可);**跨面回归必须由该面的判据承担**,不得以「canary 还绿着」代替(apx 批 T3 的突变实验就是这条的反证)。 **交叉引用**:apx 批计划 `docs/superpowers/plans/2026-09-16-apx-conversion-fix.md` §8(Global Constraints 注)· 批报告判据分工节(T7 落)。 -### 0quater 「**新增诊断 ≠ 修好**」**已被证明会工作**(2026-09-16 #93 批实证) +### 0quater 「新增诊断 ≠ 修好」的成立实证(2026-09-16 #93 批) **机制**:一次**修改触发面**(补实参推断)会**同时**带来两类结果——① 真修好(原本静默的错被报出/被修)② **新引入误报**(原本合法的写法被判错)。二者在「诊断计数」上**不可区分** ⇒ 若用「新增诊断数上升」当修好证据,**必然把误报一起记成修好**。 **实证(#93 批 T4)**:该批修好实参推断后,74 档 rc 逐档不变、码集变化 11 档**逐条归因全部「本来就该报」**(零误报)——**但**另两条载体变红:`tests/probes/p_spawn.cr`(29 探针之一)rc 0→1、`tests/selfhost/test_interp_parity.py`(已挂 CI)23/23→22/23。 根因 = **`go i a..b body` 的迭代变量在 checker 里从未绑定**(checker 缺口,此前被「实参从不被推断」这个 bug 掩盖)⇒ 修好推断后**暴露为 N01 误报**。 -⇒ **若按「新增诊断一律算修好」,这两处红会被记为修好**——而该批的**腿 C 纪律**(逐条归因 + **不许把新增诊断一律当修好**)**当场抓到了它**,遂停下取裁、补绑定、复验回归。 +⇒ **若按「新增诊断一律算修好」,这两处红会被记为修好**——而该批的**腿 C 纪律**(逐条归因 + **不得把新增诊断一律当修好**)**当场识别出该形态**,遂停下取裁、补绑定、复验回归。 **落地要求(与 §0/§0bis/§0ter 并列的第四条)**: -> **凡是「改判定触发面」的批次,判据必须**把「新增诊断」默认按**回归嫌疑**处理**,逐条归因到「本来就该报」才计入修好;**且必须有「原载体回归」这一判据**(本例 = 29 探针 + 已挂套件的 rc 基线),因为**新形态的断言不等价于原载体的断言**。 +> 凡是「改判定触发面」的批次,判据必须把「新增诊断」默认按**回归嫌疑**处理,逐条归因到「本来就该报」才计入修好;**且必须有「原载体回归」这一判据**(本例 = 29 探针 + 已挂套件的 rc 基线),因为**新形态的断言不等价于原载体的断言**。 **出处**:`docs/superpowers/plans/2026-09-16-arg-inference-fix.md` §3ter · §3quater · §3quinquies · `TODO.md #93` 追记 4。 -## 1. 表 A:字节级/序列级断言清单(22 条;坐标为**当前**实读) +## 1. 表 A:字节级/序列级断言清单(22 条;坐标为当前实读) | # | 对象 | 判据(要点) | 强度 | |---|---|---|---| @@ -185,10 +185,10 @@ apx 审计(`2026-09-16-apx-conversion-audit.md`)表 B 的十条探针源** | **B2** | `test_hit_table.py:1220`(`stream[:2]`)| 只比 REX+opcode 两字节;**整条指令面**(modrm/sib/disp 及其后)无字节证据 | 改 `src/arch/x86_64/core-x86.toml`:事件 1(sub)`modrm_reg_role` `"dst"→"src1"`,或 `modrm_rm_role` `"src2"→"dst"`,或 `opcode = [0x4D,0x29,0x90]` 尾加一字节 ⇒ **均绿**(walker 只校验角色名 ∈ 白名单 `:1020-1025` 与 opcode 1..3B)| **无**(同文件自注 `:344-346`:sub/nand 事件在现架构对真 IR **不可达** ⇒ 注入逐字节对照 A7 与运行闭环都碰不到事件 1-4)| | **B3** | `test_hit_table.py:281`(**引文锚**:`bad = [s for s in ("dst=255", "s2=255", "dst=-1", "s2=-1") if s in out]`;`:284` 为 `if bad:` 分支邻域)| 未用标记值字段的检查 = **4 字面量黑名单** | 未用字段写 `1` 或 `0xFE`(−2) ⇒ 不出现 `255/-1` 字面 ⇒ **绿** | 无(该字段无消费者 ⇒ 危害低)| | **B4** | `test_cir_warm_path.py:176-197` + `test_ccr_v7.py:1853` | STR 段冷/暖**显式豁免**(只登记尺寸)+ 前缀判据 | 冷态 `str_intern` 把某名字写坏(长度/顺序不变、该串**不进发射面**)⇒ 七段全等 + ELF 全字节等仍成立 ⇒ **绿** | **部分**(ELF 全字节等仅在串入发射面时咬)| -| **B5** | `test_ccr_types.py:1777` | `--dump-tk-terms` stdout **剔行后**比对 | 多打印一行 `123\t…` 形态数据行 ⇒ 被 `stripped` 吃掉 ⇒ **绿** | 产物面有(`:1773` `dot_flag == dot_plain`);stdout 面无 | +| **B5** | `test_ccr_types.py:1777` | `--dump-tk-terms` stdout **剔行后**比对 | 多打印一行 `123\t…` 形态数据行 ⇒ 被 `stripped` 过滤掉 ⇒ **绿** | 产物面有(`:1773` `dot_flag == dot_plain`);stdout 面无 | | **B6** | `test_mw_task2.py:242` | 慢路径块**只有 2B 锚** `4D 19`(`sbb r11,r11`,**不含 ModRM**)| `4D 19` 后插 `90`,或 ModRM 换行为等价编码(块体字节全变)⇒ 锚命中、行为不变 ⇒ **绿** | **有行为兜底**(A6:t2–t6 的 16B stdout 覆盖全部被语料触发的溢出形态);漏洞限「未触发形态的块体字节漂移」| -**判为「实为强」(不凑数,勿计为弱)**:`test_mw_task2.py:120-127` 尾声 `find(tail)`(2B needle,模板由 oracle 帧字节构造 ⇒ 误配只会截短 ⇒ jo 数低于 oracle ⇒ 红)· `test_hit_table.py:1424-1425`(十进制前缀必随掩码漂移)· `test_global_seams.py:230`(残余 = 全文件**存在性**:命中 ≠ 命中在真实站点,属该形态通用极限)。 +**判为「实为强」的条目(不计入弱判据)**:`test_mw_task2.py:120-127` 尾声 `find(tail)`(2B needle,模板由 oracle 帧字节构造 ⇒ 误配只会截短 ⇒ jo 数低于 oracle ⇒ 红)· `test_hit_table.py:1424-1425`(十进制前缀必随掩码漂移)· `test_global_seams.py:230`(残余 = 全文件**存在性**:命中 ≠ 命中在真实站点,属该形态通用极限)。 ## 3. 表 C:兜底网盘点(05:58 后状态) diff --git a/docs/superpowers/specs/2026-09-16-opt-rep-batch-report.md b/docs/superpowers/specs/2026-09-16-opt-rep-batch-report.md index cc61ce8f..557e790d 100644 --- a/docs/superpowers/specs/2026-09-16-opt-rep-batch-report.md +++ b/docs/superpowers/specs/2026-09-16-opt-rep-batch-report.md @@ -54,7 +54,7 @@ ## 6. 过程事故与教训 1. **工作副本 stale 事故(零损失,两次实证)**:**他方推进 op log ⇒ 别的 workspace 会 stale**;`jj workspace update-stale` 会**以 op log 重建工作目录**、**未快照文件不留痕**(首现于 T2 计划文件,造成一次重写;T3/T5 两次因**先备份到仓库外**而零损失)。**纪律**:stale 前先 `jj status` 快照,或先把未快照文件备份到仓库外;产出即路径限定提交(「未被快照的文件不算存在」)。 -2. **「值面登记 ≠ 绑定 var 登记」**:T3 首版修法无效(登记落在**值 var**、写点读**绑定 var**),由突变 M_T3_3 咬出。 +2. **「值面登记 ≠ 绑定 var 登记」**:T3 首版修法无效(登记落在**值 var**、写点读**绑定 var**),由突变 M_T3_3 暴露。 3. **零足迹纪律**:新增类型面查询必须先核是否 `alloc_type`(T2 曾因未门控使非可选 `.ccr` +168B);本批全部新增面首判 `g_optrep_on` + 仅可选面登记 ⇒ canary/`.ccr` 全程不变。 ## 7. 交付物 diff --git a/docs/superpowers/specs/2026-09-28-doc-tone-normalization-design.md b/docs/superpowers/specs/2026-09-28-doc-tone-normalization-design.md new file mode 100644 index 00000000..5fa8ea1e --- /dev/null +++ b/docs/superpowers/specs/2026-09-28-doc-tone-normalization-design.md @@ -0,0 +1,86 @@ +# 文档文风规范设计 + +日期:2026-09-28 +状态:草稿,待批准 + +## 为什么 + +Core 的文档已经有两套规矩:按读者分的目录树,和每篇开头的定位声明(受众 / 状态 / 真源)。缺的是怎么写。 + +问题有三类。 + +一是用命令口吻。`CLAUDE.md` 写「不许」「禁止」,还写明违反的后果。 + +二是拿比喻当名词用。判据叫「有牙」,执行分支叫「腿」,没修的缺陷叫「还活着」,关掉的条目叫「划销」。这些词当术语在用,却多数没有定义。 + +三是满屏符号。方括号标签「【高危·预存】」、`⚠`、`✅`、平均每行一次的粗体。 + +以前清过一次。`CHANGELOG.md` 里留着那次记录:`tone down chuunibyou conclusions`、`remove conversational/promotional language`。那次清的是宣传式的写法,且只清了 `docs/`。现在多出来的是审计式的写法,主要在 `TODO.md` 和 `docs/superpowers/`。 + +## 写成什么样 + +照 LLVM 写。三个特征: + +**用陈述句。** 规则说出来,后面跟理由,三句讲完: + +> There are some conventions that are not uniformly followed in the code base (e.g. the naming convention). This is because they are relatively new, and a lot of code was written before they were put in place. Our long-term goal is for the entire codebase to follow the convention, but we explicitly do not want patches that do large-scale reformatting of existing code. + +**不修饰。** LLVM 九篇正文约两万行,没有 emoji,没有 `⚠`;感叹号 23 个,几乎都在代码和网址里。要提醒读者就写 `Note`、`Warning`。 + +**旧结论不划掉。** 废弃的命名在正文里平铺一句(`In the past, this namespace had only the name GR …`)。删除线和审计批注交给版本控制。 + +## 规范 + +写 `docs/doc-style.md`,一页以内,用上面那种写法写。内容: + +- 用陈述句。规则后面跟理由。 +- 不写「不许」「禁止」,也不写违反的后果。 +- 比喻不当术语。一个概念要反复用,第一次出现时给定义,之后当普通词用。 +- 不用 emoji、`⚠`、`✅` 和方括号标签。要提醒时写「注:」「重要:」「警告:」。 +- 标题不加编号,标题说明这节讲什么。 +- 中文正文用全角标点(`,` `:` `;`),代码、标识符和英文串里用半角。 +- 旧的结论用带日期的说明留住,不划删除线。 +- 保留现有的定位声明、真源条款和分类树。这几项本仓比 LLVM 做得好。 + +## 怎么做 + +1. 写 `docs/doc-style.md`。 +2. 先改三份,用它们试出规范哪里不对: + - `docs/developer/syntax.md`(现状已较接近) + - `docs/maintainer/design/execution-model.md`(半角标点) + - `docs/superpowers/plans/2026-09-16-criteria-carrier.md`(审计式写法最重) + + 改的时候发现规范写得不对,就回头改规范。 +3. 其余按目录依次改:根目录和 `docs/developer` → `docs/maintainer` → `docs/academic` 等零散目录 → `docs/superpowers` → `docs/pseudocode`。 +4. 每改完一批通读一遍,开 PR 给人看。 + +像不像工程文档,要人读了才算,不加自动检查。只有文档之间的链接需要机器确认,改完看链接目标还在不在。 + +## CLAUDE.md + +它同时是给 AI 的指令和机械门的载体,跟别的文档不一样。写法照改,但下面这些一字不动: + +- 铁律的标题和 #1–#6 编号。`tools/baseline/canary_check.sh:22` 按编号引用「铁律 6」。 +- `TODO #2026-09-10-3` 的引用形式,在 `elf.cr` 死文件那一条里。`tests/harness/test_todo_id_migration.py` 的 J4 用例取自这里。 +- `jj` / `git` 禁令的意思。`.claude/hooks/block-git.py` 管着这一面。 +- 各机械门的命令、路径和计数。 + +改完跑这两个测试确认没坏: + +```bash +python3 tests/harness/test_todo_id_migration.py +python3 tests/harness/test_block_git.py +``` + +## 范围 + +文字和内容分两次改。第一次只改文字:事实、数字、结论、链接目标、`file:line`、提交 sha 都不动。文档里跟实现不符的说法,按 `2026-09-16-doc-reality-audit.md` 的 35 条另开一次改。两类改动混在一个 diff 里没法审。 + +`docs/pseudocode/` 由源码生成(`tools/pseudocode_check.py`),改之前先看生成器是不是也产出这些文字。 + +`.superpowers/sdd/` 下的 321 份不在范围内。它们没进版本控制,是 SDD 工具的暂存区。 + +## 待定 + +1. 标点按全角。`glossary.md` 已经是这个分工:中文说明用全角,代码和标识符用半角。 +2. 改内容另开一次,不跟改文字一起做。 diff --git a/docs/z-vision.md b/docs/z-vision.md index 9b12563c..b6b5749e 100644 --- a/docs/z-vision.md +++ b/docs/z-vision.md @@ -1,8 +1,8 @@ -# Core 愿景(Vision) +# Core 愿景(Vision) -> 定位:受众 = 所有读者(开发者/维护者/学术);状态 = active;本文件是愿景陈述,技术细节以各 design 文档为准。 +> 定位:受众 = 所有读者(开发者/维护者/学术);状态 = active;本文件是愿景陈述,技术细节以各 design 文档为准。 -> 本文件是 Core 的长期目标陈述——"为什么存在"。技术细节见各设计文档;进度见 TODO.md。 +> 本文件是 Core 的长期目标陈述——回答"为什么存在"。技术细节见各设计文档;进度见 `TODO.md`。 --- @@ -22,7 +22,7 @@ **Core 的路径**:规约用 Core 语言本身书写(`#check`/`#ensure`/`spec fn`,不需要学数理逻辑),编译器经翻译桥自动编译进 CIC 项,健全性由 CIC 内核 + SMT 证书保证。用户写意图,编译器管证明。 -**状态**:设计完成(spec-design v2),**0 实现**——requires/ensures 语法已入 .cr(独立 .corespec 格式 2026-09 退役,见 maintainer/adr/adr-0001),.csr、翻译桥、内核绑定待推进。 +**状态**:设计完成(spec-design v2),**0 实现**——requires/ensures 语法已入 `.cr`(独立 `.corespec` 格式 2026-09 退役,见 `docs/maintainer/adr/adr-0001`),`.csr`、翻译桥、内核绑定待推进。 ## 目标三:一门语言覆盖从零基础到系统编程的完整路径 @@ -30,22 +30,22 @@ **Core 的路径**:渐进式学习路径——同一门语言从基础(DAG)到系统编程(字节级 + 并发 + 规约),概念只增不减,无模式切换(见 `docs/developer/tutorial.md`)。 -**状态**:语言本体已实现(自举成功、ELF 后端、apx 后端快路径(binary64)、并发、指针三 pass)。 +**状态**:语言本体已实现——自举成功、ELF 后端、apx 后端快路径(binary64)、并发、指针三 pass。 --- -## 为什么现在做(技术背景) +## 技术背景(推进时机) -- **语义保鲜**:CompCert 已证明"保留语义的编译"可行(其正确性定理即 semantic preservation)——Core 把它从"编译器的证明目标"变成"语言的设计目标" -- **验证平民化**:SMT 求解器成熟(Z3/veriT),证书化验证有先例(SMTCoq:求解器不可信、健全性在内核)——门槛降低的技术前提已具备 -- **范式多元化趋势**:量子/异构硬件在演进——范式无关的语义层是尚未被占据的位置(现有语言都绑定经典执行模型) +- **语义保鲜**:CompCert 已证明"保留语义的编译"可行(其正确性定理即 semantic preservation)——Core 把它从"编译器的证明目标"变成"语言的设计目标"。 +- **验证平民化**:SMT 求解器成熟(Z3/veriT),证书化验证有先例(SMTCoq:求解器不可信、健全性在内核)——门槛降低的技术前提已具备。 +- **范式多元化趋势**:量子/异构硬件在演进——范式无关的语义层是尚未被占据的位置(现有语言都绑定经典执行模型)。 -## 边界(不是承诺) +## 边界(非承诺) -- 量子等新范式的实用化时间不在 Core 控制内;Core 保证的是"图准备好了",不是"范式会来" -- 验证体系(目标二)当前为设计态,落地时间取决于推进 -- 分布式/概率 pass 为设计态(见对应文档) -- 本文件描述长期目标;当前可用的能力以语言本体为准(自举、ELF、并发、指针安全) +- 量子等新范式的实用化时间不在 Core 控制内;Core 保证的是"图准备好了",不是"范式会来"。 +- 验证体系(目标二)当前为设计态,落地时间取决于推进。 +- 分布式/概率 pass 为设计态(见对应文档)。 +- 本文件描述长期目标;当前可用的能力以语言本体为准(自举、ELF、并发、指针安全)。 --- diff --git a/editor/README.md b/editor/README.md index 6ba0b6b2..b4ae93fe 100644 --- a/editor/README.md +++ b/editor/README.md @@ -19,7 +19,7 @@ cp -r editor/nvim/plugin/*.lua ~/.config/nvim/lua/plugins/ | 功能 | 触发方式 | 说明 | |------|----------|------| | 语法高亮 | 自动 | `.cr`/`.cir`/`.ccr` 文件 | -| 代码补全 | 自动 | blink.cmp 关键字 + types | +| 代码补全 | 自动 | `blink.cmp` 关键字 + types | | 代码片段 | `fn` `struct` 等 | 共 20+ 片段 | | 诊断 | 保存时自动 | 编译器错误显示在行内 | | Quickfix | `:make` | 编译结果 + 错误列表 | @@ -31,7 +31,7 @@ cp -r editor/nvim/plugin/*.lua ~/.config/nvim/lua/plugins/ ### 错误诊断格式 -编译器输出 `error CODE: MSG` → `--> LINE:COL` 会被自动解析为: +编译器输出的 `error CODE: MSG` 与 `--> LINE:COL` 由插件自动解析。 ## VS Code @@ -41,7 +41,7 @@ cp -r editor/nvim/plugin/*.lua ~/.config/nvim/lua/plugins/ code --install-extension editor/vscode-core/ ``` -或从 VS Code 插件市场搜索 "core-lang"。 +也可从 VS Code 插件市场搜索 `core-lang` 安装。 ## 项目仓库 diff --git a/grammar/core.ebnf b/grammar/core.ebnf index c703d287..1674fcd8 100644 --- a/grammar/core.ebnf +++ b/grammar/core.ebnf @@ -1,27 +1,30 @@ (*** 顶层结构 ***) CompilationUnit = { FileIdDecl | ModuleDecl | ImportDecl } { TopLevelDecl } ; -FileIdDecl = 'fileid' STRING_LIT ';' ; -ModuleDecl = 'mod' Path ';' ; -ImportDecl = 'import' [ '@' IDENT ] IDENT [ ':' IDENT ] ';' ; +FileIdDecl = 'fileid' STRING_LIT ; +ModuleDecl = 'mod' Path ; +ImportDecl = 'import' [ '@' IDENT ] IDENT [ ':' IDENT ] ; Path = IDENT { '::' IDENT } ; TopLevelDecl = FunctionDecl | FlowDecl | StructDecl | EnumDecl | InterfaceDecl | ImplDecl | TypeAlias ; (*** 函数 ***) -FunctionDecl = [ 'pub' ] 'fn' IDENT [ GenericParams ] '(' [ ParamList ] ')' '->' Type - { Annotation } - ( FunctionBody | '=' Expr ';' ) ; +(* v4:函数体 = 签名后 `:` + layout region;规约标注(批 6)位于 region 开头, + 产生式统一用 Annotation(见下方「规约标注」节),不再另立 VerificationAnnotation。 *) +FunctionDecl = [ 'pub' ] 'fn' IDENT '(' [ ParamList ] ')' [ '->' Type ] ':' + FunctionLayout ; + +FunctionLayout = { Annotation } { Statement } ; +SpecExpr = ( QuantifiedSpec | LogicalOr ) [ '==>' SpecExpr ] ; +QuantifiedSpec = ( 'forall' | 'exists' ) '(' IDENT ':' Type ')' '=>' SpecExpr ; GenericParams = '[' IDENT { ',' IDENT } ']' ; ParamList = Param { ',' Param } ; Param = IDENT ':' Type ; -FunctionBody = Block ; +FlowDecl = 'flow' IDENT '(' [ ParamList ] ')' [ '->' Type ] ':' FlowLayout ; -FlowDecl = 'flow' IDENT [ GenericParams ] '(' [ ParamList ] ')' '->' Type - { Annotation } - ( FunctionBody | '=' Expr ';' ) ; +FlowLayout = { Annotation } { Statement } ; (*** 规约标注(批 6;2026-09-17 正式接入)***) (* 位置 = **签名之后、body 之前**(spec-design §四);可多条,按源序。 @@ -32,10 +35,11 @@ FlowDecl = 'flow' IDENT [ GenericParams ] '(' [ ParamList ] ')' '->' Type 语义:标注**不影响运行时**(不产 IR;裁-S4「不编图」)——本刀只登记 + 常量折叠判定, 未证(yellow)不阻断编译;唯一硬错 = `#check(常量假)` ⇒ error[V01]。见 docs/superpowers/plans/2026-09-17-spec-grammar.md。 *) -Annotation = ANNOT_HASH IDENT '(' Expr ')' ; +Annotation = ANNOT_HASH IDENT '(' SpecExpr ')' ; (*** 类型 ***) -Type = BaseType | PathType | RefType | OptionalType | TupleType | ArrayType | SliceType ; +Type = BaseType | PathType | RefType | PtrType | OptionalType | FunctionType + | TupleType | ArrayType | SliceType | '.' | 'auto' | TypeOf ; (* 注:'Self' 非词法关键字——lexer.cr lookup_keyword() 无 Self,按标识符解析; 接口方法签名中的 Self 由 checker 按上下文处理,以源码实现为准 *) BaseType = 'int' | 'dex' | 'bool' | 'string' | 'char' | 'unit' | 'never' | 'Self' ; @@ -43,16 +47,19 @@ BaseType = 'int' | 'dex' | 'bool' | 'string' | 'char' | 'unit' | 'never' | 'Self 'apx' 标签(近似授权,后端 binary64 快路径) *) PathType = Path ; RefType = '&' [ 'mut' ] Type ; +PtrType = '*' Type ; OptionalType = Type '?' ; +FunctionType = 'fn' '(' [ Type { ',' Type } ] ')' '->' Type ; +TypeOf = 'typeof' '(' Expr ')' ; TupleType = '(' [ Type { ',' Type } ] ')' ; ArrayType = '[' Type ';' INT_LIT ']' ; SliceType = '[' Type ']' ; (*** 表达式 ***) Expr = Assignment | LogicalOr ; -Assignment = [ Let | Move ] LogicalOr [ '=' LogicalOr ] ; +Assignment = [ Let ] Pipeline [ '=' Pipeline ] ; Let = IDENT [ ':' ( Type | 'auto' | '.' ) [ ',' Tag { ',' Tag } ] ] ( ':=' | '=' ) ; -Move = 'move' IDENT '=' ; +Pipeline = LogicalOr { '|>' LogicalOr } ; LogicalOr = LogicalAnd { '||' LogicalAnd } ; LogicalAnd = Equality { '&&' Equality } ; @@ -61,8 +68,8 @@ Comparison = Addition { ('<' | '>' | '<=' | '>=') Addition } ; Addition = Multiplication { ('+' | '-') Multiplication } ; Multiplication = Unary { ('*' | '/' | '%') Unary } ; Unary = ('-' | '!' | '&' | '&mut') Unary | CallOrField ; -CallOrField = Primary { '(' [ ArgList ] ')' | '.' IDENT | '[' Expr ']' | '?' } ; -Primary = Literal | IDENT | ProjectAccess | '(' Expr ')' | 'move' Primary | BlockExpr | IfExpr | MatchExpr | LoopExpr | ForExpr | GoExpr | AwaitExpr | UnsafeExpr ; +CallOrField = Primary { '(' [ ArgList ] ')' | '.' IDENT | '[' Expr ']' } ; +Primary = Literal | IDENT | ProjectAccess | '(' Expr ')' | LambdaExpr | IfExpr | MatchExpr | LoopExpr | ForExpr | GoExpr | AwaitExpr | UnsafeExpr ; ProjectAccess = '@' IDENT IDENT '::' IDENT ; ArgList = Expr { ',' Expr } ; @@ -71,47 +78,52 @@ ArgList = Expr { ',' Expr } ; 定点小数,数值迁移 Task 4);f32/f64 后缀已退役(2026-09-10 语言面收窄 §2)——词法 对数字字面量的字母后缀一律响亮报错,宽度 = 机器形状,归映射层(数值类型设计, 2026-08-16) *) -Literal = INT_LIT | DEX_LIT | STRING_LIT | CHAR_LIT | BOOL_LIT | UNIT_LIT | 'None' | 'Some' '(' Expr ')' ; -BlockExpr = Block ; -IfExpr = 'if' Expr Block [ 'else' ( Block | IfExpr ) ] ; -MatchExpr = 'match' Expr '{' MatchArm { ',' MatchArm } '}' ; -MatchArm = Pattern '=>' Expr ; +Literal = INT_LIT | DEX_LIT | STRING_LIT | CHAR_LIT | BOOL_LIT | UNIT_LIT | 'none' ; +LambdaExpr = 'fn' '(' [ ParamList ] ')' [ '->' Type ] ( '=>' Expr | ':' Layout ) ; +IfExpr = 'if' Expr ':' Layout [ 'else' ( IfExpr | ':' Layout ) ] ; +MatchExpr = 'match' Expr ':' MatchLayout ; +MatchLayout = MatchArm { MatchArm } ; +MatchArm = '|' Pattern '=>' ( Expr | Layout ) ; Pattern = Literal | IDENT | TuplePattern | StructPattern | EnumPattern | '_' ; TuplePattern = '(' [ Pattern { ',' Pattern } ] ')' ; StructPattern = Path '{' [ FieldPattern { ',' FieldPattern } ] '}' ; FieldPattern = IDENT '=' Pattern ; EnumPattern = Path '(' [ Pattern { ',' Pattern } ] ')' | Path ; -LoopExpr = 'loop' Block ; -ForExpr = 'for' IDENT 'in' Expr Block ; +LoopExpr = 'loop' ':' LoopLayout ; +LoopLayout = { LoopVerification } { Statement } ; +LoopVerification = '#' ( 'invariant' | 'variant' ) '(' SpecExpr ')' ; +ForExpr = 'for' IDENT 'in' Expr ':' LoopLayout ; GoExpr = 'go' Expr ; AwaitExpr = 'await' Expr ; -UnsafeExpr = 'unsafe' Block ; +UnsafeExpr = 'unsafe' ':' Layout ; -Block = '{' { Statement } '}' ; -Statement = Expr ';' | LetStmt | ReturnStmt | YieldStmt | BreakStmt | ContinueStmt ; +(* Layout is established by ':' plus relative indentation. The first child + establishes the sibling anchor; a shallower column closes the region. *) +Layout = { Statement } ; +Statement = Expr | LetStmt | ReturnStmt | YieldStmt | BreakStmt | ContinueStmt ; -LetStmt = IDENT [ ':' ( Type | 'auto' | '.' ) [ ',' Tag { ',' Tag } ] ] ( ':=' | '=' ) Expr ';' ; +LetStmt = IDENT [ ':' ( Type | 'auto' | '.' ) [ ',' Tag { ',' Tag } ] ] ( ':=' | '=' ) Expr ; (* 变量标签:mut 可变 / pub 公开 / apx 近似授权(后端变换许可,与 mut/pub 同族—— 数值类型设计 2026-08-16) *) Tag = 'mut' | 'pub' | 'apx' ; -ReturnStmt = 'return' [ Expr ] ';' ; -YieldStmt = 'yield' Expr ';' ; -BreakStmt = 'break' ';' ; -ContinueStmt = 'continue' ';' ; +ReturnStmt = 'return' [ Expr ] ; +YieldStmt = 'yield' Expr ; +BreakStmt = 'break' ; +ContinueStmt = 'continue' ; (*** 复合类型声明 ***) -StructDecl = [ 'pub' ] 'struct' IDENT GenericParams? '{' { FieldDecl ',' } '}' ; +StructDecl = [ 'pub' ] 'struct' IDENT ':' { FieldDecl } ; FieldDecl = IDENT ':' Type ; -EnumDecl = [ 'pub' ] 'enum' IDENT GenericParams? '{' Variant { ',' Variant } '}' ; +EnumDecl = [ 'pub' ] 'enum' IDENT ':' { '|' Variant } ; Variant = IDENT [ '(' Type { ',' Type } ')' ] ; -InterfaceDecl = [ 'pub' ] 'interface' IDENT GenericParams? '{' { InterfaceMethod ';' } '}' ; +InterfaceDecl = [ 'pub' ] 'interface' IDENT ':' { InterfaceMethod } ; InterfaceMethod = 'fn' IDENT '(' [ ParamList ] ')' '->' Type ; -ImplDecl = 'impl' [ GenericParams? ] Path [ 'for' Path ] '{' { FunctionDecl } '}' ; +ImplDecl = 'impl' Path [ 'for' Path ] ':' { FunctionDecl } ; -TypeAlias = 'type' IDENT '=' Type ';' ; \ No newline at end of file +TypeAlias = 'type' IDENT '=' Type ; diff --git a/tests/bootstrap/test_pipeline.py b/tests/bootstrap/test_pipeline.py index 6ec728ae..8c4c7b1a 100644 --- a/tests/bootstrap/test_pipeline.py +++ b/tests/bootstrap/test_pipeline.py @@ -98,6 +98,57 @@ def test_raw(name, src, expected): } ''', 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 { @@ -272,6 +323,14 @@ def test_raw(name, src, expected): } ''', 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 { 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/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/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/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/tools/baseline/REBUILD.md b/tools/baseline/REBUILD.md index 1d5d2817..bf3ce410 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 + 日志;档数=**实读枚举**: 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..c351ae1e --- /dev/null +++ b/tools/v4_frontend_probe.py @@ -0,0 +1,835 @@ +#!/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 io +import os +import re +import subprocess +import sys + +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 + +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, 'all': 60, +} + + +# ── 全管线(与 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` 表(抽法沿用施工计划 §十二 的脚本)。""" + blk = text[text.index('fn lookup_keyword'):] + blk = blk[:blk.index('\n}\n') + 3] + 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 + + +# ── 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 ('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)) From 87fdcb29a717baf1165fdaaa725e43a329f9eb1a Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 17:08:24 +0800 Subject: [PATCH 02/15] =?UTF-8?q?v4=20=E8=BF=81=E7=A7=BB=EF=BC=88=E6=89=B9?= =?UTF-8?q?=E5=86=85=C2=B7=E7=AC=AC=E4=BA=8C=E7=AC=94=EF=BC=89=EF=BC=9AT4?= =?UTF-8?q?=20=E8=AF=AD=E6=96=99=E6=94=B9=E5=86=99=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E2=80=94=E2=80=94src=20=E5=85=A8=2092=20=E6=A1=A3=EF=BC=8C85?= =?UTF-8?q?=20=E8=BF=81=E7=A7=BB=20/=206=20no-op=20/=201=20=E6=AD=BB?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 工具(一次性迁移工具,非常设判据):tools/v4_migrate.py + tools/v4_migrate_v3lex.py(vendored v3 扫描器) ## 结果(92 档 = src/**/*.cr 全量) - **85 档已迁移**(内容改变)· **6 档 no-op**(本就无 {} / ;,v4 形与 v3 形逐字节同: compiler/_import.cr · linker.cr(0 字节) · regalloc-consistency.cr · lsp/_import.cr · stdlib/_import.cr · targets/x86_64-linux/_import.cr)· **1 档未迁移**(compiler/elf.cr)。 ## 判据读数 - **V1(v4 前端解析,最强)**:91/92 过;唯一挂的恰是未迁移的 elf.cr。我**独立复跑**确认同一读数。 三条反向突变(region 头缩进错 / 删 `:` / sibling 错位)全红 ⇒ J-T4-3 由 V1 直接兜住。 - **V2(只改形状的证明)**:76 档**逐 token(类型名, 词素)完全相同**(我另抽检 fmt.cr 1507 token / checker.cr 21361 token 独立复核 = IDENTICAL);9 档的差异**恰为**本笔裁定的显式改写, 逐条 difflib 可读:dyn_arr 1 · parser 7 · ld 14 · cli 4(unsafe 上提 + return 补写)· interp 4 · main 1 · module 1 · opt 1 · provenance_verify 1(空 region 裁决,全是纯 delete)。 口径补正(采纳):不能一把抓全丢 `;`/`{}` —— `[T; N]` 的 `;` 与 struct 字面量的 `{}` 必须保留; v4 侧的块开是 `COLON_BLOCK`,也须列入丢弃集。首轮不做此区分时假红 701/38 项。 - **V3(计数)**:`{`/`}` token 级 11,378 → **1**(只剩 src/stdlib/toml.cr:268 的 struct 字面量); `;` 29,556 → **16**(全是 src/stdlib/collections.cr 的 `[T; N]`)。 - **V4a 注释行:10,289 → 10,636(↑,0 档下降)· V4b 空行:2,583 → 2,596(↑,0 档下降)**。 ⇒ V4b 是本笔**新增的判据面**:我抽检 fmt.cr 时抓到空行被吞(17→6,`}` 行消失时把相邻空行一起吃了), 要求修(根因两条:`_plain_gap` 连续换行吞行 + EOF 收尾少一个 `\n`)并扩成 A/B 双读数。 ## 本笔裁定(附理由,逐条留痕) - **空 region 12 处 / 7 档**(计划只记 3 处——「只含注释的块」与 `{ }` 在 token 面不可区分): 5 处按规则自处理(无 else 且条件纯局部量的 `if … { }` 整条删;只含注释的函数体补匹配返回类型的显式 `return`); 7 处逐条裁定后全批(if/else-if 链整条删 · `if str_len(…) > 0 { }` 整条删(str_len = fmt.cr:4-8 纯读取, 我实核)· 空 `else` 从句单独摘除)。 **已知偏差**:main.cr:21 / module.cr:172 删掉的条件各含一次内存读 ⇒ 无效指针下原式会陷阱而删后不会; 列为 B1/B2 建起来后的重点核对项。 - **`unsafe { … }` 作值 10 处 / 3 档**(ld 6 · cli 2 · parser 2):v4 里 unsafe 是 region(语句位), 实参位是表达式位 ⇒ 原式非法。前端加「**region 作声明右值**」后机械上提临时量(10 处全为单个 `@str_of`/`@ptr_of`),求值次数与副作用次序逐条论证保持。 - **elf.cr 不迁移**:死文件(三面清单皆无)+ v3 下也解析不过(86/375/380/388 行各缺一个 `)`)+ J4 载体。 ## 前端与文档的配套改动(本笔) - `bootstrap/corec/frontend/parser.py`:`_at_line_end()` 增**第三态**「prev == DEDENT 即行边界」 ⇒ `x := unsafe: …` 这类以 region 收尾的声明可解析(实测 OK)。 - `docs/core-language-syntax_v4.md` §4.1:新增「region 作声明右值」(含反向不成立:`f(unsafe: …)` 非法)。 - `docs/maintainer/design/v4-layout-spec.md` §10:T0 补遗三节(括号外续行非法 · 空 region 无法表达 + 裁定与留痕 · region 作右值),逐条带施工期实测。 - `tools/v4_frontend_probe.py`:修 `selfhost_keywords` 抽取(原按 `\n}\n` 切块,v4 形下当场 ValueError)。 - `docs/superpowers/specs/2026-09-11-policy-injection-design.md:439`:`缺口` → `口子`(避免与该文 其余 5 处「缺口 = 缺失项」撞义)。 ## 批内位置 T0 规格 ✓ · T1/T2 ✓(探针 94 条)· **T3 ✓** · **T4 ✓(本笔)** · T5 自源 parser · T6 其余语料 · T7 收尾重锁。 ⇒ 此刻 tests/bootstrap 仍全红、自举链仍断 —— 这是 (乙) 的**预期中间态**(前端已硬切,自源尚未跟上)。 --- bootstrap/corec/frontend/parser.py | 8 + docs/core-language-syntax_v4.md | 20 + docs/maintainer/design/v4-layout-spec.md | 62 + .../2026-09-11-policy-injection-design.md | 2 +- src/arch/hit/hit.cr | 2238 +++--- src/arch/hit/lower_to_core.cr | 1170 +-- src/arch/x86_64/frame.cr | 444 +- src/arch/x86_64/instr.cr | 3477 ++++---- src/arch/x86_64/regalloc.cr | 1355 ++-- src/arch/x86_64/sizes.cr | 173 +- src/arch/x86_64/tag2l.cr | 749 +- src/compiler/ast.cr | 895 ++- src/compiler/ccr_io.cr | 3403 ++++---- src/compiler/ccr_types.cr | 582 +- src/compiler/checker.cr | 7133 +++++++++-------- src/compiler/cir_cache.cr | 1113 +-- src/compiler/corearch.cr | 975 ++- src/compiler/dataflow.cr | 1047 +-- src/compiler/diag.cr | 328 +- src/compiler/dump.cr | 985 +-- src/compiler/dyn_arr.cr | 2847 ++++--- src/compiler/entry.cr | 3 +- src/compiler/ext_mgr.cr | 132 +- src/compiler/ext_safety.cr | 42 +- src/compiler/globals.cr | 786 +- src/compiler/iface_axis.cr | 220 +- src/compiler/iface_registry.cr | 400 +- src/compiler/interp.cr | 1436 ++-- src/compiler/ir_gen.cr | 6517 +++++++-------- src/compiler/lexer.cr | 1516 ++-- src/compiler/main.cr | 1174 ++- src/compiler/module.cr | 1188 +-- src/compiler/monomorph.cr | 1597 ++-- src/compiler/opt.cr | 618 +- src/compiler/parser.cr | 3852 ++++----- src/compiler/pass.cr | 15 +- src/compiler/project.cr | 78 +- src/compiler/provenance_verify.cr | 207 +- src/compiler/ptr_analysis.cr | 559 +- src/compiler/purity_selftest.cr | 489 +- src/compiler/region_check.cr | 293 +- src/compiler/ty_shadow.cr | 1936 ++--- src/compiler/type_engine.cr | 1257 +-- src/compiler/type_selftest.cr | 5585 +++++++------ src/compiler/type_terms.cr | 677 +- src/format/elf/elf.cr | 2957 ++++--- src/format/elf/ld.cr | 1141 ++- src/format/elf/resolve.cr | 139 +- src/kernel/bytes.cr | 103 +- src/kernel/check.cr | 183 +- src/kernel/kernel_main.cr | 343 +- src/kernel/mctt.cr | 222 +- src/kernel/nbe.cr | 482 +- src/kernel/subst.cr | 39 +- src/kernel/subtype.cr | 38 +- src/kernel/term_io.cr | 499 +- src/kernel/test_term_io.cr | 374 +- src/lattice/ent_kernel.cr | 1490 ++-- src/lsp/analysis.cr | 2191 ++--- src/lsp/json.cr | 1215 +-- src/lsp/lsp.cr | 630 +- src/lsp/main.cr | 7 +- src/lsp/rpc.cr | 574 +- src/lsp/test_json.cr | 156 +- src/os/linux/callseq.cr | 274 +- src/os/linux/entry.cr | 203 +- src/os/linux/syscall.cr | 42 +- src/runtime/arena_globals.cr | 6 +- src/runtime/rt.cr | 12 +- src/scheduler/example.cr | 21 +- src/stdlib/arena.cr | 157 +- src/stdlib/assert.cr | 108 +- src/stdlib/chan.cr | 253 +- src/stdlib/cli.cr | 637 +- src/stdlib/collections.cr | 232 +- src/stdlib/dex.cr | 66 +- src/stdlib/fmt.cr | 531 +- src/stdlib/goroutine.cr | 56 +- src/stdlib/hotpatch.cr | 46 +- src/stdlib/io.cr | 131 +- src/stdlib/math.cr | 115 +- src/stdlib/os.cr | 164 +- src/stdlib/panic.cr | 45 +- src/stdlib/sched.cr | 261 +- src/stdlib/scheduler.cr | 287 +- src/stdlib/toml.cr | 426 +- src/stdlib/trace.cr | 22 +- src/stdlib/variadic.cr | 29 +- src/targets/x86_64-linux/main.cr | 308 +- tools/v4_frontend_probe.py | 11 +- tools/v4_migrate.py | 853 ++ tools/v4_migrate_v3lex.py | 477 ++ 92 files changed, 43539 insertions(+), 34600 deletions(-) create mode 100644 tools/v4_migrate.py create mode 100644 tools/v4_migrate_v3lex.py diff --git a/bootstrap/corec/frontend/parser.py b/bootstrap/corec/frontend/parser.py index a3e85355..264c16be 100644 --- a/bootstrap/corec/frontend/parser.py +++ b/bootstrap/corec/frontend/parser.py @@ -70,7 +70,15 @@ def _at_line_end(self): """当前位置是否处于行边界:NEWLINE / DEDENT / EOF。 `DEDENT` 与 `EOF` **不消费**——它们是 region 收尾信号,由块产生式处理。 + + 第三态:**刚吃掉 DEDENT**(= region 收尾)也构成行边界。`_expect_region` 的 + 反向操作由块产生式完成(`expect(DEDENT)`),此时 lexer 已把下一行的首 token + 接在 DEDENT 之后(token 次序 NEWLINE → DEDENT → 下一行首 token),所以 + 「prev == DEDENT」等价于「站在新一行的行首」。少了这条,`x := unsafe: …` + 这类**以 region 收尾的声明/表达式**会在 `_end_decl` 处被误判为「同行还有 token」。 """ + if self.pos > 0 and self.tokens[self.pos - 1].type == TokenType.DEDENT: + return True return (self.check(TokenType.NEWLINE) or self.check(TokenType.DEDENT) or self.check(TokenType.EOF)) diff --git a/docs/core-language-syntax_v4.md b/docs/core-language-syntax_v4.md index a547ed54..81098522 100644 --- a/docs/core-language-syntax_v4.md +++ b/docs/core-language-syntax_v4.md @@ -385,6 +385,26 @@ count += 1 v4 不使用显式 `move`。region、借用有效性、escape、capture 与存储 realization 由程序关系推导。 +### 4.1 region 作声明右值 + +声明的右值可以是一个 region。region 的值 = 它最后一项的值(与函数体一致:只有最后一项是值,其余按语句处理): + +```core +raw := unsafe: + @str_of(buf) + +total := if ready: + compute() +else: + 0 +``` + +这条形式的用途是把**只能以 region 书写**的构造(`unsafe`、带 region 的分支)放进一个值的位置。 +它不引入新的表达式种类:region 仍是 region,只是在右值位被读取其尾值。 + +⚠ 反向不成立:`f(unsafe: …)` —— 把 region 直接塞进**实参位** —— 不是合法文本(实参位是表达式位, +region 不是表达式)。需要时先把 region 的值绑定到一个名字,再把名字传进去。 + --- ## 五、表达式与运算符 diff --git a/docs/maintainer/design/v4-layout-spec.md b/docs/maintainer/design/v4-layout-spec.md index be053d94..4eafa3e4 100644 --- a/docs/maintainer/design/v4-layout-spec.md +++ b/docs/maintainer/design/v4-layout-spec.md @@ -897,3 +897,65 @@ python3 tools/v4_layout_probe.py tokenize-sites --rev develop@origin --require-b | 裁定 (b) 的 `:` 双 token | 本档 §2.1(维护者裁定) | — | | 现行语料行尾 `:` = 0 | 227 档 · 0 处 | `python3 tools/v4_layout_probe.py colon-positions --rev develop@origin` | | v4 目标行尾 `:` = 57 处,全是 region 开启 | 77 个 core 代码块 | 同上(`--fixture-only` 不含语料;v4 侧扫描见 §2.2 表) | + +--- + +## 10. T4 施工期补遗(本档 §1–§5 五条判定**未覆盖**的三面) + +> **本节的来历**:§1–§5 是从「语料里已有的 `{}` 形状」反推 layout 规则;三面都不在 +> `{}` 的射程内,因此 T4 落地时才现形。**本节的每一条都带施工期实测读数**(标注口径同 §0.2: +> `[T4·实核]` = T4 施工时实测)。 +> **地位**:本节是 §1–§5 的**补遗**,不是替代;与 §1–§5 冲突时以本节的裁定为准(维护者已裁)。 + +### 10.1 括号外的续行在 v4 **不合法**(`[T4·实核]`) + +v4 的换行只在**括号外**构成 layout 断点:`()` / `[]` / 结构体字面量的 `{}` 内是隐式续行 +(`bootstrap/corec/frontend/lexer.py` 的 `bracket_depth == 0` 判据)。**括号外**把一条语句 +拆成两行(行尾是二元运算符,或次行以二元运算符开头)⇒ 次行首 token 列更深 ⇒ 发 INDENT ⇒ +parse 当场失败。实测: + +``` +if a == 0 || ← 行尾 `||` + b == 0: → SyntaxError: Unexpected token +``` + +⇒ **语料迁移(T4/T6)必须把这类续行并成一行**。语料里有真站点(如 +`src/compiler/project.cr`、`src/compiler/module.cr` 的条件式;`[T4·实核]` 逐档计)。 + +### 10.2 空 region 在 v4 **无法表达**(`[T4·实核]`) + +region 的语法要求至少一个 token(`_expect_region` 吃 COLON_BLOCK → NEWLINE → **INDENT**), +所以「`{ }`」与「只含注释的块」在 token 面**不可区分**,都是「region 无 token」⇒ parse 失败: + +``` +fn f() -> int: + // nothing → SyntaxError: Expected INDENT, got EOF +``` + +**维护者裁定(2026-10-11)= 逐处改写,不扩语法面**: +- 无 `else`、且条件无副作用的 `if … { }` ⇒ **整条删掉**(`src/compiler/interp.cr` 的 + `if op2 == 33 { }` 一类即此类:条件只读局部量); +- 函数体只含注释 ⇒ 保留注释 + **补一条与声明返回类型匹配的显式 `return`**; +- 其余形态(循环体空、`else` 分支空、声明体内的空 region)⇒ 逐处上报裁定,**不得自行拍**。 + +**不予采纳的两条**(留痕,防后人重走):① region 内塞一个 `unit` 占位——`unit` 是**类型名**, +当 no-op 语句用是 v4 文档没有的面;实测 `Parser(Lexer(...))` 虽接受 `unit` 作语句,但语义上是 +「一个类型引用」而不是「空操作」,属绕过;② 把「region 可空」写进规格并改两个前端——改动面最大。 + +### 10.3 region 作**声明右值**:已裁定支持(`[T4·实核]`) + +`unsafe` 在语料里有「作实参/右值」的用法(`b := read_file(unsafe { @str_of(...) })`)。 +v4 里 `unsafe` 是 region(语句位),而**实参位是表达式位** ⇒ 直接塞进去不是合法文本 +(lexer 在括号内不发 layout,region 永远等不到 INDENT)。实测 `f(unsafe: …)` 必 FAIL。 + +**维护者裁定(2026-10-11)= 支持「region 作声明右值」**:声明的右值可以是一个 region, +其值取该 region 的尾值(与函数体同规则:只有最后一项是值)。于是 +`x := unsafe: ` 成立,语料侧的 `f(unsafe { E })` 由 T4 **机械上提**: +先 `t := unsafe: `,再把原处的 `unsafe { E }` 换成 `t`。 + +- 落地 = `bootstrap/corec/frontend/parser.py` 的 `_at_line_end()` 增加**第三态**: + 「prev == DEDENT 即行边界」(region 收尾后 lexer 已把下一行首 token 接在 DEDENT 之后)。 + 少了这条,`x := unsafe: …` 会在 `_end_decl` 处被误判成「同行还有 token」(`[T4·实核]` 复现: + `expected end of line, got 'return'`)。 +- **反向仍不成立**:`f(unsafe: …)`(region 进实参位)依然不是合法文本;需要时先绑名字。 +- 目标语法文档同步:`docs/core-language-syntax_v4.md` §4.1。 diff --git a/docs/superpowers/specs/2026-09-11-policy-injection-design.md b/docs/superpowers/specs/2026-09-11-policy-injection-design.md index 5095a3c3..6924e227 100644 --- a/docs/superpowers/specs/2026-09-11-policy-injection-design.md +++ b/docs/superpowers/specs/2026-09-11-policy-injection-design.md @@ -436,7 +436,7 @@ if is_valid(s) { sh_run_text(sh_text(s)) } // s 仍是 string,不是 Sh` 与 `φ` 共用形状项机制,需要一条统一的分工判据(归 S-B4 输入)。 diff --git a/src/arch/hit/hit.cr b/src/arch/hit/hit.cr index a4533ff7..74e0efe1 100644 --- a/src/arch/hit/hit.cr +++ b/src/arch/hit/hit.cr @@ -26,170 +26,190 @@ import fmt // ════════════════════════════════════════════════════════════════ // g_hit_events:每事件 40B = 10 × i32 -HIT_EVENT_REC : int = 40; -HIT_EV_OFF_ID : int = 0; // 最小核事件号(1-4 数据 + 5-9 控制/调用/系统) -HIT_EV_OFF_NAME : int = 4; // 名字串下标(g_hit_names 表) -HIT_EV_OFF_INPUTS : int = 8; // 事件签名(无宽度/寄存器/寻址——最小核抽象) -HIT_EV_OFF_OUTPUTS : int = 12; -HIT_EV_OFF_SIDE : int = 16; // 0 = pure,1 = effect +HIT_EVENT_REC : int = 40 +HIT_EV_OFF_ID : int = 0 // 最小核事件号(1-4 数据 + 5-9 控制/调用/系统) +HIT_EV_OFF_NAME : int = 4 // 名字串下标(g_hit_names 表) +HIT_EV_OFF_INPUTS : int = 8 // 事件签名(无宽度/寄存器/寻址——最小核抽象) +HIT_EV_OFF_OUTPUTS : int = 12 +HIT_EV_OFF_SIDE : int = 16 // 0 = pure,1 = effect // 20/24/28 = proj0(M1 兼容视区):M1 消费方(emit_instr_tabled → hit_ev_step_of // → hit_proj_step(es, 0, st))只读首投影视图,故把 proj0 的 isa/步数/首步偏移 // 镜像于此,多 proj 事件的其余形态走 32/36 字段。旧路径消费面布局不变。 -HIT_EV_OFF_ISA : int = 20; // proj0 ISA 码(1 = x86-64) -HIT_EV_OFF_STEP_COUNT : int = 24; // proj0 步数 -HIT_EV_OFF_STEP_OFF : int = 28; // proj0 首步在 g_hit_steps 的字节偏移 -HIT_EV_OFF_PROJ_OFF : int = 32; // 首投影记录下标(g_hit_projs,12B/条) -HIT_EV_OFF_PROJ_COUNT : int = 36; // 投影形态数(M1 恒 1) +HIT_EV_OFF_ISA : int = 20 // proj0 ISA 码(1 = x86-64) +HIT_EV_OFF_STEP_COUNT : int = 24 // proj0 步数 +HIT_EV_OFF_STEP_OFF : int = 28 // proj0 首步在 g_hit_steps 的字节偏移 +HIT_EV_OFF_PROJ_OFF : int = 32 // 首投影记录下标(g_hit_projs,12B/条) +HIT_EV_OFF_PROJ_COUNT : int = 36 // 投影形态数(M1 恒 1) // g_hit_projs:每投影 12B = 3 × i32(事件 32/36 字段索引本表) -HIT_PROJ_REC : int = 12; -HIT_PJ_OFF_ISA : int = 0; // 投影 ISA 码 -HIT_PJ_OFF_STEP_COUNT : int = 4; // 该形态步数 -HIT_PJ_OFF_STEP_OFF : int = 8; // 该形态首步在 g_hit_steps 的字节偏移 +HIT_PROJ_REC : int = 12 +HIT_PJ_OFF_ISA : int = 0 // 投影 ISA 码 +HIT_PJ_OFF_STEP_COUNT : int = 4 // 该形态步数 +HIT_PJ_OFF_STEP_OFF : int = 8 // 该形态首步在 g_hit_steps 的字节偏移 // g_hit_steps:每步 108B。前 20B = M1 布局视区(OP0/OP1/REG_ROLE/RM_ROLE/ // RM_MODE——偏移与旧布局一致,旧消费方原样可读);20B 起 = v2 规范字段。 // 模板字节 = prefix → REX → opcode 三段固定拼接序(不含 ModRM/SIB/disp/imm/ // rel——那些由槽位/角色回填,非模板字节)。 -HIT_STEP_REC : int = 108; -HIT_ST_OFF_OP0 : int = 0; // 字节流首字节(prefix/REX/opcode 拼接序) -HIT_ST_OFF_OP1 : int = 4; // 字节流第二字节(0 = 无) -HIT_ST_OFF_REG_ROLE : int = 8; // modrm.reg 侧角色码(角色 1-6 / 寄存器字面量 16+regno;0 = 无/digit 形) -HIT_ST_OFF_RM_ROLE : int = 12; // modrm.rm 角色码(同上;0 = 无) -HIT_ST_OFF_RM_MODE : int = 16; // 0 = rm 为寄存器;1 = rm 为 base+disp(缺省 base = rbp);2 = SIB +HIT_STEP_REC : int = 108 +HIT_ST_OFF_OP0 : int = 0 // 字节流首字节(prefix/REX/opcode 拼接序) +HIT_ST_OFF_OP1 : int = 4 // 字节流第二字节(0 = 无) +HIT_ST_OFF_REG_ROLE : int = 8 // modrm.reg 侧角色码(角色 1-6 / 寄存器字面量 16+regno;0 = 无/digit 形) +HIT_ST_OFF_RM_ROLE : int = 12 // modrm.rm 角色码(同上;0 = 无) +HIT_ST_OFF_RM_MODE : int = 16 // 0 = rm 为寄存器;1 = rm 为 base+disp(缺省 base = rbp);2 = SIB // ── v2 规范字段(20 起;未用恒 0)── -HIT_ST_OFF_PFX0 : int = 20; // 前缀字节 0(66/0F…) -HIT_ST_OFF_PFX1 : int = 24; // 前缀字节 1 -HIT_ST_OFF_REX : int = 28; // REX 字节(0x40|w<<3|r<<2|x<<1|b;无 REX = 0) -HIT_ST_OFF_OPB0 : int = 32; // opcode 字节 0 -HIT_ST_OFF_OPB1 : int = 36; // opcode 字节 1 -HIT_ST_OFF_OPB2 : int = 40; // opcode 字节 2 -HIT_ST_OFF_OPN : int = 44; // opcode 字节数(1..3) -HIT_ST_OFF_REG_IS_DIGIT : int = 48; // reg 侧为 /digit(1)而非角色 -HIT_ST_OFF_REG_DIGIT : int = 52; // digit 值(0..7) -HIT_ST_OFF_BASE_ROLE : int = 56; // base 角色码(rm_mode 1 = modrm base,缺省 rbp→0; +HIT_ST_OFF_PFX0 : int = 20 // 前缀字节 0(66/0F…) +HIT_ST_OFF_PFX1 : int = 24 // 前缀字节 1 +HIT_ST_OFF_REX : int = 28 // REX 字节(0x40|w<<3|r<<2|x<<1|b;无 REX = 0) +HIT_ST_OFF_OPB0 : int = 32 // opcode 字节 0 +HIT_ST_OFF_OPB1 : int = 36 // opcode 字节 1 +HIT_ST_OFF_OPB2 : int = 40 // opcode 字节 2 +HIT_ST_OFF_OPN : int = 44 // opcode 字节数(1..3) +HIT_ST_OFF_REG_IS_DIGIT : int = 48 // reg 侧为 /digit(1)而非角色 +HIT_ST_OFF_REG_DIGIT : int = 52 // digit 值(0..7) +HIT_ST_OFF_BASE_ROLE : int = 56 // base 角色码(rm_mode 1 = modrm base,缺省 rbp→0; // rm_mode 2 = SIB base;rip = 32 池/rodata/全局形) -HIT_ST_OFF_SIB_SCALE : int = 60; // SIB scale(0..3;非 rm_mode 2 = 0) -HIT_ST_OFF_SIB_INDEX : int = 64; // SIB index 角色码 -HIT_ST_OFF_DISP_SIZE : int = 68; // disp 宽度:0 = auto(槽回填按幅度选 1|4);1/4 字面 -HIT_ST_OFF_DISP_SRC : int = 72; // disp 源角色码(0 = 无/槽隐含) -HIT_ST_OFF_IMM_SIZE : int = 76; // imm 宽度(1/2/4/8;0 = 无) -HIT_ST_OFF_IMM_ROLE : int = 80; // imm 操作数角色码(字面量 lit = 100) -HIT_ST_OFF_IMM_KIND : int = 84; // imm 回填 kind(0 = 无;1 = fnaddr) -HIT_ST_OFF_IMM_LIT : int = 88; // imm 字面量值(imm_role = lit 时) -HIT_ST_OFF_REL_ROLE : int = 92; // rel 回填操作数角色码(0 = 无) -HIT_ST_OFF_REL_KIND : int = 96; // rel 回填表:1 = 事件流位置;2 = 函数;3 = 外部符号 -HIT_ST_OFF_REL_SIZE : int = 100; // rel 宽度(8/32) -HIT_ST_OFF_COND_ROLE : int = 104; // branch 条件源槽角色码(cmp/test 序列操作数) +HIT_ST_OFF_SIB_SCALE : int = 60 // SIB scale(0..3;非 rm_mode 2 = 0) +HIT_ST_OFF_SIB_INDEX : int = 64 // SIB index 角色码 +HIT_ST_OFF_DISP_SIZE : int = 68 // disp 宽度:0 = auto(槽回填按幅度选 1|4);1/4 字面 +HIT_ST_OFF_DISP_SRC : int = 72 // disp 源角色码(0 = 无/槽隐含) +HIT_ST_OFF_IMM_SIZE : int = 76 // imm 宽度(1/2/4/8;0 = 无) +HIT_ST_OFF_IMM_ROLE : int = 80 // imm 操作数角色码(字面量 lit = 100) +HIT_ST_OFF_IMM_KIND : int = 84 // imm 回填 kind(0 = 无;1 = fnaddr) +HIT_ST_OFF_IMM_LIT : int = 88 // imm 字面量值(imm_role = lit 时) +HIT_ST_OFF_REL_ROLE : int = 92 // rel 回填操作数角色码(0 = 无) +HIT_ST_OFF_REL_KIND : int = 96 // rel 回填表:1 = 事件流位置;2 = 函数;3 = 外部符号 +HIT_ST_OFF_REL_SIZE : int = 100 // rel 宽度(8/32) +HIT_ST_OFF_COND_ROLE : int = 104 // branch 条件源槽角色码(cmp/test 序列操作数) // 角色/效应/ISA 码 -HIT_ROLE_DST : int = 1; -HIT_ROLE_SRC1 : int = 2; -HIT_ROLE_SRC2 : int = 3; -HIT_ROLE_ADDR : int = 4; -HIT_ROLE_VAL : int = 5; -HIT_ROLE_COND : int = 6; // branch 条件源(v2) -HIT_SIDE_PURE : int = 0; -HIT_SIDE_EFFECT : int = 1; -HIT_ISA_X86 : int = 1; +HIT_ROLE_DST : int = 1 +HIT_ROLE_SRC1 : int = 2 +HIT_ROLE_SRC2 : int = 3 +HIT_ROLE_ADDR : int = 4 +HIT_ROLE_VAL : int = 5 +HIT_ROLE_COND : int = 6 // branch 条件源(v2) +HIT_SIDE_PURE : int = 0 +HIT_SIDE_EFFECT : int = 1 +HIT_ISA_X86 : int = 1 // 操作数码空间补充(与角色码不相交) -HIT_REG_BASE : int = 16; // 寄存器字面量 = 16 + regno(rax=0..r15=15) -HIT_CODE_RIP : int = 32; // rip 基(仅 base 键合法) -HIT_CODE_LIT : int = 100; // imm 字面量(imm_role = "lit") +HIT_REG_BASE : int = 16 // 寄存器字面量 = 16 + regno(rax=0..r15=15) +HIT_CODE_RIP : int = 32 // rip 基(仅 base 键合法) +HIT_CODE_LIT : int = 100 // imm 字面量(imm_role = "lit") // rel kind 码 -HIT_REL_EVENT : int = 1; -HIT_REL_FUNC : int = 2; -HIT_REL_EXTERN : int = 3; +HIT_REL_EVENT : int = 1 +HIT_REL_FUNC : int = 2 +HIT_REL_EXTERN : int = 3 // imm kind 码 -HIT_IMM_FNADDR : int = 1; +HIT_IMM_FNADDR : int = 1 // [runtime.x86] 条目槽(每槽 4B;见 hit_parse_runtime_chunk) -HIT_RT_CALL_MECHANISM : int = 0; -HIT_RT_CALL_RET_ADDR : int = 1; -HIT_RT_CALL_STACK_GROW : int = 2; -HIT_RT_PARAM_MODE : int = 3; -HIT_RT_PARAM_MASK : int = 4; -HIT_RT_SAVE_MASK : int = 5; -HIT_RT_EXTERN_ENTRY : int = 6; -HIT_RT_EXTERN_RESOLVE : int = 7; +HIT_RT_CALL_MECHANISM : int = 0 +HIT_RT_CALL_RET_ADDR : int = 1 +HIT_RT_CALL_STACK_GROW : int = 2 +HIT_RT_PARAM_MODE : int = 3 +HIT_RT_PARAM_MASK : int = 4 +HIT_RT_SAVE_MASK : int = 5 +HIT_RT_EXTERN_ENTRY : int = 6 +HIT_RT_EXTERN_RESOLVE : int = 7 // 表加载全局(hit.cr 仅进 corearch 构建 → 不污染 corec/corelsp) -g_hit_events : string, mut; g_hit_event_count : int, mut; g_hit_event_cap : int, mut; -g_hit_steps : string, mut; g_hit_step_count : int, mut; g_hit_step_cap : int, mut; -g_hit_projs : string, mut; g_hit_proj_count : int, mut; g_hit_proj_cap : int, mut; -g_hit_names : string, mut; g_hit_name_count : int, mut; g_hit_name_cap : int, mut; -g_hit_runtime : string, mut; g_hit_runtime_present : int, mut; +g_hit_events : string, mut +g_hit_event_count : int, mut +g_hit_event_cap : int, mut +g_hit_steps : string, mut +g_hit_step_count : int, mut +g_hit_step_cap : int, mut +g_hit_projs : string, mut +g_hit_proj_count : int, mut +g_hit_proj_cap : int, mut +g_hit_names : string, mut +g_hit_name_count : int, mut +g_hit_name_cap : int, mut +g_hit_runtime : string, mut +g_hit_runtime_present : int, mut // ════════════════════════════════════════════════════════════════ // buffer 表小工具(自持:仅用运行时内建 load8/store8/alloc) // ════════════════════════════════════════════════════════════════ -fn hit_copy_bytes(src: string, n: int, dst: string) { - i : int, mut = 0; - loop { - if i >= n { break; } - store8(dst, i, load8(src, i)); - i = i + 1; } -} +fn hit_copy_bytes(src: string, n: int, dst: string): + i : int, mut = 0 + loop: + if i >= n: + break + store8(dst, i, load8(src, i)) + i = i + 1 // 4B 小端写/读(仅存非负值——id/字节/码 均非负;字节拆取仿 w32 的 % 256 // 惯例——按位 & 不进 HIT 表值域:本文件仅 hit_bit 用倍增) -fn hit_w32(buf: string, pos: int, v: int) { - store8(buf, pos + 0, v % 256); - store8(buf, pos + 1, (v / 256) % 256); - store8(buf, pos + 2, (v / 65536) % 256); - store8(buf, pos + 3, (v / 16777216) % 256); } +fn hit_w32(buf: string, pos: int, v: int): + store8(buf, pos + 0, v % 256) + store8(buf, pos + 1, (v / 256) % 256) + store8(buf, pos + 2, (v / 65536) % 256) + store8(buf, pos + 3, (v / 16777216) % 256) -fn hit_r32(buf: string, pos: int) -> int { - return load8(buf, pos) + load8(buf, pos + 1) * 256 + - load8(buf, pos + 2) * 65536 + load8(buf, pos + 3) * 16777216; } +fn hit_r32(buf: string, pos: int) -> int: + return load8(buf, pos) + load8(buf, pos + 1) * 256 + load8(buf, pos + 2) * 65536 + load8(buf, pos + 3) * 16777216 -fn hit_zero_bytes(buf: string, from: int, n: int) { - i : int, mut = 0; - loop { - if i >= n { break; } - store8(buf, from + i, 0); - i = i + 1; } -} +fn hit_zero_bytes(buf: string, from: int, n: int): + i : int, mut = 0 + loop: + if i >= n: + break + store8(buf, from + i, 0) + i = i + 1 -fn hit_grow_events(needed: int) { - if needed < g_hit_event_cap { return; } - nc : int, mut = g_hit_event_cap * 2; - if nc < 16 { nc = 16; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * HIT_EVENT_REC); - hit_copy_bytes(g_hit_events, g_hit_event_cap * HIT_EVENT_REC, nb); - g_hit_events = nb; - g_hit_event_cap = nc; } +fn hit_grow_events(needed: int): + if needed < g_hit_event_cap: + return + nc : int, mut = g_hit_event_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * HIT_EVENT_REC) + hit_copy_bytes(g_hit_events, g_hit_event_cap * HIT_EVENT_REC, nb) + g_hit_events = nb + g_hit_event_cap = nc -fn hit_grow_steps(needed: int) { - if needed < g_hit_step_cap { return; } - nc : int, mut = g_hit_step_cap * 2; - if nc < 16 { nc = 16; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * HIT_STEP_REC); - hit_copy_bytes(g_hit_steps, g_hit_step_cap * HIT_STEP_REC, nb); - g_hit_steps = nb; - g_hit_step_cap = nc; } +fn hit_grow_steps(needed: int): + if needed < g_hit_step_cap: + return + nc : int, mut = g_hit_step_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * HIT_STEP_REC) + hit_copy_bytes(g_hit_steps, g_hit_step_cap * HIT_STEP_REC, nb) + g_hit_steps = nb + g_hit_step_cap = nc -fn hit_grow_projs(needed: int) { - if needed < g_hit_proj_cap { return; } - nc : int, mut = g_hit_proj_cap * 2; - if nc < 16 { nc = 16; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * HIT_PROJ_REC); - hit_copy_bytes(g_hit_projs, g_hit_proj_cap * HIT_PROJ_REC, nb); - g_hit_projs = nb; - g_hit_proj_cap = nc; } +fn hit_grow_projs(needed: int): + if needed < g_hit_proj_cap: + return + nc : int, mut = g_hit_proj_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * HIT_PROJ_REC) + hit_copy_bytes(g_hit_projs, g_hit_proj_cap * HIT_PROJ_REC, nb) + g_hit_projs = nb + g_hit_proj_cap = nc -fn hit_grow_names(needed: int) { - if needed < g_hit_name_cap { return; } - nc : int, mut = g_hit_name_cap * 2; - if nc < 16 { nc = 16; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * 8); - hit_copy_bytes(g_hit_names, g_hit_name_cap * 8, nb); - g_hit_names = nb; - g_hit_name_cap = nc; } +fn hit_grow_names(needed: int): + if needed < g_hit_name_cap: + return + nc : int, mut = g_hit_name_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * 8) + hit_copy_bytes(g_hit_names, g_hit_name_cap * 8, nb) + g_hit_names = nb + g_hit_name_cap = nc // ════════════════════════════════════════════════════════════════ // toml 文本扫描(表文件结构层;标量值解析复用 stdlib toml.cr) @@ -200,258 +220,361 @@ fn hit_grow_names(needed: int) { // 行尾 / 空白 / '\r'(CRLF)/ '#'(行尾注释)——容忍手写表的 // "[[event.proj]] # 注释" 形式;同时避免 "[[event]]" 前缀误配 // "[[event.proj]]"(tag 后必须紧跟界定符)。 -fn hit_find_tag(content: string, pos: int, tag: string) -> int { - slen := str_len(content); - tlen := str_len(tag); - p : int, mut = pos; - loop { - if p >= slen { break; } - s : int, mut = p; - loop { - if s >= slen { break; } - c := load8(content, s); - if c == 32 || c == 9 { s = s + 1; } else { break; } - } - e : int, mut = s; - loop { - if e >= slen { break; } - if load8(content, e) == 10 { break; } - e = e + 1; } - if s + tlen <= e { - m : int, mut = 0; - ok : int, mut = 1; - loop { - if m >= tlen { break; } - if load8(content, s + m) != load8(tag, m) { ok = 0; break; } - m = m + 1; } - if ok == 1 { - if s + tlen == e { return s; } // tag 到行尾(\n 或 EOF) - c2 := load8(content, s + tlen); - if c2 == 13 || c2 == 32 || c2 == 9 || c2 == 35 { return s; } - } - } - p = e + 1; } - return -1; } +fn hit_find_tag(content: string, pos: int, tag: string) -> int: + slen := str_len(content) + tlen := str_len(tag) + p : int, mut = pos + loop: + if p >= slen: + break + s : int, mut = p + loop: + if s >= slen: + break + c := load8(content, s) + if c == 32 || c == 9: + s = s + 1 + else: + break + e : int, mut = s + loop: + if e >= slen: + break + if load8(content, e) == 10: + break + e = e + 1 + if s + tlen <= e: + m : int, mut = 0 + ok : int, mut = 1 + loop: + if m >= tlen: + break + if load8(content, s + m) != load8(tag, m): + ok = 0 + break + m = m + 1 + if ok == 1: + if s + tlen == e: + return s + // tag 到行尾(\n 或 EOF) + c2 := load8(content, s + tlen) + if c2 == 13 || c2 == 32 || c2 == 9 || c2 == 35: + return s + p = e + 1 + return -1 // pos 所在行的行尾后偏移(下一行首;EOF = 文长) -fn hit_line_after(content: string, pos: int) -> int { - slen := str_len(content); - i : int, mut = pos; - loop { - if i >= slen { break; } - if load8(content, i) == 10 { return i + 1; } - i = i + 1; } - return slen; } +fn hit_line_after(content: string, pos: int) -> int: + slen := str_len(content) + i : int, mut = pos + loop: + if i >= slen: + break + if load8(content, i) == 10: + return i + 1 + i = i + 1 + return slen // 行首 token(键名)判定:text 中是否存在以 key 为整 token 的行 // (token 终止符 = 空白 / '=' / 行尾;'#' 注释行跳过)。 -fn hit_has_key(text: string, key: string) -> int { - slen := str_len(text); - klen := str_len(key); - p : int, mut = 0; - loop { - if p >= slen { break; } - s : int, mut = p; - loop { - if s >= slen { break; } - c := load8(text, s); - if c == 32 || c == 9 { s = s + 1; } else { break; } } - e : int, mut = s; - loop { - if e >= slen { break; } - if load8(text, e) == 10 { break; } - e = e + 1; } - if s < e && load8(text, s) == 35 { p = e + 1; continue; } // '#' 注释行 - t : int, mut = s; - loop { - if t >= e { break; } - c := load8(text, t); - if c == 32 || c == 9 || c == 61 { break; } - t = t + 1; } - if t - s == klen { - m : int, mut = 0; - ok : int, mut = 1; - loop { - if m >= klen { break; } - if load8(text, s + m) != load8(key, m) { ok = 0; break; } - m = m + 1; } - if ok == 1 { return 1; } - } - p = e + 1; } - return 0; } +fn hit_has_key(text: string, key: string) -> int: + slen := str_len(text) + klen := str_len(key) + p : int, mut = 0 + loop: + if p >= slen: + break + s : int, mut = p + loop: + if s >= slen: + break + c := load8(text, s) + if c == 32 || c == 9: + s = s + 1 + else: + break + e : int, mut = s + loop: + if e >= slen: + break + if load8(text, e) == 10: + break + e = e + 1 + if s < e && load8(text, s) == 35: + p = e + 1 + continue + // '#' 注释行 + t : int, mut = s + loop: + if t >= e: + break + c := load8(text, t) + if c == 32 || c == 9 || c == 61: + break + t = t + 1 + if t - s == klen: + m : int, mut = 0 + ok : int, mut = 1 + loop: + if m >= klen: + break + if load8(text, s + m) != load8(key, m): + ok = 0 + break + m = m + 1 + if ok == 1: + return 1 + p = e + 1 + return 0 // allowed(空格分隔键名表)中是否含 key(整 token 匹配) -fn hit_key_allowed(allowed: string, key: string) -> int { - alen := str_len(allowed); - klen := str_len(key); - p : int, mut = 0; - loop { - if p >= alen { break; } - loop { - if p >= alen { break; } - if load8(allowed, p) == 32 { p = p + 1; } else { break; } } - if p >= alen { break; } - e : int, mut = p; - loop { - if e >= alen { break; } - if load8(allowed, e) == 32 { break; } - e = e + 1; } - if e - p == klen { - m : int, mut = 0; - ok : int, mut = 1; - loop { - if m >= klen { break; } - if load8(allowed, p + m) != load8(key, m) { ok = 0; break; } - m = m + 1; } - if ok == 1 { return 1; } - } - p = e; } - return 0; } +fn hit_key_allowed(allowed: string, key: string) -> int: + alen := str_len(allowed) + klen := str_len(key) + p : int, mut = 0 + loop: + if p >= alen: + break + loop: + if p >= alen: + break + if load8(allowed, p) == 32: + p = p + 1 + else: + break + if p >= alen: + break + e : int, mut = p + loop: + if e >= alen: + break + if load8(allowed, e) == 32: + break + e = e + 1 + if e - p == klen: + m : int, mut = 0 + ok : int, mut = 1 + loop: + if m >= klen: + break + if load8(allowed, p + m) != load8(key, m): + ok = 0 + break + m = m + 1 + if ok == 1: + return 1 + p = e + return 0 // 本层键名白名单扫描:任一非 '#' 行以不在 allowed 中的键开头 → 报错 // "unknown key"。Returns 0 = 干净;1 = 已报未知键。 -fn hit_scan_keys_ok(text: string, allowed: string) -> int { - slen := str_len(text); - p : int, mut = 0; - loop { - if p >= slen { break; } - s : int, mut = p; - loop { - if s >= slen { break; } - c := load8(text, s); - if c == 32 || c == 9 { s = s + 1; } else { break; } } - e : int, mut = s; - loop { - if e >= slen { break; } - if load8(text, e) == 10 { break; } - e = e + 1; } - if s < e && load8(text, s) != 35 { // 非注释行 - t : int, mut = s; - loop { - if t >= e { break; } - c := load8(text, t); - if c == 32 || c == 9 || c == 61 { break; } - t = t + 1; } - if t > s { - tok := str_sub(text, s, t - s); - if hit_key_allowed(allowed, tok) == 0 { - print("error: HIT table: unknown key '"); print(tok); println("'"); - return 1; } - } - } - p = e + 1; } - return 0; } +fn hit_scan_keys_ok(text: string, allowed: string) -> int: + slen := str_len(text) + p : int, mut = 0 + loop: + if p >= slen: + break + s : int, mut = p + loop: + if s >= slen: + break + c := load8(text, s) + if c == 32 || c == 9: + s = s + 1 + else: + break + e : int, mut = s + loop: + if e >= slen: + break + if load8(text, e) == 10: + break + e = e + 1 + if s < e && load8(text, s) != 35: + // 非注释行 + t : int, mut = s + loop: + if t >= e: + break + c := load8(text, t) + if c == 32 || c == 9 || c == 61: + break + t = t + 1 + if t > s: + tok := str_sub(text, s, t - s) + if hit_key_allowed(allowed, tok) == 0: + print("error: HIT table: unknown key '") + print(tok) + println("'") + return 1 + p = e + 1 + return 0 // 原始值串(key = 之后到行尾注释前,去首尾空白;返回原样含引号) -fn hit_raw_str(text: string, key: string) -> string { - slen := str_len(text); - klen := str_len(key); - p : int, mut = 0; - loop { - if p >= slen { return ""; } - s : int, mut = p; - loop { - if s >= slen { break; } - c := load8(text, s); - if c == 32 || c == 9 { s = s + 1; } else { break; } } - e : int, mut = s; - loop { - if e >= slen { break; } - if load8(text, e) == 10 { break; } - e = e + 1; } - if s < e && load8(text, s) != 35 && s + klen <= e { - m : int, mut = 0; - ok : int, mut = 1; - loop { - if m >= klen { break; } - if load8(text, s + m) != load8(key, m) { ok = 0; break; } - m = m + 1; } - if ok == 1 { - q : int, mut = s + klen; - loop { - if q >= e { break; } - if load8(text, q) == 32 || load8(text, q) == 9 { q = q + 1; } else { break; } } - if q < e && load8(text, q) == 61 { - v0 : int, mut = q + 1; - loop { - if v0 >= e { break; } - if load8(text, v0) == 32 || load8(text, v0) == 9 { v0 = v0 + 1; } else { break; } } - v1 : int, mut = v0; - loop { - if v1 >= e { break; } - if load8(text, v1) == 35 { break; } // '#' 行尾注释 - v1 = v1 + 1; } - loop { - if v1 <= v0 { break; } - c := load8(text, v1 - 1); - if c == 32 || c == 9 || c == 13 { v1 = v1 - 1; } else { break; } } - return str_sub(text, v0, v1 - v0); - } - } - } - p = e + 1; } - return ""; } +fn hit_raw_str(text: string, key: string) -> string: + slen := str_len(text) + klen := str_len(key) + p : int, mut = 0 + loop: + if p >= slen: + return "" + s : int, mut = p + loop: + if s >= slen: + break + c := load8(text, s) + if c == 32 || c == 9: + s = s + 1 + else: + break + e : int, mut = s + loop: + if e >= slen: + break + if load8(text, e) == 10: + break + e = e + 1 + if s < e && load8(text, s) != 35 && s + klen <= e: + m : int, mut = 0 + ok : int, mut = 1 + loop: + if m >= klen: + break + if load8(text, s + m) != load8(key, m): + ok = 0 + break + m = m + 1 + if ok == 1: + q : int, mut = s + klen + loop: + if q >= e: + break + if load8(text, q) == 32 || load8(text, q) == 9: + q = q + 1 + else: + break + if q < e && load8(text, q) == 61: + v0 : int, mut = q + 1 + loop: + if v0 >= e: + break + if load8(text, v0) == 32 || load8(text, v0) == 9: + v0 = v0 + 1 + else: + break + v1 : int, mut = v0 + loop: + if v1 >= e: + break + if load8(text, v1) == 35: + break + // '#' 行尾注释 + v1 = v1 + 1 + loop: + if v1 <= v0: + break + c := load8(text, v1 - 1) + if c == 32 || c == 9 || c == 13: + v1 = v1 - 1 + else: + break + return str_sub(text, v0, v1 - v0) + p = e + 1 + return "" // 事件名 → 角色码(1..6;0 = 未知/缺失) -fn hit_role_code(name: string) -> int { - if str_eq(name, "dst") != 0 { return HIT_ROLE_DST; } - if str_eq(name, "src1") != 0 { return HIT_ROLE_SRC1; } - if str_eq(name, "src2") != 0 { return HIT_ROLE_SRC2; } - if str_eq(name, "addr") != 0 { return HIT_ROLE_ADDR; } - if str_eq(name, "val") != 0 { return HIT_ROLE_VAL; } - if str_eq(name, "cond") != 0 { return HIT_ROLE_COND; } - return 0; } +fn hit_role_code(name: string) -> int: + if str_eq(name, "dst") != 0: + return HIT_ROLE_DST + if str_eq(name, "src1") != 0: + return HIT_ROLE_SRC1 + if str_eq(name, "src2") != 0: + return HIT_ROLE_SRC2 + if str_eq(name, "addr") != 0: + return HIT_ROLE_ADDR + if str_eq(name, "val") != 0: + return HIT_ROLE_VAL + if str_eq(name, "cond") != 0: + return HIT_ROLE_COND + return 0 // 寄存器名 → regno(0..15);非寄存器名 → -1 -fn hit_reg_code(name: string) -> int { - if str_eq(name, "rax") != 0 { return 0; } - if str_eq(name, "rcx") != 0 { return 1; } - if str_eq(name, "rdx") != 0 { return 2; } - if str_eq(name, "rbx") != 0 { return 3; } - if str_eq(name, "rsp") != 0 { return 4; } - if str_eq(name, "rbp") != 0 { return 5; } - if str_eq(name, "rsi") != 0 { return 6; } - if str_eq(name, "rdi") != 0 { return 7; } - if str_eq(name, "r8") != 0 { return 8; } - if str_eq(name, "r9") != 0 { return 9; } - if str_eq(name, "r10") != 0 { return 10; } - if str_eq(name, "r11") != 0 { return 11; } - if str_eq(name, "r12") != 0 { return 12; } - if str_eq(name, "r13") != 0 { return 13; } - if str_eq(name, "r14") != 0 { return 14; } - if str_eq(name, "r15") != 0 { return 15; } - return -1; } +fn hit_reg_code(name: string) -> int: + if str_eq(name, "rax") != 0: + return 0 + if str_eq(name, "rcx") != 0: + return 1 + if str_eq(name, "rdx") != 0: + return 2 + if str_eq(name, "rbx") != 0: + return 3 + if str_eq(name, "rsp") != 0: + return 4 + if str_eq(name, "rbp") != 0: + return 5 + if str_eq(name, "rsi") != 0: + return 6 + if str_eq(name, "rdi") != 0: + return 7 + if str_eq(name, "r8") != 0: + return 8 + if str_eq(name, "r9") != 0: + return 9 + if str_eq(name, "r10") != 0: + return 10 + if str_eq(name, "r11") != 0: + return 11 + if str_eq(name, "r12") != 0: + return 12 + if str_eq(name, "r13") != 0: + return 13 + if str_eq(name, "r14") != 0: + return 14 + if str_eq(name, "r15") != 0: + return 15 + return -1 // 操作数码:角色 1..6 或寄存器字面量 16+regno;0 = 未知 -fn hit_operand_code(name: string) -> int { - rc := hit_role_code(name); - if rc != 0 { return rc; } - rn := hit_reg_code(name); - if rn >= 0 { return HIT_REG_BASE + rn; } - return 0; } +fn hit_operand_code(name: string) -> int: + rc := hit_role_code(name) + if rc != 0: + return rc + rn := hit_reg_code(name) + if rn >= 0: + return HIT_REG_BASE + rn + return 0 // base 键码:操作数码或 rip(32);0 = 未知 -fn hit_base_code(name: string) -> int { - oc := hit_operand_code(name); - if oc != 0 { return oc; } - if str_eq(name, "rip") != 0 { return HIT_CODE_RIP; } - return 0; } +fn hit_base_code(name: string) -> int: + oc := hit_operand_code(name) + if oc != 0: + return oc + if str_eq(name, "rip") != 0: + return HIT_CODE_RIP + return 0 // 2^n(按位或不存在,倍增) -fn hit_bit(n: int) -> int { - b : int, mut = 1; - i : int, mut = 0; - loop { - if i >= n { break; } - b = b * 2; - i = i + 1; } - return b; } +fn hit_bit(n: int) -> int: + b : int, mut = 1 + i : int, mut = 0 + loop: + if i >= n: + break + b = b * 2 + i = i + 1 + return b -fn hit_err_ev(ev_id: int) { - print("error: HIT table: event "); print_i(ev_id); print(": "); } +fn hit_err_ev(ev_id: int): + print("error: HIT table: event ") + print_i(ev_id) + print(": ") -fn hit_err_step(ev_id: int, step_no: int) { - print("error: HIT table: event "); print_i(ev_id); print(" step "); print_i(step_no); print(": "); } +fn hit_err_step(ev_id: int, step_no: int): + print("error: HIT table: event ") + print_i(ev_id) + print(" step ") + print_i(step_no) + print(": ") // ════════════════════════════════════════════════════════════════ // schema v2 步字段解析(模板语言核心) @@ -459,519 +582,648 @@ fn hit_err_step(ev_id: int, step_no: int) { // text = 一个 [[event.proj.step]] 小节全文(或 v1 平铺投影的 proj 层文本—— // isa_ok = 1 时允许 isa 键混于其中)。解析成功 → 追加一条 108B 步记录。 // Returns 0 = 成功;1 = 失败(错误已打印)。 -fn hit_parse_step(text: string, ev_id: int, step_no: int, isa_ok: int) -> int { - if isa_ok == 1 { - if hit_scan_keys_ok(text, "isa prefix opcode rex_w rex_r rex_x rex_b modrm_reg_role modrm_reg_digit modrm_rm_role rm_mode modrm_base_role sib_scale sib_index_role sib_base_role disp_size disp_src imm_size imm_role imm_lit imm_kind rel_role rel_kind rel_size cond_role") != 0 { return 1; } - } else { - if hit_scan_keys_ok(text, "prefix opcode rex_w rex_r rex_x rex_b modrm_reg_role modrm_reg_digit modrm_rm_role rm_mode modrm_base_role sib_scale sib_index_role sib_base_role disp_size disp_src imm_size imm_role imm_lit imm_kind rel_role rel_kind rel_size cond_role") != 0 { return 1; } - } +fn hit_parse_step(text: string, ev_id: int, step_no: int, isa_ok: int) -> int: + if isa_ok == 1: + if hit_scan_keys_ok(text, "isa prefix opcode rex_w rex_r rex_x rex_b modrm_reg_role modrm_reg_digit modrm_rm_role rm_mode modrm_base_role sib_scale sib_index_role sib_base_role disp_size disp_src imm_size imm_role imm_lit imm_kind rel_role rel_kind rel_size cond_role") != 0: + return 1 + else: + if hit_scan_keys_ok(text, "prefix opcode rex_w rex_r rex_x rex_b modrm_reg_role modrm_reg_digit modrm_rm_role rm_mode modrm_base_role sib_scale sib_index_role sib_base_role disp_size disp_src imm_size imm_role imm_lit imm_kind rel_role rel_kind rel_size cond_role") != 0: + return 1 // ── 输出记录字段(函数顶给默认值;各组按需覆盖)── - op0 : int, mut = 0; op1 : int, mut = 0; - reg_code : int, mut = 0; is_digit : int, mut = 0; digit_val : int, mut = 0; - rm_code : int, mut = 0; rm_mode : int, mut = 0; - base_code : int, mut = 0; scl_val : int, mut = 0; idx_code : int, mut = 0; - dsz_code : int, mut = 0; dsrc_code : int, mut = 0; - isz_val : int, mut = 0; iro_code : int, mut = 0; ik_val : int, mut = 0; ilit_val : int, mut = 0; - rro_code : int, mut = 0; rk_val : int, mut = 0; rs_val : int, mut = 0; - cond_code : int, mut = 0; - rex_byte : int, mut = 0; npf : int, mut = 0; - pfx0 : int, mut = 0; pfx1 : int, mut = 0; + op0 : int, mut = 0 + op1 : int, mut = 0 + reg_code : int, mut = 0 + is_digit : int, mut = 0 + digit_val : int, mut = 0 + rm_code : int, mut = 0 + rm_mode : int, mut = 0 + base_code : int, mut = 0 + scl_val : int, mut = 0 + idx_code : int, mut = 0 + dsz_code : int, mut = 0 + dsrc_code : int, mut = 0 + isz_val : int, mut = 0 + iro_code : int, mut = 0 + ik_val : int, mut = 0 + ilit_val : int, mut = 0 + rro_code : int, mut = 0 + rk_val : int, mut = 0 + rs_val : int, mut = 0 + cond_code : int, mut = 0 + rex_byte : int, mut = 0 + npf : int, mut = 0 + pfx0 : int, mut = 0 + pfx1 : int, mut = 0 // ── rex 位(出现则须 0/1;任一出现且值 1 才产生 REX 字节)── - rwp := hit_has_key(text, "rex_w"); - rrp := hit_has_key(text, "rex_r"); - rxp := hit_has_key(text, "rex_x"); - rbp := hit_has_key(text, "rex_b"); - rw : int, mut = 0; rr : int, mut = 0; rx : int, mut = 0; rb : int, mut = 0; - if rwp == 1 { rw = toml_get_int(text, "rex_w"); } - if rrp == 1 { rr = toml_get_int(text, "rex_r"); } - if rxp == 1 { rx = toml_get_int(text, "rex_x"); } - if rbp == 1 { rb = toml_get_int(text, "rex_b"); } - if rwp == 1 && (rw < 0 || rw > 1) { hit_err_step(ev_id, step_no); println("bad rex bit"); return 1; } - if rrp == 1 && (rr < 0 || rr > 1) { hit_err_step(ev_id, step_no); println("bad rex bit"); return 1; } - if rxp == 1 && (rx < 0 || rx > 1) { hit_err_step(ev_id, step_no); println("bad rex bit"); return 1; } - if rbp == 1 && (rb < 0 || rb > 1) { hit_err_step(ev_id, step_no); println("bad rex bit"); return 1; } - if (rwp == 1 && rw == 1) || (rrp == 1 && rr == 1) || - (rxp == 1 && rx == 1) || (rbp == 1 && rb == 1) { - rex_byte = 0x40; - if rwp == 1 && rw == 1 { rex_byte = rex_byte + 8; } - if rrp == 1 && rr == 1 { rex_byte = rex_byte + 4; } - if rxp == 1 && rx == 1 { rex_byte = rex_byte + 2; } - if rbp == 1 && rb == 1 { rex_byte = rex_byte + 1; } - } + rwp := hit_has_key(text, "rex_w") + rrp := hit_has_key(text, "rex_r") + rxp := hit_has_key(text, "rex_x") + rbp := hit_has_key(text, "rex_b") + rw : int, mut = 0 + rr : int, mut = 0 + rx : int, mut = 0 + rb : int, mut = 0 + if rwp == 1: + rw = toml_get_int(text, "rex_w") + if rrp == 1: + rr = toml_get_int(text, "rex_r") + if rxp == 1: + rx = toml_get_int(text, "rex_x") + if rbp == 1: + rb = toml_get_int(text, "rex_b") + if rwp == 1 && (rw < 0 || rw > 1): + hit_err_step(ev_id, step_no) + println("bad rex bit") + return 1 + if rrp == 1 && (rr < 0 || rr > 1): + hit_err_step(ev_id, step_no) + println("bad rex bit") + return 1 + if rxp == 1 && (rx < 0 || rx > 1): + hit_err_step(ev_id, step_no) + println("bad rex bit") + return 1 + if rbp == 1 && (rb < 0 || rb > 1): + hit_err_step(ev_id, step_no) + println("bad rex bit") + return 1 + if (rwp == 1 && rw == 1) || (rrp == 1 && rr == 1) || (rxp == 1 && rx == 1) || (rbp == 1 && rb == 1): + rex_byte = 0x40 + if rwp == 1 && rw == 1: + rex_byte = rex_byte + 8 + if rrp == 1 && rr == 1: + rex_byte = rex_byte + 4 + if rxp == 1 && rx == 1: + rex_byte = rex_byte + 2 + if rbp == 1 && rb == 1: + rex_byte = rex_byte + 1 // ── prefix(≤2 字节;每字节 ≤255)── - if hit_has_key(text, "prefix") == 1 { - pfb := alloc(16); - npf = toml_get_int_list(text, "prefix", pfb, 3); - if npf < 0 { - hit_err_step(ev_id, step_no); println("prefix missing/malformed"); - return 1; } - if npf > 2 { - hit_err_step(ev_id, step_no); println("prefix >2 bytes"); - return 1; } - j : int, mut = 0; - loop { - if j >= npf { break; } - if hit_r32(pfb, j * 4) > 255 { - hit_err_step(ev_id, step_no); println("prefix byte >255 (not a byte)"); - return 1; } - j = j + 1; } - if npf >= 1 { pfx0 = hit_r32(pfb, 0); } - if npf >= 2 { pfx1 = hit_r32(pfb, 4); } - } + if hit_has_key(text, "prefix") == 1: + pfb := alloc(16) + npf = toml_get_int_list(text, "prefix", pfb, 3) + if npf < 0: + hit_err_step(ev_id, step_no) + println("prefix missing/malformed") + return 1 + if npf > 2: + hit_err_step(ev_id, step_no) + println("prefix >2 bytes") + return 1 + j : int, mut = 0 + loop: + if j >= npf: + break + if hit_r32(pfb, j * 4) > 255: + hit_err_step(ev_id, step_no) + println("prefix byte >255 (not a byte)") + return 1 + j = j + 1 + if npf >= 1: + pfx0 = hit_r32(pfb, 0) + if npf >= 2: + pfx1 = hit_r32(pfb, 4) // ── opcode(必选,1..3 字节;每字节 ≤255)── - opc_p := hit_has_key(text, "opcode"); - opb := alloc(16); - nop := toml_get_int_list(text, "opcode", opb, 4); - if opc_p == 0 || nop < 1 { - hit_err_step(ev_id, step_no); println("opcode missing/malformed"); - return 1; } - if nop > 3 { - hit_err_step(ev_id, step_no); println("opcode >3 bytes"); - return 1; } - j : int, mut = 0; - loop { - if j >= nop { break; } - if hit_r32(opb, j * 4) > 255 { - hit_err_step(ev_id, step_no); println("opcode byte >255 (not a byte)"); - return 1; } - j = j + 1; } + opc_p := hit_has_key(text, "opcode") + opb := alloc(16) + nop := toml_get_int_list(text, "opcode", opb, 4) + if opc_p == 0 || nop < 1: + hit_err_step(ev_id, step_no) + println("opcode missing/malformed") + return 1 + if nop > 3: + hit_err_step(ev_id, step_no) + println("opcode >3 bytes") + return 1 + j : int, mut = 0 + loop: + if j >= nop: + break + if hit_r32(opb, j * 4) > 255: + hit_err_step(ev_id, step_no) + println("opcode byte >255 (not a byte)") + return 1 + j = j + 1 // ── modrm 族关联校验(键出现才算族;各组字段按需自校验)── - h_role := hit_has_key(text, "modrm_reg_role"); - h_digit := hit_has_key(text, "modrm_reg_digit"); - h_rm := hit_has_key(text, "modrm_rm_role"); - h_mode := hit_has_key(text, "rm_mode"); - h_base := hit_has_key(text, "modrm_base_role"); - h_scl := hit_has_key(text, "sib_scale"); - h_sidx := hit_has_key(text, "sib_index_role"); - h_sbas := hit_has_key(text, "sib_base_role"); - h_dsz := hit_has_key(text, "disp_size"); - h_dsrc := hit_has_key(text, "disp_src"); - grp := h_role + h_digit + h_rm + h_mode + h_base + h_scl + h_sidx + h_sbas + h_dsz + h_dsrc; - if grp > 0 { - if h_role == 1 && h_digit == 1 { - hit_err_step(ev_id, step_no); println("modrm reg role and digit both present"); - return 1; } - if h_role == 0 && h_digit == 0 { - hit_err_step(ev_id, step_no); println("modrm reg role/digit missing"); - return 1; } - if h_role == 1 { - reg_code = hit_operand_code(toml_get_str(text, "modrm_reg_role")); - if reg_code == 0 { - hit_err_step(ev_id, step_no); println("unknown modrm role"); - return 1; } - } else { - digit_val = toml_get_int(text, "modrm_reg_digit"); - if digit_val < 0 || digit_val > 7 { - hit_err_step(ev_id, step_no); println("bad reg digit"); - return 1; } - is_digit = 1; - } - if h_rm == 0 { - hit_err_step(ev_id, step_no); println("modrm rm role missing"); - return 1; } - rm_code = hit_operand_code(toml_get_str(text, "modrm_rm_role")); - if rm_code == 0 { - hit_err_step(ev_id, step_no); println("unknown modrm role"); - return 1; } - if h_mode == 1 { - rm_mode = toml_get_int(text, "rm_mode"); - if rm_mode < 0 || rm_mode > 2 { - hit_err_step(ev_id, step_no); println("bad rm_mode"); - return 1; } - } - if h_scl + h_sidx + h_sbas > 0 && rm_mode != 2 { - hit_err_step(ev_id, step_no); println("sib fields need rm_mode 2"); - return 1; } - if rm_mode == 2 && (h_scl == 0 || h_sbas == 0) { - hit_err_step(ev_id, step_no); println("rm_mode 2 needs sib_scale and sib_base_role"); - return 1; } - if h_base == 1 && rm_mode == 0 { - hit_err_step(ev_id, step_no); println("modrm_base_role needs rm_mode 1/2"); - return 1; } - if h_base == 1 && rm_mode == 1 { - base_code = hit_base_code(toml_get_str(text, "modrm_base_role")); - if base_code == 0 { - hit_err_step(ev_id, step_no); println("bad modrm_base_role"); - return 1; } - } - if (h_dsz + h_dsrc > 0) && rm_mode == 0 { - hit_err_step(ev_id, step_no); println("disp needs rm_mode 1/2"); - return 1; } - if rm_mode == 2 { - scl_val = toml_get_int(text, "sib_scale"); - if scl_val < 0 || scl_val > 3 { - hit_err_step(ev_id, step_no); println("bad sib_scale"); - return 1; } - if h_sidx == 1 { - idx_code = hit_operand_code(toml_get_str(text, "sib_index_role")); - if idx_code == 0 { - hit_err_step(ev_id, step_no); println("bad sib_index_role"); - return 1; } - } - base_code = hit_base_code(toml_get_str(text, "sib_base_role")); - if base_code == 0 { - hit_err_step(ev_id, step_no); println("bad sib_base_role"); - return 1; } - } - if h_dsz == 1 { - dv := hit_raw_str(text, "disp_size"); - if str_len(dv) >= 2 && load8(dv, 0) == 34 && load8(dv, str_len(dv) - 1) == 34 { - dv = str_sub(dv, 1, str_len(dv) - 2); } - dv_ok : int, mut = 0; - if str_eq(dv, "auto") != 0 { dsz_code = 0; dv_ok = 1; } - if str_eq(dv, "1") != 0 { dsz_code = 1; dv_ok = 1; } - if str_eq(dv, "4") != 0 { dsz_code = 4; dv_ok = 1; } - if dv_ok == 0 { - hit_err_step(ev_id, step_no); println("bad disp_size"); - return 1; } - } - if h_dsrc == 1 { - dsrc_code = hit_operand_code(toml_get_str(text, "disp_src")); - if dsrc_code == 0 { - hit_err_step(ev_id, step_no); println("bad disp_src"); - return 1; } - } - } + h_role := hit_has_key(text, "modrm_reg_role") + h_digit := hit_has_key(text, "modrm_reg_digit") + h_rm := hit_has_key(text, "modrm_rm_role") + h_mode := hit_has_key(text, "rm_mode") + h_base := hit_has_key(text, "modrm_base_role") + h_scl := hit_has_key(text, "sib_scale") + h_sidx := hit_has_key(text, "sib_index_role") + h_sbas := hit_has_key(text, "sib_base_role") + h_dsz := hit_has_key(text, "disp_size") + h_dsrc := hit_has_key(text, "disp_src") + grp := h_role + h_digit + h_rm + h_mode + h_base + h_scl + h_sidx + h_sbas + h_dsz + h_dsrc + if grp > 0: + if h_role == 1 && h_digit == 1: + hit_err_step(ev_id, step_no) + println("modrm reg role and digit both present") + return 1 + if h_role == 0 && h_digit == 0: + hit_err_step(ev_id, step_no) + println("modrm reg role/digit missing") + return 1 + if h_role == 1: + reg_code = hit_operand_code(toml_get_str(text, "modrm_reg_role")) + if reg_code == 0: + hit_err_step(ev_id, step_no) + println("unknown modrm role") + return 1 + else: + digit_val = toml_get_int(text, "modrm_reg_digit") + if digit_val < 0 || digit_val > 7: + hit_err_step(ev_id, step_no) + println("bad reg digit") + return 1 + is_digit = 1 + if h_rm == 0: + hit_err_step(ev_id, step_no) + println("modrm rm role missing") + return 1 + rm_code = hit_operand_code(toml_get_str(text, "modrm_rm_role")) + if rm_code == 0: + hit_err_step(ev_id, step_no) + println("unknown modrm role") + return 1 + if h_mode == 1: + rm_mode = toml_get_int(text, "rm_mode") + if rm_mode < 0 || rm_mode > 2: + hit_err_step(ev_id, step_no) + println("bad rm_mode") + return 1 + if h_scl + h_sidx + h_sbas > 0 && rm_mode != 2: + hit_err_step(ev_id, step_no) + println("sib fields need rm_mode 2") + return 1 + if rm_mode == 2 && (h_scl == 0 || h_sbas == 0): + hit_err_step(ev_id, step_no) + println("rm_mode 2 needs sib_scale and sib_base_role") + return 1 + if h_base == 1 && rm_mode == 0: + hit_err_step(ev_id, step_no) + println("modrm_base_role needs rm_mode 1/2") + return 1 + if h_base == 1 && rm_mode == 1: + base_code = hit_base_code(toml_get_str(text, "modrm_base_role")) + if base_code == 0: + hit_err_step(ev_id, step_no) + println("bad modrm_base_role") + return 1 + if (h_dsz + h_dsrc > 0) && rm_mode == 0: + hit_err_step(ev_id, step_no) + println("disp needs rm_mode 1/2") + return 1 + if rm_mode == 2: + scl_val = toml_get_int(text, "sib_scale") + if scl_val < 0 || scl_val > 3: + hit_err_step(ev_id, step_no) + println("bad sib_scale") + return 1 + if h_sidx == 1: + idx_code = hit_operand_code(toml_get_str(text, "sib_index_role")) + if idx_code == 0: + hit_err_step(ev_id, step_no) + println("bad sib_index_role") + return 1 + base_code = hit_base_code(toml_get_str(text, "sib_base_role")) + if base_code == 0: + hit_err_step(ev_id, step_no) + println("bad sib_base_role") + return 1 + if h_dsz == 1: + dv := hit_raw_str(text, "disp_size") + if str_len(dv) >= 2 && load8(dv, 0) == 34 && load8(dv, str_len(dv) - 1) == 34: + dv = str_sub(dv, 1, str_len(dv) - 2) + dv_ok : int, mut = 0 + if str_eq(dv, "auto") != 0: + dsz_code = 0 + dv_ok = 1 + if str_eq(dv, "1") != 0: + dsz_code = 1 + dv_ok = 1 + if str_eq(dv, "4") != 0: + dsz_code = 4 + dv_ok = 1 + if dv_ok == 0: + hit_err_step(ev_id, step_no) + println("bad disp_size") + return 1 + if h_dsrc == 1: + dsrc_code = hit_operand_code(toml_get_str(text, "disp_src")) + if dsrc_code == 0: + hit_err_step(ev_id, step_no) + println("bad disp_src") + return 1 // ── imm 族(与 modrm 族无关:字面量/回填载体)── - h_isz := hit_has_key(text, "imm_size"); - h_iro := hit_has_key(text, "imm_role"); - h_ik := hit_has_key(text, "imm_kind"); - h_ilit := hit_has_key(text, "imm_lit"); - if h_isz == 1 { - isz_val = toml_get_int(text, "imm_size"); - if isz_val != 1 && isz_val != 2 && isz_val != 4 && isz_val != 8 { - hit_err_step(ev_id, step_no); println("bad imm_size"); - return 1; } - if h_iro == 0 && h_ik == 0 { - hit_err_step(ev_id, step_no); println("imm_size without imm_role/imm_kind"); - return 1; } - } - if h_iro == 1 { - inm := toml_get_str(text, "imm_role"); - if str_eq(inm, "lit") != 0 { iro_code = HIT_CODE_LIT; } - else { - iro_code = hit_operand_code(inm); - if iro_code == 0 { - hit_err_step(ev_id, step_no); println("bad imm_role"); - return 1; } - } - } - if h_ik == 1 { - if str_eq(toml_get_str(text, "imm_kind"), "fnaddr") == 0 { - hit_err_step(ev_id, step_no); println("bad imm_kind"); - return 1; } - if h_isz == 0 || isz_val != 8 { - hit_err_step(ev_id, step_no); println("imm_kind fnaddr needs imm_size 8"); - return 1; } - ik_val = HIT_IMM_FNADDR; - } - if h_ilit == 1 { - ilit_val = toml_get_int(text, "imm_lit"); - if ilit_val < 0 { - hit_err_step(ev_id, step_no); println("bad imm_lit (negative unsupported)"); - return 1; } - } + h_isz := hit_has_key(text, "imm_size") + h_iro := hit_has_key(text, "imm_role") + h_ik := hit_has_key(text, "imm_kind") + h_ilit := hit_has_key(text, "imm_lit") + if h_isz == 1: + isz_val = toml_get_int(text, "imm_size") + if isz_val != 1 && isz_val != 2 && isz_val != 4 && isz_val != 8: + hit_err_step(ev_id, step_no) + println("bad imm_size") + return 1 + if h_iro == 0 && h_ik == 0: + hit_err_step(ev_id, step_no) + println("imm_size without imm_role/imm_kind") + return 1 + if h_iro == 1: + inm := toml_get_str(text, "imm_role") + if str_eq(inm, "lit") != 0: + iro_code = HIT_CODE_LIT + else: + iro_code = hit_operand_code(inm) + if iro_code == 0: + hit_err_step(ev_id, step_no) + println("bad imm_role") + return 1 + if h_ik == 1: + if str_eq(toml_get_str(text, "imm_kind"), "fnaddr") == 0: + hit_err_step(ev_id, step_no) + println("bad imm_kind") + return 1 + if h_isz == 0 || isz_val != 8: + hit_err_step(ev_id, step_no) + println("imm_kind fnaddr needs imm_size 8") + return 1 + ik_val = HIT_IMM_FNADDR + if h_ilit == 1: + ilit_val = toml_get_int(text, "imm_lit") + if ilit_val < 0: + hit_err_step(ev_id, step_no) + println("bad imm_lit (negative unsupported)") + return 1 // ── rel 族(三字段同现;kind = event/func/extern;size = 8/32)── - h_rro := hit_has_key(text, "rel_role"); - h_rk := hit_has_key(text, "rel_kind"); - h_rs := hit_has_key(text, "rel_size"); - if h_rro + h_rk + h_rs > 0 { - if h_rro == 0 || h_rk == 0 || h_rs == 0 { - hit_err_step(ev_id, step_no); println("rel fields incomplete (role/kind/size)"); - return 1; } - rkn := toml_get_str(text, "rel_kind"); - if str_eq(rkn, "event") == 0 && str_eq(rkn, "func") == 0 && str_eq(rkn, "extern") == 0 { - hit_err_step(ev_id, step_no); println("bad rel kind"); - return 1; } - if str_eq(rkn, "event") != 0 { rk_val = HIT_REL_EVENT; } - if str_eq(rkn, "func") != 0 { rk_val = HIT_REL_FUNC; } - if str_eq(rkn, "extern") != 0 { rk_val = HIT_REL_EXTERN; } - rs_val = toml_get_int(text, "rel_size"); - if rs_val != 8 && rs_val != 32 { - hit_err_step(ev_id, step_no); println("bad rel size"); - return 1; } - rro_code = hit_operand_code(toml_get_str(text, "rel_role")); - if rro_code == 0 { - hit_err_step(ev_id, step_no); println("bad rel role"); - return 1; } - } + h_rro := hit_has_key(text, "rel_role") + h_rk := hit_has_key(text, "rel_kind") + h_rs := hit_has_key(text, "rel_size") + if h_rro + h_rk + h_rs > 0: + if h_rro == 0 || h_rk == 0 || h_rs == 0: + hit_err_step(ev_id, step_no) + println("rel fields incomplete (role/kind/size)") + return 1 + rkn := toml_get_str(text, "rel_kind") + if str_eq(rkn, "event") == 0 && str_eq(rkn, "func") == 0 && str_eq(rkn, "extern") == 0: + hit_err_step(ev_id, step_no) + println("bad rel kind") + return 1 + if str_eq(rkn, "event") != 0: + rk_val = HIT_REL_EVENT + if str_eq(rkn, "func") != 0: + rk_val = HIT_REL_FUNC + if str_eq(rkn, "extern") != 0: + rk_val = HIT_REL_EXTERN + rs_val = toml_get_int(text, "rel_size") + if rs_val != 8 && rs_val != 32: + hit_err_step(ev_id, step_no) + println("bad rel size") + return 1 + rro_code = hit_operand_code(toml_get_str(text, "rel_role")) + if rro_code == 0: + hit_err_step(ev_id, step_no) + println("bad rel role") + return 1 // ── cond 键(branch 条件源槽)── - if hit_has_key(text, "cond_role") == 1 { - cond_code = hit_operand_code(toml_get_str(text, "cond_role")); - if cond_code == 0 { - hit_err_step(ev_id, step_no); println("bad cond_role"); - return 1; } - } + if hit_has_key(text, "cond_role") == 1: + cond_code = hit_operand_code(toml_get_str(text, "cond_role")) + if cond_code == 0: + hit_err_step(ev_id, step_no) + println("bad cond_role") + return 1 // ── 字节流组装(prefix → REX → opcode)+ 追加 108B 步记录 ── - stb := alloc(8); - nst : int, mut = 0; - if npf >= 1 { store8(stb, nst, pfx0); nst = nst + 1; } - if npf >= 2 { store8(stb, nst, pfx1); nst = nst + 1; } - if rex_byte != 0 { store8(stb, nst, rex_byte); nst = nst + 1; } - j = 0; - loop { - if j >= nop { break; } - store8(stb, nst, hit_r32(opb, j * 4)); - nst = nst + 1; - j = j + 1; } - if nst > 0 { op0 = load8(stb, 0); } - if nst > 1 { op1 = load8(stb, 1); } - hit_grow_steps(g_hit_step_count + 1); - sb := g_hit_step_count * HIT_STEP_REC; - g_hit_step_count = g_hit_step_count + 1; - hit_zero_bytes(g_hit_steps, sb, HIT_STEP_REC); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_OP0, op0); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_OP1, op1); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_REG_ROLE, reg_code); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_RM_ROLE, rm_code); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_RM_MODE, rm_mode); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_PFX0, pfx0); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_PFX1, pfx1); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_REX, rex_byte); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_OPB0, hit_r32(opb, 0)); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_OPB1, hit_r32(opb, 4)); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_OPB2, hit_r32(opb, 8)); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_OPN, nop); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_REG_IS_DIGIT, is_digit); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_REG_DIGIT, digit_val); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_BASE_ROLE, base_code); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_SIB_SCALE, scl_val); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_SIB_INDEX, idx_code); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_DISP_SIZE, dsz_code); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_DISP_SRC, dsrc_code); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_IMM_SIZE, isz_val); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_IMM_ROLE, iro_code); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_IMM_KIND, ik_val); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_IMM_LIT, ilit_val); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_REL_ROLE, rro_code); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_REL_KIND, rk_val); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_REL_SIZE, rs_val); - hit_w32(g_hit_steps, sb + HIT_ST_OFF_COND_ROLE, cond_code); - return 0; } + stb := alloc(8) + nst : int, mut = 0 + if npf >= 1: + store8(stb, nst, pfx0) + nst = nst + 1 + if npf >= 2: + store8(stb, nst, pfx1) + nst = nst + 1 + if rex_byte != 0: + store8(stb, nst, rex_byte) + nst = nst + 1 + j = 0 + loop: + if j >= nop: + break + store8(stb, nst, hit_r32(opb, j * 4)) + nst = nst + 1 + j = j + 1 + if nst > 0: + op0 = load8(stb, 0) + if nst > 1: + op1 = load8(stb, 1) + hit_grow_steps(g_hit_step_count + 1) + sb := g_hit_step_count * HIT_STEP_REC + g_hit_step_count = g_hit_step_count + 1 + hit_zero_bytes(g_hit_steps, sb, HIT_STEP_REC) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_OP0, op0) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_OP1, op1) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_REG_ROLE, reg_code) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_RM_ROLE, rm_code) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_RM_MODE, rm_mode) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_PFX0, pfx0) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_PFX1, pfx1) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_REX, rex_byte) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_OPB0, hit_r32(opb, 0)) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_OPB1, hit_r32(opb, 4)) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_OPB2, hit_r32(opb, 8)) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_OPN, nop) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_REG_IS_DIGIT, is_digit) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_REG_DIGIT, digit_val) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_BASE_ROLE, base_code) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_SIB_SCALE, scl_val) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_SIB_INDEX, idx_code) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_DISP_SIZE, dsz_code) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_DISP_SRC, dsrc_code) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_IMM_SIZE, isz_val) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_IMM_ROLE, iro_code) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_IMM_KIND, ik_val) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_IMM_LIT, ilit_val) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_REL_ROLE, rro_code) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_REL_KIND, rk_val) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_REL_SIZE, rs_val) + hit_w32(g_hit_steps, sb + HIT_ST_OFF_COND_ROLE, cond_code) + return 0 // ════════════════════════════════════════════════════════════════ // [[event.proj]] 投影小节解析(chunk 内 ph 处起;多步/平铺两形) // ════════════════════════════════════════════════════════════════ // Returns 0 = 成功;1 = 失败(错误已打印)。 -fn hit_parse_proj_section(chunk: string, ph: int, ev_id: int) -> int { - pl := hit_line_after(chunk, ph); +fn hit_parse_proj_section(chunk: string, ph: int, ev_id: int) -> int: + pl := hit_line_after(chunk, ph) // 本投影文本终点:平铺 = 下一 [[event.proj]](或块尾);步小节形 = 首步头 //(步头位于下一 proj 头之前才算本投影的步小节——防跨 proj 误配) - nxt_pr := hit_find_tag(chunk, pl, "[[event.proj]]"); - st_hdr := hit_find_tag(chunk, pl, "[[event.proj.step]]"); - sectioned : int, mut = 0; - pend : int, mut = str_len(chunk); - if st_hdr >= 0 && (nxt_pr < 0 || st_hdr < nxt_pr) { - sectioned = 1; - pend = st_hdr; } - else if nxt_pr >= 0 { - pend = nxt_pr; } - pfields := str_sub(chunk, pl, pend - pl); + nxt_pr := hit_find_tag(chunk, pl, "[[event.proj]]") + st_hdr := hit_find_tag(chunk, pl, "[[event.proj.step]]") + sectioned : int, mut = 0 + pend : int, mut = str_len(chunk) + if st_hdr >= 0 && (nxt_pr < 0 || st_hdr < nxt_pr): + sectioned = 1 + pend = st_hdr + else if nxt_pr >= 0: + pend = nxt_pr + pfields := str_sub(chunk, pl, pend - pl) // isa 必选且须为 x86-64(层级无关:平铺时 isa 混于步字段) - if str_eq(toml_get_str(pfields, "isa"), "x86-64") == 0 { - hit_err_ev(ev_id); println("unknown isa"); - return 1; } - first_step := g_hit_step_count; - scnt : int, mut = 0; - if sectioned == 0 { + if str_eq(toml_get_str(pfields, "isa"), "x86-64") == 0: + hit_err_ev(ev_id) + println("unknown isa") + return 1 + first_step := g_hit_step_count + scnt : int, mut = 0 + if sectioned == 0: // 平铺单步(v1 子集:isa 之外的字段 = 单步字段;白名单扫 = 步层全表) - if hit_parse_step(pfields, ev_id, 0, 1) != 0 { return 1; } - scnt = 1; } - else { - if hit_scan_keys_ok(pfields, "isa") != 0 { return 1; } + if hit_parse_step(pfields, ev_id, 0, 1) != 0: + return 1 + scnt = 1 + else: + if hit_scan_keys_ok(pfields, "isa") != 0: + return 1 // 步小节逐个解析(步文本终点 = 下一 step 头 / 下一 proj 头 / 块尾) - sp : int, mut = st_hdr; - loop { - if sp < 0 { break; } - sl := hit_line_after(chunk, sp); - ns := hit_find_tag(chunk, sl, "[[event.proj.step]]"); - np2 := hit_find_tag(chunk, sl, "[[event.proj]]"); - send : int, mut = str_len(chunk); - if ns >= 0 && ns < send { send = ns; } - if np2 >= 0 && np2 < send { send = np2; } - stext := str_sub(chunk, sl, send - sl); - if hit_parse_step(stext, ev_id, scnt, 0) != 0 { return 1; } - scnt = scnt + 1; + sp : int, mut = st_hdr + loop: + if sp < 0: + break + sl := hit_line_after(chunk, sp) + ns := hit_find_tag(chunk, sl, "[[event.proj.step]]") + np2 := hit_find_tag(chunk, sl, "[[event.proj]]") + send : int, mut = str_len(chunk) + if ns >= 0 && ns < send: + send = ns + if np2 >= 0 && np2 < send: + send = np2 + stext := str_sub(chunk, sl, send - sl) + if hit_parse_step(stext, ev_id, scnt, 0) != 0: + return 1 + scnt = scnt + 1 // 续行边界(Task 1 评审 fix):ns 在下一 proj 头之后 = 属于后续 // [[event.proj]] 的步小节——不得续入本投影(np2 只截步文本、不 // 终止循环;旧缺陷 = 静默吸收后续投影步:本投影步数膨胀 + 步 // 记录重复入库,多 proj 步小节事件加载成功但表已错) - if ns >= 0 && (np2 < 0 || ns < np2) { sp = ns; } - else { sp = -1; } } - if scnt == 0 { - hit_err_ev(ev_id); println("projection has no steps"); - return 1; } - } + if ns >= 0 && (np2 < 0 || ns < np2): + sp = ns + else: + sp = -1 + if scnt == 0: + hit_err_ev(ev_id) + println("projection has no steps") + return 1 // 追加投影记录(isa/步数/首步字节偏移) - hit_grow_projs(g_hit_proj_count + 1); - ps := g_hit_proj_count; - g_hit_proj_count = ps + 1; - hit_w32(g_hit_projs, ps * HIT_PROJ_REC + HIT_PJ_OFF_ISA, HIT_ISA_X86); - hit_w32(g_hit_projs, ps * HIT_PROJ_REC + HIT_PJ_OFF_STEP_COUNT, scnt); - hit_w32(g_hit_projs, ps * HIT_PROJ_REC + HIT_PJ_OFF_STEP_OFF, first_step * HIT_STEP_REC); - return 0; } + hit_grow_projs(g_hit_proj_count + 1) + ps := g_hit_proj_count + g_hit_proj_count = ps + 1 + hit_w32(g_hit_projs, ps * HIT_PROJ_REC + HIT_PJ_OFF_ISA, HIT_ISA_X86) + hit_w32(g_hit_projs, ps * HIT_PROJ_REC + HIT_PJ_OFF_STEP_COUNT, scnt) + hit_w32(g_hit_projs, ps * HIT_PROJ_REC + HIT_PJ_OFF_STEP_OFF, first_step * HIT_STEP_REC) + return 0 // ════════════════════════════════════════════════════════════════ // [[event]] 事件小节解析(含其全部投影小节) // ════════════════════════════════════════════════════════════════ // chunk = 自 "[[event]]" 行起、到下个节头前的文本(不含下一节)。 // Returns 0 = 成功;1 = 失败(错误已打印)。 -fn hit_parse_event_chunk(chunk: string) -> int { +fn hit_parse_event_chunk(chunk: string) -> int: // 事件字段区 = 头行后、首个 proj/step 小节前(step 在 proj 前 = 结构错) - fe := hit_line_after(chunk, 0); - p_off := hit_find_tag(chunk, fe, "[[event.proj]]"); - s_off := hit_find_tag(chunk, fe, "[[event.proj.step]]"); - if s_off >= 0 && (p_off < 0 || s_off < p_off) { - println("error: HIT table: stray [[event.proj.step]] before [[event.proj]]"); - return 1; } - fend : int, mut = str_len(chunk); - if p_off >= 0 && p_off < fend { fend = p_off; } - if s_off >= 0 && s_off < fend { fend = s_off; } - ev_text := str_sub(chunk, fe, fend - fe); - if hit_scan_keys_ok(ev_text, "id name arith inputs outputs side_effect") != 0 { return 1; } - id := toml_get_int(ev_text, "id"); - if id <= 0 { - println("error: HIT table: event missing or invalid id"); - return 1; } + fe := hit_line_after(chunk, 0) + p_off := hit_find_tag(chunk, fe, "[[event.proj]]") + s_off := hit_find_tag(chunk, fe, "[[event.proj.step]]") + if s_off >= 0 && (p_off < 0 || s_off < p_off): + println("error: HIT table: stray [[event.proj.step]] before [[event.proj]]") + return 1 + fend : int, mut = str_len(chunk) + if p_off >= 0 && p_off < fend: + fend = p_off + if s_off >= 0 && s_off < fend: + fend = s_off + ev_text := str_sub(chunk, fe, fend - fe) + if hit_scan_keys_ok(ev_text, "id name arith inputs outputs side_effect") != 0: + return 1 + id := toml_get_int(ev_text, "id") + if id <= 0: + println("error: HIT table: event missing or invalid id") + return 1 // 重复 id 检测 - k : int, mut = 0; - loop { - if k >= g_hit_event_count { break; } - if hit_r32(g_hit_events, k * HIT_EVENT_REC + HIT_EV_OFF_ID) == id { - print("error: HIT table: duplicate event id "); print_i(id); println(""); - return 1; } - k = k + 1; } - name := toml_get_str(ev_text, "name"); - if str_len(name) == 0 { - hit_err_ev(id); println("missing name"); - return 1; } - inputs := toml_get_int(ev_text, "inputs"); - outputs := toml_get_int(ev_text, "outputs"); - se := toml_get_str(ev_text, "side_effect"); - side : int, mut = -1; - if str_eq(se, "pure") != 0 { side = HIT_SIDE_PURE; } - if str_eq(se, "effect") != 0 { side = HIT_SIDE_EFFECT; } - if side < 0 { - hit_err_ev(id); println("bad side_effect"); - return 1; } + k : int, mut = 0 + loop: + if k >= g_hit_event_count: + break + if hit_r32(g_hit_events, k * HIT_EVENT_REC + HIT_EV_OFF_ID) == id: + print("error: HIT table: duplicate event id ") + print_i(id) + println("") + return 1 + k = k + 1 + name := toml_get_str(ev_text, "name") + if str_len(name) == 0: + hit_err_ev(id) + println("missing name") + return 1 + inputs := toml_get_int(ev_text, "inputs") + outputs := toml_get_int(ev_text, "outputs") + se := toml_get_str(ev_text, "side_effect") + side : int, mut = -1 + if str_eq(se, "pure") != 0: + side = HIT_SIDE_PURE + if str_eq(se, "effect") != 0: + side = HIT_SIDE_EFFECT + if side < 0: + hit_err_ev(id) + println("bad side_effect") + return 1 // 名字入名字表(8B/项存串指针;str_sub 副本 arena 存活) - hit_grow_names(g_hit_name_count + 1); - name_ni : int, mut = g_hit_name_count; - g_hit_name_count = name_ni + 1; - store_str_ptr(g_hit_names, name_ni * 8, name); + hit_grow_names(g_hit_name_count + 1) + name_ni : int, mut = g_hit_name_count + g_hit_name_count = name_ni + 1 + store_str_ptr(g_hit_names, name_ni * 8, name) // 事件行追加(proj 范围字段在投影解析后回填) - hit_grow_events(g_hit_event_count + 1); - slot := g_hit_event_count; - g_hit_event_count = slot + 1; - hit_zero_bytes(g_hit_events, slot * HIT_EVENT_REC, HIT_EVENT_REC); - hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_ID, id); - hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_NAME, name_ni); - hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_INPUTS, inputs); - hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_OUTPUTS, outputs); - hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_SIDE, side); + hit_grow_events(g_hit_event_count + 1) + slot := g_hit_event_count + g_hit_event_count = slot + 1 + hit_zero_bytes(g_hit_events, slot * HIT_EVENT_REC, HIT_EVENT_REC) + hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_ID, id) + hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_NAME, name_ni) + hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_INPUTS, inputs) + hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_OUTPUTS, outputs) + hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_SIDE, side) // 投影小节(多 proj:事件 32/36 记范围;20/24/28 = proj0 镜像) - first_proj : int, mut = g_hit_proj_count; - pcount : int, mut = 0; - hpos : int, mut = fend; - loop { - ph := hit_find_tag(chunk, hpos, "[[event.proj]]"); - if ph < 0 { break; } - pcount = pcount + 1; - if hit_parse_proj_section(chunk, ph, id) != 0 { return 1; } - hpos = ph + 1; } - if pcount == 0 { - hit_err_ev(id); println("missing [[event.proj]]"); - return 1; } - hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_OFF, first_proj); - hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_COUNT, pcount); + first_proj : int, mut = g_hit_proj_count + pcount : int, mut = 0 + hpos : int, mut = fend + loop: + ph := hit_find_tag(chunk, hpos, "[[event.proj]]") + if ph < 0: + break + pcount = pcount + 1 + if hit_parse_proj_section(chunk, ph, id) != 0: + return 1 + hpos = ph + 1 + if pcount == 0: + hit_err_ev(id) + println("missing [[event.proj]]") + return 1 + hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_OFF, first_proj) + hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_COUNT, pcount) // proj0 镜像(M1 消费方视区:isa/步数/首步字节偏移) - p0 := first_proj * HIT_PROJ_REC; + p0 := first_proj * HIT_PROJ_REC hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_ISA, - hit_r32(g_hit_projs, p0 + HIT_PJ_OFF_ISA)); + hit_r32(g_hit_projs, p0 + HIT_PJ_OFF_ISA)) hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_STEP_COUNT, - hit_r32(g_hit_projs, p0 + HIT_PJ_OFF_STEP_COUNT)); + hit_r32(g_hit_projs, p0 + HIT_PJ_OFF_STEP_COUNT)) hit_w32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_STEP_OFF, - hit_r32(g_hit_projs, p0 + HIT_PJ_OFF_STEP_OFF)); - return 0; } + hit_r32(g_hit_projs, p0 + HIT_PJ_OFF_STEP_OFF)) + return 0 // ════════════════════════════════════════════════════════════════ // [runtime.x86] 运行时小节(spec §6 最小描述;可选小节,出现则 8 键齐备) // ════════════════════════════════════════════════════════════════ // chunk = 自 "[runtime.x86]" 行起、到下个节头前的文本(不含下一节)。 // Returns 0 = 成功;1 = 失败(错误已打印)。 -fn hit_parse_runtime_chunk(chunk: string) -> int { - fe := hit_line_after(chunk, 0); - text := str_sub(chunk, fe, str_len(chunk) - fe); - if hit_scan_keys_ok(text, "call_mechanism call_ret_addr call_stack_grow param_mode param_regs save_regs extern_entry extern_resolve") != 0 { return 1; } +fn hit_parse_runtime_chunk(chunk: string) -> int: + fe := hit_line_after(chunk, 0) + text := str_sub(chunk, fe, str_len(chunk) - fe) + if hit_scan_keys_ok(text, "call_mechanism call_ret_addr call_stack_grow param_mode param_regs save_regs extern_entry extern_resolve") != 0: + return 1 // 8 键齐备 - if hit_has_key(text, "call_mechanism") == 0 { println("error: HIT table: runtime section missing call_mechanism"); return 1; } - if hit_has_key(text, "call_ret_addr") == 0 { println("error: HIT table: runtime section missing call_ret_addr"); return 1; } - if hit_has_key(text, "call_stack_grow") == 0 { println("error: HIT table: runtime section missing call_stack_grow"); return 1; } - if hit_has_key(text, "param_mode") == 0 { println("error: HIT table: runtime section missing param_mode"); return 1; } - if hit_has_key(text, "param_regs") == 0 { println("error: HIT table: runtime section missing param_regs"); return 1; } - if hit_has_key(text, "save_regs") == 0 { println("error: HIT table: runtime section missing save_regs"); return 1; } - if hit_has_key(text, "extern_entry") == 0 { println("error: HIT table: runtime section missing extern_entry"); return 1; } - if hit_has_key(text, "extern_resolve") == 0 { println("error: HIT table: runtime section missing extern_resolve"); return 1; } - rt := alloc(32); + if hit_has_key(text, "call_mechanism") == 0: + println("error: HIT table: runtime section missing call_mechanism") + return 1 + if hit_has_key(text, "call_ret_addr") == 0: + println("error: HIT table: runtime section missing call_ret_addr") + return 1 + if hit_has_key(text, "call_stack_grow") == 0: + println("error: HIT table: runtime section missing call_stack_grow") + return 1 + if hit_has_key(text, "param_mode") == 0: + println("error: HIT table: runtime section missing param_mode") + return 1 + if hit_has_key(text, "param_regs") == 0: + println("error: HIT table: runtime section missing param_regs") + return 1 + if hit_has_key(text, "save_regs") == 0: + println("error: HIT table: runtime section missing save_regs") + return 1 + if hit_has_key(text, "extern_entry") == 0: + println("error: HIT table: runtime section missing extern_entry") + return 1 + if hit_has_key(text, "extern_resolve") == 0: + println("error: HIT table: runtime section missing extern_resolve") + return 1 + rt := alloc(32) // 机制枚举值(非 stack/pushed/down/regs/call_rel32/ext_rel → 拒) - if str_eq(toml_get_str(text, "call_mechanism"), "stack") == 0 { - println("error: HIT table: bad call_mechanism"); - return 1; } - hit_w32(rt, HIT_RT_CALL_MECHANISM * 4, 1); - if str_eq(toml_get_str(text, "call_ret_addr"), "pushed") == 0 { - println("error: HIT table: bad call_ret_addr"); - return 1; } - hit_w32(rt, HIT_RT_CALL_RET_ADDR * 4, 1); - if str_eq(toml_get_str(text, "call_stack_grow"), "down") == 0 { - println("error: HIT table: bad call_stack_grow"); - return 1; } - hit_w32(rt, HIT_RT_CALL_STACK_GROW * 4, 1); - pm := toml_get_str(text, "param_mode"); - if str_eq(pm, "regs") == 0 && str_eq(pm, "stack") == 0 { - println("error: HIT table: bad param_mode"); - return 1; } - if str_eq(pm, "regs") != 0 { hit_w32(rt, HIT_RT_PARAM_MODE * 4, 1); } - if str_eq(pm, "stack") != 0 { hit_w32(rt, HIT_RT_PARAM_MODE * 4, 2); } - if str_eq(toml_get_str(text, "extern_entry"), "call_rel32") == 0 { - println("error: HIT table: bad extern_entry"); - return 1; } - hit_w32(rt, HIT_RT_EXTERN_ENTRY * 4, 1); - if str_eq(toml_get_str(text, "extern_resolve"), "ext_rel") == 0 { - println("error: HIT table: bad extern_resolve"); - return 1; } - hit_w32(rt, HIT_RT_EXTERN_RESOLVE * 4, 1); + if str_eq(toml_get_str(text, "call_mechanism"), "stack") == 0: + println("error: HIT table: bad call_mechanism") + return 1 + hit_w32(rt, HIT_RT_CALL_MECHANISM * 4, 1) + if str_eq(toml_get_str(text, "call_ret_addr"), "pushed") == 0: + println("error: HIT table: bad call_ret_addr") + return 1 + hit_w32(rt, HIT_RT_CALL_RET_ADDR * 4, 1) + if str_eq(toml_get_str(text, "call_stack_grow"), "down") == 0: + println("error: HIT table: bad call_stack_grow") + return 1 + hit_w32(rt, HIT_RT_CALL_STACK_GROW * 4, 1) + pm := toml_get_str(text, "param_mode") + if str_eq(pm, "regs") == 0 && str_eq(pm, "stack") == 0: + println("error: HIT table: bad param_mode") + return 1 + if str_eq(pm, "regs") != 0: + hit_w32(rt, HIT_RT_PARAM_MODE * 4, 1) + if str_eq(pm, "stack") != 0: + hit_w32(rt, HIT_RT_PARAM_MODE * 4, 2) + if str_eq(toml_get_str(text, "extern_entry"), "call_rel32") == 0: + println("error: HIT table: bad extern_entry") + return 1 + hit_w32(rt, HIT_RT_EXTERN_ENTRY * 4, 1) + if str_eq(toml_get_str(text, "extern_resolve"), "ext_rel") == 0: + println("error: HIT table: bad extern_resolve") + return 1 + hit_w32(rt, HIT_RT_EXTERN_RESOLVE * 4, 1) // 寄存器掩码(空格分隔寄存器名 → regno 位集) - if hit_parse_reg_mask(toml_get_str(text, "param_regs"), rt, HIT_RT_PARAM_MASK * 4) != 0 { return 1; } - if hit_parse_reg_mask(toml_get_str(text, "save_regs"), rt, HIT_RT_SAVE_MASK * 4) != 0 { return 1; } - g_hit_runtime = rt; - g_hit_runtime_present = 1; - return 0; } + if hit_parse_reg_mask(toml_get_str(text, "param_regs"), rt, HIT_RT_PARAM_MASK * 4) != 0: + return 1 + if hit_parse_reg_mask(toml_get_str(text, "save_regs"), rt, HIT_RT_SAVE_MASK * 4) != 0: + return 1 + g_hit_runtime = rt + g_hit_runtime_present = 1 + return 0 // 寄存器掩码解析(空格分隔名列表 → 位掩码写 rt+pos);0 = 成功;1 = 未知名(已打印) -fn hit_parse_reg_mask(raw: string, rt: string, pos: int) -> int { - rlen := str_len(raw); - mask : int, mut = 0; - p : int, mut = 0; - loop { - if p >= rlen { break; } - loop { - if p >= rlen { break; } - if load8(raw, p) == 32 { p = p + 1; } else { break; } } - if p >= rlen { break; } - e : int, mut = p; - loop { - if e >= rlen { break; } - if load8(raw, e) == 32 { break; } - e = e + 1; } - rn := hit_reg_code(str_sub(raw, p, e - p)); - if rn < 0 { - print("error: HIT table: runtime unknown register '"); - print(str_sub(raw, p, e - p)); println("'"); - return 1; } - mask = mask + hit_bit(rn); - p = e; } - hit_w32(rt, pos, mask); - return 0; } +fn hit_parse_reg_mask(raw: string, rt: string, pos: int) -> int: + rlen := str_len(raw) + mask : int, mut = 0 + p : int, mut = 0 + loop: + if p >= rlen: + break + loop: + if p >= rlen: + break + if load8(raw, p) == 32: + p = p + 1 + else: + break + if p >= rlen: + break + e : int, mut = p + loop: + if e >= rlen: + break + if load8(raw, e) == 32: + break + e = e + 1 + rn := hit_reg_code(str_sub(raw, p, e - p)) + if rn < 0: + print("error: HIT table: runtime unknown register '") + print(str_sub(raw, p, e - p)) + println("'") + return 1 + mask = mask + hit_bit(rn) + p = e + hit_w32(rt, pos, mask) + return 0 // ════════════════════════════════════════════════════════════════ // 公共接口(M1 Task 1 契约 + M2a Task 1 扩展) @@ -981,186 +1233,238 @@ fn hit_parse_reg_mask(raw: string, rt: string, pos: int) -> int { // 重复调用覆盖旧表)。[[event]] 与 [runtime.x86] 小节按出现序任意交错解析 //(runtime 可夹在事件间,尾部追加事件亦可)。Returns 0 = 成功;1 = 失败 //(错误已打印,表不可用)。 -fn load_hit_table(path: string) -> int { - content := read_file(path); - if str_len(content) == 0 { - print("error: cannot open HIT table: "); println(path); - return 1; } - g_hit_event_count = 0; - g_hit_step_count = 0; - g_hit_proj_count = 0; - g_hit_name_count = 0; - g_hit_runtime_present = 0; - expected := toml_get_int(content, "events"); // [table] events(缺省 0 → 尾部校验兜底) - pos : int, mut = 0; - loop { - ev := hit_find_tag(content, pos, "[[event]]"); - rt := hit_find_tag(content, pos, "[runtime.x86]"); - if ev < 0 && rt < 0 { break; } - if ev < 0 || (rt >= 0 && rt < ev) { +fn load_hit_table(path: string) -> int: + content := read_file(path) + if str_len(content) == 0: + print("error: cannot open HIT table: ") + println(path) + return 1 + g_hit_event_count = 0 + g_hit_step_count = 0 + g_hit_proj_count = 0 + g_hit_name_count = 0 + g_hit_runtime_present = 0 + expected := toml_get_int(content, "events") // [table] events(缺省 0 → 尾部校验兜底) + pos : int, mut = 0 + loop: + ev := hit_find_tag(content, pos, "[[event]]") + rt := hit_find_tag(content, pos, "[runtime.x86]") + if ev < 0 && rt < 0: + break + if ev < 0 || (rt >= 0 && rt < ev): // [runtime.x86] 小节:到下一 [[event]] / 再一 runtime 头 / EOF 为止 - end : int, mut = str_len(content); - e2 := hit_find_tag(content, rt + 1, "[[event]]"); - r2 := hit_find_tag(content, rt + 1, "[runtime.x86]"); - if e2 >= 0 && e2 < end { end = e2; } - if r2 >= 0 && r2 < end { end = r2; } - chunk := str_sub(content, rt, end - rt); - if hit_parse_runtime_chunk(chunk) != 0 { return 1; } - pos = end; } - else { - end : int, mut = str_len(content); - e2 := hit_find_tag(content, ev + 1, "[[event]]"); - r2 := hit_find_tag(content, ev + 1, "[runtime.x86]"); - if e2 >= 0 && e2 < end { end = e2; } - if r2 >= 0 && r2 < end { end = r2; } - chunk := str_sub(content, ev, end - ev); - if hit_parse_event_chunk(chunk) != 0 { return 1; } - pos = end; } } - if g_hit_event_count == 0 { - println("error: HIT table: no [[event]] sections"); - return 1; } + end : int, mut = str_len(content) + e2 := hit_find_tag(content, rt + 1, "[[event]]") + r2 := hit_find_tag(content, rt + 1, "[runtime.x86]") + if e2 >= 0 && e2 < end: + end = e2 + if r2 >= 0 && r2 < end: + end = r2 + chunk := str_sub(content, rt, end - rt) + if hit_parse_runtime_chunk(chunk) != 0: + return 1 + pos = end + else: + end : int, mut = str_len(content) + e2 := hit_find_tag(content, ev + 1, "[[event]]") + r2 := hit_find_tag(content, ev + 1, "[runtime.x86]") + if e2 >= 0 && e2 < end: + end = e2 + if r2 >= 0 && r2 < end: + end = r2 + chunk := str_sub(content, ev, end - ev) + if hit_parse_event_chunk(chunk) != 0: + return 1 + pos = end + if g_hit_event_count == 0: + println("error: HIT table: no [[event]] sections") + return 1 // 注(M2a Task 1 评审记录):spec §2「运行时核事件 id 1-9 每表必具」与验证项 // 「缺事件…拒绝」的加载器强制在场检查暂缓——事件绑定 = Task 4 落地(届时 // 消费方按 id 查找自然暴露缺失),此处仅拦零事件与 [table] events 计数不符。 - if g_hit_event_count != expected { - print("error: HIT table: [table] events="); print_i(expected); - print(" parsed="); print_i(g_hit_event_count); println(" mismatch"); - return 1; } - return 0; } + if g_hit_event_count != expected: + print("error: HIT table: [table] events=") + print_i(expected) + print(" parsed=") + print_i(g_hit_event_count) + println(" mismatch") + return 1 + return 0 // 表模式激活态:加载成功(g_hit_event_count > 0)= 发射循环启用表优先 -fn hit_table_active() -> int { - if g_hit_event_count > 0 { return 1; } - return 0; } +fn hit_table_active() -> int: + if g_hit_event_count > 0: + return 1 + return 0 // 事件 id → 事件槽(记录下标);-1 = 无 -fn hit_event_lookup(id: int) -> int { - i : int, mut = 0; - loop { - if i >= g_hit_event_count { break; } - if hit_r32(g_hit_events, i * HIT_EVENT_REC + HIT_EV_OFF_ID) == id { return i; } - i = i + 1; } - return -1; } +fn hit_event_lookup(id: int) -> int: + i : int, mut = 0 + loop: + if i >= g_hit_event_count: + break + if hit_r32(g_hit_events, i * HIT_EVENT_REC + HIT_EV_OFF_ID) == id: + return i + i = i + 1 + return -1 // 事件名(诊断用;g_hit_names 表取串) -fn hit_event_name(slot: int) -> string { - if slot < 0 || slot >= g_hit_event_count { return ""; } - ni := hit_r32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_NAME); - if ni < 0 || ni >= g_hit_name_count { return ""; } - return load_str_ptr(g_hit_names, ni * 8); } +fn hit_event_name(slot: int) -> string: + if slot < 0 || slot >= g_hit_event_count: + return "" + ni := hit_r32(g_hit_events, slot * HIT_EVENT_REC + HIT_EV_OFF_NAME) + if ni < 0 || ni >= g_hit_name_count: + return "" + return load_str_ptr(g_hit_names, ni * 8) // 事件投影形态数;-1 = 事件槽非法 -fn hit_proj_count(event_slot: int) -> int { - if event_slot < 0 || event_slot >= g_hit_event_count { return -1; } - return hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_COUNT); } +fn hit_proj_count(event_slot: int) -> int: + if event_slot < 0 || event_slot >= g_hit_event_count: + return -1 + return hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_COUNT) // 事件第 proj_i 投影步数;-1 = 越界 -fn hit_proj_step_count(event_slot: int, proj_i: int) -> int { - if event_slot < 0 || event_slot >= g_hit_event_count { return -1; } - po := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_OFF); - pc := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_COUNT); - if proj_i < 0 || proj_i >= pc { return -1; } - return hit_r32(g_hit_projs, (po + proj_i) * HIT_PROJ_REC + HIT_PJ_OFF_STEP_COUNT); } +fn hit_proj_step_count(event_slot: int, proj_i: int) -> int: + if event_slot < 0 || event_slot >= g_hit_event_count: + return -1 + po := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_OFF) + pc := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_COUNT) + if proj_i < 0 || proj_i >= pc: + return -1 + return hit_r32(g_hit_projs, (po + proj_i) * HIT_PROJ_REC + HIT_PJ_OFF_STEP_COUNT) // 取事件第 proj_i 投影第 step_i 步:把该步 108B v2 记录原样复制到 out //(字段布局 = 上方 HIT_ST_OFF_* 常量序;调用方保证 ≥108B)。 // Returns 0 = 成功;-1 = 事件槽/proj/步号非法。 -fn hit_proj_step_get(event_slot: int, proj_i: int, step_i: int, out: string) -> int { - if event_slot < 0 || event_slot >= g_hit_event_count { return -1; } - po := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_OFF); - pc := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_COUNT); - if proj_i < 0 || proj_i >= pc { return -1; } - ps := (po + proj_i) * HIT_PROJ_REC; - sc := hit_r32(g_hit_projs, ps + HIT_PJ_OFF_STEP_COUNT); - if step_i < 0 || step_i >= sc { return -1; } - off := hit_r32(g_hit_projs, ps + HIT_PJ_OFF_STEP_OFF); - j : int, mut = 0; - loop { - if j >= HIT_STEP_REC { break; } - store8(out, j, load8(g_hit_steps, off + step_i * HIT_STEP_REC + j)); - j = j + 1; } - return 0; } +fn hit_proj_step_get(event_slot: int, proj_i: int, step_i: int, out: string) -> int: + if event_slot < 0 || event_slot >= g_hit_event_count: + return -1 + po := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_OFF) + pc := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_PROJ_COUNT) + if proj_i < 0 || proj_i >= pc: + return -1 + ps := (po + proj_i) * HIT_PROJ_REC + sc := hit_r32(g_hit_projs, ps + HIT_PJ_OFF_STEP_COUNT) + if step_i < 0 || step_i >= sc: + return -1 + off := hit_r32(g_hit_projs, ps + HIT_PJ_OFF_STEP_OFF) + j : int, mut = 0 + loop: + if j >= HIT_STEP_REC: + break + store8(out, j, load8(g_hit_steps, off + step_i * HIT_STEP_REC + j)) + j = j + 1 + return 0 // 取事件投影步(M1 契约 = proj0 视图):把该步记录原样复制到 out(调用方 // 保证 ≥HIT_STEP_REC;M1 消费方只读前 20B 视区 = 布局未变。事件 24/28 字段 // = proj0 镜像,语义与 M1 记录等价——单投影事件的 proj0 = 唯一投影)。 // Returns 0 = 成功;-1 = 事件槽/步号非法。 -fn hit_proj_step(event_slot: int, step_i: int, out: string) -> int { - if event_slot < 0 || event_slot >= g_hit_event_count { return -1; } - sc := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_STEP_COUNT); - if step_i < 0 || step_i >= sc { return -1; } - off := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_STEP_OFF); - j : int, mut = 0; - loop { - if j >= HIT_STEP_REC { break; } - store8(out, j, load8(g_hit_steps, off + step_i * HIT_STEP_REC + j)); - j = j + 1; } - return 0; } +fn hit_proj_step(event_slot: int, step_i: int, out: string) -> int: + if event_slot < 0 || event_slot >= g_hit_event_count: + return -1 + sc := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_STEP_COUNT) + if step_i < 0 || step_i >= sc: + return -1 + off := hit_r32(g_hit_events, event_slot * HIT_EVENT_REC + HIT_EV_OFF_STEP_OFF) + j : int, mut = 0 + loop: + if j >= HIT_STEP_REC: + break + store8(out, j, load8(g_hit_steps, off + step_i * HIT_STEP_REC + j)) + j = j + 1 + return 0 // 运行时条目查询:key = 8 键名之一(call_mechanism/call_ret_addr/ // call_stack_grow/param_mode/param_regs/save_regs/extern_entry/extern_resolve)。 // 值 = 4B 码或位掩码写入 out。Returns 0 = 已写;-1 = 无 runtime 小节/未知键。 -fn hit_runtime_get(key: string, out: string) -> int { - if g_hit_runtime_present == 0 { return -1; } - slot : int, mut = -1; - if str_eq(key, "call_mechanism") != 0 { slot = HIT_RT_CALL_MECHANISM; } - if str_eq(key, "call_ret_addr") != 0 { slot = HIT_RT_CALL_RET_ADDR; } - if str_eq(key, "call_stack_grow") != 0 { slot = HIT_RT_CALL_STACK_GROW; } - if str_eq(key, "param_mode") != 0 { slot = HIT_RT_PARAM_MODE; } - if str_eq(key, "param_regs") != 0 { slot = HIT_RT_PARAM_MASK; } - if str_eq(key, "save_regs") != 0 { slot = HIT_RT_SAVE_MASK; } - if str_eq(key, "extern_entry") != 0 { slot = HIT_RT_EXTERN_ENTRY; } - if str_eq(key, "extern_resolve") != 0 { slot = HIT_RT_EXTERN_RESOLVE; } - if slot < 0 { return -1; } - hit_w32(out, 0, hit_r32(g_hit_runtime, slot * 4)); - return 0; } +fn hit_runtime_get(key: string, out: string) -> int: + if g_hit_runtime_present == 0: + return -1 + slot : int, mut = -1 + if str_eq(key, "call_mechanism") != 0: + slot = HIT_RT_CALL_MECHANISM + if str_eq(key, "call_ret_addr") != 0: + slot = HIT_RT_CALL_RET_ADDR + if str_eq(key, "call_stack_grow") != 0: + slot = HIT_RT_CALL_STACK_GROW + if str_eq(key, "param_mode") != 0: + slot = HIT_RT_PARAM_MODE + if str_eq(key, "param_regs") != 0: + slot = HIT_RT_PARAM_MASK + if str_eq(key, "save_regs") != 0: + slot = HIT_RT_SAVE_MASK + if str_eq(key, "extern_entry") != 0: + slot = HIT_RT_EXTERN_ENTRY + if str_eq(key, "extern_resolve") != 0: + slot = HIT_RT_EXTERN_RESOLVE + if slot < 0: + return -1 + hit_w32(out, 0, hit_r32(g_hit_runtime, slot * 4)) + return 0 // ── --dump-table 读回通道(corearch 加载后调用;只读表状态,零写侧影响)── // 评审项 1 锁(多 proj 步小节归属)与评审项 4(v2 字段区读回覆盖)共用: // 每事件一行 proj 表记录回读(hit_proj_count/hit_proj_step_count——步数吞并 // 在此失真);每步一行 v2 字段区探针(hit_proj_step_get 整条 108B 复制后读 // opcode 区 OPB0 = 偏移 32——写读一致的实证);runtime 槽位掩码读回。 -fn hit_dump_table_state() { +fn hit_dump_table_state(): // 事件 → 逐 proj 步数(proj0 镜像/M1 视区也随 p0 步数一起验证) - ei : int, mut = 0; - loop { - if ei >= g_hit_event_count { break; } - print("hit proj: ev="); - print_i(hit_r32(g_hit_events, ei * HIT_EVENT_REC + HIT_EV_OFF_ID)); - pc := hit_proj_count(ei); - print(" projs="); print_i(pc); - pi : int, mut = 0; - loop { - if pi >= pc { break; } - print(" p"); print_i(pi); print("="); - print_i(hit_proj_step_count(ei, pi)); - pi = pi + 1; } - println(""); - ei = ei + 1; } + ei : int, mut = 0 + loop: + if ei >= g_hit_event_count: + break + print("hit proj: ev=") + print_i(hit_r32(g_hit_events, ei * HIT_EVENT_REC + HIT_EV_OFF_ID)) + pc := hit_proj_count(ei) + print(" projs=") + print_i(pc) + pi : int, mut = 0 + loop: + if pi >= pc: + break + print(" p") + print_i(pi) + print("=") + print_i(hit_proj_step_count(ei, pi)) + pi = pi + 1 + println("") + ei = ei + 1 // 逐步 opcode 首字节探针(v2 字段区 = 步记录偏移 32 起) - st := alloc(HIT_STEP_REC); - ej : int, mut = 0; - loop { - if ej >= g_hit_event_count { break; } - idj := hit_r32(g_hit_events, ej * HIT_EVENT_REC + HIT_EV_OFF_ID); - pj : int, mut = 0; - loop { - if pj >= hit_proj_count(ej) { break; } - sj : int, mut = 0; - loop { - if sj >= hit_proj_step_count(ej, pj) { break; } - if hit_proj_step_get(ej, pj, sj, st) == 0 { - print("hit step: ev="); print_i(idj); - print(" p="); print_i(pj); print(" s="); print_i(sj); - print(" opb="); print_i(hit_r32(st, HIT_ST_OFF_OPB0)); - println(""); } - sj = sj + 1; } - pj = pj + 1; } - ej = ej + 1; } + st := alloc(HIT_STEP_REC) + ej : int, mut = 0 + loop: + if ej >= g_hit_event_count: + break + idj := hit_r32(g_hit_events, ej * HIT_EVENT_REC + HIT_EV_OFF_ID) + pj : int, mut = 0 + loop: + if pj >= hit_proj_count(ej): + break + sj : int, mut = 0 + loop: + if sj >= hit_proj_step_count(ej, pj): + break + if hit_proj_step_get(ej, pj, sj, st) == 0: + print("hit step: ev=") + print_i(idj) + print(" p=") + print_i(pj) + print(" s=") + print_i(sj) + print(" opb=") + print_i(hit_r32(st, HIT_ST_OFF_OPB0)) + println("") + sj = sj + 1 + pj = pj + 1 + ej = ej + 1 // runtime 槽读回(掩码十进制 = 测试期望锚:param = rdi rsi rdx rcx r8 r9; // save = rbx r12-15) - if hit_runtime_get("param_regs", st) == 0 { - print("hit rt: param_regs="); print_i(hit_r32(st, 0)); println(""); } - if hit_runtime_get("save_regs", st) == 0 { - print("hit rt: save_regs="); print_i(hit_r32(st, 0)); println(""); } -} + if hit_runtime_get("param_regs", st) == 0: + print("hit rt: param_regs=") + print_i(hit_r32(st, 0)) + println("") + if hit_runtime_get("save_regs", st) == 0: + print("hit rt: save_regs=") + print_i(hit_r32(st, 0)) + println("") diff --git a/src/arch/hit/lower_to_core.cr b/src/arch/hit/lower_to_core.cr index f39ee3a1..14348664 100644 --- a/src/arch/hit/lower_to_core.cr +++ b/src/arch/hit/lower_to_core.cr @@ -43,29 +43,36 @@ import hit // ════════════════════════════════════════════════════════════════ // 最小核事件号契约(core-x86.toml 的 id 同此——表加载侧按 id 匹配,缺则旧路径) -HIT_EV_SUB : int = 1; -HIT_EV_NAND : int = 2; -HIT_EV_LOAD : int = 3; -HIT_EV_STORE : int = 4; -HIT_EV_JUMP : int = 5; // M2a:jump(rel32 事件流位置回填——发射 = instr.cr Task 2) -HIT_EV_BRANCH: int = 6; // M2a:branch/call/ret/extern 模板已声明——发射 = Task 3 起 -HIT_EV_CALL : int = 7; -HIT_EV_RET : int = 8; -HIT_EV_EXTERN: int = 9; - -HIT_ES_REC : int = 20; // 5 × i32 -HIT_ES_OFF_ID : int = 0; -HIT_ES_OFF_DST : int = 4; -HIT_ES_OFF_S1 : int = 8; -HIT_ES_OFF_S2 : int = 12; -HIT_ES_OFF_FLAGS : int = 16; -HIT_ES_S1_POOL : int = 1; // src1 = 常量池槽(否则 = 变量号) -HIT_ES_S2_POOL : int = 2; // src2 = 常量池槽(否则 = 变量号) - -g_hit_ev_stream : string, mut; g_hit_ev_count : int, mut; g_hit_ev_cap : int, mut; -g_hit_ev_map : string, mut; g_hit_ev_map_size : int, mut; // 每 IR 指令 8B {start u32, count u32} -g_hit_pool : string, mut; g_hit_pool_count : int, mut; g_hit_pool_cap : int, mut; -g_hit_pool_patch : string, mut; g_hit_pool_patch_count : int, mut; g_hit_pool_patch_cap : int, mut; // 16B/条 {pos i64, k i64} +HIT_EV_SUB : int = 1 +HIT_EV_NAND : int = 2 +HIT_EV_LOAD : int = 3 +HIT_EV_STORE : int = 4 +HIT_EV_JUMP : int = 5 // M2a:jump(rel32 事件流位置回填——发射 = instr.cr Task 2) +HIT_EV_BRANCH: int = 6 // M2a:branch/call/ret/extern 模板已声明——发射 = Task 3 起 +HIT_EV_CALL : int = 7 +HIT_EV_RET : int = 8 +HIT_EV_EXTERN: int = 9 + +HIT_ES_REC : int = 20 // 5 × i32 +HIT_ES_OFF_ID : int = 0 +HIT_ES_OFF_DST : int = 4 +HIT_ES_OFF_S1 : int = 8 +HIT_ES_OFF_S2 : int = 12 +HIT_ES_OFF_FLAGS : int = 16 +HIT_ES_S1_POOL : int = 1 // src1 = 常量池槽(否则 = 变量号) +HIT_ES_S2_POOL : int = 2 // src2 = 常量池槽(否则 = 变量号) + +g_hit_ev_stream : string, mut +g_hit_ev_count : int, mut +g_hit_ev_cap : int, mut +g_hit_ev_map : string, mut +g_hit_ev_map_size : int, mut // 每 IR 指令 8B {start u32, count u32} +g_hit_pool : string, mut +g_hit_pool_count : int, mut +g_hit_pool_cap : int, mut +g_hit_pool_patch : string, mut +g_hit_pool_patch_count : int, mut +g_hit_pool_patch_cap : int, mut // 16B/条 {pos i64, k i64} // ── M2a Task 2:rel 回填表 + 事件发射位置表 + 注入通道激活态 ── // g_hit_rel:三张回填表合一(kind 0 = 事件流位置、1 = 函数起点、2 = 外部符号序), @@ -74,166 +81,224 @@ g_hit_pool_patch : string, mut; g_hit_pool_patch_count : int, mut; g_hit_pool_p // g_hit_ev_pos:事件序 → 发射字节位置(8B/序;发射器边发边记——jump 回填消费)。 // g_hit_inject_active:--hit-events-file 注入通道激活(测试专用——预检拒绝升级为 // 大声错误 + 事件计数不符 = exit 1,防静默落旧路径掩盖注入文件错误)。 -g_hit_rel : string, mut; g_hit_rel_count : int, mut; g_hit_rel_cap : int, mut; -g_hit_ev_pos : string, mut; g_hit_ev_pos_count : int, mut; g_hit_ev_pos_cap : int, mut; -g_hit_inject_active : int, mut; - -fn hit_grow_ev(needed: int) { - if needed < g_hit_ev_cap { return; } - nc : ., mut = g_hit_ev_cap * 2; - if nc < 64 { nc = 64; } - if nc < needed { nc = needed + 8; } - nb := alloc(nc * HIT_ES_REC); - hit_copy_bytes(g_hit_ev_stream, g_hit_ev_cap * HIT_ES_REC, nb); - g_hit_ev_stream = nb; - g_hit_ev_cap = nc; } - -fn hit_grow_pool(needed: int) { - if needed < g_hit_pool_cap { return; } - nc : ., mut = g_hit_pool_cap * 2; - if nc < 8 { nc = 8; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * 8); - hit_copy_bytes(g_hit_pool, g_hit_pool_cap * 8, nb); - g_hit_pool = nb; - g_hit_pool_cap = nc; } - -fn hit_grow_pool_patch(needed: int) { - if needed < g_hit_pool_patch_cap { return; } - nc : ., mut = g_hit_pool_patch_cap * 2; - if nc < 8 { nc = 8; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * 16); - hit_copy_bytes(g_hit_pool_patch, g_hit_pool_patch_cap * 16, nb); - g_hit_pool_patch = nb; - g_hit_pool_patch_cap = nc; } - -fn hit_grow_rel(needed: int) { - if needed < g_hit_rel_cap { return; } - nc : ., mut = g_hit_rel_cap * 2; - if nc < 8 { nc = 8; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * 24); - hit_copy_bytes(g_hit_rel, g_hit_rel_cap * 24, nb); - g_hit_rel = nb; - g_hit_rel_cap = nc; } - -fn hit_grow_ev_pos(needed: int) { - if needed < g_hit_ev_pos_cap { return; } - nc : ., mut = g_hit_ev_pos_cap * 2; - if nc < 8 { nc = 8; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * 8); - hit_copy_bytes(g_hit_ev_pos, g_hit_ev_pos_cap * 8, nb); - g_hit_ev_pos = nb; - g_hit_ev_pos_cap = nc; } +g_hit_rel : string, mut +g_hit_rel_count : int, mut +g_hit_rel_cap : int, mut +g_hit_ev_pos : string, mut +g_hit_ev_pos_count : int, mut +g_hit_ev_pos_cap : int, mut +g_hit_inject_active : int, mut + +fn hit_grow_ev(needed: int): + if needed < g_hit_ev_cap: + return + nc : ., mut = g_hit_ev_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 8 + nb := alloc(nc * HIT_ES_REC) + hit_copy_bytes(g_hit_ev_stream, g_hit_ev_cap * HIT_ES_REC, nb) + g_hit_ev_stream = nb + g_hit_ev_cap = nc + +fn hit_grow_pool(needed: int): + if needed < g_hit_pool_cap: + return + nc : ., mut = g_hit_pool_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * 8) + hit_copy_bytes(g_hit_pool, g_hit_pool_cap * 8, nb) + g_hit_pool = nb + g_hit_pool_cap = nc + +fn hit_grow_pool_patch(needed: int): + if needed < g_hit_pool_patch_cap: + return + nc : ., mut = g_hit_pool_patch_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * 16) + hit_copy_bytes(g_hit_pool_patch, g_hit_pool_patch_cap * 16, nb) + g_hit_pool_patch = nb + g_hit_pool_patch_cap = nc + +fn hit_grow_rel(needed: int): + if needed < g_hit_rel_cap: + return + nc : ., mut = g_hit_rel_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * 24) + hit_copy_bytes(g_hit_rel, g_hit_rel_cap * 24, nb) + g_hit_rel = nb + g_hit_rel_cap = nc + +fn hit_grow_ev_pos(needed: int): + if needed < g_hit_ev_pos_cap: + return + nc : ., mut = g_hit_ev_pos_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * 8) + hit_copy_bytes(g_hit_ev_pos, g_hit_ev_pos_cap * 8, nb) + g_hit_ev_pos = nb + g_hit_ev_pos_cap = nc // rel 回填登记(M2a Task 2 接口——instr.cr 发射器调用;elf.cr 发射后回填)。 // kind: 0 = 事件流位置(jump/branch——事件序目标,本任务落地)、 // 1 = 函数起点、2 = 外部符号序(Task 4/5 消费——登记接口先行,回填拒接)。 -fn hit_rel_add(kind: int, pos: int, target: int) { - hit_grow_rel(g_hit_rel_count + 1); - slot : ., mut = g_hit_rel_count; - g_hit_rel_count = slot + 1; - w64(g_hit_rel, slot * 24, kind); - w64(g_hit_rel, slot * 24 + 8, pos); - w64(g_hit_rel, slot * 24 + 16, target); } +fn hit_rel_add(kind: int, pos: int, target: int): + hit_grow_rel(g_hit_rel_count + 1) + slot : ., mut = g_hit_rel_count + g_hit_rel_count = slot + 1 + w64(g_hit_rel, slot * 24, kind) + w64(g_hit_rel, slot * 24 + 8, pos) + w64(g_hit_rel, slot * 24 + 16, target) // 事件序 → 发射位置记录(8B;发射器在事件字节落位前写入——位置 = 绝对 buf 偏移) -fn hit_ev_pos_set(ord: int, pos: int) { - hit_grow_ev_pos(ord + 1); - w64(g_hit_ev_pos, ord * 8, pos); - if ord + 1 > g_hit_ev_pos_count { g_hit_ev_pos_count = ord + 1; } } +fn hit_ev_pos_set(ord: int, pos: int): + hit_grow_ev_pos(ord + 1) + w64(g_hit_ev_pos, ord * 8, pos) + if ord + 1 > g_hit_ev_pos_count: + g_hit_ev_pos_count = ord + 1 // 8B 补码小端写(借位链,两补正确——负值池槽可表达;仿 dyn_arr w32 链扩至 8 字节) -fn hit_pool_w64(buf: string, pos: int, v: int) { - b0 : ., mut = v % 256; t1 : ., mut = v / 256; - b1 : ., mut = t1 % 256; t2 : ., mut = t1 / 256; - b2 : ., mut = t2 % 256; t3 : ., mut = t2 / 256; - b3 : ., mut = t3 % 256; t4 : ., mut = t3 / 256; - b4 : ., mut = t4 % 256; t5 : ., mut = t4 / 256; - b5 : ., mut = t5 % 256; t6 : ., mut = t5 / 256; - b6 : ., mut = t6 % 256; t7 : ., mut = t6 / 256; - b7 : ., mut = t7 % 256; - 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; b4 = b4 - 1; } - if b4 < 0 { b4 = b4 + 256; b5 = b5 - 1; } - if b5 < 0 { b5 = b5 + 256; b6 = b6 - 1; } - if b6 < 0 { b6 = b6 + 256; b7 = b7 - 1; } - if b7 < 0 { b7 = b7 + 256; } - store8(buf, pos + 0, b0); store8(buf, pos + 1, b1); - store8(buf, pos + 2, b2); store8(buf, pos + 3, b3); - store8(buf, pos + 4, b4); store8(buf, pos + 5, b5); - store8(buf, pos + 6, b6); store8(buf, pos + 7, b7); } - -fn hit_lower_reset() { - g_hit_ev_count = 0; - g_hit_pool_count = 0; - g_hit_pool_patch_count = 0; +fn hit_pool_w64(buf: string, pos: int, v: int): + b0 : ., mut = v % 256 + t1 : ., mut = v / 256 + b1 : ., mut = t1 % 256 + t2 : ., mut = t1 / 256 + b2 : ., mut = t2 % 256 + t3 : ., mut = t2 / 256 + b3 : ., mut = t3 % 256 + t4 : ., mut = t3 / 256 + b4 : ., mut = t4 % 256 + t5 : ., mut = t4 / 256 + b5 : ., mut = t5 % 256 + t6 : ., mut = t5 / 256 + b6 : ., mut = t6 % 256 + t7 : ., mut = t6 / 256 + b7 : ., mut = t7 % 256 + 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 + b4 = b4 - 1 + if b4 < 0: + b4 = b4 + 256 + b5 = b5 - 1 + if b5 < 0: + b5 = b5 + 256 + b6 = b6 - 1 + if b6 < 0: + b6 = b6 + 256 + b7 = b7 - 1 + if b7 < 0: + b7 = b7 + 256 + store8(buf, pos + 0, b0) + store8(buf, pos + 1, b1) + store8(buf, pos + 2, b2) + store8(buf, pos + 3, b3) + store8(buf, pos + 4, b4) + store8(buf, pos + 5, b5) + store8(buf, pos + 6, b6) + store8(buf, pos + 7, b7) + +fn hit_lower_reset(): + g_hit_ev_count = 0 + g_hit_pool_count = 0 + g_hit_pool_patch_count = 0 // M2a Task 2:rel 回填表 + 事件位置表逐次发射清零 - g_hit_rel_count = 0; - g_hit_ev_pos_count = 0; } + g_hit_rel_count = 0 + g_hit_ev_pos_count = 0 -fn hit_ev_map_init(n: int) { - g_hit_ev_map_size = n; - g_hit_ev_map = alloc(n * 8 + 8); } +fn hit_ev_map_init(n: int): + g_hit_ev_map_size = n + g_hit_ev_map = alloc(n * 8 + 8) -fn hit_ev_map_set(i: int, start: int, cnt: int) { - w32(g_hit_ev_map, i * 8, start); - w32(g_hit_ev_map, i * 8 + 4, cnt); } +fn hit_ev_map_set(i: int, start: int, cnt: int): + w32(g_hit_ev_map, i * 8, start) + w32(g_hit_ev_map, i * 8 + 4, cnt) -fn hit_ev_map_cnt(i: int) -> int { - if i < 0 || i >= g_hit_ev_map_size { return 0; } - return r32(g_hit_ev_map, i * 8 + 4); } +fn hit_ev_map_cnt(i: int) -> int: + if i < 0 || i >= g_hit_ev_map_size: + return 0 + return r32(g_hit_ev_map, i * 8 + 4) -fn hit_ev_map_start(i: int) -> int { - if i < 0 || i >= g_hit_ev_map_size { return 0; } - return r32(g_hit_ev_map, i * 8); } +fn hit_ev_map_start(i: int) -> int: + if i < 0 || i >= g_hit_ev_map_size: + return 0 + return r32(g_hit_ev_map, i * 8) // 追加一条事件(20B);未用操作数 = 0(勿存 -1:hit_w32 非负约定——M2-2a) -fn hit_ev_append(ev_id: int, d: int, s1: int, s2: int, flags: int) { - hit_grow_ev(g_hit_ev_count + 1); - slot : ., mut = g_hit_ev_count; - g_hit_ev_count = slot + 1; - hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_ID, ev_id); - hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_DST, d); - hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_S1, s1); - hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_S2, s2); - hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_FLAGS, flags); } +fn hit_ev_append(ev_id: int, d: int, s1: int, s2: int, flags: int): + hit_grow_ev(g_hit_ev_count + 1) + slot : ., mut = g_hit_ev_count + g_hit_ev_count = slot + 1 + hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_ID, ev_id) + hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_DST, d) + hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_S1, s1) + hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_S2, s2) + hit_w32(g_hit_ev_stream, slot * HIT_ES_REC + HIT_ES_OFF_FLAGS, flags) // 事件流访问器(dump/编码器消费;i 为流内下标) -fn hit_ev_id(i: int) -> int { return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_ID); } -fn hit_ev_dst(i: int) -> int { return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_DST); } -fn hit_ev_s1(i: int) -> int { return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_S1); } -fn hit_ev_s2(i: int) -> int { return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_S2); } -fn hit_ev_flags(i: int) -> int { return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_FLAGS); } -fn hit_ev_total() -> int { return g_hit_ev_count; } +fn hit_ev_id(i: int) -> int: + return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_ID) +fn hit_ev_dst(i: int) -> int: + return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_DST) +fn hit_ev_s1(i: int) -> int: + return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_S1) +fn hit_ev_s2(i: int) -> int: + return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_S2) +fn hit_ev_flags(i: int) -> int: + return hit_r32(g_hit_ev_stream, i * HIT_ES_REC + HIT_ES_OFF_FLAGS) +fn hit_ev_total() -> int: + return g_hit_ev_count // 常量池:按值去重 intern;返回槽号 -fn hit_pool_intern(v: int) -> int { - k : ., mut = 0; - loop { - if k >= g_hit_pool_count { break; } - if r64(g_hit_pool, k * 8) == v { return k; } - k = k + 1; } - hit_grow_pool(g_hit_pool_count + 1); - pk : ., mut = g_hit_pool_count; - g_hit_pool_count = pk + 1; - hit_pool_w64(g_hit_pool, pk * 8, v); - return pk; } - -fn hit_pool_total() -> int { return g_hit_pool_count; } -fn hit_pool_val(k: int) -> int { return r64(g_hit_pool, k * 8); } +fn hit_pool_intern(v: int) -> int: + k : ., mut = 0 + loop: + if k >= g_hit_pool_count: + break + if r64(g_hit_pool, k * 8) == v: + return k + k = k + 1 + hit_grow_pool(g_hit_pool_count + 1) + pk : ., mut = g_hit_pool_count + g_hit_pool_count = pk + 1 + hit_pool_w64(g_hit_pool, pk * 8, v) + return pk + +fn hit_pool_total() -> int: + return g_hit_pool_count +fn hit_pool_val(k: int) -> int: + return r64(g_hit_pool, k * 8) // 池引用 patch 记录(编码器在发射池值 mov 时调用;elf.cr 于 rodata 定稿后回填) -fn hit_pool_patch_add(pos: int, k: int) { - hit_grow_pool_patch(g_hit_pool_patch_count + 1); - slot : ., mut = g_hit_pool_patch_count; - g_hit_pool_patch_count = slot + 1; - w64(g_hit_pool_patch, slot * 16, pos); - w64(g_hit_pool_patch, slot * 16 + 8, k); } +fn hit_pool_patch_add(pos: int, k: int): + hit_grow_pool_patch(g_hit_pool_patch_count + 1) + slot : ., mut = g_hit_pool_patch_count + g_hit_pool_patch_count = slot + 1 + w64(g_hit_pool_patch, slot * 16, pos) + w64(g_hit_pool_patch, slot * 16 + 8, k) // ════════════════════════════════════════════════════════════════ // 降低规则(IR 直线子集 → 事件流) @@ -241,58 +306,67 @@ fn hit_pool_patch_add(pos: int, k: int) { // 降低单条 IR 指令并追加事件。Returns 0 = 成功(可能无事件 = 旧路径直通); // 1 = 超子集 op(错误已打印)——调用方中止(exit 1)。 -fn hit_lower_instr(j: int) -> int { - op := iri_op(j); - d := iri_dest(j); - s1 := iri_s1(j); - s2 := iri_s2(j); - s3 := iri_s3(j); - ti := iri_tk(j); - if op == IR_CONST { +fn hit_lower_instr(j: int) -> int: + op := iri_op(j) + d := iri_dest(j) + s1 := iri_s1(j) + s2 := iri_s2(j) + s3 := iri_s3(j) + ti := iri_tk(j) + if op == IR_CONST: // 字符串常量走旧路径(g2_str_off/rodataref 字符串机制); // 其余常量 → 池槽 load 事件(8B 槽值发射时写 rodata) - if ti == TI_STR { return 0; } - if d < 0 { return 0; } - k := hit_pool_intern(s1); - hit_ev_append(HIT_EV_LOAD, d, k, 0, HIT_ES_S1_POOL); // load 事件:addr = 池槽(s2 = 0 未用) - return 0; } - if op == IR_BINARY { - if ti == TI_DEX { return 0; } // binary64 运算走旧 SSE 路径(M1 不移表) - if s3 == OP_SUB { - if d < 0 || s1 < 0 || s2 < 0 { return 0; } - hit_ev_append(HIT_EV_SUB, d, s1, s2, 0); - return 0; } - if s3 == OP_ADD { - if d < 0 || s1 < 0 || s2 < 0 { return 0; } + if ti == TI_STR: + return 0 + if d < 0: + return 0 + k := hit_pool_intern(s1) + hit_ev_append(HIT_EV_LOAD, d, k, 0, HIT_ES_S1_POOL) // load 事件:addr = 池槽(s2 = 0 未用) + return 0 + if op == IR_BINARY: + if ti == TI_DEX: + return 0 + // binary64 运算走旧 SSE 路径(M1 不移表) + if s3 == OP_SUB: + if d < 0 || s1 < 0 || s2 < 0: + return 0 + hit_ev_append(HIT_EV_SUB, d, s1, s2, 0) + return 0 + if s3 == OP_ADD: + if d < 0 || s1 < 0 || s2 < 0: + return 0 // dest-fresh 前提(M2-2c 防御):E1 先把中间值 (0−b) 写入 d 槽; // d == a 时 E2 读 src1(a) 读到的已是中间值 → a − (0−b) 语义崩。 // 落 0 事件 = 旧路径(旧路径编码器逐事件先读后写,无此前提)。 - if d == s1 { return 0; } - k0 := hit_pool_intern(0); // 合成 0(最小核无 const 事件) + if d == s1: + return 0 + k0 := hit_pool_intern(0) // 合成 0(最小核无 const 事件) // sub 反减 add(a,b) := sub(a, sub(0,b))——中间值驻 d: // E1: d ← 0 − b;E2: d ← a − d(编码器先读后写,读先于写) - hit_ev_append(HIT_EV_SUB, d, k0, s2, HIT_ES_S1_POOL); - hit_ev_append(HIT_EV_SUB, d, s1, d, 0); - return 0; } + hit_ev_append(HIT_EV_SUB, d, k0, s2, HIT_ES_S1_POOL) + hit_ev_append(HIT_EV_SUB, d, s1, d, 0) + return 0 // 其余子操作(mul/div/mod/移位/位与/或/…)= 超出 M1 直线子集 - print("error: HIT lower: instr "); print_i(j); - print(" op="); print_i(op); print(" sub="); print_i(s3); - println(" needs more events (M1 straight-line subset: const/load/store/add/sub)"); - return 1; } - if op == IR_LOAD { - if d >= 0 && s1 >= 0 { + print("error: HIT lower: instr ") + print_i(j) + print(" op=") + print_i(op) + print(" sub=") + print_i(s3) + println(" needs more events (M1 straight-line subset: const/load/store/add/sub)") + return 1 + if op == IR_LOAD: + if d >= 0 && s1 >= 0: // 槽读 → 槽写(全局/形态不符由编码器预检 → 整条落旧路径); // s2 = 0 未用(勿存 -1:hit_w32 非负约定,M2-2a) - hit_ev_append(HIT_EV_LOAD, d, s1, 0, 0); - } - return 0; } - if op == IR_STORE { - if s1 >= 0 && s2 >= 0 { + hit_ev_append(HIT_EV_LOAD, d, s1, 0, 0) + return 0 + if op == IR_STORE: + if s1 >= 0 && s2 >= 0: // 槽写:addr = s1 槽、val = s2;dst = 0 未用(M2-2a) - hit_ev_append(HIT_EV_STORE, 0, s1, s2, 0); - } - return 0; } - return 0; } + hit_ev_append(HIT_EV_STORE, 0, s1, s2, 0) + return 0 + return 0 // 全程序降低(corearch 表模式下、发射前调用)。 // M1 直线子集契约 = 入口函数 main 的指令流;.ccr 随带的标准库辅助函数 @@ -301,32 +375,40 @@ fn hit_lower_instr(j: int) -> int { // 超子集 op(mod/移位/…)→ 'needs more events' 报错(exit 1)。 // map 全量清零(未降低指令 0 事件);仅降低 main。 // Returns 0 = 成功;1 = 超子集 op(错误已打印,调用方 exit 1)。 -fn hit_lower_program() -> int { - hit_lower_reset(); - hit_ev_map_init(g_ir_instr_count); - mi : ., mut = 0; - loop { - if mi >= g_ir_instr_count { break; } - hit_ev_map_set(mi, 0, 0); - mi = mi + 1; } - entry : ., mut = -1; - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } - if str_eq(istr_get(r64(g_ir_func_name_idx, fi * 8)), "main") != 0 { entry = fi; break; } - fi = fi + 1; } - if entry < 0 { return 0; } // 无 main = M1 载体外(不降低,全旧路径) - ist := r64(g_ir_func_instr_start, entry * 8); - ic := r64(g_ir_func_instr_count, entry * 8); - ii : ., mut = 0; - loop { - if ii >= ic { break; } - j := ist + ii; - base : ., mut = g_hit_ev_count; - if hit_lower_instr(j) != 0 { return 1; } - hit_ev_map_set(j, base, g_hit_ev_count - base); - ii = ii + 1; } - return 0; } +fn hit_lower_program() -> int: + hit_lower_reset() + hit_ev_map_init(g_ir_instr_count) + mi : ., mut = 0 + loop: + if mi >= g_ir_instr_count: + break + hit_ev_map_set(mi, 0, 0) + mi = mi + 1 + entry : ., mut = -1 + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break + if str_eq(istr_get(r64(g_ir_func_name_idx, fi * 8)), "main") != 0: + entry = fi + break + fi = fi + 1 + if entry < 0: + return 0 + // 无 main = M1 载体外(不降低,全旧路径) + ist := r64(g_ir_func_instr_start, entry * 8) + ic := r64(g_ir_func_instr_count, entry * 8) + ii : ., mut = 0 + loop: + if ii >= ic: + break + j := ist + ii + base : ., mut = g_hit_ev_count + if hit_lower_instr(j) != 0: + return 1 + hit_ev_map_set(j, base, g_hit_ev_count - base) + ii = ii + 1 + return 0 // ════════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════════ @@ -357,301 +439,387 @@ fn hit_lower_program() -> int { // // 注入事件行暂存(解析期不知目标指令——两遍:先解析行,后走指令附着): // 每行 20B = {id i32, flags i32, dst i32, s1 i32, s2 i32}(flags 位见下) -g_hit_inj : string, mut; g_hit_inj_count : int, mut; g_hit_inj_cap : int, mut; - -HIT_INJ_HAS_DST : int = 1; // dst 域显式(否则 = 指令 dest) -HIT_INJ_HAS_S1 : int = 2; // s1 域显式 -HIT_INJ_HAS_S2 : int = 4; // s2 域显式 -HIT_INJ_S1_POOL : int = 8; // s1 = 池槽引用 -HIT_INJ_S2_POOL : int = 16; // s2 = 池槽引用 - -fn hit_grow_inj(needed: int) { - if needed < g_hit_inj_cap { return; } - nc : ., mut = g_hit_inj_cap * 2; - if nc < 8 { nc = 8; } - if nc < needed { nc = needed + 4; } - nb := alloc(nc * 20); - hit_copy_bytes(g_hit_inj, g_hit_inj_cap * 20, nb); - g_hit_inj = nb; - g_hit_inj_cap = nc; } - -fn hit_inj_line_id(i: int) -> int { return hit_r32(g_hit_inj, i * 20 + 0); } -fn hit_inj_line_flags(i: int) -> int { return hit_r32(g_hit_inj, i * 20 + 4); } -fn hit_inj_line_dst(i: int) -> int { return hit_r32(g_hit_inj, i * 20 + 8); } -fn hit_inj_line_s1(i: int) -> int { return hit_r32(g_hit_inj, i * 20 + 12); } -fn hit_inj_line_s2(i: int) -> int { return hit_r32(g_hit_inj, i * 20 + 16); } +g_hit_inj : string, mut +g_hit_inj_count : int, mut +g_hit_inj_cap : int, mut + +HIT_INJ_HAS_DST : int = 1 // dst 域显式(否则 = 指令 dest) +HIT_INJ_HAS_S1 : int = 2 // s1 域显式 +HIT_INJ_HAS_S2 : int = 4 // s2 域显式 +HIT_INJ_S1_POOL : int = 8 // s1 = 池槽引用 +HIT_INJ_S2_POOL : int = 16 // s2 = 池槽引用 + +fn hit_grow_inj(needed: int): + if needed < g_hit_inj_cap: + return + nc : ., mut = g_hit_inj_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * 20) + hit_copy_bytes(g_hit_inj, g_hit_inj_cap * 20, nb) + g_hit_inj = nb + g_hit_inj_cap = nc + +fn hit_inj_line_id(i: int) -> int: + return hit_r32(g_hit_inj, i * 20 + 0) +fn hit_inj_line_flags(i: int) -> int: + return hit_r32(g_hit_inj, i * 20 + 4) +fn hit_inj_line_dst(i: int) -> int: + return hit_r32(g_hit_inj, i * 20 + 8) +fn hit_inj_line_s1(i: int) -> int: + return hit_r32(g_hit_inj, i * 20 + 12) +fn hit_inj_line_s2(i: int) -> int: + return hit_r32(g_hit_inj, i * 20 + 16) // 事件名 → 事件槽(反向查名——dump 打印名、注入文件写名;未知 → -1) -fn hit_inj_event_by_name(name: string) -> int { - ei : ., mut = 0; - loop { - if ei >= g_hit_event_count { break; } - if str_eq(hit_event_name(ei), name) != 0 { return ei; } - ei = ei + 1; } - return -1; } +fn hit_inj_event_by_name(name: string) -> int: + ei : ., mut = 0 + loop: + if ei >= g_hit_event_count: + break + if str_eq(hit_event_name(ei), name) != 0: + return ei + ei = ei + 1 + return -1 // 注入行附着期望:指令 (op, subop, ti) 是否期望事件行 (l_id, l_pool)。 // 未列事件(6-9 等)= 无期望 → 行不得附着(拒绝面)。 -fn hit_inj_line_expected(op: int, subop: int, ti: int, l_id: int, l_pool: int) -> int { - if l_id == HIT_EV_JUMP { if op == IR_JUMP && l_pool == 0 { return 1; } return 0; } - if l_id == HIT_EV_SUB { - if op == IR_BINARY && subop == OP_SUB { return 1; } - return 0; } - if l_id == HIT_EV_STORE { if op == IR_STORE { return 1; } return 0; } - if l_id == HIT_EV_LOAD { - if op == IR_LOAD && l_pool == 0 { return 1; } - if op == IR_CONST && ti != TI_STR && l_pool == 1 { return 1; } - return 0; } - if l_id == 11 { // cst 夹具事件(imm 直载 const)——注入测试载体,见上注 - if op == IR_CONST && ti != TI_STR && l_pool == 0 { return 1; } - return 0; } - return 0; } +fn hit_inj_line_expected(op: int, subop: int, ti: int, l_id: int, l_pool: int) -> int: + if l_id == HIT_EV_JUMP: + if op == IR_JUMP && l_pool == 0: + return 1 + return 0 + if l_id == HIT_EV_SUB: + if op == IR_BINARY && subop == OP_SUB: + return 1 + return 0 + if l_id == HIT_EV_STORE: + if op == IR_STORE: + return 1 + return 0 + if l_id == HIT_EV_LOAD: + if op == IR_LOAD && l_pool == 0: + return 1 + if op == IR_CONST && ti != TI_STR && l_pool == 1: + return 1 + return 0 + if l_id == 11: + // cst 夹具事件(imm 直载 const)——注入测试载体,见上注 + if op == IR_CONST && ti != TI_STR && l_pool == 0: + return 1 + return 0 + return 0 // 行分派:pool 值行 / ev 事件行 / 坏行。0 = 行已处理;1 = 错误(已打印)。 -fn hit_inj_parse_line(line: string) -> int { - llen := str_len(line); - if llen >= 4 && load8(line, 0) == 112 && load8(line, 1) == 111 && - load8(line, 2) == 111 && load8(line, 3) == 108 && - (llen == 4 || load8(line, 4) == 32) { - return hit_inj_parse_pool_line(line); } - if llen >= 2 && load8(line, 0) == 101 && load8(line, 1) == 118 && - (llen == 2 || load8(line, 2) == 32) { - return hit_inj_parse_ev_line(line); } - print("error: HIT events: bad event line: "); println(line); - return 1; } +fn hit_inj_parse_line(line: string) -> int: + llen := str_len(line) + if llen >= 4 && load8(line, 0) == 112 && load8(line, 1) == 111 && load8(line, 2) == 111 && load8(line, 3) == 108 && (llen == 4 || load8(line, 4) == 32): + return hit_inj_parse_pool_line(line) + if llen >= 2 && load8(line, 0) == 101 && load8(line, 1) == 118 && (llen == 2 || load8(line, 2) == 32): + return hit_inj_parse_ev_line(line) + print("error: HIT events: bad event line: ") + println(line) + return 1 // pool 行:空格分隔值按序入池槽(可多行)。0 = 成功;1 = 错误(已打印)。 -fn hit_inj_parse_pool_line(line: string) -> int { - llen := str_len(line); - vp : ., mut = 4; - loop { - loop { - if vp >= llen { break; } - if load8(line, vp) == 32 { vp = vp + 1; } else { break; } } - if vp >= llen { break; } - vv := hit_inj_parse_int(line, vp); - if vv < 0 { - print("error: HIT events: bad pool value at line: "); - println(line); - return 1; } - hit_grow_pool(g_hit_pool_count + 1); - hit_pool_w64(g_hit_pool, g_hit_pool_count * 8, vv); - g_hit_pool_count = g_hit_pool_count + 1; - loop { // 越过该值全部数字('-' 含首字符——已在 parse 校验) - if vp >= llen { break; } - c := load8(line, vp); - if c >= 48 && c <= 57 || c == 45 { vp = vp + 1; } else { break; } } } - return 0; } +fn hit_inj_parse_pool_line(line: string) -> int: + llen := str_len(line) + vp : ., mut = 4 + loop: + loop: + if vp >= llen: + break + if load8(line, vp) == 32: + vp = vp + 1 + else: + break + if vp >= llen: + break + vv := hit_inj_parse_int(line, vp) + if vv < 0: + print("error: HIT events: bad pool value at line: ") + println(line) + return 1 + hit_grow_pool(g_hit_pool_count + 1) + hit_pool_w64(g_hit_pool, g_hit_pool_count * 8, vv) + g_hit_pool_count = g_hit_pool_count + 1 + loop: + // 越过该值全部数字('-' 含首字符——已在 parse 校验) + if vp >= llen: + break + c := load8(line, vp) + if c >= 48 && c <= 57 || c == 45: + vp = vp + 1 + else: + break + return 0 // ev 行:`ev [dst=N] [s1=[pool]N] [s2=[pool]N]`——操作数域缺省 = 附着时 // 取指令同名操作数(附着规则见 hit_inj_line_expected)。行暂存 20B 待遍 2 附着。 // 0 = 成功;1 = 错误(已打印)。 -fn hit_inj_parse_ev_line(line: string) -> int { - llen := str_len(line); - np : ., mut = 2; - loop { - if np >= llen { break; } - if load8(line, np) == 32 { np = np + 1; } else { break; } } - ne : ., mut = np; - loop { - if ne >= llen { break; } - if load8(line, ne) == 32 { break; } - ne = ne + 1; } - if ne <= np { - print("error: HIT events: bad event line: "); println(line); - return 1; } - es := hit_inj_event_by_name(str_sub(line, np, ne - np)); - if es < 0 { - print("error: HIT events: unknown event '"); - print(str_sub(line, np, ne - np)); println("'"); - return 1; } - ev_id := hit_r32(g_hit_events, es * HIT_EVENT_REC + HIT_EV_OFF_ID); - fl : ., mut = 0; - dv : ., mut = 0; - s1v : ., mut = 0; - s2v : ., mut = 0; - dpos := hit_inj_field_of(line, ne, "dst", 0); - if dpos == -2 { - print("error: HIT events: bad dst at line: "); println(line); - return 1; } - if dpos >= 0 { - dv = hit_inj_parse_int(line, dpos); - if dv < 0 { - print("error: HIT events: bad dst at line: "); println(line); - return 1; } - fl = fl + HIT_INJ_HAS_DST; } - s1pos := hit_inj_field_of(line, ne, "s1", 1); - if s1pos == -2 { - print("error: HIT events: bad s1 at line: "); println(line); - return 1; } - if s1pos >= 0 { - if load8(line, s1pos) == 112 { // poolN - s1v = str_int(str_sub(line, s1pos + 4, str_len(line) - s1pos - 4)); - fl = fl + HIT_INJ_HAS_S1 + HIT_INJ_S1_POOL; } - else { - s1v = hit_inj_parse_int(line, s1pos); - if s1v < 0 { - print("error: HIT events: bad s1 at line: "); println(line); - return 1; } - fl = fl + HIT_INJ_HAS_S1; } } - s2pos := hit_inj_field_of(line, ne, "s2", 1); - if s2pos == -2 { - print("error: HIT events: bad s2 at line: "); println(line); - return 1; } - if s2pos >= 0 { - if load8(line, s2pos) == 112 { - s2v = str_int(str_sub(line, s2pos + 4, str_len(line) - s2pos - 4)); - fl = fl + HIT_INJ_HAS_S2 + HIT_INJ_S2_POOL; } - else { - s2v = hit_inj_parse_int(line, s2pos); - if s2v < 0 { - print("error: HIT events: bad s2 at line: "); println(line); - return 1; } - fl = fl + HIT_INJ_HAS_S2; } } - hit_grow_inj(g_hit_inj_count + 1); - hit_w32(g_hit_inj, g_hit_inj_count * 20 + 0, ev_id); - hit_w32(g_hit_inj, g_hit_inj_count * 20 + 4, fl); - hit_w32(g_hit_inj, g_hit_inj_count * 20 + 8, dv); - hit_w32(g_hit_inj, g_hit_inj_count * 20 + 12, s1v); - hit_w32(g_hit_inj, g_hit_inj_count * 20 + 16, s2v); - g_hit_inj_count = g_hit_inj_count + 1; - return 0; } +fn hit_inj_parse_ev_line(line: string) -> int: + llen := str_len(line) + np : ., mut = 2 + loop: + if np >= llen: + break + if load8(line, np) == 32: + np = np + 1 + else: + break + ne : ., mut = np + loop: + if ne >= llen: + break + if load8(line, ne) == 32: + break + ne = ne + 1 + if ne <= np: + print("error: HIT events: bad event line: ") + println(line) + return 1 + es := hit_inj_event_by_name(str_sub(line, np, ne - np)) + if es < 0: + print("error: HIT events: unknown event '") + print(str_sub(line, np, ne - np)) + println("'") + return 1 + ev_id := hit_r32(g_hit_events, es * HIT_EVENT_REC + HIT_EV_OFF_ID) + fl : ., mut = 0 + dv : ., mut = 0 + s1v : ., mut = 0 + s2v : ., mut = 0 + dpos := hit_inj_field_of(line, ne, "dst", 0) + if dpos == -2: + print("error: HIT events: bad dst at line: ") + println(line) + return 1 + if dpos >= 0: + dv = hit_inj_parse_int(line, dpos) + if dv < 0: + print("error: HIT events: bad dst at line: ") + println(line) + return 1 + fl = fl + HIT_INJ_HAS_DST + s1pos := hit_inj_field_of(line, ne, "s1", 1) + if s1pos == -2: + print("error: HIT events: bad s1 at line: ") + println(line) + return 1 + if s1pos >= 0: + if load8(line, s1pos) == 112: + // poolN + s1v = str_int(str_sub(line, s1pos + 4, str_len(line) - s1pos - 4)) + fl = fl + HIT_INJ_HAS_S1 + HIT_INJ_S1_POOL + else: + s1v = hit_inj_parse_int(line, s1pos) + if s1v < 0: + print("error: HIT events: bad s1 at line: ") + println(line) + return 1 + fl = fl + HIT_INJ_HAS_S1 + s2pos := hit_inj_field_of(line, ne, "s2", 1) + if s2pos == -2: + print("error: HIT events: bad s2 at line: ") + println(line) + return 1 + if s2pos >= 0: + if load8(line, s2pos) == 112: + s2v = str_int(str_sub(line, s2pos + 4, str_len(line) - s2pos - 4)) + fl = fl + HIT_INJ_HAS_S2 + HIT_INJ_S2_POOL + else: + s2v = hit_inj_parse_int(line, s2pos) + if s2v < 0: + print("error: HIT events: bad s2 at line: ") + println(line) + return 1 + fl = fl + HIT_INJ_HAS_S2 + hit_grow_inj(g_hit_inj_count + 1) + hit_w32(g_hit_inj, g_hit_inj_count * 20 + 0, ev_id) + hit_w32(g_hit_inj, g_hit_inj_count * 20 + 4, fl) + hit_w32(g_hit_inj, g_hit_inj_count * 20 + 8, dv) + hit_w32(g_hit_inj, g_hit_inj_count * 20 + 12, s1v) + hit_w32(g_hit_inj, g_hit_inj_count * 20 + 16, s2v) + g_hit_inj_count = g_hit_inj_count + 1 + return 0 // 注入文件解析 + 指令附着(入口函数 = main——与降低同定位)。0 = 成功;1 = 错 //(错误已打印——corearch 侧 exit 1)。 -fn hit_inject_events(path: string) -> int { - content := read_file(path); - if str_len(content) == 0 { - print("error: cannot open HIT events file: "); println(path); - return 1; } - hit_lower_reset(); - g_hit_inj_count = 0; +fn hit_inject_events(path: string) -> int: + content := read_file(path) + if str_len(content) == 0: + print("error: cannot open HIT events file: ") + println(path) + return 1 + hit_lower_reset() + g_hit_inj_count = 0 // ── 遍 1:逐行解析(pool 值直入池;ev 行暂存待附着)── - slen := str_len(content); - ln : ., mut = 0; - loop { - if ln >= slen { break; } - s : ., mut = ln; - loop { - if s >= slen { break; } - c := load8(content, s); - if c == 32 || c == 9 { s = s + 1; } else { break; } } - e : ., mut = s; - loop { - if e >= slen { break; } - if load8(content, e) == 10 { break; } - e = e + 1; } - if s < e && load8(content, s) != 35 { // 非注释非空行 - line := str_sub(content, s, e - s); - if hit_inj_parse_line(line) != 0 { return 1; } - } - ln = e + 1; } + slen := str_len(content) + ln : ., mut = 0 + loop: + if ln >= slen: + break + s : ., mut = ln + loop: + if s >= slen: + break + c := load8(content, s) + if c == 32 || c == 9: + s = s + 1 + else: + break + e : ., mut = s + loop: + if e >= slen: + break + if load8(content, e) == 10: + break + e = e + 1 + if s < e && load8(content, s) != 35: + // 非注释非空行 + line := str_sub(content, s, e - s) + if hit_inj_parse_line(line) != 0: + return 1 + ln = e + 1 // ── 遍 2:入口函数(main)指令序附着(行序 = 指令序——未匹配行留待下条)── - entry : ., mut = -1; - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } - if str_eq(istr_get(r64(g_ir_func_name_idx, fi * 8)), "main") != 0 { entry = fi; break; } - fi = fi + 1; } - if entry < 0 { - println("error: HIT events: no main function to attach events to"); - return 1; } - hit_ev_map_init(g_ir_instr_count); - mi : ., mut = 0; - loop { - if mi >= g_ir_instr_count { break; } - hit_ev_map_set(mi, 0, 0); - mi = mi + 1; } - ist := r64(g_ir_func_instr_start, entry * 8); - ic := r64(g_ir_func_instr_count, entry * 8); - cur : ., mut = 0; // 下一条未附着行 - ii : ., mut = 0; - loop { - if ii >= ic { break; } - j := ist + ii; - if cur < g_hit_inj_count { - op := iri_op(j); - ti := iri_tk(j); - subop : ., mut = -1; - if op == IR_BINARY { subop = iri_s3(j); } - l_id := hit_inj_line_id(cur); - l_fl := hit_inj_line_flags(cur); - l_pool : ., mut = 0; - if l_fl / 8 % 2 == 1 { l_pool = 1; } - if hit_inj_line_expected(op, subop, ti, l_id, l_pool) == 1 { - if l_id == HIT_EV_JUMP && l_fl / 2 % 2 == 0 { - println("error: HIT events: jump event needs explicit s1 (target event ordinal)"); - return 1; } + entry : ., mut = -1 + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break + if str_eq(istr_get(r64(g_ir_func_name_idx, fi * 8)), "main") != 0: + entry = fi + break + fi = fi + 1 + if entry < 0: + println("error: HIT events: no main function to attach events to") + return 1 + hit_ev_map_init(g_ir_instr_count) + mi : ., mut = 0 + loop: + if mi >= g_ir_instr_count: + break + hit_ev_map_set(mi, 0, 0) + mi = mi + 1 + ist := r64(g_ir_func_instr_start, entry * 8) + ic := r64(g_ir_func_instr_count, entry * 8) + cur : ., mut = 0 // 下一条未附着行 + ii : ., mut = 0 + loop: + if ii >= ic: + break + j := ist + ii + if cur < g_hit_inj_count: + op := iri_op(j) + ti := iri_tk(j) + subop : ., mut = -1 + if op == IR_BINARY: + subop = iri_s3(j) + l_id := hit_inj_line_id(cur) + l_fl := hit_inj_line_flags(cur) + l_pool : ., mut = 0 + if l_fl / 8 % 2 == 1: + l_pool = 1 + if hit_inj_line_expected(op, subop, ti, l_id, l_pool) == 1: + if l_id == HIT_EV_JUMP && l_fl / 2 % 2 == 0: + println("error: HIT events: jump event needs explicit s1 (target event ordinal)") + return 1 // 附着:事件记录 = 行值(缺省取指令同名操作数) - d : ., mut = hit_inj_line_dst(cur); - if l_fl % 2 == 0 { d = iri_dest(j); if d < 0 { d = 0; } } - s1 : ., mut = hit_inj_line_s1(cur); - if l_fl / 2 % 2 == 0 { s1 = iri_s1(j); if s1 < 0 { s1 = 0; } } - s2 : ., mut = hit_inj_line_s2(cur); - if l_fl / 4 % 2 == 0 { s2 = iri_s2(j); if s2 < 0 { s2 = 0; } } - evfl : ., mut = 0; - if l_fl / 8 % 2 == 1 { evfl = evfl + HIT_ES_S1_POOL; } - if l_fl / 16 % 2 == 1 { evfl = evfl + HIT_ES_S2_POOL; } - hit_ev_append(l_id, d, s1, s2, evfl); - hit_ev_map_set(j, g_hit_ev_count - 1, 1); - cur = cur + 1; } } - ii = ii + 1; } + d : ., mut = hit_inj_line_dst(cur) + if l_fl % 2 == 0: + d = iri_dest(j) + if d < 0: + d = 0 + s1 : ., mut = hit_inj_line_s1(cur) + if l_fl / 2 % 2 == 0: + s1 = iri_s1(j) + if s1 < 0: + s1 = 0 + s2 : ., mut = hit_inj_line_s2(cur) + if l_fl / 4 % 2 == 0: + s2 = iri_s2(j) + if s2 < 0: + s2 = 0 + evfl : ., mut = 0 + if l_fl / 8 % 2 == 1: + evfl = evfl + HIT_ES_S1_POOL + if l_fl / 16 % 2 == 1: + evfl = evfl + HIT_ES_S2_POOL + hit_ev_append(l_id, d, s1, s2, evfl) + hit_ev_map_set(j, g_hit_ev_count - 1, 1) + cur = cur + 1 + ii = ii + 1 // ── 遍 3:尾校验(未附着行 = 作者错——事件不支持/与指令序不符)── - if cur < g_hit_inj_count { - print("error: HIT events: no instruction expects event "); - print(hit_event_name(hit_event_lookup(hit_inj_line_id(cur)))); - print(" (line "); print_i(cur + 1); println(")"); - return 1; } - if g_hit_inj_count == 0 { - println("error: HIT events: file has no ev lines"); - return 1; } + if cur < g_hit_inj_count: + print("error: HIT events: no instruction expects event ") + print(hit_event_name(hit_event_lookup(hit_inj_line_id(cur)))) + print(" (line ") + print_i(cur + 1) + println(")") + return 1 + if g_hit_inj_count == 0: + println("error: HIT events: file has no ev lines") + return 1 // jump 事件目标 = 事件序——范围校验(0 ≤ 目标 < 总事件数) - ji : ., mut = 0; - loop { - if ji >= g_hit_ev_count { break; } - if hit_ev_id(ji) == HIT_EV_JUMP { - t := hit_ev_s1(ji); - if t < 0 || t >= g_hit_ev_count { - print("error: HIT events: jump target event ordinal "); - print_i(t); print(" out of range (0.."); - print_i(g_hit_ev_count - 1); println(")"); - return 1; } } - ji = ji + 1; } - return 0; } + ji : ., mut = 0 + loop: + if ji >= g_hit_ev_count: + break + if hit_ev_id(ji) == HIT_EV_JUMP: + t := hit_ev_s1(ji) + if t < 0 || t >= g_hit_ev_count: + print("error: HIT events: jump target event ordinal ") + print_i(t) + print(" out of range (0..") + print_i(g_hit_ev_count - 1) + println(")") + return 1 + ji = ji + 1 + return 0 // 行内数值 token 解析(val 起为值首;返回 值;-1 = 非数) -fn hit_inj_parse_int(content: string, val: int) -> int { - slen := str_len(content); - p : ., mut = val; - if p < slen && load8(content, p) == 45 { p = p + 1; } // '-'(池负值) - if p >= slen { return -1; } - if load8(content, p) < 48 || load8(content, p) > 57 { return -1; } - return str_int(str_sub(content, val, str_len(content) - val)); } +fn hit_inj_parse_int(content: string, val: int) -> int: + slen := str_len(content) + p : ., mut = val + if p < slen && load8(content, p) == 45: + p = p + 1 + // '-'(池负值) + if p >= slen: + return -1 + if load8(content, p) < 48 || load8(content, p) > 57: + return -1 + return str_int(str_sub(content, val, str_len(content) - val)) // k=v 字段定位:从 fpos 起找 token "k=";命中返回 v 起偏移(v = 数或 "pool")。 // 返回:≥0 = 值起;-1 = 键未出现;-2 = 键出现但值非数/非 pool(坏值——调用方报错)。 -fn hit_inj_field_of(content: string, fpos: int, key: string, pool_ok: int) -> int { - slen := str_len(content); - klen := str_len(key); - p : ., mut = fpos; - loop { - if p + klen >= slen { return -1; } - if load8(content, p + klen) == 61 && (p == fpos || load8(content, p - 1) == 32) { - m : ., mut = 0; - ok : ., mut = 1; - loop { - if m >= klen { break; } - if load8(content, p + m) != load8(key, m) { ok = 0; break; } - m = m + 1; } - if ok == 1 { - v0 : ., mut = p + klen + 1; - if v0 >= slen { return -2; } - c := load8(content, v0); - if pool_ok == 1 && c == 112 && v0 + 4 <= slen && - load8(content, v0 + 1) == 111 && load8(content, v0 + 2) == 111 && - load8(content, v0 + 3) == 108 { return v0; } - if c >= 48 && c <= 57 || c == 45 { return v0; } - return -2; } - } - p = p + 1; } - return -1; } +fn hit_inj_field_of(content: string, fpos: int, key: string, pool_ok: int) -> int: + slen := str_len(content) + klen := str_len(key) + p : ., mut = fpos + loop: + if p + klen >= slen: + return -1 + if load8(content, p + klen) == 61 && (p == fpos || load8(content, p - 1) == 32): + m : ., mut = 0 + ok : ., mut = 1 + loop: + if m >= klen: + break + if load8(content, p + m) != load8(key, m): + ok = 0 + break + m = m + 1 + if ok == 1: + v0 : ., mut = p + klen + 1 + if v0 >= slen: + return -2 + c := load8(content, v0) + if pool_ok == 1 && c == 112 && v0 + 4 <= slen && load8(content, v0 + 1) == 111 && load8(content, v0 + 2) == 111 && load8(content, v0 + 3) == 108: + return v0 + if c >= 48 && c <= 57 || c == 45: + return v0 + return -2 + p = p + 1 + return -1 diff --git a/src/arch/x86_64/frame.cr b/src/arch/x86_64/frame.cr index aff540a3..40ee6fc1 100644 --- a/src/arch/x86_64/frame.cr +++ b/src/arch/x86_64/frame.cr @@ -37,34 +37,35 @@ // ── tag 表读取(H3 自 instr.cr 迁入;表由 tag2l.cr mw_setup_tags 按函数填充 // ——波 1 Task 4 起 tag 表 owner 在 tag2l.cr)── -fn g2_tag_off(v: int) -> int { +fn g2_tag_off(v: int) -> int: // var v(当前函数内)的 tag 字节偏移(相对 rbp,恒负);-1 = 非 tagged。 // 仅当前函数内有效(表由 mw_setup_tags 按函数填充)。 - if v < 0 { return -1; } - lv := v - g_current_func_var_start; - if lv < 0 { return -1; } - if str_len(g_x86_mw_tag_off) <= lv * 8 { return -1; } - return r64(g_x86_mw_tag_off, lv * 8); -} + if v < 0: + return -1 + lv := v - g_current_func_var_start + if lv < 0: + return -1 + if str_len(g_x86_mw_tag_off) <= lv * 8: + return -1 + return r64(g_x86_mw_tag_off, lv * 8) // ── 帧总字节(H2 ①:Phase 2 dry-run 与 Phase 3 共用)── -fn pf_frame_size(vc: int) -> int { +fn pf_frame_size(vc: int) -> int: // 帧总字节 = var 槽 vc*8 + tag 区(g_x86_mw_tag_count 字节)再按现 SysV // 规则补 16 对齐:opt≥1(6 pushes)帧 ≡ 8 (mod 16);opt<1(1 push)≡ 0。 // tag 数为 0 时对任意 vc 的结果与旧公式逐字节一致(快路径零变化)。 - sz : ., mut = vc * 8 + g_x86_mw_tag_count; - r := sz % 16; - if g_opt_level >= 1 { - if r != 8 { - pad := 8 - r; - if pad < 0 { pad = pad + 16; } - sz = sz + pad; - } - } else { - if r != 0 { sz = sz + (16 - r); } - } - return sz; -} + sz : ., mut = vc * 8 + g_x86_mw_tag_count + r := sz % 16 + if g_opt_level >= 1: + if r != 8: + pad := 8 - r + if pad < 0: + pad = pad + 16 + sz = sz + pad + else: + if r != 0: + sz = sz + (16 - r) + return sz // ── Phase 2 dry-run:帧相关字节总数(序言 + 尾声;不含形参落槽与函数体)── // H2 ②:dry-run 核算(本函数)与 H2 ③ 实际发射(pf_prologue/pf_epilogue)必须 @@ -75,14 +76,17 @@ fn pf_frame_size(vc: int) -> int { // sz_callee_saved_pop(9B/函数——push/pop 对已在 sz_callee_saved_push+pop 内, // 见下方函数尾再计点)。Phase 2 total_code 为临时值(Phase 3 由实际 cp 重算 // rodata/bss/函数偏移——elf.cr:1380/1422/1088),**无发射字节影响**、偏保守。 -fn pf_frame_overhead(ss: int) -> int { - sz : ., mut = sz_push_rbp() + sz_mov_rbp_rsp(); - if g_opt_level >= 1 { sz = sz + sz_callee_saved_push() + sz_callee_saved_pop(); } // push rbx,r12-r15(9) + pop r15-r12,rbx(9) - sz = sz + sz_sub_rsp(ss); - sz = sz + sz_add_rsp(ss) + sz_pop_rbp() + sz_ret(); - if g_opt_level >= 1 { sz = sz + sz_callee_saved_pop(); } // pop r15,r14,r13,r12,rbx - return sz; -} +fn pf_frame_overhead(ss: int) -> int: + sz : ., mut = sz_push_rbp() + sz_mov_rbp_rsp() + if g_opt_level >= 1: + sz = sz + sz_callee_saved_push() + sz_callee_saved_pop() + // push rbx,r12-r15(9) + pop r15-r12,rbx(9) + sz = sz + sz_sub_rsp(ss) + sz = sz + sz_add_rsp(ss) + sz_pop_rbp() + sz_ret() + if g_opt_level >= 1: + sz = sz + sz_callee_saved_pop() + // pop r15,r14,r13,r12,rbx + return sz // ── Phase 3 序言(帧 setup + 形参落槽 + 寄存器参数装载)── // 发射序(opt≥1 六寄存器保存 → push rbp/mov rbp,rsp → sub rsp 占位(立即数 @@ -90,102 +94,160 @@ fn pf_frame_overhead(ss: int) -> int { // 清 tag)→ 寄存器分配参数装载);返回新 cp。g_x86_sub_rsp_pos = sub rsp // 立即数字段位置(供 pf_epilogue 回填);帧尺寸 ss 显式传入(= pf_frame_size // 结果——H2 单源,本函数不再自行计算帧尺寸)。 -fn pf_prologue(vs: int, pc: int, ss: int, buf: string, pos: int) -> int { - cp : ., mut = pos; +fn pf_prologue(vs: int, pc: int, ss: int, buf: string, pos: int) -> int: + cp : ., mut = pos // Save callee-saved registers (pushed before rbp setup → at [rbp+8..48]) - if g_opt_level >= 1 { - w8(buf, cp, 83); cp = cp + 1; // push rbx - w8(buf, cp, 65); w8(buf, cp+1, 84); cp = cp + 2; // push r12 - w8(buf, cp, 65); w8(buf, cp+1, 85); cp = cp + 2; // push r13 - w8(buf, cp, 65); w8(buf, cp+1, 86); cp = cp + 2; // push r14 - w8(buf, cp, 65); w8(buf, cp+1, 87); cp = cp + 2; // push r15 - } + if g_opt_level >= 1: + w8(buf, cp, 83) + cp = cp + 1 // push rbx + w8(buf, cp, 65) + w8(buf, cp+1, 84) + cp = cp + 2 // push r12 + w8(buf, cp, 65) + w8(buf, cp+1, 85) + cp = cp + 2 // push r13 + w8(buf, cp, 65) + w8(buf, cp+1, 86) + cp = cp + 2 // push r14 + w8(buf, cp, 65) + w8(buf, cp+1, 87) + cp = cp + 2 // push r15 // frame - w8(buf, cp, 85); cp = cp + 1; // push rbp - w8(buf, cp, 72); w8(buf, cp+1, 137); w8(buf, cp+2, 229); cp = cp + 3; // mov rbp, rsp - g_x86_sub_rsp_pos = cp; - if ss > 0 { - if ss > 127 { - w8(buf, cp, 72); w8(buf, cp+1, 129); w8(buf, cp+2, 236); - e2_w32(buf, cp+3, 0); cp = cp + 7; - } else { - w8(buf, cp, 72); w8(buf, cp+1, 131); w8(buf, cp+2, 236); w8(buf, cp+3, 0); cp = cp + 4; - } - } + w8(buf, cp, 85) + cp = cp + 1 // push rbp + w8(buf, cp, 72) + w8(buf, cp+1, 137) + w8(buf, cp+2, 229) + cp = cp + 3 // mov rbp, rsp + g_x86_sub_rsp_pos = cp + if ss > 0: + if ss > 127: + w8(buf, cp, 72) + w8(buf, cp+1, 129) + w8(buf, cp+2, 236) + e2_w32(buf, cp+3, 0) + cp = cp + 7 + else: + w8(buf, cp, 72) + w8(buf, cp+1, 131) + w8(buf, cp+2, 236) + w8(buf, cp+3, 0) + cp = cp + 4 // Save register and caller-stack params into this function's slots. - pi := 0; loop { if pi >= pc { break; } - po2 := -(vs + pi + 1 - g_current_func_var_start) * 8; // force stack slot, ignore reg alloc - pty := irv_type(vs + pi); - if pty == TI_DEX && pi < 6 { + pi := 0 + loop: + if pi >= pc: + break + po2 := -(vs + pi + 1 - g_current_func_var_start) * 8 // force stack slot, ignore reg alloc + pty := irv_type(vs + pi) + if pty == TI_DEX && pi < 6: // float 参数在 XMM:movsd [rbp+po2], xmm{frn}(SysV) // frn = 第 pi 个参数前的 float 参数数 - frn : ., mut = 0; - fj : ., mut = 0; - loop { if fj >= pi { break; } - if irv_type(vs + fj) == TI_DEX { frn = frn + 1; } - fj = fj + 1; } - if frn < 8 { + frn : ., mut = 0 + fj : ., mut = 0 + loop: + if fj >= pi: + break + if irv_type(vs + fj) == TI_DEX: + frn = frn + 1 + fj = fj + 1 + if frn < 8: // movsd [rbp+po2], xmm{frn} — F2 0F 11 /rn(mod=01, rm=5) - w8(buf, cp, 242); w8(buf, cp+1, 15); w8(buf, cp+2, 17); - w8(buf, cp+3, 64 + frn * 8 + 5); w8(buf, cp+4, po2); cp = cp + 5; - } else { + w8(buf, cp, 242) + w8(buf, cp+1, 15) + w8(buf, cp+2, 17) + w8(buf, cp+3, 64 + frn * 8 + 5) + w8(buf, cp+4, po2) + cp = cp + 5 + else: // 9+ binary64 参数在栈上(边缘场景,位置布局简化处理) - caller_off := 16 + (pi - 6) * 8; - if g_opt_level >= 1 { caller_off = caller_off + 40; } - cp = cp + e2_sd_load(buf, cp, caller_off); - cp = cp + e2_sd_store(buf, cp, po2); - } - } else if pi >= 6 { - caller_off := 16 + (pi - 6) * 8; - if g_opt_level >= 1 { caller_off = caller_off + 40; } - if pty == TI_DEX { - cp = cp + e2_sd_load(buf, cp, caller_off); - cp = cp + e2_sd_store(buf, cp, po2); - } else { - cp = cp + e2_ld(buf, cp, 10, caller_off); - cp = cp + e2_st(buf, cp, 10, po2); - } - } else { - if pi == 0 { cp = cp + e2_st(buf, cp, 7, po2); } - if pi == 1 { w8(buf, cp, 72); w8(buf, cp+1, 137); w8(buf, cp+2, 117); w8(buf, cp+3, po2); cp = cp + 4; } - if pi == 2 { w8(buf, cp, 72); w8(buf, cp+1, 137); w8(buf, cp+2, 85); w8(buf, cp+3, po2); cp = cp + 4; } - if pi == 3 { w8(buf, cp, 72); w8(buf, cp+1, 137); w8(buf, cp+2, 77); w8(buf, cp+3, po2); cp = cp + 4; } - if pi == 4 { w8(buf, cp, 76); w8(buf, cp+1, 137); w8(buf, cp+2, 69); w8(buf, cp+3, po2); cp = cp + 4; } - if pi == 5 { w8(buf, cp, 76); w8(buf, cp+1, 137); w8(buf, cp+2, 77); w8(buf, cp+3, po2); cp = cp + 4; } - } + caller_off := 16 + (pi - 6) * 8 + if g_opt_level >= 1: + caller_off = caller_off + 40 + cp = cp + e2_sd_load(buf, cp, caller_off) + cp = cp + e2_sd_store(buf, cp, po2) + else if pi >= 6: + caller_off := 16 + (pi - 6) * 8 + if g_opt_level >= 1: + caller_off = caller_off + 40 + if pty == TI_DEX: + cp = cp + e2_sd_load(buf, cp, caller_off) + cp = cp + e2_sd_store(buf, cp, po2) + else: + cp = cp + e2_ld(buf, cp, 10, caller_off) + cp = cp + e2_st(buf, cp, 10, po2) + else: + if pi == 0: + cp = cp + e2_st(buf, cp, 7, po2) + if pi == 1: + w8(buf, cp, 72) + w8(buf, cp+1, 137) + w8(buf, cp+2, 117) + w8(buf, cp+3, po2) + cp = cp + 4 + if pi == 2: + w8(buf, cp, 72) + w8(buf, cp+1, 137) + w8(buf, cp+2, 85) + w8(buf, cp+3, po2) + cp = cp + 4 + if pi == 3: + w8(buf, cp, 72) + w8(buf, cp+1, 137) + w8(buf, cp+2, 77) + w8(buf, cp+3, po2) + cp = cp + 4 + if pi == 4: + w8(buf, cp, 76) + w8(buf, cp+1, 137) + w8(buf, cp+2, 69) + w8(buf, cp+3, po2) + cp = cp + 4 + if pi == 5: + w8(buf, cp, 76) + w8(buf, cp+1, 137) + w8(buf, cp+2, 77) + w8(buf, cp+3, po2) + cp = cp + 4 // int 多字 M1(Task 4)tag 卫生③:tagged 参数行的 prologue 定值 // 清 tag——参数在函数内首次定值前可能被消费者读取(tag 闭包可含 // 参数行:p = p + k 的 B' 定值拷贝),无本清则读到上次调用/垃圾 // tag。参数行按强制栈槽保存(po2),tag 字节同在帧内。 - if pty == TI_INT { - ptg := g2_tag_off(vs + pi); - if ptg != -1 { - if ptg >= -128 && ptg <= 127 { - w8(buf, cp, 198); w8(buf, cp+1, 69); w8(buf, cp+2, ptg); w8(buf, cp+3, 0); cp = cp + 4; - } else { - w8(buf, cp, 198); w8(buf, cp+1, 133); e2_w32(buf, cp+2, ptg); w8(buf, cp+6, 0); cp = cp + 7; - } - } - } - pi = pi + 1; } + if pty == TI_INT: + ptg := g2_tag_off(vs + pi) + if ptg != -1: + if ptg >= -128 && ptg <= 127: + w8(buf, cp, 198) + w8(buf, cp+1, 69) + w8(buf, cp+2, ptg) + w8(buf, cp+3, 0) + cp = cp + 4 + else: + w8(buf, cp, 198) + w8(buf, cp+1, 133) + e2_w32(buf, cp+2, ptg) + w8(buf, cp+6, 0) + cp = cp + 7 + pi = pi + 1 // Load register-allocated parameters from stack to callee-saved regs - if g_opt_level >= 1 { - pi2 : ., mut = 0; - loop { if pi2 >= pc || pi2 >= 6 { break; } - pri := get_reg_for_var(vs + pi2); - if pri >= 0 { - pso2 := -(vs + pi2 + 1 - g_current_func_var_start) * 8; // force stack slot + if g_opt_level >= 1: + pi2 : ., mut = 0 + loop: + if pi2 >= pc || pi2 >= 6: + break + pri := get_reg_for_var(vs + pi2) + if pri >= 0: + pso2 := -(vs + pi2 + 1 - g_current_func_var_start) * 8 // force stack slot // mov reg, [rbp+offset] — load from stack to allocated register - cp = cp + emit_rex(buf, cp, 1, pri/8, 0, 0); - e2_w8(buf, cp, 139); cp = cp + 1; // 0x8B MOV r64, r/m64 - cp = cp + emit_modrm(buf, cp, 1, pri%8, 5); // [rbp+disp8] - e2_w8(buf, cp, pso2); cp = cp + 1; - } - pi2 = pi2 + 1; } - } - return cp; -} + cp = cp + emit_rex(buf, cp, 1, pri/8, 0, 0) + e2_w8(buf, cp, 139) + cp = cp + 1 // 0x8B MOV r64, r/m64 + cp = cp + emit_modrm(buf, cp, 1, pri%8, 5) // [rbp+disp8] + e2_w8(buf, cp, pso2) + cp = cp + 1 + pi2 = pi2 + 1 + return cp // ── Phase 3 尾声 + 函数尾附加块 —— @@ -193,49 +255,68 @@ fn pf_prologue(vs: int, pc: int, ss: int, buf: string, pos: int) -> int { // epilogue 发射(add rsp / opt≥1 六寄存器逆序 pop / pop rbp / ret)→ 函数尾 // 附加块(jo 慢路径块 + 2L 操作数块;逐站点独立块,冷区)。返回新 cp。 // ss 显式传入(= 序言所用帧尺寸;H2 单源)。 -fn pf_epilogue(ss: int, buf: string, pos: int) -> int { - cp : ., mut = pos; +fn pf_epilogue(ss: int, buf: string, pos: int) -> int: + cp : ., mut = pos // patch RETURNs to epilogue - epi_pos := cp; - print(" rets: "); print(int_str(g_x86_ret_patch_count)); println(""); - rpi := 0; loop { if rpi >= g_x86_ret_patch_count { break; } - jmp_pos := r64(g_x86_ret_patch_pos, rpi * 8); - rel := epi_pos - (jmp_pos + 5); - w32(buf, jmp_pos + 1, rel); - rpi = rpi + 1; } - g_x86_ret_patch_count = 0; + epi_pos := cp + print(" rets: ") + print(int_str(g_x86_ret_patch_count)) + println("") + rpi := 0 + loop: + if rpi >= g_x86_ret_patch_count: + break + jmp_pos := r64(g_x86_ret_patch_pos, rpi * 8) + rel := epi_pos - (jmp_pos + 5) + w32(buf, jmp_pos + 1, rel) + rpi = rpi + 1 + g_x86_ret_patch_count = 0 // Patch prologue sub rsp with actual stack size - if ss > 0 { - ss3 := ss; - if ss3 > 127 { - e2_w32(buf, g_x86_sub_rsp_pos + 3, ss3); - } else { - w8(buf, g_x86_sub_rsp_pos + 3, ss3); - } - } + if ss > 0: + ss3 := ss + if ss3 > 127: + e2_w32(buf, g_x86_sub_rsp_pos + 3, ss3) + else: + w8(buf, g_x86_sub_rsp_pos + 3, ss3) // epilogue (emit with correct stack size, no placeholder) - if ss > 0 { - if ss > 127 { - w8(buf, cp, 72); w8(buf, cp+1, 129); w8(buf, cp+2, 196); - e2_w32(buf, cp+3, ss); cp = cp + 7; - } else { - w8(buf, cp, 72); w8(buf, cp+1, 131); w8(buf, cp+2, 196); w8(buf, cp+3, ss); cp = cp + 4; - } - } - if g_opt_level >= 1 { + if ss > 0: + if ss > 127: + w8(buf, cp, 72) + w8(buf, cp+1, 129) + w8(buf, cp+2, 196) + e2_w32(buf, cp+3, ss) + cp = cp + 7 + else: + w8(buf, cp, 72) + w8(buf, cp+1, 131) + w8(buf, cp+2, 196) + w8(buf, cp+3, ss) + cp = cp + 4 + if g_opt_level >= 1: // Pops in REVERSE order: rbp, r15, r14, r13, r12, rbx - w8(buf, cp, 93); cp = cp + 1; // pop rbp - w8(buf, cp, 65); w8(buf, cp+1, 95); cp = cp + 2; // pop r15 - w8(buf, cp, 65); w8(buf, cp+1, 94); cp = cp + 2; // pop r14 - w8(buf, cp, 65); w8(buf, cp+1, 93); cp = cp + 2; // pop r13 - w8(buf, cp, 65); w8(buf, cp+1, 92); cp = cp + 2; // pop r12 - w8(buf, cp, 91); cp = cp + 1; // pop rbx - } else { - w8(buf, cp, 93); cp = cp + 1; // pop rbp - } - w8(buf, cp, 195); cp = cp + 1; // ret + w8(buf, cp, 93) + cp = cp + 1 // pop rbp + w8(buf, cp, 65) + w8(buf, cp+1, 95) + cp = cp + 2 // pop r15 + w8(buf, cp, 65) + w8(buf, cp+1, 94) + cp = cp + 2 // pop r14 + w8(buf, cp, 65) + w8(buf, cp+1, 93) + cp = cp + 2 // pop r13 + w8(buf, cp, 65) + w8(buf, cp+1, 92) + cp = cp + 2 // pop r12 + w8(buf, cp, 91) + cp = cp + 1 // pop rbx + else: + w8(buf, cp, 93) + cp = cp + 1 // pop rbp + w8(buf, cp, 195) + cp = cp + 1 // ret // ── int 多字 M1(Task 3):慢路径块(函数尾附加)+ jo rel32 回填 ── // 每 jo 站点独立块(块形状决策:jo 现场 = dest 槽/回跳点逐站点而异, @@ -248,19 +329,20 @@ fn pf_epilogue(ss: int, buf: string, pos: int) -> int { // 同源同值)→ tag 置位 → jmp 回该站点快路径 store 之后。 // jo 记录(pos/dest/is_sub/resume——g2_init 清零逐函数段)此处按站 // 点点序发射;无 jo 的函数不发块、零字节影响(untagged 快路径零变化)。 - if g_x86_mw_jo_count > 0 { - mw_ji : ., mut = 0; - loop { if mw_ji >= g_x86_mw_jo_count { break; } - jo_pos := r64(g_x86_mw_jo_pos, mw_ji * 8); - jo_d := r64(g_x86_mw_jo_dest, mw_ji * 8); - jo_sub := r64(g_x86_mw_jo_is_sub, mw_ji * 8); - jo_res := r64(g_x86_mw_jo_resume, mw_ji * 8); - mw_blk := cp; - w32(buf, jo_pos + 2, mw_blk - (jo_pos + 6)); - cp = cp + e2_mw_slow_block(buf, cp, jo_d, jo_sub, jo_res); - mw_ji = mw_ji + 1; } - g_x86_mw_jo_count = 0; - } + if g_x86_mw_jo_count > 0: + mw_ji : ., mut = 0 + loop: + if mw_ji >= g_x86_mw_jo_count: + break + jo_pos := r64(g_x86_mw_jo_pos, mw_ji * 8) + jo_d := r64(g_x86_mw_jo_dest, mw_ji * 8) + jo_sub := r64(g_x86_mw_jo_is_sub, mw_ji * 8) + jo_res := r64(g_x86_mw_jo_resume, mw_ji * 8) + mw_blk := cp + w32(buf, jo_pos + 2, mw_blk - (jo_pos + 6)) + cp = cp + e2_mw_slow_block(buf, cp, jo_d, jo_sub, jo_res) + mw_ji = mw_ji + 1 + g_x86_mw_jo_count = 0 // ── int 多字 M1(Task 4):2L 操作数块(函数尾附加,jo 块之后)── // 每消费者站点独立块(快路径 tag 检查 jne → 块首;块 = 128 位算术 // 或比较 + 公共落值——e2_mw_opnd_block,tag2l.cr)。块形状按站点 @@ -268,22 +350,24 @@ fn pf_epilogue(ss: int, buf: string, pos: int) -> int { // 块与函数体同批回填(alloc_patch 计数逐函数不重置)。jne rel32 // 位置在 oc 记录(pos1/pos2,-1 = 无第二个检查),块位置 = 发射时 // cp。无消费者站点的函数零字节(untagged 快路径零变化保持)。 - if g_x86_mw_oc_count > 0 { - mw_oi : ., mut = 0; - loop { if mw_oi >= g_x86_mw_oc_count { break; } - oc_p1 := r64(g_x86_mw_oc_pos1, mw_oi * 8); - oc_p2 := r64(g_x86_mw_oc_pos2, mw_oi * 8); - oc_s1 := r64(g_x86_mw_oc_s1, mw_oi * 8); - oc_s2 := r64(g_x86_mw_oc_s2, mw_oi * 8); - oc_d := r64(g_x86_mw_oc_dest, mw_oi * 8); - oc_op := r64(g_x86_mw_oc_op, mw_oi * 8); - oc_res := r64(g_x86_mw_oc_resume, mw_oi * 8); - oc_blk := cp; - if oc_p1 >= 0 { w32(buf, oc_p1 + 2, oc_blk - (oc_p1 + 6)); } - if oc_p2 >= 0 { w32(buf, oc_p2 + 2, oc_blk - (oc_p2 + 6)); } - cp = cp + e2_mw_opnd_block(buf, cp, oc_s1, oc_s2, oc_d, oc_op, oc_res); - mw_oi = mw_oi + 1; } - g_x86_mw_oc_count = 0; - } - return cp; -} + if g_x86_mw_oc_count > 0: + mw_oi : ., mut = 0 + loop: + if mw_oi >= g_x86_mw_oc_count: + break + oc_p1 := r64(g_x86_mw_oc_pos1, mw_oi * 8) + oc_p2 := r64(g_x86_mw_oc_pos2, mw_oi * 8) + oc_s1 := r64(g_x86_mw_oc_s1, mw_oi * 8) + oc_s2 := r64(g_x86_mw_oc_s2, mw_oi * 8) + oc_d := r64(g_x86_mw_oc_dest, mw_oi * 8) + oc_op := r64(g_x86_mw_oc_op, mw_oi * 8) + oc_res := r64(g_x86_mw_oc_resume, mw_oi * 8) + oc_blk := cp + if oc_p1 >= 0: + w32(buf, oc_p1 + 2, oc_blk - (oc_p1 + 6)) + if oc_p2 >= 0: + w32(buf, oc_p2 + 2, oc_blk - (oc_p2 + 6)) + cp = cp + e2_mw_opnd_block(buf, cp, oc_s1, oc_s2, oc_d, oc_op, oc_res) + mw_oi = mw_oi + 1 + g_x86_mw_oc_count = 0 + return cp diff --git a/src/arch/x86_64/instr.cr b/src/arch/x86_64/instr.cr index d1eb4615..9fe477aa 100644 --- a/src/arch/x86_64/instr.cr +++ b/src/arch/x86_64/instr.cr @@ -3,93 +3,103 @@ // ══════════════════════════════════════════════════════════════ // State globals (set by caller before emit phase) -g_x86_rodata_base : int, mut; -g_x86_func_frame_start : int, mut; // abs buf pos of current function body (after frame) -g_current_func_var_start : int, mut; // var_start of current function, set before emit -g_hit_tabled_count : int, mut; // 表驱动实际发射事件条数(诊断:corearch 表模式总结) +g_x86_rodata_base : int, mut +g_x86_func_frame_start : int, mut // abs buf pos of current function body (after frame) +g_current_func_var_start : int, mut // var_start of current function, set before emit +g_hit_tabled_count : int, mut // 表驱动实际发射事件条数(诊断:corearch 表模式总结) -E2_REG_SLOT_BASE : int = 1000000000; +E2_REG_SLOT_BASE : int = 1000000000 -fn g2_init() { - g_x86_emit_var_count = 0; - g_x86_emit_stack_size = 0; - g_x86_ret_patch_count = 0; +fn g2_init(): + g_x86_emit_var_count = 0 + g_x86_emit_stack_size = 0 + g_x86_ret_patch_count = 0 // g_x86_mw_jo_count: reset per function — jo rel32s are patched to the // function-tail slow-path block right after each function's epilogue. - g_x86_mw_jo_count = 0; + g_x86_mw_jo_count = 0 // g_x86_mw_oc_count (Task 4): reset per function — 2L 操作数检查 // (jne 0F 85)同款回填到函数尾 2L 块。 - g_x86_mw_oc_count = 0; + g_x86_mw_oc_count = 0 // g_x86_alloc_patch_count NOT reset: alloc calls are patched after all funcs. // g_x86_ext_rel_count NOT reset: extern relocations span all functions. // g_x86_rip_patch_count NOT reset -} // ── Optimization metadata: register assignment lookup ── // Reads g_opt_meta to find register for a variable. regalloc 移后端(2026-09-07) // 后 g_opt_meta 由 corearch O2 自算填充(load 后 alloc_registers,不再经 .ccr // 传输);O0/O1 恒空 → 全栈发射。Returns -1 if no register assigned. -fn get_reg_for_var(var_idx: int) -> int { - mi : ., mut = 0; - loop { if mi >= g_opt_meta_count { break; } - mo := mi * OPT_META_STRIDE; - mk := r32(g_opt_meta, mo); - if mk == OPT_KEY_REG_ASSIGN { - data_len := r32(g_opt_meta, mo + 4); - di : ., mut = 4; // skip count u32, pairs start at +4 - loop { if di >= data_len { break; } - vi := r32(g_opt_meta, mo + 8 + di); - if vi == var_idx { - return r32(g_opt_meta, mo + 8 + di + 4); - } - di = di + 8; - } - } - mi = mi + 1; - } - return -1; -} - -fn g2_slot(v: int) -> int { +fn get_reg_for_var(var_idx: int) -> int: + mi : ., mut = 0 + loop: + if mi >= g_opt_meta_count: + break + mo := mi * OPT_META_STRIDE + mk := r32(g_opt_meta, mo) + if mk == OPT_KEY_REG_ASSIGN: + data_len := r32(g_opt_meta, mo + 4) + di : ., mut = 4 // skip count u32, pairs start at +4 + loop: + if di >= data_len: + break + vi := r32(g_opt_meta, mo + 8 + di) + if vi == var_idx: + return r32(g_opt_meta, mo + 8 + di + 4) + di = di + 8 + mi = mi + 1 + return -1 + +fn g2_slot(v: int) -> int: // Register encoding uses a positive sentinel range so it cannot collide // with large negative stack frame offsets. - if v >= E2_REG_SLOT_BASE { return v; } + if v >= E2_REG_SLOT_BASE: + return v // Check optimization metadata for register assignment (opt_level >= 1) - if g_opt_level >= 1 && v >= 0 { - rn := get_reg_for_var(v); - if rn >= 0 { return E2_REG_SLOT_BASE + rn; } - } + if g_opt_level >= 1 && v >= 0: + rn := get_reg_for_var(v) + if rn >= 0: + return E2_REG_SLOT_BASE + rn // Stack sharing: if this var maps to another, use that var's slot - if v >= 0 && str_len(g_stack_map) > v * 8 { - mapped := r64(g_stack_map, v * 8); - if mapped >= 0 && mapped != v { v = mapped; } - } + if v >= 0 && str_len(g_stack_map) > v * 8: + mapped := r64(g_stack_map, v * 8) + if mapped >= 0 && mapped != v: + v = mapped // Function-relative slot: offset within current function's stack frame // Keeps offsets small (disp8 range) for large absolute var indices - if v >= 0 { return -(v + 1 - g_current_func_var_start) * 8; } - return 0; -} - -fn g2_str_off(si: int) -> int { - o := 0; i := 0; - loop { - if i >= g_x86_str_count { break; } - if r64(g_x86_str_offs, i * 8) == si { return o + 8; } // +8 for this string's header - o = o + 8 + istr_len(r64(g_x86_str_offs, i * 8)) + 1; - if o % 8 != 0 { o = o + 8 - (o % 8); } - i = i + 1; - } - grow_str_offs(g_x86_str_count + 1); w64(g_x86_str_offs, g_x86_str_count * 8, si); g_x86_str_count = g_x86_str_count + 1; - return o + 8; // +8 for this string's header -} - -fn g2_rodata_sz() -> int { - o := 0; i := 0; - loop { if i >= g_x86_str_count { break; } o = o + 8 + istr_len(r64(g_x86_str_offs, i * 8)) + 1; if o % 8 != 0 { o = o + 8 - (o % 8); } i = i + 1; } - return o; -} + if v >= 0: + return -(v + 1 - g_current_func_var_start) * 8 + return 0 + +fn g2_str_off(si: int) -> int: + o := 0 + i := 0 + loop: + if i >= g_x86_str_count: + break + if r64(g_x86_str_offs, i * 8) == si: + return o + 8 + // +8 for this string's header + o = o + 8 + istr_len(r64(g_x86_str_offs, i * 8)) + 1 + if o % 8 != 0: + o = o + 8 - (o % 8) + i = i + 1 + grow_str_offs(g_x86_str_count + 1) + w64(g_x86_str_offs, g_x86_str_count * 8, si) + g_x86_str_count = g_x86_str_count + 1 + return o + 8 // +8 for this string's header + +fn g2_rodata_sz() -> int: + o := 0 + i := 0 + loop: + if i >= g_x86_str_count: + break + o = o + 8 + istr_len(r64(g_x86_str_offs, i * 8)) + 1 + if o % 8 != 0: + o = o + 8 - (o % 8) + i = i + 1 + return o // int 多字 M1(tagged 槽)/ tag 表 / 2L 编码族——**全章移至 // src/arch/x86_64/tag2l.cr**(值表示、识别规则 A/B/B'、M1 边界、tag 卫生、 @@ -110,337 +120,390 @@ fn g2_rodata_sz() -> int { // sys_syscall4_stub;rax 号 + rdi/rsi/rdx(/r10) 参数序 + 0F 05 + 回存)。 // ── Byte encoding helpers ── -fn e2_w8(buf: string, pos: int, val: int) { store8(buf, pos, val % 256); } -fn e2_w16(buf: string, off: int, val: int) { w32(buf, off, val); } -fn e2_w32(buf: string, pos: int, val: int) -> int { - w32(buf, pos, val); - return 4; -} -fn e2_w64(buf: string, pos: int, val: int) -> int { w64(buf, pos, val); return 8; } +fn e2_w8(buf: string, pos: int, val: int): + store8(buf, pos, val % 256) +fn e2_w16(buf: string, off: int, val: int): + w32(buf, off, val) +fn e2_w32(buf: string, pos: int, val: int) -> int: + w32(buf, pos, val) + return 4 +fn e2_w64(buf: string, pos: int, val: int) -> int: + w64(buf, pos, val) + return 8 // ── Encoding primitives (computed, no magic numbers) ── // REX byte: 0100 WRXB — computed from W/R/X/B flags (0 or 1 each) -fn emit_rex(buf: string, pos: int, W: int, R: int, X: int, B: int) -> int { - e2_w8(buf, pos, 64 + W*8 + R*4 + X*2 + B); return 1; -} +fn emit_rex(buf: string, pos: int, W: int, R: int, X: int, B: int) -> int: + e2_w8(buf, pos, 64 + W*8 + R*4 + X*2 + B) + return 1 // ModRM byte: mod<6:7> | reg<3:5> | rm<0:2> -fn emit_modrm(buf: string, pos: int, m: int, reg: int, rm: int) -> int { - e2_w8(buf, pos, m*64 + reg*8 + rm); return 1; -} +fn emit_modrm(buf: string, pos: int, m: int, reg: int, rm: int) -> int: + e2_w8(buf, pos, m*64 + reg*8 + rm) + return 1 // SIB byte: scale<6:7> | index<3:5> | base<0:2> -fn emit_sib(buf: string, pos: int, scale: int, index: int, base: int) -> int { - e2_w8(buf, pos, scale*64 + index*8 + base); return 1; -} +fn emit_sib(buf: string, pos: int, scale: int, index: int, base: int) -> int: + e2_w8(buf, pos, scale*64 + index*8 + base) + return 1 -fn e2_mov(b: string, p: int, d: int, s: int) -> int { +fn e2_mov(b: string, p: int, d: int, s: int) -> int: // mov r64, r64 — opcode 0x89 MOV r/m, r, mod=3 (register) // REX: W=1, R=source>>3, B=dest>>3 - cp := p; - cp = cp + emit_rex(b, cp, 1, s/8, 0, d/8); - e2_w8(b, cp, 137); cp = cp + 1; // opcode 0x89 MOV r/m, r - cp = cp + emit_modrm(b, cp, 3, s%8, d%8); - return cp - p; -} - -fn e2_ld(b: string, p: int, r: int, o: int) -> int { + cp := p + cp = cp + emit_rex(b, cp, 1, s/8, 0, d/8) + e2_w8(b, cp, 137) + cp = cp + 1 // opcode 0x89 MOV r/m, r + cp = cp + emit_modrm(b, cp, 3, s%8, d%8) + return cp - p + +fn e2_ld(b: string, p: int, r: int, o: int) -> int: // mov r64, [src] — opcode 0x8B MOV r, r/m, 3 addressing modes - cp := p; - if o >= E2_REG_SLOT_BASE { + cp := p + if o >= E2_REG_SLOT_BASE: // Register-to-register: mov r_dest, r_src (copies value from alloc'd reg) - src_reg := o - E2_REG_SLOT_BASE; - return e2_mov(b, p, r, src_reg); - } - if o >= -128 && o <= 127 { + src_reg := o - E2_REG_SLOT_BASE + return e2_mov(b, p, r, src_reg) + if o >= -128 && o <= 127: // [rbp+disp8] (mod=01, rm=5) - cp = cp + emit_rex(b, cp, 1, r/8, 0, 0); - e2_w8(b, cp, 139); cp = cp + 1; - cp = cp + emit_modrm(b, cp, 1, r%8, 5); - e2_w8(b, cp, o); cp = cp + 1; - return cp - p; - } + cp = cp + emit_rex(b, cp, 1, r/8, 0, 0) + e2_w8(b, cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(b, cp, 1, r%8, 5) + e2_w8(b, cp, o) + cp = cp + 1 + return cp - p // [rbp+disp32] (mod=02, rm=5) - cp = cp + emit_rex(b, cp, 1, r/8, 0, 0); - e2_w8(b, cp, 139); cp = cp + 1; - cp = cp + emit_modrm(b, cp, 2, r%8, 5); - cp = cp + e2_w32(b, cp, o); - return cp - p; -} + cp = cp + emit_rex(b, cp, 1, r/8, 0, 0) + e2_w8(b, cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(b, cp, 2, r%8, 5) + cp = cp + e2_w32(b, cp, o) + return cp - p -fn e2_st(b: string, p: int, r: int, o: int) -> int { +fn e2_st(b: string, p: int, r: int, o: int) -> int: // mov [dst], r64 — opcode 0x89 MOV r/m, r, 3 addressing modes - if o >= E2_REG_SLOT_BASE { + if o >= E2_REG_SLOT_BASE: // register destination: use 3-operand mov (mod=3) - dst_reg := o - E2_REG_SLOT_BASE; - return e2_mov(b, p, dst_reg, r); - } - cp := p; - cp = cp + emit_rex(b, cp, 1, r/8, 0, 0); // REX.W + REX.R(if r>=8) - e2_w8(b, cp, 137); cp = cp + 1; // opcode 0x89 MOV r/m, r - if o >= -128 && o <= 127 { - cp = cp + emit_modrm(b, cp, 1, r%8, 5); - e2_w8(b, cp, o); cp = cp + 1; - return cp - p; - } - cp = cp + emit_modrm(b, cp, 2, r%8, 5); - cp = cp + e2_w32(b, cp, o); - return cp - p; -} - -fn e2_li(b: string, p: int, o: int, v: int) -> int { - cp := p; + dst_reg := o - E2_REG_SLOT_BASE + return e2_mov(b, p, dst_reg, r) + cp := p + cp = cp + emit_rex(b, cp, 1, r/8, 0, 0) // REX.W + REX.R(if r>=8) + e2_w8(b, cp, 137) + cp = cp + 1 // opcode 0x89 MOV r/m, r + if o >= -128 && o <= 127: + cp = cp + emit_modrm(b, cp, 1, r%8, 5) + e2_w8(b, cp, o) + cp = cp + 1 + return cp - p + cp = cp + emit_modrm(b, cp, 2, r%8, 5) + cp = cp + e2_w32(b, cp, o) + return cp - p + +fn e2_li(b: string, p: int, o: int, v: int) -> int: + cp := p // mov [rbp+disp], imm64 — two-step for values outside signed 32-bit range - if v < -2147483647 - 1 || v > 2147483647 { + if v < -2147483647 - 1 || v > 2147483647: // Step 1: mov rax, imm64 (REX.W + 0xB8 MOV r, imm + rax + 8B imm) - cp = cp + emit_rex(b, cp, 1, 0, 0, 0); - e2_w8(b, cp, 184); cp = cp + 1; // 0xB8 MOV r, imm (reg=0→rax) - cp = cp + e2_w64(b, cp, v); + cp = cp + emit_rex(b, cp, 1, 0, 0, 0) + e2_w8(b, cp, 184) + cp = cp + 1 // 0xB8 MOV r, imm (reg=0→rax) + cp = cp + e2_w64(b, cp, v) // Step 2: mov [rbp+disp], rax (REX.W + 0x89 MOV r/m, r) - cp = cp + emit_rex(b, cp, 1, 0, 0, 0); - e2_w8(b, cp, 137); cp = cp + 1; - if o >= -128 && o <= 127 { - cp = cp + emit_modrm(b, cp, 1, 0, 5); - e2_w8(b, cp, o); cp = cp + 1; - } else { - cp = cp + emit_modrm(b, cp, 2, 0, 5); - cp = cp + e2_w32(b, cp, o); - } - return cp - p; - } + cp = cp + emit_rex(b, cp, 1, 0, 0, 0) + e2_w8(b, cp, 137) + cp = cp + 1 + if o >= -128 && o <= 127: + cp = cp + emit_modrm(b, cp, 1, 0, 5) + e2_w8(b, cp, o) + cp = cp + 1 + else: + cp = cp + emit_modrm(b, cp, 2, 0, 5) + cp = cp + e2_w32(b, cp, o) + return cp - p // mov [rbp+disp], imm32 — opcode 0xC7 MOV r/m, imm, sign-extended - cp = cp + emit_rex(b, cp, 1, 0, 0, 0); - e2_w8(b, cp, 199); cp = cp + 1; // 0xC7 MOV r/m, imm32 - if o >= -128 && o <= 127 { - cp = cp + emit_modrm(b, cp, 1, 0, 5); - e2_w8(b, cp, o); cp = cp + 1; - cp = cp + e2_w32(b, cp, v); - } else { - cp = cp + emit_modrm(b, cp, 2, 0, 5); - cp = cp + e2_w32(b, cp, o); - cp = cp + e2_w32(b, cp, v); - } - return cp - p; -} - -fn e2_lr(b: string, p: int, rel: int) -> int { + cp = cp + emit_rex(b, cp, 1, 0, 0, 0) + e2_w8(b, cp, 199) + cp = cp + 1 // 0xC7 MOV r/m, imm32 + if o >= -128 && o <= 127: + cp = cp + emit_modrm(b, cp, 1, 0, 5) + e2_w8(b, cp, o) + cp = cp + 1 + cp = cp + e2_w32(b, cp, v) + else: + cp = cp + emit_modrm(b, cp, 2, 0, 5) + cp = cp + e2_w32(b, cp, o) + cp = cp + e2_w32(b, cp, v) + return cp - p + +fn e2_lr(b: string, p: int, rel: int) -> int: // lea r10, [rip + rel] — dest=r10, REX.R=1 since r10>=8 - cp := p; - cp = cp + emit_rex(b, cp, 1, 1, 0, 0); - e2_w8(b, cp, 141); cp = cp + 1; // LEA opcode 0x8D - cp = cp + emit_modrm(b, cp, 0, 2, 5); // r10%8=2, rm=5=RIP-relative - cp = cp + e2_w32(b, cp, rel); - return cp - p; -} - -fn e2_lrb(buf: string, p: int, rel: int) -> int { + cp := p + cp = cp + emit_rex(b, cp, 1, 1, 0, 0) + e2_w8(b, cp, 141) + cp = cp + 1 // LEA opcode 0x8D + cp = cp + emit_modrm(b, cp, 0, 2, 5) // r10%8=2, rm=5=RIP-relative + cp = cp + e2_w32(b, cp, rel) + return cp - p + +fn e2_lrb(buf: string, p: int, rel: int) -> int: // lea r11, [rip + rel] — dest=r11, REX.R=1 since r11>=8 - cp := p; - cp = cp + emit_rex(buf, cp, 1, 1, 0, 0); - e2_w8(buf, cp, 141); cp = cp + 1; - cp = cp + emit_modrm(buf, cp, 0, 3, 5); // r11%8=3 - cp = cp + e2_w32(buf, cp, rel); - return cp - p; -} - -fn e2_lb(b: string, p: int, o: int) -> int { + cp := p + cp = cp + emit_rex(buf, cp, 1, 1, 0, 0) + e2_w8(buf, cp, 141) + cp = cp + 1 + cp = cp + emit_modrm(buf, cp, 0, 3, 5) // r11%8=3 + cp = cp + e2_w32(buf, cp, rel) + return cp - p + +fn e2_lb(b: string, p: int, o: int) -> int: // lea r10, [rbp + offset] - cp := p; - cp = cp + emit_rex(b, cp, 1, 1, 0, 0); // REX.W + REX.R (r10 >= 8) - e2_w8(b, cp, 141); cp = cp + 1; // LEA opcode 0x8D - if o >= -128 && o <= 127 { - cp = cp + emit_modrm(b, cp, 1, 2, 5); // mod=01=[rbp+disp8], reg=2=r10%8, rm=5=rbp - e2_w8(b, cp, o); cp = cp + 1; - } else { - cp = cp + emit_modrm(b, cp, 2, 2, 5); // mod=10=[rbp+disp32] - cp = cp + e2_w32(b, cp, o); - } - return cp - p; -} - -fn e2_call(b: string, p: int, rel: int) -> int { + cp := p + cp = cp + emit_rex(b, cp, 1, 1, 0, 0) // REX.W + REX.R (r10 >= 8) + e2_w8(b, cp, 141) + cp = cp + 1 // LEA opcode 0x8D + if o >= -128 && o <= 127: + cp = cp + emit_modrm(b, cp, 1, 2, 5) // mod=01=[rbp+disp8], reg=2=r10%8, rm=5=rbp + e2_w8(b, cp, o) + cp = cp + 1 + else: + cp = cp + emit_modrm(b, cp, 2, 2, 5) // mod=10=[rbp+disp32] + cp = cp + e2_w32(b, cp, o) + return cp - p + +fn e2_call(b: string, p: int, rel: int) -> int: // call rel32 — opcode 0xE8 - e2_w8(b, p, 232); e2_w32(b, p+1, rel); return 5; -} + e2_w8(b, p, 232) + e2_w32(b, p+1, rel) + return 5 -fn e2_jmp(b: string, p: int, rel: int) -> int { +fn e2_jmp(b: string, p: int, rel: int) -> int: // jmp rel32 — opcode 0xE9 - e2_w8(b, p, 233); e2_w32(b, p+1, rel); return 5; -} + e2_w8(b, p, 233) + e2_w32(b, p+1, rel) + return 5 -fn e2_je(b: string, p: int, rel: int) -> int { +fn e2_je(b: string, p: int, rel: int) -> int: // je rel32 near — 2-byte opcode 0x0F 0x84 - e2_w8(b, p, 15); e2_w8(b, p+1, 132); e2_w32(b, p+2, rel); return 6; -} + e2_w8(b, p, 15) + e2_w8(b, p+1, 132) + e2_w32(b, p+2, rel) + return 6 -fn e2_jae(b: string, p: int, rel: int) -> int { +fn e2_jae(b: string, p: int, rel: int) -> int: // jae rel32 near — 2-byte opcode 0x0F 0x83 - e2_w8(b, p, 15); e2_w8(b, p+1, 131); e2_w32(b, p+2, rel); return 6; -} - -fn e2_ptr_bounds_check(b: string, p: int, base_var: int, alloc_sz: int, access_width: int) -> int { - if base_var < 0 || alloc_sz <= 0 { return 0; } - width : ., mut = access_width; - if width <= 0 { width = 8; } - limit : ., mut = alloc_sz - width + 1; - if limit < 0 { limit = 0; } - - cp : ., mut = 0; - cp = cp + e2_load_var(b, p+cp, 11, base_var); + e2_w8(b, p, 15) + e2_w8(b, p+1, 131) + e2_w32(b, p+2, rel) + return 6 + +fn e2_ptr_bounds_check(b: string, p: int, base_var: int, alloc_sz: int, access_width: int) -> int: + if base_var < 0 || alloc_sz <= 0: + return 0 + width : ., mut = access_width + if width <= 0: + width = 8 + limit : ., mut = alloc_sz - width + 1 + if limit < 0: + limit = 0 + + cp : ., mut = 0 + cp = cp + e2_load_var(b, p+cp, 11, base_var) // rax = pointer - allocation base; keep r10 intact for the access. - cp = cp + emit_rex(b, p+cp, 1, 10/8, 0, 0); - e2_w8(b, p+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(b, p+cp, 3, 10%8, 0); - cp = cp + emit_rex(b, p+cp, 1, 11/8, 0, 0); - e2_w8(b, p+cp, 41); cp = cp + 1; - cp = cp + emit_modrm(b, p+cp, 3, 11%8, 0); + cp = cp + emit_rex(b, p+cp, 1, 10/8, 0, 0) + e2_w8(b, p+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(b, p+cp, 3, 10%8, 0) + cp = cp + emit_rex(b, p+cp, 1, 11/8, 0, 0) + e2_w8(b, p+cp, 41) + cp = cp + 1 + cp = cp + emit_modrm(b, p+cp, 3, 11%8, 0) // F17:limit ≥ 2³¹ 时 cmp imm32 符号扩展会把 limit 变负——无符号比较永不陷阱。 // 改为 movabs rcx, imm64 + cmp rax, rcx(64 位无符号比较正确)。 // movabs rcx, imm64 — REX.W 0x48 + 0xB9 + imm64 - e2_w8(b, p+cp, 72); e2_w8(b, p+cp+1, 185); - e2_w64(b, p+cp+2, limit); cp = cp + 10; + e2_w8(b, p+cp, 72) + e2_w8(b, p+cp+1, 185) + e2_w64(b, p+cp+2, limit) + cp = cp + 10 // cmp rax, rcx — REX.W 0x48 + 0x39 + ModRM(3, reg=1, rm=0) - cp = cp + emit_rex(b, p+cp, 1, 0, 0, 0); - e2_w8(b, p+cp, 57); cp = cp + 1; - cp = cp + emit_modrm(b, p+cp, 3, 1, 0); - crash_jmp_pos := p+cp; - cp = cp + e2_jae(b, p+cp, 0); - cp = cp + emit_rex(b, p+cp, 1, 10/8, 0, 10/8); - e2_w8(b, p+cp, 133); cp = cp + 1; - cp = cp + emit_modrm(b, p+cp, 3, 10%8, 10%8); - safe_jmp_pos := p+cp; - e2_w8(b, p+cp, 117); e2_w8(b, p+cp+1, 0); cp = cp + 2; - e2_w8(b, p+cp, 15); e2_w8(b, p+cp+1, 11); cp = cp + 2; - e2_w32(b, crash_jmp_pos + 2, (p+cp) - (crash_jmp_pos + 6) - 2); - w8(b, safe_jmp_pos + 1, (p+cp) - (safe_jmp_pos + 2)); - return cp; -} + cp = cp + emit_rex(b, p+cp, 1, 0, 0, 0) + e2_w8(b, p+cp, 57) + cp = cp + 1 + cp = cp + emit_modrm(b, p+cp, 3, 1, 0) + crash_jmp_pos := p+cp + cp = cp + e2_jae(b, p+cp, 0) + cp = cp + emit_rex(b, p+cp, 1, 10/8, 0, 10/8) + e2_w8(b, p+cp, 133) + cp = cp + 1 + cp = cp + emit_modrm(b, p+cp, 3, 10%8, 10%8) + safe_jmp_pos := p+cp + e2_w8(b, p+cp, 117) + e2_w8(b, p+cp+1, 0) + cp = cp + 2 + e2_w8(b, p+cp, 15) + e2_w8(b, p+cp+1, 11) + cp = cp + 2 + e2_w32(b, crash_jmp_pos + 2, (p+cp) - (crash_jmp_pos + 6) - 2) + w8(b, safe_jmp_pos + 1, (p+cp) - (safe_jmp_pos + 2)) + return cp // F6:仅 null 陷阱(无分配信息时——s3=0 快速路径)。 // test r10, r10(REX.WRB 0x4D 0x85 0xD2);null → ud2(SIGILL) -fn e2_ptr_null_check(b: string, p: int) -> int { - cp := p; - cp = cp + emit_rex(b, cp, 1, 10/8, 0, 10/8); - e2_w8(b, cp, 133); cp = cp + 1; - cp = cp + emit_modrm(b, cp, 3, 10%8, 10%8); - e2_w8(b, cp, 117); e2_w8(b, cp+1, 2); cp = cp + 2; // jne +2 (skip ud2) - e2_w8(b, cp, 15); e2_w8(b, cp+1, 11); cp = cp + 2; // ud2 (SIGILL) - return cp - p; -} +fn e2_ptr_null_check(b: string, p: int) -> int: + cp := p + cp = cp + emit_rex(b, cp, 1, 10/8, 0, 10/8) + e2_w8(b, cp, 133) + cp = cp + 1 + cp = cp + emit_modrm(b, cp, 3, 10%8, 10%8) + e2_w8(b, cp, 117) + e2_w8(b, cp+1, 2) + cp = cp + 2 // jne +2 (skip ud2) + e2_w8(b, cp, 15) + e2_w8(b, cp+1, 11) + cp = cp + 2 // ud2 (SIGILL) + return cp - p // F14:movabs rdi, imm64 — REX.W 0x48 + 0xBF + imm64(64 位尺寸语义; // 修复前 mov edi, imm32 对 ≥2³² 尺寸按 mod 2³² 回绕) -fn e2_movabs_rdi(b: string, p: int, v: int) -> int { - e2_w8(b, p, 72); e2_w8(b, p+1, 191); e2_w64(b, p+2, v); return 10; -} -fn e2_alu(b: string, p: int, op: int) -> int { +fn e2_movabs_rdi(b: string, p: int, v: int) -> int: + e2_w8(b, p, 72) + e2_w8(b, p+1, 191) + e2_w64(b, p+2, v) + return 10 +fn e2_alu(b: string, p: int, op: int) -> int: // ALU r/m, r: REX.W + REX.RB (r11, r10) + opcode + ModRM reg=11, rm=10 - cp := p; - cp = cp + emit_rex(b, cp, 1, 1, 0, 1); // W=1, R=1(r11/8), B=1(r10/8) - e2_w8(b, cp, op); cp = cp + 1; - cp = cp + emit_modrm(b, cp, 3, 11%8, 10%8); // mod=3(register), reg=3, rm=2 - return cp - p; -} + cp := p + cp = cp + emit_rex(b, cp, 1, 1, 0, 1) // W=1, R=1(r11/8), B=1(r10/8) + e2_w8(b, cp, op) + cp = cp + 1 + cp = cp + emit_modrm(b, cp, 3, 11%8, 10%8) // mod=3(register), reg=3, rm=2 + return cp - p // ── SSE2 double 运算(IEEE 754 标准,float 支持)── // movsd xmm0, [rbp+disp] — F2 0F 10 /0 -fn e2_sd_load(b: string, p: int, o: int) -> int { - cp := p; - w8(b, cp, 242); w8(b, cp+1, 15); w8(b, cp+2, 16); cp = cp + 3; - if o >= -128 && o <= 127 { - w8(b, cp, 69); w8(b, cp+1, o); cp = cp + 2; // ModRM 01 000 101 - } else { - w8(b, cp, 133); cp = cp + 1; // ModRM 10 000 101 - cp = cp + e2_w32(b, cp, o); - } - return cp - p; -} +fn e2_sd_load(b: string, p: int, o: int) -> int: + cp := p + w8(b, cp, 242) + w8(b, cp+1, 15) + w8(b, cp+2, 16) + cp = cp + 3 + if o >= -128 && o <= 127: + w8(b, cp, 69) + w8(b, cp+1, o) + cp = cp + 2 // ModRM 01 000 101 + else: + w8(b, cp, 133) + cp = cp + 1 // ModRM 10 000 101 + cp = cp + e2_w32(b, cp, o) + return cp - p // movsd xmm1, [rbp+disp] — F2 0F 10 /1 -fn e2_sd_load1(b: string, p: int, o: int) -> int { - cp := p; - w8(b, cp, 242); w8(b, cp+1, 15); w8(b, cp+2, 16); cp = cp + 3; - if o >= -128 && o <= 127 { - w8(b, cp, 77); w8(b, cp+1, o); cp = cp + 2; // ModRM 01 001 101 - } else { - w8(b, cp, 141); cp = cp + 1; // ModRM 10 001 101 - cp = cp + e2_w32(b, cp, o); - } - return cp - p; -} +fn e2_sd_load1(b: string, p: int, o: int) -> int: + cp := p + w8(b, cp, 242) + w8(b, cp+1, 15) + w8(b, cp+2, 16) + cp = cp + 3 + if o >= -128 && o <= 127: + w8(b, cp, 77) + w8(b, cp+1, o) + cp = cp + 2 // ModRM 01 001 101 + else: + w8(b, cp, 141) + cp = cp + 1 // ModRM 10 001 101 + cp = cp + e2_w32(b, cp, o) + return cp - p // movsd xmm{rn}, [rbp+disp] — F2 0F 10 /rn(rn=0..7,SysV float 参数) -fn e2_sd_load_x(b: string, p: int, o: int, rn: int) -> int { - cp := p; - w8(b, cp, 242); w8(b, cp+1, 15); w8(b, cp+2, 16); cp = cp + 3; - if o >= -128 && o <= 127 { - w8(b, cp, 64 + rn * 8 + 5); w8(b, cp+1, o); cp = cp + 2; - } else { - w8(b, cp, 128 + rn * 8 + 5); cp = cp + 1; - cp = cp + e2_w32(b, cp, o); - } - return cp - p; -} +fn e2_sd_load_x(b: string, p: int, o: int, rn: int) -> int: + cp := p + w8(b, cp, 242) + w8(b, cp+1, 15) + w8(b, cp+2, 16) + cp = cp + 3 + if o >= -128 && o <= 127: + w8(b, cp, 64 + rn * 8 + 5) + w8(b, cp+1, o) + cp = cp + 2 + else: + w8(b, cp, 128 + rn * 8 + 5) + cp = cp + 1 + cp = cp + e2_w32(b, cp, o) + return cp - p // 存返回值到 dest:dex(binary64,apx 快路径)→ movsd [slot], xmm0(SysV XMM0 返回);int → rax -fn e2_store_ret(b: string, p: int, d: int) -> int { - if d >= 0 && irv_type(d) == TI_DEX { - return e2_sd_store(b, p, g2_slot(d)); - } - return e2_st(b, p, 0, g2_slot(d)); -} +fn e2_store_ret(b: string, p: int, d: int) -> int: + if d >= 0 && irv_type(d) == TI_DEX: + return e2_sd_store(b, p, g2_slot(d)) + return e2_st(b, p, 0, g2_slot(d)) // 压栈 binary64 值(8 字节,apx 快路径):sub rsp,8 + movsd [rsp],xmm0 -fn e2_push_xmm0(b: string, p: int) -> int { - cp := p; - w8(b, cp, 72); w8(b, cp+1, 131); w8(b, cp+2, 236); w8(b, cp+3, 8); cp = cp + 4; - w8(b, cp, 242); w8(b, cp+1, 15); w8(b, cp+2, 17); w8(b, cp+3, 4); w8(b, cp+4, 36); cp = cp + 5; - return cp - p; -} - -fn e2_sd_cvt(b: string, p: int, o: int) -> int { - cp := p; - w8(b, cp, 242); w8(b, cp+1, 72); w8(b, cp+2, 15); w8(b, cp+3, 42); cp = cp + 4; - if o >= -128 && o <= 127 { - w8(b, cp, 69); w8(b, cp+1, o); cp = cp + 2; // ModRM 01 000 101 - } else { - w8(b, cp, 133); cp = cp + 1; // ModRM 10 000 101 - cp = cp + e2_w32(b, cp, o); - } - return cp - p; -} +fn e2_push_xmm0(b: string, p: int) -> int: + cp := p + w8(b, cp, 72) + w8(b, cp+1, 131) + w8(b, cp+2, 236) + w8(b, cp+3, 8) + cp = cp + 4 + w8(b, cp, 242) + w8(b, cp+1, 15) + w8(b, cp+2, 17) + w8(b, cp+3, 4) + w8(b, cp+4, 36) + cp = cp + 5 + return cp - p + +fn e2_sd_cvt(b: string, p: int, o: int) -> int: + cp := p + w8(b, cp, 242) + w8(b, cp+1, 72) + w8(b, cp+2, 15) + w8(b, cp+3, 42) + cp = cp + 4 + if o >= -128 && o <= 127: + w8(b, cp, 69) + w8(b, cp+1, o) + cp = cp + 2 // ModRM 01 000 101 + else: + w8(b, cp, 133) + cp = cp + 1 // ModRM 10 000 101 + cp = cp + e2_w32(b, cp, o) + return cp - p // movsd [rbp+disp], xmm0 — F2 0F 11 /0 -fn e2_sd_store(b: string, p: int, o: int) -> int { - cp := p; - w8(b, cp, 242); w8(b, cp+1, 15); w8(b, cp+2, 17); cp = cp + 3; - if o >= -128 && o <= 127 { - w8(b, cp, 69); w8(b, cp+1, o); cp = cp + 2; - } else { - w8(b, cp, 133); cp = cp + 1; - cp = cp + e2_w32(b, cp, o); - } - return cp - p; -} +fn e2_sd_store(b: string, p: int, o: int) -> int: + cp := p + w8(b, cp, 242) + w8(b, cp+1, 15) + w8(b, cp+2, 17) + cp = cp + 3 + if o >= -128 && o <= 127: + w8(b, cp, 69) + w8(b, cp+1, o) + cp = cp + 2 + else: + w8(b, cp, 133) + cp = cp + 1 + cp = cp + e2_w32(b, cp, o) + return cp - p // ── emit_instr: write one instruction to buffer, return bytes written ── -fn e2_load_var(buf: string, pos: int, reg: int, var_idx: int) -> int { - if var_idx >= 0 && r64(g_x86_is_global, var_idx * 8) != 0 { - grow_rip_patch(g_x86_rip_patch_count + 1); - w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, pos + 3); - w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, var_idx); - g_x86_rip_patch_count = g_x86_rip_patch_count + 1; - sz := e2_lrb(buf, pos, 0); +fn e2_load_var(buf: string, pos: int, reg: int, var_idx: int) -> int: + if var_idx >= 0 && r64(g_x86_is_global, var_idx * 8) != 0: + grow_rip_patch(g_x86_rip_patch_count + 1) + w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, pos + 3) + w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, var_idx) + g_x86_rip_patch_count = g_x86_rip_patch_count + 1 + sz := e2_lrb(buf, pos, 0) // mov reg, [r11] — memory load (NOT register copy; e2_ld + e2_rslot would misinterpret) - cp2 := pos + sz; - cp2 = cp2 + emit_rex(buf, cp2, 1, reg/8, 0, 11/8); - e2_w8(buf, cp2, 139); cp2 = cp2 + 1; // 0x8B MOV r, r/m - cp2 = cp2 + emit_modrm(buf, cp2, 0, reg%8, 11%8); - sz = cp2 - pos; - return sz; - } - return e2_ld(buf, pos, reg, g2_slot(var_idx)); -} + cp2 := pos + sz + cp2 = cp2 + emit_rex(buf, cp2, 1, reg/8, 0, 11/8) + e2_w8(buf, cp2, 139) + cp2 = cp2 + 1 // 0x8B MOV r, r/m + cp2 = cp2 + emit_modrm(buf, cp2, 0, reg%8, 11%8) + sz = cp2 - pos + return sz + return e2_ld(buf, pos, reg, g2_slot(var_idx)) // ── 全局行操作数 seam(2026-09-16 批):全局 vs 局部的分派单入口 ── // 根因:`g2_slot` 对**全局行**(`v < g_current_func_var_start`)返回**帧外伪 rbp 偏移** @@ -450,1110 +513,1394 @@ fn e2_load_var(buf: string, pos: int, reg: int, var_idx: int) -> int { // `e2_lea_glob`:lea r11,[rip+0] + RIP 补丁登记(disp32 位置 = pos+3,与 `e2_load_var` // 内联段逐字节同序)。**仅当 is_global 时调用**;scratch = r11 **即时消费、不跨指令存活** // (双全局操作数形 = 两次「lea r11 + 消费」序列,目标寄存器各自独立 ⇒ 无需第二 scratch)。 -fn e2_lea_glob(buf: string, pos: int, var_idx: int) -> int { - grow_rip_patch(g_x86_rip_patch_count + 1); - w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, pos + 3); - w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, var_idx); - g_x86_rip_patch_count = g_x86_rip_patch_count + 1; - return e2_lrb(buf, pos, 0); -} - -fn e2_is_glob(var_idx: int) -> int { - if var_idx < 0 { return 0; } - return r64(g_x86_is_global, var_idx * 8); -} +fn e2_lea_glob(buf: string, pos: int, var_idx: int) -> int: + grow_rip_patch(g_x86_rip_patch_count + 1) + w64(g_x86_rip_patch_pos, g_x86_rip_patch_count * 8, pos + 3) + w64(g_x86_rip_patch_globals, g_x86_rip_patch_count * 8, var_idx) + g_x86_rip_patch_count = g_x86_rip_patch_count + 1 + return e2_lrb(buf, pos, 0) + +fn e2_is_glob(var_idx: int) -> int: + if var_idx < 0: + return 0 + return r64(g_x86_is_global, var_idx * 8) // 读侧 dex(movsd xmm{n}, [槽]):全局 → RIP 相对(lea r11 + movsd [r11]); // 局部 → 现 `e2_sd_load`/`e2_sd_load1`/`e2_sd_load_x` 原字节(按 xmmn 分派,n=0/1 与 // `e2_sd_load_x` 编码逐字节等价)。消费点:IR_BINARY(TI_DEX) 双操作数、cs_args_dispatch、 // cs_stack_args(callseq.cr)。 -fn e2_sd_ld_var(buf: string, pos: int, xmmn: int, var_idx: int) -> int { - if e2_is_glob(var_idx) != 0 { - cp := e2_lea_glob(buf, pos, var_idx); +fn e2_sd_ld_var(buf: string, pos: int, xmmn: int, var_idx: int) -> int: + if e2_is_glob(var_idx) != 0: + cp := e2_lea_glob(buf, pos, var_idx) // movsd xmm{n}, [r11] — F2 **41** 0F 10 /n, ModRM mod=00 reg=n rm=3 // (41 = REX.B:r11 在 ModRM rm 需 REX.B=1;漏它则 rm=3 变成 [rbx] ⇒ 野指针 139) - e2_w8(buf, pos+cp, 242); e2_w8(buf, pos+cp+1, 65); e2_w8(buf, pos+cp+2, 15); e2_w8(buf, pos+cp+3, 16); - e2_w8(buf, pos+cp+4, xmmn * 8 + 3); - return cp + 5; - } - if xmmn == 0 { return e2_sd_load(buf, pos, g2_slot(var_idx)); } - if xmmn == 1 { return e2_sd_load1(buf, pos, g2_slot(var_idx)); } - return e2_sd_load_x(buf, pos, g2_slot(var_idx), xmmn); -} + e2_w8(buf, pos+cp, 242) + e2_w8(buf, pos+cp+1, 65) + e2_w8(buf, pos+cp+2, 15) + e2_w8(buf, pos+cp+3, 16) + e2_w8(buf, pos+cp+4, xmmn * 8 + 3) + return cp + 5 + if xmmn == 0: + return e2_sd_load(buf, pos, g2_slot(var_idx)) + if xmmn == 1: + return e2_sd_load1(buf, pos, g2_slot(var_idx)) + return e2_sd_load_x(buf, pos, g2_slot(var_idx), xmmn) // 读侧 dex(int 源 cvt 形,IR_I2F):全局 → RIP 相对 cvtsi2sd;局部 → 现 `e2_sd_cvt` 原字节。 -fn e2_sd_cvt_var(buf: string, pos: int, var_idx: int) -> int { - if e2_is_glob(var_idx) != 0 { - cp := e2_lea_glob(buf, pos, var_idx); +fn e2_sd_cvt_var(buf: string, pos: int, var_idx: int) -> int: + if e2_is_glob(var_idx) != 0: + cp := e2_lea_glob(buf, pos, var_idx) // cvtsi2sd xmm0, [r11] — F2 **49** 0F 2A /0, ModRM mod=00 reg=0 rm=3 // (49 = REX.W=1 + REX.B=1:REX.B 选 r11;漏它则 rm=3 变成 [rbx]) - e2_w8(buf, pos+cp, 242); e2_w8(buf, pos+cp+1, 73); e2_w8(buf, pos+cp+2, 15); - e2_w8(buf, pos+cp+3, 42); e2_w8(buf, pos+cp+4, 3); - return cp + 5; - } - return e2_sd_cvt(buf, pos, g2_slot(var_idx)); -} + e2_w8(buf, pos+cp, 242) + e2_w8(buf, pos+cp+1, 73) + e2_w8(buf, pos+cp+2, 15) + e2_w8(buf, pos+cp+3, 42) + e2_w8(buf, pos+cp+4, 3) + return cp + 5 + return e2_sd_cvt(buf, pos, g2_slot(var_idx)) // 写侧 dex(movsd [槽], xmm0):全局 → RIP 相对;局部 → 现 `e2_sd_store` 原字节。 -fn e2_sd_st_var(buf: string, pos: int, var_idx: int) -> int { - if e2_is_glob(var_idx) != 0 { - cp := e2_lea_glob(buf, pos, var_idx); +fn e2_sd_st_var(buf: string, pos: int, var_idx: int) -> int: + if e2_is_glob(var_idx) != 0: + cp := e2_lea_glob(buf, pos, var_idx) // movsd [r11], xmm0 — F2 **41** 0F 11 /0, ModRM mod=00 reg=0 rm=3(41 = REX.B) - e2_w8(buf, pos+cp, 242); e2_w8(buf, pos+cp+1, 65); e2_w8(buf, pos+cp+2, 15); - e2_w8(buf, pos+cp+3, 17); e2_w8(buf, pos+cp+4, 3); - return cp + 5; - } - return e2_sd_store(buf, pos, g2_slot(var_idx)); -} + e2_w8(buf, pos+cp, 242) + e2_w8(buf, pos+cp+1, 65) + e2_w8(buf, pos+cp+2, 15) + e2_w8(buf, pos+cp+3, 17) + e2_w8(buf, pos+cp+4, 3) + return cp + 5 + return e2_sd_store(buf, pos, g2_slot(var_idx)) // 写侧 int(mov [槽], reg):全局 → RIP 相对(lea r11 + mov [r11], reg); // 局部 → 现 `e2_st` 原字节。消费点:HIT 表路径 dest 回存(hit_ev_emit_one)+ IR_AWAIT dest。 -fn e2_st_var(buf: string, pos: int, reg: int, var_idx: int) -> int { - if e2_is_glob(var_idx) != 0 { - cp := e2_lea_glob(buf, pos, var_idx); +fn e2_st_var(buf: string, pos: int, reg: int, var_idx: int) -> int: + if e2_is_glob(var_idx) != 0: + cp := e2_lea_glob(buf, pos, var_idx) // mov [r11], reg — REX.WRB + 0x89 - cp = cp + emit_rex(buf, pos+cp, 1, reg/8, 0, 11/8); - e2_w8(buf, pos+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, reg%8, 11%8); - return cp; - } - return e2_st(buf, pos, reg, g2_slot(var_idx)); -} - -fn e2_rslot(r: int) -> int { return E2_REG_SLOT_BASE + r; } - -fn emit_instr(instr_idx: int, buf: string, pos: int) -> int { - op := iri_op(instr_idx); d := iri_dest(instr_idx); s1 := iri_s1(instr_idx); s2 := iri_s2(instr_idx); s3 := iri_s3(instr_idx); ti := iri_tk(instr_idx); - cp := 0; - - if op == IR_NOP { return 0; } - - if op == IR_I2F && d >= 0 { + cp = cp + emit_rex(buf, pos+cp, 1, reg/8, 0, 11/8) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, reg%8, 11%8) + return cp + return e2_st(buf, pos, reg, g2_slot(var_idx)) + +fn e2_rslot(r: int) -> int: + return E2_REG_SLOT_BASE + r + +fn emit_instr(instr_idx: int, buf: string, pos: int) -> int: + op := iri_op(instr_idx) + d := iri_dest(instr_idx) + s1 := iri_s1(instr_idx) + s2 := iri_s2(instr_idx) + s3 := iri_s3(instr_idx) + ti := iri_tk(instr_idx) + cp := 0 + + if op == IR_NOP: + return 0 + + if op == IR_I2F && d >= 0: // int → binary64:cvtsi2sd xmm0, [槽] — F2 0F 2A /0,然后 movsd 存回。 // 读写两端走全局行 seam(修复前 s1 为全局行时读帧外伪偏移 ⇒ 静默错值)。 - cp = cp + e2_sd_cvt_var(buf, pos+cp, s1); // cvtsi2sd xmm0, [s1] - cp = cp + e2_sd_st_var(buf, pos+cp, d); - return cp; - } + cp = cp + e2_sd_cvt_var(buf, pos+cp, s1) // cvtsi2sd xmm0, [s1] + cp = cp + e2_sd_st_var(buf, pos+cp, d) + return cp - if op == IR_F2I && d >= 0 { + if op == IR_F2I && d >= 0: // binary64 → int:movsd xmm0, [s1];cvttsd2si rax, xmm0(F2 48 0F 2C C0,截断);存回 - do2 := g2_slot(d); - cp = cp + e2_sd_load(buf, pos+cp, g2_slot(s1)); - w8(buf, pos+cp, 242); w8(buf, pos+cp+1, 72); w8(buf, pos+cp+2, 15); - w8(buf, pos+cp+3, 44); w8(buf, pos+cp+4, 192); cp = cp + 5; - cp = cp + e2_st(buf, pos+cp, 0, do2); - return cp; - } - - if op == IR_CONST && d >= 0 { - do2 := g2_slot(d); - if ti == TI_STR { - ro := g2_str_off(s1); + do2 := g2_slot(d) + cp = cp + e2_sd_load(buf, pos+cp, g2_slot(s1)) + w8(buf, pos+cp, 242) + w8(buf, pos+cp+1, 72) + w8(buf, pos+cp+2, 15) + w8(buf, pos+cp+3, 44) + w8(buf, pos+cp+4, 192) + cp = cp + 5 + cp = cp + e2_st(buf, pos+cp, 0, do2) + return cp + + if op == IR_CONST && d >= 0: + do2 := g2_slot(d) + if ti == TI_STR: + ro := g2_str_off(s1) // Record for post-emission patching (rodata position from Phase 3) - grow_rodataref(g_x86_rodataref_count + 1); - w64(g_x86_rodataref_pos, g_x86_rodataref_count * 8, pos + cp); - w64(g_x86_rodataref_ro, g_x86_rodataref_count * 8, ro); - g_x86_rodataref_count = g_x86_rodataref_count + 1; - cp = cp + e2_lr(buf, pos+cp, 0); // placeholder, patched later - cp = cp + e2_st(buf, pos+cp, 10, do2); - } else if r64(g_x86_is_global, d * 8) != 0 { + grow_rodataref(g_x86_rodataref_count + 1) + w64(g_x86_rodataref_pos, g_x86_rodataref_count * 8, pos + cp) + w64(g_x86_rodataref_ro, g_x86_rodataref_count * 8, ro) + g_x86_rodataref_count = g_x86_rodataref_count + 1 + cp = cp + e2_lr(buf, pos+cp, 0) // placeholder, patched later + cp = cp + e2_st(buf, pos+cp, 10, do2) + else if r64(g_x86_is_global, d * 8) != 0: // R2 P4 Task 5:**全局行**直写(g2_slot 对全局行返回帧外伪偏移 ⇒ 修复前 // 本分支落 `e2_li` 即写栈垃圾 = 静默丢写;解释器同 IR 直写 g_ir_vals ⇒ // **两路径分歧**)。与 IR_LOAD/IR_STORE 的全局分派同款:常量入 r10 + // RIP 相对 store(e2_lrb 取址、patch 记录与 IR_STORE 同构)。 // 注:TI_STR 分支(rodata 指针)对全局行同样未分派——当前零发射点 // (字符串常量入全局走 .data/_init_globals),登记不改。 - e2_w8(buf, pos+cp, 73); e2_w8(buf, pos+cp+1, 186); // movabs r10, imm64(REX.W + B8+rd) - e2_w64(buf, pos+cp+2, s1); cp = cp + 10; - 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, d); - g_x86_rip_patch_count = g_x86_rip_patch_count + 1; - cp = cp + e2_lrb(buf, pos+cp, 0); + e2_w8(buf, pos+cp, 73) + e2_w8(buf, pos+cp+1, 186) // movabs r10, imm64(REX.W + B8+rd) + e2_w64(buf, pos+cp+2, s1) + cp = cp + 10 + 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, d) + g_x86_rip_patch_count = g_x86_rip_patch_count + 1 + cp = cp + e2_lrb(buf, pos+cp, 0) // mov [r11], r10 — REX.WRB + 0x89 - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 11/8); e2_w8(buf, pos+cp, 137); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 11%8); - } else { - cp = cp + e2_li(buf, pos+cp, do2, s1); - } - return cp; - } - - if op == IR_BINARY { - do2 := g2_slot(d); - if ti == TI_DEX { + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 11/8) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 11%8) + else: + cp = cp + e2_li(buf, pos+cp, do2, s1) + return cp + + if op == IR_BINARY: + do2 := g2_slot(d) + if ti == TI_DEX: // binary64 运算(SSE2 double,IEEE 754)——apx 快路径标准答案实现 // 操作数两端走全局行 seam(修复前全局行读帧外伪偏移 ⇒ 静默错值) - cp = cp + e2_sd_ld_var(buf, pos+cp, 0, s1); // xmm0 = s1 - cp = cp + e2_sd_ld_var(buf, pos+cp, 1, s2); // xmm1 = s2 + cp = cp + e2_sd_ld_var(buf, pos+cp, 0, s1) // xmm0 = s1 + cp = cp + e2_sd_ld_var(buf, pos+cp, 1, s2) // xmm1 = s2 // F2 0F 5x C1:addsd/subsd/mulsd/divsd xmm0, xmm1 - if s3 == OP_ADD { w8(buf, pos+cp, 242); w8(buf, pos+cp+1, 15); w8(buf, pos+cp+2, 88); w8(buf, pos+cp+3, 193); cp = cp + 4; } - else if s3 == OP_SUB { w8(buf, pos+cp, 242); w8(buf, pos+cp+1, 15); w8(buf, pos+cp+2, 92); w8(buf, pos+cp+3, 193); cp = cp + 4; } - else if s3 == OP_MUL { w8(buf, pos+cp, 242); w8(buf, pos+cp+1, 15); w8(buf, pos+cp+2, 89); w8(buf, pos+cp+3, 193); cp = cp + 4; } - else if s3 == OP_DIV { w8(buf, pos+cp, 242); w8(buf, pos+cp+1, 15); w8(buf, pos+cp+2, 94); w8(buf, pos+cp+3, 193); cp = cp + 4; } - if s3 >= OP_ADD && s3 <= OP_DIV { - cp = cp + e2_sd_st_var(buf, pos+cp, d); - } else if s3 >= OP_EQ && s3 <= OP_GE { - w8(buf, pos+cp, 102); w8(buf, pos+cp+1, 15); w8(buf, pos+cp+2, 47); w8(buf, pos+cp+3, 193); cp = cp + 4; - if s3 == OP_EQ { + if s3 == OP_ADD: + w8(buf, pos+cp, 242) + w8(buf, pos+cp+1, 15) + w8(buf, pos+cp+2, 88) + w8(buf, pos+cp+3, 193) + cp = cp + 4 + else if s3 == OP_SUB: + w8(buf, pos+cp, 242) + w8(buf, pos+cp+1, 15) + w8(buf, pos+cp+2, 92) + w8(buf, pos+cp+3, 193) + cp = cp + 4 + else if s3 == OP_MUL: + w8(buf, pos+cp, 242) + w8(buf, pos+cp+1, 15) + w8(buf, pos+cp+2, 89) + w8(buf, pos+cp+3, 193) + cp = cp + 4 + else if s3 == OP_DIV: + w8(buf, pos+cp, 242) + w8(buf, pos+cp+1, 15) + w8(buf, pos+cp+2, 94) + w8(buf, pos+cp+3, 193) + cp = cp + 4 + if s3 >= OP_ADD && s3 <= OP_DIV: + cp = cp + e2_sd_st_var(buf, pos+cp, d) + else if s3 >= OP_EQ && s3 <= OP_GE: + w8(buf, pos+cp, 102) + w8(buf, pos+cp+1, 15) + w8(buf, pos+cp+2, 47) + w8(buf, pos+cp+3, 193) + cp = cp + 4 + if s3 == OP_EQ: // setnp al(0F 9B C0);sete cl(0F 94 C1);and al, cl(20 C8) - w8(buf, pos+cp, 15); w8(buf, pos+cp+1, 155); w8(buf, pos+cp+2, 192); cp = cp + 3; - w8(buf, pos+cp, 15); w8(buf, pos+cp+1, 148); w8(buf, pos+cp+2, 193); cp = cp + 3; - w8(buf, pos+cp, 32); w8(buf, pos+cp+1, 200); cp = cp + 2; - } else if s3 == OP_NE { + w8(buf, pos+cp, 15) + w8(buf, pos+cp+1, 155) + w8(buf, pos+cp+2, 192) + cp = cp + 3 + w8(buf, pos+cp, 15) + w8(buf, pos+cp+1, 148) + w8(buf, pos+cp+2, 193) + cp = cp + 3 + w8(buf, pos+cp, 32) + w8(buf, pos+cp+1, 200) + cp = cp + 2 + else if s3 == OP_NE: // setp al(0F 9A C0);setne cl(0F 95 C1);or al, cl(08 C8) - w8(buf, pos+cp, 15); w8(buf, pos+cp+1, 154); w8(buf, pos+cp+2, 192); cp = cp + 3; - w8(buf, pos+cp, 15); w8(buf, pos+cp+1, 149); w8(buf, pos+cp+2, 193); cp = cp + 3; - w8(buf, pos+cp, 8); w8(buf, pos+cp+1, 200); cp = cp + 2; - } else { + w8(buf, pos+cp, 15) + w8(buf, pos+cp+1, 154) + w8(buf, pos+cp+2, 192) + cp = cp + 3 + w8(buf, pos+cp, 15) + w8(buf, pos+cp+1, 149) + w8(buf, pos+cp+2, 193) + cp = cp + 3 + w8(buf, pos+cp, 8) + w8(buf, pos+cp+1, 200) + cp = cp + 2 + else: // LT/GT/LE/GE 不动——硬件标志语义已正确(含无序时 LT/LE 为真) - sop : ., mut = 146; - if s3 == OP_GT { sop = 151; } // seta(CF=0 && ZF=0) - else if s3 == OP_LE { sop = 150; } // setbe - else if s3 == OP_GE { sop = 147; } // setae - w8(buf, pos+cp, 15); w8(buf, pos+cp+1, sop); w8(buf, pos+cp+2, 192); cp = cp + 3; - } + sop : ., mut = 146 + if s3 == OP_GT: + sop = 151 + // seta(CF=0 && ZF=0) + else if s3 == OP_LE: + sop = 150 + // setbe + else if s3 == OP_GE: + sop = 147 + // setae + w8(buf, pos+cp, 15) + w8(buf, pos+cp+1, sop) + w8(buf, pos+cp+2, 192) + cp = cp + 3 // movzx r10d, al — 44 0F B6 D0 - w8(buf, pos+cp, 68); w8(buf, pos+cp+1, 15); w8(buf, pos+cp+2, 182); w8(buf, pos+cp+3, 208); cp = cp + 4; - cp = cp + e2_st(buf, pos+cp, 10, do2); - } - return cp; - } - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - cp = cp + e2_load_var(buf, pos+cp, 11, s2); + w8(buf, pos+cp, 68) + w8(buf, pos+cp+1, 15) + w8(buf, pos+cp+2, 182) + w8(buf, pos+cp+3, 208) + cp = cp + 4 + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_load_var(buf, pos+cp, 11, s2) // int 多字 M1(Task 4):消费者站点 tag 检查——操作数行 tagged 且站点 // 属 2L 消费面(add/sub dest tagged = jo 同条件;比较任一操作数 // tagged)→ 快路径前查 tag:任一操作数 2L(tag=1)→ 函数尾 2L 块 // (128 位算术/比较,e2_mw_opnd_block)。untagged 行/站点零字节。 // (tag 检查在操作数装载后——检查只写标志,不扰 r10/r11。) - mw_oc : ., mut = -1; - if (s3 == OP_ADD || s3 == OP_SUB) && g2_tag_off(d) != -1 || (s3 >= OP_EQ && s3 <= OP_GE) { - if g2_tag_off(s1) != -1 { - if mw_oc == -1 { mw_oc = mw_oc_new(s1, s2, d, s3); } - cp = cp + e2_mw_oc_check(buf, pos+cp, mw_oc, 0, s1); - } - if s1 != s2 && g2_tag_off(s2) != -1 { - if mw_oc == -1 { mw_oc = mw_oc_new(s1, s2, d, s3); } - cp = cp + e2_mw_oc_check(buf, pos+cp, mw_oc, 1, s2); - } - } - if s3 == OP_ADD { - cp = cp + e2_alu(buf, pos+cp, 1); + mw_oc : ., mut = -1 + if (s3 == OP_ADD || s3 == OP_SUB) && g2_tag_off(d) != -1 || (s3 >= OP_EQ && s3 <= OP_GE): + if g2_tag_off(s1) != -1: + if mw_oc == -1: + mw_oc = mw_oc_new(s1, s2, d, s3) + cp = cp + e2_mw_oc_check(buf, pos+cp, mw_oc, 0, s1) + if s1 != s2 && g2_tag_off(s2) != -1: + if mw_oc == -1: + mw_oc = mw_oc_new(s1, s2, d, s3) + cp = cp + e2_mw_oc_check(buf, pos+cp, mw_oc, 1, s2) + if s3 == OP_ADD: + cp = cp + e2_alu(buf, pos+cp, 1) // int 多字 M1(Task 2/3):tagged dest 的 add/sub 后紧跟溢出跳 // (e2_alu 的 OF 其后无任何写标志指令可再被读)→ 函数尾慢路径 // 块。慢路径在快路径 store 之前跳走(块内自回存 dest 值 + 置 tag // 并跳回 store 之后继续——e2_mw_slow_block,tag2l.cr;块发射 = // frame.cr pf_epilogue 函数尾按站点)。站点记录 dest 与 op(is_sub // ——高 limb 修正规则因 op 异)。 - if g2_tag_off(d) != -1 { cp = cp + e2_mw_jo(buf, pos+cp, d, 0); } - } - else if s3 == OP_SUB { - cp = cp + e2_alu(buf, pos+cp, 41); - if g2_tag_off(d) != -1 { cp = cp + e2_mw_jo(buf, pos+cp, d, 1); } - } - else if s3 == OP_MUL { + if g2_tag_off(d) != -1: + cp = cp + e2_mw_jo(buf, pos+cp, d, 0) + else if s3 == OP_SUB: + cp = cp + e2_alu(buf, pos+cp, 41) + if g2_tag_off(d) != -1: + cp = cp + e2_mw_jo(buf, pos+cp, d, 1) + else if s3 == OP_MUL: // imul r10, r11 — 2-byte opcode 0x0F 0xAF - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 11/8); - e2_w8(buf, pos+cp, 15); cp = cp + 1; - e2_w8(buf, pos+cp, 175); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 11%8); - } - else if s3 == OP_SHL { + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 11/8) + e2_w8(buf, pos+cp, 15) + cp = cp + 1 + e2_w8(buf, pos+cp, 175) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 11%8) + else if s3 == OP_SHL: // mov rcx, r11; shl r10, cl - cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 0); - e2_w8(buf, pos+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 1); - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8); - e2_w8(buf, pos+cp, 211); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 4, 10%8); - } - else if s3 == OP_SHR { + cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 0) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 1) + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8) + e2_w8(buf, pos+cp, 211) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 4, 10%8) + else if s3 == OP_SHR: // mov rcx, r11; shr r10, cl - cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 0); - e2_w8(buf, pos+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 1); - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8); - e2_w8(buf, pos+cp, 211); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 5, 10%8); - } - else if s3 == OP_PTR_ADD { // p + n: scale n by element size (8), add to p + cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 0) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 1) + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8) + e2_w8(buf, pos+cp, 211) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 5, 10%8) + else if s3 == OP_PTR_ADD: + // p + n: scale n by element size (8), add to p // imul r11, 8, r11 — REX.WRB + 0x6B + ModRM(3, r11, r11) + imm8 //(0x4D:reg 字段与 rm 同为 r11——R(reg)与 B(rm)都需置位) - cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 11/8); - e2_w8(buf, pos+cp, 107); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 11%8); - e2_w8(buf, pos+cp, 8); cp = cp + 1; + cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 11/8) + e2_w8(buf, pos+cp, 107) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 11%8) + e2_w8(buf, pos+cp, 8) + cp = cp + 1 // add r10, r11 - cp = cp + e2_alu(buf, pos+cp, 1); - } - else if s3 == OP_PTR_SUB { // p - n: scale n by element size (8), sub from p + cp = cp + e2_alu(buf, pos+cp, 1) + else if s3 == OP_PTR_SUB: + // p - n: scale n by element size (8), sub from p // imul r11, 8, r11 - cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 11/8); - e2_w8(buf, pos+cp, 107); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 11%8); - e2_w8(buf, pos+cp, 8); cp = cp + 1; + cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 11/8) + e2_w8(buf, pos+cp, 107) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 11%8) + e2_w8(buf, pos+cp, 8) + cp = cp + 1 // sub r10, r11 - cp = cp + e2_alu(buf, pos+cp, 41); - } - else if s3 == OP_PTR_DIFF { // p - q: diff in bytes, then /8 → element count + cp = cp + e2_alu(buf, pos+cp, 41) + else if s3 == OP_PTR_DIFF: + // p - q: diff in bytes, then /8 → element count // sub r10, r11 - cp = cp + e2_alu(buf, pos+cp, 41); + cp = cp + e2_alu(buf, pos+cp, 41) // sar r10, 3 — divide by 8 - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8); - e2_w8(buf, pos+cp, 193); cp = cp + 1; // 0xC1 SHIFT r/m, imm8 - cp = cp + emit_modrm(buf, pos+cp, 3, 7, 10%8); // /7 = SAR - e2_w8(buf, pos+cp, 3); cp = cp + 1; // shift by 3 - } - else if s3 == OP_DIV || s3 == OP_MOD { - cp = cp + e2_mov(buf, pos+cp, 0, 10); + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8) + e2_w8(buf, pos+cp, 193) + cp = cp + 1 // 0xC1 SHIFT r/m, imm8 + cp = cp + emit_modrm(buf, pos+cp, 3, 7, 10%8) // /7 = SAR + e2_w8(buf, pos+cp, 3) + cp = cp + 1 // shift by 3 + else if s3 == OP_DIV || s3 == OP_MOD: + cp = cp + e2_mov(buf, pos+cp, 0, 10) // cqo: REX.W + 0x99 - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0); e2_w8(buf, pos+cp, 153); cp = cp + 1; + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0) + e2_w8(buf, pos+cp, 153) + cp = cp + 1 // idiv r11: REX.WB + 0xF7 + /7 - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 11/8); e2_w8(buf, pos+cp, 247); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 7, 11%8); - if s3 == OP_DIV { cp = cp + e2_mov(buf, pos+cp, 10, 0); } else { cp = cp + e2_mov(buf, pos+cp, 10, 2); } - } - else if s3 >= OP_EQ && s3 <= OP_GE { - cp = cp + e2_alu(buf, pos+cp, 57); // cmp - sop := 148; if s3 == OP_NE { sop = 149; } else if s3 == OP_LT { sop = 156; } else if s3 == OP_GT { sop = 159; } else if s3 == OP_LE { sop = 158; } else if s3 == OP_GE { sop = 157; } + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 11/8) + e2_w8(buf, pos+cp, 247) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 7, 11%8) + if s3 == OP_DIV: + cp = cp + e2_mov(buf, pos+cp, 10, 0) + else: + cp = cp + e2_mov(buf, pos+cp, 10, 2) + else if s3 >= OP_EQ && s3 <= OP_GE: + cp = cp + e2_alu(buf, pos+cp, 57) // cmp + sop := 148 + if s3 == OP_NE: + sop = 149 + else if s3 == OP_LT: + sop = 156 + else if s3 == OP_GT: + sop = 159 + else if s3 == OP_LE: + sop = 158 + else if s3 == OP_GE: + sop = 157 // SETcc al — 2-byte opcode 0x0F 0x9x - e2_w8(buf, pos+cp, 15); cp = cp + 1; e2_w8(buf, pos+cp, sop); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 0, 0); + e2_w8(buf, pos+cp, 15) + cp = cp + 1 + e2_w8(buf, pos+cp, sop) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 0, 0) // movzx r10d, al — REX.R + 0x0FB6(rm=al 无需 B——R 只因 reg=r10) - cp = cp + emit_rex(buf, pos+cp, 0, 10/8, 0, 0); e2_w8(buf, pos+cp, 15); cp = cp + 1; e2_w8(buf, pos+cp, 182); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 0); - } - else if s3 == OP_AND { cp = cp + e2_alu(buf, pos+cp, 33); } - else if s3 == OP_OR { cp = cp + e2_alu(buf, pos+cp, 9); } - cp = cp + e2_st(buf, pos+cp, 10, do2); + cp = cp + emit_rex(buf, pos+cp, 0, 10/8, 0, 0) + e2_w8(buf, pos+cp, 15) + cp = cp + 1 + e2_w8(buf, pos+cp, 182) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 0) + else if s3 == OP_AND: + cp = cp + e2_alu(buf, pos+cp, 33) + else if s3 == OP_OR: + cp = cp + e2_alu(buf, pos+cp, 9) + cp = cp + e2_st(buf, pos+cp, 10, do2) // int 多字 M1(Task 4)tag 卫生①:快路径 64 位定值点 tag 清 0—— // 快值落 tagged 槽后 tag 必须为 0(否则回边再执行时 stale tag=1 会 // 把快值当 2-limb 指针读)。jo/2L 块跳 resume 在此之后——慢路径自 // 写 tag=1,不被本条清除(resume 位于本条之后)。dest untagged → // 零字节(mul/shl/…/非 add-sub 的 tagged dest 不存在——防御兜底)。 - cp = cp + e2_mw_tag_clr(buf, pos+cp, d); - return cp; - } - - if op == IR_UNARY && d >= 0 { - do2 := g2_slot(d); - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - if s3 == UOP_NEG { + cp = cp + e2_mw_tag_clr(buf, pos+cp, d) + return cp + + if op == IR_UNARY && d >= 0: + do2 := g2_slot(d) + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + if s3 == UOP_NEG: // neg r10: REX.WB + 0xF7 + /3 - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8); e2_w8(buf, pos+cp, 247); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 3, 10%8); - } - else if s3 == UOP_NOT { + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8) + e2_w8(buf, pos+cp, 247) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 3, 10%8) + else if s3 == UOP_NOT: // test r10, r10 (REX.WRB + 0x85) - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 133); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 10%8); + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 133) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 10%8) // sete al (0x0F 0x94) - e2_w8(buf, pos+cp, 15); cp = cp + 1; e2_w8(buf, pos+cp, 148); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 0, 0); + e2_w8(buf, pos+cp, 15) + cp = cp + 1 + e2_w8(buf, pos+cp, 148) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 0, 0) // movzx r10, al - cp = cp + emit_rex(buf, pos+cp, 0, 10/8, 0, 0); e2_w8(buf, pos+cp, 15); cp = cp + 1; e2_w8(buf, pos+cp, 182); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 0); - } - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_CALL { - fa := s1; ac := s2; + cp = cp + emit_rex(buf, pos+cp, 0, 10/8, 0, 0) + e2_w8(buf, pos+cp, 15) + cp = cp + 1 + e2_w8(buf, pos+cp, 182) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 0) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_CALL: + fa := s1 + ac := s2 // SysV AMD64 参数分派 + 栈超限压栈 = OS 轴序列(callseq.cr,波 1 // Task 5 抽取——三处同源合流/差异核对见该文件头注)。 // 第一遍:寄存器参数(位置顺序,左到右) - cp = cs_args_dispatch(buf, pos, cp, fa, ac); + cp = cs_args_dispatch(buf, pos, cp, fa, ac) // 第二遍:栈参数(右到左压,第 7 个 int / 第 9 个 binary64 超限才压) - stack_total := cs_stack_count(fa, ac); - cp = cs_stack_args(buf, pos, cp, fa, ac); + stack_total := cs_stack_count(fa, ac) + cp = cs_stack_args(buf, pos, cp, fa, ac) // Match builtins by interned string index (integer compare, no str_eq) - if s3 == g_ni_syscall3 { + if s3 == g_ni_syscall3: // Linux syscall 约定发射序 = OS 轴序列(syscall.cr,波 1 Task 6 // 抽取——rax 号 + rdi/rsi/rdx 参数序 + 0F 05 + rax 回存)。 - cp = sys_syscall3_stub(buf, pos, cp, d); - } else if s3 == g_ni_syscall4 { + cp = sys_syscall3_stub(buf, pos, cp, d) + else if s3 == g_ni_syscall4: // Linux syscall 约定发射序 = OS 轴序列(syscall.cr,波 1 Task 6 // 抽取——第 4 参经 r10 的约定与 I-2 修复史见该文件内注)。 - cp = sys_syscall4_stub(buf, pos, cp, d); - } else if s3 == g_ni_load8 { + cp = sys_syscall4_stub(buf, pos, cp, d) + else if s3 == g_ni_load8: // movzx rax, byte [rdi+rsi] — REX.W + 0x0FB6 + SIB - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0); e2_w8(buf, pos+cp, 15); cp = cp + 1; e2_w8(buf, pos+cp, 182); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 0, 4); cp = cp + emit_sib(buf, pos+cp, 0, 6, 7); - if d >= 0 { cp = cp + e2_store_ret(buf, pos+cp, d); } - } else if s3 == g_ni_store8 { + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0) + e2_w8(buf, pos+cp, 15) + cp = cp + 1 + e2_w8(buf, pos+cp, 182) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 0, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 6, 7) + if d >= 0: + cp = cp + e2_store_ret(buf, pos+cp, d) + else if s3 == g_ni_store8: // mov [rdi+rsi], dl — 0x88 + SIB (3rd arg in rdx = register 2) - e2_w8(buf, pos+cp, 136); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4); cp = cp + emit_sib(buf, pos+cp, 0, 6, 7); - } else if s3 == g_ni_load64 || s3 == g_ni_load_str_ptr || s3 == g_ni_r64 { + e2_w8(buf, pos+cp, 136) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 6, 7) + else if s3 == g_ni_load64 || s3 == g_ni_load_str_ptr || s3 == g_ni_r64: // mov rax, [rdi + rsi] // mov rax, [rdi+rsi] — REX.W + 0x8B + SIB - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0); e2_w8(buf, pos+cp, 139); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 0, 4); cp = cp + emit_sib(buf, pos+cp, 0, 6, 7); - if d >= 0 { cp = cp + e2_store_ret(buf, pos+cp, d); } - } else if s3 == g_ni_store_str_ptr { + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 0, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 6, 7) + if d >= 0: + cp = cp + e2_store_ret(buf, pos+cp, d) + else if s3 == g_ni_store_str_ptr: // mov [rdi + rsi], rdx // mov [rdi+rsi], rdx — REX.W + 0x89 + SIB - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0); e2_w8(buf, pos+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4); cp = cp + emit_sib(buf, pos+cp, 0, 6, 7); - } else if s3 == g_ni_get_arg && gv_argv >= 0 { + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 6, 7) + else if s3 == g_ni_get_arg && gv_argv >= 0: // Convert C argv[n] into a Core string with the hidden length header. // NB: gv_argv must be >= 0 (g_rt_argv_ptr registered as a global). // If it's -1, fall through to regular call path — the LEA displacement // would be registered as a rip_patch with gvi=-1 and SKIPPED by the // patch loop, leaving displacement=0 and causing GPF on dereference. - 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, gv_argv); - g_x86_rip_patch_count = g_x86_rip_patch_count + 1; - cp = cp + e2_lr(buf, pos+cp, 0); // lea r10, [rip+0] placeholder + 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, gv_argv) + g_x86_rip_patch_count = g_x86_rip_patch_count + 1 + cp = cp + e2_lr(buf, pos+cp, 0) // lea r10, [rip+0] placeholder // mov r10, [r10] — REX.WRB + 0x8B - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 10%8); // mov r10, [r10] + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 10%8) // mov r10, [r10] // mov r10, [r10 + rdi*8] — SIB(scale=3, index=rdi%8, base=r10%8) - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 4); cp = cp + emit_sib(buf, pos+cp, 3, 7, 10%8); + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 4) + cp = cp + emit_sib(buf, pos+cp, 3, 7, 10%8) // test r10, r10 — REX.WRB + 0x85 - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 133); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 10%8); - e2_w8(buf, pos+cp, 117); e2_w8(buf, pos+cp+1, 18); cp = cp + 2; // jne valid - - e2_w8(buf, pos+cp, 191); e2_w32(buf, pos+cp+1, 1); cp = cp + 5; // mov edi, 1 - grow_alloc_patch(g_x86_alloc_patch_count + 1); w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call alloc + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 133) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 10%8) + e2_w8(buf, pos+cp, 117) + e2_w8(buf, pos+cp+1, 18) + cp = cp + 2 // jne valid + + e2_w8(buf, pos+cp, 191) + e2_w32(buf, pos+cp+1, 1) + cp = cp + 5 // mov edi, 1 + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + e2_w8(buf, pos+cp, 232) + e2_w32(buf, pos+cp+1, 0) + cp = cp + 5 // call alloc // mov byte [rax], 0 — 0xC6 /0 - e2_w8(buf, pos+cp, 198); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 0, 0); e2_w8(buf, pos+cp, 0); cp = cp + 1; - cp = cp + e2_jmp(buf, pos+cp, 47); + e2_w8(buf, pos+cp, 198) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 0, 0) + e2_w8(buf, pos+cp, 0) + cp = cp + 1 + cp = cp + e2_jmp(buf, pos+cp, 47) // xor edi, edi - e2_w8(buf, pos+cp, 49); e2_w8(buf, pos+cp+1, 255); cp = cp + 2; + e2_w8(buf, pos+cp, 49) + e2_w8(buf, pos+cp+1, 255) + cp = cp + 2 // cmp byte [r10+rdi], 0 — 0x80 /7 + SIB - cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 10/8); e2_w8(buf, pos+cp, 128); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 7, 4); cp = cp + emit_sib(buf, pos+cp, 0, 7, 10%8); e2_w8(buf, pos+cp, 0); cp = cp + 1; - e2_w8(buf, pos+cp, 116); e2_w8(buf, pos+cp+1, 8); cp = cp + 2; // je len_done + cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 10/8) + e2_w8(buf, pos+cp, 128) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 7, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 7, 10%8) + e2_w8(buf, pos+cp, 0) + cp = cp + 1 + e2_w8(buf, pos+cp, 116) + e2_w8(buf, pos+cp+1, 8) + cp = cp + 2 // je len_done // inc rdi — REX.W + 0xFF /0 - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0); e2_w8(buf, pos+cp, 255); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 0, 7); - cp = cp + e2_jmp(buf, pos+cp, -15); + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0) + e2_w8(buf, pos+cp, 255) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 0, 7) + cp = cp + e2_jmp(buf, pos+cp, -15) // inc rdi (null terminator) — REX.W + 0xFF /0 - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0); e2_w8(buf, pos+cp, 255); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 0, 7); + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0) + e2_w8(buf, pos+cp, 255) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 0, 7) // alloc clobbers caller-saved r10; preserve the argv[n] source pointer. - e2_w8(buf, pos+cp, 65); e2_w8(buf, pos+cp+1, 82); cp = cp + 2; // push r10 - grow_alloc_patch(g_x86_alloc_patch_count + 1); w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call alloc - e2_w8(buf, pos+cp, 65); e2_w8(buf, pos+cp+1, 90); cp = cp + 2; // pop r10 + e2_w8(buf, pos+cp, 65) + e2_w8(buf, pos+cp+1, 82) + cp = cp + 2 // push r10 + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + e2_w8(buf, pos+cp, 232) + e2_w32(buf, pos+cp+1, 0) + cp = cp + 5 // call alloc + e2_w8(buf, pos+cp, 65) + e2_w8(buf, pos+cp+1, 90) + cp = cp + 2 // pop r10 // xor r11d, r11d — REX.RB + 0x31 - cp = cp + emit_rex(buf, pos+cp, 0, 11/8, 0, 11/8); e2_w8(buf, pos+cp, 49); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 11%8); + cp = cp + emit_rex(buf, pos+cp, 0, 11/8, 0, 11/8) + e2_w8(buf, pos+cp, 49) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 11%8) // mov dl, [r10+r11] — 0x8A + SIB (REX.X=1 for r11 index) - cp = cp + emit_rex(buf, pos+cp, 0, 0, 11/8, 10/8); e2_w8(buf, pos+cp, 138); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4); cp = cp + emit_sib(buf, pos+cp, 0, 11%8, 10%8); + cp = cp + emit_rex(buf, pos+cp, 0, 0, 11/8, 10/8) + e2_w8(buf, pos+cp, 138) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 11%8, 10%8) // mov [rax+r11], dl — 0x88 + SIB (REX.X=1 for r11 index) - cp = cp + emit_rex(buf, pos+cp, 0, 0, 11/8, 0); e2_w8(buf, pos+cp, 136); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4); cp = cp + emit_sib(buf, pos+cp, 0, 11%8, 0); + cp = cp + emit_rex(buf, pos+cp, 0, 0, 11/8, 0) + e2_w8(buf, pos+cp, 136) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 11%8, 0) // inc r11 — REX.WB + 0xFF /0 - cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 11/8); e2_w8(buf, pos+cp, 255); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 0, 11%8); + cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 11/8) + e2_w8(buf, pos+cp, 255) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 0, 11%8) // test dl, dl - e2_w8(buf, pos+cp, 132); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 2, 2); - e2_w8(buf, pos+cp, 117); e2_w8(buf, pos+cp+1, 241); cp = cp + 2; // jne copy_loop - if d >= 0 { cp = cp + e2_store_ret(buf, pos+cp, d); } - } else if s3 == g_ni_w64 { + e2_w8(buf, pos+cp, 132) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 2, 2) + e2_w8(buf, pos+cp, 117) + e2_w8(buf, pos+cp+1, 241) + cp = cp + 2 // jne copy_loop + if d >= 0: + cp = cp + e2_store_ret(buf, pos+cp, d) + else if s3 == g_ni_w64: // w64(buf, pos, val) → mov [rsi+rdi??], rdx // Actually args: rdi=buf, rsi=pos, rdx=val // Just: mov [rdi+rsi], rdx - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0); e2_w8(buf, pos+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4); cp = cp + emit_sib(buf, pos+cp, 0, 6, 7); - } else if s3 == g_ni_dyncpy { + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 0) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 2, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 6, 7) + else if s3 == g_ni_dyncpy: // _dyncpy(src, n, dst) → memcpy(dst, src, n) // rdi=src, rsi=n, rdx=dst // Loop: for(i=0; i= 0 { + e2_w8(buf, pos+cp, 73) + e2_w8(buf, pos+cp+1, 186) + e2_w64(buf, pos+cp+2, 0) // placeholder — patched in elf.cr Phase 3 + cp = cp + 10 + cp = cp + e2_st(buf, pos+cp, 10, do2) + else if s3 >= 0: // 通用调用路径 = callseq.cr cs_call_direct(查名 → e2_call / // 外部位 + 返回值存;波 1 Task 5 抽取) - cp = cs_call_direct(buf, pos, cp, s3, d); - } else { + cp = cs_call_direct(buf, pos, cp, s3, d) + else: // xor eax, eax - e2_w8(buf, pos+cp, 49); e2_w8(buf, pos+cp+1, 192); cp = cp + 2; - if d >= 0 { cp = cp + e2_store_ret(buf, pos+cp, d); } - } + e2_w8(buf, pos+cp, 49) + e2_w8(buf, pos+cp+1, 192) + cp = cp + 2 + if d >= 0: + cp = cp + e2_store_ret(buf, pos+cp, d) // 栈清理(call 后恢复 rsp)= callseq.cr cs_stack_cleanup(波 1 Task 5 抽取) - cp = cs_stack_cleanup(buf, pos, cp, stack_total); - return cp; - } + cp = cs_stack_cleanup(buf, pos, cp, stack_total) + return cp - if op == IR_CALL_EXTERN { - do2 := g2_slot(d); - name_ni := s1; + if op == IR_CALL_EXTERN: + do2 := g2_slot(d) + name_ni := s1 // F16①:装载参数(s2=首参、s3=参数个数,SysV AMD64 约定: // int rdi,rsi,rdx,rcx,r8,r9;float xmm0-7)——修复前 call 前无任何装载。 // 分派段 = callseq.cr cs_args_dispatch(波 1 Task 5 三处同源合流)。 // **注**:extern 路径只做寄存器分派——无栈参压栈/栈清理(预存行为, // 逐字节保持;差异核对见 callseq.cr 头注)。 - cp = cs_args_dispatch(buf, pos, cp, s2, s3); + cp = cs_args_dispatch(buf, pos, cp, s2, s3) // Record external relocation - grow_ext_rel(g_x86_ext_rel_count + 1); - w64(g_x86_ext_rel_pos, g_x86_ext_rel_count * 8, pos + cp); - w64(g_x86_ext_rel_name, g_x86_ext_rel_count * 8, name_ni); - g_x86_ext_rel_count = g_x86_ext_rel_count + 1; + grow_ext_rel(g_x86_ext_rel_count + 1) + w64(g_x86_ext_rel_pos, g_x86_ext_rel_count * 8, pos + cp) + w64(g_x86_ext_rel_name, g_x86_ext_rel_count * 8, name_ni) + g_x86_ext_rel_count = g_x86_ext_rel_count + 1 // Emit call placeholder (E8 + rel32 = 0, patched later) - e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; + e2_w8(buf, pos+cp, 232) + e2_w32(buf, pos+cp+1, 0) + cp = cp + 5 // Store return value from rax - cp = cp + e2_st(buf, pos+cp, 0, do2); - return cp; - } - - if op == IR_HOTPATCH_ROUTE { - do2 := g2_slot(d); - name_ni := s1; - 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, name_ni); - 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; - cp = cp + e2_st(buf, pos+cp, 0, do2); - return cp; - } - - if op == IR_SPAWN { - do2 := g2_slot(d); + cp = cp + e2_st(buf, pos+cp, 0, do2) + return cp + + if op == IR_HOTPATCH_ROUTE: + do2 := g2_slot(d) + name_ni := s1 + 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, name_ni) + 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 + cp = cp + e2_st(buf, pos+cp, 0, do2) + return cp + + if op == IR_SPAWN: + do2 := g2_slot(d) // F4:操作数约定对齐——s1=首参、s2=参数个数、s3=函数名 ni // (ir_gen L939 发射 `emit(IR_SPAWN, dest2, val_var, 1, func_ni, -1)`; // interp 同用 s3 查函数名。修复前 `name_ni := s1` 拿参数变量索引当 // 函数名查表 → 补丁失败 → call rel32=0 → 栈不平衡 → SIGSEGV 139。) - name_ni := s3; + name_ni := s3 // F4:补参数装载——与 IR_CALL 完全相同的 SysV AMD64 分派 // (int: rdi,rsi,rdx,rcx,r8,r9 + 栈超限;float: xmm0-7)—— // = callseq.cr cs_args_dispatch(波 1 Task 5 三处同源合流)。 - fa := s1; ac := s2; - cp = cs_args_dispatch(buf, pos, cp, fa, ac); + fa := s1 + ac := s2 + cp = cs_args_dispatch(buf, pos, cp, fa, ac) // 栈参数(右到左压,第 7 个 int / 第 9 个 float 超限才压)——同 IR_CALL // (= callseq.cr cs_stack_args/cs_stack_count;波 1 Task 5 抽取) - stack_total := cs_stack_count(fa, ac); - cp = cs_stack_args(buf, pos, cp, fa, ac); + stack_total := cs_stack_count(fa, ac) + cp = cs_stack_args(buf, pos, cp, fa, ac) // Emit call to function + store result (single-threaded approximation) - 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, name_ni); - 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; + 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, name_ni) + 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 后恢复 rsp)——同 IR_CALL(= callseq.cr cs_stack_cleanup) - cp = cs_stack_cleanup(buf, pos, cp, stack_total); - if d >= 0 && irv_type(d) == TI_DEX { - cp = cp + e2_sd_store(buf, pos+cp, do2); - } else { - cp = cp + e2_st(buf, pos+cp, 0, do2); - } - return cp; - } - - if op == IR_FNADDR { + cp = cs_stack_cleanup(buf, pos, cp, stack_total) + if d >= 0 && irv_type(d) == TI_DEX: + cp = cp + e2_sd_store(buf, pos+cp, do2) + else: + cp = cp + e2_st(buf, pos+cp, 0, do2) + return cp + + if op == IR_FNADDR: // Load function address into dest: movabs r10, imm64 + store. // The imm64 is a placeholder patched in Phase 3 (after all functions // are placed) with the function's absolute VA (TEXT_BASE + buf pos). - do2 := g2_slot(d); - name_ni := s1; - grow_fnaddr_patch(g_x86_fnaddr_patch_count + 1); - w64(g_x86_fnaddr_patch_pos, g_x86_fnaddr_patch_count * 8, pos + cp); - w64(g_x86_fnaddr_patch_name, g_x86_fnaddr_patch_count * 8, name_ni); - g_x86_fnaddr_patch_count = g_x86_fnaddr_patch_count + 1; + do2 := g2_slot(d) + name_ni := s1 + grow_fnaddr_patch(g_x86_fnaddr_patch_count + 1) + w64(g_x86_fnaddr_patch_pos, g_x86_fnaddr_patch_count * 8, pos + cp) + w64(g_x86_fnaddr_patch_name, g_x86_fnaddr_patch_count * 8, name_ni) + g_x86_fnaddr_patch_count = g_x86_fnaddr_patch_count + 1 // movabs r10, imm64: REX.W+B = 0x49, opcode 0xBA (0xB8 + reg 2, // REX.B extends to 10 = r10). 0x49 0xBB would encode r11 — the // following e2_st(..., 10, ...) stores r10, so the register MUST be r10. - e2_w8(buf, pos+cp, 73); e2_w8(buf, pos+cp+1, 186); // movabs r10, imm64 - e2_w64(buf, pos+cp+2, 0); // placeholder — patched in elf.cr Phase 3 - cp = cp + 10; - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_RETURN { + e2_w8(buf, pos+cp, 73) + e2_w8(buf, pos+cp+1, 186) // movabs r10, imm64 + e2_w64(buf, pos+cp+2, 0) // placeholder — patched in elf.cr Phase 3 + cp = cp + 10 + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_RETURN: // 值序列 + ret_patch 登记 + jmp 占位 = callseq.cr cs_ret_value // (波 1 Task 5 抽取;tag 读路径 A 见该文件注释) - cp = cs_ret_value(buf, pos, cp, s1); - return cp; - } - - if op == IR_ALLOC { - return 0; - } - - if op == IR_ALLOC_STRUCT { - do2 := g2_slot(d); - name_ni := s3; - if name_ni >= 0 { - si := -1; sfi := 0; - loop { if sfi >= g_struct_count { break; } if si_name(sfi) == name_ni { si = sfi; break; } sfi = sfi + 1; } - if si >= 0 { - fc := si_field_count(si); - if fc > 0 { - cp = cp + e2_movabs_rdi(buf, pos+cp, fc * 8); - grow_alloc_patch(g_x86_alloc_patch_count + 1); w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call placeholder - cp = cp + e2_st(buf, pos+cp, 0, do2); - } - } - } - return cp; - } - - if op == IR_ALLOC_ARRAY { - do2 := g2_slot(d); sz := s1 * 8; - if sz > 0 { - cp = cp + e2_movabs_rdi(buf, pos+cp, sz); - grow_alloc_patch(g_x86_alloc_patch_count + 1); w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call placeholder - cp = cp + e2_st(buf, pos+cp, 0, do2); - } else if s1 > 0 { + cp = cs_ret_value(buf, pos, cp, s1) + return cp + + if op == IR_ALLOC: + return 0 + + if op == IR_ALLOC_STRUCT: + do2 := g2_slot(d) + name_ni := s3 + if name_ni >= 0: + si := -1 + sfi := 0 + loop: + if sfi >= g_struct_count: + break + if si_name(sfi) == name_ni: + si = sfi + break + sfi = sfi + 1 + if si >= 0: + fc := si_field_count(si) + if fc > 0: + cp = cp + e2_movabs_rdi(buf, pos+cp, fc * 8) + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + e2_w8(buf, pos+cp, 232) + e2_w32(buf, pos+cp+1, 0) + cp = cp + 5 // call placeholder + cp = cp + e2_st(buf, pos+cp, 0, do2) + return cp + + if op == IR_ALLOC_ARRAY: + do2 := g2_slot(d) + sz := s1 * 8 + if sz > 0: + cp = cp + e2_movabs_rdi(buf, pos+cp, sz) + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + e2_w8(buf, pos+cp, 232) + e2_w32(buf, pos+cp+1, 0) + cp = cp + 5 // call placeholder + cp = cp + e2_st(buf, pos+cp, 0, do2) + else if s1 > 0: // F14:s1*8 在 64 位内溢出为负(s1 > 2⁶¹)——不静默不发射; // 按 OOM 处理(alloc(-1) → null),后续访问由 null 陷阱捕获。 - cp = cp + e2_movabs_rdi(buf, pos+cp, -1); - grow_alloc_patch(g_x86_alloc_patch_count + 1); w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call placeholder - cp = cp + e2_st(buf, pos+cp, 0, do2); - } - return cp; - } - - if op == IR_ARENA_NEW { - do2 := g2_slot(d); - if s1 > 0 { + cp = cp + e2_movabs_rdi(buf, pos+cp, -1) + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + e2_w8(buf, pos+cp, 232) + e2_w32(buf, pos+cp+1, 0) + cp = cp + 5 // call placeholder + cp = cp + e2_st(buf, pos+cp, 0, do2) + return cp + + if op == IR_ARENA_NEW: + do2 := g2_slot(d) + if s1 > 0: // Scope actually allocates: create a fresh arena via arena_new(). - ni_arena_new := str_intern("arena_new"); - 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, ni_arena_new); - 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 placeholder - cp = cp + e2_st(buf, pos+cp, 0, do2); // store returned arena_id from rax - } else { + ni_arena_new := str_intern("arena_new") + 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, ni_arena_new) + 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 placeholder + cp = cp + e2_st(buf, pos+cp, 0, do2) // store returned arena_id from rax + else: // No allocations in this scope: no arena. dest = -1 (none). // Avoids calling arena_new from arena infrastructure itself // (arena_new/arena_reset/_grow_arena_meta), which would recurse. // IR_ARENA_RESET with id < 0 is a safe no-op in arena_reset. - 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; // mov rax, -1 - cp = cp + e2_st(buf, pos+cp, 0, do2); - } - return cp; - } - - if op == IR_ARENA_RESET { + 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 // mov rax, -1 + cp = cp + e2_st(buf, pos+cp, 0, do2) + return cp + + if op == IR_ARENA_RESET: // Load arena_id into edi (register 7 = rdi for first arg) - cp = cp + e2_load_var(buf, pos+cp, 7, s1); + cp = cp + e2_load_var(buf, pos+cp, 7, s1) // Skip the call when no arena was created (id < 0). Without this, // arena_reset's own exit marker would call arena_reset(-1), whose // early return still runs its exit marker → infinite recursion. // test rdi, rdi — 48 85 FF - w8(buf, pos+cp, 72); w8(buf, pos+cp+1, 133); w8(buf, pos+cp+2, 255); cp = cp + 3; + w8(buf, pos+cp, 72) + w8(buf, pos+cp+1, 133) + w8(buf, pos+cp+2, 255) + cp = cp + 3 // jl +5 (skip the 5-byte call) — 7C 05 - w8(buf, pos+cp, 124); w8(buf, pos+cp+1, 5); cp = cp + 2; - ni_arena_reset := str_intern("arena_reset"); - 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, ni_arena_reset); - 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 placeholder - return cp; - } - - if op == IR_LOAD && d >= 0 { - do2 := g2_slot(d); - if s1 >= 0 { - isg : ., mut = r64(g_x86_is_global, s1 * 8); - if isg != 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); + w8(buf, pos+cp, 124) + w8(buf, pos+cp+1, 5) + cp = cp + 2 + ni_arena_reset := str_intern("arena_reset") + 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, ni_arena_reset) + 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 placeholder + return cp + + if op == IR_LOAD && d >= 0: + do2 := g2_slot(d) + if s1 >= 0: + isg : ., mut = r64(g_x86_is_global, s1 * 8) + if isg != 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) // mov r10, [r10] — REX.WRB + 0x8B - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 10%8); - cp = cp + e2_st(buf, pos+cp, 10, do2); + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 10%8) + cp = cp + e2_st(buf, pos+cp, 10, do2) // 全局源(恒 64 位值)→ d tagged 时防御性清 tag - cp = cp + e2_mw_tag_clr(buf, pos+cp, d); - } else { - cp = cp + e2_load_var(buf, pos+cp, 10, s1); cp = cp + e2_st(buf, pos+cp, 10, do2); + cp = cp + e2_mw_tag_clr(buf, pos+cp, d) + else: + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_st(buf, pos+cp, 10, do2) // 拷贝定值 tag 传播(源 tagged → 运行时 tag 拷贝;源 untagged // → 清 0)——d 为 as 转换/拷贝链行(规则 B 闭包成员) - cp = cp + e2_mw_tag_cpy(buf, pos+cp, d, s1); - } - } else { cp = cp + e2_load_var(buf, pos+cp, 10, s1); cp = cp + e2_st(buf, pos+cp, 10, do2); } + cp = cp + e2_mw_tag_cpy(buf, pos+cp, d, s1) + else: + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_st(buf, pos+cp, 10, do2) // s1<0 尾分支(域外行——现 IR 形态防御兜底):mw_setup_tags 规则 B 只扫 // 函数域 [vs, ve)(s1 ∈ 域 且 tagged 才标 d)→ d 恒 untagged——快值原样 // 直拷,无 e2_mw_tag_cpy/清 0 字节(tag 拷贝只对有 tag 字节的域内行发)。 - return cp; - } - - if op == IR_STORE { - o1 := g2_slot(s1); - if s1 >= 0 { - if r64(g_x86_is_global, s1 * 8) != 0 { - cp = cp + e2_load_var(buf, pos+cp, 10, s2); - 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_lrb(buf, pos+cp, 0); + return cp + + if op == IR_STORE: + o1 := g2_slot(s1) + if s1 >= 0: + if r64(g_x86_is_global, s1 * 8) != 0: + cp = cp + e2_load_var(buf, pos+cp, 10, s2) + 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_lrb(buf, pos+cp, 0) // mov [r11], r10 — REX.WRB + 0x89 - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 11/8); e2_w8(buf, pos+cp, 137); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 11%8); - } else { - cp = cp + e2_load_var(buf, pos+cp, 10, s2); cp = cp + e2_st(buf, pos+cp, 10, o1); + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 11/8) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 11%8) + else: + cp = cp + e2_load_var(buf, pos+cp, 10, s2) + cp = cp + e2_st(buf, pos+cp, 10, o1) // 拷贝定值 tag 传播(规则 B' 闭包成员:s2 tagged → 运行时 tag // 拷贝;untagged/全局源 → 清 0)——变量行真定值载体 - cp = cp + e2_mw_tag_cpy(buf, pos+cp, s1, s2); - } - } else { cp = cp + e2_load_var(buf, pos+cp, 10, s2); cp = cp + e2_st(buf, pos+cp, 10, o1); } + cp = cp + e2_mw_tag_cpy(buf, pos+cp, s1, s2) + else: + cp = cp + e2_load_var(buf, pos+cp, 10, s2) + cp = cp + e2_st(buf, pos+cp, 10, o1) // s1<0 尾分支(域外目标行——现 IR 形态防御兜底):规则 B' 只标函数域内 // [vs, ve) 的 s1(且 s2 tagged)→ 域外 s1 恒 untagged——快值原样直拷, // 无 tag 拷贝/清 0(g2_tag_off 域外恒 -1,拷贝源 s2 的 tag 无需落地)。 - return cp; - } + return cp - if op == IR_LOAD_FIELD && d >= 0 { - do2 := g2_slot(d); fi2 := s3; - fo : ., mut = fi2 * 8; + if op == IR_LOAD_FIELD && d >= 0: + do2 := g2_slot(d) + fi2 := s3 + fo : ., mut = fi2 * 8 // 基址加载走 e2_load_var(局部 = [rbp+slot];全局 = RIP 相对 lea, // 与 IR_LOAD_INDEX/IR_ADDR_INDEX 的「handles local and global」同规约)。 // 修复前为 g2_slot(s1)+e2_ld:全局行落在本函数帧之外,g2_slot 返回正的 // 伪 rbp 偏移 → 读栈垃圾(全局结构体字段读静默错值)。 - cp = cp + e2_load_var(buf, pos+cp, 10, s1); + cp = cp + e2_load_var(buf, pos+cp, 10, s1) // mov r10, [r10 + disp32] — REX.WRB + 0x8B - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 2, 10%8, 10%8); cp = cp + e2_w32(buf, pos+cp, fo); - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_STORE_FIELD { - fi2 := s3; - fo : ., mut = fi2 * 8; - cp = cp + e2_load_var(buf, pos+cp, 10, s1); cp = cp + e2_load_var(buf, pos+cp, 11, s2); + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 2, 10%8, 10%8) + cp = cp + e2_w32(buf, pos+cp, fo) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_STORE_FIELD: + fi2 := s3 + fo : ., mut = fi2 * 8 + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_load_var(buf, pos+cp, 11, s2) // mov [r10 + disp32], r11 — REX.WRB + 0x89 - cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 10/8); e2_w8(buf, pos+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 2, 11%8, 10%8); cp = cp + e2_w32(buf, pos+cp, fo); - return cp; - } - - if op == IR_REF && d >= 0 { - do2 := g2_slot(d); - if s1 >= 0 && r64(g_x86_is_global, s1 * 8) != 0 { + cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 10/8) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 2, 11%8, 10%8) + cp = cp + e2_w32(buf, pos+cp, fo) + return cp + + if op == IR_REF && d >= 0: + do2 := g2_slot(d) + if s1 >= 0 && r64(g_x86_is_global, s1 * 8) != 0: // 全局取址:lea r10, [rip+rel32] + RIP 补丁(与 IR_STORE 全局分支、 // e2_load_var 全局分支同规约)。修复前一律 e2_lb(g2_slot(s1))—— // 全局行的 g2_slot 是**帧外的伪 rbp 偏移**(与 IR_LOAD_FIELD 修复前 // 同型缺陷)⇒ `&g` 取到栈上垃圾地址:`*p = x` 写进帧内临时、读回 // 自洽(`*p` 仍读到 x),但与全局槽 `g` 完全脱钩(EL2 实测:ELF // `*p = 5; return g` 恒为初值,interp 正确)。 - 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); - } else { - cp = cp + e2_lb(buf, pos+cp, g2_slot(s1)); - } - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_DEREF && d >= 0 { - do2 := g2_slot(d); - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - if s3 != 0 { - n := e2_ptr_bounds_check(buf, pos+cp, s2, s3, ti); - if n <= 0 { cp = cp + e2_ptr_null_check(buf, pos+cp); } else { cp = cp + n; } - } else { + 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) + else: + cp = cp + e2_lb(buf, pos+cp, g2_slot(s1)) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_DEREF && d >= 0: + do2 := g2_slot(d) + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + if s3 != 0: + n := e2_ptr_bounds_check(buf, pos+cp, s2, s3, ti) + if n <= 0: + cp = cp + e2_ptr_null_check(buf, pos+cp) + else: + cp = cp + n + else: // F6:无分配信息(s3=0)时至少保留 null 陷阱 - cp = cp + e2_ptr_null_check(buf, pos+cp); - } + cp = cp + e2_ptr_null_check(buf, pos+cp) // mov r10, [r10] - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 10%8); - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_ADDR_INDEX && d >= 0 { - do2 := g2_slot(d); + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 10%8) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_ADDR_INDEX && d >= 0: + do2 := g2_slot(d) // load array pointer from arr base slot (handles both local and global) - cp = cp + e2_load_var(buf, pos+cp, 10, s1); + cp = cp + e2_load_var(buf, pos+cp, 10, s1) // load index (handles both local and global) - cp = cp + e2_load_var(buf, pos+cp, 11, s2); + cp = cp + e2_load_var(buf, pos+cp, 11, s2) // lea r10, [r10 + r11*8] = address of arr[i] on heap - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 11/8, 10/8); - e2_w8(buf, pos+cp, 141); cp = cp + 1; // 0x8D LEA - cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 4); // mod=0, reg=r10, rm=4(SIB) - cp = cp + emit_sib(buf, pos+cp, 3, 11%8, 10%8); // scale=3, index=r11, base=r10 - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_STORE_PTR { + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 11/8, 10/8) + e2_w8(buf, pos+cp, 141) + cp = cp + 1 // 0x8D LEA + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 4) // mod=0, reg=r10, rm=4(SIB) + cp = cp + emit_sib(buf, pos+cp, 3, 11%8, 10%8) // scale=3, index=r11, base=r10 + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_STORE_PTR: // load pointer (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - if s3 != 0 { - n := e2_ptr_bounds_check(buf, pos+cp, d, s3, ti); - if n <= 0 { cp = cp + e2_ptr_null_check(buf, pos+cp); } else { cp = cp + n; } - } else { + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + if s3 != 0: + n := e2_ptr_bounds_check(buf, pos+cp, d, s3, ti) + if n <= 0: + cp = cp + e2_ptr_null_check(buf, pos+cp) + else: + cp = cp + n + else: // F6:s3=0(provenance 未填充/unsafe)时至少保留 null 陷阱—— // 修复前整个检查序列(含 null 陷阱)被跳过(instr.cr 旧 L1051)。 - cp = cp + e2_ptr_null_check(buf, pos+cp); - } + cp = cp + e2_ptr_null_check(buf, pos+cp) // load value to store (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 11, s2); + cp = cp + e2_load_var(buf, pos+cp, 11, s2) // mov [r10], r11 — REX.WRB + 0x89 - cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 10/8); e2_w8(buf, pos+cp, 137); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 0, 11%8, 10%8); - return cp; - } - - if op == IR_BRANCH { - cp = cp + e2_load_var(buf, pos+cp, 10, s1); + cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 10/8) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 11%8, 10%8) + return cp + + if op == IR_BRANCH: + cp = cp + e2_load_var(buf, pos+cp, 10, s1) // test r10, r10 - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 133); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 10%8); + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 133) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 10%8, 10%8) // je → false_label (s3), jmp → true_label (s2) // Single-pass backpatching: known labels emit immediately, unknown record pending - je_rel_pos := pos+cp + 2; - cp = cp + e2_je(buf, pos+cp, 0); - if s3 >= 0 && r64(g_label_poses, s3 * 8) >= 0 { - target := r64(g_label_poses, s3 * 8); - e2_w32(buf, je_rel_pos, target - (je_rel_pos + 4)); - } else if s3 >= 0 { - grow_pending(g_pending_count + 1); - w64(g_pending_pos, g_pending_count*8, je_rel_pos); - w64(g_pending_label, g_pending_count*8, s3); - g_pending_count = g_pending_count + 1; - } - jmp_rel_pos := pos+cp + 1; - cp = cp + e2_jmp(buf, pos+cp, 0); - if s2 >= 0 && r64(g_label_poses, s2 * 8) >= 0 { - target := r64(g_label_poses, s2 * 8); - e2_w32(buf, jmp_rel_pos, target - (jmp_rel_pos + 4)); - } else if s2 >= 0 { - grow_pending(g_pending_count + 1); - w64(g_pending_pos, g_pending_count*8, jmp_rel_pos); - w64(g_pending_label, g_pending_count*8, s2); - g_pending_count = g_pending_count + 1; - } - return cp; - } - - if op == IR_JUMP { - jmp_rel_pos := pos+cp + 1; - cp = cp + e2_jmp(buf, pos+cp, 0); - if s1 >= 0 && r64(g_label_poses, s1 * 8) >= 0 { - target := r64(g_label_poses, s1 * 8); - e2_w32(buf, jmp_rel_pos, target - (jmp_rel_pos + 4)); - } else if s1 >= 0 { - grow_pending(g_pending_count + 1); - w64(g_pending_pos, g_pending_count*8, jmp_rel_pos); - w64(g_pending_label, g_pending_count*8, s1); - g_pending_count = g_pending_count + 1; - } - return cp; - } - - if op == IR_LABEL { - li := iri_s1(instr_idx); - if li >= 0 { - grow_label_poses(li + 1); - w64(g_label_poses, li * 8, pos); - if li + 1 > g_label_count { g_label_count = li + 1; } + je_rel_pos := pos+cp + 2 + cp = cp + e2_je(buf, pos+cp, 0) + if s3 >= 0 && r64(g_label_poses, s3 * 8) >= 0: + target := r64(g_label_poses, s3 * 8) + e2_w32(buf, je_rel_pos, target - (je_rel_pos + 4)) + else if s3 >= 0: + grow_pending(g_pending_count + 1) + w64(g_pending_pos, g_pending_count*8, je_rel_pos) + w64(g_pending_label, g_pending_count*8, s3) + g_pending_count = g_pending_count + 1 + jmp_rel_pos := pos+cp + 1 + cp = cp + e2_jmp(buf, pos+cp, 0) + if s2 >= 0 && r64(g_label_poses, s2 * 8) >= 0: + target := r64(g_label_poses, s2 * 8) + e2_w32(buf, jmp_rel_pos, target - (jmp_rel_pos + 4)) + else if s2 >= 0: + grow_pending(g_pending_count + 1) + w64(g_pending_pos, g_pending_count*8, jmp_rel_pos) + w64(g_pending_label, g_pending_count*8, s2) + g_pending_count = g_pending_count + 1 + return cp + + if op == IR_JUMP: + jmp_rel_pos := pos+cp + 1 + cp = cp + e2_jmp(buf, pos+cp, 0) + if s1 >= 0 && r64(g_label_poses, s1 * 8) >= 0: + target := r64(g_label_poses, s1 * 8) + e2_w32(buf, jmp_rel_pos, target - (jmp_rel_pos + 4)) + else if s1 >= 0: + grow_pending(g_pending_count + 1) + w64(g_pending_pos, g_pending_count*8, jmp_rel_pos) + w64(g_pending_label, g_pending_count*8, s1) + g_pending_count = g_pending_count + 1 + return cp + + if op == IR_LABEL: + li := iri_s1(instr_idx) + if li >= 0: + grow_label_poses(li + 1) + w64(g_label_poses, li * 8, pos) + if li + 1 > g_label_count: + g_label_count = li + 1 // Patch all pending forward jumps targeting this label - pi : ., mut = 0; - loop { if pi >= g_pending_count { break; } - if r64(g_pending_label, pi * 8) == li { - rp := r64(g_pending_pos, pi * 8); - e2_w32(buf, rp, pos - (rp + 4)); - w64(g_pending_label, pi * 8, -1); - } - pi = pi + 1; } - } - return 0; - } - - if op == IR_LOAD_ENUM_TAG && d >= 0 { - do2 := g2_slot(d); + pi : ., mut = 0 + loop: + if pi >= g_pending_count: + break + if r64(g_pending_label, pi * 8) == li: + rp := r64(g_pending_pos, pi * 8) + e2_w32(buf, rp, pos - (rp + 4)) + w64(g_pending_label, pi * 8, -1) + pi = pi + 1 + return 0 + + if op == IR_LOAD_ENUM_TAG && d >= 0: + do2 := g2_slot(d) // R2 P4 Task 5(与 IR_CONST 全局行分支同族):**tag 读取源走 e2_load_var** // (局部 = [rbp+slot];全局 = RIP 相对 lea)。修复前 `e2_ld(o1)` 对全局行读 // 帧外伪偏移 ⇒ tag 读垃圾 ⇒ 全局可选槽的 match **静默走空臂**(实测: // `g : int? = Some(5)` + Some 臂 ELF=0 / 解释器=5 = 双路径分歧,基线同病)。 // 注:目的槽仍按帧槽(全局目的行的 RIP 相对 store 未接——当前零发射点)。 - cp = cp + e2_load_var(buf, pos+cp, 10, s1); + cp = cp + e2_load_var(buf, pos+cp, 10, s1) // mov r10, [r10 + disp32] — tag at offset 0 // mov r10, [r10 + 0] (enum tag) - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 2, 10%8, 10%8); cp = cp + e2_w32(buf, pos+cp, 0); - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_LOAD_INDEX && d >= 0 { - do2 := g2_slot(d); idx := s3; + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 2, 10%8, 10%8) + cp = cp + e2_w32(buf, pos+cp, 0) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_LOAD_INDEX && d >= 0: + do2 := g2_slot(d) + idx := s3 // load array pointer (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - if irv_type(s1) == TI_STR { + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + if irv_type(s1) == TI_STR: // Strings are byte sequences, unlike arrays of 8-byte values. - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 15); cp = cp + 1; - e2_w8(buf, pos+cp, 182); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 2, 10%8, 10%8); cp = cp + e2_w32(buf, pos+cp, idx); - } else { - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 2, 10%8, 10%8); cp = cp + e2_w32(buf, pos+cp, idx * 8); - } - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_STORE_INDEX { - idx := s3; + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 15) + cp = cp + 1 + e2_w8(buf, pos+cp, 182) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 2, 10%8, 10%8) + cp = cp + e2_w32(buf, pos+cp, idx) + else: + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 0, 10/8) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 2, 10%8, 10%8) + cp = cp + e2_w32(buf, pos+cp, idx * 8) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_STORE_INDEX: + idx := s3 // load array pointer (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 10, s1); + cp = cp + e2_load_var(buf, pos+cp, 10, s1) // load value to store (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 11, s2); + cp = cp + e2_load_var(buf, pos+cp, 11, s2) // mov [r10 + disp32], r11 - if irv_type(s1) == TI_STR { + if irv_type(s1) == TI_STR: // String assignment stores one byte, not a full machine word. - cp = cp + emit_rex(buf, pos+cp, 0, 11/8, 0, 10/8); e2_w8(buf, pos+cp, 136); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 2, 11%8, 10%8); cp = cp + e2_w32(buf, pos+cp, idx); - } else { + cp = cp + emit_rex(buf, pos+cp, 0, 11/8, 0, 10/8) + e2_w8(buf, pos+cp, 136) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 2, 11%8, 10%8) + cp = cp + e2_w32(buf, pos+cp, idx) + else: // mov [r10 + idx*8], r11 - cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 10/8); e2_w8(buf, pos+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 2, 11%8, 10%8); cp = cp + e2_w32(buf, pos+cp, idx * 8); - } - return cp; - } - - if op == IR_LOAD_INDEX_VAR && d >= 0 { - do2 := g2_slot(d); + cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 10/8) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 2, 11%8, 10%8) + cp = cp + e2_w32(buf, pos+cp, idx * 8) + return cp + + if op == IR_LOAD_INDEX_VAR && d >= 0: + do2 := g2_slot(d) // load array pointer (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 10, s1); + cp = cp + e2_load_var(buf, pos+cp, 10, s1) // load index (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 11, s2); + cp = cp + e2_load_var(buf, pos+cp, 11, s2) // Strings use byte indexing; arrays use 8-byte element indexing. - if irv_type(s1) == TI_STR { - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 11/8, 10/8); e2_w8(buf, pos+cp, 15); cp = cp + 1; e2_w8(buf, pos+cp, 182); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 4); cp = cp + emit_sib(buf, pos+cp, 0, 11%8, 10%8); - } else { - cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 11/8, 10/8); e2_w8(buf, pos+cp, 139); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 4); cp = cp + emit_sib(buf, pos+cp, 3, 11%8, 10%8); - } - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_STORE_INDEX_VAR && d >= 0 { + if irv_type(s1) == TI_STR: + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 11/8, 10/8) + e2_w8(buf, pos+cp, 15) + cp = cp + 1 + e2_w8(buf, pos+cp, 182) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 11%8, 10%8) + else: + cp = cp + emit_rex(buf, pos+cp, 1, 10/8, 11/8, 10/8) + e2_w8(buf, pos+cp, 139) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 10%8, 4) + cp = cp + emit_sib(buf, pos+cp, 3, 11%8, 10%8) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_STORE_INDEX_VAR && d >= 0: // load array pointer (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 10, s1); + cp = cp + e2_load_var(buf, pos+cp, 10, s1) // load index (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 11, s2); + cp = cp + e2_load_var(buf, pos+cp, 11, s2) // load value to store (handles local and global) - cp = cp + e2_load_var(buf, pos+cp, 12, d); - if irv_type(s1) == TI_STR { + cp = cp + e2_load_var(buf, pos+cp, 12, d) + if irv_type(s1) == TI_STR: // String assignment stores one byte at the runtime byte index. - cp = cp + emit_rex(buf, pos+cp, 0, 12/8, 0, 10/8); e2_w8(buf, pos+cp, 136); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 12%8, 4); cp = cp + emit_sib(buf, pos+cp, 0, 11%8, 10%8); - } else { + cp = cp + emit_rex(buf, pos+cp, 0, 12/8, 0, 10/8) + e2_w8(buf, pos+cp, 136) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 12%8, 4) + cp = cp + emit_sib(buf, pos+cp, 0, 11%8, 10%8) + else: // mov [r10 + r11*8], r12 — SIB(scale=3, index=r11%8, base=r10%8) - cp = cp + emit_rex(buf, pos+cp, 1, 12/8, 11/8, 10/8); e2_w8(buf, pos+cp, 137); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 12%8, 4); cp = cp + emit_sib(buf, pos+cp, 3, 11%8, 10%8); - } - return cp; - } - - if op == IR_MAKE_ENUM && d >= 0 { - do2 := g2_slot(d); alloc_size := 8 + s2 * 8; - e2_w8(buf, pos+cp, 191); e2_w32(buf, pos+cp+1, alloc_size); cp = cp + 5; // mov edi, size - grow_alloc_patch(g_x86_alloc_patch_count + 1); w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - e2_w8(buf, pos+cp, 232); e2_w32(buf, pos+cp+1, 0); cp = cp + 5; // call placeholder - cp = cp + e2_st(buf, pos+cp, 0, do2); - cp = cp + e2_ld(buf, pos+cp, 10, do2); + cp = cp + emit_rex(buf, pos+cp, 1, 12/8, 11/8, 10/8) + e2_w8(buf, pos+cp, 137) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 12%8, 4) + cp = cp + emit_sib(buf, pos+cp, 3, 11%8, 10%8) + return cp + + if op == IR_MAKE_ENUM && d >= 0: + do2 := g2_slot(d) + alloc_size := 8 + s2 * 8 + e2_w8(buf, pos+cp, 191) + e2_w32(buf, pos+cp+1, alloc_size) + cp = cp + 5 // mov edi, size + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + cp) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + e2_w8(buf, pos+cp, 232) + e2_w32(buf, pos+cp+1, 0) + cp = cp + 5 // call placeholder + cp = cp + e2_st(buf, pos+cp, 0, do2) + cp = cp + e2_ld(buf, pos+cp, 10, do2) // mov qword [r10 + 0], s1 — 0xC7 + REX.WB - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8); e2_w8(buf, pos+cp, 199); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 0, 0, 10%8); cp = cp + e2_w32(buf, pos+cp, s1); - return cp; - } - - if op == IR_SLICE && d >= 0 { - do2 := g2_slot(d); + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 10/8) + e2_w8(buf, pos+cp, 199) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 0, 0, 10%8) + cp = cp + e2_w32(buf, pos+cp, s1) + return cp + + if op == IR_SLICE && d >= 0: + do2 := g2_slot(d) // 数组指针(s1)与低界(s2)两端走全局行 seam(修复前直吃 g2_slot ⇒ 全局行 // 读帧外伪偏移:实测 ELF 71 vs 解释器 20 的静默错值,见批计划 §T1 B4) - cp = cp + e2_load_var(buf, pos+cp, 10, s1); cp = cp + e2_load_var(buf, pos+cp, 11, s2); + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_load_var(buf, pos+cp, 11, s2) // shl r11, 3 — REX.WB + 0xC1, /4 - cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 11/8); e2_w8(buf, pos+cp, 193); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 4, 11%8); e2_w8(buf, pos+cp, 3); cp = cp + 1; + cp = cp + emit_rex(buf, pos+cp, 1, 0, 0, 11/8) + e2_w8(buf, pos+cp, 193) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 4, 11%8) + e2_w8(buf, pos+cp, 3) + cp = cp + 1 // add r10, r11 — REX.WRB + 0x01 - cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 10/8); e2_w8(buf, pos+cp, 1); cp = cp + 1; cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 10%8); - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - if op == IR_AWAIT && d >= 0 && s1 >= 0 { + cp = cp + emit_rex(buf, pos+cp, 1, 11/8, 0, 10/8) + e2_w8(buf, pos+cp, 1) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 11%8, 10%8) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + if op == IR_AWAIT && d >= 0 && s1 >= 0: // s1 走全局行 seam(修复前全局行读帧外伪偏移 ⇒ 静默错值,实测 interp 9 / ELF 26) - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - cp = cp + e2_st_var(buf, pos+cp, 10, d); - return cp; - } + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_st_var(buf, pos+cp, 10, d) + return cp - if op == IR_BOUNDS_CHECK && s2 >= 0 { + if op == IR_BOUNDS_CHECK && s2 >= 0: // s1 = index var, s2 = max_len 字面量 — index < 0 或 index >= max_len → ud2 // F1c:s2 是字面量长度(发射约定),修复前按变量槽加载(e2_load_var)—— // 把长度当变量索引读,检查恒错。 - cp = cp + e2_load_var(buf, pos+cp, 10, s1); // index - if ti != 0 { + cp = cp + e2_load_var(buf, pos+cp, 10, s1) // index + if ti != 0: // Dynamic upper bound: load len_var into r11. - cp = cp + e2_load_var(buf, pos+cp, 11, s2); - } else { + cp = cp + e2_load_var(buf, pos+cp, 11, s2) + else: // Constant upper bound: movabs r11, imm64. - e2_w8(buf, pos+cp, 73); e2_w8(buf, pos+cp+1, 187); - e2_w64(buf, pos+cp+2, s2); cp = cp + 10; - } - cp = cp + e2_alu(buf, pos+cp, 57); // cmp r10, r11 + e2_w8(buf, pos+cp, 73) + e2_w8(buf, pos+cp+1, 187) + e2_w64(buf, pos+cp+2, s2) + cp = cp + 10 + cp = cp + e2_alu(buf, pos+cp, 57) // cmp r10, r11 // jb +2: if index < max (unsigned below), skip the 2-byte ud2 → continue - e2_w8(buf, pos+cp, 114); // 0x72 = jb rel8 - e2_w8(buf, pos+cp+1, 2); // skip past ud2 - cp = cp + 2; + e2_w8(buf, pos+cp, 114) // 0x72 = jb rel8 + e2_w8(buf, pos+cp+1, 2) // skip past ud2 + cp = cp + 2 // 注意:必须用 pos+cp(Phase 3 的 pos 为绝对基址)——修复前写 cp(相对 // 偏移)→ ud2 落到缓冲区开头(后被 ELF 头覆盖)→ 检查恒不陷阱。 - e2_w8(buf, pos+cp, 15); e2_w8(buf, pos+cp+1, 11); cp = cp + 2; // ud2 (SIGILL) - return cp; - } + e2_w8(buf, pos+cp, 15) + e2_w8(buf, pos+cp+1, 11) + cp = cp + 2 // ud2 (SIGILL) + return cp - if op == IR_INLINE { + if op == IR_INLINE: // No-op at runtime — just a compile hint - return 0; - } - if op == IR_NO_BOUNDS_CHECK { + return 0 + if op == IR_NO_BOUNDS_CHECK: // No-op — consumed by ProvenanceVerify pass - return 0; - } - if op == IR_FAST { + return 0 + if op == IR_FAST: // No-op — consumed by optimization passes - return 0; - } - if op == IR_APPROX { + return 0 + if op == IR_APPROX: // No-op — annotation only (apx: approved for approximate arithmetic) - return 0; - } - if op == IR_UNROLL { + return 0 + if op == IR_UNROLL: // No-op — consumed by loop unrolling pass - return 0; - } - if op == IR_SECTION { + return 0 + if op == IR_SECTION: // No-op — consumed by section assignment pass - return 0; - } - if op == IR_LAZY_THUNK { + return 0 + if op == IR_LAZY_THUNK: // Calls are currently emitted eagerly before the thunk wrapper, so // lowering the wrapper is a typed value transfer. - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - cp = cp + e2_st(buf, pos+cp, 10, g2_slot(d)); - return cp; - } - if op == IR_LAZY_FORCE { - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - cp = cp + e2_st(buf, pos+cp, 10, g2_slot(d)); - return cp; - } - - if op == IR_YIELD { + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_st(buf, pos+cp, 10, g2_slot(d)) + return cp + if op == IR_LAZY_FORCE: + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_st(buf, pos+cp, 10, g2_slot(d)) + return cp + + if op == IR_YIELD: // F5b:eager 单线程近似——与 IR_AWAIT 一致的槽转移(d ← ρ(s1)), // 与 interp 一致(语义表 2.7:eager 近似,D 设计族)。 // 原实现 `call sched_yield()` 且忽略 s1:① 与定义语义(向 flow 消费者 // 通道发射值)不符;② sched_yield 未导入 → call rel32 补丁悬空 → 崩溃; // 导入后无 goroutine 上下文(fiber_switch 无栈可切)同样崩溃(139)。 // 发射侧 dest=-1(ir_gen L1569)→ 本近似为 no-op(yield 值被丢弃)。 - if d >= 0 && s1 >= 0 { - cp = cp + e2_ld(buf, pos+cp, 10, g2_slot(s1)); - cp = cp + e2_st(buf, pos+cp, 10, g2_slot(d)); - } - return cp; - } + if d >= 0 && s1 >= 0: + cp = cp + e2_ld(buf, pos+cp, 10, g2_slot(s1)) + cp = cp + e2_st(buf, pos+cp, 10, g2_slot(d)) + return cp // ── Dynamic type opcodes ── - if op == IR_DYN_PACK && d >= 0 { + if op == IR_DYN_PACK && d >= 0: // Pack value (s1) + tag (s2) into 16-byte dyn_var slot - do2 := g2_slot(d); - cp = cp + e2_load_var(buf, pos+cp, 10, s1); - cp = cp + e2_st(buf, pos+cp, 10, do2); // low 8: value - cp = cp + e2_li(buf, pos+cp, do2 + 8, s2); // high 8: tag (type index) - return cp; - } - - if op == IR_DYN_TAG && d >= 0 { + do2 := g2_slot(d) + cp = cp + e2_load_var(buf, pos+cp, 10, s1) + cp = cp + e2_st(buf, pos+cp, 10, do2) // low 8: value + cp = cp + e2_li(buf, pos+cp, do2 + 8, s2) // high 8: tag (type index) + return cp + + if op == IR_DYN_TAG && d >= 0: // Extract tag from dyn_var (offset +8) - do2 := g2_slot(d); - s1do := g2_slot(s1); - cp = cp + e2_ld(buf, pos+cp, 10, s1do + 8); - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_DYN_VAL && d >= 0 { + do2 := g2_slot(d) + s1do := g2_slot(s1) + cp = cp + e2_ld(buf, pos+cp, 10, s1do + 8) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_DYN_VAL && d >= 0: // Extract value from dyn_var (offset +0) - do2 := g2_slot(d); - s1do := g2_slot(s1); - cp = cp + e2_ld(buf, pos+cp, 10, s1do); - cp = cp + e2_st(buf, pos+cp, 10, do2); - return cp; - } - - if op == IR_DYN_DISPATCH { + do2 := g2_slot(d) + s1do := g2_slot(s1) + cp = cp + e2_ld(buf, pos+cp, 10, s1do) + cp = cp + e2_st(buf, pos+cp, 10, do2) + return cp + + if op == IR_DYN_DISPATCH: // Tag dispatch table: load tag from dyn_var, compare against known types, // jump to common handler that extracts value, or type_error on mismatch. - do2 := g2_slot(d); - s1do := g2_slot(s1); - ti_int : int = 0; ti_bool : int = 2; ti_str : int = 3; + do2 := g2_slot(d) + s1do := g2_slot(s1) + ti_int : int = 0 + ti_bool : int = 2 + ti_str : int = 3 // 1. Load tag from dyn_var offset +8: mov r10, [rbp + s1do + 8] - cp = cp + e2_ld(buf, pos+cp, 10, s1do + 8); + cp = cp + e2_ld(buf, pos+cp, 10, s1do + 8) // 2. Compare-and-jump chain using short rel8 jumps // cmp r10d, TI_INT (0) — REX.RB + 0x83 + ModRM(/7,r10%8) + imm8 - cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 10/8); - e2_w8(buf, pos+cp, 131); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 7, 10%8); - e2_w8(buf, pos+cp, ti_int); cp = cp + 1; - j1_off := cp; // position of the je rel8 offset byte - e2_w8(buf, pos+cp, 116); e2_w8(buf, pos+cp+1, 0); cp = cp + 2; // 0x74 = je rel8 + cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 10/8) + e2_w8(buf, pos+cp, 131) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 7, 10%8) + e2_w8(buf, pos+cp, ti_int) + cp = cp + 1 + j1_off := cp // position of the je rel8 offset byte + e2_w8(buf, pos+cp, 116) + e2_w8(buf, pos+cp+1, 0) + cp = cp + 2 // 0x74 = je rel8 // cmp r10d, TI_BOOL (2) - cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 10/8); - e2_w8(buf, pos+cp, 131); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 7, 10%8); - e2_w8(buf, pos+cp, ti_bool); cp = cp + 1; - j2_off := cp; - e2_w8(buf, pos+cp, 116); e2_w8(buf, pos+cp+1, 0); cp = cp + 2; + cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 10/8) + e2_w8(buf, pos+cp, 131) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 7, 10%8) + e2_w8(buf, pos+cp, ti_bool) + cp = cp + 1 + j2_off := cp + e2_w8(buf, pos+cp, 116) + e2_w8(buf, pos+cp+1, 0) + cp = cp + 2 // cmp r10d, TI_STR (3) - cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 10/8); - e2_w8(buf, pos+cp, 131); cp = cp + 1; - cp = cp + emit_modrm(buf, pos+cp, 3, 7, 10%8); - e2_w8(buf, pos+cp, ti_str); cp = cp + 1; - j3_off := cp; - e2_w8(buf, pos+cp, 116); e2_w8(buf, pos+cp+1, 0); cp = cp + 2; + cp = cp + emit_rex(buf, pos+cp, 0, 0, 0, 10/8) + e2_w8(buf, pos+cp, 131) + cp = cp + 1 + cp = cp + emit_modrm(buf, pos+cp, 3, 7, 10%8) + e2_w8(buf, pos+cp, ti_str) + cp = cp + 1 + j3_off := cp + e2_w8(buf, pos+cp, 116) + e2_w8(buf, pos+cp+1, 0) + cp = cp + 2 // 3. .type_error: 未知 tag——静默产 0(语义表 2.6 BC9 的占位设计意图: // 「未知 tag 静默返回 0」;s2 方法名当前未用,占位)。 @@ -1561,38 +1908,42 @@ fn emit_instr(instr_idx: int, buf: string, pos: int) -> int { // (push rbp; sub rsp)时弹出局部槽 → SIGSEGV;改 xor r10d,r10d + // jmp .done(值级 d := 0,无中间 ret,不崩溃)。注意:本段必须位于 // compare-chain 之后(落空即到此)、.case_common 之前。 - e2_w8(buf, pos+cp, 69); e2_w8(buf, pos+cp+1, 49); e2_w8(buf, pos+cp+2, 210); cp = cp + 3; // xor r10d, r10d (45 31 D2) - type_jmp_off := cp; - e2_w8(buf, pos+cp, 235); e2_w8(buf, pos+cp+1, 0); cp = cp + 2; // 0xEB = jmp rel8 .done + e2_w8(buf, pos+cp, 69) + e2_w8(buf, pos+cp+1, 49) + e2_w8(buf, pos+cp+2, 210) + cp = cp + 3 // xor r10d, r10d (45 31 D2) + type_jmp_off := cp + e2_w8(buf, pos+cp, 235) + e2_w8(buf, pos+cp+1, 0) + cp = cp + 2 // 0xEB = jmp rel8 .done // 4. .case_common: extract value from dyn_var offset +0 - case_pos := cp; - cp = cp + e2_ld(buf, pos+cp, 10, s1do); + case_pos := cp + cp = cp + e2_ld(buf, pos+cp, 10, s1do) // jmp rel8 .done - jmp_done_off := cp; - e2_w8(buf, pos+cp, 235); e2_w8(buf, pos+cp+1, 0); cp = cp + 2; // 0xEB = jmp rel8 + jmp_done_off := cp + e2_w8(buf, pos+cp, 235) + e2_w8(buf, pos+cp+1, 0) + cp = cp + 2 // 0xEB = jmp rel8 // 5. .done: store extracted value in destination slot - done_pos := cp; - if d >= 0 { - cp = cp + e2_st(buf, pos+cp, 10, do2); - } + done_pos := cp + if d >= 0: + cp = cp + e2_st(buf, pos+cp, 10, do2) // 6. Patch all forward jump offsets (rel8) // F3:写入位置加 pos 基——原实现用指令内相对偏移(j1_off 等,cp 系) // 当绝对缓冲区偏移 → 补丁写错地址 → 三个 je rel8 恒 0 → 已知 tag 也 // 坠错误路径 → SIGSEGV(139)。对照全文件其他补丁的 `pos + cp` 惯例。 - e2_w8(buf, pos + j1_off + 1, case_pos - (j1_off + 2)); - e2_w8(buf, pos + j2_off + 1, case_pos - (j2_off + 2)); - e2_w8(buf, pos + j3_off + 1, case_pos - (j3_off + 2)); - e2_w8(buf, pos + jmp_done_off + 1, done_pos - (jmp_done_off + 2)); - e2_w8(buf, pos + type_jmp_off + 1, done_pos - (type_jmp_off + 2)); + e2_w8(buf, pos + j1_off + 1, case_pos - (j1_off + 2)) + e2_w8(buf, pos + j2_off + 1, case_pos - (j2_off + 2)) + e2_w8(buf, pos + j3_off + 1, case_pos - (j3_off + 2)) + e2_w8(buf, pos + jmp_done_off + 1, done_pos - (jmp_done_off + 2)) + e2_w8(buf, pos + type_jmp_off + 1, done_pos - (type_jmp_off + 2)) - return cp; - } + return cp - return 0; -} + return 0 // ══════════════════════════════════════════════════════════════ // HIT 表驱动发射(M1 Task 2/3)——事件流编码器(emit_instr 的并行路径) @@ -1612,38 +1963,51 @@ fn emit_instr(instr_idx: int, buf: string, pos: int) -> int { // 布局常量 hit.cr(HIT_*)。 // 角色 → M1 寄存器对低 3 位(modrm 字段编码;r10=2 主累加 / r11=3 第二操作数) -fn hit_role_reg_low(role: int) -> int { - if role == HIT_ROLE_DST { return 2; } - if role == HIT_ROLE_SRC1 { return 2; } - if role == HIT_ROLE_SRC2 { return 3; } - if role == HIT_ROLE_VAL { return 2; } - return -1; } // addr/未知:无寄存器惯例(M1 addr 走 rbp+disp 形态) +fn hit_role_reg_low(role: int) -> int: + if role == HIT_ROLE_DST: + return 2 + if role == HIT_ROLE_SRC1: + return 2 + if role == HIT_ROLE_SRC2: + return 3 + if role == HIT_ROLE_VAL: + return 2 + return -1 +// addr/未知:无寄存器惯例(M1 addr 走 rbp+disp 形态) // 角色 → 绝对寄存器号(M1 惯例 r10/r11:低 3 位 + REX.R 位含在表 opcode 内) -fn hit_role_reg(role: int) -> int { - low := hit_role_reg_low(role); - if low < 0 { return -1; } - return 8 + low; } +fn hit_role_reg(role: int) -> int: + low := hit_role_reg_low(role) + if low < 0: + return -1 + return 8 + low // 槽/池寻址形态的 addr 变量可用性:须为当前函数真内存槽变量 // (表模板 = rbp+disp32:寄存器分配变量/全局走旧路径——e2 族已有其语义) -fn hit_ev_slot_addr_ok(v: int) -> int { - if v < 0 { return 0; } - if v >= g_ir_var_count { return 0; } - if r64(g_x86_is_global, v * 8) != 0 { return 0; } - if v < g_current_func_var_start { return 0; } - o := g2_slot(v); - if o >= E2_REG_SLOT_BASE { return 0; } - return 1; } +fn hit_ev_slot_addr_ok(v: int) -> int: + if v < 0: + return 0 + if v >= g_ir_var_count: + return 0 + if r64(g_x86_is_global, v * 8) != 0: + return 0 + if v < g_current_func_var_start: + return 0 + o := g2_slot(v) + if o >= E2_REG_SLOT_BASE: + return 0 + return 1 // 取事件模板步(proj0 视图整条 108B 记录复制入 st;本文件 M1 消费面只读 // 前 20B 视区——schema v2 记录加宽后偏移 0-16 语义未变,见 hit.cr 布局注释); // -1 = 表无此事件/步非法 -fn hit_ev_step_of(ev_id: int, st: string) -> int { - es := hit_event_lookup(ev_id); - if es < 0 { return -1; } - if hit_proj_step(es, 0, st) != 0 { return -1; } - return 0; } +fn hit_ev_step_of(ev_id: int, st: string) -> int: + es := hit_event_lookup(ev_id) + if es < 0: + return -1 + if hit_proj_step(es, 0, st) != 0: + return -1 + return 0 // ── v2 步模板发射/预检(M2a Task 2——模板解释器字段发射)── // 形态族字段(hit.cr HIT_ST_OFF_* v2 区)按解释器固定序组装:prefix → rex → @@ -1660,343 +2024,470 @@ fn hit_ev_step_of(ev_id: int, st: string) -> int { // POOL:load 事件 s1 = 池槽——池 mov([rip+disp] 硬编码辅助——M1 通道,非模板) // JUMP(5):无 modrm rel32 步(E9——目标 = 事件序) // IMM(11 cst——注入夹具):/digit + [rbp+disp] + imm(imm 值 = 事件 s1 原值) -HIT_EV_CLS_ALU : int = 0; -HIT_EV_CLS_MEM : int = 1; -HIT_EV_CLS_POOL : int = 2; -HIT_EV_CLS_JUMP : int = 3; -HIT_EV_CLS_IMM : int = 4; - -fn hit_ev_class(ev_id: int, fl: int) -> int { - if ev_id == HIT_EV_SUB || ev_id == HIT_EV_NAND { return HIT_EV_CLS_ALU; } - if ev_id == HIT_EV_LOAD && fl % 2 == 1 { return HIT_EV_CLS_POOL; } - if ev_id == HIT_EV_LOAD || ev_id == HIT_EV_STORE { return HIT_EV_CLS_MEM; } - if ev_id == HIT_EV_JUMP { return HIT_EV_CLS_JUMP; } - if ev_id == 11 { return HIT_EV_CLS_IMM; } // cst 夹具(注入测试载体) - return -1; } // 事件 6-9 = Task 3 前拒绝(无语义类 → 落旧路径) +HIT_EV_CLS_ALU : int = 0 +HIT_EV_CLS_MEM : int = 1 +HIT_EV_CLS_POOL : int = 2 +HIT_EV_CLS_JUMP : int = 3 +HIT_EV_CLS_IMM : int = 4 + +fn hit_ev_class(ev_id: int, fl: int) -> int: + if ev_id == HIT_EV_SUB || ev_id == HIT_EV_NAND: + return HIT_EV_CLS_ALU + if ev_id == HIT_EV_LOAD && fl % 2 == 1: + return HIT_EV_CLS_POOL + if ev_id == HIT_EV_LOAD || ev_id == HIT_EV_STORE: + return HIT_EV_CLS_MEM + if ev_id == HIT_EV_JUMP: + return HIT_EV_CLS_JUMP + if ev_id == 11: + return HIT_EV_CLS_IMM + // cst 夹具(注入测试载体) + return -1 +// 事件 6-9 = Task 3 前拒绝(无语义类 → 落旧路径) // 形态(proj)选择:类按所需形态逐 proj 选首个匹配(条目序 = 优先序—— // 槽寻址 = rm_mode 1/2 形态、寄存器对 = 0;jump 取首个投影)。st = 选中 // proj 的步 0 记录(108B)。返回 proj 下标;-1 = 无匹配形态('no projection // for shape'——预检落旧路径)。 -fn hit_ev_proj_pick(es: int, cls: int, st: string) -> int { - pc := hit_proj_count(es); - pi : ., mut = 0; - loop { - if pi >= pc { break; } - if hit_proj_step_get(es, pi, 0, st) != 0 { return -1; } - rm_mode := hit_r32(st, HIT_ST_OFF_RM_MODE); - if cls == HIT_EV_CLS_ALU && rm_mode == 0 { return pi; } - if cls == HIT_EV_CLS_MEM && (rm_mode == 1 || rm_mode == 2) { return pi; } - if cls == HIT_EV_CLS_IMM && rm_mode == 1 { return pi; } - if cls == HIT_EV_CLS_JUMP { return pi; } - pi = pi + 1; } - return -1; } +fn hit_ev_proj_pick(es: int, cls: int, st: string) -> int: + pc := hit_proj_count(es) + pi : ., mut = 0 + loop: + if pi >= pc: + break + if hit_proj_step_get(es, pi, 0, st) != 0: + return -1 + rm_mode := hit_r32(st, HIT_ST_OFF_RM_MODE) + if cls == HIT_EV_CLS_ALU && rm_mode == 0: + return pi + if cls == HIT_EV_CLS_MEM && (rm_mode == 1 || rm_mode == 2): + return pi + if cls == HIT_EV_CLS_IMM && rm_mode == 1: + return pi + if cls == HIT_EV_CLS_JUMP: + return pi + pi = pi + 1 + return -1 // 模板字节头:prefix → rex → opcode(v2 字段区逐段;st = 108B 步记录)。 // 返回字节数。 -fn hit_st_head(st: string, buf: string, pos: int) -> int { - cp : ., mut = 0; - p0 := hit_r32(st, HIT_ST_OFF_PFX0); - if p0 != 0 { e2_w8(buf, pos + cp, p0); cp = cp + 1; } - p1 := hit_r32(st, HIT_ST_OFF_PFX1); - if p1 != 0 { e2_w8(buf, pos + cp, p1); cp = cp + 1; } - rx := hit_r32(st, HIT_ST_OFF_REX); - if rx != 0 { e2_w8(buf, pos + cp, rx); cp = cp + 1; } - nop := hit_r32(st, HIT_ST_OFF_OPN); - j : ., mut = 0; - loop { - if j >= nop { break; } - if j == 0 { e2_w8(buf, pos + cp, hit_r32(st, HIT_ST_OFF_OPB0)); } - if j == 1 { e2_w8(buf, pos + cp, hit_r32(st, HIT_ST_OFF_OPB1)); } - if j == 2 { e2_w8(buf, pos + cp, hit_r32(st, HIT_ST_OFF_OPB2)); } - cp = cp + 1; - j = j + 1; } - return cp; } +fn hit_st_head(st: string, buf: string, pos: int) -> int: + cp : ., mut = 0 + p0 := hit_r32(st, HIT_ST_OFF_PFX0) + if p0 != 0: + e2_w8(buf, pos + cp, p0) + cp = cp + 1 + p1 := hit_r32(st, HIT_ST_OFF_PFX1) + if p1 != 0: + e2_w8(buf, pos + cp, p1) + cp = cp + 1 + rx := hit_r32(st, HIT_ST_OFF_REX) + if rx != 0: + e2_w8(buf, pos + cp, rx) + cp = cp + 1 + nop := hit_r32(st, HIT_ST_OFF_OPN) + j : ., mut = 0 + loop: + if j >= nop: + break + if j == 0: + e2_w8(buf, pos + cp, hit_r32(st, HIT_ST_OFF_OPB0)) + if j == 1: + e2_w8(buf, pos + cp, hit_r32(st, HIT_ST_OFF_OPB1)) + if j == 2: + e2_w8(buf, pos + cp, hit_r32(st, HIT_ST_OFF_OPB2)) + cp = cp + 1 + j = j + 1 + return cp // rm_mode 1(base = rbp)的 modrm + disp 发射:宽度按步 disp_size 字段 //(0 = auto——槽偏移幅度选 disp8|32,与旧路径 e2_ld/e2_st 同规则 ④)。 // 返回字节数;宽度不符(disp8 越界)= -1。 -fn hit_st_modrm_disp(st: string, buf: string, pos: int, reg_lo: int, disp_val: int) -> int { - dsz := hit_r32(st, HIT_ST_OFF_DISP_SIZE); - cp : ., mut = 0; - if dsz == 1 { - if disp_val < -128 || disp_val > 127 { return -1; } - cp = cp + emit_modrm(buf, pos + cp, 1, reg_lo, 5); - e2_w8(buf, pos + cp, disp_val); - cp = cp + 1; } - else if dsz == 4 { - cp = cp + emit_modrm(buf, pos + cp, 2, reg_lo, 5); - cp = cp + e2_w32(buf, pos + cp, disp_val); } - else { - if disp_val >= -128 && disp_val <= 127 { - cp = cp + emit_modrm(buf, pos + cp, 1, reg_lo, 5); - e2_w8(buf, pos + cp, disp_val); - cp = cp + 1; } - else { - cp = cp + emit_modrm(buf, pos + cp, 2, reg_lo, 5); - cp = cp + e2_w32(buf, pos + cp, disp_val); } } - return cp; } +fn hit_st_modrm_disp(st: string, buf: string, pos: int, reg_lo: int, disp_val: int) -> int: + dsz := hit_r32(st, HIT_ST_OFF_DISP_SIZE) + cp : ., mut = 0 + if dsz == 1: + if disp_val < -128 || disp_val > 127: + return -1 + cp = cp + emit_modrm(buf, pos + cp, 1, reg_lo, 5) + e2_w8(buf, pos + cp, disp_val) + cp = cp + 1 + else if dsz == 4: + cp = cp + emit_modrm(buf, pos + cp, 2, reg_lo, 5) + cp = cp + e2_w32(buf, pos + cp, disp_val) + else: + if disp_val >= -128 && disp_val <= 127: + cp = cp + emit_modrm(buf, pos + cp, 1, reg_lo, 5) + e2_w8(buf, pos + cp, disp_val) + cp = cp + 1 + else: + cp = cp + emit_modrm(buf, pos + cp, 2, reg_lo, 5) + cp = cp + e2_w32(buf, pos + cp, disp_val) + return cp // 步 imm 发射(imm_size 1/2/4/8;值由调用方解析——lit 取模板字面量、操作数 // 角色取事件域原值)。返回字节数。 -fn hit_st_imm(st: string, buf: string, pos: int, imm_val: int) -> int { - isz := hit_r32(st, HIT_ST_OFF_IMM_SIZE); - if isz == 0 { return 0; } - if isz == 1 { e2_w8(buf, pos, imm_val); return 1; } - if isz == 2 { e2_w8(buf, pos, imm_val); e2_w8(buf, pos + 1, imm_val / 256); return 2; } - if isz == 4 { e2_w32(buf, pos, imm_val); return 4; } - e2_w64(buf, pos, imm_val); - return 8; } +fn hit_st_imm(st: string, buf: string, pos: int, imm_val: int) -> int: + isz := hit_r32(st, HIT_ST_OFF_IMM_SIZE) + if isz == 0: + return 0 + if isz == 1: + e2_w8(buf, pos, imm_val) + return 1 + if isz == 2: + e2_w8(buf, pos, imm_val) + e2_w8(buf, pos + 1, imm_val / 256) + return 2 + if isz == 4: + e2_w32(buf, pos, imm_val) + return 4 + e2_w64(buf, pos, imm_val) + return 8 // 步 rel 发射 + 回填登记(kind 0 = 事件流位置——pos = rel 字段偏移;宽 = 32)。 // 返回字节数;kind/宽度非本任务面 = -1(预检已拦——防御)。 -fn hit_st_rel_emit(st: string, buf: string, pos: int, target: int) -> int { - rk := hit_r32(st, HIT_ST_OFF_REL_KIND); - if rk == 0 { return 0; } - rs := hit_r32(st, HIT_ST_OFF_REL_SIZE); - if rk == HIT_REL_EVENT && rs == 32 { - e2_w32(buf, pos, 0); // 占位——elf.cr 发射后按事件位置表回填 - hit_rel_add(0, pos, target); - return 4; } - return -1; } +fn hit_st_rel_emit(st: string, buf: string, pos: int, target: int) -> int: + rk := hit_r32(st, HIT_ST_OFF_REL_KIND) + if rk == 0: + return 0 + rs := hit_r32(st, HIT_ST_OFF_REL_SIZE) + if rk == HIT_REL_EVENT && rs == 32: + e2_w32(buf, pos, 0) // 占位——elf.cr 发射后按事件位置表回填 + hit_rel_add(0, pos, target) + return 4 + return -1 // 单条事件预检(发射前整条指令全过才落字节;任一不支持 → 整条落旧路径, // 不产生半写)。Returns 0 = 可发射;1 = 不支持。 -fn hit_ev_preflight_ok(ev_i: int) -> int { - ev_id := hit_ev_id(ev_i); - d := hit_ev_dst(ev_i); - s1 := hit_ev_s1(ev_i); - s2 := hit_ev_s2(ev_i); - fl := hit_ev_flags(ev_i); - es := hit_event_lookup(ev_id); - if es < 0 { return 1; } // 表在但事件缺 → 保守落旧路径 - cls := hit_ev_class(ev_id, fl); - if cls < 0 { return 1; } // 事件 6-9 等 = 无语义类 → 拒绝(Task 3 前保持) - if cls == HIT_EV_CLS_POOL { +fn hit_ev_preflight_ok(ev_i: int) -> int: + ev_id := hit_ev_id(ev_i) + d := hit_ev_dst(ev_i) + s1 := hit_ev_s1(ev_i) + s2 := hit_ev_s2(ev_i) + fl := hit_ev_flags(ev_i) + es := hit_event_lookup(ev_id) + if es < 0: + return 1 + // 表在但事件缺 → 保守落旧路径 + cls := hit_ev_class(ev_id, fl) + if cls < 0: + return 1 + // 事件 6-9 等 = 无语义类 → 拒绝(Task 3 前保持) + if cls == HIT_EV_CLS_POOL: // 池载入:load 模板 proj0 视区(= hit_ev_emit_pool_mov 同源形态) - if d < 0 { return 1; } - if s1 < 0 || s1 >= g_hit_pool_count { return 1; } - stx := alloc(HIT_STEP_REC); - if hit_ev_step_of(ev_id, stx) != 0 { return 1; } - rm_mode := hit_r32(stx, HIT_ST_OFF_RM_MODE); - rr := hit_r32(stx, HIT_ST_OFF_REG_ROLE); - mr := hit_r32(stx, HIT_ST_OFF_RM_ROLE); - if rm_mode != 1 || rr != HIT_ROLE_DST || mr != HIT_ROLE_ADDR { return 1; } - if hit_role_reg_low(rr) < 0 { return 1; } - return 0; } - st := alloc(HIT_STEP_REC); - pj := hit_ev_proj_pick(es, cls, st); - if pj < 0 { return 1; } // 'no projection for shape' - if hit_proj_step_count(es, pj) != 1 { return 1; } // 多步序列 = Task 3/6 - rm_mode := hit_r32(st, HIT_ST_OFF_RM_MODE); - rr := hit_r32(st, HIT_ST_OFF_REG_ROLE); - mr := hit_r32(st, HIT_ST_OFF_RM_ROLE); + if d < 0: + return 1 + if s1 < 0 || s1 >= g_hit_pool_count: + return 1 + stx := alloc(HIT_STEP_REC) + if hit_ev_step_of(ev_id, stx) != 0: + return 1 + rm_mode := hit_r32(stx, HIT_ST_OFF_RM_MODE) + rr := hit_r32(stx, HIT_ST_OFF_REG_ROLE) + mr := hit_r32(stx, HIT_ST_OFF_RM_ROLE) + if rm_mode != 1 || rr != HIT_ROLE_DST || mr != HIT_ROLE_ADDR: + return 1 + if hit_role_reg_low(rr) < 0: + return 1 + return 0 + st := alloc(HIT_STEP_REC) + pj := hit_ev_proj_pick(es, cls, st) + if pj < 0: + return 1 + // 'no projection for shape' + if hit_proj_step_count(es, pj) != 1: + return 1 + // 多步序列 = Task 3/6 + rm_mode := hit_r32(st, HIT_ST_OFF_RM_MODE) + rr := hit_r32(st, HIT_ST_OFF_REG_ROLE) + mr := hit_r32(st, HIT_ST_OFF_RM_ROLE) // ── 步字段支持门(本任务发射面外 → 保守落旧路径)── - if hit_r32(st, HIT_ST_OFF_OPN) < 1 { return 1; } // opcode 必选(loader 已验——防御) - if hit_r32(st, HIT_ST_OFF_SIB_SCALE) != 0 || rm_mode == 2 { return 1; } // SIB = M2c 批 3 - if hit_r32(st, HIT_ST_OFF_BASE_ROLE) != 0 { return 1; } // 非 rbp 基(rip/槽值寄存器 = 批 4/3) - if hit_r32(st, HIT_ST_OFF_REG_ROLE) >= HIT_REG_BASE { return 1; } // 寄存器字面量角色 = M2c - if hit_r32(st, HIT_ST_OFF_RM_ROLE) >= HIT_REG_BASE { return 1; } - if hit_r32(st, HIT_ST_OFF_IMM_KIND) != 0 { return 1; } // imm64 fnaddr 回填 = M2c 批 2 - if hit_r32(st, HIT_ST_OFF_REL_SIZE) == 8 { return 1; } // rel8 = Task 12(批 2 G2) - if hit_r32(st, HIT_ST_OFF_COND_ROLE) != 0 { return 1; } // cond 发射 = Task 3 - if hit_r32(st, HIT_ST_OFF_REL_KIND) == HIT_REL_FUNC || - hit_r32(st, HIT_ST_OFF_REL_KIND) == HIT_REL_EXTERN { return 1; } // Task 4/5 - if cls == HIT_EV_CLS_JUMP { + if hit_r32(st, HIT_ST_OFF_OPN) < 1: + return 1 + // opcode 必选(loader 已验——防御) + if hit_r32(st, HIT_ST_OFF_SIB_SCALE) != 0 || rm_mode == 2: + return 1 + // SIB = M2c 批 3 + if hit_r32(st, HIT_ST_OFF_BASE_ROLE) != 0: + return 1 + // 非 rbp 基(rip/槽值寄存器 = 批 4/3) + if hit_r32(st, HIT_ST_OFF_REG_ROLE) >= HIT_REG_BASE: + return 1 + // 寄存器字面量角色 = M2c + if hit_r32(st, HIT_ST_OFF_RM_ROLE) >= HIT_REG_BASE: + return 1 + if hit_r32(st, HIT_ST_OFF_IMM_KIND) != 0: + return 1 + // imm64 fnaddr 回填 = M2c 批 2 + if hit_r32(st, HIT_ST_OFF_REL_SIZE) == 8: + return 1 + // rel8 = Task 12(批 2 G2) + if hit_r32(st, HIT_ST_OFF_COND_ROLE) != 0: + return 1 + // cond 发射 = Task 3 + if hit_r32(st, HIT_ST_OFF_REL_KIND) == HIT_REL_FUNC || hit_r32(st, HIT_ST_OFF_REL_KIND) == HIT_REL_EXTERN: + return 1 + // Task 4/5 + if cls == HIT_EV_CLS_JUMP: // 无条件转移:E9 rel32——目标 = 事件序(s1);dst/s2 未用(恒 0) - if d != 0 || s2 != 0 { return 1; } - if fl != 0 { return 1; } - if s1 < 0 || s1 >= g_hit_ev_count { return 1; } - if rr != 0 || mr != 0 { return 1; } // 无 modrm 形态 - if hit_r32(st, HIT_ST_OFF_REL_KIND) != HIT_REL_EVENT { return 1; } - return 0; } - if cls == HIT_EV_CLS_ALU { + if d != 0 || s2 != 0: + return 1 + if fl != 0: + return 1 + if s1 < 0 || s1 >= g_hit_ev_count: + return 1 + if rr != 0 || mr != 0: + return 1 + // 无 modrm 形态 + if hit_r32(st, HIT_ST_OFF_REL_KIND) != HIT_REL_EVENT: + return 1 + return 0 + if cls == HIT_EV_CLS_ALU: // 双寄存器累加形(sub/nand…):rm = dst 累加(r10)、reg = src2(r11) - if mr != HIT_ROLE_DST { return 1; } - if rr != HIT_ROLE_SRC2 { return 1; } - if hit_role_reg_low(rr) < 0 || hit_role_reg_low(mr) < 0 { return 1; } - if d < 0 { return 1; } - if fl % 2 == 0 && s1 < 0 { return 1; } // var 操作数须非负 - if fl / 2 % 2 == 0 && s2 < 0 { return 1; } - if fl / 2 % 2 == 1 { return 1; } // M1:仅首操作数可为池 - return 0; } - if cls == HIT_EV_CLS_IMM { + if mr != HIT_ROLE_DST: + return 1 + if rr != HIT_ROLE_SRC2: + return 1 + if hit_role_reg_low(rr) < 0 || hit_role_reg_low(mr) < 0: + return 1 + if d < 0: + return 1 + if fl % 2 == 0 && s1 < 0: + return 1 + // var 操作数须非负 + if fl / 2 % 2 == 0 && s2 < 0: + return 1 + if fl / 2 % 2 == 1: + return 1 + // M1:仅首操作数可为池 + return 0 + if cls == HIT_EV_CLS_IMM: // cst(注入夹具):/digit + [rbp+disp] + imm——rm = dst 槽、值 = s1 原值 - if d < 0 || s1 < 0 { return 1; } - if fl != 0 { return 1; } - if hit_r32(st, HIT_ST_OFF_REG_IS_DIGIT) != 1 { return 1; } - if hit_r32(st, HIT_ST_OFF_REG_DIGIT) > 7 { return 1; } - if mr != HIT_ROLE_DST { return 1; } - if hit_r32(st, HIT_ST_OFF_IMM_SIZE) == 0 { return 1; } - if hit_r32(st, HIT_ST_OFF_REL_KIND) != 0 { return 1; } - return 0; } + if d < 0 || s1 < 0: + return 1 + if fl != 0: + return 1 + if hit_r32(st, HIT_ST_OFF_REG_IS_DIGIT) != 1: + return 1 + if hit_r32(st, HIT_ST_OFF_REG_DIGIT) > 7: + return 1 + if mr != HIT_ROLE_DST: + return 1 + if hit_r32(st, HIT_ST_OFF_IMM_SIZE) == 0: + return 1 + if hit_r32(st, HIT_ST_OFF_REL_KIND) != 0: + return 1 + return 0 // MEM(load/store 槽寻址):reg 角色 = dst(load)或 val(store)——rm 侧 = addr - if mr != HIT_ROLE_ADDR { return 1; } - if hit_role_reg_low(rr) < 0 { return 1; } - if rr == HIT_ROLE_DST { // load:读 [addr槽] → dst 槽 - if d < 0 { return 1; } - if fl % 2 == 1 { return 1; } // 池 load = C_POOL(上已走) - if hit_ev_slot_addr_ok(s1) == 0 { return 1; } - return 0; } - if rr == HIT_ROLE_VAL { // store:写 [addr槽] ← val - if fl % 2 == 1 { return 1; } // 写池 = 无意义(池只读)——保守 - if hit_ev_slot_addr_ok(s1) == 0 { return 1; } - if s2 < 0 { return 1; } - return 0; } - return 1; } + if mr != HIT_ROLE_ADDR: + return 1 + if hit_role_reg_low(rr) < 0: + return 1 + if rr == HIT_ROLE_DST: + // load:读 [addr槽] → dst 槽 + if d < 0: + return 1 + if fl % 2 == 1: + return 1 + // 池 load = C_POOL(上已走) + if hit_ev_slot_addr_ok(s1) == 0: + return 1 + return 0 + if rr == HIT_ROLE_VAL: + // store:写 [addr槽] ← val + if fl % 2 == 1: + return 1 + // 写池 = 无意义(池只读)——保守 + if hit_ev_slot_addr_ok(s1) == 0: + return 1 + if s2 < 0: + return 1 + return 0 + return 1 // 池值 → 寄存器:mov r64, [rip+disp32]——load 事件模板字节 + mod=00(rm=101 = // rip 相对;disp 由 elf.cr 于 rodata 定稿后按池槽回填)。reg 低 3 位 = 目标。 // 返回写入字节数(恒 7);load 事件形态不符 = -1(调用方整条落旧路径)。 -fn hit_ev_emit_pool_mov(buf: string, pos: int, reg_low: int, k: int) -> int { - st := alloc(HIT_STEP_REC); - if hit_ev_step_of(HIT_EV_LOAD, st) != 0 { return -1; } - rm_mode := hit_r32(st, HIT_ST_OFF_RM_MODE); - rr := hit_r32(st, HIT_ST_OFF_REG_ROLE); - mr := hit_r32(st, HIT_ST_OFF_RM_ROLE); - if rm_mode != 1 || rr != HIT_ROLE_DST || mr != HIT_ROLE_ADDR { return -1; } - rl := hit_role_reg_low(rr); - if rl != reg_low { return -1; } // 目标寄存器须与 load 模板 reg 角色一致 - cp : ., mut = pos; - e2_w8(buf, cp, hit_r32(st, HIT_ST_OFF_OP0)); cp = cp + 1; - op1 := hit_r32(st, HIT_ST_OFF_OP1); - if op1 != 0 { e2_w8(buf, cp, op1); cp = cp + 1; } - cp = cp + emit_modrm(buf, cp, 0, reg_low, 5); - e2_w32(buf, cp, 0); cp = cp + 4; - hit_pool_patch_add(pos, k); - return cp - pos; } +fn hit_ev_emit_pool_mov(buf: string, pos: int, reg_low: int, k: int) -> int: + st := alloc(HIT_STEP_REC) + if hit_ev_step_of(HIT_EV_LOAD, st) != 0: + return -1 + rm_mode := hit_r32(st, HIT_ST_OFF_RM_MODE) + rr := hit_r32(st, HIT_ST_OFF_REG_ROLE) + mr := hit_r32(st, HIT_ST_OFF_RM_ROLE) + if rm_mode != 1 || rr != HIT_ROLE_DST || mr != HIT_ROLE_ADDR: + return -1 + rl := hit_role_reg_low(rr) + if rl != reg_low: + return -1 + // 目标寄存器须与 load 模板 reg 角色一致 + cp : ., mut = pos + e2_w8(buf, cp, hit_r32(st, HIT_ST_OFF_OP0)) + cp = cp + 1 + op1 := hit_r32(st, HIT_ST_OFF_OP1) + if op1 != 0: + e2_w8(buf, cp, op1) + cp = cp + 1 + cp = cp + emit_modrm(buf, cp, 0, reg_low, 5) + e2_w32(buf, cp, 0) + cp = cp + 4 + hit_pool_patch_add(pos, k) + return cp - pos // 编码单条事件 → 字节(预检已过;此处仍防御性 -1)。 -fn hit_ev_emit_one(ev_i: int, buf: string, pos: int) -> int { - ev_id := hit_ev_id(ev_i); - d := hit_ev_dst(ev_i); - s1 := hit_ev_s1(ev_i); - s2 := hit_ev_s2(ev_i); - fl := hit_ev_flags(ev_i); - es := hit_event_lookup(ev_id); - if es < 0 { return -1; } - cls := hit_ev_class(ev_id, fl); - if cls < 0 { return -1; } - st := alloc(HIT_STEP_REC); - cp : ., mut = 0; - if cls == HIT_EV_CLS_POOL { +fn hit_ev_emit_one(ev_i: int, buf: string, pos: int) -> int: + ev_id := hit_ev_id(ev_i) + d := hit_ev_dst(ev_i) + s1 := hit_ev_s1(ev_i) + s2 := hit_ev_s2(ev_i) + fl := hit_ev_flags(ev_i) + es := hit_event_lookup(ev_id) + if es < 0: + return -1 + cls := hit_ev_class(ev_id, fl) + if cls < 0: + return -1 + st := alloc(HIT_STEP_REC) + cp : ., mut = 0 + if cls == HIT_EV_CLS_POOL: // 池载入:mov r10, [rip+池槽](load 模板字节 + rip 回填——M1 通道) - n := hit_ev_emit_pool_mov(buf, pos, hit_role_reg_low(HIT_ROLE_DST), s1); - if n < 0 { return -1; } - cp = cp + n; + n := hit_ev_emit_pool_mov(buf, pos, hit_role_reg_low(HIT_ROLE_DST), s1) + if n < 0: + return -1 + cp = cp + n // dest 回存走全局行 seam(表实例面:d 为全局行时原先写帧外伪偏移) - cp = cp + e2_st_var(buf, pos + cp, 10, d); - return cp; } - if hit_ev_proj_pick(es, cls, st) < 0 { return -1; } - rm_mode := hit_r32(st, HIT_ST_OFF_RM_MODE); - rr := hit_r32(st, HIT_ST_OFF_REG_ROLE); - mr := hit_r32(st, HIT_ST_OFF_RM_ROLE); - if cls == HIT_EV_CLS_JUMP { + cp = cp + e2_st_var(buf, pos + cp, 10, d) + return cp + if hit_ev_proj_pick(es, cls, st) < 0: + return -1 + rm_mode := hit_r32(st, HIT_ST_OFF_RM_MODE) + rr := hit_r32(st, HIT_ST_OFF_REG_ROLE) + mr := hit_r32(st, HIT_ST_OFF_RM_ROLE) + if cls == HIT_EV_CLS_JUMP: // E9 rel32(模板头)+ rel 登记(目标 = 事件序 s1——elf.cr 按位置表回填) - hd := hit_st_head(st, buf, pos + cp); - if hd < 0 { return -1; } - cp = cp + hd; - n2 := hit_st_rel_emit(st, buf, pos + cp, s1); - if n2 < 0 { return -1; } - cp = cp + n2; - return cp; } - if cls == HIT_EV_CLS_ALU { + hd := hit_st_head(st, buf, pos + cp) + if hd < 0: + return -1 + cp = cp + hd + n2 := hit_st_rel_emit(st, buf, pos + cp, s1) + if n2 < 0: + return -1 + cp = cp + n2 + return cp + if cls == HIT_EV_CLS_ALU: // 双寄存器累加形:rm = dst 累加器(首输入驻)、reg = src2 - r_acc := hit_role_reg(mr); // dst → 10 - r_sec := hit_role_reg(rr); // src2 → 11 - if r_acc < 0 || r_sec < 0 { return -1; } - if fl % 2 == 1 { + r_acc := hit_role_reg(mr) // dst → 10 + r_sec := hit_role_reg(rr) // src2 → 11 + if r_acc < 0 || r_sec < 0: + return -1 + if fl % 2 == 1: // 首输入 = 池:mov r10, [rip+池槽](load 模板字节;预检已验形态) - n3 := hit_ev_emit_pool_mov(buf, pos, hit_role_reg_low(mr), s1); - if n3 < 0 { return -1; } - cp = cp + n3; } - else { - cp = cp + e2_load_var(buf, pos + cp, r_acc, s1); } - cp = cp + e2_load_var(buf, pos + cp, r_sec, s2); + n3 := hit_ev_emit_pool_mov(buf, pos, hit_role_reg_low(mr), s1) + if n3 < 0: + return -1 + cp = cp + n3 + else: + cp = cp + e2_load_var(buf, pos + cp, r_acc, s1) + cp = cp + e2_load_var(buf, pos + cp, r_sec, s2) // 指令字节:prefix → rex → opcode 三段(v2 字段区——legacy 视区同源) - hd2 := hit_st_head(st, buf, pos + cp); - if hd2 < 0 { return -1; } - cp = cp + hd2; + hd2 := hit_st_head(st, buf, pos + cp) + if hd2 < 0: + return -1 + cp = cp + hd2 // modrm:mod=3(寄存器);reg/rm 低 3 位来自角色(src2→r11=3、dst→r10=2) - cp = cp + emit_modrm(buf, pos + cp, 3, hit_role_reg_low(rr), hit_role_reg_low(mr)); + cp = cp + emit_modrm(buf, pos + cp, 3, hit_role_reg_low(rr), hit_role_reg_low(mr)) // 结果回存(先读后写——dst 兼作操作数(add 反减中间值)时读先于写) - cp = cp + e2_st_var(buf, pos + cp, r_acc, d); - return cp; } - if cls == HIT_EV_CLS_IMM { + cp = cp + e2_st_var(buf, pos + cp, r_acc, d) + return cp + if cls == HIT_EV_CLS_IMM: // cst:/digit + [rbp+disp(auto)] + imm——rm = dst 槽、imm 值 = s1 原值 - hd3 := hit_st_head(st, buf, pos + cp); - if hd3 < 0 { return -1; } - cp = cp + hd3; + hd3 := hit_st_head(st, buf, pos + cp) + if hd3 < 0: + return -1 + cp = cp + hd3 n4 := hit_st_modrm_disp(st, buf, pos + cp, - hit_r32(st, HIT_ST_OFF_REG_DIGIT), g2_slot(d)); - if n4 < 0 { return -1; } - cp = cp + n4; - iv : ., mut = s1; - if hit_r32(st, HIT_ST_OFF_IMM_ROLE) == HIT_CODE_LIT { - iv = hit_r32(st, HIT_ST_OFF_IMM_LIT); } - n5 := hit_st_imm(st, buf, pos + cp, iv); - if n5 < 0 { return -1; } - cp = cp + n5; - return cp; } + hit_r32(st, HIT_ST_OFF_REG_DIGIT), g2_slot(d)) + if n4 < 0: + return -1 + cp = cp + n4 + iv : ., mut = s1 + if hit_r32(st, HIT_ST_OFF_IMM_ROLE) == HIT_CODE_LIT: + iv = hit_r32(st, HIT_ST_OFF_IMM_LIT) + n5 := hit_st_imm(st, buf, pos + cp, iv) + if n5 < 0: + return -1 + cp = cp + n5 + return cp // MEM:reg 角色(dst/val)→ r10(glue 寄存器对同 M1);rm = [rbp+disp 槽] - reg_lo := hit_role_reg_low(rr); - if reg_lo < 0 { return -1; } - r_val := hit_role_reg(rr); - if r_val < 0 { return -1; } - if rr == HIT_ROLE_DST { + reg_lo := hit_role_reg_low(rr) + if reg_lo < 0: + return -1 + r_val := hit_role_reg(rr) + if r_val < 0: + return -1 + if rr == HIT_ROLE_DST: // load:读 [addr槽] → dst(disp = addr 槽偏移——auto/1/4 按步字段) - hd4 := hit_st_head(st, buf, pos + cp); - if hd4 < 0 { return -1; } - cp = cp + hd4; - n6 := hit_st_modrm_disp(st, buf, pos + cp, reg_lo, g2_slot(s1)); - if n6 < 0 { return -1; } - cp = cp + n6; - cp = cp + e2_st_var(buf, pos + cp, r_val, d); - return cp; } - if rr == HIT_ROLE_VAL { + hd4 := hit_st_head(st, buf, pos + cp) + if hd4 < 0: + return -1 + cp = cp + hd4 + n6 := hit_st_modrm_disp(st, buf, pos + cp, reg_lo, g2_slot(s1)) + if n6 < 0: + return -1 + cp = cp + n6 + cp = cp + e2_st_var(buf, pos + cp, r_val, d) + return cp + if rr == HIT_ROLE_VAL: // store:写 [addr槽] ← val(val 槽值先载入角色寄存器) - cp = cp + e2_load_var(buf, pos + cp, r_val, s2); - hd5 := hit_st_head(st, buf, pos + cp); - if hd5 < 0 { return -1; } - cp = cp + hd5; - n7 := hit_st_modrm_disp(st, buf, pos + cp, reg_lo, g2_slot(s1)); - if n7 < 0 { return -1; } - cp = cp + n7; - return cp; } - return -1; } + cp = cp + e2_load_var(buf, pos + cp, r_val, s2) + hd5 := hit_st_head(st, buf, pos + cp) + if hd5 < 0: + return -1 + cp = cp + hd5 + n7 := hit_st_modrm_disp(st, buf, pos + cp, reg_lo, g2_slot(s1)) + if n7 < 0: + return -1 + cp = cp + n7 + return cp + return -1 // 表驱动单指令发射。与 emit_instr 同签名;返回写入字节数;-1 = 无事件/不支持。 // 消费 lower_to_core.cr 的事件流:0 事件 = 非子集指令(旧路径); // 有事件 = 预检整条 → 逐事件表投影发射(g_hit_tabled_count 计事件条数)。 -fn emit_instr_tabled(instr_idx: int, buf: string, pos: int) -> int { - cnt := hit_ev_map_cnt(instr_idx); - if cnt <= 0 { return -1; } - start := hit_ev_map_start(instr_idx); - e : ., mut = 0; - loop { - if e >= cnt { break; } - if hit_ev_preflight_ok(start + e) != 0 { +fn emit_instr_tabled(instr_idx: int, buf: string, pos: int) -> int: + cnt := hit_ev_map_cnt(instr_idx) + if cnt <= 0: + return -1 + start := hit_ev_map_start(instr_idx) + e : ., mut = 0 + loop: + if e >= cnt: + break + if hit_ev_preflight_ok(start + e) != 0: // 注入通道(测试专用):预检拒绝 = 文件事件无法经表发射——大声错误 // (corearch 于发射后按事件计数不符 exit 1——不静默落旧路径掩盖); // 真实降低路径 = 整条落旧路径(M1 混合模式,不半写)。 - if g_hit_inject_active != 0 { - print("error: HIT events: event "); - print_i(start + e); - print(" ("); print(hit_event_name(hit_event_lookup(hit_ev_id(start + e)))); - println(") not emittable (shape/operands)"); - } - return -1; } - e = e + 1; } - cp : ., mut = 0; - e2 : ., mut = 0; - loop { - if e2 >= cnt { break; } + if g_hit_inject_active != 0: + print("error: HIT events: event ") + print_i(start + e) + print(" (") + print(hit_event_name(hit_event_lookup(hit_ev_id(start + e)))) + println(") not emittable (shape/operands)") + return -1 + e = e + 1 + cp : ., mut = 0 + e2 : ., mut = 0 + loop: + if e2 >= cnt: + break // 事件序 → 字节位置(M2a Task 2:rel 回填表 kind 0 的目标解析表—— // 边发射边记;位置 = 事件首字节的绝对 buf 偏移) - hit_ev_pos_set(start + e2, pos + cp); - n := hit_ev_emit_one(start + e2, buf, pos + cp); - if n < 0 { return -1; } // 预检后不可达(防御) - cp = cp + n; - g_hit_tabled_count = g_hit_tabled_count + 1; - e2 = e2 + 1; } - return cp; } + hit_ev_pos_set(start + e2, pos + cp) + n := hit_ev_emit_one(start + e2, buf, pos + cp) + if n < 0: + return -1 + // 预检后不可达(防御) + cp = cp + n + g_hit_tabled_count = g_hit_tabled_count + 1 + e2 = e2 + 1 + return cp diff --git a/src/arch/x86_64/regalloc.cr b/src/arch/x86_64/regalloc.cr index 4a820403..e11c277a 100644 --- a/src/arch/x86_64/regalloc.cr +++ b/src/arch/x86_64/regalloc.cr @@ -19,14 +19,15 @@ // 守卫缺失时 accessor 对槽后区域越界读:条目表容量 ≥ 计数、alloc 零初始化 // → 全零槽 [ls=0, le=0] 与任何区间相交 → 误判共存返回 1(读穿缓冲则崩溃)。 // 输出 "coexist-oob-guard: <0|1>",r != 0 → 退出码 1(测试断言 rc + 数值)。 -fn inject_coexist_oob() -> int { - e1 := g_entry_count; - e2 := g_entry_count + 1; - r := entries_coexist(0, e1, e2); - print("coexist-oob-guard: "); println(int_str(r)); - if r != 0 { return 1; } - return 0; -} +fn inject_coexist_oob() -> int: + e1 := g_entry_count + e2 := g_entry_count + 1 + r := entries_coexist(0, e1, e2) + print("coexist-oob-guard: ") + println(int_str(r)) + if r != 0: + return 1 + return 0 // ===== Task 5 测试钩子(cir --check-regalloc 载体专用注入;真实构建路径 // 永不调用——注入只存在于 cir debug 分支,不触碰生产分配器行为)===== @@ -37,70 +38,68 @@ fn inject_coexist_oob() -> int { // 寄存器驻留(meta_remove_var——真实分配已覆盖时 append 伪造对会被既有对遮蔽, // 撤销使位置判定退化到 home/栈 seam),再置 home = 同一槽 7 → 规则 ① home 组 // 违反。撤销的 var 无 home 条目(home=-1)不参与 sweep,无侧伤。 -fn try_inject_home_conflict(func_i: int) -> int { - es := entry_start(func_i); - ec := entry_count(func_i); - if ec < 2 { return 0; } - e1i : ., mut = 0; - loop { - if e1i >= ec { break; } - e1 := es + e1i; - v1 := ent_var(e1); - if v1 < 0 { e1i = e1i + 1; continue; } - e2i : ., mut = e1i + 1; - loop { - if e2i >= ec { break; } - e2 := es + e2i; - v2 := ent_var(e2); - if v1 != v2 && entries_coexist(func_i, e1, e2) != 0 { - meta_remove_var(v1); - meta_remove_var(v2); - w32(g_ir_entries, e1 * ESZ_ENTRY + OFF_ENTRY_HOME, 7); - w32(g_ir_entries, e2 * ESZ_ENTRY + OFF_ENTRY_HOME, 7); - return 1; - } - e2i = e2i + 1; - } - e1i = e1i + 1; - } - return 0; -} +fn try_inject_home_conflict(func_i: int) -> int: + es := entry_start(func_i) + ec := entry_count(func_i) + if ec < 2: + return 0 + e1i : ., mut = 0 + loop: + if e1i >= ec: + break + e1 := es + e1i + v1 := ent_var(e1) + if v1 < 0: + e1i = e1i + 1 + continue + e2i : ., mut = e1i + 1 + loop: + if e2i >= ec: + break + e2 := es + e2i + v2 := ent_var(e2) + if v1 != v2 && entries_coexist(func_i, e1, e2) != 0: + meta_remove_var(v1) + meta_remove_var(v2) + w32(g_ir_entries, e1 * ESZ_ENTRY + OFF_ENTRY_HOME, 7) + w32(g_ir_entries, e2 * ESZ_ENTRY + OFF_ENTRY_HOME, 7) + return 1 + e2i = e2i + 1 + e1i = e1i + 1 + return 0 -fn inject_home_conflict() -> int { - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } - if try_inject_home_conflict(fi) != 0 { return 1; } - fi = fi + 1; - } - return 0; -} +fn inject_home_conflict() -> int: + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break + if try_inject_home_conflict(fi) != 0: + return 1 + fi = fi + 1 + return 0 // ── 元数据写侧辅助(CAG 真实分配后注入以改写真实输出为手段—— // append 首匹配语义会被既有对遮蔽,注入须原位改写/移除)── // 返回 var 的 reg 字段偏移(g_opt_meta 内;-1 = 无对)。与 instr.cr // get_reg_for_var 同布局(随迁后同进程——见判定区头注)。 -fn meta_reg_pair_off(var_idx: int) -> int { - mi : ., mut = 0; - loop { - if mi >= g_opt_meta_count { break; } - mo := mi * OPT_META_STRIDE; - if r32(g_opt_meta, mo) == OPT_KEY_REG_ASSIGN { - cnt := r32(g_opt_meta, mo + 8); - di : ., mut = 0; - loop { - if di >= cnt { break; } - if r32(g_opt_meta, mo + 12 + di * 8) == var_idx { - return mo + 16 + di * 8; - } - di = di + 1; - } - } - mi = mi + 1; - } - return -1; -} +fn meta_reg_pair_off(var_idx: int) -> int: + mi : ., mut = 0 + loop: + if mi >= g_opt_meta_count: + break + mo := mi * OPT_META_STRIDE + if r32(g_opt_meta, mo) == OPT_KEY_REG_ASSIGN: + cnt := r32(g_opt_meta, mo + 8) + di : ., mut = 0 + loop: + if di >= cnt: + break + if r32(g_opt_meta, mo + 12 + di * 8) == var_idx: + return mo + 16 + di * 8 + di = di + 1 + mi = mi + 1 + return -1 // ── 登记表配对辅助(双份同步纪律——内核完备 Task 3)── // 判定面输入 = 位置登记表(kern_loc_assign/clear/of,ent_kernel.cr);本文件 @@ -112,149 +111,162 @@ fn meta_reg_pair_off(var_idx: int) -> int { // phase 5(原语直写不经辅助函数——单独配对,见 alloc 区尾注记)。 // 条目的所属函数未知(var_idx = 全局 var id)→ 全表扫描(注入 = cir debug // 通道,低频小表;生产路径 = phase 5 段界扫描不经本辅助)。 -fn reg_assign_var_entries(var_idx: int, loc: int) { - e : ., mut = 0; - loop { - if e >= g_entry_count { break; } - if ent_var(e) == var_idx { kern_loc_assign(e, loc); } - e = e + 1; - } -} +fn reg_assign_var_entries(var_idx: int, loc: int): + e : ., mut = 0 + loop: + if e >= g_entry_count: + break + if ent_var(e) == var_idx: + kern_loc_assign(e, loc) + e = e + 1 -fn reg_clear_var_entries(var_idx: int) { - e : ., mut = 0; - loop { - if e >= g_entry_count { break; } - if ent_var(e) == var_idx { kern_loc_clear(e); } - e = e + 1; - } -} +fn reg_clear_var_entries(var_idx: int): + e : ., mut = 0 + loop: + if e >= g_entry_count: + break + if ent_var(e) == var_idx: + kern_loc_clear(e) + e = e + 1 // 强制 var → reg(已有对原位改写;无对追加——append 语义 = 首匹配生效, // 无对时追加必然生效) -fn meta_set_reg(var_idx: int, reg: int) { - po := meta_reg_pair_off(var_idx); - if po >= 0 { w32(g_opt_meta, po, reg); } - else { meta_append_reg_assign(var_idx, reg); } - reg_assign_var_entries(var_idx, reg); // 登记表配对(判定面同步) -} +fn meta_set_reg(var_idx: int, reg: int): + po := meta_reg_pair_off(var_idx) + if po >= 0: + w32(g_opt_meta, po, reg) + else: + meta_append_reg_assign(var_idx, reg) + reg_assign_var_entries(var_idx, reg) // 登记表配对(判定面同步) // 移除 var 的分配对(块内左移收拢;空块整体移除)——「撤销寄存器驻留」= // 位置判定退化为 home/栈(entries home=-1 → 不参与规则① sweep,无侧伤) -fn meta_remove_var(var_idx: int) { - mi : ., mut = 0; - loop { - if mi >= g_opt_meta_count { break; } - mo := mi * OPT_META_STRIDE; - if r32(g_opt_meta, mo) == OPT_KEY_REG_ASSIGN { - cnt := r32(g_opt_meta, mo + 8); - di : ., mut = 0; - loop { - if di >= cnt { break; } - if r32(g_opt_meta, mo + 12 + di * 8) == var_idx { +fn meta_remove_var(var_idx: int): + mi : ., mut = 0 + loop: + if mi >= g_opt_meta_count: + break + mo := mi * OPT_META_STRIDE + if r32(g_opt_meta, mo) == OPT_KEY_REG_ASSIGN: + cnt := r32(g_opt_meta, mo + 8) + di : ., mut = 0 + loop: + if di >= cnt: + break + if r32(g_opt_meta, mo + 12 + di * 8) == var_idx: // 移除第 di 对:后续对左移 8B(数据区 = count@+8 + 对@+12) - sh : ., mut = di; - loop { if sh + 1 >= cnt { break; } - w32(g_opt_meta, mo + 12 + sh * 8, r32(g_opt_meta, mo + 12 + (sh + 1) * 8)); - w32(g_opt_meta, mo + 16 + sh * 8, r32(g_opt_meta, mo + 16 + (sh + 1) * 8)); - sh = sh + 1; } - cnt = cnt - 1; - w32(g_opt_meta, mo + 8, cnt); - w32(g_opt_meta, mo + 4, 4 + cnt * 8); - if cnt == 0 { + sh : ., mut = di + loop: + if sh + 1 >= cnt: + break + w32(g_opt_meta, mo + 12 + sh * 8, r32(g_opt_meta, mo + 12 + (sh + 1) * 8)) + w32(g_opt_meta, mo + 16 + sh * 8, r32(g_opt_meta, mo + 16 + (sh + 1) * 8)) + sh = sh + 1 + cnt = cnt - 1 + w32(g_opt_meta, mo + 8, cnt) + w32(g_opt_meta, mo + 4, 4 + cnt * 8) + if cnt == 0: // 空块整体移除:后续块左移一个 OPT_META_STRIDE - mj : ., mut = mi; - loop { if mj + 1 >= g_opt_meta_count { break; } - so := (mj + 1) * OPT_META_STRIDE; - kk : ., mut = 0; - loop { if kk >= OPT_META_STRIDE / 8 { break; } - w64(g_opt_meta, mj * OPT_META_STRIDE + kk * 8, r64(g_opt_meta, so + kk * 8)); - kk = kk + 1; } - mj = mj + 1; } - g_opt_meta_count = g_opt_meta_count - 1; - } - reg_clear_var_entries(var_idx); // 登记表配对(判定面同步) - return; - } - di = di + 1; - } - } - mi = mi + 1; - } -} + mj : ., mut = mi + loop: + if mj + 1 >= g_opt_meta_count: + break + so := (mj + 1) * OPT_META_STRIDE + kk : ., mut = 0 + loop: + if kk >= OPT_META_STRIDE / 8: + break + w64(g_opt_meta, mj * OPT_META_STRIDE + kk * 8, r64(g_opt_meta, so + kk * 8)) + kk = kk + 1 + mj = mj + 1 + g_opt_meta_count = g_opt_meta_count - 1 + reg_clear_var_entries(var_idx) // 登记表配对(判定面同步) + return + di = di + 1 + mi = mi + 1 // REG_ASSIGN 对总数(--check-regalloc 看门狗行;rc>0 = 寄存器真实分配实证) -fn meta_reg_assign_total() -> int { - tot : ., mut = 0; - mi : ., mut = 0; - loop { - if mi >= g_opt_meta_count { break; } - mo := mi * OPT_META_STRIDE; - if r32(g_opt_meta, mo) == OPT_KEY_REG_ASSIGN { tot = tot + r32(g_opt_meta, mo + 8); } - mi = mi + 1; - } - return tot; -} +fn meta_reg_assign_total() -> int: + tot : ., mut = 0 + mi : ., mut = 0 + loop: + if mi >= g_opt_meta_count: + break + mo := mi * OPT_META_STRIDE + if r32(g_opt_meta, mo) == OPT_KEY_REG_ASSIGN: + tot = tot + r32(g_opt_meta, mo + 8) + mi = mi + 1 + return tot // 追加一条 OPT_KEY_REG_ASSIGN 记录(格式同 alloc_registers 写侧;首个匹配即 // 生效——故伪造目标须是真实分配未覆盖的 var,后端 get_reg_for_var 同语义) -fn meta_append_reg_assign(var_idx: int, reg: int) { - grow_opt_meta(g_opt_meta_count + 1); - eo := g_opt_meta_count * OPT_META_STRIDE; - store8(g_opt_meta, eo, 0); store8(g_opt_meta, eo + 1, 0); - store8(g_opt_meta, eo + 2, 0); store8(g_opt_meta, eo + 3, 0); // OPT_KEY_REG_ASSIGN=0 - dl : ., mut = 4 + 8; - store8(g_opt_meta, eo + 4, dl % 256); store8(g_opt_meta, eo + 5, (dl / 256) % 256); - store8(g_opt_meta, eo + 6, (dl / 65536) % 256); store8(g_opt_meta, eo + 7, (dl / 16777216) % 256); - store8(g_opt_meta, eo + 8, 1); store8(g_opt_meta, eo + 9, 0); - store8(g_opt_meta, eo + 10, 0); store8(g_opt_meta, eo + 11, 0); // count = 1 - store8(g_opt_meta, eo + 12, var_idx % 256); store8(g_opt_meta, eo + 13, (var_idx / 256) % 256); - store8(g_opt_meta, eo + 14, (var_idx / 65536) % 256); store8(g_opt_meta, eo + 15, (var_idx / 16777216) % 256); - store8(g_opt_meta, eo + 16, reg % 256); store8(g_opt_meta, eo + 17, (reg / 256) % 256); - store8(g_opt_meta, eo + 18, (reg / 65536) % 256); store8(g_opt_meta, eo + 19, (reg / 16777216) % 256); - g_opt_meta_count = g_opt_meta_count + 1; -} +fn meta_append_reg_assign(var_idx: int, reg: int): + grow_opt_meta(g_opt_meta_count + 1) + eo := g_opt_meta_count * OPT_META_STRIDE + store8(g_opt_meta, eo, 0) + store8(g_opt_meta, eo + 1, 0) + store8(g_opt_meta, eo + 2, 0) + store8(g_opt_meta, eo + 3, 0) // OPT_KEY_REG_ASSIGN=0 + dl : ., mut = 4 + 8 + store8(g_opt_meta, eo + 4, dl % 256) + store8(g_opt_meta, eo + 5, (dl / 256) % 256) + store8(g_opt_meta, eo + 6, (dl / 65536) % 256) + store8(g_opt_meta, eo + 7, (dl / 16777216) % 256) + store8(g_opt_meta, eo + 8, 1) + store8(g_opt_meta, eo + 9, 0) + store8(g_opt_meta, eo + 10, 0) + store8(g_opt_meta, eo + 11, 0) // count = 1 + store8(g_opt_meta, eo + 12, var_idx % 256) + store8(g_opt_meta, eo + 13, (var_idx / 256) % 256) + store8(g_opt_meta, eo + 14, (var_idx / 65536) % 256) + store8(g_opt_meta, eo + 15, (var_idx / 16777216) % 256) + store8(g_opt_meta, eo + 16, reg % 256) + store8(g_opt_meta, eo + 17, (reg / 256) % 256) + store8(g_opt_meta, eo + 18, (reg / 65536) % 256) + store8(g_opt_meta, eo + 19, (reg / 16777216) % 256) + g_opt_meta_count = g_opt_meta_count + 1 // 注入 ①-寄存器组冲突:找一对不同 var 的共存条目 (e1, e2),把两 var 的 // REG_ASSIGN 原位改写为同一 reg 3(已有对改写 / 无对追加——真实分配覆盖与否 // 均确定生效;共存条目同组同寄存器 → 规则 ① 寄存器组违反)。 // 注入仅存在于 cir debug 分支(真实构建路径永不注入)。 -fn try_inject_reg_conflict(func_i: int) -> int { - es := entry_start(func_i); - ec := entry_count(func_i); - if ec < 2 { return 0; } - e1i : ., mut = 0; - loop { - if e1i >= ec { break; } - e1 := es + e1i; - v1 := ent_var(e1); - if v1 < 0 { e1i = e1i + 1; continue; } - e2i : ., mut = e1i + 1; - loop { - if e2i >= ec { break; } - e2 := es + e2i; - v2 := ent_var(e2); - if v1 != v2 && entries_coexist(func_i, e1, e2) != 0 { - meta_set_reg(v1, 3); - meta_set_reg(v2, 3); - return 1; - } - e2i = e2i + 1; - } - e1i = e1i + 1; - } - return 0; -} +fn try_inject_reg_conflict(func_i: int) -> int: + es := entry_start(func_i) + ec := entry_count(func_i) + if ec < 2: + return 0 + e1i : ., mut = 0 + loop: + if e1i >= ec: + break + e1 := es + e1i + v1 := ent_var(e1) + if v1 < 0: + e1i = e1i + 1 + continue + e2i : ., mut = e1i + 1 + loop: + if e2i >= ec: + break + e2 := es + e2i + v2 := ent_var(e2) + if v1 != v2 && entries_coexist(func_i, e1, e2) != 0: + meta_set_reg(v1, 3) + meta_set_reg(v2, 3) + return 1 + e2i = e2i + 1 + e1i = e1i + 1 + return 0 -fn inject_reg_conflict() -> int { - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } - if try_inject_reg_conflict(fi) != 0 { return 1; } - fi = fi + 1; - } - return 0; -} +fn inject_reg_conflict() -> int: + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break + if try_inject_reg_conflict(fi) != 0: + return 1 + fi = fi + 1 + return 0 // 注入 ②-读点空洞:找 var——其最后一个版本条目(def ≥ 0 中 def 最大) // live_end > def(定值后仍有读)——把该 var 置为寄存器驻留并把该版本 live_end @@ -262,73 +274,68 @@ fn inject_reg_conflict() -> int { // 真实分配下:目标 var 已被分配 → 保持其原 reg(规则① 零扰动)直接截断即红; // 未分配(rc=0 时代/栈驻留 var)→ 强制 reg 3——先把与目标共存且已分配的 var // 全部撤销(防强制 reg 引发规则① 侧伤;撤销 var 无位置参与 sweep,无新违反)。 -fn try_inject_read_gap(func_i: int) -> int { - vc := r64(g_ir_func_var_count, func_i * 8); - vs := r64(g_ir_func_var_start, func_i * 8); - es := entry_start(func_i); - ec := entry_count(func_i); - lv : ., mut = 0; - loop { - if lv >= vc { break; } - gv := vs + lv; +fn try_inject_read_gap(func_i: int) -> int: + vc := r64(g_ir_func_var_count, func_i * 8) + vs := r64(g_ir_func_var_start, func_i * 8) + es := entry_start(func_i) + ec := entry_count(func_i) + lv : ., mut = 0 + loop: + if lv >= vc: + break + gv := vs + lv // 该 var 最后一条 def ≥ 0 条目(表内定值点升序 → 末条即 def 最大) - last : ., mut = -1; - ei : ., mut = 0; - loop { - if ei >= ec { break; } - e := es + ei; - if ent_var(e) == gv && ent_def(e) >= 0 { last = e; } - ei = ei + 1; - } - if last >= 0 && ent_live_end(last) > ent_def(last) { + last : ., mut = -1 + ei : ., mut = 0 + loop: + if ei >= ec: + break + e := es + ei + if ent_var(e) == gv && ent_def(e) >= 0: + last = e + ei = ei + 1 + if last >= 0 && ent_live_end(last) > ent_def(last): // 探针 = 读 meta_reg_for_var(内核完备 Task 3 后 = 登记表读——探针 // 与 verify 读同一判定输入通道——单真源选择,理由注记:registry 由 // 实例配对写点(alloc phase 5 + meta_set_reg/meta_remove_var)保持 // 与 g_opt_meta 同步——本注入的撤销/强制驻留经配对辅助,探针读 = // g_opt_meta 的一致视图,无需实例侧私有直扫) - if meta_reg_for_var(gv) < 0 { + if meta_reg_for_var(gv) < 0: // 强制驻留路径:撤销与 gv 任何版本条目共存的已分配 var - ej : ., mut = 0; - loop { - if ej >= ec { break; } - e2 := es + ej; - v2 := ent_var(e2); - if v2 != gv && meta_reg_for_var(v2) >= 0 { - ek : ., mut = 0; - loop { - if ek >= ec { break; } - if ent_var(es + ek) == gv && - entries_coexist(func_i, es + ek, e2) != 0 { - meta_remove_var(v2); - break; - } - ek = ek + 1; - } - } - ej = ej + 1; - } - meta_set_reg(gv, 3); - } - w32(g_ir_entries, last * ESZ_ENTRY + OFF_ENTRY_LE, ent_def(last)); - return 1; - } - lv = lv + 1; - } - return 0; -} + ej : ., mut = 0 + loop: + if ej >= ec: + break + e2 := es + ej + v2 := ent_var(e2) + if v2 != gv && meta_reg_for_var(v2) >= 0: + ek : ., mut = 0 + loop: + if ek >= ec: + break + if ent_var(es + ek) == gv && entries_coexist(func_i, es + ek, e2) != 0: + meta_remove_var(v2) + break + ek = ek + 1 + ej = ej + 1 + meta_set_reg(gv, 3) + w32(g_ir_entries, last * ESZ_ENTRY + OFF_ENTRY_LE, ent_def(last)) + return 1 + lv = lv + 1 + return 0 -fn inject_read_gap() -> int { +fn inject_read_gap() -> int: // 函数迭代序 = 1..n-1 再 0:优先注入非 func 0 目标(F1 回归前提——规则 ② 的 // 坐标失明面只在 ist > 0 的函数上显形)。GC 批 2 后 _arena 等每函数首条 // def 使 func 0 恒可注入——若仍从 0 扫起,注入恒落 main,非 func 0 面失守。 - fi : ., mut = 1; - loop { - if fi >= g_ir_func_count { break; } - if try_inject_read_gap(fi) != 0 { return 1; } - fi = fi + 1; - } - return try_inject_read_gap(0); -} + fi : ., mut = 1 + loop: + if fi >= g_ir_func_count: + break + if try_inject_read_gap(fi) != 0: + return 1 + fi = fi + 1 + return try_inject_read_gap(0) // ------------------------------------------------------------------ // Register allocation — CAG 上下文贪心(docs/regalloc-cache-mapping.md §五 定案) @@ -393,198 +400,215 @@ fn inject_read_gap() -> int { // 同文字区间模型——条件定值携带语义的判定侧同步 = 该升级点前的一贯挂账, // 回归语义锚 = test_live_ranges COND_DEF_CARRY 源,见报告 cag-report.md)。 -fn label_pos_of(id: int, lab_id: string, lab_ps: string, n: int) -> int { - i : ., mut = 0; - loop { - if i >= n { break; } - if r64(lab_id, i * 8) == id { return r64(lab_ps, i * 8); } - i = i + 1; - } - return -1; -} +fn label_pos_of(id: int, lab_id: string, lab_ps: string, n: int) -> int: + i : ., mut = 0 + loop: + if i >= n: + break + if r64(lab_id, i * 8) == id: + return r64(lab_ps, i * 8) + i = i + 1 + return -1 -fn alloc_registers() { - if g_opt_level < 1 { return; } +fn alloc_registers(): + if g_opt_level < 1: + return // v6 数据基础:存在区间表先行(尾部重建版本条目表——判定消费同源数据) - compute_live_ranges(); - MAX_REGS : int = 5; + compute_live_ranges() + MAX_REGS : int = 5 // callee-saved 物理寄存器(rbx, r12-r15;x86 枚举号,e2_mov/e2_ld REX 编码) - reg_phys : string, mut = alloc(5 * 8); - w64(reg_phys, 0, 3); w64(reg_phys, 8, 12); - w64(reg_phys, 16, 13); w64(reg_phys, 24, 14); w64(reg_phys, 32, 15); - 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); - 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); - if vc <= 0 || ic <= 0 { fi = fi + 1; continue; } + reg_phys : string, mut = alloc(5 * 8) + w64(reg_phys, 0, 3) + w64(reg_phys, 8, 12) + w64(reg_phys, 16, 13) + w64(reg_phys, 24, 14) + w64(reg_phys, 32, 15) + 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) + 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) + if vc <= 0 || ic <= 0: + fi = fi + 1 + continue // ── 阶段 1:门控扫描(并行 hazard 标志)── - haz_const : string, mut = alloc(vc * 8); // IR_CONST dest(e2_li 写路径) - haz_ref : string, mut = alloc(vc * 8); // IR_REF s1(槽地址泄漏) - haz_i2f : string, mut = alloc(vc * 8); // IR_I2F s1(sd_cvt 内存源) - haz_dyn : string, mut = alloc(vc * 8); // IR_DYN_*(16B 双槽布局) - haz_dex : string, mut = alloc(vc * 8); // ti==TI_DEX/S 指令引用 - iz : ., mut = 0; - loop { - if iz >= vc { break; } - w64(haz_const, iz * 8, 0); w64(haz_ref, iz * 8, 0); w64(haz_i2f, iz * 8, 0); - w64(haz_dyn, iz * 8, 0); w64(haz_dex, iz * 8, 0); - iz = iz + 1; - } - 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); - if d >= vs && d < vs + vc { - dl := d - vs; - if op == IR_CONST { w64(haz_const, dl * 8, 1); } - if op == IR_DYN_PACK || op == IR_DYN_TAG || op == IR_DYN_VAL || - op == IR_DYN_DISPATCH { w64(haz_dyn, dl * 8, 1); } - } - if op == IR_REF && s1 >= vs && s1 < vs + vc { w64(haz_ref, (s1 - vs) * 8, 1); } - if op == IR_I2F && s1 >= vs && s1 < vs + vc { w64(haz_i2f, (s1 - vs) * 8, 1); } - if op == IR_DYN_PACK || op == IR_DYN_TAG || op == IR_DYN_VAL || - op == IR_DYN_DISPATCH { - if s1 >= vs && s1 < vs + vc { w64(haz_dyn, (s1 - vs) * 8, 1); } - if s2 >= vs && s2 < vs + vc { w64(haz_dyn, (s2 - vs) * 8, 1); } - } - tk := iri_tk(inst); - if tk == TI_DEX || tk == TI_DEX_S { - if d >= vs && d < vs + vc { w64(haz_dex, (d - vs) * 8, 1); } - if s1 >= vs && s1 < vs + vc { w64(haz_dex, (s1 - vs) * 8, 1); } - if s2 >= vs && s2 < vs + vc { w64(haz_dex, (s2 - vs) * 8, 1); } - } - ii = ii + 1; - } + haz_const : string, mut = alloc(vc * 8) // IR_CONST dest(e2_li 写路径) + haz_ref : string, mut = alloc(vc * 8) // IR_REF s1(槽地址泄漏) + haz_i2f : string, mut = alloc(vc * 8) // IR_I2F s1(sd_cvt 内存源) + haz_dyn : string, mut = alloc(vc * 8) // IR_DYN_*(16B 双槽布局) + haz_dex : string, mut = alloc(vc * 8) // ti==TI_DEX/S 指令引用 + iz : ., mut = 0 + loop: + if iz >= vc: + break + w64(haz_const, iz * 8, 0) + w64(haz_ref, iz * 8, 0) + w64(haz_i2f, iz * 8, 0) + w64(haz_dyn, iz * 8, 0) + w64(haz_dex, iz * 8, 0) + iz = iz + 1 + 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) + if d >= vs && d < vs + vc: + dl := d - vs + if op == IR_CONST: + w64(haz_const, dl * 8, 1) + if op == IR_DYN_PACK || op == IR_DYN_TAG || op == IR_DYN_VAL || op == IR_DYN_DISPATCH: + w64(haz_dyn, dl * 8, 1) + if op == IR_REF && s1 >= vs && s1 < vs + vc: + w64(haz_ref, (s1 - vs) * 8, 1) + if op == IR_I2F && s1 >= vs && s1 < vs + vc: + w64(haz_i2f, (s1 - vs) * 8, 1) + if op == IR_DYN_PACK || op == IR_DYN_TAG || op == IR_DYN_VAL || op == IR_DYN_DISPATCH: + if s1 >= vs && s1 < vs + vc: + w64(haz_dyn, (s1 - vs) * 8, 1) + if s2 >= vs && s2 < vs + vc: + w64(haz_dyn, (s2 - vs) * 8, 1) + tk := iri_tk(inst) + if tk == TI_DEX || tk == TI_DEX_S: + if d >= vs && d < vs + vc: + w64(haz_dex, (d - vs) * 8, 1) + if s1 >= vs && s1 < vs + vc: + w64(haz_dex, (s1 - vs) * 8, 1) + if s2 >= vs && s2 < vs + vc: + w64(haz_dex, (s2 - vs) * 8, 1) + ii = ii + 1 // ── 阶段 2:回边探测 + 携带值标记(region 生命周期上下文)── - ln : ., mut = 0; - ii = 0; - loop { if ii >= ic { break; } - if iri_op(ist + ii) == IR_LABEL { if iri_s1(ist + ii) >= 0 { ln = ln + 1; } } - ii = ii + 1; - } - lab_id : string, mut = alloc(ln * 8); - lab_ps : string, mut = alloc(ln * 8); - li : ., mut = 0; - ii = 0; - loop { - if ii >= ic { break; } - if iri_op(ist + ii) == IR_LABEL && iri_s1(ist + ii) >= 0 { - w64(lab_id, li * 8, iri_s1(ist + ii)); - w64(lab_ps, li * 8, ii); - li = li + 1; - } - ii = ii + 1; - } + ln : ., mut = 0 + ii = 0 + loop: + if ii >= ic: + break + if iri_op(ist + ii) == IR_LABEL: + if iri_s1(ist + ii) >= 0: + ln = ln + 1 + ii = ii + 1 + lab_id : string, mut = alloc(ln * 8) + lab_ps : string, mut = alloc(ln * 8) + li : ., mut = 0 + ii = 0 + loop: + if ii >= ic: + break + if iri_op(ist + ii) == IR_LABEL && iri_s1(ist + ii) >= 0: + w64(lab_id, li * 8, iri_s1(ist + ii)) + w64(lab_ps, li * 8, ii) + li = li + 1 + ii = ii + 1 // 回边 span 收集(16B {label_pos, branch_pos};上限 = 指令数) - bt : string, mut = alloc(ic * 16); - bn : ., mut = 0; - has_loop : ., mut = 0; - ii = 0; - loop { - if ii >= ic { break; } - inst := ist + ii; - op := iri_op(inst); - if op == IR_JUMP { - tp := label_pos_of(iri_s1(inst), lab_id, lab_ps, ln); - if tp >= 0 && tp < ii { - w64(bt, bn * 16, tp); w64(bt, bn * 16 + 8, ii); - bn = bn + 1; has_loop = 1; - } - } else if op == IR_BRANCH { - tp := label_pos_of(iri_s2(inst), lab_id, lab_ps, ln); - if tp >= 0 && tp < ii { - w64(bt, bn * 16, tp); w64(bt, bn * 16 + 8, ii); - bn = bn + 1; has_loop = 1; - } - tp = label_pos_of(iri_s3(inst), lab_id, lab_ps, ln); - if tp >= 0 && tp < ii { - w64(bt, bn * 16, tp); w64(bt, bn * 16 + 8, ii); - bn = bn + 1; has_loop = 1; - } - } - ii = ii + 1; - } - car : string, mut = alloc(vc * 8); - iz = 0; - loop { if iz >= vc { break; } w64(car, iz * 8, 0); iz = iz + 1; } - if has_loop != 0 { + bt : string, mut = alloc(ic * 16) + bn : ., mut = 0 + has_loop : ., mut = 0 + ii = 0 + loop: + if ii >= ic: + break + inst := ist + ii + op := iri_op(inst) + if op == IR_JUMP: + tp := label_pos_of(iri_s1(inst), lab_id, lab_ps, ln) + if tp >= 0 && tp < ii: + w64(bt, bn * 16, tp) + w64(bt, bn * 16 + 8, ii) + bn = bn + 1 + has_loop = 1 + else if op == IR_BRANCH: + tp := label_pos_of(iri_s2(inst), lab_id, lab_ps, ln) + if tp >= 0 && tp < ii: + w64(bt, bn * 16, tp) + w64(bt, bn * 16 + 8, ii) + bn = bn + 1 + has_loop = 1 + tp = label_pos_of(iri_s3(inst), lab_id, lab_ps, ln) + if tp >= 0 && tp < ii: + w64(bt, bn * 16, tp) + w64(bt, bn * 16 + 8, ii) + bn = bn + 1 + has_loop = 1 + ii = ii + 1 + car : string, mut = alloc(vc * 8) + iz = 0 + loop: + if iz >= vc: + break + w64(car, iz * 8, 0) + iz = iz + 1 + if has_loop != 0: // span 内逐指令扫:var 的 span 内首引用若为读形式 → 值跨回边存活 // (携带);定值形式(dest / STORE-s1)首引用且每轮必执行 → 每轮 // 刷新,不携带。状态:0 未见 / 1 首引用 = 定值 / 2 首引用 = 读。 // 条件定值健全化(评审 Critical):首引用为定值 d 但 d 可被 span 内 // 条件分支跳过(仍在 span 继续循环)→ 未必每轮刷新 → 同读形式按 // 携带处理(差分标记 + 前缀累计见下)。 - st : string, mut = alloc(vc * 8); - st_def : string, mut = alloc(vc * 8); // state-1 var 的定值位置 - skp : string, mut = alloc((ic + 2) * 8); // 可跳过位置差分(span 局部序) - bi : ., mut = 0; - loop { - if bi >= bn { break; } - t0 := r64(bt, bi * 16); - b0 := r64(bt, bi * 16 + 8); - iz = 0; - loop { - if iz >= vc { break; } - w64(st, iz * 8, 0); - w64(st_def, iz * 8, -1); - iz = iz + 1; - } - pp : ., mut = t0; - loop { - if pp > b0 { break; } - inst := ist + pp; - op := iri_op(inst); - d := iri_dest(inst); s1 := iri_s1(inst); s2 := iri_s2(inst); - if d >= vs && d < vs + vc { - lvd := d - vs; - if r64(st, lvd * 8) == 0 { + st : string, mut = alloc(vc * 8) + st_def : string, mut = alloc(vc * 8) // state-1 var 的定值位置 + skp : string, mut = alloc((ic + 2) * 8) // 可跳过位置差分(span 局部序) + bi : ., mut = 0 + loop: + if bi >= bn: + break + t0 := r64(bt, bi * 16) + b0 := r64(bt, bi * 16 + 8) + iz = 0 + loop: + if iz >= vc: + break + w64(st, iz * 8, 0) + w64(st_def, iz * 8, -1) + iz = iz + 1 + pp : ., mut = t0 + loop: + if pp > b0: + break + inst := ist + pp + op := iri_op(inst) + d := iri_dest(inst) + s1 := iri_s1(inst) + s2 := iri_s2(inst) + if d >= vs && d < vs + vc: + lvd := d - vs + if r64(st, lvd * 8) == 0: // dest 定值同指令自读(s1/s2 == d):读先于写,该读 // 可能取上一轮值 → 按读首引用(携带)处理 - if s1 == d || s2 == d { - w64(st, lvd * 8, 2); - w64(car, lvd * 8, 1); - } else { - w64(st, lvd * 8, 1); - w64(st_def, lvd * 8, pp); - } - } - } - if op == IR_STORE && s1 >= vs && s1 < vs + vc { - lvs := s1 - vs; - if r64(st, lvs * 8) == 0 { - if s2 == s1 { - w64(st, lvs * 8, 2); - w64(car, lvs * 8, 1); - } else { - w64(st, lvs * 8, 1); - w64(st_def, lvs * 8, pp); - } - } - } - if s1 >= vs && s1 < vs + vc && op != IR_STORE { - lv1 := s1 - vs; - if r64(st, lv1 * 8) == 0 { - w64(st, lv1 * 8, 2); - w64(car, lv1 * 8, 1); - } - } - if s2 >= vs && s2 < vs + vc { - lv2 := s2 - vs; - if r64(st, lv2 * 8) == 0 { - w64(st, lv2 * 8, 2); - w64(car, lv2 * 8, 1); - } - } - pp = pp + 1; - } + if s1 == d || s2 == d: + w64(st, lvd * 8, 2) + w64(car, lvd * 8, 1) + else: + w64(st, lvd * 8, 1) + w64(st_def, lvd * 8, pp) + if op == IR_STORE && s1 >= vs && s1 < vs + vc: + lvs := s1 - vs + if r64(st, lvs * 8) == 0: + if s2 == s1: + w64(st, lvs * 8, 2) + w64(car, lvs * 8, 1) + else: + w64(st, lvs * 8, 1) + w64(st_def, lvs * 8, pp) + if s1 >= vs && s1 < vs + vc && op != IR_STORE: + lv1 := s1 - vs + if r64(st, lv1 * 8) == 0: + w64(st, lv1 * 8, 2) + w64(car, lv1 * 8, 1) + if s2 >= vs && s2 < vs + vc: + lv2 := s2 - vs + if r64(st, lv2 * 8) == 0: + w64(st, lv2 * 8, 2) + w64(car, lv2 * 8, 1) + pp = pp + 1 // 条件定值健全化——差分标记:BRANCH(pp)的 forward 目标 // t ∈ (pp, b0] ⇒ 位置 (pp, t) 可被跳过且循环仍继续(区间 // [pp+1, t−1] 覆盖 +1,终点 t 处 −1);前缀累计 > 0 ⟺ 该位置 @@ -600,170 +624,183 @@ fn alloc_registers() { // (pp→t) 同样生成 [pp+1, t−1] 差分:跳过仍继续循环的路径 // 等价(continue 前向形态同理;回跳 continue/break 外跳因 // 目标 ≤ pp 或 > b0 不计)。over-mark 只损利用率、方向安全。 - zz : ., mut = 0; - spn := b0 - t0 + 1; - loop { if zz >= spn { break; } w64(skp, zz * 8, 0); zz = zz + 1; } - pp = t0; - loop { - if pp > b0 { break; } - if iri_op(ist + pp) == IR_BRANCH { - t2 := label_pos_of(iri_s2(ist + pp), lab_id, lab_ps, ln); - t3 := label_pos_of(iri_s3(ist + pp), lab_id, lab_ps, ln); - if t2 > pp && t2 <= b0 { - w64(skp, (pp + 1 - t0) * 8, r64(skp, (pp + 1 - t0) * 8) + 1); - w64(skp, (t2 - t0) * 8, r64(skp, (t2 - t0) * 8) - 1); - } - if t3 > pp && t3 <= b0 { - w64(skp, (pp + 1 - t0) * 8, r64(skp, (pp + 1 - t0) * 8) + 1); - w64(skp, (t3 - t0) * 8, r64(skp, (t3 - t0) * 8) - 1); - } - } else if iri_op(ist + pp) == IR_JUMP { - t1 := label_pos_of(iri_s1(ist + pp), lab_id, lab_ps, ln); - if t1 > pp && t1 <= b0 { - w64(skp, (pp + 1 - t0) * 8, r64(skp, (pp + 1 - t0) * 8) + 1); - w64(skp, (t1 - t0) * 8, r64(skp, (t1 - t0) * 8) - 1); - } - } - pp = pp + 1; - } + zz : ., mut = 0 + spn := b0 - t0 + 1 + loop: + if zz >= spn: + break + w64(skp, zz * 8, 0) + zz = zz + 1 + pp = t0 + loop: + if pp > b0: + break + if iri_op(ist + pp) == IR_BRANCH: + t2 := label_pos_of(iri_s2(ist + pp), lab_id, lab_ps, ln) + t3 := label_pos_of(iri_s3(ist + pp), lab_id, lab_ps, ln) + if t2 > pp && t2 <= b0: + w64(skp, (pp + 1 - t0) * 8, r64(skp, (pp + 1 - t0) * 8) + 1) + w64(skp, (t2 - t0) * 8, r64(skp, (t2 - t0) * 8) - 1) + if t3 > pp && t3 <= b0: + w64(skp, (pp + 1 - t0) * 8, r64(skp, (pp + 1 - t0) * 8) + 1) + w64(skp, (t3 - t0) * 8, r64(skp, (t3 - t0) * 8) - 1) + else if iri_op(ist + pp) == IR_JUMP: + t1 := label_pos_of(iri_s1(ist + pp), lab_id, lab_ps, ln) + if t1 > pp && t1 <= b0: + w64(skp, (pp + 1 - t0) * 8, r64(skp, (pp + 1 - t0) * 8) + 1) + w64(skp, (t1 - t0) * 8, r64(skp, (t1 - t0) * 8) - 1) + pp = pp + 1 // 前缀累计:skp[p−t0] > 0 ⟺ 位置 p 可被某条件分支跳过 - acc : ., mut = 0; - pp = t0; - loop { - if pp > b0 { break; } - acc = acc + r64(skp, (pp - t0) * 8); - if acc != 0 { w64(skp, (pp - t0) * 8, 1); } - else { w64(skp, (pp - t0) * 8, 0); } - pp = pp + 1; - } + acc : ., mut = 0 + pp = t0 + loop: + if pp > b0: + break + acc = acc + r64(skp, (pp - t0) * 8) + if acc != 0: + w64(skp, (pp - t0) * 8, 1) + else: + w64(skp, (pp - t0) * 8, 0) + pp = pp + 1 // state-1(首引用 = 定值)var:定值点可被跳过 → 条件定值, // 每轮未必刷新 → 旧值跨回边存活 → 携带(窗口扩至整函数) - iz = 0; - loop { - if iz >= vc { break; } - if r64(st, iz * 8) == 1 { - dd := r64(st_def, iz * 8); - if dd >= t0 && r64(skp, (dd - t0) * 8) != 0 { - w64(car, iz * 8, 1); - } - } - iz = iz + 1; - } - bi = bi + 1; - } - } + iz = 0 + loop: + if iz >= vc: + break + if r64(st, iz * 8) == 1: + dd := r64(st_def, iz * 8) + if dd >= t0 && r64(skp, (dd - t0) * 8) != 0: + w64(car, iz * 8, 1) + iz = iz + 1 + bi = bi + 1 // ── 阶段 3:候选构建(窗口 = [first_ref,last_ref] + 上下文修正)── - var_reg : string, mut = alloc(vc * 8); // 活跃集:函数内 var → reg 序 (0..4) - var_end : string, mut = alloc(vc * 8); // 活跃集窗口终点(free 判据—— + var_reg : string, mut = alloc(vc * 8) // 活跃集:函数内 var → reg 序 (0..4) + var_end : string, mut = alloc(vc * 8) // 活跃集窗口终点(free 判据—— // 携带值扩窗后 ≠ live_last,须存) - var_asg : string, mut = alloc(vc * 8); // 终分配:函数内 var → 物理 reg - reg_occ : string, mut = alloc(MAX_REGS * 8); - cand_st : string, mut = alloc(vc * 8); - cand_en : string, mut = alloc(vc * 8); - cand_lv : string, mut = alloc(vc * 8); - lv : ., mut = 0; - loop { if lv >= vc { break; } - w64(var_reg, lv * 8, -1); w64(var_end, lv * 8, 0); w64(var_asg, lv * 8, -1); - lv = lv + 1; - } - lv = 0; - loop { if lv >= MAX_REGS { break; } w64(reg_occ, lv * 8, -1); lv = lv + 1; } - cc : ., mut = 0; - lv = 0; - loop { - if lv >= vc { break; } - gv := vs + lv; - f := live_first(fi, gv); - l := live_last(fi, gv); - if f < 0 || l <= f { lv = lv + 1; continue; } // 未用 / 单指令引用 - ty := irv_type(gv); - if ty == TI_DEX || ty == TI_DEX_S || ty == TI_DYN || ty == TI_UNIT { - lv = lv + 1; continue; - } - if r64(haz_const, lv * 8) != 0 || r64(haz_ref, lv * 8) != 0 || - r64(haz_i2f, lv * 8) != 0 || r64(haz_dyn, lv * 8) != 0 || - r64(haz_dex, lv * 8) != 0 { - lv = lv + 1; continue; - } - st : ., mut = f; - en : ., mut = l; - if lv < pc { st = 0; } // 参数入口装载 → 窗口自函数头 - if r64(car, lv * 8) != 0 { st = 0; en = ic - 1; } // 携带值 → 整函数 - w64(cand_st, cc * 8, st); - w64(cand_en, cc * 8, en); - w64(cand_lv, cc * 8, lv); - cc = cc + 1; - lv = lv + 1; - } + var_asg : string, mut = alloc(vc * 8) // 终分配:函数内 var → 物理 reg + reg_occ : string, mut = alloc(MAX_REGS * 8) + cand_st : string, mut = alloc(vc * 8) + cand_en : string, mut = alloc(vc * 8) + cand_lv : string, mut = alloc(vc * 8) + lv : ., mut = 0 + loop: + if lv >= vc: + break + w64(var_reg, lv * 8, -1) + w64(var_end, lv * 8, 0) + w64(var_asg, lv * 8, -1) + lv = lv + 1 + lv = 0 + loop: + if lv >= MAX_REGS: + break + w64(reg_occ, lv * 8, -1) + lv = lv + 1 + cc : ., mut = 0 + lv = 0 + loop: + if lv >= vc: + break + gv := vs + lv + f := live_first(fi, gv) + l := live_last(fi, gv) + if f < 0 || l <= f: + lv = lv + 1 + continue + // 未用 / 单指令引用 + ty := irv_type(gv) + if ty == TI_DEX || ty == TI_DEX_S || ty == TI_DYN || ty == TI_UNIT: + lv = lv + 1 + continue + if r64(haz_const, lv * 8) != 0 || r64(haz_ref, lv * 8) != 0 || r64(haz_i2f, lv * 8) != 0 || r64(haz_dyn, lv * 8) != 0 || r64(haz_dex, lv * 8) != 0: + lv = lv + 1 + continue + st : ., mut = f + en : ., mut = l + if lv < pc: + st = 0 + // 参数入口装载 → 窗口自函数头 + if r64(car, lv * 8) != 0: + st = 0 + en = ic - 1 + // 携带值 → 整函数 + w64(cand_st, cc * 8, st) + w64(cand_en, cc * 8, en) + w64(cand_lv, cc * 8, lv) + cc = cc + 1 + lv = lv + 1 // 候选按 (start, lv) 稳定升序(插入排序;起点 = 指令位置,C ≤ vc 小集) - ci2 : ., mut = 1; - loop { - if ci2 >= cc { break; } - ks := r64(cand_st, ci2 * 8); - kl := r64(cand_lv, ci2 * 8); - ke := r64(cand_en, ci2 * 8); - jj : ., mut = ci2; - loop { - if jj <= 0 { break; } - pj := jj - 1; - ps := r64(cand_st, pj * 8); - pl := r64(cand_lv, pj * 8); - if ps < ks || (ps == ks && pl < kl) { break; } - w64(cand_st, jj * 8, ps); - w64(cand_en, jj * 8, r64(cand_en, pj * 8)); - w64(cand_lv, jj * 8, pl); - jj = jj - 1; - } - w64(cand_st, jj * 8, ks); - w64(cand_en, jj * 8, ke); - w64(cand_lv, jj * 8, kl); - ci2 = ci2 + 1; - } + ci2 : ., mut = 1 + loop: + if ci2 >= cc: + break + ks := r64(cand_st, ci2 * 8) + kl := r64(cand_lv, ci2 * 8) + ke := r64(cand_en, ci2 * 8) + jj : ., mut = ci2 + loop: + if jj <= 0: + break + pj := jj - 1 + ps := r64(cand_st, pj * 8) + pl := r64(cand_lv, pj * 8) + if ps < ks || (ps == ks && pl < kl): + break + w64(cand_st, jj * 8, ps) + w64(cand_en, jj * 8, r64(cand_en, pj * 8)) + w64(cand_lv, jj * 8, pl) + jj = jj - 1 + w64(cand_st, jj * 8, ks) + w64(cand_en, jj * 8, ke) + w64(cand_lv, jj * 8, kl) + ci2 = ci2 + 1 // ── 阶段 4:位置扫描 First Fit(同位置先 free 后分配)── - ci : ., mut = 0; - p : ., mut = 0; - loop { - if p >= ic { break; } + ci : ., mut = 0 + p : ., mut = 0 + loop: + if p >= ic: + break // free:窗口终点(分配时记入 var_end;携带值扩窗 ≠ live_last)已过 → // 归还寄存器。rc=0 根因修复点:free 发生在末引用之后、寄存器按窗口 // 终点正确复用(旧实现 free 后 meta 收集丢失 + reg 序单调不复用)。 - lv2 : ., mut = 0; - loop { - if lv2 >= vc { break; } - rr := r64(var_reg, lv2 * 8); - if rr >= 0 && r64(var_end, lv2 * 8) < p { - w64(var_reg, lv2 * 8, -1); - w64(reg_occ, rr * 8, -1); - } - lv2 = lv2 + 1; - } + lv2 : ., mut = 0 + loop: + if lv2 >= vc: + break + rr := r64(var_reg, lv2 * 8) + if rr >= 0 && r64(var_end, lv2 * 8) < p: + w64(var_reg, lv2 * 8, -1) + w64(reg_occ, rr * 8, -1) + lv2 = lv2 + 1 // assign:起点 == p 的候选(窗口终点 = p−1 的 var 已先 free → 可复用 // 同寄存器;终点恰 = p 的 var 仍活跃于 p,不释放——同指令共存条目 // 不得同寄存器) - loop { - if ci >= cc { break; } - if r64(cand_st, ci * 8) != p { break; } - lvv := r64(cand_lv, ci * 8); - eend := r64(cand_en, ci * 8); - ci = ci + 1; - rj : ., mut = 0; - tk : ., mut = -1; - loop { - if rj >= MAX_REGS { break; } - if r64(reg_occ, rj * 8) < 0 { tk = rj; break; } - rj = rj + 1; - } - if tk >= 0 { - w64(var_reg, lvv * 8, tk); - w64(var_end, lvv * 8, eend); - w64(reg_occ, tk * 8, lvv); - w64(var_asg, lvv * 8, r64(reg_phys, tk * 8)); - } - } - p = p + 1; - } + loop: + if ci >= cc: + break + if r64(cand_st, ci * 8) != p: + break + lvv := r64(cand_lv, ci * 8) + eend := r64(cand_en, ci * 8) + ci = ci + 1 + rj : ., mut = 0 + tk : ., mut = -1 + loop: + if rj >= MAX_REGS: + break + if r64(reg_occ, rj * 8) < 0: + tk = rj + break + rj = rj + 1 + if tk >= 0: + w64(var_reg, lvv * 8, tk) + w64(var_end, lvv * 8, eend) + w64(reg_occ, tk * 8, lvv) + w64(var_asg, lvv * 8, r64(reg_phys, tk * 8)) + p = p + 1 // ── 阶段 5:终分配写 g_opt_meta ── // 块格式(ast.cr OPT_META_STRIDE=64 = 头 8B + 数据 ≤56B):每块 ≤5 对 @@ -771,59 +808,72 @@ fn alloc_registers() { // 分配对数超过 5 时按 5 切块多块拼接(reader/get_reg_for_var 全块扫描, // 首匹配生效;同 var 恒在同一块内 1 对,无跨块遮蔽问题)。 // 修复前只收「末指令仍活跃」var → 恒空(rc=0);现写全部已分配对。 - rc : ., mut = 0; - lv = 0; - loop { if lv >= vc { break; } - if r64(var_asg, lv * 8) >= 0 { rc = rc + 1; } - lv = lv + 1; - } - if rc > 0 { + rc : ., mut = 0 + lv = 0 + loop: + if lv >= vc: + break + if r64(var_asg, lv * 8) >= 0: + rc = rc + 1 + lv = lv + 1 + if rc > 0: // 预收集已分配 var(函数内下标)——切块时按序取 - asg_lv : string, mut = alloc(rc * 8); - ai : ., mut = 0; - lv = 0; - loop { if lv >= vc { break; } - if r64(var_asg, lv * 8) >= 0 { - w64(asg_lv, ai * 8, lv); - ai = ai + 1; - } - lv = lv + 1; - } - pb : ., mut = 0; - loop { - if pb >= rc { break; } - n_in : ., mut = rc - pb; - if n_in > 5 { n_in = 5; } - ei : ., mut = g_opt_meta_count; - grow_opt_meta(ei + 1); + asg_lv : string, mut = alloc(rc * 8) + ai : ., mut = 0 + lv = 0 + loop: + if lv >= vc: + break + if r64(var_asg, lv * 8) >= 0: + w64(asg_lv, ai * 8, lv) + ai = ai + 1 + lv = lv + 1 + pb : ., mut = 0 + loop: + if pb >= rc: + break + n_in : ., mut = rc - pb + if n_in > 5: + n_in = 5 + ei : ., mut = g_opt_meta_count + grow_opt_meta(ei + 1) // Write key(u32) + data_len(u32) header using store8 - eo := ei * OPT_META_STRIDE; - store8(g_opt_meta, eo, 0); store8(g_opt_meta, eo+1, 0); - store8(g_opt_meta, eo+2, 0); store8(g_opt_meta, eo+3, 0); // OPT_KEY_REG_ASSIGN=0 - dl : ., mut = 4 + n_in * 8; - store8(g_opt_meta, eo+4, dl%256); store8(g_opt_meta, eo+5, (dl/256)%256); - store8(g_opt_meta, eo+6, (dl/65536)%256); store8(g_opt_meta, eo+7, (dl/16777216)%256); + eo := ei * OPT_META_STRIDE + store8(g_opt_meta, eo, 0) + store8(g_opt_meta, eo+1, 0) + store8(g_opt_meta, eo+2, 0) + store8(g_opt_meta, eo+3, 0) // OPT_KEY_REG_ASSIGN=0 + dl : ., mut = 4 + n_in * 8 + store8(g_opt_meta, eo+4, dl%256) + store8(g_opt_meta, eo+5, (dl/256)%256) + store8(g_opt_meta, eo+6, (dl/65536)%256) + store8(g_opt_meta, eo+7, (dl/16777216)%256) // Write count - store8(g_opt_meta, eo+8, n_in%256); store8(g_opt_meta, eo+9, (n_in/256)%256); - store8(g_opt_meta, eo+10, (n_in/65536)%256); store8(g_opt_meta, eo+11, (n_in/16777216)%256); + store8(g_opt_meta, eo+8, n_in%256) + store8(g_opt_meta, eo+9, (n_in/256)%256) + store8(g_opt_meta, eo+10, (n_in/65536)%256) + store8(g_opt_meta, eo+11, (n_in/16777216)%256) // Write pairs: [var_idx(u32), reg(u32)]...(对 @+12 起,8B 步进) - di : ., mut = 12; - pi : ., mut = 0; - loop { - if pi >= n_in { break; } - lvp := r64(asg_lv, (pb + pi) * 8); - vw := vs + lvp; - rn := r64(var_asg, lvp * 8); - store8(g_opt_meta, eo+di, vw%256); store8(g_opt_meta, eo+di+1, (vw/256)%256); - store8(g_opt_meta, eo+di+2, (vw/65536)%256); store8(g_opt_meta, eo+di+3, (vw/16777216)%256); - store8(g_opt_meta, eo+di+4, rn%256); store8(g_opt_meta, eo+di+5, (rn/256)%256); - store8(g_opt_meta, eo+di+6, (rn/65536)%256); store8(g_opt_meta, eo+di+7, (rn/16777216)%256); - di = di + 8; - pi = pi + 1; - } - g_opt_meta_count = ei + 1; - pb = pb + n_in; - } + di : ., mut = 12 + pi : ., mut = 0 + loop: + if pi >= n_in: + break + lvp := r64(asg_lv, (pb + pi) * 8) + vw := vs + lvp + rn := r64(var_asg, lvp * 8) + store8(g_opt_meta, eo+di, vw%256) + store8(g_opt_meta, eo+di+1, (vw/256)%256) + store8(g_opt_meta, eo+di+2, (vw/65536)%256) + store8(g_opt_meta, eo+di+3, (vw/16777216)%256) + store8(g_opt_meta, eo+di+4, rn%256) + store8(g_opt_meta, eo+di+5, (rn/256)%256) + store8(g_opt_meta, eo+di+6, (rn/65536)%256) + store8(g_opt_meta, eo+di+7, (rn/16777216)%256) + di = di + 8 + pi = pi + 1 + g_opt_meta_count = ei + 1 + pb = pb + n_in // ── 阶段 5 尾:登记表配对(双份同步纪律——内核完备 Task 3)── // g_opt_meta = emit 面私有结构(instr.cr get_reg_for_var 消费);判定 // 面输入 = 位置登记表(kern_loc_assign——每 g_opt_meta 写点成对登记, @@ -832,27 +882,25 @@ fn alloc_registers() { // +entry_count(fi)) 且 ent_var(e) == vw 逐一 kern_loc_assign(e, rn)—— // 与判定侧 meta_reg_for_var 投影语义精确等价的前提(var 分配 ⇔ 全 // 条目登记;分配器将来升条目级时按条目登记,判定零改动)。 - es := entry_start(fi); - ec := entry_count(fi); - ai = 0; - loop { - if ai >= rc { break; } - lvp := r64(asg_lv, ai * 8); - vw := vs + lvp; - rn := r64(var_asg, lvp * 8); - ej : ., mut = 0; - loop { - if ej >= ec { break; } - e := es + ej; - if ent_var(e) == vw { kern_loc_assign(e, rn); } - ej = ej + 1; - } - ai = ai + 1; - } - } - fi = fi + 1; - } -} + es := entry_start(fi) + ec := entry_count(fi) + ai = 0 + loop: + if ai >= rc: + break + lvp := r64(asg_lv, ai * 8) + vw := vs + lvp + rn := r64(var_asg, lvp * 8) + ej : ., mut = 0 + loop: + if ej >= ec: + break + e := es + ej + if ent_var(e) == vw: + kern_loc_assign(e, rn) + ej = ej + 1 + ai = ai + 1 + fi = fi + 1 // ===== 语义对象模型(内核完备 Task 1):调度重建 = 实例事务 ===== // NOD→g_ir_instrs 线性重建自 ccr_io.cr load_ccr 移出(原 NOD 段重建循环函数 @@ -864,18 +912,17 @@ fn alloc_registers() { // 消费——Task 0 确认零线性流依赖)。调用方:corearch.cr / 组合根 // src/targets/x86_64-linux/main.cr(自举 stage 链入口)——load_ccr 成功后、 // 分派/发射前调用一次。 -fn build_linear_schedule() { - grow_ir_instrs(g_v7_nod_count); - ni : ., mut = 0; - loop { - if ni >= g_v7_nod_count { break; } - iri_set_op(ni, nod_op(ni)); - iri_set_dest(ni, nod_dest(ni)); - iri_set_s1(ni, nod_s1(ni)); - iri_set_s2(ni, nod_s2(ni)); - iri_set_s3(ni, nod_s3(ni)); - iri_set_tk(ni, nod_tk(ni)); - g_ir_instr_count = ni + 1; - ni = ni + 1; - } -} +fn build_linear_schedule(): + grow_ir_instrs(g_v7_nod_count) + ni : ., mut = 0 + loop: + if ni >= g_v7_nod_count: + break + iri_set_op(ni, nod_op(ni)) + iri_set_dest(ni, nod_dest(ni)) + iri_set_s1(ni, nod_s1(ni)) + iri_set_s2(ni, nod_s2(ni)) + iri_set_s3(ni, nod_s3(ni)) + iri_set_tk(ni, nod_tk(ni)) + g_ir_instr_count = ni + 1 + ni = ni + 1 diff --git a/src/arch/x86_64/sizes.cr b/src/arch/x86_64/sizes.cr index 7905dedd..187f9a11 100644 --- a/src/arch/x86_64/sizes.cr +++ b/src/arch/x86_64/sizes.cr @@ -16,72 +16,133 @@ // ══════════════════════════════════════════════════════════════ // ── Basic encoding sizes (one per e2_* helper in instr.cr) ── -fn sz_mov() -> int { return 3; } -fn sz_ld(o: int) -> int { if o >= E2_REG_SLOT_BASE { return 3; } if o >= -128 && o <= 127 { return 4; } return 7; } -fn sz_st(o: int) -> int { if o >= E2_REG_SLOT_BASE { return 3; } if o >= -128 && o <= 127 { return 4; } return 7; } -fn sz_li(o: int, v: int) -> int { - if v < -2147483647 - 1 || v > 2147483647 { - if o >= -128 && o <= 127 { return 14; } // mov rax,imm64(10) + mov [rbp+disp8],rax(4) - return 17; // mov rax,imm64(10) + mov [rbp+disp32],rax(7) - } - if o >= -128 && o <= 127 { return 8; } - return 11; -} -fn sz_lr() -> int { return 7; } -fn sz_lrb() -> int { return 7; } -fn sz_lb(o: int) -> int { if o >= -128 && o <= 127 { return 4; } return 7; } -fn sz_call() -> int { return 5; } -fn sz_jmp() -> int { return 5; } -fn sz_je() -> int { return 6; } -fn sz_alu() -> int { return 3; } -fn sz_jo() -> int { return 6; } // jo rel32 (0F 80 cd)——慢路径块附函数尾,rel8 ±127 在 >127B 函数体上不可达 -fn sz_syscall() -> int { return 2; } +fn sz_mov() -> int: + return 3 +fn sz_ld(o: int) -> int: + if o >= E2_REG_SLOT_BASE: + return 3 + if o >= -128 && o <= 127: + return 4 + return 7 +fn sz_st(o: int) -> int: + if o >= E2_REG_SLOT_BASE: + return 3 + if o >= -128 && o <= 127: + return 4 + return 7 +fn sz_li(o: int, v: int) -> int: + if v < -2147483647 - 1 || v > 2147483647: + if o >= -128 && o <= 127: + return 14 + // mov rax,imm64(10) + mov [rbp+disp8],rax(4) + return 17 // mov rax,imm64(10) + mov [rbp+disp32],rax(7) + if o >= -128 && o <= 127: + return 8 + return 11 +fn sz_lr() -> int: + return 7 +fn sz_lrb() -> int: + return 7 +fn sz_lb(o: int) -> int: + if o >= -128 && o <= 127: + return 4 + return 7 +fn sz_call() -> int: + return 5 +fn sz_jmp() -> int: + return 5 +fn sz_je() -> int: + return 6 +fn sz_alu() -> int: + return 3 +fn sz_jo() -> int: + return 6 +// jo rel32 (0F 80 cd)——慢路径块附函数尾,rel8 ±127 在 >127B 函数体上不可达 +fn sz_syscall() -> int: + return 2 // ── Prologue / epilogue sizes ── -fn sz_push_rbp() -> int { return 1; } -fn sz_mov_rbp_rsp() -> int { return 3; } -fn sz_sub_rsp(ss: int) -> int { - if ss <= 0 { return 0; } - if ss > 127 { return 7; } - return 4; -} -fn sz_add_rsp(ss: int) -> int { return sz_sub_rsp(ss); } -fn sz_pop_rbp() -> int { return 1; } -fn sz_ret() -> int { return 1; } +fn sz_push_rbp() -> int: + return 1 +fn sz_mov_rbp_rsp() -> int: + return 3 +fn sz_sub_rsp(ss: int) -> int: + if ss <= 0: + return 0 + if ss > 127: + return 7 + return 4 +fn sz_add_rsp(ss: int) -> int: + return sz_sub_rsp(ss) +fn sz_pop_rbp() -> int: + return 1 +fn sz_ret() -> int: + return 1 // callee-saved 保存/恢复(opt≥1):push rbx(1)+r12..r15(4×2)=9 / pop r15..r12(4×2) // +rbx(1)=9——frame.cr pf_frame_overhead 核算与 pf_prologue/pf_epilogue 发射同源 // (波 1 Task 4 起自 pf_frame_overhead 的硬编码 18/9 提到本文件——值逐字节不变)。 -fn sz_callee_saved_push() -> int { return 9; } -fn sz_callee_saved_pop() -> int { return 9; } +fn sz_callee_saved_push() -> int: + return 9 +fn sz_callee_saved_pop() -> int: + return 9 // Each register param save uses func-relative offsets (always disp8) -fn sz_save_param() -> int { return 4; } +fn sz_save_param() -> int: + return 4 // Stack params need one load from the caller frame and one local store. -fn sz_save_stack_param() -> int { return 8; } +fn sz_save_stack_param() -> int: + return 8 // ── _start size (simple case, no argc/argv globals) ── -fn sz_start_body() -> int { return 4 + 5 + sz_call() + 2 + 5 + sz_syscall(); } -fn sz_start_argv_save() -> int { return sz_lr() + 3; } +fn sz_start_body() -> int: + return 4 + 5 + sz_call() + 2 + 5 + sz_syscall() +fn sz_start_argv_save() -> int: + return sz_lr() + 3 // ── per-opcode instruction size estimates (used by Phase 2 layout) ── -fn instr_size(op: int) -> int { - if op == IR_INLINE { return 0; } - if op == IR_NO_BOUNDS_CHECK { return 0; } - if op == IR_FAST { return 0; } - if op == IR_UNROLL { return 0; } - if op == IR_SECTION { return 0; } - if op == IR_APPROX { return 0; } - if op == IR_LAZY_THUNK { return 11; } - if op == IR_LAZY_FORCE { return 11; } - if op == IR_SPAWN { return 9; } // call(5) + store(4) - if op == IR_YIELD { return 0; } // no-op (for now) - if op == IR_CALL_EXTERN { return 9; } // call(5) + store(4) = 9 bytes - if op == IR_HOTPATCH_ROUTE { return 9; } // call(5) + store(4) = 9 bytes - if op == IR_FNADDR { return 14; } // movabs(10) + store(4) = 14 bytes - if op == IR_DYN_PACK { return 16; } // load_var + st + li (value+tag pack) - if op == IR_DYN_TAG { return 8; } // ld(off+8) + st - if op == IR_DYN_VAL { return 8; } // ld(off+0) + st - if op == IR_DYN_DISPATCH { return 40; } // tag load + cmp/je chain (common case ~35-44B) +fn instr_size(op: int) -> int: + if op == IR_INLINE: + return 0 + if op == IR_NO_BOUNDS_CHECK: + return 0 + if op == IR_FAST: + return 0 + if op == IR_UNROLL: + return 0 + if op == IR_SECTION: + return 0 + if op == IR_APPROX: + return 0 + if op == IR_LAZY_THUNK: + return 11 + if op == IR_LAZY_FORCE: + return 11 + if op == IR_SPAWN: + return 9 + // call(5) + store(4) + if op == IR_YIELD: + return 0 + // no-op (for now) + if op == IR_CALL_EXTERN: + return 9 + // call(5) + store(4) = 9 bytes + if op == IR_HOTPATCH_ROUTE: + return 9 + // call(5) + store(4) = 9 bytes + if op == IR_FNADDR: + return 14 + // movabs(10) + store(4) = 14 bytes + if op == IR_DYN_PACK: + return 16 + // load_var + st + li (value+tag pack) + if op == IR_DYN_TAG: + return 8 + // ld(off+8) + st + if op == IR_DYN_VAL: + return 8 + // ld(off+0) + st + if op == IR_DYN_DISPATCH: + return 40 + // tag load + cmp/je chain (common case ~35-44B) // Unknown / non-annotation opcodes fall back to caller's heuristic (ic*5) - return 0; -} + return 0 diff --git a/src/arch/x86_64/tag2l.cr b/src/arch/x86_64/tag2l.cr index e4200f79..74370a25 100644 --- a/src/arch/x86_64/tag2l.cr +++ b/src/arch/x86_64/tag2l.cr @@ -79,7 +79,7 @@ // 循环行,O2 性能)。若将来引入 reg 形态不完整的机制(动态 spill 等)再议。 // ══════════════════════════════════════════════════════════════ -fn mw_setup_tags(fi: int, vs: int, vc: int) { +fn mw_setup_tags(fi: int, vs: int, vc: int): // 识别函数 fi(var 域 [vs, vs+vc))的潜在多字变量并建立 tag 字节偏移表。 // 纯 IR 函数——输入即 .ccr 载入后的最终 IR(发射所见),无格式/无跨进程态。 // 卫生锚:tag 读写模型与识别规则必须同域——tagged 行定值点全集 = ①add/sub @@ -87,14 +87,19 @@ fn mw_setup_tags(fi: int, vs: int, vc: int) { // ④2L 慢路径块写 tag=1(四类由发射侧逐一维护 ⇒ 无帧入口清零——论证全文见 // 本文件 e2_mw_opnd_block 前「Task 4:tag 卫生」注释块;规则 A/B/B' 只标 // 这四类会写的行——闭包 ⊇ 2L 可能态由唯一生产者论证闭合)。 - grow_mw_tag_off(vc); - z : ., mut = 0; - loop { if z >= vc { break; } w64(g_x86_mw_tag_off, z * 8, -1); z = z + 1; } - g_x86_mw_tag_count = 0; - if vc <= 0 { return; } - ic := r64(g_ir_func_instr_count, fi * 8); - ist := r64(g_ir_func_instr_start, fi * 8); - ve := vs + vc; + grow_mw_tag_off(vc) + z : ., mut = 0 + loop: + if z >= vc: + break + w64(g_x86_mw_tag_off, z * 8, -1) + z = z + 1 + g_x86_mw_tag_count = 0 + if vc <= 0: + return + ic := r64(g_ir_func_instr_count, fi * 8) + ist := r64(g_ir_func_instr_start, fi * 8) + ve := vs + vc // Pass 1:不动点扫描(规则 A/B/B' 单调,重复全扫至某遍无新标收敛; // ≤ vc+1 遍——回边携带:循环体内拷贝点可线性先于其 tag 源的定值, // 单遍前向(定义先于使用)论证只对无环成立)。dest/目标在函数域内且 @@ -102,60 +107,51 @@ fn mw_setup_tags(fi: int, vs: int, vc: int) { // A. IR_BINARY(ADD/SUB) → 标 dest; // B. IR_LOAD d←s1(as 转换拷贝)且 s1 已标 → 标 d; // B'. IR_STORE ρ(s1):=ρ(s2)(赋值定值拷贝)且 s2 已标 → 标 s1。 - chg : ., mut = 1; - ii : ., mut = 0; - loop { - if chg == 0 { break; } - chg = 0; - ii = 0; - loop { - if ii >= ic { break; } - ino := ist + ii; - op := iri_op(ino); - if op == IR_BINARY { - d := iri_dest(ino); - if d >= vs && d < ve && irv_type(d) == TI_INT { - s3 := iri_s3(ino); - if (s3 == OP_ADD || s3 == OP_SUB) && r64(g_x86_mw_tag_off, (d - vs) * 8) == -1 { - w64(g_x86_mw_tag_off, (d - vs) * 8, 0); // 0 = 已标记(占位) - chg = 1; - } - } - } else if op == IR_LOAD { - d := iri_dest(ino); - if d >= vs && d < ve && irv_type(d) == TI_INT { - s1 := iri_s1(ino); - if s1 >= vs && s1 < ve && irv_type(s1) == TI_INT && r64(g_x86_mw_tag_off, (s1 - vs) * 8) != -1 && r64(g_x86_mw_tag_off, (d - vs) * 8) == -1 { - w64(g_x86_mw_tag_off, (d - vs) * 8, 0); - chg = 1; - } - } - } else if op == IR_STORE { - s1 := iri_s1(ino); - if s1 >= vs && s1 < ve && irv_type(s1) == TI_INT { - s2 := iri_s2(ino); - if s2 >= vs && s2 < ve && irv_type(s2) == TI_INT && r64(g_x86_mw_tag_off, (s2 - vs) * 8) != -1 && r64(g_x86_mw_tag_off, (s1 - vs) * 8) == -1 { - w64(g_x86_mw_tag_off, (s1 - vs) * 8, 0); - chg = 1; - } - } - } - ii = ii + 1; - } - } + chg : ., mut = 1 + ii : ., mut = 0 + loop: + if chg == 0: + break + chg = 0 + ii = 0 + loop: + if ii >= ic: + break + ino := ist + ii + op := iri_op(ino) + if op == IR_BINARY: + d := iri_dest(ino) + if d >= vs && d < ve && irv_type(d) == TI_INT: + s3 := iri_s3(ino) + if (s3 == OP_ADD || s3 == OP_SUB) && r64(g_x86_mw_tag_off, (d - vs) * 8) == -1: + w64(g_x86_mw_tag_off, (d - vs) * 8, 0) // 0 = 已标记(占位) + chg = 1 + else if op == IR_LOAD: + d := iri_dest(ino) + if d >= vs && d < ve && irv_type(d) == TI_INT: + s1 := iri_s1(ino) + if s1 >= vs && s1 < ve && irv_type(s1) == TI_INT && r64(g_x86_mw_tag_off, (s1 - vs) * 8) != -1 && r64(g_x86_mw_tag_off, (d - vs) * 8) == -1: + w64(g_x86_mw_tag_off, (d - vs) * 8, 0) + chg = 1 + else if op == IR_STORE: + s1 := iri_s1(ino) + if s1 >= vs && s1 < ve && irv_type(s1) == TI_INT: + s2 := iri_s2(ino) + if s2 >= vs && s2 < ve && irv_type(s2) == TI_INT && r64(g_x86_mw_tag_off, (s2 - vs) * 8) != -1 && r64(g_x86_mw_tag_off, (s1 - vs) * 8) == -1: + w64(g_x86_mw_tag_off, (s1 - vs) * 8, 0) + chg = 1 + ii = ii + 1 // Pass 2:变量索引升序分配 tag 字节(k-th → rbp - (vc*8 + k))。 - cnt : ., mut = 0; - k : ., mut = 0; - loop { - if k >= vc { break; } - if r64(g_x86_mw_tag_off, k * 8) != -1 { - cnt = cnt + 1; - w64(g_x86_mw_tag_off, k * 8, -(vc * 8 + cnt)); - } - k = k + 1; - } - g_x86_mw_tag_count = cnt; -} + cnt : ., mut = 0 + k : ., mut = 0 + loop: + if k >= vc: + break + if r64(g_x86_mw_tag_off, k * 8) != -1: + cnt = cnt + 1 + w64(g_x86_mw_tag_off, k * 8, -(vc * 8 + cnt)) + k = k + 1 + g_x86_mw_tag_count = cnt // ── Task 2:快路径溢出检测发射(jo → 函数尾慢路径块)── // 发射条件 = 规则 A 的 add/sub 指令(emit 侧与 mw_setup_tags 同源判定): @@ -167,35 +163,39 @@ fn mw_setup_tags(fi: int, vs: int, vc: int) { // 整条落旧路径):比较(OP_EQ..OP_GE)且任一操作数行 tagged → 同样需旧路 // 径(2L 比较读 tag——表路径不知 tag)。add/sub 的 tagged 操作数已由 dest // tagged 覆盖(规则 A 保证操作数 tagged ⟹ dest tagged)。 -fn mw_int_arith_jo_needed(instr_idx: int) -> int { - if iri_op(instr_idx) != IR_BINARY { return 0; } - s3 := iri_s3(instr_idx); - if s3 >= OP_EQ && s3 <= OP_GE { - s1 := iri_s1(instr_idx); - if g2_tag_off(s1) != -1 { return 1; } - s2 := iri_s2(instr_idx); - if s1 != s2 && g2_tag_off(s2) != -1 { return 1; } - return 0; - } - if s3 != OP_ADD && s3 != OP_SUB { return 0; } - if g2_tag_off(iri_dest(instr_idx)) == -1 { return 0; } - return 1; } +fn mw_int_arith_jo_needed(instr_idx: int) -> int: + if iri_op(instr_idx) != IR_BINARY: + return 0 + s3 := iri_s3(instr_idx) + if s3 >= OP_EQ && s3 <= OP_GE: + s1 := iri_s1(instr_idx) + if g2_tag_off(s1) != -1: + return 1 + s2 := iri_s2(instr_idx) + if s1 != s2 && g2_tag_off(s2) != -1: + return 1 + return 0 + if s3 != OP_ADD && s3 != OP_SUB: + return 0 + if g2_tag_off(iri_dest(instr_idx)) == -1: + return 0 + return 1 // jo rel32(0F 80 cd,6B)→ 慢路径块,位置后知:记录站点现场到 // g_x86_mw_jo_{pos,dest,is_sub}(g2_init 清零、frame.cr pf_epilogue 函数尾统一 // 发射块并回填;resume 由 elf.cr 于该指令发射完后按序补写)。 // rel32(非 rel8):块附函数尾——函数体 >127B 时 rel8 不可达(编译器自身 // 的大函数在自举回归里必然命中;Task 2 用 t3 大函数用例锁定该编码)。 -fn e2_mw_jo(b: string, p: int, d: int, is_sub: int) -> int { - grow_mw_jo_patch(g_x86_mw_jo_count + 1); - w64(g_x86_mw_jo_pos, g_x86_mw_jo_count * 8, p); - w64(g_x86_mw_jo_dest, g_x86_mw_jo_count * 8, d); - w64(g_x86_mw_jo_is_sub, g_x86_mw_jo_count * 8, is_sub); - g_x86_mw_jo_count = g_x86_mw_jo_count + 1; - w8(b, p, 15); w8(b, p + 1, 128); // 0F 80 = jo rel32 - e2_w32(b, p + 2, 0); // 占位——frame.cr pf_epilogue 块位置已知后回填 - return 6; -} +fn e2_mw_jo(b: string, p: int, d: int, is_sub: int) -> int: + grow_mw_jo_patch(g_x86_mw_jo_count + 1) + w64(g_x86_mw_jo_pos, g_x86_mw_jo_count * 8, p) + w64(g_x86_mw_jo_dest, g_x86_mw_jo_count * 8, d) + w64(g_x86_mw_jo_is_sub, g_x86_mw_jo_count * 8, is_sub) + g_x86_mw_jo_count = g_x86_mw_jo_count + 1 + w8(b, p, 15) + w8(b, p + 1, 128) // 0F 80 = jo rel32 + e2_w32(b, p + 2, 0) // 占位——frame.cr pf_epilogue 块位置已知后回填 + return 6 // ── Task 3:慢路径块(每站点独立块,附于函数尾 epilogue 之后)── // 站点状态(jo 到达块时): @@ -225,51 +225,80 @@ fn e2_mw_jo(b: string, p: int, d: int, is_sub: int) -> int { // (r10 ≥ 0)——add/sub 同式,CF 式只是其标志实现。 // 边界核对(brute-force 全样本验证 + 逐用例,见 mw-m1-task-3 报告): // a=b=−2^63(add,S=−2^64 恰在 128 域内):L=0、CF=1 → [lo=0, hi=−1] ✓。 -fn e2_mw_slow_block(b: string, p: int, d: int, is_sub: int, resume: int) -> int { - cp : ., mut = 0; +fn e2_mw_slow_block(b: string, p: int, d: int, is_sub: int, resume: int) -> int: + cp : ., mut = 0 // 1. 高 limb → r11(add:sbb r11,r11 = −CF;sub:+not → CF?0:−1)。 // 须为块内首操作——CF 其后随时可能被写。 - w8(b, p + cp, 77); w8(b, p + cp + 1, 25); w8(b, p + cp + 2, 219); cp = cp + 3; // sbb r11, r11 (4D 19 DB) - if is_sub != 0 { - w8(b, p + cp, 73); w8(b, p + cp + 1, 247); w8(b, p + cp + 2, 211); cp = cp + 3; // not r11 (49 F7 D3—REX.WB: rm=r11 需 B 位) - } + w8(b, p + cp, 77) + w8(b, p + cp + 1, 25) + w8(b, p + cp + 2, 219) + cp = cp + 3 // sbb r11, r11 (4D 19 DB) + if is_sub != 0: + w8(b, p + cp, 73) + w8(b, p + cp + 1, 247) + w8(b, p + cp + 2, 211) + cp = cp + 3 // not r11 (49 F7 D3—REX.WB: rm=r11 需 B 位) // 2. 保存 lo/hi(alloc 调用会摧毁 caller-saved r10/r11):两 push 后 // rsp ≡ 0 (mod 16)——满足 SysV call 对齐(进入块时 rsp ≡ 0)。 - w8(b, p + cp, 65); w8(b, p + cp + 1, 82); cp = cp + 2; // push r10 (41 52) - w8(b, p + cp, 65); w8(b, p + cp + 1, 83); cp = cp + 2; // push r11 (41 53) + w8(b, p + cp, 65) + w8(b, p + cp + 1, 82) + cp = cp + 2 // push r10 (41 52) + w8(b, p + cp, 65) + w8(b, p + cp + 1, 83) + cp = cp + 2 // push r11 (41 53) // 3. alloc(16)——16B 2-limb 对象;与 IR_ALLOC_* 同款补丁表注册 // (g_x86_alloc_patch_count 逐函数不重置——函数尾块与函数体同批回填)。 // mov edi, 16(BF imm32——16 为合法 imm32) - w8(b, p + cp, 191); e2_w32(b, p + cp + 1, 16); cp = cp + 5; - grow_alloc_patch(g_x86_alloc_patch_count + 1); - w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, p + cp); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - w8(b, p + cp, 232); e2_w32(b, p + cp + 1, 0); cp = cp + 5; // call alloc(占位回填) + w8(b, p + cp, 191) + e2_w32(b, p + cp + 1, 16) + cp = cp + 5 + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, p + cp) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + w8(b, p + cp, 232) + e2_w32(b, p + cp + 1, 0) + cp = cp + 5 // call alloc(占位回填) // 4. 恢复 lo/hi - w8(b, p + cp, 65); w8(b, p + cp + 1, 91); cp = cp + 2; // pop r11 (41 5B) - w8(b, p + cp, 65); w8(b, p + cp + 1, 90); cp = cp + 2; // pop r10 (41 5A) + w8(b, p + cp, 65) + w8(b, p + cp + 1, 91) + cp = cp + 2 // pop r11 (41 5B) + w8(b, p + cp, 65) + w8(b, p + cp + 1, 90) + cp = cp + 2 // pop r10 (41 5A) // 5. 写 2-limb 对象(rax = alloc 返回的数据指针):[+0] = lo(环绕值)、 // [+8] = hi(符号扩展修正)。注意 REX:rm=rax 无需 B 位——仅 R(源 // r10/r11)→ 4C(对照 elf.cr alloc 内 mov [rax], r9 = 4C 89 08)。 - w8(b, p + cp, 76); w8(b, p + cp + 1, 137); w8(b, p + cp + 2, 16); cp = cp + 3; // mov [rax], r10 (4C 89 10) - w8(b, p + cp, 76); w8(b, p + cp + 1, 137); w8(b, p + cp + 2, 88); w8(b, p + cp + 3, 8); cp = cp + 4; // mov [rax+8], r11 (4C 89 58 08) + w8(b, p + cp, 76) + w8(b, p + cp + 1, 137) + w8(b, p + cp + 2, 16) + cp = cp + 3 // mov [rax], r10 (4C 89 10) + w8(b, p + cp, 76) + w8(b, p + cp + 1, 137) + w8(b, p + cp + 2, 88) + w8(b, p + cp + 3, 8) + cp = cp + 4 // mov [rax+8], r11 (4C 89 58 08) // 6. 值槽存指针(跳过快路径 e2_st——本块自回存 dest;g2_slot 含 // O1/O2 reg 形态:E2_REG_SLOT_BASE 编码 → e2_mov reg, rax) - cp = cp + e2_st(b, p + cp, 0, g2_slot(d)); + cp = cp + e2_st(b, p + cp, 0, g2_slot(d)) // 7. tag 字节置位(g2_tag_off(d) ≠ −1 由 jo 发射条件保证):槽内现为 // 2-limb 指针 ⇔ tag = 1(tag 不变量慢路径侧)。 - tago := g2_tag_off(d); - if tago >= -128 && tago <= 127 { - w8(b, p + cp, 198); w8(b, p + cp + 1, 69); w8(b, p + cp + 2, tago); w8(b, p + cp + 3, 1); cp = cp + 4; - } else { - w8(b, p + cp, 198); w8(b, p + cp + 1, 133); e2_w32(b, p + cp + 2, tago); - w8(b, p + cp + 6, 1); cp = cp + 7; - } + tago := g2_tag_off(d) + if tago >= -128 && tago <= 127: + w8(b, p + cp, 198) + w8(b, p + cp + 1, 69) + w8(b, p + cp + 2, tago) + w8(b, p + cp + 3, 1) + cp = cp + 4 + else: + w8(b, p + cp, 198) + w8(b, p + cp + 1, 133) + e2_w32(b, p + cp + 2, tago) + w8(b, p + cp + 6, 1) + cp = cp + 7 // 8. 跳回快路径 store 之后(resume = 该站点指令尾,elf.cr 填) - w8(b, p + cp, 233); // E9 jmp rel32 - e2_w32(b, p + cp + 1, resume - (p + cp + 5)); - return cp + 5; -} + w8(b, p + cp, 233) // E9 jmp rel32 + e2_w32(b, p + cp + 1, resume - (p + cp + 5)) + return cp + 5 // ── Task 4:tag 卫生(定值点写 tag)+ 消费者读路径 ── // 值表示:槽 64 位 = 快值 或 2-limb 堆对象指针;旁路 tag 字节 0/1。 @@ -304,78 +333,101 @@ fn e2_mw_slow_block(b: string, p: int, d: int, is_sub: int, resume: int) -> int // 字节级小助手(rbp 相对偏移,disp8/disp32 自动): // test byte [rbp+off], 0xFF——F6 /0(ZF ⇔ 字节==0;只写标志) -fn e2_mw_t8(b: string, p: int, off: int) -> int { - if off >= -128 && off <= 127 { - w8(b, p, 246); w8(b, p+1, 69); w8(b, p+2, off); w8(b, p+3, 255); return 4; - } - w8(b, p, 246); w8(b, p+1, 133); e2_w32(b, p+2, off); w8(b, p+6, 255); return 7; -} +fn e2_mw_t8(b: string, p: int, off: int) -> int: + if off >= -128 && off <= 127: + w8(b, p, 246) + w8(b, p+1, 69) + w8(b, p+2, off) + w8(b, p+3, 255) + return 4 + w8(b, p, 246) + w8(b, p+1, 133) + e2_w32(b, p+2, off) + w8(b, p+6, 255) + return 7 // mov byte [rbp+off], imm——C6 /0 -fn e2_mw_b8(b: string, p: int, off: int, imm: int) -> int { - if off >= -128 && off <= 127 { - w8(b, p, 198); w8(b, p+1, 69); w8(b, p+2, off); w8(b, p+3, imm); return 4; - } - w8(b, p, 198); w8(b, p+1, 133); e2_w32(b, p+2, off); w8(b, p+6, imm); return 7; -} +fn e2_mw_b8(b: string, p: int, off: int, imm: int) -> int: + if off >= -128 && off <= 127: + w8(b, p, 198) + w8(b, p+1, 69) + w8(b, p+2, off) + w8(b, p+3, imm) + return 4 + w8(b, p, 198) + w8(b, p+1, 133) + e2_w32(b, p+2, off) + w8(b, p+6, imm) + return 7 // mov al, [rbp+off]——8A /0(rax 低字节 scratch——发射点 rax 无 live) -fn e2_mw_ld8(b: string, p: int, off: int) -> int { - if off >= -128 && off <= 127 { - w8(b, p, 138); w8(b, p+1, 69); w8(b, p+2, off); return 3; - } - w8(b, p, 138); w8(b, p+1, 133); e2_w32(b, p+2, off); return 6; -} +fn e2_mw_ld8(b: string, p: int, off: int) -> int: + if off >= -128 && off <= 127: + w8(b, p, 138) + w8(b, p+1, 69) + w8(b, p+2, off) + return 3 + w8(b, p, 138) + w8(b, p+1, 133) + e2_w32(b, p+2, off) + return 6 // mov [rbp+off], al——88 /0 -fn e2_mw_st8(b: string, p: int, off: int) -> int { - if off >= -128 && off <= 127 { - w8(b, p, 136); w8(b, p+1, 69); w8(b, p+2, off); return 3; - } - w8(b, p, 136); w8(b, p+1, 133); e2_w32(b, p+2, off); return 6; -} +fn e2_mw_st8(b: string, p: int, off: int) -> int: + if off >= -128 && off <= 127: + w8(b, p, 136) + w8(b, p+1, 69) + w8(b, p+2, off) + return 3 + w8(b, p, 136) + w8(b, p+1, 133) + e2_w32(b, p+2, off) + return 6 // 定值点 tag 清 0:变量 v 的槽刚被 64 位快值定值(v tagged 时发 mov byte 0)。 -fn e2_mw_tag_clr(b: string, p: int, v: int) -> int { - tg := g2_tag_off(v); - if tg == -1 { return 0; } - return e2_mw_b8(b, p, tg, 0); -} +fn e2_mw_tag_clr(b: string, p: int, v: int) -> int: + tg := g2_tag_off(v) + if tg == -1: + return 0 + return e2_mw_b8(b, p, tg, 0) // 拷贝定值 tag 传播:dst 的槽 ← src 的值(拷贝后 dst 的 tag = src 的 tag; // src 无 tag 字节(恒快)→ dst 清 0)。dst untagged → 零字节。 -fn e2_mw_tag_cpy(b: string, p: int, dst: int, src: int) -> int { - dtg := g2_tag_off(dst); - if dtg == -1 { return 0; } - stg := g2_tag_off(src); - if stg == -1 { return e2_mw_b8(b, p, dtg, 0); } - c : ., mut = e2_mw_ld8(b, p, stg); - c = c + e2_mw_st8(b, p + c, dtg); - return c; -} +fn e2_mw_tag_cpy(b: string, p: int, dst: int, src: int) -> int: + dtg := g2_tag_off(dst) + if dtg == -1: + return 0 + stg := g2_tag_off(src) + if stg == -1: + return e2_mw_b8(b, p, dtg, 0) + c : ., mut = e2_mw_ld8(b, p, stg) + c = c + e2_mw_st8(b, p + c, dtg) + return c // ── 消费者站点记录(oc = operand-check):位置后知(函数尾块),jo 同款 ── -fn mw_oc_new(s1: int, s2: int, d: int, op: int) -> int { - grow_mw_oc_patch(g_x86_mw_oc_count + 1); - w64(g_x86_mw_oc_pos1, g_x86_mw_oc_count * 8, -1); - w64(g_x86_mw_oc_pos2, g_x86_mw_oc_count * 8, -1); - w64(g_x86_mw_oc_s1, g_x86_mw_oc_count * 8, s1); - w64(g_x86_mw_oc_s2, g_x86_mw_oc_count * 8, s2); - w64(g_x86_mw_oc_dest, g_x86_mw_oc_count * 8, d); - w64(g_x86_mw_oc_op, g_x86_mw_oc_count * 8, op); - g_x86_mw_oc_count = g_x86_mw_oc_count + 1; - return g_x86_mw_oc_count - 1; -} +fn mw_oc_new(s1: int, s2: int, d: int, op: int) -> int: + grow_mw_oc_patch(g_x86_mw_oc_count + 1) + w64(g_x86_mw_oc_pos1, g_x86_mw_oc_count * 8, -1) + w64(g_x86_mw_oc_pos2, g_x86_mw_oc_count * 8, -1) + w64(g_x86_mw_oc_s1, g_x86_mw_oc_count * 8, s1) + w64(g_x86_mw_oc_s2, g_x86_mw_oc_count * 8, s2) + w64(g_x86_mw_oc_dest, g_x86_mw_oc_count * 8, d) + w64(g_x86_mw_oc_op, g_x86_mw_oc_count * 8, op) + g_x86_mw_oc_count = g_x86_mw_oc_count + 1 + return g_x86_mw_oc_count - 1 // 站点检查:test tag(v), 0xFF;jne rel32(0F 85)→ 该站点函数尾 2L 块。 // rel32 恒选:块附函数尾,函数体 >127B 时 rel8 不可达(jo 同理由)。chk = // 0/1 → pos1/pos2(站点至多 2 个检查——s1、s2 各行一个,s1==s2 只发 1 个)。 // 记录位置 = jne 起始(p+c——test 前缀 4/7B 后;rel32 字段在 jne 起 +2—— // 若误记 test 起,回填会覆写 test 的 disp/imm 字节)。 -fn e2_mw_oc_check(b: string, p: int, oc: int, chk: int, v: int) -> int { - c : ., mut = e2_mw_t8(b, p, g2_tag_off(v)); - if chk == 0 { w64(g_x86_mw_oc_pos1, oc * 8, p + c); } - else { w64(g_x86_mw_oc_pos2, oc * 8, p + c); } - w8(b, p + c, 15); w8(b, p + c + 1, 133); e2_w32(b, p + c + 2, 0); - return c + 6; -} +fn e2_mw_oc_check(b: string, p: int, oc: int, chk: int, v: int) -> int: + c : ., mut = e2_mw_t8(b, p, g2_tag_off(v)) + if chk == 0: + w64(g_x86_mw_oc_pos1, oc * 8, p + c) + else: + w64(g_x86_mw_oc_pos2, oc * 8, p + c) + w8(b, p + c, 15) + w8(b, p + c + 1, 133) + e2_w32(b, p + c + 2, 0) + return c + 6 // ── 2L 操作数装载(解 2-limb 对象到寄存器对)── // regs: A = (r8=lo, r9=hi),B = (r10=lo, r11=hi);rax = 指针 scratch; @@ -383,20 +435,23 @@ fn e2_mw_oc_check(b: string, p: int, oc: int, chk: int, v: int) -> int { // (指针)入 rax 后解 [rax+0]/[rax+8](对象布局 [+0]=lo [+8]=hi)。 // mov r8, [rax] 4C 8B 00 mov r9, [rax+8] 4C 8B 48 08 // mov r10, [rax] 4C 8B 10 mov r11, [rax+8] 4C 8B 58 08 -fn e2_mw_ld2(b: string, p: int, lo_r: int, hi_r: int) -> int { - w8(b, p, 76); w8(b, p+1, 139); w8(b, p+2, (lo_r % 8) * 8); // mov r{lo}, [rax] - w8(b, p+3, 76); w8(b, p+4, 139); - w8(b, p+5, 64 + (hi_r % 8) * 8); w8(b, p+6, 8); // mov r{hi}, [rax+8] - return 7; -} +fn e2_mw_ld2(b: string, p: int, lo_r: int, hi_r: int) -> int: + w8(b, p, 76) + w8(b, p+1, 139) + w8(b, p+2, (lo_r % 8) * 8) // mov r{lo}, [rax] + w8(b, p+3, 76) + w8(b, p+4, 139) + w8(b, p+5, 64 + (hi_r % 8) * 8) + w8(b, p+6, 8) // mov r{hi}, [rax+8] + return 7 // mov r{hi}, r{lo}; sar r{hi}, 63——快值 64→128 符号扩展(hi = sext) -fn e2_mw_sext(b: string, p: int, lo_r: int, hi_r: int) -> int { - c : ., mut = e2_mov(b, p, hi_r, lo_r); - w8(b, p+c, 73); w8(b, p+c+1, 193); // REX.WB + C1 /7 - w8(b, p+c+2, 248 + (hi_r % 8)); // modrm 11 111 rm(/7 = SAR) - w8(b, p+c+3, 63); - return c + 4; -} +fn e2_mw_sext(b: string, p: int, lo_r: int, hi_r: int) -> int: + c : ., mut = e2_mov(b, p, hi_r, lo_r) + w8(b, p+c, 73) + w8(b, p+c+1, 193) // REX.WB + C1 /7 + w8(b, p+c+2, 248 + (hi_r % 8)) // modrm 11 111 rm(/7 = SAR) + w8(b, p+c+3, 63) + return c + 4 // ── 2L 操作数块(每消费者站点独立,附于函数尾 jo 块之后)── // 入口:≥1 操作数 2L(快路径 tag 检查 jne rel32 → 块首)。现场:无 live @@ -412,136 +467,254 @@ fn e2_mw_sext(b: string, p: int, lo_r: int, hi_r: int) -> int { // 但 rel8 只跨发射点后的局部子区,最远前向 = je → L_fit 越过 2L 存储尾 // ≤ ~60B——±127 恒足;跨块长距跳恒 rel32:tag 检查 jne → 块首、块尾 jmp → // resume)。rel8 目标在块内顺序发射中即时回填(目标 = 已到达的后续位置)。 -fn e2_mw_opnd_block(b: string, p: int, s1: int, s2: int, d: int, op: int, resume: int) -> int { - cp : ., mut = 0; - t1 := g2_tag_off(s1); - t2 : ., mut = t1; - if s1 != s2 { t2 = g2_tag_off(s2); } - is_cmp : ., mut = 0; - if op >= OP_EQ && op <= OP_GE { is_cmp = 1; } - is_sub : ., mut = 0; - if is_cmp == 0 && op == OP_SUB { is_sub = 1; } +fn e2_mw_opnd_block(b: string, p: int, s1: int, s2: int, d: int, op: int, resume: int) -> int: + cp : ., mut = 0 + t1 := g2_tag_off(s1) + t2 : ., mut = t1 + if s1 != s2: + t2 = g2_tag_off(s2) + is_cmp : ., mut = 0 + if op >= OP_EQ && op <= OP_GE: + is_cmp = 1 + is_sub : ., mut = 0 + if is_cmp == 0 && op == OP_SUB: + is_sub = 1 - if t1 != -1 && t2 != -1 { + if t1 != -1 && t2 != -1: // ── 双 tagged 分派:测 t1——0 → A 快 + B 必 2L;1 → A 2L 再测 t2 ── - cp = cp + e2_mw_t8(b, p+cp, t1); - j_a2l : ., mut = cp; w8(b, p+cp, 117); w8(b, p+cp+1, 0); cp = cp + 2; // jne L_a2l + cp = cp + e2_mw_t8(b, p+cp, t1) + j_a2l : ., mut = cp + w8(b, p+cp, 117) + w8(b, p+cp+1, 0) + cp = cp + 2 // jne L_a2l // A 快 - cp = cp + e2_load_var(b, p+cp, 8, s1); - cp = cp + e2_mw_sext(b, p+cp, 8, 9); + cp = cp + e2_load_var(b, p+cp, 8, s1) + cp = cp + e2_mw_sext(b, p+cp, 8, 9) // B 必 2L - cp = cp + e2_load_var(b, p+cp, 0, s2); - cp = cp + e2_mw_ld2(b, p+cp, 10, 11); - j_op1 : ., mut = cp; w8(b, p+cp, 235); w8(b, p+cp+1, 0); cp = cp + 2; // jmp L_op + cp = cp + e2_load_var(b, p+cp, 0, s2) + cp = cp + e2_mw_ld2(b, p+cp, 10, 11) + j_op1 : ., mut = cp + w8(b, p+cp, 235) + w8(b, p+cp+1, 0) + cp = cp + 2 // jmp L_op // L_a2l:A 2L - w8(b, p + j_a2l + 1, cp - (j_a2l + 2)); - cp = cp + e2_load_var(b, p+cp, 0, s1); - cp = cp + e2_mw_ld2(b, p+cp, 8, 9); - cp = cp + e2_mw_t8(b, p+cp, t2); - j_both : ., mut = cp; w8(b, p+cp, 117); w8(b, p+cp+1, 0); cp = cp + 2; // jne L_both + w8(b, p + j_a2l + 1, cp - (j_a2l + 2)) + cp = cp + e2_load_var(b, p+cp, 0, s1) + cp = cp + e2_mw_ld2(b, p+cp, 8, 9) + cp = cp + e2_mw_t8(b, p+cp, t2) + j_both : ., mut = cp + w8(b, p+cp, 117) + w8(b, p+cp+1, 0) + cp = cp + 2 // jne L_both // B 快 - cp = cp + e2_load_var(b, p+cp, 10, s2); - cp = cp + e2_mw_sext(b, p+cp, 10, 11); - j_op2 : ., mut = cp; w8(b, p+cp, 235); w8(b, p+cp+1, 0); cp = cp + 2; // jmp L_op + cp = cp + e2_load_var(b, p+cp, 10, s2) + cp = cp + e2_mw_sext(b, p+cp, 10, 11) + j_op2 : ., mut = cp + w8(b, p+cp, 235) + w8(b, p+cp+1, 0) + cp = cp + 2 // jmp L_op // L_both:B 2L - w8(b, p + j_both + 1, cp - (j_both + 2)); - cp = cp + e2_load_var(b, p+cp, 0, s2); - cp = cp + e2_mw_ld2(b, p+cp, 10, 11); + w8(b, p + j_both + 1, cp - (j_both + 2)) + cp = cp + e2_load_var(b, p+cp, 0, s2) + cp = cp + e2_mw_ld2(b, p+cp, 10, 11) // L_op = 当前 cp——回填两个 jmp - w8(b, p + j_op1 + 1, cp - (j_op1 + 2)); - w8(b, p + j_op2 + 1, cp - (j_op2 + 2)); - } else if t1 != -1 { + w8(b, p + j_op1 + 1, cp - (j_op1 + 2)) + w8(b, p + j_op2 + 1, cp - (j_op2 + 2)) + else if t1 != -1: // 仅 s1 tagged:入口 ⟹ s1 2L → A 2L;B 恒快 - cp = cp + e2_load_var(b, p+cp, 0, s1); - cp = cp + e2_mw_ld2(b, p+cp, 8, 9); - cp = cp + e2_load_var(b, p+cp, 10, s2); - cp = cp + e2_mw_sext(b, p+cp, 10, 11); - } else { + cp = cp + e2_load_var(b, p+cp, 0, s1) + cp = cp + e2_mw_ld2(b, p+cp, 8, 9) + cp = cp + e2_load_var(b, p+cp, 10, s2) + cp = cp + e2_mw_sext(b, p+cp, 10, 11) + else: // 仅 s2 tagged:入口 ⟹ s2 2L → A 恒快;B 2L - cp = cp + e2_load_var(b, p+cp, 8, s1); - cp = cp + e2_mw_sext(b, p+cp, 8, 9); - cp = cp + e2_load_var(b, p+cp, 0, s2); - cp = cp + e2_mw_ld2(b, p+cp, 10, 11); - } + cp = cp + e2_load_var(b, p+cp, 8, s1) + cp = cp + e2_mw_sext(b, p+cp, 8, 9) + cp = cp + e2_load_var(b, p+cp, 0, s2) + cp = cp + e2_mw_ld2(b, p+cp, 10, 11) // ── L_op:128 位运算(A=(r8,r9) B=(r10,r11))── - if is_cmp == 0 { + if is_cmp == 0: // 算术:结果 (r10 = lo, r11 = hi) - if is_sub == 0 { - w8(b, p+cp, 77); w8(b, p+cp+1, 1); w8(b, p+cp+2, 194); cp = cp + 3; // add r10, r8(lo + CF) - w8(b, p+cp, 77); w8(b, p+cp+1, 17); w8(b, p+cp+2, 203); cp = cp + 3; // adc r11, r9(hi 进位链) - } else { - w8(b, p+cp, 77); w8(b, p+cp+1, 41); w8(b, p+cp+2, 208); cp = cp + 3; // sub r8, r10(lo,CF=借位) - w8(b, p+cp, 76); w8(b, p+cp+1, 137); w8(b, p+cp+2, 216); cp = cp + 3; // mov rax, r11(暂存 bh) - w8(b, p+cp, 77); w8(b, p+cp+1, 137); w8(b, p+cp+2, 203); cp = cp + 3; // mov r11, r9(ah) - w8(b, p+cp, 73); w8(b, p+cp+1, 25); w8(b, p+cp+2, 195); cp = cp + 3; // sbb r11, rax(ah−bh−CF) - w8(b, p+cp, 77); w8(b, p+cp+1, 137); w8(b, p+cp+2, 194); cp = cp + 3; // mov r10, r8(lo) - } + if is_sub == 0: + w8(b, p+cp, 77) + w8(b, p+cp+1, 1) + w8(b, p+cp+2, 194) + cp = cp + 3 // add r10, r8(lo + CF) + w8(b, p+cp, 77) + w8(b, p+cp+1, 17) + w8(b, p+cp+2, 203) + cp = cp + 3 // adc r11, r9(hi 进位链) + else: + w8(b, p+cp, 77) + w8(b, p+cp+1, 41) + w8(b, p+cp+2, 208) + cp = cp + 3 // sub r8, r10(lo,CF=借位) + w8(b, p+cp, 76) + w8(b, p+cp+1, 137) + w8(b, p+cp+2, 216) + cp = cp + 3 // mov rax, r11(暂存 bh) + w8(b, p+cp, 77) + w8(b, p+cp+1, 137) + w8(b, p+cp+2, 203) + cp = cp + 3 // mov r11, r9(ah) + w8(b, p+cp, 73) + w8(b, p+cp+1, 25) + w8(b, p+cp+2, 195) + cp = cp + 3 // sbb r11, rax(ah−bh−CF) + w8(b, p+cp, 77) + w8(b, p+cp+1, 137) + w8(b, p+cp+2, 194) + cp = cp + 3 // mov r10, r8(lo) // 公共落值:fits-64 ⇔ hi == signmask(lo) → 降级快值;否则 2L 对象 // (结果界:|加数| ≤ 2^64−1 + 2^65 → |和| < 2^66 ≪ 2^127——M1 码域 // 内恒可表示,无需码域错误路径——见块注释)。 - cp = cp + e2_mov(b, p+cp, 2, 10); // mov rdx, r10 - w8(b, p+cp, 72); w8(b, p+cp+1, 193); w8(b, p+cp+2, 250); w8(b, p+cp+3, 63); cp = cp + 4; // sar rdx, 63(signmask) - w8(b, p+cp, 73); w8(b, p+cp+1, 57); w8(b, p+cp+2, 211); cp = cp + 3; // cmp r11, rdx(0x49 39 D3:REX.W+B——reg=rdx;错编 0x4D = reg r10 = cmp r11,r10——假 fit 截断,d1/d2 判别) - j_fit : ., mut = cp; w8(b, p+cp, 116); w8(b, p+cp+1, 0); cp = cp + 2; // je L_fit + cp = cp + e2_mov(b, p+cp, 2, 10) // mov rdx, r10 + w8(b, p+cp, 72) + w8(b, p+cp+1, 193) + w8(b, p+cp+2, 250) + w8(b, p+cp+3, 63) + cp = cp + 4 // sar rdx, 63(signmask) + w8(b, p+cp, 73) + w8(b, p+cp+1, 57) + w8(b, p+cp+2, 211) + cp = cp + 3 // cmp r11, rdx(0x49 39 D3:REX.W+B——reg=rdx;错编 0x4D = reg r10 = cmp r11,r10——假 fit 截断,d1/d2 判别) + j_fit : ., mut = cp + w8(b, p+cp, 116) + w8(b, p+cp+1, 0) + cp = cp + 2 // je L_fit // 2L 存储:alloc(16) + 2-limb 写 + 槽存指针 + tag=1(同 Task 3 块) - w8(b, p+cp, 65); w8(b, p+cp+1, 82); cp = cp + 2; // push r10 - w8(b, p+cp, 65); w8(b, p+cp+1, 83); cp = cp + 2; // push r11 - w8(b, p+cp, 191); e2_w32(b, p+cp+1, 16); cp = cp + 5; // mov edi, 16 - grow_alloc_patch(g_x86_alloc_patch_count + 1); - w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, p + cp); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - w8(b, p+cp, 232); e2_w32(b, p+cp+1, 0); cp = cp + 5; // call alloc - w8(b, p+cp, 65); w8(b, p+cp+1, 91); cp = cp + 2; // pop r11 - w8(b, p+cp, 65); w8(b, p+cp+1, 90); cp = cp + 2; // pop r10 - w8(b, p+cp, 76); w8(b, p+cp+1, 137); w8(b, p+cp+2, 16); cp = cp + 3; // mov [rax], r10 - w8(b, p+cp, 76); w8(b, p+cp+1, 137); w8(b, p+cp+2, 88); w8(b, p+cp+3, 8); cp = cp + 4; // mov [rax+8], r11 - cp = cp + e2_st(b, p+cp, 0, g2_slot(d)); // 值槽存指针 - cp = cp + e2_mw_b8(b, p+cp, g2_tag_off(d), 1); // tag = 1 - w8(b, p+cp, 233); e2_w32(b, p+cp+1, resume - (p+cp+5)); cp = cp + 5; // jmp rel32 → resume - l_fit := cp; - w8(b, p + j_fit + 1, l_fit - (j_fit + 2)); // 回填 je → L_fit - cp = cp + e2_st(b, p+cp, 10, g2_slot(d)); // 降级:快值落槽 - cp = cp + e2_mw_tag_clr(b, p+cp, d); // tag = 0 - w8(b, p+cp, 233); e2_w32(b, p+cp+1, resume - (p+cp+5)); cp = cp + 5; // jmp rel32 → resume - return cp; - } + w8(b, p+cp, 65) + w8(b, p+cp+1, 82) + cp = cp + 2 // push r10 + w8(b, p+cp, 65) + w8(b, p+cp+1, 83) + cp = cp + 2 // push r11 + w8(b, p+cp, 191) + e2_w32(b, p+cp+1, 16) + cp = cp + 5 // mov edi, 16 + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, p + cp) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + w8(b, p+cp, 232) + e2_w32(b, p+cp+1, 0) + cp = cp + 5 // call alloc + w8(b, p+cp, 65) + w8(b, p+cp+1, 91) + cp = cp + 2 // pop r11 + w8(b, p+cp, 65) + w8(b, p+cp+1, 90) + cp = cp + 2 // pop r10 + w8(b, p+cp, 76) + w8(b, p+cp+1, 137) + w8(b, p+cp+2, 16) + cp = cp + 3 // mov [rax], r10 + w8(b, p+cp, 76) + w8(b, p+cp+1, 137) + w8(b, p+cp+2, 88) + w8(b, p+cp+3, 8) + cp = cp + 4 // mov [rax+8], r11 + cp = cp + e2_st(b, p+cp, 0, g2_slot(d)) // 值槽存指针 + cp = cp + e2_mw_b8(b, p+cp, g2_tag_off(d), 1) // tag = 1 + w8(b, p+cp, 233) + e2_w32(b, p+cp+1, resume - (p+cp+5)) + cp = cp + 5 // jmp rel32 → resume + l_fit := cp + w8(b, p + j_fit + 1, l_fit - (j_fit + 2)) // 回填 je → L_fit + cp = cp + e2_st(b, p+cp, 10, g2_slot(d)) // 降级:快值落槽 + cp = cp + e2_mw_tag_clr(b, p+cp, d) // tag = 0 + w8(b, p+cp, 233) + e2_w32(b, p+cp+1, resume - (p+cp+5)) + cp = cp + 5 // jmp rel32 → resume + return cp // ── 比较:结果 0/1(128 位语义——高 limb 带符号、同则低 limb 无符号)── - if op == OP_EQ || op == OP_NE { - w8(b, p+cp, 77); w8(b, p+cp+1, 49); w8(b, p+cp+2, 208); cp = cp + 3; // xor r8, r10(al^bl) - w8(b, p+cp, 77); w8(b, p+cp+1, 49); w8(b, p+cp+2, 217); cp = cp + 3; // xor r9, r11(ah^bh) - w8(b, p+cp, 77); w8(b, p+cp+1, 9); w8(b, p+cp+2, 193); cp = cp + 3; // or r9, r8(ZF ⇔ 全等) - if op == OP_EQ { w8(b, p+cp, 15); w8(b, p+cp+1, 148); w8(b, p+cp+2, 192); cp = cp + 3; } // sete al - else { w8(b, p+cp, 15); w8(b, p+cp+1, 149); w8(b, p+cp+2, 192); cp = cp + 3; } // setne al - } else { + if op == OP_EQ || op == OP_NE: + w8(b, p+cp, 77) + w8(b, p+cp+1, 49) + w8(b, p+cp+2, 208) + cp = cp + 3 // xor r8, r10(al^bl) + w8(b, p+cp, 77) + w8(b, p+cp+1, 49) + w8(b, p+cp+2, 217) + cp = cp + 3 // xor r9, r11(ah^bh) + w8(b, p+cp, 77) + w8(b, p+cp+1, 9) + w8(b, p+cp+2, 193) + cp = cp + 3 // or r9, r8(ZF ⇔ 全等) + if op == OP_EQ: + w8(b, p+cp, 15) + w8(b, p+cp+1, 148) + w8(b, p+cp+2, 192) + cp = cp + 3 + // sete al + else: + w8(b, p+cp, 15) + w8(b, p+cp+1, 149) + w8(b, p+cp+2, 192) + cp = cp + 3 + // setne al + else: // LT/GT/LE/GE:eax 缺省 0(假);决定性 jcc → L_t(真)/L_d(假, // 前向);hi 同 → lo 无符号再判。布局: // xor eax; cmphi; j_ht L_t; j_hf L_d; cmplo; j_lf L_d; // L_t: mov eax,1; L_d: 落值(j_ht 落 L_t、其余落 L_d——全前向) - w8(b, p+cp, 49); w8(b, p+cp+1, 192); cp = cp + 2; // xor eax, eax - w8(b, p+cp, 77); w8(b, p+cp+1, 57); w8(b, p+cp+2, 217); cp = cp + 3; // cmp r9, r11(hi 符号) - hi_t : ., mut = 124; hi_f : ., mut = 127; // 缺省 LT/LE:jl → 真、jg → 假 - if op == OP_GT || op == OP_GE { hi_t = 127; hi_f = 124; } // GT/GE:jg → 真、jl → 假 - j_ht : ., mut = cp; w8(b, p+cp, hi_t); w8(b, p+cp+1, 0); cp = cp + 2; - j_hf : ., mut = cp; w8(b, p+cp, hi_f); w8(b, p+cp+1, 0); cp = cp + 2; - w8(b, p+cp, 77); w8(b, p+cp+1, 57); w8(b, p+cp+2, 208); cp = cp + 3; // cmp r8, r10(lo 无符号) - lo_f : ., mut = 115; // 缺省 LT:jae(lo ≥u → 假) - if op == OP_LE { lo_f = 119; } else if op == OP_GT { lo_f = 118; } else if op == OP_GE { lo_f = 114; } + w8(b, p+cp, 49) + w8(b, p+cp+1, 192) + cp = cp + 2 // xor eax, eax + w8(b, p+cp, 77) + w8(b, p+cp+1, 57) + w8(b, p+cp+2, 217) + cp = cp + 3 // cmp r9, r11(hi 符号) + hi_t : ., mut = 124 + hi_f : ., mut = 127 // 缺省 LT/LE:jl → 真、jg → 假 + if op == OP_GT || op == OP_GE: + hi_t = 127 + hi_f = 124 + // GT/GE:jg → 真、jl → 假 + j_ht : ., mut = cp + w8(b, p+cp, hi_t) + w8(b, p+cp+1, 0) + cp = cp + 2 + j_hf : ., mut = cp + w8(b, p+cp, hi_f) + w8(b, p+cp+1, 0) + cp = cp + 2 + w8(b, p+cp, 77) + w8(b, p+cp+1, 57) + w8(b, p+cp+2, 208) + cp = cp + 3 // cmp r8, r10(lo 无符号) + lo_f : ., mut = 115 // 缺省 LT:jae(lo ≥u → 假) + if op == OP_LE: + lo_f = 119 + else if op == OP_GT: + lo_f = 118 + else if op == OP_GE: + lo_f = 114 // LE: ja / GT: jbe / GE: jb(lo 不满足 → 假——L_d 前向) - j_lf : ., mut = cp; w8(b, p+cp, lo_f); w8(b, p+cp+1, 0); cp = cp + 2; + j_lf : ., mut = cp + w8(b, p+cp, lo_f) + w8(b, p+cp+1, 0) + cp = cp + 2 // L_t: mov eax, 1(落入 L_d 共享落值——全前向布局) - l_t := cp; w8(b, p+cp, 184); e2_w32(b, p+cp+1, 1); cp = cp + 5; + l_t := cp + w8(b, p+cp, 184) + e2_w32(b, p+cp+1, 1) + cp = cp + 5 // L_d = 当前 cp——回填(j_ht → L_t;j_hf/j_lf → L_d) - w8(b, p + j_ht + 1, l_t - (j_ht + 2)); - w8(b, p + j_hf + 1, cp - (j_hf + 2)); - w8(b, p + j_lf + 1, cp - (j_lf + 2)); - } + w8(b, p + j_ht + 1, l_t - (j_ht + 2)) + w8(b, p + j_hf + 1, cp - (j_hf + 2)) + w8(b, p + j_lf + 1, cp - (j_lf + 2)) // L_d:movzx + 落值(0/1 恒快;dest 若静态 tagged 防御性清 0——结果行 // 实际恒 untagged,见 mw_setup_tags 规则域) - w8(b, p+cp, 68); w8(b, p+cp+1, 15); w8(b, p+cp+2, 182); w8(b, p+cp+3, 208); cp = cp + 4; // movzx r10d, al - cp = cp + e2_st(b, p+cp, 10, g2_slot(d)); - cp = cp + e2_mw_tag_clr(b, p+cp, d); - w8(b, p+cp, 233); e2_w32(b, p+cp+1, resume - (p+cp+5)); cp = cp + 5; // jmp rel32 → resume - return cp; -} + w8(b, p+cp, 68) + w8(b, p+cp+1, 15) + w8(b, p+cp+2, 182) + w8(b, p+cp+3, 208) + cp = cp + 4 // movzx r10d, al + cp = cp + e2_st(b, p+cp, 10, g2_slot(d)) + cp = cp + e2_mw_tag_clr(b, p+cp, d) + w8(b, p+cp, 233) + e2_w32(b, p+cp+1, resume - (p+cp+5)) + cp = cp + 5 // jmp rel32 → resume + return cp diff --git a/src/compiler/ast.cr b/src/compiler/ast.cr index dbc0ff42..c03e89df 100644 --- a/src/compiler/ast.cr +++ b/src/compiler/ast.cr @@ -2,153 +2,151 @@ // Core compiler - shared type definitions and constants // Token kind constants -T_EOF : int = 0; -T_IDENT : int = 1; -T_INT : int = 2; -T_DEX : int = 3; // 3.14 字面量令牌(数值迁移 Task 3:T_FLOAT → T_DEX,值=binary64 位模式 = apx 快路径表示;精确解析在 Task 4) -T_STRING : int = 4; -T_FN : int = 5; -T_MUT : int = 7; -T_IF : int = 8; -T_ELSE : int = 9; -T_LOOP : int = 10; -T_FOR : int = 11; -T_IN : int = 12; -T_RETURN : int = 13; -T_BREAK : int = 14; -T_CONTINUE : int = 15; -T_STRUCT : int = 16; -T_ENUM : int = 17; -T_IMPL : int = 18; -T_PUB : int = 19; -T_TRUE : int = 20; -T_FALSE : int = 21; -T_MOVE : int = 22; -T_SELF : int = 23; -T_LPAREN : int = 24; -T_RPAREN : int = 25; -T_LBRACE : int = 26; -T_RBRACE : int = 27; -T_COMMA : int = 28; -T_SEMI : int = 29; -T_COLON : int = 30; -T_DOT : int = 31; -T_ARROW : int = 32; -T_EQ : int = 33; -T_EQEQ : int = 34; -T_BANG : int = 35; -T_BANGEQ : int = 36; -T_LT : int = 37; -T_GT : int = 38; -T_LTEQ : int = 39; -T_GTEQ : int = 40; -T_PLUS : int = 41; -T_MINUS : int = 42; -T_STAR : int = 43; -T_SLASH : int = 44; -T_ANDAND : int = 45; -T_PIPEPIPE : int = 46; -T_AMPERSAND : int = 47; -T_UNDERSCORE : int = 48; -T_UNIT : int = 49; -T_PATHSEP : int = 50; -T_LBRACKET : int = 51; -T_RBRACKET : int = 52; -T_MATCH : int = 53; -T_FATARROW : int = 54; -T_PERCENT : int = 55; -T_CHAR : int = 56; -T_WHILE : int = 57; -T_DOTDOT : int = 58; -T_DOTDOTDOT : int = 59; -T_TYPE : int = 60; -T_MOD : int = 61; -T_IMPORT : int = 62; -T_AS : int = 63; -T_GO : int = 64; -T_AWAIT : int = 65; -T_FLOW : int = 66; -T_YIELD : int = 67; -T_UNSAFE : int = 68; -T_INTERFACE : int = 97; -T_COLON_EQ : int = 98; -T_AUTO : int = 69; -T_AT : int = 70; -T_FILEID : int = 71; -T_QUESTION : int = 72; -T_PLUS_EQ : int = 73; -T_MINUS_EQ : int = 74; -T_STAR_EQ : int = 75; -T_SLASH_EQ : int = 76; +T_EOF : int = 0 +T_IDENT : int = 1 +T_INT : int = 2 +T_DEX : int = 3 // 3.14 字面量令牌(数值迁移 Task 3:T_FLOAT → T_DEX,值=binary64 位模式 = apx 快路径表示;精确解析在 Task 4) +T_STRING : int = 4 +T_FN : int = 5 +T_MUT : int = 7 +T_IF : int = 8 +T_ELSE : int = 9 +T_LOOP : int = 10 +T_FOR : int = 11 +T_IN : int = 12 +T_RETURN : int = 13 +T_BREAK : int = 14 +T_CONTINUE : int = 15 +T_STRUCT : int = 16 +T_ENUM : int = 17 +T_IMPL : int = 18 +T_PUB : int = 19 +T_TRUE : int = 20 +T_FALSE : int = 21 +T_MOVE : int = 22 +T_SELF : int = 23 +T_LPAREN : int = 24 +T_RPAREN : int = 25 +T_LBRACE : int = 26 +T_RBRACE : int = 27 +T_COMMA : int = 28 +T_SEMI : int = 29 +T_COLON : int = 30 +T_DOT : int = 31 +T_ARROW : int = 32 +T_EQ : int = 33 +T_EQEQ : int = 34 +T_BANG : int = 35 +T_BANGEQ : int = 36 +T_LT : int = 37 +T_GT : int = 38 +T_LTEQ : int = 39 +T_GTEQ : int = 40 +T_PLUS : int = 41 +T_MINUS : int = 42 +T_STAR : int = 43 +T_SLASH : int = 44 +T_ANDAND : int = 45 +T_PIPEPIPE : int = 46 +T_AMPERSAND : int = 47 +T_UNDERSCORE : int = 48 +T_UNIT : int = 49 +T_PATHSEP : int = 50 +T_LBRACKET : int = 51 +T_RBRACKET : int = 52 +T_MATCH : int = 53 +T_FATARROW : int = 54 +T_PERCENT : int = 55 +T_CHAR : int = 56 +T_WHILE : int = 57 +T_DOTDOT : int = 58 +T_DOTDOTDOT : int = 59 +T_TYPE : int = 60 +T_MOD : int = 61 +T_IMPORT : int = 62 +T_AS : int = 63 +T_GO : int = 64 +T_AWAIT : int = 65 +T_FLOW : int = 66 +T_YIELD : int = 67 +T_UNSAFE : int = 68 +T_INTERFACE : int = 97 +T_COLON_EQ : int = 98 +T_AUTO : int = 69 +T_AT : int = 70 +T_FILEID : int = 71 +T_QUESTION : int = 72 +T_PLUS_EQ : int = 73 +T_MINUS_EQ : int = 74 +T_STAR_EQ : int = 75 +T_SLASH_EQ : int = 76 // 77-86 原为宽度后缀 token kind(T_INT_I8..T_INT_U64 / T_FLOAT_F32 / T_FLOAT_F64)。 // 2026-09-10 语言面收窄 §2 删除:lexer 从不发射这些 kind(宽度后缀已退役,改响亮报错), // parser 侧引用同步移除。**勿重编号**——编号空间稳定(先例:T_FLOAT_TYPE 91 已删除)。 -T_NONE : int = 87; -T_SOME : int = 88; -T_LET : int = 89; -T_INT_TYPE : int = 90; +T_NONE : int = 87 +T_SOME : int = 88 +T_LET : int = 89 +T_INT_TYPE : int = 90 // T_FLOAT_TYPE 91 已删除(数值迁移 Task 5:float 类型名移除;勿重编号——保持 LSP // 区间 T_INT_TYPE..T_AUTO_TYPE 90..95 连续,见 analysis.cr 说明) -T_BOOL_TYPE : int = 92; -T_UNIT_TYPE : int = 93; -T_STR_TYPE : int = 94; -T_AUTO_TYPE : int = 95; -T_REF : int = 96; -T_DYN : int = 99; // dynamic type -T_EXTERN : int = 100; // extern "C" / foreign function declaration +T_BOOL_TYPE : int = 92 +T_UNIT_TYPE : int = 93 +T_STR_TYPE : int = 94 +T_AUTO_TYPE : int = 95 +T_REF : int = 96 +T_DYN : int = 99 // dynamic type +T_EXTERN : int = 100 // extern "C" / foreign function declaration // 101:批 6「正式规约语法」(T1 词法面)——`#` 标注 sigil 的 token。 // **取号 = T_ 空间空洞外的下一个自由号**(已用 0..100;空洞 6 / 77-86 / 91 **不占**—— // 占空洞会与「勿重编号」的既存约定混淆)。**既有 0..100 一个不动**(T1 判据①)。 // 语义约束:`#` 后必须跟 IDENT(`check`/`ensure` **不做关键字**——本仓已有 `fn check` // (parser.cr:30)与 CLI 子命令 `"check"`(main.cr:235),做关键字会当场打断自源)。 -T_HASH : int = 101; -T_INTERP : int = 102; // 字符串插值洞 token(批 8 插值展开):lexeme = 洞内原文,iv bit0/bit1 = 同一字面量的 part 链,bit2 = 洞已闭合 +T_HASH : int = 101 +T_INTERP : int = 102 // 字符串插值洞 token(批 8 插值展开):lexeme = 洞内原文,iv bit0/bit1 = 同一字面量的 part 链,bit2 = 洞已闭合 // W_I8..W_F64(1..10)原为「宽度标注」值域,仅供宽度后缀 token 分支使用。 // 2026-09-10 语言面收窄 §2 随死分支一并删除。**勿重编号**。 // Type constants -TY_INT : int = 0; -TY_DEX : int = 1; // dex 精确小数(数值迁移 Task 3:TY_FLOAT 更名;Task 5:float 类型名移除,用户写 dex) -TY_BOOL : int = 2; -TY_STRING : int = 3; -TY_UNIT : int = 4; -TY_NEVER : int = 5; -TY_CHAR : int = 6; -TY_GENERIC_PARAM : int = 7; // special sentinel for generic type params -TY_DEX_S : int = 8; // dex 定点形式(TI_DEX_S)的类型表占位 data(终审 M1:占住表项 +TY_INT : int = 0 +TY_DEX : int = 1 // dex 精确小数(数值迁移 Task 3:TY_FLOAT 更名;Task 5:float 类型名移除,用户写 dex) +TY_BOOL : int = 2 +TY_STRING : int = 3 +TY_UNIT : int = 4 +TY_NEVER : int = 5 +TY_CHAR : int = 6 +TY_GENERIC_PARAM : int = 7 // special sentinel for generic type params +TY_DEX_S : int = 8 // dex 定点形式(TI_DEX_S)的类型表占位 data(终审 M1:占住表项 // 下标 8,用户类型从 9 起;占位项永不参与解析/运算) -MAX_GENERICS : int = 4; // max generic params per declaration (language limit) +MAX_GENERICS : int = 4 // max generic params per declaration (language limit) // 容量批 T3(裁-CAP-2 (a)):`MAX_STRUCT_FIELDS` / `MAX_ENUM_VARIANTS` / `MAX_VARIANT_TYPES` // **已退役**(记录布局迁侧表 ⇒ 三面上限解除,P022/P023 硬错随之停发)。数值 16 不再具有 // 语义(旧定长内嵌槽区的容量);布局真源 = `dyn_arr.cr` 的 OFF_SI_*/OFF_EI_* 与侧表访问器。 // Token struct -struct Token { +struct Token: kind: int, lexeme: string, int_val: int, line: int, col: int, -} // ── 记录镜像声明(旧):容量批 T3 起**删除**——`FuncInfo`/`StructInfo`/`EnumInfo`/ // `EnumVariant` 三个镜像结构在全仓**零类型使用点**(仅注释命中),且其定长槽区(`[.;64]` // 等)与运行期布局早已不一致(旧布局 = 内存字节缓冲 + 定长内嵌槽区,T3 起字段/变体迁 // 侧表)。布局真源 = `dyn_arr.cr`(ESZ_*/OFF_* 常量 + 侧表访问器)。 // Loop context (for break/continue) -struct LoopInfo { +struct LoopInfo: start_label: string, end_label: string, -} // Block statement index storage: sequential statement indices for each block // EXPR_BLOCK uses a=start_idx_into_g_block_stmts, b=stmt_count // Flat AST node - representation varies by kind -struct ASTNode { +struct ASTNode: kind: int, a: int, // child/index slot 1 b: int, // child/index slot 2 @@ -158,155 +156,153 @@ struct ASTNode { data: int, // extra data (mutable flag, etc.) line: int, col: int, -} // AST node kind constants -EXPR_NONE : int = 0; -EXPR_INT : int = 1; // int_val = value -EXPR_DEX : int = 27; // int_val = value (as scaled int) —— 3.14 字面量节点(数值迁移 Task 3 更名) -EXPR_STRING : int = 2; // int_val = str table index -EXPR_BOOL : int = 3; // int_val = 0/1 -EXPR_IDENT : int = 4; // int_val = name str table index -EXPR_BINARY : int = 5; // a=left, b=right, c=opcode -EXPR_UNARY : int = 6; // a=operand, c=opcode -EXPR_CALL : int = 7; // a=func, b=first arg idx, c=arg count, type_val=CALL_FLAG_* -CALL_FLAG_MODULE : int = 1; -CALL_FLAG_INLINE : int = 2; +EXPR_NONE : int = 0 +EXPR_INT : int = 1 // int_val = value +EXPR_DEX : int = 27 // int_val = value (as scaled int) —— 3.14 字面量节点(数值迁移 Task 3 更名) +EXPR_STRING : int = 2 // int_val = str table index +EXPR_BOOL : int = 3 // int_val = 0/1 +EXPR_IDENT : int = 4 // int_val = name str table index +EXPR_BINARY : int = 5 // a=left, b=right, c=opcode +EXPR_UNARY : int = 6 // a=operand, c=opcode +EXPR_CALL : int = 7 // a=func, b=first arg idx, c=arg count, type_val=CALL_FLAG_* +CALL_FLAG_MODULE : int = 1 +CALL_FLAG_INLINE : int = 2 // R2 P3b Task 6(Step 3,mangling 退役):接口方法调用(泛型形参接收者,`fn f[T: I]` 体内 // `x.m()`)——data = **泛型形参名 ni**(不是合成的 "T.m" 串);实例化时由 monomorph 按 // 具体类型查方法表(`iface_find_method`)解析为真实函数名。旧态 = 名字拼接 + 克隆期文本替换, // 实例体内调用目标悬空(产物运行 rc=139,实测)。 -CALL_FLAG_IFACE_METHOD : int = 4; -EXPR_BLOCK : int = 8; // a=g_block_stmts start, b=stmt count -EXPR_IF : int = 9; // a=cond, b=then, c=else (-1 if none) -EXPR_LOOP : int = 10; // a=body -EXPR_LET : int = 11; // a=name idx, b=type, c=value, data=is_mut -EXPR_RETURN : int = 12; // a=value expr (-1 if none) -EXPR_FIELD : int = 13; // a=object, int_val=field name idx -EXPR_INDEX : int = 14; // a=object, b=index -EXPR_ASSIGN : int = 15; // a=target, b=value -EXPR_STRUCT : int = 16; // a=type name idx, b=first wrapper(g_ast 中连续;wrapper kind=EXPR_NONE 且 a=字段值节点、b=字段名 idx(TODO #2026-09-11-11 ①;-1 = 无名字信息,按位序回落)), c=field count (struct literal) -EXPR_FN : int = 17; // a=name idx, b=first param, c=param count, d=body, data=return_type -EXPR_PARAM : int = 18; // a=name idx, int_val=type +CALL_FLAG_IFACE_METHOD : int = 4 +EXPR_BLOCK : int = 8 // a=g_block_stmts start, b=stmt count +EXPR_IF : int = 9 // a=cond, b=then, c=else (-1 if none) +EXPR_LOOP : int = 10 // a=body +EXPR_LET : int = 11 // a=name idx, b=type, c=value, data=is_mut +EXPR_RETURN : int = 12 // a=value expr (-1 if none) +EXPR_FIELD : int = 13 // a=object, int_val=field name idx +EXPR_INDEX : int = 14 // a=object, b=index +EXPR_ASSIGN : int = 15 // a=target, b=value +EXPR_STRUCT : int = 16 // a=type name idx, b=first wrapper(g_ast 中连续;wrapper kind=EXPR_NONE 且 a=字段值节点、b=字段名 idx(TODO #2026-09-11-11 ①;-1 = 无名字信息,按位序回落)), c=field count (struct literal) +EXPR_FN : int = 17 // a=name idx, b=first param, c=param count, d=body, data=return_type +EXPR_PARAM : int = 18 // a=name idx, int_val=type // 表示层概念(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 -EXPR_ARRAY : int = 19; // a=first elem, b=elem count -EXPR_BREAK : int = 20; -EXPR_CONTINUE : int = 21; -EXPR_FOR : int = 22; // a=var name idx, b=iter, c=body -EXPR_MATCH : int = 23; // a=expr, b=first arm, c=arm count -EXPR_ARM : int = 24; // a=pattern, b=body -EXPR_WILDCARD : int = 25; -EXPR_ENUMPAT : int = 26; // a=name idx, b=first subpat, c=subpat count -EXPR_STMT : int = 28; // a=inner expr; expression used as statement (with );), returns unit -EXPR_CHAR : int = 29; // int_val = codepoint -EXPR_WHILE : int = 30; // a=cond, b=body -EXPR_RANGE : int = 31; // a=start, b=end -EXPR_MOVE : int = 32; // a=expr being moved -EXPR_ENUM_CONSTRUCTOR : int = 37; // a=name idx, b=first arg, c=arg count -EXPR_REFTYPE : int = 38; // a=inner type node, data=mut flag (for &T / &mut T in type position) -EXPR_GENERIC_APPLY : int = 39; // a=base name idx, b=first arg type node, c=arg count -EXPR_TUPLE : int = 40; // a=first wrapper(g_ast 中连续;wrapper kind=EXPR_NONE 且 a=元素值节点), b=elem count (tuple literal) -EXPR_ARG : int = 41; // a=expr, b=next arg node or -1 (argument linked list) -EXPR_GO : int = 42; // go expr: a=-1, b=body; go var start..end expr: a=-1, b=body, c=iter_ni, data=range_node -EXPR_FLOW : int = 43; // flow fn — a=fn_name_ni, b=param_count, c=first_param, data=body -EXPR_YIELD : int = 44; // yield expr — a=value expr -EXPR_AWAIT : int = 45; // await expr — a=value expr (future/flow to wait on) -EXPR_AT : int = 46; // @builtin: a=name_ni, b=args_node, c=0, iv=0, tv=0, data=0 +EXPR_ARRAY : int = 19 // a=first elem, b=elem count +EXPR_BREAK : int = 20 +EXPR_CONTINUE : int = 21 +EXPR_FOR : int = 22 // a=var name idx, b=iter, c=body +EXPR_MATCH : int = 23 // a=expr, b=first arm, c=arm count +EXPR_ARM : int = 24 // a=pattern, b=body +EXPR_WILDCARD : int = 25 +EXPR_ENUMPAT : int = 26 // a=name idx, b=first subpat, c=subpat count +EXPR_STMT : int = 28 // a=inner expr; expression used as statement (with );), returns unit +EXPR_CHAR : int = 29 // int_val = codepoint +EXPR_WHILE : int = 30 // a=cond, b=body +EXPR_RANGE : int = 31 // a=start, b=end +EXPR_MOVE : int = 32 // a=expr being moved +EXPR_ENUM_CONSTRUCTOR : int = 37 // a=name idx, b=first arg, c=arg count +EXPR_REFTYPE : int = 38 // a=inner type node, data=mut flag (for &T / &mut T in type position) +EXPR_GENERIC_APPLY : int = 39 // a=base name idx, b=first arg type node, c=arg count +EXPR_TUPLE : int = 40 // a=first wrapper(g_ast 中连续;wrapper kind=EXPR_NONE 且 a=元素值节点), b=elem count (tuple literal) +EXPR_ARG : int = 41 // a=expr, b=next arg node or -1 (argument linked list) +EXPR_GO : int = 42 // go expr: a=-1, b=body; go var start..end expr: a=-1, b=body, c=iter_ni, data=range_node +EXPR_FLOW : int = 43 // flow fn — a=fn_name_ni, b=param_count, c=first_param, data=body +EXPR_YIELD : int = 44 // yield expr — a=value expr +EXPR_AWAIT : int = 45 // await expr — a=value expr (future/flow to wait on) +EXPR_AT : int = 46 // @builtin: a=name_ni, b=args_node, c=0, iv=0, tv=0, data=0 // Desugared constructs -EXPR_TRY : int = 33; // a=expr being tried (? operator) -EXPR_UNSAFE : int = 34; // a=block body -EXPR_STRUCTPAT : int = 35; // struct pattern: a=name ni, b=first wrapper(连续;wrapper kind=EXPR_NONE 且 a=子模式节点), c=field count -EXPR_AS : int = 36; // a=expr, b=type node (cast: expr as Type) -EXPR_PTRTYPE : int = 47; // a=inner_type (for *T in type position) -EXPR_EXTERN : int = 48; // a=name_ni, b=first_param, c=param_count, data=ffi_lang_ni +EXPR_TRY : int = 33 // a=expr being tried (? operator) +EXPR_UNSAFE : int = 34 // a=block body +EXPR_STRUCTPAT : int = 35 // struct pattern: a=name ni, b=first wrapper(连续;wrapper kind=EXPR_NONE 且 a=子模式节点), c=field count +EXPR_AS : int = 36 // a=expr, b=type node (cast: expr as Type) +EXPR_PTRTYPE : int = 47 // a=inner_type (for *T in type position) +EXPR_EXTERN : int = 48 // a=name_ni, b=first_param, c=param_count, data=ffi_lang_ni // R2 P3 Task 4:`T?` 的目标形态(退役「T? → EXPR_GENERIC_APPLY(Option, T)」的**名字依赖**: // 旧形态要求内建 Option 名注册在符号表里,且 §5.4 的「T? = T ∪ null」无法表达)。 // a = 内层类型节点。-1 内层 / 非法形态 → res_type_node 落 TI_UNIT(照各类型节点分支同款)。 -EXPR_OPTIONAL : int = 49; // a=inner type node (T? 类型位置) +EXPR_OPTIONAL : int = 49 // a=inner type node (T? 类型位置) // 字符串插值洞(批 8 插值展开):`"a${expr}b"` 在 parser 处被拆成 // `("a" + HOLE(int_str(expr))) + "b"` 形态;HOLE 节点由 parser 建、**checker 就地改写**为 // 带类型转换的调用(`ast_set_kind/a/b/c`,父节点只存索引 ⇒ 无需父指针)。 // data = 洞文本(interned),line/col = 洞在源中的位置(诊断用)。 -EXPR_INTERP_HOLE : int = 50; // data=hole text ni(解析期);checker 改写后本 kind 不再存在 +EXPR_INTERP_HOLE : int = 50 // data=hole text ni(解析期);checker 改写后本 kind 不再存在 // Field representation in struct literal: two consecutive AST nodes // (name_idx, value_idx, line=line, col=col) -struct FieldPair { +struct FieldPair: name_idx: int, value_idx: int, line: int, col: int, -} // Binary operator codes -OP_ADD : int = 1; -OP_SUB : int = 2; -OP_MUL : int = 3; -OP_DIV : int = 4; -OP_MOD : int = 5; -OP_EQ : int = 6; -OP_NE : int = 7; -OP_LT : int = 8; -OP_GT : int = 9; -OP_LE : int = 10; -OP_GE : int = 11; -OP_AND : int = 12; -OP_OR : int = 13; -OP_ASSIGN : int = 14; -OP_SHL : int = 15; // strength reduction: x << n -OP_SHR : int = 16; // strength reduction: x >> n -OP_PTR_ADD : int = 17; // p + n (p: *T, n: int) → scaled by sizeof(T) -OP_PTR_SUB : int = 18; // p - n -OP_PTR_DIFF : int = 19; // p - q → element count +OP_ADD : int = 1 +OP_SUB : int = 2 +OP_MUL : int = 3 +OP_DIV : int = 4 +OP_MOD : int = 5 +OP_EQ : int = 6 +OP_NE : int = 7 +OP_LT : int = 8 +OP_GT : int = 9 +OP_LE : int = 10 +OP_GE : int = 11 +OP_AND : int = 12 +OP_OR : int = 13 +OP_ASSIGN : int = 14 +OP_SHL : int = 15 // strength reduction: x << n +OP_SHR : int = 16 // strength reduction: x >> n +OP_PTR_ADD : int = 17 // p + n (p: *T, n: int) → scaled by sizeof(T) +OP_PTR_SUB : int = 18 // p - n +OP_PTR_DIFF : int = 19 // p - q → element count // Unary operator codes -UOP_NEG : int = 1; -UOP_NOT : int = 2; -UOP_REF : int = 3; -UOP_DEREF : int = 4; +UOP_NEG : int = 1 +UOP_NOT : int = 2 +UOP_REF : int = 3 +UOP_DEREF : int = 4 // Type table pre-allocated indices (for checker type system) -TI_INT : int = 0; -TI_DEX : int = 1; // dex 精确小数(数值迁移 Task 3:TI_FLOAT 更名,编号不变——.ccr 兼容) -TI_BOOL : int = 2; -TI_STR : int = 3; -TI_UNIT : int = 4; -TI_NEVER : int = 5; -TI_CHAR : int = 6; -TI_DYN : int = 7; // dynamic type +TI_INT : int = 0 +TI_DEX : int = 1 // dex 精确小数(数值迁移 Task 3:TI_FLOAT 更名,编号不变——.ccr 兼容) +TI_BOOL : int = 2 +TI_STR : int = 3 +TI_UNIT : int = 4 +TI_NEVER : int = 5 +TI_CHAR : int = 6 +TI_DYN : int = 7 // dynamic type // TI_DEX_S = 8:dex 定点精确形式(缩放整数)的 IR 变量类型(数值迁移 Task 4)。 // 终审 M1 修复:8 现在是类型表的占位表项下标(init_types 末尾 alloc_type(TYP_BASE, // TY_DEX_S, 0) 占位)——用户类型从 9 起,TI_DEX_S 哨兵永不再与真实类型碰撞。 // TI_DEX_S 仍不查类型表(type_size/type_align/is_ptr_var 处保留显式守卫,见 ir_gen.cr), // 值永远以 8 字节槽存储。 -TI_DEX_S : int = 8; +TI_DEX_S : int = 8 // Type table entry kinds -TYP_BASE : int = 0; // data = TY_* constant -TYP_NAMED : int = 1; // data = name string index +TYP_BASE : int = 0 // data = TY_* constant +TYP_NAMED : int = 1 // data = name string index // 表示层概念(2026-09-10 语言面收窄裁决 §1):`[T; N]` 退役为「内联容量存储」表示提示(语义归处 = product / 序列+长度约束 / F11)——完整注记见本文件 EXPR_ARRAY 常量处,spec 见 docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md §1 -TYP_ARRAY : int = 2; // data = element type idx, extra = size -TYP_REF : int = 3; // data = inner type idx, extra = mut flag -TYP_PTR : int = 4; // data=pointee_type, extra=address_space (0=tracked, 1=external) -TYP_GENERIC_PARAM : int = 7; // data = name string index (unresolved generic param) -TYP_GENERIC_APPLY : int = 8; // data = base type idx, extra = arg list start in g_gen_apply_data +TYP_ARRAY : int = 2 // data = element type idx, extra = size +TYP_REF : int = 3 // data = inner type idx, extra = mut flag +TYP_PTR : int = 4 // data=pointee_type, extra=address_space (0=tracked, 1=external) +TYP_GENERIC_PARAM : int = 7 // data = name string index (unresolved generic param) +TYP_GENERIC_APPLY : int = 8 // data = base type idx, extra = arg list start in g_gen_apply_data // 表示层概念(2026-09-10 语言面收窄裁决 §1):`[T; N]` 退役为「内联容量存储」表示提示(语义归处 = product / 序列+长度约束 / F11)——完整注记见本文件 EXPR_ARRAY 常量处,spec 见 docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md §1 -TYP_SLICE : int = 9; // data = element type idx (dynamic-length view into array) -TYP_TUPLE : int = 10; // data = element_count, extra = elem types start in g_gen_apply_data -TYP_DYN : int = 11; // data = type set bitmap (0 = single known type) +TYP_SLICE : int = 9 // data = element type idx (dynamic-length view into array) +TYP_TUPLE : int = 10 // data = element_count, extra = elem types start in g_gen_apply_data +TYP_DYN : int = 11 // data = type set bitmap (0 = single known type) // R2 P3 Task 4(联合/可选):`T?` = `T ∪ null`(spec §5.4)——不再是「内建 Option[T] 命名类型」。 // data = 内层类型行;桥接侧译作 union(内层项, null 原子项)(ty_shadow.cr 的 TYP_OPTIONAL 分支)。 // 引擎面 = 联合项(非原子类)⇒ `iface_kind_of` 对之行回 -1(不得按单一原子处理)。 -TYP_OPTIONAL : int = 12; // data = inner type idx(T? = T ∪ null) +TYP_OPTIONAL : int = 12 // data = inner type idx(T? = T ∪ null) // `null` 的类型(`None` 值的类型;spec §5.4 的「T ∪ null」里的 null)。值域单点 ⇒ 引擎侧 // AK_NULL 原子(原生第九员);行不带参数(None 无载荷)。与 AK_UNIT/AK_NEVER 均不相交。 -TYP_NULL : int = 13; // 无字段(data/extra 恒 0) +TYP_NULL : int = 13 // 无字段(data/extra 恒 0) // Error codes: category * 1000 + number, matching docs/developer/errors.md // Category 0 = unclassified (000-) @@ -328,304 +324,308 @@ TYP_NULL : int = 13; // 无字段(data/extra 恒 0) // Category 16= ICE (Internal compiler error) // P0xx — Syntax (Parser) -EC_P_EXPECTED : int = 1001; // P001 Expected X, got Y -EC_P_TOPLEVEL : int = 1002; // P002 Unexpected token at top level -EC_P_EXPR : int = 1003; // P003 Unexpected token in expression -EC_P_ARR_SIZE : int = 1004; // P004 Array size not constant -EC_P_PATTERN : int = 1005; // P005 Unexpected token in pattern -EC_P_BRACKET : int = 1006; // P006 Missing closing delimiter -EC_P_SEMI : int = 1007; // P007 Expected semicolon -EC_P_STRUCT_EMPTY : int = 1008; // P008 Empty struct body -EC_P_ENUM_EMPTY : int = 1009; // P009 Empty enum body -EC_P_FN_EMPTY : int = 1010; // P010 Empty function body -EC_P_PARAM_TYPE : int = 1011; // P011 Parameter needs type annotation -EC_P_GENERIC_LIST : int = 1012; // P012 Invalid generic param list -EC_P_FIELD_SYNTAX : int = 1013; // P013 Invalid field syntax -EC_P_MATCH_EMPTY : int = 1014; // P014 Match body empty -EC_P_PAT_BIND : int = 1015; // P015 Invalid pattern binding -EC_P_IMPORT_PATH : int = 1016; // P016 Invalid import path -EC_P_FILEID : int = 1017; // P017 Invalid fileid declaration -EC_P_VAR_DECL : int = 1018; // P018 Invalid var declaration -EC_P_LIT_OVERFLOW : int = 1019; // P019 Numeric literal overflow -EC_P_TOO_MANY_PARAMS : int = 1020; // P020 Too many function parameters (FuncInfo 参数槽区容量) -EC_P_NESTED_FN : int = 1021; // P021 Nested function declaration (函数声明仅限顶层) -EC_P_ENUM_LIMIT : int = 1022; // P022 **已退役**(容量批 T3:变体/载荷上限解除,零 raise) -EC_P_STRUCT_LIMIT : int = 1023; // P023 **已退役**(容量批 T3:字段上限解除,零 raise) -EC_P_EXTERN_OPTIONAL : int = 1024; // P024 extern 声明含可选形参/返回(C ABI 无可选表示;批 8 条目 3) -EC_P_TOPLEVEL_TOKEN : int = 1025; // P025 Unrecognized top-level token(顶层兜底不再静默吞;批 8 条目 4) -EC_P_APX_TAG : int = 1026; // P026 `apx` 标签不适用于该声明(白名单 = 显式 dex / int;批 8 条目 5) -EC_P_INTERP_UNCLOSED : int = 1027; // P027 **畸形插值**(`${` 无配对 `}` / `${}` 空洞 / 洞内尾随垃圾;此前静默吞到行尾) -EC_P_INTERP_TYPE : int = 1028; // P028 插值洞类型不可插值(白名单 = string/int/dex/bool/char;fail-closed) -EC_P_INTERP_HOLE_LEAK : int = 1029; // P029 **内部不变量破坏**:插值洞到达发射面(checker 未改写;见 ir_gen 兜底) +EC_P_EXPECTED : int = 1001 // P001 Expected X, got Y +EC_P_TOPLEVEL : int = 1002 // P002 Unexpected token at top level +EC_P_EXPR : int = 1003 // P003 Unexpected token in expression +EC_P_ARR_SIZE : int = 1004 // P004 Array size not constant +EC_P_PATTERN : int = 1005 // P005 Unexpected token in pattern +EC_P_BRACKET : int = 1006 // P006 Missing closing delimiter +EC_P_SEMI : int = 1007 // P007 Expected semicolon +EC_P_STRUCT_EMPTY : int = 1008 // P008 Empty struct body +EC_P_ENUM_EMPTY : int = 1009 // P009 Empty enum body +EC_P_FN_EMPTY : int = 1010 // P010 Empty function body +EC_P_PARAM_TYPE : int = 1011 // P011 Parameter needs type annotation +EC_P_GENERIC_LIST : int = 1012 // P012 Invalid generic param list +EC_P_FIELD_SYNTAX : int = 1013 // P013 Invalid field syntax +EC_P_MATCH_EMPTY : int = 1014 // P014 Match body empty +EC_P_PAT_BIND : int = 1015 // P015 Invalid pattern binding +EC_P_IMPORT_PATH : int = 1016 // P016 Invalid import path +EC_P_FILEID : int = 1017 // P017 Invalid fileid declaration +EC_P_VAR_DECL : int = 1018 // P018 Invalid var declaration +EC_P_LIT_OVERFLOW : int = 1019 // P019 Numeric literal overflow +EC_P_TOO_MANY_PARAMS : int = 1020 // P020 Too many function parameters (FuncInfo 参数槽区容量) +EC_P_NESTED_FN : int = 1021 // P021 Nested function declaration (函数声明仅限顶层) +EC_P_ENUM_LIMIT : int = 1022 // P022 **已退役**(容量批 T3:变体/载荷上限解除,零 raise) +EC_P_STRUCT_LIMIT : int = 1023 // P023 **已退役**(容量批 T3:字段上限解除,零 raise) +EC_P_EXTERN_OPTIONAL : int = 1024 // P024 extern 声明含可选形参/返回(C ABI 无可选表示;批 8 条目 3) +EC_P_TOPLEVEL_TOKEN : int = 1025 // P025 Unrecognized top-level token(顶层兜底不再静默吞;批 8 条目 4) +EC_P_APX_TAG : int = 1026 // P026 `apx` 标签不适用于该声明(白名单 = 显式 dex / int;批 8 条目 5) +EC_P_INTERP_UNCLOSED : int = 1027 // P027 **畸形插值**(`${` 无配对 `}` / `${}` 空洞 / 洞内尾随垃圾;此前静默吞到行尾) +EC_P_INTERP_TYPE : int = 1028 // P028 插值洞类型不可插值(白名单 = string/int/dex/bool/char;fail-closed) +EC_P_INTERP_HOLE_LEAK : int = 1029 // P029 **内部不变量破坏**:插值洞到达发射面(checker 未改写;见 ir_gen 兜底) // N0xx — Name Resolution -EC_N_UNDEFINED : int = 2001; // N001 Undefined name -EC_N_STRUCT : int = 2002; // N002 Undefined struct -EC_N_FIELD : int = 2003; // N003 Undefined field -EC_N_ENUM_CON : int = 2004; // N004 Undefined enum constructor -EC_N_ENUM_VAR : int = 2005; // N005 Undefined enum variant -EC_N_FUNC : int = 2006; // N006 Undefined function -EC_N_TYPE : int = 2007; // N007 Undefined type -EC_N_METHOD : int = 2008; // N008 Undefined method -EC_N_GENERIC_TYPE : int = 2009; // N009 Undefined type in generic apply -EC_N_GENERIC_PARAM : int = 2010; // N010 Undefined generic param -EC_N_DUPLICATE : int = 2011; // N011 Duplicate definition -EC_N_DUP_FIELD : int = 2012; // N012 Duplicate field -EC_N_DUP_VARIANT : int = 2013; // N013 Duplicate variant -EC_N_DUP_FUNC : int = 2014; // N014 Duplicate function -EC_N_FILEID_CONFLICT : int = 2015; // N015 Fileid conflict -EC_N_MODULE : int = 2016; // N016 Undefined module -EC_N_PROJECT : int = 2017; // N017 Undefined project -EC_N_CYCLE : int = 2018; // N018 Cyclic import -EC_N_IMPORT_FILE : int = 2019; // N019 Import file not found -EC_N_IMPORT_READ : int = 2020; // N020 Import read failure -EC_N_REEXPORT : int = 2021; // N021 Re-export conflict +EC_N_UNDEFINED : int = 2001 // N001 Undefined name +EC_N_STRUCT : int = 2002 // N002 Undefined struct +EC_N_FIELD : int = 2003 // N003 Undefined field +EC_N_ENUM_CON : int = 2004 // N004 Undefined enum constructor +EC_N_ENUM_VAR : int = 2005 // N005 Undefined enum variant +EC_N_FUNC : int = 2006 // N006 Undefined function +EC_N_TYPE : int = 2007 // N007 Undefined type +EC_N_METHOD : int = 2008 // N008 Undefined method +EC_N_GENERIC_TYPE : int = 2009 // N009 Undefined type in generic apply +EC_N_GENERIC_PARAM : int = 2010 // N010 Undefined generic param +EC_N_DUPLICATE : int = 2011 // N011 Duplicate definition +EC_N_DUP_FIELD : int = 2012 // N012 Duplicate field +EC_N_DUP_VARIANT : int = 2013 // N013 Duplicate variant +EC_N_DUP_FUNC : int = 2014 // N014 Duplicate function +EC_N_FILEID_CONFLICT : int = 2015 // N015 Fileid conflict +EC_N_MODULE : int = 2016 // N016 Undefined module +EC_N_PROJECT : int = 2017 // N017 Undefined project +EC_N_CYCLE : int = 2018 // N018 Cyclic import +EC_N_IMPORT_FILE : int = 2019 // N019 Import file not found +EC_N_IMPORT_READ : int = 2020 // N020 Import read failure +EC_N_REEXPORT : int = 2021 // N021 Re-export conflict // I0xx — Type Inference -EC_I_INFER : int = 3001; // I001 Cannot infer type -EC_I_INFER_GLOBAL : int = 3002; // I002 Cannot infer global type -EC_I_INFER_RET : int = 3003; // I003 Cannot infer return type -EC_I_INFER_GENERIC : int = 3004; // I004 Cannot infer generic param -EC_I_AMBIGUOUS : int = 3005; // I005 Ambiguous type -EC_I_INFINITE : int = 3006; // I006 Infinite type +EC_I_INFER : int = 3001 // I001 Cannot infer type +EC_I_INFER_GLOBAL : int = 3002 // I002 Cannot infer global type +EC_I_INFER_RET : int = 3003 // I003 Cannot infer return type +EC_I_INFER_GENERIC : int = 3004 // I004 Cannot infer generic param +EC_I_AMBIGUOUS : int = 3005 // I005 Ambiguous type +EC_I_INFINITE : int = 3006 // I006 Infinite type // TA0xx — Type: Assignment -EC_TA_ASSIGN : int = 4001; // TA01 Cannot assign T2 to T1 -EC_TA_DECL : int = 4002; // TA02 Declared vs init type mismatch -EC_TA_BATCH : int = 4003; // TA03 Batch declaration mixed types -EC_TA_IMMUTABLE : int = 4004; // TA04 Assign to immutable -EC_TA_NOT_MUT : int = 4005; // TA05 Variable not mutable -EC_TA_GLOBAL_MUT : int = 4006; // TA06 Global not mutable -EC_TA_TUPLE_ARITY : int = 4007; // TA07 Tuple destructuring arity -EC_TA_UNKNOWN_TAG : int = 4008; // TA08 Unknown declaration tag +EC_TA_ASSIGN : int = 4001 // TA01 Cannot assign T2 to T1 +EC_TA_DECL : int = 4002 // TA02 Declared vs init type mismatch +EC_TA_BATCH : int = 4003 // TA03 Batch declaration mixed types +EC_TA_IMMUTABLE : int = 4004 // TA04 Assign to immutable +EC_TA_NOT_MUT : int = 4005 // TA05 Variable not mutable +EC_TA_GLOBAL_MUT : int = 4006 // TA06 Global not mutable +EC_TA_TUPLE_ARITY : int = 4007 // TA07 Tuple destructuring arity +EC_TA_UNKNOWN_TAG : int = 4008 // TA08 Unknown declaration tag // TF0xx — Type: Function -EC_TF_RETURN : int = 5001; // TF01 Return type mismatch -EC_TF_MISSING_RET : int = 5002; // TF02 Missing return -EC_TF_EXTRA_RET : int = 5003; // TF03 Extra return in unit fn -EC_TF_BRANCH_RET : int = 5004; // TF04 Branch return mismatch -EC_TF_ARG_COUNT : int = 5005; // TF05 Arg count mismatch -EC_TF_ARG_TOO_MANY : int = 5006; // TF06 Too many args -EC_TF_ARG_TYPE : int = 5007; // TF07 Arg type mismatch -EC_TF_METHOD_NOT_FOUND : int = 5008; // TF08 Method not found -EC_TF_METHOD_ARG_CNT : int = 5009; // TF09 Method arg count mismatch -EC_TF_METHOD_ARG_TYP : int = 5010; // TF10 Method arg type mismatch -EC_TF_NON_STRUCT : int = 5011; // TF11 Method call on non-struct -EC_TF_NO_MAIN : int = 5012; // TF12 No main function -EC_TF_MAIN_SIG : int = 5013; // TF13 Main signature wrong -EC_TF_SELF_PARAM : int = 5014; // TF14 Invalid self param -EC_TF_SELF_REQUIRED : int = 5015; // TF15 Method needs self -EC_TF_CALL_NOT_FOUND : int = 5016; // TF16 Function not in scope -EC_TF_AMBIGUOUS : int = 5017; // TF17 Ambiguous function call +EC_TF_RETURN : int = 5001 // TF01 Return type mismatch +EC_TF_MISSING_RET : int = 5002 // TF02 Missing return +EC_TF_EXTRA_RET : int = 5003 // TF03 Extra return in unit fn +EC_TF_BRANCH_RET : int = 5004 // TF04 Branch return mismatch +EC_TF_ARG_COUNT : int = 5005 // TF05 Arg count mismatch +EC_TF_ARG_TOO_MANY : int = 5006 // TF06 Too many args +EC_TF_ARG_TYPE : int = 5007 // TF07 Arg type mismatch +EC_TF_METHOD_NOT_FOUND : int = 5008 // TF08 Method not found +EC_TF_METHOD_ARG_CNT : int = 5009 // TF09 Method arg count mismatch +EC_TF_METHOD_ARG_TYP : int = 5010 // TF10 Method arg type mismatch +EC_TF_NON_STRUCT : int = 5011 // TF11 Method call on non-struct +EC_TF_NO_MAIN : int = 5012 // TF12 No main function +EC_TF_MAIN_SIG : int = 5013 // TF13 Main signature wrong +EC_TF_SELF_PARAM : int = 5014 // TF14 Invalid self param +EC_TF_SELF_REQUIRED : int = 5015 // TF15 Method needs self +EC_TF_CALL_NOT_FOUND : int = 5016 // TF16 Function not in scope +EC_TF_AMBIGUOUS : int = 5017 // TF17 Ambiguous function call // TB0xx — Type: Binary ops -EC_TB_ADD : int = 6001; // TB01 Cannot add -EC_TB_SUB : int = 6002; // TB02 Cannot sub -EC_TB_MUL : int = 6003; // TB03 Cannot mul -EC_TB_DIV : int = 6004; // TB04 Cannot div -EC_TB_MOD : int = 6005; // TB05 Cannot mod -EC_TB_CMP : int = 6006; // TB06 Cannot compare ==/!= -EC_TB_ORDER : int = 6007; // TB07 Cannot order /<=/>= -EC_TB_AND_OR : int = 6008; // TB08 &&/|| need bool -EC_TB_STR_CONCAT : int = 6009; // TB09 String + non-string +EC_TB_ADD : int = 6001 // TB01 Cannot add +EC_TB_SUB : int = 6002 // TB02 Cannot sub +EC_TB_MUL : int = 6003 // TB03 Cannot mul +EC_TB_DIV : int = 6004 // TB04 Cannot div +EC_TB_MOD : int = 6005 // TB05 Cannot mod +EC_TB_CMP : int = 6006 // TB06 Cannot compare ==/!= +EC_TB_ORDER : int = 6007 // TB07 Cannot order /<=/>= +EC_TB_AND_OR : int = 6008 // TB08 &&/|| need bool +EC_TB_STR_CONCAT : int = 6009 // TB09 String + non-string // TU0xx — Type: Unary ops -EC_TU_NEG : int = 7001; // TU01 Cannot negate -EC_TU_NOT : int = 7002; // TU02 ! requires bool -EC_TU_DEREF : int = 7003; // TU03 Cannot deref non-ref +EC_TU_NEG : int = 7001 // TU01 Cannot negate +EC_TU_NOT : int = 7002 // TU02 ! requires bool +EC_TU_DEREF : int = 7003 // TU03 Cannot deref non-ref // TC0xx — Type: Control flow -EC_TC_IF_COND : int = 8001; // TC01 If condition must be bool -EC_TC_IF_BRANCH : int = 8002; // TC02 If branches have different types -EC_TC_IF_NO_ELSE : int = 8003; // TC03 If without else returns unit -EC_TC_WHILE_COND : int = 8004; // TC04 While condition must be bool -EC_TC_BREAK_VAL : int = 8005; // TC05 Break value mismatch -EC_TC_BREAK_OUT : int = 8006; // TC06 Break outside loop -EC_TC_CONT_OUT : int = 8007; // TC07 Continue outside loop +EC_TC_IF_COND : int = 8001 // TC01 If condition must be bool +EC_TC_IF_BRANCH : int = 8002 // TC02 If branches have different types +EC_TC_IF_NO_ELSE : int = 8003 // TC03 If without else returns unit +EC_TC_WHILE_COND : int = 8004 // TC04 While condition must be bool +EC_TC_BREAK_VAL : int = 8005 // TC05 Break value mismatch +EC_TC_BREAK_OUT : int = 8006 // TC06 Break outside loop +EC_TC_CONT_OUT : int = 8007 // TC07 Continue outside loop // TM0xx — Type: Match -EC_TM_ENUM : int = 9001; // TM01 Match must be enum -EC_TM_ARM_TYPE : int = 9002; // TM02 Arm type mismatch -EC_TM_EXHAUST : int = 9003; // TM03 Non-exhaustive -EC_TM_REDUNDANT : int = 9004; // TM04 Redundant arm -EC_TM_WILDCARD_ORDER : int = 9005; // TM05 Wildcard not last -EC_TM_ARG_CNT : int = 9006; // TM06 Constructor arg count -EC_TM_ARG_TYPE : int = 9007; // TM07 Constructor arg type -EC_TM_BIND_DUP : int = 9008; // TM08 Pattern binding dup -EC_TM_NESTED : int = 9009; // TM09 Nested pattern not allowed +EC_TM_ENUM : int = 9001 // TM01 Match must be enum +EC_TM_ARM_TYPE : int = 9002 // TM02 Arm type mismatch +EC_TM_EXHAUST : int = 9003 // TM03 Non-exhaustive +EC_TM_REDUNDANT : int = 9004 // TM04 Redundant arm +EC_TM_WILDCARD_ORDER : int = 9005 // TM05 Wildcard not last +EC_TM_ARG_CNT : int = 9006 // TM06 Constructor arg count +EC_TM_ARG_TYPE : int = 9007 // TM07 Constructor arg type +EC_TM_BIND_DUP : int = 9008 // TM08 Pattern binding dup +EC_TM_NESTED : int = 9009 // TM09 Nested pattern not allowed // TK0xx — Type: Array/Slice -EC_TK_INDEX : int = 10001; // TK01 Cannot index -EC_TK_ELEM_TYPE : int = 10002; // TK02 Element type mismatch -EC_TK_SIZE_TYPE : int = 10003; // TK03 Size must be int -EC_TK_SIZE_NEG : int = 10004; // TK04 Size must be positive -EC_TK_SLICE_BOUNDS : int = 10005; // TK05 Slice out of bounds -EC_TK_SLICE_LEN : int = 10006; // TK06 Slice length negative -EC_TK_FOR_ITER : int = 10007; // TK07 Cannot iterate -EC_TK_FOR_TYPE : int = 10008; // TK08 For var type mismatch +EC_TK_INDEX : int = 10001 // TK01 Cannot index +EC_TK_ELEM_TYPE : int = 10002 // TK02 Element type mismatch +EC_TK_SIZE_TYPE : int = 10003 // TK03 Size must be int +EC_TK_SIZE_NEG : int = 10004 // TK04 Size must be positive +EC_TK_SLICE_BOUNDS : int = 10005 // TK05 Slice out of bounds +EC_TK_SLICE_LEN : int = 10006 // TK06 Slice length negative +EC_TK_FOR_ITER : int = 10007 // TK07 Cannot iterate +EC_TK_FOR_TYPE : int = 10008 // TK08 For var type mismatch // TS0xx — Type: Struct literal -EC_TS_MISSING_FIELD : int = 11001; // TS01 Missing field -EC_TS_UNKNOWN_FIELD : int = 11002; // TS02 Unknown field -EC_TS_FIELD_TYPE : int = 11003; // TS03 Field type mismatch -EC_TS_FIELD_DUP : int = 11004; // TS04 Field init twice +EC_TS_MISSING_FIELD : int = 11001 // TS01 Missing field +EC_TS_UNKNOWN_FIELD : int = 11002 // TS02 Unknown field +EC_TS_FIELD_TYPE : int = 11003 // TS03 Field type mismatch +EC_TS_FIELD_DUP : int = 11004 // TS04 Field init twice // TG0xx — Type: Generic -EC_TG_ARG_COUNT : int = 12001; // TG01 Generic arg count mismatch -EC_TG_BOUND : int = 12002; // TG02 Generic bound unsatisfied +EC_TG_ARG_COUNT : int = 12001 // TG01 Generic arg count mismatch +EC_TG_BOUND : int = 12002 // TG02 Generic bound unsatisfied // B0xx — Borrow -EC_B_BORROW_MUT : int = 13001; // B001 Mutable borrow on already-borrowed -EC_B_BORROW_IMMUT : int = 13002; // B002 Immutable borrow on mutable-borrowed -EC_B_BORROW_MUT2 : int = 13003; // B003 Two mutable borrows -EC_B_USE_WHILE_BORROWED : int = 13004; // B004 Use while borrowed -EC_B_ESCAPE : int = 13010; // B010 Reference escapes function -EC_B_LIFETIME : int = 13011; // B011 Lifetime too short -EC_B_MOVE_USE : int = 13020; // B020 Use of moved value -EC_B_MOVE_AGAIN : int = 13021; // B021 Move of already-moved -EC_B_MOVE_BORROWED : int = 13022; // B022 Move while borrowed +EC_B_BORROW_MUT : int = 13001 // B001 Mutable borrow on already-borrowed +EC_B_BORROW_IMMUT : int = 13002 // B002 Immutable borrow on mutable-borrowed +EC_B_BORROW_MUT2 : int = 13003 // B003 Two mutable borrows +EC_B_USE_WHILE_BORROWED : int = 13004 // B004 Use while borrowed +EC_B_ESCAPE : int = 13010 // B010 Reference escapes function +EC_B_LIFETIME : int = 13011 // B011 Lifetime too short +EC_B_MOVE_USE : int = 13020 // B020 Use of moved value +EC_B_MOVE_AGAIN : int = 13021 // B021 Move of already-moved +EC_B_MOVE_BORROWED : int = 13022 // B022 Move while borrowed // R0xx — Runtime -EC_R_DIV_ZERO : int = 14001; // R001 Division by zero -EC_R_OOB : int = 14002; // R002 Index out of bounds -EC_R_OVERFLOW : int = 14003; // R003 Integer overflow -EC_R_LOSSY_CONVERT : int = 14004; // R004 Lossy conversion +EC_R_DIV_ZERO : int = 14001 // R001 Division by zero +EC_R_OOB : int = 14002 // R002 Index out of bounds +EC_R_OVERFLOW : int = 14003 // R003 Integer overflow +EC_R_LOSSY_CONVERT : int = 14004 // R004 Lossy conversion // E0xx — I/O -EC_E_READ_FILE : int = 15001; // E001 Cannot read source -EC_E_WRITE_FILE : int = 15002; // E002 Cannot write output -EC_E_CCR_CORRUPT : int = 15003; // E003 CCR file corrupt -EC_E_CCR_OPEN : int = 15004; // E004 Cannot open CCR +EC_E_READ_FILE : int = 15001 // E001 Cannot read source +EC_E_WRITE_FILE : int = 15002 // E002 Cannot write output +EC_E_CCR_CORRUPT : int = 15003 // E003 CCR file corrupt +EC_E_CCR_OPEN : int = 15004 // E004 Cannot open CCR // ICE — Internal -EC_ICE_UNEXPECTED : int = 16001; // ICE01 Unexpected -EC_ICE_OVERFLOW : int = 16002; // ICE02 Buffer overflow -EC_ICE_UNSUPPORTED : int = 16003; // ICE03 Unsupported +EC_ICE_UNEXPECTED : int = 16001 // ICE01 Unexpected +EC_ICE_OVERFLOW : int = 16002 // ICE02 Buffer overflow +EC_ICE_UNSUPPORTED : int = 16003 // ICE03 Unsupported // R2 P5 Task 4(P-A):类型判定不可判(引擎 -1 = 未覆盖面/预算耗尽,或桥接缺口 = 该行译不成 // 类型项)。三态纪律:**未知不得当 0/1** ⇒ 硬错(legacy 回落面已删,D24)。反例(两侧类型项 // 文本)随诊断输出;判定点无 AST 位置 ⇒ line/col = 0。 -EC_ICE_TY_INDET : int = 16004; // ICE04 Type judgment indeterminate +EC_ICE_TY_INDET : int = 16004 // ICE04 Type judgment indeterminate // V0xx — **规约语法/验证面**(批 6「正式规约语法」开族;17xxx 为空闲段,`error_cat_prefix` // 的 `cat == 17 ⇒ "V"` 同步)。本批只落「形态错」与「常量假」两类可判定错误: // **未证(yellow)不是错误**——它只进 `--dump-vcs` 通道,绝不走诊断(否则 fail-closed // 闸门会把「没证明」变成 rc=1,违反裁-V6)。 -EC_V_CHECK_FALSE : int = 17001; // V01 `#check(常量假)`——可判定且必错(本批唯一「红」) -EC_V_BAD_TAG : int = 17002; // V02 未知 `#` 标签 / `#` 后非 IDENT -EC_V_ANN_SYNTAX : int = 17003; // V03 标注形态错(缺 `(` / 未闭合 `)`) -EC_V_RESULT_SHADOW : int = 17004; // V04 `#ensure` 的 `result` 绑定与形参/作用域名冲突(裁-S8:硬错,不静默择一) -EC_V_NOT_BOOL : int = 17005; // V05 标注表达式类型非 bool(本批子集:须恰为 TI_BOOL) -EC_V_CALL_BANNED : int = 17006; // V06 标注表达式含调用(裁-V5:C1 子集**先禁调用**,避开纯度时序坑) +EC_V_CHECK_FALSE : int = 17001 // V01 `#check(常量假)`——可判定且必错(本批唯一「红」) +EC_V_BAD_TAG : int = 17002 // V02 未知 `#` 标签 / `#` 后非 IDENT +EC_V_ANN_SYNTAX : int = 17003 // V03 标注形态错(缺 `(` / 未闭合 `)`) +EC_V_RESULT_SHADOW : int = 17004 // V04 `#ensure` 的 `result` 绑定与形参/作用域名冲突(裁-S8:硬错,不静默择一) +EC_V_NOT_BOOL : int = 17005 // V05 标注表达式类型非 bool(本批子集:须恰为 TI_BOOL) +EC_V_CALL_BANNED : int = 17006 // V06 标注表达式含调用(裁-V5:C1 子集**先禁调用**,避开纯度时序坑) // 规约标注**三态**(裁-S5:绿/黄只在 `--dump-vcs` 通道;红走诊断通道) -SPEC_ST_YELLOW : int = 0; // 未证(默认;不阻断编译) -SPEC_ST_GREEN : int = 1; // 常量折叠为真(可判定) -SPEC_ST_RED : int = 2; // 有硬错(V01/V04/V05/V06 任一命中;**粘性**) +SPEC_ST_YELLOW : int = 0 // 未证(默认;不阻断编译) +SPEC_ST_GREEN : int = 1 // 常量折叠为真(可判定) +SPEC_ST_RED : int = 2 // 有硬错(V01/V04/V05/V06 任一命中;**粘性**) // Diagnostic entry -struct Diag { +struct Diag: code: int, msg: string, line: int, col: int, -} // Symbol kinds for checker -SYM_FN : int = 0; -SYM_TYPE : int = 1; -SYM_LOCAL : int = 2; -SYM_PARAM : int = 3; -SYM_GLOBAL : int = 4; -SYM_MODULE : int = 5; -SYM_SO_FN : int = 6; +SYM_FN : int = 0 +SYM_TYPE : int = 1 +SYM_LOCAL : int = 2 +SYM_PARAM : int = 3 +SYM_GLOBAL : int = 4 +SYM_MODULE : int = 5 +SYM_SO_FN : int = 6 // Parameter/function tag flags (stored in sym_type for SYM_SO_FN) -TAG_VARIADIC : int = 1; -TAG_AUTO_STR : int = 2; +TAG_VARIADIC : int = 1 +TAG_AUTO_STR : int = 2 -g_gen_apply_data : string, mut; g_gen_apply_data_count : int, mut; g_gen_apply_data_cap : int, mut; +g_gen_apply_data : string, mut +g_gen_apply_data_count : int, mut +g_gen_apply_data_cap : int, mut // Module system globals -g_seg_starts : string, mut; g_seg_fileids : string, mut; g_seg_count : int, mut; g_seg_cap : int, mut; -g_line_fileid : string, mut; g_line_count : int, mut; g_line_cap : int, mut; -g_source_dir : string, mut; // directory of the main source file (for _import.core lookup) +g_seg_starts : string, mut +g_seg_fileids : string, mut +g_seg_count : int, mut +g_seg_cap : int, mut +g_line_fileid : string, mut +g_line_count : int, mut +g_line_cap : int, mut +g_source_dir : string, mut // directory of the main source file (for _import.core lookup) // IR instruction opcodes -IR_NOP : int = 0; -IR_CONST : int = 1; -IR_BINARY : int = 2; -IR_UNARY : int = 3; -IR_CALL : int = 4; -IR_RETURN : int = 5; -IR_ALLOC : int = 6; -IR_ALLOC_STRUCT : int = 7; -IR_ALLOC_ARRAY : int = 8; -IR_STORE : int = 9; -IR_LOAD : int = 10; -IR_LOAD_FIELD : int = 11; -IR_STORE_FIELD : int = 12; -IR_LOAD_INDEX : int = 13; -IR_STORE_INDEX : int = 14; -IR_LOAD_INDEX_VAR : int = 15; -IR_STORE_INDEX_VAR : int = 16; -IR_MAKE_ENUM : int = 17; -IR_REF : int = 18; -IR_BRANCH : int = 19; -IR_JUMP : int = 20; -IR_LABEL : int = 21; -IR_PHI : int = 22; -IR_LOAD_ENUM_TAG : int = 23; -IR_SLICE : int = 24; // dest=slice_var, s1=arr_var, s2=low_var, src3=high_var — create slice ptr from range -IR_DEREF : int = 25; // dest=loaded_val, s1=ptr, s2=runtime_base, s3=alloc_size, type_kind=width -IR_STORE_PTR : int = 26; // dest=runtime_base, s1=ptr, s2=value, s3=alloc_size, type_kind=width -IR_ADDR_INDEX : int = 31; // dest=addr, s1=arr_var, s2=index_var, s3=scale — compute &arr[index] without loading -IR_SPAWN : int = 27; // dest=result_var, s1=first_arg, s2=arg_count, s3=fn_name_ni, type_kind=spawn_count (-1=dynamic) -IR_YIELD : int = 28; // s1=value_var — emit value from flow to consumer channel -IR_AWAIT : int = 29; // dest=value_var, s1=future_var — block until future ready, get value -IR_BOUNDS_CHECK : int = 30; // s1=index, s2=max_len/len_var, type_kind=1 for dynamic max -IR_ARENA_NEW : int = 32; // dest=arena_var, src1=size_estimate -IR_ARENA_RESET : int = 33; // src1=arena_id (dest=-1) -IR_INLINE : int = 34; // src1=fn_var — inline hint -IR_NO_BOUNDS_CHECK : int = 35; // — skip bounds check for subsequent DEREFs -IR_FAST : int = 36; // — allow precision-for-speed optimizations -IR_UNROLL : int = 37; // src1=unroll_count — loop unroll hint -IR_SECTION : int = 38; // src1=section_name_ni — code section hint -IR_HOTPATCH_ROUTE : int = 39; // dest=result_var, s1=fn_name_ni, s2=first_arg, s3=arg_count -IR_DYN_TAG : int = 41; // dest=tag_var, s1=dyn_var — extract tag -IR_DYN_VAL : int = 42; // dest=val_var, s1=dyn_var — extract value -IR_DYN_PACK : int = 43; // dest=dyn_var, s1=val_var, s2=type_idx — pack dyn -IR_DYN_DISPATCH : int = 44; // s1=dyn_var, s2=dispatch_table_ni — dispatch by tag -IR_CALL_EXTERN : int = 45; // dest=result_var, s1=func_name_ni, s2=first_arg, s3=arg_count -IR_LAZY_THUNK : int = 46; // dest=thunk_var, s1=expr_var — wrap as lazy thunk -IR_LAZY_FORCE : int = 47; // dest=val_var, s1=thunk_var — force evaluation -IR_FNADDR : int = 48; // dest=addr_var, s1=fn_name_ni — load function address (movabs + link-time patch) -IR_I2F : int = 49; // dest=dex_var(bits), s1=int_var — int → binary64(cvtsi2sd,apx 快路径) -IR_F2I : int = 50; // dest=int_var, s1=dex_var(bits) — binary64 → int(cvttsd2si 截断,apx 快路径) -IR_APPROX : int = 51; // — 无操作数注解:apx 变量声明处(语义许可,后端可忽略,interp 跳过) +IR_NOP : int = 0 +IR_CONST : int = 1 +IR_BINARY : int = 2 +IR_UNARY : int = 3 +IR_CALL : int = 4 +IR_RETURN : int = 5 +IR_ALLOC : int = 6 +IR_ALLOC_STRUCT : int = 7 +IR_ALLOC_ARRAY : int = 8 +IR_STORE : int = 9 +IR_LOAD : int = 10 +IR_LOAD_FIELD : int = 11 +IR_STORE_FIELD : int = 12 +IR_LOAD_INDEX : int = 13 +IR_STORE_INDEX : int = 14 +IR_LOAD_INDEX_VAR : int = 15 +IR_STORE_INDEX_VAR : int = 16 +IR_MAKE_ENUM : int = 17 +IR_REF : int = 18 +IR_BRANCH : int = 19 +IR_JUMP : int = 20 +IR_LABEL : int = 21 +IR_PHI : int = 22 +IR_LOAD_ENUM_TAG : int = 23 +IR_SLICE : int = 24 // dest=slice_var, s1=arr_var, s2=low_var, src3=high_var — create slice ptr from range +IR_DEREF : int = 25 // dest=loaded_val, s1=ptr, s2=runtime_base, s3=alloc_size, type_kind=width +IR_STORE_PTR : int = 26 // dest=runtime_base, s1=ptr, s2=value, s3=alloc_size, type_kind=width +IR_ADDR_INDEX : int = 31 // dest=addr, s1=arr_var, s2=index_var, s3=scale — compute &arr[index] without loading +IR_SPAWN : int = 27 // dest=result_var, s1=first_arg, s2=arg_count, s3=fn_name_ni, type_kind=spawn_count (-1=dynamic) +IR_YIELD : int = 28 // s1=value_var — emit value from flow to consumer channel +IR_AWAIT : int = 29 // dest=value_var, s1=future_var — block until future ready, get value +IR_BOUNDS_CHECK : int = 30 // s1=index, s2=max_len/len_var, type_kind=1 for dynamic max +IR_ARENA_NEW : int = 32 // dest=arena_var, src1=size_estimate +IR_ARENA_RESET : int = 33 // src1=arena_id (dest=-1) +IR_INLINE : int = 34 // src1=fn_var — inline hint +IR_NO_BOUNDS_CHECK : int = 35 // — skip bounds check for subsequent DEREFs +IR_FAST : int = 36 // — allow precision-for-speed optimizations +IR_UNROLL : int = 37 // src1=unroll_count — loop unroll hint +IR_SECTION : int = 38 // src1=section_name_ni — code section hint +IR_HOTPATCH_ROUTE : int = 39 // dest=result_var, s1=fn_name_ni, s2=first_arg, s3=arg_count +IR_DYN_TAG : int = 41 // dest=tag_var, s1=dyn_var — extract tag +IR_DYN_VAL : int = 42 // dest=val_var, s1=dyn_var — extract value +IR_DYN_PACK : int = 43 // dest=dyn_var, s1=val_var, s2=type_idx — pack dyn +IR_DYN_DISPATCH : int = 44 // s1=dyn_var, s2=dispatch_table_ni — dispatch by tag +IR_CALL_EXTERN : int = 45 // dest=result_var, s1=func_name_ni, s2=first_arg, s3=arg_count +IR_LAZY_THUNK : int = 46 // dest=thunk_var, s1=expr_var — wrap as lazy thunk +IR_LAZY_FORCE : int = 47 // dest=val_var, s1=thunk_var — force evaluation +IR_FNADDR : int = 48 // dest=addr_var, s1=fn_name_ni — load function address (movabs + link-time patch) +IR_I2F : int = 49 // dest=dex_var(bits), s1=int_var — int → binary64(cvtsi2sd,apx 快路径) +IR_F2I : int = 50 // dest=int_var, s1=dex_var(bits) — binary64 → int(cvttsd2si 截断,apx 快路径) +IR_APPROX : int = 51 // — 无操作数注解:apx 变量声明处(语义许可,后端可忽略,interp 跳过) // Resolution flag for BRANCH/JUMP (stored in type_kind field after label resolution) -IR_RESOLVED : int = 1; +IR_RESOLVED : int = 1 // IR variable -struct IRVar { +struct IRVar: name: string, id: int, type_kind: int, -} // IR instruction (flat representation) -struct IRInstr { +struct IRInstr: opcode: int, dest: int, // destination var index src1: int, // source var/val 1 src2: int, // source var/val 2 src3: int, // extra data (label, field name, etc.) type_kind: int, // type info -} // === Dataflow Graph (.cir) structures === -struct DFNode { +struct DFNode: opcode: int, dest_var: int, // IR var this node defines (-1 if none) src1: int, // original operands (same semantics as IRInstr) @@ -634,30 +634,35 @@ struct DFNode { type_kind: int, first_edge: int, // index of first outgoing edge into g_df_edges (-1 = none) edge_count: int, // number of outgoing edges -} -struct DFEdge { +struct DFEdge: from_node: int, to_node: int, next_out: int, // next edge from same source (-1 = none) kind: int, // 0=data (def-use), 1=state (ordering/termination) -} // Dataflow graph arrays -g_df_nodes : string, mut; g_df_node_count : int, mut; g_df_node_cap : int, mut; -g_df_edges : string, mut; g_df_edge_count : int, mut; g_df_edge_cap : int, mut; -g_df_var_producer : string, mut; g_df_func_node_start : string, mut; g_df_func_node_count : string, mut; +g_df_nodes : string, mut +g_df_node_count : int, mut +g_df_node_cap : int, mut +g_df_edges : string, mut +g_df_edge_count : int, mut +g_df_edge_cap : int, mut +g_df_var_producer : string, mut +g_df_func_node_start : string, mut +g_df_func_node_count : string, mut // 缓存收窄批(CIR_CACHE_VER 20):每函数**边**起点——df_begin_func 记 g_df_edge_count, // 该函数的边 = [edge_start, g_df_edge_count)(写侧 O(1) 取界,取代「写全图边表」)。 -g_df_func_edge_start : string, mut; -g_df_cap : int, mut; +g_df_func_edge_start : string, mut +g_df_cap : int, mut // Usage count: how many consumers each IR variable has -g_var_use_count : string, mut; g_var_use_count_cap : int, mut; +g_var_use_count : string, mut +g_var_use_count_cap : int, mut // ── Optimization metadata keys (.ccr v3+ extensible section) ── -OPT_KEY_REG_ASSIGN : int = 0; // [var_idx:u32, reg_num:u8]... -OPT_META_STRIDE : int = 64; // header (8) + up to 5 register pairs -OPT_KEY_STACK_SHARE : int = 1; // [var_idx:u32, mapped_to:u32]... -OPT_KEY_CSE : int = 2; // [op:u32, s1:u32, s2:u32, res:u32]... +OPT_KEY_REG_ASSIGN : int = 0 // [var_idx:u32, reg_num:u8]... +OPT_META_STRIDE : int = 64 // header (8) + up to 5 register pairs +OPT_KEY_STACK_SHARE : int = 1 // [var_idx:u32, mapped_to:u32]... +OPT_KEY_CSE : int = 2 // [op:u32, s1:u32, s2:u32, res:u32]... diff --git a/src/compiler/ccr_io.cr b/src/compiler/ccr_io.cr index f6762734..37770f50 100644 --- a/src/compiler/ccr_io.cr +++ b/src/compiler/ccr_io.cr @@ -131,13 +131,13 @@ // --- Byte buffer helpers --- // No bitwise ops in Core — use arithmetic instead. -CCR_MAGIC : int = 827474755; // "CCR1" (0x31524343) -CCR_VERSION : int = 9; // v9-only(load 校验 ==9;拒 version≠9——D10 先例:v8 及更早整类拒收,**不得**静默当「段/字段缺席 = 空表」)。 +CCR_MAGIC : int = 827474755 // "CCR1" (0x31524343) +CCR_VERSION : int = 9 // v9-only(load 校验 ==9;拒 version≠9——D10 先例:v8 及更早整类拒收,**不得**静默当「段/字段缺席 = 空表」)。 // R2 P6 Task 3(β):v8→v9 = NOD 记录 36→40B(+28 项索引 i32、邻接域顺移 +32/+36)——旧文件在版本闸整类拒收 // (cache miss 语义 = 使用者重编;.cir 快照面零改动 ⇒ CIR_CACHE_VER 当时为 17——**该值此后由 TODO #2026-09-16-16 批 2 升到 18**(见该批计划 §12.4),**再于 2026-09-17 由批 5(opt-dex,TODO #2026-09-16-29)升到 19**(`dex?` 载荷形式规范化);**再于同日由缓存膨胀批升到 20**(段粒度按函数收窄 + 边端点相对 id + 尾部基线见证 trailer));`.ccr` 侧仍不 bump) -CCR_SEG_COUNT : int = 8; // STR SYM NOD ENT REG EDG TYPE IFACE(规范序 tag 1..8;预留 9+ 不占空间——D9:原 7/8 预留段顺移) -CCR_SEG_TYPE : int = 7; // TYPE 段 tag(数值权威 = 段序;D9) -CCR_SEG_IFACE : int = 8; // IFACE 段 tag(D9) +CCR_SEG_COUNT : int = 8 // STR SYM NOD ENT REG EDG TYPE IFACE(规范序 tag 1..8;预留 9+ 不占空间——D9:原 7/8 预留段顺移) +CCR_SEG_TYPE : int = 7 // TYPE 段 tag(数值权威 = 段序;D9) +CCR_SEG_IFACE : int = 8 // IFACE 段 tag(D9) // On-disk NOD record size: 32B 语义区(8 字段)+ 邻接 2 × u32 = 40 bytes — v7 spec §3.3 // {op, dest, s1(i64), src2, src3, tk, item, first_edge, edge_count}(v5 原 28B 语义 @@ -147,262 +147,251 @@ CCR_SEG_IFACE : int = 8; // IFACE 段 tag(D9) // 项索引(i32,-1 = 无项;写侧装填 = ccr_types.cr:ccr_nod_item_populate, // 读侧 = load_ccr 的 TYPE 段后一致性硬校验——见该段注)。内存对象记录 = 本记录 // 前 32B(ESZ_NOD_SEM,剥离邻接)——见 ent_kernel.cr 语义对象节。 -ESZ_NOD_DISK : int = 40; +ESZ_NOD_DISK : int = 40 // On-disk EDG record size: 2 × u32 = 8 bytes — v7 spec §3.4 // {to_nod u32, kind u32}(from = 所属节点,邻接隐含——文件序节点 i 的出边 // 在 [first_edge, first_edge+edge_count) 连续段内) -ESZ_EDGE_DISK : int = 8; +ESZ_EDGE_DISK : int = 8 // On-disk REG record size: 6 × i32 = 24 bytes — v6 坐标化字段序 // {kind, parent, enter_nod, exit_nod, first_ent, last_ent}(v5 的 nstart/ncount // 不落盘——load 由 enter/exit 派生:nstart = enter, ncount = exit − enter)。 // NOTE: the in-memory SG entry is ESZ_SG (48 bytes, u64 fields) — that is NOT // the wire format. Always use ESZ_SG_DISK for .ccr size math, never ESZ_SG. -ESZ_SG_DISK : int = 24; +ESZ_SG_DISK : int = 24 // SYM 落盘记录尺寸: // 全局记录 16B {name u32, type u32, init_val i64}(v5 var_idx 槽 → type) // 函数记录 = 24B 定长头 {name, param_count, ret_type, root_region, // first_ent, last_ent} + param_ents[i32 × param_count] // + {var_count u32} + var_decls[8B × var_count] -ESZ_GLOBAL_DISK : int = 16; -ESZ_FUNC_HEAD_DISK : int = 24; -ESZ_VARDECL_DISK : int = 8; +ESZ_GLOBAL_DISK : int = 16 +ESZ_FUNC_HEAD_DISK : int = 24 +ESZ_VARDECL_DISK : int = 8 // On-disk ENT record: 7 × 4B = 28 bytes (var_id/version/def_nod/live_start/ // live_end/home/flags; version + 半开 live_end 由内存 24B 表转换,见文件头注释). // The in-memory entry table is ESZ_ENTRY (24 bytes, no version field — the // per-var ordinal is derivable from group order); disk record ≠ memory record. -ESZ_ENTRY_DISK : int = 28; - -fn bw_byte(val: int, shift: int) -> int { - if shift == 0 { return val % 256; } - if shift >= 24 { return (val / 16777216) % 256; } - if shift >= 16 { return (val / 65536) % 256; } - if shift >= 8 { return (val / 256) % 256; } - return 0; -} - -fn buf_write_u32(buf: string, pos: int, val: int) { - w32(buf, pos, val); -} - -fn buf_write_i32(buf: string, pos: int, val: int) { - w32(buf, pos, val); -} - -fn buf_write_i64(buf: string, pos: int, val: int) { - w64(buf, pos, val); -} - -fn buf_read_u32(buf: string, pos: int) -> int { - b0 := load8(buf, pos); - b1 := load8(buf, pos + 1); - b2 := load8(buf, pos + 2); - b3 := load8(buf, pos + 3); - return b0 + b1 * 256 + b2 * 65536 + b3 * 16777216; -} - -fn buf_read_i32(buf: string, pos: int) -> int { - b0 := load8(buf, pos); - b1 := load8(buf, pos + 1); - b2 := load8(buf, pos + 2); - b3 := load8(buf, pos + 3); - val := b0 + b1 * 256 + b2 * 65536; - if b3 >= 128 { return val + (b3 - 256) * 16777216; } - return val + b3 * 16777216; -} - -fn buf_read_i64(buf: string, pos: int) -> int { +ESZ_ENTRY_DISK : int = 28 + +fn bw_byte(val: int, shift: int) -> int: + if shift == 0: + return val % 256 + if shift >= 24: + return (val / 16777216) % 256 + if shift >= 16: + return (val / 65536) % 256 + if shift >= 8: + return (val / 256) % 256 + return 0 + +fn buf_write_u32(buf: string, pos: int, val: int): + w32(buf, pos, val) + +fn buf_write_i32(buf: string, pos: int, val: int): + w32(buf, pos, val) + +fn buf_write_i64(buf: string, pos: int, val: int): + w64(buf, pos, val) + +fn buf_read_u32(buf: string, pos: int) -> int: + b0 := load8(buf, pos) + b1 := load8(buf, pos + 1) + b2 := load8(buf, pos + 2) + b3 := load8(buf, pos + 3) + return b0 + b1 * 256 + b2 * 65536 + b3 * 16777216 + +fn buf_read_i32(buf: string, pos: int) -> int: + b0 := load8(buf, pos) + b1 := load8(buf, pos + 1) + b2 := load8(buf, pos + 2) + b3 := load8(buf, pos + 3) + val := b0 + b1 * 256 + b2 * 65536 + if b3 >= 128: + return val + (b3 - 256) * 16777216 + return val + b3 * 16777216 + +fn buf_read_i64(buf: string, pos: int) -> int: // Little-endian signed 64-bit. The low dword must be read UNSIGNED: // reading it signed (buf_read_i32) would double-subtract for negatives // (e.g. -7 = lo -7 + hi -1 → -7 + -2^32, not -7). - b0 := load8(buf, pos); - b1 := load8(buf, pos + 1); - b2 := load8(buf, pos + 2); - b3 := load8(buf, pos + 3); - lo := b0 + b1 * 256 + b2 * 65536 + b3 * 16777216; - h0 := load8(buf, pos + 4); - h1 := load8(buf, pos + 5); - h2 := load8(buf, pos + 6); - h3 := load8(buf, pos + 7); - hi : ., mut = h0 + h1 * 256 + h2 * 65536; - if h3 >= 128 { hi = hi + (h3 - 256) * 16777216; } - else { hi = hi + h3 * 16777216; } // 修复 15:h3 < 128 时漏加 h3×2^24 → bit 56-62 丢失 + b0 := load8(buf, pos) + b1 := load8(buf, pos + 1) + b2 := load8(buf, pos + 2) + b3 := load8(buf, pos + 3) + lo := b0 + b1 * 256 + b2 * 65536 + b3 * 16777216 + h0 := load8(buf, pos + 4) + h1 := load8(buf, pos + 5) + h2 := load8(buf, pos + 6) + h3 := load8(buf, pos + 7) + hi : ., mut = h0 + h1 * 256 + h2 * 65536 + if h3 >= 128: + hi = hi + (h3 - 256) * 16777216 + else: + hi = hi + h3 * 16777216 + // 修复 15:h3 < 128 时漏加 h3×2^24 → bit 56-62 丢失 // Keep the factor within the parser's supported integer-literal range. - hi_part := hi * 65536; - hi_part = hi_part * 65536; - return lo + hi_part; -} + hi_part := hi * 65536 + hi_part = hi_part * 65536 + return lo + hi_part // Check a byte range without forming an overflowing end position. CCR counts // come from the file, so every variable-length section must use this helper // before reading or growing an array from its count. -fn ccr_has_bytes(pos: int, need: int, fsize: int) -> int { - if pos < 0 || need < 0 || pos > fsize { return 0; } - if need > fsize - pos { return 0; } - return 1; -} - -fn ccr_i32_fits(val: int) -> int { - if val < -2147483648 || val > 2147483647 { return 0; } - return 1; -} - -fn ccr_validate_i32_fields() -> int { - ii : ., mut = 0; - loop { - if ii >= g_ir_instr_count { break; } - if ccr_i32_fits(iri_dest(ii)) == 0 || - ccr_i32_fits(iri_s2(ii)) == 0 || - ccr_i32_fits(iri_s3(ii)) == 0 { return 0; } - ii = ii + 1; - } +fn ccr_has_bytes(pos: int, need: int, fsize: int) -> int: + if pos < 0 || need < 0 || pos > fsize: + return 0 + if need > fsize - pos: + return 0 + return 1 + +fn ccr_i32_fits(val: int) -> int: + if val < -2147483648 || val > 2147483647: + return 0 + return 1 + +fn ccr_validate_i32_fields() -> int: + ii : ., mut = 0 + loop: + if ii >= g_ir_instr_count: + break + if ccr_i32_fits(iri_dest(ii)) == 0 || ccr_i32_fits(iri_s2(ii)) == 0 || ccr_i32_fits(iri_s3(ii)) == 0: + return 0 + ii = ii + 1 // REG 落盘字段 = kind/parent/enter/exit(nstart/ncount 由 enter/exit 派生, // 不再落盘——v5 校验过的内存 nstart/ncount 字段随之免除) - si : ., mut = 0; - loop { - if si >= g_sg_count { break; } - f := si * ESZ_SG; - if ccr_i32_fits(r64(g_sgs, f + OFF_SG_KIND)) == 0 || - ccr_i32_fits(r64(g_sgs, f + OFF_SG_ENTER)) == 0 || - ccr_i32_fits(r64(g_sgs, f + OFF_SG_EXIT)) == 0 || - ccr_i32_fits(r64(g_sgs, f + OFF_SG_PARENT)) == 0 { return 0; } - si = si + 1; - } - return 1; -} + si : ., mut = 0 + loop: + if si >= g_sg_count: + break + f := si * ESZ_SG + if ccr_i32_fits(r64(g_sgs, f + OFF_SG_KIND)) == 0 || ccr_i32_fits(r64(g_sgs, f + OFF_SG_ENTER)) == 0 || ccr_i32_fits(r64(g_sgs, f + OFF_SG_EXIT)) == 0 || ccr_i32_fits(r64(g_sgs, f + OFF_SG_PARENT)) == 0: + return 0 + si = si + 1 + return 1 // 函数 fi 的根 region = REG 行序第 fi 个 SG_FUNC 行(压栈序:每个已编译函数 // df_begin_func 推 SG_FUNC,嵌套行紧随其根行——根行按函数序 1:1)。 // 返回行 id;-1 = 越界/结构不一致。 -fn ccr_func_root_sg(func_i: int) -> int { - if func_i < 0 { return -1; } - k : ., mut = 0; - si : ., mut = 0; - loop { - if si >= g_sg_count { break; } - if r64(g_sgs, si * ESZ_SG + OFF_SG_KIND) == SG_FUNC { - if k == func_i { return si; } - k = k + 1; - } - si = si + 1; - } - return -1; -} +fn ccr_func_root_sg(func_i: int) -> int: + if func_i < 0: + return -1 + k : ., mut = 0 + si : ., mut = 0 + loop: + if si >= g_sg_count: + break + if r64(g_sgs, si * ESZ_SG + OFF_SG_KIND) == SG_FUNC: + if k == func_i: + return si + k = k + 1 + si = si + 1 + return -1 // --- Segment size calculation(段体大小;Header+段表 = 16 + 12×6 = 88)--- // 每段自带计数 u32;写侧与 calc 侧逐字节一致(v7 测试 walk 校验 end==fsize)。 -fn ccr_str_seg_size() -> int { - sz : ., mut = 4; // str_count - si : ., mut = 0; - loop { - if si >= g_str_count { break; } - sz = sz + 4 + istr_len(si); - si = si + 1; - } - return sz; -} - -fn ccr_sym_seg_size() -> int { +fn ccr_str_seg_size() -> int: + sz : ., mut = 4 // str_count + si : ., mut = 0 + loop: + if si >= g_str_count: + break + sz = sz + 4 + istr_len(si) + si = si + 1 + return sz + +fn ccr_sym_seg_size() -> int: // 布局 = ccr_sym_seg_size/save_ccr/load_ccr 三方逐字节一致(见头注释): // globals(16B) → funcs(24B 头 + param_ents + var_count + var_decls 8B) // → str_consts → structs → enums → opt_meta - sz : ., mut = 4 + g_ir_global_count * ESZ_GLOBAL_DISK; // global_count + globals - sz = sz + 4; // func_count - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } - pc := r64(g_ir_func_param_count, fi * 8); - vc := r64(g_ir_func_var_count, fi * 8); - sz = sz + ESZ_FUNC_HEAD_DISK + pc * 4 + 4 + vc * ESZ_VARDECL_DISK; - fi = fi + 1; - } - sz = sz + 4 + g_ir_str_const_count * 4; // str_const_count + str_consts + sz : ., mut = 4 + g_ir_global_count * ESZ_GLOBAL_DISK // global_count + globals + sz = sz + 4 // func_count + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break + pc := r64(g_ir_func_param_count, fi * 8) + vc := r64(g_ir_func_var_count, fi * 8) + sz = sz + ESZ_FUNC_HEAD_DISK + pc * 4 + 4 + vc * ESZ_VARDECL_DISK + fi = fi + 1 + sz = sz + 4 + g_ir_str_const_count * 4 // str_const_count + str_consts // structs: struct_count + {name, field_count, fields×8B} - sz = sz + 4; - sti : ., mut = 0; - loop { - if sti >= g_struct_count { break; } - sz = sz + 8 + si_field_count(sti) * 8; - sti = sti + 1; - } + sz = sz + 4 + sti : ., mut = 0 + loop: + if sti >= g_struct_count: + break + sz = sz + 8 + si_field_count(sti) * 8 + sti = sti + 1 // enums: enum_count + {name, variant_count, variants×{name, tc, types×4B}} - sz = sz + 4; - ei : ., mut = 0; - loop { - if ei >= g_enum_count { break; } - vc := ei_variant_count(ei); - sz = sz + 8; // name + variant_count - vi : ., mut = 0; - loop { - if vi >= vc { break; } - tc := ei_variant_type_count(ei, vi); - sz = sz + 8 + tc * 4; // variant name + tc + types - vi = vi + 1; - } - ei = ei + 1; - } + sz = sz + 4 + ei : ., mut = 0 + loop: + if ei >= g_enum_count: + break + vc := ei_variant_count(ei) + sz = sz + 8 // name + variant_count + vi : ., mut = 0 + loop: + if vi >= vc: + break + tc := ei_variant_type_count(ei, vi) + sz = sz + 8 + tc * 4 // variant name + tc + types + vi = vi + 1 + ei = ei + 1 // opt_meta: opt_count + {key, len, data} - sz = sz + 4; - mi : ., mut = 0; - loop { - if mi >= g_opt_meta_count { break; } - sz = sz + 8 + r32(g_opt_meta, mi * OPT_META_STRIDE + 4); - mi = mi + 1; - } - return sz; -} - -fn ccr_nod_seg_size() -> int { - return 4 + g_ir_instr_count * ESZ_NOD_DISK; -} - -fn ccr_edg_seg_size(edge_total: int) -> int { - return 4 + edge_total * ESZ_EDGE_DISK; -} - -fn ccr_ent_seg_size() -> int { - return 4 + g_entry_count * ESZ_ENTRY_DISK; -} - -fn ccr_reg_seg_size() -> int { - return 4 + g_sg_count * ESZ_SG_DISK; -} + sz = sz + 4 + mi : ., mut = 0 + loop: + if mi >= g_opt_meta_count: + break + sz = sz + 8 + r32(g_opt_meta, mi * OPT_META_STRIDE + 4) + mi = mi + 1 + return sz + +fn ccr_nod_seg_size() -> int: + return 4 + g_ir_instr_count * ESZ_NOD_DISK + +fn ccr_edg_seg_size(edge_total: int) -> int: + return 4 + edge_total * ESZ_EDGE_DISK + +fn ccr_ent_seg_size() -> int: + return 4 + g_entry_count * ESZ_ENTRY_DISK + +fn ccr_reg_seg_size() -> int: + return 4 + g_sg_count * ESZ_SG_DISK // R2 P4 Task 2:TYPE(7) 段体大小 = 段体缓冲长度(D18:内容构造 = corec-only // ccr_types.cr;本文件保持共享层纯度——ccr_io.cr 同时在 corearch 清单内,任何 // 前端符号引用 = corearch N06 静默未定义)。缓冲**含首字段 row_count** ⇒ 段体 // 大小 ≡ 缓冲长度(单源;T1 空壳期注释写的「4 + 段体缓冲长度」是缓冲不含计数的 // 方案,实施取「缓冲 = 完整段体」,偏差登记见 Task 2 报告)。 -fn ccr_type_seg_size() -> int { - return g_ccr_type_seg_len; -} +fn ccr_type_seg_size() -> int: + return g_ccr_type_seg_len // R2 P4 Task 3:IFACE(8) 段体大小(D14 五小节;D18 解耦——内容构造 = corec-only // ccr_types.cr 的 ccr_iface_populate/ccr_iface_seg_build;本文件(corearch 也链接) // 只按段表搬运/解析)。缓冲**含首字段 native_count** ⇒ 段体大小 ≡ 缓冲长度(单源)。 -fn ccr_iface_seg_size() -> int { - return g_ccr_iface_seg_len; -} +fn ccr_iface_seg_size() -> int: + return g_ccr_iface_seg_len // --- Size calculation(v8:16B header + 8×12B seg table + 各段体)--- // edge_total = EDG 记录总数(save_ccr 先行收集,见 ccr_collect_edges)。 -fn calc_ccr_size(edge_total: int) -> int { - sz : ., mut = 16 + CCR_SEG_COUNT * 12; - sz = sz + ccr_str_seg_size(); - sz = sz + ccr_sym_seg_size(); - sz = sz + ccr_nod_seg_size(); - sz = sz + ccr_ent_seg_size(); - sz = sz + ccr_reg_seg_size(); - sz = sz + ccr_edg_seg_size(edge_total); - sz = sz + ccr_type_seg_size(); - sz = sz + ccr_iface_seg_size(); - return sz; -} +fn calc_ccr_size(edge_total: int) -> int: + sz : ., mut = 16 + CCR_SEG_COUNT * 12 + sz = sz + ccr_str_seg_size() + sz = sz + ccr_sym_seg_size() + sz = sz + ccr_nod_seg_size() + sz = sz + ccr_ent_seg_size() + sz = sz + ccr_reg_seg_size() + sz = sz + ccr_edg_seg_size(edge_total) + sz = sz + ccr_type_seg_size() + sz = sz + ccr_iface_seg_size() + return sz // --- EDG 内容收集(写侧;v7 spec §3.4/§4)--- // g_df_edges = 每节点头插出边链表(dataflow.cr df_add_edge_kind,OFF_DFE_NEXT @@ -411,66 +400,76 @@ fn calc_ccr_size(edge_total: int) -> int { // 同域(v7 守卫面强度保持):链表归属错乱/后向边(to_nod ≤ 所属节点,自环 // 含)/kind > 1 → 拒绝落盘(内存图 = 文件 EDG 的唯一源,loader 永不拒绝 // 自己 writer 的产物)。 -fn ccr_collect_edges(edge_counts: string, edge_offs: string) -> int { - total : ., mut = 0; - ni : ., mut = 0; - loop { - if ni >= g_ir_instr_count { break; } - w64(edge_offs, ni * 8, total); - cnt : ., mut = 0; - eid : ., mut = r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_FIRST_EDGE); - loop { - if eid < 0 { break; } - if eid >= g_df_edge_count { return -1; } // 链表越界(缓存恢复错乱防御) - if r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_FROM) != ni { return -1; } - eto := r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_TO); - if eto <= ni { return -1; } // v7 §4 规则 1:to_nod > 所属节点 - if r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_KIND) > 1 { return -1; } - cnt = cnt + 1; - eid = r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_NEXT); - } - w64(edge_counts, ni * 8, cnt); - total = total + cnt; - ni = ni + 1; - } - return total; -} +fn ccr_collect_edges(edge_counts: string, edge_offs: string) -> int: + total : ., mut = 0 + ni : ., mut = 0 + loop: + if ni >= g_ir_instr_count: + break + w64(edge_offs, ni * 8, total) + cnt : ., mut = 0 + eid : ., mut = r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_FIRST_EDGE) + loop: + if eid < 0: + break + if eid >= g_df_edge_count: + return -1 + // 链表越界(缓存恢复错乱防御) + if r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_FROM) != ni: + return -1 + eto := r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_TO) + if eto <= ni: + return -1 + // v7 §4 规则 1:to_nod > 所属节点 + if r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_KIND) > 1: + return -1 + cnt = cnt + 1 + eid = r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_NEXT) + w64(edge_counts, ni * 8, cnt) + total = total + cnt + ni = ni + 1 + return total // 第二遍:按节点序把出边写入扁平缓冲(slot = edge_offs[i] 起连续) -fn ccr_fill_edge_buf(buf: string, edge_offs: string) { - ni : ., mut = 0; - loop { - if ni >= g_ir_instr_count { break; } - slot : ., mut = r64(edge_offs, ni * 8); - eid : ., mut = r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_FIRST_EDGE); - loop { - if eid < 0 { break; } - eto := r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_TO); - ekind := r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_KIND); - w64(buf, slot * 8, eto + ekind * 4294967296); - slot = slot + 1; - eid = r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_NEXT); - } - ni = ni + 1; - } -} +fn ccr_fill_edge_buf(buf: string, edge_offs: string): + ni : ., mut = 0 + loop: + if ni >= g_ir_instr_count: + break + slot : ., mut = r64(edge_offs, ni * 8) + eid : ., mut = r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_FIRST_EDGE) + loop: + if eid < 0: + break + eto := r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_TO) + ekind := r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_KIND) + w64(buf, slot * 8, eto + ekind * 4294967296) + slot = slot + 1 + eid = r64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_NEXT) + ni = ni + 1 // --- v7 读侧载入缓冲(EDG 校验后保留——图边语义对象:内核完备 Task 1 起经 // 对象面 v7_edge_to/v7_edge_kind 消费(ent_kernel.cr——节点出边遍历 = 配方 // 输入集);g_df_edges 在 corearch 编译物中存在但 dataflow.cr 不在其内—— // 独立缓冲)--- -g_v7_edges : string, mut; // EDG 扁平记录(8B/条,文件序 = 节点运行序) -g_v7_edge_count : int, mut; +g_v7_edges : string, mut // EDG 扁平记录(8B/条,文件序 = 节点运行序) +g_v7_edge_count : int, mut // --- Entry-table accessors(内存 24B 表读——写侧/loader 本地别名;内核 // ent_* 等价访问器在 ent_kernel.cr(双 concat 共享,2026-09-10 Task 2 起), // 本组保留不收敛(按实际引用删原则)。buf_read_i32 带符号扩展同内核。)--- -fn ccr_ent_var(e: int) -> int { return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_VAR); } -fn ccr_ent_def(e: int) -> int { return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_DEF); } -fn ccr_ent_ls(e: int) -> int { return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_LS); } -fn ccr_ent_le(e: int) -> int { return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_LE); } -fn ccr_ent_home(e: int) -> int { return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_HOME); } -fn ccr_ent_flags(e: int) -> int { return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_FLAGS); } +fn ccr_ent_var(e: int) -> int: + return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_VAR) +fn ccr_ent_def(e: int) -> int: + return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_DEF) +fn ccr_ent_ls(e: int) -> int: + return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_LS) +fn ccr_ent_le(e: int) -> int: + return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_LE) +fn ccr_ent_home(e: int) -> int: + return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_HOME) +fn ccr_ent_flags(e: int) -> int: + return buf_read_i32(g_ir_entries, e * ESZ_ENTRY + OFF_ENTRY_FLAGS) // --- Entry 表载体 grow 注记(内核抽取 Task 2:写侧单源化)--- // compute_entries_v7/ccr_grow_* 镜像已删——corec 写侧直调内核 @@ -482,16 +481,16 @@ fn ccr_ent_flags(e: int) -> int { return buf_read_i32(g_ir_entries, e * ESZ_ENTR // 函数条目块 [es, es+ec) 内 var 的 def=-1 条目 id(SYM func param_ents 回填 // 用——参数「入参」条目 = 该参数 def=-1 条目;被重定值/从未引用 → 无 = -1; // def=-1 补丁每 var 至多一条)。写侧守卫:返回 id 恒 ≥ es 且在块内。 -fn ccr_param_entry_id(var_id: int, es: int, ec: int) -> int { - e : ., mut = 0; - loop { - if e >= ec { break; } - ei := es + e; - if ccr_ent_var(ei) == var_id && ccr_ent_def(ei) < 0 { return ei; } - e = e + 1; - } - return -1; -} +fn ccr_param_entry_id(var_id: int, es: int, ec: int) -> int: + e : ., mut = 0 + loop: + if e >= ec: + break + ei := es + e + if ccr_ent_var(ei) == var_id && ccr_ent_def(ei) < 0: + return ei + e = e + 1 + return -1 // --- 写侧对象镜像(内核完备 Task 2——A 通道中立化写侧载体裁决 2026-09-10)--- // corec 写侧不经 loader——内核 compute 系(ent_kernel.cr)现读 NOD 对象面 @@ -504,37 +503,38 @@ fn ccr_param_entry_id(var_id: int, es: int, ec: int) -> int { // ccr_validate_i32_fields 形状守卫)→ loader 载入文件产生的镜像与本函数产物 // 逐字节同 —— compute 尾随逐函数 compute_entries,ENT 数据面双进程同值、 // 产物 byte-identical(行为零变化判据)。 -fn populate_nod_objects() { - g_v7_nod_sem = alloc((g_ir_instr_count + 8) * ESZ_NOD_SEM); - g_v7_nod_count = g_ir_instr_count; - ii : ., mut = 0; - loop { - if ii >= g_ir_instr_count { break; } - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_OP, iri_op(ii)); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_DEST, iri_dest(ii)); - w64(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S1, iri_s1(ii)); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S2, iri_s2(ii)); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S3, iri_s3(ii)); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_TK, iri_tk(ii)); +fn populate_nod_objects(): + g_v7_nod_sem = alloc((g_ir_instr_count + 8) * ESZ_NOD_SEM) + g_v7_nod_count = g_ir_instr_count + ii : ., mut = 0 + loop: + if ii >= g_ir_instr_count: + break + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_OP, iri_op(ii)) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_DEST, iri_dest(ii)) + w64(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S1, iri_s1(ii)) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S2, iri_s2(ii)) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S3, iri_s3(ii)) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_TK, iri_tk(ii)) // R2 P6 Task 3(β):项索引(TYPE 段文件空间;-1 = 无项)。缓冲由 corec-only // 的 ccr_types.cr:ccr_nod_item_populate 装填(D18:本文件在 corearch 清单内, // 此处**不得**引桥接层符号),本函数纯搬运;缓冲短于节点数(不经 // ccr_seg_prepare_save 的诊断路径)⇒ 落 -1(响亮面由 load 侧一致性校验承担)。 - it0 : ., mut = -1; - if ii < g_ccr_nod_item_count { it0 = buf_read_i32(g_ccr_nod_item, ii * 4); } - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_ITEM, it0); - ii = ii + 1; - } -} + it0 : ., mut = -1 + if ii < g_ccr_nod_item_count: + it0 = buf_read_i32(g_ccr_nod_item, ii * 4) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_ITEM, it0) + ii = ii + 1 // --- Save(写侧与 calc 侧一致;段表规范序、段体连续)--- -fn save_ccr(path: string) -> int { +fn save_ccr(path: string) -> int: // The v7 wire format stores these fields as signed i32 — 编码层文件格式 // 限制(字段形状 = 文件布局域,hw-map/经典投影实例;与 int 语义无涉, // int-unbounded-semantics 定稿 §三)。Refuse to emit a lossy file instead // of letting w32 silently keep only the low bits. - if ccr_validate_i32_fields() == 0 { return -1; } + if ccr_validate_i32_fields() == 0: + return -1 // v7 Task 2(ENT 主干化)+ 内核抽取 Task 2(写侧单源化):ENT 数据面先行 // ——corec 写侧直调内核 compute_live_ranges()(尾部逐函数内调 compute_entries, @@ -547,91 +547,126 @@ fn save_ccr(path: string) -> int { // 写侧不经 loader → 本进程 compute 前先 populate(g_ir_instrs → // g_v7_nod_sem 镜像,与 loader 载入对称);同值 → ENT 产物与直读时代 // byte-identical(双进程同实现,无第二套 compute)。 - populate_nod_objects(); - compute_live_ranges(); + populate_nod_objects() + compute_live_ranges() // v7:EDG 内容先收集(NOD 邻接域 + 段尺寸先决)——g_df_edges 内存 = // 头插链表,按节点序走查 → 每节点出边连续段(first_edge = 前缀累计) - edge_counts := alloc((g_ir_instr_count + 8) * 8); - edge_offs := alloc((g_ir_instr_count + 8) * 8); - edge_total := ccr_collect_edges(edge_counts, edge_offs); - if edge_total < 0 { return -1; } - edge_buf : string, mut = ""; - if edge_total > 0 { - edge_buf = alloc(edge_total * 8); - ccr_fill_edge_buf(edge_buf, edge_offs); - } - - tsz := calc_ccr_size(edge_total); - buf := alloc(tsz); - pos : ., mut = 0; + edge_counts := alloc((g_ir_instr_count + 8) * 8) + edge_offs := alloc((g_ir_instr_count + 8) * 8) + edge_total := ccr_collect_edges(edge_counts, edge_offs) + if edge_total < 0: + return -1 + edge_buf : string, mut = "" + if edge_total > 0: + edge_buf = alloc(edge_total * 8) + ccr_fill_edge_buf(edge_buf, edge_offs) + + tsz := calc_ccr_size(edge_total) + buf := alloc(tsz) + pos : ., mut = 0 // Header(16B) - buf_write_u32(buf, pos, CCR_MAGIC); pos = pos + 4; - buf_write_u32(buf, pos, CCR_VERSION); pos = pos + 4; - buf_write_u32(buf, pos, CCR_SEG_COUNT); pos = pos + 4; - buf_write_u32(buf, pos, 0); pos = pos + 4; // reserved + buf_write_u32(buf, pos, CCR_MAGIC) + pos = pos + 4 + buf_write_u32(buf, pos, CCR_VERSION) + pos = pos + 4 + buf_write_u32(buf, pos, CCR_SEG_COUNT) + pos = pos + 4 + buf_write_u32(buf, pos, 0) + pos = pos + 4 // reserved // 段体大小(与 calc_ccr_size 同一来源逐段一致) - s1 := ccr_str_seg_size(); - s2 := ccr_sym_seg_size(); - s3 := ccr_nod_seg_size(); - s4 := ccr_ent_seg_size(); - s5 := ccr_reg_seg_size(); - s6 := ccr_edg_seg_size(edge_total); - s7 := ccr_type_seg_size(); // R2 P4 Task 2:内容面(缓冲长度) - s8 := ccr_iface_seg_size(); // R2 P4 Task 3:内容面(缓冲长度) + s1 := ccr_str_seg_size() + s2 := ccr_sym_seg_size() + s3 := ccr_nod_seg_size() + s4 := ccr_ent_seg_size() + s5 := ccr_reg_seg_size() + s6 := ccr_edg_seg_size(edge_total) + s7 := ccr_type_seg_size() // R2 P4 Task 2:内容面(缓冲长度) + s8 := ccr_iface_seg_size() // R2 P4 Task 3:内容面(缓冲长度) // Seg table(8 × 12B;offset = 前段尾,从段表后起;规范序 tag 1..8) - o1 : ., mut = 16 + CCR_SEG_COUNT * 12; - o2 : ., mut = o1 + s1; - o3 : ., mut = o2 + s2; - o4 : ., mut = o3 + s3; - o5 : ., mut = o4 + s4; - o6 : ., mut = o5 + s5; - o7 : ., mut = o6 + s6; - o8 : ., mut = o7 + s7; - - buf_write_u32(buf, pos, 1); buf_write_u32(buf, pos + 4, o1); buf_write_u32(buf, pos + 8, s1); pos = pos + 12; - buf_write_u32(buf, pos, 2); buf_write_u32(buf, pos + 4, o2); buf_write_u32(buf, pos + 8, s2); pos = pos + 12; - buf_write_u32(buf, pos, 3); buf_write_u32(buf, pos + 4, o3); buf_write_u32(buf, pos + 8, s3); pos = pos + 12; - buf_write_u32(buf, pos, 4); buf_write_u32(buf, pos + 4, o4); buf_write_u32(buf, pos + 8, s4); pos = pos + 12; - buf_write_u32(buf, pos, 5); buf_write_u32(buf, pos + 4, o5); buf_write_u32(buf, pos + 8, s5); pos = pos + 12; - buf_write_u32(buf, pos, 6); buf_write_u32(buf, pos + 4, o6); buf_write_u32(buf, pos + 8, s6); pos = pos + 12; - buf_write_u32(buf, pos, CCR_SEG_TYPE); buf_write_u32(buf, pos + 4, o7); buf_write_u32(buf, pos + 8, s7); pos = pos + 12; - buf_write_u32(buf, pos, CCR_SEG_IFACE); buf_write_u32(buf, pos + 4, o8); buf_write_u32(buf, pos + 8, s8); pos = pos + 12; + o1 : ., mut = 16 + CCR_SEG_COUNT * 12 + o2 : ., mut = o1 + s1 + o3 : ., mut = o2 + s2 + o4 : ., mut = o3 + s3 + o5 : ., mut = o4 + s4 + o6 : ., mut = o5 + s5 + o7 : ., mut = o6 + s6 + o8 : ., mut = o7 + s7 + + buf_write_u32(buf, pos, 1) + buf_write_u32(buf, pos + 4, o1) + buf_write_u32(buf, pos + 8, s1) + pos = pos + 12 + buf_write_u32(buf, pos, 2) + buf_write_u32(buf, pos + 4, o2) + buf_write_u32(buf, pos + 8, s2) + pos = pos + 12 + buf_write_u32(buf, pos, 3) + buf_write_u32(buf, pos + 4, o3) + buf_write_u32(buf, pos + 8, s3) + pos = pos + 12 + buf_write_u32(buf, pos, 4) + buf_write_u32(buf, pos + 4, o4) + buf_write_u32(buf, pos + 8, s4) + pos = pos + 12 + buf_write_u32(buf, pos, 5) + buf_write_u32(buf, pos + 4, o5) + buf_write_u32(buf, pos + 8, s5) + pos = pos + 12 + buf_write_u32(buf, pos, 6) + buf_write_u32(buf, pos + 4, o6) + buf_write_u32(buf, pos + 8, s6) + pos = pos + 12 + buf_write_u32(buf, pos, CCR_SEG_TYPE) + buf_write_u32(buf, pos + 4, o7) + buf_write_u32(buf, pos + 8, s7) + pos = pos + 12 + buf_write_u32(buf, pos, CCR_SEG_IFACE) + buf_write_u32(buf, pos + 4, o8) + buf_write_u32(buf, pos + 8, s8) + pos = pos + 12 // === STR: strings === - buf_write_u32(buf, pos, g_str_count); pos = pos + 4; - si : ., mut = 0; - loop { - if si >= g_str_count { break; } - sl := istr_len(si); - buf_write_u32(buf, pos, sl); pos = pos + 4; - ci : ., mut = 0; - loop { - if ci >= sl { break; } - store8(buf, pos, str_load8(si, ci)); - pos = pos + 1; - ci = ci + 1; - } - si = si + 1; - } + buf_write_u32(buf, pos, g_str_count) + pos = pos + 4 + si : ., mut = 0 + loop: + if si >= g_str_count: + break + sl := istr_len(si) + buf_write_u32(buf, pos, sl) + pos = pos + 4 + ci : ., mut = 0 + loop: + if ci >= sl: + break + store8(buf, pos, str_load8(si, ci)) + pos = pos + 1 + ci = ci + 1 + si = si + 1 // === SYM: globals(16B each: name u32, type u32, init_val i64)=== // v5 var_idx 槽 → type(var_idx 恒 == 行序——ir_gen reg_one_global 每全局 // 一 var 行、行序与记录序锁步;下方校验强制,失配拒绝 = 防止未来布局漂移 // 时静默生成行序错位的文件)。全局行 = var 命名空间前缀 0..G-1。 - buf_write_u32(buf, pos, g_ir_global_count); pos = pos + 4; - gi : ., mut = 0; - loop { - if gi >= g_ir_global_count { break; } - if r64(g_ir_globals, gi * 24 + 8) != gi { return -1; } - buf_write_u32(buf, pos, r64(g_ir_globals, gi * 24)); pos = pos + 4; // name - buf_write_u32(buf, pos, irv_type(gi)); pos = pos + 4; // type - buf_write_i64(buf, pos, r64(g_ir_globals, gi * 24 + 16)); pos = pos + 8; // init_val - gi = gi + 1; - } + buf_write_u32(buf, pos, g_ir_global_count) + pos = pos + 4 + gi : ., mut = 0 + loop: + if gi >= g_ir_global_count: + break + if r64(g_ir_globals, gi * 24 + 8) != gi: + return -1 + buf_write_u32(buf, pos, r64(g_ir_globals, gi * 24)) + pos = pos + 4 // name + buf_write_u32(buf, pos, irv_type(gi)) + pos = pos + 4 // type + buf_write_i64(buf, pos, r64(g_ir_globals, gi * 24 + 16)) + pos = pos + 8 // init_val + gi = gi + 1 // === SYM: funcs(24B 头 + param_ents + var 声明区——v5 func_meta 的 // instr_start/count 由 root_region span 取代、var_start/count 由声明区 @@ -642,184 +677,239 @@ fn save_ccr(path: string) -> int { // 总量守恒时察觉不到块错位(声明区左移/右移一格、总量不变 → 文件行序 // 静默漂移,ENT var_id 命名空间错位)。失配 = 函数非序发射 → 拒绝;与 // loader REG root span 校验(load 侧同域闭环)同风格。 - vcursor : ., mut = g_ir_global_count; - buf_write_u32(buf, pos, g_ir_func_count); pos = pos + 4; - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } - froot := ccr_func_root_sg(fi); - if froot < 0 { return -1; } - vc := r64(g_ir_func_var_count, fi * 8); - vs := r64(g_ir_func_var_start, fi * 8); - if vs != vcursor { return -1; } // 声明区起点 ≠ 前缀累计 → 行序错位 - vcursor = vcursor + vc; - pc := r64(g_ir_func_param_count, fi * 8); - if pc > vc { return -1; } + vcursor : ., mut = g_ir_global_count + buf_write_u32(buf, pos, g_ir_func_count) + pos = pos + 4 + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break + froot := ccr_func_root_sg(fi) + if froot < 0: + return -1 + vc := r64(g_ir_func_var_count, fi * 8) + vs := r64(g_ir_func_var_start, fi * 8) + if vs != vcursor: + return -1 + // 声明区起点 ≠ 前缀累计 → 行序错位 + vcursor = vcursor + vc + pc := r64(g_ir_func_param_count, fi * 8) + if pc > vc: + return -1 // v7 Task 2:条目块界实回填(内核 compute_live_ranges 已先行)——函数条目 // 块 = ENT 文件序连续段 [es, es+ec)(SYM func 与 REG 根行同源双写; // loader 块对照消费:pcnt==0 ↔ -1、ffe == 块首、fle == 块末) - es := r64(g_ir_func_entry_start, fi * 8); - ec := r64(g_ir_func_entry_count, fi * 8); - fe2 : ., mut = -1; - le2 : ., mut = -1; - if ec > 0 { fe2 = es; le2 = es + ec - 1; } - buf_write_u32(buf, pos, r64(g_ir_func_name_idx, fi * 8)); pos = pos + 4; - buf_write_u32(buf, pos, pc); pos = pos + 4; - buf_write_u32(buf, pos, r64(g_ir_func_ret_type, fi * 8)); pos = pos + 4; - buf_write_i32(buf, pos, froot); pos = pos + 4; - buf_write_i32(buf, pos, fe2); pos = pos + 4; - buf_write_i32(buf, pos, le2); pos = pos + 4; + es := r64(g_ir_func_entry_start, fi * 8) + ec := r64(g_ir_func_entry_count, fi * 8) + fe2 : ., mut = -1 + le2 : ., mut = -1 + if ec > 0: + fe2 = es + le2 = es + ec - 1 + buf_write_u32(buf, pos, r64(g_ir_func_name_idx, fi * 8)) + pos = pos + 4 + buf_write_u32(buf, pos, pc) + pos = pos + 4 + buf_write_u32(buf, pos, r64(g_ir_func_ret_type, fi * 8)) + pos = pos + 4 + buf_write_i32(buf, pos, froot) + pos = pos + 4 + buf_write_i32(buf, pos, fe2) + pos = pos + 4 + buf_write_i32(buf, pos, le2) + pos = pos + 4 // param_ents 实回填:参数「入参」条目 = 该参数 var 的 def=-1 条目 id // (函数内被重定值/从未引用 → -1;头注释 §3.2 语义)。loader 只做 // 界拒绝(pid < -1)——与 ENT 的一致性由 Python 侧/测试网对照。 - pp : ., mut = 0; - loop { - if pp >= pc { break; } - buf_write_i32(buf, pos, ccr_param_entry_id(vs + pp, es, ec)); - pos = pos + 4; - pp = pp + 1; - } + pp : ., mut = 0 + loop: + if pp >= pc: + break + buf_write_i32(buf, pos, ccr_param_entry_id(vs + pp, es, ec)) + pos = pos + 4 + pp = pp + 1 // var 声明区(行序声明——name/type;ENT「存在即声明」的名称/类型投影) - buf_write_u32(buf, pos, vc); pos = pos + 4; - vv : ., mut = 0; - loop { - if vv >= vc { break; } - row := vs + vv; - if row < 0 || row >= g_ir_var_count { return -1; } - buf_write_u32(buf, pos, irv_name(row)); pos = pos + 4; - buf_write_u32(buf, pos, irv_type(row)); pos = pos + 4; - vv = vv + 1; - } - fi = fi + 1; - } - if vcursor != g_ir_var_count { return -1; } // 末块未铺满命名空间 → 洞 + buf_write_u32(buf, pos, vc) + pos = pos + 4 + vv : ., mut = 0 + loop: + if vv >= vc: + break + row := vs + vv + if row < 0 || row >= g_ir_var_count: + return -1 + buf_write_u32(buf, pos, irv_name(row)) + pos = pos + 4 + buf_write_u32(buf, pos, irv_type(row)) + pos = pos + 4 + vv = vv + 1 + fi = fi + 1 + if vcursor != g_ir_var_count: + return -1 + // 末块未铺满命名空间 → 洞 // === SYM: string constants === - buf_write_u32(buf, pos, g_ir_str_const_count); pos = pos + 4; - sci : ., mut = 0; - loop { - if sci >= g_ir_str_const_count { break; } - buf_write_u32(buf, pos, r64(g_ir_str_consts, sci * 8)); pos = pos + 4; - sci = sci + 1; - } + buf_write_u32(buf, pos, g_ir_str_const_count) + pos = pos + 4 + sci : ., mut = 0 + loop: + if sci >= g_ir_str_const_count: + break + buf_write_u32(buf, pos, r64(g_ir_str_consts, sci * 8)) + pos = pos + 4 + sci = sci + 1 // === SYM: structs === - buf_write_u32(buf, pos, g_struct_count); pos = pos + 4; - sti : ., mut = 0; - loop { - if sti >= g_struct_count { break; } - fc := si_field_count(sti); - buf_write_u32(buf, pos, si_name(sti)); pos = pos + 4; - buf_write_u32(buf, pos, fc); pos = pos + 4; - fii : ., mut = 0; - loop { - if fii >= fc { break; } - buf_write_u32(buf, pos, si_field_name(sti, fii)); pos = pos + 4; - buf_write_u32(buf, pos, si_field_type(sti, fii)); pos = pos + 4; - fii = fii + 1; - } - sti = sti + 1; - } + buf_write_u32(buf, pos, g_struct_count) + pos = pos + 4 + sti : ., mut = 0 + loop: + if sti >= g_struct_count: + break + fc := si_field_count(sti) + buf_write_u32(buf, pos, si_name(sti)) + pos = pos + 4 + buf_write_u32(buf, pos, fc) + pos = pos + 4 + fii : ., mut = 0 + loop: + if fii >= fc: + break + buf_write_u32(buf, pos, si_field_name(sti, fii)) + pos = pos + 4 + buf_write_u32(buf, pos, si_field_type(sti, fii)) + pos = pos + 4 + fii = fii + 1 + sti = sti + 1 // === SYM: enums === - buf_write_u32(buf, pos, g_enum_count); pos = pos + 4; - ei2 : ., mut = 0; - loop { - if ei2 >= g_enum_count { break; } - vc := ei_variant_count(ei2); - buf_write_u32(buf, pos, ei_name(ei2)); pos = pos + 4; - buf_write_u32(buf, pos, vc); pos = pos + 4; - vi2 : ., mut = 0; - loop { - if vi2 >= vc { break; } - tcnt := ei_variant_type_count(ei2, vi2); - buf_write_u32(buf, pos, ei_variant_name(ei2, vi2)); pos = pos + 4; - buf_write_u32(buf, pos, tcnt); pos = pos + 4; - tf : ., mut = 0; - loop { - if tf >= tcnt { break; } - buf_write_u32(buf, pos, ei_variant_type(ei2, vi2, tf)); pos = pos + 4; - tf = tf + 1; - } - vi2 = vi2 + 1; - } - ei2 = ei2 + 1; - } + buf_write_u32(buf, pos, g_enum_count) + pos = pos + 4 + ei2 : ., mut = 0 + loop: + if ei2 >= g_enum_count: + break + vc := ei_variant_count(ei2) + buf_write_u32(buf, pos, ei_name(ei2)) + pos = pos + 4 + buf_write_u32(buf, pos, vc) + pos = pos + 4 + vi2 : ., mut = 0 + loop: + if vi2 >= vc: + break + tcnt := ei_variant_type_count(ei2, vi2) + buf_write_u32(buf, pos, ei_variant_name(ei2, vi2)) + pos = pos + 4 + buf_write_u32(buf, pos, tcnt) + pos = pos + 4 + tf : ., mut = 0 + loop: + if tf >= tcnt: + break + buf_write_u32(buf, pos, ei_variant_type(ei2, vi2, tf)) + pos = pos + 4 + tf = tf + 1 + vi2 = vi2 + 1 + ei2 = ei2 + 1 // === SYM: opt_meta === - buf_write_u32(buf, pos, g_opt_meta_count); pos = pos + 4; - mi : ., mut = 0; - loop { - if mi >= g_opt_meta_count { break; } - mo := mi * OPT_META_STRIDE; - mk := r32(g_opt_meta, mo); // key (u8 padded to u64) - md_len := r32(g_opt_meta, mo + 4); // data length - buf_write_u32(buf, pos, mk); pos = pos + 4; - buf_write_u32(buf, pos, md_len); pos = pos + 4; - di : ., mut = 0; - loop { if di >= md_len { break; } - store8(buf, pos, load8(g_opt_meta, mo + 8 + di)); - pos = pos + 1; - di = di + 1; - } - mi = mi + 1; - } + buf_write_u32(buf, pos, g_opt_meta_count) + pos = pos + 4 + mi : ., mut = 0 + loop: + if mi >= g_opt_meta_count: + break + mo := mi * OPT_META_STRIDE + mk := r32(g_opt_meta, mo) // key (u8 padded to u64) + md_len := r32(g_opt_meta, mo + 4) // data length + buf_write_u32(buf, pos, mk) + pos = pos + 4 + buf_write_u32(buf, pos, md_len) + pos = pos + 4 + di : ., mut = 0 + loop: + if di >= md_len: + break + store8(buf, pos, load8(g_opt_meta, mo + 8 + di)) + pos = pos + 1 + di = di + 1 + mi = mi + 1 // === NOD: instructions(36B each;NOD id = 文件序 = 全局指令序;28B // 语义字段与 v6 逐字段一致 + first_edge/edge_count 邻接索引——EDG 段 // 由 edge_buf 在段体末尾落盘)=== - buf_write_u32(buf, pos, g_ir_instr_count); pos = pos + 4; - ii : ., mut = 0; - loop { - if ii >= g_ir_instr_count { break; } - buf_write_u32(buf, pos, iri_op(ii)); pos = pos + 4; - buf_write_i32(buf, pos, iri_dest(ii)); pos = pos + 4; + buf_write_u32(buf, pos, g_ir_instr_count) + pos = pos + 4 + ii : ., mut = 0 + loop: + if ii >= g_ir_instr_count: + break + buf_write_u32(buf, pos, iri_op(ii)) + pos = pos + 4 + buf_write_i32(buf, pos, iri_dest(ii)) + pos = pos + 4 // 修复 14:s1 改 64 位——IR_CONST 的大 int 常量 / float 位模式 // 之前被截断成 32 位(float 常量静默损坏) - buf_write_i64(buf, pos, iri_s1(ii)); pos = pos + 8; - buf_write_i32(buf, pos, iri_s2(ii)); pos = pos + 4; - buf_write_i32(buf, pos, iri_s3(ii)); pos = pos + 4; - buf_write_u32(buf, pos, iri_tk(ii)); pos = pos + 4; + buf_write_i64(buf, pos, iri_s1(ii)) + pos = pos + 8 + buf_write_i32(buf, pos, iri_s2(ii)) + pos = pos + 4 + buf_write_i32(buf, pos, iri_s3(ii)) + pos = pos + 4 + buf_write_u32(buf, pos, iri_tk(ii)) + pos = pos + 4 // R2 P6 Task 3(β):项索引(i32;-1 = 无项)——与内存镜像同源 // (g_ccr_nod_item,corec-only 侧装填;本文件纯搬运)。 - it1 : ., mut = -1; - if ii < g_ccr_nod_item_count { it1 = buf_read_i32(g_ccr_nod_item, ii * 4); } - buf_write_i32(buf, pos, it1); pos = pos + 4; - buf_write_u32(buf, pos, r64(edge_offs, ii * 8)); pos = pos + 4; // first_edge - buf_write_u32(buf, pos, r64(edge_counts, ii * 8)); pos = pos + 4; // edge_count - ii = ii + 1; - } + it1 : ., mut = -1 + if ii < g_ccr_nod_item_count: + it1 = buf_read_i32(g_ccr_nod_item, ii * 4) + buf_write_i32(buf, pos, it1) + pos = pos + 4 + buf_write_u32(buf, pos, r64(edge_offs, ii * 8)) + pos = pos + 4 // first_edge + buf_write_u32(buf, pos, r64(edge_counts, ii * 8)) + pos = pos + 4 // edge_count + ii = ii + 1 // === ENT: entries(28B each;内存闭区间 → 盘上:version 组内序数、live_end+1 半开)=== // 版本序数:每 var 一张计数槽(var 全局槽 id 唯一属一个函数——组内序 = 全局序) - buf_write_u32(buf, pos, g_entry_count); pos = pos + 4; - vcnt : string, mut = alloc((g_ir_var_count + 8) * 8); - vz : ., mut = 0; - loop { - if vz >= g_ir_var_count + 8 { break; } - w64(vcnt, vz * 8, 0); - vz = vz + 1; - } - ej : ., mut = 0; - loop { - if ej >= g_entry_count { break; } - ev := ccr_ent_var(ej); - ed := ccr_ent_def(ej); - els := ccr_ent_ls(ej); - ele := ccr_ent_le(ej); - eho := ccr_ent_home(ej); - efl := ccr_ent_flags(ej); - ord := r64(vcnt, ev * 8) + 1; - w64(vcnt, ev * 8, ord); - buf_write_i32(buf, pos, ev); pos = pos + 4; // var_id - buf_write_u32(buf, pos, ord); pos = pos + 4; // version(1-based) - buf_write_i32(buf, pos, ed); pos = pos + 4; // def_nod(-1 = 无定值) - buf_write_u32(buf, pos, els); pos = pos + 4; // live_start(含定值) - buf_write_u32(buf, pos, ele + 1); pos = pos + 4; // live_end(半开 = 内存闭区间 +1) - buf_write_i32(buf, pos, eho); pos = pos + 4; // home(-1 = 未分配) - buf_write_u32(buf, pos, efl); pos = pos + 4; // flags - ej = ej + 1; - } + buf_write_u32(buf, pos, g_entry_count) + pos = pos + 4 + vcnt : string, mut = alloc((g_ir_var_count + 8) * 8) + vz : ., mut = 0 + loop: + if vz >= g_ir_var_count + 8: + break + w64(vcnt, vz * 8, 0) + vz = vz + 1 + ej : ., mut = 0 + loop: + if ej >= g_entry_count: + break + ev := ccr_ent_var(ej) + ed := ccr_ent_def(ej) + els := ccr_ent_ls(ej) + ele := ccr_ent_le(ej) + eho := ccr_ent_home(ej) + efl := ccr_ent_flags(ej) + ord := r64(vcnt, ev * 8) + 1 + w64(vcnt, ev * 8, ord) + buf_write_i32(buf, pos, ev) + pos = pos + 4 // var_id + buf_write_u32(buf, pos, ord) + pos = pos + 4 // version(1-based) + buf_write_i32(buf, pos, ed) + pos = pos + 4 // def_nod(-1 = 无定值) + buf_write_u32(buf, pos, els) + pos = pos + 4 // live_start(含定值) + buf_write_u32(buf, pos, ele + 1) + pos = pos + 4 // live_end(半开 = 内存闭区间 +1) + buf_write_i32(buf, pos, eho) + pos = pos + 4 // home(-1 = 未分配) + buf_write_u32(buf, pos, efl) + pos = pos + 4 // flags + ej = ej + 1 // === REG: region(24B each——spec §3.5 字段序 {kind, parent, enter_nod, // exit_nod, first_ent, last_ent};v5 nstart/ncount 不落盘 = enter/exit 派生, @@ -827,122 +917,143 @@ fn save_ccr(path: string) -> int { // first/last 语义:区内条目 = 定值点 def_nod ∈ [enter, exit)(定值点升序 → // 文件条目序连续段);根 region(kind=SG_FUNC,函数 k = 行序第 k 个根)= // 整个函数条目块(含 def=-1 参数条目);无条目 = -1。 - buf_write_u32(buf, pos, g_sg_count); pos = pos + 4; - rfunc : ., mut = -1; // 当前根 region 的函数号(行序 = 压栈序) - si2 : ., mut = 0; - loop { - if si2 >= g_sg_count { break; } - f := si2 * ESZ_SG; - sk2 := r64(g_sgs, f + OFF_SG_KIND); - sen := r64(g_sgs, f + OFF_SG_ENTER); - sex := r64(g_sgs, f + OFF_SG_EXIT); - spa := r64(g_sgs, f + OFF_SG_PARENT); - if sex < sen { return -1; } // 未闭合 → ncount 不可派生 - if sk2 == SG_FUNC { rfunc = rfunc + 1; } - if rfunc < 0 || rfunc >= g_ir_func_count { return -1; } // 行序结构失配 + buf_write_u32(buf, pos, g_sg_count) + pos = pos + 4 + rfunc : ., mut = -1 // 当前根 region 的函数号(行序 = 压栈序) + si2 : ., mut = 0 + loop: + if si2 >= g_sg_count: + break + f := si2 * ESZ_SG + sk2 := r64(g_sgs, f + OFF_SG_KIND) + sen := r64(g_sgs, f + OFF_SG_ENTER) + sex := r64(g_sgs, f + OFF_SG_EXIT) + spa := r64(g_sgs, f + OFF_SG_PARENT) + if sex < sen: + return -1 + // 未闭合 → ncount 不可派生 + if sk2 == SG_FUNC: + rfunc = rfunc + 1 + if rfunc < 0 || rfunc >= g_ir_func_count: + return -1 + // 行序结构失配 // v7 Task 2:条目范围实回填(内核 compute_live_ranges 已先行)——根 region // (SG_FUNC)= 整个函数条目块(含 def=-1 参数条目;与 SYM func // first/last 同源双写——loader 逐根行对照);嵌套 region = 定值点 // def_nod ∈ [enter, exit) 的条目段(块内定值点升序 → 文件条目序连续 // 一段;无 = -1)。头注释 §3.5 语义:区间 = def_nod 归属,非全块。 - fe2 : ., mut = -1; - le2 : ., mut = -1; - bes := r64(g_ir_func_entry_start, rfunc * 8); - bec := r64(g_ir_func_entry_count, rfunc * 8); - if sk2 == SG_FUNC { - if bec > 0 { fe2 = bes; le2 = bes + bec - 1; } - } else { - kk : ., mut = 0; - loop { - if kk >= bec { break; } - eid2 := bes + kk; - ed2 := ccr_ent_def(eid2); - if ed2 >= sen && ed2 < sex { - if fe2 < 0 { fe2 = eid2; } - le2 = eid2; - } - kk = kk + 1; - } - } - if sk2 == SG_FUNC { + fe2 : ., mut = -1 + le2 : ., mut = -1 + bes := r64(g_ir_func_entry_start, rfunc * 8) + bec := r64(g_ir_func_entry_count, rfunc * 8) + if sk2 == SG_FUNC: + if bec > 0: + fe2 = bes + le2 = bes + bec - 1 + else: + kk : ., mut = 0 + loop: + if kk >= bec: + break + eid2 := bes + kk + ed2 := ccr_ent_def(eid2) + if ed2 >= sen && ed2 < sex: + if fe2 < 0: + fe2 = eid2 + le2 = eid2 + kk = kk + 1 + if sk2 == SG_FUNC: // 根 region span = 函数指令范围(REG = 文件里函数边界的唯一真源, // 与 func 表一致性校验——失配 = 内部状态漂移) - is2 := r64(g_ir_func_instr_start, rfunc * 8); - ic2 := r64(g_ir_func_instr_count, rfunc * 8); - if sen != is2 || sex != is2 + ic2 { return -1; } - } - buf_write_i32(buf, pos, sk2); pos = pos + 4; - buf_write_i32(buf, pos, spa); pos = pos + 4; - buf_write_i32(buf, pos, sen); pos = pos + 4; - buf_write_i32(buf, pos, sex); pos = pos + 4; - buf_write_i32(buf, pos, fe2); pos = pos + 4; - buf_write_i32(buf, pos, le2); pos = pos + 4; - si2 = si2 + 1; - } + is2 := r64(g_ir_func_instr_start, rfunc * 8) + ic2 := r64(g_ir_func_instr_count, rfunc * 8) + if sen != is2 || sex != is2 + ic2: + return -1 + buf_write_i32(buf, pos, sk2) + pos = pos + 4 + buf_write_i32(buf, pos, spa) + pos = pos + 4 + buf_write_i32(buf, pos, sen) + pos = pos + 4 + buf_write_i32(buf, pos, sex) + pos = pos + 4 + buf_write_i32(buf, pos, fe2) + pos = pos + 4 + buf_write_i32(buf, pos, le2) + pos = pos + 4 + si2 = si2 + 1 // === EDG: edges(v7 必落;8B each {to_nod u32, kind u32}——所属节点 = // 邻接隐含:节点 i 出边连续段 [first_edge, first_edge+edge_count), // edge_buf = 收集遍的扁平记录(打包 to + kind×2^32,此处解包写 u32 对)=== - buf_write_u32(buf, pos, edge_total); pos = pos + 4; - ei3 : ., mut = 0; - loop { - if ei3 >= edge_total { break; } - ev := r64(edge_buf, ei3 * 8); - buf_write_u32(buf, pos, ev % 4294967296); pos = pos + 4; // to_nod - buf_write_u32(buf, pos, ev / 4294967296); pos = pos + 4; // kind - ei3 = ei3 + 1; - } + buf_write_u32(buf, pos, edge_total) + pos = pos + 4 + ei3 : ., mut = 0 + loop: + if ei3 >= edge_total: + break + ev := r64(edge_buf, ei3 * 8) + buf_write_u32(buf, pos, ev % 4294967296) + pos = pos + 4 // to_nod + buf_write_u32(buf, pos, ev / 4294967296) + pos = pos + 4 // kind + ei3 = ei3 + 1 // === TYPE(7):段体缓冲搬运(R2 P4 Task 2;内容构造 = corec-only // ccr_types.cr 的 ccr_type_prepare_save,D18——本处只按段表搬运)=== // 缓冲含首字段 row_count ⇒ 大小 ≡ ccr_type_seg_size()(同一来源)。空缓冲 = // 未装填(调用点漏调 prepare)⇒ **拒绝落盘**:不得产出「两小节缺席」的 // 半成品文件(三态纪律;行表恒含原生 9 行,空缓冲只可能是程序错误)。 - if g_ccr_type_seg_len <= 0 { return -1; } - ct : ., mut = 0; - loop { - if ct >= g_ccr_type_seg_len { break; } - store8(buf, pos, load8(g_ccr_type_seg, ct)); - pos = pos + 1; - ct = ct + 1; - } + if g_ccr_type_seg_len <= 0: + return -1 + ct : ., mut = 0 + loop: + if ct >= g_ccr_type_seg_len: + break + store8(buf, pos, load8(g_ccr_type_seg, ct)) + pos = pos + 1 + ct = ct + 1 // === IFACE(8):段体缓冲搬运(R2 P4 Task 3;内容构造 = corec-only ccr_types.cr // 的 ccr_iface_populate/ccr_iface_seg_build,D18——本处只按段表搬运)=== // 缓冲含首字段 native_count ⇒ 大小 ≡ ccr_iface_seg_size()(同一来源)。空缓冲 = // 未装填(调用点漏调 prepare)⇒ **拒绝落盘**(不得产出「五小节缺席」的半成品; // 条目表恒 16 行 ⇒ 空缓冲只可能是程序错误,三态纪律)。 - if g_ccr_iface_seg_len <= 0 { return -1; } - ict : ., mut = 0; - loop { - if ict >= g_ccr_iface_seg_len { break; } - store8(buf, pos, load8(g_ccr_iface_seg, ict)); - pos = pos + 1; - ict = ict + 1; - } + if g_ccr_iface_seg_len <= 0: + return -1 + ict : ., mut = 0 + loop: + if ict >= g_ccr_iface_seg_len: + break + store8(buf, pos, load8(g_ccr_iface_seg, ict)) + pos = pos + 1 + ict = ict + 1 // Use syscall directly (write_file uses str_len which stops at null) - fd := syscall3(2, path, 577, 420); // open(O_WRONLY|O_CREAT|O_TRUNC, 0644) - if fd < 0 { return -1; } - written : ., mut = 0; - written = syscall3(1, fd, buf, tsz); // write(fd, buf, tsz) - r2 := syscall3(3, fd, 0, 0); // close(fd) - if written != tsz { return -1; } - return 0; -} + fd := syscall3(2, path, 577, 420) // open(O_WRONLY|O_CREAT|O_TRUNC, 0644) + if fd < 0: + return -1 + written : ., mut = 0 + written = syscall3(1, fd, buf, tsz) // write(fd, buf, tsz) + r2 := syscall3(3, fd, 0, 0) // close(fd) + if written != tsz: + return -1 + return 0 // GC-4 测试钩子(corec ccr --inject-var-shift 载体;真实构建路径永不调用): // func0 var 声明区起点左移 1 行(globals ≥ 1 时新块 [vs-1, vs-1+vc0) 恒留在 // 命名空间内——行首行被 globals 末行顶替、行尾少写 func0 末行)。Σ 计数级 // 守卫(Σ func var_count == g_ir_var_count,总量守恒)察觉不到;位置级守卫 // (vs == 前缀累计)必须拒绝 save——模拟未来函数非序发射的静默错位。 -fn inject_var_shift() -> int { - if g_ir_func_count < 1 { return 1; } - vs := r64(g_ir_func_var_start, 0); - if vs < 1 { return 1; } // 无 globals 行可借位 → 注入前置不满足 - w64(g_ir_func_var_start, 0, vs - 1); - return 0; -} +fn inject_var_shift() -> int: + if g_ir_func_count < 1: + return 1 + vs := r64(g_ir_func_var_start, 0) + if vs < 1: + return 1 + // 无 globals 行可借位 → 注入前置不满足 + w64(g_ir_func_var_start, 0, vs - 1) + return 0 // --- Load(v8-only:校验 Header + 段表规范布局 + 逐段越界拒绝;version ≠ 8 // = v7 读路径退役——拒绝。R2 P4 Task 1:段表 = 8 段规范序(加段成本 = 闸界 @@ -965,60 +1076,135 @@ fn inject_var_shift() -> int { // 缓冲重建,与原重建段产物逐字节一致(28B 语义字段与 v6 逐字段相同,文件 // 布局变化不影响下游——ELF 发射)。 -fn load_ccr(data: string, fsize: int) -> int { - if fsize < 16 { return -1; } // header +fn load_ccr(data: string, fsize: int) -> int: + if fsize < 16: + return -1 + // header - pos : ., mut = 0; + pos : ., mut = 0 // Magic - magic := buf_read_u32(data, pos); pos = pos + 4; - if magic != CCR_MAGIC { return -1; } + magic := buf_read_u32(data, pos) + pos = pos + 4 + if magic != CCR_MAGIC: + return -1 // Version — v6-only(无 v5 兼容/转换工具) - ver := buf_read_u32(data, pos); pos = pos + 4; - if ver != CCR_VERSION { return -1; } + ver := buf_read_u32(data, pos) + pos = pos + 4 + if ver != CCR_VERSION: + return -1 // Seg count + reserved - seg_cnt := buf_read_u32(data, pos); pos = pos + 4; - rsv := buf_read_u32(data, pos); pos = pos + 4; - if seg_cnt > (fsize - 16) / 12 { return -1; } + seg_cnt := buf_read_u32(data, pos) + pos = pos + 4 + rsv := buf_read_u32(data, pos) + pos = pos + 4 + if seg_cnt > (fsize - 16) / 12: + return -1 // 段表:规范布局——tag 必须 = 行号(1..),offset 必须 = 前段尾,段不越界。 // (段表 {tag, offset, size} 结构本身允段序自由,v7 writer 只用规范序—— // loader 按规范序校验,非规范布局一律拒绝。) - seg_off1 : ., mut = 0; seg_off2 : ., mut = 0; seg_off3 : ., mut = 0; - seg_off4 : ., mut = 0; seg_off5 : ., mut = 0; seg_off6 : ., mut = 0; - seg_off7 : ., mut = 0; seg_off8 : ., mut = 0; - seg_end1 : ., mut = 0; seg_end2 : ., mut = 0; seg_end3 : ., mut = 0; - seg_end4 : ., mut = 0; seg_end5 : ., mut = 0; seg_end6 : ., mut = 0; - seg_end7 : ., mut = 0; seg_end8 : ., mut = 0; - have1 : ., mut = 0; have2 : ., mut = 0; have3 : ., mut = 0; - have4 : ., mut = 0; have5 : ., mut = 0; have6 : ., mut = 0; - have7 : ., mut = 0; have8 : ., mut = 0; - cursor : ., mut = 16 + seg_cnt * 12; - ri : ., mut = 0; - loop { - if ri >= seg_cnt { break; } - if !ccr_has_bytes(pos, 12, fsize) { return -1; } - tg := buf_read_u32(data, pos); pos = pos + 4; - soff := buf_read_u32(data, pos); pos = pos + 4; - ssz := buf_read_u32(data, pos); pos = pos + 4; - if tg < 1 || tg > CCR_SEG_COUNT { return -1; } - if tg != ri + 1 { return -1; } // 规范 tag 序 - if soff != cursor { return -1; } // 段体连续 - if ssz > fsize - cursor { return -1; } // 越界拒绝 + seg_off1 : ., mut = 0 + seg_off2 : ., mut = 0 + seg_off3 : ., mut = 0 + seg_off4 : ., mut = 0 + seg_off5 : ., mut = 0 + seg_off6 : ., mut = 0 + seg_off7 : ., mut = 0 + seg_off8 : ., mut = 0 + seg_end1 : ., mut = 0 + seg_end2 : ., mut = 0 + seg_end3 : ., mut = 0 + seg_end4 : ., mut = 0 + seg_end5 : ., mut = 0 + seg_end6 : ., mut = 0 + seg_end7 : ., mut = 0 + seg_end8 : ., mut = 0 + have1 : ., mut = 0 + have2 : ., mut = 0 + have3 : ., mut = 0 + have4 : ., mut = 0 + have5 : ., mut = 0 + have6 : ., mut = 0 + have7 : ., mut = 0 + have8 : ., mut = 0 + cursor : ., mut = 16 + seg_cnt * 12 + ri : ., mut = 0 + loop: + if ri >= seg_cnt: + break + if !ccr_has_bytes(pos, 12, fsize): + return -1 + tg := buf_read_u32(data, pos) + pos = pos + 4 + soff := buf_read_u32(data, pos) + pos = pos + 4 + ssz := buf_read_u32(data, pos) + pos = pos + 4 + if tg < 1 || tg > CCR_SEG_COUNT: + return -1 + if tg != ri + 1: + return -1 + // 规范 tag 序 + if soff != cursor: + return -1 + // 段体连续 + if ssz > fsize - cursor: + return -1 + // 越界拒绝 // 重复 tag 防御(规范序下不可能,双保险) - if tg == 1 { if have1 != 0 { return -1; } seg_off1 = soff; seg_end1 = soff + ssz; have1 = 1; } - if tg == 2 { if have2 != 0 { return -1; } seg_off2 = soff; seg_end2 = soff + ssz; have2 = 1; } - if tg == 3 { if have3 != 0 { return -1; } seg_off3 = soff; seg_end3 = soff + ssz; have3 = 1; } - if tg == 4 { if have4 != 0 { return -1; } seg_off4 = soff; seg_end4 = soff + ssz; have4 = 1; } - if tg == 5 { if have5 != 0 { return -1; } seg_off5 = soff; seg_end5 = soff + ssz; have5 = 1; } - if tg == 6 { if have6 != 0 { return -1; } seg_off6 = soff; seg_end6 = soff + ssz; have6 = 1; } - if tg == CCR_SEG_TYPE { if have7 != 0 { return -1; } seg_off7 = soff; seg_end7 = soff + ssz; have7 = 1; } - if tg == CCR_SEG_IFACE { if have8 != 0 { return -1; } seg_off8 = soff; seg_end8 = soff + ssz; have8 = 1; } - cursor = soff + ssz; - ri = ri + 1; - } + if tg == 1: + if have1 != 0: + return -1 + seg_off1 = soff + seg_end1 = soff + ssz + have1 = 1 + if tg == 2: + if have2 != 0: + return -1 + seg_off2 = soff + seg_end2 = soff + ssz + have2 = 1 + if tg == 3: + if have3 != 0: + return -1 + seg_off3 = soff + seg_end3 = soff + ssz + have3 = 1 + if tg == 4: + if have4 != 0: + return -1 + seg_off4 = soff + seg_end4 = soff + ssz + have4 = 1 + if tg == 5: + if have5 != 0: + return -1 + seg_off5 = soff + seg_end5 = soff + ssz + have5 = 1 + if tg == 6: + if have6 != 0: + return -1 + seg_off6 = soff + seg_end6 = soff + ssz + have6 = 1 + if tg == CCR_SEG_TYPE: + if have7 != 0: + return -1 + seg_off7 = soff + seg_end7 = soff + ssz + have7 = 1 + if tg == CCR_SEG_IFACE: + if have8 != 0: + return -1 + seg_off8 = soff + seg_end8 = soff + ssz + have8 = 1 + cursor = soff + ssz + ri = ri + 1 // STR/SYM/NOD/REG 必备(v6 坐标化后 func 指令边界 = root_region span 的 // 唯一真源,REG 缺段无法重建函数边界);EDG v7 必落(spec §3.4——文件 @@ -1027,269 +1213,350 @@ fn load_ccr(data: string, fsize: int) -> int { // 兼容语义保留);TYPE/IFACE 必备(R2 P4 Task 1,D11——可选段 = 两种 // .ccr 在野 = 任何消费者都要处理缺席 = 静默降级面;本阶段承诺即 // 「信息恒随载体」,与 ENT 的可选先例不同源) - if have1 == 0 || have2 == 0 || have3 == 0 || have5 == 0 || have6 == 0 { return -1; } - if have7 == 0 || have8 == 0 { return -1; } - if have4 == 0 { seg_off4 = 0; seg_end4 = 0; } + if have1 == 0 || have2 == 0 || have3 == 0 || have5 == 0 || have6 == 0: + return -1 + if have7 == 0 || have8 == 0: + return -1 + if have4 == 0: + seg_off4 = 0 + seg_end4 = 0 // 状态重置(corearch 单次加载;保持可重入) - g_str_count = 0; - g_ir_var_count = 0; - g_ir_instr_count = 0; - g_ir_func_count = 0; - g_ir_str_const_count = 0; - g_struct_count = 0; - g_enum_count = 0; - g_sg_count = 0; - g_ir_global_count = 0; - g_opt_meta_count = 0; - g_entry_count = 0; - g_v7_edge_count = 0; - g_v7_nod_count = 0; // 内核完备 Task 1:NOD 对象缓冲计数(NOD 段载入后置位) + g_str_count = 0 + g_ir_var_count = 0 + g_ir_instr_count = 0 + g_ir_func_count = 0 + g_ir_str_const_count = 0 + g_struct_count = 0 + g_enum_count = 0 + g_sg_count = 0 + g_ir_global_count = 0 + g_opt_meta_count = 0 + g_entry_count = 0 + g_v7_edge_count = 0 + g_v7_nod_count = 0 // 内核完备 Task 1:NOD 对象缓冲计数(NOD 段载入后置位) // R2 P4 Task 2:TYPE 段有真实内存表(g_types 行表 + 项层 g_type_terms/ // g_tt_index)——复位在 TYPE 段解析处(行表大小随段内容,且需与项层 memo // 同步作废;见该段注释)。 // R2 P4 Task 3:IFACE 段同理有真实内存表(g_iface_entries/g_iface_shape_*/ // g_ifaces/g_impl_for/g_methods)——计数复位在此(表缓冲随段内容重建; // g_iface_registry_ok 清 0 = 「表未建立」,本段解析末尾置 1 = **段真源**)。 - g_iface_count = 0; - g_iface_entry_count = 0; - g_iface_registry_ok = 0; - g_iface_shape_count = 0; - g_impl_for_count = 0; - g_method_count = 0; + g_iface_count = 0 + g_iface_entry_count = 0 + g_iface_registry_ok = 0 + g_iface_shape_count = 0 + g_impl_for_count = 0 + g_method_count = 0 // === STR: strings === - pos = seg_off1; - if !ccr_has_bytes(pos, 4, seg_end1) { return -1; } - str_cnt := buf_read_u32(data, pos); pos = pos + 4; - si : ., mut = 0; - loop { - if si >= str_cnt { break; } - if !ccr_has_bytes(pos, 4, seg_end1) { return -1; } - sl := buf_read_u32(data, pos); pos = pos + 4; - if !ccr_has_bytes(pos, sl, seg_end1) { return -1; } + pos = seg_off1 + if !ccr_has_bytes(pos, 4, seg_end1): + return -1 + str_cnt := buf_read_u32(data, pos) + pos = pos + 4 + si : ., mut = 0 + loop: + if si >= str_cnt: + break + if !ccr_has_bytes(pos, 4, seg_end1): + return -1 + sl := buf_read_u32(data, pos) + pos = pos + 4 + if !ccr_has_bytes(pos, sl, seg_end1): + return -1 // Allocate buffer for string content - s := alloc(sl + 1); - ci : ., mut = 0; - loop { - if ci >= sl { break; } - store8(s, ci, load8(data, pos)); - pos = pos + 1; - ci = ci + 1; - } - store8(s, sl, 0); - str_intern(s); - si = si + 1; - } + s := alloc(sl + 1) + ci : ., mut = 0 + loop: + if ci >= sl: + break + store8(s, ci, load8(data, pos)) + pos = pos + 1 + ci = ci + 1 + store8(s, sl, 0) + str_intern(s) + si = si + 1 // === SYM: globals(16B each: name u32, type u32, init_val i64)=== // var 命名空间重建(流式):全局行 = 记录序 0..G-1(行名/型随本记录携带, // v5 的 var 行 = 同源冗余);id = 行序。后续函数声明区行序相接。 - pos = seg_off2; - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - gc := buf_read_u32(data, pos); pos = pos + 4; - if gc > (seg_end2 - seg_off2) / ESZ_GLOBAL_DISK { return -1; } - grow_ir_globals(gc); - gi : ., mut = 0; - loop { - if gi >= gc { break; } - if !ccr_has_bytes(pos, ESZ_GLOBAL_DISK, seg_end2) { return -1; } - gname_ni := buf_read_u32(data, pos); pos = pos + 4; - gtype := buf_read_u32(data, pos); pos = pos + 4; - ginit_val := buf_read_i64(data, pos); pos = pos + 8; - grow_ir_vars(g_ir_var_count + 1); - gvar := g_ir_var_count; - irv_set_name(gvar, gname_ni); - irv_set_id(gvar, gvar); - irv_set_type(gvar, gtype); - g_ir_var_count = gvar + 1; - w64(g_ir_globals, gi * 24, gname_ni); - w64(g_ir_globals, gi * 24 + 8, gvar); - w64(g_ir_globals, gi * 24 + 16, ginit_val); - g_ir_global_count = gi + 1; - gi = gi + 1; - } + pos = seg_off2 + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + gc := buf_read_u32(data, pos) + pos = pos + 4 + if gc > (seg_end2 - seg_off2) / ESZ_GLOBAL_DISK: + return -1 + grow_ir_globals(gc) + gi : ., mut = 0 + loop: + if gi >= gc: + break + if !ccr_has_bytes(pos, ESZ_GLOBAL_DISK, seg_end2): + return -1 + gname_ni := buf_read_u32(data, pos) + pos = pos + 4 + gtype := buf_read_u32(data, pos) + pos = pos + 4 + ginit_val := buf_read_i64(data, pos) + pos = pos + 8 + grow_ir_vars(g_ir_var_count + 1) + gvar := g_ir_var_count + irv_set_name(gvar, gname_ni) + irv_set_id(gvar, gvar) + irv_set_type(gvar, gtype) + g_ir_var_count = gvar + 1 + w64(g_ir_globals, gi * 24, gname_ni) + w64(g_ir_globals, gi * 24 + 8, gvar) + w64(g_ir_globals, gi * 24 + 16, ginit_val) + g_ir_global_count = gi + 1 + gi = gi + 1 // === SYM: funcs(24B 头 + param_ents + var 声明区)=== // 头字段 = spec §3.2:name/param_count/ret_type/root_region(REG 行 id)/ // first_ent/last_ent(本函数条目文件范围)。instr/var 范围不落盘:instr = // root_region span(REG 段解析后回填),var_start = 声明区行序游标。 - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - func_cnt := buf_read_u32(data, pos); pos = pos + 4; - if func_cnt > (seg_end2 - pos) / ESZ_FUNC_HEAD_DISK { return -1; } - grow_ir_func_meta(func_cnt); + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + func_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if func_cnt > (seg_end2 - pos) / ESZ_FUNC_HEAD_DISK: + return -1 + grow_ir_func_meta(func_cnt) // func 记录临时元数据(REG 段回填/ENT 块界校验用):{root i64, first i64, last i64} - fn_meta := alloc((func_cnt + 8) * 24); - fi : ., mut = 0; - loop { - if fi >= func_cnt { break; } - if !ccr_has_bytes(pos, ESZ_FUNC_HEAD_DISK, seg_end2) { return -1; } - fname := buf_read_u32(data, pos); pos = pos + 4; - fpc := buf_read_u32(data, pos); pos = pos + 4; - fret := buf_read_u32(data, pos); pos = pos + 4; - froot := buf_read_i32(data, pos); pos = pos + 4; - ffe := buf_read_i32(data, pos); pos = pos + 4; - fle := buf_read_i32(data, pos); pos = pos + 4; - if froot < 0 { return -1; } // 每函数必有根 region(df_begin_func) - if ffe < -1 || fle < -1 || (ffe == -1) != (fle == -1) { return -1; } - w64(g_ir_func_name_idx, fi * 8, fname); - w64(g_ir_func_param_count, fi * 8, fpc); - w64(g_ir_func_ret_type, fi * 8, fret); - w64(fn_meta, fi * 24, froot); - w64(fn_meta, fi * 24 + 8, ffe); - w64(fn_meta, fi * 24 + 16, fle); + fn_meta := alloc((func_cnt + 8) * 24) + fi : ., mut = 0 + loop: + if fi >= func_cnt: + break + if !ccr_has_bytes(pos, ESZ_FUNC_HEAD_DISK, seg_end2): + return -1 + fname := buf_read_u32(data, pos) + pos = pos + 4 + fpc := buf_read_u32(data, pos) + pos = pos + 4 + fret := buf_read_u32(data, pos) + pos = pos + 4 + froot := buf_read_i32(data, pos) + pos = pos + 4 + ffe := buf_read_i32(data, pos) + pos = pos + 4 + fle := buf_read_i32(data, pos) + pos = pos + 4 + if froot < 0: + return -1 + // 每函数必有根 region(df_begin_func) + if ffe < -1 || fle < -1 || (ffe == -1) != (fle == -1): + return -1 + w64(g_ir_func_name_idx, fi * 8, fname) + w64(g_ir_func_param_count, fi * 8, fpc) + w64(g_ir_func_ret_type, fi * 8, fret) + w64(fn_meta, fi * 24, froot) + w64(fn_meta, fi * 24 + 8, ffe) + w64(fn_meta, fi * 24 + 16, fle) // param_ents(i32 each;内存无消费者——只做越界拒绝) - pj : ., mut = 0; - loop { - if pj >= fpc { break; } - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - pid := buf_read_i32(data, pos); pos = pos + 4; - if pid < -1 { return -1; } - pj = pj + 1; - } + pj : ., mut = 0 + loop: + if pj >= fpc: + break + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + pid := buf_read_i32(data, pos) + pos = pos + 4 + if pid < -1: + return -1 + pj = pj + 1 // var 声明区(行序 = 创建序,前 param_count 个 = 参数) - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - fvc := buf_read_u32(data, pos); pos = pos + 4; - if fpc > fvc { return -1; } - if fvc > (seg_end2 - pos) / ESZ_VARDECL_DISK { return -1; } - fvs2 := g_ir_var_count; - w64(g_ir_func_var_start, fi * 8, fvs2); - dj : ., mut = 0; - loop { - if dj >= fvc { break; } - if !ccr_has_bytes(pos, ESZ_VARDECL_DISK, seg_end2) { return -1; } - dname := buf_read_u32(data, pos); pos = pos + 4; - dtype := buf_read_u32(data, pos); pos = pos + 4; - grow_ir_vars(g_ir_var_count + 1); - drow := g_ir_var_count; - irv_set_name(drow, dname); - irv_set_id(drow, drow); - irv_set_type(drow, dtype); - g_ir_var_count = drow + 1; - dj = dj + 1; - } - if g_ir_var_count - fvs2 != fvc { return -1; } - w64(g_ir_func_var_count, fi * 8, fvc); - g_ir_func_count = fi + 1; - fi = fi + 1; - } + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + fvc := buf_read_u32(data, pos) + pos = pos + 4 + if fpc > fvc: + return -1 + if fvc > (seg_end2 - pos) / ESZ_VARDECL_DISK: + return -1 + fvs2 := g_ir_var_count + w64(g_ir_func_var_start, fi * 8, fvs2) + dj : ., mut = 0 + loop: + if dj >= fvc: + break + if !ccr_has_bytes(pos, ESZ_VARDECL_DISK, seg_end2): + return -1 + dname := buf_read_u32(data, pos) + pos = pos + 4 + dtype := buf_read_u32(data, pos) + pos = pos + 4 + grow_ir_vars(g_ir_var_count + 1) + drow := g_ir_var_count + irv_set_name(drow, dname) + irv_set_id(drow, drow) + irv_set_type(drow, dtype) + g_ir_var_count = drow + 1 + dj = dj + 1 + if g_ir_var_count - fvs2 != fvc: + return -1 + w64(g_ir_func_var_count, fi * 8, fvc) + g_ir_func_count = fi + 1 + fi = fi + 1 // === SYM: string constants(4B each)=== - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - str_const_cnt := buf_read_u32(data, pos); pos = pos + 4; - if str_const_cnt > (seg_end2 - seg_off2) / 4 { return -1; } - grow_ir_str_consts(str_const_cnt); - sci : ., mut = 0; - loop { - if sci >= str_const_cnt { break; } - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - scv := buf_read_u32(data, pos); pos = pos + 4; w64(g_ir_str_consts, sci * 8, scv); - g_ir_str_const_count = sci + 1; - sci = sci + 1; - } + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + str_const_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if str_const_cnt > (seg_end2 - seg_off2) / 4: + return -1 + grow_ir_str_consts(str_const_cnt) + sci : ., mut = 0 + loop: + if sci >= str_const_cnt: + break + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + scv := buf_read_u32(data, pos) + pos = pos + 4 + w64(g_ir_str_consts, sci * 8, scv) + g_ir_str_const_count = sci + 1 + sci = sci + 1 // === SYM: structs === - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - struct_cnt := buf_read_u32(data, pos); pos = pos + 4; - if struct_cnt > (seg_end2 - seg_off2) / 8 { return -1; } - grow_structs(struct_cnt); - g_struct_count = struct_cnt; - sti : ., mut = 0; - loop { - if sti >= struct_cnt { break; } - if !ccr_has_bytes(pos, 8, seg_end2) { return -1; } - sname_ni := buf_read_u32(data, pos); pos = pos + 4; - fc := buf_read_u32(data, pos); pos = pos + 4; + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + struct_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if struct_cnt > (seg_end2 - seg_off2) / 8: + return -1 + grow_structs(struct_cnt) + g_struct_count = struct_cnt + sti : ., mut = 0 + loop: + if sti >= struct_cnt: + break + if !ccr_has_bytes(pos, 8, seg_end2): + return -1 + sname_ni := buf_read_u32(data, pos) + pos = pos + 4 + fc := buf_read_u32(data, pos) + pos = pos + 4 // 容量批 T3(裁-CAP-2 (a)):字段数**无硬上限**(侧表承载)⇒ 旧 MAX_STRUCT_FIELDS // 读回闸与 16 槽清零循环一并删除;段界核算保留(fc 越段 ⇒ 拒绝,三态纪律)。 - if fc > (seg_end2 - pos) / 8 { return -1; } - w64(g_structs, sti * ESZ_STRUCTINFO + OFF_SI_NAME, sname_ni); - w64(g_structs, sti * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, fc); - si_set_field_base(sti, g_si_f_used); + if fc > (seg_end2 - pos) / 8: + return -1 + w64(g_structs, sti * ESZ_STRUCTINFO + OFF_SI_NAME, sname_ni) + w64(g_structs, sti * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, fc) + si_set_field_base(sti, g_si_f_used) // Zero generic slots - w64(g_structs, sti * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT, 0); - zgi : ., mut = 0; - loop { if zgi >= 4 { break; } w64(g_structs, sti * ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES + zgi * 8, 0); zgi = zgi + 1; } + w64(g_structs, sti * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT, 0) + zgi : ., mut = 0 + loop: + if zgi >= 4: + break + w64(g_structs, sti * ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES + zgi * 8, 0) + zgi = zgi + 1 // Write field data(侧表;盘面逐字段变长,格式不变) - fi2 : ., mut = 0; - loop { - if fi2 >= fc { break; } - fn_ni := buf_read_u32(data, pos); pos = pos + 4; - ft := buf_read_u32(data, pos); pos = pos + 4; - si_set_field_name(sti, fi2, fn_ni); - si_set_field_type(sti, fi2, ft); - fi2 = fi2 + 1; - } - si_commit_fields(sti, fc); - sti = sti + 1; - } + fi2 : ., mut = 0 + loop: + if fi2 >= fc: + break + fn_ni := buf_read_u32(data, pos) + pos = pos + 4 + ft := buf_read_u32(data, pos) + pos = pos + 4 + si_set_field_name(sti, fi2, fn_ni) + si_set_field_type(sti, fi2, ft) + fi2 = fi2 + 1 + si_commit_fields(sti, fc) + sti = sti + 1 // === SYM: enums === - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - enum_cnt := buf_read_u32(data, pos); pos = pos + 4; - if enum_cnt > (seg_end2 - seg_off2) / 8 { return -1; } - grow_enums(enum_cnt); - g_enum_count = enum_cnt; - ei : ., mut = 0; - loop { - if ei >= enum_cnt { break; } - if !ccr_has_bytes(pos, 8, seg_end2) { return -1; } - ename_ni := buf_read_u32(data, pos); pos = pos + 4; - vc := buf_read_u32(data, pos); pos = pos + 4; + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + enum_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if enum_cnt > (seg_end2 - seg_off2) / 8: + return -1 + grow_enums(enum_cnt) + g_enum_count = enum_cnt + ei : ., mut = 0 + loop: + if ei >= enum_cnt: + break + if !ccr_has_bytes(pos, 8, seg_end2): + return -1 + ename_ni := buf_read_u32(data, pos) + pos = pos + 4 + vc := buf_read_u32(data, pos) + pos = pos + 4 // 容量批 T3(裁-CAP-2 (a)):变体/载荷数**无硬上限**(侧表)⇒ 旧两闸与 16 槽清零 // 循环删除;段界核算保留(三态纪律) - if vc > (seg_end2 - pos) / 8 { return -1; } - w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_NAME, ename_ni); - w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, vc); - ei_set_variant_base(ei, g_ei_v_used); - w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 0); - zgi2 : ., mut = 0; - loop { if zgi2 >= 4 { break; } w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES + zgi2 * 8, 0); zgi2 = zgi2 + 1; } + if vc > (seg_end2 - pos) / 8: + return -1 + w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_NAME, ename_ni) + w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, vc) + ei_set_variant_base(ei, g_ei_v_used) + w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT, 0) + zgi2 : ., mut = 0 + loop: + if zgi2 >= 4: + break + w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES + zgi2 * 8, 0) + zgi2 = zgi2 + 1 // Write variant data - vi3 : ., mut = 0; - loop { - if vi3 >= vc { break; } - vni := buf_read_u32(data, pos); pos = pos + 4; - tc := buf_read_u32(data, pos); pos = pos + 4; - if tc > (seg_end2 - pos) / 4 { return -1; } - ei_set_variant_name(ei, vi3, vni); - ei_set_variant_type_count(ei, vi3, tc); - tf : ., mut = 0; - loop { - if tf >= tc { break; } - tval := buf_read_u32(data, pos); pos = pos + 4; - ei_set_variant_type(ei, vi3, tf, tval); - tf = tf + 1; - } - vi3 = vi3 + 1; - } - ei = ei + 1; - } + vi3 : ., mut = 0 + loop: + if vi3 >= vc: + break + vni := buf_read_u32(data, pos) + pos = pos + 4 + tc := buf_read_u32(data, pos) + pos = pos + 4 + if tc > (seg_end2 - pos) / 4: + return -1 + ei_set_variant_name(ei, vi3, vni) + ei_set_variant_type_count(ei, vi3, tc) + tf : ., mut = 0 + loop: + if tf >= tc: + break + tval := buf_read_u32(data, pos) + pos = pos + 4 + ei_set_variant_type(ei, vi3, tf, tval) + tf = tf + 1 + vi3 = vi3 + 1 + ei = ei + 1 // === SYM: opt_meta === - if !ccr_has_bytes(pos, 4, seg_end2) { return -1; } - mc := buf_read_u32(data, pos); pos = pos + 4; - mi : ., mut = 0; - loop { - if mi >= mc { break; } - if !ccr_has_bytes(pos, 8, seg_end2) { return -1; } - mk := buf_read_u32(data, pos); pos = pos + 4; - md_len := buf_read_u32(data, pos); pos = pos + 4; - if md_len > OPT_META_STRIDE - 8 || !ccr_has_bytes(pos, md_len, seg_end2) { return -1; } + if !ccr_has_bytes(pos, 4, seg_end2): + return -1 + mc := buf_read_u32(data, pos) + pos = pos + 4 + mi : ., mut = 0 + loop: + if mi >= mc: + break + if !ccr_has_bytes(pos, 8, seg_end2): + return -1 + mk := buf_read_u32(data, pos) + pos = pos + 4 + md_len := buf_read_u32(data, pos) + pos = pos + 4 + if md_len > OPT_META_STRIDE - 8 || !ccr_has_bytes(pos, md_len, seg_end2): + return -1 // Allocate and store entry - grow_opt_meta(mi + 1); - mo := mi * OPT_META_STRIDE; - w32(g_opt_meta, mo, mk); - w32(g_opt_meta, mo + 4, md_len); - di : ., mut = 0; - loop { if di >= md_len { break; } - store8(g_opt_meta, mo + 8 + di, load8(data, pos)); - pos = pos + 1; - di = di + 1; - } - g_opt_meta_count = mi + 1; - mi = mi + 1; - } + grow_opt_meta(mi + 1) + mo := mi * OPT_META_STRIDE + w32(g_opt_meta, mo, mk) + w32(g_opt_meta, mo + 4, md_len) + di : ., mut = 0 + loop: + if di >= md_len: + break + store8(g_opt_meta, mo + 8 + di, load8(data, pos)) + pos = pos + 1 + di = di + 1 + g_opt_meta_count = mi + 1 + mi = mi + 1 // === REG: region(24B each——spec §3.5 字段序 {kind, parent, enter_nod, // exit_nod, first_ent, last_ent})=== @@ -1299,59 +1566,76 @@ fn load_ccr(data: string, fsize: int) -> int { // first/last 校验:SG_FUNC 根行(行序第 k 个 = 函数 k)的区内条目范围必须 // 与 SYM func 记录 first/last 一致(同信息双写,失配 = 格式不一致)。 // 函数指令边界重建:func root_region(SYM)→ REG span = [enter, exit)。 - pos = seg_off5; - if !ccr_has_bytes(pos, 4, seg_end5) { return -1; } - sg_n := buf_read_u32(data, pos); pos = pos + 4; - if sg_n > (seg_end5 - seg_off5) / ESZ_SG_DISK { return -1; } - sg_i : ., mut = 0; - rfcnt : ., mut = 0; // 已见 SG_FUNC 根行数(行序 = 函数序 1:1) - loop { - if sg_i >= sg_n { break; } - grow_sg(sg_i + 1); - f := sg_i * ESZ_SG; - rk := buf_read_i32(data, pos); pos = pos + 4; - rp := buf_read_i32(data, pos); pos = pos + 4; - ren := buf_read_i32(data, pos); pos = pos + 4; - rex := buf_read_i32(data, pos); pos = pos + 4; - rfe := buf_read_i32(data, pos); pos = pos + 4; - rle := buf_read_i32(data, pos); pos = pos + 4; - if rex < ren { return -1; } // 未闭合 → ncount 不可派生 - if rfe < -1 || rle < -1 || (rfe == -1) != (rle == -1) { return -1; } - w64(g_sgs, f + OFF_SG_KIND, rk); - w64(g_sgs, f + OFF_SG_ENTER, ren); - w64(g_sgs, f + OFF_SG_EXIT, rex); - w64(g_sgs, f + OFF_SG_PARENT, rp); - w64(g_sgs, f + OFF_SG_NSTART, ren); - w64(g_sgs, f + OFF_SG_NCOUNT, rex - ren); - if rk == SG_FUNC { - if rfcnt >= func_cnt { return -1; } // 根行多于函数记录 - if rfe != r64(fn_meta, rfcnt * 24 + 8) || rle != r64(fn_meta, rfcnt * 24 + 16) { - return -1; // REG 根行条目范围 ≠ SYM func 记录 - } - rfcnt = rfcnt + 1; - } - sg_i = sg_i + 1; - } - if rfcnt != func_cnt { return -1; } // 根行少于函数记录(每函数必有根) - g_sg_count = sg_n; + pos = seg_off5 + if !ccr_has_bytes(pos, 4, seg_end5): + return -1 + sg_n := buf_read_u32(data, pos) + pos = pos + 4 + if sg_n > (seg_end5 - seg_off5) / ESZ_SG_DISK: + return -1 + sg_i : ., mut = 0 + rfcnt : ., mut = 0 // 已见 SG_FUNC 根行数(行序 = 函数序 1:1) + loop: + if sg_i >= sg_n: + break + grow_sg(sg_i + 1) + f := sg_i * ESZ_SG + rk := buf_read_i32(data, pos) + pos = pos + 4 + rp := buf_read_i32(data, pos) + pos = pos + 4 + ren := buf_read_i32(data, pos) + pos = pos + 4 + rex := buf_read_i32(data, pos) + pos = pos + 4 + rfe := buf_read_i32(data, pos) + pos = pos + 4 + rle := buf_read_i32(data, pos) + pos = pos + 4 + if rex < ren: + return -1 + // 未闭合 → ncount 不可派生 + if rfe < -1 || rle < -1 || (rfe == -1) != (rle == -1): + return -1 + w64(g_sgs, f + OFF_SG_KIND, rk) + w64(g_sgs, f + OFF_SG_ENTER, ren) + w64(g_sgs, f + OFF_SG_EXIT, rex) + w64(g_sgs, f + OFF_SG_PARENT, rp) + w64(g_sgs, f + OFF_SG_NSTART, ren) + w64(g_sgs, f + OFF_SG_NCOUNT, rex - ren) + if rk == SG_FUNC: + if rfcnt >= func_cnt: + return -1 + // 根行多于函数记录 + if rfe != r64(fn_meta, rfcnt * 24 + 8) || rle != r64(fn_meta, rfcnt * 24 + 16): + return -1 // REG 根行条目范围 ≠ SYM func 记录 + rfcnt = rfcnt + 1 + sg_i = sg_i + 1 + if rfcnt != func_cnt: + return -1 + // 根行少于函数记录(每函数必有根) + g_sg_count = sg_n // 函数指令边界回填:instr_start = root_region enter, instr_count = exit − enter // (根 region span = 函数节点范围——与 v5 func_meta instr_start/count 恒等, // 内存态与 v5 逐字节一致) - bfi : ., mut = 0; - loop { - if bfi >= func_cnt { break; } - rid := r64(fn_meta, bfi * 24); - if rid < 0 || rid >= sg_n { return -1; } - fr := rid * ESZ_SG; - if r64(g_sgs, fr + OFF_SG_KIND) != SG_FUNC { return -1; } - ren := r64(g_sgs, fr + OFF_SG_ENTER); - rex := r64(g_sgs, fr + OFF_SG_EXIT); - if rex < ren { return -1; } - w64(g_ir_func_instr_start, bfi * 8, ren); - w64(g_ir_func_instr_count, bfi * 8, rex - ren); - bfi = bfi + 1; - } + bfi : ., mut = 0 + loop: + if bfi >= func_cnt: + break + rid := r64(fn_meta, bfi * 24) + if rid < 0 || rid >= sg_n: + return -1 + fr := rid * ESZ_SG + if r64(g_sgs, fr + OFF_SG_KIND) != SG_FUNC: + return -1 + ren := r64(g_sgs, fr + OFF_SG_ENTER) + rex := r64(g_sgs, fr + OFF_SG_EXIT) + if rex < ren: + return -1 + w64(g_ir_func_instr_start, bfi * 8, ren) + w64(g_ir_func_instr_count, bfi * 8, rex - ren) + bfi = bfi + 1 // === NOD: instructions(36B each)=== // 内核完备 Task 1(语义对象模型):loader 产出 = 对象载入 + 守卫——28B @@ -1361,39 +1645,52 @@ fn load_ccr(data: string, fsize: int) -> int { // 线性重建段已移出本函数(调度重建 = 实例事务 build_linear_schedule, // regalloc.cr——load 返回后、发射/分派前由入口调用);g_ir_instrs/ // g_ir_instr_count 本段不再触碰(重建段原写点全清)。 - pos = seg_off3; - if !ccr_has_bytes(pos, 4, seg_end3) { return -1; } - instr_cnt := buf_read_u32(data, pos); pos = pos + 4; - if instr_cnt > (seg_end3 - seg_off3) / ESZ_NOD_DISK { return -1; } - g_v7_nod_sem = alloc((instr_cnt + 8) * ESZ_NOD_SEM); - g_v7_nod_meta = alloc((instr_cnt + 8) * ESZ_NOD_META); - ii : ., mut = 0; - loop { - if ii >= instr_cnt { break; } - if !ccr_has_bytes(pos, ESZ_NOD_DISK, seg_end3) { return -1; } - opcode := buf_read_u32(data, pos); pos = pos + 4; - dest := buf_read_i32(data, pos); pos = pos + 4; - s1 := buf_read_i64(data, pos); pos = pos + 8; // 修复 14:s1 64 位 - s2 := buf_read_i32(data, pos); pos = pos + 4; - s3 := buf_read_i32(data, pos); pos = pos + 4; - tk := buf_read_u32(data, pos); pos = pos + 4; - it2 := buf_read_i32(data, pos); pos = pos + 4; // R2 P6 Task 3:项索引(i32;-1 = 无项) - nfe := buf_read_u32(data, pos); pos = pos + 4; // first_edge(邻接索引) - nec := buf_read_u32(data, pos); pos = pos + 4; // edge_count + pos = seg_off3 + if !ccr_has_bytes(pos, 4, seg_end3): + return -1 + instr_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if instr_cnt > (seg_end3 - seg_off3) / ESZ_NOD_DISK: + return -1 + g_v7_nod_sem = alloc((instr_cnt + 8) * ESZ_NOD_SEM) + g_v7_nod_meta = alloc((instr_cnt + 8) * ESZ_NOD_META) + ii : ., mut = 0 + loop: + if ii >= instr_cnt: + break + if !ccr_has_bytes(pos, ESZ_NOD_DISK, seg_end3): + return -1 + opcode := buf_read_u32(data, pos) + pos = pos + 4 + dest := buf_read_i32(data, pos) + pos = pos + 4 + s1 := buf_read_i64(data, pos) + pos = pos + 8 // 修复 14:s1 64 位 + s2 := buf_read_i32(data, pos) + pos = pos + 4 + s3 := buf_read_i32(data, pos) + pos = pos + 4 + tk := buf_read_u32(data, pos) + pos = pos + 4 + it2 := buf_read_i32(data, pos) + pos = pos + 4 // R2 P6 Task 3:项索引(i32;-1 = 无项) + nfe := buf_read_u32(data, pos) + pos = pos + 4 // first_edge(邻接索引) + nec := buf_read_u32(data, pos) + pos = pos + 4 // edge_count // 对象缓冲写(语义字段 = 盘字节镜像——w32/w64 低 32/64 位存储,存取 // 经 nod_* 访问器 buf_read_* 符号扩展,数值与原重建段消费完全一致) - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_OP, opcode); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_DEST, dest); - w64(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S1, s1); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S2, s2); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S3, s3); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_TK, tk); - w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_ITEM, it2); // R2 P6 Task 3:项索引(-1 = 无) - w64(g_v7_nod_meta, ii * ESZ_NOD_META, nfe); - w64(g_v7_nod_meta, ii * ESZ_NOD_META + 8, nec); - ii = ii + 1; - } - g_v7_nod_count = instr_cnt; + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_OP, opcode) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_DEST, dest) + w64(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S1, s1) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S2, s2) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_S3, s3) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_TK, tk) + w32(g_v7_nod_sem, ii * ESZ_NOD_SEM + OFF_NS_ITEM, it2) // R2 P6 Task 3:项索引(-1 = 无) + w64(g_v7_nod_meta, ii * ESZ_NOD_META, nfe) + w64(g_v7_nod_meta, ii * ESZ_NOD_META + 8, nec) + ii = ii + 1 + g_v7_nod_count = instr_cnt // GC-3(SYM 评审 M1):REG root span 对 NOD 空间上界校验——函数指令边界 // (root_region span)在 REG 段解析时回填,instr_cnt 直到 NOD 段才可知; @@ -1401,85 +1698,105 @@ fn load_ccr(data: string, fsize: int) -> int { // NOD 空间外读指令(缓冲外静默/崩溃)。逐函数校验 instr_start + count // ≤ instr_cnt(含负值拒绝;风格与 ENT ele > instr_cnt 拒绝一致——载荷 // 消费前的最后一次可拒绝点)。 - rfi : ., mut = 0; - loop { - if rfi >= func_cnt { break; } - ris := r64(g_ir_func_instr_start, rfi * 8); - ric := r64(g_ir_func_instr_count, rfi * 8); - if ris < 0 || ric < 0 || ris + ric > instr_cnt { return -1; } - rfi = rfi + 1; - } + rfi : ., mut = 0 + loop: + if rfi >= func_cnt: + break + ris := r64(g_ir_func_instr_start, rfi * 8) + ric := r64(g_ir_func_instr_count, rfi * 8) + if ris < 0 || ric < 0 || ris + ric > instr_cnt: + return -1 + rfi = rfi + 1 // === ENT: entries(28B each → 内存 24B 表)=== // 盘上半开 live_end → 内存闭区间 −1;version 字段不入内存(组内序可推)。 - if have4 != 0 { - pos = seg_off4; - if !ccr_has_bytes(pos, 4, seg_end4) { return -1; } - ent_cnt := buf_read_u32(data, pos); pos = pos + 4; - if ent_cnt > (seg_end4 - seg_off4) / ESZ_ENTRY_DISK { return -1; } - grow_entries(ent_cnt); - eii : ., mut = 0; - loop { - if eii >= ent_cnt { break; } - if !ccr_has_bytes(pos, ESZ_ENTRY_DISK, seg_end4) { return -1; } - ev := buf_read_i32(data, pos); pos = pos + 4; // var_id - evr := buf_read_u32(data, pos); pos = pos + 4; // version(盘上仅校验用) - ed := buf_read_i32(data, pos); pos = pos + 4; // def_nod - els := buf_read_u32(data, pos); pos = pos + 4; // live_start(含定值) - ele := buf_read_u32(data, pos); pos = pos + 4; // live_end(半开) - eho := buf_read_i32(data, pos); pos = pos + 4; // home - efl := buf_read_u32(data, pos); pos = pos + 4; // flags + if have4 != 0: + pos = seg_off4 + if !ccr_has_bytes(pos, 4, seg_end4): + return -1 + ent_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if ent_cnt > (seg_end4 - seg_off4) / ESZ_ENTRY_DISK: + return -1 + grow_entries(ent_cnt) + eii : ., mut = 0 + loop: + if eii >= ent_cnt: + break + if !ccr_has_bytes(pos, ESZ_ENTRY_DISK, seg_end4): + return -1 + ev := buf_read_i32(data, pos) + pos = pos + 4 // var_id + evr := buf_read_u32(data, pos) + pos = pos + 4 // version(盘上仅校验用) + ed := buf_read_i32(data, pos) + pos = pos + 4 // def_nod + els := buf_read_u32(data, pos) + pos = pos + 4 // live_start(含定值) + ele := buf_read_u32(data, pos) + pos = pos + 4 // live_end(半开) + eho := buf_read_i32(data, pos) + pos = pos + 4 // home + efl := buf_read_u32(data, pos) + pos = pos + 4 // flags // 语义校验(越界拒绝,先例 ccr 校验风格) - if evr < 1 { return -1; } - if ev < 0 || ev >= g_ir_var_count { return -1; } // var 命名空间 = SYM 行重建总量 - if els >= ele || ele > instr_cnt { return -1; } - if ed >= 0 { - if ed >= instr_cnt { return -1; } - if ed != els { return -1; } // 定值条目 live_start == def - } + if evr < 1: + return -1 + if ev < 0 || ev >= g_ir_var_count: + return -1 + // var 命名空间 = SYM 行重建总量 + if els >= ele || ele > instr_cnt: + return -1 + if ed >= 0: + if ed >= instr_cnt: + return -1 + if ed != els: + return -1 + // 定值条目 live_start == def // 内存闭区间表 - mo2 := eii * ESZ_ENTRY; - w32(g_ir_entries, mo2 + OFF_ENTRY_VAR, ev); - w32(g_ir_entries, mo2 + OFF_ENTRY_DEF, ed); - w32(g_ir_entries, mo2 + OFF_ENTRY_LS, els); - w32(g_ir_entries, mo2 + OFF_ENTRY_LE, ele - 1); - w32(g_ir_entries, mo2 + OFF_ENTRY_HOME, eho); - w32(g_ir_entries, mo2 + OFF_ENTRY_FLAGS, efl); - g_entry_count = eii + 1; - eii = eii + 1; - } + mo2 := eii * ESZ_ENTRY + w32(g_ir_entries, mo2 + OFF_ENTRY_VAR, ev) + w32(g_ir_entries, mo2 + OFF_ENTRY_DEF, ed) + w32(g_ir_entries, mo2 + OFF_ENTRY_LS, els) + w32(g_ir_entries, mo2 + OFF_ENTRY_LE, ele - 1) + w32(g_ir_entries, mo2 + OFF_ENTRY_HOME, eho) + w32(g_ir_entries, mo2 + OFF_ENTRY_FLAGS, efl) + g_entry_count = eii + 1 + eii = eii + 1 // 函数条目段界重建:条目按函数升序成块落盘(compute_entries func_i 升序), // 每函数一段 [start, count)——块判定 = var 槽 ∈ 该函数 var 区间(var 槽 // 全属唯一函数,段序与函数序一致)。重建结果与 SYM func 记录 // first_ent/last_ent 逐函数对照(同信息双写,失配 = 格式不一致)。 - grow_func_entry_meta(func_cnt); - pf : ., mut = 0; - pe : ., mut = 0; - loop { - if pf >= func_cnt { break; } - fvs := r64(g_ir_func_var_start, pf * 8); - fvc := r64(g_ir_func_var_count, pf * 8); - pstart := pe; - w64(g_ir_func_entry_start, pf * 8, pe); - loop { - if pe >= g_entry_count { break; } - pv := buf_read_i32(g_ir_entries, pe * ESZ_ENTRY + OFF_ENTRY_VAR); - if fvc <= 0 || pv < fvs || pv >= fvs + fvc { break; } - pe = pe + 1; - } - pcnt := pe - pstart; - w64(g_ir_func_entry_count, pf * 8, pcnt); - ffe := r64(fn_meta, pf * 24 + 8); - fle := r64(fn_meta, pf * 24 + 16); - if pcnt == 0 { - if ffe != -1 || fle != -1 { return -1; } - } else { - if ffe != pstart || fle != pstart + pcnt - 1 { return -1; } - } - pf = pf + 1; - } - if pe != g_entry_count { return -1; } - } + grow_func_entry_meta(func_cnt) + pf : ., mut = 0 + pe : ., mut = 0 + loop: + if pf >= func_cnt: + break + fvs := r64(g_ir_func_var_start, pf * 8) + fvc := r64(g_ir_func_var_count, pf * 8) + pstart := pe + w64(g_ir_func_entry_start, pf * 8, pe) + loop: + if pe >= g_entry_count: + break + pv := buf_read_i32(g_ir_entries, pe * ESZ_ENTRY + OFF_ENTRY_VAR) + if fvc <= 0 || pv < fvs || pv >= fvs + fvc: + break + pe = pe + 1 + pcnt := pe - pstart + w64(g_ir_func_entry_count, pf * 8, pcnt) + ffe := r64(fn_meta, pf * 24 + 8) + fle := r64(fn_meta, pf * 24 + 16) + if pcnt == 0: + if ffe != -1 || fle != -1: + return -1 + else: + if ffe != pstart || fle != pstart + pcnt - 1: + return -1 + pf = pf + 1 + if pe != g_entry_count: + return -1 // === EDG: edges(v7 必落;8B each {to_nod u32, kind u32}——所属节点 = // 邻接隐含:节点 i 出边连续段 [first_edge, first_edge+edge_count),first_edge @@ -1492,44 +1809,63 @@ fn load_ccr(data: string, fsize: int) -> int { // 校验通过后边表入 g_v7_edges 缓冲(文件序连续段——图语义消费通道/调试)。 // branch/jump 目标 = 操作数引用非边(v7 §4 边界声明)——NOD 操作数不参与 // 本段校验。 - pos = seg_off6; - if !ccr_has_bytes(pos, 4, seg_end6) { return -1; } - edg_cnt := buf_read_u32(data, pos); pos = pos + 4; - if edg_cnt > (seg_end6 - seg_off6) / ESZ_EDGE_DISK { return -1; } - v7_buf : string, mut = ""; - if edg_cnt > 0 { - v7_buf = alloc(edg_cnt * 8); - } - g_v7_edges = v7_buf; - g_v7_edge_count = edg_cnt; - ei4 : ., mut = 0; - run_off : ., mut = 0; - loop { - if ei4 >= instr_cnt { break; } + pos = seg_off6 + if !ccr_has_bytes(pos, 4, seg_end6): + return -1 + edg_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if edg_cnt > (seg_end6 - seg_off6) / ESZ_EDGE_DISK: + return -1 + v7_buf : string, mut = "" + if edg_cnt > 0: + v7_buf = alloc(edg_cnt * 8) + g_v7_edges = v7_buf + g_v7_edge_count = edg_cnt + ei4 : ., mut = 0 + run_off : ., mut = 0 + loop: + if ei4 >= instr_cnt: + break // 邻接域读内核对象缓冲 g_v7_nod_meta(原 nod_edge_meta loader 局部—— // 内核完备 Task 1 对象留存形态裁决 (a):对象 = 内核持有物,EDG 守卫 // 与对象面 nod_edge_first/count 同源;守卫逻辑零改动) - nfe := r64(g_v7_nod_meta, ei4 * ESZ_NOD_META); - nec := r64(g_v7_nod_meta, ei4 * ESZ_NOD_META + 8); - if nfe != run_off { return -1; } // ① 前缀累计失配(段错位/伪造) - if run_off + nec > edg_cnt { return -1; } // ① 节点段越出 EDG 空间 - rec : ., mut = 0; - loop { - if rec >= nec { break; } - if !ccr_has_bytes(pos, ESZ_EDGE_DISK, seg_end6) { return -1; } - eto := buf_read_u32(data, pos); pos = pos + 4; - ekind := buf_read_u32(data, pos); pos = pos + 4; - if ekind > 1 { return -1; } // ④ 未知边类 - if eto >= instr_cnt { return -1; } // ③ to 出 NOD 空间 - if eto <= ei4 { return -1; } // ③ 后向/自环(拓扑不变量) - w64(v7_buf, (run_off + rec) * 8, eto + ekind * 4294967296); - rec = rec + 1; - } - run_off = run_off + nec; - ei4 = ei4 + 1; - } - if run_off != edg_cnt { return -1; } // ② Σ edge_count == edg_count - if pos != seg_end6 { return -1; } // ② 行走完 == 段体大小 + nfe := r64(g_v7_nod_meta, ei4 * ESZ_NOD_META) + nec := r64(g_v7_nod_meta, ei4 * ESZ_NOD_META + 8) + if nfe != run_off: + return -1 + // ① 前缀累计失配(段错位/伪造) + if run_off + nec > edg_cnt: + return -1 + // ① 节点段越出 EDG 空间 + rec : ., mut = 0 + loop: + if rec >= nec: + break + if !ccr_has_bytes(pos, ESZ_EDGE_DISK, seg_end6): + return -1 + eto := buf_read_u32(data, pos) + pos = pos + 4 + ekind := buf_read_u32(data, pos) + pos = pos + 4 + if ekind > 1: + return -1 + // ④ 未知边类 + if eto >= instr_cnt: + return -1 + // ③ to 出 NOD 空间 + if eto <= ei4: + return -1 + // ③ 后向/自环(拓扑不变量) + w64(v7_buf, (run_off + rec) * 8, eto + ekind * 4294967296) + rec = rec + 1 + run_off = run_off + nec + ei4 = ei4 + 1 + if run_off != edg_cnt: + return -1 + // ② Σ edge_count == edg_count + if pos != seg_end6: + return -1 + // ② 行走完 == 段体大小 // === TYPE(7):类型面(R2 P4 Task 2 内容面——两小节解析 + 内存重建)=== // D12 字节:row_count → 行表(24B/条)→ term_count → 项 DAG(40B/条;哈希 @@ -1544,50 +1880,71 @@ fn load_ccr(data: string, fsize: int) -> int { // 重建(旧行号语义的缓存一并清;行表大小随段内容,此处为唯一复位点)。 // corearch 侧无桥接/checker 层:行表 = 数据(消费者 = --dump-types 通道 + // 未来判定原语),本处不做语义解释。 - g_type_count = 0; - tt_layer_reset(); - pos = seg_off7; - if !ccr_has_bytes(pos, 4, seg_end7) { return -1; } - trow_cnt := buf_read_u32(data, pos); pos = pos + 4; - if trow_cnt > (seg_end7 - pos) / ESZ_TYPE_ROW { return -1; } - grow_types(trow_cnt); - trow : ., mut = 0; - loop { - if trow >= trow_cnt { break; } - if !ccr_has_bytes(pos, ESZ_TYPE_ROW, seg_end7) { return -1; } - w64(g_types, trow * ESZ_TYPE_ROW + OFF_TR_KIND, buf_read_i64(data, pos)); pos = pos + 8; - w64(g_types, trow * ESZ_TYPE_ROW + OFF_TR_DATA, buf_read_i64(data, pos)); pos = pos + 8; - w64(g_types, trow * ESZ_TYPE_ROW + OFF_TR_EXTRA, buf_read_i64(data, pos)); pos = pos + 8; - trow = trow + 1; - } - g_type_count = trow_cnt; - if !ccr_has_bytes(pos, 4, seg_end7) { return -1; } - tterm_cnt := buf_read_u32(data, pos); pos = pos + 4; - if tterm_cnt > (seg_end7 - pos) / ESZ_TYPE_TERM_DISK { return -1; } - grow_type_terms(tterm_cnt + 1); - tj : ., mut = 0; - loop { - if tj >= tterm_cnt { break; } - if !ccr_has_bytes(pos, ESZ_TYPE_TERM_DISK, seg_end7) { return -1; } - ttag := buf_read_i64(data, pos); pos = pos + 8; - ta := buf_read_i64(data, pos); pos = pos + 8; - tb := buf_read_i64(data, pos); pos = pos + 8; - tc2 := buf_read_i64(data, pos); pos = pos + 8; - td := buf_read_i64(data, pos); pos = pos + 8; - if ttag < 0 || ttag > TT_CONS { return -1; } - if ta < -1 || tb < -1 || tc2 < -1 || td < -1 { return -1; } - if ccr_type_term_ref_ok(ttag, ta, tb, tc2, td, tj) == 0 { return -1; } - w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_TAG, ttag); - w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_A, ta); - w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_B, tb); - w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_C, tc2); - w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_D, td); - w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_HASH, tt_hash5(ttag, ta, tb, tc2, td)); - g_type_term_count = tj + 1; - tj = tj + 1; - } - if pos != seg_end7 { return -1; } // 段体恰两小节(无尾随字节) - grow_tt_index(g_type_term_count + 1); // 索引重建(cap 已清零 → 必走重建) + g_type_count = 0 + tt_layer_reset() + pos = seg_off7 + if !ccr_has_bytes(pos, 4, seg_end7): + return -1 + trow_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if trow_cnt > (seg_end7 - pos) / ESZ_TYPE_ROW: + return -1 + grow_types(trow_cnt) + trow : ., mut = 0 + loop: + if trow >= trow_cnt: + break + if !ccr_has_bytes(pos, ESZ_TYPE_ROW, seg_end7): + return -1 + w64(g_types, trow * ESZ_TYPE_ROW + OFF_TR_KIND, buf_read_i64(data, pos)) + pos = pos + 8 + w64(g_types, trow * ESZ_TYPE_ROW + OFF_TR_DATA, buf_read_i64(data, pos)) + pos = pos + 8 + w64(g_types, trow * ESZ_TYPE_ROW + OFF_TR_EXTRA, buf_read_i64(data, pos)) + pos = pos + 8 + trow = trow + 1 + g_type_count = trow_cnt + if !ccr_has_bytes(pos, 4, seg_end7): + return -1 + tterm_cnt := buf_read_u32(data, pos) + pos = pos + 4 + if tterm_cnt > (seg_end7 - pos) / ESZ_TYPE_TERM_DISK: + return -1 + grow_type_terms(tterm_cnt + 1) + tj : ., mut = 0 + loop: + if tj >= tterm_cnt: + break + if !ccr_has_bytes(pos, ESZ_TYPE_TERM_DISK, seg_end7): + return -1 + ttag := buf_read_i64(data, pos) + pos = pos + 8 + ta := buf_read_i64(data, pos) + pos = pos + 8 + tb := buf_read_i64(data, pos) + pos = pos + 8 + tc2 := buf_read_i64(data, pos) + pos = pos + 8 + td := buf_read_i64(data, pos) + pos = pos + 8 + if ttag < 0 || ttag > TT_CONS: + return -1 + if ta < -1 || tb < -1 || tc2 < -1 || td < -1: + return -1 + if ccr_type_term_ref_ok(ttag, ta, tb, tc2, td, tj) == 0: + return -1 + w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_TAG, ttag) + w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_A, ta) + w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_B, tb) + w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_C, tc2) + w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_D, td) + w64(g_type_terms, tj * ESZ_TYPE_TERM + OFF_TT_HASH, tt_hash5(ttag, ta, tb, tc2, td)) + g_type_term_count = tj + 1 + tj = tj + 1 + if pos != seg_end7: + return -1 + // 段体恰两小节(无尾随字节) + grow_tt_index(g_type_term_count + 1) // 索引重建(cap 已清零 → 必走重建) // === IFACE(8):接口面(R2 P4 Task 3 内容面——D14 五小节解析 + 内存重建)=== // 重建 = g_iface_entries(条目表;并置 g_iface_registry_ok = 1——**段 = corearch @@ -1603,157 +1960,228 @@ fn load_ccr(data: string, fsize: int) -> int { // ④ 结构域:ak ∈ 0..AK_NULL、method_count ≤ MAX_IFACE_METHODS、 // param_count ≤ MAX_IFACE_METHOD_PARAMS、self_mode ∈ 0..3。 // IFACE 段 = 纯信息面(不参与 ELF 发射);本段解析失败 = 整体拒绝(load_ccr -1)。 - pos = seg_off8; - if !ccr_has_bytes(pos, 4, seg_end8) { return -1; } - ifc_nat := buf_read_u32(data, pos); pos = pos + 4; - if ifc_nat != IFACE_ENTRY_COUNT { return -1; } - if !ccr_has_bytes(pos, ifc_nat * 24, seg_end8) { return -1; } - g_iface_entries = alloc(ifc_nat * ESZ_IFACE_ENTRY); - ifr : ., mut = 0; - loop { - if ifr >= ifc_nat { break; } - fak := buf_read_i32(data, pos); pos = pos + 4; - fti := buf_read_i32(data, pos); pos = pos + 4; - fname := buf_read_i32(data, pos); pos = pos + 4; - flit := buf_read_i32(data, pos); pos = pos + 4; - fops := buf_read_i64(data, pos); pos = pos + 8; - if fak < 0 || fak > AK_NULL { return -1; } // 原子类域 - if fti < -1 || fti >= g_type_count { return -1; } // 类型行引用域(跨段) - if fname < 0 || fname >= g_str_count { return -1; } // 名字引用域(跨段) - if flit < -1 { return -1; } - fo2 := ifr * ESZ_IFACE_ENTRY; - w64(g_iface_entries, fo2 + OFF_IE_AK, fak); - w64(g_iface_entries, fo2 + OFF_IE_TI, fti); - w64(g_iface_entries, fo2 + OFF_IE_NAME, fname); - w64(g_iface_entries, fo2 + OFF_IE_LIT, flit); - w64(g_iface_entries, fo2 + OFF_IE_OPS, fops); - ifr = ifr + 1; - } - g_iface_entry_count = ifc_nat; - g_iface_registry_ok = 1; + pos = seg_off8 + if !ccr_has_bytes(pos, 4, seg_end8): + return -1 + ifc_nat := buf_read_u32(data, pos) + pos = pos + 4 + if ifc_nat != IFACE_ENTRY_COUNT: + return -1 + if !ccr_has_bytes(pos, ifc_nat * 24, seg_end8): + return -1 + g_iface_entries = alloc(ifc_nat * ESZ_IFACE_ENTRY) + ifr : ., mut = 0 + loop: + if ifr >= ifc_nat: + break + fak := buf_read_i32(data, pos) + pos = pos + 4 + fti := buf_read_i32(data, pos) + pos = pos + 4 + fname := buf_read_i32(data, pos) + pos = pos + 4 + flit := buf_read_i32(data, pos) + pos = pos + 4 + fops := buf_read_i64(data, pos) + pos = pos + 8 + if fak < 0 || fak > AK_NULL: + return -1 + // 原子类域 + if fti < -1 || fti >= g_type_count: + return -1 + // 类型行引用域(跨段) + if fname < 0 || fname >= g_str_count: + return -1 + // 名字引用域(跨段) + if flit < -1: + return -1 + fo2 := ifr * ESZ_IFACE_ENTRY + w64(g_iface_entries, fo2 + OFF_IE_AK, fak) + w64(g_iface_entries, fo2 + OFF_IE_TI, fti) + w64(g_iface_entries, fo2 + OFF_IE_NAME, fname) + w64(g_iface_entries, fo2 + OFF_IE_LIT, flit) + w64(g_iface_entries, fo2 + OFF_IE_OPS, fops) + ifr = ifr + 1 + g_iface_entry_count = ifc_nat + g_iface_registry_ok = 1 // ② 横切形状(名 ni + 形状项) - if !ccr_has_bytes(pos, 4, seg_end8) { return -1; } - ifc_shn := buf_read_u32(data, pos); pos = pos + 4; - if ifc_shn > (seg_end8 - pos) / 8 { return -1; } - iface_shape_grow(ifc_shn); - ifs : ., mut = 0; - loop { - if ifs >= ifc_shn { break; } - sname := buf_read_i32(data, pos); pos = pos + 4; - sterm := buf_read_i32(data, pos); pos = pos + 4; - if sname < 0 || sname >= g_str_count { return -1; } - if sterm < 0 || sterm >= tt_count() { return -1; } // 项引用域(跨段) - w64(g_iface_shape_names, ifs * 8, sname); - w64(g_iface_shape_terms, ifs * 8, sterm); - ifs = ifs + 1; - } - g_iface_shape_count = ifc_shn; + if !ccr_has_bytes(pos, 4, seg_end8): + return -1 + ifc_shn := buf_read_u32(data, pos) + pos = pos + 4 + if ifc_shn > (seg_end8 - pos) / 8: + return -1 + iface_shape_grow(ifc_shn) + ifs : ., mut = 0 + loop: + if ifs >= ifc_shn: + break + sname := buf_read_i32(data, pos) + pos = pos + 4 + sterm := buf_read_i32(data, pos) + pos = pos + 4 + if sname < 0 || sname >= g_str_count: + return -1 + if sterm < 0 || sterm >= tt_count(): + return -1 + // 项引用域(跨段) + w64(g_iface_shape_names, ifs * 8, sname) + w64(g_iface_shape_terms, ifs * 8, sterm) + ifs = ifs + 1 + g_iface_shape_count = ifc_shn // ③ 用户接口(头 16B + 方法 80B × method_count) - if !ccr_has_bytes(pos, 4, seg_end8) { return -1; } - ifc_usn := buf_read_u32(data, pos); pos = pos + 4; - if ifc_usn > (seg_end8 - pos) / 16 { return -1; } - grow_ifaces(ifc_usn); - ifu : ., mut = 0; - loop { - if ifu >= ifc_usn { break; } - if !ccr_has_bytes(pos, 16, seg_end8) { return -1; } - uname := buf_read_i32(data, pos); pos = pos + 4; - umc := buf_read_i32(data, pos); pos = pos + 4; - ugc := buf_read_i32(data, pos); pos = pos + 4; - pos = pos + 4; // pad(预留) - if uname < 0 || uname >= g_str_count { return -1; } - if umc < 0 || umc > MAX_IFACE_METHODS { return -1; } - if ugc < 0 { return -1; } - if !ccr_has_bytes(pos, umc * 80, seg_end8) { return -1; } - ub := ifu * ESZ_IFACEINFO; + if !ccr_has_bytes(pos, 4, seg_end8): + return -1 + ifc_usn := buf_read_u32(data, pos) + pos = pos + 4 + if ifc_usn > (seg_end8 - pos) / 16: + return -1 + grow_ifaces(ifc_usn) + ifu : ., mut = 0 + loop: + if ifu >= ifc_usn: + break + if !ccr_has_bytes(pos, 16, seg_end8): + return -1 + uname := buf_read_i32(data, pos) + pos = pos + 4 + umc := buf_read_i32(data, pos) + pos = pos + 4 + ugc := buf_read_i32(data, pos) + pos = pos + 4 + pos = pos + 4 // pad(预留) + if uname < 0 || uname >= g_str_count: + return -1 + if umc < 0 || umc > MAX_IFACE_METHODS: + return -1 + if ugc < 0: + return -1 + if !ccr_has_bytes(pos, umc * 80, seg_end8): + return -1 + ub := ifu * ESZ_IFACEINFO // 先清零整条记录(防上轮残留;节点槽/项槽的初值 = -1 由下方逐槽写) - uz : ., mut = 0; - loop { if uz >= ESZ_IFACEINFO { break; } w8(g_ifaces, ub + uz, 0); uz = uz + 1; } - w64(g_ifaces, ub + OFF_IF_NAME, uname); - w64(g_ifaces, ub + OFF_IF_METHOD_COUNT, umc); - w64(g_ifaces, ub + OFF_IF_GENERIC_COUNT, ugc); - ium : ., mut = 0; - loop { - if ium >= umc { break; } - mb := ub + OFF_IF_METHODS + ium * ESZ_IFMETHOD; - mname := buf_read_i32(data, pos); pos = pos + 4; - mpc := buf_read_i32(data, pos); pos = pos + 4; - msm := buf_read_i32(data, pos); pos = pos + 4; - mrt := buf_read_i32(data, pos); pos = pos + 4; - if mname < 0 || mname >= g_str_count { return -1; } - if mpc < 0 || mpc > MAX_IFACE_METHOD_PARAMS { return -1; } - if msm < 0 || msm > 3 { return -1; } - if mrt < -1 || mrt >= tt_count() { return -1; } // 项引用域(跨段) - w64(g_ifaces, mb + OFF_IFM_NAME, mname); - w64(g_ifaces, mb + OFF_IFM_PARAM_COUNT, mpc); - w64(g_ifaces, mb + OFF_IFM_SELF_MODE, msm); - w64(g_ifaces, mb + OFF_IFM_RET_TERM, mrt); - w64(g_ifaces, mb + OFF_IFM_RET_NODE, -1); // corearch 无 AST ⇒ 节点槽恒 -1 - mq : ., mut = 0; - loop { - if mq >= MAX_IFACE_METHOD_PARAMS { break; } - mt := buf_read_i32(data, pos); pos = pos + 4; - if mt < -1 || mt >= tt_count() { return -1; } // 项引用域(跨段) - w64(g_ifaces, mb + OFF_IFM_PARAM_TERMS + mq * 8, mt); - w64(g_ifaces, mb + OFF_IFM_PARAM_NODES + mq * 8, -1); // 节点槽恒 -1 - mq = mq + 1; - } - mp : ., mut = 0; - loop { - if mp >= MAX_IFACE_METHOD_PARAMS { break; } - mc2 := buf_read_i32(data, pos); pos = pos + 4; // 裸码(信息面) - if mc2 < -1 { return -1; } - w64(g_ifaces, mb + OFF_IFM_PARAM_TYPES + mp * 8, mc2); - mp = mp + 1; - } - ium = ium + 1; - } - ifu = ifu + 1; - } - g_iface_count = ifc_usn; + uz : ., mut = 0 + loop: + if uz >= ESZ_IFACEINFO: + break + w8(g_ifaces, ub + uz, 0) + uz = uz + 1 + w64(g_ifaces, ub + OFF_IF_NAME, uname) + w64(g_ifaces, ub + OFF_IF_METHOD_COUNT, umc) + w64(g_ifaces, ub + OFF_IF_GENERIC_COUNT, ugc) + ium : ., mut = 0 + loop: + if ium >= umc: + break + mb := ub + OFF_IF_METHODS + ium * ESZ_IFMETHOD + mname := buf_read_i32(data, pos) + pos = pos + 4 + mpc := buf_read_i32(data, pos) + pos = pos + 4 + msm := buf_read_i32(data, pos) + pos = pos + 4 + mrt := buf_read_i32(data, pos) + pos = pos + 4 + if mname < 0 || mname >= g_str_count: + return -1 + if mpc < 0 || mpc > MAX_IFACE_METHOD_PARAMS: + return -1 + if msm < 0 || msm > 3: + return -1 + if mrt < -1 || mrt >= tt_count(): + return -1 + // 项引用域(跨段) + w64(g_ifaces, mb + OFF_IFM_NAME, mname) + w64(g_ifaces, mb + OFF_IFM_PARAM_COUNT, mpc) + w64(g_ifaces, mb + OFF_IFM_SELF_MODE, msm) + w64(g_ifaces, mb + OFF_IFM_RET_TERM, mrt) + w64(g_ifaces, mb + OFF_IFM_RET_NODE, -1) // corearch 无 AST ⇒ 节点槽恒 -1 + mq : ., mut = 0 + loop: + if mq >= MAX_IFACE_METHOD_PARAMS: + break + mt := buf_read_i32(data, pos) + pos = pos + 4 + if mt < -1 || mt >= tt_count(): + return -1 + // 项引用域(跨段) + w64(g_ifaces, mb + OFF_IFM_PARAM_TERMS + mq * 8, mt) + w64(g_ifaces, mb + OFF_IFM_PARAM_NODES + mq * 8, -1) // 节点槽恒 -1 + mq = mq + 1 + mp : ., mut = 0 + loop: + if mp >= MAX_IFACE_METHOD_PARAMS: + break + mc2 := buf_read_i32(data, pos) + pos = pos + 4 // 裸码(信息面) + if mc2 < -1: + return -1 + w64(g_ifaces, mb + OFF_IFM_PARAM_TYPES + mp * 8, mc2) + mp = mp + 1 + ium = ium + 1 + ifu = ifu + 1 + g_iface_count = ifc_usn // ④ impl 边(g_impl_for:{trait_ni, type_ni}——声明元数据) - if !ccr_has_bytes(pos, 4, seg_end8) { return -1; } - ifc_imp := buf_read_u32(data, pos); pos = pos + 4; - if ifc_imp > (seg_end8 - pos) / 8 { return -1; } - grow_impl_for(ifc_imp); - ifi : ., mut = 0; - loop { - if ifi >= ifc_imp { break; } - itr := buf_read_i32(data, pos); pos = pos + 4; - ity := buf_read_i32(data, pos); pos = pos + 4; - if itr < 0 || itr >= g_str_count { return -1; } - if ity < 0 || ity >= g_str_count { return -1; } - w64(g_impl_for, ifi * 16, itr); - w64(g_impl_for, ifi * 16 + 8, ity); - ifi = ifi + 1; - } - g_impl_for_count = ifc_imp; + if !ccr_has_bytes(pos, 4, seg_end8): + return -1 + ifc_imp := buf_read_u32(data, pos) + pos = pos + 4 + if ifc_imp > (seg_end8 - pos) / 8: + return -1 + grow_impl_for(ifc_imp) + ifi : ., mut = 0 + loop: + if ifi >= ifc_imp: + break + itr := buf_read_i32(data, pos) + pos = pos + 4 + ity := buf_read_i32(data, pos) + pos = pos + 4 + if itr < 0 || itr >= g_str_count: + return -1 + if ity < 0 || ity >= g_str_count: + return -1 + w64(g_impl_for, ifi * 16, itr) + w64(g_impl_for, ifi * 16 + 8, ity) + ifi = ifi + 1 + g_impl_for_count = ifc_imp // ⑤ 方法表(g_methods:{type_ni, method_ni, mangled_ni}——iface_find_method 数据面) - if !ccr_has_bytes(pos, 4, seg_end8) { return -1; } - ifc_met := buf_read_u32(data, pos); pos = pos + 4; - if ifc_met > (seg_end8 - pos) / 12 { return -1; } - grow_methods(ifc_met); - ifm : ., mut = 0; - loop { - if ifm >= ifc_met { break; } - mtn := buf_read_i32(data, pos); pos = pos + 4; - mmn := buf_read_i32(data, pos); pos = pos + 4; - mmg := buf_read_i32(data, pos); pos = pos + 4; - if mtn < 0 || mtn >= g_str_count { return -1; } - if mmn < 0 || mmn >= g_str_count { return -1; } - if mmg < 0 || mmg >= g_str_count { return -1; } - w64(g_methods, ifm * 24, mtn); - w64(g_methods, ifm * 24 + 8, mmn); - w64(g_methods, ifm * 24 + 16, mmg); - ifm = ifm + 1; - } - g_method_count = ifc_met; - - if pos != seg_end8 { return -1; } // 五小节行走完 == 段体(无尾随字节) + if !ccr_has_bytes(pos, 4, seg_end8): + return -1 + ifc_met := buf_read_u32(data, pos) + pos = pos + 4 + if ifc_met > (seg_end8 - pos) / 12: + return -1 + grow_methods(ifc_met) + ifm : ., mut = 0 + loop: + if ifm >= ifc_met: + break + mtn := buf_read_i32(data, pos) + pos = pos + 4 + mmn := buf_read_i32(data, pos) + pos = pos + 4 + mmg := buf_read_i32(data, pos) + pos = pos + 4 + if mtn < 0 || mtn >= g_str_count: + return -1 + if mmn < 0 || mmn >= g_str_count: + return -1 + if mmg < 0 || mmg >= g_str_count: + return -1 + w64(g_methods, ifm * 24, mtn) + w64(g_methods, ifm * 24 + 8, mmn) + w64(g_methods, ifm * 24 + 16, mmg) + ifm = ifm + 1 + g_method_count = ifc_met + + if pos != seg_end8: + return -1 + // 五小节行走完 == 段体(无尾随字节) // === NOD 项索引一致性硬校验(R2 P6 Task 3 β)=== // 时点约束:项索引的解析域 = TYPE 段重建的项表(g_type_terms/tt_count)⇒ **必须** @@ -1766,20 +2194,21 @@ fn load_ccr(data: string, fsize: int) -> int { // · item = -1 ⇒ 无需校验(无项:复合行 / 辅码面 / // 无面 / 暖态缺行——码由 `tk` 槽逐字节承担) // 合法文件恒通过(写侧两值同源于 ccr_types.cr:ccr_nod_item_populate 的单次派生)。 - ni : ., mut = 0; - loop { - if ni >= g_v7_nod_count { break; } - itv := nod_item(ni); - if itv < -1 { return -1; } - if itv >= 0 { - if itv >= tt_count() { return -1; } - if tt_atom_of_term(itv) != nod_tk(ni) { return -1; } - } - ni = ni + 1; - } - - return 0; -} + ni : ., mut = 0 + loop: + if ni >= g_v7_nod_count: + break + itv := nod_item(ni) + if itv < -1: + return -1 + if itv >= 0: + if itv >= tt_count(): + return -1 + if tt_atom_of_term(itv) != nod_tk(ni): + return -1 + ni = ni + 1 + + return 0 // ─── TYPE 段项引用拓扑(R2 P4 Task 2;load 侧校验 + 通道/dump 共用)─── // 项引用 = -1(无)或 < 自身行号(DAG 由 tt_term 追加式构造 ⇒ 子项恒先建)。 @@ -1790,22 +2219,27 @@ fn load_ccr(data: string, fsize: int) -> int { // 令牌值/mut 标记——可达数千)、d = 保留 // TT_BOT/TT_TOP/TT_NIL:无引用槽 ;TT_TOP_K:a = k;TT_VAR:a = 绑定变量 // 构造点单源见 ty_shadow.cr 的 sh_ref_mut_marker/sh_name_token/sh_seq_term 三处注记。 -fn ccr_type_ref_before(r: int, row: int) -> int { - if r < 0 { return 1; } // -1 = 无引用 - if r < row { return 1; } // 子项恒先建(DAG 无环) - return 0; -} - -fn ccr_type_term_ref_ok(tag: int, a: int, b: int, c: int, d: int, row: int) -> int { - if tag == TT_UNION || tag == TT_INTER || tag == TT_CONS { - if ccr_type_ref_before(a, row) == 0 { return 0; } - return ccr_type_ref_before(b, row); - } - if tag == TT_NOT { return ccr_type_ref_before(a, row); } - if tag == TT_MU { return ccr_type_ref_before(b, row); } - if tag == TT_ATOM { return ccr_type_ref_before(c, row); } - return 1; // ⊥ / ⊤ / ⊤ₖ / VAR / NIL:无引用槽(a 为标注) -} +fn ccr_type_ref_before(r: int, row: int) -> int: + if r < 0: + return 1 + // -1 = 无引用 + if r < row: + return 1 + // 子项恒先建(DAG 无环) + return 0 + +fn ccr_type_term_ref_ok(tag: int, a: int, b: int, c: int, d: int, row: int) -> int: + if tag == TT_UNION || tag == TT_INTER || tag == TT_CONS: + if ccr_type_ref_before(a, row) == 0: + return 0 + return ccr_type_ref_before(b, row) + if tag == TT_NOT: + return ccr_type_ref_before(a, row) + if tag == TT_MU: + return ccr_type_ref_before(b, row) + if tag == TT_ATOM: + return ccr_type_ref_before(c, row) + return 1 // ⊥ / ⊤ / ⊤ₖ / VAR / NIL:无引用槽(a 为标注) // ─── --dump-types 通道(R2 P4 Task 2):段内容面打印 ─── // 写侧(corec `ccr --dump-types`,经 ccr_types.cr 的 ccr_type_selftest_dump 调 @@ -1814,35 +2248,48 @@ fn ccr_type_term_ref_ok(tag: int, a: int, b: int, c: int, d: int, row: int) -> i // 读侧意义 = §6.3 的读回证据:载入段重建后的行表/项 DAG 与写侧逐行一致, // 且 probe 行的跨进程同值 = 项层原语(tt_norm/tt_is_dnf/tt_is_literal)在同构 // 重建表上逐点同值(下标含新建项 ⇒ 索引重建/去重行为的实证)。 -CCR_TYPE_PROBE_N : int = 16; // probe 窗口(前 N 项) - -fn ccr_type_surface_dump() { - print("rows: "); print_i(g_type_count); println(""); - i : ., mut = 0; - loop { - if i >= g_type_count { break; } - print("row "); print_i(i); - print(" kind "); print_i(r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_KIND)); - print(" data "); print_i(r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_DATA)); - print(" extra "); print_i(r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_EXTRA)); - println(""); - i = i + 1; - } - print("terms: "); print_i(tt_count()); println(""); - j : ., mut = 0; - loop { - if j >= tt_count() { break; } - print("term "); print_i(j); - print(" tag "); print_i(tt_tag(j)); - print(" a "); print_i(tt_a(j)); - print(" b "); print_i(tt_b(j)); - print(" c "); print_i(tt_c(j)); - print(" d "); print_i(tt_d(j)); - println(""); - j = j + 1; - } - ccr_type_probe_dump(); -} +CCR_TYPE_PROBE_N : int = 16 // probe 窗口(前 N 项) + +fn ccr_type_surface_dump(): + print("rows: ") + print_i(g_type_count) + println("") + i : ., mut = 0 + loop: + if i >= g_type_count: + break + print("row ") + print_i(i) + print(" kind ") + print_i(r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_KIND)) + print(" data ") + print_i(r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_DATA)) + print(" extra ") + print_i(r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_EXTRA)) + println("") + i = i + 1 + print("terms: ") + print_i(tt_count()) + println("") + j : ., mut = 0 + loop: + if j >= tt_count(): + break + print("term ") + print_i(j) + print(" tag ") + print_i(tt_tag(j)) + print(" a ") + print_i(tt_a(j)) + print(" b ") + print_i(tt_b(j)) + print(" c ") + print_i(tt_c(j)) + print(" d ") + print_i(tt_d(j)) + println("") + j = j + 1 + ccr_type_probe_dump() // 项层原语跨进程同值探针(**项层**——type_terms.cr 面;判定原语 ty_sub 族不入 // corearch 清单,见 build_selfhost_native.py 的 backend_support_nodes 注记): @@ -1862,168 +2309,240 @@ fn ccr_type_surface_dump() { // 写侧逐行一致;`ifaceprobe` 行 = **跨段引用域的可解析性**(每个项槽在重建的项表上 // 解析:tag/a/c 折叠成摘要——两侧同值即「段内项索引在 corearch 侧解析到同构项」)。 // **零建项**(纯读:不动项表/预算/memo——与 TYPE 的 probe 不同,本处无需构造面)。 -fn ccr_iface_surface_dump() { - print("ifacenative: "); print_i(g_iface_entry_count); println(""); - ei2 : ., mut = 0; - loop { - if ei2 >= g_iface_entry_count { break; } - eo2 := ei2 * ESZ_IFACE_ENTRY; - print("native "); print_i(ei2); - print(" ak "); print_i(r64(g_iface_entries, eo2 + OFF_IE_AK)); - print(" ti "); print_i(r64(g_iface_entries, eo2 + OFF_IE_TI)); - print(" name "); print_i(r64(g_iface_entries, eo2 + OFF_IE_NAME)); - print(" lit "); print_i(r64(g_iface_entries, eo2 + OFF_IE_LIT)); - print(" ops "); print_i(r64(g_iface_entries, eo2 + OFF_IE_OPS)); - println(""); - ei2 = ei2 + 1; - } - print("ifaceshapes: "); print_i(g_iface_shape_count); println(""); - sh2 : ., mut = 0; - loop { - if sh2 >= g_iface_shape_count { break; } - print("shape "); print_i(sh2); - print(" name "); print_i(r64(g_iface_shape_names, sh2 * 8)); - print(" term "); print_i(r64(g_iface_shape_terms, sh2 * 8)); - println(""); - sh2 = sh2 + 1; - } - print("ifaceuser: "); print_i(g_iface_count); println(""); - iu2 : ., mut = 0; - loop { - if iu2 >= g_iface_count { break; } - bo := iu2 * ESZ_IFACEINFO; - mc3 := r64(g_ifaces, bo + OFF_IF_METHOD_COUNT); - print("iface "); print_i(iu2); - print(" name "); print_i(r64(g_ifaces, bo + OFF_IF_NAME)); - print(" methods "); print_i(mc3); - print(" generics "); print_i(r64(g_ifaces, bo + OFF_IF_GENERIC_COUNT)); - println(""); - mj2 : ., mut = 0; - loop { - if mj2 >= mc3 { break; } - mbo := bo + OFF_IF_METHODS + mj2 * ESZ_IFMETHOD; - mpc := r64(g_ifaces, mbo + OFF_IFM_PARAM_COUNT); - print("method "); print_i(iu2); print(" "); print_i(mj2); - print(" name "); print_i(r64(g_ifaces, mbo + OFF_IFM_NAME)); - print(" params "); print_i(mpc); - print(" self "); print_i(r64(g_ifaces, mbo + OFF_IFM_SELF_MODE)); - print(" ret "); print_i(r64(g_ifaces, mbo + OFF_IFM_RET_TERM)); - println(""); - mq2 : ., mut = 0; - loop { - if mq2 >= MAX_IFACE_METHOD_PARAMS { break; } - print("mparam "); print_i(iu2); print(" "); print_i(mj2); - print(" "); print_i(mq2); - print(" code "); print_i(r64(g_ifaces, mbo + OFF_IFM_PARAM_TYPES + mq2 * 8)); - print(" term "); print_i(r64(g_ifaces, mbo + OFF_IFM_PARAM_TERMS + mq2 * 8)); - println(""); - mq2 = mq2 + 1; - } - mj2 = mj2 + 1; - } - iu2 = iu2 + 1; - } - print("ifaceimpl: "); print_i(g_impl_for_count); println(""); - ip2 : ., mut = 0; - loop { - if ip2 >= g_impl_for_count { break; } - print("impl "); print_i(ip2); - print(" trait "); print_i(r64(g_impl_for, ip2 * 16)); - print(" type "); print_i(r64(g_impl_for, ip2 * 16 + 8)); - println(""); - ip2 = ip2 + 1; - } - print("ifacemethods: "); print_i(g_method_count); println(""); - im2 : ., mut = 0; - loop { - if im2 >= g_method_count { break; } - print("gmethod "); print_i(im2); - print(" type "); print_i(r64(g_methods, im2 * 24)); - print(" method "); print_i(r64(g_methods, im2 * 24 + 8)); - print(" mangled "); print_i(r64(g_methods, im2 * 24 + 16)); - println(""); - im2 = im2 + 1; - } +fn ccr_iface_surface_dump(): + print("ifacenative: ") + print_i(g_iface_entry_count) + println("") + ei2 : ., mut = 0 + loop: + if ei2 >= g_iface_entry_count: + break + eo2 := ei2 * ESZ_IFACE_ENTRY + print("native ") + print_i(ei2) + print(" ak ") + print_i(r64(g_iface_entries, eo2 + OFF_IE_AK)) + print(" ti ") + print_i(r64(g_iface_entries, eo2 + OFF_IE_TI)) + print(" name ") + print_i(r64(g_iface_entries, eo2 + OFF_IE_NAME)) + print(" lit ") + print_i(r64(g_iface_entries, eo2 + OFF_IE_LIT)) + print(" ops ") + print_i(r64(g_iface_entries, eo2 + OFF_IE_OPS)) + println("") + ei2 = ei2 + 1 + print("ifaceshapes: ") + print_i(g_iface_shape_count) + println("") + sh2 : ., mut = 0 + loop: + if sh2 >= g_iface_shape_count: + break + print("shape ") + print_i(sh2) + print(" name ") + print_i(r64(g_iface_shape_names, sh2 * 8)) + print(" term ") + print_i(r64(g_iface_shape_terms, sh2 * 8)) + println("") + sh2 = sh2 + 1 + print("ifaceuser: ") + print_i(g_iface_count) + println("") + iu2 : ., mut = 0 + loop: + if iu2 >= g_iface_count: + break + bo := iu2 * ESZ_IFACEINFO + mc3 := r64(g_ifaces, bo + OFF_IF_METHOD_COUNT) + print("iface ") + print_i(iu2) + print(" name ") + print_i(r64(g_ifaces, bo + OFF_IF_NAME)) + print(" methods ") + print_i(mc3) + print(" generics ") + print_i(r64(g_ifaces, bo + OFF_IF_GENERIC_COUNT)) + println("") + mj2 : ., mut = 0 + loop: + if mj2 >= mc3: + break + mbo := bo + OFF_IF_METHODS + mj2 * ESZ_IFMETHOD + mpc := r64(g_ifaces, mbo + OFF_IFM_PARAM_COUNT) + print("method ") + print_i(iu2) + print(" ") + print_i(mj2) + print(" name ") + print_i(r64(g_ifaces, mbo + OFF_IFM_NAME)) + print(" params ") + print_i(mpc) + print(" self ") + print_i(r64(g_ifaces, mbo + OFF_IFM_SELF_MODE)) + print(" ret ") + print_i(r64(g_ifaces, mbo + OFF_IFM_RET_TERM)) + println("") + mq2 : ., mut = 0 + loop: + if mq2 >= MAX_IFACE_METHOD_PARAMS: + break + print("mparam ") + print_i(iu2) + print(" ") + print_i(mj2) + print(" ") + print_i(mq2) + print(" code ") + print_i(r64(g_ifaces, mbo + OFF_IFM_PARAM_TYPES + mq2 * 8)) + print(" term ") + print_i(r64(g_ifaces, mbo + OFF_IFM_PARAM_TERMS + mq2 * 8)) + println("") + mq2 = mq2 + 1 + mj2 = mj2 + 1 + iu2 = iu2 + 1 + print("ifaceimpl: ") + print_i(g_impl_for_count) + println("") + ip2 : ., mut = 0 + loop: + if ip2 >= g_impl_for_count: + break + print("impl ") + print_i(ip2) + print(" trait ") + print_i(r64(g_impl_for, ip2 * 16)) + print(" type ") + print_i(r64(g_impl_for, ip2 * 16 + 8)) + println("") + ip2 = ip2 + 1 + print("ifacemethods: ") + print_i(g_method_count) + println("") + im2 : ., mut = 0 + loop: + if im2 >= g_method_count: + break + print("gmethod ") + print_i(im2) + print(" type ") + print_i(r64(g_methods, im2 * 24)) + print(" method ") + print_i(r64(g_methods, im2 * 24 + 8)) + print(" mangled ") + print_i(r64(g_methods, im2 * 24 + 16)) + println("") + im2 = im2 + 1 // 跨段引用域探针:逐接口/方法/有效形参的项槽 // resolved = 0 ≤ t < tt_count()(在重建项表上可解析);unbuilt = t == -1; // bad = t < -1 || t ≥ tt_count()(**必须为 0**——写侧不产、loader 拒绝)。 // 摘要 = Σ (tt_tag×31 + tt_a) 与 (tt_c×31 + 2) 的混入(两侧同值 = 段内项索引 // 解析到同构项;TYPE 段的跨进程同构由 --dump-types 的 probe 行独立承担)。 - slots : ., mut = 0; - built : ., mut = 0; - unbuilt : ., mut = 0; - bad : ., mut = 0; - hsh : ., mut = 0; - ipc : ., mut = 0; - loop { - if ipc >= g_iface_count { break; } - boc := ipc * ESZ_IFACEINFO; - mcc := r64(g_ifaces, boc + OFF_IF_METHOD_COUNT); - mic : ., mut = 0; - loop { - if mic >= mcc { break; } - mbc := boc + OFF_IF_METHODS + mic * ESZ_IFMETHOD; - pcc := r64(g_ifaces, mbc + OFF_IFM_PARAM_COUNT); - slots = slots + 1; - rtc := r64(g_ifaces, mbc + OFF_IFM_RET_TERM); - if rtc == -1 { unbuilt = unbuilt + 1; } - if rtc >= 0 { - if rtc >= tt_count() { bad = bad + 1; } - if rtc < tt_count() { built = built + 1; hsh = hsh * 31 + tt_tag(rtc); hsh = hsh * 31 + tt_a(rtc); hsh = hsh * 31 + tt_c(rtc); } - } - if rtc < -1 { bad = bad + 1; } - pqc : ., mut = 0; - loop { - if pqc >= pcc { break; } - slots = slots + 1; - ptc := r64(g_ifaces, mbc + OFF_IFM_PARAM_TERMS + pqc * 8); - if ptc == -1 { unbuilt = unbuilt + 1; } - if ptc >= 0 { - if ptc >= tt_count() { bad = bad + 1; } - if ptc < tt_count() { built = built + 1; hsh = hsh * 31 + tt_tag(ptc); hsh = hsh * 31 + tt_a(ptc); hsh = hsh * 31 + tt_c(ptc); } - } - if ptc < -1 { bad = bad + 1; } - pqc = pqc + 1; - } - mic = mic + 1; - } - ipc = ipc + 1; - } - print("ifaceprobe: slots "); print_i(slots); - print(" built "); print_i(built); - print(" unbuilt "); print_i(unbuilt); - print(" bad "); print_i(bad); - print(" digest "); println(int_str(hsh)); -} - -fn ccr_type_probe_dump() { - n := tt_count(); - if n > CCR_TYPE_PROBE_N { n = CCR_TYPE_PROBE_N; } - tt_budget_state_reset(); - nn_ok : ., mut = 0; - nn_bad : ., mut = 0; - dnf_ok : ., mut = 0; - lit_ok : ., mut = 0; - h : ., mut = 0; - i : ., mut = 0; - loop { - if i >= n { break; } - norm := tt_norm(i); - if norm < 0 { nn_bad = nn_bad + 1; } else { nn_ok = nn_ok + 1; } - d := -1; - if norm >= 0 { d = tt_is_dnf(norm); } - if d == 1 { dnf_ok = dnf_ok + 1; } - if tt_is_literal(i) == 1 { lit_ok = lit_ok + 1; } + slots : ., mut = 0 + built : ., mut = 0 + unbuilt : ., mut = 0 + bad : ., mut = 0 + hsh : ., mut = 0 + ipc : ., mut = 0 + loop: + if ipc >= g_iface_count: + break + boc := ipc * ESZ_IFACEINFO + mcc := r64(g_ifaces, boc + OFF_IF_METHOD_COUNT) + mic : ., mut = 0 + loop: + if mic >= mcc: + break + mbc := boc + OFF_IF_METHODS + mic * ESZ_IFMETHOD + pcc := r64(g_ifaces, mbc + OFF_IFM_PARAM_COUNT) + slots = slots + 1 + rtc := r64(g_ifaces, mbc + OFF_IFM_RET_TERM) + if rtc == -1: + unbuilt = unbuilt + 1 + if rtc >= 0: + if rtc >= tt_count(): + bad = bad + 1 + if rtc < tt_count(): + built = built + 1 + hsh = hsh * 31 + tt_tag(rtc) + hsh = hsh * 31 + tt_a(rtc) + hsh = hsh * 31 + tt_c(rtc) + if rtc < -1: + bad = bad + 1 + pqc : ., mut = 0 + loop: + if pqc >= pcc: + break + slots = slots + 1 + ptc := r64(g_ifaces, mbc + OFF_IFM_PARAM_TERMS + pqc * 8) + if ptc == -1: + unbuilt = unbuilt + 1 + if ptc >= 0: + if ptc >= tt_count(): + bad = bad + 1 + if ptc < tt_count(): + built = built + 1 + hsh = hsh * 31 + tt_tag(ptc) + hsh = hsh * 31 + tt_a(ptc) + hsh = hsh * 31 + tt_c(ptc) + if ptc < -1: + bad = bad + 1 + pqc = pqc + 1 + mic = mic + 1 + ipc = ipc + 1 + print("ifaceprobe: slots ") + print_i(slots) + print(" built ") + print_i(built) + print(" unbuilt ") + print_i(unbuilt) + print(" bad ") + print_i(bad) + print(" digest ") + println(int_str(hsh)) + +fn ccr_type_probe_dump(): + n := tt_count() + if n > CCR_TYPE_PROBE_N: + n = CCR_TYPE_PROBE_N + tt_budget_state_reset() + nn_ok : ., mut = 0 + nn_bad : ., mut = 0 + dnf_ok : ., mut = 0 + lit_ok : ., mut = 0 + h : ., mut = 0 + i : ., mut = 0 + loop: + if i >= n: + break + norm := tt_norm(i) + if norm < 0: + nn_bad = nn_bad + 1 + else: + nn_ok = nn_ok + 1 + d := -1 + if norm >= 0: + d = tt_is_dnf(norm) + if d == 1: + dnf_ok = dnf_ok + 1 + if tt_is_literal(i) == 1: + lit_ok = lit_ok + 1 // 摘要 = 规范化结果下标 + DNF 位(-1 = 预算耗尽,下标面用 -1 表示) - h = h * 31 + (norm + 2); - h = h * 31 + (d + 2); - i = i + 1; - } - print("probe: n "); print_i(n); - print(" norm_ok "); print_i(nn_ok); - print(" norm_unknown "); print_i(nn_bad); - print(" dnf_ok "); print_i(dnf_ok); - print(" lit_ok "); print_i(lit_ok); - print(" exhausted "); print_i(g_ty_exhausted); - print(" digest "); println(int_str(h)); -} + h = h * 31 + (norm + 2) + h = h * 31 + (d + 2) + i = i + 1 + print("probe: n ") + print_i(n) + print(" norm_ok ") + print_i(nn_ok) + print(" norm_unknown ") + print_i(nn_bad) + print(" dnf_ok ") + print_i(dnf_ok) + print(" lit_ok ") + print_i(lit_ok) + print(" exhausted ") + print_i(g_ty_exhausted) + print(" digest ") + println(int_str(h)) diff --git a/src/compiler/ccr_types.cr b/src/compiler/ccr_types.cr index b2f76356..ea8ab9f1 100644 --- a/src/compiler/ccr_types.cr +++ b/src/compiler/ccr_types.cr @@ -51,34 +51,32 @@ // / main.cr:636 `build`)之后无类型项消费者——`ccr` 分支随后即 return;`build` 分支 // 其后只拼 corearch 命令行(子进程)并 syscall 执行(R2 P5 T5 前此处另有影子摘要 // sh_finish——已随影子层下线删除)。 -fn ccr_type_populate() -> int { +fn ccr_type_populate() -> int: // ① 复位:项层(含引擎预算/memo/lits——见 tt_layer_reset 注记)→ 桥接层。 // 三面都持**旧行号语义**的缓存,少复位任一面 = 陈旧项被当活项(静默)。 - tt_layer_reset(); - sh_map_reset(); // ti→term 桥接缓存(cap/entries 复位;hits 计数随 P5 T5 删除) - sh_unf_map_reset(); // ti→展开项缓存 + tt_layer_reset() + sh_map_reset() // ti→term 桥接缓存(cap/entries 复位;hits 计数随 P5 T5 删除) + sh_unf_map_reset() // ti→展开项缓存 // ①.5 形状重注册(D13 顺序第 2 步,R2 P4 Task 3 落地):六形状按 D17 名重注册 // (幂等覆盖)——先于行装填 ⇒ 形状项行号 = 构造序前段(确定性;形状表本体 // 随 IFACE 段 ② 小节落盘)。 - iface_shape_builtin_init(); + iface_shape_builtin_init() // ② 行序装填:0..g_type_count-1(原生 9 行经 sh_native_ak 快路径,不入缓存)。 // 不可译行 ⇒ 拒绝(-1):**不得**把缺项的类型行静默写成空/跳过—— // 段是「信息恒随载体」的兑现面,缺项即载体损坏。 - i : ., mut = 0; - loop { - if i >= g_type_count { break; } - if sh_term_of_ti(i) < 0 { - print("error: TYPE segment: type row "); - print(int_str(i)); - println(" is not translatable to a type term (save refused)"); - return -1; - } - i = i + 1; - } + i : ., mut = 0 + loop: + if i >= g_type_count: + break + if sh_term_of_ti(i) < 0: + print("error: TYPE segment: type row ") + print(int_str(i)) + println(" is not translatable to a type term (save refused)") + return -1 + i = i + 1 // ③ 接口签名项装填(D13 第③段,R2 P4 Task 3 落地):按接口声明序逐方法装填 // ret_term/param_terms(写入 g_ifaces 的项槽——与 IFACE 段 ③ 小节同一读点)。 - return ccr_iface_populate(); -} + return ccr_iface_populate() // ─── IFACE 段 ③ 小节:接口签名项装填(corec 侧)─── // 逐接口(声明序)逐方法逐形参调 `sh_iface_sig_ret_term`/`sh_iface_sig_param_term` @@ -91,205 +89,241 @@ fn ccr_type_populate() -> int { // 接收者槽 = unit 占位项(sh_iface_sig_param_term 的 self 约定),不触发拒绝。 // **先 report-only**:全语料(计划 Global Constraints 的五类)跑过、零命中后才作硬门 // (报告登记;Corpus 实测见 Task 3 报告 §report-only)。 -fn ccr_iface_populate() -> int { - iface_ensure(); // 条目表可能早于 init_types 被查(自测通道);幂等 - ii : ., mut = 0; - loop { - if ii >= g_iface_count { break; } - mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT); - if mc < 0 || mc > MAX_IFACE_METHODS { - print("error: IFACE segment: interface "); - print(int_str(ii)); - print(" method count "); print(int_str(mc)); - println(" out of range (save refused)"); - return -1; - } - mi : ., mut = 0; - loop { - if mi >= mc { break; } - mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD; - pc := r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT); - if pc < 0 || pc > MAX_IFACE_METHOD_PARAMS { - print("error: IFACE segment: method "); - print(int_str(mi)); - print(" of interface "); print(int_str(ii)); - print(" param count "); print(int_str(pc)); - println(" out of range (save refused)"); - return -1; - } - rt := sh_iface_sig_ret_term(ii, mi); - if rt < 0 { - print("error: IFACE segment: interface "); - print(int_str(ii)); - print(" method "); print(int_str(mi)); - println(" return signature is not translatable to a type term (save refused)"); - return -1; - } - w64(g_ifaces, mbase + OFF_IFM_RET_TERM, rt); - pj : ., mut = 0; - loop { - if pj >= MAX_IFACE_METHOD_PARAMS { break; } - w64(g_ifaces, mbase + OFF_IFM_PARAM_TERMS + pj * 8, -1); // 未用槽 = -1 - pj = pj + 1; - } - pk : ., mut = 0; - loop { - if pk >= pc { break; } - pt := sh_iface_sig_param_term(ii, mi, pk); - if pt < 0 { - print("error: IFACE segment: interface "); - print(int_str(ii)); - print(" method "); print_i(mi); - print(" param "); print_i(pk); - println(" signature is not translatable to a type term (save refused)"); - return -1; - } - w64(g_ifaces, mbase + OFF_IFM_PARAM_TERMS + pk * 8, pt); - pk = pk + 1; - } - mi = mi + 1; - } - ii = ii + 1; - } - return 0; -} +fn ccr_iface_populate() -> int: + iface_ensure() // 条目表可能早于 init_types 被查(自测通道);幂等 + ii : ., mut = 0 + loop: + if ii >= g_iface_count: + break + mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT) + if mc < 0 || mc > MAX_IFACE_METHODS: + print("error: IFACE segment: interface ") + print(int_str(ii)) + print(" method count ") + print(int_str(mc)) + println(" out of range (save refused)") + return -1 + mi : ., mut = 0 + loop: + if mi >= mc: + break + mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD + pc := r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT) + if pc < 0 || pc > MAX_IFACE_METHOD_PARAMS: + print("error: IFACE segment: method ") + print(int_str(mi)) + print(" of interface ") + print(int_str(ii)) + print(" param count ") + print(int_str(pc)) + println(" out of range (save refused)") + return -1 + rt := sh_iface_sig_ret_term(ii, mi) + if rt < 0: + print("error: IFACE segment: interface ") + print(int_str(ii)) + print(" method ") + print(int_str(mi)) + println(" return signature is not translatable to a type term (save refused)") + return -1 + w64(g_ifaces, mbase + OFF_IFM_RET_TERM, rt) + pj : ., mut = 0 + loop: + if pj >= MAX_IFACE_METHOD_PARAMS: + break + w64(g_ifaces, mbase + OFF_IFM_PARAM_TERMS + pj * 8, -1) // 未用槽 = -1 + pj = pj + 1 + pk : ., mut = 0 + loop: + if pk >= pc: + break + pt := sh_iface_sig_param_term(ii, mi, pk) + if pt < 0: + print("error: IFACE segment: interface ") + print(int_str(ii)) + print(" method ") + print_i(mi) + print(" param ") + print_i(pk) + println(" signature is not translatable to a type term (save refused)") + return -1 + w64(g_ifaces, mbase + OFF_IFM_PARAM_TERMS + pk * 8, pt) + pk = pk + 1 + mi = mi + 1 + ii = ii + 1 + return 0 // ─── 段体构造(D12 布局 → g_ccr_type_seg/g_ccr_type_seg_len)─── // 缓冲 = 完整段体(含首字段 row_count),故 ccr_type_seg_size() ≡ 本长度(单源)。 // 调用前必须已 ccr_type_populate()(段内容 = 装填结果,非惰性活表)。 -fn ccr_type_seg_build() -> int { - rc := g_type_count; - tc := tt_count(); - need := 4 + rc * ESZ_TYPE_ROW + 4 + tc * ESZ_TYPE_TERM_DISK; - buf := alloc(need + 64); - pos : ., mut = 0; - w32(buf, pos, rc); pos = pos + 4; - i : ., mut = 0; - loop { - if i >= rc { break; } - w64(buf, pos, r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_KIND)); pos = pos + 8; - w64(buf, pos, r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_DATA)); pos = pos + 8; - w64(buf, pos, r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_EXTRA)); pos = pos + 8; - i = i + 1; - } - w32(buf, pos, tc); pos = pos + 4; - j : ., mut = 0; - loop { - if j >= tc { break; } - w64(buf, pos, tt_tag(j)); pos = pos + 8; - w64(buf, pos, tt_a(j)); pos = pos + 8; - w64(buf, pos, tt_b(j)); pos = pos + 8; - w64(buf, pos, tt_c(j)); pos = pos + 8; - w64(buf, pos, tt_d(j)); pos = pos + 8; - j = j + 1; - } - g_ccr_type_seg = buf; - g_ccr_type_seg_len = need; - return 0; -} +fn ccr_type_seg_build() -> int: + rc := g_type_count + tc := tt_count() + need := 4 + rc * ESZ_TYPE_ROW + 4 + tc * ESZ_TYPE_TERM_DISK + buf := alloc(need + 64) + pos : ., mut = 0 + w32(buf, pos, rc) + pos = pos + 4 + i : ., mut = 0 + loop: + if i >= rc: + break + w64(buf, pos, r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_KIND)) + pos = pos + 8 + w64(buf, pos, r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_DATA)) + pos = pos + 8 + w64(buf, pos, r64(g_types, i * ESZ_TYPE_ROW + OFF_TR_EXTRA)) + pos = pos + 8 + i = i + 1 + w32(buf, pos, tc) + pos = pos + 4 + j : ., mut = 0 + loop: + if j >= tc: + break + w64(buf, pos, tt_tag(j)) + pos = pos + 8 + w64(buf, pos, tt_a(j)) + pos = pos + 8 + w64(buf, pos, tt_b(j)) + pos = pos + 8 + w64(buf, pos, tt_c(j)) + pos = pos + 8 + w64(buf, pos, tt_d(j)) + pos = pos + 8 + j = j + 1 + g_ccr_type_seg = buf + g_ccr_type_seg_len = need + return 0 // ─── IFACE 段体构造(D14 五小节 → g_ccr_iface_seg/g_ccr_iface_seg_len)─── // 缓冲 = 完整段体(含首字段 native_count),故 ccr_iface_seg_size() ≡ 本长度(单源)。 // 调用前必须已 ccr_type_populate()(③ 小节项槽 = 装填结果)。 // 尺寸 = 4 + 16×24(①)+ [4 + sc×8](②)+ [4 + Σ(16 + mc×80)](③)+ [4 + ic×8](④) // + [4 + gc×12](⑤)——与写侧逐字节一致(calc 侧读同一函数)。 -fn ccr_iface_seg_build() -> int { - need : ., mut = 4 + IFACE_ENTRY_COUNT * 24; - need = need + 4 + g_iface_shape_count * 8; - need = need + 4; - ii : ., mut = 0; - loop { - if ii >= g_iface_count { break; } - mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT); - need = need + 16 + mc * 80; - ii = ii + 1; - } - need = need + 4 + g_impl_for_count * 8; - need = need + 4 + g_method_count * 12; - buf := alloc(need + 64); - pos : ., mut = 0; +fn ccr_iface_seg_build() -> int: + need : ., mut = 4 + IFACE_ENTRY_COUNT * 24 + need = need + 4 + g_iface_shape_count * 8 + need = need + 4 + ii : ., mut = 0 + loop: + if ii >= g_iface_count: + break + mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT) + need = need + 16 + mc * 80 + ii = ii + 1 + need = need + 4 + g_impl_for_count * 8 + need = need + 4 + g_method_count * 12 + buf := alloc(need + 64) + pos : ., mut = 0 // ① 原生条目(IFACE_ENTRY_COUNT 行——写侧段 = 内存表原样;计数 = 常量而非 // g_iface_entry_count:表内容恒为常量表,计数漂移 = 程序错误 ⇒ 用常量让 // loader 的 == IFACE_ENTRY_COUNT 闸两侧同源) - w32(buf, pos, IFACE_ENTRY_COUNT); pos = pos + 4; - ei : ., mut = 0; - loop { - if ei >= IFACE_ENTRY_COUNT { break; } - eo := ei * ESZ_IFACE_ENTRY; - buf_write_i32(buf, pos, r64(g_iface_entries, eo + OFF_IE_AK)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_iface_entries, eo + OFF_IE_TI)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_iface_entries, eo + OFF_IE_NAME)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_iface_entries, eo + OFF_IE_LIT)); pos = pos + 4; - buf_write_i64(buf, pos, r64(g_iface_entries, eo + OFF_IE_OPS)); pos = pos + 8; - ei = ei + 1; - } + w32(buf, pos, IFACE_ENTRY_COUNT) + pos = pos + 4 + ei : ., mut = 0 + loop: + if ei >= IFACE_ENTRY_COUNT: + break + eo := ei * ESZ_IFACE_ENTRY + buf_write_i32(buf, pos, r64(g_iface_entries, eo + OFF_IE_AK)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_iface_entries, eo + OFF_IE_TI)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_iface_entries, eo + OFF_IE_NAME)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_iface_entries, eo + OFF_IE_LIT)) + pos = pos + 4 + buf_write_i64(buf, pos, r64(g_iface_entries, eo + OFF_IE_OPS)) + pos = pos + 8 + ei = ei + 1 // ② 横切形状(名 ni + 形状项) - w32(buf, pos, g_iface_shape_count); pos = pos + 4; - si : ., mut = 0; - loop { - if si >= g_iface_shape_count { break; } - buf_write_i32(buf, pos, r64(g_iface_shape_names, si * 8)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_iface_shape_terms, si * 8)); pos = pos + 4; - si = si + 1; - } + w32(buf, pos, g_iface_shape_count) + pos = pos + 4 + si : ., mut = 0 + loop: + if si >= g_iface_shape_count: + break + buf_write_i32(buf, pos, r64(g_iface_shape_names, si * 8)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_iface_shape_terms, si * 8)) + pos = pos + 4 + si = si + 1 // ③ 用户接口(头 16B + 方法 80B × method_count) - w32(buf, pos, g_iface_count); pos = pos + 4; - fi : ., mut = 0; - loop { - if fi >= g_iface_count { break; } - fo := fi * ESZ_IFACEINFO; - buf_write_i32(buf, pos, r64(g_ifaces, fo + OFF_IF_NAME)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_ifaces, fo + OFF_IF_METHOD_COUNT)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_ifaces, fo + OFF_IF_GENERIC_COUNT)); pos = pos + 4; - buf_write_i32(buf, pos, 0); pos = pos + 4; // pad(对齐/预留) - mc2 := r64(g_ifaces, fo + OFF_IF_METHOD_COUNT); - mj : ., mut = 0; - loop { - if mj >= mc2 { break; } - mo := fo + OFF_IF_METHODS + mj * ESZ_IFMETHOD; - buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_NAME)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_PARAM_COUNT)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_SELF_MODE)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_RET_TERM)); pos = pos + 4; - pk2 : ., mut = 0; - loop { - if pk2 >= MAX_IFACE_METHOD_PARAMS { break; } - buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_PARAM_TERMS + pk2 * 8)); pos = pos + 4; - pk2 = pk2 + 1; - } - pq : ., mut = 0; - loop { - if pq >= MAX_IFACE_METHOD_PARAMS { break; } - buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_PARAM_TYPES + pq * 8)); pos = pos + 4; - pq = pq + 1; - } - mj = mj + 1; - } - fi = fi + 1; - } + w32(buf, pos, g_iface_count) + pos = pos + 4 + fi : ., mut = 0 + loop: + if fi >= g_iface_count: + break + fo := fi * ESZ_IFACEINFO + buf_write_i32(buf, pos, r64(g_ifaces, fo + OFF_IF_NAME)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_ifaces, fo + OFF_IF_METHOD_COUNT)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_ifaces, fo + OFF_IF_GENERIC_COUNT)) + pos = pos + 4 + buf_write_i32(buf, pos, 0) + pos = pos + 4 // pad(对齐/预留) + mc2 := r64(g_ifaces, fo + OFF_IF_METHOD_COUNT) + mj : ., mut = 0 + loop: + if mj >= mc2: + break + mo := fo + OFF_IF_METHODS + mj * ESZ_IFMETHOD + buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_NAME)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_PARAM_COUNT)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_SELF_MODE)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_RET_TERM)) + pos = pos + 4 + pk2 : ., mut = 0 + loop: + if pk2 >= MAX_IFACE_METHOD_PARAMS: + break + buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_PARAM_TERMS + pk2 * 8)) + pos = pos + 4 + pk2 = pk2 + 1 + pq : ., mut = 0 + loop: + if pq >= MAX_IFACE_METHOD_PARAMS: + break + buf_write_i32(buf, pos, r64(g_ifaces, mo + OFF_IFM_PARAM_TYPES + pq * 8)) + pos = pos + 4 + pq = pq + 1 + mj = mj + 1 + fi = fi + 1 // ④ impl 边(g_impl_for:{trait_ni, type_ni}——声明元数据,裁决 2 不入判定) - w32(buf, pos, g_impl_for_count); pos = pos + 4; - gi2 : ., mut = 0; - loop { - if gi2 >= g_impl_for_count { break; } - buf_write_i32(buf, pos, r64(g_impl_for, gi2 * 16)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_impl_for, gi2 * 16 + 8)); pos = pos + 4; - gi2 = gi2 + 1; - } + w32(buf, pos, g_impl_for_count) + pos = pos + 4 + gi2 : ., mut = 0 + loop: + if gi2 >= g_impl_for_count: + break + buf_write_i32(buf, pos, r64(g_impl_for, gi2 * 16)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_impl_for, gi2 * 16 + 8)) + pos = pos + 4 + gi2 = gi2 + 1 // ⑤ 方法表(g_methods:{type_ni, method_ni, mangled_ni}——iface_find_method 的唯一数据面) - w32(buf, pos, g_method_count); pos = pos + 4; - mi2 : ., mut = 0; - loop { - if mi2 >= g_method_count { break; } - buf_write_i32(buf, pos, r64(g_methods, mi2 * 24)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_methods, mi2 * 24 + 8)); pos = pos + 4; - buf_write_i32(buf, pos, r64(g_methods, mi2 * 24 + 16)); pos = pos + 4; - mi2 = mi2 + 1; - } - g_ccr_iface_seg = buf; - g_ccr_iface_seg_len = need; - return 0; -} + w32(buf, pos, g_method_count) + pos = pos + 4 + mi2 : ., mut = 0 + loop: + if mi2 >= g_method_count: + break + buf_write_i32(buf, pos, r64(g_methods, mi2 * 24)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_methods, mi2 * 24 + 8)) + pos = pos + 4 + buf_write_i32(buf, pos, r64(g_methods, mi2 * 24 + 16)) + pos = pos + 4 + mi2 = mi2 + 1 + g_ccr_iface_seg = buf + g_ccr_iface_seg_len = need + return 0 // save 前单入口(main.cr 两处调用点共用:D13 装填 → 两段体构造)——-1 = 拒绝落盘。 // R2 P4 Task 3:原 ccr_type_prepare_save 更名(IFACE 段同批入缓冲;调用点三处同步)。 @@ -297,22 +331,23 @@ fn ccr_iface_seg_build() -> int { // 落盘,rc=1 + 诊断)——三态纪律:不可译**不得**静默留空项(那会让 .ccr 的 NOD 类型码 // 静默降级)。时点在本函数入口:拆分器(emit 期与 .cir 装载侧)已把失败计数写好, // 而落盘是最后一道闸(装填/段构造都不看该项面 ⇒ 不在入口拦就没人拦)。 -fn ccr_seg_prepare_save() -> int { - if g_tk_face_fail != 0 { - print("error: "); - print_i(g_tk_face_fail); - println(" type-face DF node(s) with untranslatable type row — refusing to save .ccr (D23)"); - return -1; - } - if ccr_type_populate() != 0 { return -1; } - if ccr_type_seg_build() != 0 { return -1; } - if ccr_iface_seg_build() != 0 { return -1; } +fn ccr_seg_prepare_save() -> int: + if g_tk_face_fail != 0: + print("error: ") + print_i(g_tk_face_fail) + println(" type-face DF node(s) with untranslatable type row — refusing to save .ccr (D23)") + return -1 + if ccr_type_populate() != 0: + return -1 + if ccr_type_seg_build() != 0: + return -1 + if ccr_iface_seg_build() != 0: + return -1 // R2 P6 Task 3(β):NOD 项索引装填——**必须排在 ccr_type_populate() 之后** // (文件空间 = 该调用重建的项表;emit 期活表索引此前已作废),且排在两段体 // 构造之后(本函数只**查询**桥接缓存——行装填已把 0..g_type_count-1 全部 // 建项 ⇒ 全部命中、不新增项 ⇒ 段体字节不受影响)。失败 = 沿用 D23 闸。 - return ccr_nod_item_populate(); -} + return ccr_nod_item_populate() // ─── R2 P6 Task 3(β):NOD 项索引装填(corec 侧;D18——本文件 corec-only)─── // 逐节点(序 = 全局指令序 = 盘上 NOD 记录序)由**盘上派生码**反查 TYPE 段**文件 @@ -328,38 +363,41 @@ fn ccr_seg_prepare_save() -> int { // 拆分,不得二次构造」——实读时序下不可实施(ccr_type_populate 的 tt_layer_reset // 在 save 前作废 emit 期引用);本实现 = 保存期由码经同一桥接函数重派生,与 // `.cir` 装载侧的重派生同构(P4 T4 先例)。 -fn ccr_nod_item_populate() -> int { - n := g_ir_instr_count; - g_ccr_nod_item = alloc((n + 8) * 4); - g_ccr_nod_item_count = n; - ii : ., mut = 0; - loop { - if ii >= n { break; } - tk := iri_tk(ii); - it : ., mut = -1; - if sh_tk_face_of_code(iri_op(ii), tk) == 0 { it = sh_term_of_ti(tk); } - w32(g_ccr_nod_item, ii * 4, it); - ii = ii + 1; - } - return 0; -} +fn ccr_nod_item_populate() -> int: + n := g_ir_instr_count + g_ccr_nod_item = alloc((n + 8) * 4) + g_ccr_nod_item_count = n + ii : ., mut = 0 + loop: + if ii >= n: + break + tk := iri_tk(ii) + it : ., mut = -1 + if sh_tk_face_of_code(iri_op(ii), tk) == 0: + it = sh_term_of_ti(tk) + w32(g_ccr_nod_item, ii * 4, it) + ii = ii + 1 + return 0 // ─── 自测/对拍通道(corec 侧 `ccr --dump-types`)─── // 共享面 dump(ccr_io.cr 的 ccr_type_surface_dump——与 corearch 侧 --dump-types // **同一条打印路径**,跨进程行格式零分歧)+ corec-only 的「行 → 项」映射节 // (corearch 无桥接层故无此节;测试按 "rowterms:" 标记切分两侧输出)。 // 行格式契约见 tests/selfhost/test_ccr_types.py:parse_type_dump。 -fn ccr_type_selftest_dump() { - ccr_type_surface_dump(); - print("rowterms: "); print_i(g_type_count); println(""); - i : ., mut = 0; - loop { - if i >= g_type_count { break; } - print("rowterm "); print_i(i); print(" "); - println(int_str(sh_term_of_ti(i))); - i = i + 1; - } -} +fn ccr_type_selftest_dump(): + ccr_type_surface_dump() + print("rowterms: ") + print_i(g_type_count) + println("") + i : ., mut = 0 + loop: + if i >= g_type_count: + break + print("rowterm ") + print_i(i) + print(" ") + println(int_str(sh_term_of_ti(i))) + i = i + 1 // ─── 自测/对拍通道(corec 侧 `ccr --dump-ifaces`)─── // 共享面 dump(ccr_io.cr 的 ccr_iface_surface_dump——与 corearch 侧 --dump-ifaces @@ -368,31 +406,43 @@ fn ccr_type_selftest_dump() { // 与 ccr_iface_populate 的写入路径分离)——测试据此断言「落盘值 == 活算值」, // 即装填与签名来源零漂移(若 populate 写错槽/写旧值,本节与文件/共享转储不一致)。 // 行格式契约见 tests/selfhost/test_ccr_types.py:parse_iface_dump("ifacesig:" 标记切分)。 -fn ccr_iface_selftest_dump() { - ccr_iface_surface_dump(); - print("ifacesig: "); print_i(g_iface_count); println(""); - 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; } - mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD; - pc := r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT); - print("ifacesig "); print_i(ii); print(" "); print_i(mi); - print(" ret "); print_i(sh_iface_sig_ret_term(ii, mi)); - print(" pc "); print_i(pc); println(""); - pj : ., mut = 0; - loop { - if pj >= pc { break; } - print("ifacesigp "); print_i(ii); print(" "); print_i(mi); - print(" "); print_i(pj); print(" "); - println(int_str(sh_iface_sig_param_term(ii, mi, pj))); - pj = pj + 1; - } - mi = mi + 1; - } - ii = ii + 1; - } -} +fn ccr_iface_selftest_dump(): + ccr_iface_surface_dump() + print("ifacesig: ") + print_i(g_iface_count) + println("") + 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 + mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD + pc := r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT) + print("ifacesig ") + print_i(ii) + print(" ") + print_i(mi) + print(" ret ") + print_i(sh_iface_sig_ret_term(ii, mi)) + print(" pc ") + print_i(pc) + println("") + pj : ., mut = 0 + loop: + if pj >= pc: + break + print("ifacesigp ") + print_i(ii) + print(" ") + print_i(mi) + print(" ") + print_i(pj) + print(" ") + println(int_str(sh_iface_sig_param_term(ii, mi, pj))) + pj = pj + 1 + mi = mi + 1 + ii = ii + 1 diff --git a/src/compiler/checker.cr b/src/compiler/checker.cr index 66425d6b..13cb5551 100644 --- a/src/compiler/checker.cr +++ b/src/compiler/checker.cr @@ -7,15 +7,14 @@ // Entries are 3 ints: kind, data, extra(24B/条——布局常量 ESZ_TYPE_ROW/OFF_TR_* // 在 globals.cr 单源,R2 P4 Task 2 起与 TYPE 段序列化/dump 同源) -fn alloc_type(kind: int, data: int, extra: int) -> int { - idx := g_type_count; - grow_types(idx + 1); - w64(g_types, idx * ESZ_TYPE_ROW + OFF_TR_KIND, kind); - w64(g_types, idx * ESZ_TYPE_ROW + OFF_TR_DATA, data); - w64(g_types, idx * ESZ_TYPE_ROW + OFF_TR_EXTRA, extra); - g_type_count = idx + 1; - return idx; -} +fn alloc_type(kind: int, data: int, extra: int) -> int: + idx := g_type_count + grow_types(idx + 1) + w64(g_types, idx * ESZ_TYPE_ROW + OFF_TR_KIND, kind) + w64(g_types, idx * ESZ_TYPE_ROW + OFF_TR_DATA, data) + w64(g_types, idx * ESZ_TYPE_ROW + OFF_TR_EXTRA, extra) + g_type_count = idx + 1 + return idx // ─── R2 P2a Task 1(F1):同名 TYP_NAMED 建表去重 ─── // 背景(P1 影子对拍 9/9 差异的根因):同一类型名在**每个出现点**都建一行——struct 字面量 @@ -39,19 +38,21 @@ fn alloc_type(kind: int, data: int, extra: int) -> int { // 借道 named_dedup_probe(**不**经守卫)——否则重放自身可能再触发扩容 = 递归。 // ③ 回写前重探:探测与回写之间若有插入/扩容,先前槽位即失效。本路径当前**不可达** // (alloc_type 不回入本函数、grow_types 不碰本表),保留 = 固化契约 + 与先例同形。 -NAMED_DEDUP_INIT_CAP : int = 1024; - -fn named_dedup_init() { - if g_named_dedup_cap <= 0 { - nc : ., mut = NAMED_DEDUP_INIT_CAP; - nb := alloc(nc * 16); - i : ., mut = 0; - loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; } - g_named_dedup = nb; - g_named_dedup_cap = nc; - g_named_dedup_count = 0; - } -} +NAMED_DEDUP_INIT_CAP : int = 1024 + +fn named_dedup_init(): + if g_named_dedup_cap <= 0: + nc : ., mut = NAMED_DEDUP_INIT_CAP + nb := alloc(nc * 16) + i : ., mut = 0 + loop: + if i >= nc: + break + w64(nb, i * 16, -1) + i = i + 1 + g_named_dedup = nb + g_named_dedup_cap = nc + g_named_dedup_count = 0 // 类型表重置(行号空间作废)时侧表随之作废:cap=0 → 下次用惰性重建(空槽全 -1)。 // **可达且必需**(Task 1 评审纠错——原注「不可达防御」是错的):`reset_frontend_state()` @@ -61,60 +62,66 @@ fn named_dedup_init() { // 字符串表(`g_str_count`/`g_str_hash` 零触及)→ 长驻进程内 `str_intern` 名字下标跨请求 // 稳定 ⇒ 陈旧 name→ti **必然命中**,返回的是**上一请求**的行号(此刻新表仅重建到基类型) // → 越界/错行静默错型。删本重置 = 静默错型,不是可选防御。 -fn named_dedup_reset() { - g_named_dedup_cap = 0; - g_named_dedup_count = 0; -} +fn named_dedup_reset(): + g_named_dedup_cap = 0 + g_named_dedup_count = 0 // 无守卫探测(**只可在扩容守卫之后调用**;重建重放借道这里,不经守卫 = 防递归): // 命中 → 该键所在槽;未命中 → 空槽(**不插入**)。形态 = sh_map_find_nogrow(槽位变量 // `slot` + break + 尾 return;函数体不以无 break 的 loop 收尾——自托管 checker 对该形态 // 有 TF01 误报面)。 -fn named_dedup_probe(name_idx: int) -> int { - cap := g_named_dedup_cap; - p : ., mut = tt_mod(name_idx, cap); - slot : ., mut = -1; - loop { - k := r64(g_named_dedup, p * 16); - if k < 0 { slot = p; break; } - if k == name_idx { slot = p; break; } - p = p + 1; if p >= cap { p = 0; } - } - return slot; -} +fn named_dedup_probe(name_idx: int) -> int: + cap := g_named_dedup_cap + p : ., mut = tt_mod(name_idx, cap) + slot : ., mut = -1 + loop: + k := r64(g_named_dedup, p * 16) + if k < 0: + slot = p + break + if k == name_idx: + slot = p + break + p = p + 1 + if p >= cap: + p = 0 + return slot // 扩容 = 重建 + 重放既有条目(sh_map_rehash / 引擎 grow_tt_index 同式);计数随重放重算。 -fn named_dedup_rehash() { - old := g_named_dedup; - old_cap := g_named_dedup_cap; - nc : ., mut = old_cap * 2; - if nc < NAMED_DEDUP_INIT_CAP { nc = NAMED_DEDUP_INIT_CAP; } - nb := alloc(nc * 16); - i : ., mut = 0; - loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; } - g_named_dedup = nb; - g_named_dedup_cap = nc; - g_named_dedup_count = 0; - j : ., mut = 0; - loop { - if j >= old_cap { break; } - k := r64(old, j * 16); - if k >= 0 { - s := named_dedup_probe(k); - w64(g_named_dedup, s * 16, k); - w64(g_named_dedup, s * 16 + 8, r64(old, j * 16 + 8)); - g_named_dedup_count = g_named_dedup_count + 1; - } - j = j + 1; - } -} +fn named_dedup_rehash(): + old := g_named_dedup + old_cap := g_named_dedup_cap + nc : ., mut = old_cap * 2 + if nc < NAMED_DEDUP_INIT_CAP: + nc = NAMED_DEDUP_INIT_CAP + nb := alloc(nc * 16) + i : ., mut = 0 + loop: + if i >= nc: + break + w64(nb, i * 16, -1) + i = i + 1 + g_named_dedup = nb + g_named_dedup_cap = nc + g_named_dedup_count = 0 + j : ., mut = 0 + loop: + if j >= old_cap: + break + k := r64(old, j * 16) + if k >= 0: + s := named_dedup_probe(k) + w64(g_named_dedup, s * 16, k) + w64(g_named_dedup, s * 16 + 8, r64(old, j * 16 + 8)) + g_named_dedup_count = g_named_dedup_count + 1 + j = j + 1 // 槽位(含装填因子守卫 + 重建重放):命中 → 该键所在槽;未命中 → 空槽(不插入)。 -fn named_dedup_slot(name_idx: int) -> int { - named_dedup_init(); - if (g_named_dedup_count + 1) * 2 >= g_named_dedup_cap { named_dedup_rehash(); } - return named_dedup_probe(name_idx); -} +fn named_dedup_slot(name_idx: int) -> int: + named_dedup_init() + if (g_named_dedup_count + 1) * 2 >= g_named_dedup_cap: + named_dedup_rehash() + return named_dedup_probe(name_idx) // 同名 TYP_NAMED 归一行(唯一分配点,8 处调用点见文件头注):命中返回既有行,未命中 // 分配 + 登记。键域契约:name_idx >= 0(-1 = 空槽哨兵)——负键不进侧表(退化为裸分配), @@ -122,35 +129,35 @@ fn named_dedup_slot(name_idx: int) -> int { // (`alloc` 是 bump 分配且不置零 → 不是特指某个固定值,而是任意值——静默错型)。 // 8 处实参均为名字下标(str_intern / si_name / ei_name / 类型节点的 ast_int_val)≥ 0, // 该分支当前不可达 = 防御。 -fn alloc_named_type(name_idx: int) -> int { - if name_idx < 0 { return alloc_type(TYP_NAMED, name_idx, 0); } - slot := named_dedup_slot(name_idx); - if r64(g_named_dedup, slot * 16) == name_idx { return r64(g_named_dedup, slot * 16 + 8); } - ti := alloc_type(TYP_NAMED, name_idx, 0); +fn alloc_named_type(name_idx: int) -> int: + if name_idx < 0: + return alloc_type(TYP_NAMED, name_idx, 0) + slot := named_dedup_slot(name_idx) + if r64(g_named_dedup, slot * 16) == name_idx: + return r64(g_named_dedup, slot * 16 + 8) + ti := alloc_type(TYP_NAMED, name_idx, 0) // 回写前重探(见文件头注③) - slot2 := named_dedup_slot(name_idx); - if r64(g_named_dedup, slot2 * 16) == name_idx { + slot2 := named_dedup_slot(name_idx) + if r64(g_named_dedup, slot2 * 16) == name_idx: // 防御(当前不可达):既有登记优先 → 本次刚分配的行成孤儿行(不写侧表、不计数)。 // 反例写法(无条件写 slot2)会覆盖活跃条目 = 丢登记。 - return r64(g_named_dedup, slot2 * 16 + 8); - } - w64(g_named_dedup, slot2 * 16, name_idx); - w64(g_named_dedup, slot2 * 16 + 8, ti); - g_named_dedup_count = g_named_dedup_count + 1; - return ti; -} + return r64(g_named_dedup, slot2 * 16 + 8) + w64(g_named_dedup, slot2 * 16, name_idx) + w64(g_named_dedup, slot2 * 16 + 8, ti) + g_named_dedup_count = g_named_dedup_count + 1 + return ti // 自测用(type_selftest.cr):该名字当前在类型表里占的行数(恒 0/1;0 = 尚未分配)。 -fn named_dedup_rows(name_idx: int) -> int { - n : ., mut = 0; - i : ., mut = 0; - loop { - if i >= g_type_count { break; } - if get_type_kind(i) == TYP_NAMED && get_type_data(i) == name_idx { n = n + 1; } - i = i + 1; - } - return n; -} +fn named_dedup_rows(name_idx: int) -> int: + n : ., mut = 0 + i : ., mut = 0 + loop: + if i >= g_type_count: + break + if get_type_kind(i) == TYP_NAMED && get_type_data(i) == name_idx: + n = n + 1 + i = i + 1 + return n // ─── R2 P2a Task 3(C-4):侧表 ↔ res_type_node **管线内断言**(`--verify-named-dedup`)─── // 背景(Task 1 交接必测项,评审裁决):`f1.*` 用例是**人造夹具**(自测通道不经 check_all, @@ -169,170 +176,170 @@ fn named_dedup_rows(name_idx: int) -> int { // 只计不改:不动类型表/侧表/符号表,只读 + 计数。返回 = 不一致条数(0 = 全过)。 // 摘要行恒打印(本函数仅在 --verify-named-dedup 下被调用;默认路径零调用)。 // 性能注:③ 的 find_gsym 是符号表倒序线性扫描 → 语料越大越慢,仅调试通道(默认关)。 -fn named_dedup_verify() -> int { - bad : ., mut = 0; // 不一致条数(返回) - named_rows : ., mut = 0; // 断言①覆盖的 TYP_NAMED 行数 - ident_checked : ., mut = 0; // 断言③覆盖的类型名引用节点数 +fn named_dedup_verify() -> int: + bad : ., mut = 0 // 不一致条数(返回) + named_rows : ., mut = 0 // 断言①覆盖的 TYP_NAMED 行数 + ident_checked : ., mut = 0 // 断言③覆盖的类型名引用节点数 // ① 类型表 → 侧表 - ti : ., mut = 0; - loop { - if ti >= g_type_count { break; } - if get_type_kind(ti) == TYP_NAMED { - named_rows = named_rows + 1; - ni := get_type_data(ti); - slot := named_dedup_slot(ni); - if r64(g_named_dedup, slot * 16) != ni { bad = bad + 1; } - else if r64(g_named_dedup, slot * 16 + 8) != ti { bad = bad + 1; } - } - ti = ti + 1; - } + ti : ., mut = 0 + loop: + if ti >= g_type_count: + break + if get_type_kind(ti) == TYP_NAMED: + named_rows = named_rows + 1 + ni := get_type_data(ti) + slot := named_dedup_slot(ni) + if r64(g_named_dedup, slot * 16) != ni: + bad = bad + 1 + else if r64(g_named_dedup, slot * 16 + 8) != ti: + bad = bad + 1 + ti = ti + 1 // ② 侧表 → 类型表 + 唯一性 - e : ., mut = 0; - loop { - if e >= g_named_dedup_cap { break; } - ni2 := r64(g_named_dedup, e * 16); - if ni2 >= 0 { - ti2 := r64(g_named_dedup, e * 16 + 8); - if get_type_kind(ti2) != TYP_NAMED { bad = bad + 1; } - else if get_type_data(ti2) != ni2 { bad = bad + 1; } - if named_dedup_rows(ni2) != 1 { bad = bad + 1; } - } - e = e + 1; - } + e : ., mut = 0 + loop: + if e >= g_named_dedup_cap: + break + ni2 := r64(g_named_dedup, e * 16) + if ni2 >= 0: + ti2 := r64(g_named_dedup, e * 16 + 8) + if get_type_kind(ti2) != TYP_NAMED: + bad = bad + 1 + else if get_type_data(ti2) != ni2: + bad = bad + 1 + if named_dedup_rows(ni2) != 1: + bad = bad + 1 + e = e + 1 // ③ 读取面:EXPR_IDENT(类型名引用)→ res_type_node 必须落回侧表同一行 - ai : ., mut = 0; - loop { - if ai >= g_ast_count { break; } - if ast_kind(ai) == EXPR_IDENT { - ni3 := ast_int_val(ai); - si := find_gsym(ni3); - if si >= 0 && sym_kind(si) == SYM_TYPE { - sti := sym_type(si); + ai : ., mut = 0 + loop: + if ai >= g_ast_count: + break + if ast_kind(ai) == EXPR_IDENT: + ni3 := ast_int_val(ai) + si := find_gsym(ni3) + if si >= 0 && sym_kind(si) == SYM_TYPE: + sti := sym_type(si) // 泛型形参也 def_sym 为 SYM_TYPE,但其行 kind = TYP_GENERIC_PARAM(不经侧表) - if get_type_kind(sti) == TYP_NAMED { - ident_checked = ident_checked + 1; - slot3 := named_dedup_slot(ni3); - if r64(g_named_dedup, slot3 * 16) != ni3 { bad = bad + 1; } - else if r64(g_named_dedup, slot3 * 16 + 8) != res_type_node(ai) { bad = bad + 1; } - } - } - } - ai = ai + 1; - } - print("[named-dedup] named_rows="); - print(int_str(named_rows)); - print(" ident_checks="); - print(int_str(ident_checked)); - print(" mismatches="); - println(int_str(bad)); - return bad; -} - -fn init_types() { - g_type_count = 0; - named_dedup_reset(); // 类型表重置 → 侧表随之作废(陈旧 name→ti 不得跨重置复用) + if get_type_kind(sti) == TYP_NAMED: + ident_checked = ident_checked + 1 + slot3 := named_dedup_slot(ni3) + if r64(g_named_dedup, slot3 * 16) != ni3: + bad = bad + 1 + else if r64(g_named_dedup, slot3 * 16 + 8) != res_type_node(ai): + bad = bad + 1 + ai = ai + 1 + print("[named-dedup] named_rows=") + print(int_str(named_rows)) + print(" ident_checks=") + print(int_str(ident_checked)) + print(" mismatches=") + println(int_str(bad)) + return bad + +fn init_types(): + g_type_count = 0 + named_dedup_reset() // 类型表重置 → 侧表随之作废(陈旧 name→ti 不得跨重置复用) // R2 P3 Task 5:约束诊断去重侧表同理作废(键含 AST 节点下标:跨编译期复用会漏报/误报) - gen_constr_seen_reset(); + gen_constr_seen_reset() // R2 P2a Task 3 评审 Critical:桥接缓存(ti→term)**同理必须作废**——本批起判定路径无条件 // 调 sh_term_of_ti,长驻进程(corelsp 每请求 init_types)复用行号时会命中陈旧 ti→term // ⇒ 两个不同类型被判等(静默漏报;评审实证见 ty_shadow.cr:sh_map_reset 注记)。 - sh_map_reset(); + sh_map_reset() // R2 P3 Task 0:展开层缓存(ti→展开项)**同理必须作废**(同因:行号空间复用 ⇒ 陈旧 // ti→展开项命中 = 把上一请求的类型结构安到当前行上;同 sh_map_reset 的评审 Critical)。 - sh_unf_map_reset(); + sh_unf_map_reset() // R2 P5 Task 4:判定回落计数(g_replace_*)随 legacy 一并删除——未知面改走 P-A 硬错 // (ICE04,无跨请求累积语义:诊断在产生它的那次编译里即出)。 // R2 P5 Task 2(D23):单槽化建项失败位同生命周期(类型行号空间作废 ⇒ 该位只对本 // 编译期有意义;LSP 每请求 init_types ⇒ 不跨请求累积)。 - g_tk_face_fail = 0; - alloc_type(TYP_BASE, TY_INT, 0); // TI_INT = 0 - alloc_type(TYP_BASE, TY_DEX, 0); // TI_DEX = 1 - alloc_type(TYP_BASE, TY_BOOL, 0); // TI_BOOL = 2 - alloc_type(TYP_BASE, TY_STRING, 0); // TI_STR = 3 - alloc_type(TYP_BASE, TY_UNIT, 0); // TI_UNIT = 4 - alloc_type(TYP_BASE, TY_NEVER, 0); // TI_NEVER = 5 - alloc_type(TYP_BASE, TY_CHAR, 0); // TI_CHAR = 6 - alloc_type(TYP_DYN, 0, 0); // TI_DYN = 7 + g_tk_face_fail = 0 + alloc_type(TYP_BASE, TY_INT, 0) // TI_INT = 0 + alloc_type(TYP_BASE, TY_DEX, 0) // TI_DEX = 1 + alloc_type(TYP_BASE, TY_BOOL, 0) // TI_BOOL = 2 + alloc_type(TYP_BASE, TY_STRING, 0) // TI_STR = 3 + alloc_type(TYP_BASE, TY_UNIT, 0) // TI_UNIT = 4 + alloc_type(TYP_BASE, TY_NEVER, 0) // TI_NEVER = 5 + alloc_type(TYP_BASE, TY_CHAR, 0) // TI_CHAR = 6 + alloc_type(TYP_DYN, 0, 0) // TI_DYN = 7 // TI_DEX_S = 8 占位表项(终审 M1 修复):TI_DEX_S 是 dex 定点精确形式(缩放整数) // 的 IR 变量类型哨兵,值恰为 8——曾与"首个动态分配类型下标"碰撞,@sizeOf/@alignOf/ // is_ptr_var 的哨兵守卫对首个真实类型误触发。占住下标 8 后用户类型从 9 起, // 守卫永不再命中真实类型(TI_DEX_S 本身仍不查类型表,见 ir_gen.cr 注释)。 - alloc_type(TYP_BASE, TY_DEX_S, 0); // TI_DEX_S = 8 占位 + alloc_type(TYP_BASE, TY_DEX_S, 0) // TI_DEX_S = 8 占位 // R2 P2b Task 1:本质条目表(iface_registry.cr)——静态数据(AK_*/TI_* 常量 + -1/0 + // R2 P4 Task 3 起的注册名 ni),不 alloc 类型行、不缓存本函数刚分配的行号 ⇒ 重复调用 // 无副作用(长驻进程每请求一次)。 // 位置 = 9 行原生 alloc 之后(表内容不依赖类型表,此处仅为「随类型表生命周期初始化」)。 - iface_registry_init(); + iface_registry_init() // R2 P4 Task 3(裁决 1 + D17):六形状**名字生产注册面**(sequence/sequence_ro/ // sequence_rw/indexable/iterable/product → sh_shape_*() 构造点)。无条件调用(幂等: // iface_shape_register 同名覆盖;reset_frontend_state 清 count 后由本行重建)—— // 段内容 = 表本体(生产编译下恰 6 条)。详细边界见 iface_shape_builtin_init 注。 - iface_shape_builtin_init(); -} + iface_shape_builtin_init() // ── Runtime builtin declarations (no .cr body, implemented in rt.s) ── -g_rt_builtin_count : int, mut; -g_rt_builtin_names : string, mut; -g_rt_builtin_ret_types : string, mut; - -fn init_builtins() { - g_rt_builtin_count = 0; g_rt_builtin_names = alloc(8 * 8); g_rt_builtin_ret_types = alloc(8 * 8); - - bi_add("load8", TI_INT); - bi_add("store8", TI_INT); - bi_add("load64", TI_INT); - bi_add("r64", TI_INT); - bi_add("alloc", TI_STR); - bi_add("get_arg", TI_STR); - bi_add("w32", TI_UNIT); - bi_add("w64", TI_UNIT); - bi_add("_dyncpy", TI_UNIT); - bi_add("load_str_ptr", TI_STR); - bi_add("store_str_ptr", TI_INT); - bi_add("sched_call_0", TI_INT); - bi_add("sched_call_1", TI_INT); - bi_add("sched_call_2", TI_INT); - bi_add("sched_call_3", TI_INT); - bi_add("sched_call_4", TI_INT); - bi_add("fiber_switch", TI_INT); - bi_add("fiber_init", TI_INT); - bi_add("sched_go", TI_INT); - bi_add("m_start_workers", TI_UNIT); - bi_add("g_set_curg", TI_UNIT); - bi_add("g_get_curg", TI_INT); -} - -fn bi_add(name: string, ret_ti: int) { - ni := str_intern(name); - if g_rt_builtin_count * 8 + 8 > str_len(g_rt_builtin_names) { - nc := g_rt_builtin_count * 2 + 16; - nb := alloc(nc * 8); _dyncpy(g_rt_builtin_names, g_rt_builtin_count * 8, nb); - g_rt_builtin_names = nb; - } - if g_rt_builtin_count * 8 + 8 > str_len(g_rt_builtin_ret_types) { - nc := g_rt_builtin_count * 2 + 16; - nb := alloc(nc * 8); _dyncpy(g_rt_builtin_ret_types, g_rt_builtin_count * 8, nb); - g_rt_builtin_ret_types = nb; - } - w64(g_rt_builtin_names, g_rt_builtin_count * 8, ni); - w64(g_rt_builtin_ret_types, g_rt_builtin_count * 8, ret_ti); - g_rt_builtin_count = g_rt_builtin_count + 1; -} - -fn get_type_kind(ti: int) -> int { - if ti >= 0 && ti < g_type_count { return r64(g_types, ti * 24); } - return -1; -} - -fn get_type_data(ti: int) -> int { - if ti >= 0 && ti < g_type_count { return r64(g_types, ti * 24 + 8); } - return 0; -} - -fn get_type_extra(ti: int) -> int { - if ti >= 0 && ti < g_type_count { return r64(g_types, ti * 24 + 16); } - return 0; -} +g_rt_builtin_count : int, mut +g_rt_builtin_names : string, mut +g_rt_builtin_ret_types : string, mut + +fn init_builtins(): + g_rt_builtin_count = 0 + g_rt_builtin_names = alloc(8 * 8) + g_rt_builtin_ret_types = alloc(8 * 8) + + bi_add("load8", TI_INT) + bi_add("store8", TI_INT) + bi_add("load64", TI_INT) + bi_add("r64", TI_INT) + bi_add("alloc", TI_STR) + bi_add("get_arg", TI_STR) + bi_add("w32", TI_UNIT) + bi_add("w64", TI_UNIT) + bi_add("_dyncpy", TI_UNIT) + bi_add("load_str_ptr", TI_STR) + bi_add("store_str_ptr", TI_INT) + bi_add("sched_call_0", TI_INT) + bi_add("sched_call_1", TI_INT) + bi_add("sched_call_2", TI_INT) + bi_add("sched_call_3", TI_INT) + bi_add("sched_call_4", TI_INT) + bi_add("fiber_switch", TI_INT) + bi_add("fiber_init", TI_INT) + bi_add("sched_go", TI_INT) + bi_add("m_start_workers", TI_UNIT) + bi_add("g_set_curg", TI_UNIT) + bi_add("g_get_curg", TI_INT) + +fn bi_add(name: string, ret_ti: int): + ni := str_intern(name) + if g_rt_builtin_count * 8 + 8 > str_len(g_rt_builtin_names): + nc := g_rt_builtin_count * 2 + 16 + nb := alloc(nc * 8) + _dyncpy(g_rt_builtin_names, g_rt_builtin_count * 8, nb) + g_rt_builtin_names = nb + if g_rt_builtin_count * 8 + 8 > str_len(g_rt_builtin_ret_types): + nc := g_rt_builtin_count * 2 + 16 + nb := alloc(nc * 8) + _dyncpy(g_rt_builtin_ret_types, g_rt_builtin_count * 8, nb) + g_rt_builtin_ret_types = nb + w64(g_rt_builtin_names, g_rt_builtin_count * 8, ni) + w64(g_rt_builtin_ret_types, g_rt_builtin_count * 8, ret_ti) + g_rt_builtin_count = g_rt_builtin_count + 1 + +fn get_type_kind(ti: int) -> int: + if ti >= 0 && ti < g_type_count: + return r64(g_types, ti * 24) + return -1 + +fn get_type_data(ti: int) -> int: + if ti >= 0 && ti < g_type_count: + return r64(g_types, ti * 24 + 8) + return 0 + +fn get_type_extra(ti: int) -> int: + if ti >= 0 && ti < g_type_count: + return r64(g_types, ti * 24 + 16) + return 0 // ─── R2 P2a Task 2(F2):常量档数组长度约束 ─── // 背景(P1 findings §6.F2):身份判等(当时的 type_equal 结构判等,R2 P5 Task 4 已删)曾把 N @@ -378,62 +385,66 @@ fn get_type_extra(ti: int) -> int { // 同 kind 的 N 比较**两面皆对称**(ty_equiv 双向 / extra 相等),逐站复验见 p3-task1 报告; // hotpatch 站(1,两侧皆声明、无源/目标)改用 `type_compat_sym`(对称核 = 现状语义)。 // **方向只在「宽度不匹配」的固定性维上生效**——同 kind 面(含两个数组比 N)逐位保持 P2a 语义。 -fn array_len_walk(ti_a: int, ti_b: int, dir: int) -> int { - ka := get_type_kind(ti_a); - kb := get_type_kind(ti_b); - if ka != kb { - if dir == 1 { if ka == TYP_SLICE && kb == TYP_ARRAY { return 0; } } // 视图→固定:不给放行 - return 1; - } - if ka == TYP_ARRAY { - if get_type_extra(ti_a) != get_type_extra(ti_b) { return 0; } - return array_len_walk(get_type_data(ti_a), get_type_data(ti_b), dir); - } - if ka == TYP_PTR || ka == TYP_REF || ka == TYP_SLICE { - return array_len_walk(get_type_data(ti_a), get_type_data(ti_b), dir); - } - if ka == TYP_TUPLE { - fc := get_type_data(ti_a); - if fc != get_type_data(ti_b) { return 1; } // 字段数不同:身份判定负责 - fs1 := get_type_extra(ti_a); - fs2 := get_type_extra(ti_b); - fi : ., mut = 0; - loop { - if fi >= fc { break; } - if array_len_walk(r64(g_gen_apply_data, (fs1 + fi) * 8), r64(g_gen_apply_data, (fs2 + fi) * 8), dir) == 0 { return 0; } - fi = fi + 1; - } - return 1; - } - if ka == TYP_GENERIC_APPLY { - if get_type_data(ti_a) != get_type_data(ti_b) { return 1; } // 基型不同:身份判定负责 - as1 := get_type_extra(ti_a); - as2 := get_type_extra(ti_b); - ac1 := r64(g_gen_apply_data, as1 * 8); - ac2 := r64(g_gen_apply_data, as2 * 8); - if ac1 != ac2 { return 1; } // 实参数不同:身份判定负责 - ai : ., mut = 0; - loop { - if ai >= ac1 { break; } - if array_len_walk(r64(g_gen_apply_data, (as1 + 1 + ai) * 8), r64(g_gen_apply_data, (as2 + 1 + ai) * 8), dir) == 0 { return 0; } - ai = ai + 1; - } - return 1; - } - return 1; -} +fn array_len_walk(ti_a: int, ti_b: int, dir: int) -> int: + ka := get_type_kind(ti_a) + kb := get_type_kind(ti_b) + if ka != kb: + if dir == 1: + if ka == TYP_SLICE && kb == TYP_ARRAY: + return 0 + // 视图→固定:不给放行 + return 1 + if ka == TYP_ARRAY: + if get_type_extra(ti_a) != get_type_extra(ti_b): + return 0 + return array_len_walk(get_type_data(ti_a), get_type_data(ti_b), dir) + if ka == TYP_PTR || ka == TYP_REF || ka == TYP_SLICE: + return array_len_walk(get_type_data(ti_a), get_type_data(ti_b), dir) + if ka == TYP_TUPLE: + fc := get_type_data(ti_a) + if fc != get_type_data(ti_b): + return 1 + // 字段数不同:身份判定负责 + fs1 := get_type_extra(ti_a) + fs2 := get_type_extra(ti_b) + fi : ., mut = 0 + loop: + if fi >= fc: + break + if array_len_walk(r64(g_gen_apply_data, (fs1 + fi) * 8), r64(g_gen_apply_data, (fs2 + fi) * 8), dir) == 0: + return 0 + fi = fi + 1 + return 1 + if ka == TYP_GENERIC_APPLY: + if get_type_data(ti_a) != get_type_data(ti_b): + return 1 + // 基型不同:身份判定负责 + as1 := get_type_extra(ti_a) + as2 := get_type_extra(ti_b) + ac1 := r64(g_gen_apply_data, as1 * 8) + ac2 := r64(g_gen_apply_data, as2 * 8) + if ac1 != ac2: + return 1 + // 实参数不同:身份判定负责 + ai : ., mut = 0 + loop: + if ai >= ac1: + break + if array_len_walk(r64(g_gen_apply_data, (as1 + 1 + ai) * 8), r64(g_gen_apply_data, (as2 + 1 + ai) * 8), dir) == 0: + return 0 + ai = ai + 1 + return 1 + return 1 // 方向面(有源/目标语义的站点):见上「参序约定」注记。 -fn array_len_constraint_ok(ti_a: int, ti_b: int) -> int { - return array_len_walk(ti_a, ti_b, 1); -} +fn array_len_constraint_ok(ti_a: int, ti_b: int) -> int: + return array_len_walk(ti_a, ti_b, 1) // 对称核(无方向的站点:hotpatch 一致性——两侧皆声明):= R2 P2a Task 2 原语义逐字 // (跨 kind 一律无约束)。保留为独立入口的理由 = 「无源/目标」不是「源/目标之一」的退化, // 用方向版会退化成**任一路由参序决定的任意判**(同一声明对换个声明序即改判)。 -fn array_len_constraint_sym(ti_a: int, ti_b: int) -> int { - return array_len_walk(ti_a, ti_b, 0); -} +fn array_len_constraint_sym(ti_a: int, ti_b: int) -> int: + return array_len_walk(ti_a, ti_b, 0) // F2 判定点组合(**站点**用):身份判等 ∧ 常量档长度约束 ∧(Task 1)方向规则。 // N 不入身份(R1 裁决)⇒ 判定点必须在 type_equal 之外显式补检——否则 Task 3 替换身份实现后 @@ -443,8 +454,8 @@ fn array_len_constraint_sym(ti_a: int, ti_b: int) -> int { // ——否则判定面旁路(历史依据:影子对拍期站点调用次数/位置必须可比,P1 登记;影子通道已随 // P5 Task 5 下线,本条 = 判定面单点纪律的继承)。 // 参序 =(源,目标)——见 array_len_walk 上方的归一说明。 -fn type_compat_strict(ti_a: int, ti_b: int) -> int { - if !type_equal(ti_a, ti_b) { +fn type_compat_strict(ti_a: int, ti_b: int) -> int: + if !type_equal(ti_a, ti_b): // ─── R2 P3 Task 4:**可选目标的子类型注入**(`T ⊆ T?`、`null ⊆ T?`)─── // 语义(spec §5.4):`T?` = `T ∪ null` ⇒ 裸 T 值与 None 值**本来就该**流进 T? 的槽 // (返回位/赋值位/实参位/字段位…同一组合函数)。而行面判定是**身份**口径 @@ -455,45 +466,44 @@ fn type_compat_strict(ti_a: int, ti_b: int) -> int { // 站点面(type_equal 采样、长度档、措辞分派)与 P2a/P2b 判据**零改动**。反方向 // (`T?` 值进 `T` 槽)不注入:引擎 ty_sub(union, T) = 0 ⇒ 照旧拒绝(soundness 面)。 // 三态纪律:引擎 0/-1(不含/未知)一律**不放行**(未知不得当放宽)。 - if get_type_kind(ti_b) == TYP_OPTIONAL { - if ti_subsumes(ti_a, ti_b) == 1 { return 1; } - } - return 0; - } - if array_len_constraint_ok(ti_a, ti_b) == 0 { return -1; } - return 1; -} + if get_type_kind(ti_b) == TYP_OPTIONAL: + if ti_subsumes(ti_a, ti_b) == 1: + return 1 + return 0 + if array_len_constraint_ok(ti_a, ti_b) == 0: + return -1 + return 1 // R2 P3 Task 4:ti 级包含判定(源 ⊆ 目标)——桥接 + 引擎 `ty_sub` 三态,**仅 1 放行** // (0 = 确定不含、-1 = 未知 ⇒ 都回 0:本入口只服务「放松注入」,未知绝不当放宽 = 三态纪律)。 // 预算前后隔离照 type_equal_engine 的窗口纪律(引擎 memo 跨查询命中会让结果依赖预算历史); // 不触碰 `g_replace_*` 计数(那两个计数是 type_equal 替换面的台账,本入口不属该面)。 -fn ti_subsumes(src_ti: int, tgt_ti: int) -> int { - a := sh_term_of_ti(src_ti); - b := sh_term_of_ti(tgt_ti); - if a < 0 || b < 0 { return 0; } - ty_budget_reset(200000); - s := ty_sub(a, b); - ty_budget_reset(200000); - if s == 1 { return 1; } - return 0; -} +fn ti_subsumes(src_ti: int, tgt_ti: int) -> int: + a := sh_term_of_ti(src_ti) + b := sh_term_of_ti(tgt_ti) + if a < 0 || b < 0: + return 0 + ty_budget_reset(200000) + s := ty_sub(a, b) + ty_budget_reset(200000) + if s == 1: + return 1 + return 0 // 无方向站点的组合(与 type_compat_strict 同构,仅长度面走对称核):hotpatch 站(1)用。 -fn type_compat_sym(ti_a: int, ti_b: int) -> int { - if !type_equal(ti_a, ti_b) { return 0; } - if array_len_constraint_sym(ti_a, ti_b) == 0 { return -1; } - return 1; -} +fn type_compat_sym(ti_a: int, ti_b: int) -> int: + if !type_equal(ti_a, ti_b): + return 0 + if array_len_constraint_sym(ti_a, ti_b) == 0: + return -1 + return 1 // F2 判定点诊断:verdict ≠ 1 时发码——-1(长度约束违反)用专属措辞,0 用原措辞。 -fn diag_type_incompatible(verdict: int, code: int, what: string, line: int, col: int) { - if verdict == -1 { - check_error(code, "Array length constraint not satisfied", line, col); - } else { - check_error(code, what, line, col); - } -} +fn diag_type_incompatible(verdict: int, code: int, what: string, line: int, col: int): + if verdict == -1: + check_error(code, "Array length constraint not satisfied", line, col) + else: + check_error(code, what, line, col) // ─── R2 P5 Task 6(TODO #2026-09-11-14):声明位点的值/注解兼容判定 ─── // 背景:`EXPR_LET` 站点自 P3 Task 1 实测起为**无任何兼容检查**的洞(`checker.cr` 该分支 @@ -519,17 +529,19 @@ fn diag_type_incompatible(verdict: int, code: int, what: string, line: int, col: // `get_type_kind(ret_ti) != TYP_GENERIC_PARAM` 豁免)。 // 三态纪律:本函数只消费 `type_compat_strict` 的 {1,0,-1};不可判(引擎 -1 / 桥接缺口)由 // `type_equal` 内部按 P-A 发 ICE04(硬错),**不**在本函数内回落或近似。 -fn check_let_annot_compat(node: int, val_node: int, val_ti: int, ti: int) { - type_node := ast_b(node); // EXPR_LET: b = 注解类型节点(-1 = 无) - if type_node < 0 || val_node < 0 { return; } - if ti == TI_DYN { return; } - if val_ti == TI_NEVER { return; } - if get_type_kind(ti) == TYP_GENERIC_PARAM { return; } - compat := type_compat_strict(val_ti, ti); - if compat != 1 { - diag_type_incompatible(compat, EC_TA_DECL, "Variable declared as " + type_display(ti) + ", got " + type_display(val_ti), ast_line(node), ast_col(node)); - } -} +fn check_let_annot_compat(node: int, val_node: int, val_ti: int, ti: int): + type_node := ast_b(node) // EXPR_LET: b = 注解类型节点(-1 = 无) + if type_node < 0 || val_node < 0: + return + if ti == TI_DYN: + return + if val_ti == TI_NEVER: + return + if get_type_kind(ti) == TYP_GENERIC_PARAM: + return + compat := type_compat_strict(val_ti, ti) + if compat != 1: + diag_type_incompatible(compat, EC_TA_DECL, "Variable declared as " + type_display(ti) + ", got " + type_display(val_ti), ast_line(node), ast_col(node)) // R2 P1:本文件曾同时有**结构判等实现**(原名 type_equal)与引擎判定两套。 // R2 P2a Task 3:结构判等降级为 `type_equal_legacy`(影子对拍对照物 + 引擎 -1 的回落实现)。 @@ -547,17 +559,16 @@ fn check_let_annot_compat(node: int, val_node: int, val_ti: int, ti: int) { // 诊断面:新码 ICE04(main.cr 硬名单 ⇒ build 亦拒绝)+ 反例(两侧类型项文本,D23 先例)。 // 判定点(type_equal 无 AST 位置)⇒ line/col = 0;定位由调用点自身的诊断(TA01/TF01…)承担。 // 全语料零命中(report-only 先行,由 Task 3 的 0 计数支撑)⇒ 零行为变化。 -fn ty_indeterminate_report(kind: int, t1: int, t2: int, a: int, b: int, unc: int, exh: int) { - msg : ., mut = ""; - if kind == 0 { - msg = "type judgment indeterminate: no type term for type row " + int_str(t1) + " / " + int_str(t2) + " (bridge gap)"; - } else { - cause : ., mut = "uncovered face"; - if unc == 0 && exh != 0 { cause = "budget exhausted"; } - msg = "type judgment indeterminate: " + tt_display(a) + " vs " + tt_display(b) + " (" + cause + ")"; - } - check_error(EC_ICE_TY_INDET, msg, 0, 0); -} +fn ty_indeterminate_report(kind: int, t1: int, t2: int, a: int, b: int, unc: int, exh: int): + msg : ., mut = "" + if kind == 0: + msg = "type judgment indeterminate: no type term for type row " + int_str(t1) + " / " + int_str(t2) + " (bridge gap)" + else: + cause : ., mut = "uncovered face" + if unc == 0 && exh != 0: + cause = "budget exhausted" + msg = "type judgment indeterminate: " + tt_display(a) + " vs " + tt_display(b) + " (" + cause + ")" + check_error(EC_ICE_TY_INDET, msg, 0, 0) // ─── R2 P2a Task 3 / R2 P5 Task 4:判定 = 引擎唯一权威 ─── // 判定主体(P1 的包装层拆两半:本函数 = 引擎判定,`type_equal` = 入口转发)。 @@ -574,56 +585,66 @@ fn ty_indeterminate_report(kind: int, t1: int, t2: int, a: int, b: int, unc: int // N 面(Task 2/3 评审裁决「N 不得回身份」):本函数路径**不含** N 比较——桥接的 AK_SEQUENCE // 参数链只含元素项;长度拒绝一律由 array_len_constraint_ok 在判定点(type_compat_strict) // 承担。本函数**不得**引入任何 N(get_type_extra 的数组位)比较。 -fn type_equal_engine(t1: int, t2: int) -> bool { - if t1 == t2 { return true; } // 快路径:同一行 - a := sh_term_of_ti(t1); - b := sh_term_of_ti(t2); - if a < 0 || b < 0 { - ty_indeterminate_report(0, t1, t2, a, b, 0, 0); - return false; - } - ty_budget_reset(200000); - e := ty_equiv(a, b); +fn type_equal_engine(t1: int, t2: int) -> bool: + if t1 == t2: + return true + // 快路径:同一行 + a := sh_term_of_ti(t1) + b := sh_term_of_ti(t2) + if a < 0 || b < 0: + ty_indeterminate_report(0, t1, t2, a, b, 0, 0) + return false + ty_budget_reset(200000) + e := ty_equiv(a, b) // 成因位须在**第二次 reset 之前**读(ty_budget_reset 清 g_ty_uncovered/g_ty_exhausted) - unc := ty_uncovered(); - exh := ty_exhausted(); - ty_budget_reset(200000); // 判定后即复位(不污染后续查询) - if e == 1 { return true; } - if e == 0 { return false; } + unc := ty_uncovered() + exh := ty_exhausted() + ty_budget_reset(200000) // 判定后即复位(不污染后续查询) + if e == 1: + return true + if e == 0: + return false // e == -1(未知):P-A —— 不静默、不回落:硬错 + 反例 - ty_indeterminate_report(1, t1, t2, a, b, unc, exh); - return false; -} + ty_indeterminate_report(1, t1, t2, a, b, unc, exh) + return false // R2 P1 影子对拍包装 / R2 P2a Task 3 判定入口 → R2 P5 Task 4 纯转发(对照物删除)。 // **R2 P5 Task 5**:影子通道整体下线(`sh_compare` 及其调用点、ring/摘要/站点直方图/CLI 通道、 // `g_shadow_*` 全部删除)。保留本名与转发形态 = 判定入口单点(调用面零改动;站点/计数面无残留)。 -fn type_equal(t1: int, t2: int) -> bool { - return type_equal_engine(t1, t2); -} - -fn scan_for_yield(node: int) -> int { - if node < 0 { return 0; } - k := ast_kind(node); - if k == EXPR_YIELD { return 1; } - if k == EXPR_BLOCK { - ss := ast_a(node); sc := ast_b(node); - i : ., mut = 0; - loop { if i >= sc { break; } - sn := r64(g_block_stmts, (ss + i) * 8); - if scan_for_yield(sn) != 0 { return 1; } - i = i + 1; } - return 0; } - if k == EXPR_LOOP || k == EXPR_WHILE { - return scan_for_yield(ast_a(node)); } - if k == EXPR_IF { - if scan_for_yield(ast_a(node)) != 0 { return 1; } - if scan_for_yield(ast_b(node)) != 0 { return 1; } - if ast_c(node) >= 0 && scan_for_yield(ast_c(node)) != 0 { return 1; } - return 0; } - if k == EXPR_FOR { return scan_for_yield(ast_c(node)); } - return 0; -} +fn type_equal(t1: int, t2: int) -> bool: + return type_equal_engine(t1, t2) + +fn scan_for_yield(node: int) -> int: + if node < 0: + return 0 + k := ast_kind(node) + if k == EXPR_YIELD: + return 1 + if k == EXPR_BLOCK: + ss := ast_a(node) + sc := ast_b(node) + i : ., mut = 0 + loop: + if i >= sc: + break + sn := r64(g_block_stmts, (ss + i) * 8) + if scan_for_yield(sn) != 0: + return 1 + i = i + 1 + return 0 + if k == EXPR_LOOP || k == EXPR_WHILE: + return scan_for_yield(ast_a(node)) + if k == EXPR_IF: + if scan_for_yield(ast_a(node)) != 0: + return 1 + if scan_for_yield(ast_b(node)) != 0: + return 1 + if ast_c(node) >= 0 && scan_for_yield(ast_c(node)) != 0: + return 1 + return 0 + if k == EXPR_FOR: + return scan_for_yield(ast_c(node)) + return 0 // ─── 落空(fall through)分析 —— TF01 收口 ─── // 背景:函数体返回检查(站点 5)以「块类型 = 末语句类型」判返回;以**无 break 的 loop** @@ -635,88 +656,90 @@ fn scan_for_yield(node: int) -> int { // 循环体内是否存在**直属于本循环**的 break(嵌套 loop/while/for 内的 break 归内层 ⇒ // 在循环节点处截断、不下钻)。返回 1 亦覆盖「形态未知」(默认兜底)——未知按「可能有 // break」处理 = fail-closed:宁可照旧报 TF01,也不误判「无 break ⇒ 永不落空」。 -fn loop_body_has_break(node: int) -> int { - if node < 0 { return 0; } - k := ast_kind(node); - if k == EXPR_BREAK { return 1; } - if k == EXPR_LOOP || k == EXPR_WHILE || k == EXPR_FOR { return 0; } - if k == EXPR_BLOCK { - ss := ast_a(node); sc := ast_b(node); - i : ., mut = 0; - loop { if i >= sc { break; } - if loop_body_has_break(r64(g_block_stmts, (ss + i) * 8)) != 0 { return 1; } - i = i + 1; } - return 0; - } - if k == EXPR_IF { - if loop_body_has_break(ast_a(node)) != 0 { return 1; } - if loop_body_has_break(ast_b(node)) != 0 { return 1; } - return loop_body_has_break(ast_c(node)); - } - if k == EXPR_MATCH { +fn loop_body_has_break(node: int) -> int: + if node < 0: + return 0 + k := ast_kind(node) + if k == EXPR_BREAK: + return 1 + if k == EXPR_LOOP || k == EXPR_WHILE || k == EXPR_FOR: + return 0 + if k == EXPR_BLOCK: + ss := ast_a(node) + sc := ast_b(node) + i : ., mut = 0 + loop: + if i >= sc: + break + if loop_body_has_break(r64(g_block_stmts, (ss + i) * 8)) != 0: + return 1 + i = i + 1 + return 0 + if k == EXPR_IF: + if loop_body_has_break(ast_a(node)) != 0: + return 1 + if loop_body_has_break(ast_b(node)) != 0: + return 1 + return loop_body_has_break(ast_c(node)) + if k == EXPR_MATCH: // 臂 = EXPR_ARM 链(parser 以 arm.c 串联,尾 -1)——**非连续槽**,勿按段扫 - if loop_body_has_break(ast_a(node)) != 0 { return 1; } - an : ., mut = ast_b(node); - loop { if an < 0 { break; } - if loop_body_has_break(ast_b(an)) != 0 { return 1; } - an = ast_c(an); } - return 0; - } - if k == EXPR_ARM || k == EXPR_BINARY || k == EXPR_ASSIGN || k == EXPR_INDEX || - k == EXPR_RANGE || k == EXPR_AS || k == EXPR_ARG || k == EXPR_CALL { - if loop_body_has_break(ast_a(node)) != 0 { return 1; } - return loop_body_has_break(ast_b(node)); - } - if k == EXPR_ENUM_CONSTRUCTOR || k == EXPR_AT { + if loop_body_has_break(ast_a(node)) != 0: + return 1 + an : ., mut = ast_b(node) + loop: + if an < 0: + break + if loop_body_has_break(ast_b(an)) != 0: + return 1 + an = ast_c(an) + return 0 + if k == EXPR_ARM || k == EXPR_BINARY || k == EXPR_ASSIGN || k == EXPR_INDEX || k == EXPR_RANGE || k == EXPR_AS || k == EXPR_ARG || k == EXPR_CALL: + if loop_body_has_break(ast_a(node)) != 0: + return 1 + return loop_body_has_break(ast_b(node)) + if k == EXPR_ENUM_CONSTRUCTOR || k == EXPR_AT: // a = 名 ni(**不是节点**):只下钻实参链(b) - return loop_body_has_break(ast_b(node)); - } - if k == EXPR_GO { + return loop_body_has_break(ast_b(node)) + if k == EXPR_GO: // a 恒 -1、体在 b(range 形态另有 c/data);a/b 双下钻 = 保守(go 体内 break 不漏判) - if loop_body_has_break(ast_a(node)) != 0 { return 1; } - return loop_body_has_break(ast_b(node)); - } - if k == EXPR_LET { + if loop_body_has_break(ast_a(node)) != 0: + return 1 + return loop_body_has_break(ast_b(node)) + if k == EXPR_LET: // a = 名 ni(**不是节点**):只下钻类型(b)与值(c) - if loop_body_has_break(ast_b(node)) != 0 { return 1; } - return loop_body_has_break(ast_c(node)); - } - if k == EXPR_STRUCT || k == EXPR_STRUCTPAT || k == EXPR_ENUMPAT || k == EXPR_GENERIC_APPLY { + if loop_body_has_break(ast_b(node)) != 0: + return 1 + return loop_body_has_break(ast_c(node)) + if k == EXPR_STRUCT || k == EXPR_STRUCTPAT || k == EXPR_ENUMPAT || k == EXPR_GENERIC_APPLY: // 连续子节点段:首 b、个数 c(wrapper.a = 值/子模式,经 EXPR_NONE 分支承接) - return seg_has_break(ast_b(node), ast_c(node)); - } - if k == EXPR_ARRAY || k == EXPR_TUPLE { - return seg_has_break(ast_a(node), ast_b(node)); - } - if k == EXPR_NONE { + return seg_has_break(ast_b(node), ast_c(node)) + if k == EXPR_ARRAY || k == EXPR_TUPLE: + return seg_has_break(ast_a(node), ast_b(node)) + if k == EXPR_NONE: // wrapper(a = 值节点)或基类型节点(a = 0):照 monomorph 的判据 - if ast_a(node) >= 0 && ast_a(node) != node { return loop_body_has_break(ast_a(node)); } - return 0; - } - if k == EXPR_STMT || k == EXPR_UNSAFE || k == EXPR_RETURN || k == EXPR_YIELD || - k == EXPR_AWAIT || k == EXPR_MOVE || k == EXPR_TRY || k == EXPR_UNARY || - k == EXPR_FIELD || k == EXPR_OPTIONAL || k == EXPR_REFTYPE || k == EXPR_PTRTYPE { - return loop_body_has_break(ast_a(node)); - } - if k == EXPR_INT || k == EXPR_DEX || k == EXPR_BOOL || k == EXPR_STRING || - k == EXPR_IDENT || k == EXPR_CHAR || k == EXPR_WILDCARD || k == EXPR_CONTINUE { - return 0; - } + if ast_a(node) >= 0 && ast_a(node) != node: + return loop_body_has_break(ast_a(node)) + return 0 + if k == EXPR_STMT || k == EXPR_UNSAFE || k == EXPR_RETURN || k == EXPR_YIELD || k == EXPR_AWAIT || k == EXPR_MOVE || k == EXPR_TRY || k == EXPR_UNARY || k == EXPR_FIELD || k == EXPR_OPTIONAL || k == EXPR_REFTYPE || k == EXPR_PTRTYPE: + return loop_body_has_break(ast_a(node)) + if k == EXPR_INT || k == EXPR_DEX || k == EXPR_BOOL || k == EXPR_STRING || k == EXPR_IDENT || k == EXPR_CHAR || k == EXPR_WILDCARD || k == EXPR_CONTINUE: + return 0 // 兜底(含 EXPR_FN/PARAM/FLOW/EXTERN 等未枚举形态):按「可能有 break」保守处理 - return 1; -} - -fn seg_has_break(first: int, count: int) -> int { - if first < 0 { return 0; } - i : ., mut = 0; - loop { if i >= count { break; } - n := first + i; - if n >= 0 && n < g_ast_count { - if loop_body_has_break(n) != 0 { return 1; } - } - i = i + 1; } - return 0; -} + return 1 + +fn seg_has_break(first: int, count: int) -> int: + if first < 0: + return 0 + i : ., mut = 0 + loop: + if i >= count: + break + n := first + i + if n >= 0 && n < g_ast_count: + if loop_body_has_break(n) != 0: + return 1 + i = i + 1 + return 0 // 语句是否**不能落空**(走到本语句之后的代码):1 = 确定不能,0 = 可能落空(保守默认)。 // 注意 `return` 在此**不判 divergence**:它虽然「不能走完」,但**带返回值**——本分析只服务 @@ -725,448 +748,450 @@ fn seg_has_break(first: int, count: int) -> int { // 双分支皆不可落空且无 else 的 if、包裹层(STMT/UNSAFE/嵌套 block)。 // **登记面**:非落空体内的 return 值类型本分析**不核对**(checker 现模型无逐 return 核对; // 该面 = 既有面——本条只把「以无 break 的 loop 收尾」从 TF01 误报中解放,不新增核对)。 -fn stmt_cannot_fall_through(node: int) -> int { - if node < 0 { return 0; } - k := ast_kind(node); - if k == EXPR_BLOCK { - ss := ast_a(node); sc := ast_b(node); - i : ., mut = 0; - loop { if i >= sc { break; } - if stmt_cannot_fall_through(r64(g_block_stmts, (ss + i) * 8)) != 0 { return 1; } - i = i + 1; } - return 0; - } - if k == EXPR_LOOP { +fn stmt_cannot_fall_through(node: int) -> int: + if node < 0: + return 0 + k := ast_kind(node) + if k == EXPR_BLOCK: + ss := ast_a(node) + sc := ast_b(node) + i : ., mut = 0 + loop: + if i >= sc: + break + if stmt_cannot_fall_through(r64(g_block_stmts, (ss + i) * 8)) != 0: + return 1 + i = i + 1 + return 0 + if k == EXPR_LOOP: // 无直系 break ⇒ 只可能从体内 return 出(loop_body_has_break 的未知 = 1 保证 // 此处判 1 只在**确定**无 break 时成立) - if loop_body_has_break(ast_a(node)) == 0 { return 1; } - return 0; - } - if k == EXPR_IF { - if ast_c(node) < 0 { return 0; } // 无 else:条件不成立即落空 - if stmt_cannot_fall_through(ast_b(node)) == 0 { return 0; } - return stmt_cannot_fall_through(ast_c(node)); - } - if k == EXPR_STMT || k == EXPR_UNSAFE { return stmt_cannot_fall_through(ast_a(node)); } - return 0; -} + if loop_body_has_break(ast_a(node)) == 0: + return 1 + return 0 + if k == EXPR_IF: + if ast_c(node) < 0: + return 0 + // 无 else:条件不成立即落空 + if stmt_cannot_fall_through(ast_b(node)) == 0: + return 0 + return stmt_cannot_fall_through(ast_c(node)) + if k == EXPR_STMT || k == EXPR_UNSAFE: + return stmt_cannot_fall_through(ast_a(node)) + return 0 // 语句是否**确定发散**(本层不产出值、不落到后继)——**含 `return`**。 // **仅服务 TC02 的「else 支类型是幻影」判定**(消费点 = infer_expr 的 EXPR_IF 合并点守卫); // **不得**用于 TF01——那里豁免 return 体会洗白真错面(lits_copy 型),见上一条的头注。 // 保守默认 0(不确定即 0):只认 return 族 + 包裹层(STMT/UNSAFE)+ 块内任一句确定发散。 // 未覆盖面(登记,本批不判):`break`/`continue` 收尾的分支(需循环上下文)。 -fn stmt_diverges(node: int) -> int { - if node < 0 { return 0; } - k := ast_kind(node); - if k == EXPR_RETURN { return 1; } - if k == EXPR_STMT || k == EXPR_UNSAFE { return stmt_diverges(ast_a(node)); } - if k == EXPR_BLOCK { - ss := ast_a(node); sc := ast_b(node); - i : ., mut = 0; - loop { if i >= sc { break; } - if stmt_diverges(r64(g_block_stmts, (ss + i) * 8)) != 0 { return 1; } - i = i + 1; } - return 0; - } - return 0; -} +fn stmt_diverges(node: int) -> int: + if node < 0: + return 0 + k := ast_kind(node) + if k == EXPR_RETURN: + return 1 + if k == EXPR_STMT || k == EXPR_UNSAFE: + return stmt_diverges(ast_a(node)) + if k == EXPR_BLOCK: + ss := ast_a(node) + sc := ast_b(node) + i : ., mut = 0 + loop: + if i >= sc: + break + if stmt_diverges(r64(g_block_stmts, (ss + i) * 8)) != 0: + return 1 + i = i + 1 + return 0 + return 0 // --- Symbol table --- -struct SymEntry { +struct SymEntry: name_idx: int, kind: int, type_idx: int, node_idx: int, -} - -fn push_scope() { - grow_scope_bounds(g_scope_depth + 1); - w64(g_scope_bounds, g_scope_depth * 8, g_sym_count); - g_scope_depth = g_scope_depth + 1; -} - -fn pop_scope() { - if g_scope_depth > 0 { - g_scope_depth = g_scope_depth - 1; - g_sym_count = r64(g_scope_bounds, g_scope_depth * 8); - } -} - -fn def_sym(name_idx: int, kind: int, type_idx: int, node_idx: int) { - grow_syms(g_sym_count + 1); - sym_set_name(g_sym_count, name_idx); - sym_set_kind(g_sym_count, kind); - sym_set_type(g_sym_count, type_idx); - sym_set_node(g_sym_count, node_idx); - g_sym_count = g_sym_count + 1; -} - -fn find_sym(name_idx: int) -> int { - i : ., mut = g_sym_count - 1; - loop { - if i < 0 { return -1; } - if sym_name(i) == name_idx { return i; } - i = i - 1; - } - return -1; -} - -fn find_gsym(name_idx: int) -> int { - i : ., mut = g_sym_count - 1; - loop { - if i < 0 { break; } // 主表未命中 ⇒ 落到下方侧表回退 - if sym_name(i) == name_idx && sym_kind(i) >= SYM_FN && sym_kind(i) <= SYM_SO_FN { return i; } - i = i - 1; - } + +fn push_scope(): + grow_scope_bounds(g_scope_depth + 1) + w64(g_scope_bounds, g_scope_depth * 8, g_sym_count) + g_scope_depth = g_scope_depth + 1 + +fn pop_scope(): + if g_scope_depth > 0: + g_scope_depth = g_scope_depth - 1 + g_sym_count = r64(g_scope_bounds, g_scope_depth * 8) + +fn def_sym(name_idx: int, kind: int, type_idx: int, node_idx: int): + grow_syms(g_sym_count + 1) + sym_set_name(g_sym_count, name_idx) + sym_set_kind(g_sym_count, kind) + sym_set_type(g_sym_count, type_idx) + sym_set_node(g_sym_count, node_idx) + g_sym_count = g_sym_count + 1 + +fn find_sym(name_idx: int) -> int: + i : ., mut = g_sym_count - 1 + loop: + if i < 0: + return -1 + if sym_name(i) == name_idx: + return i + i = i - 1 + return -1 + +fn find_gsym(name_idx: int) -> int: + i : ., mut = g_sym_count - 1 + loop: + if i < 0: + break + // 主表未命中 ⇒ 落到下方侧表回退 + if sym_name(i) == name_idx && sym_kind(i) >= SYM_FN && sym_kind(i) <= SYM_SO_FN: + return i + i = i - 1 // 侧表回退(第 4 批 #82/#83):索引元数据只在名字**被引用**(走到这里)且主表**没有** // 同名条目时才物化 ⇒ 未引用条目零产物足迹;且同名 `.cr` 声明优先(裁-HR-2: // 宿主家目录里的文件**不得**悄悄改写用户源码声明的含义)。 // **查不到时做了什么**:主表无 + 侧表无 ⇒ 返回 -1,由调用点报 Undefined(响亮)。 // **绝不**在此放行——那是「响亮失败 → 静默错值」的退化(本批红线)。 - ssi := find_so_side(name_idx); - if ssi < 0 { return -1; } - return so_materialize(ssi); -} - -fn find_so_fn(name_idx: int) -> int { - i : ., mut = 0; - loop { - if i >= g_sym_count { break; } - if sym_name(i) == name_idx { - if sym_kind(i) == SYM_SO_FN { return i; } + ssi := find_so_side(name_idx) + if ssi < 0: + return -1 + return so_materialize(ssi) + +fn find_so_fn(name_idx: int) -> int: + i : ., mut = 0 + loop: + if i >= g_sym_count: + break + if sym_name(i) == name_idx: + if sym_kind(i) == SYM_SO_FN: + return i // 同名 `.cr` 声明优先(裁-HR-2)⇒ 不物化 SO_FN(`print`/`println` 走声明面)。 // 注:原先此处注释称「SO_FN 在 SYM_FN 之前」——那是**改造前**的现状描述 // (导入期注册 + check_all 复位后追加);改造后物化发生在**首次查找**, // 物化条目追加在表尾,且「有声明则不物化」⇒ 该顺序假设已不存在。 - return -1; - } - i = i + 1; - } - ssi := find_so_side(name_idx); - if ssi < 0 { return -1; } - return so_materialize(ssi); -} + return -1 + i = i + 1 + ssi := find_so_side(name_idx) + if ssi < 0: + return -1 + return so_materialize(ssi) // --- Error tracking --- // Uses g_diags, g_diag_count from globals.cr (and ast.cr) // Old g_check_errors is replaced by structured g_diags. -fn check_error(code: int, msg: string, line: int, col: int) { - grow_diags(g_diag_count + 1); - w64(g_diags, g_diag_count * DIAG_REC_SIZE, code); - store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, msg); - 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; -} +fn check_error(code: int, msg: string, line: int, col: int): + grow_diags(g_diag_count + 1) + w64(g_diags, g_diag_count * DIAG_REC_SIZE, code) + store_str_ptr(g_diags, g_diag_count * DIAG_REC_SIZE + 8, msg) + 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 // --- Borrow checking --- -fn find_borrow_entry(var_ni: int) -> int { - i : ., mut = 0; - loop { - if i >= g_borrow_count { return -1; } - if r64(g_borrow_vars, i * 8) == var_ni { return i; } - i = i + 1; - } - return -1; -} - -fn check_borrow(var_ni: int, is_mut: int) -> bool { - bi := find_borrow_entry(var_ni); - if bi >= 0 { - if is_mut != 0 { +fn find_borrow_entry(var_ni: int) -> int: + i : ., mut = 0 + loop: + if i >= g_borrow_count: + return -1 + if r64(g_borrow_vars, i * 8) == var_ni: + return i + i = i + 1 + return -1 + +fn check_borrow(var_ni: int, is_mut: int) -> bool: + bi := find_borrow_entry(var_ni) + if bi >= 0: + if is_mut != 0: // &mut x: fail if any borrow exists - if r64(g_borrow_refs, bi * 8) > 0 || r64(g_borrow_muts, bi * 8) != 0 { return false; } - w64(g_borrow_muts, bi * 8, 1); - return true; - } else { + if r64(g_borrow_refs, bi * 8) > 0 || r64(g_borrow_muts, bi * 8) != 0: + return false + w64(g_borrow_muts, bi * 8, 1) + return true + else: // &x: fail if mutable borrow exists - if r64(g_borrow_muts, bi * 8) != 0 { return false; } - w64(g_borrow_refs, bi * 8, r64(g_borrow_refs, bi * 8) + 1); - return true; - } - } + if r64(g_borrow_muts, bi * 8) != 0: + return false + w64(g_borrow_refs, bi * 8, r64(g_borrow_refs, bi * 8) + 1) + return true // First borrow of this variable - grow_borrow_vars(g_borrow_count + 1); - w64(g_borrow_vars, g_borrow_count * 8, var_ni); - w64(g_borrow_refs, g_borrow_count * 8, 0); - w64(g_borrow_muts, g_borrow_count * 8, 0); - if is_mut != 0 { w64(g_borrow_muts, g_borrow_count * 8, 1); } - else { w64(g_borrow_refs, g_borrow_count * 8, 1); } - g_borrow_count = g_borrow_count + 1; - return true; -} - -fn check_use(var_ni: int) -> bool { - bi := find_borrow_entry(var_ni); - if bi >= 0 { - if r64(g_borrow_refs, bi * 8) > 0 || r64(g_borrow_muts, bi * 8) != 0 { return false; } - } - return true; -} - -fn push_borrow_scope() { - grow_borrow_markers(g_borrow_scope_depth + 1); - w64(g_borrow_scope_markers, g_borrow_scope_depth * 8, g_holder_count); - g_borrow_scope_depth = g_borrow_scope_depth + 1; -} - -fn pop_borrow_scope() { - if g_borrow_scope_depth > 0 { - g_borrow_scope_depth = g_borrow_scope_depth - 1; - marker := r64(g_borrow_scope_markers, g_borrow_scope_depth * 8); + grow_borrow_vars(g_borrow_count + 1) + w64(g_borrow_vars, g_borrow_count * 8, var_ni) + w64(g_borrow_refs, g_borrow_count * 8, 0) + w64(g_borrow_muts, g_borrow_count * 8, 0) + if is_mut != 0: + w64(g_borrow_muts, g_borrow_count * 8, 1) + else: + w64(g_borrow_refs, g_borrow_count * 8, 1) + g_borrow_count = g_borrow_count + 1 + return true + +fn check_use(var_ni: int) -> bool: + bi := find_borrow_entry(var_ni) + if bi >= 0: + if r64(g_borrow_refs, bi * 8) > 0 || r64(g_borrow_muts, bi * 8) != 0: + return false + return true + +fn push_borrow_scope(): + grow_borrow_markers(g_borrow_scope_depth + 1) + w64(g_borrow_scope_markers, g_borrow_scope_depth * 8, g_holder_count) + g_borrow_scope_depth = g_borrow_scope_depth + 1 + +fn pop_borrow_scope(): + if g_borrow_scope_depth > 0: + g_borrow_scope_depth = g_borrow_scope_depth - 1 + marker := r64(g_borrow_scope_markers, g_borrow_scope_depth * 8) // Release all borrows held from marker to end - loop { - if g_holder_count <= marker { break; } - g_holder_count = g_holder_count - 1; - borrowed_ni := r64(g_holder_borrowed, g_holder_count * 8); - is_mut := r64(g_holder_is_mut, g_holder_count * 8); - bi := find_borrow_entry(borrowed_ni); - if bi >= 0 { - if is_mut != 0 { w64(g_borrow_muts, bi * 8, 0); } - else { - if r64(g_borrow_refs, bi * 8) > 0 { w64(g_borrow_refs, bi * 8, r64(g_borrow_refs, bi * 8) - 1); } - } + loop: + if g_holder_count <= marker: + break + g_holder_count = g_holder_count - 1 + borrowed_ni := r64(g_holder_borrowed, g_holder_count * 8) + is_mut := r64(g_holder_is_mut, g_holder_count * 8) + bi := find_borrow_entry(borrowed_ni) + if bi >= 0: + if is_mut != 0: + w64(g_borrow_muts, bi * 8, 0) + else: + if r64(g_borrow_refs, bi * 8) > 0: + w64(g_borrow_refs, bi * 8, r64(g_borrow_refs, bi * 8) - 1) // Clean up entry if no more borrows - if r64(g_borrow_refs, bi * 8) == 0 && r64(g_borrow_muts, bi * 8) == 0 { - si : ., mut = bi; - loop { - if si + 1 >= g_borrow_count { break; } - w64(g_borrow_vars, si * 8, r64(g_borrow_vars, (si + 1) * 8)); - w64(g_borrow_refs, si * 8, r64(g_borrow_refs, (si + 1) * 8)); - w64(g_borrow_muts, si * 8, r64(g_borrow_muts, (si + 1) * 8)); - si = si + 1; - } - g_borrow_count = g_borrow_count - 1; - } - } - } - } -} - -fn push_unsafe_scope() { g_unsafe_depth = g_unsafe_depth + 1; } -fn pop_unsafe_scope() { if g_unsafe_depth > 0 { g_unsafe_depth = g_unsafe_depth - 1; } } - -fn record_borrow_holder(borrower_ni: int, borrowed_ni: int, is_mut: int) { - grow_holder(g_holder_count + 1); - w64(g_holder_borrowers, g_holder_count * 8, borrower_ni); - w64(g_holder_borrowed, g_holder_count * 8, borrowed_ni); - w64(g_holder_is_mut, g_holder_count * 8, is_mut); - g_holder_count = g_holder_count + 1; -} - -fn borrow_var_name(node: int) -> int { - if node < 0 { return -1; } - if ast_kind(node) == EXPR_IDENT { return ast_int_val(node); } - return -1; -} + if r64(g_borrow_refs, bi * 8) == 0 && r64(g_borrow_muts, bi * 8) == 0: + si : ., mut = bi + loop: + if si + 1 >= g_borrow_count: + break + w64(g_borrow_vars, si * 8, r64(g_borrow_vars, (si + 1) * 8)) + w64(g_borrow_refs, si * 8, r64(g_borrow_refs, (si + 1) * 8)) + w64(g_borrow_muts, si * 8, r64(g_borrow_muts, (si + 1) * 8)) + si = si + 1 + g_borrow_count = g_borrow_count - 1 + +fn push_unsafe_scope(): + g_unsafe_depth = g_unsafe_depth + 1 +fn pop_unsafe_scope(): + if g_unsafe_depth > 0: + g_unsafe_depth = g_unsafe_depth - 1 + +fn record_borrow_holder(borrower_ni: int, borrowed_ni: int, is_mut: int): + grow_holder(g_holder_count + 1) + w64(g_holder_borrowers, g_holder_count * 8, borrower_ni) + w64(g_holder_borrowed, g_holder_count * 8, borrowed_ni) + w64(g_holder_is_mut, g_holder_count * 8, is_mut) + g_holder_count = g_holder_count + 1 + +fn borrow_var_name(node: int) -> int: + if node < 0: + return -1 + if ast_kind(node) == EXPR_IDENT: + return ast_int_val(node) + return -1 // --- Type resolution utilities --- -fn res_type_node(node: int) -> int { - if node < 0 { return TI_UNIT; } - if ast_kind(node) == 0 { +fn res_type_node(node: int) -> int: + if node < 0: + return TI_UNIT + if ast_kind(node) == 0: // Base type node: type_val = TY_* // P2b Task 6:8 行内联链 → 单表 `ty_code_to_ti`(尾部回落显式写出,不藏表里); // 本站点域 = {INT,DEX,BOOL,STRING,UNIT,NEVER,CHAR} ∪ {7 = dyn 码}——**与 res_call_type 的 // 唯一语义差 = NEVER 格**(该函数无此格,见其注)。域外(如 TY_DEX_S=8/未知码)落 TI_UNIT。 - tv := ast_type_val(node); - mapped : ., mut = ty_code_to_ti(tv); - if mapped < 0 { mapped = TI_UNIT; } - return mapped; - } - if ast_kind(node) == EXPR_IDENT { + tv := ast_type_val(node) + mapped : ., mut = ty_code_to_ti(tv) + if mapped < 0: + mapped = TI_UNIT + return mapped + if ast_kind(node) == EXPR_IDENT: // Named type: int_val = name string index - name_idx := ast_int_val(node); - si := find_gsym(name_idx); - if si >= 0 && sym_kind(si) == SYM_TYPE { - return sym_type(si); - } + name_idx := ast_int_val(node) + si := find_gsym(name_idx) + if si >= 0 && sym_kind(si) == SYM_TYPE: + return sym_type(si) // Create named type entry - return alloc_named_type(name_idx); - } - if ast_kind(node) == EXPR_ARRAY { + return alloc_named_type(name_idx) + if ast_kind(node) == EXPR_ARRAY: // 表示层概念(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 // Array type [T; N] or slice type [T] (size 0) - elem := res_type_node(ast_a(node)); - sz := ast_int_val(node); - if sz == 0 { - return alloc_type(TYP_SLICE, elem, 0); - } - return alloc_type(TYP_ARRAY, elem, sz); - } - if ast_kind(node) == EXPR_REFTYPE { + elem := res_type_node(ast_a(node)) + sz := ast_int_val(node) + if sz == 0: + return alloc_type(TYP_SLICE, elem, 0) + return alloc_type(TYP_ARRAY, elem, sz) + if ast_kind(node) == EXPR_REFTYPE: // Reference type &T or &mut T - inner := res_type_node(ast_a(node)); - mut_flag := ast_int_val(node); - return alloc_type(TYP_REF, inner, mut_flag); - } - if ast_kind(node) == EXPR_PTRTYPE { + inner := res_type_node(ast_a(node)) + mut_flag := ast_int_val(node) + return alloc_type(TYP_REF, inner, mut_flag) + if ast_kind(node) == EXPR_PTRTYPE: // Pointer type *T - inner := res_type_node(ast_a(node)); - return alloc_type(TYP_PTR, inner, 0); - } - if ast_kind(node) == EXPR_OPTIONAL { + inner := res_type_node(ast_a(node)) + return alloc_type(TYP_PTR, inner, 0) + if ast_kind(node) == EXPR_OPTIONAL: // R2 P3 Task 4:`T?` = `T ∪ null`(spec §5.4)——行 = TYP_OPTIONAL(data = 内层行)。 // 语义在三层落:① 桥接把本行译作 union(内层项, null 原子项)(ty_shadow.cr); // ② 引擎按普通联合项判定(包含/等价/不相交/穷尽性,全走既有 DNF 路径,零新规则); // ③ 判定点(type_compat_strict 等)不变——`int ⊆ int ∪ null`、`int ∪ null ⊄ int`。 // 一条**不**去侧表的理由:本行无名字(旧形态 Option[T] 的「名字身份」正是本任务退役的 // 东西),故不进 named_dedup;同内容的两个行在引擎侧译成同一个项(DAG 去重)⇒ 判定等价。 - inner := res_type_node(ast_a(node)); - return alloc_type(TYP_OPTIONAL, inner, 0); - } - if ast_kind(node) == EXPR_GENERIC_APPLY { + inner := res_type_node(ast_a(node)) + return alloc_type(TYP_OPTIONAL, inner, 0) + if ast_kind(node) == EXPR_GENERIC_APPLY: // Generic application: Box[int] - name_idx := ast_a(node); - first_arg_node := ast_b(node); - arg_count := ast_c(node); - si := find_gsym(name_idx); - if si < 0 || sym_kind(si) != SYM_TYPE { - check_error(EC_N_GENERIC_TYPE, "Undefined type in generic application", ast_line(node), ast_col(node)); - return TI_UNIT; - } - base_ti := sym_type(si); + name_idx := ast_a(node) + first_arg_node := ast_b(node) + arg_count := ast_c(node) + si := find_gsym(name_idx) + if si < 0 || sym_kind(si) != SYM_TYPE: + check_error(EC_N_GENERIC_TYPE, "Undefined type in generic application", ast_line(node), ast_col(node)) + return TI_UNIT + base_ti := sym_type(si) // 两趟(照 #2026-09-16-2 元组第二根因同款):实参类型解析**自身也会向 // g_gen_apply_data 追加**(嵌套应用如 Box[Box[int]] 的内层载荷)—— // 先解析进暂存,后一次性认领连续块。修复前「先认领块再逐参解析」会让 // 内层 append 冲掉外层的 count 槽与后续载荷槽(终点 count 截断), // `Box[Box[int]]` 的字段/返回位因此被误判(假拒)。 - args : string, mut; - if arg_count > 0 { - args = alloc(arg_count * 8); - ai : ., mut = 0; - an : ., mut = first_arg_node; - loop { - if ai >= arg_count { break; } - w64(args, ai * 8, res_type_node(an)); - ai = ai + 1; - an = an + 1; - } - } + args : string, mut + if arg_count > 0: + args = alloc(arg_count * 8) + ai : ., mut = 0 + an : ., mut = first_arg_node + loop: + if ai >= arg_count: + break + w64(args, ai * 8, res_type_node(an)) + ai = ai + 1 + an = an + 1 // R2 P3 Task 5(Step 3):**实例化点**的结构/枚举泛型约束检查(`Box[T: I]` 的 `Box[P]`)。 // 判定 = ty_sub(本质轴)+ 反例诊断;用户接口约束 = -1 零动作(P3b 阻塞面)。 - gen_inst_constr_check(node, find_struct(name_idx), find_enum(name_idx), args, arg_count); + gen_inst_constr_check(node, find_struct(name_idx), find_enum(name_idx), args, arg_count) // Store args in g_gen_apply_data: [count, arg1, arg2, ...] - data_start := g_gen_apply_data_count; - grow_gen_apply_data(data_start + 1 + arg_count); - w64(g_gen_apply_data, data_start * 8, arg_count); - ai2 : ., mut = 0; - loop { - if ai2 >= arg_count { break; } - w64(g_gen_apply_data, (data_start + 1 + ai2) * 8, r64(args, ai2 * 8)); - ai2 = ai2 + 1; - } - g_gen_apply_data_count = data_start + 1 + arg_count; - return alloc_type(TYP_GENERIC_APPLY, base_ti, data_start); - } - return TI_UNIT; -} - -fn find_struct(name_idx: int) -> int { - i : ., mut = 0; - loop { - if i >= g_struct_count { return -1; } - if si_name(i) == name_idx { return i; } - i = i + 1; - } - return -1; -} - -fn find_enum(name_idx: int) -> int { - i : ., mut = 0; - loop { - if i >= g_enum_count { return -1; } - if ei_name(i) == name_idx { return i; } - i = i + 1; - } - return -1; -} - -fn find_iface(name_ni: int) -> int { - i : ., mut = 0; - loop { - if i >= g_iface_count { return -1; } - if r64(g_ifaces, i * ESZ_IFACEINFO + OFF_IF_NAME) == name_ni { return i; } - i = i + 1; - } - return -1; -} + data_start := g_gen_apply_data_count + grow_gen_apply_data(data_start + 1 + arg_count) + w64(g_gen_apply_data, data_start * 8, arg_count) + ai2 : ., mut = 0 + loop: + if ai2 >= arg_count: + break + w64(g_gen_apply_data, (data_start + 1 + ai2) * 8, r64(args, ai2 * 8)) + ai2 = ai2 + 1 + g_gen_apply_data_count = data_start + 1 + arg_count + return alloc_type(TYP_GENERIC_APPLY, base_ti, data_start) + return TI_UNIT + +fn find_struct(name_idx: int) -> int: + i : ., mut = 0 + loop: + if i >= g_struct_count: + return -1 + if si_name(i) == name_idx: + return i + i = i + 1 + return -1 + +fn find_enum(name_idx: int) -> int: + i : ., mut = 0 + loop: + if i >= g_enum_count: + return -1 + if ei_name(i) == name_idx: + return i + i = i + 1 + return -1 + +fn find_iface(name_ni: int) -> int: + i : ., mut = 0 + loop: + if i >= g_iface_count: + return -1 + if r64(g_ifaces, i * ESZ_IFACEINFO + OFF_IF_NAME) == name_ni: + return i + i = i + 1 + return -1 // ─── R2 P3 Task 0:展开层的「行 → 声明」入口(名字解析归 checker;展开层只读声明表)─── // ti 接受两种形态(与桥接 sh_term_of_ti 的 TYP_NAMED / TYP_GENERIC_APPLY 两分支同域): // TYP_NAMED(data = 名字 ni)/ TYP_GENERIC_APPLY(data = 基型行;基型须为 TYP_NAMED)。 // -1 = 既非命名行也非泛型应用行 / 基型非命名行。**只读**(不改类型表、不报诊断、不分配)。 -fn decl_name_of_ti(ti: int) -> int { - if ti < 0 { return -1; } - k := get_type_kind(ti); - if k == TYP_NAMED { return get_type_data(ti); } - if k == TYP_GENERIC_APPLY { - base := get_type_data(ti); - if get_type_kind(base) == TYP_NAMED { return get_type_data(base); } - } - return -1; -} +fn decl_name_of_ti(ti: int) -> int: + if ti < 0: + return -1 + k := get_type_kind(ti) + if k == TYP_NAMED: + return get_type_data(ti) + if k == TYP_GENERIC_APPLY: + base := get_type_data(ti) + if get_type_kind(base) == TYP_NAMED: + return get_type_data(base) + return -1 // 命名/泛型应用行 → struct 声明行(-1 = 非此二形态 / 该名字未声明为 struct) -fn find_struct_row_of(ti: int) -> int { - ni := decl_name_of_ti(ti); - if ni < 0 { return -1; } - return find_struct(ni); -} +fn find_struct_row_of(ti: int) -> int: + ni := decl_name_of_ti(ti) + if ni < 0: + return -1 + return find_struct(ni) // 同上 → enum 声明行 -fn find_enum_row_of(ti: int) -> int { - ni := decl_name_of_ti(ti); - if ni < 0 { return -1; } - return find_enum(ni); -} - -fn get_type_name(ti: int) -> int { - k := get_type_kind(ti); - if k == TYP_NAMED { return get_type_data(ti); } - if k == TYP_BASE { - d := get_type_data(ti); - if d == TY_INT { return str_intern("int"); } - if d == TY_DEX { return str_intern("dex"); } - if d == TY_BOOL { return str_intern("bool"); } - if d == TY_STRING { return str_intern("string"); } - if d == TY_UNIT { return str_intern("unit"); } - if d == TY_CHAR { return str_intern("char"); } - } - if k == TYP_GENERIC_APPLY { - base := get_type_data(ti); - if get_type_kind(base) == TYP_NAMED { return get_type_data(base); } - } - return -1; -} +fn find_enum_row_of(ti: int) -> int: + ni := decl_name_of_ti(ti) + if ni < 0: + return -1 + return find_enum(ni) + +fn get_type_name(ti: int) -> int: + k := get_type_kind(ti) + if k == TYP_NAMED: + return get_type_data(ti) + if k == TYP_BASE: + d := get_type_data(ti) + if d == TY_INT: + return str_intern("int") + if d == TY_DEX: + return str_intern("dex") + if d == TY_BOOL: + return str_intern("bool") + if d == TY_STRING: + return str_intern("string") + if d == TY_UNIT: + return str_intern("unit") + if d == TY_CHAR: + return str_intern("char") + if k == TYP_GENERIC_APPLY: + base := get_type_data(ti) + if get_type_kind(base) == TYP_NAMED: + return get_type_data(base) + return -1 // R2 P3b Task 6(Step 3,mangling 退役):方法解析从「`Type.method` 字符串拼接 + `find_func`」 // 改为**表查询**(`g_methods` 三元组 {type_ni, method_ni, func_name_ni},parser 的 impl 分支 // 唯一写点;引擎侧同一入口 `iface_find_method`)。域等价(同一 impl 声明面),且**零 str_intern** // ——旧形态对缺失方法名会往驻留表追加新串(`.ccr` STR 段增长面,见 A.3-②)。 -fn type_has_method(type_ni: int, method_ni: int) -> bool { - if iface_find_method(type_ni, method_ni) < 0 { return false; } - return true; -} +fn type_has_method(type_ni: int, method_ni: int) -> bool: + if iface_find_method(type_ni, method_ni) < 0: + return false + return true // 接口满足判定(bool 面;语义 = 引擎轴 C 用户谓词的**同一实现** `iface_user_satisfies_ii`, // 见 type_engine.cr:方法名表查询 + 接收者模式 + 签名项引擎判定)。保持 bool 返回值的理由 = // 调用点(泛型约束的函数调用位点)的既有语义「不能判定为满足 ⇒ 报 TG02」逐字不变(措辞/去重/ // rc 不在本任务面内);三态面由 `iface_satisfies` / `iface_user_satisfies` 承担。 -fn check_iface(type_ni: int, iface_ii: int) -> bool { - if iface_user_satisfies_ii(type_ni, iface_ii) == 1 { return true; } - return false; -} +fn check_iface(type_ni: int, iface_ii: int) -> bool: + if iface_user_satisfies_ii(type_ni, iface_ii) == 1: + return true + return false // ═══════════════ R2 P3 Task 5:泛型约束(保留 / 实例化判定 / 反例)═══════════════ // 语义(spec §5.2):`fn f[T]`(约束 = ⊤)/ `fn f[T: I]`(约束 = 类型项 I);**结构/枚举泛型 @@ -1185,246 +1210,272 @@ fn check_iface(type_ni: int, iface_ii: int) -> bool { // 约束名 → 类型行(-1 = 不是类型名)。原生名按 parse_type 的字典逐名判(parser.cr 的 // 8 个基类型名分支:int/dex/bool/string/char/never/unit/dyn——**原生名不经符号表**, // init_types 只建类型行不 def_sym);其余查符号表 SYM_TYPE(struct/enum/别名/泛型形参)。 -fn gen_constr_type_ti(c_ni: int) -> int { - if c_ni < 0 { return -1; } - s := istr_get(c_ni); - if str_eq(s, "int") != 0 { return TI_INT; } - if str_eq(s, "dex") != 0 { return TI_DEX; } - if str_eq(s, "bool") != 0 { return TI_BOOL; } - if str_eq(s, "string") != 0 { return TI_STR; } - if str_eq(s, "char") != 0 { return TI_CHAR; } - if str_eq(s, "unit") != 0 { return TI_UNIT; } - if str_eq(s, "never") != 0 { return TI_NEVER; } - if str_eq(s, "dyn") != 0 { return TI_DYN; } - si := find_gsym(c_ni); - if si >= 0 && sym_kind(si) == SYM_TYPE { return sym_type(si); } - return -1; -} +fn gen_constr_type_ti(c_ni: int) -> int: + if c_ni < 0: + return -1 + s := istr_get(c_ni) + if str_eq(s, "int") != 0: + return TI_INT + if str_eq(s, "dex") != 0: + return TI_DEX + if str_eq(s, "bool") != 0: + return TI_BOOL + if str_eq(s, "string") != 0: + return TI_STR + if str_eq(s, "char") != 0: + return TI_CHAR + if str_eq(s, "unit") != 0: + return TI_UNIT + if str_eq(s, "never") != 0: + return TI_NEVER + if str_eq(s, "dyn") != 0: + return TI_DYN + si := find_gsym(c_ni) + if si >= 0 && sym_kind(si) == SYM_TYPE: + return sym_type(si) + return -1 // 约束满足三态:1 = 满足 / 0 = 违反 / -1 = **不判**(名字非类型/非接口 / 桥接失败)。三态 // 直传(**不**把 -1 折成 0/1)。 // R2 P3b Task 0:本函数 = `iface_satisfies` 统一入口的**函数调用点消费者**(P2b 交接契约①)。 -fn gen_constr_satisfied(c_ni: int, arg_ti: int) -> int { - if c_ni < 0 || arg_ti < 0 { return -1; } - if find_iface(c_ni) >= 0 { +fn gen_constr_satisfied(c_ni: int, arg_ti: int) -> int: + if c_ni < 0 || arg_ti < 0: + return -1 + if find_iface(c_ni) >= 0: // 用户轴(接口名):`iface_satisfies` 已交付(P3b Task 0)——**1 提前返回**(与回落 // 路径结论一致,省一次名拼接/查表);**0 与 -1 一律落下方既有 `check_iface` 名拼接 // 路径**(本层口径 = P3a「函数调用点逐字不动」:措辞/去重/rc 全保持)。0 → 诊断的 // 切换(= 走 gen_constr_raise 的新措辞)归 Task 6 Step 3——两处谓词同源( // iface_user_satisfies 与 check_iface 判同一面),故此处**不存在**判定分歧。 - s := iface_satisfies(arg_ti, c_ni); - if s == 1 { return 1; } - return -1; - } - cti := gen_constr_type_ti(c_ni); - if cti < 0 { return -1; } // 非类型名(未定义名等):不判、不发明诊断 - a := sh_term_of_ti(arg_ti); - b := sh_term_of_ti(cti); - if a < 0 || b < 0 { return -1; } // 桥接缺口 ⇒ 不判 - ty_budget_reset(200000); - s := ty_sub(a, b); - ty_budget_reset(200000); - return s; // 1/0/-1 直传 -} + s := iface_satisfies(arg_ti, c_ni) + if s == 1: + return 1 + return -1 + cti := gen_constr_type_ti(c_ni) + if cti < 0: + return -1 + // 非类型名(未定义名等):不判、不发明诊断 + a := sh_term_of_ti(arg_ti) + b := sh_term_of_ti(cti) + if a < 0 || b < 0: + return -1 + // 桥接缺口 ⇒ 不判 + ty_budget_reset(200000) + s := ty_sub(a, b) + ty_budget_reset(200000) + return s // 1/0/-1 直传 // 实例化点(结构/枚举 `Box[T: I]` 的 `Box[P]`)专用满足判定:**用户轴直取 iface_satisfies // 的真值**(不回落)——回落面是函数调用点的消息/去重口径(见 gen_constr_satisfied 注), // 与实例化点无关。purpose:本批(P3b Task 0)起 `T: I` 在实例化点**真判定**(此前 = 恒 -1 // 不判、零诊断——P3a 登记面)。三态直传:-1 = 不判 ⇒ 调用方零动作。 -fn gen_inst_constr_satisfied(c_ni: int, arg_ti: int) -> int { - if c_ni < 0 || arg_ti < 0 { return -1; } - if find_iface(c_ni) >= 0 { return iface_satisfies(arg_ti, c_ni); } - return gen_constr_satisfied(c_ni, arg_ti); -} +fn gen_inst_constr_satisfied(c_ni: int, arg_ti: int) -> int: + if c_ni < 0 || arg_ti < 0: + return -1 + if find_iface(c_ni) >= 0: + return iface_satisfies(arg_ti, c_ni) + return gen_constr_satisfied(c_ni, arg_ti) // 反例文本(诊断用):`实参 \ 约束` 的具体值。三态 -1 / 反例不可得 → ""(**不谎报反例**)。 -fn gen_constr_witness_str(arg_ti: int, c_ni: int) -> string { - cti := gen_constr_type_ti(c_ni); - if cti < 0 { return ""; } - a := sh_term_of_ti(arg_ti); - b := sh_term_of_ti(cti); - if a < 0 || b < 0 { return ""; } - ty_budget_reset(200000); - w := tt_witness(a, b); - ty_budget_reset(200000); - if w < 0 { return ""; } - return tt_display(w); -} +fn gen_constr_witness_str(arg_ti: int, c_ni: int) -> string: + cti := gen_constr_type_ti(c_ni) + if cti < 0: + return "" + a := sh_term_of_ti(arg_ti) + b := sh_term_of_ti(cti) + if a < 0 || b < 0: + return "" + ty_budget_reset(200000) + w := tt_witness(a, b) + ty_budget_reset(200000) + if w < 0: + return "" + return tt_display(w) // 诊断发射(措辞分派:既有接口路径的措辞/码不动;本路径 = 约束 + 反例)。码沿用 // EC_TG_BOUND(TG02,软诊断:check rc=1 / build rc=0 —— 与既有约束检查同门,**不新增硬门**)。 -fn gen_constr_raise(arg_ti: int, c_ni: int, line: int, col: int) { +fn gen_constr_raise(arg_ti: int, c_ni: int, line: int, col: int): // 措辞分派:接口名约束 ⇒ **与既有 check_iface 路径同措辞**("does not satisfy interface // 'X'"——两站点一致性;接口非类型行 ⇒ 反例项不可得 = 不附反例,不谎报);类型名约束 ⇒ // 既有措辞 + 反例(措辞与反例面 P3a 已交付,逐字未动)。 - if find_iface(c_ni) >= 0 { - msg_i := "Type '" + type_display(arg_ti) + "' does not satisfy interface '" + istr_get(c_ni) + "'"; - check_error(EC_TG_BOUND, msg_i, line, col); - return; - } - msg := "Type '" + type_display(arg_ti) + "' does not satisfy constraint '" + istr_get(c_ni) + "'"; - w := gen_constr_witness_str(arg_ti, c_ni); - if str_len(w) > 0 { msg = msg + " (counterexample: " + w + ")"; } - check_error(EC_TG_BOUND, msg, line, col); -} + if find_iface(c_ni) >= 0: + msg_i := "Type '" + type_display(arg_ti) + "' does not satisfy interface '" + istr_get(c_ni) + "'" + check_error(EC_TG_BOUND, msg_i, line, col) + return + msg := "Type '" + type_display(arg_ti) + "' does not satisfy constraint '" + istr_get(c_ni) + "'" + w := gen_constr_witness_str(arg_ti, c_ni) + if str_len(w) > 0: + msg = msg + " (counterexample: " + w + ")" + check_error(EC_TG_BOUND, msg, line, col) // ─── 诊断去重侧表(开放寻址,16B/条 {key, 1};key = node * MAX_GENERICS + gi)─── // 为何需要:实例化点的判定函数(res_type_node / res_call_type)按**语法出现点**调用,同一 // AST 节点可被多次解析(字段访问、多次引用同一注解…),且 `check_error` 无去重 ⇒ 不去重即 // 同一条约束违反被打印多次。键 = (节点, 形参下标)——同节点不同形参各报一条(信息不丢)。 // 生命周期同 named_dedup(init_types 置 cap=0 → 惰性重建);键含 AST 节点下标 ⇒ 随编译期作废。 -fn gen_constr_seen_init() { - if g_constr_seen_cap > 0 { return; } - nc := 1024; - nb := alloc(nc * 16); - i : ., mut = 0; - loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; } - g_constr_seen = nb; - g_constr_seen_cap = nc; - g_constr_seen_count = 0; -} - -fn gen_constr_seen_reset() { - g_constr_seen_cap = 0; - g_constr_seen_count = 0; -} - -fn gen_constr_seen_probe(k: int) -> int { - cap := g_constr_seen_cap; - p : ., mut = tt_mod(k, cap); - ret : ., mut = -1; - loop { - kk := r64(g_constr_seen, p * 16); - if kk < 0 { ret = p; break; } - if kk == k { ret = p; break; } - p = p + 1; if p >= cap { p = 0; } - } - return ret; -} - -fn gen_constr_seen_rehash() { - old := g_constr_seen; - old_cap := g_constr_seen_cap; - nc := old_cap * 2; - nb := alloc(nc * 16); - i : ., mut = 0; - loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; } - g_constr_seen = nb; - g_constr_seen_cap = nc; - g_constr_seen_count = 0; - j : ., mut = 0; - loop { - if j >= old_cap { break; } - kk := r64(old, j * 16); - if kk >= 0 { - s := gen_constr_seen_probe(kk); - w64(g_constr_seen, s * 16, kk); - w64(g_constr_seen, s * 16 + 8, 1); - g_constr_seen_count = g_constr_seen_count + 1; - } - j = j + 1; - } -} +fn gen_constr_seen_init(): + if g_constr_seen_cap > 0: + return + nc := 1024 + nb := alloc(nc * 16) + i : ., mut = 0 + loop: + if i >= nc: + break + w64(nb, i * 16, -1) + i = i + 1 + g_constr_seen = nb + g_constr_seen_cap = nc + g_constr_seen_count = 0 + +fn gen_constr_seen_reset(): + g_constr_seen_cap = 0 + g_constr_seen_count = 0 + +fn gen_constr_seen_probe(k: int) -> int: + cap := g_constr_seen_cap + p : ., mut = tt_mod(k, cap) + ret : ., mut = -1 + loop: + kk := r64(g_constr_seen, p * 16) + if kk < 0: + ret = p + break + if kk == k: + ret = p + break + p = p + 1 + if p >= cap: + p = 0 + return ret + +fn gen_constr_seen_rehash(): + old := g_constr_seen + old_cap := g_constr_seen_cap + nc := old_cap * 2 + nb := alloc(nc * 16) + i : ., mut = 0 + loop: + if i >= nc: + break + w64(nb, i * 16, -1) + i = i + 1 + g_constr_seen = nb + g_constr_seen_cap = nc + g_constr_seen_count = 0 + j : ., mut = 0 + loop: + if j >= old_cap: + break + kk := r64(old, j * 16) + if kk >= 0: + s := gen_constr_seen_probe(kk) + w64(g_constr_seen, s * 16, kk) + w64(g_constr_seen, s * 16 + 8, 1) + g_constr_seen_count = g_constr_seen_count + 1 + j = j + 1 // 1 = 首次(调用方报诊断),0 = 已报过(丢弃)。装填因子守卫在探测**前**(表满 + 键不存在 // ⇒ 开放寻址永不退出,照 named_dedup / sh_map 同款同因)。 -fn gen_constr_seen_add(k: int) -> int { - gen_constr_seen_init(); - if (g_constr_seen_count + 1) * 2 >= g_constr_seen_cap { gen_constr_seen_rehash(); } - s := gen_constr_seen_probe(k); - if r64(g_constr_seen, s * 16) == k { return 0; } - w64(g_constr_seen, s * 16, k); - w64(g_constr_seen, s * 16 + 8, 1); - g_constr_seen_count = g_constr_seen_count + 1; - return 1; -} +fn gen_constr_seen_add(k: int) -> int: + gen_constr_seen_init() + if (g_constr_seen_count + 1) * 2 >= g_constr_seen_cap: + gen_constr_seen_rehash() + s := gen_constr_seen_probe(k) + if r64(g_constr_seen, s * 16) == k: + return 0 + w64(g_constr_seen, s * 16, k) + w64(g_constr_seen, s * 16 + 8, 1) + g_constr_seen_count = g_constr_seen_count + 1 + return 1 // ─── 实例化点检查(结构/枚举泛型:`Box[T: I]` 的 `Box[P]`)─── // 消费点 = res_type_node / res_call_type 的 EXPR_GENERIC_APPLY 分支(实参已解析成 ti 处)。 // sa/ea = struct/enum 声明行(-1 = 该名字不是 struct/enum —— 接口泛型/未知名,零动作)。 // **实参缺位不判**(不越界读);**arg_ti < 0 不判**(未解析);用户接口约束经 // gen_constr_satisfied 回 -1 ⇒ 零动作(P3b 阻塞面,见该函数注)。 -fn gen_inst_constr_check(app_node: int, sa: int, ea: int, args: string, arg_count: int) { - gc : ., mut = 0; - if sa >= 0 { gc = si_generic_count(sa); } - else if ea >= 0 { gc = ei_generic_count(ea); } - else { return; } - i : ., mut = 0; - loop { - if i >= gc { break; } - if i >= arg_count { break; } - c_ni : ., mut = -1; - if sa >= 0 { c_ni = si_gen_constr(sa, i); } else { c_ni = ei_gen_constr(ea, i); } - if c_ni >= 0 { - arg_ti := r64(args, i * 8); - if arg_ti >= 0 { - if gen_inst_constr_satisfied(c_ni, arg_ti) == 0 { - if gen_constr_seen_add(app_node * MAX_GENERICS + i) != 0 { - gen_constr_raise(arg_ti, c_ni, ast_line(app_node), ast_col(app_node)); - } - } - } - } - i = i + 1; - } -} +fn gen_inst_constr_check(app_node: int, sa: int, ea: int, args: string, arg_count: int): + gc : ., mut = 0 + if sa >= 0: + gc = si_generic_count(sa) + else if ea >= 0: + gc = ei_generic_count(ea) + else: + return + i : ., mut = 0 + loop: + if i >= gc: + break + if i >= arg_count: + break + c_ni : ., mut = -1 + if sa >= 0: + c_ni = si_gen_constr(sa, i) + else: + c_ni = ei_gen_constr(ea, i) + if c_ni >= 0: + arg_ti := r64(args, i * 8) + if arg_ti >= 0: + if gen_inst_constr_satisfied(c_ni, arg_ti) == 0: + if gen_constr_seen_add(app_node * MAX_GENERICS + i) != 0: + gen_constr_raise(arg_ti, c_ni, ast_line(app_node), ast_col(app_node)) + i = i + 1 // --- First pass: collect all declarations --- -fn collect_decls() { - i : ., mut = 0; +fn collect_decls(): + i : ., mut = 0 // First: register all struct types - loop { - if i >= g_struct_count { break; } - name_idx := si_name(i); - type_idx := alloc_named_type(name_idx); - def_sym(name_idx, SYM_TYPE, type_idx, -1); - i = i + 1; - } + loop: + if i >= g_struct_count: + break + name_idx := si_name(i) + type_idx := alloc_named_type(name_idx) + def_sym(name_idx, SYM_TYPE, type_idx, -1) + i = i + 1 // Resolve struct field types now that all struct names are registered - i = 0; - loop { - if i >= g_struct_count { break; } - j : ., mut = 0; - loop { - if j >= si_field_count(i) { break; } + i = 0 + loop: + if i >= g_struct_count: + break + j : ., mut = 0 + loop: + if j >= si_field_count(i): + break // Field types were stored by parser as unpack_type() results (TY_* or 0) // We need to resolve them — but they're stored as ints, not nodes. // For now, leave as-is; fields are resolved during type inference. - j = j + 1; - } - i = i + 1; - } + j = j + 1 + i = i + 1 // Register struct generic params for type resolution - i = 0; - loop { - if i >= g_struct_count { break; } - gc := si_generic_count(i); - if gc > 0 { - gj : ., mut = 0; - loop { - if gj >= gc { break; } - gname_ni := si_generic_name(i, gj); - g_ti := alloc_type(TYP_GENERIC_PARAM, gname_ni, 0); - grow_gen_params(g_gen_param_count + 2); - w64(g_gen_params, g_gen_param_count * 8, gname_ni); - w64(g_gen_params, (g_gen_param_count + 1) * 8, g_ti); - g_gen_param_count = g_gen_param_count + 2; - def_sym(gname_ni, SYM_TYPE, g_ti, -1); - gj = gj + 1; - } - } - i = i + 1; - } + i = 0 + loop: + if i >= g_struct_count: + break + gc := si_generic_count(i) + if gc > 0: + gj : ., mut = 0 + loop: + if gj >= gc: + break + gname_ni := si_generic_name(i, gj) + g_ti := alloc_type(TYP_GENERIC_PARAM, gname_ni, 0) + grow_gen_params(g_gen_param_count + 2) + w64(g_gen_params, g_gen_param_count * 8, gname_ni) + w64(g_gen_params, (g_gen_param_count + 1) * 8, g_ti) + g_gen_param_count = g_gen_param_count + 2 + def_sym(gname_ni, SYM_TYPE, g_ti, -1) + gj = gj + 1 + i = i + 1 // Register all interface types - i = 0; - loop { - if i >= g_iface_count { break; } - name_idx := r64(g_ifaces, i * ESZ_IFACEINFO + OFF_IF_NAME); - type_idx := alloc_named_type(name_idx); - def_sym(name_idx, SYM_TYPE, type_idx, -1); - i = i + 1; - } + i = 0 + loop: + if i >= g_iface_count: + break + name_idx := r64(g_ifaces, i * ESZ_IFACEINFO + OFF_IF_NAME) + type_idx := alloc_named_type(name_idx) + def_sym(name_idx, SYM_TYPE, type_idx, -1) + i = i + 1 // ─── R2 P3 Task 4:**退役**内建 Option 注册(spec §5.4)─── // 旧行为:无用户 `enum Option` 时自动注册一个名为 "Option" 的**命名类型**行并 def_sym // (`T?` 经 parser 降级为 `Option[T]` 泛型应用,靠这个名字解析)。 @@ -1438,496 +1489,487 @@ fn collect_decls() { // 名字串判断同期退役(改按类型项结构解包)。 // Register all enum types and their variant constructors - i = 0; - loop { - if i >= g_enum_count { break; } - name_idx := ei_name(i); - type_idx := alloc_named_type(name_idx); - def_sym(name_idx, SYM_TYPE, type_idx, -1); + i = 0 + loop: + if i >= g_enum_count: + break + name_idx := ei_name(i) + type_idx := alloc_named_type(name_idx) + def_sym(name_idx, SYM_TYPE, type_idx, -1) // Register each variant as a function returning the enum type - vi : ., mut = 0; - loop { - if vi >= ei_variant_count(i) { break; } - vname_idx := ei_variant_name(i, vi); - def_sym(vname_idx, SYM_FN, type_idx, -1); - vi = vi + 1; - } - i = i + 1; - } + vi : ., mut = 0 + loop: + if vi >= ei_variant_count(i): + break + vname_idx := ei_variant_name(i, vi) + def_sym(vname_idx, SYM_FN, type_idx, -1) + vi = vi + 1 + i = i + 1 // Register enum generic params for type resolution - i = 0; - loop { - if i >= g_enum_count { break; } - gc := ei_generic_count(i); - if gc > 0 { - gj : ., mut = 0; - loop { - if gj >= gc { break; } - gname_ni := ei_generic_name(i, gj); - g_ti := alloc_type(TYP_GENERIC_PARAM, gname_ni, 0); - grow_gen_params(g_gen_param_count + 2); - w64(g_gen_params, g_gen_param_count * 8, gname_ni); - w64(g_gen_params, (g_gen_param_count + 1) * 8, g_ti); - g_gen_param_count = g_gen_param_count + 2; - def_sym(gname_ni, SYM_TYPE, g_ti, -1); - gj = gj + 1; - } - } - i = i + 1; - } + i = 0 + loop: + if i >= g_enum_count: + break + gc := ei_generic_count(i) + if gc > 0: + gj : ., mut = 0 + loop: + if gj >= gc: + break + gname_ni := ei_generic_name(i, gj) + g_ti := alloc_type(TYP_GENERIC_PARAM, gname_ni, 0) + grow_gen_params(g_gen_param_count + 2) + w64(g_gen_params, g_gen_param_count * 8, gname_ni) + w64(g_gen_params, (g_gen_param_count + 1) * 8, g_ti) + g_gen_param_count = g_gen_param_count + 2 + def_sym(gname_ni, SYM_TYPE, g_ti, -1) + gj = gj + 1 + i = i + 1 // Register type aliases - i = 0; - loop { - if i >= g_type_alias_count { break; } - name_idx := r64(g_type_aliases, i * 16); - type_node := r64(g_type_aliases, i * 16 + 8); - ti := res_type_node(type_node); - def_sym(name_idx, SYM_TYPE, ti, -1); - i = i + 1; - } + i = 0 + loop: + if i >= g_type_alias_count: + break + name_idx := r64(g_type_aliases, i * 16) + type_node := r64(g_type_aliases, i * 16 + 8) + ti := res_type_node(type_node) + def_sym(name_idx, SYM_TYPE, ti, -1) + i = i + 1 // Register all functions - i = 0; - loop { - if i >= g_func_count { break; } - name_idx := fi_name(i); - fn_node := fi_ast_node(i); - hotpatch_ver := ast_int_val(fn_node) / 256; - rt := fi_return_type(i); - rt_ti := TI_UNIT; + i = 0 + loop: + if i >= g_func_count: + break + name_idx := fi_name(i) + fn_node := fi_ast_node(i) + hotpatch_ver := ast_int_val(fn_node) / 256 + rt := fi_return_type(i) + rt_ti := TI_UNIT // For generic functions, skip return type resolution (depends on call site) - if fi_generic_count(i) > 0 { - rt_ti = TI_UNIT; + if fi_generic_count(i) > 0: + rt_ti = TI_UNIT // Register function generic params for type resolution - gj : ., mut = 0; - loop { - if gj >= fi_generic_count(i) { break; } - gname_ni := fi_generic_name(i, gj); - g_ti := alloc_type(TYP_GENERIC_PARAM, gname_ni, 0); - grow_gen_params(g_gen_param_count + 2); - w64(g_gen_params, g_gen_param_count * 8, gname_ni); - w64(g_gen_params, (g_gen_param_count + 1) * 8, g_ti); - g_gen_param_count = g_gen_param_count + 2; - def_sym(gname_ni, SYM_TYPE, g_ti, -1); - gj = gj + 1; - } - } else { - type_node := ast_type_val(fn_node); - if type_node > 0 && ast_kind(type_node) != 0 { - rt_ti = res_type_node(type_node); - } else { + gj : ., mut = 0 + loop: + if gj >= fi_generic_count(i): + break + gname_ni := fi_generic_name(i, gj) + g_ti := alloc_type(TYP_GENERIC_PARAM, gname_ni, 0) + grow_gen_params(g_gen_param_count + 2) + w64(g_gen_params, g_gen_param_count * 8, gname_ni) + w64(g_gen_params, (g_gen_param_count + 1) * 8, g_ti) + g_gen_param_count = g_gen_param_count + 2 + def_sym(gname_ni, SYM_TYPE, g_ti, -1) + gj = gj + 1 + else: + type_node := ast_type_val(fn_node) + if type_node > 0 && ast_kind(type_node) != 0: + rt_ti = res_type_node(type_node) + else: // P2b Task 6:值经单表 `ty_code_to_ti`;**本站点域 = 现状链 {INT,DEX,BOOL,STRING,UNIT}** // (无 CHAR/NEVER/7 ⇒ 三者与域外码一律保留 `rt_ti` 初值 TI_UNIT——域差异**逐站保留**, // 不得按「表 + 尾回落」一刀切:站点域差异是**载荷**的,探针 F1/F2/F4 实证, // `fn f() -> char` 的非泛型符号类型现状 = unit、extern 站点同形 = char)。 - rt_mapped := ty_code_to_ti(rt); - if rt_mapped >= 0 && rt_mapped != TI_CHAR && rt_mapped != TI_NEVER && rt_mapped != TI_DYN { - rt_ti = rt_mapped; - } - } - } - if hotpatch_ver > 0 { + rt_mapped := ty_code_to_ti(rt) + if rt_mapped >= 0 && rt_mapped != TI_CHAR && rt_mapped != TI_NEVER && rt_mapped != TI_DYN: + rt_ti = rt_mapped + if hotpatch_ver > 0: // @hotpatch function: register with mangled name fn_name.vN - fn_name_str := istr_get(name_idx); - mangled_name := fn_name_str + ".v" + int_str(hotpatch_ver); - mangled_ni := str_intern(mangled_name); - def_sym(mangled_ni, SYM_FN, rt_ti, fn_node); + fn_name_str := istr_get(name_idx) + mangled_name := fn_name_str + ".v" + int_str(hotpatch_ver) + mangled_ni := str_intern(mangled_name) + def_sym(mangled_ni, SYM_FN, rt_ti, fn_node) // Verify signature matches the first version - fj : ., mut = 0; - loop { - if fj >= i { break; } - if fi_name(fj) == name_idx { - first_fn := fi_ast_node(fj); - first_rt := fi_return_type(fj); - first_rt_ti := TI_UNIT; - type_node2 := ast_type_val(first_fn); - if type_node2 > 0 && ast_kind(type_node2) != 0 { - first_rt_ti = res_type_node(type_node2); - } else { + fj : ., mut = 0 + loop: + if fj >= i: + break + if fi_name(fj) == name_idx: + first_fn := fi_ast_node(fj) + first_rt := fi_return_type(fj) + first_rt_ti := TI_UNIT + type_node2 := ast_type_val(first_fn) + if type_node2 > 0 && ast_kind(type_node2) != 0: + first_rt_ti = res_type_node(type_node2) + else: // P2b Task 6:同上一处(本站点 = **hotpatch 首版**返回,域与上一处逐字相同) - first_mapped := ty_code_to_ti(first_rt); - if first_mapped >= 0 && first_mapped != TI_CHAR && first_mapped != TI_NEVER && first_mapped != TI_DYN { - first_rt_ti = first_mapped; - } - } + first_mapped := ty_code_to_ti(first_rt) + if first_mapped >= 0 && first_mapped != TI_CHAR && first_mapped != TI_NEVER && first_mapped != TI_DYN: + first_rt_ti = first_mapped // P3 Task 1:本站两侧**皆声明**(无源/目标之分)⇒ 长度面走对称核(= 现状语义) - compat := type_compat_sym(rt_ti, first_rt_ti); - if compat != 1 { - diag_type_incompatible(compat, EC_TF_RETURN, "Hotpatch return type mismatch for '" + fn_name_str + "'", ast_line(fn_node), ast_col(fn_node)); - } - first_pc := fi_param_count(fj); - cur_pc := fi_param_count(i); - if first_pc != cur_pc { - check_error(EC_N_DUPLICATE, "Hotpatch parameter count mismatch for '" + fn_name_str + "'", ast_line(fn_node), ast_col(fn_node)); - } - break; - } - fj = fj + 1; - } + compat := type_compat_sym(rt_ti, first_rt_ti) + if compat != 1: + diag_type_incompatible(compat, EC_TF_RETURN, "Hotpatch return type mismatch for '" + fn_name_str + "'", ast_line(fn_node), ast_col(fn_node)) + first_pc := fi_param_count(fj) + cur_pc := fi_param_count(i) + if first_pc != cur_pc: + check_error(EC_N_DUPLICATE, "Hotpatch parameter count mismatch for '" + fn_name_str + "'", ast_line(fn_node), ast_col(fn_node)) + break + fj = fj + 1 // Also register original name for call resolution (latest version wins) - def_sym(name_idx, SYM_FN, rt_ti, fn_node); - } else { + def_sym(name_idx, SYM_FN, rt_ti, fn_node) + else: // Normal function: check for duplicates (allow if existing is @hotpatch) - existing_si := find_gsym(name_idx); - if existing_si >= 0 && sym_kind(existing_si) == SYM_FN { - existing_node := sym_node(existing_si); - existing_is_hotpatch : ., mut = 0; - if existing_node >= 0 && ast_kind(existing_node) == EXPR_FN { - existing_is_hotpatch = ast_int_val(existing_node) / 256; - } - if existing_is_hotpatch == 0 { - fn_name_str := istr_get(name_idx); - check_error(EC_N_DUPLICATE, "Duplicate function definition '" + fn_name_str + "'", ast_line(fn_node), ast_col(fn_node)); - } - } - def_sym(name_idx, SYM_FN, rt_ti, fn_node); - } - fi_set_ispure(i, 1); // optimistic: all functions are pure - i = i + 1; - } + existing_si := find_gsym(name_idx) + if existing_si >= 0 && sym_kind(existing_si) == SYM_FN: + existing_node := sym_node(existing_si) + existing_is_hotpatch : ., mut = 0 + if existing_node >= 0 && ast_kind(existing_node) == EXPR_FN: + existing_is_hotpatch = ast_int_val(existing_node) / 256 + if existing_is_hotpatch == 0: + fn_name_str := istr_get(name_idx) + check_error(EC_N_DUPLICATE, "Duplicate function definition '" + fn_name_str + "'", ast_line(fn_node), ast_col(fn_node)) + def_sym(name_idx, SYM_FN, rt_ti, fn_node) + fi_set_ispure(i, 1) // optimistic: all functions are pure + i = i + 1 // Register extern function declarations (EXPR_EXTERN nodes not yet in g_funcs) - ei : ., mut = 0; - loop { - if ei >= g_ast_count { break; } - if ast_kind(ei) == EXPR_EXTERN { - name_ni := ast_a(ei); - first_param := ast_b(ei); - param_count := ast_c(ei); - ret_type := ast_type_val(ei); + ei : ., mut = 0 + loop: + if ei >= g_ast_count: + break + if ast_kind(ei) == EXPR_EXTERN: + name_ni := ast_a(ei) + first_param := ast_b(ei) + param_count := ast_c(ei) + ret_type := ast_type_val(ei) // Resolve return type to type index // P2b Task 6:值经单表 `ty_code_to_ti`;**本站点域 = {INT,DEX,BOOL,STRING,UNIT,CHAR}** // (含 CHAR、缺 NEVER/7——与上方 hotpatch 注册站点的域**不同且载荷**:探针 F4 实测 // `extern fn f() -> char` 的符号类型 = char,而 F1 同形非 extern = unit) - rt_ti : ., mut = TI_UNIT; - ext_mapped := ty_code_to_ti(ret_type); - if ext_mapped >= 0 && ext_mapped != TI_NEVER && ext_mapped != TI_DYN { - rt_ti = ext_mapped; - } + rt_ti : ., mut = TI_UNIT + ext_mapped := ty_code_to_ti(ret_type) + if ext_mapped >= 0 && ext_mapped != TI_NEVER && ext_mapped != TI_DYN: + rt_ti = ext_mapped // Register in symbol table (skip if duplicate) - if find_gsym(name_ni) < 0 { - def_sym(name_ni, SYM_FN, rt_ti, ei); - } + if find_gsym(name_ni) < 0: + def_sym(name_ni, SYM_FN, rt_ti, ei) // Register in g_funcs for backend codegen and linking - func_idx := g_func_count; - grow_funcs(func_idx + 1); - fi_set_name(func_idx, name_ni); - fi_set_param_count(func_idx, param_count); - fi_set_return_type(func_idx, ret_type); - fi_set_ast_node(func_idx, ei); - fi_set_generic_count(func_idx, 0); - fi_set_ispure(func_idx, 1); // optimistic: extern functions are pure - g_func_count = func_idx + 1; - } - ei = ei + 1; - } + func_idx := g_func_count + grow_funcs(func_idx + 1) + fi_set_name(func_idx, name_ni) + fi_set_param_count(func_idx, param_count) + fi_set_return_type(func_idx, ret_type) + fi_set_ast_node(func_idx, ei) + fi_set_generic_count(func_idx, 0) + fi_set_ispure(func_idx, 1) // optimistic: extern functions are pure + g_func_count = func_idx + 1 + ei = ei + 1 // Register all global variables - i = 0; - loop { - if i >= g_global_let_count { break; } - node := r64(g_global_lets, i * 8); - name_idx := ast_a(node); // EXPR_LET: a = name idx - type_node := ast_b(node); // EXPR_LET: b = type node (-1 if none) - ti := TI_UNIT; - if type_node >= 0 { ti = res_type_node(type_node); } - def_sym(name_idx, SYM_GLOBAL, ti, node); - i = i + 1; - } + i = 0 + loop: + if i >= g_global_let_count: + break + node := r64(g_global_lets, i * 8) + name_idx := ast_a(node) // EXPR_LET: a = name idx + type_node := ast_b(node) // EXPR_LET: b = type node (-1 if none) + ti := TI_UNIT + if type_node >= 0: + ti = res_type_node(type_node) + def_sym(name_idx, SYM_GLOBAL, ti, node) + i = i + 1 // Register module aliases (from imports) - mi : ., mut = 0; - loop { - if mi >= g_mod_count { break; } - alias_ni := r64(g_mods, mi * 24); - fileid_ni := r64(g_mods, mi * 24 + 8); - def_sym(alias_ni, SYM_MODULE, fileid_ni, -1); - mi = mi + 1; - } + mi : ., mut = 0 + loop: + if mi >= g_mod_count: + break + alias_ni := r64(g_mods, mi * 24) + fileid_ni := r64(g_mods, mi * 24 + 8) + def_sym(alias_ni, SYM_MODULE, fileid_ni, -1) + mi = mi + 1 // Register mod path declarations (mod foo::bar;) - pi : ., mut = 0; - loop { - if pi >= g_mod_path_count { break; } - mpn := r64(g_mod_path_names, pi * 8); - def_sym(mpn, SYM_MODULE, mpn, -1); - pi = pi + 1; - } + pi : ., mut = 0 + loop: + if pi >= g_mod_path_count: + break + mpn := r64(g_mod_path_names, pi * 8) + def_sym(mpn, SYM_MODULE, mpn, -1) + pi = pi + 1 // Build module function lookup table for qualified access (e.g., mymath.add) - main_fni : ., mut = 0; - if g_file_count > 0 { main_fni = r64(g_files, 0); } - g_mod_func_count = 0; g_mod_func_cap = 0; - fi : ., mut = 0; - loop { - if fi >= g_func_count { break; } - fn_node := fi_ast_node(fi); - fn_line := ast_line(fn_node); - if fn_line > 0 && fn_line <= g_line_count { - fileid_ni := r64(g_line_fileid, (fn_line - 1) * 8); - if fileid_ni != main_fni && fileid_ni != 0 && g_line_count > 0 { - grow_mod_funcs(g_mod_func_count + 1); - w64(g_mod_func_fileids, g_mod_func_count * 8, fileid_ni); - w64(g_mod_func_names, g_mod_func_count * 8, fi_name(fi)); - fn_si := find_sym(fi_name(fi)); - if fn_si >= 0 { - w64(g_mod_func_tis, g_mod_func_count * 8, sym_type(fn_si)); - } - g_mod_func_count = g_mod_func_count + 1; - } - } - fi = fi + 1; - } -} + main_fni : ., mut = 0 + if g_file_count > 0: + main_fni = r64(g_files, 0) + g_mod_func_count = 0 + g_mod_func_cap = 0 + fi : ., mut = 0 + loop: + if fi >= g_func_count: + break + fn_node := fi_ast_node(fi) + fn_line := ast_line(fn_node) + if fn_line > 0 && fn_line <= g_line_count: + fileid_ni := r64(g_line_fileid, (fn_line - 1) * 8) + if fileid_ni != main_fni && fileid_ni != 0 && g_line_count > 0: + grow_mod_funcs(g_mod_func_count + 1) + w64(g_mod_func_fileids, g_mod_func_count * 8, fileid_ni) + w64(g_mod_func_names, g_mod_func_count * 8, fi_name(fi)) + fn_si := find_sym(fi_name(fi)) + if fn_si >= 0: + w64(g_mod_func_tis, g_mod_func_count * 8, sym_type(fn_si)) + g_mod_func_count = g_mod_func_count + 1 + fi = fi + 1 // --- Generic type inference helpers --- -fn is_func_generic(fi: int, name_idx: int) -> bool { - if fi < 0 || fi >= g_func_count { return false; } - gi : ., mut = 0; - loop { - if gi >= fi_generic_count(fi) { return false; } - if r64(g_funcs, fi * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gi * 8) == name_idx { return true; } - gi = gi + 1; - } - return false; -} - -fn find_func(name_idx: int) -> int { - i : ., mut = 0; - loop { - if i >= g_func_count { return -1; } - if fi_name(i) == name_idx { return i; } - i = i + 1; - } - return -1; -} +fn is_func_generic(fi: int, name_idx: int) -> bool: + if fi < 0 || fi >= g_func_count: + return false + gi : ., mut = 0 + loop: + if gi >= fi_generic_count(fi): + return false + if r64(g_funcs, fi * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gi * 8) == name_idx: + return true + gi = gi + 1 + return false + +fn find_func(name_idx: int) -> int: + i : ., mut = 0 + loop: + if i >= g_func_count: + return -1 + if fi_name(i) == name_idx: + return i + i = i + 1 + return -1 // ─── TODO #2026-09-11-11 ①②:struct 字面量的名字绑定 / 类型比对 辅助 ─── // 字段名 idx → 声明下标(-1 = 该名字不在声明中)。名字 idx 来自 parser 写入的 wrapper.b // (EXPR_STRUCT 契约,见 ast.cr / parser.cr struct 字面量分支)。 -fn struct_field_index_by_name(si: int, name_ni: int) -> int { - if si < 0 || name_ni < 0 { return -1; } - j : ., mut = 0; - loop { - if j >= si_field_count(si) { return -1; } - if si_field_name(si, j) == name_ni { return j; } - j = j + 1; - } - return -1; -} +fn struct_field_index_by_name(si: int, name_ni: int) -> int: + if si < 0 || name_ni < 0: + return -1 + j : ., mut = 0 + loop: + if j >= si_field_count(si): + return -1 + if si_field_name(si, j) == name_ni: + return j + j = j + 1 + return -1 // 类型里是否**仍含未实例化的泛型参数**(TYP_GENERIC_PARAM,可嵌套在数组 / 指针 / 引用 / // 切片 / 元组 / 泛型应用内)。字面量的「字段类型 vs 声明」「元素同质性」判定在**任一侧** // 含未实例化参数时**跳过**——参数未实例化时比较不成立,强行比较 = 假拒(实测泛型函数体 // `fn f[T](x: T) { p := P{a: 1, b: x}; }`:x 的类型是 T,与声明的 int 比较必假)。参数实例化 // 由 monomorph 负责,此判定不越权。 -fn ti_has_generic_param(ti: int) -> int { - k := get_type_kind(ti); - if k < 0 { return 0; } - if k == TYP_GENERIC_PARAM { return 1; } - if k == TYP_ARRAY || k == TYP_PTR || k == TYP_REF || k == TYP_SLICE { - return ti_has_generic_param(get_type_data(ti)); - } - if k == TYP_TUPLE { - cnt := get_type_data(ti); - st := get_type_extra(ti); - i : ., mut = 0; - loop { - if i >= cnt { break; } - if ti_has_generic_param(r64(g_gen_apply_data, (st + i) * 8)) != 0 { return 1; } - i = i + 1; - } - return 0; - } - if k == TYP_GENERIC_APPLY { - st := get_type_extra(ti); - cnt := r64(g_gen_apply_data, st * 8); - i : ., mut = 0; - loop { - if i >= cnt { break; } - if ti_has_generic_param(r64(g_gen_apply_data, (st + 1 + i) * 8)) != 0 { return 1; } - i = i + 1; - } - return 0; - } - return 0; -} +fn ti_has_generic_param(ti: int) -> int: + k := get_type_kind(ti) + if k < 0: + return 0 + if k == TYP_GENERIC_PARAM: + return 1 + if k == TYP_ARRAY || k == TYP_PTR || k == TYP_REF || k == TYP_SLICE: + return ti_has_generic_param(get_type_data(ti)) + if k == TYP_TUPLE: + cnt := get_type_data(ti) + st := get_type_extra(ti) + i : ., mut = 0 + loop: + if i >= cnt: + break + if ti_has_generic_param(r64(g_gen_apply_data, (st + i) * 8)) != 0: + return 1 + i = i + 1 + return 0 + if k == TYP_GENERIC_APPLY: + st := get_type_extra(ti) + cnt := r64(g_gen_apply_data, st * 8) + i : ., mut = 0 + loop: + if i >= cnt: + break + if ti_has_generic_param(r64(g_gen_apply_data, (st + 1 + i) * 8)) != 0: + return 1 + i = i + 1 + return 0 + return 0 // 字段**声明类型节点**是否提及本结构体的泛型参数(`T` / `[T; 3]` / `Box[T]` …)。提及 = // 该字段的声明类型在字面量处**无法静态解析**:结构体泛型参数在字面量作用域不在名字表里, // res_type_node 会把 `T` 误解析成名为 "T" 的具名类型 → 与实参比较必假(假拒)。故这些字段 // 的类型比对跳过;参数本身走绑定路径(is_struct_generic 判定,见 EXPR_STRUCT 分支)。 -fn type_node_mentions_struct_param(si: int, tn: int) -> int { - if tn < 0 || si < 0 { return 0; } - k := ast_kind(tn); - if k == EXPR_IDENT { - if is_struct_generic(si, ast_int_val(tn)) { return 1; } - return 0; - } - if k == EXPR_ARRAY || k == EXPR_REFTYPE || k == EXPR_PTRTYPE || k == EXPR_OPTIONAL { +fn type_node_mentions_struct_param(si: int, tn: int) -> int: + if tn < 0 || si < 0: + return 0 + k := ast_kind(tn) + if k == EXPR_IDENT: + if is_struct_generic(si, ast_int_val(tn)): + return 1 + return 0 + if k == EXPR_ARRAY || k == EXPR_REFTYPE || k == EXPR_PTRTYPE || k == EXPR_OPTIONAL: // EXPR_OPTIONAL(P3 Task 4):内层提及形参(`T?` 字段)⇒ 同上跳过字面量处的静态比对。 - return type_node_mentions_struct_param(si, ast_a(tn)); - } - if k == EXPR_GENERIC_APPLY { - if is_struct_generic(si, ast_a(tn)) { return 1; } - cnt := ast_c(tn); - an : ., mut = ast_b(tn); - i : ., mut = 0; - loop { - if i >= cnt { break; } - if an >= 0 { - if type_node_mentions_struct_param(si, an) != 0 { return 1; } - } - an = an + 1; - i = i + 1; - } - return 0; - } - return 0; -} + return type_node_mentions_struct_param(si, ast_a(tn)) + if k == EXPR_GENERIC_APPLY: + if is_struct_generic(si, ast_a(tn)): + return 1 + cnt := ast_c(tn) + an : ., mut = ast_b(tn) + i : ., mut = 0 + loop: + if i >= cnt: + break + if an >= 0: + if type_node_mentions_struct_param(si, an) != 0: + return 1 + an = an + 1 + i = i + 1 + return 0 + return 0 // 类型展示名(诊断措辞用):具名/基型/泛型应用基名走 get_type_name,其余构造子递归拼装。 // 未识别 → "?"(不伪造名字)。 -fn type_display(ti: int) -> string { - k := get_type_kind(ti); +fn type_display(ti: int) -> string: + k := get_type_kind(ti) // 泛型应用**先于** get_type_name 捷径处理(#2026-09-11-11 评审 Minor #2):后者对 // TYP_GENERIC_APPLY 只返回基名 ⇒ 实参全丢(「expected Box, got Box」—— // 真正不匹配的那个类型实参恰是读者最需要的),且使本函数下方的实参分支 // 成死码。此处展开成 `Box[int]` / `Pair[Box[int], string]` 形式。 - if k == TYP_GENERIC_APPLY { - base := get_type_data(ti); - s : string, mut; - s = type_display(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 + type_display(r64(g_gen_apply_data, (start + 1 + i) * 8)); - i = i + 1; - } - s = s + "]"; - return s; - } - ni := get_type_name(ti); - if ni >= 0 { return istr_get(ni); } - if k == TYP_ARRAY { return "[" + type_display(get_type_data(ti)) + "; " + int_str(get_type_extra(ti)) + "]"; } - if k == TYP_SLICE { return "[" + type_display(get_type_data(ti)) + "]"; } - if k == TYP_PTR { return "*" + type_display(get_type_data(ti)); } - if k == TYP_REF { return "&" + type_display(get_type_data(ti)); } - if k == TYP_GENERIC_PARAM { return istr_get(get_type_data(ti)); } - if k == TYP_DYN { return "dyn"; } + if k == TYP_GENERIC_APPLY: + base := get_type_data(ti) + s : string, mut + s = type_display(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 + type_display(r64(g_gen_apply_data, (start + 1 + i) * 8)) + i = i + 1 + s = s + "]" + return s + ni := get_type_name(ti) + if ni >= 0: + return istr_get(ni) + if k == TYP_ARRAY: + return "[" + type_display(get_type_data(ti)) + "; " + int_str(get_type_extra(ti)) + "]" + if k == TYP_SLICE: + return "[" + type_display(get_type_data(ti)) + "]" + if k == TYP_PTR: + return "*" + type_display(get_type_data(ti)) + if k == TYP_REF: + return "&" + type_display(get_type_data(ti)) + if k == TYP_GENERIC_PARAM: + return istr_get(get_type_data(ti)) + if k == TYP_DYN: + return "dyn" // R2 P3 Task 4:`T?` 显示为 `T?`、null 单点类型显示为 "null"(诊断措辞面;未识别仍 "?") - if k == TYP_OPTIONAL { return type_display(get_type_data(ti)) + "?"; } - if k == TYP_NULL { return "null"; } - return "?"; -} - -fn is_struct_generic(si: int, name_idx: int) -> bool { - if si < 0 || si >= g_struct_count { return false; } - gi : ., mut = 0; - loop { - if gi >= si_generic_count(si) { return false; } - if si_generic_name(si, gi) == name_idx { return true; } - gi = gi + 1; - } - return false; -} - -fn find_struct_by_name(name_idx: int) -> int { - i : ., mut = 0; - loop { - if i >= g_struct_count { return -1; } - if si_name(i) == name_idx { return i; } - i = i + 1; - } - return -1; -} - -fn res_call_type(node: int, func_fi: int) -> int { + if k == TYP_OPTIONAL: + return type_display(get_type_data(ti)) + "?" + if k == TYP_NULL: + return "null" + return "?" + +fn is_struct_generic(si: int, name_idx: int) -> bool: + if si < 0 || si >= g_struct_count: + return false + gi : ., mut = 0 + loop: + if gi >= si_generic_count(si): + return false + if si_generic_name(si, gi) == name_idx: + return true + gi = gi + 1 + return false + +fn find_struct_by_name(name_idx: int) -> int: + i : ., mut = 0 + loop: + if i >= g_struct_count: + return -1 + if si_name(i) == name_idx: + return i + i = i + 1 + return -1 + +fn res_call_type(node: int, func_fi: int) -> int: // Resolve a type node for call inference, treating generic params as TYP_GENERIC_PARAM - if node < 0 { return TI_UNIT; } - if ast_kind(node) == 0 { + if node < 0: + return TI_UNIT + if ast_kind(node) == 0: // P2b Task 6:7 行内联链 → 单表 `ty_code_to_ti`;**本站点与 res_type_node 的唯一语义差 // = NEVER 格**(现状链无 TY_NEVER 分支 ⇒ 落尾 TI_UNIT)——探针实测**可达** // (`fn g[T](a: T) -> never {...}` 的调用位点;插桩 build 实测 PROBE6_CALL_NEVER 命中 1 次, // 见报告 §探针)⇒ 差异**显式保留**,不静默合一;「never 在调用位点被当 unit」登记为 P3 待裁决项。 - tv := ast_type_val(node); - mapped : ., mut = ty_code_to_ti(tv); - if mapped < 0 || tv == TY_NEVER { mapped = TI_UNIT; } - return mapped; - } - if ast_kind(node) == EXPR_IDENT { - name_idx := ast_int_val(node); - if is_func_generic(func_fi, name_idx) { - return alloc_type(TYP_GENERIC_PARAM, name_idx, 0); - } + tv := ast_type_val(node) + mapped : ., mut = ty_code_to_ti(tv) + if mapped < 0 || tv == TY_NEVER: + mapped = TI_UNIT + return mapped + if ast_kind(node) == EXPR_IDENT: + name_idx := ast_int_val(node) + if is_func_generic(func_fi, name_idx): + return alloc_type(TYP_GENERIC_PARAM, name_idx, 0) // Regular named type - si := find_gsym(name_idx); - if si >= 0 && sym_kind(si) == SYM_TYPE { return sym_type(si); } - return alloc_named_type(name_idx); - } - if ast_kind(node) == EXPR_GENERIC_APPLY { - name_idx := ast_a(node); - first_an := ast_b(node); - ac := ast_c(node); - si := find_gsym(name_idx); - if si < 0 || sym_kind(si) != SYM_TYPE { return TI_UNIT; } - base_ti := sym_type(si); + si := find_gsym(name_idx) + if si >= 0 && sym_kind(si) == SYM_TYPE: + return sym_type(si) + return alloc_named_type(name_idx) + if ast_kind(node) == EXPR_GENERIC_APPLY: + name_idx := ast_a(node) + first_an := ast_b(node) + ac := ast_c(node) + si := find_gsym(name_idx) + if si < 0 || sym_kind(si) != SYM_TYPE: + return TI_UNIT + base_ti := sym_type(si) // 两趟(同 res_type_node 的泛型应用分支:实参解析会追加嵌套应用载荷) - args : string, mut; - if ac > 0 { - args = alloc(ac * 8); - ai : ., mut = 0; - an : ., mut = first_an; - loop { - if ai >= ac { break; } - w64(args, ai * 8, res_call_type(an, func_fi)); - ai = ai + 1; - an = an + 1; - } - } + args : string, mut + if ac > 0: + args = alloc(ac * 8) + ai : ., mut = 0 + an : ., mut = first_an + loop: + if ai >= ac: + break + w64(args, ai * 8, res_call_type(an, func_fi)) + ai = ai + 1 + an = an + 1 // R2 P3 Task 5(Step 3):调用位点的实例化检查(与 res_type_node 同源;本节的存在理由 // = 调用位点的类型语法(形参/返回/字段)两侧都要覆盖——见 res_call_type 头注的域差)。 - gen_inst_constr_check(node, find_struct(name_idx), find_enum(name_idx), args, ac); - ds := g_gen_apply_data_count; - grow_gen_apply_data(ds + 1 + ac); - w64(g_gen_apply_data, ds * 8, ac); - ai2 : ., mut = 0; - loop { - if ai2 >= ac { break; } - w64(g_gen_apply_data, (ds + 1 + ai2) * 8, r64(args, ai2 * 8)); - ai2 = ai2 + 1; - } - g_gen_apply_data_count = ds + 1 + ac; - return alloc_type(TYP_GENERIC_APPLY, base_ti, ds); - } - if ast_kind(node) == EXPR_REFTYPE { - inner := res_call_type(ast_a(node), func_fi); - mf := ast_int_val(node); - return alloc_type(TYP_REF, inner, mf); - } - if ast_kind(node) == EXPR_OPTIONAL { + gen_inst_constr_check(node, find_struct(name_idx), find_enum(name_idx), args, ac) + ds := g_gen_apply_data_count + grow_gen_apply_data(ds + 1 + ac) + w64(g_gen_apply_data, ds * 8, ac) + ai2 : ., mut = 0 + loop: + if ai2 >= ac: + break + w64(g_gen_apply_data, (ds + 1 + ai2) * 8, r64(args, ai2 * 8)) + ai2 = ai2 + 1 + g_gen_apply_data_count = ds + 1 + ac + return alloc_type(TYP_GENERIC_APPLY, base_ti, ds) + if ast_kind(node) == EXPR_REFTYPE: + inner := res_call_type(ast_a(node), func_fi) + mf := ast_int_val(node) + return alloc_type(TYP_REF, inner, mf) + if ast_kind(node) == EXPR_OPTIONAL: // R2 P3 Task 4:`T?` 在调用位点的解析(与 res_type_node 同语义;本函数只多一条 // 泛型形参分支的差异,见函数头注——optional 分支两侧一致)。 - inner := res_call_type(ast_a(node), func_fi); - return alloc_type(TYP_OPTIONAL, inner, 0); - } - return TI_UNIT; -} - -fn unify_types(pattern: int, concrete: int) -> bool { - if pattern == concrete { return true; } - pk := get_type_kind(pattern); - ck := get_type_kind(concrete); - if pk < 0 || ck < 0 { return false; } + inner := res_call_type(ast_a(node), func_fi) + return alloc_type(TYP_OPTIONAL, inner, 0) + return TI_UNIT + +fn unify_types(pattern: int, concrete: int) -> bool: + if pattern == concrete: + return true + pk := get_type_kind(pattern) + ck := get_type_kind(concrete) + if pk < 0 || ck < 0: + return false // ─── 批 8(甲)批 1 刀 1:`T?` 模式(TYP_OPTIONAL)分支 ─────────────────────── // 根因:此前 `T?` 模式落**兜底** `type_compat_strict(concrete, pattern)` ⇒ 内层泛型参数 // **不代入、不绑定、恒假** ⇒ 泛型调用里 `T?` 形参的实参**既不绑定也不校验**: @@ -1942,141 +1984,140 @@ fn unify_types(pattern: int, concrete: int) -> bool { // (其 pattern 恒为 `TYP_GENERIC_PARAM`——守卫要求字段类型节点是 `EXPR_IDENT` 泛型参数)。 // 纪律:**只加分支,不改既有三条规则的语义**(`pattern == concrete` / `TYP_GENERIC_PARAM` / // `TYP_GENERIC_APPLY` 逐字未动);不改任何调用点。 - if pk == TYP_OPTIONAL { - inner_p := get_type_data(pattern); - if inner_p < 0 { return false; } - if ck == TYP_OPTIONAL { - inner_c := get_type_data(concrete); - if inner_c < 0 { return false; } - return unify_types(inner_p, inner_c); - } - return unify_types(inner_p, concrete); - } - if pk == TYP_GENERIC_PARAM { - name_idx := get_type_data(pattern); - mi : ., mut = 0; - loop { - if mi >= g_gen_map_count { break; } - if r64(g_gen_map_names, mi * 8) == name_idx { + if pk == TYP_OPTIONAL: + inner_p := get_type_data(pattern) + if inner_p < 0: + return false + if ck == TYP_OPTIONAL: + inner_c := get_type_data(concrete) + if inner_c < 0: + return false + return unify_types(inner_p, inner_c) + return unify_types(inner_p, concrete) + if pk == TYP_GENERIC_PARAM: + name_idx := get_type_data(pattern) + mi : ., mut = 0 + loop: + if mi >= g_gen_map_count: + break + if r64(g_gen_map_names, mi * 8) == name_idx: // P3 Task 1 参序归一:源 = concrete(实参),目标 = 已绑定项 - return type_compat_strict(concrete, r64(g_gen_map_types, mi * 8)) == 1; - } - mi = mi + 1; - } - grow_gen_map(g_gen_map_count + 1); - w64(g_gen_map_names, g_gen_map_count * 8, name_idx); - w64(g_gen_map_types, g_gen_map_count * 8, concrete); - g_gen_map_count = g_gen_map_count + 1; - return true; - return false; - } - if pk == TYP_GENERIC_APPLY && ck == TYP_GENERIC_APPLY { + return type_compat_strict(concrete, r64(g_gen_map_types, mi * 8)) == 1 + mi = mi + 1 + grow_gen_map(g_gen_map_count + 1) + w64(g_gen_map_names, g_gen_map_count * 8, name_idx) + w64(g_gen_map_types, g_gen_map_count * 8, concrete) + g_gen_map_count = g_gen_map_count + 1 + return true + return false + if pk == TYP_GENERIC_APPLY && ck == TYP_GENERIC_APPLY: // P3 Task 1 参序归一:源 = concrete 基型,目标 = pattern 基型(两侧恒 TYP_NAMED ⇒ 方向面不可达) - if type_compat_strict(get_type_data(concrete), get_type_data(pattern)) != 1 { return false; } - ps := get_type_extra(pattern); - cs := get_type_extra(concrete); - pc := r64(g_gen_apply_data, ps * 8); - cc := r64(g_gen_apply_data, cs * 8); - if pc != cc { return false; } - ai : ., mut = 0; - loop { - if ai >= pc { break; } - if !unify_types(r64(g_gen_apply_data, (ps + 1 + ai) * 8), r64(g_gen_apply_data, (cs + 1 + ai) * 8)) { return false; } - ai = ai + 1; - } - return true; - } + if type_compat_strict(get_type_data(concrete), get_type_data(pattern)) != 1: + return false + ps := get_type_extra(pattern) + cs := get_type_extra(concrete) + pc := r64(g_gen_apply_data, ps * 8) + cc := r64(g_gen_apply_data, cs * 8) + if pc != cc: + return false + ai : ., mut = 0 + loop: + if ai >= pc: + break + if !unify_types(r64(g_gen_apply_data, (ps + 1 + ai) * 8), r64(g_gen_apply_data, (cs + 1 + ai) * 8)): + return false + ai = ai + 1 + return true // P3 Task 1 参序归一:源 = concrete(实参),目标 = pattern(声明) - return type_compat_strict(concrete, pattern) == 1; -} + return type_compat_strict(concrete, pattern) == 1 -fn substitute_return_type(ti: int) -> int { +fn substitute_return_type(ti: int) -> int: // Substitute generic params using g_gen_map - if g_gen_map_count == 0 { return ti; } - k := get_type_kind(ti); - if k == TYP_GENERIC_PARAM { - name_idx := get_type_data(ti); - mi : ., mut = 0; - loop { - if mi >= g_gen_map_count { break; } - if r64(g_gen_map_names, mi * 8) == name_idx { return r64(g_gen_map_types, mi * 8); } - mi = mi + 1; - } - return ti; - } - if k == TYP_GENERIC_APPLY { - base := get_type_data(ti); - start := get_type_extra(ti); - count := r64(g_gen_apply_data, start * 8); + if g_gen_map_count == 0: + return ti + k := get_type_kind(ti) + if k == TYP_GENERIC_PARAM: + name_idx := get_type_data(ti) + mi : ., mut = 0 + loop: + if mi >= g_gen_map_count: + break + if r64(g_gen_map_names, mi * 8) == name_idx: + return r64(g_gen_map_types, mi * 8) + mi = mi + 1 + return ti + if k == TYP_GENERIC_APPLY: + base := get_type_data(ti) + start := get_type_extra(ti) + count := r64(g_gen_apply_data, start * 8) // 两趟(同 res_type_node:递归代换会追加嵌套应用载荷 ⇒ 先算进暂存再认领块) - subs : string, mut; - if count > 0 { - subs = alloc(count * 8); - ai : ., mut = 0; - loop { - if ai >= count { break; } - w64(subs, ai * 8, substitute_return_type(r64(g_gen_apply_data, (start + 1 + ai) * 8))); - ai = ai + 1; - } - } - new_start := g_gen_apply_data_count; - grow_gen_apply_data(new_start + 1 + count); - w64(g_gen_apply_data, new_start * 8, count); - ai2 : ., mut = 0; - loop { - if ai2 >= count { break; } - w64(g_gen_apply_data, (new_start + 1 + ai2) * 8, r64(subs, ai2 * 8)); - ai2 = ai2 + 1; - } - g_gen_apply_data_count = new_start + 1 + count; - return alloc_type(TYP_GENERIC_APPLY, base, new_start); - } - return ti; -} - -fn infer_gen_call(fi: int, call_node: int, first_arg: int, arg_count: int) -> int { + subs : string, mut + if count > 0: + subs = alloc(count * 8) + ai : ., mut = 0 + loop: + if ai >= count: + break + w64(subs, ai * 8, substitute_return_type(r64(g_gen_apply_data, (start + 1 + ai) * 8))) + ai = ai + 1 + new_start := g_gen_apply_data_count + grow_gen_apply_data(new_start + 1 + count) + w64(g_gen_apply_data, new_start * 8, count) + ai2 : ., mut = 0 + loop: + if ai2 >= count: + break + w64(g_gen_apply_data, (new_start + 1 + ai2) * 8, r64(subs, ai2 * 8)) + ai2 = ai2 + 1 + g_gen_apply_data_count = new_start + 1 + count + return alloc_type(TYP_GENERIC_APPLY, base, new_start) + return ti + +fn infer_gen_call(fi: int, call_node: int, first_arg: int, arg_count: int) -> int: // Infer concrete types for a generic function call - fn_node := fi_ast_node(fi); - first_param := ast_b(fn_node); - param_count := ast_c(fn_node); - ret_type_node := ast_type_val(fn_node); + fn_node := fi_ast_node(fi) + first_param := ast_b(fn_node) + param_count := ast_c(fn_node) + ret_type_node := ast_type_val(fn_node) - g_gen_map_count = 0; g_gen_map_cap = 0; + g_gen_map_count = 0 + g_gen_map_cap = 0 // First pass: infer arg types and build mapping - pi : ., mut = 0; - pn : ., mut = first_param; - an : ., mut = first_arg; - loop { - if pi >= param_count || pi >= arg_count { break; } - if pn < 0 || an < 0 { break; } - - orig_type_node := ast_data(pn); // original param type node - - if orig_type_node >= 0 { - pattern_ti := res_call_type(orig_type_node, fi); - concrete_ti := infer_expr(ast_a(an)); + pi : ., mut = 0 + pn : ., mut = first_param + an : ., mut = first_arg + loop: + if pi >= param_count || pi >= arg_count: + break + if pn < 0 || an < 0: + break + + orig_type_node := ast_data(pn) // original param type node + + if orig_type_node >= 0: + pattern_ti := res_call_type(orig_type_node, fi) + concrete_ti := infer_expr(ast_a(an)) // 批 8(甲)S1【report-only】:接上**被丢弃的返回值**——只打点、不阻断(S3 才升硬错)。 // 误报护栏(六类,lead 2026-09-18 指定):① 整数字面量 → 数值形参(字面量多态; // `unify_types` 对 int→dex/int? 不成立)② 未推断出形(TI_UNIT,多见于未覆盖面)—— // 两类**直接跳过**;泛型 `T`↔`T` 由 `unify_types` 自身绑定语义处理;`None→T?` 同; // 方法接收者偏移与外/变参面**本条不覆盖**(见 S1 报告的范围节)。 // 判定一律经**类型引擎**(`unify_types`),不自写等值判定。 - s1_skip : ., mut = 0; - if ast_kind(ast_a(an)) == EXPR_INT { s1_skip = 1; } - if concrete_ti == TI_UNIT { s1_skip = 1; } - if !unify_types(pattern_ti, concrete_ti) { - if s1_skip == 0 { + s1_skip : ., mut = 0 + if ast_kind(ast_a(an)) == EXPR_INT: + s1_skip = 1 + if concrete_ti == TI_UNIT: + s1_skip = 1 + if !unify_types(pattern_ti, concrete_ti): + if s1_skip == 0: println("[S1-ARG] line=" + int_str(ast_line(ast_a(an))) + " col=" + int_str(ast_col(ast_a(an))) - + " pi=" + int_str(pi) + " p=" + type_display(pattern_ti) - + " a=" + type_display(concrete_ti)); - } - } - } else { - infer_expr(ast_a(an)); - } - - pi = pi + 1; + + " pi=" + int_str(pi) + " p=" + type_display(pattern_ti) + + " a=" + type_display(concrete_ti)) + else: + infer_expr(ast_a(an)) + + pi = pi + 1 // ─── R2 P3 Task 5(Step 1):F4 形参链导航修复(TODO #2026-09-11-4)─── // 旧态 `pn = pn + 1` 假设 EXPR_PARAM 在节点表里**连续**——不成立:每个形参的类型 // 节点由 parse_type 在**该形参节点之前**分配(parser.cr 的 `pty := parse_type()` → @@ -2089,58 +2130,53 @@ fn infer_gen_call(fi: int, call_node: int, first_arg: int, arg_count: int) -> in // 形参凭空绑定 T(`fn take[T](n: int, a: T)` 场景)。 // 修法 = 前扫到下一个 EXPR_PARAM(与 ir_gen.cr 的三处同款同因::1481-1487 的 dex 参数 // 对齐 / :2279-2285 的参数建 var / :2715 的 mono 克隆),扫到表尾置 -1(外循环 break)。 - pn = pn + 1; - loop { if pn >= g_ast_count { pn = -1; break; } if ast_kind(pn) == EXPR_PARAM { break; } pn = pn + 1; } - an = ast_b(an); // next EXPR_ARG - } + pn = pn + 1 + loop: + if pn >= g_ast_count: + pn = -1 + break + if ast_kind(pn) == EXPR_PARAM: + break + pn = pn + 1 + an = ast_b(an) // next EXPR_ARG // Check generic constraints (if any) - gc := fi_generic_count(fi); - if gc > 0 { - gci : ., mut = 0; - loop { - if gci >= gc { break; } - constr_idx := fi * MAX_GENERICS + gci; - if constr_idx < g_generic_constr_count { - iface_ni := r64(g_generic_constr, constr_idx * 8); - if iface_ni >= 0 { - pname_ni := fi_generic_name(fi, gci); - concrete_ti : ., mut = -1; - hmi : ., mut = 0; - loop { - if hmi >= g_gen_map_count { break; } - if r64(g_gen_map_names, hmi * 8) == pname_ni { - concrete_ti = r64(g_gen_map_types, hmi * 8); - break; - } - hmi = hmi + 1; - } - if concrete_ti >= 0 { + gc := fi_generic_count(fi) + if gc > 0: + gci : ., mut = 0 + loop: + if gci >= gc: + break + constr_idx := fi * MAX_GENERICS + gci + if constr_idx < g_generic_constr_count: + iface_ni := r64(g_generic_constr, constr_idx * 8) + if iface_ni >= 0: + pname_ni := fi_generic_name(fi, gci) + concrete_ti : ., mut = -1 + hmi : ., mut = 0 + loop: + if hmi >= g_gen_map_count: + break + if r64(g_gen_map_names, hmi * 8) == pname_ni: + concrete_ti = r64(g_gen_map_types, hmi * 8) + break + hmi = hmi + 1 + if concrete_ti >= 0: // R2 P3 Task 5(Step 3):先走**本质轴**引擎判定(约束名 = 原生/已声明 // 类型名时 `ty_sub(实参项, 约束项)` + 反例);用户接口名 ⇒ 0 不在此直取 // (1 走提前返回;0/-1 落下方既有 check_iface 路径——**措辞/去重/rc 逐字 // 未动**,0 → 新措辞的诊断切换归 Task 6 Step 3;见 gen_constr_satisfied 注)。 - if gen_constr_satisfied(iface_ni, concrete_ti) == 0 { - if gen_constr_seen_add(call_node * MAX_GENERICS + gci) != 0 { - gen_constr_raise(concrete_ti, iface_ni, ast_line(call_node), ast_col(call_node)); - } - } else { - type_ni := get_type_name(concrete_ti); - if type_ni >= 0 { - ii := find_iface(iface_ni); - if ii >= 0 { - if !check_iface(type_ni, ii) { - check_error(EC_TG_BOUND, "Type '" + istr_get(type_ni) + "' does not satisfy interface '" + istr_get(iface_ni) + "'", ast_line(call_node), ast_col(call_node)); - } - } - } - } - } - } - } - gci = gci + 1; - } - } + if gen_constr_satisfied(iface_ni, concrete_ti) == 0: + if gen_constr_seen_add(call_node * MAX_GENERICS + gci) != 0: + gen_constr_raise(concrete_ti, iface_ni, ast_line(call_node), ast_col(call_node)) + else: + type_ni := get_type_name(concrete_ti) + if type_ni >= 0: + ii := find_iface(iface_ni) + if ii >= 0: + if !check_iface(type_ni, ii): + check_error(EC_TG_BOUND, "Type '" + istr_get(type_ni) + "' does not satisfy interface '" + istr_get(iface_ni) + "'", ast_line(call_node), ast_col(call_node)) + gci = gci + 1 // ─── R2 P3 Task 5(Step 4):调用点**泛型绑定**登记(monomorph 实例键类型项化)─── // 旧态 = 把「首个绑定的类型名」写进调用节点 int_val(唯一读者 `ir_gen.cr` 的 @@ -2150,407 +2186,421 @@ fn infer_gen_call(fi: int, call_node: int, first_arg: int, arg_count: int) -> in // ——parser 建 EXPR_CALL 时 iv 初值即 0,见 parser.cr 的 alloc_node(EXPR_CALL, …, 0, …))。 // ir_gen 据此生成规范实例键(inst_key_of_ti)并以 ti 型替换(monomorph.cr); // 绑定全缺(g_gen_map_count == 0,如 T 只出现在返回型)⇒ 不写(0 = 回落旧名字路径)。 - if g_gen_map_count > 0 { - gc_b := fi_generic_count(fi); - if gc_b > 0 { - bstart := g_gen_binds_count; - grow_gen_binds(bstart + 1 + gc_b); - w64(g_gen_binds, bstart * 8, gc_b); - gi_b : ., mut = 0; - loop { - if gi_b >= gc_b { break; } - pname_b := fi_generic_name(fi, gi_b); - tv_b : ., mut = -1; - hmi_b : ., mut = 0; - loop { - if hmi_b >= g_gen_map_count { break; } - if r64(g_gen_map_names, hmi_b * 8) == pname_b { - tv_b = r64(g_gen_map_types, hmi_b * 8); - break; - } - hmi_b = hmi_b + 1; - } - w64(g_gen_binds, (bstart + 1 + gi_b) * 8, tv_b); - gi_b = gi_b + 1; - } - g_gen_binds_count = bstart + 1 + gc_b; - ast_set_int_val(call_node, bstart + 1); - } - } + if g_gen_map_count > 0: + gc_b := fi_generic_count(fi) + if gc_b > 0: + bstart := g_gen_binds_count + grow_gen_binds(bstart + 1 + gc_b) + w64(g_gen_binds, bstart * 8, gc_b) + gi_b : ., mut = 0 + loop: + if gi_b >= gc_b: + break + pname_b := fi_generic_name(fi, gi_b) + tv_b : ., mut = -1 + hmi_b : ., mut = 0 + loop: + if hmi_b >= g_gen_map_count: + break + if r64(g_gen_map_names, hmi_b * 8) == pname_b: + tv_b = r64(g_gen_map_types, hmi_b * 8) + break + hmi_b = hmi_b + 1 + w64(g_gen_binds, (bstart + 1 + gi_b) * 8, tv_b) + gi_b = gi_b + 1 + g_gen_binds_count = bstart + 1 + gc_b + ast_set_int_val(call_node, bstart + 1) // Substitute return type - if g_gen_map_count > 0 && ret_type_node >= 0 { - resolved_ret := res_call_type(ret_type_node, fi); - return substitute_return_type(resolved_ret); - } + if g_gen_map_count > 0 && ret_type_node >= 0: + resolved_ret := res_call_type(ret_type_node, fi) + return substitute_return_type(resolved_ret) // Fallback: look up from symbol table - func_ni : ., mut = ast_a(fn_node); - si := find_gsym(func_ni); - if si >= 0 && sym_kind(si) == SYM_FN { - return sym_type(si); - } - return TI_UNIT; -} + func_ni : ., mut = ast_a(fn_node) + si := find_gsym(func_ni) + if si >= 0 && sym_kind(si) == SYM_FN: + return sym_type(si) + return TI_UNIT // --- check_func with generic param scope --- -fn check_func(fi: int) { - g_checker_current_fi = fi; +fn check_func(fi: int): + g_checker_current_fi = fi // Reset per-function borrow state - g_borrow_count = 0; g_borrow_cap = 0; - g_holder_count = 0; g_holder_cap = 0; - g_borrow_scope_depth = 0; g_borrow_scope_markers_cap = 0; - fn_node := fi_ast_node(fi); + g_borrow_count = 0 + g_borrow_cap = 0 + g_holder_count = 0 + g_holder_cap = 0 + g_borrow_scope_depth = 0 + g_borrow_scope_markers_cap = 0 + fn_node := fi_ast_node(fi) // Extern functions have no body to check — skip - if ast_kind(fn_node) == EXPR_EXTERN { return; } - name_idx := ast_a(fn_node); // EXPR_FN: a = name idx - first_param := ast_b(fn_node); // EXPR_FN: b = first param node - param_count := ast_c(fn_node); // EXPR_FN: c = param count - return_type := fi_return_type(fi); // EXPR_FN: raw return TY_*, safe from hotpatch encoding - body := ast_data(fn_node); // EXPR_FN: data = body node - - push_scope(); + if ast_kind(fn_node) == EXPR_EXTERN: + return + name_idx := ast_a(fn_node) // EXPR_FN: a = name idx + first_param := ast_b(fn_node) // EXPR_FN: b = first param node + param_count := ast_c(fn_node) // EXPR_FN: c = param count + return_type := fi_return_type(fi) // EXPR_FN: raw return TY_*, safe from hotpatch encoding + body := ast_data(fn_node) // EXPR_FN: data = body node + + push_scope() // Register generic params if any - if fi_generic_count(fi) > 0 { - gi : ., mut = 0; - loop { - if gi >= fi_generic_count(fi) { break; } - gname_idx := r64(g_funcs, fi * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gi * 8); - g_ti := alloc_type(TYP_GENERIC_PARAM, gname_idx, 0); - def_sym(gname_idx, SYM_TYPE, g_ti, -1); - gi = gi + 1; - } - } + if fi_generic_count(fi) > 0: + gi : ., mut = 0 + loop: + if gi >= fi_generic_count(fi): + break + gname_idx := r64(g_funcs, fi * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gi * 8) + g_ti := alloc_type(TYP_GENERIC_PARAM, gname_idx, 0) + def_sym(gname_idx, SYM_TYPE, g_ti, -1) + gi = gi + 1 // Add params to scope - pi : ., mut = 0; - pn : ., mut = first_param; - loop { - if pi >= param_count { break; } - if pn < 0 { break; } - pname_idx := ast_a(pn); // EXPR_PARAM: a = name idx - self_mode := ast_int_val(pn); // EXPR_PARAM: int_val = self mode (0=normal, 1=self, 2=&self, 3=&mut self, -1=variadic) - if self_mode == -1 { pi = pi + 1; pn = pn + 1; continue; } - ti : ., mut = TI_UNIT; - if self_mode == 0 { + pi : ., mut = 0 + pn : ., mut = first_param + loop: + if pi >= param_count: + break + if pn < 0: + break + pname_idx := ast_a(pn) // EXPR_PARAM: a = name idx + self_mode := ast_int_val(pn) // EXPR_PARAM: int_val = self mode (0=normal, 1=self, 2=&self, 3=&mut self, -1=variadic) + if self_mode == -1: + pi = pi + 1 + pn = pn + 1 + continue + ti : ., mut = TI_UNIT + if self_mode == 0: // Regular param: resolve using original type node if it's non-base (named/generic) - orig_type_node := ast_data(pn); - if orig_type_node >= 0 && ast_kind(orig_type_node) != 0 { - ti = res_type_node(orig_type_node); - } else { + orig_type_node := ast_data(pn) + if orig_type_node >= 0 && ast_kind(orig_type_node) != 0: + ti = res_type_node(orig_type_node) + else: // Base type: switch on type_val (TY_*) // P2b Task 6:值经单表 `ty_code_to_ti`;**本站点域 = {INT,DEX,BOOL,STRING,CHAR}** // (缺 UNIT/NEVER/7——UNIT 缺不等于行为差:映射值 = 初值 TI_UNIT;NEVER 差异载荷, // 探针 F7 实测:`fn f(b: never)` 的形参符号类型 = unit(@raw_int 报 TF07)) - ptype := ast_type_val(pn); - ptype_mapped := ty_code_to_ti(ptype); - if ptype_mapped >= 0 && ptype_mapped != TI_NEVER && ptype_mapped != TI_DYN { - ti = ptype_mapped; - } - } - } else { + ptype := ast_type_val(pn) + ptype_mapped := ty_code_to_ti(ptype) + if ptype_mapped >= 0 && ptype_mapped != TI_NEVER && ptype_mapped != TI_DYN: + ti = ptype_mapped + else: // Self param: derive struct type from mangled function name "Struct.method" - fn_name := istr_get(fi_name(fi)); - fn_len := str_len(fn_name); - dot_pos : ., mut = -1; - di : ., mut = 0; - loop { - if di >= fn_len { break; } - if load8(fn_name, di) == 46 { dot_pos = di; break; } // '.' = 46 - di = di + 1; - } - if dot_pos > 0 { - struct_name := str_sub(fn_name, 0, dot_pos); - struct_ni := str_intern(struct_name); - si := find_gsym(struct_ni); - if si >= 0 && sym_kind(si) == SYM_TYPE { - struct_ti := sym_type(si); - if self_mode == 1 { + fn_name := istr_get(fi_name(fi)) + fn_len := str_len(fn_name) + dot_pos : ., mut = -1 + di : ., mut = 0 + loop: + if di >= fn_len: + break + if load8(fn_name, di) == 46: + dot_pos = di + break + // '.' = 46 + di = di + 1 + if dot_pos > 0: + struct_name := str_sub(fn_name, 0, dot_pos) + struct_ni := str_intern(struct_name) + si := find_gsym(struct_ni) + if si >= 0 && sym_kind(si) == SYM_TYPE: + struct_ti := sym_type(si) + if self_mode == 1: // self by value - ti = struct_ti; - } else { + ti = struct_ti + else: // &self (mode 2) or &mut self (mode 3) - mut_flag := 0; - if self_mode == 3 { mut_flag = 1; } - ti = alloc_type(TYP_REF, struct_ti, mut_flag); - } - } - } - } - def_sym(pname_idx, SYM_PARAM, ti, -1); - pi = pi + 1; + mut_flag := 0 + if self_mode == 3: + mut_flag = 1 + ti = alloc_type(TYP_REF, struct_ti, mut_flag) + def_sym(pname_idx, SYM_PARAM, ti, -1) + pi = pi + 1 // Params are not contiguous — type nodes are allocated between them - pn = pn + 1; - loop { - if pn >= g_ast_count { break; } - if ast_kind(pn) == EXPR_PARAM { break; } - pn = pn + 1; - } - } + pn = pn + 1 + loop: + if pn >= g_ast_count: + break + if ast_kind(pn) == EXPR_PARAM: + break + pn = pn + 1 // Check body - if body >= 0 { - body_ti := infer_expr(body); - ret_ti : ., mut = TI_UNIT; + if body >= 0: + body_ti := infer_expr(body) + ret_ti : ., mut = TI_UNIT // First check for named type via the stored type node (kind != 0) - type_node := ast_type_val(fn_node); - if type_node > 0 && ast_kind(type_node) != 0 { - ret_ti = res_type_node(type_node); - } else { + type_node := ast_type_val(fn_node) + if type_node > 0 && ast_kind(type_node) != 0: + ret_ti = res_type_node(type_node) + else: // P2b Task 6:值经单表 `ty_code_to_ti`;**本站点域 = {INT..CHAR}**(含 NEVER;缺 7—— // 探针 F11:`fn f() -> dyn` 的体检查用 unit 兜底,与 F10 的 never 格互不干扰) - ret_ti_mapped := ty_code_to_ti(return_type); - if ret_ti_mapped >= 0 && ret_ti_mapped != TI_DYN { ret_ti = ret_ti_mapped; } - } - compat := type_compat_strict(body_ti, ret_ti); + ret_ti_mapped := ty_code_to_ti(return_type) + if ret_ti_mapped >= 0 && ret_ti_mapped != TI_DYN: + ret_ti = ret_ti_mapped + compat := type_compat_strict(body_ti, ret_ti) // 落空分析(TF01 收口,见 stmt_cannot_fall_through 头注):体确定不能落空(如以 // 无 break 的 loop 收尾)⇒ 「块类型 = 末语句类型」推出的 unit 不是缺返回值的证据, // 等价于 never 格(与下行既有 TI_NEVER 豁免同路)。 - if compat != 1 && body_ti != TI_NEVER && stmt_cannot_fall_through(body) == 0 { + if compat != 1 && body_ti != TI_NEVER && stmt_cannot_fall_through(body) == 0: // Skip check if return type is generic param (can't verify at declaration) // Skip check for flow functions (yield instead of return) - is_flow_fn : ., mut = 0; - if body >= 0 && scan_for_yield(body) != 0 { is_flow_fn = 1; } - if !is_flow_fn && get_type_kind(ret_ti) != TYP_GENERIC_PARAM { - diag_type_incompatible(compat, EC_TF_RETURN, "Function return type mismatch", ast_line(fn_node), ast_col(fn_node)); - } - } - } + is_flow_fn : ., mut = 0 + if body >= 0 && scan_for_yield(body) != 0: + is_flow_fn = 1 + if !is_flow_fn && get_type_kind(ret_ti) != TYP_GENERIC_PARAM: + diag_type_incompatible(compat, EC_TF_RETURN, "Function return type mismatch", ast_line(fn_node), ast_col(fn_node)) // 批 6(T3):规约标注面——**在 pop_scope 之前**(形参仍在作用域内,`#check(a > 0)` 才能定型) - spec_check_func(fn_node, return_type); - pop_scope(); -} + spec_check_func(fn_node, return_type) + pop_scope() // 批 6(T3):**每函数标注检查** —— bool 型 + `#ensure` 的 `result` 域 + C1 子集(禁调用)。 // 时点 = `check_func` 尾部(形参已入作用域);`result` 用**嵌套作用域**绑定 ⇒ 不泄进函数体。 // 三态纪律:`infer_expr` 给不出 bool(含未覆盖面)⇒ 一律 **V05 硬错**(**不得**「未知当通过」)。 // 域检查的第二重来源 = `infer_expr` 对未定义名的既有诊断(N06/N01,build 面非豁免 ⇒ 阻断)。 -fn spec_check_func(fn_node: int, return_type: int) { - if g_spec_count == 0 { return; } - hit : ., mut = 0; - i : ., mut = 0; - loop { - if i >= g_spec_count { break; } - if spec_fnode(i) == fn_node { hit = 1; break; } - i = i + 1; - } - if hit == 0 { return; } - push_scope(); +fn spec_check_func(fn_node: int, return_type: int): + if g_spec_count == 0: + return + hit : ., mut = 0 + i : ., mut = 0 + loop: + if i >= g_spec_count: + break + if spec_fnode(i) == fn_node: + hit = 1 + break + i = i + 1 + if hit == 0: + return + push_scope() // `#ensure` 的 `result` 绑定(裁-S8):与既有作用域名冲突 ⇒ **硬错**(不静默择一、不静默遮蔽) // ⚠ **零足迹纪律**:`str_intern("result")` **只能在确需绑定时调用**——无条件调用会让 // STR 段凭空 +10B(T3 首轮被 Δ 判据当场抓住:d0 用例期望 Δ=0、实测 10;根因即此)。 - ri : ., mut = -1; - j : ., mut = 0; - loop { - if j >= g_spec_count { break; } - if spec_fnode(j) == fn_node && spec_kind(j) == 1 { ri = j; break; } - j = j + 1; - } - if ri >= 0 { - res_ni := str_intern("result"); - if find_sym(res_ni) >= 0 { - spec_set_status(ri, SPEC_ST_RED); + ri : ., mut = -1 + j : ., mut = 0 + loop: + if j >= g_spec_count: + break + if spec_fnode(j) == fn_node && spec_kind(j) == 1: + ri = j + break + j = j + 1 + if ri >= 0: + res_ni := str_intern("result") + if find_sym(res_ni) >= 0: + spec_set_status(ri, SPEC_ST_RED) check_error(EC_V_RESULT_SHADOW, "'result' is already bound in this scope (#ensure binding would shadow it)", - spec_line(ri), spec_col(ri)); - } else { - def_sym(res_ni, SYM_LOCAL, ty_code_to_ti(return_type), -1); - } - } + spec_line(ri), spec_col(ri)) + else: + def_sym(res_ni, SYM_LOCAL, ty_code_to_ti(return_type), -1) // 逐条:① 禁调用(裁-V5 的 C1 子集;避开纯度时序坑——本批**未**解决该时序,只绕开) // ② 表达式必须恰为 bool - k : ., mut = 0; - loop { - if k >= g_spec_count { break; } - if spec_fnode(k) == fn_node { - if spec_has_call(spec_expr(k)) != 0 { - spec_set_status(k, SPEC_ST_RED); + k : ., mut = 0 + loop: + if k >= g_spec_count: + break + if spec_fnode(k) == fn_node: + if spec_has_call(spec_expr(k)) != 0: + spec_set_status(k, SPEC_ST_RED) check_error(EC_V_CALL_BANNED, "annotation expression must not contain calls (C1 subset)", - spec_line(k), spec_col(k)); - } else { - t := infer_expr(spec_expr(k)); - if t != TI_BOOL { - spec_set_status(k, SPEC_ST_RED); + spec_line(k), spec_col(k)) + else: + t := infer_expr(spec_expr(k)) + if t != TI_BOOL: + spec_set_status(k, SPEC_ST_RED) check_error(EC_V_NOT_BOOL, "annotation expression must be bool", - spec_line(k), spec_col(k)); - } - } - } - k = k + 1; - } - pop_scope(); -} + spec_line(k), spec_col(k)) + k = k + 1 + pop_scope() // 标注表达式的**调用扫描**(C1 子集:禁调用)。只走 C1 允许的节点形(字面量/标识符/一元/二元), // 遇到调用即返回 1;未知节点形 = 不判定(返回 0,由 bool 型那一关兜住)。 -fn spec_has_call(e: int) -> int { - if e < 0 { return 0; } - k := ast_kind(e); - if k == EXPR_CALL { return 1; } - if k == EXPR_BINARY { - if spec_has_call(ast_a(e)) != 0 { return 1; } - return spec_has_call(ast_b(e)); - } - if k == EXPR_UNARY { return spec_has_call(ast_a(e)); } - return 0; -} - -fn check_impl_for() { - pi : ., mut = 0; - loop { - if pi >= g_impl_for_count { break; } - iface_ni := r64(g_impl_for, pi * 16); - type_ni := r64(g_impl_for, pi * 16 + 8); +fn spec_has_call(e: int) -> int: + if e < 0: + return 0 + k := ast_kind(e) + if k == EXPR_CALL: + return 1 + if k == EXPR_BINARY: + if spec_has_call(ast_a(e)) != 0: + return 1 + return spec_has_call(ast_b(e)) + if k == EXPR_UNARY: + return spec_has_call(ast_a(e)) + return 0 + +fn check_impl_for(): + pi : ., mut = 0 + loop: + if pi >= g_impl_for_count: + break + iface_ni := r64(g_impl_for, pi * 16) + type_ni := r64(g_impl_for, pi * 16 + 8) // Find interface by name - ii := find_iface(iface_ni); - if ii < 0 { - iface_name := istr_get(iface_ni); - check_error(EC_N_UNDEFINED, "Undefined interface '" + iface_name + "'", 0, 0); - pi = pi + 1; - continue; - } - method_count := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT); - mi : ., mut = 0; - loop { - if mi >= method_count { break; } - mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD; - method_ni := r64(g_ifaces, mbase + OFF_IFM_NAME); - method_pc := r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT); - method_name := istr_get(method_ni); - iface_name2 := istr_get(iface_ni); + ii := find_iface(iface_ni) + if ii < 0: + iface_name := istr_get(iface_ni) + check_error(EC_N_UNDEFINED, "Undefined interface '" + iface_name + "'", 0, 0) + pi = pi + 1 + continue + method_count := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT) + mi : ., mut = 0 + loop: + if mi >= method_count: + break + mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD + method_ni := r64(g_ifaces, mbase + OFF_IFM_NAME) + method_pc := r64(g_ifaces, mbase + OFF_IFM_PARAM_COUNT) + method_name := istr_get(method_ni) + iface_name2 := istr_get(iface_ni) // R2 P3b Task 6(Step 3,mangling 退役):方法解析 = **表查询** // (`g_methods` 三元组 → 函数名 ni → 函数行),不再拼 "Type.method" 串。 - func_ni := iface_find_method(type_ni, method_ni); - fi : ., mut = -1; - if func_ni >= 0 { fi = find_func(func_ni); } - if fi < 0 { - check_error(EC_TF_METHOD_NOT_FOUND, "Impl missing method '" + method_name + "' for interface '" + iface_name2 + "'", 0, 0); - mi = mi + 1; - continue; - } + func_ni := iface_find_method(type_ni, method_ni) + fi : ., mut = -1 + if func_ni >= 0: + fi = find_func(func_ni) + if fi < 0: + check_error(EC_TF_METHOD_NOT_FOUND, "Impl missing method '" + method_name + "' for interface '" + iface_name2 + "'", 0, 0) + mi = mi + 1 + continue // 接收者模式(调用约定维度;旧态两侧皆码 0 ⇒ 不可比 ⇒ 本任务起显式比较) - if sh_iface_self_mode(ii, mi) != sh_func_self_mode(fi) { - check_error(EC_TF_METHOD_ARG_TYP, "Param 1 type mismatch for method '" + method_name + "' in interface '" + iface_name2 + "'", 0, 0); - } + if sh_iface_self_mode(ii, mi) != sh_func_self_mode(fi): + check_error(EC_TF_METHOD_ARG_TYP, "Param 1 type mismatch for method '" + method_name + "' in interface '" + iface_name2 + "'", 0, 0) // 参数计数 - actual_pc := fi_param_count(fi); - if actual_pc != method_pc { - check_error(EC_TF_METHOD_ARG_CNT, "Param count mismatch for method '" + method_name + "': expected " + int_str(method_pc) + " got " + int_str(actual_pc), 0, 0); - } + actual_pc := fi_param_count(fi) + if actual_pc != method_pc: + check_error(EC_TF_METHOD_ARG_CNT, "Param count mismatch for method '" + method_name + "': expected " + int_str(method_pc) + " got " + int_str(actual_pc), 0, 0) // 逐参类型(**签名项**比较:N 不入项 / 泛型应用展开 / 命名行按名 —— 取代旧裸码相等) - pti : ., mut = 0; - loop { - if pti >= method_pc || pti >= MAX_IFACE_METHOD_PARAMS { break; } - apt := sh_func_sig_param_term(fi, pti); - ept := sh_iface_sig_param_term(ii, mi, pti); - if apt >= 0 && ept >= 0 { + pti : ., mut = 0 + loop: + if pti >= method_pc || pti >= MAX_IFACE_METHOD_PARAMS: + break + apt := sh_func_sig_param_term(fi, pti) + ept := sh_iface_sig_param_term(ii, mi, pti) + if apt >= 0 && ept >= 0: // 判定 = 引擎的不变槽结构比较原语(0/1 全域;理由见 type_engine.cr 的 // iface_user_satisfies_ii 注——ty_sub 会把「确定不同」上抛为 -1 = 未覆盖面) - if tt_list_same(apt, ept) != 1 { - pnum_str := int_str(pti + 1); - check_error(EC_TF_METHOD_ARG_TYP, "Param " + pnum_str + " type mismatch for method '" + method_name + "' in interface '" + iface_name2 + "'", 0, 0); - } - } - pti = pti + 1; - } + if tt_list_same(apt, ept) != 1: + pnum_str := int_str(pti + 1) + check_error(EC_TF_METHOD_ARG_TYP, "Param " + pnum_str + " type mismatch for method '" + method_name + "' in interface '" + iface_name2 + "'", 0, 0) + pti = pti + 1 // 返回类型(签名项比较;同上) - art := sh_func_sig_ret_term(fi); - ert := sh_iface_sig_ret_term(ii, mi); - if art >= 0 && ert >= 0 { - if tt_list_same(art, ert) != 1 { - check_error(EC_TF_RETURN, "Return type mismatch for method '" + method_name + "' in interface '" + iface_name2 + "'", 0, 0); - } - } - mi = mi + 1; - } - pi = pi + 1; - } -} - -fn check_global_let(node: int) { - val_node := ast_c(node); // EXPR_LET: c = value - type_node := ast_b(node); // EXPR_LET: b = 注解类型节点(-1 = 无) - val_ti := TI_UNIT; - if val_node >= 0 { - val_ti = infer_expr(val_node); - } + art := sh_func_sig_ret_term(fi) + ert := sh_iface_sig_ret_term(ii, mi) + if art >= 0 && ert >= 0: + if tt_list_same(art, ert) != 1: + check_error(EC_TF_RETURN, "Return type mismatch for method '" + method_name + "' in interface '" + iface_name2 + "'", 0, 0) + mi = mi + 1 + pi = pi + 1 + +fn check_global_let(node: int): + val_node := ast_c(node) // EXPR_LET: c = value + type_node := ast_b(node) // EXPR_LET: b = 注解类型节点(-1 = 无) + val_ti := TI_UNIT + if val_node >= 0: + val_ti = infer_expr(val_node) // R2 P5 Task 6(TODO #2026-09-11-14):全局初始化器的值/注解兼容检查(局部站点同款; // 全局符号类型在注册趟(check_global_lets)即取注解行 ⇒ 不查同样静默错产物)。 - ti := val_ti; - if type_node >= 0 { ti = res_type_node(type_node); } - check_let_annot_compat(node, val_node, val_ti, ti); -} + ti := val_ti + if type_node >= 0: + ti = res_type_node(type_node) + check_let_annot_compat(node, val_node, val_ti, ti) // --- Dynamic type set tracking --- -fn grow_dyn_type_sets(needed: int) { - if needed < g_dyn_type_set_cap { return; } - nc : ., mut = g_dyn_type_set_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_dyn_type_sets, g_dyn_type_set_cap * 8, nb); - g_dyn_type_sets = nb; g_dyn_type_set_cap = nc; -} - -fn dyn_set_type(var_idx: int, ti: int) { - grow_dyn_type_sets(var_idx + 1); - old_bits := r64(g_dyn_type_sets, var_idx * 8); - bit : ., mut = 1; - if ti >= 0 && ti < 64 { - bit = 1; shl := ti; loop { if shl <= 0 { break; } bit = bit * 2; shl = shl - 1; } - } - w64(g_dyn_type_sets, var_idx * 8, old_bits + bit); - if var_idx >= g_dyn_type_set_count { g_dyn_type_set_count = var_idx + 1; } -} - -fn dyn_has_type(var_idx: int, ti: int) -> int { - if var_idx < 0 || var_idx >= g_dyn_type_set_count { return 0; } - set := r64(g_dyn_type_sets, var_idx * 8); - bit : ., mut = 1; - if ti >= 0 && ti < 64 { - bit = 1; shl := ti; loop { if shl <= 0 { break; } bit = bit * 2; shl = shl - 1; } - } - if (set / bit) % 2 != 0 { return 1; } - return 0; -} - -fn union_bitmaps(a: int, b: int) -> int { - r : ., mut = 0; - pos : ., mut = 0; - loop { - if pos >= 64 { break; } - bit : ., mut = 1; - shl := pos; - loop { if shl <= 0 { break; } bit = bit * 2; shl = shl - 1; } - if (a / bit) % 2 != 0 || (b / bit) % 2 != 0 { r = r + bit; } - pos = pos + 1; - } - return r; -} - -fn validate_dyn_method(si: int, method_ni: int, line: int, col: int) { - if si < 0 || si >= g_dyn_type_set_count { return; } - set := r64(g_dyn_type_sets, si * 8); - if set == 0 { return; } - ti : ., mut = 0; - loop { - if ti >= g_type_count { break; } - if ti >= 64 { break; } - bit : ., mut = 1; - shl := ti; - loop { if shl <= 0 { break; } bit = bit * 2; shl = shl - 1; } - if (set / bit) % 2 != 0 { - type_ni := get_type_name(ti); - if type_ni >= 0 { - if !type_has_method(type_ni, method_ni) { - tname := istr_get(type_ni); - mname := istr_get(method_ni); - check_error(EC_N_METHOD, "dyn: method '" + mname + "' not found on type '" + tname + "'", line, col); - } - } - } - ti = ti + 1; - } -} +fn grow_dyn_type_sets(needed: int): + if needed < g_dyn_type_set_cap: + return + nc : ., mut = g_dyn_type_set_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_dyn_type_sets, g_dyn_type_set_cap * 8, nb) + g_dyn_type_sets = nb + g_dyn_type_set_cap = nc + +fn dyn_set_type(var_idx: int, ti: int): + grow_dyn_type_sets(var_idx + 1) + old_bits := r64(g_dyn_type_sets, var_idx * 8) + bit : ., mut = 1 + if ti >= 0 && ti < 64: + bit = 1 + shl := ti + loop: + if shl <= 0: + break + bit = bit * 2 + shl = shl - 1 + w64(g_dyn_type_sets, var_idx * 8, old_bits + bit) + if var_idx >= g_dyn_type_set_count: + g_dyn_type_set_count = var_idx + 1 + +fn dyn_has_type(var_idx: int, ti: int) -> int: + if var_idx < 0 || var_idx >= g_dyn_type_set_count: + return 0 + set := r64(g_dyn_type_sets, var_idx * 8) + bit : ., mut = 1 + if ti >= 0 && ti < 64: + bit = 1 + shl := ti + loop: + if shl <= 0: + break + bit = bit * 2 + shl = shl - 1 + if (set / bit) % 2 != 0: + return 1 + return 0 + +fn union_bitmaps(a: int, b: int) -> int: + r : ., mut = 0 + pos : ., mut = 0 + loop: + if pos >= 64: + break + bit : ., mut = 1 + shl := pos + loop: + if shl <= 0: + break + bit = bit * 2 + shl = shl - 1 + if (a / bit) % 2 != 0 || (b / bit) % 2 != 0: + r = r + bit + pos = pos + 1 + return r + +fn validate_dyn_method(si: int, method_ni: int, line: int, col: int): + if si < 0 || si >= g_dyn_type_set_count: + return + set := r64(g_dyn_type_sets, si * 8) + if set == 0: + return + ti : ., mut = 0 + loop: + if ti >= g_type_count: + break + if ti >= 64: + break + bit : ., mut = 1 + shl := ti + loop: + if shl <= 0: + break + bit = bit * 2 + shl = shl - 1 + if (set / bit) % 2 != 0: + type_ni := get_type_name(ti) + if type_ni >= 0: + if !type_has_method(type_ni, method_ni): + tname := istr_get(type_ni) + mname := istr_get(method_ni) + check_error(EC_N_METHOD, "dyn: method '" + mname + "' not found on type '" + tname + "'", line, col) + ti = ti + 1 // --- Type inference --- @@ -2564,12 +2614,13 @@ fn validate_dyn_method(si: int, method_ni: int, line: int, col: int) { // 主病灶)· `:2824`(runtime builtin)· `:2831`(EC_N_FUNC 未定义函数);函数尾的 // `func_ni < 0` 路径本就用同一循环(已改为调用本函数,单一真源)。 // 注:泛型直调(`:2791` → `infer_gen_call`)内部**已推**(`:2020`/`:2023`),无需在此重复。 -fn infer_call_args(first_arg: int) { - an : ., mut = first_arg; - loop { - if an < 0 { break; } - anode := ast_a(an); - infer_expr(anode); +fn infer_call_args(first_arg: int): + an : ., mut = first_arg + loop: + if an < 0: + break + anode := ast_a(an) + infer_expr(anode) // (b) fail-closed 护栏(维护者裁-ARG-2;TODO #2026-09-16-31):实参位的调用若是 `EXPR_FIELD` // 被调而 `ast_data` 仍为 0 ⇒ **被调名从未被回填**(模块/方法分支没跑到)⇒ ir_gen 会读出 // 伪函数名(`istr_get(0)` = 文件首个 interned 串,有 `import` 时恰为 "import")⇒ 后端 @@ -2578,75 +2629,83 @@ fn infer_call_args(first_arg: int) { // 之后、ir_gen 之前 ⇒ 在 checker 侧报错才被该闸门覆盖),**绝不静默产坏产物**。 // **正常路径下恒不触发**((a) 已让所有已解析路径推实参;dyn 方法调用的名字由 dyn 分支 // 回填,实测 `dyn_dispatch` 正常 ⇒ 不误伤)——其价值 = **防未来同类回归**。 - if anode >= 0 { - if ast_kind(anode) == EXPR_CALL { - fnode := ast_a(anode); - if fnode >= 0 { - if ast_kind(fnode) == EXPR_FIELD { - if ast_data(anode) <= 0 { - check_error(EC_N_FUNC, "Unresolved module/method call in argument position", ast_line(anode), ast_col(anode)); - } - } - } - } - } - an = ast_b(an); - } -} + if anode >= 0: + if ast_kind(anode) == EXPR_CALL: + fnode := ast_a(anode) + if fnode >= 0: + if ast_kind(fnode) == EXPR_FIELD: + if ast_data(anode) <= 0: + check_error(EC_N_FUNC, "Unresolved module/method call in argument position", ast_line(anode), ast_col(anode)) + an = ast_b(an) // bool 洞的转换节点:改写为 `bool_str(x)` 调用(`fmt.cr`)。抽成函数是为了让 `infer_expr` 的 // 分支保持单行、便于审计(转换表:string 恒等 · int→int_str · bool→bool_str · 其它 P028)。 -fn interp_bool_node(node: int, inner: int) -> int { - callee := alloc_node(EXPR_IDENT, 0, 0, 0, str_intern("bool_str"), 0, 0, ast_line(node), ast_col(node)); - wrapper := alloc_node(EXPR_NONE, inner, -1, 0, 0, 0, 0, ast_line(node), ast_col(node)); - ast_set_kind(node, EXPR_CALL); - ast_set_a(node, callee); - ast_set_b(node, wrapper); - ast_set_c(node, 1); - ast_set_data(node, 0); - ast_set_type_val(node, TY_STRING); - return TI_STR; -} +fn interp_bool_node(node: int, inner: int) -> int: + callee := alloc_node(EXPR_IDENT, 0, 0, 0, str_intern("bool_str"), 0, 0, ast_line(node), ast_col(node)) + wrapper := alloc_node(EXPR_NONE, inner, -1, 0, 0, 0, 0, ast_line(node), ast_col(node)) + ast_set_kind(node, EXPR_CALL) + ast_set_a(node, callee) + ast_set_b(node, wrapper) + ast_set_c(node, 1) + ast_set_data(node, 0) + ast_set_type_val(node, TY_STRING) + return TI_STR // S1P 测量辅助(**只在 CORE_S1P=1 路径被调用**):从 `g_source` 取第 line 行的前 48 字符。 // 目的 = 把「合并流坐标」映射回**源文本**(跨文件定位:本仓的 S1P 打点原本只有合并流行号, // 反推文件归属两种假设均对不上)。**只用于测量**:默认位不被调用 ⇒ 产物零足迹不受影响; // `str_sub` 走 alloc(**不 intern**)⇒ 不污染 STR 段。 -fn s1p_src_frag(line: int) -> string { - p : ., mut = 0; ln : ., mut = 1; start : ., mut = -1; end : ., mut = -1; - loop { - if p >= g_source_len { break; } - c := load8(g_source, p); - if ln == line && start < 0 { start = p; } - if start >= 0 && c == 10 { end = p; break; } - if c == 10 { ln = ln + 1; } - p = p + 1; - } - if start < 0 { return ""; } - if end < 0 { end = p; } - if end - start > 48 { end = start + 48; } - return str_sub(g_source, start, end - start); -} +fn s1p_src_frag(line: int) -> string: + p : ., mut = 0 + ln : ., mut = 1 + start : ., mut = -1 + end : ., mut = -1 + loop: + if p >= g_source_len: + break + c := load8(g_source, p) + if ln == line && start < 0: + start = p + if start >= 0 && c == 10: + end = p + break + if c == 10: + ln = ln + 1 + p = p + 1 + if start < 0: + return "" + if end < 0: + end = p + if end - start > 48: + end = start + 48 + return str_sub(g_source, start, end - start) // ─── 批 8(甲)刀 2:S1P 台账三件(门 / 单实参判定 / 枚举环)——与 `s1p_arg_ring` 同一契约 ─── // 门(懒初始化 + `CORE_S1P`):**所有类型引擎调用都必须在门后**(默认位一步不执行 = 零足迹)。 -fn s1p_gate() -> int { - if g_s1p_seen == 0 { +fn s1p_gate() -> int: + if g_s1p_seen == 0: // ⚠ **哨兵必须用零值**(详情见 `s1p_arg_ring` 内注 + TODO #2026-09-18-12) - g_s1p_seen = 1; - ev2 := get_env("CORE_S1P"); - if str_len(ev2) > 0 && ev2 == "1" { g_s1p_on = 1; } else { g_s1p_on = 0; } - } - return g_s1p_on; -} + g_s1p_seen = 1 + ev2 := get_env("CORE_S1P") + if str_len(ev2) > 0 && ev2 == "1": + g_s1p_on = 1 + else: + g_s1p_on = 0 + return g_s1p_on // 单实参:跳过规则(②`None`→`T?` / ③字面量多态 / 形参型不可得 / 未推断出形)⇒ 否则 `unify_types` // 判定 ⇒ 失配则**只打数值**台账一行(格式见 `s1p_arg_ring`;`call_ni` = 被调名 intern 下标)。 -fn s1p_arg_one(arg_n: int, pi2: int, pti: int, ati: int, is_ext: int, call_ni: int) { - skip : ., mut = 0; - if pti < 0 { skip = 1; } // 形参型不可得 - if ati == TI_UNIT { skip = 1; } // 未推断出形 - if ast_kind(arg_n) == EXPR_INT || ast_kind(arg_n) == EXPR_DEX { skip = 1; } // ③ 字面量多态 +fn s1p_arg_one(arg_n: int, pi2: int, pti: int, ati: int, is_ext: int, call_ni: int): + skip : ., mut = 0 + if pti < 0: + skip = 1 + // 形参型不可得 + if ati == TI_UNIT: + skip = 1 + // 未推断出形 + if ast_kind(arg_n) == EXPR_INT || ast_kind(arg_n) == EXPR_DEX: + skip = 1 + // ③ 字面量多态 // ─── 哨兵/不可判定值族(2026-09-19 小刀):**未知 ≠ 异型** ─────────────────────── // 三条**同族但分属两个空间**的判定——⚠ **不得互换**(见下): // · `ati == TI_NEVER` —— 判**实参类型项下标**:类型**不可得**(未解析名等)⇒ 不是「不匹配」; @@ -2657,67 +2716,70 @@ fn s1p_arg_one(arg_n: int, pi2: int, pti: int, ati: int, is_ext: int, call_ni: i // 写成 `get_type_kind(ati) == TI_DYN`)**能编过、且可能蒙对一部分用例**(两条 skip 在同一屏、 // 都让同一批输入不再报)⇒ **判据必须能区分「空间写错」与「规则缺一条」**:见 // `tests/selfhost/test_s1p_sentinel_skips.py` 的**逐条突变自证**(本刀硬性要求)。 - if ati == TI_NEVER { skip = 1; } // 类型不可得 ⇒ 未知 ≠ 异型 - if ati == TI_DYN { skip = 1; } // dyn = ⊤ + if ati == TI_NEVER: + skip = 1 + // 类型不可得 ⇒ 未知 ≠ 异型 + if ati == TI_DYN: + skip = 1 + // dyn = ⊤ // 前缀条 `ati > TI_DEX_S` **必需**:类型表下标 0..8 = 标量/占位 ⇒ 直接查表会读到**占位行的 kind** // (**假阳性来源**;同 `@raw_int` 分支 `:4217-4218` 同款护栏)。泛型形参行下标 ≥ 10。 - if ati > TI_DEX_S && get_type_kind(ati) == TYP_GENERIC_PARAM { skip = 1; } // 泛型形参:声明期不可验证 - if ast_kind(arg_n) == EXPR_ENUM_CONSTRUCTOR { - nm2 := istr_get(ast_a(arg_n)); - if str_eq(nm2, "None") != 0 { + if ati > TI_DEX_S && get_type_kind(ati) == TYP_GENERIC_PARAM: + skip = 1 + // 泛型形参:声明期不可验证 + if ast_kind(arg_n) == EXPR_ENUM_CONSTRUCTOR: + nm2 := istr_get(ast_a(arg_n)) + if str_eq(nm2, "None") != 0: // ② None→T?(**不用 `ti_is_optional`**:该符号不在 corelsp 单元 ⇒ 本文件为 // corec+corelsp **共享**单元,只能用两侧皆有的符号) - if pti >= 0 && get_type_kind(pti) == TYP_OPTIONAL { skip = 1; } - } - } - if skip == 0 { - if !unify_types(pti, ati) { + if pti >= 0 && get_type_kind(pti) == TYP_OPTIONAL: + skip = 1 + if skip == 0: + if !unify_types(pti, ati): println(int_str(9917 + is_ext) + " " + int_str(ast_line(arg_n)) - + " " + int_str(ast_col(arg_n)) - + " " + int_str(pi2) - + " " + int_str(pti) + " " + int_str(ati) - + " " + istr_get(call_ni) - + " @@ " + s1p_src_frag(ast_line(arg_n))); - } - } -} + + " " + int_str(ast_col(arg_n)) + + " " + int_str(pi2) + + " " + int_str(pti) + " " + int_str(ati) + + " " + istr_get(call_ni) + + " @@ " + s1p_src_frag(ast_line(arg_n))) // 枚举构造器环:形参型来自**枚举声明**的变体载荷(变体**不注册 FuncInfo** ⇒ 不能用 `s1p_arg_ring`)。 // 载荷类型节点 = `ei_variant_type_node(enum_i, vi, k)` ⇒ `res_type_node` 取类型项(**门后**执行)。 -fn s1p_enum_ring(name_idx: int, first_arg: int, arg_count: int) { - if name_idx < 0 { return; } - if s1p_gate() == 0 { return; } - i : ., mut = 0; - loop { - if i >= g_enum_count { break; } - vi : ., mut = 0; - loop { - if vi >= ei_variant_count(i) { break; } - if ei_variant_name(i, vi) == name_idx { - tc := ei_variant_type_count(i, vi); - if arg_count == tc { - an2 : ., mut = first_arg; - k2 : ., mut = 0; - loop { - if an2 < 0 { break; } - if k2 >= tc { break; } - arg_n := ast_a(an2); - ati := infer_expr(arg_n); - tn := ei_variant_type_node(i, vi, k2); - pti : ., mut = -1; - if tn >= 0 { pti = res_type_node(tn); } - s1p_arg_one(arg_n, k2, pti, ati, 0, name_idx); - k2 = k2 + 1; - an2 = ast_b(an2); - } - } - return; - } - vi = vi + 1; - } - i = i + 1; - } -} +fn s1p_enum_ring(name_idx: int, first_arg: int, arg_count: int): + if name_idx < 0: + return + if s1p_gate() == 0: + return + i : ., mut = 0 + loop: + if i >= g_enum_count: + break + vi : ., mut = 0 + loop: + if vi >= ei_variant_count(i): + break + if ei_variant_name(i, vi) == name_idx: + tc := ei_variant_type_count(i, vi) + if arg_count == tc: + an2 : ., mut = first_arg + k2 : ., mut = 0 + loop: + if an2 < 0: + break + if k2 >= tc: + break + arg_n := ast_a(an2) + ati := infer_expr(arg_n) + tn := ei_variant_type_node(i, vi, k2) + pti : ., mut = -1 + if tn >= 0: + pti = res_type_node(tn) + s1p_arg_one(arg_n, k2, pti, ati, 0, name_idx) + k2 = k2 + 1 + an2 = ast_b(an2) + return + vi = vi + 1 + i = i + 1 // ─── 批 8(甲)刀 2:S1P 台账环(**可复用**——四调用形态共用一份,照 (乙) 批 `dex_align_call_args` 先例)─── // 契约: @@ -2733,66 +2795,86 @@ fn s1p_enum_ring(name_idx: int, first_arg: int, arg_count: int) { // `EXPR_FIELD` 的被调对象位)⇒ `param_skip` 指明「形参链首需跳过的接收者位数」: // **直调/extern/模块限定 = 0**(形参链无 self)· **方法 = 1**(形参链含 self,与实参链对齐时跳过)。 // 元数口径(照旧):`arg_count + param_skip != fi_param_count(fi)` ⇒ **静默跳过**(不打点、不据此判定)。 -fn s1p_arg_ring(fi: int, first_arg: int, arg_count: int, param_skip: int, is_ext: int) { - if fi < 0 { return; } - fnode := fi_ast_node(fi); - if fnode < 0 { return; } - fn_kind : ., mut = 0; - if ast_kind(fnode) == EXPR_FN { fn_kind = 1; } - if fn_kind == 0 && is_ext == 0 { return; } - pc := fi_param_count(fi); - if arg_count + param_skip != pc { return; } - pn2 : ., mut = ast_b(fnode); +fn s1p_arg_ring(fi: int, first_arg: int, arg_count: int, param_skip: int, is_ext: int): + if fi < 0: + return + fnode := fi_ast_node(fi) + if fnode < 0: + return + fn_kind : ., mut = 0 + if ast_kind(fnode) == EXPR_FN: + fn_kind = 1 + if fn_kind == 0 && is_ext == 0: + return + pc := fi_param_count(fi) + if arg_count + param_skip != pc: + return + pn2 : ., mut = ast_b(fnode) // 跳过形参链首的接收者位(`param_skip` 个 EXPR_PARAM;按「下一个 EXPR_PARAM」游标语义——与 parser // 的分配布局一致:形参的类型子树先于该形参节点分配 ⇒ 形参之间不连续,见 F4 形参链导航修复注) - k : ., mut = 0; - loop { - if k >= param_skip { break; } - if pn2 < 0 { return; } - pn2 = pn2 + 1; - loop { if pn2 >= g_ast_count { pn2 = -1; break; } - if ast_kind(pn2) == EXPR_PARAM { break; } pn2 = pn2 + 1; } - k = k + 1; - } - pi2 : ., mut = param_skip; - an2 : ., mut = first_arg; - loop { - if an2 < 0 { break; } - if pn2 < 0 { break; } - if pi2 >= pc { break; } - if g_s1p_seen == 0 { + k : ., mut = 0 + loop: + if k >= param_skip: + break + if pn2 < 0: + return + pn2 = pn2 + 1 + loop: + if pn2 >= g_ast_count: + pn2 = -1 + break + if ast_kind(pn2) == EXPR_PARAM: + break + pn2 = pn2 + 1 + k = k + 1 + pi2 : ., mut = param_skip + an2 : ., mut = first_arg + loop: + if an2 < 0: + break + if pn2 < 0: + break + if pi2 >= pc: + break + if g_s1p_seen == 0: // 懒初始化:`CORE_S1P=1` 才开(`os.cr` 的 `get_env` 在 corec/corelsp 两单元皆在) // ⚠ **哨兵必须用零值**:2026-09-18 实测——`globals.cr` 里 `g_s1p_on : int, mut = -1;` // 在 **Python bootstrap 构建 corec** 时**初值静默丢成 0**(`.quad 0`)⇒「未初始化 = -1」 // 判据恒假 ⇒ 懒初始化永不执行 ⇒ 开关恒关(活性自证抓出:探针 0 命中)。 // 面 = bootstrap 构出的 corec(self-hosted 正常)⇒ 已单独登记(TODO #2026-09-18-12)。 - g_s1p_seen = 1; - ev2 := get_env("CORE_S1P"); - if str_len(ev2) > 0 && ev2 == "1" { g_s1p_on = 1; } else { g_s1p_on = 0; } - } + g_s1p_seen = 1 + ev2 := get_env("CORE_S1P") + if str_len(ev2) > 0 && ev2 == "1": + g_s1p_on = 1 + else: + g_s1p_on = 0 // ⚠ **整块受门**(2026-09-18 实测):仅把 print 受门**不够**——本块里的类型引擎调用 // (`infer_expr`/`res_call_type`/`unify_types`)会向 TYPE(7) 段的项表里**留项**(memo) // ⇒ 输出 `.ccr` 的段 7 变长(实测:门只罩 print 时 `opt_dex_test.cr` 的 `.ccr` // 187029→187053 **+24B**、ELF 同;其余 36/37 档零差)。故**默认位下本块一步都不执行**。 - if g_s1p_on != 0 { - arg_n := ast_a(an2); - ati := infer_expr(arg_n); - ptn := ast_data(pn2); - pti : ., mut = -1; - if ptn >= 0 { pti = res_call_type(ptn, fi); } + if g_s1p_on != 0: + arg_n := ast_a(an2) + ati := infer_expr(arg_n) + ptn := ast_data(pn2) + pti : ., mut = -1 + if ptn >= 0: + pti = res_call_type(ptn, fi) // 单实参判定与打点(跳过规则 ②③ + `unify_types` + **只打数值**台账)——三件共用 - s1p_arg_one(arg_n, pi2, pti, ati, is_ext, fi_name(fi)); - } - pi2 = pi2 + 1; - an2 = ast_b(an2); - pn2 = pn2 + 1; - loop { if pn2 >= g_ast_count { pn2 = -1; break; } - if ast_kind(pn2) == EXPR_PARAM { break; } pn2 = pn2 + 1; } - } -} - -fn infer_expr(node: int) -> int { - if node < 0 { return TI_UNIT; } + s1p_arg_one(arg_n, pi2, pti, ati, is_ext, fi_name(fi)) + pi2 = pi2 + 1 + an2 = ast_b(an2) + pn2 = pn2 + 1 + loop: + if pn2 >= g_ast_count: + pn2 = -1 + break + if ast_kind(pn2) == EXPR_PARAM: + break + pn2 = pn2 + 1 + +fn infer_expr(node: int) -> int: + if node < 0: + return TI_UNIT // R2 P2b Task 3:字面量定型 → 本质条目表查表(唯一真源 = iface_registry.cr 的 lit_code 列)。 @@ -2800,313 +2882,293 @@ fn infer_expr(node: int) -> int { // checker.cr:1892-1897 → 现址 :1896-1901,偏移 +4)**逐格转录**进表;5 个 kind 的判断 // 顺序与短路行为**逐字保持**——EXPR_NONE 转发行仍夹在 EXPR_INT 与 EXPR_DEX 之间, // **不得**重排、**不得**合并成「先取 kind 再查」的循环(那会改短路面)。 - if ast_kind(node) == EXPR_INT { return iface_lit_ti(EXPR_INT); } - if ast_kind(node) == EXPR_NONE && ast_a(node) >= 0 && ast_a(node) != node { return infer_expr(ast_a(node)); } - if ast_kind(node) == EXPR_DEX { return iface_lit_ti(EXPR_DEX); } - if ast_kind(node) == EXPR_STRING { return iface_lit_ti(EXPR_STRING); } - if ast_kind(node) == EXPR_BOOL { return iface_lit_ti(EXPR_BOOL); } - if ast_kind(node) == EXPR_CHAR { return iface_lit_ti(EXPR_CHAR); } - - if ast_kind(node) == EXPR_IDENT { - name_idx := ast_int_val(node); + if ast_kind(node) == EXPR_INT: + return iface_lit_ti(EXPR_INT) + if ast_kind(node) == EXPR_NONE && ast_a(node) >= 0 && ast_a(node) != node: + return infer_expr(ast_a(node)) + if ast_kind(node) == EXPR_DEX: + return iface_lit_ti(EXPR_DEX) + if ast_kind(node) == EXPR_STRING: + return iface_lit_ti(EXPR_STRING) + if ast_kind(node) == EXPR_BOOL: + return iface_lit_ti(EXPR_BOOL) + if ast_kind(node) == EXPR_CHAR: + return iface_lit_ti(EXPR_CHAR) + + if ast_kind(node) == EXPR_IDENT: + name_idx := ast_int_val(node) // Borrow check: can't use variable while it's borrowed - if !check_use(name_idx) { - name := istr_get(name_idx); - check_error(EC_B_USE_WHILE_BORROWED, "Cannot use '" + name + "' while it is borrowed", ast_line(node), ast_col(node)); - } - si := find_sym(name_idx); - if si >= 0 { return sym_type(si); } - name := istr_get(name_idx); - check_error(EC_N_UNDEFINED, "Undefined name '" + name + "'", ast_line(node), ast_col(node)); - return TI_NEVER; - } - if ast_kind(node) == EXPR_INTERP_HOLE { + if !check_use(name_idx): + name := istr_get(name_idx) + check_error(EC_B_USE_WHILE_BORROWED, "Cannot use '" + name + "' while it is borrowed", ast_line(node), ast_col(node)) + si := find_sym(name_idx) + if si >= 0: + return sym_type(si) + name := istr_get(name_idx) + check_error(EC_N_UNDEFINED, "Undefined name '" + name + "'", ast_line(node), ast_col(node)) + return TI_NEVER + if ast_kind(node) == EXPR_INTERP_HOLE: // 字符串插值洞(批 8 展开):**就地改写**本节点为「带类型转换的表达式」——父节点只存索引 // ⇒ 无需父指针(扁平 AST 的天然便利)。转换表(维护者签字):string 恒等 · int→`int_str` · // char→`chr` · bool→`if b {"true"} else {"false"}`(**不经 int**,遵「bool 不隐式转 int」裁定); // **其它类型(含 dex 两形态)⇒ P028 硬错**(fail-closed;dex 见下方实测注)。洞表达式由 parser // 末尾统一解析到 a 槽;解析失败(a<0)⇒ 退化为空串(错误已由 parser 报过,不级联)。 - inner := ast_a(node); - if inner < 0 || inner == node { - ast_set_kind(node, EXPR_STRING); - ast_set_a(node, 0); ast_set_b(node, 0); ast_set_c(node, 0); - ast_set_data(node, str_intern("")); - ast_set_type_val(node, TY_STRING); - return TI_STR; - } - hti := infer_expr(inner); + inner := ast_a(node) + if inner < 0 || inner == node: + ast_set_kind(node, EXPR_STRING) + ast_set_a(node, 0) + ast_set_b(node, 0) + ast_set_c(node, 0) + ast_set_data(node, str_intern("")) + ast_set_type_val(node, TY_STRING) + return TI_STR + hti := infer_expr(inner) // 实测两条(2026-09-18,签名表的**落地更正**,逐条有实测): // ① `bool` 洞**不**合成 `if` 表达式:分支需 `EXPR_BLOCK`、且实测 rc=139 ⇒ 改走 stdlib // `bool_str(b)`(`fmt.cr` 新增;**不经 int**,遵「bool 不隐式转 int」裁定,返回 "true"/"false")。 // ② `char` **本批不放开**(见下方 P028 注):签名表原写 `char ⇒ chr`,但实测 char 的运行期值是 // **字符串**(`ir_gen` EXPR_CHAR 发串常量),`chr(char)` 把串指针当码点 ⇒ 输出空;改走恒等则 // 触发**预存缺口** `string + char` = rc=139(`"c=" + ch` 独立复现)⇒ 须先修那条,属另案。 - if hti == TI_STR { + if hti == TI_STR: // 恒等:把本节点改写成内层表达式的字段副本(父只存索引 ⇒ 副本即等价) - ast_set_kind(node, ast_kind(inner)); - ast_set_a(node, ast_a(inner)); - ast_set_b(node, ast_b(inner)); - ast_set_c(node, ast_c(inner)); - ast_set_int_val(node, ast_int_val(inner)); - ast_set_type_val(node, ast_type_val(inner)); - ast_set_data(node, ast_data(inner)); - return infer_expr(node); - } - if hti == TI_BOOL { return interp_bool_node(node, inner); } - if hti == TI_INT { - cname := "int_str"; - callee := alloc_node(EXPR_IDENT, 0, 0, 0, str_intern(cname), 0, 0, ast_line(node), ast_col(node)); - wrapper := alloc_node(EXPR_NONE, inner, -1, 0, 0, 0, 0, ast_line(node), ast_col(node)); - ast_set_kind(node, EXPR_CALL); - ast_set_a(node, callee); - ast_set_b(node, wrapper); - ast_set_c(node, 1); - ast_set_data(node, 0); - ast_set_type_val(node, TY_STRING); - return TI_STR; - } + ast_set_kind(node, ast_kind(inner)) + ast_set_a(node, ast_a(inner)) + ast_set_b(node, ast_b(inner)) + ast_set_c(node, ast_c(inner)) + ast_set_int_val(node, ast_int_val(inner)) + ast_set_type_val(node, ast_type_val(inner)) + ast_set_data(node, ast_data(inner)) + return infer_expr(node) + if hti == TI_BOOL: + return interp_bool_node(node, inner) + if hti == TI_INT: + cname := "int_str" + callee := alloc_node(EXPR_IDENT, 0, 0, 0, str_intern(cname), 0, 0, ast_line(node), ast_col(node)) + wrapper := alloc_node(EXPR_NONE, inner, -1, 0, 0, 0, 0, ast_line(node), ast_col(node)) + ast_set_kind(node, EXPR_CALL) + ast_set_a(node, callee) + ast_set_b(node, wrapper) + ast_set_c(node, 1) + ast_set_data(node, 0) + ast_set_type_val(node, TY_STRING) + return TI_STR // 不可插值类型(本批 fail-closed): // · `dex`(TI_DEX / TI_DEX_S):本仓 dex 有 bits 与 scaled 两表示,`dex_str` 只按其一工作 ⇒ 不猜; // · `char`:**预存缺口**——char 的运行期值虽是字符串,但 `string + char` 实测 **rc=139** // (`"c=" + ch` 独立复现,与本批无关)⇒ 洞路径必然踩同一坑,故本批不放开; // · 其它(struct/enum/optional/array/函数…)本就不该插值。 - check_error(EC_P_INTERP_TYPE, "string interpolation supports string/int/bool here; for dex/char or other types convert explicitly (dex: int_str(@raw_int(d)); char: pre-existing 'string + char' defect, separately registered)", ast_line(node), ast_col(node)); - ast_set_kind(node, EXPR_STRING); - ast_set_a(node, 0); ast_set_b(node, 0); ast_set_c(node, 0); - ast_set_data(node, str_intern("")); - ast_set_type_val(node, TY_STRING); - return TI_STR; - } - - if ast_kind(node) == EXPR_NONE { + check_error(EC_P_INTERP_TYPE, "string interpolation supports string/int/bool here; for dex/char or other types convert explicitly (dex: int_str(@raw_int(d)); char: pre-existing 'string + char' defect, separately registered)", ast_line(node), ast_col(node)) + ast_set_kind(node, EXPR_STRING) + ast_set_a(node, 0) + ast_set_b(node, 0) + ast_set_c(node, 0) + ast_set_data(node, str_intern("")) + ast_set_type_val(node, TY_STRING) + return TI_STR + + if ast_kind(node) == EXPR_NONE: // Wrapper node in struct literal: forward to inner expression - if ast_a(node) >= 0 && ast_a(node) != node { return infer_expr(ast_a(node)); } - return TI_UNIT; - } - - if ast_kind(node) == EXPR_BINARY { - left := ast_a(node); - right := ast_b(node); - op := ast_c(node); + if ast_a(node) >= 0 && ast_a(node) != node: + return infer_expr(ast_a(node)) + return TI_UNIT + + if ast_kind(node) == EXPR_BINARY: + left := ast_a(node) + right := ast_b(node) + op := ast_c(node) // R2 P5 Task 4(D25):`EXPR_BINARY + OP_ASSIGN` 分支**已删**(站点 6 随之退役—— // 其挂点在本分支内)。不可达三面证明:① `tok2op`(parser.cr)不产 OP_ASSIGN; // ② `T_EQ` → `EXPR_ASSIGN`(parser.cr);③ `+=` 族显式构造 `EXPR_ASSIGN` 包裹的 // `EXPR_BINARY` 且 op ∈ {ADD,SUB,MUL,DIV} ⇒ 全仓无生产者(含 opt/pass 面)。 // 实证:全语料 shadow 站点直方图 `assign-binary=0`(32988 次判定)。**赋值判定点 // = 站点 8(EXPR_ASSIGN,见 infer_expr 的 EXPR_ASSIGN 分支)**,逐字保留。 - lt := infer_expr(left); - rt := infer_expr(right); - if op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV || op == OP_MOD { + lt := infer_expr(left) + rt := infer_expr(right) + if op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV || op == OP_MOD: // String concatenation for OP_ADD - if op == OP_ADD && (lt == TI_STR || rt == TI_STR) { return TI_STR; } + if op == OP_ADD && (lt == TI_STR || rt == TI_STR): + return TI_STR // S3(2026-09-20,维护者裁):指针算术门**纳入 `TYP_REF`**——与 S1(`&x → TYP_REF`)配套。 // **不改本门 ⇒ `&x + 1` 落空 ⇒ 报诊断**(S1 落地后 `selftest-types` 恰 2 例红即此)。 // **结果 kind = 保持操作数 kind**(`return lt` / `return rt`):REF 进 ⇒ REF 出。 // 裁定理由:S3 的语义是「**让 REF 能进门**」,不是「把结果降级成 PTR」——降级会让 // 引用性在算术后**静默丢失**(一个新的语义跳变,而本批在收的正是这种跳变)。 // Pointer arithmetic: *T + n or n + *T → *T(PTR/REF 皆可,结果随左/右操作数) - if (op == OP_ADD || op == OP_SUB) && ((get_type_kind(lt) == TYP_PTR || get_type_kind(lt) == TYP_REF) && rt == TI_INT) { - return lt; // return the address type unchanged(PTR 进 PTR 出 · REF 进 REF 出) - } - if (op == OP_ADD || op == OP_SUB) && (lt == TI_INT && (get_type_kind(rt) == TYP_PTR || get_type_kind(rt) == TYP_REF)) { - return rt; - } + if (op == OP_ADD || op == OP_SUB) && ((get_type_kind(lt) == TYP_PTR || get_type_kind(lt) == TYP_REF) && rt == TI_INT): + return lt // return the address type unchanged(PTR 进 PTR 出 · REF 进 REF 出) + if (op == OP_ADD || op == OP_SUB) && (lt == TI_INT && (get_type_kind(rt) == TYP_PTR || get_type_kind(rt) == TYP_REF)): + return rt // Pointer difference: *T - *T → int(PTR/REF 皆可;**两侧不必同 kind**——与既有宽松面一致) - if op == OP_SUB && (get_type_kind(lt) == TYP_PTR || get_type_kind(lt) == TYP_REF) && (get_type_kind(rt) == TYP_PTR || get_type_kind(rt) == TYP_REF) { - return TI_INT; - } + if op == OP_SUB && (get_type_kind(lt) == TYP_PTR || get_type_kind(lt) == TYP_REF) && (get_type_kind(rt) == TYP_PTR || get_type_kind(rt) == TYP_REF): + return TI_INT // Check: arithmetic ops require int or dex —— R2 P2b Task 4:查表(门形状 = ANY: // 「至少一侧许可即通过」,与改动前的 `&&` 形状一字等价)。转录依据 = 本处改动前的 // `lt != TI_INT && lt != TI_DEX && rt != TI_INT && rt != TI_DEX`;表的 ADD..MOD 格 // **只含 int/dex**(PTR/STRING 不在内——早退规则 :1946/:1948/:1951/:1955(接线前实测 // 行号;接线后本块 +4)仍在原处 = 结果规则,不进本门)。负控(须仍报 error[TB01]): // `*T + *T`、`"a" - "b"`。 - if iface_permits(iface_kind_of(lt), op) == 0 && iface_permits(iface_kind_of(rt), op) == 0 { - check_error(EC_TB_ADD, "Arithmetic operation requires int or dex", ast_line(node), ast_col(node)); - } - if lt == TI_DEX || rt == TI_DEX { return TI_DEX; } - return TI_INT; - } - if op == OP_EQ || op == OP_NE || op == OP_LT || op == OP_GT || op == OP_LE || op == OP_GE { - return TI_BOOL; - } - if op == OP_AND || op == OP_OR { + if iface_permits(iface_kind_of(lt), op) == 0 && iface_permits(iface_kind_of(rt), op) == 0: + check_error(EC_TB_ADD, "Arithmetic operation requires int or dex", ast_line(node), ast_col(node)) + if lt == TI_DEX || rt == TI_DEX: + return TI_DEX + return TI_INT + if op == OP_EQ || op == OP_NE || op == OP_LT || op == OP_GT || op == OP_LE || op == OP_GE: + return TI_BOOL + if op == OP_AND || op == OP_OR: // R2 P2b Task 4:查表(门形状 = ALL「每侧都须许可」)。转录依据 = 本处改动前的 // `lt != TI_BOOL && lt != TI_INT || rt != TI_BOOL && rt != TI_INT`(= 某侧「非 bool 且 // 非 int」即报错);谓词写 OP_AND(**不另设** IP_LOGIC——OP_AND/OP_OR 在表中同步置位, // 且现状 :1969 对两个 op 一字不分)。表的 AND/OR 格恰 {int, bool}——**dex 不在内** // (`1.5 && true` 现状 error[TC01],探针 N7 实测)。 - if iface_permits(iface_kind_of(lt), OP_AND) == 0 || iface_permits(iface_kind_of(rt), OP_AND) == 0 { - check_error(EC_TC_IF_COND, "Logical operator requires bool or int operands", ast_line(node), ast_col(node)); - } - return TI_BOOL; - } - return TI_INT; - } - - if ast_kind(node) == EXPR_UNARY { - op := ast_c(node); - if op == UOP_NEG || op == UOP_NOT { - return infer_expr(ast_a(node)); - } - if op == UOP_REF { - operand := ast_a(node); - is_mut := ast_int_val(node); - inner : ., mut = TI_UNIT; - if ast_kind(operand) == EXPR_IDENT { - vi := ast_int_val(operand); - if !check_borrow(vi, is_mut) { - name := istr_get(vi); - if is_mut != 0 { - check_error(EC_B_BORROW_MUT, "Cannot borrow '" + name + "' as mutable, already borrowed", ast_line(node), ast_col(node)); - } else { - check_error(EC_B_BORROW_IMMUT, "Cannot borrow '" + name + "' as immutable, already mutably borrowed", ast_line(node), ast_col(node)); - } - } - si := find_sym(vi); - if si >= 0 { inner = sym_type(si); } - } else { - inner = infer_expr(operand); - } + if iface_permits(iface_kind_of(lt), OP_AND) == 0 || iface_permits(iface_kind_of(rt), OP_AND) == 0: + check_error(EC_TC_IF_COND, "Logical operator requires bool or int operands", ast_line(node), ast_col(node)) + return TI_BOOL + return TI_INT + + if ast_kind(node) == EXPR_UNARY: + op := ast_c(node) + if op == UOP_NEG || op == UOP_NOT: + return infer_expr(ast_a(node)) + if op == UOP_REF: + operand := ast_a(node) + is_mut := ast_int_val(node) + inner : ., mut = TI_UNIT + if ast_kind(operand) == EXPR_IDENT: + vi := ast_int_val(operand) + if !check_borrow(vi, is_mut): + name := istr_get(vi) + if is_mut != 0: + check_error(EC_B_BORROW_MUT, "Cannot borrow '" + name + "' as mutable, already borrowed", ast_line(node), ast_col(node)) + else: + check_error(EC_B_BORROW_IMMUT, "Cannot borrow '" + name + "' as immutable, already mutably borrowed", ast_line(node), ast_col(node)) + si := find_sym(vi) + if si >= 0: + inner = sym_type(si) + else: + inner = infer_expr(operand) // S1(2026-09-20,裁定二):`&x` 由 `TYP_PTR` 改判 **`TYP_REF`**, // 且 `extra` 由写死的 0 改取 **`is_mut`**(`:2949` 已在手,此前被丢弃)—— // **两个实参必须同批**:只换 kind 不写 extra ⇒ REF 的 extra 恒 0 ⇒ 与 // 引擎侧 `AK_REF` 槽 0(mut,**参与身份**)不一致(§8 S1)。 - return alloc_type(TYP_REF, inner, is_mut); - } - if op == UOP_DEREF { - inner := infer_expr(ast_a(node)); - if get_type_kind(inner) == TYP_REF { - return get_type_data(inner); - } - if get_type_kind(inner) == TYP_PTR { - return get_type_data(inner); - } - if get_type_kind(inner) == TYP_GENERIC_PARAM { - return inner; - } - return inner; - } - return infer_expr(ast_a(node)); - } - - if ast_kind(node) == EXPR_CALL { - func_node := ast_a(node); - first_arg := ast_b(node); - arg_count := ast_c(node); - func_ni : ., mut = -1; + return alloc_type(TYP_REF, inner, is_mut) + if op == UOP_DEREF: + inner := infer_expr(ast_a(node)) + if get_type_kind(inner) == TYP_REF: + return get_type_data(inner) + if get_type_kind(inner) == TYP_PTR: + return get_type_data(inner) + if get_type_kind(inner) == TYP_GENERIC_PARAM: + return inner + return inner + return infer_expr(ast_a(node)) + + if ast_kind(node) == EXPR_CALL: + func_node := ast_a(node) + first_arg := ast_b(node) + arg_count := ast_c(node) + func_ni : ., mut = -1 // Method call: obj.method(args) or module.func(args) - if ast_kind(func_node) == EXPR_FIELD { - obj := ast_a(func_node); - method_ni := ast_int_val(func_node); + if ast_kind(func_node) == EXPR_FIELD: + obj := ast_a(func_node) + method_ni := ast_int_val(func_node) // Module-qualified call: module.func(args) - mod_call_done : ., mut = 0; - mod_found_mfi : ., mut = -1; - if ast_kind(obj) == EXPR_IDENT { - mod_name_ni := ast_int_val(obj); - si := find_sym(mod_name_ni); - if si >= 0 && sym_kind(si) == SYM_MODULE { - fileid_ni := sym_type(si); + mod_call_done : ., mut = 0 + mod_found_mfi : ., mut = -1 + if ast_kind(obj) == EXPR_IDENT: + mod_name_ni := ast_int_val(obj) + si := find_sym(mod_name_ni) + if si >= 0 && sym_kind(si) == SYM_MODULE: + fileid_ni := sym_type(si) // Look up (fileid, method) in module function table - mfi : ., mut = 0; - loop { - if mfi >= g_mod_func_count { break; } - if r64(g_mod_func_fileids, mfi * 8) == fileid_ni && r64(g_mod_func_names, mfi * 8) == method_ni { - func_ni = r64(g_mod_func_names, mfi * 8); - ast_set_data(node, func_ni); - call_flags := ast_type_val(node); - if call_flags == CALL_FLAG_INLINE { - ast_set_type_val(node, CALL_FLAG_MODULE + CALL_FLAG_INLINE); - } else { - ast_set_type_val(node, CALL_FLAG_MODULE); - } - mod_call_done = 1; - mod_found_mfi = mfi; - break; - } - mfi = mfi + 1; - } - } - } - if mod_call_done == 1 { + mfi : ., mut = 0 + loop: + if mfi >= g_mod_func_count: + break + if r64(g_mod_func_fileids, mfi * 8) == fileid_ni && r64(g_mod_func_names, mfi * 8) == method_ni: + func_ni = r64(g_mod_func_names, mfi * 8) + ast_set_data(node, func_ni) + call_flags := ast_type_val(node) + if call_flags == CALL_FLAG_INLINE: + ast_set_type_val(node, CALL_FLAG_MODULE + CALL_FLAG_INLINE) + else: + ast_set_type_val(node, CALL_FLAG_MODULE) + mod_call_done = 1 + mod_found_mfi = mfi + break + mfi = mfi + 1 + if mod_call_done == 1: // Infer arg types - an : ., mut = first_arg; - loop { - if an < 0 { break; } - infer_expr(ast_a(an)); - an = ast_b(an); - } + an : ., mut = first_arg + loop: + if an < 0: + break + infer_expr(ast_a(an)) + an = ast_b(an) // 批 8(甲)刀 2:模块限定调用接入 S1P 台账(此前未覆盖——本分支同样早退)。 // `param_skip = 0`:形参链无 self(模块函数是普通 fn)。 - fi_mod := find_func(func_ni); - s1p_arg_ring(fi_mod, first_arg, arg_count, 0, 0); - if mod_found_mfi >= 0 { - return r64(g_mod_func_tis, mod_found_mfi * 8); - } - return TI_UNIT; - } - - obj_ti := infer_expr(obj); + fi_mod := find_func(func_ni) + s1p_arg_ring(fi_mod, first_arg, arg_count, 0, 0) + if mod_found_mfi >= 0: + return r64(g_mod_func_tis, mod_found_mfi * 8) + return TI_UNIT + + obj_ti := infer_expr(obj) // --- Dyn method validation --- - if obj_ti == TI_DYN { - if ast_kind(obj) == EXPR_IDENT { - obj_ni := ast_int_val(obj); - obj_si := find_sym(obj_ni); - if obj_si >= 0 { - validate_dyn_method(obj_si, method_ni, ast_line(node), ast_col(node)); - } - } + if obj_ti == TI_DYN: + if ast_kind(obj) == EXPR_IDENT: + obj_ni := ast_int_val(obj) + obj_si := find_sym(obj_ni) + if obj_si >= 0: + validate_dyn_method(obj_si, method_ni, ast_line(node), ast_col(node)) // Infer arg types (for side effects) - an_dyn : ., mut = first_arg; - loop { - if an_dyn < 0 { break; } - infer_expr(ast_a(an_dyn)); - an_dyn = ast_b(an_dyn); - } - return TI_UNIT; - } - lookup_ti : ., mut = obj_ti; + an_dyn : ., mut = first_arg + loop: + if an_dyn < 0: + break + infer_expr(ast_a(an_dyn)) + an_dyn = ast_b(an_dyn) + return TI_UNIT + lookup_ti : ., mut = obj_ti // Unwrap generic apply to base type - if lookup_ti >= 0 && lookup_ti < g_type_count && get_type_kind(lookup_ti) == TYP_GENERIC_APPLY { - lookup_ti = get_type_data(lookup_ti); - } - if lookup_ti >= 0 && lookup_ti < g_type_count && get_type_kind(lookup_ti) == TYP_NAMED { - struct_ni := get_type_data(lookup_ti); + if lookup_ti >= 0 && lookup_ti < g_type_count && get_type_kind(lookup_ti) == TYP_GENERIC_APPLY: + lookup_ti = get_type_data(lookup_ti) + if lookup_ti >= 0 && lookup_ti < g_type_count && get_type_kind(lookup_ti) == TYP_NAMED: + struct_ni := get_type_data(lookup_ti) // Look up method in method table - mi : ., mut = 0; - loop { - if mi >= g_method_count { break; } - if r64(g_methods, mi * 24) == struct_ni && r64(g_methods, mi * 24 + 8) == method_ni { - func_ni = r64(g_methods, mi * 24 + 16); - ast_set_data(node, func_ni); - break; - } - mi = mi + 1; - } - } + mi : ., mut = 0 + loop: + if mi >= g_method_count: + break + if r64(g_methods, mi * 24) == struct_ni && r64(g_methods, mi * 24 + 8) == method_ni: + func_ni = r64(g_methods, mi * 24 + 16) + ast_set_data(node, func_ni) + break + mi = mi + 1 // Generic param method call resolution - if func_ni < 0 && get_type_kind(lookup_ti) == TYP_GENERIC_PARAM { - gen_ni := get_type_data(lookup_ti); - gc2 := fi_generic_count(g_checker_current_fi); - gci2 : ., mut = 0; - loop { - if gci2 >= gc2 { break; } - gname_idx2 := r64(g_funcs, g_checker_current_fi * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gci2 * 8); - if gname_idx2 == gen_ni { - constr_idx2 := g_checker_current_fi * MAX_GENERICS + gci2; - if constr_idx2 < g_generic_constr_count { - iface_ni2 := r64(g_generic_constr, constr_idx2 * 8); - if iface_ni2 >= 0 { - ii2 := find_iface(iface_ni2); - if ii2 >= 0 { - imc2 := r64(g_ifaces, ii2 * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT); - imi2 : ., mut = 0; - loop { - if imi2 >= imc2 { break; } - imbase2 := ii2 * ESZ_IFACEINFO + OFF_IF_METHODS + imi2 * ESZ_IFMETHOD; - if r64(g_ifaces, imbase2 + OFF_IFM_NAME) == method_ni { + if func_ni < 0 && get_type_kind(lookup_ti) == TYP_GENERIC_PARAM: + gen_ni := get_type_data(lookup_ti) + gc2 := fi_generic_count(g_checker_current_fi) + gci2 : ., mut = 0 + loop: + if gci2 >= gc2: + break + gname_idx2 := r64(g_funcs, g_checker_current_fi * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gci2 * 8) + if gname_idx2 == gen_ni: + constr_idx2 := g_checker_current_fi * MAX_GENERICS + gci2 + if constr_idx2 < g_generic_constr_count: + iface_ni2 := r64(g_generic_constr, constr_idx2 * 8) + if iface_ni2 >= 0: + ii2 := find_iface(iface_ni2) + if ii2 >= 0: + imc2 := r64(g_ifaces, ii2 * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT) + imi2 : ., mut = 0 + loop: + if imi2 >= imc2: + break + imbase2 := ii2 * ESZ_IFACEINFO + OFF_IF_METHODS + imi2 * ESZ_IFMETHOD + if r64(g_ifaces, imbase2 + OFF_IFM_NAME) == method_ni: // R2 P3b Task 6(Step 3,mangling 退役):不再合成 "T.m" // 串——调用点记(**泛型形参名 ni**,标记位),实例化 // 时由 monomorph 按具体类型查方法表解析为真实函数名 @@ -3114,42 +3176,34 @@ fn infer_expr(node: int) -> int { // CALL_FLAG_IFACE_METHOD 注)。旧态 = 名字拼接 + 克隆 // 期文本替换 ⇒ 实例体内调用目标悬空(实测产物运行 // rc=139);本任务起表查询(同 iface_find_method)。 - ast_set_data(node, gen_ni); - ast_set_type_val(node, CALL_FLAG_IFACE_METHOD); - iface_ret2 := r64(g_ifaces, imbase2 + OFF_IFM_RET_TI); + ast_set_data(node, gen_ni) + ast_set_type_val(node, CALL_FLAG_IFACE_METHOD) + iface_ret2 := r64(g_ifaces, imbase2 + OFF_IFM_RET_TI) // P2b Task 6:值经单表 `ty_code_to_ti`;本站点值域 = parser 写入的 // `unpack_type(返回型节点)`(parser.cr:1701,即 TY_* 码);**域 = {INT..CHAR}** // (缺 NEVER/7 ⇒ 落尾 TI_UNIT)。**显式化**:现状 6 行用的是 `iface_ret2 == TY_*` // 而值域是 TI_*,靠「TY_INT==TI_INT==0 … TY_CHAR==TI_CHAR==6」的数值撞车成立, // 合一后改按语义查表(探针 F13:`-> never` 的 iface 方法在调用点 = unit; // F14:`-> char` = char)。 - iface_ret_ti := ty_code_to_ti(iface_ret2); - if iface_ret_ti >= 0 && iface_ret_ti != TI_NEVER && iface_ret_ti != TI_DYN { - func_ni = gen_ni; - return iface_ret_ti; - } - func_ni = gen_ni; return TI_UNIT; - } - imi2 = imi2 + 1; - } - } - } - } - break; - } - gci2 = gci2 + 1; - } - } + iface_ret_ti := ty_code_to_ti(iface_ret2) + if iface_ret_ti >= 0 && iface_ret_ti != TI_NEVER && iface_ret_ti != TI_DYN: + func_ni = gen_ni + return iface_ret_ti + func_ni = gen_ni + return TI_UNIT + imi2 = imi2 + 1 + break + gci2 = gci2 + 1 // Infer arg types (walk EXPR_ARG chain) - an : ., mut = first_arg; - loop { - if an < 0 { break; } - infer_expr(ast_a(an)); - an = ast_b(an); - } - if func_ni >= 0 { - si := find_gsym(func_ni); - if si >= 0 && sym_kind(si) == SYM_FN { + an : ., mut = first_arg + loop: + if an < 0: + break + infer_expr(ast_a(an)) + an = ast_b(an) + if func_ni >= 0: + si := find_gsym(func_ni) + if si >= 0 && sym_kind(si) == SYM_FN: // R2 P6 Task 4a(E-11,姊妹站点):与直调站点守卫同形—— // `func_ni` = parser impl 分支写入的 mangled ni("S.m", // parser.cr:1887-1894)⇒ 与直调面同一张 g_funcs/符号表, @@ -3160,78 +3214,72 @@ fn infer_expr(node: int) -> int { // 只认 `fn`,parser.cr:1864-1899)⇒ 不需 EXPR_FN 限定 // (行为等价,非逐字镜像)。嵌套 if 同直调站点(`&&` 不短路 + // 表读无护栏)。 - fi_m := find_func(func_ni); + fi_m := find_func(func_ni) // 批 8(甲)刀 2:方法调用接入 S1P 台账(此前**未覆盖**——本分支在 S1P 块之前 // 早退 ⇒ 方法实参位是台账盲区)。`param_skip = 1`:实参链**不含**接收者,而 // 形参链**含** self ⇒ 形参游标跳过 self 后与实参 1:1(元数口径 = arg_count + 1 == pc)。 - s1p_arg_ring(fi_m, first_arg, arg_count, 1, 0); - if fi_m >= 0 { - if fi_generic_count(fi_m) == 0 { - if sym_type(si) == TI_UNIT { - if fi_return_type(fi_m) == TY_NEVER { - return TI_NEVER; - } - } - } - } - return sym_type(si); - } - } - return TI_UNIT; - } + s1p_arg_ring(fi_m, first_arg, arg_count, 1, 0) + if fi_m >= 0: + if fi_generic_count(fi_m) == 0: + if sym_type(si) == TI_UNIT: + if fi_return_type(fi_m) == TY_NEVER: + return TI_NEVER + return sym_type(si) + return TI_UNIT // Determine function name and return type - if ast_kind(func_node) == EXPR_IDENT { - func_ni = ast_int_val(func_node); - } + if ast_kind(func_node) == EXPR_IDENT: + func_ni = ast_int_val(func_node) // @builtin(args) — transfer args from EXPR_CALL to EXPR_AT, then delegate - if ast_kind(func_node) == EXPR_AT { - ast_set_b(func_node, first_arg); - return infer_expr(func_node); - } + if ast_kind(func_node) == EXPR_AT: + ast_set_b(func_node, first_arg) + return infer_expr(func_node) // Check builtins (syscall3/syscall4 — OS communication, no .cr body) - if func_ni >= 0 { - s := istr_get(func_ni); - if s == "syscall3" { return TI_INT; } - if s == "syscall4" { return TI_INT; } - } + if func_ni >= 0: + s := istr_get(func_ni) + if s == "syscall3": + return TI_INT + if s == "syscall4": + return TI_INT // Check for SYM_SO_FN (.so extension registered) - so_fn_fi : ., mut = -1; - if func_ni >= 0 { - si := find_gsym(func_ni); - if si >= 0 && sym_kind(si) == SYM_SO_FN { - so_fn_fi = si; - tag_flags2 := sym_type(si); // stores tag_flags - type_enc2 := sym_node(si); // stores type encoding + so_fn_fi : ., mut = -1 + if func_ni >= 0: + si := find_gsym(func_ni) + if si >= 0 && sym_kind(si) == SYM_SO_FN: + so_fn_fi = si + tag_flags2 := sym_type(si) // stores tag_flags + type_enc2 := sym_node(si) // stores type encoding // Infer arg types (walk EXPR_ARG chain) - an : ., mut = first_arg; - loop { - if an < 0 { break; } - infer_expr(ast_a(an)); - an = ast_b(an); - } + an : ., mut = first_arg + loop: + if an < 0: + break + infer_expr(ast_a(an)) + an = ast_b(an) // Decode return type (type_enc2 % 100) - ret_code2 : ., mut = type_enc2 - (type_enc2 / 100) * 100; + ret_code2 : ., mut = type_enc2 - (type_enc2 / 100) * 100 // Map back to TI_* - if ret_code2 == 0 { return TI_INT; } - if ret_code2 == 1 { return TI_STR; } - if ret_code2 == 2 { return TI_UNIT; } - if ret_code2 == 3 { return TI_DEX; } - if ret_code2 == 4 { return TI_BOOL; } - return TI_UNIT; - } - } + if ret_code2 == 0: + return TI_INT + if ret_code2 == 1: + return TI_STR + if ret_code2 == 2: + return TI_UNIT + if ret_code2 == 3: + return TI_DEX + if ret_code2 == 4: + return TI_BOOL + return TI_UNIT // Look up function - if func_ni >= 0 && so_fn_fi < 0 { - si := find_gsym(func_ni); - if si >= 0 && sym_kind(si) == SYM_FN { + if func_ni >= 0 && so_fn_fi < 0: + si := find_gsym(func_ni) + if si >= 0 && sym_kind(si) == SYM_FN: // Check if generic function - fi := find_func(func_ni); - if fi >= 0 && fi_generic_count(fi) > 0 { - return infer_gen_call(fi, node, first_arg, arg_count); - } + fi := find_func(func_ni) + if fi >= 0 && fi_generic_count(fi) > 0: + return infer_gen_call(fi, node, first_arg, arg_count) // R2 P6 Task 4a(E-11):被调**非泛型 `fn` 声明**的返回行 = `never` // ⇒ 调用推断 `never`。声明注册趟把 NEVER 钳成 unit(collect_decls 的 // 域守卫 :1491:`rt_mapped != TI_NEVER`)⇒ 此处按裸码 `fi_return_type` @@ -3244,20 +3292,15 @@ fn infer_expr(node: int) -> int { // (bootstrap/corec/frontend/ir_gen.py:226-235),且 `fi_return_type` // (dyn_arr.cr:459)与 `ast_kind`(dyn_arr.cr:370)均无护栏 ⇒ 不得写 // `guard && 表读`。 - if fi >= 0 { - if sym_type(si) == TI_UNIT { - if fi_return_type(fi) == TY_NEVER { - fnd := fi_ast_node(fi); - if fnd >= 0 { - if ast_kind(fnd) == EXPR_FN { - infer_call_args(first_arg); // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) - return TI_NEVER; - } - } - } - } - } - infer_call_args(first_arg); // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) + if fi >= 0: + if sym_type(si) == TI_UNIT: + if fi_return_type(fi) == TY_NEVER: + fnd := fi_ast_node(fi) + if fnd >= 0: + if ast_kind(fnd) == EXPR_FN: + infer_call_args(first_arg) // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) + return TI_NEVER + infer_call_args(first_arg) // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) // ── 批 8 PR-B · S1′(report-only;**新点 = 直调/方法调用解析尾**,2026-09-18)──── // 目的:测 (ii)「直调实参类型不校验」的**真实面**(旧 S1 接在 `infer_gen_call` 的泛型 // 推断丢弃点 ⇒ 全语料 0 打点,已证泛型面未被触碰)。本点覆盖**非泛型直调 + 方法调用**。 @@ -3274,137 +3317,127 @@ fn infer_expr(node: int) -> int { // ⑥ 元数不齐(含变参面):有效实参数 ≠ 形参数 ⇒ 静默跳过(**不打点**,不据此判定)。 // 台账格式(**扫面锚定用**,只认行首):`9917|9918 ` // ——**不得**只 grep `9917` 裸串(会命中源码回显,见 2026-09-18 扫面假阳教训)。 - if fi >= 0 { - fnode := fi_ast_node(fi); - is_ext2 : ., mut = 0; - if fnode >= 0 && ast_kind(fnode) == EXPR_EXTERN { is_ext2 = 1; } - s1p_arg_ring(fi, first_arg, arg_count, 0, is_ext2); - } - return sym_type(si); // return type - } + if fi >= 0: + fnode := fi_ast_node(fi) + is_ext2 : ., mut = 0 + if fnode >= 0 && ast_kind(fnode) == EXPR_EXTERN: + is_ext2 = 1 + s1p_arg_ring(fi, first_arg, arg_count, 0, is_ext2) + return sym_type(si) // return type // Check runtime builtins (no .cr body, implemented in rt.s) - bi : ., mut = 0; - loop { - if bi >= g_rt_builtin_count { break; } - if r64(g_rt_builtin_names, bi * 8) == func_ni { - infer_call_args(first_arg); // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) - return r64(g_rt_builtin_ret_types, bi * 8); - } - bi = bi + 1; - } + bi : ., mut = 0 + loop: + if bi >= g_rt_builtin_count: + break + if r64(g_rt_builtin_names, bi * 8) == func_ni: + infer_call_args(first_arg) // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) + return r64(g_rt_builtin_ret_types, bi * 8) + bi = bi + 1 // Not found in symbol table or builtins — report error - name := istr_get(func_ni); - check_error(EC_N_FUNC, "Undefined function '" + name + "'", ast_line(node), ast_col(node)); - infer_call_args(first_arg); // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) - return TI_NEVER; - } - infer_call_args(first_arg); // 单一真源(与上述 4 处同一函数) - return TI_INT; // external/unknown functions - } - - if ast_kind(node) == EXPR_BLOCK { - stmt_start := ast_a(node); - stmt_count := ast_b(node); - res : ., mut = TI_UNIT; - push_borrow_scope(); - i : ., mut = 0; - loop { - if i >= stmt_count { break; } - sn := r64(g_block_stmts, (stmt_start + i) * 8); - res = infer_expr(sn); - i = i + 1; - } + name := istr_get(func_ni) + check_error(EC_N_FUNC, "Undefined function '" + name + "'", ast_line(node), ast_col(node)) + infer_call_args(first_arg) // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) + return TI_NEVER + infer_call_args(first_arg) // 单一真源(与上述 4 处同一函数) + return TI_INT // external/unknown functions + + if ast_kind(node) == EXPR_BLOCK: + stmt_start := ast_a(node) + stmt_count := ast_b(node) + res : ., mut = TI_UNIT + push_borrow_scope() + i : ., mut = 0 + loop: + if i >= stmt_count: + break + sn := r64(g_block_stmts, (stmt_start + i) * 8) + res = infer_expr(sn) + i = i + 1 // Track the last-statement type for debugging // (no operation needed — res is already the last type) - pop_borrow_scope(); - return res; - } - - if ast_kind(node) == EXPR_IF { - cond := ast_a(node); - then_node := ast_b(node); - else_node := ast_c(node); - cond_ti := infer_expr(cond); + pop_borrow_scope() + return res + + if ast_kind(node) == EXPR_IF: + cond := ast_a(node) + then_node := ast_b(node) + else_node := ast_c(node) + cond_ti := infer_expr(cond) // Accept int as truthy/falsy in conditions (not just strict bool) // R2 P2b Task 4:查表(门形状 = ONE 单操作数)。转录依据 = 本处改动前的 // `cond_ti != TI_BOOL && cond_ti != TI_INT`;IP_COND 格恰 {int, bool}——**dex 拒** // (`if 1.5` 现状 error[TC01],探针 N8 实测)。**不得**与 `while` 的 IP_COND_BOOL 合并 // (那条只收 bool——合并 = 收紧 `if` 或放宽 `while`)。 - if iface_permits(iface_kind_of(cond_ti), IP_COND) == 0 { - check_error(EC_TC_IF_COND, "If condition must be bool or int", ast_line(node), ast_col(node)); - } + if iface_permits(iface_kind_of(cond_ti), IP_COND) == 0: + check_error(EC_TC_IF_COND, "If condition must be bool or int", ast_line(node), ast_col(node)) // --- Dyn type set merge: save pre-if state --- - pre_dyn_count : ., mut = g_dyn_type_set_count; - pre_dyn_save : string, mut = ""; - if pre_dyn_count > 0 { - pre_dyn_save = alloc(pre_dyn_count * 8); - _dyncpy(g_dyn_type_sets, pre_dyn_count * 8, pre_dyn_save); - } + pre_dyn_count : ., mut = g_dyn_type_set_count + pre_dyn_save : string, mut = "" + if pre_dyn_count > 0: + pre_dyn_save = alloc(pre_dyn_count * 8) + _dyncpy(g_dyn_type_sets, pre_dyn_count * 8, pre_dyn_save) // --- Process then branch --- - push_borrow_scope(); - then_ti := infer_expr(then_node); - pop_borrow_scope(); + push_borrow_scope() + then_ti := infer_expr(then_node) + pop_borrow_scope() // --- Save then-branch dyn state --- - then_dyn_count : ., mut = g_dyn_type_set_count; - then_dyn_save : string, mut = ""; - if then_dyn_count > 0 { - then_dyn_save = alloc(then_dyn_count * 8); - _dyncpy(g_dyn_type_sets, then_dyn_count * 8, then_dyn_save); - } + then_dyn_count : ., mut = g_dyn_type_set_count + then_dyn_save : string, mut = "" + if then_dyn_count > 0: + then_dyn_save = alloc(then_dyn_count * 8) + _dyncpy(g_dyn_type_sets, then_dyn_count * 8, then_dyn_save) // --- Restore pre-if state (zero stale entries beyond pre_dyn_count) --- - g_dyn_type_set_count = pre_dyn_count; - if pre_dyn_count > 0 { - _dyncpy(pre_dyn_save, pre_dyn_count * 8, g_dyn_type_sets); - } - iz : ., mut = pre_dyn_count; - loop { - if iz >= then_dyn_count { break; } - w64(g_dyn_type_sets, iz * 8, 0); - iz = iz + 1; - } + g_dyn_type_set_count = pre_dyn_count + if pre_dyn_count > 0: + _dyncpy(pre_dyn_save, pre_dyn_count * 8, g_dyn_type_sets) + iz : ., mut = pre_dyn_count + loop: + if iz >= then_dyn_count: + break + w64(g_dyn_type_sets, iz * 8, 0) + iz = iz + 1 // --- Process else branch (if any) --- - if else_node >= 0 { - push_borrow_scope(); - else_ti := infer_expr(else_node); - pop_borrow_scope(); + if else_node >= 0: + push_borrow_scope() + else_ti := infer_expr(else_node) + pop_borrow_scope() // --- Merge dyn type sets from both branches --- - merge_count : ., mut = then_dyn_count; - if g_dyn_type_set_count > merge_count { merge_count = g_dyn_type_set_count; } - grow_dyn_type_sets(merge_count); - g_dyn_type_set_count = merge_count; - mi : ., mut = 0; - loop { - if mi >= merge_count { break; } - then_bits : ., mut = 0; - if mi < then_dyn_count { then_bits = r64(then_dyn_save, mi * 8); } - else_bits : ., mut = 0; - if mi < g_dyn_type_set_count { else_bits = r64(g_dyn_type_sets, mi * 8); } - merged := union_bitmaps(then_bits, else_bits); - w64(g_dyn_type_sets, mi * 8, merged); - mi = mi + 1; - } - g_dyn_type_set_count = merge_count; + merge_count : ., mut = then_dyn_count + if g_dyn_type_set_count > merge_count: + merge_count = g_dyn_type_set_count + grow_dyn_type_sets(merge_count) + g_dyn_type_set_count = merge_count + mi : ., mut = 0 + loop: + if mi >= merge_count: + break + then_bits : ., mut = 0 + if mi < then_dyn_count: + then_bits = r64(then_dyn_save, mi * 8) + else_bits : ., mut = 0 + if mi < g_dyn_type_set_count: + else_bits = r64(g_dyn_type_sets, mi * 8) + merged := union_bitmaps(then_bits, else_bits) + w64(g_dyn_type_sets, mi * 8, merged) + mi = mi + 1 + g_dyn_type_set_count = merge_count // P3 Task 1 参序归一:合并**结果类型 = then_ti**(下方 return then_ti)⇒ 源 = else 侧, // 目标 = then 侧(长度约束更弱者放前面会被这里拦住 = 与结果类型一致;反之亦然) - compat := type_compat_strict(else_ti, then_ti); + compat := type_compat_strict(else_ti, then_ti) // TC02 收口(P3):if 的**值类型定义为 then_ti**(下方 return then_ti)⇒ 当 **else 支 // 确定发散**(`return` 族收尾、不产出值)时,else 侧的「类型」是幻影(EXPR_RETURN 推断 // = 所返回值类型)⇒ 相容判定无对象 ⇒ 不报。 // **不对称是有意的**:then 支发散时 then_ti 本身即幻影(模型面,另案)⇒ 该形态继续报 // TC02(保留真信号)。谓词 = stmt_diverges(头注:只服务本判定点)。 - if compat != 1 && then_ti != TI_NEVER && else_ti != TI_NEVER { - if stmt_diverges(else_node) == 0 { - diag_type_incompatible(compat, EC_TC_IF_BRANCH, "If branches have different types", ast_line(node), ast_col(node)); - } - } - return then_ti; - } - return TI_UNIT; - } - - if ast_kind(node) == EXPR_GO { + if compat != 1 && then_ti != TI_NEVER && else_ti != TI_NEVER: + if stmt_diverges(else_node) == 0: + diag_type_incompatible(compat, EC_TC_IF_BRANCH, "If branches have different types", ast_line(node), ast_col(node)) + return then_ti + return TI_UNIT + + if ast_kind(node) == EXPR_GO: // a=-1, b=body; c=iter_ni (>=0 for range mode) - body := ast_b(node); + body := ast_b(node) // **range-go 迭代变量绑定**(2026-09-16 #2026-09-16-31 批 T4;维护者裁 (i)):`go i a..b body` 的 // 语义**就是绑定 `i`**(ir_gen 侧按 `EXPR_GO.c` 使用该名),而本分支此前**不绑** ⇒ // checker 与语言语义不一致(checker 缺口,非误报豁免问题)。 @@ -3414,258 +3447,245 @@ fn infer_expr(node: int) -> int { // 绑定语义与 `for` **同源**(先例 `checker.cr:3039-3051`):**int 局部**(与 ir_gen 的 // `iter_var_ni` 用法一致)+ **作用域严格限 body**(进前绑、出后恢复); // `ast_c(node) <= 0`(单发形 `go f(x)`)**不绑、完全不受影响**(硬条件 1)。 - iter_ni := ast_c(node); - scoped : ., mut = 0; - push_borrow_scope(); - if iter_ni > 0 { - push_scope(); - def_sym(iter_ni, SYM_LOCAL, TI_INT, -1); - scoped = 1; - } - body_ti := infer_expr(body); - if scoped != 0 { pop_scope(); } - pop_borrow_scope(); - rn := ast_data(node); - if rn <= 0 { - return body_ti; // single go: future of body type - } + iter_ni := ast_c(node) + scoped : ., mut = 0 + push_borrow_scope() + if iter_ni > 0: + push_scope() + def_sym(iter_ni, SYM_LOCAL, TI_INT, -1) + scoped = 1 + body_ti := infer_expr(body) + if scoped != 0: + pop_scope() + pop_borrow_scope() + rn := ast_data(node) + if rn <= 0: + return body_ti // single go: future of body type // Range go: returns array of body type (size from data=range_node) - range_node := ast_data(node); - rng_count := ast_b(range_node) - ast_a(range_node); + range_node := ast_data(node) + rng_count := ast_b(range_node) - ast_a(range_node) // 表示层概念(2026-09-10 语言面收窄裁决 §1):`[T; N]` 退役为「内联容量存储」表示提示(语义归处 = product / 序列+长度约束 / F11)——完整注记见本文件 res_type_node 的 EXPR_ARRAY 分支处,spec 见 docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md §1 - return alloc_type(TYP_ARRAY, body_ti, rng_count); - } + return alloc_type(TYP_ARRAY, body_ti, rng_count) - if ast_kind(node) == EXPR_YIELD { - val := ast_a(node); - val_ti : ., mut = TI_UNIT; - if val >= 0 { val_ti = infer_expr(val); } + if ast_kind(node) == EXPR_YIELD: + val := ast_a(node) + val_ti : ., mut = TI_UNIT + if val >= 0: + val_ti = infer_expr(val) // In a flow, the yield type is the flow's result type; return the value type - return val_ti; // yield's type is the yielded value's type - } + return val_ti // yield's type is the yielded value's type - if ast_kind(node) == EXPR_AWAIT { - val := ast_a(node); - val_ti := infer_expr(val); + if ast_kind(node) == EXPR_AWAIT: + val := ast_a(node) + val_ti := infer_expr(val) // If awaiting an array of T, return array element type T // If awaiting a single future, return the type directly - if get_type_kind(val_ti) == TYP_ARRAY { - return get_type_data(val_ti); // await [Future] → T - } - return val_ti; - } - - if ast_kind(node) == EXPR_LOOP { - push_borrow_scope(); - infer_expr(ast_a(node)); - pop_borrow_scope(); - return TI_UNIT; - } - - if ast_kind(node) == EXPR_WHILE { - cond := ast_a(node); - body := ast_b(node); - cond_ti := infer_expr(cond); + if get_type_kind(val_ti) == TYP_ARRAY: + return get_type_data(val_ti) // await [Future] → T + return val_ti + + if ast_kind(node) == EXPR_LOOP: + push_borrow_scope() + infer_expr(ast_a(node)) + pop_borrow_scope() + return TI_UNIT + + if ast_kind(node) == EXPR_WHILE: + cond := ast_a(node) + body := ast_b(node) + cond_ti := infer_expr(cond) // R2 P2b Task 4:查表(门形状 = ONE)。转录依据 = 本处改动前的 `cond_ti != TI_BOOL`; // IP_COND_BOOL 格**只含 bool**(`while 1` 现状 error[TC04],探针 N9 实测)。 - if iface_permits(iface_kind_of(cond_ti), IP_COND_BOOL) == 0 { - check_error(EC_TC_WHILE_COND, "While condition must be bool", ast_line(node), ast_col(node)); - } - push_borrow_scope(); - infer_expr(body); - pop_borrow_scope(); - return TI_UNIT; - } - - if ast_kind(node) == EXPR_FOR { - var_ni := ast_a(node); - iter := ast_b(node); - body := ast_c(node); - infer_expr(iter); - push_scope(); - push_borrow_scope(); - def_sym(var_ni, SYM_LOCAL, TI_INT, -1); - infer_expr(body); - pop_borrow_scope(); - pop_scope(); - return TI_UNIT; - } - - if ast_kind(node) == EXPR_RANGE { - st := infer_expr(ast_a(node)); - et := infer_expr(ast_b(node)); - if st != TI_INT { check_error(EC_TB_ADD, "Range start must be int", ast_line(node), ast_col(node)); } - if et != TI_INT { check_error(EC_TB_ADD, "Range end must be int", ast_line(node), ast_col(node)); } - return TI_INT; - } - - if ast_kind(node) == EXPR_MATCH { - match_expr := ast_a(node); - first_arm := ast_b(node); - match_ti := infer_expr(match_expr); - res : ., mut = TI_UNIT; - ai : ., mut = 0; - an : ., mut = first_arm; + if iface_permits(iface_kind_of(cond_ti), IP_COND_BOOL) == 0: + check_error(EC_TC_WHILE_COND, "While condition must be bool", ast_line(node), ast_col(node)) + push_borrow_scope() + infer_expr(body) + pop_borrow_scope() + return TI_UNIT + + if ast_kind(node) == EXPR_FOR: + var_ni := ast_a(node) + iter := ast_b(node) + body := ast_c(node) + infer_expr(iter) + push_scope() + push_borrow_scope() + def_sym(var_ni, SYM_LOCAL, TI_INT, -1) + infer_expr(body) + pop_borrow_scope() + pop_scope() + return TI_UNIT + + if ast_kind(node) == EXPR_RANGE: + st := infer_expr(ast_a(node)) + et := infer_expr(ast_b(node)) + if st != TI_INT: + check_error(EC_TB_ADD, "Range start must be int", ast_line(node), ast_col(node)) + if et != TI_INT: + check_error(EC_TB_ADD, "Range end must be int", ast_line(node), ast_col(node)) + return TI_INT + + if ast_kind(node) == EXPR_MATCH: + match_expr := ast_a(node) + first_arm := ast_b(node) + match_ti := infer_expr(match_expr) + res : ., mut = TI_UNIT + ai : ., mut = 0 + an : ., mut = first_arm // R2 P3 Task 3:穷尽性判定面(补集空性 + 具体变体反例)。收集与臂体推断同趟: // 模式类别/归属 → 模式项 CONS 链(m_pats)+ 覆盖位(m_cover)+ 不可映射标记 // (m_unmappable);臂体推断后统一判(判据本体与消费点封装见 ty_shadow.cr 末段)。 - m_pats : ., mut = tt_nil(); - mc_save := mc_begin(); // 容量批 T3:覆盖位图入栈(无界;旧态 = 单 int 2^vi) - m_unmappable : ., mut = 0; - m_wild : ., mut = 0; // 通配/绑定已见(冗余臂判据用;非穷尽性判据本体) - m_dup : ., mut = -1; // 首个冗余臂模式节点(-1 = 无) - loop { - if an < 0 { break; } - arm_pat := ast_a(an); // EXPR_ARM: a = pattern - arm_body := ast_b(an); // EXPR_ARM: b = body - if arm_pat >= 0 { - pk := sh_match_pat_kind(arm_pat); - if pk == 1 { - if m_wild != 0 { if m_dup < 0 { m_dup = arm_pat; } } - m_wild = 1; - m_pats = tt_cons(tt_top(), m_pats); - } else if pk == 2 { - vi := sh_match_pat_variant(match_ti, arm_pat); - vt : ., mut = -1; - if vi >= 0 { vt = sh_match_variant_term(match_ti, vi); } + m_pats : ., mut = tt_nil() + mc_save := mc_begin() // 容量批 T3:覆盖位图入栈(无界;旧态 = 单 int 2^vi) + m_unmappable : ., mut = 0 + m_wild : ., mut = 0 // 通配/绑定已见(冗余臂判据用;非穷尽性判据本体) + m_dup : ., mut = -1 // 首个冗余臂模式节点(-1 = 无) + loop: + if an < 0: + break + arm_pat := ast_a(an) // EXPR_ARM: a = pattern + arm_body := ast_b(an) // EXPR_ARM: b = body + if arm_pat >= 0: + pk := sh_match_pat_kind(arm_pat) + if pk == 1: + if m_wild != 0: + if m_dup < 0: + m_dup = arm_pat + m_wild = 1 + m_pats = tt_cons(tt_top(), m_pats) + else if pk == 2: + vi := sh_match_pat_variant(match_ti, arm_pat) + vt : ., mut = -1 + if vi >= 0: + vt = sh_match_variant_term(match_ti, vi) // R2 P3 Task 4:可选域(`T?`)——枚举归属不成立时试 `Some`/`None` 两分支 // (sh_match_opt_pat 对非可选 scrutinee 恒 -1 ⇒ 既有枚举/非枚举面零变化)。 - oi : ., mut = -1; - if vi < 0 { - oi = sh_match_opt_pat(match_ti, arm_pat); - if oi >= 0 { vt = sh_match_opt_term(match_ti, oi); } - } - if vt < 0 { - m_unmappable = 1; // 非本枚举/非本域/未声明变体名 ⇒ 不判(不得当 ∅/⊤) - } else { - ci : ., mut = vi; - if vi < 0 { ci = oi; } // 可选域:覆盖位 0 = 有值 / 1 = null - if m_wild != 0 { if m_dup < 0 { m_dup = arm_pat; } } - if mc_has(ci) != 0 { if m_dup < 0 { m_dup = arm_pat; } } - mc_add(ci); - m_pats = tt_cons(vt, m_pats); - } - } else { - m_unmappable = 1; // 字面量/struct 模式 ⇒ 不判(登记) - } - } + oi : ., mut = -1 + if vi < 0: + oi = sh_match_opt_pat(match_ti, arm_pat) + if oi >= 0: + vt = sh_match_opt_term(match_ti, oi) + if vt < 0: + m_unmappable = 1 // 非本枚举/非本域/未声明变体名 ⇒ 不判(不得当 ∅/⊤) + else: + ci : ., mut = vi + if vi < 0: + ci = oi + // 可选域:覆盖位 0 = 有值 / 1 = null + if m_wild != 0: + if m_dup < 0: + m_dup = arm_pat + if mc_has(ci) != 0: + if m_dup < 0: + m_dup = arm_pat + mc_add(ci) + m_pats = tt_cons(vt, m_pats) + else: + m_unmappable = 1 // 字面量/struct 模式 ⇒ 不判(登记) // Bind pattern variables in new scope - push_scope(); - if arm_pat >= 0 { - if ast_kind(arm_pat) == EXPR_ENUMPAT { + push_scope() + if arm_pat >= 0: + if ast_kind(arm_pat) == EXPR_ENUMPAT: // Bind sub-patterns - sub_pat := ast_b(arm_pat); - sub_count := ast_c(arm_pat); - spi : ., mut = 0; - spn : ., mut = sub_pat; - loop { - if spi >= sub_count { break; } - if spn >= 0 { - if ast_kind(spn) == EXPR_IDENT { - def_sym(ast_int_val(spn), SYM_LOCAL, TI_INT, -1); - } - spn = spn + 1; - } - spi = spi + 1; - } - } - if ast_kind(arm_pat) == EXPR_IDENT { - def_sym(ast_int_val(arm_pat), SYM_LOCAL, TI_INT, -1); - } - } - push_borrow_scope(); - arm_ti := infer_expr(arm_body); - pop_borrow_scope(); - if ai == 0 { res = arm_ti; } - pop_scope(); - an = ast_c(an); // next arm via linked list - ai = ai + 1; - } + sub_pat := ast_b(arm_pat) + sub_count := ast_c(arm_pat) + spi : ., mut = 0 + spn : ., mut = sub_pat + loop: + if spi >= sub_count: + break + if spn >= 0: + if ast_kind(spn) == EXPR_IDENT: + def_sym(ast_int_val(spn), SYM_LOCAL, TI_INT, -1) + spn = spn + 1 + spi = spi + 1 + if ast_kind(arm_pat) == EXPR_IDENT: + def_sym(ast_int_val(arm_pat), SYM_LOCAL, TI_INT, -1) + push_borrow_scope() + arm_ti := infer_expr(arm_body) + pop_borrow_scope() + if ai == 0: + res = arm_ti + pop_scope() + an = ast_c(an) // next arm via linked list + ai = ai + 1 // 穷尽性判定:引擎补集空性(预算前后隔离照 type_equal_engine 的窗口纪律)。 // 三态:0 = 不穷尽(诊断 + 具体反例变体名);1 = 穷尽;-1 = 不判(非枚举域/不可映射 // 模式/引擎未知)——**零诊断**(三态纪律:未知不得当「不穷尽」,也不得当「穷尽」)。 - ty_budget_reset(200000); - m_verdict := sh_match_exhaustive(match_ti, m_pats, m_unmappable); - ty_budget_reset(200000); - if m_verdict == 0 { - mi : ., mut = -1; - msg := "Non-exhaustive match"; - if get_type_kind(match_ti) == TYP_OPTIONAL { + ty_budget_reset(200000) + m_verdict := sh_match_exhaustive(match_ti, m_pats, m_unmappable) + ty_budget_reset(200000) + if m_verdict == 0: + mi : ., mut = -1 + msg := "Non-exhaustive match" + if get_type_kind(match_ti) == TYP_OPTIONAL: // `T?` 两分支反例命名(R2 P3 Task 4):0 = 有值(Some)/ 1 = null(None) - mi = mc_first_missing(2); - if mi == 0 { msg = msg + ": missing variant 'Some'"; } - if mi == 1 { msg = msg + ": missing variant 'None'"; } - } else { - ea := find_enum_row_of(match_ti); - if ea >= 0 { mi = mc_first_missing(ei_variant_count(ea)); } - if mi >= 0 { msg = msg + ": missing variant '" + istr_get(ei_variant_name(ea, mi)) + "'"; } - } - check_error(EC_TM_EXHAUST, msg, ast_line(node), ast_col(node)); - } - if m_dup >= 0 { - check_error(EC_TM_REDUNDANT, "Redundant match arm", ast_line(m_dup), ast_col(m_dup)); - } - mc_end(mc_save); // 容量批 T3:覆盖位图出栈(清零本层位 + 回退长度) - return res; - } - - if ast_kind(node) == EXPR_LET { - var_ni := ast_a(node); - type_node := ast_b(node); - val_node := ast_c(node); - val_ti := TI_UNIT; - if val_node >= 0 { - val_ti = infer_expr(val_node); + mi = mc_first_missing(2) + if mi == 0: + msg = msg + ": missing variant 'Some'" + if mi == 1: + msg = msg + ": missing variant 'None'" + else: + ea := find_enum_row_of(match_ti) + if ea >= 0: + mi = mc_first_missing(ei_variant_count(ea)) + if mi >= 0: + msg = msg + ": missing variant '" + istr_get(ei_variant_name(ea, mi)) + "'" + check_error(EC_TM_EXHAUST, msg, ast_line(node), ast_col(node)) + if m_dup >= 0: + check_error(EC_TM_REDUNDANT, "Redundant match arm", ast_line(m_dup), ast_col(m_dup)) + mc_end(mc_save) // 容量批 T3:覆盖位图出栈(清零本层位 + 回退长度) + return res + + if ast_kind(node) == EXPR_LET: + var_ni := ast_a(node) + type_node := ast_b(node) + val_node := ast_c(node) + val_ti := TI_UNIT + if val_node >= 0: + val_ti = infer_expr(val_node) // Check if value is a borrow (&x or &mut x), record the holder - if ast_kind(val_node) == EXPR_UNARY && ast_c(val_node) == UOP_REF { - borrowed_ni := borrow_var_name(ast_a(val_node)); - if borrowed_ni >= 0 { - mut_flag := ast_int_val(val_node); - record_borrow_holder(var_ni, borrowed_ni, mut_flag); - } - } - } - ti := val_ti; - if type_node >= 0 { ti = res_type_node(type_node); } + if ast_kind(val_node) == EXPR_UNARY && ast_c(val_node) == UOP_REF: + borrowed_ni := borrow_var_name(ast_a(val_node)) + if borrowed_ni >= 0: + mut_flag := ast_int_val(val_node) + record_borrow_holder(var_ni, borrowed_ni, mut_flag) + ti := val_ti + if type_node >= 0: + ti = res_type_node(type_node) // R2 P5 Task 6(TODO #2026-09-11-14):值/注解兼容检查(豁免面见 check_let_annot_compat 头注) - check_let_annot_compat(node, val_node, val_ti, ti); - if istr_get(var_ni) != "_" { - def_sym(var_ni, SYM_LOCAL, ti, -1); - if ti == TI_DYN && val_node >= 0 { - grow_dyn_type_sets(g_sym_count); - w64(g_dyn_type_sets, (g_sym_count - 1) * 8, 0); - dyn_set_type(g_sym_count - 1, val_ti); - } - } - return TI_UNIT; - } - - if ast_kind(node) == EXPR_RETURN { - if ast_a(node) >= 0 { - return infer_expr(ast_a(node)); - } - return TI_UNIT; - } - - if ast_kind(node) == EXPR_ENUM_CONSTRUCTOR { - name_idx := ast_a(node); - first_arg := ast_b(node); - arg_count := ast_c(node); - si := find_gsym(name_idx); - if si >= 0 && sym_kind(si) == SYM_FN { + check_let_annot_compat(node, val_node, val_ti, ti) + if istr_get(var_ni) != "_": + def_sym(var_ni, SYM_LOCAL, ti, -1) + if ti == TI_DYN && val_node >= 0: + grow_dyn_type_sets(g_sym_count) + w64(g_dyn_type_sets, (g_sym_count - 1) * 8, 0) + dyn_set_type(g_sym_count - 1, val_ti) + return TI_UNIT + + if ast_kind(node) == EXPR_RETURN: + if ast_a(node) >= 0: + return infer_expr(ast_a(node)) + return TI_UNIT + + if ast_kind(node) == EXPR_ENUM_CONSTRUCTOR: + name_idx := ast_a(node) + first_arg := ast_b(node) + arg_count := ast_c(node) + si := find_gsym(name_idx) + if si >= 0 && sym_kind(si) == SYM_FN: // Infer arg types (walk EXPR_ARG chain) - an : ., mut = first_arg; - loop { - if an < 0 { break; } - infer_expr(ast_a(an)); - an = ast_b(an); - } + an : ., mut = first_arg + loop: + if an < 0: + break + infer_expr(ast_a(an)) + an = ast_b(an) // 批 8(甲)刀 2:枚举构造器接入 S1P 台账(此前未覆盖——本分支同样早退)。 // **变体不注册 FuncInfo** ⇒ 形参型取自**枚举声明的变体载荷**(`s1p_enum_ring`)。 - s1p_enum_ring(name_idx, first_arg, arg_count); - return sym_type(si); // enum type - } - name := istr_get(name_idx); + s1p_enum_ring(name_idx, first_arg, arg_count) + return sym_type(si) // enum type + name := istr_get(name_idx) // ─── R2 P3 Task 4:内建可选构造器(退役内建 Option 注册后的解析路径)─── // `Some`/`None` 是**关键字**(lexer.cr 的 T_SOME/T_NONE 仅由这两个词产出)⇒ 本分派是 // 关键字名分派,不是「类型名分派」:用户声明同名**变体**时上面的 SYM_FN 命中优先 @@ -3676,124 +3696,105 @@ fn infer_expr(node: int) -> int { // IR_MAKE_ENUM + 字段存;EXPR_TRY 的 IR = 内层表达式)——本任务落**类型层**的联合/ // 可选语义,运行期表示统一(Some 值 vs 裸值)不在本任务 Files 面内(计划未列 ir_gen/ // 后端),登记为未覆盖面。 - if str_eq(name, "Some") != 0 { - at : ., mut = TI_UNIT; - if arg_count == 1 && first_arg >= 0 { - at = infer_expr(ast_a(first_arg)); - } else if arg_count > 1 { + if str_eq(name, "Some") != 0: + at : ., mut = TI_UNIT + if arg_count == 1 && first_arg >= 0: + at = infer_expr(ast_a(first_arg)) + else if arg_count > 1: // 多载荷(`Some(a, b)`):载荷行 = TYP_TUPLE(两趟落盘,照 EXPR_TUPLE 契约—— // 元素推断自身可向 g_gen_apply_data 追加数据,不得边推边写;见该分支注记)。 - tis : string, mut = alloc(arg_count * 8); - ai : ., mut = 0; - an2 : ., mut = first_arg; - loop { - if ai >= arg_count { break; } - ev : ., mut = TI_UNIT; - if an2 >= 0 { - ev = infer_expr(ast_a(an2)); - an2 = ast_b(an2); - } - w64(tis, ai * 8, ev); - ai = ai + 1; - } - ds := g_gen_apply_data_count; - grow_gen_apply_data(ds + arg_count); - ai = 0; - loop { - if ai >= arg_count { break; } - w64(g_gen_apply_data, (ds + ai) * 8, r64(tis, ai * 8)); - ai = ai + 1; - } - g_gen_apply_data_count = ds + arg_count; - at = alloc_type(TYP_TUPLE, arg_count, ds); - } - return alloc_type(TYP_OPTIONAL, at, 0); - } - if str_eq(name, "None") != 0 { - return alloc_type(TYP_NULL, 0, 0); - } - check_error(EC_N_UNDEFINED, "Undefined enum constructor '" + name + "'", ast_line(node), ast_col(node)); - return TI_UNIT; - } - - if ast_kind(node) == EXPR_FIELD { - obj := ast_a(node); - field_ni := ast_int_val(node); - obj_ti := infer_expr(obj); + tis : string, mut = alloc(arg_count * 8) + ai : ., mut = 0 + an2 : ., mut = first_arg + loop: + if ai >= arg_count: + break + ev : ., mut = TI_UNIT + if an2 >= 0: + ev = infer_expr(ast_a(an2)) + an2 = ast_b(an2) + w64(tis, ai * 8, ev) + ai = ai + 1 + ds := g_gen_apply_data_count + grow_gen_apply_data(ds + arg_count) + ai = 0 + loop: + if ai >= arg_count: + break + w64(g_gen_apply_data, (ds + ai) * 8, r64(tis, ai * 8)) + ai = ai + 1 + g_gen_apply_data_count = ds + arg_count + at = alloc_type(TYP_TUPLE, arg_count, ds) + return alloc_type(TYP_OPTIONAL, at, 0) + if str_eq(name, "None") != 0: + return alloc_type(TYP_NULL, 0, 0) + check_error(EC_N_UNDEFINED, "Undefined enum constructor '" + name + "'", ast_line(node), ast_col(node)) + return TI_UNIT + + if ast_kind(node) == EXPR_FIELD: + obj := ast_a(node) + field_ni := ast_int_val(node) + obj_ti := infer_expr(obj) // Auto-deref: if obj is a reference type, unwrap to inner type - actual_ti : ., mut = obj_ti; - if actual_ti >= 0 && actual_ti < g_type_count && get_type_kind(actual_ti) == TYP_REF { - actual_ti = get_type_data(actual_ti); - } + actual_ti : ., mut = obj_ti + if actual_ti >= 0 && actual_ti < g_type_count && get_type_kind(actual_ti) == TYP_REF: + actual_ti = get_type_data(actual_ti) // Handle generic apply: unwrap to base named type for struct lookup - if actual_ti >= 0 && actual_ti < g_type_count && get_type_kind(actual_ti) == TYP_GENERIC_APPLY { - actual_ti = get_type_data(actual_ti); - } - if actual_ti >= 0 && actual_ti < g_type_count && get_type_kind(actual_ti) == TYP_NAMED { - struct_ni := get_type_data(actual_ti); - si := find_struct(struct_ni); - if si >= 0 { - fi : ., mut = 0; - loop { - if fi >= si_field_count(si) { break; } - if si_field_name(si, fi) == field_ni { - ast_set_data(node, fi); // store field index for ir_gen - ast_set_c(node, struct_ni); // store struct name for ELF backend + if actual_ti >= 0 && actual_ti < g_type_count && get_type_kind(actual_ti) == TYP_GENERIC_APPLY: + actual_ti = get_type_data(actual_ti) + if actual_ti >= 0 && actual_ti < g_type_count && get_type_kind(actual_ti) == TYP_NAMED: + struct_ni := get_type_data(actual_ti) + si := find_struct(struct_ni) + if si >= 0: + fi : ., mut = 0 + loop: + if fi >= si_field_count(si): + break + if si_field_name(si, fi) == field_ni: + ast_set_data(node, fi) // store field index for ir_gen + ast_set_c(node, struct_ni) // store struct name for ELF backend // Resolve field type, substituting generic params if needed - ft_node := si_field_type_node(si, fi); - if ft_node >= 0 { - if ast_kind(ft_node) == EXPR_IDENT { - ft_name_idx := ast_int_val(ft_node); + ft_node := si_field_type_node(si, fi) + if ft_node >= 0: + if ast_kind(ft_node) == EXPR_IDENT: + ft_name_idx := ast_int_val(ft_node) // Check if this field type is a generic param (substitute if we have a generic apply) - if is_struct_generic(si, ft_name_idx) && get_type_kind(obj_ti) == TYP_GENERIC_APPLY { - base_ti := get_type_data(obj_ti); - ga_start := get_type_extra(obj_ti); - ga_count := r64(g_gen_apply_data, ga_start * 8); + if is_struct_generic(si, ft_name_idx) && get_type_kind(obj_ti) == TYP_GENERIC_APPLY: + base_ti := get_type_data(obj_ti) + ga_start := get_type_extra(obj_ti) + ga_count := r64(g_gen_apply_data, ga_start * 8) // Find which generic param index - gpi : ., mut = 0; - loop { - if gpi >= si_generic_count(si) { break; } - if si_generic_name(si, gpi) == ft_name_idx { + gpi : ., mut = 0 + loop: + if gpi >= si_generic_count(si): + break + if si_generic_name(si, gpi) == ft_name_idx: // Use the corresponding arg from the generic apply - if gpi < ga_count { - return r64(g_gen_apply_data, (ga_start + 1 + gpi) * 8); - } - break; - } - gpi = gpi + 1; - } - } - } - return res_type_node(ft_node); - } - return si_field_type(si, fi); - } - fi = fi + 1; - } - } - } + if gpi < ga_count: + return r64(g_gen_apply_data, (ga_start + 1 + gpi) * 8) + break + gpi = gpi + 1 + return res_type_node(ft_node) + return si_field_type(si, fi) + fi = fi + 1 // Tuple field access: t.0, t.1 - if actual_ti >= 0 && actual_ti < g_type_count && get_type_kind(actual_ti) == TYP_TUPLE { - field_name := istr_get(field_ni); - idx := str_int(field_name); - tc := get_type_data(actual_ti); - if idx >= 0 && idx < tc { - data_start := get_type_extra(actual_ti); - if ast_data(node) != idx { - ast_set_data(node, idx); - } - return r64(g_gen_apply_data, (data_start + idx) * 8); - } - } - return TI_UNIT; - } - - if ast_kind(node) == EXPR_INDEX { - arr_ti := infer_expr(ast_a(node)); - idx_ti := infer_expr(ast_b(node)); - arr_kind := get_type_kind(arr_ti); + if actual_ti >= 0 && actual_ti < g_type_count && get_type_kind(actual_ti) == TYP_TUPLE: + field_name := istr_get(field_ni) + idx := str_int(field_name) + tc := get_type_data(actual_ti) + if idx >= 0 && idx < tc: + data_start := get_type_extra(actual_ti) + if ast_data(node) != idx: + ast_set_data(node, idx) + return r64(g_gen_apply_data, (data_start + idx) * 8) + return TI_UNIT + + if ast_kind(node) == EXPR_INDEX: + arr_ti := infer_expr(ast_a(node)) + idx_ti := infer_expr(ast_b(node)) + arr_kind := get_type_kind(arr_ti) // Range index: arr[low..high] → slice type - if ast_kind(ast_b(node)) == EXPR_RANGE { + if ast_kind(ast_b(node)) == EXPR_RANGE: // R2 P3b Task 2:类别判定换位到**序列形状**(数组/切片同属 AK_SEQUENCE; // sh_shape_seq = ⊤ₖ(AK_SEQUENCE),见 iface_registry.cr 的横切形状段)。 // 固定性维度(N vs 视图)取自序列项的 b 槽(sh_seq_fixed_len_of_ti——表示层提示, @@ -3801,55 +3802,45 @@ fn infer_expr(node: int) -> int { // (数组)在 range 下产视图;切片/非序列现状 = TI_UNIT(IP_INDEX_RANGE 未接线, // 登记面 A.2 #15)。三态纪律:形状 -1(不可译行)**不**折算,回落旧 kind 直比 // (该行改动前由 `arr_kind == TYP_ARRAY` 独判 ⇒ 回落即逐行同结论)。 - seq_ok := iface_satisfies_term(arr_ti, sh_shape_seq()); - if seq_ok == -1 && arr_kind == TYP_ARRAY { seq_ok = 1; } - if seq_ok == 1 && sh_seq_fixed_len_of_ti(arr_ti) >= 0 { + seq_ok := iface_satisfies_term(arr_ti, sh_shape_seq()) + if seq_ok == -1 && arr_kind == TYP_ARRAY: + seq_ok = 1 + if seq_ok == 1 && sh_seq_fixed_len_of_ti(arr_ti) >= 0: // F11:字面量切片界编译期验证(TK05/06 既有错误码) - arr_len : ., mut = get_type_extra(arr_ti); - rn := ast_b(node); - if arr_len > 0 && ast_kind(ast_a(rn)) == EXPR_INT && ast_kind(ast_b(rn)) == EXPR_INT { - lo := ast_int_val(ast_a(rn)); - hi := ast_int_val(ast_b(rn)); - if lo < 0 || hi > arr_len { - check_error(EC_TK_SLICE_BOUNDS, "slice out of bounds: [" + int_str(lo) + ".." + int_str(hi) + "] (array length " + int_str(arr_len) + ")", ast_line(node), ast_col(node)); - } else if lo > hi { - check_error(EC_TK_SLICE_LEN, "slice length negative: [" + int_str(lo) + ".." + int_str(hi) + "]", ast_line(node), ast_col(node)); - } - } - return alloc_type(TYP_SLICE, get_type_data(arr_ti), 0); - } - return TI_UNIT; - } + arr_len : ., mut = get_type_extra(arr_ti) + rn := ast_b(node) + if arr_len > 0 && ast_kind(ast_a(rn)) == EXPR_INT && ast_kind(ast_b(rn)) == EXPR_INT: + lo := ast_int_val(ast_a(rn)) + hi := ast_int_val(ast_b(rn)) + if lo < 0 || hi > arr_len: + check_error(EC_TK_SLICE_BOUNDS, "slice out of bounds: [" + int_str(lo) + ".." + int_str(hi) + "] (array length " + int_str(arr_len) + ")", ast_line(node), ast_col(node)) + else if lo > hi: + check_error(EC_TK_SLICE_LEN, "slice length negative: [" + int_str(lo) + ".." + int_str(hi) + "]", ast_line(node), ast_col(node)) + return alloc_type(TYP_SLICE, get_type_data(arr_ti), 0) + return TI_UNIT // Regular index: arr[i] or slice[i] → element type - if arr_kind == TYP_ARRAY { + if arr_kind == TYP_ARRAY: // F2:字面量索引编译期越界检查(数组长度编译期可知时) - if ast_kind(ast_b(node)) == EXPR_INT { - idx_val := ast_int_val(ast_b(node)); - arr_len : ., mut = get_type_extra(arr_ti); - if arr_len > 0 && (idx_val < 0 || idx_val >= arr_len) { - check_error(EC_R_OOB, "index out of bounds: " + int_str(idx_val) + " (array length " + int_str(arr_len) + ")", ast_line(node), ast_col(node)); - } - } - return get_type_data(arr_ti); - } - if arr_kind == TYP_SLICE { - return get_type_data(arr_ti); // slice[i] → element type - } - if arr_ti == TI_STR { + if ast_kind(ast_b(node)) == EXPR_INT: + idx_val := ast_int_val(ast_b(node)) + arr_len : ., mut = get_type_extra(arr_ti) + if arr_len > 0 && (idx_val < 0 || idx_val >= arr_len): + check_error(EC_R_OOB, "index out of bounds: " + int_str(idx_val) + " (array length " + int_str(arr_len) + ")", ast_line(node), ast_col(node)) + return get_type_data(arr_ti) + if arr_kind == TYP_SLICE: + return get_type_data(arr_ti) // slice[i] → element type + if arr_ti == TI_STR: // A string is a byte sequence. Reject a statically known invalid // index instead of allowing a silent read past its terminator. - if ast_kind(ast_a(node)) == EXPR_STRING && ast_kind(ast_b(node)) == EXPR_INT { - string_len := istr_len(ast_int_val(ast_a(node))); - string_idx := ast_int_val(ast_b(node)); - if string_idx < 0 || string_idx >= string_len { + if ast_kind(ast_a(node)) == EXPR_STRING && ast_kind(ast_b(node)) == EXPR_INT: + string_len := istr_len(ast_int_val(ast_a(node))) + string_idx := ast_int_val(ast_b(node)) + if string_idx < 0 || string_idx >= string_len: check_error(EC_R_OOB, "string index out of bounds: " + int_str(string_idx) + " (length " + int_str(string_len) + ")", - ast_line(node), ast_col(node)); - } - } - return TI_INT; // string[i] → byte value - } + ast_line(node), ast_col(node)) + return TI_INT // string[i] → byte value // R2 P3b Task 2:兜底门从「许可位集直查」换位到**横切形状满足判定**(可索引形状 = // ⊤ₖ(SEQUENCE) ∪ ⊤ₖ(STRING),见 iface_registry.cr 的横切形状段)。与 P2b Task 5 的 // 表查同一口径:本门的**可达集** = 上方三个结果分支(arr→elem+F2 / slice→elem / @@ -3857,39 +3848,33 @@ fn infer_expr(node: int) -> int { // 与之逐行相等(全类型行枚举守门 = selftest `x2.indexable_matches_ops` + 既有 // `idx.gate_deny_covers_fallback`)。三态纪律:形状 -1(不可判:不可译行等)**不**折算成 // 0/1,而是**回落**既有许可表——改动前同类行本就走该表,故回落 = 逐行同结论。 - idx_ok := iface_satisfies_term(arr_ti, sh_shape_indexable()); - if idx_ok == -1 { idx_ok = iface_permits(iface_kind_of(arr_ti), IP_INDEX); } - if idx_ok != 1 { - check_error(EC_TK_INDEX, "Cannot index non-array type", ast_line(node), ast_col(node)); - } - return TI_INT; - } - - if ast_kind(node) == EXPR_ASSIGN { - target := ast_a(node); - val := ast_b(node); - tt := infer_expr(target); - vt := infer_expr(val); - if tt == TI_DYN { + idx_ok := iface_satisfies_term(arr_ti, sh_shape_indexable()) + if idx_ok == -1: + idx_ok = iface_permits(iface_kind_of(arr_ti), IP_INDEX) + if idx_ok != 1: + check_error(EC_TK_INDEX, "Cannot index non-array type", ast_line(node), ast_col(node)) + return TI_INT + + if ast_kind(node) == EXPR_ASSIGN: + target := ast_a(node) + val := ast_b(node) + tt := infer_expr(target) + vt := infer_expr(val) + if tt == TI_DYN: // dyn assignment: track the RHS type, skip strict type check - if ast_kind(target) == EXPR_IDENT { - target_ni := ast_int_val(target); - target_si := find_sym(target_ni); - if target_si >= 0 { - dyn_set_type(target_si, vt); - } - } - } else { + if ast_kind(target) == EXPR_IDENT: + target_ni := ast_int_val(target) + target_si := find_sym(target_ni) + if target_si >= 0: + dyn_set_type(target_si, vt) + else: // P3 Task 1 参序归一:赋值 = 目标(tt) ← 值(vt) ⇒ 源 = vt,目标 = tt - compat := type_compat_strict(vt, tt); - if compat != 1 { - diag_type_incompatible(compat, EC_TA_ASSIGN, "Assignment type mismatch", ast_line(node), ast_col(node)); - } - } - return vt; - } - - if ast_kind(node) == EXPR_STRUCT { + compat := type_compat_strict(vt, tt) + if compat != 1: + diag_type_incompatible(compat, EC_TA_ASSIGN, "Assignment type mismatch", ast_line(node), ast_col(node)) + return vt + + if ast_kind(node) == EXPR_STRUCT: // Struct literal: a = name idx, b = first field wrapper, c = field count。 // F5 契约(见 parser.cr struct 分支):wrapper 在 g_ast 中连续、wrapper.a=字段值节点; // 逐 wrapper 解引用(infer_expr 对 EXPR_NONE 前向)——直接按偏移取「下一个节点」当字段值 @@ -3900,205 +3885,189 @@ fn infer_expr(node: int) -> int { // **值按名字绑定**(与 Python bootstrap 的 gen_struct_lit 同语义;名字 → 声明下标, // 消费者 ir_gen 同步按名字取字段位):修复前值按**声明位序**绑定 ⇒ P{b:11, a:22} 静默 // 得 a=11(静默错值级,rc=0)。 - name_ni := ast_a(node); - si := find_struct_by_name(name_ni); - c := ast_c(node); - w0 := ast_b(node); + name_ni := ast_a(node) + si := find_struct_by_name(name_ni) + c := ast_c(node) + w0 := ast_b(node) // 名字信息齐备?(parser 恒写;克隆体丢名字 → 回落位序、不做名字类校验) - named : ., mut = 0; - if w0 >= 0 && c > 0 { - named = 1; - ni2 : ., mut = 0; - loop { - if ni2 >= c { break; } - if ast_b(w0 + ni2) < 0 { named = 0; break; } - ni2 = ni2 + 1; - } - } + named : ., mut = 0 + if w0 >= 0 && c > 0: + named = 1 + ni2 : ., mut = 0 + loop: + if ni2 >= c: + break + if ast_b(w0 + ni2) < 0: + named = 0 + break + ni2 = ni2 + 1 // didx[i] = 字面量第 i 个字段 → 声明字段下标(默认位序 = 无名字信息时的既有语义) - didx : string, mut = alloc((c + 1) * 8); - i : ., mut = 0; - loop { - if i >= c { break; } - w64(didx, i * 8, i); - i = i + 1; - } - if si >= 0 && (named != 0 || c == 0) { + didx : string, mut = alloc((c + 1) * 8) + i : ., mut = 0 + loop: + if i >= c: + break + w64(didx, i * 8, i) + i = i + 1 + if si >= 0 && (named != 0 || c == 0): // ── 名字 → 声明下标:未知字段 / 重复字段 / 缺字段 ── - fc := si_field_count(si); - used : string, mut = alloc((fc + 1) * 8); - j : ., mut = 0; - loop { - if j >= fc { break; } - w64(used, j * 8, 0); - j = j + 1; - } - if named != 0 { - i = 0; - loop { - if i >= c { break; } - nn := ast_b(w0 + i); - jdi := struct_field_index_by_name(si, nn); - if jdi < 0 { - check_error(EC_TS_UNKNOWN_FIELD, "Unknown field '" + istr_get(nn) + "' in struct literal " + istr_get(name_ni), ast_line(w0 + i), ast_col(w0 + i)); - } else { - if r64(used, jdi * 8) != 0 { - check_error(EC_TS_FIELD_DUP, "Field '" + istr_get(nn) + "' initialized more than once", ast_line(w0 + i), ast_col(w0 + i)); - } - w64(used, jdi * 8, 1); - w64(didx, i * 8, jdi); - } - i = i + 1; - } - } - j = 0; - loop { - if j >= fc { break; } - if r64(used, j * 8) == 0 { + fc := si_field_count(si) + used : string, mut = alloc((fc + 1) * 8) + j : ., mut = 0 + loop: + if j >= fc: + break + w64(used, j * 8, 0) + j = j + 1 + if named != 0: + i = 0 + loop: + if i >= c: + break + nn := ast_b(w0 + i) + jdi := struct_field_index_by_name(si, nn) + if jdi < 0: + check_error(EC_TS_UNKNOWN_FIELD, "Unknown field '" + istr_get(nn) + "' in struct literal " + istr_get(name_ni), ast_line(w0 + i), ast_col(w0 + i)) + else: + if r64(used, jdi * 8) != 0: + check_error(EC_TS_FIELD_DUP, "Field '" + istr_get(nn) + "' initialized more than once", ast_line(w0 + i), ast_col(w0 + i)) + w64(used, jdi * 8, 1) + w64(didx, i * 8, jdi) + i = i + 1 + j = 0 + loop: + if j >= fc: + break + if r64(used, j * 8) == 0: // 只报第一个缺字段(同一程序员错误不刷屏) - check_error(EC_TS_MISSING_FIELD, "Missing field '" + istr_get(si_field_name(si, j)) + "' in struct literal " + istr_get(name_ni), ast_line(node), ast_col(node)); - break; - } - j = j + 1; - } - } + check_error(EC_TS_MISSING_FIELD, "Missing field '" + istr_get(si_field_name(si, j)) + "' in struct literal " + istr_get(name_ni), ast_line(node), ast_col(node)) + break + j = j + 1 // ── 值类型逐个推断(一次/字段:infer_expr 有副作用,勿重复推断;结构体名未找到时 // 也要推断——嵌套诊断/dyn 记录等副作用在此,旧行为不可丢)── - vts : string, mut = alloc((c + 1) * 8); - i = 0; - loop { - if i >= c { break; } - if w0 >= 0 { w64(vts, i * 8, infer_expr(w0 + i)); } - i = i + 1; - } - if si >= 0 { - gc := si_generic_count(si); - if gc > 0 { + vts : string, mut = alloc((c + 1) * 8) + i = 0 + loop: + if i >= c: + break + if w0 >= 0: + w64(vts, i * 8, infer_expr(w0 + i)) + i = i + 1 + if si >= 0: + gc := si_generic_count(si) + if gc > 0: // ── 泛型结构体:字段类型 = 泛型参数 → 绑定(重复绑定走 unify 已绑定路径比对)── - g_gen_map_count = 0; g_gen_map_cap = 0; - i = 0; - loop { - if i >= c { break; } - jdi := r64(didx, i * 8); - if jdi >= 0 && jdi < si_field_count(si) { - dtn := si_field_type_node(si, jdi); - if dtn >= 0 && ast_kind(dtn) == EXPR_IDENT && is_struct_generic(si, ast_int_val(dtn)) { - pt := alloc_type(TYP_GENERIC_PARAM, ast_int_val(dtn), 0); - if !unify_types(pt, r64(vts, i * 8)) { - check_error(EC_TS_FIELD_TYPE, "Field '" + istr_get(si_field_name(si, jdi)) + "': expected " + istr_get(ast_int_val(dtn)) + ", got " + type_display(r64(vts, i * 8)), ast_line(w0 + i), ast_col(w0 + i)); - } - } - } - i = i + 1; - } - } + g_gen_map_count = 0 + g_gen_map_cap = 0 + i = 0 + loop: + if i >= c: + break + jdi := r64(didx, i * 8) + if jdi >= 0 && jdi < si_field_count(si): + dtn := si_field_type_node(si, jdi) + if dtn >= 0 && ast_kind(dtn) == EXPR_IDENT && is_struct_generic(si, ast_int_val(dtn)): + pt := alloc_type(TYP_GENERIC_PARAM, ast_int_val(dtn), 0) + if !unify_types(pt, r64(vts, i * 8)): + check_error(EC_TS_FIELD_TYPE, "Field '" + istr_get(si_field_name(si, jdi)) + "': expected " + istr_get(ast_int_val(dtn)) + ", got " + type_display(r64(vts, i * 8)), ast_line(w0 + i), ast_col(w0 + i)) + i = i + 1 // ── 非参数声明类型:值类型 vs 声明类型比对(两侧任一含未实例化泛型参数 → 跳过)── - i = 0; - loop { - if i >= c { break; } - jdi := r64(didx, i * 8); - if jdi >= 0 && jdi < si_field_count(si) { - dtn := si_field_type_node(si, jdi); - is_param : ., mut = 0; - if dtn >= 0 && ast_kind(dtn) == EXPR_IDENT && is_struct_generic(si, ast_int_val(dtn)) { is_param = 1; } - if is_param == 0 && type_node_mentions_struct_param(si, dtn) == 0 { - vt := r64(vts, i * 8); - if ti_has_generic_param(vt) == 0 { - dt := res_type_node(dtn); - if ti_has_generic_param(dt) == 0 { + i = 0 + loop: + if i >= c: + break + jdi := r64(didx, i * 8) + if jdi >= 0 && jdi < si_field_count(si): + dtn := si_field_type_node(si, jdi) + is_param : ., mut = 0 + if dtn >= 0 && ast_kind(dtn) == EXPR_IDENT && is_struct_generic(si, ast_int_val(dtn)): + is_param = 1 + if is_param == 0 && type_node_mentions_struct_param(si, dtn) == 0: + vt := r64(vts, i * 8) + if ti_has_generic_param(vt) == 0: + dt := res_type_node(dtn) + if ti_has_generic_param(dt) == 0: // P3 Task 1 参序归一:源 = 值类型(vt),目标 = 声明类型(dt) - verdict := type_compat_strict(vt, dt); - if verdict != 1 { - diag_type_incompatible(verdict, EC_TS_FIELD_TYPE, "Field '" + istr_get(si_field_name(si, jdi)) + "': expected " + type_display(dt) + ", got " + type_display(vt), ast_line(w0 + i), ast_col(w0 + i)); - } - } - } - } - } - i = i + 1; - } - if gc > 0 { + verdict := type_compat_strict(vt, dt) + if verdict != 1: + diag_type_incompatible(verdict, EC_TS_FIELD_TYPE, "Field '" + istr_get(si_field_name(si, jdi)) + "': expected " + type_display(dt) + ", got " + type_display(vt), ast_line(w0 + i), ast_col(w0 + i)) + i = i + 1 + if gc > 0: // ── 结果类型 TYP_GENERIC_APPLY:实参按**参数声明序**取映射 ── // (旧代码按字面量字段序写映射 + 直取映射序 = 参数序 ≠ 字段序时实参错位) - base_ti := alloc_named_type(name_ni); - ds := g_gen_apply_data_count; - grow_gen_apply_data(ds + 1 + gc); - g_gen_apply_data_count = ds + 1; - found : ., mut = 0; - g : ., mut = 0; - loop { - if g >= gc { break; } - pni := si_generic_name(si, g); - bind : ., mut = -1; - mi : ., mut = 0; - loop { - if mi >= g_gen_map_count { break; } - if r64(g_gen_map_names, mi * 8) == pni { bind = r64(g_gen_map_types, mi * 8); break; } - mi = mi + 1; - } - if bind >= 0 { - w64(g_gen_apply_data, (ds + 1 + found) * 8, bind); - found = found + 1; - } - g = g + 1; - } - w64(g_gen_apply_data, ds * 8, found); - g_gen_apply_data_count = ds + 1 + found; - return alloc_type(TYP_GENERIC_APPLY, base_ti, ds); - } - return alloc_named_type(name_ni); - } + base_ti := alloc_named_type(name_ni) + ds := g_gen_apply_data_count + grow_gen_apply_data(ds + 1 + gc) + g_gen_apply_data_count = ds + 1 + found : ., mut = 0 + g : ., mut = 0 + loop: + if g >= gc: + break + pni := si_generic_name(si, g) + bind : ., mut = -1 + mi : ., mut = 0 + loop: + if mi >= g_gen_map_count: + break + if r64(g_gen_map_names, mi * 8) == pni: + bind = r64(g_gen_map_types, mi * 8) + break + mi = mi + 1 + if bind >= 0: + w64(g_gen_apply_data, (ds + 1 + found) * 8, bind) + found = found + 1 + g = g + 1 + w64(g_gen_apply_data, ds * 8, found) + g_gen_apply_data_count = ds + 1 + found + return alloc_type(TYP_GENERIC_APPLY, base_ti, ds) + return alloc_named_type(name_ni) // 结构体名未找到:既有行为(不在此报错,返回具名类型) - return alloc_named_type(name_ni); - } + return alloc_named_type(name_ni) - if ast_kind(node) == EXPR_ARRAY { + if ast_kind(node) == EXPR_ARRAY: // Array literal(F5 契约,见 parser.cr 下标分支):a = first wrapper(连续), // b = elem count;wrapper.a=元素值节点(infer_expr 对 EXPR_NONE 前向)——不得按偏移 // 直取相邻节点当元素,复合元素子树占多槽会整体错位(静默错型/错值)。 // TODO #2026-09-11-11 ③:元素**同质性**检查——旧代码逐个覆盖 elem_ti(最终 = **最后一个**元素的 // 类型),异质字面量 [1, "x", 3] 静默通过且类型随末元素漂移。现取首元素类型为元素类型 // (与 Python bootstrap 的 ArrayLit 同语义),后续元素逐个与首元素比对(TK02)。 - elem_ti := TI_INT; // 空字面量 []:沿用旧默认 - ei : ., mut = 0; - en : ., mut = ast_a(node); - loop { - if ei >= ast_b(node) { break; } - if en >= 0 { - eti := infer_expr(en); - if ei == 0 { - elem_ti = eti; - } else { + elem_ti := TI_INT // 空字面量 []:沿用旧默认 + ei : ., mut = 0 + en : ., mut = ast_a(node) + loop: + if ei >= ast_b(node): + break + if en >= 0: + eti := infer_expr(en) + if ei == 0: + elem_ti = eti + else: // 两侧任一含未实例化泛型参数 → 跳过(不假拒,见 ti_has_generic_param) - if ti_has_generic_param(elem_ti) == 0 && ti_has_generic_param(eti) == 0 { + if ti_has_generic_param(elem_ti) == 0 && ti_has_generic_param(eti) == 0: // P3 Task 1 参序归一:源 = 本元素(eti),目标 = 首元素定下的元素类型(elem_ti) - verdict := type_compat_strict(eti, elem_ti); - if verdict != 1 { - diag_type_incompatible(verdict, EC_TK_ELEM_TYPE, "Expected array element type " + type_display(elem_ti) + ", got " + type_display(eti), ast_line(en), ast_col(en)); - } - } - } - en = en + 1; - } - ei = ei + 1; - } + verdict := type_compat_strict(eti, elem_ti) + if verdict != 1: + diag_type_incompatible(verdict, EC_TK_ELEM_TYPE, "Expected array element type " + type_display(elem_ti) + ", got " + type_display(eti), ast_line(en), ast_col(en)) + en = en + 1 + ei = ei + 1 // 表示层概念(2026-09-10 语言面收窄裁决 §1):`[T; N]` 退役为「内联容量存储」表示提示(语义归处 = product / 序列+长度约束 / F11)——完整注记见本文件 res_type_node 的 EXPR_ARRAY 分支处,spec 见 docs/superpowers/specs/2026-09-10-language-surface-narrowing-design.md §1 - return alloc_type(TYP_ARRAY, elem_ti, ast_b(node)); - } - - if ast_kind(node) == EXPR_BREAK { return TI_UNIT; } - if ast_kind(node) == EXPR_CONTINUE { return TI_UNIT; } - if ast_kind(node) == EXPR_WILDCARD { return TI_UNIT; } - if ast_kind(node) == EXPR_MOVE { - return infer_expr(ast_a(node)); - } - if ast_kind(node) == EXPR_UNSAFE { - push_unsafe_scope(); - ret := infer_expr(ast_a(node)); - pop_unsafe_scope(); - return ret; - } - if ast_kind(node) == EXPR_TRY { + return alloc_type(TYP_ARRAY, elem_ti, ast_b(node)) + + if ast_kind(node) == EXPR_BREAK: + return TI_UNIT + if ast_kind(node) == EXPR_CONTINUE: + return TI_UNIT + if ast_kind(node) == EXPR_WILDCARD: + return TI_UNIT + if ast_kind(node) == EXPR_MOVE: + return infer_expr(ast_a(node)) + if ast_kind(node) == EXPR_UNSAFE: + push_unsafe_scope() + ret := infer_expr(ast_a(node)) + pop_unsafe_scope() + return ret + if ast_kind(node) == EXPR_TRY: // R2 P3 Task 4:`?` 解包改按**类型项结构**(spec §5.4),废掉基名字符串判断 // (旧实现按 `base_name == "Option" || base_name == "Result"` 取第一个类型实参—— // 与「可选不再依赖内建 Option 枚举名」相悖,且对用户自定义枚举按名字猜测语义)。 @@ -4110,132 +4079,136 @@ fn infer_expr(node: int) -> int { // 故保守不动(如实登记:`None?` 的类型 = null 自身)。 // 其余(命名行/泛型应用行/原生行)**一律不解包**(旧行为:名字命中 Option/Result 才解包; // 用户枚举不再按名字猜——语义面登记见任务报告「收紧清单/语义保持」双表)。 - inner_ti := infer_expr(ast_a(node)); - if get_type_kind(inner_ti) == TYP_OPTIONAL { - return get_type_data(inner_ti); - } - return inner_ti; - } - if ast_kind(node) == EXPR_STRUCTPAT { - return TI_UNIT; - } - if ast_kind(node) == EXPR_AS { + inner_ti := infer_expr(ast_a(node)) + if get_type_kind(inner_ti) == TYP_OPTIONAL: + return get_type_data(inner_ti) + return inner_ti + if ast_kind(node) == EXPR_STRUCTPAT: + return TI_UNIT + if ast_kind(node) == EXPR_AS: // expr as Type — type cast - inner_ti := infer_expr(ast_a(node)); - type_node := ast_b(node); - target_ti := res_type_node(type_node); - if get_type_kind(target_ti) == TYP_PTR { - inner_kind := get_type_kind(inner_ti); - asp : ., mut = 1; - if inner_kind == TYP_PTR { - asp = get_type_extra(inner_ti); - } else if inner_kind == TYP_REF { - asp = 0; - } - return alloc_type(TYP_PTR, get_type_data(target_ti), asp); - } - return target_ti; - } - if ast_kind(node) == EXPR_STMT { - infer_expr(ast_a(node)); - return TI_UNIT; - } - if ast_kind(node) == EXPR_TUPLE { + inner_ti := infer_expr(ast_a(node)) + type_node := ast_b(node) + target_ti := res_type_node(type_node) + if get_type_kind(target_ti) == TYP_PTR: + inner_kind := get_type_kind(inner_ti) + asp : ., mut = 1 + if inner_kind == TYP_PTR: + asp = get_type_extra(inner_ti) + else if inner_kind == TYP_REF: + asp = 0 + return alloc_type(TYP_PTR, get_type_data(target_ti), asp) + return target_ti + if ast_kind(node) == EXPR_STMT: + infer_expr(ast_a(node)) + return TI_UNIT + if ast_kind(node) == EXPR_TUPLE: // Tuple: create a TYP_TUPLE type with element types // F5 契约:a=首 wrapper(g_ast 中连续)、b=元素个数;wrapper.a = 元素值节点。 // 复合元素(如 [1,2,3])的值节点自身不连续,必须经 wrapper 解引用—— // 直读 `elem_idx + e` 会把元素子节点当元素(类型错录 → 假拒 + soundness 漏放)。 - elem_idx := ast_a(node); - ec : ., mut = ast_b(node); + elem_idx := ast_a(node) + ec : ., mut = ast_b(node) // 元素类型**两趟**记录(F5 第二根因):先逐个推断(元素的推断自身可能向 // g_gen_apply_data 追加数据——嵌套元组 / 泛型应用 / 泛型结构字面量的 // g_gen_map 段),再一次性连续落盘。若照旧在循环前取 data_start 边推边写, // 前面元素追加的数据会把后续元素的位置顶开,extra 与实际落点错位(实测: // ((2,3),1) 的元素表被读成内层元组的字段 [int,int] → 嵌套元组异型互赋静默通过)。 - tis : string, mut = alloc(ec * 8); - e : ., mut = 0; - loop { - if e >= ec { break; } - wn : ., mut = -1; - if elem_idx >= 0 { wn = ast_a(elem_idx + e); } - w64(tis, e * 8, infer_expr(wn)); - e = e + 1; - } - data_start := g_gen_apply_data_count; - grow_gen_apply_data(data_start + ec); - e = 0; - loop { - if e >= ec { break; } - w64(g_gen_apply_data, (data_start + e) * 8, r64(tis, e * 8)); - e = e + 1; - } - g_gen_apply_data_count = data_start + ec; - return alloc_type(TYP_TUPLE, ec, data_start); - } - - if ast_kind(node) == EXPR_AT { - name_ni := ast_a(node); - name := istr_get(name_ni); - args := ast_b(node); + tis : string, mut = alloc(ec * 8) + e : ., mut = 0 + loop: + if e >= ec: + break + wn : ., mut = -1 + if elem_idx >= 0: + wn = ast_a(elem_idx + e) + w64(tis, e * 8, infer_expr(wn)) + e = e + 1 + data_start := g_gen_apply_data_count + grow_gen_apply_data(data_start + ec) + e = 0 + loop: + if e >= ec: + break + w64(g_gen_apply_data, (data_start + e) * 8, r64(tis, e * 8)) + e = e + 1 + g_gen_apply_data_count = data_start + ec + return alloc_type(TYP_TUPLE, ec, data_start) + + if ast_kind(node) == EXPR_AT: + name_ni := ast_a(node) + name := istr_get(name_ni) + args := ast_b(node) // @sizeOf(T) — 1 type argument - if str_eq(name, "sizeOf") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@sizeOf requires a type argument", ast_line(node), ast_col(node)); return TI_NEVER; } - ti := res_type_node(args); - if ti < 0 { check_error(EC_N_UNDEFINED, "@sizeOf: unknown type", ast_line(node), ast_col(node)); return TI_NEVER; } - return TI_INT; - } + if str_eq(name, "sizeOf") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@sizeOf requires a type argument", ast_line(node), ast_col(node)) + return TI_NEVER + ti := res_type_node(args) + if ti < 0: + check_error(EC_N_UNDEFINED, "@sizeOf: unknown type", ast_line(node), ast_col(node)) + return TI_NEVER + return TI_INT // @addr(fn) — function address, type int - if str_eq(name, "addr") != 0 { - ast_set_type_val(node, TI_INT); // function address is an int - return TI_INT; - } + if str_eq(name, "addr") != 0: + ast_set_type_val(node, TI_INT) // function address is an int + return TI_INT // @alignOf(T) — 1 type argument - if str_eq(name, "alignOf") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@alignOf requires a type argument", ast_line(node), ast_col(node)); return TI_NEVER; } - ti := res_type_node(args); - if ti < 0 { check_error(EC_N_UNDEFINED, "@alignOf: unknown type", ast_line(node), ast_col(node)); return TI_NEVER; } - return TI_INT; - } + if str_eq(name, "alignOf") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@alignOf requires a type argument", ast_line(node), ast_col(node)) + return TI_NEVER + ti := res_type_node(args) + if ti < 0: + check_error(EC_N_UNDEFINED, "@alignOf: unknown type", ast_line(node), ast_col(node)) + return TI_NEVER + return TI_INT // @fields(T) — 1 type argument, returns []string - if str_eq(name, "fields") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@fields requires a type argument", ast_line(node), ast_col(node)); return TI_NEVER; } - ti := res_type_node(args); - return TI_STR; - } + if str_eq(name, "fields") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@fields requires a type argument", ast_line(node), ast_col(node)) + return TI_NEVER + ti := res_type_node(args) + return TI_STR // @hasField(T, name) — type + string - if str_eq(name, "hasField") != 0 { - if args < 0 || ast_b(args) < 0 { check_error(EC_N_UNDEFINED, "@hasField requires 2 args", ast_line(node), ast_col(node)); return TI_NEVER; } - ti := res_type_node(ast_a(args)); - return TI_BOOL; - } + if str_eq(name, "hasField") != 0: + if args < 0 || ast_b(args) < 0: + check_error(EC_N_UNDEFINED, "@hasField requires 2 args", ast_line(node), ast_col(node)) + return TI_NEVER + ti := res_type_node(ast_a(args)) + return TI_BOOL // @field(T, name) — type + string, returns FieldInfo - if str_eq(name, "field") != 0 { - if args < 0 || ast_b(args) < 0 { check_error(EC_N_UNDEFINED, "@field requires 2 args", ast_line(node), ast_col(node)); return TI_NEVER; } - ti := res_type_node(ast_a(args)); - return TI_INT; - } + if str_eq(name, "field") != 0: + if args < 0 || ast_b(args) < 0: + check_error(EC_N_UNDEFINED, "@field requires 2 args", ast_line(node), ast_col(node)) + return TI_NEVER + ti := res_type_node(ast_a(args)) + return TI_INT // @typeInfo(T) — returns TypeInfo - if str_eq(name, "typeInfo") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@typeInfo requires a type argument", ast_line(node), ast_col(node)); return TI_NEVER; } - ti := res_type_node(args); + if str_eq(name, "typeInfo") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@typeInfo requires a type argument", ast_line(node), ast_col(node)) + return TI_NEVER + ti := res_type_node(args) // 返回型 = **类型名串**(与 ir_gen 的发射面一致:该分支构造 `"int"`/`"bool"`/… 或命名行名字)。 // 契约出处 = `TODO.md` 的 `@` 内建清单「`@typeInfo(T)` — 类型名称字符串」。 // 修复前此处恒 `TI_INT`(原注释自承「placeholder — returns handle」)⇒ **声明 int、产物 string** // ⇒ 消费点(`str_len(@typeInfo(X))` / `println(@typeInfo(X))`)在台账面被记为 p=3 vs a=0 的「异型」。 - return TI_STR; - } + return TI_STR // @raw_int(expr) — dex 表达式 → 缩放整数原值(显式转换,数值迁移 Task 4) - if str_eq(name, "raw_int") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@raw_int requires an expression", ast_line(node), ast_col(node)); return TI_NEVER; } - av := infer_expr(ast_a(args)); + if str_eq(name, "raw_int") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@raw_int requires an expression", ast_line(node), ast_col(node)) + return TI_NEVER + av := infer_expr(ast_a(args)) // 参数校验:**有「原值」语义的类型**才可取其原值—— // · dex(缩放位原值)· int(原值即其缩放值)· **地址型(地址字)**。 // @@ -4260,57 +4233,55 @@ fn infer_expr(node: int) -> int { // 正是该联合决策要避免的。 // 注:类型表下标 0..8 = 标量/占位(`TI_INT`..`TI_DEX_S`)⇒ 仅当 `av > TI_DEX_S` 才查表, // 否则会拿标量下标读到占位行的 kind(假阳性来源)。 - if av != TI_DEX && av != TI_INT && av != TI_NEVER { - if !(av > TI_DEX_S && (get_type_kind(av) == TYP_PTR || get_type_kind(av) == TYP_REF)) { - check_error(EC_TF_ARG_TYPE, "@raw_int requires a dex (or int) or address (pointer/reference) expression", ast_line(node), ast_col(node)); - return TI_NEVER; - } - } - return TI_INT; - } + if av != TI_DEX && av != TI_INT && av != TI_NEVER: + if !(av > TI_DEX_S && (get_type_kind(av) == TYP_PTR || get_type_kind(av) == TYP_REF)): + check_error(EC_TF_ARG_TYPE, "@raw_int requires a dex (or int) or address (pointer/reference) expression", ast_line(node), ast_col(node)) + return TI_NEVER + return TI_INT // @comptime(expr) — force compile-time eval - if str_eq(name, "comptime") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@comptime requires an expression", ast_line(node), ast_col(node)); return TI_NEVER; } - v := infer_expr(ast_a(args)); - ast_set_type_val(node, v); - return v; - } + if str_eq(name, "comptime") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@comptime requires an expression", ast_line(node), ast_col(node)) + return TI_NEVER + v := infer_expr(ast_a(args)) + ast_set_type_val(node, v) + return v // @inline(fn) — inline hint - if str_eq(name, "inline") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@inline requires a function argument", ast_line(node), ast_col(node)); return TI_NEVER; } - v := infer_expr(ast_a(args)); - ast_set_type_val(node, v); - return v; - } + if str_eq(name, "inline") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@inline requires a function argument", ast_line(node), ast_col(node)) + return TI_NEVER + v := infer_expr(ast_a(args)) + ast_set_type_val(node, v) + return v // @NoBoundsCheck — no args, unit - if str_eq(name, "NoBoundsCheck") != 0 { - return TI_UNIT; - } + if str_eq(name, "NoBoundsCheck") != 0: + return TI_UNIT // @fast — no args, unit - if str_eq(name, "fast") != 0 { - return TI_UNIT; - } + if str_eq(name, "fast") != 0: + return TI_UNIT // @unroll(n) — requires integer argument - if str_eq(name, "unroll") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@unroll requires an integer argument", ast_line(node), ast_col(node)); return TI_UNIT; } - return TI_UNIT; - } + if str_eq(name, "unroll") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@unroll requires an integer argument", ast_line(node), ast_col(node)) + return TI_UNIT + return TI_UNIT // @section(name) — requires string argument - if str_eq(name, "section") != 0 { - if args < 0 { check_error(EC_N_UNDEFINED, "@section requires a string argument", ast_line(node), ast_col(node)); return TI_UNIT; } - return TI_UNIT; - } + if str_eq(name, "section") != 0: + if args < 0: + check_error(EC_N_UNDEFINED, "@section requires a string argument", ast_line(node), ast_col(node)) + return TI_UNIT + return TI_UNIT // @hotpatch — function annotation, not an expression - if str_eq(name, "hotpatch") != 0 { - return TI_UNIT; - } + if str_eq(name, "hotpatch") != 0: + return TI_UNIT // ── 2(a) 视图内建:**同一个 64 位字的两种看法**(零转换、零拷贝、零运行期动作)── // `@ptr_of(s: string) -> int` · `@str_of(p: int) -> string` @@ -4319,41 +4290,33 @@ fn infer_expr(node: int) -> int { // 安全面(team-lead 裁 (ii)):**必须出现在 `unsafe` 块内**;块外 ⇒ 硬错(不做软约束—— // 没有机械判据的约定会腐烂)。`g_unsafe_depth` 由 EXPR_UNSAFE 分支压栈维护。 // 未知名仍走文件末尾的 fail-closed(EC_N_UNDEFINED),不得静默。 - if str_eq(name, "ptr_of") != 0 || str_eq(name, "str_of") != 0 { - if g_unsafe_depth == 0 { - check_error(EC_N_UNDEFINED, "@" + name + " must appear inside an `unsafe` block", ast_line(node), ast_col(node)); - return TI_NEVER; - } - if args < 0 { - check_error(EC_N_UNDEFINED, "@" + name + " requires exactly 1 argument", ast_line(node), ast_col(node)); - return TI_NEVER; - } - av := infer_expr(ast_a(args)); - if str_eq(name, "ptr_of") != 0 { - if av != TI_STR && av != TI_NEVER { - check_error(EC_TF_ARG_TYPE, "@ptr_of requires a string expression", ast_line(node), ast_col(node)); - return TI_NEVER; - } - return TI_INT; - } - if av != TI_INT && av != TI_NEVER { - check_error(EC_TF_ARG_TYPE, "@str_of requires an int expression", ast_line(node), ast_col(node)); - return TI_NEVER; - } - return TI_STR; - } - - check_error(EC_N_UNDEFINED, "unknown @ builtin: " + name, ast_line(node), ast_col(node)); - return TI_UNIT; - } - - return TI_UNIT; -} + if str_eq(name, "ptr_of") != 0 || str_eq(name, "str_of") != 0: + if g_unsafe_depth == 0: + check_error(EC_N_UNDEFINED, "@" + name + " must appear inside an `unsafe` block", ast_line(node), ast_col(node)) + return TI_NEVER + if args < 0: + check_error(EC_N_UNDEFINED, "@" + name + " requires exactly 1 argument", ast_line(node), ast_col(node)) + return TI_NEVER + av := infer_expr(ast_a(args)) + if str_eq(name, "ptr_of") != 0: + if av != TI_STR && av != TI_NEVER: + check_error(EC_TF_ARG_TYPE, "@ptr_of requires a string expression", ast_line(node), ast_col(node)) + return TI_NEVER + return TI_INT + if av != TI_INT && av != TI_NEVER: + check_error(EC_TF_ARG_TYPE, "@str_of requires an int expression", ast_line(node), ast_col(node)) + return TI_NEVER + return TI_STR + + check_error(EC_N_UNDEFINED, "unknown @ builtin: " + name, ast_line(node), ast_col(node)) + return TI_UNIT + + return TI_UNIT // --- Main entry --- -fn check_all() { - init_types(); +fn check_all(): + init_types() // 【已删除:SYM_SO_FN 保全缓冲】(第 4 批 #82/#83 T3,2026-09-17) // 原实现在此把 `SYM_SO_FN` 条目搬进 `alloc(128*8)` 三个临时数组、复位后再追加回去。 // 它随「`import` 期即注册 SO_FN」而存在;本批改为**侧表 + 首次引用时物化**后: @@ -4363,63 +4326,68 @@ fn check_all() { // 配合无上界的 `w64(so_names, so_count*8, …)`:索引 >128 行时越界,实测 N=2000 // 时对合法声明 `src/stdlib/io.cr:27 read_file` 报假诊断;N=200 时**产物不变但堆已坏**)。 // ⚠ 该缺陷的历史不得随代码删除而消失:#98 条目保留,状态记「随本批消除」。 - g_sym_count = 0; - g_scope_depth = 0; g_scope_bounds_cap = 0; - g_diag_count = 0; g_diag_cap = 0; - g_gen_map_count = 0; g_gen_map_cap = 0; - g_gen_apply_data_count = 0; - g_gen_apply_data_cap = 0; - g_gen_param_count = 0; g_gen_param_cap = 0; - g_dyn_type_set_count = 0; g_dyn_type_set_cap = 0; g_dyn_type_sets = ""; + g_sym_count = 0 + g_scope_depth = 0 + g_scope_bounds_cap = 0 + g_diag_count = 0 + g_diag_cap = 0 + g_gen_map_count = 0 + g_gen_map_cap = 0 + g_gen_apply_data_count = 0 + g_gen_apply_data_cap = 0 + g_gen_param_count = 0 + g_gen_param_cap = 0 + g_dyn_type_set_count = 0 + g_dyn_type_set_cap = 0 + g_dyn_type_sets = "" // First pass: collect declarations - collect_decls(); - init_builtins(); + collect_decls() + init_builtins() // 【已删除:SYM_SO_FN 回填循环】(同上 T3)——与上方保全缓冲同生共死; // 物化改由 `find_gsym`/`find_so_fn` 的侧表回退承担(首次引用时追加,天然在复位之后)。 // Register runtime builtins as proper SYM_FN (no .cr body, implemented in rt.s) // These must come after collect_decls so user-defined funcs take priority. - ri2 : ., mut = 0; - loop { - if ri2 >= g_rt_builtin_count { break; } - ni2 := r64(g_rt_builtin_names, ri2 * 8); - ti2 := r64(g_rt_builtin_ret_types, ri2 * 8); - if find_gsym(ni2) < 0 { // skip if already defined by user - si2 := g_sym_count; - grow_syms(si2 + 1); - sym_set_name(si2, ni2); - sym_set_kind(si2, SYM_FN); - sym_set_type(si2, ti2); - sym_set_node(si2, -1); - g_sym_count = si2 + 1; - } - ri2 = ri2 + 1; - } + ri2 : ., mut = 0 + loop: + if ri2 >= g_rt_builtin_count: + break + ni2 := r64(g_rt_builtin_names, ri2 * 8) + ti2 := r64(g_rt_builtin_ret_types, ri2 * 8) + if find_gsym(ni2) < 0: + // skip if already defined by user + si2 := g_sym_count + grow_syms(si2 + 1) + sym_set_name(si2, ni2) + sym_set_kind(si2, SYM_FN) + sym_set_type(si2, ti2) + sym_set_node(si2, -1) + g_sym_count = si2 + 1 + ri2 = ri2 + 1 // Second pass: check function bodies - i : ., mut = 0; - loop { - if i >= g_func_count { break; } - check_func(i); - i = i + 1; - } + i : ., mut = 0 + loop: + if i >= g_func_count: + break + check_func(i) + i = i + 1 // Check global let initializers - i = 0; - loop { - if i >= g_global_let_count { break; } - check_global_let(r64(g_global_lets, i * 8)); - i = i + 1; - } + i = 0 + loop: + if i >= g_global_let_count: + break + check_global_let(r64(g_global_lets, i * 8)) + i = i + 1 // Check impl-for relationships - check_impl_for(); + check_impl_for() // 批 6(T2/T3):规约标注面检查(形态 + 常量折叠的唯一判定面)。见 spec_check_all 头注。 - spec_check_all(); -} + spec_check_all() // ─── 批 6:规约标注面(`#check` / `#ensure`)──────────────────────────────────── // 本批边界(裁-V5/V6 + 裁-S4/S5/S9): @@ -4432,72 +4400,131 @@ fn check_all() { // 折叠结果侧信道:`g_spec_fold_ok` = 0 表示「本次折叠不可用(含子表达式不可折叠)」。 // 显式侧信道而非哨兵值(int 全域都是合法值 ⇒ 哨兵必然歧义)。 -g_spec_fold_ok : int, mut; +g_spec_fold_ok : int, mut // 常量折叠(int/bool 域;不可折叠 ⇒ g_spec_fold_ok = 0)。 // 覆盖 = C1 子集里**字面量闭合**的形态:int/bool 字面量 · 一元 `-`/`!` · 二元 算术/比较/逻辑。 // **不做代数化简**(如 `x*0`)——只折字面量,避免把「未证」误升为「已证」。 -fn spec_fold_val(e: int) -> int { - g_spec_fold_ok = 0; - if e < 0 { return 0; } - k := ast_kind(e); - if k == EXPR_INT { g_spec_fold_ok = 1; return ast_int_val(e); } - if k == EXPR_BOOL { g_spec_fold_ok = 1; return ast_int_val(e); } - if k == EXPR_UNARY { - op := ast_c(e); - v := spec_fold_val(ast_a(e)); - if g_spec_fold_ok == 0 { return 0; } - if op == UOP_NEG { g_spec_fold_ok = 1; return 0 - v; } - if op == UOP_NOT { g_spec_fold_ok = 1; if v == 0 { return 1; } return 0; } - g_spec_fold_ok = 0; return 0; - } - if k == EXPR_BINARY { - op := ast_c(e); - l := spec_fold_val(ast_a(e)); - if g_spec_fold_ok == 0 { return 0; } - r := spec_fold_val(ast_b(e)); - if g_spec_fold_ok == 0 { return 0; } - if op == OP_ADD { g_spec_fold_ok = 1; return l + r; } - if op == OP_SUB { g_spec_fold_ok = 1; return l - r; } - if op == OP_MUL { g_spec_fold_ok = 1; return l * r; } - if op == OP_DIV { if r == 0 { g_spec_fold_ok = 0; return 0; } g_spec_fold_ok = 1; return l / r; } - if op == OP_MOD { if r == 0 { g_spec_fold_ok = 0; return 0; } g_spec_fold_ok = 1; return l % r; } - if op == OP_EQ { g_spec_fold_ok = 1; if l == r { return 1; } return 0; } - if op == OP_NE { g_spec_fold_ok = 1; if l != r { return 1; } return 0; } - if op == OP_LT { g_spec_fold_ok = 1; if l < r { return 1; } return 0; } - if op == OP_GT { g_spec_fold_ok = 1; if l > r { return 1; } return 0; } - if op == OP_LE { g_spec_fold_ok = 1; if l <= r { return 1; } return 0; } - if op == OP_GE { g_spec_fold_ok = 1; if l >= r { return 1; } return 0; } - if op == OP_AND { g_spec_fold_ok = 1; if l != 0 && r != 0 { return 1; } return 0; } - if op == OP_OR { g_spec_fold_ok = 1; if l != 0 || r != 0 { return 1; } return 0; } - g_spec_fold_ok = 0; return 0; - } - return 0; // 变量 / 调用 / 字段 / 下标 / 字面量外一切 ⇒ 未证 -} +fn spec_fold_val(e: int) -> int: + g_spec_fold_ok = 0 + if e < 0: + return 0 + k := ast_kind(e) + if k == EXPR_INT: + g_spec_fold_ok = 1 + return ast_int_val(e) + if k == EXPR_BOOL: + g_spec_fold_ok = 1 + return ast_int_val(e) + if k == EXPR_UNARY: + op := ast_c(e) + v := spec_fold_val(ast_a(e)) + if g_spec_fold_ok == 0: + return 0 + if op == UOP_NEG: + g_spec_fold_ok = 1 + return 0 - v + if op == UOP_NOT: + g_spec_fold_ok = 1 + if v == 0: + return 1 + return 0 + g_spec_fold_ok = 0 + return 0 + if k == EXPR_BINARY: + op := ast_c(e) + l := spec_fold_val(ast_a(e)) + if g_spec_fold_ok == 0: + return 0 + r := spec_fold_val(ast_b(e)) + if g_spec_fold_ok == 0: + return 0 + if op == OP_ADD: + g_spec_fold_ok = 1 + return l + r + if op == OP_SUB: + g_spec_fold_ok = 1 + return l - r + if op == OP_MUL: + g_spec_fold_ok = 1 + return l * r + if op == OP_DIV: + if r == 0: + g_spec_fold_ok = 0 + return 0 + g_spec_fold_ok = 1 + return l / r + if op == OP_MOD: + if r == 0: + g_spec_fold_ok = 0 + return 0 + g_spec_fold_ok = 1 + return l % r + if op == OP_EQ: + g_spec_fold_ok = 1 + if l == r: + return 1 + return 0 + if op == OP_NE: + g_spec_fold_ok = 1 + if l != r: + return 1 + return 0 + if op == OP_LT: + g_spec_fold_ok = 1 + if l < r: + return 1 + return 0 + if op == OP_GT: + g_spec_fold_ok = 1 + if l > r: + return 1 + return 0 + if op == OP_LE: + g_spec_fold_ok = 1 + if l <= r: + return 1 + return 0 + if op == OP_GE: + g_spec_fold_ok = 1 + if l >= r: + return 1 + return 0 + if op == OP_AND: + g_spec_fold_ok = 1 + if l != 0 && r != 0: + return 1 + return 0 + if op == OP_OR: + g_spec_fold_ok = 1 + if l != 0 || r != 0: + return 1 + return 0 + g_spec_fold_ok = 0 + return 0 + return 0 // 变量 / 调用 / 字段 / 下标 / 字面量外一切 ⇒ 未证 // 规约标注面检查:逐条走侧表;**唯一硬错 = `#check(常量假)`**(`EC_V_CHECK_FALSE` = V01)。 // `#ensure` 本批不做常量红判定(后置条件在编译期无输入 ⇒ 常量假同样可判,但**留 T3 收口**: // 本条**只判 `#check`**,避免在 T2 扩大红面)。 -fn spec_check_all() { - i : ., mut = 0; - loop { - if i >= g_spec_count { break; } +fn spec_check_all(): + i : ., mut = 0 + loop: + if i >= g_spec_count: + break // T3:`#ensure` 的常量假同样可判定且必错 ⇒ 与 `#check` 同判(T2 只判了 #check)。 - ex := spec_expr(i); - v := spec_fold_val(ex); - if g_spec_fold_ok != 0 { - if v == 0 { - spec_set_status(i, SPEC_ST_RED); - nm : ., mut = "#check(...)"; - if spec_kind(i) == 1 { nm = "#ensure(...)"; } - check_error(EC_V_CHECK_FALSE, nm + " is statically false", spec_line(i), spec_col(i)); - } else { - spec_set_status(i, SPEC_ST_GREEN); - } - } - i = i + 1; - } -} + ex := spec_expr(i) + v := spec_fold_val(ex) + if g_spec_fold_ok != 0: + if v == 0: + spec_set_status(i, SPEC_ST_RED) + nm : ., mut = "#check(...)" + if spec_kind(i) == 1: + nm = "#ensure(...)" + check_error(EC_V_CHECK_FALSE, nm + " is statically false", spec_line(i), spec_col(i)) + else: + spec_set_status(i, SPEC_ST_GREEN) + i = i + 1 // ─── 效应/纯度修正 Task 1(P0 插队批):真纯度计算 ───────────────────────── // 语义出处:docs/superpowers/plans/2026-08-08-region-cfg.md:484「非纯调用才进链; @@ -4530,200 +4557,216 @@ fn spec_check_all() { // 冻结该判定(use_count 时序缺陷另批修)⇒ 删掉默认值会让 lazy 全部不发射、 // 发射面逐字节改变。真纯度在 IR 生成后由本函数覆盖写回。 -fn purity_op_effect(op: int) -> int { - if op == IR_STORE { return 1; } - if op == IR_STORE_FIELD { return 1; } - if op == IR_STORE_INDEX { return 1; } - if op == IR_STORE_INDEX_VAR { return 1; } - if op == IR_STORE_PTR { return 1; } - if op == IR_CALL_EXTERN { return 1; } - if op == IR_HOTPATCH_ROUTE { return 1; } - if op == IR_DYN_DISPATCH { return 1; } - if op == IR_SPAWN { return 1; } - if op == IR_YIELD { return 1; } - if op == IR_AWAIT { return 1; } - return 0; -} +fn purity_op_effect(op: int) -> int: + if op == IR_STORE: + return 1 + if op == IR_STORE_FIELD: + return 1 + if op == IR_STORE_INDEX: + return 1 + if op == IR_STORE_INDEX_VAR: + return 1 + if op == IR_STORE_PTR: + return 1 + if op == IR_CALL_EXTERN: + return 1 + if op == IR_HOTPATCH_ROUTE: + return 1 + if op == IR_DYN_DISPATCH: + return 1 + if op == IR_SPAWN: + return 1 + if op == IR_YIELD: + return 1 + if op == IR_AWAIT: + return 1 + return 0 // IR 函数序号(g_ir_func_* 表下标)→ 源 FuncInfo 下标;-1 = 越界(不可达防御)。 // 依据:IR 生成循环按源序**跳过泛型函数**发 IR;monomorph 实例只追加到 g_funcs // 末尾(唯一创建点 = ir_gen.cr 的调用点)⇒ IR 序 = 源序非泛型子序列 ++ 实例创建序, // 与本函数「按源序跳过泛型」的重放一致。调用方另按 g_ir_func_name_idx 复核名字, // 复核失败即保守判不纯(防映射漂移静默错标)。 -fn src_func_of_ir(irf: int) -> int { - cnt : ., mut = 0; - i : ., mut = 0; - loop { - if i >= g_func_count { return -1; } - if fi_generic_count(i) == 0 { - if cnt == irf { return i; } - cnt = cnt + 1; - } - i = i + 1; - } - return -1; -} +fn src_func_of_ir(irf: int) -> int: + cnt : ., mut = 0 + i : ., mut = 0 + loop: + if i >= g_func_count: + return -1 + if fi_generic_count(i) == 0: + if cnt == irf: + return i + cnt = cnt + 1 + i = i + 1 + return -1 // DF 节点序号 → 所属 IR 函数序号(-1 = 无)。g_df_func_node_start 单调 ⇒ 线性 // 取下界即上界;unsafe 区稀少,不值得为它引二分。 -fn df_func_of_node(pos: int) -> int { - best : ., mut = -1; - irf : ., mut = 0; - loop { - if irf >= g_ir_func_count { break; } - if r64(g_df_func_node_start, irf * 8) <= pos { best = irf; } - irf = irf + 1; - } - return best; -} - -fn compute_all_purity() { - fcount := g_func_count; - if fcount <= 0 { return; } - if g_ir_func_count <= 0 { return; } // 无 IR 体(check-only 路径)⇒ 不覆盖默认值 +fn df_func_of_node(pos: int) -> int: + best : ., mut = -1 + irf : ., mut = 0 + loop: + if irf >= g_ir_func_count: + break + if r64(g_df_func_node_start, irf * 8) <= pos: + best = irf + irf = irf + 1 + return best + +fn compute_all_purity(): + fcount := g_func_count + if fcount <= 0: + return + if g_ir_func_count <= 0: + return + // 无 IR 体(check-only 路径)⇒ 不覆盖默认值 // 侧表(本函数自持):local = 局部效应/硬不纯位;pure = 当前纯度工作值; // callee = 每条 IR 指令的可解析被调 fi(-1 = 非调用;不可解析记在 local 位)。 // alloc 不保证清零(rt.s bump 分配器)⇒ 三表全部显式初始化。 - local := alloc(fcount * 8); - pure := alloc(fcount * 8); - callee := alloc(g_ir_instr_count * 8); - z : ., mut = 0; - loop { - if z >= fcount { break; } - w64(local, z * 8, 0); - w64(pure, z * 8, 0); - z = z + 1; - } - z = 0; - loop { - if z >= g_ir_instr_count { break; } - w64(callee, z * 8, -1); - z = z + 1; - } + local := alloc(fcount * 8) + pure := alloc(fcount * 8) + callee := alloc(g_ir_instr_count * 8) + z : ., mut = 0 + loop: + if z >= fcount: + break + w64(local, z * 8, 0) + w64(pure, z * 8, 0) + z = z + 1 + z = 0 + loop: + if z >= g_ir_instr_count: + break + w64(callee, z * 8, -1) + z = z + 1 // ── 1) 逐 IR 函数扫体:局部效应位 + 调用边解析 ── - irf : ., mut = 0; - loop { - if irf >= g_ir_func_count { break; } - sfi := src_func_of_ir(irf); - map_ok : ., mut = 1; - if sfi < 0 { map_ok = 0; } - else if r64(g_ir_func_name_idx, irf * 8) != fi_name(sfi) { map_ok = 0; } - else if ast_kind(fi_ast_node(sfi)) == EXPR_EXTERN { map_ok = 0; } - if map_ok == 0 { + irf : ., mut = 0 + loop: + if irf >= g_ir_func_count: + break + sfi := src_func_of_ir(irf) + map_ok : ., mut = 1 + if sfi < 0: + map_ok = 0 + else if r64(g_ir_func_name_idx, irf * 8) != fi_name(sfi): + map_ok = 0 + else if ast_kind(fi_ast_node(sfi)) == EXPR_EXTERN: + map_ok = 0 + if map_ok == 0: // 映射漂移/extern 声明体(无可生成的体):保守判不纯 - if sfi >= 0 { w64(local, sfi * 8, 1); } - irf = irf + 1; continue; - } - istart := r64(g_ir_func_instr_start, irf * 8); - icnt := r64(g_ir_func_instr_count, irf * 8); - ii := istart; - loop { - if ii >= istart + icnt { break; } - op := iri_op(ii); - if purity_op_effect(op) != 0 { w64(local, sfi * 8, 1); } - if op == IR_CALL { - cf := find_func(iri_s3(ii)); - if cf < 0 { w64(local, sfi * 8, 1); } // 不可解析(runtime builtin)⇒ 不纯 - else { w64(callee, ii * 8, cf); } - } - if op == IR_INLINE { - cf2 := find_func(iri_s1(ii)); - if cf2 < 0 { w64(local, sfi * 8, 1); } - else { w64(callee, ii * 8, cf2); } - } - ii = ii + 1; - } - irf = irf + 1; - } + if sfi >= 0: + w64(local, sfi * 8, 1) + irf = irf + 1 + continue + istart := r64(g_ir_func_instr_start, irf * 8) + icnt := r64(g_ir_func_instr_count, irf * 8) + ii := istart + loop: + if ii >= istart + icnt: + break + op := iri_op(ii) + if purity_op_effect(op) != 0: + w64(local, sfi * 8, 1) + if op == IR_CALL: + cf := find_func(iri_s3(ii)) + if cf < 0: + w64(local, sfi * 8, 1) + // 不可解析(runtime builtin)⇒ 不纯 + else: + w64(callee, ii * 8, cf) + if op == IR_INLINE: + cf2 := find_func(iri_s1(ii)) + if cf2 < 0: + w64(local, sfi * 8, 1) + else: + w64(callee, ii * 8, cf2) + ii = ii + 1 + irf = irf + 1 // ── 2) unsafe 区 ⇒ 归属函数不纯(IR 无 unsafe opcode:效应藏在块内裸操作里; // 归属 = 区起始节点落在哪个函数的节点区间)── - si : ., mut = 0; - loop { - if si >= g_sg_count { break; } - if r64(g_sgs, si * ESZ_SG + OFF_SG_KIND) == SG_UNSAFE { - uf := df_func_of_node(r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART)); - if uf >= 0 { - usf := src_func_of_ir(uf); - if usf >= 0 { w64(local, usf * 8, 1); } - } - } - si = si + 1; - } + si : ., mut = 0 + loop: + if si >= g_sg_count: + break + if r64(g_sgs, si * ESZ_SG + OFF_SG_KIND) == SG_UNSAFE: + uf := df_func_of_node(r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART)) + if uf >= 0: + usf := src_func_of_ir(uf) + if usf >= 0: + w64(local, usf * 8, 1) + si = si + 1 // ── 3) 不动点:全不纯起点升纯(保守单调,语义见头注 ④)── - changed : ., mut = 1; - loop { - if changed == 0 { break; } - changed = 0; - irf = 0; - loop { - if irf >= g_ir_func_count { break; } - sf := src_func_of_ir(irf); - if sf >= 0 { - if r64(local, sf * 8) == 0 { - if r64(pure, sf * 8) == 0 { - ist2 := r64(g_ir_func_instr_start, irf * 8); - ic2 := r64(g_ir_func_instr_count, irf * 8); - allpure : ., mut = 1; - ii2 := ist2; - loop { - if ii2 >= ist2 + ic2 { break; } - c := r64(callee, ii2 * 8); - if c >= 0 { - if r64(pure, c * 8) == 0 { allpure = 0; break; } - } - ii2 = ii2 + 1; - } - if allpure != 0 { - w64(pure, sf * 8, 1); - changed = 1; - } - } - } - } - irf = irf + 1; - } - } + changed : ., mut = 1 + loop: + if changed == 0: + break + changed = 0 + irf = 0 + loop: + if irf >= g_ir_func_count: + break + sf := src_func_of_ir(irf) + if sf >= 0: + if r64(local, sf * 8) == 0: + if r64(pure, sf * 8) == 0: + ist2 := r64(g_ir_func_instr_start, irf * 8) + ic2 := r64(g_ir_func_instr_count, irf * 8) + allpure : ., mut = 1 + ii2 := ist2 + loop: + if ii2 >= ist2 + ic2: + break + c := r64(callee, ii2 * 8) + if c >= 0: + if r64(pure, c * 8) == 0: + allpure = 0 + break + ii2 = ii2 + 1 + if allpure != 0: + w64(pure, sf * 8, 1) + changed = 1 + irf = irf + 1 // ── 4) 泛型源(无 IR 体)回填:源纯度 = 实例合取(无实例 = 0)── - fi : ., mut = 0; - loop { - if fi >= fcount { break; } - if fi_generic_count(fi) > 0 { - ninst : ., mut = 0; - allp : ., mut = 1; - gi : ., mut = 0; - loop { - if gi >= g_purity_inst_count { break; } - if r64(g_purity_inst, gi * 24) == fi { - ninst = ninst + 1; - nf := r64(g_purity_inst, gi * 24 + 16); - if nf >= 0 && nf < fcount { - if r64(pure, nf * 8) == 0 { allp = 0; } - } else { allp = 0; } - } - gi = gi + 1; - } - if ninst > 0 && allp != 0 { w64(pure, fi * 8, 1); } - } - fi = fi + 1; - } + fi : ., mut = 0 + loop: + if fi >= fcount: + break + if fi_generic_count(fi) > 0: + ninst : ., mut = 0 + allp : ., mut = 1 + gi : ., mut = 0 + loop: + if gi >= g_purity_inst_count: + break + if r64(g_purity_inst, gi * 24) == fi: + ninst = ninst + 1 + nf := r64(g_purity_inst, gi * 24 + 16) + if nf >= 0 && nf < fcount: + if r64(pure, nf * 8) == 0: + allp = 0 + else: + allp = 0 + gi = gi + 1 + if ninst > 0 && allp != 0: + w64(pure, fi * 8, 1) + fi = fi + 1 // ── 5) 写回 ── - fi = 0; - loop { - if fi >= fcount { break; } - fi_set_ispure(fi, r64(pure, fi * 8)); - fi = fi + 1; - } -} + fi = 0 + loop: + if fi >= fcount: + break + fi_set_ispure(fi, r64(pure, fi * 8)) + fi = fi + 1 // 自测辅助:按名查纯度(-1 = 无此函数——与 0/1 区分,防「查不到」被当「不纯」)。 -fn fi_ispure_of(name_ni: int) -> int { - fi := find_func(name_ni); - if fi < 0 { return -1; } - return fi_ispure(fi); -} +fn fi_ispure_of(name_ni: int) -> int: + fi := find_func(name_ni) + if fi < 0: + return -1 + return fi_ispure(fi) diff --git a/src/compiler/cir_cache.cr b/src/compiler/cir_cache.cr index 240fee13..b6809331 100644 --- a/src/compiler/cir_cache.cr +++ b/src/compiler/cir_cache.cr @@ -47,7 +47,7 @@ // R2 P5 Task 2(D19 单槽化)后:盘上仍只有**一个** tk 字段(= 派生码,由 // sh_dfn_code_of_slots 产出),装载侧由它同时重派生**两槽**(项引用 + 辅码)—— // 盘面布局/版本位与 P4 逐字节相同(单槽化只在内存语义面)。 -CIR_CACHE_MAGIC : int = -4485090715960753727; +CIR_CACHE_MAGIC : int = -4485090715960753727 // 21:**串域跨进程 id 修复**(2026-09-18 · TODO #2026-09-18-9 · 计划 // `docs/superpowers/plans/2026-09-18-cir-cache-str-domain.md`)——快照内既存的 // **绝对 intern id**(指令/节点槽、var 名)在命中装载时被按**读侧**编号解释, @@ -132,11 +132,11 @@ CIR_CACHE_MAGIC : int = -4485090715960753727; // 变化**(与「快照携带会漂移的量」的 19/20/21 代不同族):即便身份闸失效,本代也不复活旧语义。 // ⚠ **同批登记**:指纹不覆盖函数体 ⇒ **身份闸是唯一防线**(同族 TODO #2026-09-17-17)—— // 若将来身份闸被移除/降级,任何**体级**编辑都会静默复活旧 IR。 -CIR_CACHE_VER : int = 22; +CIR_CACHE_VER : int = 22 -g_cir_write_buf : string, mut; -g_cir_write_pos : int, mut; -g_cir_write_cap : int, mut; +g_cir_write_buf : string, mut +g_cir_write_pos : int, mut +g_cir_write_cap : int, mut // === 编译器身份(TODO #2026-09-10-1)=== // 现象:缓存键 = 源路径::函数名 + 纯 AST 指纹(func_fingerprint/sig_fingerprint @@ -171,17 +171,17 @@ g_cir_write_cap : int, mut; // 不该有链边」这类**格式**变更);身份 = 自动细粒度(编译器内容驱动,覆盖 // 「同格式、不同前端行为」)。两者都必须匹配才命中——格式变更手工 bump, // 行为变更由身份自动接管,不必再记得 bump。 -g_cir_compiler_id : int, mut = 0; -g_cir_compiler_id_ready : int, mut = 0; +g_cir_compiler_id : int, mut = 0 +g_cir_compiler_id_ready : int, mut = 0 // 运行中编译器 ELF 的内容哈希(memoized)。0 = 取不到身份(无 procfs / // 读取失败 / 空文件)——调用方按「身份不可证」处理(关缓存,见两端点)。 -fn cir_compiler_identity() -> int { - if g_cir_compiler_id_ready != 0 { return g_cir_compiler_id; } - g_cir_compiler_id_ready = 1; - g_cir_compiler_id = cir_hash_running_binary(); - return g_cir_compiler_id; -} +fn cir_compiler_identity() -> int: + if g_cir_compiler_id_ready != 0: + return g_cir_compiler_id + g_cir_compiler_id_ready = 1 + g_cir_compiler_id = cir_hash_running_binary() + return g_cir_compiler_id // 单趟乘加哈希(FNV-1 64-bit 常数;本语言无 XOR 运算符——与 ir_gen.cr // func_fingerprint 同族写法)。8 字节字一步(load64 = 单条未对齐小端读; @@ -194,313 +194,317 @@ fn cir_compiler_identity() -> int { // open("/proc/self/exe")),身份不可得/无条目可查时不付。 // 非密码学用途(对侧不设敌手):它要区分的是「同一编译器的两次构建」,随机 // 差异撞上 2^-64 忽略;能写缓存文件的对手本来就能写任意载荷。 -fn cir_hash_running_binary() -> int { - fd := syscall3(2, "/proc/self/exe", 0, 0); // open(O_RDONLY) - if fd < 0 { return 0; } - buf := alloc(65536); - h : ., mut = -3750763034362895579; // FNV-1 64 offset basis(signed i64) - total : ., mut = 0; - loop { - n := syscall3(0, fd, buf, 65536); // read(fd, buf, 65536) - if n <= 0 { break; } - i : ., mut = 0; - loop { - if i + 8 > n { break; } - h = h * 1099511628211 + load64(buf, i); - i = i + 8; - } - loop { - if i >= n { break; } - h = h * 1099511628211 + load8(buf, i); - i = i + 1; - } - total = total + n; - } - r1 := syscall3(3, fd, 0, 0); // close(fd) - if total == 0 { return 0; } - h = h * 1099511628211 + total; - return h; -} +fn cir_hash_running_binary() -> int: + fd := syscall3(2, "/proc/self/exe", 0, 0) // open(O_RDONLY) + if fd < 0: + return 0 + buf := alloc(65536) + h : ., mut = -3750763034362895579 // FNV-1 64 offset basis(signed i64) + total : ., mut = 0 + loop: + n := syscall3(0, fd, buf, 65536) // read(fd, buf, 65536) + if n <= 0: + break + i : ., mut = 0 + loop: + if i + 8 > n: + break + h = h * 1099511628211 + load64(buf, i) + i = i + 8 + loop: + if i >= n: + break + h = h * 1099511628211 + load8(buf, i) + i = i + 1 + total = total + n + r1 := syscall3(3, fd, 0, 0) // close(fd) + if total == 0: + return 0 + h = h * 1099511628211 + total + return h // Count non-function regions belonging to one function. The function SG is // recreated by df_begin_func on a cache hit, so only nested records are stored. -fn cir_cache_sg_count(node_start: int, node_count: int) -> int { - count : ., mut = 0; - si : ., mut = 0; - loop { - if si >= g_sg_count { break; } - kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND); - nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART); - if kind != SG_FUNC && nstart >= node_start && nstart < node_start + node_count { - count = count + 1; - } - si = si + 1; - } - return count; -} +fn cir_cache_sg_count(node_start: int, node_count: int) -> int: + count : ., mut = 0 + si : ., mut = 0 + loop: + if si >= g_sg_count: + break + kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND) + nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART) + if kind != SG_FUNC && nstart >= node_start && nstart < node_start + node_count: + count = count + 1 + si = si + 1 + return count // Encode a region parent as an index within the serialized nested-region // list. -1 denotes the function SG recreated by df_begin_func. -fn cir_cache_sg_parent(sg_idx: int, node_start: int, node_count: int) -> int { - parent := r64(g_sgs, sg_idx * ESZ_SG + OFF_SG_PARENT); - if parent < 0 { return -1; } - parent_kind := r64(g_sgs, parent * ESZ_SG + OFF_SG_KIND); - parent_start := r64(g_sgs, parent * ESZ_SG + OFF_SG_NSTART); - if parent_kind == SG_FUNC && parent_start == node_start { return -1; } - - local : ., mut = 0; - si : ., mut = 0; - loop { - if si >= sg_idx { break; } - kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND); - nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART); - if kind != SG_FUNC && nstart >= node_start && nstart < node_start + node_count { - if si == parent { return local; } - local = local + 1; - } - si = si + 1; - } - return -1; -} +fn cir_cache_sg_parent(sg_idx: int, node_start: int, node_count: int) -> int: + parent := r64(g_sgs, sg_idx * ESZ_SG + OFF_SG_PARENT) + if parent < 0: + return -1 + parent_kind := r64(g_sgs, parent * ESZ_SG + OFF_SG_KIND) + parent_start := r64(g_sgs, parent * ESZ_SG + OFF_SG_NSTART) + if parent_kind == SG_FUNC && parent_start == node_start: + return -1 + + local : ., mut = 0 + si : ., mut = 0 + loop: + if si >= sg_idx: + break + kind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND) + nstart := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART) + if kind != SG_FUNC && nstart >= node_start && nstart < node_start + node_count: + if si == parent: + return local + local = local + 1 + si = si + 1 + return -1 // Save one function's DFG state to a .cir cache file. // path: full file path (including .core/cache/cir/ prefix) // source_fi: source FuncInfo index used for AST fingerprints // ir_fi: compact IR function index used for IR/DFG ranges // Returns 0 on success, -1 on failure. -fn save_cir_cache(path: string, source_fi: int, ir_fi: int) -> int { +fn save_cir_cache(path: string, source_fi: int, ir_fi: int) -> int: // 身份不可证(无 procfs 等)⇒ 绝不落盘:否则身份 0 的条目会被另一个同样 // 取不到身份的编译器当作「同身份」命中——即本单的静默类在退化路径复活。 // 关缓存 = 每次都全量重建 = 正确性优先(见 cir_compiler_identity 头注)。 - cid := cir_compiler_identity(); - if cid == 0 { return -1; } + cid := cir_compiler_identity() + if cid == 0: + return -1 - fd := syscall3(2, path, 577, 420); // O_WRONLY|O_CREAT|O_TRUNC, 0644 - if fd < 0 { return -1; } + fd := syscall3(2, path, 577, 420) // O_WRONLY|O_CREAT|O_TRUNC, 0644 + if fd < 0: + return -1 // Compute fingerprint - fn_node := fi_ast_node(source_fi); - fp := func_fingerprint(fn_node); - sig := sig_fingerprint(fn_node); - name_ni := r64(g_ir_func_name_idx, ir_fi * 8); - name := istr_get(name_ni); - name_len := str_len(name); - - var_start := r64(g_ir_func_var_start, ir_fi * 8); - var_count := r64(g_ir_func_var_count, ir_fi * 8); - node_start := r64(g_df_func_node_start, ir_fi * 8); - node_count := r64(g_df_func_node_count, ir_fi * 8); - instr_start := r64(g_ir_func_instr_start, ir_fi * 8); - instr_count := r64(g_ir_func_instr_count, ir_fi * 8); + fn_node := fi_ast_node(source_fi) + fp := func_fingerprint(fn_node) + sig := sig_fingerprint(fn_node) + name_ni := r64(g_ir_func_name_idx, ir_fi * 8) + name := istr_get(name_ni) + name_len := str_len(name) + + var_start := r64(g_ir_func_var_start, ir_fi * 8) + var_count := r64(g_ir_func_var_count, ir_fi * 8) + node_start := r64(g_df_func_node_start, ir_fi * 8) + node_count := r64(g_df_func_node_count, ir_fi * 8) + instr_start := r64(g_ir_func_instr_start, ir_fi * 8) + instr_count := r64(g_ir_func_instr_count, ir_fi * 8) // Serialize in memory and issue one write. The previous per-field writes // made a full self-host build perform millions of syscalls on its cache. - total_size : ., mut = 48 + name_len; // v17 头部 = magic/ver/identity/fp/sig/name_len - total_size = total_size + 8 + var_count * 24; + total_size : ., mut = 48 + name_len // v17 头部 = magic/ver/identity/fp/sig/name_len + total_size = total_size + 8 + var_count * 24 // 节点盘记录 = 8 字段 × 8B = 64B(R2 P5 Task 2 起 = {op,dest,s1,s2,s3,**派生码**, // first_edge,edge_count};第 9 槽 OFF_DF_AUX 不落盘——两槽装载时按派生码重派生, // 见文件头 v18 注)。 - total_size = total_size + 8 + node_count * 64; + total_size = total_size + 8 + node_count * 64 // 缓存收窄批(CIR_CACHE_VER 20):**只写本函数的边**([edge_start, g_df_edge_count)), // 盘记录 24B/条 = {rel_from, rel_to, kind}(相对 node_start 的**有符号**偏移;`next` 不落盘, // 装载期由 df_add_edge_kind 前插重建)。旧格式写**全图边表** ⇒ 全缓存 O(函数数 × 累计图) // = 二次膨胀(实测 97.0% 的缓存字节是边记录、其中 99.70% 属于别的函数)。 - edge_start := r64(g_df_func_edge_start, ir_fi * 8); - own_edge_count : ., mut = g_df_edge_count - edge_start; - if own_edge_count < 0 { own_edge_count = 0; } - total_size = total_size + 8 + own_edge_count * 24; - total_size = total_size + 8 + instr_count * 48; - total_size = total_size + 8; - size_si : ., mut = 0; - loop { - if size_si >= g_ir_str_const_count { break; } - size_ni := r64(g_ir_str_consts, size_si * 8); - total_size = total_size + 8 + str_len(istr_get(size_ni)); - size_si = size_si + 1; - } + edge_start := r64(g_df_func_edge_start, ir_fi * 8) + own_edge_count : ., mut = g_df_edge_count - edge_start + if own_edge_count < 0: + own_edge_count = 0 + total_size = total_size + 8 + own_edge_count * 24 + total_size = total_size + 8 + instr_count * 48 + total_size = total_size + 8 + size_si : ., mut = 0 + loop: + if size_si >= g_ir_str_const_count: + break + size_ni := r64(g_ir_str_consts, size_si * 8) + total_size = total_size + 8 + str_len(istr_get(size_ni)) + size_si = size_si + 1 // v13: nested SG records (kind/enter/exit/parent/nstart/ncount). - sg_count := cir_cache_sg_count(node_start, node_count); - total_size = total_size + 8 + sg_count * 48; + sg_count := cir_cache_sg_count(node_start, node_count) + total_size = total_size + 8 + sg_count * 48 // v21 生成期 intern 日志段 = {基线见证, 条数, × (len, bytes)} - total_size = total_size + 16; - size_ri : ., mut = 0; - loop { - if size_ri >= g_cir_rec_count { break; } - total_size = total_size + 8 + str_len(istr_get(r64(g_cir_rec_ids, size_ri * 8))); - size_ri = size_ri + 1; - } + total_size = total_size + 16 + size_ri : ., mut = 0 + loop: + if size_ri >= g_cir_rec_count: + break + total_size = total_size + 8 + str_len(istr_get(r64(g_cir_rec_ids, size_ri * 8))) + size_ri = size_ri + 1 // v20 尾部 trailer = {var_start, node_start}(**基线见证**;装载期先校验后恢复) - total_size = total_size + 16; - if total_size > g_cir_write_cap { - new_cap := g_cir_write_cap * 2; - if new_cap < 4096 { new_cap = 4096; } - if new_cap < total_size { new_cap = total_size; } - g_cir_write_buf = alloc(new_cap); - g_cir_write_cap = new_cap; - } - g_cir_write_pos = 0; + total_size = total_size + 16 + if total_size > g_cir_write_cap: + new_cap := g_cir_write_cap * 2 + if new_cap < 4096: + new_cap = 4096 + if new_cap < total_size: + new_cap = total_size + g_cir_write_buf = alloc(new_cap) + g_cir_write_cap = new_cap + g_cir_write_pos = 0 // Write header - w64_cir(fd, CIR_CACHE_MAGIC); - w64_cir(fd, CIR_CACHE_VER); - w64_cir(fd, cid); // v17: 编译器身份(重建即失效) - w64_cir(fd, fp); - w64_cir(fd, sig); - w64_cir(fd, name_len); - write_fd(fd, name, name_len); + w64_cir(fd, CIR_CACHE_MAGIC) + w64_cir(fd, CIR_CACHE_VER) + w64_cir(fd, cid) // v17: 编译器身份(重建即失效) + w64_cir(fd, fp) + w64_cir(fd, sig) + w64_cir(fd, name_len) + write_fd(fd, name, name_len) // Determine var range for this function - w64_cir(fd, var_count); - vi : ., mut = 0; - loop { - if vi >= var_count { break; } - v_idx := var_start + vi; - w64_cir(fd, irv_name(v_idx)); - w64_cir(fd, irv_id(v_idx)); - w64_cir(fd, irv_type(v_idx)); - vi = vi + 1; - } + w64_cir(fd, var_count) + vi : ., mut = 0 + loop: + if vi >= var_count: + break + v_idx := var_start + vi + w64_cir(fd, irv_name(v_idx)) + w64_cir(fd, irv_id(v_idx)) + w64_cir(fd, irv_type(v_idx)) + vi = vi + 1 // Write function's node range - w64_cir(fd, node_count); - ni2 : ., mut = 0; - loop { - if ni2 >= node_count { break; } - n := node_start + ni2; - w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE)); - w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_DEST)); - w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S1)); - w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S2)); - w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3)); + w64_cir(fd, node_count) + ni2 : ., mut = 0 + loop: + if ni2 >= node_count: + break + n := node_start + ni2 + w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE)) + w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_DEST)) + w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S1)) + w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S2)) + w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3)) // R2 P5 Task 2(D19):盘记录承载**派生码**(不是 40 槽——单槽化后 40 槽 = // 进程内类型项引用,不得跨进程/跨复位,D20;辅码槽同理不入盘)。派生码逐节点 // ≡ 单槽化前的混用码 ⇒ 盘面逐字节不变(布局与版本位零改动)。 w64_cir(fd, sh_dfn_code_of_slots(r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_TK), - r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_AUX))); - w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_FIRST_EDGE)); - w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_EDGE_COUNT)); + r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_AUX))) + w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_FIRST_EDGE)) + w64_cir(fd, r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_EDGE_COUNT)) // 项槽/辅码槽**不写盘**:两槽都是 (opcode, 派生码) 的纯函数,装载侧按 emit 的 // 等价时点重派生(文件头 v18 注——实测快照携带进程内索引会在暖路径整体悬空)。 - ni2 = ni2 + 1; - } + ni2 = ni2 + 1 // Persist nested SG metadata with offsets relative to this function's // node range. Parent indices are local to this serialized section. - w64_cir(fd, sg_count); - sg_i : ., mut = 0; - loop { - if sg_i >= g_sg_count { break; } - kind := r64(g_sgs, sg_i * ESZ_SG + OFF_SG_KIND); - nstart := r64(g_sgs, sg_i * ESZ_SG + OFF_SG_NSTART); - if kind != SG_FUNC && nstart >= node_start && nstart < node_start + node_count { - w64_cir(fd, kind); - w64_cir(fd, r64(g_sgs, sg_i * ESZ_SG + OFF_SG_ENTER) - node_start); - w64_cir(fd, r64(g_sgs, sg_i * ESZ_SG + OFF_SG_EXIT) - node_start); - w64_cir(fd, cir_cache_sg_parent(sg_i, node_start, node_count)); - w64_cir(fd, nstart - node_start); - w64_cir(fd, r64(g_sgs, sg_i * ESZ_SG + OFF_SG_NCOUNT)); - } - sg_i = sg_i + 1; - } + w64_cir(fd, sg_count) + sg_i : ., mut = 0 + loop: + if sg_i >= g_sg_count: + break + kind := r64(g_sgs, sg_i * ESZ_SG + OFF_SG_KIND) + nstart := r64(g_sgs, sg_i * ESZ_SG + OFF_SG_NSTART) + if kind != SG_FUNC && nstart >= node_start && nstart < node_start + node_count: + w64_cir(fd, kind) + w64_cir(fd, r64(g_sgs, sg_i * ESZ_SG + OFF_SG_ENTER) - node_start) + w64_cir(fd, r64(g_sgs, sg_i * ESZ_SG + OFF_SG_EXIT) - node_start) + w64_cir(fd, cir_cache_sg_parent(sg_i, node_start, node_count)) + w64_cir(fd, nstart - node_start) + w64_cir(fd, r64(g_sgs, sg_i * ESZ_SG + OFF_SG_NCOUNT)) + sg_i = sg_i + 1 // Write this function's edges only (v20)。 // 历史注(v5–v19):此处写的是**全图边表**,注释原文「For simplicity, write ALL edges // (they're few compared to nodes)」——该「边比节点少」的前提**早已失效**(实测 4,314 万条边 // 记录 vs 20.6 万节点记录),它正是本条二次膨胀的起点(见计划 §1.1 的「假设已失效」注)。 // v20:只写 [edge_start, g_df_edge_count) 且端点存**相对 node_start 的有符号偏移**。 - w64_cir(fd, own_edge_count); - ei : ., mut = 0; - loop { - if ei >= own_edge_count { break; } - e := edge_start + ei; - w64_cir(fd, r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_FROM) - node_start); - w64_cir(fd, r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_TO) - node_start); - w64_cir(fd, r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_KIND)); - ei = ei + 1; - } + w64_cir(fd, own_edge_count) + ei : ., mut = 0 + loop: + if ei >= own_edge_count: + break + e := edge_start + ei + w64_cir(fd, r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_FROM) - node_start) + w64_cir(fd, r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_TO) - node_start) + w64_cir(fd, r64(g_df_edges, e * ESZ_DFEDGE + OFF_DFE_KIND)) + ei = ei + 1 // Write function's instruction range - w64_cir(fd, instr_count); - ii : ., mut = 0; - loop { - if ii >= instr_count { break; } - inst := instr_start + ii; - w64_cir(fd, iri_op(inst)); - w64_cir(fd, iri_dest(inst)); - w64_cir(fd, iri_s1(inst)); - w64_cir(fd, iri_s2(inst)); - w64_cir(fd, iri_s3(inst)); - w64_cir(fd, iri_tk(inst)); - ii = ii + 1; - } + w64_cir(fd, instr_count) + ii : ., mut = 0 + loop: + if ii >= instr_count: + break + inst := instr_start + ii + w64_cir(fd, iri_op(inst)) + w64_cir(fd, iri_dest(inst)) + w64_cir(fd, iri_s1(inst)) + w64_cir(fd, iri_s2(inst)) + w64_cir(fd, iri_s3(inst)) + w64_cir(fd, iri_tk(inst)) + ii = ii + 1 // Write string constants used by this function - w64_cir(fd, g_ir_str_const_count); - si : ., mut = 0; - loop { - if si >= g_ir_str_const_count { break; } - ni3 := r64(g_ir_str_consts, si * 8); - s := istr_get(ni3); - sl := str_len(s); - w64_cir(fd, sl); - vi = 0; - loop { if vi >= sl { break; } - w8_cir(fd, load8(s, vi)); - vi = vi + 1; } - si = si + 1; - } + w64_cir(fd, g_ir_str_const_count) + si : ., mut = 0 + loop: + if si >= g_ir_str_const_count: + break + ni3 := r64(g_ir_str_consts, si * 8) + s := istr_get(ni3) + sl := str_len(s) + w64_cir(fd, sl) + vi = 0 + loop: + if vi >= sl: + break + w8_cir(fd, load8(s, vi)) + vi = vi + 1 + si = si + 1 // v21 生成期 intern 日志(**只存内容,不存 id**——跨进程 id 不可跨进程解释;装载侧按序重放 // 即把读侧串表推到与写侧同态,故盘上不需要任何编号)。 // 首字段 = **基线见证**:本函数生成窗口开始时的 `g_str_count`(写侧)。装载侧在重放**之前** // 要求读侧 `g_str_count` 与之相等——不等 = 两侧不同态(如:本进程在更早的函数处走了不同 // 的生成/装载路径)⇒ 拒绝(cache miss = 无害重建),绝不带着错编号继续。 - w64_cir(fd, g_cir_rec_base); - w64_cir(fd, g_cir_rec_count); - ri : ., mut = 0; - loop { - if ri >= g_cir_rec_count { break; } - rs := istr_get(r64(g_cir_rec_ids, ri * 8)); - rl := str_len(rs); - w64_cir(fd, rl); - rj : ., mut = 0; - loop { if rj >= rl { break; } - w8_cir(fd, load8(rs, rj)); - rj = rj + 1; } - ri = ri + 1; - } + w64_cir(fd, g_cir_rec_base) + w64_cir(fd, g_cir_rec_count) + ri : ., mut = 0 + loop: + if ri >= g_cir_rec_count: + break + rs := istr_get(r64(g_cir_rec_ids, ri * 8)) + rl := str_len(rs) + w64_cir(fd, rl) + rj : ., mut = 0 + loop: + if rj >= rl: + break + w8_cir(fd, load8(rs, rj)) + rj = rj + 1 + ri = ri + 1 // v20 尾部 trailer(**基线见证**):{var_start, node_start}。装载期**先校验后恢复**: // var 域恒校验(唯一不可低成本重映射的镜像域);node 域仅在快照含越界 rel 时作条件见证。 - w64_cir(fd, var_start); - w64_cir(fd, node_start); + w64_cir(fd, var_start) + w64_cir(fd, node_start) - written := syscall3(1, fd, g_cir_write_buf, g_cir_write_pos); - syscall3(3, fd, 0, 0); - if written != g_cir_write_pos { return -1; } - return 0; -} + written := syscall3(1, fd, g_cir_write_buf, g_cir_write_pos) + syscall3(3, fd, 0, 0) + if written != g_cir_write_pos: + return -1 + return 0 // Write helpers for the in-memory cache serializer. -fn w64_cir(fd: int, val: int) { - w64(g_cir_write_buf, g_cir_write_pos, val); - g_cir_write_pos = g_cir_write_pos + 8; -} - -fn w8_cir(fd: int, val: int) { - store8(g_cir_write_buf, g_cir_write_pos, val); - g_cir_write_pos = g_cir_write_pos + 1; -} - -fn write_fd(fd: int, data: string, len: int) { - write_pos : ., mut = 0; - loop { - if write_pos >= len { break; } - store8(g_cir_write_buf, g_cir_write_pos, load8(data, write_pos)); - g_cir_write_pos = g_cir_write_pos + 1; - write_pos = write_pos + 1; - } -} +fn w64_cir(fd: int, val: int): + w64(g_cir_write_buf, g_cir_write_pos, val) + g_cir_write_pos = g_cir_write_pos + 8 + +fn w8_cir(fd: int, val: int): + store8(g_cir_write_buf, g_cir_write_pos, val) + g_cir_write_pos = g_cir_write_pos + 1 + +fn write_fd(fd: int, data: string, len: int): + write_pos : ., mut = 0 + loop: + if write_pos >= len: + break + store8(g_cir_write_buf, g_cir_write_pos, load8(data, write_pos)) + g_cir_write_pos = g_cir_write_pos + 1 + write_pos = write_pos + 1 // === 快照装载读缓冲(R2 P5 Task 1:暖态 SIGSEGV 根因修复)=== // 根因链(实测,自源语料 src/compiler/main.cr -O 0,seed 见报告 §1): @@ -519,184 +523,229 @@ fn write_fd(fd: int, data: string, len: int) { // 尺寸(本语料实测最大 3,987,879B = 3.80MiB)而非全体累计。布局语义 = 与 read_file 返回的字符串 // 逐位同:alloc(cap+8) 的长度头在 buf-8,每次读取后改写为 fsize+1 ⇒ // str_len(g_cir_read_buf) == fsize,既有消费面(r64/str_sub)零改动。 -g_cir_read_buf : string, mut; -g_cir_read_cap : int, mut; // 数据区容量(不含 -8 处的 8B 长度头) +g_cir_read_buf : string, mut +g_cir_read_cap : int, mut // 数据区容量(不含 -8 处的 8B 长度头) // 读取快照文件到复用缓冲。返回文件长度;< 0 = 不可用(open 失败/空文件/短读/ // 缓冲分配失败)——调用方按 cache miss 处理(三态纪律:载入失败 ⇒ 拒绝, // 不得静默当空表)。快照恒为 save_cir_cache 单次 write 产出的常规文件 ⇒ // fsize <= 0(空文件或伪文件)= 不可用,不做 read_file 的伪文件循环回退。 -fn cir_read_snapshot(path: string) -> int { - fd := syscall3(2, path, 0, 0); // open(O_RDONLY) - if fd < 0 { return -1; } - fsize := syscall3(8, fd, 0, 2); // lseek(fd, 0, SEEK_END) - if fsize <= 0 { - r0 := syscall3(3, fd, 0, 0); // close - return -1; - } - if fsize + 1 > g_cir_read_cap { - new_cap : ., mut = g_cir_read_cap; - if new_cap < 4096 { new_cap = 4096; } - loop { - if new_cap >= fsize + 1 { break; } - new_cap = new_cap * 2; - } - g_cir_read_buf = alloc(new_cap + 8); - g_cir_read_cap = new_cap; - } - r2 := syscall3(8, fd, 0, 0); // lseek(fd, 0, SEEK_SET) - nread := syscall3(0, fd, g_cir_read_buf, fsize); // read(fd, buf, fsize) - r3 := syscall3(3, fd, 0, 0); // close(fd) +fn cir_read_snapshot(path: string) -> int: + fd := syscall3(2, path, 0, 0) // open(O_RDONLY) + if fd < 0: + return -1 + fsize := syscall3(8, fd, 0, 2) // lseek(fd, 0, SEEK_END) + if fsize <= 0: + r0 := syscall3(3, fd, 0, 0) // close + return -1 + if fsize + 1 > g_cir_read_cap: + new_cap : ., mut = g_cir_read_cap + if new_cap < 4096: + new_cap = 4096 + loop: + if new_cap >= fsize + 1: + break + new_cap = new_cap * 2 + g_cir_read_buf = alloc(new_cap + 8) + g_cir_read_cap = new_cap + r2 := syscall3(8, fd, 0, 0) // lseek(fd, 0, SEEK_SET) + nread := syscall3(0, fd, g_cir_read_buf, fsize) // read(fd, buf, fsize) + r3 := syscall3(3, fd, 0, 0) // close(fd) // 缓冲不可得(alloc 耗尽 ⇒ g_cir_read_buf 仍为 0 ⇒ read 取 EFAULT)或短读 // (并发截断等)⇒ 均**不可用** ⇒ miss:绝不拿半份/空载荷继续解析(静默错值 // 类)。⚠ 此处刻意**不写** `buf == 0` 形态的空判——该字符串-整型混比在 // Python bootstrap 侧(x86_64_stack_asm.py:168 按 _is_string_var 分派)会编成 // `str_eq(buf, 0)` → `str_len(0)` 解引用 NULL-8 = 崩溃(与自举侧 int 比较 // 语义不一致,登记见报告 §6);read 的 EFAULT 面已是同效且更稳的判据。 - if nread != fsize { return -1; } - w64(g_cir_read_buf, -8, fsize + 1); // 长度头 = fsize(str_len 口径同 read_file) - return fsize; -} + if nread != fsize: + return -1 + w64(g_cir_read_buf, -8, fsize + 1) // 长度头 = fsize(str_len 口径同 read_file) + return fsize // Load a .cir cache file and restore DFG state. // func_idx is the function index used to verify the cached fingerprints // against the current AST. Returns 0 on success, -1 on failure (cache miss). -fn load_cir_cache(path: string, func_idx: int) -> int { +fn load_cir_cache(path: string, func_idx: int) -> int: // 快照读入**复用缓冲**(不逐函数新分配——见 cir_read_snapshot 头注)。 - dlen := cir_read_snapshot(path); - if dlen < 0 { return -1; } - data := g_cir_read_buf; + dlen := cir_read_snapshot(path) + if dlen < 0: + return -1 + data := g_cir_read_buf // v17 头部 = 48B + 函数名(再至少 8B 载荷段头)。 - if dlen < 56 { return -1; } - pos : ., mut = 0; + if dlen < 56: + return -1 + pos : ., mut = 0 // Validate header - magic := r64(data, pos); pos = pos + 8; - if magic != CIR_CACHE_MAGIC { return -1; } - ver := r64(data, pos); pos = pos + 8; - if ver != CIR_CACHE_VER { return -1; } + magic := r64(data, pos) + pos = pos + 8 + if magic != CIR_CACHE_MAGIC: + return -1 + ver := r64(data, pos) + pos = pos + 8 + if ver != CIR_CACHE_VER: + return -1 // v17: 编译器身份——条目由另一个(或旧版)编译器二进制写入 ⇒ 其字符串 // 驻留序/索引与本次运行不一致,而 fp/sig 只覆盖目标源(同源必同)⇒ 必须 // 在此拒绝,否则下面恢复出的旧序索引即成活产物(TODO #2026-09-10-1 静默类)。 // 身份取不到(0)同样拒绝(save 侧对称地不落盘):身份不可证 = 不可命中。 - cid := cir_compiler_identity(); - entry_cid := r64(data, pos); pos = pos + 8; - if cid == 0 || entry_cid != cid { return -1; } + cid := cir_compiler_identity() + entry_cid := r64(data, pos) + pos = pos + 8 + if cid == 0 || entry_cid != cid: + return -1 - fp := r64(data, pos); pos = pos + 8; - sig := r64(data, pos); pos = pos + 8; + fp := r64(data, pos) + pos = pos + 8 + sig := r64(data, pos) + pos = pos + 8 // Verify fingerprints against current AST. // If the function body or signature changed, the cache is stale. - fn_node := fi_ast_node(func_idx); - current_fp := func_fingerprint(fn_node); - if fp != current_fp { return -1; } - current_sig := sig_fingerprint(fn_node); - if sig != current_sig { return -1; } + fn_node := fi_ast_node(func_idx) + current_fp := func_fingerprint(fn_node) + if fp != current_fp: + return -1 + current_sig := sig_fingerprint(fn_node) + if sig != current_sig: + return -1 // Verify function identity (name) - name_len := r64(data, pos); pos = pos + 8; + name_len := r64(data, pos) + pos = pos + 8 // Skip name string (we already know which function we tried to load) - pos = pos + name_len; + pos = pos + name_len // === v20 尾部 trailer = 基线见证(**先校验后恢复**)=== // 最短合法条目 = 头 48 + trailer 16(上方 dlen < 56 的粗检已过 ⇒ 此处再按 64 收紧)。 - if dlen < 64 { return -1; } + if dlen < 64: + return -1 // === 结构预扫(**只读,不动全局**)=== // 为什么先扫后恢复:装载的破坏性写在半途失败会污染全局数组(随后回归生成会**叠加**到 // 半恢复的图上)⇒ 所有校验必须在**任何写之前**完成(P4:截断/越界 ⇒ rc=0/miss,不得 139/垃圾)。 - p : ., mut = pos; - var_p := p; - p_var_count := r64(data, p); p = p + 8 + p_var_count * 24; - if p > dlen { return -1; } - node_p := p; - p_node_count := r64(data, p); p = p + 8 + p_node_count * 64; - if p > dlen { return -1; } - sg_p := p; - p_sg_count := r64(data, p); p = p + 8 + p_sg_count * 48; - if p > dlen { return -1; } - edge_p := p; - p_edge_count := r64(data, p); p = p + 8 + p_edge_count * 24; - if p > dlen { return -1; } - instr_p := p; - p_instr_count := r64(data, p); p = p + 8 + p_instr_count * 48; - if p > dlen { return -1; } - str_p := p; - p_str_count := r64(data, p); p = p + 8; - p_si : ., mut = 0; - loop { - if p_si >= p_str_count { break; } - sl_p := r64(data, p); p = p + 8 + sl_p; - if p > dlen { return -1; } - p_si = p_si + 1; - } + p : ., mut = pos + var_p := p + p_var_count := r64(data, p) + p = p + 8 + p_var_count * 24 + if p > dlen: + return -1 + node_p := p + p_node_count := r64(data, p) + p = p + 8 + p_node_count * 64 + if p > dlen: + return -1 + sg_p := p + p_sg_count := r64(data, p) + p = p + 8 + p_sg_count * 48 + if p > dlen: + return -1 + edge_p := p + p_edge_count := r64(data, p) + p = p + 8 + p_edge_count * 24 + if p > dlen: + return -1 + instr_p := p + p_instr_count := r64(data, p) + p = p + 8 + p_instr_count * 48 + if p > dlen: + return -1 + str_p := p + p_str_count := r64(data, p) + p = p + 8 + p_si : ., mut = 0 + loop: + if p_si >= p_str_count: + break + sl_p := r64(data, p) + p = p + 8 + sl_p + if p > dlen: + return -1 + p_si = p_si + 1 // v21 生成期 intern 日志段(**只读扫描**):{基线见证, 条数, × (len, bytes)} - j_p := p; - p_j_base := r64(data, p); p = p + 8; - p_j_count := r64(data, p); p = p + 8; - p_ji : ., mut = 0; - loop { - if p_ji >= p_j_count { break; } - jl_p := r64(data, p); p = p + 8 + jl_p; - if p > dlen { return -1; } - p_ji = p_ji + 1; - } + j_p := p + p_j_base := r64(data, p) + p = p + 8 + p_j_count := r64(data, p) + p = p + 8 + p_ji : ., mut = 0 + loop: + if p_ji >= p_j_count: + break + jl_p := r64(data, p) + p = p + 8 + jl_p + if p > dlen: + return -1 + p_ji = p_ji + 1 // trailer 定位于**扫描终点 p**(而非 dlen−16):**尾随字节容忍**——装载历来忽略条目尾随字节 // (既有契约:`test_cir_warm_path.py` 的 D5 用例即其钉子——补零条目仍须**命中**),故只要求 // `p + 16 <= dlen`;**截断**(p+16 > dlen,含「恰缺 trailer」「trailer 半截」)仍 fail-closed miss。 - if p + 16 > dlen { return -1; } - var_start_w := r64(data, p); - node_start_w := r64(data, p + 8); + if p + 16 > dlen: + return -1 + var_start_w := r64(data, p) + node_start_w := r64(data, p + 8) // var 域是**唯一无法低成本重映射**的镜像域(var 下标出现在节点 dest/s1..s3 与指令 s1..s3) // ⇒ 恒校验:不符 = 读者与写者不同态 ⇒ miss(无害重建;「宁可 miss 不可静默」)。 - if g_ir_var_count != var_start_w { return -1; } + if g_ir_var_count != var_start_w: + return -1 // 边端点合法性 + **条件见证**:常态(rel 全在 [0, node_count))下节点基线平移**不**影响相对 id // 的正确性 ⇒ 不校验 node_start(否则每次编辑都会让「被编辑函数之后的所有条目」集体 miss); // 仅当出现**越界 rel**(全档实测 1/1618 档:from 指向更早函数/全局的节点)时,才要求节点基线一致。 - base_node_v := g_df_node_count; - need_node_witness : ., mut = 0; - ei_v : ., mut = 0; - loop { - if ei_v >= p_edge_count { break; } - eo_v := edge_p + 8 + ei_v * 24; - rf_v := r64(data, eo_v); - rt_v := r64(data, eo_v + 8); - if rf_v >= p_node_count { return -1; } // 前向引用 = 异常(写侧 from 恒 ≤ 当前节点)⇒ 拒 - if rt_v >= p_node_count { return -1; } // to 越界 = 异常 ⇒ 拒 - if rf_v < 0 || rt_v < 0 { - need_node_witness = 1; - if base_node_v + rf_v < 0 { return -1; } - if base_node_v + rt_v < 0 { return -1; } - } - ei_v = ei_v + 1; - } - if need_node_witness != 0 { if g_df_node_count != node_start_w { return -1; } } + base_node_v := g_df_node_count + need_node_witness : ., mut = 0 + ei_v : ., mut = 0 + loop: + if ei_v >= p_edge_count: + break + eo_v := edge_p + 8 + ei_v * 24 + rf_v := r64(data, eo_v) + rt_v := r64(data, eo_v + 8) + if rf_v >= p_node_count: + return -1 + // 前向引用 = 异常(写侧 from 恒 ≤ 当前节点)⇒ 拒 + if rt_v >= p_node_count: + return -1 + // to 越界 = 异常 ⇒ 拒 + if rf_v < 0 || rt_v < 0: + need_node_witness = 1 + if base_node_v + rf_v < 0: + return -1 + if base_node_v + rt_v < 0: + return -1 + ei_v = ei_v + 1 + if need_node_witness != 0: + if g_df_node_count != node_start_w: + return -1 // **逐节点见证**(v20;盘值降格为校验):盘上 node.edge_count 必须等于「该节点在边表里的 // 出边条数」——链由重放重建,重建前先把盘值与重放应得值对齐,不符即拒(半恢复不允许)。 // 缓冲区按 p_node_count 现取(bump 分配器不回收;全档累计 Σnode ≈ 20.6 万槽 ≈ 1.6MB,可忽略)。 - if p_node_count > 0 { - tally := alloc(p_node_count * 8); - tz : ., mut = 0; - loop { if tz >= p_node_count { break; } w64(tally, tz * 8, 0); tz = tz + 1; } - ei_t : ., mut = 0; - loop { - if ei_t >= p_edge_count { break; } - rf_t := r64(data, edge_p + 8 + ei_t * 24); - if rf_t >= 0 { w64(tally, rf_t * 8, r64(tally, rf_t * 8) + 1); } - ei_t = ei_t + 1; - } - nj : ., mut = 0; - loop { - if nj >= p_node_count { break; } - ec_disk := r64(data, node_p + 8 + nj * 64 + 56); - if ec_disk != r64(tally, nj * 8) { return -1; } - nj = nj + 1; - } - } + if p_node_count > 0: + tally := alloc(p_node_count * 8) + tz : ., mut = 0 + loop: + if tz >= p_node_count: + break + w64(tally, tz * 8, 0) + tz = tz + 1 + ei_t : ., mut = 0 + loop: + if ei_t >= p_edge_count: + break + rf_t := r64(data, edge_p + 8 + ei_t * 24) + if rf_t >= 0: + w64(tally, rf_t * 8, r64(tally, rf_t * 8) + 1) + ei_t = ei_t + 1 + nj : ., mut = 0 + loop: + if nj >= p_node_count: + break + ec_disk := r64(data, node_p + 8 + nj * 64 + 56) + if ec_disk != r64(tally, nj * 8): + return -1 + nj = nj + 1 // === v21 串域修复:按序重放「生成期 intern 日志」(**必须先于任何 id 消费**)=== // 为什么先于恢复:快照内一切 id(var 名 / 指令与节点槽 / str 段引用者)都是**写侧编号**; @@ -705,192 +754,222 @@ fn load_cir_cache(path: string, func_idx: int) -> int { // 基线见证:读侧此刻的 g_str_count 必须等于写侧窗口开始时的值——不等 = 两侧不同态 // (更早的函数走了不同的生成/装载路径)⇒ 拒绝(cache miss = 无害重建),绝不带错编号继续。 // `--inject-cir-skip-journal`(隐藏 debug,仅判据突变自证用)= 跳过重放 ⇒ 本缺陷原样复现。 - if g_cir_skip_journal == 0 { - if g_str_count != p_j_base { return -1; } - jp : ., mut = j_p + 16; - ji : ., mut = 0; - loop { - if ji >= p_j_count { break; } - jl2 := r64(data, jp); jp = jp + 8; - js := str_sub(data, jp, jl2); jp = jp + jl2; - str_intern(js); - ji = ji + 1; - } - } + if g_cir_skip_journal == 0: + if g_str_count != p_j_base: + return -1 + jp : ., mut = j_p + 16 + ji : ., mut = 0 + loop: + if ji >= p_j_count: + break + jl2 := r64(data, jp) + jp = jp + 8 + js := str_sub(data, jp, jl2) + jp = jp + jl2 + str_intern(js) + ji = ji + 1 // Restore vars - var_count := r64(data, pos); pos = pos + 8; - vi : ., mut = 0; - loop { - if vi >= var_count { break; } - name_ni := r64(data, pos); pos = pos + 8; - v_id := r64(data, pos); pos = pos + 8; - v_type := r64(data, pos); pos = pos + 8; + var_count := r64(data, pos) + pos = pos + 8 + vi : ., mut = 0 + loop: + if vi >= var_count: + break + name_ni := r64(data, pos) + pos = pos + 8 + v_id := r64(data, pos) + pos = pos + 8 + v_type := r64(data, pos) + pos = pos + 8 // Ensure var array is large enough - if v_id >= g_ir_var_count { - grow_ir_vars(v_id + 1); - g_ir_var_count = v_id + 1; - } - irv_set_name(v_id, name_ni); - irv_set_id(v_id, v_id); - irv_set_type(v_id, v_type); - vi = vi + 1; - } + if v_id >= g_ir_var_count: + grow_ir_vars(v_id + 1) + g_ir_var_count = v_id + 1 + irv_set_name(v_id, name_ni) + irv_set_id(v_id, v_id) + irv_set_type(v_id, v_type) + vi = vi + 1 // Restore nodes - node_count := r64(data, pos); pos = pos + 8; - base_node := g_df_node_count; - grow_df_nodes(g_df_node_count + node_count); + node_count := r64(data, pos) + pos = pos + 8 + base_node := g_df_node_count + grow_df_nodes(g_df_node_count + node_count) // RegionCheck 显式映射:恢复的节点没有经过 df_create_node,须在此同步写入 // node→region 映射,否则 subgraph_containing 在缓存命中路径读到未初始化 // 的 g_df_node_region(null → SIGSEGV)。缓存不保存内层 region(Minor #4), // 以当前 open 的 func region(df_begin_func 已 sg_push)为归属——与旧的 // 线性扫 g_sgs 在缓存命中路径得到的结果一致。 - grow_df_node_region(base_node + node_count); - ni : ., mut = 0; - loop { - if ni >= node_count { break; } - n := base_node + ni; - w64(g_df_node_region, n * 8, g_cur_sg); - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE, r64(data, pos)); pos = pos + 8; - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_DEST, r64(data, pos)); pos = pos + 8; - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S1, r64(data, pos)); pos = pos + 8; - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S2, r64(data, pos)); pos = pos + 8; - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3, r64(data, pos)); pos = pos + 8; + grow_df_node_region(base_node + node_count) + ni : ., mut = 0 + loop: + if ni >= node_count: + break + n := base_node + ni + w64(g_df_node_region, n * 8, g_cur_sg) + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE, r64(data, pos)) + pos = pos + 8 + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_DEST, r64(data, pos)) + pos = pos + 8 + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S1, r64(data, pos)) + pos = pos + 8 + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S2, r64(data, pos)) + pos = pos + 8 + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_S3, r64(data, pos)) + pos = pos + 8 // R2 P5 Task 2(D19):盘上只有**一个** tk 字段(派生码);两槽皆由它**重派生** // ——时点 = emit 的等价点(逐函数、逐节点序),拆分器单源 = sh_tk_split,故项表 // 追加序与冷路径一致 ⇒ 冷/暖两态同项**同索引**(T4 用例逐行对拍)。项引用/辅码 // **不读盘**(进程内项引用跨进程必悬空;盘上不存第二份 f(tk) 值 = 无第二真源)。 - tk_disk := r64(data, pos); pos = pos + 8; + tk_disk := r64(data, pos) + pos = pos + 8 // 装载侧变体(不置 D23 失败位——盘码可能落在暖进程更小的类型表之外,见 // ty_shadow.cr 的 sh_tk_split_load 注;缓存命中绝不因此让编译失败)。 - sh_tk_split_load(r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE), tk_disk); - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_TK, g_sh_slot_term); - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_AUX, g_sh_slot_aux); + sh_tk_split_load(r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE), tk_disk) + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_TK, g_sh_slot_term) + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_AUX, g_sh_slot_aux) // v20:盘上 first_edge/edge_count **不信任**(边下标随新基线平移)——两槽归零后由 // 下方的 df_add_edge_kind 重放**重建**;盘值已在预扫中作**逐节点见证**校验过。 - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_FIRST_EDGE, -1); - w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_EDGE_COUNT, 0); - pos = pos + 16; // 跳过盘上两字段 + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_FIRST_EDGE, -1) + w64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_EDGE_COUNT, 0) + pos = pos + 16 // 跳过盘上两字段 // Record var producer. 幽灵边修复(v7 注 A 裁决)缓存面:grow_df_arrays // 对新增长区播种 -1(dyn_arr.cr 同款注释)——快照内未产出 var(参数等) // 的 producer 槽恒 -1(修复前零页 = 0 =「节点 0」→ 缓存命中函数保留 // 幽灵边);本处只覆写快照内真实定值的 var。旧快照由 CIR_CACHE_VER // 13→14 失效。 - dest := r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_DEST); - if dest >= 0 { - grow_df_arrays(dest + 1); - w64(g_df_var_producer, dest * 8, n); - } - ni = ni + 1; - } - g_df_node_count = base_node + node_count; + dest := r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_DEST) + if dest >= 0: + grow_df_arrays(dest + 1) + w64(g_df_var_producer, dest * 8, n) + ni = ni + 1 + g_df_node_count = base_node + node_count // Restore nested SG metadata (v13). The current function SG was opened by // df_begin_func; cached parent=-1 refers to that SG. - sg_count := r64(data, pos); pos = pos + 8; - sg_base := g_sg_count; - sg_i : ., mut = 0; - loop { - if sg_i >= sg_count { break; } - new_sg := g_sg_count; - grow_sg(new_sg + 1); - kind := r64(data, pos); pos = pos + 8; - enter_rel := r64(data, pos); pos = pos + 8; - exit_rel := r64(data, pos); pos = pos + 8; - parent_rel := r64(data, pos); pos = pos + 8; - nstart_rel := r64(data, pos); pos = pos + 8; - ncount := r64(data, pos); pos = pos + 8; - parent := g_cur_sg; - if parent_rel >= 0 { parent = sg_base + parent_rel; } - f := new_sg * ESZ_SG; - w64(g_sgs, f + OFF_SG_KIND, kind); - w64(g_sgs, f + OFF_SG_ENTER, base_node + enter_rel); - w64(g_sgs, f + OFF_SG_EXIT, base_node + exit_rel); - w64(g_sgs, f + OFF_SG_PARENT, parent); - w64(g_sgs, f + OFF_SG_NSTART, base_node + nstart_rel); - w64(g_sgs, f + OFF_SG_NCOUNT, ncount); - g_sg_count = new_sg + 1; + sg_count := r64(data, pos) + pos = pos + 8 + sg_base := g_sg_count + sg_i : ., mut = 0 + loop: + if sg_i >= sg_count: + break + new_sg := g_sg_count + grow_sg(new_sg + 1) + kind := r64(data, pos) + pos = pos + 8 + enter_rel := r64(data, pos) + pos = pos + 8 + exit_rel := r64(data, pos) + pos = pos + 8 + parent_rel := r64(data, pos) + pos = pos + 8 + nstart_rel := r64(data, pos) + pos = pos + 8 + ncount := r64(data, pos) + pos = pos + 8 + parent := g_cur_sg + if parent_rel >= 0: + parent = sg_base + parent_rel + f := new_sg * ESZ_SG + w64(g_sgs, f + OFF_SG_KIND, kind) + w64(g_sgs, f + OFF_SG_ENTER, base_node + enter_rel) + w64(g_sgs, f + OFF_SG_EXIT, base_node + exit_rel) + w64(g_sgs, f + OFF_SG_PARENT, parent) + w64(g_sgs, f + OFF_SG_NSTART, base_node + nstart_rel) + w64(g_sgs, f + OFF_SG_NCOUNT, ncount) + g_sg_count = new_sg + 1 // Later (inner) records overwrite the enclosing region mapping. - rn : ., mut = base_node + nstart_rel; - rend := rn + ncount; - loop { - if rn >= rend { break; } - w64(g_df_node_region, rn * 8, new_sg); - rn = rn + 1; - } - sg_i = sg_i + 1; - } + rn : ., mut = base_node + nstart_rel + rend := rn + ncount + loop: + if rn >= rend: + break + w64(g_df_node_region, rn * 8, new_sg) + rn = rn + 1 + sg_i = sg_i + 1 // Restore this function's edges (v20): 3×8B = {rel_from, rel_to, kind},`next` 不落盘。 // 逐条经 **df_add_edge_kind** 重放(与冷路径同一函数、同一前插序)⇒ 逐节点链序与 // edge_count 与写者同态;且相对 id 在**节点基线平移**(部分 rebuild)时仍指向正确节点 // ——这正是 R3(绝对 id + 全量覆盖的「未声明同态」)的根因级闭合。 - own_edge_count := r64(data, pos); pos = pos + 8; - ei : ., mut = 0; - loop { - if ei >= own_edge_count { break; } - rel_from := r64(data, pos); pos = pos + 8; - rel_to := r64(data, pos); pos = pos + 8; - e_kind := r64(data, pos); pos = pos + 8; + own_edge_count := r64(data, pos) + pos = pos + 8 + ei : ., mut = 0 + loop: + if ei >= own_edge_count: + break + rel_from := r64(data, pos) + pos = pos + 8 + rel_to := r64(data, pos) + pos = pos + 8 + e_kind := r64(data, pos) + pos = pos + 8 // 有符号映射(rel<0 = 指向更早函数/全局的节点;界与基线见证已在预扫校验) - df_add_edge_kind(base_node + rel_from, base_node + rel_to, e_kind); - ei = ei + 1; - } + df_add_edge_kind(base_node + rel_from, base_node + rel_to, e_kind) + ei = ei + 1 // Restore instructions - instr_count := r64(data, pos); pos = pos + 8; - base_instr := g_ir_instr_count; - grow_ir_instrs(g_ir_instr_count + instr_count); - ii : ., mut = 0; - loop { - if ii >= instr_count { break; } - inst := base_instr + ii; - iri_set_op(inst, r64(data, pos)); pos = pos + 8; - iri_set_dest(inst, r64(data, pos)); pos = pos + 8; - iri_set_s1(inst, r64(data, pos)); pos = pos + 8; - iri_set_s2(inst, r64(data, pos)); pos = pos + 8; - iri_set_s3(inst, r64(data, pos)); pos = pos + 8; - iri_set_tk(inst, r64(data, pos)); pos = pos + 8; - ii = ii + 1; - } - g_ir_instr_count = base_instr + instr_count; + instr_count := r64(data, pos) + pos = pos + 8 + base_instr := g_ir_instr_count + grow_ir_instrs(g_ir_instr_count + instr_count) + ii : ., mut = 0 + loop: + if ii >= instr_count: + break + inst := base_instr + ii + iri_set_op(inst, r64(data, pos)) + pos = pos + 8 + iri_set_dest(inst, r64(data, pos)) + pos = pos + 8 + iri_set_s1(inst, r64(data, pos)) + pos = pos + 8 + iri_set_s2(inst, r64(data, pos)) + pos = pos + 8 + iri_set_s3(inst, r64(data, pos)) + pos = pos + 8 + iri_set_tk(inst, r64(data, pos)) + pos = pos + 8 + ii = ii + 1 + g_ir_instr_count = base_instr + instr_count // Restore string constants (used by nodes/instrs) - str_count := r64(data, pos); pos = pos + 8; - si : ., mut = 0; - loop { - if si >= str_count { break; } - sl := r64(data, pos); pos = pos + 8; - s := str_sub(data, pos, sl); - pos = pos + sl; - track_str(str_intern(s)); - si = si + 1; - } - - return 0; -} + str_count := r64(data, pos) + pos = pos + 8 + si : ., mut = 0 + loop: + if si >= str_count: + break + sl := r64(data, pos) + pos = pos + 8 + s := str_sub(data, pos, sl) + pos = pos + sl + track_str(str_intern(s)) + si = si + 1 + + return 0 // === v21 生成期 intern 日志:窗口开闭(main.cr 在 ir_gen_func 前后成对调用;仅缓存启用时)=== // 顺序确定性论证(判据 §顺序):① 跨函数 = main.cr 的函数循环**一个序**(写侧在该循环里生成、 // 读侧在同一循环里装载);② 函数内 = 两侧共用**唯一插入路径** `str_intern`(`dyn_arr.cr`), // 记录序即插入序;③ 窗口外的插入(parse/check 等)两侧同源同序 ⇒ 不进日志也不需要进。 // ⇒ 装载侧按记录序重放即逐条复现写侧编号(归纳:前序函数同态 ⇒ 本篇起点同态)。 -fn cir_rec_begin() { - g_cir_rec_on = 1; - g_cir_rec_count = 0; - g_cir_rec_base = g_str_count; -} +fn cir_rec_begin(): + g_cir_rec_on = 1 + g_cir_rec_count = 0 + g_cir_rec_base = g_str_count -fn cir_rec_end() { g_cir_rec_on = 0; } +fn cir_rec_end(): + g_cir_rec_on = 0 // Ensure cache directory exists. -fn make_cir_cache_dir() { +fn make_cir_cache_dir(): // Create .core/ directory hierarchy for cache. // mkdir syscall = 83 on x86-64 Linux: mkdir(path, mode) // Ignore EEXIST errors (directory may already exist). - syscall3(83, ".core", 448, 0); - syscall3(83, ".core/cache", 448, 0); - syscall3(83, ".core/cache/cir", 448, 0); -} + syscall3(83, ".core", 448, 0) + syscall3(83, ".core/cache", 448, 0) + syscall3(83, ".core/cache/cir", 448, 0) diff --git a/src/compiler/corearch.cr b/src/compiler/corearch.cr index d03e13f0..60eb05a6 100644 --- a/src/compiler/corearch.cr +++ b/src/compiler/corearch.cr @@ -48,52 +48,56 @@ // 六分支顺序与输出保持(--check-regalloc 顺序保序:强制 O2 → alloc → // 看门狗 meta_reg_assign_total → 注入钩子×3 → regalloc_verify_all → 摘要/rc)。 -INST_X86 : int = 0; -INST_TABLE : int = 1; -INST_DECL_STRIDE : int = 40; // 行 = 10 × i32(LE) -INST_OFF_ID : int = 0; -INST_OFF_NAME : int = 4; -INST_OFF_OPT_MIN : int = 8; -INST_OFF_OPT_MAX : int = 12; -INST_OFF_ALLOW_TABLE : int = 16; -INST_OFF_ALLOW_LINK : int = 20; -INST_OFF_NEEDS_ALLOC : int = 24; -INST_OFF_NEEDS_VERIFY : int = 28; -INST_OFF_NEEDS_EVICTION : int = 32; // 判定③ 形式声明(引擎不实现——§3.2) -INST_OFF_NEEDS_CALL_SITES : int = 36; // 判定④ 形式声明(引擎不实现——§3.2) - -g_instance_decl : string, mut; // 实例声明表(行 × INST_DECL_STRIDE 字节) -g_instance_count : int, mut; -g_instance_cap : int, mut; -g_active_instance : int, mut; // 引导选中实例行(= id;instance_select 设定) - -fn grow_instance_decl(needed: int) { - if needed < g_instance_cap { return; } - nc : ., mut = g_instance_cap * 2; if nc < 2 { nc = 2; } if nc < needed { nc = needed; } - nb := alloc(nc * INST_DECL_STRIDE); - _dyncpy(g_instance_decl, g_instance_cap * INST_DECL_STRIDE, nb); - g_instance_decl = nb; g_instance_cap = nc; -} +INST_X86 : int = 0 +INST_TABLE : int = 1 +INST_DECL_STRIDE : int = 40 // 行 = 10 × i32(LE) +INST_OFF_ID : int = 0 +INST_OFF_NAME : int = 4 +INST_OFF_OPT_MIN : int = 8 +INST_OFF_OPT_MAX : int = 12 +INST_OFF_ALLOW_TABLE : int = 16 +INST_OFF_ALLOW_LINK : int = 20 +INST_OFF_NEEDS_ALLOC : int = 24 +INST_OFF_NEEDS_VERIFY : int = 28 +INST_OFF_NEEDS_EVICTION : int = 32 // 判定③ 形式声明(引擎不实现——§3.2) +INST_OFF_NEEDS_CALL_SITES : int = 36 // 判定④ 形式声明(引擎不实现——§3.2) + +g_instance_decl : string, mut // 实例声明表(行 × INST_DECL_STRIDE 字节) +g_instance_count : int, mut +g_instance_cap : int, mut +g_active_instance : int, mut // 引导选中实例行(= id;instance_select 设定) + +fn grow_instance_decl(needed: int): + if needed < g_instance_cap: + return + nc : ., mut = g_instance_cap * 2 + if nc < 2: + nc = 2 + if nc < needed: + nc = needed + nb := alloc(nc * INST_DECL_STRIDE) + _dyncpy(g_instance_decl, g_instance_cap * INST_DECL_STRIDE, nb) + g_instance_decl = nb + g_instance_cap = nc fn instance_decl_add(id: int, name_idx: int, opt_min: int, opt_max: int, - allow_table: int, allow_link: int, needs_alloc: int, - needs_verify: int, needs_eviction: int, needs_call_sites: int) { - grow_instance_decl(g_instance_count + 1); - off : ., mut = g_instance_count * INST_DECL_STRIDE; - w32(g_instance_decl, off + INST_OFF_ID, id); - w32(g_instance_decl, off + INST_OFF_NAME, name_idx); - w32(g_instance_decl, off + INST_OFF_OPT_MIN, opt_min); - w32(g_instance_decl, off + INST_OFF_OPT_MAX, opt_max); - w32(g_instance_decl, off + INST_OFF_ALLOW_TABLE, allow_table); - w32(g_instance_decl, off + INST_OFF_ALLOW_LINK, allow_link); - w32(g_instance_decl, off + INST_OFF_NEEDS_ALLOC, needs_alloc); - w32(g_instance_decl, off + INST_OFF_NEEDS_VERIFY, needs_verify); - w32(g_instance_decl, off + INST_OFF_NEEDS_EVICTION, needs_eviction); - w32(g_instance_decl, off + INST_OFF_NEEDS_CALL_SITES, needs_call_sites); - g_instance_count = g_instance_count + 1; -} - -fn instance_decl_init() { + allow_table: int, allow_link: int, needs_alloc: int, + needs_verify: int, needs_eviction: int, needs_call_sites: int): + grow_instance_decl(g_instance_count + 1) + off : ., mut = g_instance_count * INST_DECL_STRIDE + w32(g_instance_decl, off + INST_OFF_ID, id) + w32(g_instance_decl, off + INST_OFF_NAME, name_idx) + w32(g_instance_decl, off + INST_OFF_OPT_MIN, opt_min) + w32(g_instance_decl, off + INST_OFF_OPT_MAX, opt_max) + w32(g_instance_decl, off + INST_OFF_ALLOW_TABLE, allow_table) + w32(g_instance_decl, off + INST_OFF_ALLOW_LINK, allow_link) + w32(g_instance_decl, off + INST_OFF_NEEDS_ALLOC, needs_alloc) + w32(g_instance_decl, off + INST_OFF_NEEDS_VERIFY, needs_verify) + w32(g_instance_decl, off + INST_OFF_NEEDS_EVICTION, needs_eviction) + w32(g_instance_decl, off + INST_OFF_NEEDS_CALL_SITES, needs_call_sites) + g_instance_count = g_instance_count + 1 + +fn instance_decl_init(): // 幂等(防重复调用——引导只调一次,注册函数最小面)。声明字段恒非负 // (0/1/3/str idx)——r32 零扩展读安全(符号修正歧义只涉及负值)。 // name 内联时机注:本函数跑在 load_ccr 前(引导期)——str idx 依当时 @@ -101,59 +105,81 @@ fn instance_decl_init() { // 重置 g_strs 重载 .ccr STR 段后这些 idx 不再指向内联名。本任务消费面 // (instance_select)全在选择期(装载前),无装载后读名路径——届时注册 // 校验若读名须装载后重内联(蓝图后续)。 - if g_instance_count > 0 { return; } + if g_instance_count > 0: + return // ③④ 行数据 = {0, 0}(x86:静态放置无驱逐事件 + callee-saved 平凡满足; // 表模式路径:恒 O0 直线路径无驱逐/调用点事件——同 {0, 0};引擎不实现, // 设计 spec §3.2——字段 = 声明完整性)。 - instance_decl_add(INST_X86, str_intern("x86"), 0, 3, 0, 1, 1, 1, 0, 0); - instance_decl_add(INST_TABLE, str_intern("table"), 0, 0, 1, 0, 0, 0, 0, 0); -} - -fn inst_id(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_ID); } -fn inst_name(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NAME); } -fn inst_opt_min(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_OPT_MIN); } -fn inst_opt_max(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_OPT_MAX); } -fn inst_allow_table(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_ALLOW_TABLE); } -fn inst_allow_link(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_ALLOW_LINK); } -fn inst_needs_alloc(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NEEDS_ALLOC); } -fn inst_needs_verify(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NEEDS_VERIFY); } -fn inst_needs_eviction(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NEEDS_EVICTION); } -fn inst_needs_call_sites(i: int) -> int { return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NEEDS_CALL_SITES); } - -fn instance_lookup(name_idx: int) -> int { + instance_decl_add(INST_X86, str_intern("x86"), 0, 3, 0, 1, 1, 1, 0, 0) + instance_decl_add(INST_TABLE, str_intern("table"), 0, 0, 1, 0, 0, 0, 0, 0) + +fn inst_id(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_ID) +fn inst_name(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NAME) +fn inst_opt_min(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_OPT_MIN) +fn inst_opt_max(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_OPT_MAX) +fn inst_allow_table(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_ALLOW_TABLE) +fn inst_allow_link(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_ALLOW_LINK) +fn inst_needs_alloc(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NEEDS_ALLOC) +fn inst_needs_verify(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NEEDS_VERIFY) +fn inst_needs_eviction(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NEEDS_EVICTION) +fn inst_needs_call_sites(i: int) -> int: + return r32(g_instance_decl, i * INST_DECL_STRIDE + INST_OFF_NEEDS_CALL_SITES) + +fn instance_lookup(name_idx: int) -> int: // 按名查行(name = str_idx,str_intern 去重 → 等值串恒同 idx)。 // 未找到返回 -1(构造保证不触发——两行两名)。 - i : ., mut = 0; - loop { - if i >= g_instance_count { break; } - if inst_name(i) == name_idx { return i; } - i = i + 1; - } - return -1; -} - -fn instance_select() -> int { + i : ., mut = 0 + loop: + if i >= g_instance_count: + break + if inst_name(i) == name_idx: + return i + i = i + 1 + return -1 + +fn instance_select() -> int: // 引导选择:读 flag → 实例名 → 查表 → 行 idx(行序 = id 序 → 行 = id)。 // 选择旗标 = --table 值存在性(与装载条件同源);兜底 INST_X86 = 默认 // 实例(防御性——lookup 未命中不掩构造错误,退默认路径)。 - nm : ., mut = "x86"; - if str_len(cli_get("table")) > 0 { nm = "table"; } - r := instance_lookup(str_intern(nm)); - if r < 0 { return INST_X86; } - return r; -} - -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; } } + nm : ., mut = "x86" + if str_len(cli_get("table")) > 0: + nm = "table" + r := instance_lookup(str_intern(nm)) + if r < 0: + return INST_X86 + return r + +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 // regalloc 移后端(2026-09-07):数据面/判定调试通道随编码决策层迁入—— // 载体 = corec cir 原隐藏标志的 corearch 同名版本(load .ccr 后内存态自算, @@ -164,63 +190,67 @@ fn split_links(val: string) { // 判定服务 + 机器侧注入钩子)的入口。分支顺序与输出保持(行为不变): // --check-regalloc 保序 = 强制 O2 → alloc_registers → 看门狗 // meta_reg_assign_total → 注入钩子×3 → regalloc_verify_all → 摘要/rc。 -fn regalloc_debug_dispatch() -> int { - if cli_has("dump-entries") != 0 { - compute_live_ranges(); - dump_entries_summary(); - return 1; - } - if cli_has("inject-coexist-oob") != 0 { - compute_live_ranges(); - if inject_coexist_oob() != 0 { return 2; } - return 1; - } - if cli_has("dump-coexist") != 0 { - compute_live_ranges(); - dump_coexist_summary(); - return 1; - } - if cli_has("dump-regassign") != 0 { +fn regalloc_debug_dispatch() -> int: + if cli_has("dump-entries") != 0: + compute_live_ranges() + dump_entries_summary() + return 1 + if cli_has("inject-coexist-oob") != 0: + compute_live_ranges() + if inject_coexist_oob() != 0: + return 2 + return 1 + if cli_has("dump-coexist") != 0: + compute_live_ranges() + dump_coexist_summary() + return 1 + if cli_has("dump-regassign") != 0: // 自算后逐对输出 var→reg(尊重 --opt-level 门:分配 = O2,O0/O1 → 空) - if g_opt_level >= 2 { alloc_registers(); } - mi : ., mut = 0; - loop { - if mi >= g_opt_meta_count { break; } - mo := mi * OPT_META_STRIDE; - if r32(g_opt_meta, mo) == OPT_KEY_REG_ASSIGN { - cnt := r32(g_opt_meta, mo + 8); - di : ., mut = 0; - loop { - if di >= cnt { break; } - print("regassign: "); print(int_str(r32(g_opt_meta, mo + 12 + di * 8))); - print(" "); println(int_str(r32(g_opt_meta, mo + 16 + di * 8))); - di = di + 1; - } - } - mi = mi + 1; - } - return 1; - } - if cli_has("check-regalloc") != 0 { - saved_opt := g_opt_level; - g_opt_level = 2; - alloc_registers(); + if g_opt_level >= 2: + alloc_registers() + mi : ., mut = 0 + loop: + if mi >= g_opt_meta_count: + break + mo := mi * OPT_META_STRIDE + if r32(g_opt_meta, mo) == OPT_KEY_REG_ASSIGN: + cnt := r32(g_opt_meta, mo + 8) + di : ., mut = 0 + loop: + if di >= cnt: + break + print("regassign: ") + print(int_str(r32(g_opt_meta, mo + 12 + di * 8))) + print(" ") + println(int_str(r32(g_opt_meta, mo + 16 + di * 8))) + di = di + 1 + mi = mi + 1 + return 1 + if cli_has("check-regalloc") != 0: + saved_opt := g_opt_level + g_opt_level = 2 + alloc_registers() // 看门狗行:REG_ASSIGN 对总数(rc>0 = 寄存器真实分配实证,防回退—— // 分配在 corearch 自算后计数 = 自算块;.ccr 不再带 corec 分配结果) - print("regalloc-assign: "); print(int_str(meta_reg_assign_total())); - println(" pairs"); - if cli_has("inject-home-conflict") != 0 { inject_home_conflict(); } - if cli_has("inject-reg-conflict") != 0 { inject_reg_conflict(); } - if cli_has("inject-read-gap") != 0 { inject_read_gap(); } - nv := regalloc_verify_all(); - g_opt_level = saved_opt; - print("regalloc-consistency: funcs "); print(int_str(g_ir_func_count)); - print(" violations "); println(int_str(nv)); - if nv != 0 { return 2; } - return 1; - } - return 0; -} + print("regalloc-assign: ") + print(int_str(meta_reg_assign_total())) + println(" pairs") + if cli_has("inject-home-conflict") != 0: + inject_home_conflict() + if cli_has("inject-reg-conflict") != 0: + inject_reg_conflict() + if cli_has("inject-read-gap") != 0: + inject_read_gap() + nv := regalloc_verify_all() + g_opt_level = saved_opt + print("regalloc-consistency: funcs ") + print(int_str(g_ir_func_count)) + print(" violations ") + println(int_str(nv)) + if nv != 0: + return 2 + return 1 + return 0 // --dump-objects 调试通道(内核完备 Task 1 测试载体):实例侧薄通道—— // 经内核对象面访问器(nod_op/nod_dest/nod_s1-3/nod_tk + nod_edge_first/count @@ -229,195 +259,224 @@ fn regalloc_debug_dispatch() -> int { // nod_inputs 调用——内联遍历自本通道搬移,dump 输出逐字节同,判据 = // test_ccr_v7 对象面断言 + --dump-objects 语料 byte-compare)。 // 行格式契约见 tests/selfhost/test_ccr_v7.py:parse_object_dump。 -fn dump_object_surface() { - print("objects: "); print_i(g_v7_nod_count); println(""); - ni : ., mut = 0; - loop { - if ni >= g_v7_nod_count { break; } - print("nod "); print_i(ni); - print(" op "); print_i(nod_op(ni)); - print(" dest "); print_i(nod_dest(ni)); - print(" s1 "); print_i(nod_s1(ni)); - print(" s2 "); print_i(nod_s2(ni)); - print(" s3 "); print_i(nod_s3(ni)); - print(" tk "); print_i(nod_tk(ni)); - print(" fe "); print_i(nod_edge_first(ni)); - print(" ec "); print_i(nod_edge_count(ni)); - println(""); - nod_inputs(ni); // 配方输入遍历(出边记录行——内核 nod_inputs 封装) - ni = ni + 1; - } -} +fn dump_object_surface(): + print("objects: ") + print_i(g_v7_nod_count) + println("") + ni : ., mut = 0 + loop: + if ni >= g_v7_nod_count: + break + print("nod ") + print_i(ni) + print(" op ") + print_i(nod_op(ni)) + print(" dest ") + print_i(nod_dest(ni)) + print(" s1 ") + print_i(nod_s1(ni)) + print(" s2 ") + print_i(nod_s2(ni)) + print(" s3 ") + print_i(nod_s3(ni)) + print(" tk ") + print_i(nod_tk(ni)) + print(" fe ") + print_i(nod_edge_first(ni)) + print(" ec ") + print_i(nod_edge_count(ni)) + println("") + nod_inputs(ni) // 配方输入遍历(出边记录行——内核 nod_inputs 封装) + ni = ni + 1 // --dump-nod-items(R2 P6 Task 3 β 读回通道):逐节点打印 NOD 项索引 → TYPE 段项表 // 取项 → `tt_atom_of_term` → 原子行。这是「项跨进程可解析」的**可观测证据**: // 头行给计数(with_item = 带项节点数——非空转门),正文逐节点给 // `{idx, atom}` 供测试断言 `atom == code`(idx ≥ 0 时)。load_ccr 已做同款**硬校验** // (域外/不一致 ⇒ 拒绝),本通道是它的显式读出面。不触发发射路径(返回 0 早退)。 -fn dump_nod_items() { - with_item : ., mut = 0; - ni : ., mut = 0; - loop { - if ni >= g_v7_nod_count { break; } - if nod_item(ni) >= 0 { with_item = with_item + 1; } - ni = ni + 1; - } - print("[nod-items] nodes="); print_i(g_v7_nod_count); - print(" with_item="); print_i(with_item); - print(" terms="); print_i(tt_count()); - print(" rows="); print_i(g_type_count); - println(""); - nj : ., mut = 0; - loop { - if nj >= g_v7_nod_count { break; } - itv := nod_item(nj); - at : ., mut = -1; - if itv >= 0 { at = tt_atom_of_term(itv); } - print("item "); print_i(nj); - print(" op "); print_i(nod_op(nj)); - print(" code "); print_i(nod_tk(nj)); - print(" idx "); print_i(itv); - print(" atom "); print_i(at); - println(""); - nj = nj + 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) — O2: load 后自算寄存器分配 + 一致性自检(emit 前,违反 = 编译错误)"); - cli_flag("table", "", "HIT table file (load & emit mapped ops through it)"); - cli_flag("hit-events-file", "", "Hidden debug: inject text event stream file (dump-events inverse; skips lowering — template compare test channel, M2a Task 2)"); - cli_flag_bool("dump-events", "", "Dump lowered HIT event stream + const pool"); - cli_flag_bool("dump-table", "", "Hidden debug: dump loaded HIT event/proj/step/runtime state (schema v2 read-back test channel)"); +fn dump_nod_items(): + with_item : ., mut = 0 + ni : ., mut = 0 + loop: + if ni >= g_v7_nod_count: + break + if nod_item(ni) >= 0: + with_item = with_item + 1 + ni = ni + 1 + print("[nod-items] nodes=") + print_i(g_v7_nod_count) + print(" with_item=") + print_i(with_item) + print(" terms=") + print_i(tt_count()) + print(" rows=") + print_i(g_type_count) + println("") + nj : ., mut = 0 + loop: + if nj >= g_v7_nod_count: + break + itv := nod_item(nj) + at : ., mut = -1 + if itv >= 0: + at = tt_atom_of_term(itv) + print("item ") + print_i(nj) + print(" op ") + print_i(nod_op(nj)) + print(" code ") + print_i(nod_tk(nj)) + print(" idx ") + print_i(itv) + print(" atom ") + print_i(at) + println("") + nj = nj + 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) — O2: load 后自算寄存器分配 + 一致性自检(emit 前,违反 = 编译错误)") + cli_flag("table", "", "HIT table file (load & emit mapped ops through it)") + cli_flag("hit-events-file", "", "Hidden debug: inject text event stream file (dump-events inverse; skips lowering — template compare test channel, M2a Task 2)") + cli_flag_bool("dump-events", "", "Dump lowered HIT event stream + const pool") + cli_flag_bool("dump-table", "", "Hidden debug: dump loaded HIT event/proj/step/runtime state (schema v2 read-back test channel)") // regalloc 移后端:数据面/判定调试通道(corec cir 原载体随迁——同名 flag) - cli_flag_bool("dump-entries", "", "Hidden debug: versioned entries summary (regalloc 移后端 test channel)"); - cli_flag_bool("dump-coexist", "", "Hidden debug: coexistence summary (regalloc 移后端 test channel)"); - cli_flag_bool("dump-regassign", "", "Hidden debug: per-pair var->reg dump after O2 self-alloc (regalloc 移后端 test channel)"); - cli_flag_bool("check-regalloc", "", "Hidden debug: O2-forced alloc + regalloc consistency self-check (regalloc 移后端 test channel)"); - cli_flag_bool("inject-home-conflict", "", "Hidden debug: inject coexisting entries onto same home slot, then verify (test hook)"); - cli_flag_bool("inject-reg-conflict", "", "Hidden debug: inject fake var->reg pair colliding with a real one, then verify (test hook)"); - cli_flag_bool("inject-read-gap", "", "Hidden debug: truncate last version interval to def point, then verify (test hook)"); - cli_flag_bool("inject-coexist-oob", "", "Hidden debug: probe entries_coexist with OOB indices (GC-1 test hook)"); - cli_flag_bool("dump-objects", "", "Hidden debug: dump loaded NOD/EDG semantic objects via object-surface accessors (内核完备 Task 1 test channel)"); - cli_flag_bool("dump-nod-items", "", "Hidden debug: dump loaded NOD item indices resolved through the TYPE segment term table (R2 P6 Task 3 β read-back channel)"); - cli_flag_bool("dump-types", "", "Hidden debug: dump loaded TYPE segment content (row table + term DAG + judgment probe; R2 P4 Task 2 read-back channel)"); - cli_flag_bool("dump-ifaces", "", "Hidden debug: dump loaded IFACE segment content (entry table + shapes + user ifaces + impls + method table + cross-segment term probe; R2 P4 Task 3 read-back channel)"); - - if cli_parse() != 0 { return 1; } + cli_flag_bool("dump-entries", "", "Hidden debug: versioned entries summary (regalloc 移后端 test channel)") + cli_flag_bool("dump-coexist", "", "Hidden debug: coexistence summary (regalloc 移后端 test channel)") + cli_flag_bool("dump-regassign", "", "Hidden debug: per-pair var->reg dump after O2 self-alloc (regalloc 移后端 test channel)") + cli_flag_bool("check-regalloc", "", "Hidden debug: O2-forced alloc + regalloc consistency self-check (regalloc 移后端 test channel)") + cli_flag_bool("inject-home-conflict", "", "Hidden debug: inject coexisting entries onto same home slot, then verify (test hook)") + cli_flag_bool("inject-reg-conflict", "", "Hidden debug: inject fake var->reg pair colliding with a real one, then verify (test hook)") + cli_flag_bool("inject-read-gap", "", "Hidden debug: truncate last version interval to def point, then verify (test hook)") + cli_flag_bool("inject-coexist-oob", "", "Hidden debug: probe entries_coexist with OOB indices (GC-1 test hook)") + cli_flag_bool("dump-objects", "", "Hidden debug: dump loaded NOD/EDG semantic objects via object-surface accessors (内核完备 Task 1 test channel)") + cli_flag_bool("dump-nod-items", "", "Hidden debug: dump loaded NOD item indices resolved through the TYPE segment term table (R2 P6 Task 3 β read-back channel)") + cli_flag_bool("dump-types", "", "Hidden debug: dump loaded TYPE segment content (row table + term DAG + judgment probe; R2 P4 Task 2 read-back channel)") + cli_flag_bool("dump-ifaces", "", "Hidden debug: dump loaded IFACE segment content (entry table + shapes + user ifaces + impls + method table + cross-segment term probe; R2 P4 Task 3 read-back channel)") + + if cli_parse() != 0: + return 1 // 注册契约引导(Task 3):读 flag → 查表选实例(--table 值存在 → 表模式 // 路径实例;否则 x86 原生实例)——后续拒绝门/表管线门/O2 职责门逐点查询 // g_active_instance 声明行字段(表驱动分派,行为不变)。 - instance_decl_init(); - g_active_instance = instance_select(); + instance_decl_init() + g_active_instance = instance_select() // 拒绝门(M2-1 显式拒绝保持——声明化):表实例声明 allow_link = 0 → // 不接受 --link/--shared。表模式池 mov [rip+disp] 的 disp 由 elf.cr 按池槽 // 回填,链接路径(ctx 重布局重定位用户代码段)下指向未经测试(M1 计划 // 偏差 #2)。显式拒绝(stderr + exit 1)优于未测组合。消息/顺序不变。 // 测试断言见 tests/selfhost/test_hit_table.py:test_reject_table_with_link_shared。 - if inst_allow_link(g_active_instance) == 0 { - if cli_has("shared") != 0 || cli_has("link") != 0 || str_len(cli_get("link")) > 0 { - em := "error: --table cannot be combined with --link/--shared (pool mov rip disp untested under ctx relayout)\n"; - syscall3(1, 2, em, str_len(em)); - return 1; } } - g_opt_level = 0; - ol : ., mut = cli_get("opt-level"); - if str_len(ol) > 0 { - g_opt_level = str_int(ol); + if inst_allow_link(g_active_instance) == 0: + if cli_has("shared") != 0 || cli_has("link") != 0 || str_len(cli_get("link")) > 0: + em := "error: --table cannot be combined with --link/--shared (pool mov rip disp untested under ctx relayout)\n" + syscall3(1, 2, em, str_len(em)) + return 1 + g_opt_level = 0 + ol : ., mut = cli_get("opt-level") + if str_len(ol) > 0: + g_opt_level = str_int(ol) // 值域钳制窗口 = x86 实例声明窗口 [0,3](默认实例——旧钳制常数即该 // 窗口值;级别消毒与实例选择正交)。表实例声明窗口 [0,0] = 语义侧 // 职责窗口(恒 O0——经 needs_alloc/needs_verify = 0 的职责门强制), // CLI 级别值透传发射侧(O1+ 帧布局沿 g_opt_level 现状保持)。 - if g_opt_level > inst_opt_max(INST_X86) { g_opt_level = inst_opt_max(INST_X86); } - if g_opt_level < inst_opt_min(INST_X86) { g_opt_level = inst_opt_min(INST_X86); } - } + if g_opt_level > inst_opt_max(INST_X86): + g_opt_level = inst_opt_max(INST_X86) + if g_opt_level < inst_opt_min(INST_X86): + g_opt_level = inst_opt_min(INST_X86) // --table(M1 Task 2):load 成功 → 表模式继续(表映射 op 走 emit_instr_tabled, // 未映射落旧路径 = 混合模式);失败即退出。load 成功打印计数供测试断言。 // 装载条件 = 实例选择同源旗标(选择已把表实例置活动——allow_table = 1)。 - tbl : ., mut = cli_get("table"); - if str_len(tbl) > 0 { - if load_hit_table(tbl) != 0 { return 1; } - g_hit_tabled_count = 0; - print("hit table loaded: "); - print_i(g_hit_event_count); - println(" events"); + tbl : ., mut = cli_get("table") + if str_len(tbl) > 0: + if load_hit_table(tbl) != 0: + return 1 + g_hit_tabled_count = 0 + print("hit table loaded: ") + print_i(g_hit_event_count) + println(" events") // --dump-table(schema v2 读回测试通道):加载态 proj/步/runtime 结构 // dump(hit.cr helper 只读表状态)。测试断言见 // tests/selfhost/test_hit_table.py:test_v2_fixture_multi_step_sections。 - if cli_has("dump-table") != 0 { hit_dump_table_state(); } - } - 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"); - println(" --table FILE load HIT table; emit mapped ops through it (M1: int sub)"); - println(" --dump-events dump lowered HIT event stream + const pool"); - 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(); + if cli_has("dump-table") != 0: + hit_dump_table_state() + 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") + println(" --table FILE load HIT table; emit mapped ops through it (M1: int sub)") + println(" --dump-events dump lowered HIT event stream + const pool") + 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() // --dump-types(R2 P4 Task 2 读回通道):载入 TYPE 段重建后的行表/项 DAG 打印 // ——与 corec 侧 `ccr --dump-types` 共用同一条打印路径(ccr_io.cr 的 // ccr_type_surface_dump;跨进程逐行对拍 + probe 行 = 判定原语同值)。不依赖 // 线性流(在被重建前返回 0——不触发发射路径)。 - if cli_has("dump-types") != 0 { - ccr_type_surface_dump(); - return 0; - } + if cli_has("dump-types") != 0: + ccr_type_surface_dump() + return 0 // --dump-ifaces(R2 P4 Task 3 读回通道):载入 IFACE 段重建后的条目表/形状表/ // 接口表/impl 边/方法表打印——与 corec 侧 `ccr --dump-ifaces` 共用同一条打印 // 路径(ccr_io.cr 的 ccr_iface_surface_dump;跨进程逐行对拍 + ifaceprobe 行 = // 跨段项索引在重建项表上的解析同值)。同样在被重建前返回 0(不触发发射路径)。 - if cli_has("dump-ifaces") != 0 { - ccr_iface_surface_dump(); - return 0; - } + if cli_has("dump-ifaces") != 0: + ccr_iface_surface_dump() + return 0 // --dump-nod-items(R2 P6 Task 3 β 读回通道):NOD 项索引 → TYPE 段项表取项 → // `tt_atom_of_term` → 原子行。与上两通道同族:TYPE 段已在 load_ccr 内重建 // (⇒ 项表可用),且在 `build_linear_schedule()` **之前**返回 0(不触发发射路径)。 // load_ccr 的 TYPE 段后一致性 pass 已把「域外/不一致 ⇒ 拒绝」做成硬闸;本通道 // 是它的显式读出面(可观测证据:项跨进程可解析 + 非空转计数)。 - if cli_has("dump-nod-items") != 0 { - dump_nod_items(); - return 0; - } + if cli_has("dump-nod-items") != 0: + dump_nod_items() + return 0 // 内核完备 Task 1(调度重建移实例):loader 只产语义对象——线性流 // (g_ir_instrs)重建 = 实例事务(build_linear_schedule,regalloc.cr—— // 重建段自 load_ccr 纯搬移,产物逐字节一致),load 成功后、分派/发射前 // 必须调用(ELF 发射/dump-entries/check-regalloc 全消费线性流)。 - build_linear_schedule(); + build_linear_schedule() // --dump-objects(Task 1 测试通道——对象面配方可读断言载体,见 // tests/selfhost/test_ccr_v7.py:test_v7_object_surface_recipe_readable): // dump 分支在重建后、发射前(返回 0——不触发 O2 职责门/发射路径)。 - if cli_has("dump-objects") != 0 { - dump_object_surface(); - return 0; - } + if cli_has("dump-objects") != 0: + dump_object_surface() + return 0 // regalloc 移后端(R1a/R3,2026-09-07):O2 分配 + 一致性判定归位 corearch // ——load 后自算自检(.ccr 不再传 REG_ASSIGN/ENT,D-1=Y)。违反 = 编译错误。 @@ -425,16 +484,17 @@ fn corearch_main() -> int { // needs_verify(x86 = 1/1 → 级别 ≥ 2 时执行;表实例 = 0/0 → O2 组合验证 // 永不执行——M1 表驱动直线路径恒 O0 语义,与旧 hit_table_active 门等价: // 此刻实例 = 装载态恒等——--table 装载成功才达此处)。 - dd := regalloc_debug_dispatch(); - if dd == 1 { return 0; } - if dd == 2 { return 1; } - if g_opt_level >= 2 && inst_needs_alloc(g_active_instance) != 0 { - alloc_registers(); - if inst_needs_verify(g_active_instance) != 0 { + dd := regalloc_debug_dispatch() + if dd == 1: + return 0 + if dd == 2: + return 1 + if g_opt_level >= 2 && inst_needs_alloc(g_active_instance) != 0: + alloc_registers() + if inst_needs_verify(g_active_instance) != 0: // 判定:成功静默(自检通过不打扰构建输出);违反 = 诊断已打印 + 拦截 - if regalloc_verify_all() != 0 { return 1; } - } - } + if regalloc_verify_all() != 0: + return 1 // --table(M1 Task 3):表模式 → 先降低(IR 直线子集 → 事件流 + 常量池)。 // 超子集 op → 'needs more events' 错误 exit 1(发射前拒绝);成功 → 事件流 @@ -446,170 +506,219 @@ fn corearch_main() -> int { // 此刻实例与装载态恒等(--table 装载成功才达此处——load 失败已提前退出, // 未给 --table 则实例 = x86 且无任何装载路径)——旧 hit_table_active() 门 // 的声明等价物。 - dump_ev : ., mut = cli_has("dump-events"); - inj_path : ., mut = cli_get("hit-events-file"); - if str_len(inj_path) > 0 && inst_allow_table(g_active_instance) == 0 { - println("error: --hit-events-file needs --table (events emit through table projections)"); - return 1; } - g_hit_inject_active = 0; - if inst_allow_table(g_active_instance) != 0 { - if str_len(inj_path) > 0 { - g_hit_inject_active = 1; - if hit_inject_events(inj_path) != 0 { return 1; } - } else { - if hit_lower_program() != 0 { return 1; } - } - if dump_ev != 0 { - print("hit events lowered: "); print_i(g_hit_ev_count); println(""); - ei : ., mut = 0; - loop { - if ei >= g_hit_ev_count { break; } - ev_id := hit_ev_id(ei); - es := hit_event_lookup(ev_id); - print(" ev "); - if es < 0 { print("?"); } else { print(hit_event_name(es)); } - print(" dst="); print_i(hit_ev_dst(ei)); - print(" s1="); - if hit_ev_flags(ei) % 2 == 1 { print("pool"); print_i(hit_ev_s1(ei)); } - else { print_i(hit_ev_s1(ei)); } - print(" s2="); - if hit_ev_flags(ei) / 2 % 2 == 1 { print("pool"); print_i(hit_ev_s2(ei)); } - else { print_i(hit_ev_s2(ei)); } - println(""); - ei = ei + 1; } + dump_ev : ., mut = cli_has("dump-events") + inj_path : ., mut = cli_get("hit-events-file") + if str_len(inj_path) > 0 && inst_allow_table(g_active_instance) == 0: + println("error: --hit-events-file needs --table (events emit through table projections)") + return 1 + g_hit_inject_active = 0 + if inst_allow_table(g_active_instance) != 0: + if str_len(inj_path) > 0: + g_hit_inject_active = 1 + if hit_inject_events(inj_path) != 0: + return 1 + else: + if hit_lower_program() != 0: + return 1 + if dump_ev != 0: + print("hit events lowered: ") + print_i(g_hit_ev_count) + println("") + ei : ., mut = 0 + loop: + if ei >= g_hit_ev_count: + break + ev_id := hit_ev_id(ei) + es := hit_event_lookup(ev_id) + print(" ev ") + if es < 0: + print("?") + else: + print(hit_event_name(es)) + print(" dst=") + print_i(hit_ev_dst(ei)) + print(" s1=") + if hit_ev_flags(ei) % 2 == 1: + print("pool") + print_i(hit_ev_s1(ei)) + else: + print_i(hit_ev_s1(ei)) + print(" s2=") + if hit_ev_flags(ei) / 2 % 2 == 1: + print("pool") + print_i(hit_ev_s2(ei)) + else: + print_i(hit_ev_s2(ei)) + println("") + ei = ei + 1 // 池值行(M2a Task 2:注入文件 pool 行的 dump 逆面——值域随槽序) - print("hit pool entries: "); print_i(g_hit_pool_count); println(""); - if g_hit_pool_count > 0 { - print("hit pool:"); - hpi : ., mut = 0; - loop { - if hpi >= g_hit_pool_count { break; } - print(" "); print_i(r64(g_hit_pool, hpi * 8)); - hpi = hpi + 1; } - println(""); } - } - } - - emit_so := cli_has("shared"); - link_val := cli_get("link"); - out_path := cli_get("output"); + print("hit pool entries: ") + print_i(g_hit_pool_count) + println("") + if g_hit_pool_count > 0: + print("hit pool:") + hpi : ., mut = 0 + loop: + if hpi >= g_hit_pool_count: + break + print(" ") + print_i(r64(g_hit_pool, hpi * 8)) + hpi = hpi + 1 + println("") + + emit_so := cli_has("shared") + link_val := cli_get("link") + out_path := cli_get("output") // Pure-static (no --link, not --shared): the binary must be self-contained, // so the backend emits g_set_curg/g_get_curg bridge stubs (rt.s is not linked). // With --link, the stubs stay external and resolve from core_rt.so (rt.s). - 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 // --shared: emit as ET_DYN - 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 // Default: ELF (static or dynamic) - 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 { + if str_len(link_val) > 0: + ctx_init() + if str_eq(link_val, "auto") != 0: // Look for core_rt.so relative to compiler binary - 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); } } + 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) // Also try ./build/, ./, and ~/.core/lib/ - 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; } + 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 // Clear rip-relative patches in user code (they point to original BSS) // NOP the mov [r10],rXX that follows each lea r10,[rip+...] - 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); - if sz == -2 { - println("error: 静态链接失败——存在无法解析的外部符号(见上方列表)"); - return 1; - } - } else { + 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) + if sz == -2: + println("error: 静态链接失败——存在无法解析的外部符号(见上方列表)") + return 1 + else: // F16②:纯静态构建(无 .so 可查)下 extern 符号无法解析—— // 修复前静默保留 call rel32=0 → 运行时跳入 ELF 头崩溃(rc=139)。 - if g_x86_ext_rel_count > 0 { - println("error: 无法解析外部符号(静态构建未链接任何运行库):"); - ri2 : ., mut = 0; - loop { if ri2 >= g_x86_ext_rel_count { break; } - println(" " + istr_get(r64(g_x86_ext_rel_name, ri2 * 8))); - ri2 = ri2 + 1; } - return 1; - } + if g_x86_ext_rel_count > 0: + println("error: 无法解析外部符号(静态构建未链接任何运行库):") + ri2 : ., mut = 0 + loop: + if ri2 >= g_x86_ext_rel_count: + break + println(" " + istr_get(r64(g_x86_ext_rel_name, ri2 * 8))) + ri2 = ri2 + 1 + return 1 // Pure static: write directly (rt.cr prepended by frontend) // 0755(493):ELF 输出必须可执行——修复 `corec build` 输出 0644 的 // 既有怪癖(2026-08-16 Task 6:所有测试曾被迫 chmod 兜底;.so 输出保持 0644) - 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); } - } else { + 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) + else: // Dynamic linking: PLT/GOT - 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:可执行输出(同静态路径修复) 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); + 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:可执行输出(同静态路径修复) 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) // 表模式总结:g_hit_tabled_count = 表驱动实际发射事件条数(instr.cr 计数—— // add 反减 = 2 事件/指令)——「events emitted」语义准确(M2-2b 改名)。 - if str_len(tbl) > 0 { - print("hit table: "); print_i(g_hit_tabled_count); println(" events emitted"); - } + if str_len(tbl) > 0: + print("hit table: ") + print_i(g_hit_tabled_count) + println(" events emitted") // 注入通道(测试专用):事件须全部经表发射——预检拒绝(已打印)会使计数 // 短于注入行数 = 注入文件错误 → exit 1(不静默落旧路径掩盖)。 - if g_hit_inject_active != 0 && g_hit_tabled_count != g_hit_ev_count { - print("error: HIT events: "); print_i(g_hit_tabled_count); - print(" of "); print_i(g_hit_ev_count); - println(" events emitted via table (injection file event not emittable)"); - return 1; } - return 0; } + if g_hit_inject_active != 0 && g_hit_tabled_count != g_hit_ev_count: + print("error: HIT events: ") + print_i(g_hit_tabled_count) + print(" of ") + print_i(g_hit_ev_count) + println(" events emitted via table (injection file event not emittable)") + return 1 + return 0 diff --git a/src/compiler/dataflow.cr b/src/compiler/dataflow.cr index 784253d6..0161786c 100644 --- a/src/compiler/dataflow.cr +++ b/src/compiler/dataflow.cr @@ -8,56 +8,55 @@ // --- Initialization --- -fn init_df() { - g_df_node_count = 0; - g_df_edge_count = 0; - g_df_cap = 0; - g_df_node_cap = 0; - g_df_edge_cap = 0; - g_df_node_region_cap = 0; // node region array rebuilt on grow - g_cur_sg = -1; // no region open yet - g_last_state_node = -1; // state chain starts empty per compile - fi : ., mut = 0; - loop { - if fi >= g_func_count { break; } - grow_df_arrays(fi + 1); - w64(g_df_func_node_start, fi * 8, -1); - w64(g_df_func_node_count, fi * 8, 0); - fi = fi + 1; - } - vi : ., mut = 0; - loop { - if vi >= g_ir_var_count { break; } - grow_df_arrays(vi + 1); - w64(g_df_var_producer, vi * 8, -1); - vi = vi + 1; - } -} +fn init_df(): + g_df_node_count = 0 + g_df_edge_count = 0 + g_df_cap = 0 + g_df_node_cap = 0 + g_df_edge_cap = 0 + g_df_node_region_cap = 0 // node region array rebuilt on grow + g_cur_sg = -1 // no region open yet + g_last_state_node = -1 // state chain starts empty per compile + fi : ., mut = 0 + loop: + if fi >= g_func_count: + break + grow_df_arrays(fi + 1) + w64(g_df_func_node_start, fi * 8, -1) + w64(g_df_func_node_count, fi * 8, 0) + fi = fi + 1 + vi : ., mut = 0 + loop: + if vi >= g_ir_var_count: + break + grow_df_arrays(vi + 1) + w64(g_df_var_producer, vi * 8, -1) + vi = vi + 1 // --- Subgraph management (bare pointer model) --- -fn sg_push(kind: int) { - grow_sg(g_sg_count + 1); - idx := g_sg_count; - w64(g_sgs, idx * ESZ_SG + OFF_SG_KIND, kind); - w64(g_sgs, idx * ESZ_SG + OFF_SG_ENTER, g_df_node_count); - w64(g_sgs, idx * ESZ_SG + OFF_SG_EXIT, -1); - w64(g_sgs, idx * ESZ_SG + OFF_SG_NSTART, g_df_node_count); - w64(g_sgs, idx * ESZ_SG + OFF_SG_NCOUNT, 0); +fn sg_push(kind: int): + grow_sg(g_sg_count + 1) + idx := g_sg_count + w64(g_sgs, idx * ESZ_SG + OFF_SG_KIND, kind) + w64(g_sgs, idx * ESZ_SG + OFF_SG_ENTER, g_df_node_count) + w64(g_sgs, idx * ESZ_SG + OFF_SG_EXIT, -1) + w64(g_sgs, idx * ESZ_SG + OFF_SG_NSTART, g_df_node_count) + w64(g_sgs, idx * ESZ_SG + OFF_SG_NCOUNT, 0) // Parent: find innermost currently open subgraph - parent := -1; - pi := idx - 1; - loop { if pi < 0 { break; } - if r64(g_sgs, pi * ESZ_SG + OFF_SG_EXIT) < 0 { // still open - parent = pi; - break; - } - pi = pi - 1; - } - w64(g_sgs, idx * ESZ_SG + OFF_SG_PARENT, parent); - g_cur_sg = idx; // new innermost open region - g_sg_count = idx + 1; -} + parent := -1 + pi := idx - 1 + loop: + if pi < 0: + break + if r64(g_sgs, pi * ESZ_SG + OFF_SG_EXIT) < 0: + // still open + parent = pi + break + pi = pi - 1 + w64(g_sgs, idx * ESZ_SG + OFF_SG_PARENT, parent) + g_cur_sg = idx // new innermost open region + g_sg_count = idx + 1 // sg_pop: close the last OPEN (EXIT<0) region, not g_sg_count-1. // With the old code the count is never decremented, so df_end_func's pop @@ -65,27 +64,30 @@ fn sg_push(kind: int) { // innermost region's EXIT with the whole-function node count. Search back // from the top for the entry whose EXIT is still -1, close exactly that one, // and restore g_cur_sg to its parent. -fn sg_pop() { - if g_sg_count <= 0 { return; } - idx : ., mut = -1; - pi := g_sg_count - 1; - loop { - if pi < 0 { break; } - if r64(g_sgs, pi * ESZ_SG + OFF_SG_EXIT) < 0 { idx = pi; break; } - pi = pi - 1; - } - if idx < 0 { return; } - w64(g_sgs, idx * ESZ_SG + OFF_SG_EXIT, g_df_node_count); +fn sg_pop(): + if g_sg_count <= 0: + return + idx : ., mut = -1 + pi := g_sg_count - 1 + loop: + if pi < 0: + break + if r64(g_sgs, pi * ESZ_SG + OFF_SG_EXIT) < 0: + idx = pi + break + pi = pi - 1 + if idx < 0: + return + w64(g_sgs, idx * ESZ_SG + OFF_SG_EXIT, g_df_node_count) w64(g_sgs, idx * ESZ_SG + OFF_SG_NCOUNT, - g_df_node_count - r64(g_sgs, idx * ESZ_SG + OFF_SG_NSTART)); + g_df_node_count - r64(g_sgs, idx * ESZ_SG + OFF_SG_NSTART)) // Loop termination dependency: the region exit node (last node created in // the region, i.e. the exit label) must happen after the region's last // side effect — a VSDG state edge enforcing loop-exit ordering. // 循环终止依赖(kind=1)与链头推进**不在本处连接**——state 链统一在 // 全部 IR 生成结束后重建(df_replay_state_chain;时点理由见该函数头注): // 被调函数真纯度只有拿到全程序 IR 体才能算,链不能再边生成边连。 - g_cur_sg = r64(g_sgs, idx * ESZ_SG + OFF_SG_PARENT); -} + g_cur_sg = r64(g_sgs, idx * ESZ_SG + OFF_SG_PARENT) // --- Node creation --- @@ -96,82 +98,80 @@ fn sg_pop() { // ——按「共享文件零前端依赖」纪律留余量(dataflow.cr 若某日并入 corearch 清单, // 本函数零改动即可链接)。参数语义 = 「存储」:本函数只落槽,不解释、不校验、 // 不派生(派生规则单源 = ty_shadow.cr 的 sh_tk_split;码由 sh_dfn_code_of_slots 派生)。 -fn df_create_node(opcode: int, dest: int, src1: int, src2: int, src3: int, tk_term: int, tk_aux: int) -> int { - nid := g_df_node_count; - grow_df_nodes(nid + 1); - grow_df_node_region(nid + 1); - w64(g_df_node_region, nid * 8, g_cur_sg); // owning region (-1 = none) - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_OPCODE, opcode); - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_DEST, dest); - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_S1, src1); - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_S2, src2); - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_S3, src3); - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_TK, tk_term); // R2 P5 Task 2:类型项引用 - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_AUX, tk_aux); // R2 P5 Task 2:辅码 - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_FIRST_EDGE, -1); - w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_EDGE_COUNT, 0); - g_df_node_count = nid + 1; +fn df_create_node(opcode: int, dest: int, src1: int, src2: int, src3: int, tk_term: int, tk_aux: int) -> int: + nid := g_df_node_count + grow_df_nodes(nid + 1) + grow_df_node_region(nid + 1) + w64(g_df_node_region, nid * 8, g_cur_sg) // owning region (-1 = none) + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_OPCODE, opcode) + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_DEST, dest) + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_S1, src1) + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_S2, src2) + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_S3, src3) + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_TK, tk_term) // R2 P5 Task 2:类型项引用 + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_AUX, tk_aux) // R2 P5 Task 2:辅码 + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_FIRST_EDGE, -1) + w64(g_df_nodes, nid * ESZ_DFNODE + OFF_DF_EDGE_COUNT, 0) + g_df_node_count = nid + 1 // Record that this node produces `dest` - if dest >= 0 { - grow_df_arrays(dest + 1); - w64(g_df_var_producer, dest * 8, nid); - } + if dest >= 0: + grow_df_arrays(dest + 1) + w64(g_df_var_producer, dest * 8, nid) // Add edges for src fields that are IR variables (based on opcode) // 第 6 参 = 辅码(IR_BOUNDS_CHECK 的 `!= 0` = 动态上限旗标——单槽化后旗标在 // 辅码槽;见 df_connect_srcs 的 IR_BOUNDS_CHECK 分支)。 - df_connect_srcs(nid, opcode, src1, src2, src3, tk_aux); + df_connect_srcs(nid, opcode, src1, src2, src3, tk_aux) // VSDG state chain(kind=1)不在此连接——见 df_replay_state_chain 头注 // (时点:真纯度需要全程序 IR 体 ⇒ 链统一在 IR 生成结束后重建)。 - return nid; -} + return nid // --- Edge creation --- -fn df_add_edge_kind(from_id: int, to_id: int, kind: int) { - if from_id < 0 || to_id < 0 { return; } - eid := g_df_edge_count; - grow_df_edges(eid + 1); - w64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_FROM, from_id); - w64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_TO, to_id); - w64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_KIND, kind); - old_first := r64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_FIRST_EDGE); - w64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_NEXT, old_first); - w64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_FIRST_EDGE, eid); - old_cnt := r64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_EDGE_COUNT); - w64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_EDGE_COUNT, old_cnt + 1); - g_df_edge_count = eid + 1; -} +fn df_add_edge_kind(from_id: int, to_id: int, kind: int): + if from_id < 0 || to_id < 0: + return + eid := g_df_edge_count + grow_df_edges(eid + 1) + w64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_FROM, from_id) + w64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_TO, to_id) + w64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_KIND, kind) + old_first := r64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_FIRST_EDGE) + w64(g_df_edges, eid * ESZ_DFEDGE + OFF_DFE_NEXT, old_first) + w64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_FIRST_EDGE, eid) + old_cnt := r64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_EDGE_COUNT) + w64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_EDGE_COUNT, old_cnt + 1) + g_df_edge_count = eid + 1 // Data edges (def-use) — the common case -fn df_add_edge(from_id: int, to_id: int) { - df_add_edge_kind(from_id, to_id, 0); -} +fn df_add_edge(from_id: int, to_id: int): + df_add_edge_kind(from_id, to_id, 0) // VSDG state chain: keep the ordering of side-effecting operations in program // order. 只有改内存或调不纯函数的节点入链(各自与前一节点以 kind=1 状态边相连)。 // 时点(效应/纯度修正 Task 1):**不再逐节点即时连接**——改由 df_replay_state_chain // 在全部 IR 生成结束后对成品图重放调用;入链判据未变,仍是本函数。 -fn df_connect_state(node_id: int, opcode: int, s3: int) { - is_side_effect : ., mut = 0; +fn df_connect_state(node_id: int, opcode: int, s3: int): + is_side_effect : ., mut = 0 // opcode 级效应清单的**唯一真源** = purity_op_effect(checker.cr;D7「效应清单 // 收敛为一份」——链分类与纯度判定同表,两条判据才不会各自漂移)。历史两处 // 缺失即由此收敛:① IR_CALL_EXTERN 两侧皆缺(extern 调用既被乐观标纯、又不在 // 本表);② IR_STORE_PTR/IR_AWAIT 只进了纯度侧(裸指针写、spawn 同步)。 - if purity_op_effect(opcode) != 0 { is_side_effect = 1; } - if opcode == IR_CALL { + if purity_op_effect(opcode) != 0: + is_side_effect = 1 + if opcode == IR_CALL: // s3 = func name idx; resolve to func index for purity. Unknown/external // functions are conservatively treated as side-effecting. - cfi := find_func(s3); - if cfi < 0 { is_side_effect = 1; } - else if fi_ispure(cfi) == 0 { is_side_effect = 1; } - } - if is_side_effect != 0 { - if g_last_state_node >= 0 { df_add_edge_kind(g_last_state_node, node_id, 1); } - g_last_state_node = node_id; - } -} + cfi := find_func(s3) + if cfi < 0: + is_side_effect = 1 + else if fi_ispure(cfi) == 0: + is_side_effect = 1 + if is_side_effect != 0: + if g_last_state_node >= 0: + df_add_edge_kind(g_last_state_node, node_id, 1) + g_last_state_node = node_id // ─── state 链重建(效应/纯度修正 Task 1)────────────────────────────── // 出处:链原在 df_create_node 内逐节点即时连接。改为「全部 IR 生成结束后重放」的 @@ -182,468 +182,527 @@ fn df_connect_state(node_id: int, opcode: int, s3: int) { // EDG)⇒ 时点后移零发射影响。 // 重放保真:节点创建序 = 程序序;每函数链头重置(与 df_begin_func 同语义); // 循环终止规则按「区关闭位 = 该区 OFF_SG_EXIT」逐句复刻原 sg_pop 语义。 -fn df_state_close_regions_at(head: string, next: string, pos: int) { - sg := r64(head, pos * 8); - loop { - if sg < 0 { break; } +fn df_state_close_regions_at(head: string, next: string, pos: int): + sg := r64(head, pos * 8) + loop: + if sg < 0: + break // 原 sg_pop 的链语义(spec region-cfg §4.2)逐句复刻:关闭位 = 该区最后一个 // 节点 + 1(当时 g_df_node_count)⇒ last_node = pos - 1。 - last_node := pos - 1; - nstart := r64(g_sgs, sg * ESZ_SG + OFF_SG_NSTART); - if last_node >= nstart { + last_node := pos - 1 + nstart := r64(g_sgs, sg * ESZ_SG + OFF_SG_NSTART) + if last_node >= nstart: // 终止边源必须在区内(循环体无副作用时链头是区前的 store——连过去等于 // 宣称循环退出依赖于该区不含的副作用)。 - if g_last_state_node >= nstart { - df_add_edge_kind(g_last_state_node, last_node, 1); // termination dependency - } + if g_last_state_node >= nstart: + df_add_edge_kind(g_last_state_node, last_node, 1) // termination dependency // 链头推进到区退出节点:循环之后的副作用必须依赖循环终止 // (spec §4.2:不终止的循环必须终止整图)。 - g_last_state_node = last_node; - } - sg = r64(next, sg * 8); - } -} - -fn df_replay_state_chain() { - if g_ir_func_count <= 0 { return; } + g_last_state_node = last_node + sg = r64(next, sg * 8) + +fn df_replay_state_chain(): + if g_ir_func_count <= 0: + return // 位置 → 关闭区(只收 SG_LOOP/SG_FOR——链规则只对这两族生效):head[pos] 与 // next[sg] 两条 i64 链,按区号升序头插 ⇒ 同位置读出为区号降序 = sg_pop 的关闭序。 // alloc 不保证清零(rt.s bump 分配器)⇒ head 逐项显式置 -1。 - head := alloc((g_df_node_count + 1) * 8); - next := alloc((g_sg_count + 1) * 8); - i : ., mut = 0; - loop { - if i > g_df_node_count { break; } - w64(head, i * 8, -1); - i = i + 1; - } - si : ., mut = 0; - loop { - if si >= g_sg_count { break; } - k := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND); - if k == SG_LOOP || k == SG_FOR { - ex := r64(g_sgs, si * ESZ_SG + OFF_SG_EXIT); - if ex >= 0 && ex <= g_df_node_count { - w64(next, si * 8, r64(head, ex * 8)); - w64(head, ex * 8, si); - } - } - si = si + 1; - } - irf : ., mut = 0; - loop { - if irf >= g_ir_func_count { break; } - start := r64(g_df_func_node_start, irf * 8); - cnt := r64(g_df_func_node_count, irf * 8); - g_last_state_node = -1; // 每函数独立链(与 df_begin_func 同语义) - n : ., mut = 0; - loop { - if n >= cnt { break; } - if n > 0 { df_state_close_regions_at(head, next, start + n); } - pos := start + n; + head := alloc((g_df_node_count + 1) * 8) + next := alloc((g_sg_count + 1) * 8) + i : ., mut = 0 + loop: + if i > g_df_node_count: + break + w64(head, i * 8, -1) + i = i + 1 + si : ., mut = 0 + loop: + if si >= g_sg_count: + break + k := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND) + if k == SG_LOOP || k == SG_FOR: + ex := r64(g_sgs, si * ESZ_SG + OFF_SG_EXIT) + if ex >= 0 && ex <= g_df_node_count: + w64(next, si * 8, r64(head, ex * 8)) + w64(head, ex * 8, si) + si = si + 1 + irf : ., mut = 0 + loop: + if irf >= g_ir_func_count: + break + start := r64(g_df_func_node_start, irf * 8) + cnt := r64(g_df_func_node_count, irf * 8) + g_last_state_node = -1 // 每函数独立链(与 df_begin_func 同语义) + n : ., mut = 0 + loop: + if n >= cnt: + break + if n > 0: + df_state_close_regions_at(head, next, start + n) + pos := start + n df_connect_state(pos, r64(g_df_nodes, pos * ESZ_DFNODE + OFF_DF_OPCODE), - r64(g_df_nodes, pos * ESZ_DFNODE + OFF_DF_S3)); - n = n + 1; - } + r64(g_df_nodes, pos * ESZ_DFNODE + OFF_DF_S3)) + n = n + 1 // 函数末端关闭位(SG_FUNC 恒在此;循环落在函数末句时该环也在此)——只在此 // 处理:下一函数走 n=0 时跳过 start ⇒ 每个关闭位恰好处理一次。函数 0 的 // start(位 0)无人处理,但那里 last_node = -1 < nstart ≥ 0 ⇒ 规则恒 no-op。 - df_state_close_regions_at(head, next, start + cnt); - irf = irf + 1; - } -} + df_state_close_regions_at(head, next, start + cnt) + irf = irf + 1 // 链最终化(唯一入口):真纯度 + 链重建。两个调用点均在「IR 生成结束、任何链 // 消费者之前」——run 路径 = ir_gen_all 尾;文件路径 = main.cr IR 循环之后 // (cir 转储 / 区域检查 / lower_to_ccr / 保存 .ccr 之前)。 -fn df_state_finalize() { +fn df_state_finalize(): // 幂等护栏(Task 4 终审 Minor #5):重复调用会**二次连链**(同一图再加一遍 // kind=1 边 + 重算纯度)。当前两调用点互斥故不触发,属潜在坑;旗标随 // reset_frontend_state 复位(长驻进程每编译一次重建)。 - if g_df_state_finalized != 0 { return; } - g_df_state_finalized = 1; - compute_all_purity(); - df_replay_state_chain(); -} - -fn df_use_var(consumer_node: int, var_idx: int) { - if var_idx < 0 { return; } + if g_df_state_finalized != 0: + return + g_df_state_finalized = 1 + compute_all_purity() + df_replay_state_chain() + +fn df_use_var(consumer_node: int, var_idx: int): + if var_idx < 0: + return // Ensure the DF arrays are large enough for this variable index. // df_create_node only grows arrays for 'dest', but src fields (passed as // var_idx here) may have higher indices (e.g. arena_var from IR_ARENA_RESET // where dest=-1 but src1 is a high arena ID variable). - if var_idx >= g_df_cap { grow_df_arrays(var_idx + 1); } - producer := r64(g_df_var_producer, var_idx * 8); - if producer >= 0 { - df_add_edge(producer, consumer_node); - } -} + if var_idx >= g_df_cap: + grow_df_arrays(var_idx + 1) + producer := r64(g_df_var_producer, var_idx * 8) + if producer >= 0: + df_add_edge(producer, consumer_node) // Connect source operands based on opcode semantics. // Only fields that carry IR variable indices create dataflow edges. -fn df_connect_srcs(node_id: int, opcode: int, s1: int, s2: int, s3: int, tk_aux: int) { - if opcode == IR_CONST { return; } // all srcs are scalar values/labels - - if opcode == IR_BINARY { - df_use_var(node_id, s1); - df_use_var(node_id, s2); - return; - } - if opcode == IR_UNARY { - df_use_var(node_id, s1); - return; - } - if opcode == IR_CALL || opcode == IR_SPAWN { +fn df_connect_srcs(node_id: int, opcode: int, s1: int, s2: int, s3: int, tk_aux: int): + if opcode == IR_CONST: + return + // all srcs are scalar values/labels + + if opcode == IR_BINARY: + df_use_var(node_id, s1) + df_use_var(node_id, s2) + return + if opcode == IR_UNARY: + df_use_var(node_id, s1) + return + if opcode == IR_CALL || opcode == IR_SPAWN: // s1 = first argument var index, s2 = arg count (int), s3 = func name idx (int) // All args are contiguous vars starting at s1 - ac : ., mut = 0; - loop { - if ac >= s2 { break; } - df_use_var(node_id, s1 + ac); - ac = ac + 1; - } - return; - } - if opcode == IR_CALL_EXTERN { + ac : ., mut = 0 + loop: + if ac >= s2: + break + df_use_var(node_id, s1 + ac) + ac = ac + 1 + return + if opcode == IR_CALL_EXTERN: // s1 = func_name_ni (int), s2 = first_arg_var, s3 = arg_count - df_use_var(node_id, s2); - return; - } - if opcode == IR_RETURN { - if s1 >= 0 { df_use_var(node_id, s1); } - return; - } - if opcode == IR_STORE { - df_use_var(node_id, s1); // target var - df_use_var(node_id, s2); // value var - return; - } - if opcode == IR_LOAD { - df_use_var(node_id, s1); // address var - return; - } - if opcode == IR_LOAD_FIELD { - df_use_var(node_id, s1); // struct var - return; - } - if opcode == IR_STORE_FIELD { - df_use_var(node_id, s1); // struct var - df_use_var(node_id, s2); // value var - return; - } - if opcode == IR_LOAD_INDEX { - df_use_var(node_id, s1); // array var - return; - } - if opcode == IR_STORE_INDEX { - df_use_var(node_id, s1); // array var - df_use_var(node_id, s2); // value var - return; - } - if opcode == IR_LOAD_INDEX_VAR { - df_use_var(node_id, s1); // array var - df_use_var(node_id, s2); // index var - return; - } - if opcode == IR_STORE_INDEX_VAR { - df_use_var(node_id, s1); // value var - df_use_var(node_id, s2); // array var - df_use_var(node_id, s3); // index var - return; - } - if opcode == IR_BRANCH { - df_use_var(node_id, s1); // condition var (labels s2, s3 are not vars) - return; - } - if opcode == IR_BOUNDS_CHECK { - df_use_var(node_id, s1); + df_use_var(node_id, s2) + return + if opcode == IR_RETURN: + if s1 >= 0: + df_use_var(node_id, s1) + return + if opcode == IR_STORE: + df_use_var(node_id, s1) // target var + df_use_var(node_id, s2) // value var + return + if opcode == IR_LOAD: + df_use_var(node_id, s1) // address var + return + if opcode == IR_LOAD_FIELD: + df_use_var(node_id, s1) // struct var + return + if opcode == IR_STORE_FIELD: + df_use_var(node_id, s1) // struct var + df_use_var(node_id, s2) // value var + return + if opcode == IR_LOAD_INDEX: + df_use_var(node_id, s1) // array var + return + if opcode == IR_STORE_INDEX: + df_use_var(node_id, s1) // array var + df_use_var(node_id, s2) // value var + return + if opcode == IR_LOAD_INDEX_VAR: + df_use_var(node_id, s1) // array var + df_use_var(node_id, s2) // index var + return + if opcode == IR_STORE_INDEX_VAR: + df_use_var(node_id, s1) // value var + df_use_var(node_id, s2) // array var + df_use_var(node_id, s3) // index var + return + if opcode == IR_BRANCH: + df_use_var(node_id, s1) // condition var (labels s2, s3 are not vars) + return + if opcode == IR_BOUNDS_CHECK: + df_use_var(node_id, s1) // 单槽化(P5 T2):旗标已从混用 tk 槽移入**辅码**槽 ⇒ 读 tk_aux(值域不变: // 1 = 动态上限 ⇒ 上限变量 s2 也是数据依赖;0 = 字面量上限 ⇒ 不连)。 - if tk_aux != 0 { df_use_var(node_id, s2); } - return; - } - if opcode == IR_REF { - df_use_var(node_id, s1); // referenced var - return; - } - if opcode == IR_DEREF { - df_use_var(node_id, s1); // ref var - return; - } - if opcode == IR_MAKE_ENUM { + if tk_aux != 0: + df_use_var(node_id, s2) + return + if opcode == IR_REF: + df_use_var(node_id, s1) // referenced var + return + if opcode == IR_DEREF: + df_use_var(node_id, s1) // ref var + return + if opcode == IR_MAKE_ENUM: // s1 = variant name idx (int), fields are stored separately via STORE_FIELD - return; - } - if opcode == IR_SLICE { - df_use_var(node_id, s1); // array var - df_use_var(node_id, s2); // low var - df_use_var(node_id, s3); // high var - return; - } - if opcode == IR_STORE_PTR { - df_use_var(node_id, s1); // ptr var - df_use_var(node_id, s2); // value var - return; - } - if opcode == IR_LOAD_ENUM_TAG { - df_use_var(node_id, s1); // enum var - return; - } - if opcode == IR_ARENA_NEW { df_use_var(node_id, s1); return; } - if opcode == IR_ARENA_RESET { df_use_var(node_id, s1); return; } - if opcode == IR_INLINE { df_use_var(node_id, s1); return; } - if opcode == IR_HOTPATCH_ROUTE { - df_use_var(node_id, s2); // first_arg is a variable - return; - } - if opcode == IR_DYN_TAG { df_use_var(node_id, s1); return; } - if opcode == IR_DYN_VAL { df_use_var(node_id, s1); return; } - if opcode == IR_DYN_PACK { df_use_var(node_id, s1); return; } - if opcode == IR_DYN_DISPATCH { df_use_var(node_id, s1); return; } - if opcode == IR_LAZY_THUNK { df_use_var(node_id, s1); return; } - if opcode == IR_LAZY_FORCE { df_use_var(node_id, s1); return; } + return + if opcode == IR_SLICE: + df_use_var(node_id, s1) // array var + df_use_var(node_id, s2) // low var + df_use_var(node_id, s3) // high var + return + if opcode == IR_STORE_PTR: + df_use_var(node_id, s1) // ptr var + df_use_var(node_id, s2) // value var + return + if opcode == IR_LOAD_ENUM_TAG: + df_use_var(node_id, s1) // enum var + return + if opcode == IR_ARENA_NEW: + df_use_var(node_id, s1) + return + if opcode == IR_ARENA_RESET: + df_use_var(node_id, s1) + return + if opcode == IR_INLINE: + df_use_var(node_id, s1) + return + if opcode == IR_HOTPATCH_ROUTE: + df_use_var(node_id, s2) // first_arg is a variable + return + if opcode == IR_DYN_TAG: + df_use_var(node_id, s1) + return + if opcode == IR_DYN_VAL: + df_use_var(node_id, s1) + return + if opcode == IR_DYN_PACK: + df_use_var(node_id, s1) + return + if opcode == IR_DYN_DISPATCH: + df_use_var(node_id, s1) + return + if opcode == IR_LAZY_THUNK: + df_use_var(node_id, s1) + return + if opcode == IR_LAZY_FORCE: + df_use_var(node_id, s1) + return // Other opcodes (LABEL, JUMP, ALLOC, ALLOC_STRUCT, ALLOC_ARRAY, PHI): // no variable inputs to track -} // --- Usage count analysis --- -fn grow_var_use_count(needed: int) { - if needed < g_var_use_count_cap { return; } - nc : ., mut = g_var_use_count_cap * 2; - if nc < 128 { nc = 128; } - if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); - _dyncpy(g_var_use_count, g_var_use_count_cap * 8, nb); - g_var_use_count = nb; - g_var_use_count_cap = nc; -} - -fn compute_usage_counts() { +fn grow_var_use_count(needed: int): + if needed < g_var_use_count_cap: + return + nc : ., mut = g_var_use_count_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_var_use_count, g_var_use_count_cap * 8, nb) + g_var_use_count = nb + g_var_use_count_cap = nc + +fn compute_usage_counts(): // For each edge from_id→to_id, increment the usage count of // from_id's dest variable (the IR variable it produces). - ei : ., mut = 0; - loop { - if ei >= g_df_edge_count { break; } + ei : ., mut = 0 + loop: + if ei >= g_df_edge_count: + break // State edges are not data consumers — skip them for usage counts - if r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_KIND) != 0 { ei = ei + 1; continue; } - from_id := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_FROM); - dest := r64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_DEST); - if dest >= 0 { - grow_var_use_count(dest + 1); - prev := r64(g_var_use_count, dest * 8); - w64(g_var_use_count, dest * 8, prev + 1); - } - ei = ei + 1; - } -} + if r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_KIND) != 0: + ei = ei + 1 + continue + from_id := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_FROM) + dest := r64(g_df_nodes, from_id * ESZ_DFNODE + OFF_DF_DEST) + if dest >= 0: + grow_var_use_count(dest + 1) + prev := r64(g_var_use_count, dest * 8) + w64(g_var_use_count, dest * 8, prev + 1) + ei = ei + 1 // --- Lowering: dataflow graph → linear CFG IR (.ccr) --- -fn lower_to_ccr() { +fn lower_to_ccr(): // The graph was built in parallel with linear IR during emit(). // For now: clear and rebuild g_ir_instrs from graph nodes. // Since nodes are in creation order (AST walk order), sequential // walk is already a valid topological schedule. - g_ir_instr_count = 0; - - ni : ., mut = 0; - loop { - if ni >= g_df_node_count { break; } - idx := g_ir_instr_count; - grow_ir_instrs(idx + 1); - iri_set_op(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE)); - iri_set_dest(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST)); - iri_set_s1(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S1)); - iri_set_s2(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S2)); - iri_set_s3(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3)); + g_ir_instr_count = 0 + + ni : ., mut = 0 + loop: + if ni >= g_df_node_count: + break + idx := g_ir_instr_count + grow_ir_instrs(idx + 1) + iri_set_op(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE)) + iri_set_dest(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST)) + iri_set_s1(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S1)) + iri_set_s2(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S2)) + iri_set_s3(idx, r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3)) // R2 P5 Task 2(D19):iri_tk = **派生码**(不是槽值)——单槽化后 40 槽存的是 // 类型项引用,码一律经 sh_dfn_code_of_slots 派生(派生码逐节点 ≡ 单槽化前的 // 混用码 ⇒ .ccr 字节不变)。本文件对桥接符号的依赖仅此一处(df_create_node // 本身保持零前端依赖;lower_to_ccr 本就引 checker 侧 purity_op_effect)。 iri_set_tk(idx, sh_dfn_code_of_slots( - r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_TK), - r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_AUX))); - g_ir_instr_count = idx + 1; - ni = ni + 1; - } + r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_TK), + r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_AUX))) + g_ir_instr_count = idx + 1 + ni = ni + 1 // Rebuilt g_ir_instrs means g_ir_func_instr_start/count are stale. // Node i → instruction i, so df boundaries = ir boundaries. - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break w64(g_ir_func_instr_start, fi * 8, - r64(g_df_func_node_start, fi * 8)); + r64(g_df_func_node_start, fi * 8)) w64(g_ir_func_instr_count, fi * 8, - r64(g_df_func_node_count, fi * 8)); - fi = fi + 1; - } + r64(g_df_func_node_count, fi * 8)) + fi = fi + 1 // After lowering, compute per-variable usage counts for optimization passes - compute_usage_counts(); + compute_usage_counts() // regalloc 移后端(2026-09-07,D-1=Y):数据面(区间/条目)随分配归位 // corearch——.ccr ENT 恒空,不再在此无条件计算;corearch load 后自算自检 // (regalloc.cr compute_live_ranges/compute_entries,载入 NOD 流坐标同源)。 -} // --- Mark function boundary in graph --- -fn df_begin_func(func_idx: int) { - if func_idx >= 0 { - grow_df_arrays(func_idx + 1); - w64(g_df_func_node_start, func_idx * 8, g_df_node_count); +fn df_begin_func(func_idx: int): + if func_idx >= 0: + grow_df_arrays(func_idx + 1) + w64(g_df_func_node_start, func_idx * 8, g_df_node_count) // 缓存收窄批(CIR_CACHE_VER 20):记边起点——本函数的边 = [edge_start, g_df_edge_count)。 // 时点与 df_end_func 的节点计数同构:**df_begin_func 之后产生的边皆属本函数** // (节点亦然;df_begin/df_end 自身不建边,state 链在全部 save 之后才重放)。 - w64(g_df_func_edge_start, func_idx * 8, g_df_edge_count); - sg_push(SG_FUNC); - } - g_last_state_node = -1; // fresh state chain per function -} - -fn df_end_func(func_idx: int) { - if func_idx >= 0 { - start := r64(g_df_func_node_start, func_idx * 8); - w64(g_df_func_node_count, func_idx * 8, g_df_node_count - start); - sg_pop(); - } -} + w64(g_df_func_edge_start, func_idx * 8, g_df_edge_count) + sg_push(SG_FUNC) + g_last_state_node = -1 // fresh state chain per function + +fn df_end_func(func_idx: int): + if func_idx >= 0: + start := r64(g_df_func_node_start, func_idx * 8) + w64(g_df_func_node_count, func_idx * 8, g_df_node_count - start) + sg_pop() // --- DOT output --- -fn df_graph_to_dot() -> string { +fn df_graph_to_dot() -> string: // Build the graph in a growable buffer. Repeated string concatenation // allocates and copies the whole prefix for every fragment, exhausting // the native bump heap on medium/large graphs before the dump is written. - dump_buf_reset(); - dump_buf_append("digraph G {\n"); - dump_buf_append(" rankdir=TB;\n"); + dump_buf_reset() + dump_buf_append("digraph G {\n") + dump_buf_append(" rankdir=TB;\n") // Region clusters: group each subgraph's nodes into a DOT cluster - si : ., mut = 0; - loop { - if si >= g_sg_count { break; } - skind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND); - sname : ., mut = "region"; - if skind == SG_IF { sname = "if"; } - if skind == SG_LOOP { sname = "loop"; } - if skind == SG_FOR { sname = "for"; } - if skind == SG_FLOW { sname = "flow"; } - if skind == SG_UNSAFE { sname = "unsafe"; } - dump_buf_append(" subgraph cluster_"); dump_buf_append(sname); - dump_buf_append(int_str(si)); dump_buf_append(" { label=\""); - dump_buf_append(sname); dump_buf_append("\";\n"); + si : ., mut = 0 + loop: + if si >= g_sg_count: + break + skind := r64(g_sgs, si * ESZ_SG + OFF_SG_KIND) + sname : ., mut = "region" + if skind == SG_IF: + sname = "if" + if skind == SG_LOOP: + sname = "loop" + if skind == SG_FOR: + sname = "for" + if skind == SG_FLOW: + sname = "flow" + if skind == SG_UNSAFE: + sname = "unsafe" + dump_buf_append(" subgraph cluster_") + dump_buf_append(sname) + dump_buf_append(int_str(si)) + dump_buf_append(" { label=\"") + dump_buf_append(sname) + dump_buf_append("\";\n") // Nodes in this region: - n0 := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART); - n1 := r64(g_sgs, si * ESZ_SG + OFF_SG_EXIT); - if n1 >= 0 { // skip unclosed (EXIT<0) entries - ni : ., mut = n0; - loop { if ni >= n1 { break; } - dump_buf_append(" n"); dump_buf_append(int_str(ni)); dump_buf_append(";\n"); - ni = ni + 1; } - } - dump_buf_append(" }\n"); - si = si + 1; - } + n0 := r64(g_sgs, si * ESZ_SG + OFF_SG_NSTART) + n1 := r64(g_sgs, si * ESZ_SG + OFF_SG_EXIT) + if n1 >= 0: + // skip unclosed (EXIT<0) entries + ni : ., mut = n0 + loop: + if ni >= n1: + break + dump_buf_append(" n") + dump_buf_append(int_str(ni)) + dump_buf_append(";\n") + ni = ni + 1 + dump_buf_append(" }\n") + si = si + 1 // Node definitions - ni : ., mut = 0; - loop { - if ni >= g_df_node_count { break; } - n_op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE); - n_dest := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST); - n_s3 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3); - label : ., mut = df_opcode_name(n_op, n_s3); - if n_dest >= 0 { - vname := get_ir_var_name(n_dest); - if str_len(vname) > 0 { - label = vname + ":" + label; - } - } - dump_buf_append(" n"); dump_buf_append(int_str(ni)); - dump_buf_append(" [label=\""); dump_buf_append(label); - dump_buf_append("\", shape=box];\n"); - ni = ni + 1; - } + ni : ., mut = 0 + loop: + if ni >= g_df_node_count: + break + n_op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE) + n_dest := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_DEST) + n_s3 := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3) + label : ., mut = df_opcode_name(n_op, n_s3) + if n_dest >= 0: + vname := get_ir_var_name(n_dest) + if str_len(vname) > 0: + label = vname + ":" + label + dump_buf_append(" n") + dump_buf_append(int_str(ni)) + dump_buf_append(" [label=\"") + dump_buf_append(label) + dump_buf_append("\", shape=box];\n") + ni = ni + 1 // Edges (state edges dashed/red so ordering constraints stand out) - ei : ., mut = 0; - loop { - if ei >= g_df_edge_count { break; } - e_from := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_FROM); - e_to := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_TO); - if r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_KIND) != 0 { - dump_buf_append(" n"); dump_buf_append(int_str(e_from)); dump_buf_append(" -> n"); - dump_buf_append(int_str(e_to)); dump_buf_append(" [style=dashed,color=red];\n"); - } else { - dump_buf_append(" n"); dump_buf_append(int_str(e_from)); dump_buf_append(" -> n"); - dump_buf_append(int_str(e_to)); dump_buf_append(";\n"); - } - ei = ei + 1; - } - - dump_buf_append("}\n"); - return dump_buf_finish(); -} - -fn df_opcode_name(opcode: int, s3: int) -> string { - if opcode == IR_CONST { return "const"; } - if opcode == IR_BINARY { - if s3 == OP_PTR_ADD { return "ptr_add"; } - if s3 == OP_PTR_SUB { return "ptr_sub"; } - if s3 == OP_PTR_DIFF { return "ptr_diff"; } - return "binary"; - } - if opcode == IR_UNARY { return "unary"; } - if opcode == IR_CALL { return "call"; } - if opcode == IR_RETURN { return "return"; } - if opcode == IR_ALLOC { return "alloc"; } - if opcode == IR_ALLOC_STRUCT { return "alloc_struct"; } - if opcode == IR_ALLOC_ARRAY { return "alloc_array"; } - if opcode == IR_STORE { return "store"; } - if opcode == IR_LOAD { return "load"; } - if opcode == IR_LOAD_FIELD { return "load_field"; } - if opcode == IR_STORE_FIELD { return "store_field"; } - if opcode == IR_LOAD_INDEX { return "load_index"; } - if opcode == IR_STORE_INDEX { return "store_index"; } - if opcode == IR_LOAD_INDEX_VAR { return "load_index_var"; } - if opcode == IR_STORE_INDEX_VAR { return "store_index_var"; } - if opcode == IR_MAKE_ENUM { return "make_enum"; } - if opcode == IR_REF { return "ref"; } - if opcode == IR_BRANCH { return "branch"; } - if opcode == IR_JUMP { return "jump"; } - if opcode == IR_LABEL { return "label"; } - if opcode == IR_PHI { return "phi"; } - if opcode == IR_LOAD_ENUM_TAG { return "load_enum_tag"; } - if opcode == IR_SLICE { return "slice"; } - if opcode == IR_DEREF { return "deref"; } - if opcode == IR_STORE_PTR { return "store_ptr"; } - if opcode == IR_SPAWN { return "spawn"; } - if opcode == IR_YIELD { return "yield"; } - if opcode == IR_FNADDR { return "fnaddr"; } - if opcode == IR_ARENA_NEW { return "arena_new"; } - if opcode == IR_ARENA_RESET { return "arena_reset"; } - if opcode == IR_INLINE { return "inline"; } - if opcode == IR_NO_BOUNDS_CHECK { return "NoBoundsCheck"; } - if opcode == IR_FAST { return "fast"; } - if opcode == IR_UNROLL { return "unroll"; } - if opcode == IR_APPROX { return "approx"; } - if opcode == IR_SECTION { return "section"; } - if opcode == IR_HOTPATCH_ROUTE { return "hotpatch_route"; } - if opcode == IR_DYN_TAG { return "dyn_tag"; } - if opcode == IR_DYN_VAL { return "dyn_val"; } - if opcode == IR_DYN_PACK { return "dyn_pack"; } - if opcode == IR_DYN_DISPATCH { return "dyn_dispatch"; } - if opcode == IR_CALL_EXTERN { return "call_extern"; } - if opcode == IR_LAZY_THUNK { return "lazy_thunk"; } - if opcode == IR_LAZY_FORCE { return "lazy_force"; } - if opcode == IR_AWAIT { return "await"; } - if opcode == IR_BOUNDS_CHECK { return "bounds_check"; } - if opcode == IR_ADDR_INDEX { return "addr_index"; } - if opcode == IR_I2F { return "i2f"; } - if opcode == IR_F2I { return "f2i"; } - if opcode == IR_NOP { return "nop"; } - return "?"; -} + ei : ., mut = 0 + loop: + if ei >= g_df_edge_count: + break + e_from := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_FROM) + e_to := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_TO) + if r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_KIND) != 0: + dump_buf_append(" n") + dump_buf_append(int_str(e_from)) + dump_buf_append(" -> n") + dump_buf_append(int_str(e_to)) + dump_buf_append(" [style=dashed,color=red];\n") + else: + dump_buf_append(" n") + dump_buf_append(int_str(e_from)) + dump_buf_append(" -> n") + dump_buf_append(int_str(e_to)) + dump_buf_append(";\n") + ei = ei + 1 + + dump_buf_append("}\n") + return dump_buf_finish() + +fn df_opcode_name(opcode: int, s3: int) -> string: + if opcode == IR_CONST: + return "const" + if opcode == IR_BINARY: + if s3 == OP_PTR_ADD: + return "ptr_add" + if s3 == OP_PTR_SUB: + return "ptr_sub" + if s3 == OP_PTR_DIFF: + return "ptr_diff" + return "binary" + if opcode == IR_UNARY: + return "unary" + if opcode == IR_CALL: + return "call" + if opcode == IR_RETURN: + return "return" + if opcode == IR_ALLOC: + return "alloc" + if opcode == IR_ALLOC_STRUCT: + return "alloc_struct" + if opcode == IR_ALLOC_ARRAY: + return "alloc_array" + if opcode == IR_STORE: + return "store" + if opcode == IR_LOAD: + return "load" + if opcode == IR_LOAD_FIELD: + return "load_field" + if opcode == IR_STORE_FIELD: + return "store_field" + if opcode == IR_LOAD_INDEX: + return "load_index" + if opcode == IR_STORE_INDEX: + return "store_index" + if opcode == IR_LOAD_INDEX_VAR: + return "load_index_var" + if opcode == IR_STORE_INDEX_VAR: + return "store_index_var" + if opcode == IR_MAKE_ENUM: + return "make_enum" + if opcode == IR_REF: + return "ref" + if opcode == IR_BRANCH: + return "branch" + if opcode == IR_JUMP: + return "jump" + if opcode == IR_LABEL: + return "label" + if opcode == IR_PHI: + return "phi" + if opcode == IR_LOAD_ENUM_TAG: + return "load_enum_tag" + if opcode == IR_SLICE: + return "slice" + if opcode == IR_DEREF: + return "deref" + if opcode == IR_STORE_PTR: + return "store_ptr" + if opcode == IR_SPAWN: + return "spawn" + if opcode == IR_YIELD: + return "yield" + if opcode == IR_FNADDR: + return "fnaddr" + if opcode == IR_ARENA_NEW: + return "arena_new" + if opcode == IR_ARENA_RESET: + return "arena_reset" + if opcode == IR_INLINE: + return "inline" + if opcode == IR_NO_BOUNDS_CHECK: + return "NoBoundsCheck" + if opcode == IR_FAST: + return "fast" + if opcode == IR_UNROLL: + return "unroll" + if opcode == IR_APPROX: + return "approx" + if opcode == IR_SECTION: + return "section" + if opcode == IR_HOTPATCH_ROUTE: + return "hotpatch_route" + if opcode == IR_DYN_TAG: + return "dyn_tag" + if opcode == IR_DYN_VAL: + return "dyn_val" + if opcode == IR_DYN_PACK: + return "dyn_pack" + if opcode == IR_DYN_DISPATCH: + return "dyn_dispatch" + if opcode == IR_CALL_EXTERN: + return "call_extern" + if opcode == IR_LAZY_THUNK: + return "lazy_thunk" + if opcode == IR_LAZY_FORCE: + return "lazy_force" + if opcode == IR_AWAIT: + return "await" + if opcode == IR_BOUNDS_CHECK: + return "bounds_check" + if opcode == IR_ADDR_INDEX: + return "addr_index" + if opcode == IR_I2F: + return "i2f" + if opcode == IR_F2I: + return "f2i" + if opcode == IR_NOP: + return "nop" + return "?" diff --git a/src/compiler/diag.cr b/src/compiler/diag.cr index 732b08a7..705ca213 100644 --- a/src/compiler/diag.cr +++ b/src/compiler/diag.cr @@ -4,163 +4,177 @@ // ─── helpers ──────────────────────────────────────────────────── -fn read_source_line(line: int) -> string { - slen := str_len(g_source); - cur : ., mut = 1; - start : ., mut = 0; - i : ., mut = 0; - loop { - if i >= slen { break; } - if cur == line { - j : ., mut = i; - loop { - if j >= slen { break; } - c := get_char(g_source, j); - if c == "\n" { break; } - j = j + 1; - } - return str_sub(g_source, i, j - i); - } - if load8(g_source, i) == 10 { - cur = cur + 1; - start = i + 1; - } - i = i + 1; - } - return ""; -} +fn read_source_line(line: int) -> string: + slen := str_len(g_source) + cur : ., mut = 1 + start : ., mut = 0 + i : ., mut = 0 + loop: + if i >= slen: + break + if cur == line: + j : ., mut = i + loop: + if j >= slen: + break + c := get_char(g_source, j) + if c == "\n": + break + j = j + 1 + return str_sub(g_source, i, j - i) + if load8(g_source, i) == 10: + cur = cur + 1 + start = i + 1 + i = i + 1 + return "" -fn source_line_count() -> int { - count : ., mut = 1; - i : ., mut = 0; - slen := str_len(g_source); - loop { - if i >= slen { break; } - if load8(g_source, i) == 10 { count = count + 1; } - i = i + 1; - } - return count; -} +fn source_line_count() -> int: + count : ., mut = 1 + i : ., mut = 0 + slen := str_len(g_source) + loop: + if i >= slen: + break + if load8(g_source, i) == 10: + count = count + 1 + i = i + 1 + return count -fn print_source_line(line: int, col: int, annotation: string) { - if line <= 0 { return; } - ltxt := read_source_line(line); - if str_len(ltxt) == 0 { return; } - ln_str := int_str(line); - if line < 10 { ln_str = " " + ln_str; } - print(ln_str); - print(" | "); - println(ltxt); +fn print_source_line(line: int, col: int, annotation: string): + if line <= 0: + return + ltxt := read_source_line(line) + if str_len(ltxt) == 0: + return + ln_str := int_str(line) + if line < 10: + ln_str = " " + ln_str + print(ln_str) + print(" | ") + println(ltxt) // underline: spaces + ^ under the column + annotation - print(" | "); - ci : ., mut = 0; - loop { - if ci >= col - 1 { break; } - print(" "); - ci = ci + 1; - } - print("^"); - if str_len(annotation) > 0 { - print(" "); + print(" | ") + ci : ., mut = 0 + loop: + if ci >= col - 1: + break + print(" ") + ci = ci + 1 + print("^") + if str_len(annotation) > 0: + print(" ") // Short annotation: first line or up to first " — " - alen := str_len(annotation); - cutoff : ., mut = alen; + alen := str_len(annotation) + cutoff : ., mut = alen // Truncate at ' — ' (3 bytes in UTF-8: em dash = 3 bytes) - ci2 : ., mut = 0; - loop { - if ci2 + 3 > alen { break; } - c := load8(annotation, ci2); - if c == 226 { // start of em dash (— = U+2014, 3 bytes) - cutoff = ci2; - break; - } - ci2 = ci2 + 1; - } + ci2 : ., mut = 0 + loop: + if ci2 + 3 > alen: + break + c := load8(annotation, ci2) + if c == 226: + // start of em dash (— = U+2014, 3 bytes) + cutoff = ci2 + break + ci2 = ci2 + 1 // Limit to 48 chars max - if cutoff > 48 { cutoff = 48; } - print(str_sub(annotation, 0, cutoff)); - } - println(""); -} + if cutoff > 48: + cutoff = 48 + print(str_sub(annotation, 0, cutoff)) + println("") -fn error_cat_prefix(cat: int) -> string { - if cat == 1 { return "P"; } - if cat == 2 { return "N"; } - if cat == 3 { return "I"; } - if cat == 4 { return "TA"; } - if cat == 5 { return "TF"; } - if cat == 6 { return "TB"; } - if cat == 7 { return "TU"; } - if cat == 8 { return "TC"; } - if cat == 9 { return "TM"; } - if cat == 10 { return "TK"; } - if cat == 11 { return "TS"; } - if cat == 12 { return "TG"; } - if cat == 13 { return "B"; } - if cat == 14 { return "R"; } - if cat == 15 { return "E"; } - if cat == 16 { return "ICE"; } - if cat == 17 { return "V"; } // 批 6:规约语法/验证面(EC_V_*,17xxx) - return "E"; -} +fn error_cat_prefix(cat: int) -> string: + if cat == 1: + return "P" + if cat == 2: + return "N" + if cat == 3: + return "I" + if cat == 4: + return "TA" + if cat == 5: + return "TF" + if cat == 6: + return "TB" + if cat == 7: + return "TU" + if cat == 8: + return "TC" + if cat == 9: + return "TM" + if cat == 10: + return "TK" + if cat == 11: + return "TS" + if cat == 12: + return "TG" + if cat == 13: + return "B" + if cat == 14: + return "R" + if cat == 15: + return "E" + if cat == 16: + return "ICE" + if cat == 17: + return "V" + // 批 6:规约语法/验证面(EC_V_*,17xxx) + return "E" -fn pad_diag_num(num: int) -> string { - s := int_str(num); - if num < 10 { s = "0" + s; } - return s; -} +fn pad_diag_num(num: int) -> string: + s := int_str(num) + if num < 10: + s = "0" + s + return s // ─── diagnostics (g_diags) ───────────────────────────────────── // 行号 → 所属文件 id(build_line_fileid 的逐行映射);越界返回 -1 -fn diag_fileid_for_line(line: int) -> int { - if line >= 1 && line <= g_line_count { - return r64(g_line_fileid, (line - 1) * 8); - } - return -1; -} +fn diag_fileid_for_line(line: int) -> int: + if line >= 1 && line <= g_line_count: + return r64(g_line_fileid, (line - 1) * 8) + return -1 -fn print_diagnostics() { - if g_diag_count == 0 { return; } - source_lines := source_line_count(); - di : ., mut = 0; - loop { - if di >= g_diag_count { break; } - ec := r64(g_diags, di * DIAG_REC_SIZE); - msg := load_str_ptr(g_diags, di * DIAG_REC_SIZE + 8); - ln := r64(g_diags, di * DIAG_REC_SIZE + 16); - cl := r64(g_diags, di * DIAG_REC_SIZE + 24); - cat : ., mut = ec / 1000; - num : ., mut = ec % 1000; - print("error["); - print(error_cat_prefix(cat)); - print(pad_diag_num(num)); - print("]: "); - println(msg); - print(" --> "); - print(int_str(ln)); - print(":"); - println(int_str(cl)); - if ln > 0 && ln <= source_lines { - println(" |"); - print_source_line(ln, cl, msg); - } - println(""); - di = di + 1; - } -} +fn print_diagnostics(): + if g_diag_count == 0: + return + source_lines := source_line_count() + di : ., mut = 0 + loop: + if di >= g_diag_count: + break + ec := r64(g_diags, di * DIAG_REC_SIZE) + msg := load_str_ptr(g_diags, di * DIAG_REC_SIZE + 8) + ln := r64(g_diags, di * DIAG_REC_SIZE + 16) + cl := r64(g_diags, di * DIAG_REC_SIZE + 24) + cat : ., mut = ec / 1000 + num : ., mut = ec % 1000 + print("error[") + print(error_cat_prefix(cat)) + print(pad_diag_num(num)) + print("]: ") + println(msg) + print(" --> ") + print(int_str(ln)) + print(":") + println(int_str(cl)) + if ln > 0 && ln <= source_lines: + println(" |") + print_source_line(ln, cl, msg) + println("") + di = di + 1 // ─── parse errors (g_errors) ──────────────────────────────────── -fn print_parse_errors() { - if g_error_count == 0 { return; } - ei2 : ., mut = 0; - loop { - if ei2 >= g_error_count { break; } - println("error: " + istr_get(r64(g_errors, ei2 * 8))); - ei2 = ei2 + 1; - } -} +fn print_parse_errors(): + if g_error_count == 0: + return + ei2 : ., mut = 0 + loop: + if ei2 >= g_error_count: + break + println("error: " + istr_get(r64(g_errors, ei2 * 8))) + ei2 = ei2 + 1 // ─── fail-closed 判据线(FC 批 T2):豁免登记表 ──────────────────────── // 语义:**默认阻断 + 豁免登记表**——`main.cr` 的硬判定循环对每条诊断调本函数,返回 0 ⇒ 阻断 // (rc=1 + 零产物)。判据 = 「判定继续 ⇒ 产出静默错产物」(R002 / TS01-04+TK02 / TM03 / ICE04 / @@ -169,7 +183,7 @@ fn print_parse_errors() { // 必须重跑全语料 report-only 并对表(表外命中 ⇒ 停)。 // 粒度 = 码级;每条附「位点证据 / 理由 / 退出条件」三字段(证据字段不参与判定)。 // **不得**把本表写成「默认放行」形态(那会把静默错产物制度化)。 -fn diag_gate_exempt(code: int, scope: int) -> int { +fn diag_gate_exempt(code: int, scope: int) -> int: // ── scope = BUILD(5 条;build/ccr/cir/run 面)──────────────────────── // **TF01 已于 2026-09-18(批 8 A₂)撤销**——撤条归因(带根因证据,合「只减不增」纪律): // 真因 = 类型模型冲突:`alloc` 的模型是 `() -> string`(`checker.cr` 的 `bi_add("alloc", TI_STR)`), @@ -183,29 +197,35 @@ fn diag_gate_exempt(code: int, scope: int) -> int { // TF07 · 位点 = tests/suite/ptr_ref_first.cr:8(@raw_int)+ tests/selfhost/test_ccr_types.py:1805 // 理由 = EC_TF_ARG_TYPE 全仓唯一 raise 点在 @raw_int 内建位(checker.cr:3727),非调用位点 // 退出 = #2026-09-16-1/F3 调用位点收口后撤 - if scope == GATE_SCOPE_BUILD && code == EC_TF_ARG_TYPE { return 1; } + if scope == GATE_SCOPE_BUILD && code == EC_TF_ARG_TYPE: + return 1 // TF07 · 位点 = tests/suite/ptr_ref_first.cr:8(@raw_int)+ tests/selfhost/test_ccr_types.py:1805 // 理由 = EC_TF_ARG_TYPE 全仓唯一 raise 点在 @raw_int 内建位(checker.cr:3727),非调用位点 // 退出 = #2026-09-16-1/F3 调用位点收口后撤 - if scope == GATE_SCOPE_BUILD && code == EC_TF_ARG_TYPE { return 1; } + if scope == GATE_SCOPE_BUILD && code == EC_TF_ARG_TYPE: + return 1 // TB01 · 位点 = ptr_ref_first(TF07 级联)+ t3/t4 库单元 8 档(N 族级联) // 理由 = **级联码**:ANY 门(checker.cr:2473-2474)仅在**双侧**非 int/dex 时报, // 而错误标记 TI_NEVER 的回传点(:2433/:2810/:3728)先行 ⇒ 连带命中 // 退出 = 随根因码(N 族划界 / TF07)消失;**真错形态(*T + *T、"a" - "b")不受影响** - if scope == GATE_SCOPE_BUILD && code == EC_TB_ADD { return 1; } + if scope == GATE_SCOPE_BUILD && code == EC_TB_ADD: + return 1 // TM04 · 位点 = tests/selfhost/test_match_exhaust.py:217(case_soft:build rc=0 + 产物照出) // 理由 = P3 Task 3 政策(软面登记,同 Rust unreachable-pattern 警告口径) // 退出 = 政策改判(引入真 warning 通道) - if scope == GATE_SCOPE_BUILD && code == EC_TM_REDUNDANT { return 1; } + if scope == GATE_SCOPE_BUILD && code == EC_TM_REDUNDANT: + return 1 // TK01 · 位点 = tests/selfhost/test_xcut_iface.py:234-241(case_reject soft=True:build rc=0 + 产物) // 理由 = P3b Task 2 索引兜底门软面政策 // 退出 = 政策改判 - if scope == GATE_SCOPE_BUILD && code == EC_TK_INDEX { return 1; } + if scope == GATE_SCOPE_BUILD && code == EC_TK_INDEX: + return 1 // B04 · 位点 = tests/suite/ptr_arith.cr:12:8(= ELF canary 载体本人) // 理由 = 借用模型无末次使用(NLL 式)收缩——借用只随作用域退出释放 // (checker.cr:878 push / :884-915 pop) // 退出 = 裁-FC-3 取 (c)(块包裹修法)或 (i)(实现借用收缩)后撤 - if scope == GATE_SCOPE_BUILD && code == EC_B_USE_WHILE_BORROWED { return 1; } + if scope == GATE_SCOPE_BUILD && code == EC_B_USE_WHILE_BORROWED: + return 1 // ── scope = CHECK(3 条;**本批对 build/gate 无效,仅登记**)──────────── // 维护者 2026-09-14 裁(裁-FC-1 = (C) 终局):check 面 rc 规则不消费本表 ⇒ 本 3 条对判定 // **惰性**;保留 = 登记(T1 would_block.tsv 的 34 条 check 面命中即其证据)+ 若将来另裁 (B) @@ -213,8 +233,10 @@ fn diag_gate_exempt(code: int, scope: int) -> int { // N01/N06/N11 · 位点 = 25 档库单元单独 check(t2 1 + t3 13 + t4 10 + t1 1) // 理由 = concat 供货语境缺失(非独立编译单元),check rc=1 为既有语义 // 退出 = 口径固定 - if scope == GATE_SCOPE_CHECK && code == EC_N_UNDEFINED { return 1; } - if scope == GATE_SCOPE_CHECK && code == EC_N_FUNC { return 1; } - if scope == GATE_SCOPE_CHECK && code == EC_N_DUPLICATE { return 1; } - return 0; // 默认:不豁免(= 阻断) -} + if scope == GATE_SCOPE_CHECK && code == EC_N_UNDEFINED: + return 1 + if scope == GATE_SCOPE_CHECK && code == EC_N_FUNC: + return 1 + if scope == GATE_SCOPE_CHECK && code == EC_N_DUPLICATE: + return 1 + return 0 // 默认:不豁免(= 阻断) diff --git a/src/compiler/dump.cr b/src/compiler/dump.cr index 712667de..808c269a 100644 --- a/src/compiler/dump.cr +++ b/src/compiler/dump.cr @@ -1,338 +1,356 @@ // === dump.cr === // IR/CCR dump formatting helpers and diagnostic output commands. -g_dump_buf : string, mut; -g_dump_pos : int, mut; -g_dump_cap : int, mut; +g_dump_buf : string, mut +g_dump_pos : int, mut +g_dump_cap : int, mut -fn dump_buf_reset() { - g_dump_cap = 4096; - g_dump_buf = alloc(g_dump_cap); - g_dump_pos = 0; -} +fn dump_buf_reset(): + g_dump_cap = 4096 + g_dump_buf = alloc(g_dump_cap) + g_dump_pos = 0 -fn dump_buf_grow(needed: int) { - if needed < g_dump_cap { return; } - nc : ., mut = g_dump_cap * 2; - loop { if nc > needed { break; } nc = nc * 2; } - nb := alloc(nc); - if g_dump_pos > 0 { _dyncpy(g_dump_buf, g_dump_pos, nb); } - g_dump_buf = nb; - g_dump_cap = nc; -} +fn dump_buf_grow(needed: int): + if needed < g_dump_cap: + return + nc : ., mut = g_dump_cap * 2 + loop: + if nc > needed: + break + nc = nc * 2 + nb := alloc(nc) + if g_dump_pos > 0: + _dyncpy(g_dump_buf, g_dump_pos, nb) + g_dump_buf = nb + g_dump_cap = nc -fn dump_buf_append(s: string) { - sl := str_len(s); - dump_buf_grow(g_dump_pos + sl + 1); - i : ., mut = 0; - loop { - if i >= sl { break; } - store8(g_dump_buf, g_dump_pos + i, load8(s, i)); - i = i + 1; - } - g_dump_pos = g_dump_pos + sl; -} +fn dump_buf_append(s: string): + sl := str_len(s) + dump_buf_grow(g_dump_pos + sl + 1) + i : ., mut = 0 + loop: + if i >= sl: + break + store8(g_dump_buf, g_dump_pos + i, load8(s, i)) + i = i + 1 + g_dump_pos = g_dump_pos + sl -fn dump_buf_finish() -> string { - out := alloc(g_dump_pos + 1); - if g_dump_pos > 0 { _dyncpy(g_dump_buf, g_dump_pos, out); } - store8(out, g_dump_pos, 0); - return out; -} +fn dump_buf_finish() -> string: + out := alloc(g_dump_pos + 1) + if g_dump_pos > 0: + _dyncpy(g_dump_buf, g_dump_pos, out) + store8(out, g_dump_pos, 0) + return out -fn ir_var_str(var_idx: int) -> string { - if var_idx < 0 { return ""; } - n := get_ir_var_name(var_idx); - if str_len(n) > 0 { return n; } - return int_str(var_idx); -} +fn ir_var_str(var_idx: int) -> string: + if var_idx < 0: + return "" + n := get_ir_var_name(var_idx) + if str_len(n) > 0: + return n + return int_str(var_idx) -fn type_kind_name(tk: int) -> string { - if tk == 0 { return "int"; } - if tk == 1 { return "dex"; } - if tk == 2 { return "bool"; } - if tk == 3 { return "str"; } - if tk == 4 { return "unit"; } - if tk == 5 { return "never"; } - if tk == 6 { return "char"; } - if tk == 8 { return "dex"; } // TI_DEX_S(定点精确形式,数值迁移 Task 4) - return "?"; -} +fn type_kind_name(tk: int) -> string: + if tk == 0: + return "int" + if tk == 1: + return "dex" + if tk == 2: + return "bool" + if tk == 3: + return "str" + if tk == 4: + return "unit" + if tk == 5: + return "never" + if tk == 6: + return "char" + if tk == 8: + return "dex" + // TI_DEX_S(定点精确形式,数值迁移 Task 4) + return "?" -fn binop_name(op: int) -> string { - if op == 1 { return "+"; } - if op == 2 { return "-"; } - if op == 3 { return "*"; } - if op == 4 { return "/"; } - if op == 5 { return "%"; } - if op == 6 { return "=="; } - if op == 7 { return "!="; } - if op == 8 { return "<"; } - if op == 9 { return ">"; } - if op == 10 { return "<="; } - if op == 11 { return ">="; } - if op == 12 { return "&&"; } - if op == 13 { return "||"; } - if op == 17 { return "+ (ptr)"; } - if op == 18 { return "- (ptr)"; } - if op == 19 { return "- (diff)"; } - return "?"; -} +fn binop_name(op: int) -> string: + if op == 1: + return "+" + if op == 2: + return "-" + if op == 3: + return "*" + if op == 4: + return "/" + if op == 5: + return "%" + if op == 6: + return "==" + if op == 7: + return "!=" + if op == 8: + return "<" + if op == 9: + return ">" + if op == 10: + return "<=" + if op == 11: + return ">=" + if op == 12: + return "&&" + if op == 13: + return "||" + if op == 17: + return "+ (ptr)" + if op == 18: + return "- (ptr)" + if op == 19: + return "- (diff)" + return "?" -fn ir_instr_str(instr_idx: int) -> string { - opname := df_opcode_name(iri_op(instr_idx), iri_s3(instr_idx)); - s : ., mut = " "; - s = s + opname; - pa : ., mut = str_len(opname); - loop { - if pa >= 18 { break; } - s = s + " "; - pa = pa + 1; - } +fn ir_instr_str(instr_idx: int) -> string: + opname := df_opcode_name(iri_op(instr_idx), iri_s3(instr_idx)) + s : ., mut = " " + s = s + opname + pa : ., mut = str_len(opname) + loop: + if pa >= 18: + break + s = s + " " + pa = pa + 1 - if iri_op(instr_idx) == IR_CONST { - s = s + ir_var_str(iri_dest(instr_idx)) + " = " + int_str(iri_s1(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_BINARY { - s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + " " + binop_name(iri_s3(instr_idx)) + " " + ir_var_str(iri_s2(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_UNARY { - s = s + ir_var_str(iri_dest(instr_idx)) + " = unary(" + ir_var_str(iri_s1(instr_idx)) + ")"; - return s; - } - if iri_op(instr_idx) == IR_CALL { - s = s + ir_var_str(iri_dest(instr_idx)) + " = call " + istr_get(iri_s3(instr_idx)) + "("; - ai : ., mut = 0; - a_first : ., mut = 1; - loop { - if ai >= iri_s2(instr_idx) { break; } - if a_first == 0 { s = s + ", "; } - s = s + ir_var_str(iri_s1(instr_idx) + ai); - a_first = 0; - ai = ai + 1; - } - s = s + ")"; - return s; - } - if iri_op(instr_idx) == IR_RETURN { - if iri_s1(instr_idx) >= 0 { s = s + ir_var_str(iri_s1(instr_idx)); } - else { s = s + "void"; } - return s; - } - if iri_op(instr_idx) == IR_ALLOC { - s = s + ir_var_str(iri_dest(instr_idx)) + " : " + type_kind_name(iri_tk(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_ALLOC_STRUCT { - s = s + ir_var_str(iri_dest(instr_idx)) + " : struct " + istr_get(iri_s3(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_ALLOC_ARRAY { - s = s + ir_var_str(iri_dest(instr_idx)) + "[" + int_str(iri_s1(instr_idx)) + "]"; - return s; - } - if iri_op(instr_idx) == IR_STORE { - s = s + ir_var_str(iri_s1(instr_idx)) + " <- " + ir_var_str(iri_s2(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_LOAD { - s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_LOAD_FIELD { - s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + "." + int_str(iri_s3(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_STORE_FIELD { - s = s + ir_var_str(iri_s1(instr_idx)) + "." + int_str(iri_s3(instr_idx)) + " <- " + ir_var_str(iri_s2(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_LOAD_INDEX { - s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + "[" + int_str(iri_s3(instr_idx)) + "]"; - return s; - } - if iri_op(instr_idx) == IR_STORE_INDEX { - s = s + ir_var_str(iri_s1(instr_idx)) + "[" + int_str(iri_s3(instr_idx)) + "] <- " + ir_var_str(iri_s2(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_LOAD_INDEX_VAR { - s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + "[" + ir_var_str(iri_s2(instr_idx)) + "]"; - return s; - } - if iri_op(instr_idx) == IR_STORE_INDEX_VAR { - s = s + ir_var_str(iri_s1(instr_idx)) + "[" + ir_var_str(iri_s2(instr_idx)) + "] <- " + ir_var_str(iri_dest(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_MAKE_ENUM { - s = s + ir_var_str(iri_dest(instr_idx)) + " = make_enum(" + istr_get(iri_s1(instr_idx)) + ")"; - return s; - } - if iri_op(instr_idx) == IR_REF { - s = s + ir_var_str(iri_dest(instr_idx)) + " = ref " + ir_var_str(iri_s1(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_DEREF { - s = s + ir_var_str(iri_dest(instr_idx)) + " = deref " + ir_var_str(iri_s1(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_STORE_PTR { - s = s + ir_var_str(iri_s1(instr_idx)) + " := " + ir_var_str(iri_s2(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_BRANCH { - s = s + "if " + ir_var_str(iri_s1(instr_idx)) + " goto label" + int_str(iri_s2(instr_idx)) + " else label" + int_str(iri_s3(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_JUMP { - s = s + "goto label" + int_str(iri_s1(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_LABEL { - s = s + "label" + int_str(iri_s1(instr_idx)) + ":"; - return s; - } - if iri_op(instr_idx) == IR_PHI { - s = s + ir_var_str(iri_dest(instr_idx)) + " = phi("; - pi : ., mut = 0; - p_first : ., mut = 1; - loop { - if pi >= iri_s2(instr_idx) { break; } - if p_first == 0 { s = s + ", "; } - s = s + ir_var_str(iri_s1(instr_idx) + pi); - p_first = 0; - pi = pi + 1; - } - s = s + ")"; - return s; - } - if iri_op(instr_idx) == IR_LOAD_ENUM_TAG { - s = s + ir_var_str(iri_dest(instr_idx)) + " = tag " + ir_var_str(iri_s1(instr_idx)); - return s; - } - if iri_op(instr_idx) == IR_SLICE { - s = s + ir_var_str(iri_dest(instr_idx)) + " = slice " + ir_var_str(iri_s1(instr_idx)) + "[" + ir_var_str(iri_s2(instr_idx)) + ":" + ir_var_str(iri_s3(instr_idx)) + "]"; - return s; - } + if iri_op(instr_idx) == IR_CONST: + s = s + ir_var_str(iri_dest(instr_idx)) + " = " + int_str(iri_s1(instr_idx)) + return s + if iri_op(instr_idx) == IR_BINARY: + s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + " " + binop_name(iri_s3(instr_idx)) + " " + ir_var_str(iri_s2(instr_idx)) + return s + if iri_op(instr_idx) == IR_UNARY: + s = s + ir_var_str(iri_dest(instr_idx)) + " = unary(" + ir_var_str(iri_s1(instr_idx)) + ")" + return s + if iri_op(instr_idx) == IR_CALL: + s = s + ir_var_str(iri_dest(instr_idx)) + " = call " + istr_get(iri_s3(instr_idx)) + "(" + ai : ., mut = 0 + a_first : ., mut = 1 + loop: + if ai >= iri_s2(instr_idx): + break + if a_first == 0: + s = s + ", " + s = s + ir_var_str(iri_s1(instr_idx) + ai) + a_first = 0 + ai = ai + 1 + s = s + ")" + return s + if iri_op(instr_idx) == IR_RETURN: + if iri_s1(instr_idx) >= 0: + s = s + ir_var_str(iri_s1(instr_idx)) + else: + s = s + "void" + return s + if iri_op(instr_idx) == IR_ALLOC: + s = s + ir_var_str(iri_dest(instr_idx)) + " : " + type_kind_name(iri_tk(instr_idx)) + return s + if iri_op(instr_idx) == IR_ALLOC_STRUCT: + s = s + ir_var_str(iri_dest(instr_idx)) + " : struct " + istr_get(iri_s3(instr_idx)) + return s + if iri_op(instr_idx) == IR_ALLOC_ARRAY: + s = s + ir_var_str(iri_dest(instr_idx)) + "[" + int_str(iri_s1(instr_idx)) + "]" + return s + if iri_op(instr_idx) == IR_STORE: + s = s + ir_var_str(iri_s1(instr_idx)) + " <- " + ir_var_str(iri_s2(instr_idx)) + return s + if iri_op(instr_idx) == IR_LOAD: + s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + return s + if iri_op(instr_idx) == IR_LOAD_FIELD: + s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + "." + int_str(iri_s3(instr_idx)) + return s + if iri_op(instr_idx) == IR_STORE_FIELD: + s = s + ir_var_str(iri_s1(instr_idx)) + "." + int_str(iri_s3(instr_idx)) + " <- " + ir_var_str(iri_s2(instr_idx)) + return s + if iri_op(instr_idx) == IR_LOAD_INDEX: + s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + "[" + int_str(iri_s3(instr_idx)) + "]" + return s + if iri_op(instr_idx) == IR_STORE_INDEX: + s = s + ir_var_str(iri_s1(instr_idx)) + "[" + int_str(iri_s3(instr_idx)) + "] <- " + ir_var_str(iri_s2(instr_idx)) + return s + if iri_op(instr_idx) == IR_LOAD_INDEX_VAR: + s = s + ir_var_str(iri_dest(instr_idx)) + " = " + ir_var_str(iri_s1(instr_idx)) + "[" + ir_var_str(iri_s2(instr_idx)) + "]" + return s + if iri_op(instr_idx) == IR_STORE_INDEX_VAR: + s = s + ir_var_str(iri_s1(instr_idx)) + "[" + ir_var_str(iri_s2(instr_idx)) + "] <- " + ir_var_str(iri_dest(instr_idx)) + return s + if iri_op(instr_idx) == IR_MAKE_ENUM: + s = s + ir_var_str(iri_dest(instr_idx)) + " = make_enum(" + istr_get(iri_s1(instr_idx)) + ")" + return s + if iri_op(instr_idx) == IR_REF: + s = s + ir_var_str(iri_dest(instr_idx)) + " = ref " + ir_var_str(iri_s1(instr_idx)) + return s + if iri_op(instr_idx) == IR_DEREF: + s = s + ir_var_str(iri_dest(instr_idx)) + " = deref " + ir_var_str(iri_s1(instr_idx)) + return s + if iri_op(instr_idx) == IR_STORE_PTR: + s = s + ir_var_str(iri_s1(instr_idx)) + " := " + ir_var_str(iri_s2(instr_idx)) + return s + if iri_op(instr_idx) == IR_BRANCH: + s = s + "if " + ir_var_str(iri_s1(instr_idx)) + " goto label" + int_str(iri_s2(instr_idx)) + " else label" + int_str(iri_s3(instr_idx)) + return s + if iri_op(instr_idx) == IR_JUMP: + s = s + "goto label" + int_str(iri_s1(instr_idx)) + return s + if iri_op(instr_idx) == IR_LABEL: + s = s + "label" + int_str(iri_s1(instr_idx)) + ":" + return s + if iri_op(instr_idx) == IR_PHI: + s = s + ir_var_str(iri_dest(instr_idx)) + " = phi(" + pi : ., mut = 0 + p_first : ., mut = 1 + loop: + if pi >= iri_s2(instr_idx): + break + if p_first == 0: + s = s + ", " + s = s + ir_var_str(iri_s1(instr_idx) + pi) + p_first = 0 + pi = pi + 1 + s = s + ")" + return s + if iri_op(instr_idx) == IR_LOAD_ENUM_TAG: + s = s + ir_var_str(iri_dest(instr_idx)) + " = tag " + ir_var_str(iri_s1(instr_idx)) + return s + if iri_op(instr_idx) == IR_SLICE: + s = s + ir_var_str(iri_dest(instr_idx)) + " = slice " + ir_var_str(iri_s1(instr_idx)) + "[" + ir_var_str(iri_s2(instr_idx)) + ":" + ir_var_str(iri_s3(instr_idx)) + "]" + return s - s = s + "dest=" + ir_var_str(iri_dest(instr_idx)) + " s1=" + int_str(iri_s1(instr_idx)) + " s2=" + int_str(iri_s2(instr_idx)) + " s3=" + int_str(iri_s3(instr_idx)); - return s; -} + s = s + "dest=" + ir_var_str(iri_dest(instr_idx)) + " s1=" + int_str(iri_s1(instr_idx)) + " s2=" + int_str(iri_s2(instr_idx)) + " s3=" + int_str(iri_s3(instr_idx)) + return s -fn cmd_ir(src_path: string) -> int { - g_source = read_file(src_path); - if str_len(g_source) == 0 { - print("error: cannot read "); - println(src_path); - return 1; - } - g_source_dir = dirname(src_path); - g_error_count = 0; // 会话起点(tokenize 多轮累积词法错误,见 lexer.cr) - tokenize(g_source); - g_str_count = 0; - res_imports(); - parse_all(); - check_all(); - if g_diag_count > 0 { print_diagnostics(); return 1; } - if g_error_count > 0 { print_parse_errors(); return 1; } - ir_gen_all(); - dot := df_graph_to_dot(); +fn cmd_ir(src_path: string) -> int: + g_source = read_file(src_path) + if str_len(g_source) == 0: + print("error: cannot read ") + println(src_path) + return 1 + g_source_dir = dirname(src_path) + g_error_count = 0 // 会话起点(tokenize 多轮累积词法错误,见 lexer.cr) + tokenize(g_source) + g_str_count = 0 + res_imports() + parse_all() + check_all() + if g_diag_count > 0: + print_diagnostics() + return 1 + if g_error_count > 0: + print_parse_errors() + return 1 + ir_gen_all() + dot := df_graph_to_dot() - cir_path : ., mut = src_path; - slen := str_len(src_path); - if slen > 3 { - ext := str_sub(src_path, slen - 3, 3); - if str_eq(ext, ".cr") != 0 { - cir_path = str_sub(src_path, 0, slen - 3) + ".cir"; - } - } + cir_path : ., mut = src_path + slen := str_len(src_path) + if slen > 3: + ext := str_sub(src_path, slen - 3, 3) + if str_eq(ext, ".cr") != 0: + cir_path = str_sub(src_path, 0, slen - 3) + ".cir" - written := write_file(cir_path, dot); - if written < 0 { - print("error: could not write "); - println(cir_path); - return 1; - } - print(" -> "); - print(cir_path); - print(" ("); - print(int_str(g_df_node_count)); - print(" nodes, "); - print(int_str(g_df_edge_count)); - println(" edges)"); - return 0; -} + written := write_file(cir_path, dot) + if written < 0: + print("error: could not write ") + println(cir_path) + return 1 + print(" -> ") + print(cir_path) + print(" (") + print(int_str(g_df_node_count)) + print(" nodes, ") + print(int_str(g_df_edge_count)) + println(" edges)") + return 0 // Text dump of the linear CFG: "Function: name" + per-function region list // (SG_IF/SG_LOOP/SG_FOR/SG_FLOW/SG_UNSAFE) + "Block: labelN" blocks. // Shared by cmd_cir (writes to file) and main.cr's `cir` command (stdout). -fn cir_text_dump() -> string { - dump_buf_reset(); - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } - name_ni := r64(g_ir_func_name_idx, fi * 8); - dump_buf_append("Function: "); dump_buf_append(istr_get(name_ni)); dump_buf_append("\n"); - start := r64(g_ir_func_instr_start, fi * 8); - count := r64(g_ir_func_instr_count, fi * 8); +fn cir_text_dump() -> string: + dump_buf_reset() + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break + name_ni := r64(g_ir_func_name_idx, fi * 8) + dump_buf_append("Function: ") + dump_buf_append(istr_get(name_ni)) + dump_buf_append("\n") + start := r64(g_ir_func_instr_start, fi * 8) + count := r64(g_ir_func_instr_count, fi * 8) // Region list for this function (regions whose DFNode start falls in // this function's instruction range) - ri : ., mut = 0; - loop { - if ri >= g_sg_count { break; } - rkind := r64(g_sgs, ri * ESZ_SG + OFF_SG_KIND); - rstart := r64(g_sgs, ri * ESZ_SG + OFF_SG_NSTART); - rend := r64(g_sgs, ri * ESZ_SG + OFF_SG_EXIT); - if rstart >= start && rstart < start + count { - rend := r64(g_sgs, ri * ESZ_SG + OFF_SG_EXIT); - if rend >= 0 { // skip unclosed (EXIT<0) regions - rname : ., mut = "?"; - if rkind == SG_FUNC { rname = "func"; } - if rkind == SG_IF { rname = "if"; } - if rkind == SG_LOOP { rname = "loop"; } - if rkind == SG_FOR { rname = "for"; } - if rkind == SG_FLOW { rname = "flow"; } - if rkind == SG_UNSAFE { rname = "unsafe"; } - dump_buf_append(" Region: "); dump_buf_append(rname); - dump_buf_append(" nodes "); dump_buf_append(int_str(rstart)); - dump_buf_append(".."); dump_buf_append(int_str(rend)); dump_buf_append("\n"); - } - } - ri = ri + 1; - } - in_block : ., mut = 0; - ii : ., mut = 0; - loop { - if ii >= count { break; } - if iri_op(start + ii) == IR_LABEL { - if in_block != 0 { dump_buf_append("\n"); } - dump_buf_append(" Block: label"); dump_buf_append(int_str(iri_s1(start + ii))); dump_buf_append("\n"); - in_block = 1; - } else { - dump_buf_append(" "); dump_buf_append(ir_instr_str(start + ii)); dump_buf_append("\n"); - } - ii = ii + 1; - } - dump_buf_append("\n"); - fi = fi + 1; - } + ri : ., mut = 0 + loop: + if ri >= g_sg_count: + break + rkind := r64(g_sgs, ri * ESZ_SG + OFF_SG_KIND) + rstart := r64(g_sgs, ri * ESZ_SG + OFF_SG_NSTART) + rend := r64(g_sgs, ri * ESZ_SG + OFF_SG_EXIT) + if rstart >= start && rstart < start + count: + rend := r64(g_sgs, ri * ESZ_SG + OFF_SG_EXIT) + if rend >= 0: + // skip unclosed (EXIT<0) regions + rname : ., mut = "?" + if rkind == SG_FUNC: + rname = "func" + if rkind == SG_IF: + rname = "if" + if rkind == SG_LOOP: + rname = "loop" + if rkind == SG_FOR: + rname = "for" + if rkind == SG_FLOW: + rname = "flow" + if rkind == SG_UNSAFE: + rname = "unsafe" + dump_buf_append(" Region: ") + dump_buf_append(rname) + dump_buf_append(" nodes ") + dump_buf_append(int_str(rstart)) + dump_buf_append("..") + dump_buf_append(int_str(rend)) + dump_buf_append("\n") + ri = ri + 1 + in_block : ., mut = 0 + ii : ., mut = 0 + loop: + if ii >= count: + break + if iri_op(start + ii) == IR_LABEL: + if in_block != 0: + dump_buf_append("\n") + dump_buf_append(" Block: label") + dump_buf_append(int_str(iri_s1(start + ii))) + dump_buf_append("\n") + in_block = 1 + else: + dump_buf_append(" ") + dump_buf_append(ir_instr_str(start + ii)) + dump_buf_append("\n") + ii = ii + 1 + dump_buf_append("\n") + fi = fi + 1 // VSDG state edges: side-effect chain + loop termination dependencies - dump_buf_append("State edges:\n"); - ei : ., mut = 0; - loop { - if ei >= g_df_edge_count { break; } - if r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_KIND) != 0 { - e_from := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_FROM); - e_to := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_TO); - dump_buf_append(" state: n"); dump_buf_append(int_str(e_from)); - dump_buf_append(" -> n"); dump_buf_append(int_str(e_to)); dump_buf_append("\n"); - } - ei = ei + 1; - } - return dump_buf_finish(); -} + dump_buf_append("State edges:\n") + ei : ., mut = 0 + loop: + if ei >= g_df_edge_count: + break + if r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_KIND) != 0: + e_from := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_FROM) + e_to := r64(g_df_edges, ei * ESZ_DFEDGE + OFF_DFE_TO) + dump_buf_append(" state: n") + dump_buf_append(int_str(e_from)) + dump_buf_append(" -> n") + dump_buf_append(int_str(e_to)) + dump_buf_append("\n") + ei = ei + 1 + return dump_buf_finish() // ─── R2 P5 Task 2 测试通道(corec 侧 hidden flag `cir --dump-tk-terms`)─── // 用途 = 单槽化的**逐节点**观察面:两槽(OFF_DF_TK = 类型项引用、OFF_DF_AUX = 辅码) @@ -348,151 +366,156 @@ fn cir_text_dump() -> string { // 静默读越界内存):tag/a/b/c 一律 -1。aux_nonzero = 辅码非零节点数(互斥不变量 // D22-② 的观察面);face_fail = D23 建项失败计数(0 = 全语料无不可译类型面行); // rows = 当前进程类型表行数(冷/暖比对用:暖态可小于冷态——见 sh_tk_split_load 注)。 -fn df_tk_term_dump() -> string { - dump_buf_reset(); - total := g_df_node_count; - with_term : ., mut = 0; - bad_term : ., mut = 0; - auxn : ., mut = 0; - n0 : ., mut = 0; - loop { - if n0 >= total { break; } - t0 := r64(g_df_nodes, n0 * ESZ_DFNODE + OFF_DF_TK); - if t0 >= 0 { with_term = with_term + 1; } - if t0 >= tt_count() { bad_term = bad_term + 1; } - if r64(g_df_nodes, n0 * ESZ_DFNODE + OFF_DF_AUX) != 0 { auxn = auxn + 1; } - n0 = n0 + 1; - } - dump_buf_append("[df-tk-terms] nodes="); - dump_buf_append(int_str(total)); - dump_buf_append(" with_term="); - dump_buf_append(int_str(with_term)); - dump_buf_append(" bad_term="); - dump_buf_append(int_str(bad_term)); - dump_buf_append(" aux_nonzero="); - dump_buf_append(int_str(auxn)); - dump_buf_append(" face_fail="); - dump_buf_append(int_str(g_tk_face_fail)); - dump_buf_append(" terms="); - dump_buf_append(int_str(tt_count())); - dump_buf_append(" rows="); - dump_buf_append(int_str(g_type_count)); - dump_buf_append(" mint="); - dump_buf_append(int_str(IR_CONST)); - dump_buf_append(","); - dump_buf_append(int_str(IR_BINARY)); - dump_buf_append(","); - dump_buf_append(int_str(IR_ALLOC)); - dump_buf_append(","); - dump_buf_append(int_str(IR_CALL)); - dump_buf_append(","); - dump_buf_append(int_str(IR_LOAD)); - dump_buf_append(","); - dump_buf_append(int_str(IR_I2F)); - dump_buf_append(","); - dump_buf_append(int_str(IR_F2I)); - dump_buf_append("\n"); - n : ., mut = 0; - loop { - if n >= total { break; } - op := r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE); - t := r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_TK); - ax := r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_AUX); - tk := sh_dfn_code_of_slots(t, ax); - dump_buf_append(int_str(n)); - dump_buf_append("\t"); - dump_buf_append(int_str(op)); - dump_buf_append("\t"); - dump_buf_append(int_str(tk)); - dump_buf_append("\t"); - dump_buf_append(int_str(t)); - dump_buf_append("\t"); - if t >= 0 && t < tt_count() { - dump_buf_append(int_str(tt_tag(t))); - dump_buf_append("\t"); - dump_buf_append(int_str(tt_a(t))); - dump_buf_append("\t"); - dump_buf_append(int_str(tt_b(t))); - dump_buf_append("\t"); - dump_buf_append(int_str(tt_c(t))); - } else { - dump_buf_append("-1\t-1\t-1\t-1"); - } - dump_buf_append("\t"); - dump_buf_append(int_str(ax)); - dump_buf_append("\n"); - n = n + 1; - } - return dump_buf_finish(); -} +fn df_tk_term_dump() -> string: + dump_buf_reset() + total := g_df_node_count + with_term : ., mut = 0 + bad_term : ., mut = 0 + auxn : ., mut = 0 + n0 : ., mut = 0 + loop: + if n0 >= total: + break + t0 := r64(g_df_nodes, n0 * ESZ_DFNODE + OFF_DF_TK) + if t0 >= 0: + with_term = with_term + 1 + if t0 >= tt_count(): + bad_term = bad_term + 1 + if r64(g_df_nodes, n0 * ESZ_DFNODE + OFF_DF_AUX) != 0: + auxn = auxn + 1 + n0 = n0 + 1 + dump_buf_append("[df-tk-terms] nodes=") + dump_buf_append(int_str(total)) + dump_buf_append(" with_term=") + dump_buf_append(int_str(with_term)) + dump_buf_append(" bad_term=") + dump_buf_append(int_str(bad_term)) + dump_buf_append(" aux_nonzero=") + dump_buf_append(int_str(auxn)) + dump_buf_append(" face_fail=") + dump_buf_append(int_str(g_tk_face_fail)) + dump_buf_append(" terms=") + dump_buf_append(int_str(tt_count())) + dump_buf_append(" rows=") + dump_buf_append(int_str(g_type_count)) + dump_buf_append(" mint=") + dump_buf_append(int_str(IR_CONST)) + dump_buf_append(",") + dump_buf_append(int_str(IR_BINARY)) + dump_buf_append(",") + dump_buf_append(int_str(IR_ALLOC)) + dump_buf_append(",") + dump_buf_append(int_str(IR_CALL)) + dump_buf_append(",") + dump_buf_append(int_str(IR_LOAD)) + dump_buf_append(",") + dump_buf_append(int_str(IR_I2F)) + dump_buf_append(",") + dump_buf_append(int_str(IR_F2I)) + dump_buf_append("\n") + n : ., mut = 0 + loop: + if n >= total: + break + op := r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_OPCODE) + t := r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_TK) + ax := r64(g_df_nodes, n * ESZ_DFNODE + OFF_DF_AUX) + tk := sh_dfn_code_of_slots(t, ax) + dump_buf_append(int_str(n)) + dump_buf_append("\t") + dump_buf_append(int_str(op)) + dump_buf_append("\t") + dump_buf_append(int_str(tk)) + dump_buf_append("\t") + dump_buf_append(int_str(t)) + dump_buf_append("\t") + if t >= 0 && t < tt_count(): + dump_buf_append(int_str(tt_tag(t))) + dump_buf_append("\t") + dump_buf_append(int_str(tt_a(t))) + dump_buf_append("\t") + dump_buf_append(int_str(tt_b(t))) + dump_buf_append("\t") + dump_buf_append(int_str(tt_c(t))) + else: + dump_buf_append("-1\t-1\t-1\t-1") + dump_buf_append("\t") + dump_buf_append(int_str(ax)) + dump_buf_append("\n") + n = n + 1 + return dump_buf_finish() -fn cmd_cir(src_path: string) -> int { - g_source = read_file(src_path); - if str_len(g_source) == 0 { - print("error: cannot read "); - println(src_path); - return 1; - } - g_source_dir = dirname(src_path); - g_error_count = 0; // 会话起点(tokenize 多轮累积词法错误,见 lexer.cr) - tokenize(g_source); - g_str_count = 0; - res_imports(); - parse_all(); - check_all(); - if g_diag_count > 0 { print_diagnostics(); return 1; } - if g_error_count > 0 { print_parse_errors(); return 1; } - ir_gen_all(); - lower_to_ccr(); +fn cmd_cir(src_path: string) -> int: + g_source = read_file(src_path) + if str_len(g_source) == 0: + print("error: cannot read ") + println(src_path) + return 1 + g_source_dir = dirname(src_path) + g_error_count = 0 // 会话起点(tokenize 多轮累积词法错误,见 lexer.cr) + tokenize(g_source) + g_str_count = 0 + res_imports() + parse_all() + check_all() + if g_diag_count > 0: + print_diagnostics() + return 1 + if g_error_count > 0: + print_parse_errors() + return 1 + ir_gen_all() + lower_to_ccr() - ccr : ., mut = cir_text_dump(); + ccr : ., mut = cir_text_dump() - ccr_path : ., mut = src_path; - slen := str_len(src_path); - if slen > 3 { - ext := str_sub(src_path, slen - 3, 3); - if str_eq(ext, ".cr") != 0 { - ccr_path = str_sub(src_path, 0, slen - 3) + ".ccr"; - } - } + ccr_path : ., mut = src_path + slen := str_len(src_path) + if slen > 3: + ext := str_sub(src_path, slen - 3, 3) + if str_eq(ext, ".cr") != 0: + ccr_path = str_sub(src_path, 0, slen - 3) + ".ccr" - written := write_file(ccr_path, ccr); - if written < 0 { - print("error: could not write "); - println(ccr_path); - return 1; - } - print(" -> "); - print(ccr_path); - print(" ("); - print(int_str(g_ir_func_count)); - print(" functions, "); - print(int_str(g_ir_instr_count)); - println(" instrs)"); - return 0; -} + written := write_file(ccr_path, ccr) + if written < 0: + print("error: could not write ") + println(ccr_path) + return 1 + print(" -> ") + print(ccr_path) + print(" (") + print(int_str(g_ir_func_count)) + print(" functions, ") + print(int_str(g_ir_instr_count)) + println(" instrs)") + return 0 // ─── 批 6(T4):规约标注的 VC 清单 dump(`--dump-vcs`)────────────────────────── // 表达式**规范化文本**(只服务 dump;**不参与判定**——判定面在 checker.cr 的 spec_check_all/spec_check_func)。 // C1 子集:int/bool 字面量 · 标识符 · 一元 `-`/`!` · 二元(算术/比较/逻辑)· 括号(显式加括号 ⇒ 无歧义)。 // 子集外节点形 ⇒ `(?)` 兜底(由 V05/V06 在检查面拦截,不在此处判)。 -fn spec_expr_text(e: int) -> string { - if e < 0 { return "?"; } - k := ast_kind(e); - if k == EXPR_INT { return int_str(ast_int_val(e)); } - if k == EXPR_BOOL { if ast_int_val(e) != 0 { return "true"; } return "false"; } - if k == EXPR_IDENT { return istr_get(ast_int_val(e)); } - if k == EXPR_UNARY { - op := ast_c(e); - if op == UOP_NEG { return "(-" + spec_expr_text(ast_a(e)) + ")"; } - if op == UOP_NOT { return "!" + spec_expr_text(ast_a(e)); } - return "(?)"; - } - if k == EXPR_BINARY { - return "(" + spec_expr_text(ast_a(e)) + " " + binop_name(ast_c(e)) + " " + spec_expr_text(ast_b(e)) + ")"; - } - return "(?)"; -} +fn spec_expr_text(e: int) -> string: + if e < 0: + return "?" + k := ast_kind(e) + if k == EXPR_INT: + return int_str(ast_int_val(e)) + if k == EXPR_BOOL: + if ast_int_val(e) != 0: + return "true" + return "false" + if k == EXPR_IDENT: + return istr_get(ast_int_val(e)) + if k == EXPR_UNARY: + op := ast_c(e) + if op == UOP_NEG: + return "(-" + spec_expr_text(ast_a(e)) + ")" + if op == UOP_NOT: + return "!" + spec_expr_text(ast_a(e)) + return "(?)" + if k == EXPR_BINARY: + return "(" + spec_expr_text(ast_a(e)) + " " + binop_name(ast_c(e)) + " " + spec_expr_text(ast_b(e)) + ")" + return "(?)" // VC 清单 dump(隐藏通道 `--dump-vcs`;维护者 2026-09-17 四点钉死): // ① **stdout、零新产物**;开关**不改 rc/产物**(只打印)。 @@ -501,36 +524,38 @@ fn spec_expr_text(e: int) -> string { // 且本 dump 打印点位于 `main.cr::run_frontend` 的 **fail-closed 闸门之前** ⇒ 红态下也照样列出。 // ④ **只读侧表**(`g_spec_*`,与判定同源)——不另起一份状态,杜绝「dump 与判定分叉」(第二真源)。 // 序 = 侧表序 = **源序**(构造性确定);且与 `.cir` 缓存状态**无关**(dump 全在 parse/check 期算)⇒ 冷/暖恒同。 -fn vcs_dump() -> string { - dump_buf_reset(); - dump_buf_append("[vcs] count="); - dump_buf_append(int_str(g_spec_count)); - dump_buf_append("\n"); - i : ., mut = 0; - loop { - if i >= g_spec_count { break; } - st : ., mut = "yellow"; - s := spec_status(i); - if s == SPEC_ST_GREEN { st = "green"; } - else if s == SPEC_ST_RED { st = "red"; } - kn : ., mut = "check"; - if spec_kind(i) == 1 { kn = "ensure"; } - dump_buf_append("[vcs] vc "); - dump_buf_append(int_str(i)); - dump_buf_append(" fn="); - dump_buf_append(istr_get(spec_fn(i))); - dump_buf_append(" kind="); - dump_buf_append(kn); - dump_buf_append(" status="); - dump_buf_append(st); - dump_buf_append(" line="); - dump_buf_append(int_str(spec_line(i))); - dump_buf_append(" col="); - dump_buf_append(int_str(spec_col(i))); - dump_buf_append(" expr="); - dump_buf_append(spec_expr_text(spec_expr(i))); - dump_buf_append("\n"); - i = i + 1; - } - return dump_buf_finish(); -} +fn vcs_dump() -> string: + dump_buf_reset() + dump_buf_append("[vcs] count=") + dump_buf_append(int_str(g_spec_count)) + dump_buf_append("\n") + i : ., mut = 0 + loop: + if i >= g_spec_count: + break + st : ., mut = "yellow" + s := spec_status(i) + if s == SPEC_ST_GREEN: + st = "green" + else if s == SPEC_ST_RED: + st = "red" + kn : ., mut = "check" + if spec_kind(i) == 1: + kn = "ensure" + dump_buf_append("[vcs] vc ") + dump_buf_append(int_str(i)) + dump_buf_append(" fn=") + dump_buf_append(istr_get(spec_fn(i))) + dump_buf_append(" kind=") + dump_buf_append(kn) + dump_buf_append(" status=") + dump_buf_append(st) + dump_buf_append(" line=") + dump_buf_append(int_str(spec_line(i))) + dump_buf_append(" col=") + dump_buf_append(int_str(spec_col(i))) + dump_buf_append(" expr=") + dump_buf_append(spec_expr_text(spec_expr(i))) + dump_buf_append("\n") + i = i + 1 + return dump_buf_finish() diff --git a/src/compiler/dyn_arr.cr b/src/compiler/dyn_arr.cr index 717f8cf5..1dacaef8 100644 --- a/src/compiler/dyn_arr.cr +++ b/src/compiler/dyn_arr.cr @@ -4,79 +4,114 @@ // ============================================================ // Byte helpers // ============================================================ -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 // ============================================================ // Element sizes (bytes per element) // ============================================================ -ESZ_TOKEN : int = 40; // kind,lexeme,int_val,line,col = 5×8 -ESZ_ASTNODE : int = 72; // kind,a,b,c,int_val,type_val,data,line,col = 9×8 -ESZ_SYMENTRY : int = 32; // name_idx,kind,type_idx,node_idx = 4×8 -ESZ_IRVAR : int = 24; // name_idx,id,type_kind = 3×8 -ESZ_IRINSTR : int = 48; // opcode,dest,src1,src2,src3,type_kind = 6×8 -ESZ_FUNCINFO : int = 688; -ESZ_STRUCTINFO : int = 440; -ESZ_ENUMINFO : int = 4408; // name+variants[16](含载荷类型节点槽,P3 Task 4)+variant_count+generic_names[4]+generic_count +ESZ_TOKEN : int = 40 // kind,lexeme,int_val,line,col = 5×8 +ESZ_ASTNODE : int = 72 // kind,a,b,c,int_val,type_val,data,line,col = 9×8 +ESZ_SYMENTRY : int = 32 // name_idx,kind,type_idx,node_idx = 4×8 +ESZ_IRVAR : int = 24 // name_idx,id,type_kind = 3×8 +ESZ_IRINSTR : int = 48 // opcode,dest,src1,src2,src3,type_kind = 6×8 +ESZ_FUNCINFO : int = 688 +ESZ_STRUCTINFO : int = 440 +ESZ_ENUMINFO : int = 4408 // name+variants[16](含载荷类型节点槽,P3 Task 4)+variant_count+generic_names[4]+generic_count // Token field offsets -OFF_TK_KIND : int = 0; OFF_TK_LEXEME : int = 8; -OFF_TK_INTVAL : int = 16; OFF_TK_LINE : int = 24; OFF_TK_COL : int = 32; +OFF_TK_KIND : int = 0 +OFF_TK_LEXEME : int = 8 +OFF_TK_INTVAL : int = 16 +OFF_TK_LINE : int = 24 +OFF_TK_COL : int = 32 // ASTNode field offsets -OFF_AS_KIND : int = 0; OFF_AS_A : int = 8; OFF_AS_B : int = 16; OFF_AS_C : int = 24; -OFF_AS_INTVAL : int = 32; OFF_AS_TYPEVAL : int = 40; -OFF_AS_DATA : int = 48; OFF_AS_LINE : int = 56; OFF_AS_COL : int = 64; +OFF_AS_KIND : int = 0 +OFF_AS_A : int = 8 +OFF_AS_B : int = 16 +OFF_AS_C : int = 24 +OFF_AS_INTVAL : int = 32 +OFF_AS_TYPEVAL : int = 40 +OFF_AS_DATA : int = 48 +OFF_AS_LINE : int = 56 +OFF_AS_COL : int = 64 // SymEntry field offsets -OFF_SY_NAME : int = 0; OFF_SY_KIND : int = 8; -OFF_SY_TYPE : int = 16; OFF_SY_NODE : int = 24; +OFF_SY_NAME : int = 0 +OFF_SY_KIND : int = 8 +OFF_SY_TYPE : int = 16 +OFF_SY_NODE : int = 24 // IRVar field offsets -OFF_IRV_NAME : int = 0; OFF_IRV_ID : int = 8; OFF_IRV_TYPE : int = 16; +OFF_IRV_NAME : int = 0 +OFF_IRV_ID : int = 8 +OFF_IRV_TYPE : int = 16 // IRInstr field offsets -OFF_IRI_OP : int = 0; OFF_IRI_DEST : int = 8; -OFF_IRI_S1 : int = 16; OFF_IRI_S2 : int = 24; -OFF_IRI_S3 : int = 32; OFF_IRI_TK : int = 40; +OFF_IRI_OP : int = 0 +OFF_IRI_DEST : int = 8 +OFF_IRI_S1 : int = 16 +OFF_IRI_S2 : int = 24 +OFF_IRI_S3 : int = 32 +OFF_IRI_TK : int = 40 // FuncInfo offsets // 形参槽上限:param_types 是**定长内嵌槽区**(跟在 param_count 之后、return_type @@ -86,21 +121,27 @@ OFF_IRI_S3 : int = 32; OFF_IRI_TK : int = 40; // (TODO #2026-09-10-4,2026-09-11)。64 = 与 ast.cr FuncInfo 镜像 `[int; 64]` 对齐, // 并覆盖 ≥22(16 栈参 + 6 寄存器参,SysV)的栈清理形。越界 = parser 硬错 // P020(rc=1)+ 下方访问器护栏双保险——**任何情况下不得静默越界写**。 -MAX_FN_PARAMS : int = 64; -OFF_FI_NAME : int = 0; OFF_FI_PARAM_COUNT : int = 8; -OFF_FI_PARAM_TYPES : int = 16; // 64 槽 × 8B = 512 → 至 527 -OFF_FI_RETURN_TYPE : int = 528; OFF_FI_AST_NODE : int = 536; -OFF_FI_GENERIC_NAMES : int = 544; OFF_FI_GENERIC_COUNT : int = 672; -OFF_FI_ISPURE : int = 680; // 1 = pure (no side effects), 0 = impure +MAX_FN_PARAMS : int = 64 +OFF_FI_NAME : int = 0 +OFF_FI_PARAM_COUNT : int = 8 +OFF_FI_PARAM_TYPES : int = 16 // 64 槽 × 8B = 512 → 至 527 +OFF_FI_RETURN_TYPE : int = 528 +OFF_FI_AST_NODE : int = 536 +OFF_FI_GENERIC_NAMES : int = 544 +OFF_FI_GENERIC_COUNT : int = 672 +OFF_FI_ISPURE : int = 680 // 1 = pure (no side effects), 0 = impure // StructInfo offsets // 容量批 T3(裁-CAP-2 (a)):字段槽区**迁侧表**——本槽(原 field_names 首槽)改义为 // `field_base`(侧表起始行);`OFF_SI_FIELD_TYPES`/`OFF_SI_FIELD_TYPE_NODES` 保留为 // **未用填充**(记录尺寸不变 ⇒ 盘面与外部算术零改动)。 -OFF_SI_NAME : int = 0; OFF_SI_FIELD_BASE : int = 8; -OFF_SI_FIELD_TYPES : int = 136; OFF_SI_FIELD_TYPE_NODES : int = 264; // 保留未用 -OFF_SI_FIELD_COUNT : int = 392; -OFF_SI_GENERIC_NAMES : int = 400; OFF_SI_GENERIC_COUNT : int = 432; +OFF_SI_NAME : int = 0 +OFF_SI_FIELD_BASE : int = 8 +OFF_SI_FIELD_TYPES : int = 136 +OFF_SI_FIELD_TYPE_NODES : int = 264 // 保留未用 +OFF_SI_FIELD_COUNT : int = 392 +OFF_SI_GENERIC_NAMES : int = 400 +OFF_SI_GENERIC_COUNT : int = 432 // DFNode sizes and offsets // R2 P5 Task 2(D19 单槽化 α = 槽语义对调 + 辅码显式分离):类型面**单源**。 @@ -119,51 +160,59 @@ OFF_SI_GENERIC_NAMES : int = 400; OFF_SI_GENERIC_COUNT : int = 432; // 引用不得跨进程,D20)。 // 拆分器((opcode, tk) → (项, 辅码))单源 = ty_shadow.cr 的 sh_tk_split;既有消费者 // (instr.cr/regalloc/lower_to_core/dump/ccr_io)读的是**派生码**,零改动。 -ESZ_DFNODE : int = 72; // opcode,dest_var,src1,src2,src3,tk_term,first_edge,edge_count,tk_aux = 9x8 -OFF_DF_OPCODE : int = 0; OFF_DF_DEST : int = 8; -OFF_DF_S1 : int = 16; OFF_DF_S2 : int = 24; -OFF_DF_S3 : int = 32; OFF_DF_TK : int = 40; // ★语义(P5 T2):类型项引用(-1 = 无项) -OFF_DF_FIRST_EDGE : int = 48; OFF_DF_EDGE_COUNT : int = 56; -OFF_DF_AUX : int = 64; // P5 T2(D19,原 OFF_DF_TK_TERM 槽位):辅码(0 = 无) +ESZ_DFNODE : int = 72 // opcode,dest_var,src1,src2,src3,tk_term,first_edge,edge_count,tk_aux = 9x8 +OFF_DF_OPCODE : int = 0 +OFF_DF_DEST : int = 8 +OFF_DF_S1 : int = 16 +OFF_DF_S2 : int = 24 +OFF_DF_S3 : int = 32 +OFF_DF_TK : int = 40 // ★语义(P5 T2):类型项引用(-1 = 无项) +OFF_DF_FIRST_EDGE : int = 48 +OFF_DF_EDGE_COUNT : int = 56 +OFF_DF_AUX : int = 64 // P5 T2(D19,原 OFF_DF_TK_TERM 槽位):辅码(0 = 无) // DFEdge sizes and offsets -ESZ_DFEDGE : int = 32; // from_node,to_node,next_out,kind = 4x8 -OFF_DFE_FROM : int = 0; OFF_DFE_TO : int = 8; OFF_DFE_NEXT : int = 16; -OFF_DFE_KIND : int = 24; // 0=data (def-use), 1=state (ordering/termination) +ESZ_DFEDGE : int = 32 // from_node,to_node,next_out,kind = 4x8 +OFF_DFE_FROM : int = 0 +OFF_DFE_TO : int = 8 +OFF_DFE_NEXT : int = 16 +OFF_DFE_KIND : int = 24 // 0=data (def-use), 1=state (ordering/termination) // Entry record (v6 条目版本段:变量 × 定值点切分版本条目,compute_entries 填充)。 // 内存布局 = .ccr v6 落盘格式逐字节一致(24B/条,六字段各 4B,w32/r32 LE 存取): // var_idx u32, def_instr i32, live_start i32, live_end i32, home i32, flags u32。 -ESZ_ENTRY : int = 24; -OFF_ENTRY_VAR : int = 0; // 全局 IR 变量索引 -OFF_ENTRY_DEF : int = 4; // 定值指令全局索引(-1 = 无定值) -OFF_ENTRY_LS : int = 8; // 版本存在区间起点(全局指令序) -OFF_ENTRY_LE : int = 12; // 版本存在区间终点(全局指令序) -OFF_ENTRY_HOME : int = 16; // 分配槽位(-1 = 未分配) -OFF_ENTRY_FLAGS : int = 20; // 位 0 预留:无配方(条款 4b) +ESZ_ENTRY : int = 24 +OFF_ENTRY_VAR : int = 0 // 全局 IR 变量索引 +OFF_ENTRY_DEF : int = 4 // 定值指令全局索引(-1 = 无定值) +OFF_ENTRY_LS : int = 8 // 版本存在区间起点(全局指令序) +OFF_ENTRY_LE : int = 12 // 版本存在区间终点(全局指令序) +OFF_ENTRY_HOME : int = 16 // 分配槽位(-1 = 未分配) +OFF_ENTRY_FLAGS : int = 20 // 位 0 预留:无配方(条款 4b) // Subgraph entry (48 bytes each) -ESZ_SG : int = 48; -OFF_SG_KIND : int = 0; // 0=func, 1=loop, 2=for, 3=flow, 4=unsafe -OFF_SG_ENTER : int = 8; // enter seq number (instruction index) -OFF_SG_EXIT : int = 16; // exit seq number -OFF_SG_PARENT : int = 24; // parent subgraph index -OFF_SG_NSTART : int = 32; // first DFNode index -OFF_SG_NCOUNT : int = 40; // node count - -SG_FUNC : int = 0; -SG_LOOP : int = 1; -SG_FOR : int = 2; -SG_FLOW : int = 3; -SG_UNSAFE : int = 4; -SG_IF : int = 5; // conditional region: covers [condition, merge) +ESZ_SG : int = 48 +OFF_SG_KIND : int = 0 // 0=func, 1=loop, 2=for, 3=flow, 4=unsafe +OFF_SG_ENTER : int = 8 // enter seq number (instruction index) +OFF_SG_EXIT : int = 16 // exit seq number +OFF_SG_PARENT : int = 24 // parent subgraph index +OFF_SG_NSTART : int = 32 // first DFNode index +OFF_SG_NCOUNT : int = 40 // node count + +SG_FUNC : int = 0 +SG_LOOP : int = 1 +SG_FOR : int = 2 +SG_FLOW : int = 3 +SG_UNSAFE : int = 4 +SG_IF : int = 5 // conditional region: covers [condition, merge) // InterfaceInfo: fixed-size entry per interface // Header(24) + methods[16] * method_entry(240) = 3864 total(R2 P4 Task 3:168 → 240, // + 类型项槽 72B——见下 OFF_IFM_PARAM_TERMS/OFF_IFM_RET_TERM 注) -ESZ_IFACEINFO : int = 3864; -OFF_IF_NAME : int = 0; OFF_IF_METHOD_COUNT : int = 8; OFF_IF_GENERIC_COUNT : int = 16; -OFF_IF_METHODS : int = 24; // first method entry +ESZ_IFACEINFO : int = 3864 +OFF_IF_NAME : int = 0 +OFF_IF_METHOD_COUNT : int = 8 +OFF_IF_GENERIC_COUNT : int = 16 +OFF_IF_METHODS : int = 24 // first method entry // Each method entry: name_idx(8) + param_count(8) + ret_ti(8) + param_types[8](64) // + param_nodes[8](64) + ret_node(8) + self_mode(8) + param_terms[8](64) + ret_term(8) = 240 bytes // R2 P3b Task 6(Step 1 签名类型项化):**裸码槽保留**(`param_types` / `ret_ti`)—— @@ -173,12 +222,14 @@ OFF_IF_METHODS : int = 24; // first method entry // (满足判定 / impl 声明面)与 `sh_iface_shape_term` 建项。-1 = 无节点(哨兵;不用 0—— // 节点 0 是合法下标,用 0 会与「首个分配节点」混同)。接收者槽两侧皆无节点(parser 的 // self 约定,见 self_mode)。 -ESZ_IFMETHOD : int = 240; -OFF_IFM_NAME : int = 0; OFF_IFM_PARAM_COUNT : int = 8; OFF_IFM_RET_TI : int = 16; -OFF_IFM_PARAM_TYPES : int = 24; // first of up to 8 param types (each 8 bytes) → 24..87 -OFF_IFM_PARAM_NODES : int = 88; // first of up to 8 param type nodes (8B each) → 88..151 -OFF_IFM_RET_NODE : int = 152; // return type node(-1 = 无,= unit) -OFF_IFM_SELF_MODE : int = 160; // 接收者模式:0 = 无接收者(首参为普通形参)/ 1 = self / +ESZ_IFMETHOD : int = 240 +OFF_IFM_NAME : int = 0 +OFF_IFM_PARAM_COUNT : int = 8 +OFF_IFM_RET_TI : int = 16 +OFF_IFM_PARAM_TYPES : int = 24 // first of up to 8 param types (each 8 bytes) → 24..87 +OFF_IFM_PARAM_NODES : int = 88 // first of up to 8 param type nodes (8B each) → 88..151 +OFF_IFM_RET_NODE : int = 152 // return type node(-1 = 无,= unit) +OFF_IFM_SELF_MODE : int = 160 // 接收者模式:0 = 无接收者(首参为普通形参)/ 1 = self / // 2 = &self / 3 = &mut self(照 EXPR_PARAM 的 int_val 约定) // R2 P4 Task 3(IFACE 段签名项化)——**类型项槽**(-1 = 不可建/无): // param_terms[8] = 各形参的签名类型项(`sh_iface_sig_param_term`;接收者槽 = unit 占位项) @@ -188,14 +239,14 @@ OFF_IFM_SELF_MODE : int = 160; // 接收者模式:0 = 无接收者(首参 // 项槽是签名在载入侧的唯一忠实表示(二者不同域,不得互相复用)。写侧 = ccr_types.cr 的 // ccr_iface_populate 填充(与段体同一读点);读侧 = load_ccr 由段填充。**不入 .cir 快照** // (快照字段清单不含 g_ifaces——见 Task 3 报告 §布局影响面)。 -OFF_IFM_PARAM_TERMS : int = 168; // first of up to 8 param terms (8B each) → 168..231 -OFF_IFM_RET_TERM : int = 232; // return signature term (-1 = 不可建) -MAX_IFACE_METHOD_PARAMS : int = 8; +OFF_IFM_PARAM_TERMS : int = 168 // first of up to 8 param terms (8B each) → 168..231 +OFF_IFM_RET_TERM : int = 232 // return signature term (-1 = 不可建) +MAX_IFACE_METHOD_PARAMS : int = 8 // R2 P3b Task 6(Step 1):方法上限单源化(旧态 = parser 内联字面量 16,与 ESZ_IFACEINFO // 的槽数隐式绑定)。**本任务显式登记保留**(不解除):解除需把方法表迁到侧表(全部读点换位), // 按 B.4-7 的 MAX_* 统一口径「先加护栏、再评估解除」;护栏现状 = 超限**硬错 rc=1**(非静默 // 截断——实测),本任务加钉子用例(test_impl_iface.py 的 limit 组)。 -MAX_IFACE_METHODS : int = 16; +MAX_IFACE_METHODS : int = 16 // ─── 本质条目表布局(R2 P4 Task 3:自 iface_registry.cr **迁入**)─── // 迁入理由 = IFACE(8) 段的 loader(corearch 侧,ccr_io.cr)要重建 `g_iface_entries` @@ -207,29 +258,34 @@ MAX_IFACE_METHODS : int = 16; // 类型行(8 原生 = TI_* 常量;结构/命名 = -1);name_ni = 名字 ni(显示/查询用, // R2 P4 Task 3 起在注册面 str_intern 填充——裁决 1 接受 STR 段增长);lit_code = // 字面量定型(AST kind;-1 = 无);ops = 操作许可位集。 -ESZ_IFACE_ENTRY : int = 40; -OFF_IE_AK : int = 0; OFF_IE_TI : int = 8; OFF_IE_NAME : int = 16; -OFF_IE_LIT : int = 24; OFF_IE_OPS : int = 32; +ESZ_IFACE_ENTRY : int = 40 +OFF_IE_AK : int = 0 +OFF_IE_TI : int = 8 +OFF_IE_NAME : int = 16 +OFF_IE_LIT : int = 24 +OFF_IE_OPS : int = 32 // R2 P4 Task 3(裁决 3+7):13 → 16(+AK_NULL 原生第九员 + AK_SUM + AK_FN——纯信息面, // ops = 0 = 无操作许可;判定面零变化由全类型行枚举守门)。 -IFACE_ENTRY_COUNT : int = 16; +IFACE_ENTRY_COUNT : int = 16 // 形状条目表 grow(R2 P4 Task 3:自 iface_registry.cr **迁入**——同 IFACE 段 loader // 读回面:corearch 侧重建 g_iface_shape_* 需表增长;本文件 = grow 助手统一宿主, // 零依赖(alloc/_dyncpy 皆共享层))。语义/布局零变化(逐字搬迁)。 -fn iface_shape_grow(needed: int) { - if needed <= g_iface_shape_cap { return; } - nc : ., mut = g_iface_shape_cap * 2; - if nc < 8 { nc = 8; } - if nc < needed { nc = needed + 8; } - nb := alloc(nc * 8); - _dyncpy(g_iface_shape_names, g_iface_shape_cap * 8, nb); - g_iface_shape_names = nb; - nt := alloc(nc * 8); - _dyncpy(g_iface_shape_terms, g_iface_shape_cap * 8, nt); - g_iface_shape_terms = nt; - g_iface_shape_cap = nc; -} +fn iface_shape_grow(needed: int): + if needed <= g_iface_shape_cap: + return + nc : ., mut = g_iface_shape_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 8 + nb := alloc(nc * 8) + _dyncpy(g_iface_shape_names, g_iface_shape_cap * 8, nb) + g_iface_shape_names = nb + nt := alloc(nc * 8) + _dyncpy(g_iface_shape_terms, g_iface_shape_cap * 8, nt) + g_iface_shape_terms = nt + g_iface_shape_cap = nc // EnumInfo offsets // R2 P3 Task 4(T0 交接 ①):变体载荷**类型节点**槽(照 struct 先例 OFF_SI_FIELD_TYPE_NODES) @@ -239,172 +295,329 @@ fn iface_shape_grow(needed: int) { // 布局:EnumVariant = name(8) + types[16](128) + type_count(8) + type_nodes[16](128) = 272 // 容量批 T3(裁-CAP-2 (a)):变体槽区**迁侧表**——`OFF_EI_VARIANTS` 槽改义为 `variant_base` // (侧表起始行);`OFF_EV_*` 与 272B 槽区保留为**未用填充**(记录尺寸不变 ⇒ 外部算术零改动)。 -OFF_EI_NAME : int = 0; OFF_EI_VARIANTS : int = 8; // = variant_base -OFF_EI_VARIANT_COUNT : int = 4360; -OFF_EI_GENERIC_NAMES : int = 4368; OFF_EI_GENERIC_COUNT : int = 4400; -OFF_EV_NAME : int = 0; OFF_EV_TYPES : int = 8; OFF_EV_TYPE_COUNT : int = 136; -OFF_EV_TYPE_NODES : int = 144; -OFF_EV_SIZE : int = 272; +OFF_EI_NAME : int = 0 +OFF_EI_VARIANTS : int = 8 // = variant_base +OFF_EI_VARIANT_COUNT : int = 4360 +OFF_EI_GENERIC_NAMES : int = 4368 +OFF_EI_GENERIC_COUNT : int = 4400 +OFF_EV_NAME : int = 0 +OFF_EV_TYPES : int = 8 +OFF_EV_TYPE_COUNT : int = 136 +OFF_EV_TYPE_NODES : int = 144 +OFF_EV_SIZE : int = 272 // ============================================================ // Copy helper // ============================================================ -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 // ============================================================ // Grow helpers for ALL arrays // ============================================================ -fn _grow(buf_name: string, cap_name: int, esz: int, min_init: int) { +fn _grow(buf_name: string, cap_name: int, esz: int, min_init: int): + return // Helper: cap_name is by value; we return new cap. Caller must assign. // Inline expansion needed per array since Core can't do generic. -} // Each array gets its own grow function with doubling pattern. -fn grow_tokens(needed: int) { - if needed < g_tok_cap { return; } - nc : ., mut = g_tok_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * ESZ_TOKEN); _dyncpy(g_tokens, g_tok_cap * ESZ_TOKEN, nb); - g_tokens = nb; g_tok_cap = nc; } - -fn grow_ast(needed: int) { - if needed < g_ast_cap { return; } - nc : ., mut = g_ast_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * ESZ_ASTNODE); _dyncpy(g_ast, g_ast_cap * ESZ_ASTNODE, nb); - g_ast = nb; g_ast_cap = nc; } - -fn grow_syms(needed: int) { - if needed < g_sym_cap { return; } - nc : ., mut = g_sym_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * ESZ_SYMENTRY); _dyncpy(g_syms, g_sym_cap * ESZ_SYMENTRY, nb); - g_syms = nb; g_sym_cap = nc; } - -fn grow_types(needed: int) { - if needed < g_type_cap { return; } - nc : ., mut = g_type_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } +fn grow_tokens(needed: int): + if needed < g_tok_cap: + return + nc : ., mut = g_tok_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * ESZ_TOKEN) + _dyncpy(g_tokens, g_tok_cap * ESZ_TOKEN, nb) + g_tokens = nb + g_tok_cap = nc + +fn grow_ast(needed: int): + if needed < g_ast_cap: + return + nc : ., mut = g_ast_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * ESZ_ASTNODE) + _dyncpy(g_ast, g_ast_cap * ESZ_ASTNODE, nb) + g_ast = nb + g_ast_cap = nc + +fn grow_syms(needed: int): + if needed < g_sym_cap: + return + nc : ., mut = g_sym_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * ESZ_SYMENTRY) + _dyncpy(g_syms, g_sym_cap * ESZ_SYMENTRY, nb) + g_syms = nb + g_sym_cap = nc + +fn grow_types(needed: int): + if needed < g_type_cap: + return + nc : ., mut = g_type_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 // R2 P4 Task 2:行尺寸经 ESZ_TYPE_ROW 单源(globals.cr——与 alloc_type/ // TYPE 段序列化同源;原为字面量 24)。 - nb := alloc(nc * ESZ_TYPE_ROW); _dyncpy(g_types, g_type_cap * ESZ_TYPE_ROW, nb); - g_types = nb; g_type_cap = nc; } - -fn grow_funcs(needed: int) { - if needed < g_func_cap { return; } - nc : ., mut = g_func_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * ESZ_FUNCINFO); _dyncpy(g_funcs, g_func_cap * ESZ_FUNCINFO, nb); - g_funcs = nb; g_func_cap = nc; } - -fn grow_structs(needed: int) { - if needed < g_struct_cap { return; } - nc : ., mut = g_struct_cap * 2; if nc < 32 { nc = 32; } if nc < needed { nc = needed + 32; } - nb := alloc(nc * ESZ_STRUCTINFO); _dyncpy(g_structs, g_struct_cap * ESZ_STRUCTINFO, nb); - g_structs = nb; g_struct_cap = nc; } - -fn grow_enums(needed: int) { - if needed < g_enum_cap { return; } - nc : ., mut = g_enum_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * ESZ_ENUMINFO); _dyncpy(g_enums, g_enum_cap * ESZ_ENUMINFO, nb); - g_enums = nb; g_enum_cap = nc; } - -fn grow_ifaces(needed: int) { - if needed < g_iface_cap { return; } - nc : ., mut = g_iface_cap * 2; if nc < 4 { nc = 4; } if nc < needed { nc = needed + 4; } - nb := alloc(nc * ESZ_IFACEINFO); _dyncpy(g_ifaces, g_iface_cap * ESZ_IFACEINFO, nb); - g_ifaces = nb; g_iface_cap = nc; } - -fn grow_ir_vars(needed: int) { - if needed < g_ir_var_cap { return; } - nc : ., mut = g_ir_var_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * ESZ_IRVAR); _dyncpy(g_ir_vars, g_ir_var_cap * ESZ_IRVAR, nb); - g_ir_vars = nb; g_ir_var_cap = nc; } - -fn grow_ir_instrs(needed: int) { - if needed < g_ir_instr_cap { return; } - nc : ., mut = g_ir_instr_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * ESZ_IRINSTR); _dyncpy(g_ir_instrs, g_ir_instr_cap * ESZ_IRINSTR, nb); - g_ir_instrs = nb; g_ir_instr_cap = nc; } - -fn grow_ir_locals(needed: int) { - if needed < g_ir_local_cap { return; } - nc : ., mut = g_ir_local_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 16); _dyncpy(g_ir_locals, g_ir_local_cap * 16, nb); - g_ir_locals = nb; g_ir_local_cap = nc; } - -fn grow_ir_globals(needed: int) { - if needed < g_ir_global_cap { return; } - nc : ., mut = g_ir_global_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * 24); _dyncpy(g_ir_globals, g_ir_global_cap * 24, nb); - g_ir_globals = nb; g_ir_global_cap = nc; } - -fn grow_ir_str_consts(needed: int) { - if needed < g_ir_str_const_cap { return; } - nc : ., mut = g_ir_str_const_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_ir_str_consts, g_ir_str_const_cap * 8, nb); - g_ir_str_consts = nb; g_ir_str_const_cap = nc; } - -fn grow_errors(needed: int) { - if needed < g_err_cap { return; } - nc : ., mut = g_err_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * 8); _dyncpy(g_errors, g_err_cap * 8, nb); - g_errors = nb; g_err_cap = nc; } - -fn grow_block_stmts(needed: int) { - if needed < g_block_stmt_cap { return; } - nc : ., mut = g_block_stmt_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_block_stmts, g_block_stmt_cap * 8, nb); - g_block_stmts = nb; g_block_stmt_cap = nc; } - -fn grow_ir_func_meta(needed: int) { if needed < g_ir_func_name_idx_cap { return; } - if needed < g_ir_func_name_idx_cap { return; } - nc : ., mut = g_ir_func_name_idx_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_ir_func_name_idx, g_ir_func_name_idx_cap*8, n1); g_ir_func_name_idx = n1; - n2 := alloc(sz); _dyncpy(g_ir_func_ret_type, g_ir_func_ret_type_cap*8, n2); g_ir_func_ret_type = n2; - n3 := alloc(sz); _dyncpy(g_ir_func_instr_start, g_ir_func_instr_start_cap*8, n3); g_ir_func_instr_start = n3; - n4 := alloc(sz); _dyncpy(g_ir_func_instr_count, g_ir_func_instr_count_cap*8, n4); g_ir_func_instr_count = n4; - n5 := alloc(sz); _dyncpy(g_ir_func_var_start, g_ir_func_var_start_cap*8, n5); g_ir_func_var_start = n5; - n6 := alloc(sz); _dyncpy(g_ir_func_var_count, g_ir_func_var_count_cap*8, n6); g_ir_func_var_count = n6; - n7 := alloc(sz); _dyncpy(g_ir_func_param_count, g_ir_func_param_count_cap*8, n7); g_ir_func_param_count = n7; - g_ir_func_name_idx_cap=nc; g_ir_func_ret_type_cap=nc; g_ir_func_instr_start_cap=nc; - g_ir_func_instr_count_cap=nc; g_ir_func_var_start_cap=nc; g_ir_func_var_count_cap=nc; g_ir_func_param_count_cap=nc; } + nb := alloc(nc * ESZ_TYPE_ROW) + _dyncpy(g_types, g_type_cap * ESZ_TYPE_ROW, nb) + g_types = nb + g_type_cap = nc + +fn grow_funcs(needed: int): + if needed < g_func_cap: + return + nc : ., mut = g_func_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * ESZ_FUNCINFO) + _dyncpy(g_funcs, g_func_cap * ESZ_FUNCINFO, nb) + g_funcs = nb + g_func_cap = nc + +fn grow_structs(needed: int): + if needed < g_struct_cap: + return + nc : ., mut = g_struct_cap * 2 + if nc < 32: + nc = 32 + if nc < needed: + nc = needed + 32 + nb := alloc(nc * ESZ_STRUCTINFO) + _dyncpy(g_structs, g_struct_cap * ESZ_STRUCTINFO, nb) + g_structs = nb + g_struct_cap = nc + +fn grow_enums(needed: int): + if needed < g_enum_cap: + return + nc : ., mut = g_enum_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * ESZ_ENUMINFO) + _dyncpy(g_enums, g_enum_cap * ESZ_ENUMINFO, nb) + g_enums = nb + g_enum_cap = nc + +fn grow_ifaces(needed: int): + if needed < g_iface_cap: + return + nc : ., mut = g_iface_cap * 2 + if nc < 4: + nc = 4 + if nc < needed: + nc = needed + 4 + nb := alloc(nc * ESZ_IFACEINFO) + _dyncpy(g_ifaces, g_iface_cap * ESZ_IFACEINFO, nb) + g_ifaces = nb + g_iface_cap = nc + +fn grow_ir_vars(needed: int): + if needed < g_ir_var_cap: + return + nc : ., mut = g_ir_var_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * ESZ_IRVAR) + _dyncpy(g_ir_vars, g_ir_var_cap * ESZ_IRVAR, nb) + g_ir_vars = nb + g_ir_var_cap = nc + +fn grow_ir_instrs(needed: int): + if needed < g_ir_instr_cap: + return + nc : ., mut = g_ir_instr_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * ESZ_IRINSTR) + _dyncpy(g_ir_instrs, g_ir_instr_cap * ESZ_IRINSTR, nb) + g_ir_instrs = nb + g_ir_instr_cap = nc + +fn grow_ir_locals(needed: int): + if needed < g_ir_local_cap: + return + nc : ., mut = g_ir_local_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 16) + _dyncpy(g_ir_locals, g_ir_local_cap * 16, nb) + g_ir_locals = nb + g_ir_local_cap = nc + +fn grow_ir_globals(needed: int): + if needed < g_ir_global_cap: + return + nc : ., mut = g_ir_global_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * 24) + _dyncpy(g_ir_globals, g_ir_global_cap * 24, nb) + g_ir_globals = nb + g_ir_global_cap = nc + +fn grow_ir_str_consts(needed: int): + if needed < g_ir_str_const_cap: + return + nc : ., mut = g_ir_str_const_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_ir_str_consts, g_ir_str_const_cap * 8, nb) + g_ir_str_consts = nb + g_ir_str_const_cap = nc + +fn grow_errors(needed: int): + if needed < g_err_cap: + return + nc : ., mut = g_err_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * 8) + _dyncpy(g_errors, g_err_cap * 8, nb) + g_errors = nb + g_err_cap = nc + +fn grow_block_stmts(needed: int): + if needed < g_block_stmt_cap: + return + nc : ., mut = g_block_stmt_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_block_stmts, g_block_stmt_cap * 8, nb) + g_block_stmts = nb + g_block_stmt_cap = nc + +fn grow_ir_func_meta(needed: int): + if needed < g_ir_func_name_idx_cap: + return + if needed < g_ir_func_name_idx_cap: + return + nc : ., mut = g_ir_func_name_idx_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_ir_func_name_idx, g_ir_func_name_idx_cap*8, n1) + g_ir_func_name_idx = n1 + n2 := alloc(sz) + _dyncpy(g_ir_func_ret_type, g_ir_func_ret_type_cap*8, n2) + g_ir_func_ret_type = n2 + n3 := alloc(sz) + _dyncpy(g_ir_func_instr_start, g_ir_func_instr_start_cap*8, n3) + g_ir_func_instr_start = n3 + n4 := alloc(sz) + _dyncpy(g_ir_func_instr_count, g_ir_func_instr_count_cap*8, n4) + g_ir_func_instr_count = n4 + n5 := alloc(sz) + _dyncpy(g_ir_func_var_start, g_ir_func_var_start_cap*8, n5) + g_ir_func_var_start = n5 + n6 := alloc(sz) + _dyncpy(g_ir_func_var_count, g_ir_func_var_count_cap*8, n6) + g_ir_func_var_count = n6 + n7 := alloc(sz) + _dyncpy(g_ir_func_param_count, g_ir_func_param_count_cap*8, n7) + g_ir_func_param_count = n7 + g_ir_func_name_idx_cap=nc + g_ir_func_ret_type_cap=nc + g_ir_func_instr_start_cap=nc + g_ir_func_instr_count_cap=nc + g_ir_func_var_start_cap=nc + g_ir_func_var_count_cap=nc + g_ir_func_param_count_cap=nc // ============================================================ // Accessor helpers for AST node fields // ============================================================ -fn ast_kind(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_KIND); } -fn ast_a(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_A); } -fn ast_b(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_B); } -fn ast_c(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_C); } -fn ast_int_val(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_INTVAL); } -fn ast_type_val(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_TYPEVAL); } -fn ast_data(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_DATA); } -fn ast_line(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_LINE); } -fn ast_col(n: int) -> int { return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_COL); } - -fn ast_set_kind(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_KIND, v); } -fn ast_set_a(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_A, v); } -fn ast_set_b(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_B, v); } -fn ast_set_c(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_C, v); } -fn ast_set_int_val(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_INTVAL, v); } -fn ast_set_type_val(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_TYPEVAL, v); } -fn ast_set_data(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_DATA, v); } -fn ast_set_line(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_LINE, v); } -fn ast_set_col(n: int, v: int) { w64(g_ast, n * ESZ_ASTNODE + OFF_AS_COL, v); } - -fn ast_alloc(kind: int, a: int, b: int, c: int, iv: int, tv: int, d: int, line: int, col: int) -> int { - idx := g_ast_count; - grow_ast(idx + 1); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_KIND, kind); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_A, a); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_B, b); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_C, c); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_INTVAL, iv); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_TYPEVAL, tv); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_DATA, d); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_LINE, line); - w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_COL, col); - g_ast_count = idx + 1; - return idx; } +fn ast_kind(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_KIND) +fn ast_a(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_A) +fn ast_b(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_B) +fn ast_c(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_C) +fn ast_int_val(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_INTVAL) +fn ast_type_val(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_TYPEVAL) +fn ast_data(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_DATA) +fn ast_line(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_LINE) +fn ast_col(n: int) -> int: + return r64(g_ast, n * ESZ_ASTNODE + OFF_AS_COL) + +fn ast_set_kind(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_KIND, v) +fn ast_set_a(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_A, v) +fn ast_set_b(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_B, v) +fn ast_set_c(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_C, v) +fn ast_set_int_val(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_INTVAL, v) +fn ast_set_type_val(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_TYPEVAL, v) +fn ast_set_data(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_DATA, v) +fn ast_set_line(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_LINE, v) +fn ast_set_col(n: int, v: int): + w64(g_ast, n * ESZ_ASTNODE + OFF_AS_COL, v) + +fn ast_alloc(kind: int, a: int, b: int, c: int, iv: int, tv: int, d: int, line: int, col: int) -> int: + idx := g_ast_count + grow_ast(idx + 1) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_KIND, kind) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_A, a) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_B, b) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_C, c) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_INTVAL, iv) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_TYPEVAL, tv) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_DATA, d) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_LINE, line) + w64(g_ast, idx * ESZ_ASTNODE + OFF_AS_COL, col) + g_ast_count = idx + 1 + return idx // Accessor helpers for SymEntry // ─── R2 P3 Task 4:读取面护栏(n ∉ [0, g_sym_count) ⇒ -1,不触内存)─── @@ -416,182 +629,296 @@ fn ast_alloc(kind: int, a: int, b: int, c: int, iv: int, tv: int, d: int, line: // 「只有 fn、无类型声明」的源 rc=139)。修法 = 访问器自身带范围闸(与类型表访问器 // get_type_kind/get_type_data 同款);合法读零变化,越界/未分配返回 -1(哨兵语义与 // find_gsym 的 -1 一致)。根因(bootstrap 不短路)仍归 T0 §5-③ 登记,不在本任务面内。 -fn sym_name(n: int) -> int { if n < 0 || n >= g_sym_count { return -1; } return r64(g_syms, n * ESZ_SYMENTRY + OFF_SY_NAME); } -fn sym_kind(n: int) -> int { if n < 0 || n >= g_sym_count { return -1; } return r64(g_syms, n * ESZ_SYMENTRY + OFF_SY_KIND); } -fn sym_type(n: int) -> int { if n < 0 || n >= g_sym_count { return -1; } return r64(g_syms, n * ESZ_SYMENTRY + OFF_SY_TYPE); } -fn sym_node(n: int) -> int { if n < 0 || n >= g_sym_count { return -1; } return r64(g_syms, n * ESZ_SYMENTRY + OFF_SY_NODE); } -fn sym_set_name(n: int, v: int) { w64(g_syms, n * ESZ_SYMENTRY + OFF_SY_NAME, v); } -fn sym_set_kind(n: int, v: int) { w64(g_syms, n * ESZ_SYMENTRY + OFF_SY_KIND, v); } -fn sym_set_type(n: int, v: int) { w64(g_syms, n * ESZ_SYMENTRY + OFF_SY_TYPE, v); } -fn sym_set_node(n: int, v: int) { w64(g_syms, n * ESZ_SYMENTRY + OFF_SY_NODE, v); } +fn sym_name(n: int) -> int: + if n < 0 || n >= g_sym_count: + return -1 + return r64(g_syms, n * ESZ_SYMENTRY + OFF_SY_NAME) +fn sym_kind(n: int) -> int: + if n < 0 || n >= g_sym_count: + return -1 + return r64(g_syms, n * ESZ_SYMENTRY + OFF_SY_KIND) +fn sym_type(n: int) -> int: + if n < 0 || n >= g_sym_count: + return -1 + return r64(g_syms, n * ESZ_SYMENTRY + OFF_SY_TYPE) +fn sym_node(n: int) -> int: + if n < 0 || n >= g_sym_count: + return -1 + return r64(g_syms, n * ESZ_SYMENTRY + OFF_SY_NODE) +fn sym_set_name(n: int, v: int): + w64(g_syms, n * ESZ_SYMENTRY + OFF_SY_NAME, v) +fn sym_set_kind(n: int, v: int): + w64(g_syms, n * ESZ_SYMENTRY + OFF_SY_KIND, v) +fn sym_set_type(n: int, v: int): + w64(g_syms, n * ESZ_SYMENTRY + OFF_SY_TYPE, v) +fn sym_set_node(n: int, v: int): + w64(g_syms, n * ESZ_SYMENTRY + OFF_SY_NODE, v) // IRVar helpers -fn irv_name(n: int) -> int { return r64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_NAME); } -fn irv_id(n: int) -> int { return r64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_ID); } -fn irv_type(n: int) -> int { return r64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_TYPE); } -fn irv_set_name(n: int, v: int) { w64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_NAME, v); } -fn irv_set_id(n: int, v: int) { w64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_ID, v); } -fn irv_set_type(n: int, v: int) { w64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_TYPE, v); } +fn irv_name(n: int) -> int: + return r64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_NAME) +fn irv_id(n: int) -> int: + return r64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_ID) +fn irv_type(n: int) -> int: + return r64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_TYPE) +fn irv_set_name(n: int, v: int): + w64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_NAME, v) +fn irv_set_id(n: int, v: int): + w64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_ID, v) +fn irv_set_type(n: int, v: int): + w64(g_ir_vars, n * ESZ_IRVAR + OFF_IRV_TYPE, v) // IRInstr helpers -fn iri_op(n: int) -> int { return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_OP); } -fn iri_dest(n: int) -> int { return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_DEST); } -fn iri_s1(n: int) -> int { return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S1); } -fn iri_s2(n: int) -> int { return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S2); } -fn iri_s3(n: int) -> int { return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S3); } -fn iri_tk(n: int) -> int { return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_TK); } -fn iri_set_op(n: int, v: int) { w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_OP, v); } -fn iri_set_dest(n: int, v: int) { w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_DEST, v); } -fn iri_set_s1(n: int, v: int) { w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S1, v); } -fn iri_set_s2(n: int, v: int) { w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S2, v); } -fn iri_set_s3(n: int, v: int) { w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S3, v); } -fn iri_set_tk(n: int, v: int) { w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_TK, v); } +fn iri_op(n: int) -> int: + return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_OP) +fn iri_dest(n: int) -> int: + return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_DEST) +fn iri_s1(n: int) -> int: + return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S1) +fn iri_s2(n: int) -> int: + return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S2) +fn iri_s3(n: int) -> int: + return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S3) +fn iri_tk(n: int) -> int: + return r64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_TK) +fn iri_set_op(n: int, v: int): + w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_OP, v) +fn iri_set_dest(n: int, v: int): + w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_DEST, v) +fn iri_set_s1(n: int, v: int): + w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S1, v) +fn iri_set_s2(n: int, v: int): + w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S2, v) +fn iri_set_s3(n: int, v: int): + w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_S3, v) +fn iri_set_tk(n: int, v: int): + w64(g_ir_instrs, n * ESZ_IRINSTR + OFF_IRI_TK, v) // 变量名查询(原定义于 ir_gen.cr——2026-09-07 regalloc 移后端随迁本文件: // corearch 闭包不含 ir_gen.cr,regalloc.cr 判定/注入打印消费本函数;双侧共享) -fn get_ir_var_name(var_idx: int) -> string { - if var_idx >= 0 && var_idx < g_ir_var_count { - ni := irv_name(var_idx); - return istr_get(ni); - } - return ""; -} +fn get_ir_var_name(var_idx: int) -> string: + if var_idx >= 0 && var_idx < g_ir_var_count: + ni := irv_name(var_idx) + return istr_get(ni) + return "" // FuncInfo helpers -fn fi_name(n: int) -> int { return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_NAME); } -fn fi_param_count(n: int) -> int { return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_PARAM_COUNT); } -fn fi_return_type(n: int) -> int { return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_RETURN_TYPE); } -fn fi_ast_node(n: int) -> int { return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_AST_NODE); } -fn fi_generic_count(n: int) -> int { return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_GENERIC_COUNT); } -fn fi_param_type(n: int, pi: int) -> int { - if pi < 0 || pi >= MAX_FN_PARAMS { return 0; } // 越界 = 槽区外(读护栏;写侧同护栏 + parser 硬错) - return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_PARAM_TYPES + pi * 8); } -fn fi_generic_name(n: int, gi: int) -> int { return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gi * 8); } -fn fi_set_name(n: int, v: int) { w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_NAME, v); } -fn fi_set_param_count(n: int, v: int) { w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_PARAM_COUNT, v); } -fn fi_set_param_type(n: int, pi: int, v: int) { - if pi < 0 || pi >= MAX_FN_PARAMS { return; } // 槽区护栏:越界写会踩 return_type/ast_node/generic_*/ispure(TODO #2026-09-10-4 根源) - w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_PARAM_TYPES + pi*8, v); } -fn fi_set_return_type(n: int, v: int) { w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_RETURN_TYPE, v); } -fn fi_set_ast_node(n: int, v: int) { w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_AST_NODE, v); } -fn fi_set_generic_name(n: int, gi: int, v: int) { w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gi*8, v); } -fn fi_set_generic_count(n: int, v: int) { w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_GENERIC_COUNT, v); } - -fn fi_ispure(n: int) -> int { return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_ISPURE); } -fn fi_set_ispure(n: int, v: int) { w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_ISPURE, v); } +fn fi_name(n: int) -> int: + return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_NAME) +fn fi_param_count(n: int) -> int: + return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_PARAM_COUNT) +fn fi_return_type(n: int) -> int: + return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_RETURN_TYPE) +fn fi_ast_node(n: int) -> int: + return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_AST_NODE) +fn fi_generic_count(n: int) -> int: + return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_GENERIC_COUNT) +fn fi_param_type(n: int, pi: int) -> int: + if pi < 0 || pi >= MAX_FN_PARAMS: + return 0 + // 越界 = 槽区外(读护栏;写侧同护栏 + parser 硬错) + return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_PARAM_TYPES + pi * 8) +fn fi_generic_name(n: int, gi: int) -> int: + return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gi * 8) +fn fi_set_name(n: int, v: int): + w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_NAME, v) +fn fi_set_param_count(n: int, v: int): + w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_PARAM_COUNT, v) +fn fi_set_param_type(n: int, pi: int, v: int): + if pi < 0 || pi >= MAX_FN_PARAMS: + return + // 槽区护栏:越界写会踩 return_type/ast_node/generic_*/ispure(TODO #2026-09-10-4 根源) + w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_PARAM_TYPES + pi*8, v) +fn fi_set_return_type(n: int, v: int): + w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_RETURN_TYPE, v) +fn fi_set_ast_node(n: int, v: int): + w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_AST_NODE, v) +fn fi_set_generic_name(n: int, gi: int, v: int): + w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_GENERIC_NAMES + gi*8, v) +fn fi_set_generic_count(n: int, v: int): + w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_GENERIC_COUNT, v) + +fn fi_ispure(n: int) -> int: + return r64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_ISPURE) +fn fi_set_ispure(n: int, v: int): + w64(g_funcs, n * ESZ_FUNCINFO + OFF_FI_ISPURE, v) // StructInfo helpers -fn si_name(n: int) -> int { return r64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_NAME); } -fn si_field_count(n: int) -> int { return r64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT); } -fn si_generic_count(n: int) -> int { return r64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT); } +fn si_name(n: int) -> int: + return r64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_NAME) +fn si_field_count(n: int) -> int: + return r64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT) +fn si_generic_count(n: int) -> int: + return r64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_GENERIC_COUNT) // ─── 容量批 T3(裁-CAP-2 (a)):结构体字段**侧表**(无硬上限)─── // 布局:记录内 `OFF_SI_FIELD_BASE` = 本记录字段在侧表的起始行;`OFF_SI_FIELD_COUNT` = 计数 // (真值)。三条扁平表按「记录基数 + 字段下标」寻址;高水位 `g_si_f_used` 由 // `si_commit_fields` 提交(记录字段区一次性占用,不重叠)。 -fn grow_si_fields(needed: int) { - if needed <= g_si_f_cap { return; } - nc := g_si_f_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_si_f_names, g_si_f_cap * 8, nb); g_si_f_names = nb; - tb := alloc(nc * 8); _dyncpy(g_si_f_types, g_si_f_cap * 8, tb); g_si_f_types = tb; - ob := alloc(nc * 8); _dyncpy(g_si_f_nodes, g_si_f_cap * 8, ob); g_si_f_nodes = ob; - g_si_f_cap = nc; -} -fn si_field_base(n: int) -> int { return r64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_FIELD_BASE); } -fn si_set_field_base(n: int, v: int) { w64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_FIELD_BASE, v); } +fn grow_si_fields(needed: int): + if needed <= g_si_f_cap: + return + nc := g_si_f_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_si_f_names, g_si_f_cap * 8, nb) + g_si_f_names = nb + tb := alloc(nc * 8) + _dyncpy(g_si_f_types, g_si_f_cap * 8, tb) + g_si_f_types = tb + ob := alloc(nc * 8) + _dyncpy(g_si_f_nodes, g_si_f_cap * 8, ob) + g_si_f_nodes = ob + g_si_f_cap = nc +fn si_field_base(n: int) -> int: + return r64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_FIELD_BASE) +fn si_set_field_base(n: int, v: int): + w64(g_structs, n * ESZ_STRUCTINFO + OFF_SI_FIELD_BASE, v) // 提交字段区(base + 计数 ⇒ 高水位);parser 与 ccr_io 装载共用 -fn si_commit_fields(n: int, fc: int) { - b := si_field_base(n); - if b < 0 { return; } - if fc < 0 { return; } - if b + fc > g_si_f_used { g_si_f_used = b + fc; } -} +fn si_commit_fields(n: int, fc: int): + b := si_field_base(n) + if b < 0: + return + if fc < 0: + return + if b + fc > g_si_f_used: + g_si_f_used = b + fc // 读护栏(R2 P4 Task 6 / TODO #2026-09-12-2 的**计数为界**版本):fi 越界(< 0 或 ≥ count)⇒ 回哨兵 // -1(不越读);在界读 = 侧表取值。 -fn si_field_row(n: int, fi: int) -> int { - if fi < 0 { return -1; } - if fi >= si_field_count(n) { return -1; } - b := si_field_base(n); - if b < 0 { return -1; } - return b + fi; -} -fn si_field_name(n: int, fi: int) -> int { - r := si_field_row(n, fi); - if r < 0 { return -1; } - return r64(g_si_f_names, r * 8); } -fn si_field_type(n: int, fi: int) -> int { - r := si_field_row(n, fi); - if r < 0 { return -1; } - return r64(g_si_f_types, r * 8); } -fn si_field_type_node(n: int, fi: int) -> int { - r := si_field_row(n, fi); - if r < 0 { return -1; } - return r64(g_si_f_nodes, r * 8); } -fn si_generic_name(n: int, gi: int) -> int { return r64(g_structs, n*ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES + gi*8); } +fn si_field_row(n: int, fi: int) -> int: + if fi < 0: + return -1 + if fi >= si_field_count(n): + return -1 + b := si_field_base(n) + if b < 0: + return -1 + return b + fi +fn si_field_name(n: int, fi: int) -> int: + r := si_field_row(n, fi) + if r < 0: + return -1 + return r64(g_si_f_names, r * 8) +fn si_field_type(n: int, fi: int) -> int: + r := si_field_row(n, fi) + if r < 0: + return -1 + return r64(g_si_f_types, r * 8) +fn si_field_type_node(n: int, fi: int) -> int: + r := si_field_row(n, fi) + if r < 0: + return -1 + return r64(g_si_f_nodes, r * 8) +fn si_generic_name(n: int, gi: int) -> int: + return r64(g_structs, n*ESZ_STRUCTINFO + OFF_SI_GENERIC_NAMES + gi*8) // EnumInfo helpers -fn ei_name(n: int) -> int { return r64(g_enums, n * ESZ_ENUMINFO + OFF_EI_NAME); } -fn ei_variant_count(n: int) -> int { return r64(g_enums, n * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT); } -fn ei_generic_count(n: int) -> int { return r64(g_enums, n * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT); } -fn ei_generic_name(n: int, gi: int) -> int { return r64(g_enums, n*ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES + gi*8); } +fn ei_name(n: int) -> int: + return r64(g_enums, n * ESZ_ENUMINFO + OFF_EI_NAME) +fn ei_variant_count(n: int) -> int: + return r64(g_enums, n * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT) +fn ei_generic_count(n: int) -> int: + return r64(g_enums, n * ESZ_ENUMINFO + OFF_EI_GENERIC_COUNT) +fn ei_generic_name(n: int, gi: int) -> int: + return r64(g_enums, n*ESZ_ENUMINFO + OFF_EI_GENERIC_NAMES + gi*8) // 读护栏(R2 P4 Task 6 / TODO #2026-09-12-2):越界 = 槽区外(读会取到 variant_count/generic 槽或邻 // 记录)⇒ 回哨兵(名字/类型码/类型节点 = -1;计数 = 0)。在界调用点(count ≤ 16)行为不变。 // ─── 容量批 T3:枚举变体**侧表**(无硬上限;同 struct 字段形态)─── -fn grow_ei_variants(needed: int) { - if needed <= g_ei_v_cap { return; } - nc := g_ei_v_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - a := alloc(nc * 8); _dyncpy(g_ei_v_names, g_ei_v_cap * 8, a); g_ei_v_names = a; - b := alloc(nc * 8); _dyncpy(g_ei_v_tbase, g_ei_v_cap * 8, b); g_ei_v_tbase = b; - c := alloc(nc * 8); _dyncpy(g_ei_v_tcount, g_ei_v_cap * 8, c); g_ei_v_tcount = c; - z : ., mut = g_ei_v_cap; - loop { if z >= nc { break; } w64(b, z * 8, -1); z = z + 1; } // tbase 新槽 = -1 哨兵 - g_ei_v_cap = nc; -} -fn grow_ei_vtypes(needed: int) { - if needed <= g_ei_vt_cap { return; } - nc := g_ei_vt_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - a := alloc(nc * 8); _dyncpy(g_ei_vt_types, g_ei_vt_cap * 8, a); g_ei_vt_types = a; - b := alloc(nc * 8); _dyncpy(g_ei_vt_nodes, g_ei_vt_cap * 8, b); g_ei_vt_nodes = b; - g_ei_vt_cap = nc; -} -fn ei_variant_base(n: int) -> int { return r64(g_enums, n * ESZ_ENUMINFO + OFF_EI_VARIANTS); } -fn ei_set_variant_base(n: int, v: int) { w64(g_enums, n * ESZ_ENUMINFO + OFF_EI_VARIANTS, v); } -fn ei_commit_variants(n: int, vc: int) { - b := ei_variant_base(n); - if b < 0 { return; } - if vc < 0 { return; } - if b + vc > g_ei_v_used { g_ei_v_used = b + vc; } -} -fn ei_variant_row(n: int, vi: int) -> int { - if vi < 0 { return -1; } - if vi >= ei_variant_count(n) { return -1; } - b := ei_variant_base(n); - if b < 0 { return -1; } - return b + vi; -} -fn ei_variant_name(n: int, vi: int) -> int { - r := ei_variant_row(n, vi); - if r < 0 { return -1; } - return r64(g_ei_v_names, r * 8); } -fn ei_variant_type_count(n: int, vi: int) -> int { - r := ei_variant_row(n, vi); - if r < 0 { return 0; } - return r64(g_ei_v_tcount, r * 8); } -fn ei_variant_type(n: int, vi: int, ti: int) -> int { - r := ei_variant_row(n, vi); - if r < 0 { return -1; } - if ti < 0 || ti >= r64(g_ei_v_tcount, r * 8) { return -1; } - tb := r64(g_ei_v_tbase, r * 8); - if tb < 0 { return -1; } - return r64(g_ei_vt_types, (tb + ti) * 8); } +fn grow_ei_variants(needed: int): + if needed <= g_ei_v_cap: + return + nc := g_ei_v_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + a := alloc(nc * 8) + _dyncpy(g_ei_v_names, g_ei_v_cap * 8, a) + g_ei_v_names = a + b := alloc(nc * 8) + _dyncpy(g_ei_v_tbase, g_ei_v_cap * 8, b) + g_ei_v_tbase = b + c := alloc(nc * 8) + _dyncpy(g_ei_v_tcount, g_ei_v_cap * 8, c) + g_ei_v_tcount = c + z : ., mut = g_ei_v_cap + loop: + if z >= nc: + break + w64(b, z * 8, -1) + z = z + 1 + // tbase 新槽 = -1 哨兵 + g_ei_v_cap = nc +fn grow_ei_vtypes(needed: int): + if needed <= g_ei_vt_cap: + return + nc := g_ei_vt_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + a := alloc(nc * 8) + _dyncpy(g_ei_vt_types, g_ei_vt_cap * 8, a) + g_ei_vt_types = a + b := alloc(nc * 8) + _dyncpy(g_ei_vt_nodes, g_ei_vt_cap * 8, b) + g_ei_vt_nodes = b + g_ei_vt_cap = nc +fn ei_variant_base(n: int) -> int: + return r64(g_enums, n * ESZ_ENUMINFO + OFF_EI_VARIANTS) +fn ei_set_variant_base(n: int, v: int): + w64(g_enums, n * ESZ_ENUMINFO + OFF_EI_VARIANTS, v) +fn ei_commit_variants(n: int, vc: int): + b := ei_variant_base(n) + if b < 0: + return + if vc < 0: + return + if b + vc > g_ei_v_used: + g_ei_v_used = b + vc +fn ei_variant_row(n: int, vi: int) -> int: + if vi < 0: + return -1 + if vi >= ei_variant_count(n): + return -1 + b := ei_variant_base(n) + if b < 0: + return -1 + return b + vi +fn ei_variant_name(n: int, vi: int) -> int: + r := ei_variant_row(n, vi) + if r < 0: + return -1 + return r64(g_ei_v_names, r * 8) +fn ei_variant_type_count(n: int, vi: int) -> int: + r := ei_variant_row(n, vi) + if r < 0: + return 0 + return r64(g_ei_v_tcount, r * 8) +fn ei_variant_type(n: int, vi: int, ti: int) -> int: + r := ei_variant_row(n, vi) + if r < 0: + return -1 + if ti < 0 || ti >= r64(g_ei_v_tcount, r * 8): + return -1 + tb := r64(g_ei_v_tbase, r * 8) + if tb < 0: + return -1 + return r64(g_ei_vt_types, (tb + ti) * 8) // R2 P3 Task 4(T0 交接 ①):载荷第 ti 个的**类型节点**(-1/0 = 无信息——.ccr 不落本列, // 序列化读回侧该列恒 0;消费者须以 type_count 为界,不得据 0 反推「节点 0」)。 -fn ei_variant_type_node(n: int, vi: int, ti: int) -> int { - r := ei_variant_row(n, vi); - if r < 0 { return -1; } - if ti < 0 || ti >= r64(g_ei_v_tcount, r * 8) { return -1; } - tb := r64(g_ei_v_tbase, r * 8); - if tb < 0 { return -1; } - return r64(g_ei_vt_nodes, (tb + ti) * 8); } +fn ei_variant_type_node(n: int, vi: int, ti: int) -> int: + r := ei_variant_row(n, vi) + if r < 0: + return -1 + if ti < 0 || ti >= r64(g_ei_v_tcount, r * 8): + return -1 + tb := r64(g_ei_v_tbase, r * 8) + if tb < 0: + return -1 + return r64(g_ei_vt_nodes, (tb + ti) * 8) // ─── 枚举/结构体记录**受护访问器**(R2 P4 Task 6;TODO #2026-09-12-2 收口,#2026-09-10-4 同族形态)─── // 背景(TODO #2026-09-12-2 代码级定位;**容量批 T3 起该定长槽区已退役**——字段/变体迁侧表):EnumVariant 槽区(旧 `MAX_ENUM_VARIANTS` 槽 × `OFF_EV_SIZE`)与 @@ -604,658 +931,1174 @@ fn ei_variant_type_node(n: int, vi: int, ti: int) -> int { // ③ 面向用户的拒绝由 parser 的 P022/P023 硬错承担(本层只做内存安全兜底,不代替诊断)。 // count 槽(`ei_variant_count`/`si_field_count` 的写)**不设护栏**——真值是诊断依据,照 // P020 的 `add_func(pc)` 先例(计数保持真实值,超限由硬错拒绝;越界读由②兜底)。 -fn ei_set_variant_name(n: int, vi: int, v: int) { - if vi < 0 { return; } - b := ei_variant_base(n); - if b < 0 { return; } - grow_ei_variants(b + vi + 1); - if b + vi + 1 > g_ei_v_used { g_ei_v_used = b + vi + 1; } - w64(g_ei_v_names, (b + vi) * 8, v); } +fn ei_set_variant_name(n: int, vi: int, v: int): + if vi < 0: + return + b := ei_variant_base(n) + if b < 0: + return + grow_ei_variants(b + vi + 1) + if b + vi + 1 > g_ei_v_used: + g_ei_v_used = b + vi + 1 + w64(g_ei_v_names, (b + vi) * 8, v) // 载荷基址**惰性分配**(首个载荷写入时占用高水位;后续增量推进) -fn ei_variant_tbase_ensure(n: int, vi: int) -> int { - b := ei_variant_base(n); - if b < 0 { return -1; } - grow_ei_variants(b + vi + 1); - r := b + vi; - tb := r64(g_ei_v_tbase, r * 8); - if tb < 0 { - tb = g_ei_vt_used; - w64(g_ei_v_tbase, r * 8, tb); - } - return tb; -} -fn ei_set_variant_type(n: int, vi: int, ti: int, v: int) { - if vi < 0 || ti < 0 { return; } - tb := ei_variant_tbase_ensure(n, vi); - if tb < 0 { return; } - grow_ei_vtypes(tb + ti + 1); - w64(g_ei_vt_types, (tb + ti) * 8, v); - if tb + ti + 1 > g_ei_vt_used { g_ei_vt_used = tb + ti + 1; } } -fn ei_set_variant_type_count(n: int, vi: int, v: int) { - if vi < 0 { return; } - b := ei_variant_base(n); - if b < 0 { return; } - grow_ei_variants(b + vi + 1); - w64(g_ei_v_tcount, (b + vi) * 8, v); - if v > 0 { - tb := ei_variant_tbase_ensure(n, vi); // 申报区间整体占位(未写槽亦不与他人重叠) - if tb >= 0 && tb + v > g_ei_vt_used { g_ei_vt_used = tb + v; } - } } -fn ei_set_variant_type_node(n: int, vi: int, ti: int, v: int) { - if vi < 0 || ti < 0 { return; } - tb := ei_variant_tbase_ensure(n, vi); - if tb < 0 { return; } - grow_ei_vtypes(tb + ti + 1); - w64(g_ei_vt_nodes, (tb + ti) * 8, v); - if tb + ti + 1 > g_ei_vt_used { g_ei_vt_used = tb + ti + 1; } } -fn si_set_field_name(n: int, fi: int, v: int) { - if fi < 0 { return; } - b := si_field_base(n); - if b < 0 { return; } - grow_si_fields(b + fi + 1); - if b + fi + 1 > g_si_f_used { g_si_f_used = b + fi + 1; } - w64(g_si_f_names, (b + fi) * 8, v); } -fn si_set_field_type(n: int, fi: int, v: int) { - if fi < 0 { return; } - b := si_field_base(n); - if b < 0 { return; } - grow_si_fields(b + fi + 1); - if b + fi + 1 > g_si_f_used { g_si_f_used = b + fi + 1; } - w64(g_si_f_types, (b + fi) * 8, v); } -fn si_set_field_type_node(n: int, fi: int, v: int) { - if fi < 0 { return; } - b := si_field_base(n); - if b < 0 { return; } - grow_si_fields(b + fi + 1); - if b + fi + 1 > g_si_f_used { g_si_f_used = b + fi + 1; } - w64(g_si_f_nodes, (b + fi) * 8, v); } +fn ei_variant_tbase_ensure(n: int, vi: int) -> int: + b := ei_variant_base(n) + if b < 0: + return -1 + grow_ei_variants(b + vi + 1) + r := b + vi + tb := r64(g_ei_v_tbase, r * 8) + if tb < 0: + tb = g_ei_vt_used + w64(g_ei_v_tbase, r * 8, tb) + return tb +fn ei_set_variant_type(n: int, vi: int, ti: int, v: int): + if vi < 0 || ti < 0: + return + tb := ei_variant_tbase_ensure(n, vi) + if tb < 0: + return + grow_ei_vtypes(tb + ti + 1) + w64(g_ei_vt_types, (tb + ti) * 8, v) + if tb + ti + 1 > g_ei_vt_used: + g_ei_vt_used = tb + ti + 1 +fn ei_set_variant_type_count(n: int, vi: int, v: int): + if vi < 0: + return + b := ei_variant_base(n) + if b < 0: + return + grow_ei_variants(b + vi + 1) + w64(g_ei_v_tcount, (b + vi) * 8, v) + if v > 0: + tb := ei_variant_tbase_ensure(n, vi) // 申报区间整体占位(未写槽亦不与他人重叠) + if tb >= 0 && tb + v > g_ei_vt_used: + g_ei_vt_used = tb + v +fn ei_set_variant_type_node(n: int, vi: int, ti: int, v: int): + if vi < 0 || ti < 0: + return + tb := ei_variant_tbase_ensure(n, vi) + if tb < 0: + return + grow_ei_vtypes(tb + ti + 1) + w64(g_ei_vt_nodes, (tb + ti) * 8, v) + if tb + ti + 1 > g_ei_vt_used: + g_ei_vt_used = tb + ti + 1 +fn si_set_field_name(n: int, fi: int, v: int): + if fi < 0: + return + b := si_field_base(n) + if b < 0: + return + grow_si_fields(b + fi + 1) + if b + fi + 1 > g_si_f_used: + g_si_f_used = b + fi + 1 + w64(g_si_f_names, (b + fi) * 8, v) +fn si_set_field_type(n: int, fi: int, v: int): + if fi < 0: + return + b := si_field_base(n) + if b < 0: + return + grow_si_fields(b + fi + 1) + if b + fi + 1 > g_si_f_used: + g_si_f_used = b + fi + 1 + w64(g_si_f_types, (b + fi) * 8, v) +fn si_set_field_type_node(n: int, fi: int, v: int): + if fi < 0: + return + b := si_field_base(n) + if b < 0: + return + grow_si_fields(b + fi + 1) + if b + fi + 1 > g_si_f_used: + g_si_f_used = b + fi + 1 + w64(g_si_f_nodes, (b + fi) * 8, v) // ============================================================ // String table helpers (dynamic byte buffer) // ============================================================ -fn grow_g_strs(needed: int) { - if needed < g_str_cap { return; } - nc : ., mut = g_str_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_strs, g_str_cap * 8, nb); - g_strs = nb; g_str_cap = nc; } - -fn str_hash(s: string) -> int { - h : ., mut = 5381; - i : ., mut = 0; - loop { - c := load8(s, i); - if c == 0 { break; } - h = h * 33 + c; - i = i + 1; } - return h; } +fn grow_g_strs(needed: int): + if needed < g_str_cap: + return + nc : ., mut = g_str_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_strs, g_str_cap * 8, nb) + g_strs = nb + g_str_cap = nc + +fn str_hash(s: string) -> int: + h : ., mut = 5381 + i : ., mut = 0 + loop: + c := load8(s, i) + if c == 0: + break + h = h * 33 + c + i = i + 1 + return h // Hash arbitrary bytes (for function body content fingerprinting). // Uses a multiplicative hash similar to str_hash but with FNV-inspired // constants for better distribution over byte ranges. -fn hash_bytes(data: string, len: int) -> int { - h : ., mut = 2166136261; // FNV offset basis - i : ., mut = 0; - loop { - if i >= len { break; } - h = h * 16777619; // FNV prime - h = h + (load8(data, i) % 256); - i = i + 1; - } - return h; -} - -fn _grow_str_hash(ncap: int) { +fn hash_bytes(data: string, len: int) -> int: + h : ., mut = 2166136261 // FNV offset basis + i : ., mut = 0 + loop: + if i >= len: + break + h = h * 16777619 // FNV prime + h = h + (load8(data, i) % 256) + i = i + 1 + return h + +fn _grow_str_hash(ncap: int): // Allocate new table filled with -1, rehash all existing strings - nb := alloc(ncap * 8); - i : ., mut = 0; - loop { if i >= ncap { break; } w64(nb, i * 8, -1); i = i + 1; } + nb := alloc(ncap * 8) + i : ., mut = 0 + loop: + if i >= ncap: + break + w64(nb, i * 8, -1) + i = i + 1 // Rehash all strings already in g_strs into new table - si : ., mut = 0; - loop { - if si >= g_str_count { break; } - s := load_str_ptr(g_strs, si * 8); - h := str_hash(s); - pos := h % ncap; - if pos < 0 { pos = -pos; } - loop { - if r64(nb, pos * 8) < 0 { w64(nb, pos * 8, si); break; } - pos = (pos + 1) % ncap; } - si = si + 1; } - g_str_hash = nb; - g_str_hash_cap = ncap; } - -fn str_intern(s: string) -> int { + si : ., mut = 0 + loop: + if si >= g_str_count: + break + s := load_str_ptr(g_strs, si * 8) + h := str_hash(s) + pos := h % ncap + if pos < 0: + pos = -pos + loop: + if r64(nb, pos * 8) < 0: + w64(nb, pos * 8, si) + break + pos = (pos + 1) % ncap + si = si + 1 + g_str_hash = nb + g_str_hash_cap = ncap + +fn str_intern(s: string) -> int: // Lazy init hash table - if g_str_hash_cap == 0 { _grow_str_hash(64); } + if g_str_hash_cap == 0: + _grow_str_hash(64) // Hash lookup - h := str_hash(s); - cap := g_str_hash_cap; - pos := h % cap; - if pos < 0 { pos = -pos; } - loop { - si := r64(g_str_hash, pos * 8); - if si < 0 { break; } // empty slot → not found - if str_eq(load_str_ptr(g_strs, si * 8), s) != 0 { return si; } - pos = (pos + 1) % cap; } + h := str_hash(s) + cap := g_str_hash_cap + pos := h % cap + if pos < 0: + pos = -pos + loop: + si := r64(g_str_hash, pos * 8) + if si < 0: + break + // empty slot → not found + if str_eq(load_str_ptr(g_strs, si * 8), s) != 0: + return si + pos = (pos + 1) % cap // Not found: insert - grow_g_strs(g_str_count + 1); - store_str_ptr(g_strs, g_str_count * 8, s); - g_str_count = g_str_count + 1; + grow_g_strs(g_str_count + 1) + store_str_ptr(g_strs, g_str_count * 8, s) + g_str_count = g_str_count + 1 // 生成期 intern 日志(CIR_CACHE_VER 21):**唯一插入路径**在此 ⇒ 单点保证 // 「gen 期新 intern 必进日志」(不存在「判定表漏点」这一失效面)。见 globals.cr 注。 - if g_cir_rec_on != 0 { cir_rec_push(g_str_count - 1); } + if g_cir_rec_on != 0: + cir_rec_push(g_str_count - 1) // Insert into hash table (pos is the empty slot we found) - w64(g_str_hash, pos * 8, g_str_count - 1); + w64(g_str_hash, pos * 8, g_str_count - 1) // Auto-rehash if load > 70% - if g_str_count * 10 > g_str_hash_cap * 7 { - _grow_str_hash(g_str_hash_cap * 2); } - return g_str_count - 1; } + if g_str_count * 10 > g_str_hash_cap * 7: + _grow_str_hash(g_str_hash_cap * 2) + return g_str_count - 1 // 生成期 intern 日志的写入端(唯一调用点 = str_intern 的插入路径)。 // 只记 **id**(本进程载体);落盘时由 cir_cache.cr 解析为**内容**——跨进程 id 不可跨进程解释。 -fn cir_rec_push(si: int) { - if g_cir_rec_count >= g_cir_rec_cap { - nc := g_cir_rec_cap * 2; - if nc < 64 { nc = 64; } - nb := alloc(nc * 8); - _dyncpy(g_cir_rec_ids, g_cir_rec_cap * 8, nb); - g_cir_rec_ids = nb; - g_cir_rec_cap = nc; - } - w64(g_cir_rec_ids, g_cir_rec_count * 8, si); - g_cir_rec_count = g_cir_rec_count + 1; -} - -fn istr_get(idx: int) -> string { - if idx < 0 || idx >= g_str_count { return ""; } - return load_str_ptr(g_strs, idx * 8); } - -fn istr_len(idx: int) -> int { - if idx < 0 || idx >= g_str_count { return 0; } - return str_len(istr_get(idx)); } - -fn str_load8(idx: int, ci: int) -> int { - if idx < 0 || idx >= g_str_count { return 0; } - return load8(istr_get(idx), ci); } - -fn grow_line_file(needed: int) { - if needed < g_line_cap { return; } - nc : ., mut = g_line_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); _dyncpy(g_line_fileid, g_line_cap * 8, nb); - g_line_fileid = nb; g_line_cap = nc; } -fn grow_segs(needed: int) { - if needed < g_seg_cap { return; } - nc : ., mut = g_seg_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_seg_starts, g_seg_cap * 8, n1); g_seg_starts = n1; - n2 := alloc(sz); _dyncpy(g_seg_fileids, g_seg_cap * 8, n2); g_seg_fileids = n2; - g_seg_cap = nc; } -fn grow_gen_apply_data(needed: int) { - if needed < g_gen_apply_data_cap { return; } - nc : ., mut = g_gen_apply_data_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_gen_apply_data, g_gen_apply_data_cap * 8, nb); - g_gen_apply_data = nb; g_gen_apply_data_cap = nc; } -fn grow_df_nodes(needed: int) { - if needed < g_df_node_cap { return; } - nc : ., mut = g_df_node_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * ESZ_DFNODE); _dyncpy(g_df_nodes, g_df_node_cap * ESZ_DFNODE, nb); - g_df_nodes = nb; g_df_node_cap = nc; } -fn grow_df_node_region(needed: int) { - if needed < g_df_node_region_cap { return; } - nc : ., mut = g_df_node_region_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); _dyncpy(g_df_node_region, g_df_node_region_cap * 8, nb); - g_df_node_region = nb; g_df_node_region_cap = nc; } -fn grow_df_edges(needed: int) { - if needed < g_df_edge_cap { return; } - nc : ., mut = g_df_edge_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * ESZ_DFEDGE); _dyncpy(g_df_edges, g_df_edge_cap * ESZ_DFEDGE, nb); - g_df_edges = nb; g_df_edge_cap = nc; } -fn grow_df_arrays(needed: int) { - if needed < g_df_cap { return; } - nc : ., mut = g_df_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_df_var_producer, g_df_cap * 8, n1); +fn cir_rec_push(si: int): + if g_cir_rec_count >= g_cir_rec_cap: + nc := g_cir_rec_cap * 2 + if nc < 64: + nc = 64 + nb := alloc(nc * 8) + _dyncpy(g_cir_rec_ids, g_cir_rec_cap * 8, nb) + g_cir_rec_ids = nb + g_cir_rec_cap = nc + w64(g_cir_rec_ids, g_cir_rec_count * 8, si) + g_cir_rec_count = g_cir_rec_count + 1 + +fn istr_get(idx: int) -> string: + if idx < 0 || idx >= g_str_count: + return "" + return load_str_ptr(g_strs, idx * 8) + +fn istr_len(idx: int) -> int: + if idx < 0 || idx >= g_str_count: + return 0 + return str_len(istr_get(idx)) + +fn str_load8(idx: int, ci: int) -> int: + if idx < 0 || idx >= g_str_count: + return 0 + return load8(istr_get(idx), ci) + +fn grow_line_file(needed: int): + if needed < g_line_cap: + return + nc : ., mut = g_line_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_line_fileid, g_line_cap * 8, nb) + g_line_fileid = nb + g_line_cap = nc +fn grow_segs(needed: int): + if needed < g_seg_cap: + return + nc : ., mut = g_seg_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_seg_starts, g_seg_cap * 8, n1) + g_seg_starts = n1 + n2 := alloc(sz) + _dyncpy(g_seg_fileids, g_seg_cap * 8, n2) + g_seg_fileids = n2 + g_seg_cap = nc +fn grow_gen_apply_data(needed: int): + if needed < g_gen_apply_data_cap: + return + nc : ., mut = g_gen_apply_data_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_gen_apply_data, g_gen_apply_data_cap * 8, nb) + g_gen_apply_data = nb + g_gen_apply_data_cap = nc +fn grow_df_nodes(needed: int): + if needed < g_df_node_cap: + return + nc : ., mut = g_df_node_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * ESZ_DFNODE) + _dyncpy(g_df_nodes, g_df_node_cap * ESZ_DFNODE, nb) + g_df_nodes = nb + g_df_node_cap = nc +fn grow_df_node_region(needed: int): + if needed < g_df_node_region_cap: + return + nc : ., mut = g_df_node_region_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_df_node_region, g_df_node_region_cap * 8, nb) + g_df_node_region = nb + g_df_node_region_cap = nc +fn grow_df_edges(needed: int): + if needed < g_df_edge_cap: + return + nc : ., mut = g_df_edge_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * ESZ_DFEDGE) + _dyncpy(g_df_edges, g_df_edge_cap * ESZ_DFEDGE, nb) + g_df_edges = nb + g_df_edge_cap = nc +fn grow_df_arrays(needed: int): + if needed < g_df_cap: + return + nc : ., mut = g_df_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_df_var_producer, g_df_cap * 8, n1) // 幽灵边修复(v7 Task 0 注 A 裁决 = 播种修复,dataflow.cr/cir_cache.cr 同款): // producer 槽必须对全部 var 下标恒 -1——alloc 新段(零页/复用页)不可依赖, // 未定值 var(全局/参数/0 字面量槽)若留 0 =「节点 0」→ df_use_var 产幽灵边 // 0→X + 自环 (0,0)。增长区显式播种 -1;既有区由 _dyncpy 保留(定值由 // df_create_node 覆写、缓存放回路径同走本函数 → 未产出 var 保持 -1)。 - zi : ., mut = g_df_cap; - loop { - if zi >= nc { break; } - w64(n1, zi * 8, -1); - zi = zi + 1; - } - g_df_var_producer = n1; - n2 := alloc(sz); _dyncpy(g_df_func_node_start, g_df_cap * 8, n2); g_df_func_node_start = n2; - n3 := alloc(sz); _dyncpy(g_df_func_node_count, g_df_cap * 8, n3); g_df_func_node_count = n3; + zi : ., mut = g_df_cap + loop: + if zi >= nc: + break + w64(n1, zi * 8, -1) + zi = zi + 1 + g_df_var_producer = n1 + n2 := alloc(sz) + _dyncpy(g_df_func_node_start, g_df_cap * 8, n2) + g_df_func_node_start = n2 + n3 := alloc(sz) + _dyncpy(g_df_func_node_count, g_df_cap * 8, n3) + g_df_func_node_count = n3 // 缓存收窄批(CIR_CACHE_VER 20):每函数边起点随 g_df_cap 同域增长(未定值槽由 // df_begin_func 逐函数覆写;读取侧只在 df_begin_func 之后取,无未初始化读面)。 - n4 := alloc(sz); _dyncpy(g_df_func_edge_start, g_df_cap * 8, n4); g_df_func_edge_start = n4; - g_df_cap = nc; } - -fn grow_gen_map(needed: int) { - if needed < g_gen_map_cap { return; } - nc : ., mut = g_gen_map_cap * 2; if nc < 8 { nc = 8; } if nc < needed { nc = needed + 8; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_gen_map_names, g_gen_map_cap*8, n1); g_gen_map_names = n1; - n2 := alloc(sz); _dyncpy(g_gen_map_types, g_gen_map_cap*8, n2); g_gen_map_types = n2; - g_gen_map_cap = nc; } -fn grow_borrow_vars(needed: int) { - if needed < g_borrow_cap { return; } - nc : ., mut = g_borrow_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_borrow_vars, g_borrow_cap*8, n1); g_borrow_vars = n1; - n2 := alloc(sz); _dyncpy(g_borrow_refs, g_borrow_cap*8, n2); g_borrow_refs = n2; - n3 := alloc(sz); _dyncpy(g_borrow_muts, g_borrow_cap*8, n3); g_borrow_muts = n3; - g_borrow_cap = nc; } -fn grow_holder(needed: int) { - if needed < g_holder_cap { return; } - nc : ., mut = g_holder_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_holder_borrowers, g_holder_cap*8, n1); g_holder_borrowers = n1; - n2 := alloc(sz); _dyncpy(g_holder_borrowed, g_holder_cap*8, n2); g_holder_borrowed = n2; - n3 := alloc(sz); _dyncpy(g_holder_is_mut, g_holder_cap*8, n3); g_holder_is_mut = n3; - g_holder_cap = nc; } - -fn grow_global_lets(needed: int) { - if needed < g_global_lets_cap { return; } - nc : ., mut = g_global_lets_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_global_lets, g_global_lets_cap * 8, nb); - g_global_lets = nb; g_global_lets_cap = nc; } -fn grow_loop_stack(needed: int) { - if needed < g_loop_stack_cap { return; } - nc : ., mut = g_loop_stack_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 24); _dyncpy(g_loop_stack, g_loop_stack_cap * 24, nb); - g_loop_stack = nb; g_loop_stack_cap = nc; } -fn grow_type_aliases(needed: int) { - if needed < g_type_alias_cap { return; } - nc : ., mut = g_type_alias_cap * 2; if nc < 32 { nc = 32; } if nc < needed { nc = needed + 32; } - nb := alloc(nc * 16); _dyncpy(g_type_aliases, g_type_alias_cap * 16, nb); - g_type_aliases = nb; g_type_alias_cap = nc; } -fn grow_scope_bounds(needed: int) { - if needed < g_scope_bounds_cap { return; } - nc : ., mut = g_scope_bounds_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_scope_bounds, g_scope_bounds_cap * 8, nb); - g_scope_bounds = nb; g_scope_bounds_cap = nc; } -fn grow_methods(needed: int) { - if needed < g_method_cap { return; } - nc : ., mut = g_method_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 24); _dyncpy(g_methods, g_method_cap * 24, nb); - g_methods = nb; g_method_cap = nc; } -fn grow_borrow_markers(needed: int) { - if needed < g_borrow_scope_markers_cap { return; } - nc : ., mut = g_borrow_scope_markers_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_borrow_scope_markers, g_borrow_scope_markers_cap * 8, nb); - g_borrow_scope_markers = nb; g_borrow_scope_markers_cap = nc; } - -fn istr_eq(idx: int, lit: string) -> int { - if idx < 0 || idx >= g_str_count { return 0; } - if str_eq(istr_get(idx), lit) != 0 { return 1; } - return 0; } + n4 := alloc(sz) + _dyncpy(g_df_func_edge_start, g_df_cap * 8, n4) + g_df_func_edge_start = n4 + g_df_cap = nc + +fn grow_gen_map(needed: int): + if needed < g_gen_map_cap: + return + nc : ., mut = g_gen_map_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 8 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_gen_map_names, g_gen_map_cap*8, n1) + g_gen_map_names = n1 + n2 := alloc(sz) + _dyncpy(g_gen_map_types, g_gen_map_cap*8, n2) + g_gen_map_types = n2 + g_gen_map_cap = nc +fn grow_borrow_vars(needed: int): + if needed < g_borrow_cap: + return + nc : ., mut = g_borrow_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_borrow_vars, g_borrow_cap*8, n1) + g_borrow_vars = n1 + n2 := alloc(sz) + _dyncpy(g_borrow_refs, g_borrow_cap*8, n2) + g_borrow_refs = n2 + n3 := alloc(sz) + _dyncpy(g_borrow_muts, g_borrow_cap*8, n3) + g_borrow_muts = n3 + g_borrow_cap = nc +fn grow_holder(needed: int): + if needed < g_holder_cap: + return + nc : ., mut = g_holder_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_holder_borrowers, g_holder_cap*8, n1) + g_holder_borrowers = n1 + n2 := alloc(sz) + _dyncpy(g_holder_borrowed, g_holder_cap*8, n2) + g_holder_borrowed = n2 + n3 := alloc(sz) + _dyncpy(g_holder_is_mut, g_holder_cap*8, n3) + g_holder_is_mut = n3 + g_holder_cap = nc + +fn grow_global_lets(needed: int): + if needed < g_global_lets_cap: + return + nc : ., mut = g_global_lets_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_global_lets, g_global_lets_cap * 8, nb) + g_global_lets = nb + g_global_lets_cap = nc +fn grow_loop_stack(needed: int): + if needed < g_loop_stack_cap: + return + nc : ., mut = g_loop_stack_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 24) + _dyncpy(g_loop_stack, g_loop_stack_cap * 24, nb) + g_loop_stack = nb + g_loop_stack_cap = nc +fn grow_type_aliases(needed: int): + if needed < g_type_alias_cap: + return + nc : ., mut = g_type_alias_cap * 2 + if nc < 32: + nc = 32 + if nc < needed: + nc = needed + 32 + nb := alloc(nc * 16) + _dyncpy(g_type_aliases, g_type_alias_cap * 16, nb) + g_type_aliases = nb + g_type_alias_cap = nc +fn grow_scope_bounds(needed: int): + if needed < g_scope_bounds_cap: + return + nc : ., mut = g_scope_bounds_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_scope_bounds, g_scope_bounds_cap * 8, nb) + g_scope_bounds = nb + g_scope_bounds_cap = nc +fn grow_methods(needed: int): + if needed < g_method_cap: + return + nc : ., mut = g_method_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 24) + _dyncpy(g_methods, g_method_cap * 24, nb) + g_methods = nb + g_method_cap = nc +fn grow_borrow_markers(needed: int): + if needed < g_borrow_scope_markers_cap: + return + nc : ., mut = g_borrow_scope_markers_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_borrow_scope_markers, g_borrow_scope_markers_cap * 8, nb) + g_borrow_scope_markers = nb + g_borrow_scope_markers_cap = nc + +fn istr_eq(idx: int, lit: string) -> int: + if idx < 0 || idx >= g_str_count: + return 0 + if str_eq(istr_get(idx), lit) != 0: + return 1 + return 0 // ============================================================ // Grow functions for x86 backend arrays // ============================================================ -fn grow_x86_vars(needed: int) { - if needed < g_x86_var_cap { return; } - nc : ., mut = g_x86_var_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); _dyncpy(g_x86_vars, g_x86_var_cap * 8, nb); - g_x86_vars = nb; g_x86_var_cap = nc; } - -fn grow_is_enum(needed: int) { - if needed < g_x86_is_enum_cap { return; } - nc : ., mut = g_x86_is_enum_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); _dyncpy(g_x86_is_enum, g_x86_is_enum_cap * 8, nb); - g_x86_is_enum = nb; g_x86_is_enum_cap = nc; } - -fn grow_is_global(needed: int) { - if needed < g_x86_global_cap { return; } - nc : ., mut = g_x86_global_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); _dyncpy(g_x86_is_global, g_x86_global_cap * 8, nb); - g_x86_is_global = nb; g_x86_global_cap = nc; } - -fn grow_global_off(needed: int) { - if needed < g_x86_global_off_cap { return; } - nc : ., mut = g_x86_global_off_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); _dyncpy(g_x86_global_off, g_x86_global_off_cap * 8, nb); - g_x86_global_off = nb; g_x86_global_off_cap = nc; } - -fn grow_str_offs(needed: int) { - if needed < g_x86_str_cap { return; } - nc : ., mut = g_x86_str_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_x86_str_offs, g_x86_str_cap * 8, nb); - g_x86_str_offs = nb; g_x86_str_cap = nc; } - -fn grow_rip_patch(needed: int) { - if needed < g_x86_rip_patch_cap { return; } - nc : ., mut = g_x86_rip_patch_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb1 := alloc(nc * 8); _dyncpy(g_x86_rip_patch_pos, g_x86_rip_patch_cap * 8, nb1); g_x86_rip_patch_pos = nb1; - nb2 := alloc(nc * 8); _dyncpy(g_x86_rip_patch_globals, g_x86_rip_patch_cap * 8, nb2); g_x86_rip_patch_globals = nb2; - g_x86_rip_patch_cap = nc; } +fn grow_x86_vars(needed: int): + if needed < g_x86_var_cap: + return + nc : ., mut = g_x86_var_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_x86_vars, g_x86_var_cap * 8, nb) + g_x86_vars = nb + g_x86_var_cap = nc + +fn grow_is_enum(needed: int): + if needed < g_x86_is_enum_cap: + return + nc : ., mut = g_x86_is_enum_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_x86_is_enum, g_x86_is_enum_cap * 8, nb) + g_x86_is_enum = nb + g_x86_is_enum_cap = nc + +fn grow_is_global(needed: int): + if needed < g_x86_global_cap: + return + nc : ., mut = g_x86_global_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_x86_is_global, g_x86_global_cap * 8, nb) + g_x86_is_global = nb + g_x86_global_cap = nc + +fn grow_global_off(needed: int): + if needed < g_x86_global_off_cap: + return + nc : ., mut = g_x86_global_off_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_x86_global_off, g_x86_global_off_cap * 8, nb) + g_x86_global_off = nb + g_x86_global_off_cap = nc + +fn grow_str_offs(needed: int): + if needed < g_x86_str_cap: + return + nc : ., mut = g_x86_str_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_x86_str_offs, g_x86_str_cap * 8, nb) + g_x86_str_offs = nb + g_x86_str_cap = nc + +fn grow_rip_patch(needed: int): + if needed < g_x86_rip_patch_cap: + return + nc : ., mut = g_x86_rip_patch_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb1 := alloc(nc * 8) + _dyncpy(g_x86_rip_patch_pos, g_x86_rip_patch_cap * 8, nb1) + g_x86_rip_patch_pos = nb1 + nb2 := alloc(nc * 8) + _dyncpy(g_x86_rip_patch_globals, g_x86_rip_patch_cap * 8, nb2) + g_x86_rip_patch_globals = nb2 + g_x86_rip_patch_cap = nc // `.so` 扩展索引侧表(第 4 批 #82/#83):**动态增长**(本仓约定:All arrays are dynamic // byte buffers, no MAX_* limits——这正是 TODO #2026-09-17-1「容量硬编码 128 + 写入无界」要消灭的形态)。 -fn grow_so_side(needed: int) { - if needed < g_so_side_cap { return; } - nc : ., mut = g_so_side_cap * 2; if nc < 32 { nc = 32; } if nc < needed { nc = needed + 32; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_so_side_name, g_so_side_cap*8, n1); g_so_side_name = n1; - n2 := alloc(sz); _dyncpy(g_so_side_tags, g_so_side_cap*8, n2); g_so_side_tags = n2; - n3 := alloc(sz); _dyncpy(g_so_side_type, g_so_side_cap*8, n3); g_so_side_type = n3; - g_so_side_cap = nc; } +fn grow_so_side(needed: int): + if needed < g_so_side_cap: + return + nc : ., mut = g_so_side_cap * 2 + if nc < 32: + nc = 32 + if nc < needed: + nc = needed + 32 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_so_side_name, g_so_side_cap*8, n1) + g_so_side_name = n1 + n2 := alloc(sz) + _dyncpy(g_so_side_tags, g_so_side_cap*8, n2) + g_so_side_tags = n2 + n3 := alloc(sz) + _dyncpy(g_so_side_type, g_so_side_cap*8, n3) + g_so_side_type = n3 + g_so_side_cap = nc // ─── 批 6 T2:规约标注侧表(动态增长;照本仓「no MAX_* limits」约定)──────────────── -fn grow_spec_side(needed: int) { - if needed < g_spec_cap { return; } - nc : ., mut = g_spec_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_spec_fn, g_spec_cap*8, n1); g_spec_fn = n1; - n6 := alloc(sz); _dyncpy(g_spec_fnode, g_spec_cap*8, n6); g_spec_fnode = n6; - n7 := alloc(sz); _dyncpy(g_spec_status, g_spec_cap*8, n7); g_spec_status = n7; - n2 := alloc(sz); _dyncpy(g_spec_kind, g_spec_cap*8, n2); g_spec_kind = n2; - n3 := alloc(sz); _dyncpy(g_spec_expr, g_spec_cap*8, n3); g_spec_expr = n3; - n4 := alloc(sz); _dyncpy(g_spec_line, g_spec_cap*8, n4); g_spec_line = n4; - n5 := alloc(sz); _dyncpy(g_spec_col, g_spec_cap*8, n5); g_spec_col = n5; - g_spec_cap = nc; } +fn grow_spec_side(needed: int): + if needed < g_spec_cap: + return + nc : ., mut = g_spec_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_spec_fn, g_spec_cap*8, n1) + g_spec_fn = n1 + n6 := alloc(sz) + _dyncpy(g_spec_fnode, g_spec_cap*8, n6) + g_spec_fnode = n6 + n7 := alloc(sz) + _dyncpy(g_spec_status, g_spec_cap*8, n7) + g_spec_status = n7 + n2 := alloc(sz) + _dyncpy(g_spec_kind, g_spec_cap*8, n2) + g_spec_kind = n2 + n3 := alloc(sz) + _dyncpy(g_spec_expr, g_spec_cap*8, n3) + g_spec_expr = n3 + n4 := alloc(sz) + _dyncpy(g_spec_line, g_spec_cap*8, n4) + g_spec_line = n4 + n5 := alloc(sz) + _dyncpy(g_spec_col, g_spec_cap*8, n5) + g_spec_col = n5 + g_spec_cap = nc // 追加一条标注记录(**唯一写点**;源序 ⇒ 索引即源序)。 -fn spec_add(fn_ni: int, kind: int, expr: int, line: int, col: int) { - grow_spec_side(g_spec_count + 1); - i := g_spec_count; - w64(g_spec_fn, i * 8, fn_ni); - w64(g_spec_fnode, i * 8, -1); // 由 parser 在 EXPR_FN 分配后回填(spec_set_fnode) - w64(g_spec_status, i * 8, SPEC_ST_YELLOW); - w64(g_spec_kind, i * 8, kind); - w64(g_spec_expr, i * 8, expr); - w64(g_spec_line, i * 8, line); - w64(g_spec_col, i * 8, col); - g_spec_count = i + 1; -} +fn spec_add(fn_ni: int, kind: int, expr: int, line: int, col: int): + grow_spec_side(g_spec_count + 1) + i := g_spec_count + w64(g_spec_fn, i * 8, fn_ni) + w64(g_spec_fnode, i * 8, -1) // 由 parser 在 EXPR_FN 分配后回填(spec_set_fnode) + w64(g_spec_status, i * 8, SPEC_ST_YELLOW) + w64(g_spec_kind, i * 8, kind) + w64(g_spec_expr, i * 8, expr) + w64(g_spec_line, i * 8, line) + w64(g_spec_col, i * 8, col) + g_spec_count = i + 1 // 读访问器(**受护**:越界回哨兵,绝不读邻记录——照 fi_param_type 的护栏体例)。 -fn spec_fn(i: int) -> int { if i < 0 || i >= g_spec_count { return -1; } return r64(g_spec_fn, i * 8); } -fn spec_fnode(i: int) -> int { if i < 0 || i >= g_spec_count { return -1; } return r64(g_spec_fnode, i * 8); } -fn spec_status(i: int) -> int { if i < 0 || i >= g_spec_count { return -1; } return r64(g_spec_status, i * 8); } +fn spec_fn(i: int) -> int: + if i < 0 || i >= g_spec_count: + return -1 + return r64(g_spec_fn, i * 8) +fn spec_fnode(i: int) -> int: + if i < 0 || i >= g_spec_count: + return -1 + return r64(g_spec_fnode, i * 8) +fn spec_status(i: int) -> int: + if i < 0 || i >= g_spec_count: + return -1 + return r64(g_spec_status, i * 8) // 三态写入:**red 粘性**(已判红不被后续 green 覆盖——否则「有硬错」会被「常量真」抹掉)。 -fn spec_set_status(i: int, st: int) { - if i < 0 || i >= g_spec_count { return; } - cur := r64(g_spec_status, i * 8); - if cur == SPEC_ST_RED { return; } - w64(g_spec_status, i * 8, st); -} -fn spec_set_fnode(i: int, v: int) { if i < 0 || i >= g_spec_count { return; } w64(g_spec_fnode, i * 8, v); } -fn spec_kind(i: int) -> int { if i < 0 || i >= g_spec_count { return -1; } return r64(g_spec_kind, i * 8); } -fn spec_expr(i: int) -> int { if i < 0 || i >= g_spec_count { return -1; } return r64(g_spec_expr, i * 8); } -fn spec_line(i: int) -> int { if i < 0 || i >= g_spec_count { return -1; } return r64(g_spec_line, i * 8); } -fn spec_col(i: int) -> int { if i < 0 || i >= g_spec_count { return -1; } return r64(g_spec_col, i * 8); } - -fn grow_ext_rel(needed: int) { - if needed < g_x86_ext_rel_cap { return; } - nc : ., mut = g_x86_ext_rel_cap * 2; if nc < 32 { nc = 32; } if nc < needed { nc = needed + 32; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_x86_ext_rel_pos, g_x86_ext_rel_cap*8, n1); g_x86_ext_rel_pos = n1; - n2 := alloc(sz); _dyncpy(g_x86_ext_rel_name, g_x86_ext_rel_cap*8, n2); g_x86_ext_rel_name = n2; - g_x86_ext_rel_cap = nc; } - -fn grow_func_offsets(needed: int) { - if needed < g_x86_func_offsets_cap { return; } - nc : ., mut = g_x86_func_offsets_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 16); _dyncpy(g_x86_func_offsets, g_x86_func_offsets_cap * 16, nb); - g_x86_func_offsets = nb; g_x86_func_offsets_cap = nc; } - -fn grow_emit_vars(needed: int) { - if needed < g_x86_emit_vars_cap { return; } - nc : ., mut = g_x86_emit_vars_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); _dyncpy(g_x86_emit_vars, g_x86_emit_vars_cap * 8, nb); - g_x86_emit_vars = nb; g_x86_emit_vars_cap = nc; } - -fn grow_pending(needed: int) { - if needed < g_pending_cap { return; } - nc : ., mut = g_pending_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_pending_pos, g_pending_cap * 8, nb); - g_pending_pos = nb; - nb2 := alloc(nc * 8); _dyncpy(g_pending_label, g_pending_cap * 8, nb2); - g_pending_label = nb2; g_pending_cap = nc; } -fn grow_ret_patch(needed: int) { - if needed < g_x86_ret_patch_cap { return; } - nc : ., mut = g_x86_ret_patch_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_x86_ret_patch_pos, g_x86_ret_patch_cap * 8, nb); - g_x86_ret_patch_pos = nb; g_x86_ret_patch_cap = nc; } -fn grow_call_patch(needed: int) { - if needed < g_x86_call_patch_cap { return; } - nc : ., mut = g_x86_call_patch_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - n1 := alloc(nc * 8); _dyncpy(g_x86_call_patch_pos, g_x86_call_patch_cap * 8, n1); g_x86_call_patch_pos = n1; - n2 := alloc(nc * 8); _dyncpy(g_x86_call_patch_name, g_x86_call_patch_cap * 8, n2); g_x86_call_patch_name = n2; - g_x86_call_patch_cap = nc; } -fn grow_fnaddr_patch(needed: int) { - if needed < g_x86_fnaddr_patch_cap { return; } - nc : ., mut = g_x86_fnaddr_patch_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - n1 := alloc(nc * 8); _dyncpy(g_x86_fnaddr_patch_pos, g_x86_fnaddr_patch_cap * 8, n1); g_x86_fnaddr_patch_pos = n1; - n2 := alloc(nc * 8); _dyncpy(g_x86_fnaddr_patch_name, g_x86_fnaddr_patch_cap * 8, n2); g_x86_fnaddr_patch_name = n2; - g_x86_fnaddr_patch_cap = nc; } - -fn grow_func_cp(needed: int) { - if needed < g_x86_func_cp_cap { return; } - nc : ., mut = g_x86_func_cp_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_x86_func_cp, g_x86_func_cp_cap * 8, nb); - g_x86_func_cp = nb; g_x86_func_cp_cap = nc; } - -fn grow_mw_tag_off(needed: int) { - if needed < g_x86_mw_tag_off_cap { return; } - nc : ., mut = g_x86_mw_tag_off_cap * 2; if nc < 128 { nc = 128; } if nc < needed { nc = needed + 128; } - nb := alloc(nc * 8); _dyncpy(g_x86_mw_tag_off, g_x86_mw_tag_off_cap * 8, nb); - g_x86_mw_tag_off = nb; g_x86_mw_tag_off_cap = nc; } - -fn grow_mw_jo_patch(needed: int) { - if needed < g_x86_mw_jo_cap { return; } - nc : ., mut = g_x86_mw_jo_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_x86_mw_jo_pos, g_x86_mw_jo_cap * 8, nb); - g_x86_mw_jo_pos = nb; - nb2 := alloc(nc * 8); _dyncpy(g_x86_mw_jo_dest, g_x86_mw_jo_cap * 8, nb2); - g_x86_mw_jo_dest = nb2; - nb3 := alloc(nc * 8); _dyncpy(g_x86_mw_jo_is_sub, g_x86_mw_jo_cap * 8, nb3); - g_x86_mw_jo_is_sub = nb3; - nb4 := alloc(nc * 8); _dyncpy(g_x86_mw_jo_resume, g_x86_mw_jo_cap * 8, nb4); - g_x86_mw_jo_resume = nb4; - g_x86_mw_jo_cap = nc; } - -fn grow_mw_oc_patch(needed: int) { - if needed < g_x86_mw_oc_cap { return; } - nc : ., mut = g_x86_mw_oc_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_x86_mw_oc_pos1, g_x86_mw_oc_cap * 8, nb); - g_x86_mw_oc_pos1 = nb; - nb2 := alloc(nc * 8); _dyncpy(g_x86_mw_oc_pos2, g_x86_mw_oc_cap * 8, nb2); - g_x86_mw_oc_pos2 = nb2; - nb3 := alloc(nc * 8); _dyncpy(g_x86_mw_oc_s1, g_x86_mw_oc_cap * 8, nb3); - g_x86_mw_oc_s1 = nb3; - nb4 := alloc(nc * 8); _dyncpy(g_x86_mw_oc_s2, g_x86_mw_oc_cap * 8, nb4); - g_x86_mw_oc_s2 = nb4; - nb5 := alloc(nc * 8); _dyncpy(g_x86_mw_oc_dest, g_x86_mw_oc_cap * 8, nb5); - g_x86_mw_oc_dest = nb5; - nb6 := alloc(nc * 8); _dyncpy(g_x86_mw_oc_op, g_x86_mw_oc_cap * 8, nb6); - g_x86_mw_oc_op = nb6; - nb7 := alloc(nc * 8); _dyncpy(g_x86_mw_oc_resume, g_x86_mw_oc_cap * 8, nb7); - g_x86_mw_oc_resume = nb7; - g_x86_mw_oc_cap = nc; } - -fn grow_opt_meta(needed: int) { - if needed <= g_opt_meta_cap { return; } - nc : ., mut = g_opt_meta_cap * 2; - if nc < 16 { nc = 16; } - if nc < needed { nc = needed + 16; } - nb := alloc(nc * OPT_META_STRIDE); - _dyncpy(g_opt_meta, g_opt_meta_count * OPT_META_STRIDE, nb); - g_opt_meta = nb; g_opt_meta_cap = nc; -} -fn grow_func_code_sz(needed: int) { - if needed < g_x86_func_code_sz_cap { return; } - nc : ., mut = g_x86_func_code_sz_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_x86_func_code_sz, g_x86_func_code_sz_cap * 8, nb); - g_x86_func_code_sz = nb; g_x86_func_code_sz_cap = nc; } - -fn grow_rodataref(needed: int) { - if needed < g_x86_rodataref_cap { return; } - nc : ., mut = g_x86_rodataref_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - n1 := alloc(nc * 8); _dyncpy(g_x86_rodataref_pos, g_x86_rodataref_cap * 8, n1); g_x86_rodataref_pos = n1; - n2 := alloc(nc * 8); _dyncpy(g_x86_rodataref_ro, g_x86_rodataref_cap * 8, n2); g_x86_rodataref_ro = n2; - g_x86_rodataref_cap = nc; } - -fn grow_alloc_patch(needed: int) { - if needed < g_x86_alloc_patch_cap { return; } - nc : ., mut = g_x86_alloc_patch_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_x86_alloc_patch_pos, g_x86_alloc_patch_cap * 8, nb); - g_x86_alloc_patch_pos = nb; g_x86_alloc_patch_cap = nc; } - -fn grow_ir_local_scopes(needed: int) { - if needed < g_ir_local_scopes_cap { return; } - nc : ., mut = g_ir_local_scopes_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_ir_local_scopes, g_ir_local_scopes_cap * 8, nb); - g_ir_local_scopes = nb; g_ir_local_scopes_cap = nc; } - -fn grow_ir_loop_stacks(needed: int) { - if needed < g_ir_loop_stacks_cap { return; } - nc : ., mut = g_ir_loop_stacks_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - n1 := alloc(nc * 8); _dyncpy(g_ir_loop_header, g_ir_loop_stacks_cap * 8, n1); g_ir_loop_header = n1; - n2 := alloc(nc * 8); _dyncpy(g_ir_loop_exit, g_ir_loop_stacks_cap * 8, n2); g_ir_loop_exit = n2; - g_ir_loop_stacks_cap = nc; } - -fn grow_label_poses(needed: int) { - if needed < g_label_cap { return; } - nc : ., mut = g_label_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_label_poses, g_label_cap * 8, nb); - g_label_poses = nb; g_label_cap = nc; } +fn spec_set_status(i: int, st: int): + if i < 0 || i >= g_spec_count: + return + cur := r64(g_spec_status, i * 8) + if cur == SPEC_ST_RED: + return + w64(g_spec_status, i * 8, st) +fn spec_set_fnode(i: int, v: int): + if i < 0 || i >= g_spec_count: + return + w64(g_spec_fnode, i * 8, v) +fn spec_kind(i: int) -> int: + if i < 0 || i >= g_spec_count: + return -1 + return r64(g_spec_kind, i * 8) +fn spec_expr(i: int) -> int: + if i < 0 || i >= g_spec_count: + return -1 + return r64(g_spec_expr, i * 8) +fn spec_line(i: int) -> int: + if i < 0 || i >= g_spec_count: + return -1 + return r64(g_spec_line, i * 8) +fn spec_col(i: int) -> int: + if i < 0 || i >= g_spec_count: + return -1 + return r64(g_spec_col, i * 8) + +fn grow_ext_rel(needed: int): + if needed < g_x86_ext_rel_cap: + return + nc : ., mut = g_x86_ext_rel_cap * 2 + if nc < 32: + nc = 32 + if nc < needed: + nc = needed + 32 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_x86_ext_rel_pos, g_x86_ext_rel_cap*8, n1) + g_x86_ext_rel_pos = n1 + n2 := alloc(sz) + _dyncpy(g_x86_ext_rel_name, g_x86_ext_rel_cap*8, n2) + g_x86_ext_rel_name = n2 + g_x86_ext_rel_cap = nc + +fn grow_func_offsets(needed: int): + if needed < g_x86_func_offsets_cap: + return + nc : ., mut = g_x86_func_offsets_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 16) + _dyncpy(g_x86_func_offsets, g_x86_func_offsets_cap * 16, nb) + g_x86_func_offsets = nb + g_x86_func_offsets_cap = nc + +fn grow_emit_vars(needed: int): + if needed < g_x86_emit_vars_cap: + return + nc : ., mut = g_x86_emit_vars_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_x86_emit_vars, g_x86_emit_vars_cap * 8, nb) + g_x86_emit_vars = nb + g_x86_emit_vars_cap = nc + +fn grow_pending(needed: int): + if needed < g_pending_cap: + return + nc : ., mut = g_pending_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_pending_pos, g_pending_cap * 8, nb) + g_pending_pos = nb + nb2 := alloc(nc * 8) + _dyncpy(g_pending_label, g_pending_cap * 8, nb2) + g_pending_label = nb2 + g_pending_cap = nc +fn grow_ret_patch(needed: int): + if needed < g_x86_ret_patch_cap: + return + nc : ., mut = g_x86_ret_patch_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_x86_ret_patch_pos, g_x86_ret_patch_cap * 8, nb) + g_x86_ret_patch_pos = nb + g_x86_ret_patch_cap = nc +fn grow_call_patch(needed: int): + if needed < g_x86_call_patch_cap: + return + nc : ., mut = g_x86_call_patch_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + n1 := alloc(nc * 8) + _dyncpy(g_x86_call_patch_pos, g_x86_call_patch_cap * 8, n1) + g_x86_call_patch_pos = n1 + n2 := alloc(nc * 8) + _dyncpy(g_x86_call_patch_name, g_x86_call_patch_cap * 8, n2) + g_x86_call_patch_name = n2 + g_x86_call_patch_cap = nc +fn grow_fnaddr_patch(needed: int): + if needed < g_x86_fnaddr_patch_cap: + return + nc : ., mut = g_x86_fnaddr_patch_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + n1 := alloc(nc * 8) + _dyncpy(g_x86_fnaddr_patch_pos, g_x86_fnaddr_patch_cap * 8, n1) + g_x86_fnaddr_patch_pos = n1 + n2 := alloc(nc * 8) + _dyncpy(g_x86_fnaddr_patch_name, g_x86_fnaddr_patch_cap * 8, n2) + g_x86_fnaddr_patch_name = n2 + g_x86_fnaddr_patch_cap = nc + +fn grow_func_cp(needed: int): + if needed < g_x86_func_cp_cap: + return + nc : ., mut = g_x86_func_cp_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_x86_func_cp, g_x86_func_cp_cap * 8, nb) + g_x86_func_cp = nb + g_x86_func_cp_cap = nc + +fn grow_mw_tag_off(needed: int): + if needed < g_x86_mw_tag_off_cap: + return + nc : ., mut = g_x86_mw_tag_off_cap * 2 + if nc < 128: + nc = 128 + if nc < needed: + nc = needed + 128 + nb := alloc(nc * 8) + _dyncpy(g_x86_mw_tag_off, g_x86_mw_tag_off_cap * 8, nb) + g_x86_mw_tag_off = nb + g_x86_mw_tag_off_cap = nc + +fn grow_mw_jo_patch(needed: int): + if needed < g_x86_mw_jo_cap: + return + nc : ., mut = g_x86_mw_jo_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_x86_mw_jo_pos, g_x86_mw_jo_cap * 8, nb) + g_x86_mw_jo_pos = nb + nb2 := alloc(nc * 8) + _dyncpy(g_x86_mw_jo_dest, g_x86_mw_jo_cap * 8, nb2) + g_x86_mw_jo_dest = nb2 + nb3 := alloc(nc * 8) + _dyncpy(g_x86_mw_jo_is_sub, g_x86_mw_jo_cap * 8, nb3) + g_x86_mw_jo_is_sub = nb3 + nb4 := alloc(nc * 8) + _dyncpy(g_x86_mw_jo_resume, g_x86_mw_jo_cap * 8, nb4) + g_x86_mw_jo_resume = nb4 + g_x86_mw_jo_cap = nc + +fn grow_mw_oc_patch(needed: int): + if needed < g_x86_mw_oc_cap: + return + nc : ., mut = g_x86_mw_oc_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_x86_mw_oc_pos1, g_x86_mw_oc_cap * 8, nb) + g_x86_mw_oc_pos1 = nb + nb2 := alloc(nc * 8) + _dyncpy(g_x86_mw_oc_pos2, g_x86_mw_oc_cap * 8, nb2) + g_x86_mw_oc_pos2 = nb2 + nb3 := alloc(nc * 8) + _dyncpy(g_x86_mw_oc_s1, g_x86_mw_oc_cap * 8, nb3) + g_x86_mw_oc_s1 = nb3 + nb4 := alloc(nc * 8) + _dyncpy(g_x86_mw_oc_s2, g_x86_mw_oc_cap * 8, nb4) + g_x86_mw_oc_s2 = nb4 + nb5 := alloc(nc * 8) + _dyncpy(g_x86_mw_oc_dest, g_x86_mw_oc_cap * 8, nb5) + g_x86_mw_oc_dest = nb5 + nb6 := alloc(nc * 8) + _dyncpy(g_x86_mw_oc_op, g_x86_mw_oc_cap * 8, nb6) + g_x86_mw_oc_op = nb6 + nb7 := alloc(nc * 8) + _dyncpy(g_x86_mw_oc_resume, g_x86_mw_oc_cap * 8, nb7) + g_x86_mw_oc_resume = nb7 + g_x86_mw_oc_cap = nc + +fn grow_opt_meta(needed: int): + if needed <= g_opt_meta_cap: + return + nc : ., mut = g_opt_meta_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * OPT_META_STRIDE) + _dyncpy(g_opt_meta, g_opt_meta_count * OPT_META_STRIDE, nb) + g_opt_meta = nb + g_opt_meta_cap = nc +fn grow_func_code_sz(needed: int): + if needed < g_x86_func_code_sz_cap: + return + nc : ., mut = g_x86_func_code_sz_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_x86_func_code_sz, g_x86_func_code_sz_cap * 8, nb) + g_x86_func_code_sz = nb + g_x86_func_code_sz_cap = nc + +fn grow_rodataref(needed: int): + if needed < g_x86_rodataref_cap: + return + nc : ., mut = g_x86_rodataref_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + n1 := alloc(nc * 8) + _dyncpy(g_x86_rodataref_pos, g_x86_rodataref_cap * 8, n1) + g_x86_rodataref_pos = n1 + n2 := alloc(nc * 8) + _dyncpy(g_x86_rodataref_ro, g_x86_rodataref_cap * 8, n2) + g_x86_rodataref_ro = n2 + g_x86_rodataref_cap = nc + +fn grow_alloc_patch(needed: int): + if needed < g_x86_alloc_patch_cap: + return + nc : ., mut = g_x86_alloc_patch_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_x86_alloc_patch_pos, g_x86_alloc_patch_cap * 8, nb) + g_x86_alloc_patch_pos = nb + g_x86_alloc_patch_cap = nc + +fn grow_ir_local_scopes(needed: int): + if needed < g_ir_local_scopes_cap: + return + nc : ., mut = g_ir_local_scopes_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_ir_local_scopes, g_ir_local_scopes_cap * 8, nb) + g_ir_local_scopes = nb + g_ir_local_scopes_cap = nc + +fn grow_ir_loop_stacks(needed: int): + if needed < g_ir_loop_stacks_cap: + return + nc : ., mut = g_ir_loop_stacks_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + n1 := alloc(nc * 8) + _dyncpy(g_ir_loop_header, g_ir_loop_stacks_cap * 8, n1) + g_ir_loop_header = n1 + n2 := alloc(nc * 8) + _dyncpy(g_ir_loop_exit, g_ir_loop_stacks_cap * 8, n2) + g_ir_loop_exit = n2 + g_ir_loop_stacks_cap = nc + +fn grow_label_poses(needed: int): + if needed < g_label_cap: + return + nc : ., mut = g_label_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_label_poses, g_label_cap * 8, nb) + g_label_poses = nb + g_label_cap = nc // ============================================================ // Grow functions for newly-converted arrays // ============================================================ // Diag struct: code(8) + msg(8) + line(8) + col(8) + file_id(8) = 40 bytes -fn grow_diags(needed: int) { - if needed < g_diag_cap { return; } - nc : ., mut = g_diag_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * DIAG_REC_SIZE); _dyncpy(g_diags, g_diag_cap * DIAG_REC_SIZE, nb); - g_diags = nb; g_diag_cap = nc; } +fn grow_diags(needed: int): + if needed < g_diag_cap: + return + nc : ., mut = g_diag_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * DIAG_REC_SIZE) + _dyncpy(g_diags, g_diag_cap * DIAG_REC_SIZE, nb) + g_diags = nb + g_diag_cap = nc // FileEntry: fileid_ni(8) + path(8) = 16 bytes -fn grow_files(needed: int) { - if needed < g_file_cap { return; } - nc : ., mut = g_file_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * 16); _dyncpy(g_files, g_file_cap * 16, nb); - g_files = nb; g_file_cap = nc; } +fn grow_files(needed: int): + if needed < g_file_cap: + return + nc : ., mut = g_file_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * 16) + _dyncpy(g_files, g_file_cap * 16, nb) + g_files = nb + g_file_cap = nc // ModEntry: alias_ni(8) + fileid_ni(8) + path(8) = 24 bytes -fn grow_mods(needed: int) { - if needed < g_mod_cap { return; } - nc : ., mut = g_mod_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * 24); _dyncpy(g_mods, g_mod_cap * 24, nb); - g_mods = nb; g_mod_cap = nc; } +fn grow_mods(needed: int): + if needed < g_mod_cap: + return + nc : ., mut = g_mod_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * 24) + _dyncpy(g_mods, g_mod_cap * 24, nb) + g_mods = nb + g_mod_cap = nc // g_mod_func_fileids/names/tis: 3 parallel int arrays, 8 bytes per element each -fn grow_mod_funcs(needed: int) { - if needed < g_mod_func_cap { return; } - nc : ., mut = g_mod_func_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - sz := nc * 8; - n1 := alloc(sz); _dyncpy(g_mod_func_fileids, g_mod_func_cap * 8, n1); g_mod_func_fileids = n1; - n2 := alloc(sz); _dyncpy(g_mod_func_names, g_mod_func_cap * 8, n2); g_mod_func_names = n2; - n3 := alloc(sz); _dyncpy(g_mod_func_tis, g_mod_func_cap * 8, n3); g_mod_func_tis = n3; - g_mod_func_cap = nc; } +fn grow_mod_funcs(needed: int): + if needed < g_mod_func_cap: + return + nc : ., mut = g_mod_func_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + sz := nc * 8 + n1 := alloc(sz) + _dyncpy(g_mod_func_fileids, g_mod_func_cap * 8, n1) + g_mod_func_fileids = n1 + n2 := alloc(sz) + _dyncpy(g_mod_func_names, g_mod_func_cap * 8, n2) + g_mod_func_names = n2 + n3 := alloc(sz) + _dyncpy(g_mod_func_tis, g_mod_func_cap * 8, n3) + g_mod_func_tis = n3 + g_mod_func_cap = nc // g_mod_path_names: int array, 8 bytes per element -fn grow_mod_paths(needed: int) { - if needed < g_mod_path_cap { return; } - nc : ., mut = g_mod_path_cap * 2; if nc < 32 { nc = 32; } if nc < needed { nc = needed + 32; } - nb := alloc(nc * 8); _dyncpy(g_mod_path_names, g_mod_path_cap * 8, nb); - g_mod_path_names = nb; g_mod_path_cap = nc; } +fn grow_mod_paths(needed: int): + if needed < g_mod_path_cap: + return + nc : ., mut = g_mod_path_cap * 2 + if nc < 32: + nc = 32 + if nc < needed: + nc = needed + 32 + nb := alloc(nc * 8) + _dyncpy(g_mod_path_names, g_mod_path_cap * 8, nb) + g_mod_path_names = nb + g_mod_path_cap = nc // impl-for: pairs of (interface_ni, type_ni), 16 bytes per pair -fn grow_impl_for(needed: int) { - if needed < g_impl_for_cap { return; } - nc : ., mut = g_impl_for_cap * 2; if nc < 8 { nc = 8; } if nc < needed { nc = needed + 8; } - nb := alloc(nc * 16); _dyncpy(g_impl_for, g_impl_for_cap * 16, nb); - g_impl_for = nb; g_impl_for_cap = nc; } +fn grow_impl_for(needed: int): + if needed < g_impl_for_cap: + return + nc : ., mut = g_impl_for_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 8 + nb := alloc(nc * 16) + _dyncpy(g_impl_for, g_impl_for_cap * 16, nb) + g_impl_for = nb + g_impl_for_cap = nc // Generic param name storage (for syntax parsing) -fn grow_gen_params(needed: int) { - if needed < g_gen_param_cap { return; } - nc : ., mut = g_gen_param_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * 8); _dyncpy(g_gen_params, g_gen_param_cap * 8, nb); - g_gen_params = nb; g_gen_param_cap = nc; } +fn grow_gen_params(needed: int): + if needed < g_gen_param_cap: + return + nc : ., mut = g_gen_param_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * 8) + _dyncpy(g_gen_params, g_gen_param_cap * 8, nb) + g_gen_params = nb + g_gen_param_cap = nc // Generic constraints: for each (func_idx * MAX_GENERICS + param_idx), stores iface_ni or -1 -fn grow_gen_constr(needed: int) { - if needed < g_generic_constr_cap { return; } - nc : ., mut = g_generic_constr_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * 8); _dyncpy(g_generic_constr, g_generic_constr_cap * 8, nb); - g_generic_constr = nb; g_generic_constr_cap = nc; } +fn grow_gen_constr(needed: int): + if needed < g_generic_constr_cap: + return + nc : ., mut = g_generic_constr_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * 8) + _dyncpy(g_generic_constr, g_generic_constr_cap * 8, nb) + g_generic_constr = nb + g_generic_constr_cap = nc // R2 P3 Task 5:结构/枚举泛型约束侧表(键 = row * MAX_GENERICS + gi;索引空间与函数侧分家, // 见 globals.cr 表注)。增长式样逐字照 grow_gen_constr(同族第三/第四份,语义同构)。 -fn grow_sgen_constr(needed: int) { - if needed < g_sgen_constr_cap { return; } - nc : ., mut = g_sgen_constr_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * 8); _dyncpy(g_sgen_constr, g_sgen_constr_cap * 8, nb); - g_sgen_constr = nb; g_sgen_constr_cap = nc; } - -fn grow_egen_constr(needed: int) { - if needed < g_egen_constr_cap { return; } - nc : ., mut = g_egen_constr_cap * 2; if nc < 16 { nc = 16; } if nc < needed { nc = needed + 16; } - nb := alloc(nc * 8); _dyncpy(g_egen_constr, g_egen_constr_cap * 8, nb); - g_egen_constr = nb; g_egen_constr_cap = nc; } +fn grow_sgen_constr(needed: int): + if needed < g_sgen_constr_cap: + return + nc : ., mut = g_sgen_constr_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * 8) + _dyncpy(g_sgen_constr, g_sgen_constr_cap * 8, nb) + g_sgen_constr = nb + g_sgen_constr_cap = nc + +fn grow_egen_constr(needed: int): + if needed < g_egen_constr_cap: + return + nc : ., mut = g_egen_constr_cap * 2 + if nc < 16: + nc = 16 + if nc < needed: + nc = needed + 16 + nb := alloc(nc * 8) + _dyncpy(g_egen_constr, g_egen_constr_cap * 8, nb) + g_egen_constr = nb + g_egen_constr_cap = nc // R2 P3 Task 5(Step 4):调用点绑定侧表增长(i64 顺序追加,无洞——与上面两张稀疏表不同) -fn grow_gen_binds(needed: int) { - if needed < g_gen_binds_cap { return; } - nc : ., mut = g_gen_binds_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_gen_binds, g_gen_binds_cap * 8, nb); - g_gen_binds = nb; g_gen_binds_cap = nc; } +fn grow_gen_binds(needed: int): + if needed < g_gen_binds_cap: + return + nc : ., mut = g_gen_binds_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_gen_binds, g_gen_binds_cap * 8, nb) + g_gen_binds = nb + g_gen_binds_cap = nc // 结构/枚举第 gi 个泛型形参的约束名 ni(-1 = 无约束/越界)。读取面护栏(照 SI 访问器惯例: // 越界不越读——gi 上限 MAX_GENERICS、行下标上限计数)。 -fn si_gen_constr(n: int, gi: int) -> int { - if n < 0 || gi < 0 || gi >= MAX_GENERICS { return -1; } - idx := n * MAX_GENERICS + gi; - if idx >= g_sgen_constr_count { return -1; } - return r64(g_sgen_constr, idx * 8); } - -fn ei_gen_constr(n: int, gi: int) -> int { - if n < 0 || gi < 0 || gi >= MAX_GENERICS { return -1; } - idx := n * MAX_GENERICS + gi; - if idx >= g_egen_constr_count { return -1; } - return r64(g_egen_constr, idx * 8); } - -fn grow_sg(n: int) { - if n < g_sg_cap { return; } - nc := g_sg_cap; - if nc == 0 { nc = 16; } - loop { if nc > n { break; } nc = nc * 2; } - nb := alloc(nc * ESZ_SG); - if g_sg_cap > 0 { _dyncpy(g_sgs, g_sg_cap * ESZ_SG, nb); } - g_sgs = nb; - g_sg_cap = nc; } - -fn grow_pts(n: int) { - if n < g_pts_cap { return; } - nc := g_pts_cap; - if nc == 0 { nc = 16; } - loop { if nc > n { break; } nc = nc * 2; } - nb := alloc(nc * 8); - if g_pts_cap > 0 { _dyncpy(g_pts, g_pts_cap * 8, nb); } - g_pts = nb; g_pts_cap = nc; } - -fn grow_offsets(n: int) { - if n < g_offsets_cap { return; } - nc := g_offsets_cap; - if nc == 0 { nc = 16; } - loop { if nc > n { break; } nc = nc * 2; } - nb := alloc(nc * 8); - if g_offsets_cap > 0 { _dyncpy(g_offsets, g_offsets_cap * 8, nb); } - g_offsets = nb; g_offsets_cap = nc; } +fn si_gen_constr(n: int, gi: int) -> int: + if n < 0 || gi < 0 || gi >= MAX_GENERICS: + return -1 + idx := n * MAX_GENERICS + gi + if idx >= g_sgen_constr_count: + return -1 + return r64(g_sgen_constr, idx * 8) + +fn ei_gen_constr(n: int, gi: int) -> int: + if n < 0 || gi < 0 || gi >= MAX_GENERICS: + return -1 + idx := n * MAX_GENERICS + gi + if idx >= g_egen_constr_count: + return -1 + return r64(g_egen_constr, idx * 8) + +fn grow_sg(n: int): + if n < g_sg_cap: + return + nc := g_sg_cap + if nc == 0: + nc = 16 + loop: + if nc > n: + break + nc = nc * 2 + nb := alloc(nc * ESZ_SG) + if g_sg_cap > 0: + _dyncpy(g_sgs, g_sg_cap * ESZ_SG, nb) + g_sgs = nb + g_sg_cap = nc + +fn grow_pts(n: int): + if n < g_pts_cap: + return + nc := g_pts_cap + if nc == 0: + nc = 16 + loop: + if nc > n: + break + nc = nc * 2 + nb := alloc(nc * 8) + if g_pts_cap > 0: + _dyncpy(g_pts, g_pts_cap * 8, nb) + g_pts = nb + g_pts_cap = nc + +fn grow_offsets(n: int): + if n < g_offsets_cap: + return + nc := g_offsets_cap + if nc == 0: + nc = 16 + loop: + if nc > n: + break + nc = nc * 2 + nb := alloc(nc * 8) + if g_offsets_cap > 0: + _dyncpy(g_offsets, g_offsets_cap * 8, nb) + g_offsets = nb + g_offsets_cap = nc diff --git a/src/compiler/entry.cr b/src/compiler/entry.cr index 37525902..1d1ac8fe 100644 --- a/src/compiler/entry.cr +++ b/src/compiler/entry.cr @@ -1,2 +1,3 @@ // Project-mode entry point -fn main() -> int { return compiler_main(); } +fn main() -> int: + return compiler_main() diff --git a/src/compiler/ext_mgr.cr b/src/compiler/ext_mgr.cr index ad63316b..327c290d 100644 --- a/src/compiler/ext_mgr.cr +++ b/src/compiler/ext_mgr.cr @@ -13,85 +13,95 @@ // 插件 ID(在 ext_plugins.cr 中定义): // EXT_PLUGIN_SAFETY = 1 — 安全检查插件 -g_ext_flags : int, mut = 0; -g_ext_inited : int, mut = 0; +g_ext_flags : int, mut = 0 +g_ext_inited : int, mut = 0 // 插件注册表:[hook_type, plugin_id] pairs, flat array -g_ext_reg : string, mut; g_ext_reg_count : int, mut; g_ext_reg_cap : int, mut; +g_ext_reg : string, mut +g_ext_reg_count : int, mut +g_ext_reg_cap : int, mut // 钩子类型 -EXT_HOOK_ARRAY_ACCESS : int = 1; // 数组访问前 -EXT_HOOK_BINARY_OP : int = 2; // 二元运算后 +EXT_HOOK_ARRAY_ACCESS : int = 1 // 数组访问前 +EXT_HOOK_BINARY_OP : int = 2 // 二元运算后 -fn grow_ext_reg(needed: int) { - if needed < g_ext_reg_cap { return; } - ncap : ., mut = g_ext_reg_cap * 2; if ncap < 8 { ncap = 8; } if ncap < needed { ncap = needed + 8; } +fn grow_ext_reg(needed: int): + if needed < g_ext_reg_cap: + return + ncap : ., mut = g_ext_reg_cap * 2 + if ncap < 8: + ncap = 8 + if ncap < needed: + ncap = needed + 8 // 记录 = [hook_type(8), plugin_id(8)] 共 16 字节——修复 F1:原代码按 8 字节 // 扩容/拷贝,且 ext_reg 把 plugin_id 写到 +4(与 hook_type 重叠)→ 注册表 // 恒损坏 → dispatch 永远匹配不到插件 → 越界守卫从不触发。 - nb := alloc(ncap * 16); _dyncpy(g_ext_reg, g_ext_reg_cap * 16, nb); g_ext_reg = nb; g_ext_reg_cap = ncap; -} + nb := alloc(ncap * 16) + _dyncpy(g_ext_reg, g_ext_reg_cap * 16, nb) + g_ext_reg = nb + g_ext_reg_cap = ncap -fn ext_init() { - if g_ext_inited != 0 { return; } - g_ext_inited = 1; - g_ext_reg_cap = 0; g_ext_reg_count = 0; +fn ext_init(): + if g_ext_inited != 0: + return + g_ext_inited = 1 + g_ext_reg_cap = 0 + g_ext_reg_count = 0 // 环境变量控制:边界检查是 Core 的安全契约,默认开启。 // CORE_SAFE=0 显式关闭(仅 unsafe 调试场景);CORE_SAFE=1 保持显式开启兼容。 - ev := get_env("CORE_SAFE"); - if str_len(ev) > 0 && ev == "0" { g_ext_flags = 0; } else { g_ext_flags = 1; } + ev := get_env("CORE_SAFE") + if str_len(ev) > 0 && ev == "0": + g_ext_flags = 0 + else: + g_ext_flags = 1 // 内置插件初始化(未来从 .so 加载) - ext_safety_init(); -} + ext_safety_init() -fn ext_has(flag: int) -> int { - if g_ext_inited == 0 { ext_init(); } - return g_ext_flags; -} +fn ext_has(flag: int) -> int: + if g_ext_inited == 0: + ext_init() + return g_ext_flags // 注册一个插件到指定钩子 -fn ext_reg(hook_type: int, plugin_id: int) { - grow_ext_reg(g_ext_reg_count + 1); - w64(g_ext_reg, g_ext_reg_count * 16, hook_type); - w64(g_ext_reg, g_ext_reg_count * 16 + 8, plugin_id); - g_ext_reg_count = g_ext_reg_count + 1; -} +fn ext_reg(hook_type: int, plugin_id: int): + grow_ext_reg(g_ext_reg_count + 1) + w64(g_ext_reg, g_ext_reg_count * 16, hook_type) + w64(g_ext_reg, g_ext_reg_count * 16 + 8, plugin_id) + g_ext_reg_count = g_ext_reg_count + 1 // 分发钩子 — 遍历注册表,调所有匹配的插件 // arr_var / idx_var / idx_lit / arr_len_lit: 数组访问参数 // 返回: 0=继续, 1=跳过此次访问 -fn ext_dispatch_array_access(arr_var: int, idx_var: int, idx_lit: int, arr_len_lit: int) -> int { - if g_ext_inited == 0 { ext_init(); } - ri : ., mut = 0; - loop { - if ri >= g_ext_reg_count { break; } - ht := r64(g_ext_reg, ri * 16); - pid := r64(g_ext_reg, ri * 16 + 8); - if ht == EXT_HOOK_ARRAY_ACCESS { - if pid == 1 { // EXT_PLUGIN_SAFETY - r := ext_safety_on_array_access(arr_var, idx_var, idx_lit, arr_len_lit); - if r != 0 { return r; } - } - } - ri = ri + 1; - } - return 0; -} +fn ext_dispatch_array_access(arr_var: int, idx_var: int, idx_lit: int, arr_len_lit: int) -> int: + if g_ext_inited == 0: + ext_init() + ri : ., mut = 0 + loop: + if ri >= g_ext_reg_count: + break + ht := r64(g_ext_reg, ri * 16) + pid := r64(g_ext_reg, ri * 16 + 8) + if ht == EXT_HOOK_ARRAY_ACCESS: + if pid == 1: + // EXT_PLUGIN_SAFETY + r := ext_safety_on_array_access(arr_var, idx_var, idx_lit, arr_len_lit) + if r != 0: + return r + ri = ri + 1 + return 0 // 分发二元运算钩子 -fn ext_dispatch_binary_op(op: int, lv: int, rv: int, result_var: int) -> int { - if g_ext_inited == 0 { ext_init(); } - ri : ., mut = 0; - loop { - if ri >= g_ext_reg_count { break; } - ht := r64(g_ext_reg, ri * 16); - pid := r64(g_ext_reg, ri * 16 + 8); - if ht == EXT_HOOK_BINARY_OP { - if pid == 1 { - return ext_safety_on_binary_op(op, lv, rv, result_var); - } - } - ri = ri + 1; - } - return 0; -} +fn ext_dispatch_binary_op(op: int, lv: int, rv: int, result_var: int) -> int: + if g_ext_inited == 0: + ext_init() + ri : ., mut = 0 + loop: + if ri >= g_ext_reg_count: + break + ht := r64(g_ext_reg, ri * 16) + pid := r64(g_ext_reg, ri * 16 + 8) + if ht == EXT_HOOK_BINARY_OP: + if pid == 1: + return ext_safety_on_binary_op(op, lv, rv, result_var) + ri = ri + 1 + return 0 diff --git a/src/compiler/ext_safety.cr b/src/compiler/ext_safety.cr index aa7edde1..7106e6a6 100644 --- a/src/compiler/ext_safety.cr +++ b/src/compiler/ext_safety.cr @@ -5,38 +5,34 @@ // 钩子触发时 ext_mgr 调用本插件的 handler 函数。 // 插件初始化:注册到钩子 -fn ext_safety_init() { - if ext_has(0) == 0 { return; } // 等 ext_mgr 初始化 - ext_reg(EXT_HOOK_ARRAY_ACCESS, 1); // 监听数组访问 - ext_reg(EXT_HOOK_BINARY_OP, 1); // 监听二元运算 -} +fn ext_safety_init(): + if ext_has(0) == 0: + return + // 等 ext_mgr 初始化 + ext_reg(EXT_HOOK_ARRAY_ACCESS, 1) // 监听数组访问 + ext_reg(EXT_HOOK_BINARY_OP, 1) // 监听二元运算 // === 数组越界检查 handler === // 在 IR_LOAD_INDEX / IR_STORE_INDEX 之前被 ext_mgr 调用。 // idx_lit/arr_len_lit >=0 表示编译期已知的值。 // 返回: 0=继续(编译期越界时发射必陷检查——不可静默跳过,见 F1/F2) -fn ext_safety_on_array_access(arr_var: int, idx_var: int, idx_lit: int, arr_len_lit: int) -> int { +fn ext_safety_on_array_access(arr_var: int, idx_var: int, idx_lit: int, arr_len_lit: int) -> int: // 字面量索引(idx_var < 0 表示传了字面量)+ 字面量长度 → 编译期检查。 // 注意:idx_lit 可为负(arr[-1] 解析为负字面量时)——同样必须拦截。 - if arr_len_lit >= 0 && idx_var < 0 { - if idx_lit < 0 || idx_lit >= arr_len_lit { + if arr_len_lit >= 0 && idx_var < 0: + if idx_lit < 0 || idx_lit >= arr_len_lit: // 编译期越界:发射恒陷检查(IR_CONST + BOUNDS_CHECK)—— // 修复前 return 1 静默跳过访问 → 目标变量未初始化 → 静默错值。 - tmp := new_ir_var("_oob_idx", TI_INT); - emit(IR_CONST, tmp, idx_lit, 0, 0, TI_INT); - emit(IR_BOUNDS_CHECK, -1, tmp, arr_len_lit, 0, 0); - } - return 0; - } + tmp := new_ir_var("_oob_idx", TI_INT) + emit(IR_CONST, tmp, idx_lit, 0, 0, TI_INT) + emit(IR_BOUNDS_CHECK, -1, tmp, arr_len_lit, 0, 0) + return 0 // 变量索引 + 字面量长度 → 插入 IR_BOUNDS_CHECK - if arr_len_lit >= 0 && idx_var >= 0 { - emit(IR_BOUNDS_CHECK, -1, idx_var, arr_len_lit, 0, 0); - return 0; - } - return 0; -} + if arr_len_lit >= 0 && idx_var >= 0: + emit(IR_BOUNDS_CHECK, -1, idx_var, arr_len_lit, 0, 0) + return 0 + return 0 // === 算术溢出检查 handler(预留) === -fn ext_safety_on_binary_op(op: int, lv: int, rv: int, result_var: int) -> int { - return 0; -} +fn ext_safety_on_binary_op(op: int, lv: int, rv: int, result_var: int) -> int: + return 0 diff --git a/src/compiler/globals.cr b/src/compiler/globals.cr index bec4d728..a571880b 100644 --- a/src/compiler/globals.cr +++ b/src/compiler/globals.cr @@ -2,23 +2,38 @@ // ALL arrays are dynamic byte buffers (grow as needed, no MAX_* limits). // String table (dynamic byte buffer containing `string` pointers) -g_strs : string, mut; g_str_count : int, mut; g_str_cap : int, mut; +g_strs : string, mut +g_str_count : int, mut +g_str_cap : int, mut // String interning hash table: maps hash → g_strs index (-1 = empty slot) // Open addressing with linear probing. -g_str_hash : string, mut; g_str_hash_cap : int, mut; +g_str_hash : string, mut +g_str_hash_cap : int, mut // Dynamic byte buffers (all arrays, no MAX_* limits) -g_funcs : string, mut; g_func_count : int, mut; g_func_cap : int, mut; -g_structs : string, mut; g_struct_count : int, mut; g_struct_cap : int, mut; -g_enums : string, mut; g_enum_count : int, mut; g_enum_cap : int, mut; -g_syms : string, mut; g_sym_count : int, mut; g_sym_cap : int, mut; -g_types : string, mut; g_type_count : int, mut; g_type_cap : int, mut; +g_funcs : string, mut +g_func_count : int, mut +g_func_cap : int, mut +g_structs : string, mut +g_struct_count : int, mut +g_struct_cap : int, mut +g_enums : string, mut +g_enum_count : int, mut +g_enum_cap : int, mut +g_syms : string, mut +g_sym_count : int, mut +g_sym_cap : int, mut +g_types : string, mut +g_type_count : int, mut +g_type_cap : int, mut // 类型行表布局单源(R2 P4 Task 2):24B/条 {kind,data,extra}(i64×3)—— // alloc_type(checker.cr)/grow_types(dyn_arr.cr)/TYPE 段序列化与 dump(ccr_io.cr) // 三方共用,改一处即全改(此前为三处字面量 24/8/16 并行)。 -ESZ_TYPE_ROW : int = 24; -OFF_TR_KIND : int = 0; OFF_TR_DATA : int = 8; OFF_TR_EXTRA : int = 16; +ESZ_TYPE_ROW : int = 24 +OFF_TR_KIND : int = 0 +OFF_TR_DATA : int = 8 +OFF_TR_EXTRA : int = 16 // R2 P4 Task 2:TYPE(7) 段体缓冲(D18 解耦——段体**构造**在 corec-only 的 // ccr_types.cr(引用桥接层 sh_term_of_ti:corearch 无此层),本文件只声明载体, @@ -26,11 +41,13 @@ OFF_TR_KIND : int = 0; OFF_TR_DATA : int = 8; OFF_TR_EXTRA : int = 16; // (row_count u32),故段体大小 ≡ 缓冲长度(ccr_type_seg_size 单源)。 // 声明位置约束:本文件恒在最前(双 concat 共享面)——若把两件挪进 ccr_types.cr // (corearch 清单不含),ccr_io.cr 的引用即 corearch 侧 N06 静默未定义(B.6 同族)。 -g_ccr_type_seg : string, mut; g_ccr_type_seg_len : int, mut; +g_ccr_type_seg : string, mut +g_ccr_type_seg_len : int, mut // R2 P4 Task 3:IFACE(8) 段体缓冲(同 TYPE 的 D18 解耦——段体**构造**在 corec-only 的 // ccr_types.cr(引用桥接层 sh_iface_sig_*/形状构造点),ccr_io.cr 只按段表搬运/解析)。 // 缓冲**含段体首字段**(native_count u32)⇒ 段体大小 ≡ 缓冲长度(ccr_iface_seg_size 单源)。 -g_ccr_iface_seg : string, mut; g_ccr_iface_seg_len : int, mut; +g_ccr_iface_seg : string, mut +g_ccr_iface_seg_len : int, mut // R2 P6 Task 3(β):NOD 项索引装填缓冲(同 TYPE/IFACE 的 D18 解耦——**装填**在 // corec-only 的 ccr_types.cr(引用桥接层 sh_tk_face_of_code/sh_term_of_ti),本文件 // 只声明载体,ccr_io.cr 保存侧按节点序搬运落盘(盘记录 +28 i32 槽)。 @@ -39,16 +56,35 @@ g_ccr_iface_seg : string, mut; g_ccr_iface_seg_len : int, mut; // 读侧 load_ccr 在 TYPE 段解析后做**一致性硬校验**:域外或 atom_of ≠ 码 ⇒ 拒绝)。 // 声明位置约束同上方两件:本文件恒在最前(双 concat 共享面)——挪进 ccr_types.cr // 即 corearch 侧 N06 静默未定义(B.6 同族)。 -g_ccr_nod_item : string, mut; g_ccr_nod_item_count : int, mut; -g_ast : string, mut; g_ast_count : int, mut; g_ast_cap : int, mut; -g_tokens : string, mut; g_token_count : int, mut; g_tok_cap : int, mut; -g_errors : string, mut; g_error_count : int, mut; g_err_cap : int, mut; -g_block_stmts : string, mut; g_block_stmt_count : int, mut; g_block_stmt_cap : int, mut; -g_ir_vars : string, mut; g_ir_var_count : int, mut; g_ir_var_cap : int, mut; -g_ir_instrs : string, mut; g_ir_instr_count : int, mut; g_ir_instr_cap : int, mut; -g_ir_locals : string, mut; g_ir_local_count : int, mut; g_ir_local_cap : int, mut; -g_ir_globals : string, mut; g_ir_global_count : int, mut; g_ir_global_cap : int, mut; -g_ir_str_consts : string, mut; g_ir_str_const_count : int, mut; g_ir_str_const_cap : int, mut; +g_ccr_nod_item : string, mut +g_ccr_nod_item_count : int, mut +g_ast : string, mut +g_ast_count : int, mut +g_ast_cap : int, mut +g_tokens : string, mut +g_token_count : int, mut +g_tok_cap : int, mut +g_errors : string, mut +g_error_count : int, mut +g_err_cap : int, mut +g_block_stmts : string, mut +g_block_stmt_count : int, mut +g_block_stmt_cap : int, mut +g_ir_vars : string, mut +g_ir_var_count : int, mut +g_ir_var_cap : int, mut +g_ir_instrs : string, mut +g_ir_instr_count : int, mut +g_ir_instr_cap : int, mut +g_ir_locals : string, mut +g_ir_local_count : int, mut +g_ir_local_cap : int, mut +g_ir_globals : string, mut +g_ir_global_count : int, mut +g_ir_global_cap : int, mut +g_ir_str_consts : string, mut +g_ir_str_const_count : int, mut +g_ir_str_const_cap : int, mut // ── 生成期 intern 日志(CIR_CACHE_VER 21 · 串域跨进程 id 修复;TODO #2026-09-18-9)── // `g_strs`(intern 表)+ `g_str_count` 是 main.cr 缓存循环那份「快照不载 + 生成期写 + @@ -58,12 +94,12 @@ g_ir_str_consts : string, mut; g_ir_str_const_count : int, mut; g_ir_str_const_c // 修法(载进快照分支):**生成窗口内把每一次新 intern 记进日志,装载期按序重放** // ⇒ 读侧表与写侧同态 ⇒ 全部 id 原样有效(无需解释任何跨进程量、无需槽位判定表)。 // 记录点 = `dyn_arr.cr::str_intern` 的**唯一插入路径**(单点保证:不存在「表漏点」)。 -g_cir_rec_on : int, mut; // 1 = 正在记录(仅 corec 的缓存生成窗口内打开) -g_cir_rec_ids : string, mut; // 本窗口新 intern 的 id 序列(8B/条;落盘时解析为内容) -g_cir_rec_count : int, mut; -g_cir_rec_cap : int, mut; -g_cir_rec_base : int, mut; // 窗口开始时的 g_str_count(落盘为**基线见证**) -g_cir_skip_journal : int, mut; // 隐藏 debug(仅判据用):1 = 装载期跳过重放(突变自证) +g_cir_rec_on : int, mut // 1 = 正在记录(仅 corec 的缓存生成窗口内打开) +g_cir_rec_ids : string, mut // 本窗口新 intern 的 id 序列(8B/条;落盘时解析为内容) +g_cir_rec_count : int, mut +g_cir_rec_cap : int, mut +g_cir_rec_base : int, mut // 窗口开始时的 g_str_count(落盘为**基线见证**) +g_cir_skip_journal : int, mut // 隐藏 debug(仅判据用):1 = 装载期跳过重放(突变自证) // ── 可选运行期表示面(R2 P4 Task 5;裁决 5「解包侧判表示」,附录 B.7)── // 事实:`Some(1)`/`None` 走 IR_MAKE_ENUM 对象([tag][payload…]),而 `T?` 槽里的 @@ -76,73 +112,108 @@ g_cir_skip_journal : int, mut; // 隐藏 debug(仅判据用):1 = 装载 // g_ir_var_rep:IR var → 表示位变量索引(i64 数组;-1 = 无表示位)。无表示位的槽 // 走既有装箱假定(未覆盖面:结构体字段/数组元素/全局槽/match 结果/惰性 thunk, // 逐形态实测入报告——响亮失败或既有正确值,不新增静默错值)。 -g_ir_var_rep : string, mut; g_ir_var_rep_cap : int, mut; +g_ir_var_rep : string, mut +g_ir_var_rep_cap : int, mut // g_ir_var_decl_ti(容量批 T2):IR var → **声明类型索引**(i64 数组;-1 = 无注解/未知)。 // 用途 = 可选聚合槽写点装箱的「目标槽类型」判定:数组/切片元素类型只能由**声明** // (`a : [int?;2]`)忠实给出(字面量推出的元素类型对可选元素退化为对象占位)。 // 仅进程内状态,零布局变更;非可选程序不读取本表(零足迹)。 -g_ir_var_decl_ti : string, mut; g_ir_var_decl_cap : int, mut; +g_ir_var_decl_ti : string, mut +g_ir_var_decl_cap : int, mut // (A) 批(TODO #2026-09-16-4 / 裁-REP-1 (iii)):**取址名侧表**——`EXPR_UNARY+UOP_REF` 的 ident 操作数 // 的**名字索引**集合(预扫收集;进程内、零布局)。标记面按名字索引判 ⇒ **同名字在别处出现 // 会被一并标记 = 保守方向**(多标记只增装箱、不损失正确性;不会欠标记)。 -g_addr_taken_names : string, mut; g_addr_taken_cap : int, mut; g_addr_taken_count : int, mut; +g_addr_taken_names : string, mut +g_addr_taken_cap : int, mut +g_addr_taken_count : int, mut // 容量批 T3(E-3 / 裁-CAP-2 (a)):结构体字段**侧表**——字段槽区自定长内嵌记录迁出 // (记录内 `OFF_SI_FIELD_BASE` 槽 = 本表起始行;记录尺寸与既有 OFF_* 不变)。 // 三条扁平表按「全局字段行」索引(高水位 = g_si_f_used)。仅进程内状态;`.ccr` 盘面 // 不变(盘面本就逐字段变长,见 ccr_io.cr 的 SYM 布局注)。 -g_si_f_names : string, mut; g_si_f_types : string, mut; g_si_f_nodes : string, mut; -g_si_f_used : int, mut; g_si_f_cap : int, mut; +g_si_f_names : string, mut +g_si_f_types : string, mut +g_si_f_nodes : string, mut +g_si_f_used : int, mut +g_si_f_cap : int, mut // 容量批 T3:枚举变体**侧表**(同 struct 形态)——`OFF_EI_VARIANTS` 槽改义为 `variant_base`; // 变体面三条(名/载荷基址/载荷计数)+ 载荷面两条(裸码/类型节点)。 -g_ei_v_names : string, mut; g_ei_v_tbase : string, mut; g_ei_v_tcount : string, mut; -g_ei_vt_types : string, mut; g_ei_vt_nodes : string, mut; -g_ei_v_used : int, mut; g_ei_vt_used : int, mut; g_ei_v_cap : int, mut; -g_ei_vt_cap : int, mut; +g_ei_v_names : string, mut +g_ei_v_tbase : string, mut +g_ei_v_tcount : string, mut +g_ei_vt_types : string, mut +g_ei_vt_nodes : string, mut +g_ei_v_used : int, mut +g_ei_vt_used : int, mut +g_ei_v_cap : int, mut +g_ei_vt_cap : int, mut // 容量批 T3:match 覆盖位**无界位图**(旧态 = 单 int 的 2^vi 位图 ⇒ ≥63 变体溢出, // e70 实测 SIGFPE)。位图按「位下标 vi」寻址;`g_cov_len` = 当前已用位数,**栈纪律**: // mc_begin 存长度、mc_end 清零并回退(嵌套 match 安全)。 -g_cov_bits : string, mut; g_cov_cap : int, mut; g_cov_len : int, mut; +g_cov_bits : string, mut +g_cov_cap : int, mut +g_cov_len : int, mut // g_optrep_on:本编译单元是否启用表示面(AST 预扫:EXPR_OPTIONAL / `Some` / `None`)。 // 关 = **零足迹**(不注册隐藏全局、不发任何表示指令)⇒ 非可选程序的发射面逐字节不变。 -g_optrep_on : int, mut; +g_optrep_on : int, mut // g_dump_params_on:(乙) A1 判据通道(`--dump-params`,隐藏调试):形参序言创建槽时打一行 // `PARAM <函数名> p <形参名> slot=<槽型码> decl=<节点 type_val>` 到 **stdout**。 // **rc 中性 + 零产物**(用不用该 flag,rc 与产物逐字节不变;不新增 alloc/str_intern 副作用—— // 只读 `irv_type` 与 `ast_type_val` 两个纯表读,函数名走既有 `istr_get`)。 -g_dump_params_on : int, mut; +g_dump_params_on : int, mut // g_optrep_ret_cell:返回表示的信道单元(IR 全局 var;-1 = 未注册)。返回点写、 // 调用点读(读点紧跟 IR_CALL ⇒ 跨嵌套调用不被覆写;写点为值求值完成后 → 语义确定)。 -g_optrep_ret_cell : int, mut; +g_optrep_ret_cell : int, mut // g_optrep_arg_cell0 / g_optrep_arg_count:形参表示信道(每形参位一个 IR 全局 var, // 连续分配)。调用点写、被调序言读(先于任何可能改写信道的调用)。 -g_optrep_arg_cell0 : int, mut; g_optrep_arg_count : int, mut; +g_optrep_arg_cell0 : int, mut +g_optrep_arg_count : int, mut // g_cur_ret_opt:当前函数的返回类型是否可选(ir_gen_func 设置;返回点写信道用)。 -g_cur_ret_opt : int, mut; +g_cur_ret_opt : int, mut // g_cur_ret_dex_opt:当前函数的返回类型是否 `dex?`(ir_gen_func 按**返回类型节点**设置, // 批 5 · R3)。`-> dex?` 的 `g_cur_ret_ti` 与 `type_val` 均为 0(`unpack_type(EXPR_OPTIONAL)` // 塌陷)⇒ 返回点的 dex 边界转换需本标志补位(否则 apx 源经 `-> dex?` 返回不转换)。 -g_cur_ret_dex_opt : int, mut; +g_cur_ret_dex_opt : int, mut // 表示码(rep_enc_of_expr 的返回):>= 0 = 从该表示位槽**拷贝**;oe_bare() = -1 = 裸值 // 常量;oe_boxed() = -2 = 装箱常量。**用函数而非文件级常量**:Python bootstrap 的 // gen_let_decl 只对**裸字面量**记 constant_value(`-1` 解析成 UnaryOp ⇒ 丢初值 ⇒ // StackAsmGen 发 `.quad 0`)⇒ 自举链二进制里的负值文件级常量**静默读 0**(实测踩过: // 两常量读 0 后 `Some` 初值表示位与裸值同码;同类既存面 = cir_cache.cr 的 // CIR_CACHE_MAGIC,其在自举二进制里同读 0——已登记报告)。返回值表达式不受该限制。 -fn oe_bare() -> int { return 0 - 1; } -fn oe_boxed() -> int { return 0 - 2; } +fn oe_bare() -> int: + return 0 - 1 +fn oe_boxed() -> int: + return 0 - 2 // Parser/checker dynamic arrays (shared between corec and corearch builds) -g_global_lets : string, mut; g_global_let_count : int, mut; g_global_lets_cap : int, mut; -g_loop_stack : string, mut; g_loop_depth : int, mut; g_loop_stack_cap : int, mut; -g_type_aliases : string, mut; g_type_alias_count : int, mut; g_type_alias_cap : int, mut; -g_methods : string, mut; g_method_count : int, mut; g_method_cap : int, mut; -g_scope_bounds : string, mut; g_scope_depth : int, mut; g_scope_bounds_cap : int, mut; -g_borrow_scope_markers : string, mut; g_borrow_scope_depth : int, mut; g_borrow_scope_markers_cap : int, mut; +g_global_lets : string, mut +g_global_let_count : int, mut +g_global_lets_cap : int, mut +g_loop_stack : string, mut +g_loop_depth : int, mut +g_loop_stack_cap : int, mut +g_type_aliases : string, mut +g_type_alias_count : int, mut +g_type_alias_cap : int, mut +g_methods : string, mut +g_method_count : int, mut +g_method_cap : int, mut +g_scope_bounds : string, mut +g_scope_depth : int, mut +g_scope_bounds_cap : int, mut +g_borrow_scope_markers : string, mut +g_borrow_scope_depth : int, mut +g_borrow_scope_markers_cap : int, mut // Interface system -g_ifaces : string, mut; g_iface_count : int, mut; g_iface_cap : int, mut; -g_impl_for : string, mut; g_impl_for_count : int, mut; g_impl_for_cap : int, mut; -g_generic_constr : string, mut; g_generic_constr_count : int, mut; g_generic_constr_cap : int, mut; +g_ifaces : string, mut +g_iface_count : int, mut +g_iface_cap : int, mut +g_impl_for : string, mut +g_impl_for_count : int, mut +g_impl_for_cap : int, mut +g_generic_constr : string, mut +g_generic_constr_count : int, mut +g_generic_constr_cap : int, mut // R2 P3 Task 5:结构/枚举泛型约束侧表(**索引空间与函数侧分家**——g_generic_constr 的键 = // `fi * MAX_GENERICS + gi`,若共用同一缓冲,struct/enum 行号与函数行号会互相覆盖)。 // 键 = `si * MAX_GENERICS + gi`(struct)/ `ei * MAX_GENERICS + gi`(enum),值 = 约束名 ni @@ -151,59 +222,89 @@ g_generic_constr : string, mut; g_generic_constr_count : int, mut; g_generic_co // 的轴 C)——实例化点由 `gen_inst_constr_satisfied` 直取真值(本批起**真判定**:可证违反 ⇒ // TG02 软诊断),函数调用点仍回落既有 check_iface 路径(措辞逐字不动,切换归 Task 6 Step 3)。 // 见 checker.cr 的 gen_constr_* 段。 -g_sgen_constr : string, mut; g_sgen_constr_count : int, mut; g_sgen_constr_cap : int, mut; -g_egen_constr : string, mut; g_egen_constr_count : int, mut; g_egen_constr_cap : int, mut; +g_sgen_constr : string, mut +g_sgen_constr_count : int, mut +g_sgen_constr_cap : int, mut +g_egen_constr : string, mut +g_egen_constr_count : int, mut +g_egen_constr_cap : int, mut // R2 P3b Task 0(P2b 交接面回补):**横切轴形状条目表**(名字 ni → 形状类型项), // `iface_satisfies` 的轴 A。与 `g_ifaces`(用户接口 = 方法集)平行:本表条目 = 一个**类型项** // (如 `sequence` ⇒ `⊤_SEQUENCE`),满足判定 = 一条包含判定(spec §2.2)。 // 条目由 Task 2 注册(`iface_shape_register`)——**本批零条目**(空表 ⇒ 轴 A 恒 -1 = 不判, // 三态纪律不破)。⚠ 注册名须来自**已驻留**的名字 ni(lexer 已 intern 的源码标识符); // 本表初始化路径**不得** `str_intern`(.ccr STR 段硬判据,照 iface_registry.cr 的 name_ni 注)。 -g_iface_shape_names : string, mut; g_iface_shape_terms : string, mut; -g_iface_shape_count : int, mut; g_iface_shape_cap : int, mut; +g_iface_shape_names : string, mut +g_iface_shape_terms : string, mut +g_iface_shape_count : int, mut +g_iface_shape_cap : int, mut // R2 P3 Task 5(Step 4):调用点泛型绑定侧表(monomorph 实例键类型项化)。 // 由 checker 的 infer_gen_call 按**被调方泛型形参声明序**登记:每调用点 gc 个槽,值 = 实参 // 推断出的**类型行 ti**(-1 = 未绑定)。起始下标写入调用节点 `ast_int_val`(调用节点的该槽 // 在本批之前只被**死码** `ir_gen.cr find_or_create_mono_func` 读——该函数零调用者,登记见 // 报告)。ir_gen 侧据 ti 生成规范实例键 `inst_key_of_ti`,并以 ti 型替换(`g_gen_subst_tis`) // 取代纯名字文本替换(旧法:非原生实参一律塌缩 "int" ⇒ 异型实例折叠 + 错替换)。 -g_gen_binds : string, mut; g_gen_binds_count : int, mut; g_gen_binds_cap : int, mut; +g_gen_binds : string, mut +g_gen_binds_count : int, mut +g_gen_binds_cap : int, mut // R2 P3 Task 5:约束违反诊断去重侧表(开放寻址,16B/条 {key, 1};key = node*MAX_GENERICS+gi)。 // 生命周期同 g_named_dedup(init_types → gen_constr_seen_reset 置 cap=0 惰性重建;键含 AST // 节点下标 ⇒ 跨编译期复用即失效)。见 checker.cr 的 gen_constr_seen_* 段。 -g_constr_seen : string, mut; g_constr_seen_cap : int, mut; g_constr_seen_count : int, mut; -g_gen_params : string, mut; g_gen_param_count : int, mut; g_gen_param_cap : int, mut; -g_checker_current_fi : int, mut; +g_constr_seen : string, mut +g_constr_seen_cap : int, mut +g_constr_seen_count : int, mut +g_gen_params : string, mut +g_gen_param_count : int, mut +g_gen_param_cap : int, mut +g_checker_current_fi : int, mut // 批 8 PR-B · S1′ 打点开关(**默认 0 = 关**):由 `main.cr` 读 `CORE_S1P=1` 置位; // 打开时 checker 的直调点打**数值**行(行/列/形参序/形参 TI/实参 TI/被调名)。 // **为何要开关**:该打点会 `int_str`/`println` 生成新字符串 ⇒ 写进输出 `.ccr` 的 STR 段 // ⇒ 破「产物逐字节不变」(实测 `opt_dex_test.cr` 的 `.ccr` 变而 ELF 同)。默认关 ⇒ 零足迹。 -g_s1p_on : int, mut; // S1′ 打点开关:0 = 关(默认行为)· 1 = 开(`CORE_S1P=1`) -g_s1p_seen : int, mut; // 0 = 尚未读环境变量 —— **哨兵必须用零值**:全局的**非 Literal 初值** +g_s1p_on : int, mut // S1′ 打点开关:0 = 关(默认行为)· 1 = 开(`CORE_S1P=1`) +g_s1p_seen : int, mut // 0 = 尚未读环境变量 —— **哨兵必须用零值**:全局的**非 Literal 初值** // 经 Python bootstrap 构建会被**静默丢成 0**(2026-09-18 实测, // 机理见 checker.cr S1′ 注)⇒ `= -1` 这类写法不可依赖。 -g_unsafe_depth : int, mut; -g_alloc_pts : string, mut; g_alloc_pts_cap : int, mut; -g_borrow_vars : string, mut; g_borrow_refs : string, mut; g_borrow_muts : string, mut; -g_borrow_count : int, mut; g_borrow_cap : int, mut; -g_holder_borrowers : string, mut; g_holder_borrowed : string, mut; g_holder_is_mut : string, mut; -g_holder_count : int, mut; g_holder_cap : int, mut; -g_gen_map_names : string, mut; g_gen_map_types : string, mut; -g_gen_map_count : int, mut; g_gen_map_cap : int, mut; -g_dyn_type_sets : string, mut; g_dyn_type_set_count : int, mut; g_dyn_type_set_cap : int, mut; -g_stack_map : string, mut; // IR var index → shared stack slot var (-1 = own slot), set by allocator -g_home_dir : string, mut; // cached HOME dir for SO index lookup -g_home_dir_ok : int, mut; // 1 = g_home_dir initialized - -g_ir_func_name_idx : string, mut; g_ir_func_name_idx_cap : int, mut; -g_ir_func_ret_type : string, mut; g_ir_func_ret_type_cap : int, mut; -g_ir_func_instr_start : string, mut; g_ir_func_instr_start_cap : int, mut; -g_ir_func_instr_count : string, mut; g_ir_func_instr_count_cap : int, mut; -g_ir_func_var_start : string, mut; g_ir_func_var_start_cap : int, mut; -g_ir_func_var_count : string, mut; g_ir_func_var_count_cap : int, mut; -g_ir_func_param_count : string, mut; g_ir_func_param_count_cap : int, mut; -g_ir_func_count : int, mut; +g_unsafe_depth : int, mut +g_alloc_pts : string, mut +g_alloc_pts_cap : int, mut +g_borrow_vars : string, mut +g_borrow_refs : string, mut +g_borrow_muts : string, mut +g_borrow_count : int, mut +g_borrow_cap : int, mut +g_holder_borrowers : string, mut +g_holder_borrowed : string, mut +g_holder_is_mut : string, mut +g_holder_count : int, mut +g_holder_cap : int, mut +g_gen_map_names : string, mut +g_gen_map_types : string, mut +g_gen_map_count : int, mut +g_gen_map_cap : int, mut +g_dyn_type_sets : string, mut +g_dyn_type_set_count : int, mut +g_dyn_type_set_cap : int, mut +g_stack_map : string, mut // IR var index → shared stack slot var (-1 = own slot), set by allocator +g_home_dir : string, mut // cached HOME dir for SO index lookup +g_home_dir_ok : int, mut // 1 = g_home_dir initialized + +g_ir_func_name_idx : string, mut +g_ir_func_name_idx_cap : int, mut +g_ir_func_ret_type : string, mut +g_ir_func_ret_type_cap : int, mut +g_ir_func_instr_start : string, mut +g_ir_func_instr_start_cap : int, mut +g_ir_func_instr_count : string, mut +g_ir_func_instr_count_cap : int, mut +g_ir_func_var_start : string, mut +g_ir_func_var_start_cap : int, mut +g_ir_func_var_count : string, mut +g_ir_func_var_count_cap : int, mut +g_ir_func_param_count : string, mut +g_ir_func_param_count_cap : int, mut +g_ir_func_count : int, mut // v6 数据基础:存在区间表(compute_live_ranges 填充,alloc_registers 读本表—— // 填充方 = 内核 ent_kernel.cr(双 concat 共享:corec 写侧 save_ccr 直调 @@ -212,9 +313,9 @@ g_ir_func_count : int, mut; // ——坐标限定:0..instr_count-1 的函数内下标,见 ent_kernel.cr live_range_slot); // func_i 段起始 = Σ var_count[0..func_i),不乘固定稠密系数。未使用 var 为 -1。 // 与 g_ir_slice_lens 同风格:16B 记录 + grow 函数(grow_live_ranges 在 ent_kernel.cr)。 -g_ir_live_ranges : string, mut; -g_live_range_count : int, mut; -g_live_range_cap : int, mut; +g_ir_live_ranges : string, mut +g_live_range_count : int, mut +g_live_range_cap : int, mut // v6 条目表(条目版本化,compute_entries 填充——compute_live_ranges 尾部对全部 // 函数运行;v7 ENT 主干化后 .ccr ENT = 实记录,corec 写侧 save_ccr 直调内核 @@ -232,102 +333,158 @@ g_live_range_cap : int, mut; // flags(20) u32 = 0(位 0 预留:无配方,条款 4b) // 布局:每函数一段(func_i 升序追加),段界在 g_ir_func_entry_start/count(8B/条)。 // 版本号不落盘:同 var 条目按 def_instr 升序(扫描序即升序),版本序 = 组内 1-based 序号。 -g_ir_entries : string, mut; g_entry_count : int, mut; g_entry_cap : int, mut; -g_ir_func_entry_start : string, mut; g_ir_func_entry_count : string, mut; -g_ir_func_entry_cap : int, mut; +g_ir_entries : string, mut +g_entry_count : int, mut +g_entry_cap : int, mut +g_ir_func_entry_start : string, mut +g_ir_func_entry_count : string, mut +g_ir_func_entry_cap : int, mut // Module system arrays (dynamic byte buffers) -DIAG_REC_SIZE : int = 40; // g_diags 记录字节数:[ec(8) msg(8) line(8) col(8) file_id(8)] +DIAG_REC_SIZE : int = 40 // g_diags 记录字节数:[ec(8) msg(8) line(8) col(8) file_id(8)] // fail-closed 判据线(FC 批 T2):豁免表的**生效面**标签(消费点 = main.cr 的硬判定循环 // 经 diag_gate_exempt(ec, scope);表 = diag.cr)。裁-FC-1 = (C):run_frontend 只以 // GATE_SCOPE_BUILD 调用;check 面的 rc 规则(计数 > 0)不消费本表 ⇒ check 基线零变化。 -GATE_SCOPE_BUILD : int = 1; // build/ccr/cir/run 面(经 run_frontend 的 hard 判定) -GATE_SCOPE_CHECK : int = 2; // check 面(**本批不消费**:仅登记;见 diag_gate_exempt 表注) -g_diags : string, mut; g_diag_count : int, mut; g_diag_cap : int, mut; -g_files : string, mut; g_file_count : int, mut; g_file_cap : int, mut; -g_mods : string, mut; g_mod_count : int, mut; g_mod_cap : int, mut; +GATE_SCOPE_BUILD : int = 1 // build/ccr/cir/run 面(经 run_frontend 的 hard 判定) +GATE_SCOPE_CHECK : int = 2 // check 面(**本批不消费**:仅登记;见 diag_gate_exempt 表注) +g_diags : string, mut +g_diag_count : int, mut +g_diag_cap : int, mut +g_files : string, mut +g_file_count : int, mut +g_file_cap : int, mut +g_mods : string, mut +g_mod_count : int, mut +g_mod_cap : int, mut // LSP open documents: path → source text. 24-byte records: // {path_ptr(8), src_ptr(8), src_len(8)}(路径与源文本均为调用方提供的稳定堆字符串) -g_open_docs : string, mut; g_open_doc_count : int, mut; g_open_doc_cap : int, mut; +g_open_docs : string, mut +g_open_doc_count : int, mut +g_open_doc_cap : int, mut // LSP 静默模式:1 = 抑制非诊断的进度/警告 stdout 输出(保护协议通道) -g_silent_stdout : int, mut; // 默认 0:corec 命令行行为不变 -g_mod_func_fileids : string, mut; g_mod_func_names : string, mut; -g_mod_func_tis : string, mut; g_mod_func_count : int, mut; g_mod_func_cap : int, mut; -g_mod_path_names : string, mut; g_mod_path_count : int, mut; g_mod_path_cap : int, mut; +g_silent_stdout : int, mut // 默认 0:corec 命令行行为不变 +g_mod_func_fileids : string, mut +g_mod_func_names : string, mut +g_mod_func_tis : string, mut +g_mod_func_count : int, mut +g_mod_func_cap : int, mut +g_mod_path_names : string, mut +g_mod_path_count : int, mut +g_mod_path_cap : int, mut // Dynamic stacks (byte buffers) -g_ir_local_scopes : string, mut; g_ir_local_scopes_cap : int, mut; -g_ir_local_depth : int, mut; -g_ir_loop_header : string, mut; g_ir_loop_exit : string, mut; -g_ir_loop_depth : int, mut; g_ir_loop_stacks_cap : int, mut; -g_label_poses : string, mut; g_label_cap : int, mut; -g_label_count : int, mut; +g_ir_local_scopes : string, mut +g_ir_local_scopes_cap : int, mut +g_ir_local_depth : int, mut +g_ir_loop_header : string, mut +g_ir_loop_exit : string, mut +g_ir_loop_depth : int, mut +g_ir_loop_stacks_cap : int, mut +g_label_poses : string, mut +g_label_cap : int, mut +g_label_count : int, mut // Interpreter loop-region table: per SG_LOOP/SG_FOR region, the enter/exit // DF-node offsets (function-relative). Loop iteration in the interpreter is // driven by these region boundaries, not by label-table back-jumps. -g_loop_region_enter : string, mut; g_loop_region_exit : string, mut; -g_loop_region_count : int, mut; g_loop_region_cap : int, mut; +g_loop_region_enter : string, mut +g_loop_region_exit : string, mut +g_loop_region_count : int, mut +g_loop_region_cap : int, mut // Pre-computed interned string indices for builtin function name matching -g_ni_syscall3 : int, mut; g_ni_syscall4 : int, mut; g_ni_load8 : int, mut; g_ni_store8 : int, mut; -g_ni_load64 : int, mut; g_ni_load_str_ptr : int, mut; -g_ni_store_str_ptr : int, mut; g_ni_get_arg : int, mut; -g_ni_w64 : int, mut; g_ni_dyncpy : int, mut; g_ni_r64 : int, mut; -g_ni_goroutine_wrapper_addr : int, mut; +g_ni_syscall3 : int, mut +g_ni_syscall4 : int, mut +g_ni_load8 : int, mut +g_ni_store8 : int, mut +g_ni_load64 : int, mut +g_ni_load_str_ptr : int, mut +g_ni_store_str_ptr : int, mut +g_ni_get_arg : int, mut +g_ni_w64 : int, mut +g_ni_dyncpy : int, mut +g_ni_r64 : int, mut +g_ni_goroutine_wrapper_addr : int, mut // Single-pass backpatching: pending forward jumps -g_pending_pos : string, mut; // rel32 buffer positions to patch -g_pending_label : string, mut; // target label indices -g_pending_count : int, mut; g_pending_cap : int, mut; -g_next_label : int, mut; +g_pending_pos : string, mut // rel32 buffer positions to patch +g_pending_label : string, mut // target label indices +g_pending_count : int, mut +g_pending_cap : int, mut +g_next_label : int, mut // Backend arrays (all dynamic byte buffers) -g_x86_str_offs : string, mut; g_x86_str_count : int, mut; g_x86_str_cap : int, mut; -g_x86_ext_rel_pos : string, mut; g_x86_ext_rel_name : string, mut; -g_x86_ext_rel_count : int, mut; g_x86_ext_rel_cap : int, mut; +g_x86_str_offs : string, mut +g_x86_str_count : int, mut +g_x86_str_cap : int, mut +g_x86_ext_rel_pos : string, mut +g_x86_ext_rel_name : string, mut +g_x86_ext_rel_count : int, mut +g_x86_ext_rel_cap : int, mut // `.so` 扩展索引**侧表**(第 4 批 #82/#83):索引解析结果先落此处,**不**直接进串表/符号表。 // 只有被程序**引用**的名字才由 `so_materialize`(module.cr)物化 ⇒ 未引用条目零产物足迹。 // name 存**原始串**(不能存 intern 索引——注册期 intern 正是 #82 的泄漏本身); // tags/type 存 int(与符号表 SO_FN 条目的 sym_type/sym_node 同义)。 -g_so_side_name : string, mut; g_so_side_tags : string, mut; -g_so_side_type : string, mut; -g_so_side_count : int, mut; g_so_side_cap : int, mut; +g_so_side_name : string, mut +g_so_side_tags : string, mut +g_so_side_type : string, mut +g_so_side_count : int, mut +g_so_side_cap : int, mut // 批 6(T2)**规约标注侧表**:`#check(expr)` / `#ensure(expr)` 的登记面(源序追加;8B/条)。 // 设计要点(裁-S2/S3):① 标注**不挤 `EXPR_FN` 的 a/b/c 槽**(parser.cr:1451 槽语义不变); // ② 表达式 AST 节点落 `g_ast` 但**不被 body 引用** ⇒ ir_gen 走不到它 ⇒ 发射面零足迹; // ③ 侧表随前端复位(与 `g_func_count` 同生命周期——fi/ni 下标跨编译复用,不清会命中陈旧条目)。 -g_spec_fn : string, mut; // 函数名 str idx(= parse_body 的 fn_ni;仅用于消息) -g_spec_fnode : string, mut; // **EXPR_FN 节点索引**(唯一键:同名函数/方法不串台; +g_spec_fn : string, mut // 函数名 str idx(= parse_body 的 fn_ni;仅用于消息) +g_spec_fnode : string, mut // **EXPR_FN 节点索引**(唯一键:同名函数/方法不串台; // 由 parser 在 alloc_node 之后回填,见 parse_body 的 spec_start 补丁) -g_spec_kind : string, mut; // 0=#check 1=#ensure(留宽:C2 的 #pure/#tag 等) -g_spec_expr : string, mut; // 标注表达式的 AST 节点索引 -g_spec_line : string, mut; // 标注 `#` 所在行 -g_spec_col : string, mut; // 标注 `#` 所在列 -g_spec_status : string, mut; // 三态:0=yellow(未证,默认) 1=green(常量真) 2=red(有硬错) +g_spec_kind : string, mut // 0=#check 1=#ensure(留宽:C2 的 #pure/#tag 等) +g_spec_expr : string, mut // 标注表达式的 AST 节点索引 +g_spec_line : string, mut // 标注 `#` 所在行 +g_spec_col : string, mut // 标注 `#` 所在列 +g_spec_status : string, mut // 三态:0=yellow(未证,默认) 1=green(常量真) 2=red(有硬错) // **red 粘性**(spec_set_status):红色不被后续 green 覆盖 -g_spec_count : int, mut; g_spec_cap : int, mut; -g_x86_rip_patch_pos : string, mut; g_x86_rip_patch_globals : string, mut; -g_x86_rip_patch_count : int, mut; g_x86_rip_patch_cap : int, mut; -g_x86_vars : string, mut; g_x86_var_count : int, mut; g_x86_var_cap : int, mut; -g_x86_stack_size : int, mut; g_x86_func_idx : int, mut; -g_x86_is_enum : string, mut; g_x86_is_enum_count : int, mut; g_x86_is_enum_cap : int, mut; -g_x86_rodataref_pos : string, mut; g_x86_rodataref_ro : string, mut; -g_x86_func_cp : string, mut; g_x86_func_cp_cap : int, mut; -g_x86_func_code_sz : string, mut; g_x86_func_code_sz_cap : int, mut; -g_x86_rodataref_count : int, mut; g_x86_rodataref_cap : int, mut; -g_x86_is_global : string, mut; -g_x86_global_cnt : int, mut; -g_x86_global_cap : int, mut; -g_x86_global_off : string, mut; g_x86_global_off_cnt : int, mut; g_x86_global_off_cap : int, mut; -g_x86_func_offsets : string, mut; g_x86_func_offsets_cap : int, mut; g_x86_func_off_count : int, mut; -g_x86_emit_vars : string, mut; g_x86_emit_vars_cap : int, mut; g_x86_emit_var_count : int, mut; g_x86_emit_stack_size : int, mut; +g_spec_count : int, mut +g_spec_cap : int, mut +g_x86_rip_patch_pos : string, mut +g_x86_rip_patch_globals : string, mut +g_x86_rip_patch_count : int, mut +g_x86_rip_patch_cap : int, mut +g_x86_vars : string, mut +g_x86_var_count : int, mut +g_x86_var_cap : int, mut +g_x86_stack_size : int, mut +g_x86_func_idx : int, mut +g_x86_is_enum : string, mut +g_x86_is_enum_count : int, mut +g_x86_is_enum_cap : int, mut +g_x86_rodataref_pos : string, mut +g_x86_rodataref_ro : string, mut +g_x86_func_cp : string, mut +g_x86_func_cp_cap : int, mut +g_x86_func_code_sz : string, mut +g_x86_func_code_sz_cap : int, mut +g_x86_rodataref_count : int, mut +g_x86_rodataref_cap : int, mut +g_x86_is_global : string, mut +g_x86_global_cnt : int, mut +g_x86_global_cap : int, mut +g_x86_global_off : string, mut +g_x86_global_off_cnt : int, mut +g_x86_global_off_cap : int, mut +g_x86_func_offsets : string, mut +g_x86_func_offsets_cap : int, mut +g_x86_func_off_count : int, mut +g_x86_emit_vars : string, mut +g_x86_emit_vars_cap : int, mut +g_x86_emit_var_count : int, mut +g_x86_emit_stack_size : int, mut // int 多字 M1(tagged 槽,D1a):潜在多字变量的旁路 tag 区(栈帧尾附加)。 // 见 docs/superpowers/plans/2026-09-06-int-multiword-m1.md Task 1 与 // docs/superpowers/specs/2026-09-06-int-multiword-backend-design.md(D1a/D3)。 // g_x86_mw_tag_off:当前函数的 per-局部-变量 tag 字节偏移表(i64 数组,按 // 局部位置 v-var_start 索引;值 = 相对 rbp 的负字节偏移;-1 = 非 tagged)。 // g_x86_mw_tag_count:当前函数 tagged 变量数(tag 区字节数 = 每变量 1 字节)。 -g_x86_mw_tag_off : string, mut; g_x86_mw_tag_off_cap : int, mut; -g_x86_mw_tag_count : int, mut; +g_x86_mw_tag_off : string, mut +g_x86_mw_tag_off_cap : int, mut +g_x86_mw_tag_count : int, mut // g_x86_mw_jo_*:int 多字 M1 Task 2/3——tagged int add/sub 快路径溢出跳 // (jo 0F 80 rel32)站点记录表:emit_instr 发射 jo 时记录站点现场,frame.cr // pf_epilogue 于该函数尾声(慢路径块位置后知)按站点发射真实 2-limb 修正块 @@ -345,9 +502,12 @@ g_x86_mw_tag_count : int, mut; // 之后的绝对位置——elf.cr 于指令发射完、块位置已知 // 时填写,块发射时直接回填 jmp rel32)。 // 见 plan Task 2/3 与 specs/2026-09-06-int-multiword-backend-design.md(D1a/D3)。 -g_x86_mw_jo_pos : string, mut; g_x86_mw_jo_cap : int, mut; g_x86_mw_jo_count : int, mut; -g_x86_mw_jo_dest : string, mut; g_x86_mw_jo_is_sub : string, mut; -g_x86_mw_jo_resume : string, mut; +g_x86_mw_jo_pos : string, mut +g_x86_mw_jo_cap : int, mut +g_x86_mw_jo_count : int, mut +g_x86_mw_jo_dest : string, mut +g_x86_mw_jo_is_sub : string, mut +g_x86_mw_jo_resume : string, mut // g_x86_mw_oc_*:int 多字 M1 Task 4——消费者站点(tagged 操作数读 tag)记录表: // add/sub/比较站点在快路径前发 tag 检查(test byte + jne 0F 85 rel32——tag=1 // = 操作数为 2-limb),jne 目标 = 该站点函数尾 2L 块(位置后知——jo 同款 @@ -360,43 +520,68 @@ g_x86_mw_jo_resume : string, mut; // OP_EQ..OP_GE = 128 比较块); // g_x86_mw_oc_resume — 块完成后跳回点(= 该站点指令尾,同 jo)。 // 见 plan Task 4 与 e2_mw_opnd_block(tag2l.cr——波 1 Task 4 自 instr.cr 整搬)。 -g_x86_mw_oc_pos1 : string, mut; g_x86_mw_oc_pos2 : string, mut; -g_x86_mw_oc_cap : int, mut; g_x86_mw_oc_count : int, mut; -g_x86_mw_oc_s1 : string, mut; g_x86_mw_oc_s2 : string, mut; -g_x86_mw_oc_dest : string, mut; g_x86_mw_oc_op : string, mut; -g_x86_mw_oc_resume : string, mut; -g_x86_ret_patch_pos : string, mut; g_x86_ret_patch_cap : int, mut; g_x86_ret_patch_count : int, mut; -g_x86_call_patch_pos : string, mut; g_x86_call_patch_name : string, mut; -g_x86_call_patch_count : int, mut; g_x86_call_patch_cap : int, mut; -g_x86_fnaddr_patch_pos : string, mut; g_x86_fnaddr_patch_name : string, mut; -g_x86_fnaddr_patch_count : int, mut; g_x86_fnaddr_patch_cap : int, mut; -g_x86_sub_rsp_pos : int, mut; -g_x86_alloc_patch_pos : string, mut; g_x86_alloc_patch_cap : int, mut; g_x86_alloc_patch_count : int, mut; -g_x86_emit_rt_stubs : int, mut; // 1 = pure-static: backend emits g_set_curg/g_get_curg stubs +g_x86_mw_oc_pos1 : string, mut +g_x86_mw_oc_pos2 : string, mut +g_x86_mw_oc_cap : int, mut +g_x86_mw_oc_count : int, mut +g_x86_mw_oc_s1 : string, mut +g_x86_mw_oc_s2 : string, mut +g_x86_mw_oc_dest : string, mut +g_x86_mw_oc_op : string, mut +g_x86_mw_oc_resume : string, mut +g_x86_ret_patch_pos : string, mut +g_x86_ret_patch_cap : int, mut +g_x86_ret_patch_count : int, mut +g_x86_call_patch_pos : string, mut +g_x86_call_patch_name : string, mut +g_x86_call_patch_count : int, mut +g_x86_call_patch_cap : int, mut +g_x86_fnaddr_patch_pos : string, mut +g_x86_fnaddr_patch_name : string, mut +g_x86_fnaddr_patch_count : int, mut +g_x86_fnaddr_patch_cap : int, mut +g_x86_sub_rsp_pos : int, mut +g_x86_alloc_patch_pos : string, mut +g_x86_alloc_patch_cap : int, mut +g_x86_alloc_patch_count : int, mut +g_x86_emit_rt_stubs : int, mut // 1 = pure-static: backend emits g_set_curg/g_get_curg stubs // Optimization levels and metadata (extensible key-value store) -g_opt_level : int, mut; // 0=none, 1=regalloc, 2=stackshare, 3=cse -g_opt_meta : string, mut; // metadata buffer for .ccr v3+ -g_opt_meta_count : int, mut; g_opt_meta_cap : int, mut; +g_opt_level : int, mut // 0=none, 1=regalloc, 2=stackshare, 3=cse +g_opt_meta : string, mut // metadata buffer for .ccr v3+ +g_opt_meta_count : int, mut +g_opt_meta_cap : int, mut // Subgraph table (for RegionCheck pass lifetime tracking) -g_sgs : string, mut; g_sg_count : int, mut; g_sg_cap : int, mut; -g_df_node_region : string, mut; g_df_node_region_cap : int, mut; // per DFNode: owning region id (-1 = none) -g_cur_sg : int, mut; // currently open region id (-1 = none) -g_cur_ret_ti : int, mut; // 当前函数的返回 TI(dex 边界转换用,数值迁移 Task 4) -g_last_state_node : int, mut; // last side-effect DFNode id (VSDG state chain; -1 = none) -g_df_state_finalized : int, mut; // df_state_finalize 幂等旗标(0 = 未跑;数据流图重建每编译恰一次——见 dataflow.cr) +g_sgs : string, mut +g_sg_count : int, mut +g_sg_cap : int, mut +g_df_node_region : string, mut +g_df_node_region_cap : int, mut // per DFNode: owning region id (-1 = none) +g_cur_sg : int, mut // currently open region id (-1 = none) +g_cur_ret_ti : int, mut // 当前函数的返回 TI(dex 边界转换用,数值迁移 Task 4) +g_last_state_node : int, mut // last side-effect DFNode id (VSDG state chain; -1 = none) +g_df_state_finalized : int, mut // df_state_finalize 幂等旗标(0 = 未跑;数据流图重建每编译恰一次——见 dataflow.cr) // Plugin extension registry: tags and return types from .so/stdlib plugins // Each entry: 24 bytes = [ns_ni, name_ni, data_ni] -g_plugin_tags : string, mut; g_plugin_tag_count : int, mut; g_plugin_tag_cap : int, mut; -g_plugin_rtypes : string, mut; g_plugin_rtype_count : int, mut; g_plugin_rtype_cap : int, mut; +g_plugin_tags : string, mut +g_plugin_tag_count : int, mut +g_plugin_tag_cap : int, mut +g_plugin_rtypes : string, mut +g_plugin_rtype_count : int, mut +g_plugin_rtype_cap : int, mut // Pointer analysis storage -g_pts : string, mut; g_pts_count : int, mut; g_pts_cap : int, mut; -g_offsets : string, mut; g_offsets_count : int, mut; g_offsets_cap : int, mut; +g_pts : string, mut +g_pts_count : int, mut +g_pts_cap : int, mut +g_offsets : string, mut +g_offsets_count : int, mut +g_offsets_cap : int, mut // Alloc 序号 → DF 节点序号映射(修复 3:alloc pts 需要递增位号,provenance 按位号查 alloc 大小) -g_pa_alloc_count : int, mut; -g_pa_alloc_nodes : string, mut; g_pa_alloc_nodes_cap : int, mut; +g_pa_alloc_count : int, mut +g_pa_alloc_nodes : string, mut +g_pa_alloc_nodes_cap : int, mut // R2 P0 类型项引擎:类型项 DAG 表 + 结构哈希索引 + 判定 memo + 预算守卫 // (表 = 48B/条 {tag,a,b,c,d,hash},见 type_terms.cr;扩容 grow_type_terms/ @@ -405,15 +590,28 @@ g_pa_alloc_nodes : string, mut; g_pa_alloc_nodes_cap : int, mut; // 惰性 memo 槽(g_tt_top/g_tt_nil)+ 零初值 ready 位:bootstrap 后端只认字面量 // 常量初值(`= -1` 会被降级为 0,见 bootstrap x86_64_stack_asm 的 .quad 0 路径), // 故以 0 = 未建 + ready 位表达「未初始化」,与本仓库 g_home_dir_ok/g_ext_inited 同式。 -g_type_terms : string, mut; g_type_term_count : int, mut; g_type_term_cap : int, mut; -g_tt_index : string, mut; g_tt_index_cap : int, mut; g_tt_index_count : int, mut; -g_tt_nil : int, mut; g_tt_nil_ok : int, mut; -g_tt_top : int, mut; g_tt_top_ok : int, mut; -g_ty_memo_keys : string, mut; g_ty_memo_vals : string, mut; -g_ty_memo_count : int, mut; g_ty_memo_cap : int, mut; g_ty_memo_ok : int, mut; -g_ty_steps : int, mut; g_ty_budget_max : int, mut; g_ty_exhausted : int, mut; -g_ty_lits : string, mut; g_ty_lits_cap : int, mut; g_ty_lits_count : int, mut; -g_ty_uncovered : int, mut; // 未覆盖面命中位(如 AK_NAMED 具体行不展开)——P0 只登记不消费 +g_type_terms : string, mut +g_type_term_count : int, mut +g_type_term_cap : int, mut +g_tt_index : string, mut +g_tt_index_cap : int, mut +g_tt_index_count : int, mut +g_tt_nil : int, mut +g_tt_nil_ok : int, mut +g_tt_top : int, mut +g_tt_top_ok : int, mut +g_ty_memo_keys : string, mut +g_ty_memo_vals : string, mut +g_ty_memo_count : int, mut +g_ty_memo_cap : int, mut +g_ty_memo_ok : int, mut +g_ty_steps : int, mut +g_ty_budget_max : int, mut +g_ty_exhausted : int, mut +g_ty_lits : string, mut +g_ty_lits_cap : int, mut +g_ty_lits_count : int, mut +g_ty_uncovered : int, mut // 未覆盖面命中位(如 AK_NAMED 具体行不展开)——P0 只登记不消费 // R2 P2b Task 1:本质条目表(native interface entries,spec §2)——40B/条 × 5 字段 // {ak, ti_row, name_ni, lit_code, ops},布局常量与表本体(iface_registry.cr)+ 查询 API @@ -422,7 +620,9 @@ g_ty_uncovered : int, mut; // 未覆盖面命中位(如 AK_NAMED 具 // 的层,且本文件恒在最前)。 // **不 alloc g_types 行、不占类型行号**(先例 init_builtins 的 g_rt_builtin_* 旁表) // ⇒ `.ccr` 类型段/行号零扰动。ok 位 = 惰性建表旗标(0 初值惯例,见上方 g_tt_nil_ok 注记)。 -g_iface_entries : string, mut; g_iface_entry_count : int, mut; g_iface_registry_ok : int, mut; +g_iface_entries : string, mut +g_iface_entry_count : int, mut +g_iface_registry_ok : int, mut // R2 P2b Task 4:操作许可位集的**位下标常量**(spec §2.1「操作许可」;表数据在 // iface_registry.cr 的 ops 列,消费点在 checker.cr 的三个门)。 @@ -438,9 +638,14 @@ g_iface_entries : string, mut; g_iface_entry_count : int, mut; g_iface_regis // **声明位置约束**(Task 1 实测登记):bootstrap 名字解析对变量/常量按声明序、跨文件前向引用 // 不成立 —— checker.cr 位于 iface_registry.cr **之前**,故 IP_* 必须声明在本文件(checker.cr 可直接 // 引用 `IP_COND` 等);**函数**不受此限(checker.cr 可前向引用 iface_* 函数)。 -IP_UOP_BIAS : int = 20; -IP_INDEX : int = 25; IP_INDEX_RANGE : int = 26; IP_FIELD : int = 27; -IP_METHOD : int = 28; IP_AS : int = 29; IP_COND : int = 30; IP_COND_BOOL : int = 31; +IP_UOP_BIAS : int = 20 +IP_INDEX : int = 25 +IP_INDEX_RANGE : int = 26 +IP_FIELD : int = 27 +IP_METHOD : int = 28 +IP_AS : int = 29 +IP_COND : int = 30 +IP_COND_BOOL : int = 31 // R2 P1:checker ti → 类型项**桥接缓存**(16B/条 {ti, term};探测/装填因子守卫/扩容重放见 // ty_shadow.cr——桥接层自持,与引擎 g_tt_index 同式)。**这是生产面**(判定路径无条件 @@ -449,8 +654,9 @@ IP_METHOD : int = 28; IP_AS : int = 29; IP_COND : int = 30; IP_COND_BOOL : int // 判定通道已随本任务下线;`sh_` 前缀现为历史前缀,语义 = 「桥接/类型项层」)。影子期的 // 调试计数 `g_shadow_hits` 一并删除(其唯一用途 = 影子对账的命中统计)。 // entries 只增不减、恒等于占用槽数 → 兼作扩容判据(不另设 count 全局)。 -g_term_map : string, mut; g_term_map_cap : int, mut; -g_term_map_entries : int, mut; +g_term_map : string, mut +g_term_map_cap : int, mut +g_term_map_entries : int, mut // R2 P5 Task 2(D19/D23):DFNode 类型面单槽化的拆分出参 + 建项失败位。 // 出参(Core 无多返回值):`sh_tk_split` 先置默认(-1 / 0)再写 ⇒ 无残留状态; @@ -458,8 +664,9 @@ g_term_map_entries : int, mut; // g_tk_face_fail:类型面 op 的 tk **不可译**(越出类型表 / 桥接缺口,D23)⇒ 计数 +1, // save 侧拒绝落盘(rc=1 + 诊断,计数入消息);复合行(域内可译、项不可逆)= 正常 // 路径**不置位**。复位 = init_types()(同 g_replace_* 的生命周期)。 -g_sh_slot_term : int, mut; g_sh_slot_aux : int, mut; -g_tk_face_fail : int, mut; +g_sh_slot_term : int, mut +g_sh_slot_aux : int, mut +g_tk_face_fail : int, mut // **R2 P5 Task 5 删除**(本处 = 影子判定通道的全局态):`g_shadow_on` / `g_shadow_site` / // 四分类桶(total/agree/old_stricter/old_looser/unknown + bridge·engine·uncovered·budget @@ -476,7 +683,9 @@ g_tk_face_fail : int, mut; // 同式同因——P0/P1 三件套缺一即可能挂死)。count 只增不减、恒等于占用槽数 → 兼作扩容 // 判据(不另设 count 之外的全局)。init_types() 置 cap=0 → 类型表重置(行号空间作废) // 时侧表随之惰性重建,防「陈旧 name→ti 复用」把已失效行号当命中(silent miscompile)。 -g_named_dedup : string, mut; g_named_dedup_cap : int, mut; g_named_dedup_count : int, mut; +g_named_dedup : string, mut +g_named_dedup_cap : int, mut +g_named_dedup_count : int, mut // R2 P3 Task 0:引擎展开层的 per-ti 缓存(开放寻址,16B/条 {ti, 展开项})。 // **第二张表**(与 g_term_map 键空间相同 = ti,但**值语义不同**):本表存**展开项** @@ -486,8 +695,10 @@ g_named_dedup : string, mut; g_named_dedup_cap : int, mut; g_named_dedup_ // 生命周期同 g_term_map:init_types() 置 cap=0(sh_unf_map_reset)→ 类型表重置(行号空间 // 作废)时惰性重建,防陈旧 ti→展开项跨请求复用。探测/装填守卫/重建重放/回写重探见 // ty_shadow.cr(与桥接缓存同式同因;count 只增不减、恒等于占用槽数)。 -g_unf_map : string, mut; g_unf_map_cap : int, mut; -g_unf_entries : int, mut; g_unf_hits : int, mut; +g_unf_map : string, mut +g_unf_map_cap : int, mut +g_unf_entries : int, mut +g_unf_hits : int, mut // 效应/纯度修正 Task 1(P0 插队批):泛型实例 → 源映射侧表(24B/条 // {src_fi, type_args_ni, inst_fi},布局同 monomorph.cr 的 g_gen_instances)。 @@ -496,91 +707,132 @@ g_unf_entries : int, mut; g_unf_hits : int, mut; // **声明位置约束**:bootstrap 的名字解析按声明序(跨文件前向引用不成立)—— // checker.cr 的 compute_all_purity 要用本表,故它必须声明在 checker.cr 之前 // (globals.cr)。grow 帮助函数放 monomorph.cr(函数前向引用合法)。 -g_purity_inst : string, mut; g_purity_inst_count : int, mut; g_purity_inst_cap : int, mut; +g_purity_inst : string, mut +g_purity_inst_count : int, mut +g_purity_inst_cap : int, mut // R2 P2a Task 3 的判定回落计数(g_replace_unknown/g_replace_bridge)**R2 P5 Task 4 删除**: // 清零判据成立(全语料 replace_*=0)⇒ 回落面已删(legacy 一并删除);未知面改走 P-A 硬错 // (EC_ICE_TY_INDET,见 checker.cr 的 ty_indeterminate_report)。 -fn grow_plugin_tags(needed: int) { - if needed < g_plugin_tag_cap { return; } - ncap : ., mut = g_plugin_tag_cap * 2; if ncap < 8 { ncap = 8; } if ncap < needed { ncap = needed + 8; } - nb := alloc(ncap * 24); _dyncpy(g_plugin_tags, g_plugin_tag_cap * 24, nb); g_plugin_tags = nb; g_plugin_tag_cap = ncap; } - -fn grow_plugin_rtypes(needed: int) { - if needed < g_plugin_rtype_cap { return; } - ncap : ., mut = g_plugin_rtype_cap * 2; if ncap < 8 { ncap = 8; } if ncap < needed { ncap = needed + 8; } - nb := alloc(ncap * 24); _dyncpy(g_plugin_rtypes, g_plugin_rtype_cap * 24, nb); g_plugin_rtypes = nb; g_plugin_rtype_cap = ncap; } - -fn find_plugin_entry(table: string, count: int, name_ni: int, ns_ni: int) -> int { - if count <= 0 { return -1; } +fn grow_plugin_tags(needed: int): + if needed < g_plugin_tag_cap: + return + ncap : ., mut = g_plugin_tag_cap * 2 + if ncap < 8: + ncap = 8 + if ncap < needed: + ncap = needed + 8 + nb := alloc(ncap * 24) + _dyncpy(g_plugin_tags, g_plugin_tag_cap * 24, nb) + g_plugin_tags = nb + g_plugin_tag_cap = ncap + +fn grow_plugin_rtypes(needed: int): + if needed < g_plugin_rtype_cap: + return + ncap : ., mut = g_plugin_rtype_cap * 2 + if ncap < 8: + ncap = 8 + if ncap < needed: + ncap = needed + 8 + nb := alloc(ncap * 24) + _dyncpy(g_plugin_rtypes, g_plugin_rtype_cap * 24, nb) + g_plugin_rtypes = nb + g_plugin_rtype_cap = ncap + +fn find_plugin_entry(table: string, count: int, name_ni: int, ns_ni: int) -> int: + if count <= 0: + return -1 // Linear scan: match (ns, name) pair - i : ., mut = 0; - loop { if i >= count { break; } - if r64(table, i*24+8) == name_ni && r64(table, i*24) == ns_ni { return i; } - if r64(table, i*24+8) == name_ni && ns_ni < 0 && r64(table, i*24) < 0 { return i; } - i = i + 1; } - return -1; } - -fn register_plugin_tag(ns_ni: int, name_ni: int, data: int) -> int { + i : ., mut = 0 + loop: + if i >= count: + break + if r64(table, i*24+8) == name_ni && r64(table, i*24) == ns_ni: + return i + if r64(table, i*24+8) == name_ni && ns_ni < 0 && r64(table, i*24) < 0: + return i + i = i + 1 + return -1 + +fn register_plugin_tag(ns_ni: int, name_ni: int, data: int) -> int: // Conflict: same (ns, name) can't be registered twice - if find_plugin_entry(g_plugin_tags, g_plugin_tag_count, name_ni, ns_ni) >= 0 { return -2; } + if find_plugin_entry(g_plugin_tags, g_plugin_tag_count, name_ni, ns_ni) >= 0: + return -2 // Plugin with namespace can't shadow an unqualified entry - if ns_ni >= 0 && find_plugin_entry(g_plugin_tags, g_plugin_tag_count, name_ni, -1) >= 0 { return -3; } - grow_plugin_tags(g_plugin_tag_count + 1); - w64(g_plugin_tags, g_plugin_tag_count*24, ns_ni); - w64(g_plugin_tags, g_plugin_tag_count*24+8, name_ni); - w64(g_plugin_tags, g_plugin_tag_count*24+16, data); - g_plugin_tag_count = g_plugin_tag_count + 1; - return 0; } - -fn register_plugin_rtype(ns_ni: int, name_ni: int, data: int) -> int { - if find_plugin_entry(g_plugin_rtypes, g_plugin_rtype_count, name_ni, ns_ni) >= 0 { return -2; } - if ns_ni >= 0 && find_plugin_entry(g_plugin_rtypes, g_plugin_rtype_count, name_ni, -1) >= 0 { return -3; } - grow_plugin_rtypes(g_plugin_rtype_count + 1); - w64(g_plugin_rtypes, g_plugin_rtype_count*24, ns_ni); - w64(g_plugin_rtypes, g_plugin_rtype_count*24+8, name_ni); - w64(g_plugin_rtypes, g_plugin_rtype_count*24+16, data); - g_plugin_rtype_count = g_plugin_rtype_count + 1; - return 0; } + if ns_ni >= 0 && find_plugin_entry(g_plugin_tags, g_plugin_tag_count, name_ni, -1) >= 0: + return -3 + grow_plugin_tags(g_plugin_tag_count + 1) + w64(g_plugin_tags, g_plugin_tag_count*24, ns_ni) + w64(g_plugin_tags, g_plugin_tag_count*24+8, name_ni) + w64(g_plugin_tags, g_plugin_tag_count*24+16, data) + g_plugin_tag_count = g_plugin_tag_count + 1 + return 0 + +fn register_plugin_rtype(ns_ni: int, name_ni: int, data: int) -> int: + if find_plugin_entry(g_plugin_rtypes, g_plugin_rtype_count, name_ni, ns_ni) >= 0: + return -2 + if ns_ni >= 0 && find_plugin_entry(g_plugin_rtypes, g_plugin_rtype_count, name_ni, -1) >= 0: + return -3 + grow_plugin_rtypes(g_plugin_rtype_count + 1) + w64(g_plugin_rtypes, g_plugin_rtype_count*24, ns_ni) + w64(g_plugin_rtypes, g_plugin_rtype_count*24+8, name_ni) + w64(g_plugin_rtypes, g_plugin_rtype_count*24+16, data) + g_plugin_rtype_count = g_plugin_rtype_count + 1 + return 0 // ─── 前端状态重置(LSP 进程内重复检查)────────────────────────────── // 清 count 保留 cap(缓冲复用);g_strs/g_str_hash 驻留表不重置。 // 与 tokenize/res_imports/parse_all/check_all 各自内部的清零互补——防御 // 上次运行残留(尤其是 parse 阶段诊断后跳过 check_all 时 g_diags 不清零 // 导致的"幽灵诊断")。g_open_docs 是 LSP 文档源(跨检查持久),不在此清。 -fn reset_frontend_state() { - g_token_count = 0; - g_ast_count = 0; - g_error_count = 0; - g_diag_count = 0; - g_block_stmt_count = 0; - g_func_count = 0; g_struct_count = 0; g_enum_count = 0; - g_sym_count = 0; g_type_count = 0; - g_iface_count = 0; g_impl_for_count = 0; g_method_count = 0; - g_type_alias_count = 0; g_generic_constr_count = 0; g_gen_param_count = 0; +fn reset_frontend_state(): + g_token_count = 0 + g_ast_count = 0 + g_error_count = 0 + g_diag_count = 0 + g_block_stmt_count = 0 + g_func_count = 0 + g_struct_count = 0 + g_enum_count = 0 + g_sym_count = 0 + g_type_count = 0 + g_iface_count = 0 + g_impl_for_count = 0 + g_method_count = 0 + g_type_alias_count = 0 + g_generic_constr_count = 0 + g_gen_param_count = 0 // R2 P3 Task 5:三条新侧表与声明表同生命周期(si/ei/调用点下标跨编译复用——不清则 // 陈旧约束/绑定被新声明命中,静默错判;照 g_generic_constr_count 同址同因) - g_sgen_constr_count = 0; g_egen_constr_count = 0; g_gen_binds_count = 0; + g_sgen_constr_count = 0 + g_egen_constr_count = 0 + g_gen_binds_count = 0 // R2 P3b Task 0:形状条目表与声明表同生命周期(注册名 = 驻留 ni,跨编译复用会命中陈旧条目 // ⇒ 静默错判;照 g_sgen_constr_count 同址同因)。`g_strs` 驻留表本身不重置(名字 ni 稳定)。 - g_iface_shape_count = 0; + g_iface_shape_count = 0 // 批 6 T2:规约标注侧表与声明表同生命周期(函数名 ni/ast 下标跨编译复用 ⇒ 不清会命中 // 陈旧标注;照 g_iface_shape_count 同址同因;`g_strs` 驻留表不重置——名字 ni 稳定)。 - g_spec_count = 0; - g_global_let_count = 0; - g_loop_depth = 0; g_scope_depth = 0; - g_borrow_count = 0; g_holder_count = 0; - g_borrow_scope_depth = 0; - g_gen_map_count = 0; g_dyn_type_set_count = 0; - g_mod_func_count = 0; g_mod_path_count = 0; - g_file_count = 0; g_mod_count = 0; + g_spec_count = 0 + g_global_let_count = 0 + g_loop_depth = 0 + g_scope_depth = 0 + g_borrow_count = 0 + g_holder_count = 0 + g_borrow_scope_depth = 0 + g_gen_map_count = 0 + g_dyn_type_set_count = 0 + g_mod_func_count = 0 + g_mod_path_count = 0 + g_file_count = 0 + g_mod_count = 0 // Task 1 侧表与 g_func_count 同生命周期(fi 下标会整体复用——不清则陈旧 // 映射把新函数的纯度算到旧实例上,静默错标) - g_purity_inst_count = 0; - g_df_state_finalized = 0; // 与上同理:链重建每编译恰一次(幂等旗标随前端状态复位) - g_seg_count = 0; g_line_count = 0; - g_unsafe_depth = 0; - g_alloc_pts_cap = 0; - g_checker_current_fi = 0; -} + g_purity_inst_count = 0 + g_df_state_finalized = 0 // 与上同理:链重建每编译恰一次(幂等旗标随前端状态复位) + g_seg_count = 0 + g_line_count = 0 + g_unsafe_depth = 0 + g_alloc_pts_cap = 0 + g_checker_current_fi = 0 diff --git a/src/compiler/iface_axis.cr b/src/compiler/iface_axis.cr index b54dd7e3..0230d831 100644 --- a/src/compiler/iface_axis.cr +++ b/src/compiler/iface_axis.cr @@ -43,16 +43,19 @@ // `ty_budget_reset`、返回前再复位——memo 跨查询命中会让结果依赖预算历史(P0 终审 Critical 3)。 // 本常量 = 与 `gen_constr_satisfied` 同值(两处同为「一遍桥接 + 一次包含判定」的规模; // 常量定义在本文件(调用面在其后),`globals.cr` 无 IFACE_* 预算位)。 -IFACE_SAT_BUDGET : int = 200000; +IFACE_SAT_BUDGET : int = 200000 -fn iface_satisfies(t_ti: int, iface_ni: int) -> int { - if t_ti < 0 { return -1; } - if iface_ni < 0 { return -1; } +fn iface_satisfies(t_ti: int, iface_ni: int) -> int: + if t_ti < 0: + return -1 + if iface_ni < 0: + return -1 // ── 轴 A:横切形状名(空表 ⇒ 未命中,落下方轴)── - st := iface_shape_lookup(iface_ni); - if st >= 0 { return iface_satisfies_term(t_ti, st); } + st := iface_shape_lookup(iface_ni) + if st >= 0: + return iface_satisfies_term(t_ti, st) // ── 轴 C:用户接口(`find_iface` 命中 ⇒ 用户轴;不得再落本质轴)── - if find_iface(iface_ni) >= 0 { + if find_iface(iface_ni) >= 0: // 形状项路由(R2 P3b Task 6 Step 1/3 已落地):形状项 = 接口方法集(product of fn, // 建项见 ty_shadow.cr 的 sh_iface_shape_term),判定 = **逐成员包含**(下述 // iface_user_satisfies:方法名经 impl 方法表查表 + 成员 fn 项经引擎 ty_sub)。 @@ -62,39 +65,42 @@ fn iface_satisfies(t_ti: int, iface_ni: int) -> int { // ② product 的引擎比较是**不变槽链结构相等**而非子集包含 ⇒ 方法集 ⊇ 形状集 // (实现方带额外方法,常态)会被误拒。 // ⇒ 整形状 ty_sub 路由**不可用**(登记为未覆盖面);形状项作为签名载体由逐成员判定消费。 - return iface_user_satisfies(t_ti, iface_ni); - } + return iface_user_satisfies(t_ti, iface_ni) // ── 轴 B:本质轴(原生/已声明类型名;非类型名 ⇒ -1 = 不判,不发明诊断)── - cti := gen_constr_type_ti(iface_ni); - if cti < 0 { return -1; } - return iface_satisfies_ti(t_ti, cti); -} + cti := gen_constr_type_ti(iface_ni) + if cti < 0: + return -1 + return iface_satisfies_ti(t_ti, cti) // ─── 引擎面原语(Task 2 的无名字消费点可直接用 `iface_satisfies_term`)─── // `实参行 <: 形状项`:桥接失败(行不可译)⇒ -1;否则 `ty_sub` 三态**直传**(-1 上抛)。 -fn iface_satisfies_term(t_ti: int, shape: int) -> int { - if t_ti < 0 { return -1; } - if shape < 0 { return -1; } - a := sh_term_of_ti(t_ti); - if a < 0 { return -1; } - ty_budget_reset(IFACE_SAT_BUDGET); - s := ty_sub(a, shape); - ty_budget_reset(IFACE_SAT_BUDGET); - return s; -} +fn iface_satisfies_term(t_ti: int, shape: int) -> int: + if t_ti < 0: + return -1 + if shape < 0: + return -1 + a := sh_term_of_ti(t_ti) + if a < 0: + return -1 + ty_budget_reset(IFACE_SAT_BUDGET) + s := ty_sub(a, shape) + ty_budget_reset(IFACE_SAT_BUDGET) + return s // `实参行 <: 约束行`(本质轴;= gen_constr_satisfied 的引擎面) -fn iface_satisfies_ti(t_ti: int, cti: int) -> int { - if t_ti < 0 { return -1; } - if cti < 0 { return -1; } - a := sh_term_of_ti(t_ti); - b := sh_term_of_ti(cti); - if a < 0 || b < 0 { return -1; } - ty_budget_reset(IFACE_SAT_BUDGET); - s := ty_sub(a, b); - ty_budget_reset(IFACE_SAT_BUDGET); - return s; -} +fn iface_satisfies_ti(t_ti: int, cti: int) -> int: + if t_ti < 0: + return -1 + if cti < 0: + return -1 + a := sh_term_of_ti(t_ti) + b := sh_term_of_ti(cti) + if a < 0 || b < 0: + return -1 + ty_budget_reset(IFACE_SAT_BUDGET) + s := ty_sub(a, b) + ty_budget_reset(IFACE_SAT_BUDGET) + return s // 方法行查找:`(类型名 ni, 方法名 ni) → mangled 函数名 ni`(-1 = 无此方法)。 // 数据面 = parser 在 impl 块登记的 `g_methods`(24B/条 {type_ni, method_ni, mangled_ni}, @@ -104,19 +110,20 @@ fn iface_satisfies_ti(t_ti: int, cti: int) -> int { // ⚠ 本函数**零 str_intern**:查名走表、不构造串——方法缺失(= 判定 0 的路径)不得往 g_strs // 追加新串(.ccr STR 段硬判据;`type_has_method` 的 str_intern 只对**已存在**方法名幂等, // 对缺失方法名会增长驻留表——本层刻意避开该形态)。 -fn iface_find_method(type_ni: int, method_ni: int) -> int { - if type_ni < 0 { return -1; } - if method_ni < 0 { return -1; } - i : ., mut = 0; - loop { - if i >= g_method_count { return -1; } - if r64(g_methods, i * 24) == type_ni { - if r64(g_methods, i * 24 + 8) == method_ni { return r64(g_methods, i * 24 + 16); } - } - i = i + 1; - } - return -1; -} +fn iface_find_method(type_ni: int, method_ni: int) -> int: + if type_ni < 0: + return -1 + if method_ni < 0: + return -1 + i : ., mut = 0 + loop: + if i >= g_method_count: + return -1 + if r64(g_methods, i * 24) == type_ni: + if r64(g_methods, i * 24 + 8) == method_ni: + return r64(g_methods, i * 24 + 16) + i = i + 1 + return -1 // ─── 轴 C:用户接口的满足谓词(**与 check_iface 同源**;R2 P3b Task 6 Step 3 重写)─── // 语义(spec §2.3):`interface I` 的形状类型项 = 方法集(product of fn,建项 = @@ -136,40 +143,55 @@ fn iface_find_method(type_ni: int, method_ni: int) -> int { // 接口侧不产生该形态(`interface I[T]` 的形参被 parser 丢弃,登记);`dyn` 位图行不参与 // 规范形 ⇒ 含 dyn 的签名 = -1 不判。 // 预算隔离:每次引擎查询前后 `ty_budget_reset`(照本文件其它入口同款)。 -fn iface_user_satisfies(t_ti: int, iface_ni: int) -> int { - ii := find_iface(iface_ni); - if ii < 0 { return -1; } +fn iface_user_satisfies(t_ti: int, iface_ni: int) -> int: + ii := find_iface(iface_ni) + if ii < 0: + return -1 // 域限定:仅命名行(TYP_NAMED / TYP_GENERIC_APPLY 的基名)有方法表身份;其余 ⇒ 不判。 // 用 decl_name_of_ti(展开层的行→声明入口)而非 get_type_name:后者对 TYP_BASE 行会 // str_intern 基类型名(本层禁止驻留表增长,见 iface_find_method 注)。 - tname_ni := decl_name_of_ti(t_ti); - if tname_ni < 0 { return -1; } - return iface_user_satisfies_ii(tname_ni, ii); -} + tname_ni := decl_name_of_ti(t_ti) + if tname_ni < 0: + return -1 + return iface_user_satisfies_ii(tname_ni, ii) // 名字面核心(`iface_user_satisfies` 与 checker 的 `check_iface` 的**共同实现**——两侧 // 同源由构造保证,selftest `isat.predicate_same_as_check_iface` 仍逐例对拍)。 -fn iface_user_satisfies_ii(tname_ni: int, ii: int) -> int { - if tname_ni < 0 || ii < 0 { return -1; } - mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT); - if mc < 0 || mc > MAX_IFACE_METHODS { return -1; } - shp := sh_iface_shape_term(r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_NAME)); - if shp < 0 { return -1; } - mi : ., mut = 0; - loop { - if mi >= mc { return 1; } - mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD; - m_ni := r64(g_ifaces, mbase + OFF_IFM_NAME); - f_ni := iface_find_method(tname_ni, m_ni); - if f_ni < 0 { return 0; } // 无此方法 = 可证违反(名字面忠实) - fi := find_func(f_ni); - if fi < 0 { return -1; } // 表内不一致 ⇒ 不判(不发明违反) - if sh_iface_self_mode(ii, mi) != sh_func_self_mode(fi) { return 0; } // 接收者模式 +fn iface_user_satisfies_ii(tname_ni: int, ii: int) -> int: + if tname_ni < 0 || ii < 0: + return -1 + mc := r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_METHOD_COUNT) + if mc < 0 || mc > MAX_IFACE_METHODS: + return -1 + shp := sh_iface_shape_term(r64(g_ifaces, ii * ESZ_IFACEINFO + OFF_IF_NAME)) + if shp < 0: + return -1 + mi : ., mut = 0 + loop: + if mi >= mc: + return 1 + mbase := ii * ESZ_IFACEINFO + OFF_IF_METHODS + mi * ESZ_IFMETHOD + m_ni := r64(g_ifaces, mbase + OFF_IFM_NAME) + f_ni := iface_find_method(tname_ni, m_ni) + if f_ni < 0: + return 0 + // 无此方法 = 可证违反(名字面忠实) + fi := find_func(f_ni) + if fi < 0: + return -1 + // 表内不一致 ⇒ 不判(不发明违反) + if sh_iface_self_mode(ii, mi) != sh_func_self_mode(fi): + return 0 + // 接收者模式 - ifm := sh_shape_member_at(shp, mi); - if ifm < 0 { return -1; } // 形状项与方法表失同步 ⇒ 不判 - implf := sh_func_sig_term(fi); - if implf < 0 { return -1; } // impl 侧签名项不可建 ⇒ 不判 + ifm := sh_shape_member_at(shp, mi) + if ifm < 0: + return -1 + // 形状项与方法表失同步 ⇒ 不判 + implf := sh_func_sig_term(fi) + if implf < 0: + return -1 + // impl 侧签名项不可建 ⇒ 不判 // 判定 = 引擎的**不变槽结构比较原语** `tt_list_same`(0/1 **全域**)——**不是** // 直接 `ty_sub`:引擎在不变槽上把「确定不同」上抛为 -1(type_engine 的 // tt_list_variance_at 分支:`tt_type_elem_same != 1 → g_ty_uncovered = 1; return -1`, @@ -179,11 +201,10 @@ fn iface_user_satisfies_ii(tname_ni: int, ii: int) -> int { // 正确判据。**比的是 fn 项的链**(`tt_c`):fn 原子的 b 槽 = 方法名(接口侧标注; // impl 侧为 -1)是元数据不入签名——整项同一是 `tt_list_same` 的「非 CONS ⇒ 节点同一」 // 规则下的假不等(实测命中)。本原语不计步(不动预算/memo)⇒ 无需预算隔离。 - if tt_list_same(tt_c(implf), tt_c(ifm)) != 1 { return 0; } - mi = mi + 1; - } - return 1; -} + if tt_list_same(tt_c(implf), tt_c(ifm)) != 1: + return 0 + mi = mi + 1 + return 1 // checker 类型行号 → AK_*(-1 = 越界/负)。 // 分派表 = 侦查 §4.1 的 checker 侧原子宇宙 13 类,与条目表的 ak 列同源。 @@ -193,18 +214,29 @@ fn iface_user_satisfies_ii(tname_ni: int, ii: int) -> int { // TYP_DYN 行回 AK_DYN、对结构/命名行回其类,而 sh_native_ak 对同样这些行回 -1——「单源化」 // = 两入口共用**逐项分派表**,不是把两个入口合并成同一语义(type_selftest.cr 的 // `iface.bridge_gate_kept` 把该差异钉在红)。 -fn iface_kind_of(ti: int) -> int { - k := get_type_kind(ti); - if k < 0 { return -1; } // 负值/越界行(get_type_kind 已做范围闸) - if k == TYP_BASE { return iface_by_ty_code(get_type_data(ti)); } - if k == TYP_DYN { return AK_DYN; } - if k == TYP_NAMED { return AK_NAMED; } - if k == TYP_GENERIC_PARAM { return AK_NAMED; } - if k == TYP_GENERIC_APPLY { return AK_NAMED; } - if k == TYP_ARRAY { return AK_SEQUENCE; } - if k == TYP_SLICE { return AK_SEQUENCE; } - if k == TYP_REF { return AK_REF; } - if k == TYP_PTR { return AK_PTR; } - if k == TYP_TUPLE { return AK_PRODUCT; } - return -1; // 未知 kind(当前类型表无此情形) -} +fn iface_kind_of(ti: int) -> int: + k := get_type_kind(ti) + if k < 0: + return -1 + // 负值/越界行(get_type_kind 已做范围闸) + if k == TYP_BASE: + return iface_by_ty_code(get_type_data(ti)) + if k == TYP_DYN: + return AK_DYN + if k == TYP_NAMED: + return AK_NAMED + if k == TYP_GENERIC_PARAM: + return AK_NAMED + if k == TYP_GENERIC_APPLY: + return AK_NAMED + if k == TYP_ARRAY: + return AK_SEQUENCE + if k == TYP_SLICE: + return AK_SEQUENCE + if k == TYP_REF: + return AK_REF + if k == TYP_PTR: + return AK_PTR + if k == TYP_TUPLE: + return AK_PRODUCT + return -1 // 未知 kind(当前类型表无此情形) diff --git a/src/compiler/iface_registry.cr b/src/compiler/iface_registry.cr index 66412249..a1249758 100644 --- a/src/compiler/iface_registry.cr +++ b/src/compiler/iface_registry.cr @@ -62,12 +62,15 @@ // 位构造(乘 2 循环,照既有 dyn_set_type 惯例——本语言无移位运算符)。下标语义见 globals.cr // 的 IP_* 块;n ≥ 63 时 i64 负号翻转(= 全位命中)由 `iface_permits` 的越界闸拒绝,本函数只 // 供表内**已知常量**使用,不做校验(表内容 = 常量,n 恒 < 32)。 -fn iface_bit(n: int) -> int { - b : ., mut = 1; - k : ., mut = n; - loop { if k <= 0 { break; } b = b * 2; k = k - 1; } - return b; -} +fn iface_bit(n: int) -> int: + b : ., mut = 1 + k : ., mut = n + loop: + if k <= 0: + break + b = b * 2 + k = k - 1 + return b // ─── 建表(由 init_types() 尾部调用;幂等)─── // 表内容 = 常量(AK_*/TI_*/-1/0)+ **注册名 ni**(R2 P4 Task 3 起)⇒ 不读类型表、不缓存行号、 @@ -81,67 +84,68 @@ fn iface_bit(n: int) -> int { // 换结构性判据(TODO #2026-09-11-9);IFACE 段 ① 小节要求 name_ni 是 STR 段内的合法索引(跨段引用域 // 检查),无名的条目表无法兑现「信息恒随载体」。⇒ 本函数 = 生产注册面(**固定增量**: // 逐名列举于下,守门用例按新口径重定「判定/查询路径零新增驻留 + 初始化面固定增量」)。 -fn iface_registry_init() { - if g_iface_registry_ok != 0 { return; } // 幂等(内容恒定,无需重建) - g_iface_entries = alloc(IFACE_ENTRY_COUNT * ESZ_IFACE_ENTRY); - g_iface_entry_count = IFACE_ENTRY_COUNT; +fn iface_registry_init(): + if g_iface_registry_ok != 0: + return + // 幂等(内容恒定,无需重建) + g_iface_entries = alloc(IFACE_ENTRY_COUNT * ESZ_IFACE_ENTRY) + g_iface_entry_count = IFACE_ENTRY_COUNT // ─── ops 列组位集(Task 4 逐格填写;每格注现状 checker.cr 行号 = 逐格转录依据)─── // 算术门(唯一消费者 = checker.cr:1959 的 ANY 门):**只含 int/dex**——这不是省事,而是与 // :1959 一字等价所要求的最小集。现状「算术许可」是**两层**:早退规则(串拼接 :1946 / // 指针算术 :1948+:1951 / 指针差 :1955)命中即 return、不会走到门;门只管「两侧皆非数值才 // 报错」。故把 PTR/STRING 填进本组 = **放宽**(ANY 语义下 permits(PTR,ADD)=1 足以放行 // `*T + *T`、`"a" - "b"`——两条现状均为 error[TB01],有负控钉红)。 - o_arith := iface_bit(OP_ADD) + iface_bit(OP_SUB) + iface_bit(OP_MUL) + iface_bit(OP_DIV) + iface_bit(OP_MOD); + o_arith := iface_bit(OP_ADD) + iface_bit(OP_SUB) + iface_bit(OP_MUL) + iface_bit(OP_DIV) + iface_bit(OP_MOD) // 逻辑族(消费者 = checker.cr:1969 的 ALL 门):现状每侧须 `bool|int`(:1969 逐字: // `(lt != BOOL && lt != INT) || (rt != BOOL && rt != INT)`)⇒ 本组**恰 {int, bool}**。 // ⚠ 计划 Task 4 许可格表把本组写在「AK_INT/AK_DEX」行(括注「允许 bool|int」自相矛盾)—— // **实测裁决**:dex 在现状被拒(`1.5 && true` → error[TC01],探针实测)⇒ DEX 格必为 0, // 否则 = 放宽。取「与 :1969 一字等价」为准(计划 Step 2 的替换代码即此要求)。 - o_logic := iface_bit(OP_AND) + iface_bit(OP_OR); + o_logic := iface_bit(OP_AND) + iface_bit(OP_OR) // 比较族(:1965-1967 六个比较 op 恒返 bool、**不校验操作数**)+ 一元族(:1979 NEG/NOT 透传、 // :1982 REF 对任意操作数产 TYP_PTR、:2003-2014 DEREF 兜底透传)+ 转换(:2892-2908 除 PTR 的 // asp 外恒等透传)⇒ **对全部 13 类置 1**(现状宽松面的集中体现;P3 收紧旋钮,本批只登记)。 // 口径:这四项在现状**没有拒绝路径**,故本批不接线(无门可换)——表登记为 P3 的可审计位。 - o_cmp := iface_bit(OP_EQ) + iface_bit(OP_NE) + iface_bit(OP_LT) + iface_bit(OP_GT) + iface_bit(OP_LE) + iface_bit(OP_GE); - o_un := iface_bit(IP_UOP_BIAS + UOP_NEG) + iface_bit(IP_UOP_BIAS + UOP_NOT) + - iface_bit(IP_UOP_BIAS + UOP_REF) + iface_bit(IP_UOP_BIAS + UOP_DEREF); - o_base := o_cmp + o_un + iface_bit(IP_AS); // 13 类共有面(比较/一元/转换全许可) - o_cond := iface_bit(IP_COND); // `if`(:2274 收 bool|int) - o_cond_b := iface_bit(IP_COND_BOOL); // `while`(:2385 **只收 bool**——不得与上合并) + o_cmp := iface_bit(OP_EQ) + iface_bit(OP_NE) + iface_bit(OP_LT) + iface_bit(OP_GT) + iface_bit(OP_LE) + iface_bit(OP_GE) + o_un := iface_bit(IP_UOP_BIAS + UOP_NEG) + iface_bit(IP_UOP_BIAS + UOP_NOT) + iface_bit(IP_UOP_BIAS + UOP_REF) + iface_bit(IP_UOP_BIAS + UOP_DEREF) + o_base := o_cmp + o_un + iface_bit(IP_AS) // 13 类共有面(比较/一元/转换全许可) + o_cond := iface_bit(IP_COND) // `if`(:2274 收 bool|int) + o_cond_b := iface_bit(IP_COND_BOOL) // `while`(:2385 **只收 bool**——不得与上合并) // 8 原生(ti_row 取 TI_* 常量;AK↔TI 逐项分派——bool/string 两行按语义错位书写) // 第 4 参 = name_ni(R2 P4 Task 3:生产注册面固定增量——逐名 = 下表 16 行;见头注) // AK_INT :门 + 逻辑 + 条件(:2274 收 int)——**无 IP_COND_BOOL**(:2385 拒 int,探针 N9 实测) - iface_put(0, AK_INT, TI_INT, str_intern("int"), EXPR_INT, o_base + o_arith + o_logic + o_cond); + iface_put(0, AK_INT, TI_INT, str_intern("int"), EXPR_INT, o_base + o_arith + o_logic + o_cond) // AK_DEX :仅门——逻辑/条件均**不含 dex**(:1969/:2274 只认 bool|int;探针 N7/N8 实测拒) - iface_put(1, AK_DEX, TI_DEX, str_intern("dex"), EXPR_DEX, o_base + o_arith); + iface_put(1, AK_DEX, TI_DEX, str_intern("dex"), EXPR_DEX, o_base + o_arith) // AK_STRING:无算术/逻辑/条件(串拼接走 :1946 早退,不进本表);索引面 = :2619(串下标→int) // ——Task 5:IP_INDEX 已接线(兜底门;串的**结果**分支 :2644 原地保留) - iface_put(2, AK_STRING, TI_STR, str_intern("string"), EXPR_STRING, o_base + iface_bit(IP_INDEX)); + iface_put(2, AK_STRING, TI_STR, str_intern("string"), EXPR_STRING, o_base + iface_bit(IP_INDEX)) // AK_BOOL :逻辑 + 两条条件位(:2274 收 bool、:2385 收 bool) - iface_put(3, AK_BOOL, TI_BOOL, str_intern("bool"), EXPR_BOOL, o_base + o_logic + o_cond + o_cond_b); - iface_put(4, AK_UNIT, TI_UNIT, str_intern("unit"), -1, o_base); - iface_put(5, AK_NEVER, TI_NEVER, str_intern("never"), -1, o_base); - iface_put(6, AK_CHAR, TI_CHAR, str_intern("char"), EXPR_CHAR, o_base); + iface_put(3, AK_BOOL, TI_BOOL, str_intern("bool"), EXPR_BOOL, o_base + o_logic + o_cond + o_cond_b) + iface_put(4, AK_UNIT, TI_UNIT, str_intern("unit"), -1, o_base) + iface_put(5, AK_NEVER, TI_NEVER, str_intern("never"), -1, o_base) + iface_put(6, AK_CHAR, TI_CHAR, str_intern("char"), EXPR_CHAR, o_base) // AK_DYN :+ 方法面(:2066 dyn 方法校验路径)——Task 5:**未接线**(该路径的拒绝谓词 = // `type_has_method(具体行名, 方法名)`(名拼接方法表判定),非本类级位;实测 int/string // 行今日也发 EC_N_METHOD(探针 D1/D4)⇒ 类级门会抑制 = 放宽) - iface_put(7, AK_DYN, TI_DYN, str_intern("dyn"), -1, o_base + iface_bit(IP_METHOD)); + iface_put(7, AK_DYN, TI_DYN, str_intern("dyn"), -1, o_base + iface_bit(IP_METHOD)) // 结构/命名(ti_row = -1 = 类级,无「规范行」) // AK_PRODUCT :+ 字段面(:2566-2577 元组 `.N`)——Task 5:IP_FIELD **未接线**(落空 // `return TI_UNIT` 无诊断;其前的 kind 分支是结果规则) - iface_put(8, AK_PRODUCT, -1, str_intern("product"), -1, o_base + iface_bit(IP_FIELD)); + iface_put(8, AK_PRODUCT, -1, str_intern("product"), -1, o_base + iface_bit(IP_FIELD)) // AK_SEQUENCE:+ 索引面(:2605-2618 数组/切片元素 + F2 越界;:2586 range→slice) // ——Task 5:IP_INDEX 已接线(兜底门;ARRAY/SLICE 的**结果**分支原地保留); // IP_INDEX_RANGE **未接线**(range 分支 :2612-2627 的非数组落空 `return TI_UNIT` 无诊断 // ⇒ 门恒真 = 空转;登记为 P3 旋钮) - iface_put(9, AK_SEQUENCE, -1, str_intern("sequence"), -1, o_base + iface_bit(IP_INDEX) + iface_bit(IP_INDEX_RANGE)); + iface_put(9, AK_SEQUENCE, -1, str_intern("sequence"), -1, o_base + iface_bit(IP_INDEX) + iface_bit(IP_INDEX_RANGE)) // AK_REF/AK_PTR:门全 0——**指针算术由 :1948-1955 早退承担**(结果规则留代码),非本表 - iface_put(10, AK_REF, -1, str_intern("ref"), -1, o_base); - iface_put(11, AK_PTR, -1, str_intern("ptr"), -1, o_base); + iface_put(10, AK_REF, -1, str_intern("ref"), -1, o_base) + iface_put(11, AK_PTR, -1, str_intern("ptr"), -1, o_base) // AK_NAMED :+ 字段面(:2522-2563 struct 字段表)+ 方法面(:2088 方法表)——Task 5: // 两位均**未接线**(EXPR_FIELD 全形 rc=0、零诊断路径;方法面 = 逐方法表名判定, // 同 AK_DYN 注的理由);登记为 P3 旋钮 - iface_put(12, AK_NAMED, -1, str_intern("named"), -1, o_base + iface_bit(IP_FIELD) + iface_bit(IP_METHOD)); + iface_put(12, AK_NAMED, -1, str_intern("named"), -1, o_base + iface_bit(IP_FIELD) + iface_bit(IP_METHOD)) // ─── R2 P4 Task 3 扩列(裁决 3 + 7):13 → 16 —— **纯信息面**(只加「可查询性」)─── // 三行共同点:ti_row = -1(无规范行;ti_row 是**行级**面,本三原子是类级/无行)、lit_code = -1 // (无字面量)、ops = 0(**无操作许可**——null/sum/fn 面在现状对算术/逻辑/条件门全拒, @@ -150,95 +154,102 @@ fn iface_registry_init() { // `TYP_OPTIONAL`/`TYP_DYN` 等行的分派与 P2b 钉死的域逐格保持;扩列只加「可查询性」, // 不加「行 → 类」新映射(守门 = selftest 的全类型行枚举用例 + t4.null_no_ops_no_entry 重定)。 // AK_NULL(裁决 7:独立原子槽,不作 ⊥ 折叠——`type_engine.cr` 的 AK_NULL 语义零改动) - iface_put(13, AK_NULL, -1, str_intern("null"), -1, 0); + iface_put(13, AK_NULL, -1, str_intern("null"), -1, 0) // AK_SUM(枚举/联合的类级原子;checker 侧枚举类型行 = TYP_NAMED ⇒ 本行无行分派, // 忠实反映「checker 侧无 AK_SUM 行」这一现状——登记面而非新映射) - iface_put(14, AK_SUM, -1, str_intern("sum"), -1, 0); + iface_put(14, AK_SUM, -1, str_intern("sum"), -1, 0) // AK_FN(函数类型项(AK_FN)的类级原子;checker 侧无函数类型行 ⇒ 同行分派现状) - iface_put(15, AK_FN, -1, str_intern("fn"), -1, 0); - g_iface_registry_ok = 1; -} + iface_put(15, AK_FN, -1, str_intern("fn"), -1, 0) + g_iface_registry_ok = 1 // 单行写入(照 init_builtins 的 bi_add 先例:表驱动的写入收敛到一处) -fn iface_put(e: int, ak: int, ti: int, name_ni: int, lit_code: int, ops: int) { - w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_AK, ak); - w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_TI, ti); - w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_NAME, name_ni); - w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_LIT, lit_code); - w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_OPS, ops); -} +fn iface_put(e: int, ak: int, ti: int, name_ni: int, lit_code: int, ops: int): + w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_AK, ak) + w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_TI, ti) + w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_NAME, name_ni) + w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_LIT, lit_code) + w64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_OPS, ops) // 未建表守卫(init_types 会建;此处兜「查询早于 init_types」——自测通道/未来调用点不得读空表: // 空表指针 + 线性扫 = 立即越界读)。照 ty_memo_slot 的 ok 位惰性建表先例(type_engine.cr:256)。 -fn iface_ensure() { - if g_iface_registry_ok == 0 { iface_registry_init(); } -} +fn iface_ensure(): + if g_iface_registry_ok == 0: + iface_registry_init() // ─── 查询 API(spec §2.5)─── -fn iface_count() -> int { return IFACE_ENTRY_COUNT; } +fn iface_count() -> int: + return IFACE_ENTRY_COUNT // 原子类 → 条目行号(-1 = 无此原子) -fn iface_entry(ak: int) -> int { - iface_ensure(); - i : ., mut = 0; - loop { - if i >= g_iface_entry_count { break; } - if r64(g_iface_entries, i * ESZ_IFACE_ENTRY + OFF_IE_AK) == ak { return i; } - i = i + 1; - } - return -1; -} +fn iface_entry(ak: int) -> int: + iface_ensure() + i : ., mut = 0 + loop: + if i >= g_iface_entry_count: + break + if r64(g_iface_entries, i * ESZ_IFACE_ENTRY + OFF_IE_AK) == ak: + return i + i = i + 1 + return -1 // 操作许可位集(**spec §2.5 的签名**);-1/未知原子 → 全 0 = 无许可 -fn iface_ops(ak: int) -> int { - e := iface_entry(ak); - if e < 0 { return 0; } - return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_OPS); -} +fn iface_ops(ak: int) -> int: + e := iface_entry(ak) + if e < 0: + return 0 + return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_OPS) // 位测试(1/0;op 已含 UOP/IP 偏置——偏置表见 Task 4 的位下标约定)。 // 位下标越界 → 0(**不得**回绕:位构造是「乘 2」循环,op ≥ 63 会把 i64 位集推成负值 = 全位命中)。 -fn iface_permits(ak: int, op: int) -> int { - if op < 0 { return 0; } - if op > 62 { return 0; } - ops := iface_ops(ak); - if ops == 0 { return 0; } - bit : ., mut = 1; - k : ., mut = op; - loop { if k <= 0 { break; } bit = bit * 2; k = k - 1; } - if (ops / bit) % 2 != 0 { return 1; } - return 0; -} +fn iface_permits(ak: int, op: int) -> int: + if op < 0: + return 0 + if op > 62: + return 0 + ops := iface_ops(ak) + if ops == 0: + return 0 + bit : ., mut = 1 + k : ., mut = op + loop: + if k <= 0: + break + bit = bit * 2 + k = k - 1 + if (ops / bit) % 2 != 0: + return 1 + return 0 // 字面量 AST kind → 条目行号(-1 = 非字面量 kind)。查表键 = 条目的 lit_code 列 // (13 条线性扫;AST kind 面只有 5 个命中项)。lit_kind < 0 = 条目的「无字面量」哨兵, // 必须先行拒绝(否则 -1 会把无字面量的条目当成命中)。 -fn iface_lit_entry(lit_kind: int) -> int { - if lit_kind < 0 { return -1; } - iface_ensure(); - i : ., mut = 0; - loop { - if i >= g_iface_entry_count { break; } - if r64(g_iface_entries, i * ESZ_IFACE_ENTRY + OFF_IE_LIT) == lit_kind { return i; } - i = i + 1; - } - return -1; -} +fn iface_lit_entry(lit_kind: int) -> int: + if lit_kind < 0: + return -1 + iface_ensure() + i : ., mut = 0 + loop: + if i >= g_iface_entry_count: + break + if r64(g_iface_entries, i * ESZ_IFACE_ENTRY + OFF_IE_LIT) == lit_kind: + return i + i = i + 1 + return -1 // 字面量 AST kind → TI_*(-1 = 非字面量 kind)——Task 3 已接线:infer_expr(现址 :1896-1901)的 // 5 个字面量分支逐条改调本函数(表 = 唯一真源;`iface.lit_*` 用例 + `lit.infer_*` 端到端用例对拍) -fn iface_lit_ti(lit_kind: int) -> int { - e := iface_lit_entry(lit_kind); - if e < 0 { return -1; } - return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_TI); -} +fn iface_lit_ti(lit_kind: int) -> int: + e := iface_lit_entry(lit_kind) + if e < 0: + return -1 + return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_TI) // 字面量 AST kind → AK_*(同上;交叉断言/引擎侧用) -fn iface_lit_ak(lit_kind: int) -> int { - e := iface_lit_entry(lit_kind); - if e < 0 { return -1; } - return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_AK); -} +fn iface_lit_ak(lit_kind: int) -> int: + e := iface_lit_entry(lit_kind) + if e < 0: + return -1 + return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_AK) // TY_*(基类型码)→ AK_*:逐项语义分派(**唯一实现在此**);-1 = 无对应。 // P2b Task 2 单源化:桥接层 `sh_base_ak` 已改为**薄委托**本函数(改动前的字面拷贝 @@ -246,18 +257,26 @@ fn iface_lit_ak(lit_kind: int) -> int { // 已删**——对拍面改为 type_selftest.cr 的**冻结期望表** `ts_t4_ak_expected`)。 // TY_DEX_S → AK_DEX(同值域不同表示——表示层差异不进类型身份,ty_shadow.cr:78-80 已裁决) // TY_GENERIC_PARAM → AK_NAMED(泛型参数哨兵 → 命名类,不展开;ty_shadow.cr:86 已裁决) -fn iface_by_ty_code(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 iface_by_ty_code(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 // TY_*(基类型码)→ TI_*(类型表行常量);**-1 = 无对应**(调用方自行回落,本表不兜底)。 // P2b Task 6:`res_type_node`/`res_call_type` 的**双份基型分支** + 同族 6 处内联链 @@ -271,35 +290,43 @@ fn iface_by_ty_code(ty: int) -> int { // `t6.R_dex_s_unit`/`t6.C_dex_s_unit` 把「码 8 → TI_UNIT」钉红)。全 src 实测:TY_DEX_S 只出现在 // init_types 的位置公理(checker.cr:253)与注释;无任何 parser/铸点写 `type_val = 8`(parser // 只产 int/dex/bool/string/char/never/dyn 七码 + 复合节点)。**域外码一律 -1**(含负值)。 -fn ty_code_to_ti(ty: int) -> int { - if ty == TY_INT { return TI_INT; } - if ty == TY_DEX { return TI_DEX; } - if ty == TY_BOOL { return TI_BOOL; } - if ty == TY_STRING { return TI_STR; } - if ty == TY_UNIT { return TI_UNIT; } - if ty == TY_NEVER { return TI_NEVER; } - if ty == TY_CHAR { return TI_CHAR; } - if ty == TI_DYN { return TI_DYN; } // ← 现状原样:7 = TY_GENERIC_PARAM 的数值撞车格(见头注) - return -1; -} +fn ty_code_to_ti(ty: int) -> int: + if ty == TY_INT: + return TI_INT + if ty == TY_DEX: + return TI_DEX + if ty == TY_BOOL: + return TI_BOOL + if ty == TY_STRING: + return TI_STR + if ty == TY_UNIT: + return TI_UNIT + if ty == TY_NEVER: + return TI_NEVER + if ty == TY_CHAR: + return TI_CHAR + if ty == TI_DYN: + return TI_DYN + // ← 现状原样:7 = TY_GENERIC_PARAM 的数值撞车格(见头注) + return -1 // iface_kind_of 已移至 iface_axis.cr(R2 P4 Task 0,链接面纯化) // 原子类 → 规范行(8 原生 = TI_*;结构/命名条目 ti_row = -1 ⇒ 恒 -1) -fn iface_ti_of(ak: int) -> int { - e := iface_entry(ak); - if e < 0 { return -1; } - return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_TI); -} +fn iface_ti_of(ak: int) -> int: + e := iface_entry(ak) + if e < 0: + return -1 + return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_TI) // 原子类 → 注册名 ni(R2 P4 Task 3 起非 -1;-1 = 无此原子/未注册)。 // 消费面 = IFACE 段 ① 小节的 name_ni 列 + 自测守门(逐名对拍);**零 str_intern** // (只读表,不构造串——判定/查询路径不得驻留新串)。 -fn iface_name_of(ak: int) -> int { - e := iface_entry(ak); - if e < 0 { return -1; } - return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_NAME); -} +fn iface_name_of(ak: int) -> int: + e := iface_entry(ak) + if e < 0: + return -1 + return r64(g_iface_entries, e * ESZ_IFACE_ENTRY + OFF_IE_NAME) // ═══════════════ R2 P3b Task 0:横切轴形状条目表(`iface_satisfies` 的轴 A)═══════════════ // 语义(spec §2.2):每条横切接口 = **一个形状类型项**(如 `sequence` ⇒ `⊤_SEQUENCE`、 @@ -323,54 +350,60 @@ fn iface_name_of(ak: int) -> int { // 注册(返回行号;-1 = 参数非法)。name_ni < 0 / term < 0 一律拒绝——**不得**把负值当 // 「未注册」哨兵写进表(那会让 lookup 把 -1 名字与空槽混淆)。 -fn iface_shape_register(name_ni: int, term: int) -> int { - if name_ni < 0 { return -1; } - if term < 0 { return -1; } - i : ., mut = 0; - loop { - if i >= g_iface_shape_count { break; } - if r64(g_iface_shape_names, i * 8) == name_ni { - w64(g_iface_shape_terms, i * 8, term); // 覆盖(幂等重注册) - return i; - } - i = i + 1; - } - iface_shape_grow(g_iface_shape_count + 1); - w64(g_iface_shape_names, g_iface_shape_count * 8, name_ni); - w64(g_iface_shape_terms, g_iface_shape_count * 8, term); - g_iface_shape_count = g_iface_shape_count + 1; - return g_iface_shape_count - 1; -} +fn iface_shape_register(name_ni: int, term: int) -> int: + if name_ni < 0: + return -1 + if term < 0: + return -1 + i : ., mut = 0 + loop: + if i >= g_iface_shape_count: + break + if r64(g_iface_shape_names, i * 8) == name_ni: + w64(g_iface_shape_terms, i * 8, term) // 覆盖(幂等重注册) + return i + i = i + 1 + iface_shape_grow(g_iface_shape_count + 1) + w64(g_iface_shape_names, g_iface_shape_count * 8, name_ni) + w64(g_iface_shape_terms, g_iface_shape_count * 8, term) + g_iface_shape_count = g_iface_shape_count + 1 + return g_iface_shape_count - 1 // 查询:名字 ni → 形状项(-1 = 未注册/参数非法) -fn iface_shape_lookup(name_ni: int) -> int { - if name_ni < 0 { return -1; } - i : ., mut = 0; - loop { - if i >= g_iface_shape_count { return -1; } - if r64(g_iface_shape_names, i * 8) == name_ni { return r64(g_iface_shape_terms, i * 8); } - i = i + 1; - } - return -1; -} +fn iface_shape_lookup(name_ni: int) -> int: + if name_ni < 0: + return -1 + i : ., mut = 0 + loop: + if i >= g_iface_shape_count: + return -1 + if r64(g_iface_shape_names, i * 8) == name_ni: + return r64(g_iface_shape_terms, i * 8) + i = i + 1 + return -1 -fn iface_shape_count() -> int { return g_iface_shape_count; } +fn iface_shape_count() -> int: + return g_iface_shape_count // 清空(**仅自测**:形状注册是进程级全局态,自测用例注册后复位,防条目泄漏进后续用例/ // 编译——LSP 长驻进程内多编译共用本表,生产路径的复位点是 reset_frontend_state)。 -fn iface_shape_reset() { g_iface_shape_count = 0; } +fn iface_shape_reset(): + g_iface_shape_count = 0 // 类型项 → AK_*(单一原子;非单一 → -1;⊤ₖ → 其 k)。 // 越界/负项先行拒绝:tt_* 访问器**无范围闸**(约定「调用方保证 0 ≤ i < tt_count()」), // 直接喂 -1 会读到表前偏移。 -fn iface_of_term(t: int) -> int { - if t < 0 { return -1; } - if t >= tt_count() { return -1; } - tg := tt_tag(t); - if tg == TT_ATOM { return tt_a(t); } - if tg == TT_TOP_K { return tt_a(t); } - return -1; // union/inter/not/bot/top/mu/var/nil/cons -} +fn iface_of_term(t: int) -> int: + if t < 0: + return -1 + if t >= tt_count(): + return -1 + tg := tt_tag(t) + if tg == TT_ATOM: + return tt_a(t) + if tg == TT_TOP_K: + return tt_a(t) + return -1 // union/inter/not/bot/top/mu/var/nil/cons // ═══════════════ R2 P3b Task 2:横切轴形状项(Step 1「条目细化」的类型项数据面)══════════════ // spec §2.2:每条横切接口 = **一个形状类型项**,满足判定 = 一条包含判定 `T <: 形状`(与本质轴 @@ -391,7 +424,8 @@ fn iface_of_term(t: int) -> int { // 序列接口(spec §2.2 的 `序列接口 ⟺ sequence<⊤>`,按上方勘误兑现为 ⊤ₖ 类别形)。 // 数组行与切片行同属 AK_SEQUENCE ⇒ 皆满足;`&[T]`/`&mut [T]`(AK_REF 行)**不**满足(见只读形状)。 -fn sh_shape_seq() -> int { return tt_top_k(AK_SEQUENCE); } +fn sh_shape_seq() -> int: + return tt_top_k(AK_SEQUENCE) // 只读序列 = 序列本体(数组/切片)+ **只读视图**(`&[T]`)。 // 「只读 = **协变**」(计划 Step 1):视图部分的元素落在 AK_REF 的**协变槽**(Task 1 变型表: @@ -399,30 +433,33 @@ fn sh_shape_seq() -> int { return tt_top_k(AK_SEQUENCE); } // 也成立)——T1 §6-④ 登记的「只读序列形状」在**视图面**由此闭合。 // **等式语义**(Task 1 裁决:mut 标记是判定维度,非 Rust 式单向放宽):`&mut [T]` 的标记不同 // ⇒ **不**满足只读形状(判 0,可判定);`&mut [T]` 也不满足可写形状(见下:视图面不可表达)。 -fn sh_shape_seq_ro() -> int { - view := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(tt_top_k(AK_SEQUENCE), tt_nil()))); - return tt_union(tt_top_k(AK_SEQUENCE), view); -} +fn sh_shape_seq_ro() -> int: + view := tt_atom(AK_REF, -1, tt_cons(sh_ref_mut_marker(0), tt_cons(tt_top_k(AK_SEQUENCE), tt_nil()))) + return tt_union(tt_top_k(AK_SEQUENCE), view) // 可写序列 = **序列本体**(数组/切片——本语言切片可写,T1 探针 pSliceW `s[0] = 9` rc=0 实证) // ⇒ 与序列接口同项;**拒绝只读视图**(`&[T]` 是 AK_REF 行,非序列类 ⇒ 0)。 // 可写**视图**(`&mut [T]`)的形状**不可表达**:AK_REF 可写侧槽 1 = 不变(变型表)⇒ 槽内 ⊤ 落 // -1(未覆盖面)而非 1 ⇒ 本形状只覆盖本体面;该边界由 selftest `x2.rw_view_unexpressible` // 钉红(**-1 不得当 0/1 用**)。 -fn sh_shape_seq_rw() -> int { return tt_top_k(AK_SEQUENCE); } +fn sh_shape_seq_rw() -> int: + return tt_top_k(AK_SEQUENCE) // 可索引 = 序列 ∪ 字符串(串下标 → 字节值,checker 既有结果分支)。 // **与 IP_INDEX 许可集逐行同集**({AK_SEQUENCE, AK_STRING})——这是索引兜底门换位后行为保持的 // 等价前提(全类型行枚举守门 = selftest `x2.indexable_matches_ops`)。 -fn sh_shape_indexable() -> int { return tt_union(tt_top_k(AK_SEQUENCE), tt_top_k(AK_STRING)); } +fn sh_shape_indexable() -> int: + return tt_union(tt_top_k(AK_SEQUENCE), tt_top_k(AK_STRING)) // 可迭代(首版)= 序列(数组/切片)。 // 字符串**不**入本形状:迭代面现状**无任何类型检查**(checker 的 EXPR_FOR 只推迭代源类型、 // ir_gen 把它当数值界用)⇒ 无「串可迭代」的代码面证据,不宣称。 -fn sh_shape_iterable() -> int { return tt_top_k(AK_SEQUENCE); } +fn sh_shape_iterable() -> int: + return tt_top_k(AK_SEQUENCE) // product = 元组行(AK_PRODUCT)。struct 行 = AK_NAMED(结构项经展开层 / 用户轴面)⇒ 不在首版。 -fn sh_shape_product() -> int { return tt_top_k(AK_PRODUCT); } +fn sh_shape_product() -> int: + return tt_top_k(AK_PRODUCT) // ═══════════ R2 P4 Task 3:形状名生产注册面(裁决 1 + D17)═══════════ // 六个形状**按名注册**(D17 的六个 ASCII 名:sequence / sequence_ro / sequence_rw / @@ -441,11 +478,10 @@ fn sh_shape_product() -> int { return tt_top_k(AK_PRODUCT); } // // ⚠ 命名**消费语法**(`T: 可索引` 一类)不在本批(P3 未开工清单项,另裁)——本函数只兑现 // 「形状名入生产注册面」;消费方(轴 A 判定)今日走 `iface_satisfies_term` 的无名字路径。 -fn iface_shape_builtin_init() { - iface_shape_register(str_intern("sequence"), sh_shape_seq()); - iface_shape_register(str_intern("sequence_ro"), sh_shape_seq_ro()); - iface_shape_register(str_intern("sequence_rw"), sh_shape_seq_rw()); - iface_shape_register(str_intern("indexable"), sh_shape_indexable()); - iface_shape_register(str_intern("iterable"), sh_shape_iterable()); - iface_shape_register(str_intern("product"), sh_shape_product()); -} +fn iface_shape_builtin_init(): + iface_shape_register(str_intern("sequence"), sh_shape_seq()) + iface_shape_register(str_intern("sequence_ro"), sh_shape_seq_ro()) + iface_shape_register(str_intern("sequence_rw"), sh_shape_seq_rw()) + iface_shape_register(str_intern("indexable"), sh_shape_indexable()) + iface_shape_register(str_intern("iterable"), sh_shape_iterable()) + iface_shape_register(str_intern("product"), sh_shape_product()) diff --git a/src/compiler/interp.cr b/src/compiler/interp.cr index 3228fc24..e850507f 100644 --- a/src/compiler/interp.cr +++ b/src/compiler/interp.cr @@ -14,746 +14,937 @@ // 双路径一致性由 tests/selfhost/test_interp_parity.py 钉死(interp callee ≡ // interp main ≡ ELF oracle) -g_ir_vals : string, mut; g_ir_vals_cap : int, mut; +g_ir_vals : string, mut +g_ir_vals_cap : int, mut // === 调用分派 / callee 内联执行(主循环与 callee 路径的唯一实现)=== // ir_interp_abort:解释器中止码(0 = 正常;非 0 = ir_interpret 应立即返回的 // 值)。callee(含嵌套层)里的响亮失败——越界陷阱(-1)/ 动态分发·extern(2)/ // binary64 转换(-1)——沿调用链上抛到 ir_interpret,绝不静默落 0 // (TODO #2026-09-10-7 的静默分叉类:主循环有、callee 路径无 → 双路径分叉)。 -g_interp_abort : int, mut; +g_interp_abort : int, mut // 嵌套内联深度(callee 内再调用用户函数 = 递归内联)。超限响亮报错,不挂死、 // 不静默——Python 参照解释器无此概念,深度上限取足够覆盖正常递归用例。 -g_interp_call_depth : int, mut; -IR_INTERP_MAX_DEPTH : int = 400; +g_interp_call_depth : int, mut +IR_INTERP_MAX_DEPTH : int = 400 // 活动函数栈(g_interp_stack[d] = 第 d 层内联执行的函数索引)——用于重入(递归/ // 互递归)检测:同一函数再次进入时必须逐帧保存/恢复其槽区(扁平槽模型里同一 // 函数的形参/局部只有一份槽,不保存则外层帧被内层调用覆写 → 静默错值)。 -g_interp_stack : string, mut; +g_interp_stack : string, mut // IR_BINARY 统一分派(主循环与 callee 内联循环共用): // 整数路径(模 2⁶⁴)。dex 为缩放整数——同走整数路径(数值迁移 #2026-09-13-9 定稿); // IR_I2F/IR_F2I 在 dispatch 入口显式报错(interp 无 binary64 语义)。 -fn ir_interp_binary(d: int, s1: int, s2: int, s3: int, ti: int) { - if d < 0 { return; } - lv := r64(g_ir_vals, s1 * 8); rv := r64(g_ir_vals, s2 * 8); - if s3 == 1 { w64(g_ir_vals, d * 8, lv + rv); } - if s3 == 2 { w64(g_ir_vals, d * 8, lv - rv); } - if s3 == 3 { w64(g_ir_vals, d * 8, lv * rv); } - if s3 == 4 { w64(g_ir_vals, d * 8, lv / rv); } - if s3 == 5 { w64(g_ir_vals, d * 8, lv % rv); } - if s3 == 6 { if lv == rv { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - if s3 == 7 { if lv != rv { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - if s3 == 8 { if lv < rv { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - if s3 == 9 { if lv > rv { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - if s3 == 10 { if lv <= rv { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - if s3 == 11 { if lv >= rv { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - if s3 == 12 { if lv != 0 && rv != 0 { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - if s3 == 13 { if lv != 0 || rv != 0 { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - if s3 == 17 { w64(g_ir_vals, d * 8, lv + rv * 8); } // OP_PTR_ADD - if s3 == 18 { w64(g_ir_vals, d * 8, lv - rv * 8); } // OP_PTR_SUB - if s3 == 19 { w64(g_ir_vals, d * 8, (lv - rv) / 8); } // OP_PTR_DIFF -} +fn ir_interp_binary(d: int, s1: int, s2: int, s3: int, ti: int): + if d < 0: + return + lv := r64(g_ir_vals, s1 * 8) + rv := r64(g_ir_vals, s2 * 8) + if s3 == 1: + w64(g_ir_vals, d * 8, lv + rv) + if s3 == 2: + w64(g_ir_vals, d * 8, lv - rv) + if s3 == 3: + w64(g_ir_vals, d * 8, lv * rv) + if s3 == 4: + w64(g_ir_vals, d * 8, lv / rv) + if s3 == 5: + w64(g_ir_vals, d * 8, lv % rv) + if s3 == 6: + if lv == rv: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) + if s3 == 7: + if lv != rv: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) + if s3 == 8: + if lv < rv: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) + if s3 == 9: + if lv > rv: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) + if s3 == 10: + if lv <= rv: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) + if s3 == 11: + if lv >= rv: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) + if s3 == 12: + if lv != 0 && rv != 0: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) + if s3 == 13: + if lv != 0 || rv != 0: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) + if s3 == 17: + w64(g_ir_vals, d * 8, lv + rv * 8) + // OP_PTR_ADD + if s3 == 18: + w64(g_ir_vals, d * 8, lv - rv * 8) + // OP_PTR_SUB + if s3 == 19: + w64(g_ir_vals, d * 8, (lv - rv) / 8) + // OP_PTR_DIFF // 指针间接读写(近似,对照 ELF 语义): // 槽号(0 ≤ ptr < g_ir_var_count)= 栈变量的「地址」(REF 给的槽索引)→ 读写该槽; // 其余 = 堆地址(alloc/ALLOC_ARRAY 产出的真实指针)→ 读写内存。 -fn ir_interp_deref_read(ptr: int) -> int { - if ptr >= 0 && ptr < g_ir_var_count { return r64(g_ir_vals, ptr * 8); } - unsafe { return r64(@str_of(ptr), 0); } -} -fn ir_interp_deref_write(ptr: int, val: int) { - if ptr >= 0 && ptr < g_ir_var_count { w64(g_ir_vals, ptr * 8, val); } - else { unsafe { w64(@str_of(ptr), 0, val); } } -} +fn ir_interp_deref_read(ptr: int) -> int: + if ptr >= 0 && ptr < g_ir_var_count: + return r64(g_ir_vals, ptr * 8) + unsafe: + return r64(@str_of(ptr), 0) +fn ir_interp_deref_write(ptr: int, val: int): + if ptr >= 0 && ptr < g_ir_var_count: + w64(g_ir_vals, ptr * 8, val) + else: + unsafe: + w64(@str_of(ptr), 0, val) // Interpreter string values are intern-table indices (IR_CONST stores the // index, while native ELF stores a pointer). Keep string builtins in that same // representation instead of passing the index to pointer-based helpers. -fn ir_interp_str_concat(a: int, b: int) -> int { - out : string, mut = ""; - out = out + istr_get(a); - out = out + istr_get(b); - return str_intern(out); -} +fn ir_interp_str_concat(a: int, b: int) -> int: + out : string, mut = "" + out = out + istr_get(a) + out = out + istr_get(b) + return str_intern(out) -fn ir_interp_str_char(a: int, i: int) -> int { - return str_intern(get_char(istr_get(a), i)); -} +fn ir_interp_str_char(a: int, i: int) -> int: + return str_intern(get_char(istr_get(a), i)) -fn ir_interp_str_sub(a: int, start: int, len: int) -> int { - return str_intern(str_sub(istr_get(a), start, len)); -} +fn ir_interp_str_sub(a: int, start: int, len: int) -> int: + return str_intern(str_sub(istr_get(a), start, len)) // IR_CALL (4) / IR_SPAWN (27) 统一分派——d=结果槽,s1=实参首槽,s2=实参数, // s3=函数名驻留索引。内置函数近似与原主循环分支逐条同语义同守卫;用户函数经 // ir_interp_run_fn 内联执行(callee 内再调用 = 嵌套内联,深度守卫见 MAX_DEPTH)。 -fn ir_interp_call(d: int, s1: int, s2: int, s3: int) { - fn_ni := s3; - fn_name := istr_get(fn_ni); - sfi := find_so_fn(fn_ni); - if sfi >= 0 && s2 >= 1 { - tf := sym_type(sfi); - if tf == 1 || tf == 3 { // TAG_VARIADIC: print/println — NOOP (syscall3 returns 0) - } else if tf == 2 || tf == 3 { // TAG_AUTO_STR: print_i/println_i — NOOP (syscall3 returns 0) - } - } +fn ir_interp_call(d: int, s1: int, s2: int, s3: int): + fn_ni := s3 + fn_name := istr_get(fn_ni) + sfi := find_so_fn(fn_ni) + if sfi >= 0 && s2 >= 1: + tf := sym_type(sfi) + // TAG_VARIADIC: print/println — NOOP (syscall3 returns 0) + // TAG_AUTO_STR: print_i/println_i — NOOP (syscall3 returns 0) + // syscall3/syscall4 — interpreter returns 0 - if str_eq(fn_name, "syscall3") != 0 || str_eq(fn_name, "syscall4") != 0 { - if d >= 0 { w64(g_ir_vals, d * 8, 0); } - } - if str_eq(fn_name, "str_len") != 0 { - if d >= 0 && s2 >= 1 { w64(g_ir_vals, d * 8, istr_len(r64(g_ir_vals, s1 * 8))); } - } - if str_eq(fn_name, "str_eq") != 0 { - if d >= 0 && s2 >= 2 { - left_s := istr_get(r64(g_ir_vals, s1 * 8)); - right_s := istr_get(r64(g_ir_vals, (s1 + 1) * 8)); - w64(g_ir_vals, d * 8, str_eq(left_s, right_s)); - } - } - if str_eq(fn_name, "concat") != 0 { - if d >= 0 && s2 >= 2 { + if str_eq(fn_name, "syscall3") != 0 || str_eq(fn_name, "syscall4") != 0: + if d >= 0: + w64(g_ir_vals, d * 8, 0) + if str_eq(fn_name, "str_len") != 0: + if d >= 0 && s2 >= 1: + w64(g_ir_vals, d * 8, istr_len(r64(g_ir_vals, s1 * 8))) + if str_eq(fn_name, "str_eq") != 0: + if d >= 0 && s2 >= 2: + left_s := istr_get(r64(g_ir_vals, s1 * 8)) + right_s := istr_get(r64(g_ir_vals, (s1 + 1) * 8)) + w64(g_ir_vals, d * 8, str_eq(left_s, right_s)) + if str_eq(fn_name, "concat") != 0: + if d >= 0 && s2 >= 2: w64(g_ir_vals, d * 8, ir_interp_str_concat( - r64(g_ir_vals, s1 * 8), r64(g_ir_vals, (s1 + 1) * 8))); - } - } - if str_eq(fn_name, "int_str") != 0 { - if d >= 0 && s2 >= 1 { w64(g_ir_vals, d * 8, str_intern(int_str(r64(g_ir_vals, s1 * 8)))); } - } - if str_eq(fn_name, "chr") != 0 { - if d >= 0 && s2 >= 1 { w64(g_ir_vals, d * 8, str_intern(chr(r64(g_ir_vals, s1 * 8)))); } - } - if str_eq(fn_name, "get_char") != 0 { - if d >= 0 && s2 >= 2 { w64(g_ir_vals, d * 8, ir_interp_str_char(r64(g_ir_vals, s1 * 8), r64(g_ir_vals, (s1 + 1) * 8))); } - } - if str_eq(fn_name, "str_sub") != 0 { - if d >= 0 && s2 >= 3 { w64(g_ir_vals, d * 8, ir_interp_str_sub(r64(g_ir_vals, s1 * 8), r64(g_ir_vals, (s1 + 1) * 8), r64(g_ir_vals, (s1 + 2) * 8))); } - } - if str_eq(fn_name, "load_str_ptr") != 0 { - if d >= 0 && s2 >= 2 { - b := r64(g_ir_vals, s1 * 8); p := r64(g_ir_vals, s1 + 1 * 8); - lo := load8(b, p) + load8(b, p+1)*256 + - load8(b, p+2)*65536 + load8(b, p+3)*16777216; - hi := load8(b, p+4) + load8(b, p+5)*256 + - load8(b, p+6)*65536 + load8(b, p+7)*16777216; - if hi < 0 { hi = hi + 4294967296; } - w64(g_ir_vals, d * 8, lo + hi * 4294967296); - } - } - if str_eq(fn_name, "store_str_ptr") != 0 { - if s2 >= 3 { - b := r64(g_ir_vals, s1 * 8); p := r64(g_ir_vals, s1 + 1 * 8); v := r64(g_ir_vals, s1 + 2 * 8); - lo : ., mut = v % 4294967296; hi : ., mut = v / 4294967296; - if v < 0 { lo = v; hi = -1; } - store8(b, p, lo%256); store8(b, p+1, (lo/256)%256); - store8(b, p+2, (lo/65536)%256); store8(b, p+3, (lo/16777216)%256); - store8(b, p+4, hi%256); store8(b, p+5, (hi/256)%256); - store8(b, p+6, (hi/65536)%256); store8(b, p+7, (hi/16777216)%256); - } - if d >= 0 { w64(g_ir_vals, d * 8, 0); } - } + r64(g_ir_vals, s1 * 8), r64(g_ir_vals, (s1 + 1) * 8))) + if str_eq(fn_name, "int_str") != 0: + if d >= 0 && s2 >= 1: + w64(g_ir_vals, d * 8, str_intern(int_str(r64(g_ir_vals, s1 * 8)))) + if str_eq(fn_name, "chr") != 0: + if d >= 0 && s2 >= 1: + w64(g_ir_vals, d * 8, str_intern(chr(r64(g_ir_vals, s1 * 8)))) + if str_eq(fn_name, "get_char") != 0: + if d >= 0 && s2 >= 2: + w64(g_ir_vals, d * 8, ir_interp_str_char(r64(g_ir_vals, s1 * 8), r64(g_ir_vals, (s1 + 1) * 8))) + if str_eq(fn_name, "str_sub") != 0: + if d >= 0 && s2 >= 3: + w64(g_ir_vals, d * 8, ir_interp_str_sub(r64(g_ir_vals, s1 * 8), r64(g_ir_vals, (s1 + 1) * 8), r64(g_ir_vals, (s1 + 2) * 8))) + if str_eq(fn_name, "load_str_ptr") != 0: + if d >= 0 && s2 >= 2: + b := r64(g_ir_vals, s1 * 8) + p := r64(g_ir_vals, s1 + 1 * 8) + lo := load8(b, p) + load8(b, p+1)*256 + load8(b, p+2)*65536 + load8(b, p+3)*16777216 + hi := load8(b, p+4) + load8(b, p+5)*256 + load8(b, p+6)*65536 + load8(b, p+7)*16777216 + if hi < 0: + hi = hi + 4294967296 + w64(g_ir_vals, d * 8, lo + hi * 4294967296) + if str_eq(fn_name, "store_str_ptr") != 0: + if s2 >= 3: + b := r64(g_ir_vals, s1 * 8) + p := r64(g_ir_vals, s1 + 1 * 8) + v := r64(g_ir_vals, s1 + 2 * 8) + lo : ., mut = v % 4294967296 + hi : ., mut = v / 4294967296 + if v < 0: + lo = v + hi = -1 + store8(b, p, lo%256) + store8(b, p+1, (lo/256)%256) + store8(b, p+2, (lo/65536)%256) + store8(b, p+3, (lo/16777216)%256) + store8(b, p+4, hi%256) + store8(b, p+5, (hi/256)%256) + store8(b, p+6, (hi/65536)%256) + store8(b, p+7, (hi/16777216)%256) + if d >= 0: + w64(g_ir_vals, d * 8, 0) // 字符串内置已处理 → 不再走用户函数查找(对照主循环的 ip+1;continue) - if str_eq(fn_name, "str_len") != 0 || str_eq(fn_name, "str_eq") != 0 || - str_eq(fn_name, "concat") != 0 || str_eq(fn_name, "int_str") != 0 || - str_eq(fn_name, "chr") != 0 || str_eq(fn_name, "get_char") != 0 || - str_eq(fn_name, "str_sub") != 0 { return; } + if str_eq(fn_name, "str_len") != 0 || str_eq(fn_name, "str_eq") != 0 || str_eq(fn_name, "concat") != 0 || str_eq(fn_name, "int_str") != 0 || str_eq(fn_name, "chr") != 0 || str_eq(fn_name, "get_char") != 0 || str_eq(fn_name, "str_sub") != 0: + return // 用户函数内联执行(单层 / 嵌套递归) - if d < 0 { return; } - cfi : ., mut = 0; - loop { - if cfi >= g_ir_func_count { break; } - if r64(g_ir_func_name_idx, cfi * 8) == fn_ni { - f_start := r64(g_df_func_node_start, cfi * 8); - f_count := r64(g_df_func_node_count, cfi * 8); - if f_start >= 0 && f_count > 0 { - rval := ir_interp_run_fn(cfi, s1, s2); - if g_interp_abort == 0 { w64(g_ir_vals, d * 8, rval); } - } - break; - } - cfi = cfi + 1; - } -} + if d < 0: + return + cfi : ., mut = 0 + loop: + if cfi >= g_ir_func_count: + break + if r64(g_ir_func_name_idx, cfi * 8) == fn_ni: + f_start := r64(g_df_func_node_start, cfi * 8) + f_count := r64(g_df_func_node_count, cfi * 8) + if f_start >= 0 && f_count > 0: + rval := ir_interp_run_fn(cfi, s1, s2) + if g_interp_abort == 0: + w64(g_ir_vals, d * 8, rval) + break + cfi = cfi + 1 // callee 图内联执行(唯一实现):主循环的 IR_CALL 与 callee 内的 IR_CALL 都走 // 这里——两路径不再各有一份分派。建标签表 → 拷实参 → 顺序执行 f_count 节点 → // 恢复标签表 → 返回 IR_RETURN 值(无值返回 = 0,与主循环 ret_slot 清零同语义)。 // 深度守卫:嵌套超过 IR_INTERP_MAX_DEPTH 响亮报错 + 中止(不挂死、不静默)。 -fn ir_interp_run_fn(cfi: int, arg_base: int, argc: int) -> int { - f_start := r64(g_df_func_node_start, cfi * 8); - f_count := r64(g_df_func_node_count, cfi * 8); - if f_start < 0 || f_count <= 0 { return 0; } - if g_interp_call_depth >= IR_INTERP_MAX_DEPTH { - println("interpreter error: IR_INTERP_MAX_DEPTH exceeded — corec run cannot execute this recursion; build & run natively (corec build) instead"); - g_interp_abort = -1; - return 0; - } +fn ir_interp_run_fn(cfi: int, arg_base: int, argc: int) -> int: + f_start := r64(g_df_func_node_start, cfi * 8) + f_count := r64(g_df_func_node_count, cfi * 8) + if f_start < 0 || f_count <= 0: + return 0 + if g_interp_call_depth >= IR_INTERP_MAX_DEPTH: + println("interpreter error: IR_INTERP_MAX_DEPTH exceeded — corec run cannot execute this recursion; build & run natively (corec build) instead") + g_interp_abort = -1 + return 0 // 重入检测(递归 / 互递归):本函数已在活动栈上 → 外层帧与本层共用同一份 // 槽区(扁平槽模型),必须在入口保存、出口恢复,否则外层帧被覆写(静默错值)。 - reentrant : ., mut = 0; - si3 : ., mut = 0; - loop { if si3 >= g_interp_call_depth { break; } - if r64(g_interp_stack, si3 * 8) == cfi { reentrant = 1; break; } - si3 = si3 + 1; } - vs := r64(g_ir_func_var_start, cfi * 8); - vc := r64(g_ir_func_var_count, cfi * 8); - frame : string, mut = ""; has_frame : ., mut = 0; - if reentrant != 0 && vc > 0 && vs >= 0 { - frame = alloc(vc * 8); - has_frame = 1; - fi4 : ., mut = 0; - loop { if fi4 >= vc { break; } - w64(frame, fi4 * 8, r64(g_ir_vals, (vs + fi4) * 8)); - fi4 = fi4 + 1; } - } + reentrant : ., mut = 0 + si3 : ., mut = 0 + loop: + if si3 >= g_interp_call_depth: + break + if r64(g_interp_stack, si3 * 8) == cfi: + reentrant = 1 + break + si3 = si3 + 1 + vs := r64(g_ir_func_var_start, cfi * 8) + vc := r64(g_ir_func_var_count, cfi * 8) + frame : string, mut = "" + has_frame : ., mut = 0 + if reentrant != 0 && vc > 0 && vs >= 0: + frame = alloc(vc * 8) + has_frame = 1 + fi4 : ., mut = 0 + loop: + if fi4 >= vc: + break + w64(frame, fi4 * 8, r64(g_ir_vals, (vs + fi4) * 8)) + fi4 = fi4 + 1 // 实参先入缓冲再落形参槽:递归调用时实参槽与形参槽同属本函数槽区,直接 // 逐个搬运可能被己方写覆盖(缓冲后行为与原子搬移一致)。 - args_buf : string, mut = ""; - if argc > 0 { - args_buf = alloc(argc * 8); - pai : ., mut = 0; - loop { if pai >= argc { break; } - w64(args_buf, pai * 8, r64(g_ir_vals, (arg_base + pai) * 8)); - pai = pai + 1; } - } + args_buf : string, mut = "" + if argc > 0: + args_buf = alloc(argc * 8) + pai : ., mut = 0 + loop: + if pai >= argc: + break + w64(args_buf, pai * 8, r64(g_ir_vals, (arg_base + pai) * 8)) + pai = pai + 1 // 压栈(重入检测在上;深度守卫已在入口) - w64(g_interp_stack, g_interp_call_depth * 8, cfi); - g_interp_call_depth = g_interp_call_depth + 1; - rval : ., mut = 0; // callee 无值返回(IR_RETURN s1<0,如裸 return)→ 0 + w64(g_interp_stack, g_interp_call_depth * 8, cfi) + g_interp_call_depth = g_interp_call_depth + 1 + rval : ., mut = 0 // callee 无值返回(IR_RETURN s1<0,如裸 return)→ 0 // Save label state(递归安全:每层帧在局部变量里保存/恢复) - old_lc := g_label_count; - old_poses := g_label_poses; - old_poses_cap := g_label_cap; - g_label_poses = alloc(64 * 8); g_label_cap = 64; + old_lc := g_label_count + old_poses := g_label_poses + old_poses_cap := g_label_cap + g_label_poses = alloc(64 * 8) + g_label_cap = 64 // Build label map for callee - li2 : ., mut = 0; - loop { if li2 >= f_count { break; } - n_op := r64(g_df_nodes, (f_start + li2) * ESZ_DFNODE + OFF_DF_OPCODE); - n_s1 := r64(g_df_nodes, (f_start + li2) * ESZ_DFNODE + OFF_DF_S1); - if n_op == 21 { if n_s1 >= 0 { - grow_label_poses(n_s1 + 1); - w64(g_label_poses, n_s1 * 8, li2); - if n_s1 + 1 > g_label_count { g_label_count = n_s1 + 1; } - }} - li2 = li2 + 1; } + li2 : ., mut = 0 + loop: + if li2 >= f_count: + break + n_op := r64(g_df_nodes, (f_start + li2) * ESZ_DFNODE + OFF_DF_OPCODE) + n_s1 := r64(g_df_nodes, (f_start + li2) * ESZ_DFNODE + OFF_DF_S1) + if n_op == 21: + if n_s1 >= 0: + grow_label_poses(n_s1 + 1) + w64(g_label_poses, n_s1 * 8, li2) + if n_s1 + 1 > g_label_count: + g_label_count = n_s1 + 1 + li2 = li2 + 1 // Copy args from buffer to callee param vars - pstart := vs; - pai2 : ., mut = 0; - loop { if pai2 >= argc { break; } - w64(g_ir_vals, (pstart + pai2) * 8, r64(args_buf, pai2 * 8)); - pai2 = pai2 + 1; } + pstart := vs + pai2 : ., mut = 0 + loop: + if pai2 >= argc: + break + w64(g_ir_vals, (pstart + pai2) * 8, r64(args_buf, pai2 * 8)) + pai2 = pai2 + 1 // Execute callee graph (inline) - ip2 : ., mut = 0; - loop { - if ip2 >= f_count { break; } - if g_interp_abort != 0 { break; } - op2 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_OPCODE); - d2 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_DEST); - t1 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_S1); - t2 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_S2); - t3 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_S3); + ip2 : ., mut = 0 + loop: + if ip2 >= f_count: + break + if g_interp_abort != 0: + break + op2 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_OPCODE) + d2 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_DEST) + t1 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_S1) + t2 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_S2) + t3 := r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_S3) // R2 P5 Task 2(D19):这里是**派生码**(不是槽)——单槽化后 40 槽 = 类型项 // 引用。`ir_interp_binary` 当前不消费该参(槽 3 的 op 码决定运算),值仍与 // 单槽化前逐字节相同(派生码 ≡ 旧混用码)。 t4 := sh_dfn_code_of_slots(r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_TK), - r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_AUX)); - if op2 == 1 && d2 >= 0 { w64(g_ir_vals, d2 * 8, t1); } - if op2 == 2 && t1 >= 0 && t2 >= 0 { ir_interp_binary(d2, t1, t2, t3, t4); } - if op2 == 49 || op2 == 50 { - println("interpreter error: IR_I2F/IR_F2I needs binary64 semantics (apx dex) — `corec run` cannot execute apx dex arithmetic; build & run natively (corec build) instead"); - g_interp_abort = -1; break; - } - if op2 == 3 && t1 >= 0 { - ov2 := r64(g_ir_vals, t1 * 8); - if t3 == 1 { w64(g_ir_vals, d2 * 8, -ov2); } - else if t3 == 2 { if ov2 == 0 { w64(g_ir_vals, d2 * 8, 1); } else { w64(g_ir_vals, d2 * 8, 0); } } } + r64(g_df_nodes, (f_start + ip2) * ESZ_DFNODE + OFF_DF_AUX)) + if op2 == 1 && d2 >= 0: + w64(g_ir_vals, d2 * 8, t1) + if op2 == 2 && t1 >= 0 && t2 >= 0: + ir_interp_binary(d2, t1, t2, t3, t4) + if op2 == 49 || op2 == 50: + println("interpreter error: IR_I2F/IR_F2I needs binary64 semantics (apx dex) — `corec run` cannot execute apx dex arithmetic; build & run natively (corec build) instead") + g_interp_abort = -1 + break + if op2 == 3 && t1 >= 0: + ov2 := r64(g_ir_vals, t1 * 8) + if t3 == 1: + w64(g_ir_vals, d2 * 8, -ov2) + else if t3 == 2: + if ov2 == 0: + w64(g_ir_vals, d2 * 8, 1) + else: + w64(g_ir_vals, d2 * 8, 0) // Keep callee locals in the shared value store. // The old inline path skipped these opcodes, so // loop-carried assignments never changed state. - if op2 == 6 && d2 >= 0 { w64(g_ir_vals, d2 * 8, 0); } // IR_ALLOC - if op2 == 9 && t1 >= 0 && t2 >= 0 { w64(g_ir_vals, t1 * 8, r64(g_ir_vals, t2 * 8)); } // IR_STORE - if op2 == 10 && d2 >= 0 && t1 >= 0 { w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)); } // IR_LOAD + if op2 == 6 && d2 >= 0: + w64(g_ir_vals, d2 * 8, 0) + // IR_ALLOC + if op2 == 9 && t1 >= 0 && t2 >= 0: + w64(g_ir_vals, t1 * 8, r64(g_ir_vals, t2 * 8)) + // IR_STORE + if op2 == 10 && d2 >= 0 && t1 >= 0: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)) + // IR_LOAD // 聚合族(与主循环 IR_ALLOC_ARRAY/IR_ALLOC_STRUCT/LOAD|STORE_INDEX // /LOAD|STORE_FIELD/ADDR_INDEX 同语义):此前外函数内联路径缺这组 // opcode——callee 里读写聚合全局(数组/结构体)静默落 0。本批 // §1.3 让这类全局在 main 序言获得运行期存储(ir_gen.cr),callee // 侧的读路径必须同批补齐,否则双路径语义仍分叉。 - if op2 == 8 && d2 >= 0 { // IR_ALLOC_ARRAY - cnt2 := t1; esz2 := t2; - if esz2 <= 0 { esz2 = 8; } - need3 := cnt2 * esz2 + 8; - bp2 := alloc(need3); - vi3 : ., mut = 0; - loop { if vi3 >= need3 { break; } store8(bp2, vi3, 0); vi3 = vi3 + 1; } - unsafe { w64(g_ir_vals, d2 * 8, @ptr_of(bp2)); } - } - if op2 == 13 && d2 >= 0 && t1 >= 0 { // IR_LOAD_INDEX: t1=arr_var, t3=literal_idx - av2 := r64(g_ir_vals, t1 * 8); - if irv_type(t1) == TI_STR { w64(g_ir_vals, d2 * 8, str_load8(av2, t3)); } - else { unsafe { w64(g_ir_vals, d2 * 8, r64(@str_of(av2), t3 * 8)); } } - } - if op2 == 14 && t1 >= 0 && t2 >= 0 { // IR_STORE_INDEX: t1=arr_var, t2=val_var - av2 := r64(g_ir_vals, t1 * 8); - if irv_type(t1) == TI_STR { store8(istr_get(av2), t3, r64(g_ir_vals, t2 * 8)); } - else { unsafe { w64(@str_of(av2), t3 * 8, r64(g_ir_vals, t2 * 8)); } } - } - if op2 == 15 && d2 >= 0 && t1 >= 0 && t2 >= 0 { // IR_LOAD_INDEX_VAR: t1=arr_var, t2=idx_var - av2 := r64(g_ir_vals, t1 * 8); - ix2 := r64(g_ir_vals, t2 * 8); - if irv_type(t1) == TI_STR { w64(g_ir_vals, d2 * 8, str_load8(av2, ix2)); } - else { unsafe { w64(g_ir_vals, d2 * 8, r64(@str_of(av2), ix2 * 8)); } } - } - if op2 == 16 && d2 >= 0 && t1 >= 0 && t2 >= 0 { // IR_STORE_INDEX_VAR: d2=val_var, t1=arr_var, t2=idx_var - av2 := r64(g_ir_vals, t1 * 8); - ix2 := r64(g_ir_vals, t2 * 8); - if irv_type(t1) == TI_STR { store8(istr_get(av2), ix2, r64(g_ir_vals, d2 * 8)); } - else { unsafe { w64(@str_of(av2), ix2 * 8, r64(g_ir_vals, d2 * 8)); } } - } - if op2 == 31 && d2 >= 0 && t1 >= 0 && t2 >= 0 { // IR_ADDR_INDEX: &arr[i] - w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8) + r64(g_ir_vals, t2 * 8) * 8); - } - if op2 == 11 && d2 >= 0 && t1 >= 0 { // IR_LOAD_FIELD: t1=struct_var, t3=field_idx - pf2 := r64(g_ir_vals, t1 * 8); - if pf2 != 0 { unsafe { w64(g_ir_vals, d2 * 8, r64(@str_of(pf2), t3 * 8)); } } - else { w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)); } - } - if op2 == 12 && t1 >= 0 && t2 >= 0 { // IR_STORE_FIELD: t1=struct_var, t2=val_var, t3=field_idx - pf2 := r64(g_ir_vals, t1 * 8); - if pf2 != 0 { unsafe { w64(@str_of(pf2), t3 * 8, r64(g_ir_vals, t2 * 8)); } } - else { w64(g_ir_vals, t1 * 8, r64(g_ir_vals, t2 * 8)); } - } - if op2 == 7 && d2 >= 0 { // IR_ALLOC_STRUCT - si2 := find_struct(t3); - fc2 : ., mut = 0; - if si2 >= 0 { fc2 = si_field_count(si2); } - need3 := fc2 * 8 + 8; - bp2 := alloc(need3); - vi3 : ., mut = 0; - loop { if vi3 >= need3 { break; } store8(bp2, vi3, 0); vi3 = vi3 + 1; } - unsafe { w64(g_ir_vals, d2 * 8, @ptr_of(bp2)); } - } - if op2 == 32 && d2 >= 0 { w64(g_ir_vals, d2 * 8, 0); } // IR_ARENA_NEW - if op2 == 33 { } // IR_ARENA_RESET - if op2 == 46 || op2 == 47 { - if d2 >= 0 && t1 >= 0 { w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)); } - } + if op2 == 8 && d2 >= 0: + // IR_ALLOC_ARRAY + cnt2 := t1 + esz2 := t2 + if esz2 <= 0: + esz2 = 8 + need3 := cnt2 * esz2 + 8 + bp2 := alloc(need3) + vi3 : ., mut = 0 + loop: + if vi3 >= need3: + break + store8(bp2, vi3, 0) + vi3 = vi3 + 1 + unsafe: + w64(g_ir_vals, d2 * 8, @ptr_of(bp2)) + if op2 == 13 && d2 >= 0 && t1 >= 0: + // IR_LOAD_INDEX: t1=arr_var, t3=literal_idx + av2 := r64(g_ir_vals, t1 * 8) + if irv_type(t1) == TI_STR: + w64(g_ir_vals, d2 * 8, str_load8(av2, t3)) + else: + unsafe: + w64(g_ir_vals, d2 * 8, r64(@str_of(av2), t3 * 8)) + if op2 == 14 && t1 >= 0 && t2 >= 0: + // IR_STORE_INDEX: t1=arr_var, t2=val_var + av2 := r64(g_ir_vals, t1 * 8) + if irv_type(t1) == TI_STR: + store8(istr_get(av2), t3, r64(g_ir_vals, t2 * 8)) + else: + unsafe: + w64(@str_of(av2), t3 * 8, r64(g_ir_vals, t2 * 8)) + if op2 == 15 && d2 >= 0 && t1 >= 0 && t2 >= 0: + // IR_LOAD_INDEX_VAR: t1=arr_var, t2=idx_var + av2 := r64(g_ir_vals, t1 * 8) + ix2 := r64(g_ir_vals, t2 * 8) + if irv_type(t1) == TI_STR: + w64(g_ir_vals, d2 * 8, str_load8(av2, ix2)) + else: + unsafe: + w64(g_ir_vals, d2 * 8, r64(@str_of(av2), ix2 * 8)) + if op2 == 16 && d2 >= 0 && t1 >= 0 && t2 >= 0: + // IR_STORE_INDEX_VAR: d2=val_var, t1=arr_var, t2=idx_var + av2 := r64(g_ir_vals, t1 * 8) + ix2 := r64(g_ir_vals, t2 * 8) + if irv_type(t1) == TI_STR: + store8(istr_get(av2), ix2, r64(g_ir_vals, d2 * 8)) + else: + unsafe: + w64(@str_of(av2), ix2 * 8, r64(g_ir_vals, d2 * 8)) + if op2 == 31 && d2 >= 0 && t1 >= 0 && t2 >= 0: + // IR_ADDR_INDEX: &arr[i] + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8) + r64(g_ir_vals, t2 * 8) * 8) + if op2 == 11 && d2 >= 0 && t1 >= 0: + // IR_LOAD_FIELD: t1=struct_var, t3=field_idx + pf2 := r64(g_ir_vals, t1 * 8) + if pf2 != 0: + unsafe: + w64(g_ir_vals, d2 * 8, r64(@str_of(pf2), t3 * 8)) + else: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)) + if op2 == 12 && t1 >= 0 && t2 >= 0: + // IR_STORE_FIELD: t1=struct_var, t2=val_var, t3=field_idx + pf2 := r64(g_ir_vals, t1 * 8) + if pf2 != 0: + unsafe: + w64(@str_of(pf2), t3 * 8, r64(g_ir_vals, t2 * 8)) + else: + w64(g_ir_vals, t1 * 8, r64(g_ir_vals, t2 * 8)) + if op2 == 7 && d2 >= 0: + // IR_ALLOC_STRUCT + si2 := find_struct(t3) + fc2 : ., mut = 0 + if si2 >= 0: + fc2 = si_field_count(si2) + need3 := fc2 * 8 + 8 + bp2 := alloc(need3) + vi3 : ., mut = 0 + loop: + if vi3 >= need3: + break + store8(bp2, vi3, 0) + vi3 = vi3 + 1 + unsafe: + w64(g_ir_vals, d2 * 8, @ptr_of(bp2)) + if op2 == 32 && d2 >= 0: + w64(g_ir_vals, d2 * 8, 0) + // IR_ARENA_NEW + // IR_ARENA_RESET + if op2 == 46 || op2 == 47: + if d2 >= 0 && t1 >= 0: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)) // —— TODO #2026-09-10-7:以下 18 族与主循环同语义同守卫补齐(此前内联路径静默落空)—— // IR_MAKE_ENUM (17):d := alloc(8·(1+s2));M[d+0] := s1(tag = 变体名索引)—— // 与 ELF 布局 [tag][payload...] 一致的堆镜像(payload 由后续 IR_STORE_FIELD 写堆) - if op2 == 17 { - if d2 >= 0 { - need3 := 8 + t2 * 8; - bp2 := alloc(need3); - vi3 : ., mut = 0; - loop { if vi3 >= need3 { break; } store8(bp2, vi3, 0); vi3 = vi3 + 1; } - w64(bp2, 0, t1); - unsafe { w64(g_ir_vals, d2 * 8, @ptr_of(bp2)); } - } - } + if op2 == 17: + if d2 >= 0: + need3 := 8 + t2 * 8 + bp2 := alloc(need3) + vi3 : ., mut = 0 + loop: + if vi3 >= need3: + break + store8(bp2, vi3, 0) + vi3 = vi3 + 1 + w64(bp2, 0, t1) + unsafe: + w64(g_ir_vals, d2 * 8, @ptr_of(bp2)) // IR_LOAD_ENUM_TAG (23):d := M[ρ(s1)+0] - if op2 == 23 { - if d2 >= 0 && t1 >= 0 { - p23 := r64(g_ir_vals, t1 * 8); - if p23 != 0 { unsafe { w64(g_ir_vals, d2 * 8, r64(@str_of(p23), 0)); } } - } - } + if op2 == 23: + if d2 >= 0 && t1 >= 0: + p23 := r64(g_ir_vals, t1 * 8) + if p23 != 0: + unsafe: + w64(g_ir_vals, d2 * 8, r64(@str_of(p23), 0)) // IR_REF (18):d := &ρ(s1)——槽模型近似:槽号即「地址」(ir_interp_deref_* 同规则) - if op2 == 18 { if d2 >= 0 && t1 >= 0 { w64(g_ir_vals, d2 * 8, t1); } } + if op2 == 18: + if d2 >= 0 && t1 >= 0: + w64(g_ir_vals, d2 * 8, t1) // IR_DEREF (25):d := M[ρ(s1)](栈槽间接或堆读取,见 ir_interp_deref_read) - if op2 == 25 { - if d2 >= 0 && t1 >= 0 { - w64(g_ir_vals, d2 * 8, ir_interp_deref_read(r64(g_ir_vals, t1 * 8))); - } - } + if op2 == 25: + if d2 >= 0 && t1 >= 0: + w64(g_ir_vals, d2 * 8, ir_interp_deref_read(r64(g_ir_vals, t1 * 8))) // IR_SLICE (24): d := arr + low*8(与 ELF 编码一致) - if op2 == 24 { - if d2 >= 0 && t1 >= 0 && t2 >= 0 { - w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8) + r64(g_ir_vals, t2 * 8) * 8); - } - } + if op2 == 24: + if d2 >= 0 && t1 >= 0 && t2 >= 0: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8) + r64(g_ir_vals, t2 * 8) * 8) // IR_BOUNDS_CHECK (30): s1=index var, s2=max_len 字面量(ti=1 = 动态上限)—— // index < 0 或 index >= max → 陷阱(中止码 -1,与主循环 return -1 同语义) - if op2 == 30 && t2 >= 0 { - iv30 := r64(g_ir_vals, t1 * 8); - lim30 : ., mut = t2; - if t4 == 1 { lim30 = r64(g_ir_vals, t2 * 8); } - if iv30 < 0 || iv30 >= lim30 { g_interp_abort = -1; break; } - } + if op2 == 30 && t2 >= 0: + iv30 := r64(g_ir_vals, t1 * 8) + lim30 : ., mut = t2 + if t4 == 1: + lim30 = r64(g_ir_vals, t2 * 8) + if iv30 < 0 || iv30 >= lim30: + g_interp_abort = -1 + break // IR_STORE_PTR (26):M[ρ(s1)] := ρ(s2)(与 ELF 操作数一致;d=-1 发射态不再影响) - if op2 == 26 { if t1 >= 0 && t2 >= 0 { ir_interp_deref_write(r64(g_ir_vals, t1 * 8), r64(g_ir_vals, t2 * 8)); } } + if op2 == 26: + if t1 >= 0 && t2 >= 0: + ir_interp_deref_write(r64(g_ir_vals, t1 * 8), r64(g_ir_vals, t2 * 8)) // IR_YIELD (28):eager 值传递近似(d ← ρ(s1),同 IR_AWAIT) - if op2 == 28 { - if d2 >= 0 && t1 >= 0 { w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)); } - } + if op2 == 28: + if d2 >= 0 && t1 >= 0: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)) // IR_AWAIT (29) - if op2 == 29 { if d2 >= 0 { w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)); } } + if op2 == 29: + if d2 >= 0: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)) // IR_FNADDR (48) — no real addresses in the interpreter; dest = 0 - if op2 == 48 { if d2 >= 0 { w64(g_ir_vals, d2 * 8, 0); } } + if op2 == 48: + if d2 >= 0: + w64(g_ir_vals, d2 * 8, 0) // IR_APPROX (51) — pure annotation, skip(无运算语义,不能崩) - if op2 == 51 { } + // IR_DYN_PACK (43):dyn 变量双槽 [value, tag]——slot[d]=值、slot[d+1]=tag - if op2 == 43 { - if d2 >= 0 && t1 >= 0 { - w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)); - w64(g_ir_vals, (d2 + 1) * 8, t2); - } - } + if op2 == 43: + if d2 >= 0 && t1 >= 0: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)) + w64(g_ir_vals, (d2 + 1) * 8, t2) // IR_DYN_TAG (41):d := slot[ρ(s1)+1](读 +8 槽) - if op2 == 41 { if d2 >= 0 && t1 >= 0 { w64(g_ir_vals, d2 * 8, r64(g_ir_vals, (t1 + 1) * 8)); } } + if op2 == 41: + if d2 >= 0 && t1 >= 0: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, (t1 + 1) * 8)) // IR_DYN_VAL (42):d := slot[ρ(s1)](读 +0 槽) - if op2 == 42 { if d2 >= 0 && t1 >= 0 { w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)); } } + if op2 == 42: + if d2 >= 0 && t1 >= 0: + w64(g_ir_vals, d2 * 8, r64(g_ir_vals, t1 * 8)) // IR_DYN_DISPATCH (44):响亮报错(与主循环同文案同码;不再静默落空) - if op2 == 44 { - println("error: interp 不支持动态分发(IR_DYN_DISPATCH)"); - g_interp_abort = 2; break; - } + if op2 == 44: + println("error: interp 不支持动态分发(IR_DYN_DISPATCH)") + g_interp_abort = 2 + break // IR_CALL_EXTERN (45):响亮报错(ELF 静态构建同样拒绝,见 F16) - if op2 == 45 { - print("error: interp 无法调用外部函数:"); println(istr_get(t1)); - g_interp_abort = 2; break; - } + if op2 == 45: + print("error: interp 无法调用外部函数:") + println(istr_get(t1)) + g_interp_abort = 2 + break // IR_CALL (4) / IR_SPAWN (27):与主循环同一分派(嵌套内联 / 内置近似) - if op2 == 4 || op2 == 27 { ir_interp_call(d2, t1, t2, t3); } - if op2 == 5 { - if t1 >= 0 { rval = r64(g_ir_vals, t1 * 8); } - ip2 = f_count; // return exits the callee immediately - } // IR_RETURN - if op2 == 19 && t1 >= 0 { - cv2 := r64(g_ir_vals, t1 * 8); - if cv2 != 0 { if t2 >= 0 && t2 < g_label_count { ip2 = r64(g_label_poses, t2 * 8); } } - else { if t3 >= 0 && t3 < g_label_count { ip2 = r64(g_label_poses, t3 * 8); } } } - if op2 == 20 { if t1 >= 0 && t1 < g_label_count { ip2 = r64(g_label_poses, t1 * 8); } } - ip2 = ip2 + 1; - } + if op2 == 4 || op2 == 27: + ir_interp_call(d2, t1, t2, t3) + if op2 == 5: + if t1 >= 0: + rval = r64(g_ir_vals, t1 * 8) + ip2 = f_count // return exits the callee immediately + // IR_RETURN + if op2 == 19 && t1 >= 0: + cv2 := r64(g_ir_vals, t1 * 8) + if cv2 != 0: + if t2 >= 0 && t2 < g_label_count: + ip2 = r64(g_label_poses, t2 * 8) + else: + if t3 >= 0 && t3 < g_label_count: + ip2 = r64(g_label_poses, t3 * 8) + if op2 == 20: + if t1 >= 0 && t1 < g_label_count: + ip2 = r64(g_label_poses, t1 * 8) + ip2 = ip2 + 1 // Restore label state - g_label_count = old_lc; - g_label_poses = old_poses; - g_label_cap = old_poses_cap; + g_label_count = old_lc + g_label_poses = old_poses + g_label_cap = old_poses_cap // 重入帧恢复:外层帧的形参/局部/临时槽回到调用前(返回结果经局部 rval 传递, // 不占本槽区,故恢复不丢返回值) - if has_frame != 0 { - fi5 : ., mut = 0; - loop { if fi5 >= vc { break; } - w64(g_ir_vals, (vs + fi5) * 8, r64(frame, fi5 * 8)); - fi5 = fi5 + 1; } - } - g_interp_call_depth = g_interp_call_depth - 1; - if g_interp_abort != 0 { return 0; } - return rval; -} - -fn ir_interpret() -> int { + if has_frame != 0: + fi5 : ., mut = 0 + loop: + if fi5 >= vc: + break + w64(g_ir_vals, (vs + fi5) * 8, r64(frame, fi5 * 8)) + fi5 = fi5 + 1 + g_interp_call_depth = g_interp_call_depth - 1 + if g_interp_abort != 0: + return 0 + return rval + +fn ir_interpret() -> int: // Find main function in the dataflow graph - main_idx : ., mut = -1; - fi : ., mut = 0; - loop { - if fi >= g_ir_func_count { break; } - ni := r64(g_ir_func_name_idx, fi * 8); - if str_eq(istr_get(ni), "main") != 0 { main_idx = fi; break; } - fi = fi + 1; - } - if main_idx < 0 { return -1; } - node_start := r64(g_df_func_node_start, main_idx * 8); - node_count := r64(g_df_func_node_count, main_idx * 8); - if node_start < 0 || node_count <= 0 { return -1; } + main_idx : ., mut = -1 + fi : ., mut = 0 + loop: + if fi >= g_ir_func_count: + break + ni := r64(g_ir_func_name_idx, fi * 8) + if str_eq(istr_get(ni), "main") != 0: + main_idx = fi + break + fi = fi + 1 + if main_idx < 0: + return -1 + node_start := r64(g_df_func_node_start, main_idx * 8) + node_count := r64(g_df_func_node_count, main_idx * 8) + if node_start < 0 || node_count <= 0: + return -1 // 解释器状态复位(同一进程内可多次调用 ir_interpret)。 // 注:callee 返回值不再经「暂存槽」传递(原 ret_slot = g_ir_var_count, // 更早的 g_ir_vals[0] 约定会静默覆写首个全局)——现由 ir_interp_run_fn 的 // 局部返回值传递,该缺陷类结构性消失。 - g_interp_abort = 0; - g_interp_call_depth = 0; - g_interp_stack = alloc(IR_INTERP_MAX_DEPTH * 8); // 活动函数栈(重入检测) + g_interp_abort = 0 + g_interp_call_depth = 0 + g_interp_stack = alloc(IR_INTERP_MAX_DEPTH * 8) // 活动函数栈(重入检测) // Initialize value store (size = node_count + padding for destinations) - need := g_ir_var_count + 64; - if g_ir_vals_cap < need { - g_ir_vals = alloc(need * 8); - g_ir_vals_cap = need; - } - vi : ., mut = 0; - loop { - if vi >= need { break; } - w64(g_ir_vals, vi * 8, 0); - vi = vi + 1; - } + need := g_ir_var_count + 64 + if g_ir_vals_cap < need: + g_ir_vals = alloc(need * 8) + g_ir_vals_cap = need + vi : ., mut = 0 + loop: + if vi >= need: + break + w64(g_ir_vals, vi * 8, 0) + vi = vi + 1 // 编译期标量常量全局初始化阶段——与 ELF _start 的常量初始化循环 // (os/linux/entry.cr 的 g_ir_globals +16 环)同语义、同数据源。此前解释器 // 无此阶段:可变标量全局读回 0(不可变标量因 find_global_const_node 折叠 // 而侥幸正确)。运行期初始化的聚合/非常量全局不在此——它们在 main 序言以 // IR 序列注入(ir_gen.cr inject_global_inits,主循环执行)。 - gi2 : ., mut = 0; - loop { - if gi2 >= g_ir_global_count { break; } - iv2 := r64(g_ir_globals, gi2 * 24 + 16); - gv2 := r64(g_ir_globals, gi2 * 24 + 8); - if iv2 != 0 && gv2 >= 0 && gv2 < need { w64(g_ir_vals, gv2 * 8, iv2); } - gi2 = gi2 + 1; - } + gi2 : ., mut = 0 + loop: + if gi2 >= g_ir_global_count: + break + iv2 := r64(g_ir_globals, gi2 * 24 + 16) + gv2 := r64(g_ir_globals, gi2 * 24 + 8) + if iv2 != 0 && gv2 >= 0 && gv2 < need: + w64(g_ir_vals, gv2 * 8, iv2) + gi2 = gi2 + 1 // Pre-scan: build label→node mapping (for branches) - g_label_count = 0; - li : ., mut = 0; - loop { - if li >= node_count { break; } - n_op := r64(g_df_nodes, (node_start + li) * ESZ_DFNODE + OFF_DF_OPCODE); - n_s1 := r64(g_df_nodes, (node_start + li) * ESZ_DFNODE + OFF_DF_S1); - if n_op == 21 { // IR_LABEL - ln := n_s1; // label number - if ln >= 0 { - grow_label_poses(ln + 1); - w64(g_label_poses, ln * 8, li); - if ln + 1 > g_label_count { g_label_count = ln + 1; } - } - } - li = li + 1; - } + g_label_count = 0 + li : ., mut = 0 + loop: + if li >= node_count: + break + n_op := r64(g_df_nodes, (node_start + li) * ESZ_DFNODE + OFF_DF_OPCODE) + n_s1 := r64(g_df_nodes, (node_start + li) * ESZ_DFNODE + OFF_DF_S1) + if n_op == 21: + // IR_LABEL + ln := n_s1 // label number + if ln >= 0: + grow_label_poses(ln + 1) + w64(g_label_poses, ln * 8, li) + if ln + 1 > g_label_count: + g_label_count = ln + 1 + li = li + 1 // Pre-scan: record SG_LOOP/SG_FOR region enter/exit node offsets // (main function graph only — filter by node_start..node_start+node_count) - g_loop_region_count = 0; - li = 0; - loop { - if li >= g_sg_count { break; } - lk := r64(g_sgs, li * ESZ_SG + OFF_SG_KIND); - if lk == SG_LOOP || lk == SG_FOR { - l_enter := r64(g_sgs, li * ESZ_SG + OFF_SG_ENTER); - l_exit := r64(g_sgs, li * ESZ_SG + OFF_SG_EXIT); - if l_enter >= node_start && l_enter < node_start + node_count { - if g_loop_region_count + 1 > g_loop_region_cap { + g_loop_region_count = 0 + li = 0 + loop: + if li >= g_sg_count: + break + lk := r64(g_sgs, li * ESZ_SG + OFF_SG_KIND) + if lk == SG_LOOP || lk == SG_FOR: + l_enter := r64(g_sgs, li * ESZ_SG + OFF_SG_ENTER) + l_exit := r64(g_sgs, li * ESZ_SG + OFF_SG_EXIT) + if l_enter >= node_start && l_enter < node_start + node_count: + if g_loop_region_count + 1 > g_loop_region_cap: // Grow both arrays from the OLD cap — copying with the new // cap would over-read the previous (possibly empty) buffer. - nc := g_loop_region_cap * 2; if nc < 16 { nc = 16; } - nb := alloc(nc * 8); _dyncpy(g_loop_region_enter, g_loop_region_cap * 8, nb); - nb2 := alloc(nc * 8); _dyncpy(g_loop_region_exit, g_loop_region_cap * 8, nb2); - g_loop_region_enter = nb; g_loop_region_exit = nb2; g_loop_region_cap = nc; - } - w64(g_loop_region_enter, g_loop_region_count * 8, l_enter - node_start); - w64(g_loop_region_exit, g_loop_region_count * 8, l_exit - node_start); - g_loop_region_count = g_loop_region_count + 1; - } - } - li = li + 1; - } + nc := g_loop_region_cap * 2 + if nc < 16: + nc = 16 + nb := alloc(nc * 8) + _dyncpy(g_loop_region_enter, g_loop_region_cap * 8, nb) + nb2 := alloc(nc * 8) + _dyncpy(g_loop_region_exit, g_loop_region_cap * 8, nb2) + g_loop_region_enter = nb + g_loop_region_exit = nb2 + g_loop_region_cap = nc + w64(g_loop_region_enter, g_loop_region_count * 8, l_enter - node_start) + w64(g_loop_region_exit, g_loop_region_count * 8, l_exit - node_start) + g_loop_region_count = g_loop_region_count + 1 + li = li + 1 // Execute nodes in order (dataflow: sequential order = valid topological order for straight-line) - ip : ., mut = 0; - loop { - if ip >= node_count { break; } - op := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_OPCODE); - d := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_DEST); - s1 := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_S1); - s2 := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_S2); - s3 := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_S3); + ip : ., mut = 0 + loop: + if ip >= node_count: + break + op := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_OPCODE) + d := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_DEST) + s1 := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_S1) + s2 := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_S2) + s3 := r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_S3) // R2 P5 Task 2(D19):派生码(同上一处;IR_BINARY 传参,当前不消费)。 ti := sh_dfn_code_of_slots(r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_TK), - r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_AUX)); - - if op == 1 { if d >= 0 { w64(g_ir_vals, d * 8, s1); } } // IR_CONST(dex 的 s1 为缩放整数) - if op == 5 { if s1 >= 0 { return r64(g_ir_vals, s1 * 8); } return 0; } // IR_RETURN - - if op == 2 { ir_interp_binary(d, s1, s2, s3, ti); } // IR_BINARY - - if op == 3 { // IR_UNARY - ov := r64(g_ir_vals, s1 * 8); - if s3 == 1 { w64(g_ir_vals, d * 8, -ov); } - if s3 == 2 { if ov == 0 { w64(g_ir_vals, d * 8, 1); } else { w64(g_ir_vals, d * 8, 0); } } - } + r64(g_df_nodes, (node_start + ip) * ESZ_DFNODE + OFF_DF_AUX)) + + if op == 1: + if d >= 0: + w64(g_ir_vals, d * 8, s1) + // IR_CONST(dex 的 s1 为缩放整数) + if op == 5: + if s1 >= 0: + return r64(g_ir_vals, s1 * 8) + return 0 + // IR_RETURN + + if op == 2: + ir_interp_binary(d, s1, s2, s3, ti) + // IR_BINARY + + if op == 3: + // IR_UNARY + ov := r64(g_ir_vals, s1 * 8) + if s3 == 1: + w64(g_ir_vals, d * 8, -ov) + if s3 == 2: + if ov == 0: + w64(g_ir_vals, d * 8, 1) + else: + w64(g_ir_vals, d * 8, 0) // Alloc / Store / Load / Field / Index - if op == 6 { if d >= 0 { w64(g_ir_vals, d * 8, 0); } } // IR_ALLOC - if op == 7 { // IR_ALLOC_STRUCT - if d >= 0 { - si := find_struct(s3); - fc : ., mut = 0; - if si >= 0 { fc = si_field_count(si); } - need2 := fc * 8 + 8; - bp := alloc(need2); - vi2 : ., mut = 0; - loop { if vi2 >= need2 { break; } store8(bp, vi2, 0); vi2 = vi2 + 1; } - unsafe { w64(g_ir_vals, d * 8, @ptr_of(bp)); } - } - } - if op == 8 { // IR_ALLOC_ARRAY - if d >= 0 { - cnt := s1; esz := s2; - if esz <= 0 { esz = 8; } - need2 := cnt * esz + 8; - bp := alloc(need2); - vi2 : ., mut = 0; - loop { if vi2 >= need2 { break; } store8(bp, vi2, 0); vi2 = vi2 + 1; } - unsafe { w64(g_ir_vals, d * 8, @ptr_of(bp)); } - } - } - if op == 9 { if s1 >= 0 && s2 >= 0 { w64(g_ir_vals, s1 * 8, r64(g_ir_vals, s2 * 8)); } } // IR_STORE - if op == 10 { if d >= 0 { w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)); } } // IR_LOAD - if op == 11 { // IR_LOAD_FIELD: s1=struct_var, s3=field_idx - if d >= 0 && s1 >= 0 { - ptr := r64(g_ir_vals, s1 * 8); - if ptr != 0 { unsafe { w64(g_ir_vals, d * 8, r64(@str_of(ptr), s3 * 8)); } } - else { w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)); } - } - } - if op == 12 { // IR_STORE_FIELD: s1=struct_var, s2=val_var, s3=field_idx - if s1 >= 0 && s2 >= 0 { - ptr := r64(g_ir_vals, s1 * 8); - if ptr != 0 { unsafe { w64(@str_of(ptr), s3 * 8, r64(g_ir_vals, s2 * 8)); } } - else { w64(g_ir_vals, s1 * 8, r64(g_ir_vals, s2 * 8)); } - } - } - if op == 13 { // IR_LOAD_INDEX: s1=arr_var, s3=literal_idx - if d >= 0 && s1 >= 0 { - arr_value := r64(g_ir_vals, s1 * 8); - if irv_type(s1) == TI_STR { w64(g_ir_vals, d * 8, str_load8(arr_value, s3)); } - else { unsafe { w64(g_ir_vals, d * 8, r64(@str_of(arr_value), s3 * 8)); } } - } - } - if op == 14 { // IR_STORE_INDEX: s1=arr_var, s2=val_var, s3=literal_idx - if s1 >= 0 && s2 >= 0 { - arr_value := r64(g_ir_vals, s1 * 8); - if irv_type(s1) == TI_STR { store8(istr_get(arr_value), s3, r64(g_ir_vals, s2 * 8)); } - else { unsafe { w64(@str_of(arr_value), s3 * 8, r64(g_ir_vals, s2 * 8)); } } - } - } - if op == 15 { // IR_LOAD_INDEX_VAR: s1=arr_var, s2=idx_var - if d >= 0 && s1 >= 0 && s2 >= 0 { - arr_value := r64(g_ir_vals, s1 * 8); - idx := r64(g_ir_vals, s2 * 8); - if irv_type(s1) == TI_STR { w64(g_ir_vals, d * 8, str_load8(arr_value, idx)); } - else { unsafe { w64(g_ir_vals, d * 8, r64(@str_of(arr_value), idx * 8)); } } - } - } - if op == 16 { // IR_STORE_INDEX_VAR: d=val_var, s1=arr_var, s2=idx_var - if d >= 0 && s1 >= 0 && s2 >= 0 { - arr_value := r64(g_ir_vals, s1 * 8); - idx := r64(g_ir_vals, s2 * 8); - if irv_type(s1) == TI_STR { store8(istr_get(arr_value), idx, r64(g_ir_vals, d * 8)); } - else { unsafe { w64(@str_of(arr_value), idx * 8, r64(g_ir_vals, d * 8)); } } - } - } + if op == 6: + if d >= 0: + w64(g_ir_vals, d * 8, 0) + // IR_ALLOC + if op == 7: + // IR_ALLOC_STRUCT + if d >= 0: + si := find_struct(s3) + fc : ., mut = 0 + if si >= 0: + fc = si_field_count(si) + need2 := fc * 8 + 8 + bp := alloc(need2) + vi2 : ., mut = 0 + loop: + if vi2 >= need2: + break + store8(bp, vi2, 0) + vi2 = vi2 + 1 + unsafe: + w64(g_ir_vals, d * 8, @ptr_of(bp)) + if op == 8: + // IR_ALLOC_ARRAY + if d >= 0: + cnt := s1 + esz := s2 + if esz <= 0: + esz = 8 + need2 := cnt * esz + 8 + bp := alloc(need2) + vi2 : ., mut = 0 + loop: + if vi2 >= need2: + break + store8(bp, vi2, 0) + vi2 = vi2 + 1 + unsafe: + w64(g_ir_vals, d * 8, @ptr_of(bp)) + if op == 9: + if s1 >= 0 && s2 >= 0: + w64(g_ir_vals, s1 * 8, r64(g_ir_vals, s2 * 8)) + // IR_STORE + if op == 10: + if d >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)) + // IR_LOAD + if op == 11: + // IR_LOAD_FIELD: s1=struct_var, s3=field_idx + if d >= 0 && s1 >= 0: + ptr := r64(g_ir_vals, s1 * 8) + if ptr != 0: + unsafe: + w64(g_ir_vals, d * 8, r64(@str_of(ptr), s3 * 8)) + else: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)) + if op == 12: + // IR_STORE_FIELD: s1=struct_var, s2=val_var, s3=field_idx + if s1 >= 0 && s2 >= 0: + ptr := r64(g_ir_vals, s1 * 8) + if ptr != 0: + unsafe: + w64(@str_of(ptr), s3 * 8, r64(g_ir_vals, s2 * 8)) + else: + w64(g_ir_vals, s1 * 8, r64(g_ir_vals, s2 * 8)) + if op == 13: + // IR_LOAD_INDEX: s1=arr_var, s3=literal_idx + if d >= 0 && s1 >= 0: + arr_value := r64(g_ir_vals, s1 * 8) + if irv_type(s1) == TI_STR: + w64(g_ir_vals, d * 8, str_load8(arr_value, s3)) + else: + unsafe: + w64(g_ir_vals, d * 8, r64(@str_of(arr_value), s3 * 8)) + if op == 14: + // IR_STORE_INDEX: s1=arr_var, s2=val_var, s3=literal_idx + if s1 >= 0 && s2 >= 0: + arr_value := r64(g_ir_vals, s1 * 8) + if irv_type(s1) == TI_STR: + store8(istr_get(arr_value), s3, r64(g_ir_vals, s2 * 8)) + else: + unsafe: + w64(@str_of(arr_value), s3 * 8, r64(g_ir_vals, s2 * 8)) + if op == 15: + // IR_LOAD_INDEX_VAR: s1=arr_var, s2=idx_var + if d >= 0 && s1 >= 0 && s2 >= 0: + arr_value := r64(g_ir_vals, s1 * 8) + idx := r64(g_ir_vals, s2 * 8) + if irv_type(s1) == TI_STR: + w64(g_ir_vals, d * 8, str_load8(arr_value, idx)) + else: + unsafe: + w64(g_ir_vals, d * 8, r64(@str_of(arr_value), idx * 8)) + if op == 16: + // IR_STORE_INDEX_VAR: d=val_var, s1=arr_var, s2=idx_var + if d >= 0 && s1 >= 0 && s2 >= 0: + arr_value := r64(g_ir_vals, s1 * 8) + idx := r64(g_ir_vals, s2 * 8) + if irv_type(s1) == TI_STR: + store8(istr_get(arr_value), idx, r64(g_ir_vals, d * 8)) + else: + unsafe: + w64(@str_of(arr_value), idx * 8, r64(g_ir_vals, d * 8)) // IR_MAKE_ENUM (17):d := alloc(8·(1+s2));M[d+0] := s1(tag = 变体名索引)—— // 与 ELF 布局 [tag][payload...] 一致的堆镜像(payload 由后续 IR_STORE_FIELD 写堆) - if op == 17 { - if d >= 0 { - need2 := 8 + s2 * 8; - bp := alloc(need2); - vi2 : ., mut = 0; - loop { if vi2 >= need2 { break; } store8(bp, vi2, 0); vi2 = vi2 + 1; } - w64(bp, 0, s1); - unsafe { w64(g_ir_vals, d * 8, @ptr_of(bp)); } - } - } + if op == 17: + if d >= 0: + need2 := 8 + s2 * 8 + bp := alloc(need2) + vi2 : ., mut = 0 + loop: + if vi2 >= need2: + break + store8(bp, vi2, 0) + vi2 = vi2 + 1 + w64(bp, 0, s1) + unsafe: + w64(g_ir_vals, d * 8, @ptr_of(bp)) // IR_LOAD_ENUM_TAG (23):d := M[ρ(s1)+0] - if op == 23 { - if d >= 0 && s1 >= 0 { - ptr := r64(g_ir_vals, s1 * 8); - if ptr != 0 { unsafe { w64(g_ir_vals, d * 8, r64(@str_of(ptr), 0)); } } - } - } + if op == 23: + if d >= 0 && s1 >= 0: + ptr := r64(g_ir_vals, s1 * 8) + if ptr != 0: + unsafe: + w64(g_ir_vals, d * 8, r64(@str_of(ptr), 0)) // IR_REF (18):d := &ρ(s1)——槽模型近似:槽号即「地址」(ir_interp_deref_* 同规则) - if op == 18 { if d >= 0 && s1 >= 0 { w64(g_ir_vals, d * 8, s1); } } + if op == 18: + if d >= 0 && s1 >= 0: + w64(g_ir_vals, d * 8, s1) // IR_DEREF (25):d := M[ρ(s1)](栈槽间接或堆读取,见 ir_interp_deref_read) - if op == 25 { - if d >= 0 && s1 >= 0 { - w64(g_ir_vals, d * 8, ir_interp_deref_read(r64(g_ir_vals, s1 * 8))); - } - } + if op == 25: + if d >= 0 && s1 >= 0: + w64(g_ir_vals, d * 8, ir_interp_deref_read(r64(g_ir_vals, s1 * 8))) // IR_SLICE (24): d := arr + low*8(与 ELF 编码一致;BC11 补实现) - if op == 24 { - if d >= 0 && s1 >= 0 && s2 >= 0 { - w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8) + r64(g_ir_vals, s2 * 8) * 8); - } - } + if op == 24: + if d >= 0 && s1 >= 0 && s2 >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8) + r64(g_ir_vals, s2 * 8) * 8) // IR_BOUNDS_CHECK (30): s1=index var, s2=max_len 字面量 — // index < 0 或 index >= max → 陷阱(返回 -1 表示中止;BC11 补实现) - if op == 30 && s2 >= 0 { - iv := r64(g_ir_vals, s1 * 8); - limit : ., mut = s2; - if ti == 1 { limit = r64(g_ir_vals, s2 * 8); } - if iv < 0 || iv >= limit { return -1; } - } + if op == 30 && s2 >= 0: + iv := r64(g_ir_vals, s1 * 8) + limit : ., mut = s2 + if ti == 1: + limit = r64(g_ir_vals, s2 * 8) + if iv < 0 || iv >= limit: + return -1 // IR_LAZY_THUNK / IR_LAZY_FORCE. Calls are currently eager, so both // wrappers preserve the computed value. - if op == 46 || op == 47 { - if d >= 0 && s1 >= 0 { w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)); } - } + if op == 46 || op == 47: + if d >= 0 && s1 >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)) // IR_YIELD (28):eager 值传递近似(d ← ρ(s1),同 IR_AWAIT)。 // F5a:补 d >= 0 守卫——发射恒 dest=-1(ir_gen L1569),原代码 // w64(g_ir_vals, d*8 = -8, ...) 堆下溢写(g_ir_vals[-8],静默 UB)。 - if op == 28 { - if d >= 0 && s1 >= 0 { w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)); } - } + if op == 28: + if d >= 0 && s1 >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)) // IR_FNADDR — no real addresses in the interpreter; dest = 0 - if op == 48 { - if d >= 0 { w64(g_ir_vals, d * 8, 0); } - } + if op == 48: + if d >= 0: + w64(g_ir_vals, d * 8, 0) // IR_APPROX — pure annotation, skip(无运算语义,不能崩) - if op == 51 { ip = ip + 1; continue; } + if op == 51: + ip = ip + 1 + continue // IR_I2F(49) / IR_F2I(50)——int↔binary64 转换:解释器无 binary64 语义 // (数值迁移 Task 6 定稿)。apx dex 运算必然经过 bits↔缩放转换(打印/边界), // 此处显式报错替代静默跳过——跳过会让目的槽残留 0/脏值,后续除法可能 SIGFPE。 - if op == 49 || op == 50 { - println("interpreter error: IR_I2F/IR_F2I needs binary64 semantics (apx dex) — `corec run` cannot execute apx dex arithmetic; build & run natively (corec build) instead"); - return -1; - } + if op == 49 || op == 50: + println("interpreter error: IR_I2F/IR_F2I needs binary64 semantics (apx dex) — `corec run` cannot execute apx dex arithmetic; build & run natively (corec build) instead") + return -1 // IR_STORE_PTR (26):M[ρ(s1)] := ρ(s2)(与 ELF 操作数一致;d=-1 发射态不再影响)。 // 栈槽间接(指针 = 槽号)或堆写入,见 ir_interp_deref_write。 - if op == 26 { if s1 >= 0 && s2 >= 0 { ir_interp_deref_write(r64(g_ir_vals, s1 * 8), r64(g_ir_vals, s2 * 8)); } } + if op == 26: + if s1 >= 0 && s2 >= 0: + ir_interp_deref_write(r64(g_ir_vals, s1 * 8), r64(g_ir_vals, s2 * 8)) // IR_ADDR_INDEX (31):d := ρ(s1) + 8·ρ(s2)(&arr[i];s3=scale 恒 3,与 ELF 一致) - if op == 31 { - if d >= 0 && s1 >= 0 && s2 >= 0 { - w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8) + r64(g_ir_vals, s2 * 8) * 8); - } - } + if op == 31: + if d >= 0 && s1 >= 0 && s2 >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8) + r64(g_ir_vals, s2 * 8) * 8) // IR_ARENA_NEW (32) / IR_ARENA_RESET (33):interp 无 arena——no-op 近似 // (对照语义表 2.4 的 D7:ELF 有 arena 句柄/复位;解释器槽模型无作用域内存概念) - if op == 32 { if d >= 0 { w64(g_ir_vals, d * 8, 0); } } - if op == 33 { } + if op == 32: + if d >= 0: + w64(g_ir_vals, d * 8, 0) + // IR_DYN_PACK (43):dyn 变量双槽 [value, tag]——slot[d]=值、slot[d+1]=tag(对照 ELF slot+0/+8) - if op == 43 { - if d >= 0 && s1 >= 0 { - w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)); - w64(g_ir_vals, (d + 1) * 8, s2); - } - } + if op == 43: + if d >= 0 && s1 >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)) + w64(g_ir_vals, (d + 1) * 8, s2) // IR_DYN_TAG (41):d := slot[ρ(s1)+1](读 +8 槽) - if op == 41 { if d >= 0 && s1 >= 0 { w64(g_ir_vals, d * 8, r64(g_ir_vals, (s1 + 1) * 8)); } } + if op == 41: + if d >= 0 && s1 >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, (s1 + 1) * 8)) // IR_DYN_VAL (42):d := slot[ρ(s1)](读 +0 槽) - if op == 42 { if d >= 0 && s1 >= 0 { w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)); } } + if op == 42: + if d >= 0 && s1 >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)) // IR_DYN_DISPATCH (44):显式报错(不再静默跳过;对照 ELF 的占位实现——见语义表 2.6 BC9) - if op == 44 { - println("error: interp 不支持动态分发(IR_DYN_DISPATCH)"); - return 2; - } + if op == 44: + println("error: interp 不支持动态分发(IR_DYN_DISPATCH)") + return 2 // IR_CALL_EXTERN (45):显式报错(不再静默错值;ELF 静态构建同样拒绝,见 F16) - if op == 45 { - print("error: interp 无法调用外部函数:"); println(istr_get(s1)); - return 2; - } + if op == 45: + print("error: interp 无法调用外部函数:") + println(istr_get(s1)) + return 2 // IR_I2F(49)/IR_F2I(50) 在 dispatch 入口已被显式报错拦截(#2026-09-13-9 定稿:interp 无 binary64) // Branch (node-index based) - if op == 19 { - cv := r64(g_ir_vals, s1 * 8); - if cv != 0 { if s2 >= 0 && s2 < g_label_count { ip = r64(g_label_poses, s2 * 8); } } - else { if s3 >= 0 && s3 < g_label_count { ip = r64(g_label_poses, s3 * 8); } } - if ip < node_count { continue; } else { break; } - } - if op == 20 { // IR_JUMP + if op == 19: + cv := r64(g_ir_vals, s1 * 8) + if cv != 0: + if s2 >= 0 && s2 < g_label_count: + ip = r64(g_label_poses, s2 * 8) + else: + if s3 >= 0 && s3 < g_label_count: + ip = r64(g_label_poses, s3 * 8) + if ip < node_count: + continue + else: + break + if op == 20: + // IR_JUMP // Region iteration: a jump whose target is the innermost // enclosing loop region's enter is a back-edge — loop iteration // is driven by the region (SG) table: ip is taken from @@ -765,44 +956,49 @@ fn ir_interpret() -> int { // Innermost loop region enclosing the current ip (if any): // among regions containing ip, the one with the largest enter // offset is the innermost (e2 > cur_enter selection). - cur_enter : ., mut = -1; - cur_ri : ., mut = -1; - ri2 : ., mut = 0; - loop { - if ri2 >= g_loop_region_count { break; } - e2 := r64(g_loop_region_enter, ri2 * 8); - x2 := r64(g_loop_region_exit, ri2 * 8); - if ip >= e2 && ip < x2 && e2 > cur_enter { cur_enter = e2; cur_ri = ri2; } - ri2 = ri2 + 1; - } - if s1 >= 0 && s1 < g_label_count { - target := r64(g_label_poses, s1 * 8); - if target >= 0 { - if cur_ri >= 0 && target == cur_enter { + cur_enter : ., mut = -1 + cur_ri : ., mut = -1 + ri2 : ., mut = 0 + loop: + if ri2 >= g_loop_region_count: + break + e2 := r64(g_loop_region_enter, ri2 * 8) + x2 := r64(g_loop_region_exit, ri2 * 8) + if ip >= e2 && ip < x2 && e2 > cur_enter: + cur_enter = e2 + cur_ri = ri2 + ri2 = ri2 + 1 + if s1 >= 0 && s1 < g_label_count: + target := r64(g_label_poses, s1 * 8) + if target >= 0: + if cur_ri >= 0 && target == cur_enter: // Back-edge to the innermost loop region's enter: // ip comes from the region table, not label poses. - ip = r64(g_loop_region_enter, cur_ri * 8); // == cur_enter - } else { - ip = target; // plain jump, resolved via label poses - } - } else { ip = ip + 1; } - } else { ip = ip + 1; } - if ip < node_count { continue; } else { break; } - } + ip = r64(g_loop_region_enter, cur_ri * 8) // == cur_enter + else: + ip = target // plain jump, resolved via label poses + else: + ip = ip + 1 + else: + ip = ip + 1 + if ip < node_count: + continue + else: + break // IR_LABEL (21) - noop // IR_AWAIT - if op == 29 { if d >= 0 { w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)); } } + if op == 29: + if d >= 0: + w64(g_ir_vals, d * 8, r64(g_ir_vals, s1 * 8)) // IR_CALL (4) / IR_SPAWN (27) —— 统一分派(ir_interp_call;与 callee 内联 // 路径共用同一实现:内置近似 / 用户函数内联 / 嵌套递归 / 中止码上抛全在此一处)。 // 原实现把这段分派复制在主循环里,callee 路径无对应物 → 双路径静默分叉(TODO #2026-09-10-7)。 - if op == 4 || op == 27 { - ir_interp_call(d, s1, s2, s3); - if g_interp_abort != 0 { return g_interp_abort; } - } - - ip = ip + 1; - } - return 0; -} + if op == 4 || op == 27: + ir_interp_call(d, s1, s2, s3) + if g_interp_abort != 0: + return g_interp_abort + + ip = ip + 1 + return 0 diff --git a/src/compiler/ir_gen.cr b/src/compiler/ir_gen.cr index 9c804894..d40d505d 100644 --- a/src/compiler/ir_gen.cr +++ b/src/compiler/ir_gen.cr @@ -5,193 +5,212 @@ // (IR globals declared in globals.cr) // Subgraph-level arena tracking for compile-time size estimation -g_sg_alloc_total : string, mut; // per-sg: cumulative alloc size -g_sg_alloc_cap : int, mut; -g_sg_arena_var : string, mut; // per-sg: IR var for arena ID -g_sg_arena_var_cap : int, mut; -g_ir_source_hash : int, mut; -g_ir_source_hash_ready : int, mut; +g_sg_alloc_total : string, mut // per-sg: cumulative alloc size +g_sg_alloc_cap : int, mut +g_sg_arena_var : string, mut // per-sg: IR var for arena ID +g_sg_arena_var_cap : int, mut +g_ir_source_hash : int, mut +g_ir_source_hash_ready : int, mut // 切片编译期长度侧表(var → 字面量长度;-1 = 未知/无记录)。 // IR_SLICE 的字面量界(high−low)在此登记,供解引用处的越界检查 // (pass_before_array_access 的 arr_len_lit)使用——见 F11。 -g_ir_slice_lens : string, mut; // [var, len] pairs -g_ir_slice_len_count : int, mut; -g_ir_slice_len_cap : int, mut; - -fn grow_ir_slice_lens(needed: int) { - if needed < g_ir_slice_len_cap { return; } - nc := g_ir_slice_len_cap * 2; if nc < 8 { nc = 8; } if nc < needed { nc = needed + 8; } - nb := alloc(nc * 16); _dyncpy(g_ir_slice_lens, g_ir_slice_len_cap * 16, nb); - g_ir_slice_lens = nb; g_ir_slice_len_cap = nc; -} - -fn slice_len_get(var_idx: int) -> int { - si : ., mut = 0; - loop { if si >= g_ir_slice_len_count { break; } - if r64(g_ir_slice_lens, si * 16) == var_idx { return r64(g_ir_slice_lens, si * 16 + 8); } - si = si + 1; } - return -1; -} - -fn slice_len_set(var_idx: int, len: int) { - si : ., mut = 0; - loop { if si >= g_ir_slice_len_count { break; } - if r64(g_ir_slice_lens, si * 16) == var_idx { - w64(g_ir_slice_lens, si * 16 + 8, len); - return; - } - si = si + 1; } - if len < 0 { return; } - grow_ir_slice_lens(g_ir_slice_len_count + 1); - w64(g_ir_slice_lens, g_ir_slice_len_count * 16, var_idx); - w64(g_ir_slice_lens, g_ir_slice_len_count * 16 + 8, len); - g_ir_slice_len_count = g_ir_slice_len_count + 1; -} +g_ir_slice_lens : string, mut // [var, len] pairs +g_ir_slice_len_count : int, mut +g_ir_slice_len_cap : int, mut + +fn grow_ir_slice_lens(needed: int): + if needed < g_ir_slice_len_cap: + return + nc := g_ir_slice_len_cap * 2 + if nc < 8: + nc = 8 + if nc < needed: + nc = needed + 8 + nb := alloc(nc * 16) + _dyncpy(g_ir_slice_lens, g_ir_slice_len_cap * 16, nb) + g_ir_slice_lens = nb + g_ir_slice_len_cap = nc + +fn slice_len_get(var_idx: int) -> int: + si : ., mut = 0 + loop: + if si >= g_ir_slice_len_count: + break + if r64(g_ir_slice_lens, si * 16) == var_idx: + return r64(g_ir_slice_lens, si * 16 + 8) + si = si + 1 + return -1 + +fn slice_len_set(var_idx: int, len: int): + si : ., mut = 0 + loop: + if si >= g_ir_slice_len_count: + break + if r64(g_ir_slice_lens, si * 16) == var_idx: + w64(g_ir_slice_lens, si * 16 + 8, len) + return + si = si + 1 + if len < 0: + return + grow_ir_slice_lens(g_ir_slice_len_count + 1) + w64(g_ir_slice_lens, g_ir_slice_len_count * 16, var_idx) + w64(g_ir_slice_lens, g_ir_slice_len_count * 16 + 8, len) + g_ir_slice_len_count = g_ir_slice_len_count + 1 // F11(运行时界切片,2026-09-05 扩展):len 字段编码—— // >= 0 = 字面量长度;<= -2 = 长度 IR 变量(-2-len_var,避开 -1 清除码);-1 = 已清除/无记录。 -fn slice_len_raw_set(var_idx: int, len_code: int) { - si : ., mut = 0; - loop { if si >= g_ir_slice_len_count { break; } - if r64(g_ir_slice_lens, si * 16) == var_idx { - w64(g_ir_slice_lens, si * 16 + 8, len_code); - return; - } - si = si + 1; } - if len_code == -1 { return; } // 清除无条目 = no-op;负编码(长度变量)允许新增 - grow_ir_slice_lens(g_ir_slice_len_count + 1); - w64(g_ir_slice_lens, g_ir_slice_len_count * 16, var_idx); - w64(g_ir_slice_lens, g_ir_slice_len_count * 16 + 8, len_code); - g_ir_slice_len_count = g_ir_slice_len_count + 1; -} +fn slice_len_raw_set(var_idx: int, len_code: int): + si : ., mut = 0 + loop: + if si >= g_ir_slice_len_count: + break + if r64(g_ir_slice_lens, si * 16) == var_idx: + w64(g_ir_slice_lens, si * 16 + 8, len_code) + return + si = si + 1 + if len_code == -1: + return + // 清除无条目 = no-op;负编码(长度变量)允许新增 + grow_ir_slice_lens(g_ir_slice_len_count + 1) + w64(g_ir_slice_lens, g_ir_slice_len_count * 16, var_idx) + w64(g_ir_slice_lens, g_ir_slice_len_count * 16 + 8, len_code) + g_ir_slice_len_count = g_ir_slice_len_count + 1 // 登记运行时界切片的长度变量;查询返回 len_var(无 → -1)。 -fn slice_len_var_set(var_idx: int, len_var: int) { - if var_idx < 0 || len_var < 0 { return; } - slice_len_raw_set(var_idx, -2 - len_var); -} - -fn slice_len_var_get(var_idx: int) -> int { - si : ., mut = 0; - loop { if si >= g_ir_slice_len_count { break; } - if r64(g_ir_slice_lens, si * 16) == var_idx { - v := r64(g_ir_slice_lens, si * 16 + 8); - if v <= -2 { return -2 - v; } - return -1; - } - si = si + 1; } - return -1; -} +fn slice_len_var_set(var_idx: int, len_var: int): + if var_idx < 0 || len_var < 0: + return + slice_len_raw_set(var_idx, -2 - len_var) + +fn slice_len_var_get(var_idx: int) -> int: + si : ., mut = 0 + loop: + if si >= g_ir_slice_len_count: + break + if r64(g_ir_slice_lens, si * 16) == var_idx: + v := r64(g_ir_slice_lens, si * 16 + 8) + if v <= -2: + return -2 - v + return -1 + si = si + 1 + return -1 // 切片长度沿赋值/LET 传播:无条件同步 src 记录到 dst——src 无记录 // 时清除 dst(防非切片赋值后陈旧长度残留导致误守卫)。 -fn slice_len_copy_to(dst_var: int, src_var: int) { - si : ., mut = 0; - loop { if si >= g_ir_slice_len_count { break; } - if r64(g_ir_slice_lens, si * 16) == src_var { - slice_len_raw_set(dst_var, r64(g_ir_slice_lens, si * 16 + 8)); - return; - } - si = si + 1; } - slice_len_raw_set(dst_var, -1); -} +fn slice_len_copy_to(dst_var: int, src_var: int): + si : ., mut = 0 + loop: + if si >= g_ir_slice_len_count: + break + if r64(g_ir_slice_lens, si * 16) == src_var: + slice_len_raw_set(dst_var, r64(g_ir_slice_lens, si * 16 + 8)) + return + si = si + 1 + slice_len_raw_set(dst_var, -1) // 切片解引用守卫(运行时界长度):s1 = idx 变量/字面量,上限 = 长度变量 // (IR_BOUNDS_CHECK ti=1 动态上限——与 emit_string_bounds 同机制)。 -fn emit_slice_bounds(arr_var: int, idx_var: int) { - if arr_var < 0 || idx_var < 0 { return; } - lv := slice_len_var_get(arr_var); - if lv >= 0 { emit(IR_BOUNDS_CHECK, -1, idx_var, lv, 0, 1); } -} - -fn emit_slice_lit_bounds(arr_var: int, idx_lit: int) { - if arr_var < 0 { return; } - lv := slice_len_var_get(arr_var); - if lv >= 0 { - t := new_ir_var("_slice_idx", TI_INT); - emit(IR_CONST, t, idx_lit, 0, 0, TI_INT); - emit(IR_BOUNDS_CHECK, -1, t, lv, 0, 1); - } -} +fn emit_slice_bounds(arr_var: int, idx_var: int): + if arr_var < 0 || idx_var < 0: + return + lv := slice_len_var_get(arr_var) + if lv >= 0: + emit(IR_BOUNDS_CHECK, -1, idx_var, lv, 0, 1) + +fn emit_slice_lit_bounds(arr_var: int, idx_lit: int): + if arr_var < 0: + return + lv := slice_len_var_get(arr_var) + if lv >= 0: + t := new_ir_var("_slice_idx", TI_INT) + emit(IR_CONST, t, idx_lit, 0, 0, TI_INT) + emit(IR_BOUNDS_CHECK, -1, t, lv, 0, 1) // 数组/切片的编译期长度:TYP_ARRAY 的 extra=size;切片查侧表(字面量界)。 // 未知 → -1(ext_safety 不发射 IR_BOUNDS_CHECK)。 -fn arr_len_lit_of(arr_var: int) -> int { - if arr_var < 0 { return -1; } - ti := irv_type(arr_var); - if ti >= 0 && ti < g_type_count && get_type_kind(ti) == TYP_ARRAY { - return get_type_extra(ti); - } - if ti == TI_STR { - prod := r64(g_df_var_producer, arr_var * 8); +fn arr_len_lit_of(arr_var: int) -> int: + if arr_var < 0: + return -1 + ti := irv_type(arr_var) + if ti >= 0 && ti < g_type_count && get_type_kind(ti) == TYP_ARRAY: + return get_type_extra(ti) + if ti == TI_STR: + prod := r64(g_df_var_producer, arr_var * 8) // R2 P5 Task 2(D19):读 **派生码**(不是 40 槽——单槽化后 40 槽 = 类型项引用); // 常量节点的行是原子基行 ⇒ 派生码逐字节 ≡ 单槽化前该槽的混用码。 - if prod >= 0 && r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE) == IR_CONST && - sh_dfn_code_of_slots(r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_TK), - r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_AUX)) == TI_STR { - return istr_len(r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S1)); - } - } - return slice_len_get(arr_var); -} - -fn emit_string_bounds(arr_var: int, idx_var: int) { - if arr_var < 0 || idx_var < 0 || irv_type(arr_var) != TI_STR { return; } - len_var := new_ir_var("str_len", TI_INT); - emit(IR_CALL, len_var, arr_var, 1, str_intern("str_len"), TI_INT); - emit(IR_BOUNDS_CHECK, -1, idx_var, len_var, 0, 1); -} + if prod >= 0 && r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE) == IR_CONST && sh_dfn_code_of_slots(r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_TK), + r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_AUX)) == TI_STR: + return istr_len(r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S1)) + return slice_len_get(arr_var) + +fn emit_string_bounds(arr_var: int, idx_var: int): + if arr_var < 0 || idx_var < 0 || irv_type(arr_var) != TI_STR: + return + len_var := new_ir_var("str_len", TI_INT) + emit(IR_CALL, len_var, arr_var, 1, str_intern("str_len"), TI_INT) + emit(IR_BOUNDS_CHECK, -1, idx_var, len_var, 0, 1) // 字面量下标 + 字符串 → 运行时边界守卫(M-2 遗留:emit_string_bounds // 只覆盖变量下标路径,常量下标路径与 arr_len_lit 两头落空——静默越界)。 -fn emit_string_lit_bounds(arr_var: int, idx_lit: int) { - if arr_var < 0 || irv_type(arr_var) != TI_STR { return; } - idx_var := new_ir_var("_idx_lit", TI_INT); - emit(IR_CONST, idx_var, idx_lit, 0, 0, TI_INT); - emit_string_bounds(arr_var, idx_var); -} - -fn grow_sg_alloc(needed: int) { - if needed < g_sg_alloc_cap { return; } - nc := g_sg_alloc_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_sg_alloc_total, g_sg_alloc_cap * 8, nb); g_sg_alloc_total = nb; g_sg_alloc_cap = nc; } - -fn grow_sg_arena_var(needed: int) { - if needed < g_sg_arena_var_cap { return; } - nc := g_sg_arena_var_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_sg_arena_var, g_sg_arena_var_cap * 8, nb); g_sg_arena_var = nb; g_sg_arena_var_cap = nc; } - -fn sg_alloc_push(kind: int) { - grow_sg_alloc(g_sg_count + 1); - grow_sg_arena_var(g_sg_count + 1); - w64(g_sg_alloc_total, g_sg_count * 8, 0); - sg_push(kind); -} - -fn sg_alloc_pop() { - total := r64(g_sg_alloc_total, (g_sg_count - 1) * 8); - arena_var := r64(g_sg_arena_var, (g_sg_count - 1) * 8); - sg_pop(); - emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0); -} - -fn track_alloc_size(size: int) { - if g_sg_count > 0 && str_len(g_sg_alloc_total) > 0 { - prev := r64(g_sg_alloc_total, (g_sg_count - 1) * 8); - w64(g_sg_alloc_total, (g_sg_count - 1) * 8, prev + size); - } -} - -fn new_ir_var(name: string, type_idx: int) -> int { - idx := g_ir_var_count; - grow_ir_vars(idx + 1); - irv_set_name(idx, str_intern(name)); - irv_set_id(idx, idx); - irv_set_type(idx, type_idx); - g_ir_var_count = idx + 1; - return idx; -} +fn emit_string_lit_bounds(arr_var: int, idx_lit: int): + if arr_var < 0 || irv_type(arr_var) != TI_STR: + return + idx_var := new_ir_var("_idx_lit", TI_INT) + emit(IR_CONST, idx_var, idx_lit, 0, 0, TI_INT) + emit_string_bounds(arr_var, idx_var) + +fn grow_sg_alloc(needed: int): + if needed < g_sg_alloc_cap: + return + nc := g_sg_alloc_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_sg_alloc_total, g_sg_alloc_cap * 8, nb) + g_sg_alloc_total = nb + g_sg_alloc_cap = nc + +fn grow_sg_arena_var(needed: int): + if needed < g_sg_arena_var_cap: + return + nc := g_sg_arena_var_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_sg_arena_var, g_sg_arena_var_cap * 8, nb) + g_sg_arena_var = nb + g_sg_arena_var_cap = nc + +fn sg_alloc_push(kind: int): + grow_sg_alloc(g_sg_count + 1) + grow_sg_arena_var(g_sg_count + 1) + w64(g_sg_alloc_total, g_sg_count * 8, 0) + sg_push(kind) + +fn sg_alloc_pop(): + total := r64(g_sg_alloc_total, (g_sg_count - 1) * 8) + arena_var := r64(g_sg_arena_var, (g_sg_count - 1) * 8) + sg_pop() + emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0) + +fn track_alloc_size(size: int): + if g_sg_count > 0 && str_len(g_sg_alloc_total) > 0: + prev := r64(g_sg_alloc_total, (g_sg_count - 1) * 8) + w64(g_sg_alloc_total, (g_sg_count - 1) * 8, prev + size) + +fn new_ir_var(name: string, type_idx: int) -> int: + idx := g_ir_var_count + grow_ir_vars(idx + 1) + irv_set_name(idx, str_intern(name)) + irv_set_id(idx, idx) + irv_set_type(idx, type_idx) + g_ir_var_count = idx + 1 + return idx // ── 可选运行期表示面(R2 P4 Task 5;裁决 5「解包侧判表示」;附录 B.7)── // 事实:`Some(1)`/`None` 走 IR_MAKE_ENUM 对象([tag][payload…]),而 `T?` 槽里的 @@ -211,88 +230,110 @@ fn new_ir_var(name: string, type_idx: int) -> int { // 表示码常量 OE_BARE/OE_BOXED 声明在 **globals.cr**(负值文件级常量放本文件会静默读 0 // ——见该处注记与 iface_registry.cr:23 先例;实测踩过)。 -fn grow_ir_var_rep(needed: int) { - if needed < g_ir_var_rep_cap { return; } - nc := g_ir_var_rep_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_ir_var_rep, g_ir_var_rep_cap * 8, nb); +fn grow_ir_var_rep(needed: int): + if needed < g_ir_var_rep_cap: + return + nc := g_ir_var_rep_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_ir_var_rep, g_ir_var_rep_cap * 8, nb) // 新槽填 **-1(哨兵 = 无表示位)**——alloc 零初始化,不填则「未写槽」被读成 // 表示位 var 0(每个值都被判成「有表示位」= 静默错值;实测踩过:`None` 初值 // 的表示位被读成 var0 的当前值 0 = 裸值)。照 tag2l.cr 的 tag 区初始化先例。 - z : ., mut = g_ir_var_rep_cap; - loop { if z >= nc { break; } w64(nb, z * 8, -1); z = z + 1; } - g_ir_var_rep = nb; g_ir_var_rep_cap = nc; -} + z : ., mut = g_ir_var_rep_cap + loop: + if z >= nc: + break + w64(nb, z * 8, -1) + z = z + 1 + g_ir_var_rep = nb + g_ir_var_rep_cap = nc // 槽的表示位变量索引(-1 = 无表示位 = 非可选槽 / 未覆盖面 / 本编译单元未启用)。 // 守卫走 **cap(int 全局,默认 0)而非 str_len(base)**——base 未分配时是空串/空指针, // 未初始化的 str_len 即 SIGSEGV(实测:文件路径(main.cr 逐函数 + .cir 缓存)不经过 // 批量入口的复位面 ⇒ 本函数必须自守卫)。 -fn irv_rep(var_idx: int) -> int { - if var_idx < 0 { return -1; } - if g_ir_var_rep_cap <= 0 { return -1; } - if var_idx >= g_ir_var_rep_cap { return -1; } - return r64(g_ir_var_rep, var_idx * 8); -} - -fn irv_set_rep(var_idx: int, rep_var: int) { - if var_idx < 0 { return; } - grow_ir_var_rep(var_idx + 1); - w64(g_ir_var_rep, var_idx * 8, rep_var); -} +fn irv_rep(var_idx: int) -> int: + if var_idx < 0: + return -1 + if g_ir_var_rep_cap <= 0: + return -1 + if var_idx >= g_ir_var_rep_cap: + return -1 + return r64(g_ir_var_rep, var_idx * 8) + +fn irv_set_rep(var_idx: int, rep_var: int): + if var_idx < 0: + return + grow_ir_var_rep(var_idx + 1) + w64(g_ir_var_rep, var_idx * 8, rep_var) // 置表示位:enc >= 0 → 从该表示位槽拷贝;OE_BARE/OE_BOXED → 直接常量写。 -fn emit_rep_set(rep_var: int, enc: int) { - if rep_var < 0 { return; } - if enc == oe_bare() { emit(IR_CONST, rep_var, 0, 0, 0, TI_INT); return; } - if enc == oe_boxed() { emit(IR_CONST, rep_var, 1, 0, 0, TI_INT); return; } - if enc >= 0 { emit(IR_STORE, -1, rep_var, enc, 0, 0); } -} +fn emit_rep_set(rep_var: int, enc: int): + if rep_var < 0: + return + if enc == oe_bare(): + emit(IR_CONST, rep_var, 0, 0, 0, TI_INT) + return + if enc == oe_boxed(): + emit(IR_CONST, rep_var, 1, 0, 0, TI_INT) + return + if enc >= 0: + emit(IR_STORE, -1, rep_var, enc, 0, 0) // 给可选槽配表示位变量(初始值 = 1 装箱 = 既有语义);非可选/未启用 → -1。 -fn opt_rep_slot(ti: int, name: string) -> int { - if g_optrep_on == 0 { return -1; } - if ti < 0 || ti >= g_type_count { return -1; } - if get_type_kind(ti) != TYP_OPTIONAL { return -1; } - rv := new_ir_var(name + "_rep", TI_INT); - emit(IR_CONST, rv, 1, 0, 0, TI_INT); - return rv; -} +fn opt_rep_slot(ti: int, name: string) -> int: + if g_optrep_on == 0: + return -1 + if ti < 0 || ti >= g_type_count: + return -1 + if get_type_kind(ti) != TYP_OPTIONAL: + return -1 + rv := new_ir_var(name + "_rep", TI_INT) + emit(IR_CONST, rv, 1, 0, 0, TI_INT) + return rv // 全局槽的声明类型是否可选(globals 无表示位 ⇒ 视作未覆盖面;照声明区分裸/装箱假定)。 -fn global_decl_optional(name_ni: int) -> int { - gi : ., mut = 0; - loop { - if gi >= g_global_let_count { break; } - lnode := r64(g_global_lets, gi * 8); - if ast_a(lnode) == name_ni { - tn := ast_b(lnode); - if tn >= 0 && res_type_node(tn) >= 0 { - if get_type_kind(res_type_node(tn)) == TYP_OPTIONAL { return 1; } - } - return 0; - } - gi = gi + 1; - } - return 0; -} +fn global_decl_optional(name_ni: int) -> int: + gi : ., mut = 0 + loop: + if gi >= g_global_let_count: + break + lnode := r64(g_global_lets, gi * 8) + if ast_a(lnode) == name_ni: + tn := ast_b(lnode) + if tn >= 0 && res_type_node(tn) >= 0: + if get_type_kind(res_type_node(tn)) == TYP_OPTIONAL: + return 1 + return 0 + gi = gi + 1 + return 0 // 被调方返回类型是否可选。判据走**返回类型节点**(`EXPR_FN.type_val`)而非 // `fi_return_type`:后者是 parser 存的**裸类型码**,而 `T?` 的类型节点 `type_val` = 0 // ⇒ 被读成 int 行、判据恒假(实测踩过:裸值返回不写返回信道 + 调用点不读信道, // 回落装箱假定 ⇒ `fn g() -> int? { return 5; }` 的调用点解包仍崩)。 -fn callee_ret_optional(func_ni: int) -> int { - if func_ni < 0 { return 0; } - cfi := find_func(func_ni); - if cfi < 0 { return 0; } - cfn := fi_ast_node(cfi); - if cfn < 0 || ast_kind(cfn) != EXPR_FN { return 0; } - rtn := ast_type_val(cfn); - if rtn < 0 { return 0; } - rti := res_type_node(rtn); - if rti < 0 || rti >= g_type_count { return 0; } - if get_type_kind(rti) == TYP_OPTIONAL { return 1; } - return 0; -} +fn callee_ret_optional(func_ni: int) -> int: + if func_ni < 0: + return 0 + cfi := find_func(func_ni) + if cfi < 0: + return 0 + cfn := fi_ast_node(cfi) + if cfn < 0 || ast_kind(cfn) != EXPR_FN: + return 0 + rtn := ast_type_val(cfn) + if rtn < 0: + return 0 + rti := res_type_node(rtn) + if rti < 0 || rti >= g_type_count: + return 0 + if get_type_kind(rti) == TYP_OPTIONAL: + return 1 + return 0 // ── 容量批 T2(裁-CAP-1 (a)):可选**聚合槽**的存储边界规范化(写点装箱)── // 法则:可选聚合槽(结构体字段 / 数组·切片元素 / 元组元素 / 枚举载荷 / 全局槽)任何时刻恒持 @@ -304,103 +345,119 @@ fn callee_ret_optional(func_ni: int) -> int { // 槽声明类型侧表(var → 声明类型索引;-1 = 无注解/未知)。仅进程内状态,零布局变更。 // 内容(IR var 索引 → 类型索引)由声明面写入(LET 注解 / 形参类型节点),读点 = 元素写。 -fn grow_ir_var_decl(needed: int) { - if needed < g_ir_var_decl_cap { return; } - nc := g_ir_var_decl_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_ir_var_decl_ti, g_ir_var_decl_cap * 8, nb); - z : ., mut = g_ir_var_decl_cap; - loop { if z >= nc { break; } w64(nb, z * 8, -1); z = z + 1; } - g_ir_var_decl_ti = nb; g_ir_var_decl_cap = nc; -} -fn irv_decl_ti(v: int) -> int { - if v < 0 { return -1; } - if g_ir_var_decl_cap <= 0 { return -1; } - if v >= g_ir_var_decl_cap { return -1; } - return r64(g_ir_var_decl_ti, v * 8); -} -fn irv_set_decl_ti(v: int, ti: int) { - if v < 0 || ti < 0 { return; } - grow_ir_var_decl(v + 1); - w64(g_ir_var_decl_ti, v * 8, ti); -} +fn grow_ir_var_decl(needed: int): + if needed < g_ir_var_decl_cap: + return + nc := g_ir_var_decl_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_ir_var_decl_ti, g_ir_var_decl_cap * 8, nb) + z : ., mut = g_ir_var_decl_cap + loop: + if z >= nc: + break + w64(nb, z * 8, -1) + z = z + 1 + g_ir_var_decl_ti = nb + g_ir_var_decl_cap = nc +fn irv_decl_ti(v: int) -> int: + if v < 0: + return -1 + if g_ir_var_decl_cap <= 0: + return -1 + if v >= g_ir_var_decl_cap: + return -1 + return r64(g_ir_var_decl_ti, v * 8) +fn irv_set_decl_ti(v: int, ti: int): + if v < 0 || ti < 0: + return + grow_ir_var_decl(v + 1) + w64(g_ir_var_decl_ti, v * 8, ti) // 目标槽类型是否可选(未知/越界 ⇒ 0 = 不装箱) -fn ti_is_optional(ti: int) -> int { - if ti < 0 { return 0; } - if ti >= g_type_count { return 0; } - if get_type_kind(ti) == TYP_OPTIONAL { return 1; } - return 0; -} +fn ti_is_optional(ti: int) -> int: + if ti < 0: + return 0 + if ti >= g_type_count: + return 0 + if get_type_kind(ti) == TYP_OPTIONAL: + return 1 + return 0 // 槽(IR var)**声明**类型:声明侧表优先,否则运行期类型 -fn slot_decl_ti(v: int) -> int { - d := irv_decl_ti(v); - if d >= 0 { return d; } - return irv_type(v); -} +fn slot_decl_ti(v: int) -> int: + d := irv_decl_ti(v) + if d >= 0: + return d + return irv_type(v) // 声明类型 → 数组/切片元素类型(-1 = 非数组/切片) -fn elem_ti_of_decl(ti: int) -> int { - if ti < 0 { return -1; } - if ti >= g_type_count { return -1; } - k := get_type_kind(ti); - if k == TYP_ARRAY || k == TYP_SLICE { return get_type_data(ti); } - return -1; -} +fn elem_ti_of_decl(ti: int) -> int: + if ti < 0: + return -1 + if ti >= g_type_count: + return -1 + k := get_type_kind(ti) + if k == TYP_ARRAY || k == TYP_SLICE: + return get_type_data(ti) + return -1 // 数组/切片元素类型(-1 = 非数组/切片或未知) -fn elem_ti_of(arr_var: int) -> int { - return elem_ti_of_decl(slot_decl_ti(arr_var)); -} +fn elem_ti_of(arr_var: int) -> int: + return elem_ti_of_decl(slot_decl_ti(arr_var)) // 结构体字段声明类型(field_node = EXPR_FIELD 目标节点;checker 写入 ast_c = 结构体名 ni; // 数字元组下标形(ast_type_val > 0)不是结构体字段 ⇒ 不判) -fn field_ti_of_node(field_node: int, fi: int) -> int { - if field_node < 0 || fi < 0 { return -1; } - if ast_type_val(field_node) > 0 { return -1; } - si := find_struct(ast_c(field_node)); - if si < 0 { return -1; } - return res_type_node(si_field_type_node(si, fi)); -} +fn field_ti_of_node(field_node: int, fi: int) -> int: + if field_node < 0 || fi < 0: + return -1 + if ast_type_val(field_node) > 0: + return -1 + si := find_struct(ast_c(field_node)) + if si < 0: + return -1 + return res_type_node(si_field_type_node(si, fi)) // 结构体行字段声明类型(结构体字面量写点用;si = 行,来自 find_struct_by_name) -fn struct_row_field_ti(si: int, fi: int) -> int { - if si < 0 || fi < 0 { return -1; } - return res_type_node(si_field_type_node(si, fi)); -} +fn struct_row_field_ti(si: int, fi: int) -> int: + if si < 0 || fi < 0: + return -1 + return res_type_node(si_field_type_node(si, fi)) // 全局槽声明类型(-1 = 非全局/无类型节点) -fn global_decl_ti(name_ni: int) -> int { - gi : ., mut = 0; - loop { - if gi >= g_global_let_count { break; } - lnode := r64(g_global_lets, gi * 8); - if ast_a(lnode) == name_ni { - tn := ast_b(lnode); - if tn >= 0 { return res_type_node(tn); } - return -1; - } - gi = gi + 1; - } - return -1; -} +fn global_decl_ti(name_ni: int) -> int: + gi : ., mut = 0 + loop: + if gi >= g_global_let_count: + break + lnode := r64(g_global_lets, gi * 8) + if ast_a(lnode) == name_ni: + tn := ast_b(lnode) + if tn >= 0: + return res_type_node(tn) + return -1 + gi = gi + 1 + return -1 // 枚举变体载荷声明类型(-1 = 非用户枚举构造器/未知) -fn enum_payload_ti(name_ni: int, pos: int) -> int { - si := find_gsym(name_ni); - if si < 0 { return -1; } - ei := find_enum_row_of(sym_type(si)); - if ei < 0 { return -1; } - vi : ., mut = 0; - loop { - if vi >= ei_variant_count(ei) { return -1; } - if ei_variant_name(ei, vi) == name_ni { - return res_type_node(ei_variant_type_node(ei, vi, pos)); - } - vi = vi + 1; - } - return -1; -} +fn enum_payload_ti(name_ni: int, pos: int) -> int: + si := find_gsym(name_ni) + if si < 0: + return -1 + ei := find_enum_row_of(sym_type(si)) + if ei < 0: + return -1 + vi : ., mut = 0 + loop: + if vi >= ei_variant_count(ei): + return -1 + if ei_variant_name(ei, vi) == name_ni: + return res_type_node(ei_variant_type_node(ei, vi, pos)) + vi = vi + 1 + return -1 // ── 聚合读**结果槽的声明面形式**(TODO #2026-09-16-16 批 2 T3 · 裁-AGG-1 ①)────────────────────── // 聚合槽的规范存储形式**恒为精确(scaled)**(apx 批不变量「聚合面不存在 apx 形式」;写点漏斗 @@ -414,69 +471,76 @@ fn enum_payload_ti(name_ni: int, pos: int) -> int { // **未覆盖面(登记,见计划 §10)** = 元组数字下标(裁-AGG-3:元组无声明面)· match 结果槽 // (裁-AGG-2:多臂可异型)· 泛型字段/元素(裁-AGG-4:声明型 = 类型参数)· `IR_SLICE` 产物的 // 元素读(切片 var 的 IR 型恒 `TI_INT`,元素形式无处寄存)。 -fn agg_read_form_is_dex(tn: int) -> int { - if tn < 0 { return 0; } - if ast_kind(tn) != 0 { return 0; } - if ast_type_val(tn) == TY_DEX { return 1; } - return 0; -} +fn agg_read_form_is_dex(tn: int) -> int: + if tn < 0: + return 0 + if ast_kind(tn) != 0: + return 0 + if ast_type_val(tn) == TY_DEX: + return 1 + return 0 // 结构体字段读(`EXPR_FIELD`;数字元组下标形态 `ast_type_val > 0` 无声明面 ⇒ 不判) -fn agg_field_read_form(field_node: int, fi: int) -> int { - if field_node < 0 || fi < 0 { return TI_INT; } - if ast_type_val(field_node) > 0 { return TI_INT; } - si := find_struct(ast_c(field_node)); - if si < 0 { return TI_INT; } - if agg_read_form_is_dex(si_field_type_node(si, fi)) != 0 { return TI_DEX_S; } - return TI_INT; -} +fn agg_field_read_form(field_node: int, fi: int) -> int: + if field_node < 0 || fi < 0: + return TI_INT + if ast_type_val(field_node) > 0: + return TI_INT + si := find_struct(ast_c(field_node)) + if si < 0: + return TI_INT + if agg_read_form_is_dex(si_field_type_node(si, fi)) != 0: + return TI_DEX_S + return TI_INT // 数组/切片元素读:元素 ti 由**数组 var 的型**取得(纯表读);`TI_DEX`(apx 声明形态的 // 元素 ti)与 `TI_DEX_S` 都归一到**精确**读槽(聚合存储 = scaled)。 -fn agg_elem_read_form(arr_var: int) -> int { - et := elem_ti_of_decl(slot_decl_ti(arr_var)); - if et == TI_DEX || et == TI_DEX_S { return TI_DEX_S; } - return TI_INT; -} +fn agg_elem_read_form(arr_var: int) -> int: + et := elem_ti_of_decl(slot_decl_ti(arr_var)) + if et == TI_DEX || et == TI_DEX_S: + return TI_DEX_S + return TI_INT // match 臂载荷绑定读(`EXPR_ENUMPAT`:a=变体名 ni、b=首子模式、c=子模式数) -fn agg_payload_read_form(pat_node: int, pos: int) -> int { - if pat_node < 0 || pos < 0 { return TI_INT; } - name_ni := ast_a(pat_node); - si := find_gsym(name_ni); - if si < 0 { return TI_INT; } - ei := find_enum_row_of(sym_type(si)); - if ei < 0 { return TI_INT; } - vi : ., mut = 0; - loop { - if vi >= ei_variant_count(ei) { return TI_INT; } - if ei_variant_name(ei, vi) == name_ni { - if agg_read_form_is_dex(ei_variant_type_node(ei, vi, pos)) != 0 { return TI_DEX_S; } - return TI_INT; - } - vi = vi + 1; - } - return TI_INT; -} +fn agg_payload_read_form(pat_node: int, pos: int) -> int: + if pat_node < 0 || pos < 0: + return TI_INT + name_ni := ast_a(pat_node) + si := find_gsym(name_ni) + if si < 0: + return TI_INT + ei := find_enum_row_of(sym_type(si)) + if ei < 0: + return TI_INT + vi : ., mut = 0 + loop: + if vi >= ei_variant_count(ei): + return TI_INT + if ei_variant_name(ei, vi) == name_ni: + if agg_read_form_is_dex(ei_variant_type_node(ei, vi, pos)) != 0: + return TI_DEX_S + return TI_INT + vi = vi + 1 + return TI_INT // 元素表达式(元组/数组字面量的元素槽无声明面)的可选性:**保守 = 不可选 ⇒ 不装箱** // 覆盖面 = ident(声明侧表)/ 调用(被调返回类型可选);其余形态登记为未覆盖面。 -fn elem_node_optional(node: int) -> int { - if node < 0 { return 0; } - k := ast_kind(node); - if k == EXPR_IDENT { - lv := find_local(ast_int_val(node)); - if lv >= 0 { return ti_is_optional(slot_decl_ti(lv)); } - return 0; - } - if k == EXPR_CALL { - ni := ast_a(node); - fi2 := find_func(ni); - if fi2 >= 0 { return callee_ret_optional(ni); } - return 0; - } - return 0; -} +fn elem_node_optional(node: int) -> int: + if node < 0: + return 0 + k := ast_kind(node) + if k == EXPR_IDENT: + lv := find_local(ast_int_val(node)) + if lv >= 0: + return ti_is_optional(slot_decl_ti(lv)) + return 0 + if k == EXPR_CALL: + ni := ast_a(node) + fi2 := find_func(ni) + if fi2 >= 0: + return callee_ret_optional(ni) + return 0 + return 0 // (A) T3(裁-T3-1):元素表达式的**可选感知元素类型**(-1 = 不可选/未知面)。 // 字面量/切片两站点的声明面登记用。**调用点必须已判 `g_optrep_on`**——Some/None/调用 @@ -484,647 +548,680 @@ fn elem_node_optional(node: int) -> int { // `Some(x)` / `None`(关键字形)⇒ `T?`(内层此处不可得 ⇒ TI_UNIT 占位;`ti_is_optional` // 只看 kind ⇒ 写点装箱判定成立);`ident`(声明面可选)⇒ 其声明类型;`call`(返回可选) // ⇒ `T?` 占位;其余 ⇒ -1(不可选面)。 -fn elem_ti_of_node(node: int) -> int { - if node < 0 { return -1; } - k := ast_kind(node); - if k == EXPR_ENUM_CONSTRUCTOR { - nm := istr_get(ast_a(node)); - if str_eq(nm, "Some") != 0 || str_eq(nm, "None") != 0 { - return alloc_type(TYP_OPTIONAL, TI_UNIT, 0); - } - return -1; - } - if k == EXPR_IDENT { - lv := find_local(ast_int_val(node)); - if lv >= 0 { - dti := slot_decl_ti(lv); - if ti_is_optional(dti) != 0 { return dti; } - } - return -1; - } - if k == EXPR_CALL { - ni := ast_a(node); - if find_func(ni) >= 0 && callee_ret_optional(ni) != 0 { - return alloc_type(TYP_OPTIONAL, TI_UNIT, 0); - } - return -1; - } - return -1; -} +fn elem_ti_of_node(node: int) -> int: + if node < 0: + return -1 + k := ast_kind(node) + if k == EXPR_ENUM_CONSTRUCTOR: + nm := istr_get(ast_a(node)) + if str_eq(nm, "Some") != 0 || str_eq(nm, "None") != 0: + return alloc_type(TYP_OPTIONAL, TI_UNIT, 0) + return -1 + if k == EXPR_IDENT: + lv := find_local(ast_int_val(node)) + if lv >= 0: + dti := slot_decl_ti(lv) + if ti_is_optional(dti) != 0: + return dti + return -1 + if k == EXPR_CALL: + ni := ast_a(node) + if find_func(ni) >= 0 && callee_ret_optional(ni) != 0: + return alloc_type(TYP_OPTIONAL, TI_UNIT, 0) + return -1 + return -1 // 装箱体(静态):obj = Some(v)(无新 opcode;形态照既有 EXPR_ENUM_CONSTRUCTOR 发射: // IR_MAKE_ENUM 的 s1 = 变体名索引、载荷经 IR_STORE_FIELD 存 fi+1;tag 值 = 名索引) -fn emit_box_some(val_var: int) -> int { - obj := new_ir_var("box", TI_INT); - emit(IR_MAKE_ENUM, obj, str_intern("Some"), 1, 0, 0); - emit(IR_STORE_FIELD, -1, obj, val_var, 1, 0); - return obj; -} +fn emit_box_some(val_var: int) -> int: + obj := new_ir_var("box", TI_INT) + emit(IR_MAKE_ENUM, obj, str_intern("Some"), 1, 0, 0) + emit(IR_STORE_FIELD, -1, obj, val_var, 1, 0) + return obj // 写点规范化(按**可选性标志**):不可选 ⇒ 原样(零 IR);已装箱 ⇒ 原样; // 静态裸值 ⇒ 直接装箱;源槽带表示位 ⇒ **运行期条件装箱**(裸则装、装箱则原样)。 -fn box_for_slot_flag(val_node: int, val_var: int, is_opt: int) -> int { - if val_var < 0 { return val_var; } - if is_opt == 0 { return val_var; } - enc := rep_enc_of_expr(val_node, val_var); - if enc == oe_boxed() { return val_var; } - if enc == oe_bare() { return emit_box_some(val_var); } - dest := new_ir_var("boxed", TI_INT); - bare_lbl := new_label(); - keep_lbl := new_label(); - end_lbl := new_label(); - zb := new_ir_var("_bz", TI_INT); - emit(IR_CONST, zb, 0, 0, 0, TI_INT); - isb := new_ir_var("box_isbare", TI_INT); - emit(IR_BINARY, isb, enc, zb, OP_EQ, 0); - emit(IR_BRANCH, -1, isb, bare_lbl, keep_lbl, 0); - emit(IR_LABEL, -1, bare_lbl, 0, 0, 0); - boxv := emit_box_some(val_var); - emit(IR_STORE, -1, dest, boxv, 0, 0); - emit(IR_JUMP, -1, end_lbl, 0, 0, 0); - emit(IR_LABEL, -1, keep_lbl, 0, 0, 0); - emit(IR_STORE, -1, dest, val_var, 0, 0); - emit(IR_LABEL, -1, end_lbl, 0, 0, 0); - return dest; -} +fn box_for_slot_flag(val_node: int, val_var: int, is_opt: int) -> int: + if val_var < 0: + return val_var + if is_opt == 0: + return val_var + enc := rep_enc_of_expr(val_node, val_var) + if enc == oe_boxed(): + return val_var + if enc == oe_bare(): + return emit_box_some(val_var) + dest := new_ir_var("boxed", TI_INT) + bare_lbl := new_label() + keep_lbl := new_label() + end_lbl := new_label() + zb := new_ir_var("_bz", TI_INT) + emit(IR_CONST, zb, 0, 0, 0, TI_INT) + isb := new_ir_var("box_isbare", TI_INT) + emit(IR_BINARY, isb, enc, zb, OP_EQ, 0) + emit(IR_BRANCH, -1, isb, bare_lbl, keep_lbl, 0) + emit(IR_LABEL, -1, bare_lbl, 0, 0, 0) + boxv := emit_box_some(val_var) + emit(IR_STORE, -1, dest, boxv, 0, 0) + emit(IR_JUMP, -1, end_lbl, 0, 0, 0) + emit(IR_LABEL, -1, keep_lbl, 0, 0, 0) + emit(IR_STORE, -1, dest, val_var, 0, 0) + emit(IR_LABEL, -1, end_lbl, 0, 0, 0) + return dest // 写点规范化(按**目标槽类型**) -fn box_for_optional_slot(val_node: int, val_var: int, slot_ti: int) -> int { - return box_for_slot_flag(val_node, val_var, ti_is_optional(slot_ti)); -} +fn box_for_optional_slot(val_node: int, val_var: int, slot_ti: int) -> int: + return box_for_slot_flag(val_node, val_var, ti_is_optional(slot_ti)) // 值表达式的**静态表示判定**(解包侧判表示的另一半:写点置位的入参)。 // 返回:>= 0 = 从该表位槽拷贝(源值自身已配表示位:可选局部/形参/调用结果); // OE_BARE = 静态裸值(T 值注入 `T?`:字面量/算术/解包结果/非可选槽/聚合字面量…); // OE_BOXED = 静态装箱(`Some`/`None`)**或**未覆盖面回落(字段/下标/match 结果/ // 惰性 thunk/未识别形态)——回落取装箱 = P3 前既有语义,绝不新造静默错值。 -fn rep_enc_of_expr(node: int, val_var: int) -> int { - if val_var >= 0 { - rv := irv_rep(val_var); - if rv >= 0 { return rv; } - } - if node < 0 { return oe_boxed(); } - k := ast_kind(node); - if k == EXPR_ENUM_CONSTRUCTOR { - nm := istr_get(ast_a(node)); - if str_eq(nm, "Some") != 0 || str_eq(nm, "None") != 0 { return oe_boxed(); } - return oe_bare(); // 用户枚举变体 = T 值(对象指针即载荷) - } - if k == EXPR_INT || k == EXPR_BOOL || k == EXPR_DEX || k == EXPR_STRING { return oe_bare(); } - if k == EXPR_CHAR { return oe_bare(); } - if k == EXPR_BINARY || k == EXPR_UNARY || k == EXPR_AS { return oe_bare(); } - if k == EXPR_TRY { return oe_bare(); } // `?` 解包结果 = T 值 - if k == EXPR_STRUCT || k == EXPR_ARRAY || k == EXPR_TUPLE { return oe_bare(); } - if k == EXPR_IDENT { - ni := ast_int_val(node); - if find_local(ni) >= 0 { return oe_bare(); } // 无表示位(上方已排除可选槽)= 非可选槽 - gv := find_global(ni); - if gv >= 0 { - if global_decl_optional(ni) != 0 { return oe_boxed(); } - return oe_bare(); - } - return oe_bare(); // 枚举裸变体等 T 值 - } - return oe_boxed(); -} +fn rep_enc_of_expr(node: int, val_var: int) -> int: + if val_var >= 0: + rv := irv_rep(val_var) + if rv >= 0: + return rv + if node < 0: + return oe_boxed() + k := ast_kind(node) + if k == EXPR_ENUM_CONSTRUCTOR: + nm := istr_get(ast_a(node)) + if str_eq(nm, "Some") != 0 || str_eq(nm, "None") != 0: + return oe_boxed() + return oe_bare() // 用户枚举变体 = T 值(对象指针即载荷) + if k == EXPR_INT || k == EXPR_BOOL || k == EXPR_DEX || k == EXPR_STRING: + return oe_bare() + if k == EXPR_CHAR: + return oe_bare() + if k == EXPR_BINARY || k == EXPR_UNARY || k == EXPR_AS: + return oe_bare() + if k == EXPR_TRY: + return oe_bare() + // `?` 解包结果 = T 值 + if k == EXPR_STRUCT || k == EXPR_ARRAY || k == EXPR_TUPLE: + return oe_bare() + if k == EXPR_IDENT: + ni := ast_int_val(node) + if find_local(ni) >= 0: + return oe_bare() + // 无表示位(上方已排除可选槽)= 非可选槽 + gv := find_global(ni) + if gv >= 0: + if global_decl_optional(ni) != 0: + return oe_boxed() + return oe_bare() + return oe_bare() // 枚举裸变体等 T 值 + return oe_boxed() // 批 8(静默面收口 · 条目 2):操作数是否**确定可选**——保守触发面,**纯节点/表读、零 alloc_type** // (先例 `rep_enc_of_expr` / `elem_ti_of_node`): // ① var 带表示位(可选槽/形参/调用结果);② `Some`/`None` 构造子;③ 可选声明面(局部槽型 / 全局)。 // 非可选一律 0 ⇒ 比较走原路径(产物零变化 = 条目 2 判据 ⑤)。 -fn opt_cmp_optish(node: int, var: int) -> int { - if var >= 0 && irv_rep(var) >= 0 { return 1; } - if node < 0 { return 0; } - k := ast_kind(node); - if k == EXPR_ENUM_CONSTRUCTOR { - nm := istr_get(ast_a(node)); - if str_eq(nm, "Some") != 0 || str_eq(nm, "None") != 0 { return 1; } - return 0; - } - if k == EXPR_IDENT { - ni := ast_int_val(node); - lv := find_local(ni); - if lv >= 0 { - if ti_is_optional(slot_decl_ti(lv)) != 0 { return 1; } - return 0; - } - gv := find_global(ni); - if gv >= 0 && global_decl_optional(ni) != 0 { return 1; } - return 0; - } +fn opt_cmp_optish(node: int, var: int) -> int: + if var >= 0 && irv_rep(var) >= 0: + return 1 + if node < 0: + return 0 + k := ast_kind(node) + if k == EXPR_ENUM_CONSTRUCTOR: + nm := istr_get(ast_a(node)) + if str_eq(nm, "Some") != 0 || str_eq(nm, "None") != 0: + return 1 + return 0 + if k == EXPR_IDENT: + ni := ast_int_val(node) + lv := find_local(ni) + if lv >= 0: + if ti_is_optional(slot_decl_ti(lv)) != 0: + return 1 + return 0 + gv := find_global(ni) + if gv >= 0 && global_decl_optional(ni) != 0: + return 1 + return 0 // 解引用可选指针:解引用结果**不配表示位**(`ir_gen.cr` UOP_DEREF 只发 IR_DEREF), // 但 **INV-1** 保证「取址的可选槽恒装箱」⇒ 所指即装箱对象(`match *p` 走同一假定)。 - if k == EXPR_UNARY && ast_c(node) == UOP_DEREF { - if var >= 0 && ti_is_optional(irv_type(var)) != 0 { return 1; } - return 0; - } - return 0; -} + if k == EXPR_UNARY && ast_c(node) == UOP_DEREF: + if var >= 0 && ti_is_optional(irv_type(var)) != 0: + return 1 + return 0 + return 0 // 批 8(条目 2):比较点的**有效表示** = `rep_enc_of_expr` + 一条解引用规则—— // 解引用「可选指针」的槽 ⇒ 装箱对象(INV-1;`rep_enc_of_expr` 对 EXPR_UNARY 按 OE_BARE // 回落会把装箱对象当裸值 ⇒ 必须在此覆盖)。 -fn opt_cmp_enc(node: int, var: int) -> int { - if node >= 0 && ast_kind(node) == EXPR_UNARY && ast_c(node) == UOP_DEREF { - if var >= 0 && ti_is_optional(irv_type(var)) != 0 { return oe_boxed(); } - } - return rep_enc_of_expr(node, var); -} +fn opt_cmp_enc(node: int, var: int) -> int: + if node >= 0 && ast_kind(node) == EXPR_UNARY && ast_c(node) == UOP_DEREF: + if var >= 0 && ti_is_optional(irv_type(var)) != 0: + return oe_boxed() + return rep_enc_of_expr(node, var) // 批 8(条目 2):装箱对象的 (absent, payload) 提取——tag == "None" ⇒ (1, 0); // 否则 (0, 字段1)。**字段读只在非 None 分支发射**(None 对象无载荷字段 ⇒ 避免越界读)。 -fn opt_cmp_extract_boxed(var: int, out_absent: int, out_val: int, zero: int) { - tag := new_ir_var("otag", TI_INT); - emit(IR_LOAD_ENUM_TAG, tag, var, 0, 0, 0); - nv := new_ir_var("onone", TI_INT); - emit(IR_CONST, nv, str_intern("None"), 0, 0, TI_INT); - isnone := new_ir_var("isnone", TI_INT); - emit(IR_BINARY, isnone, tag, nv, OP_EQ, 0); - none_lbl := new_label(); - some_lbl := new_label(); - xend_lbl := new_label(); - emit(IR_BRANCH, -1, isnone, none_lbl, some_lbl, 0); - emit(IR_LABEL, -1, none_lbl, 0, 0, 0); - one := new_ir_var("_o1", TI_INT); - emit(IR_CONST, one, 1, 0, 0, TI_INT); - emit(IR_STORE, -1, out_absent, one, 0, 0); - emit(IR_STORE, -1, out_val, zero, 0, 0); - emit(IR_JUMP, -1, xend_lbl, 0, 0, 0); - emit(IR_LABEL, -1, some_lbl, 0, 0, 0); - emit(IR_STORE, -1, out_absent, zero, 0, 0); - pti : ., mut = TI_INT; - if var >= 0 { pti = irv_type(var); } - fv := new_ir_var("opay", pti); - emit(IR_LOAD_FIELD, fv, var, 0, 1, 0); - emit(IR_STORE, -1, out_val, fv, 0, 0); - emit(IR_LABEL, -1, xend_lbl, 0, 0, 0); -} +fn opt_cmp_extract_boxed(var: int, out_absent: int, out_val: int, zero: int): + tag := new_ir_var("otag", TI_INT) + emit(IR_LOAD_ENUM_TAG, tag, var, 0, 0, 0) + nv := new_ir_var("onone", TI_INT) + emit(IR_CONST, nv, str_intern("None"), 0, 0, TI_INT) + isnone := new_ir_var("isnone", TI_INT) + emit(IR_BINARY, isnone, tag, nv, OP_EQ, 0) + none_lbl := new_label() + some_lbl := new_label() + xend_lbl := new_label() + emit(IR_BRANCH, -1, isnone, none_lbl, some_lbl, 0) + emit(IR_LABEL, -1, none_lbl, 0, 0, 0) + one := new_ir_var("_o1", TI_INT) + emit(IR_CONST, one, 1, 0, 0, TI_INT) + emit(IR_STORE, -1, out_absent, one, 0, 0) + emit(IR_STORE, -1, out_val, zero, 0, 0) + emit(IR_JUMP, -1, xend_lbl, 0, 0, 0) + emit(IR_LABEL, -1, some_lbl, 0, 0, 0) + emit(IR_STORE, -1, out_absent, zero, 0, 0) + pti : ., mut = TI_INT + if var >= 0: + pti = irv_type(var) + fv := new_ir_var("opay", pti) + emit(IR_LOAD_FIELD, fv, var, 0, 1, 0) + emit(IR_STORE, -1, out_val, fv, 0, 0) + emit(IR_LABEL, -1, xend_lbl, 0, 0, 0) // 批 8(条目 2):归一为 (absent, payload) 二元组(写进调用点预建的 out 槽)—— // 裸(OE_BARE) ⇒ (0, 槽值);装箱(OE_BOXED)⇒ 见 `opt_cmp_extract_boxed`; // 运行期表示位(≥0)⇒ 分支判裸/装箱(裸 ⇒ (0, 槽值))。 -fn opt_cmp_norm(node: int, var: int, out_absent: int, out_val: int) { - enc := opt_cmp_enc(node, var); - zero := new_ir_var("_oz", TI_INT); - emit(IR_CONST, zero, 0, 0, 0, TI_INT); - if enc == oe_bare() { - emit(IR_STORE, -1, out_absent, zero, 0, 0); - if var >= 0 { emit(IR_STORE, -1, out_val, var, 0, 0); } - return; - } - if enc >= 0 { - bare_lbl := new_label(); - boxed_lbl := new_label(); - nend_lbl := new_label(); - isb := new_ir_var("rep_isbare", TI_INT); - emit(IR_BINARY, isb, enc, zero, OP_EQ, 0); - emit(IR_BRANCH, -1, isb, bare_lbl, boxed_lbl, 0); - emit(IR_LABEL, -1, bare_lbl, 0, 0, 0); - emit(IR_STORE, -1, out_absent, zero, 0, 0); - if var >= 0 { emit(IR_STORE, -1, out_val, var, 0, 0); } - emit(IR_JUMP, -1, nend_lbl, 0, 0, 0); - emit(IR_LABEL, -1, boxed_lbl, 0, 0, 0); - opt_cmp_extract_boxed(var, out_absent, out_val, zero); - emit(IR_LABEL, -1, nend_lbl, 0, 0, 0); - return; - } - opt_cmp_extract_boxed(var, out_absent, out_val, zero); -} - -fn emit(opcode: int, dest: int, src1: int, src2: int, src3: int, type_kind: int) { +fn opt_cmp_norm(node: int, var: int, out_absent: int, out_val: int): + enc := opt_cmp_enc(node, var) + zero := new_ir_var("_oz", TI_INT) + emit(IR_CONST, zero, 0, 0, 0, TI_INT) + if enc == oe_bare(): + emit(IR_STORE, -1, out_absent, zero, 0, 0) + if var >= 0: + emit(IR_STORE, -1, out_val, var, 0, 0) + return + if enc >= 0: + bare_lbl := new_label() + boxed_lbl := new_label() + nend_lbl := new_label() + isb := new_ir_var("rep_isbare", TI_INT) + emit(IR_BINARY, isb, enc, zero, OP_EQ, 0) + emit(IR_BRANCH, -1, isb, bare_lbl, boxed_lbl, 0) + emit(IR_LABEL, -1, bare_lbl, 0, 0, 0) + emit(IR_STORE, -1, out_absent, zero, 0, 0) + if var >= 0: + emit(IR_STORE, -1, out_val, var, 0, 0) + emit(IR_JUMP, -1, nend_lbl, 0, 0, 0) + emit(IR_LABEL, -1, boxed_lbl, 0, 0, 0) + opt_cmp_extract_boxed(var, out_absent, out_val, zero) + emit(IR_LABEL, -1, nend_lbl, 0, 0, 0) + return + opt_cmp_extract_boxed(var, out_absent, out_val, zero) + +fn emit(opcode: int, dest: int, src1: int, src2: int, src3: int, type_kind: int): // Build linear IR (.ccr) — consumed by x86-64 backend - idx := g_ir_instr_count; - grow_ir_instrs(idx + 1); - iri_set_op(idx, opcode); - iri_set_dest(idx, dest); - iri_set_s1(idx, src1); - iri_set_s2(idx, src2); - iri_set_s3(idx, src3); + idx := g_ir_instr_count + grow_ir_instrs(idx + 1) + iri_set_op(idx, opcode) + iri_set_dest(idx, dest) + iri_set_s1(idx, src1) + iri_set_s2(idx, src2) + iri_set_s3(idx, src3) // R2 P5 Task 2(D19 单槽化):类型面**单源** = DFNode 的(项, 辅码)两槽。 // 本处是**唯一**拆分点:同一次 sh_tk_split 同时喂 DFNode 两槽与 iri_tk 的派生码 // (sh_dfn_code_of_slots)——既无第二真源,也不可能两处漂移。 - sh_tk_split(opcode, type_kind); - iri_set_tk(idx, sh_dfn_code_of_slots(g_sh_slot_term, g_sh_slot_aux)); - g_ir_instr_count = idx + 1; + sh_tk_split(opcode, type_kind) + iri_set_tk(idx, sh_dfn_code_of_slots(g_sh_slot_term, g_sh_slot_aux)) + g_ir_instr_count = idx + 1 // Build dataflow graph (.cir) in parallel // 拆分时点 = **emit 期**(不得后移到 save 前:快照在 IR 生成期逐函数写 ⇒ 后填 // 必然冷/暖分歧)。代价 = 每 emit 一次分类查询(非类型面 op = 几次整数比较即 // 返回;类型面 op = sh_term_of_ti 的原生快路径/桥接缓存,实测耗时见报告 §6)。 - df_create_node(opcode, dest, src1, src2, src3, g_sh_slot_term, g_sh_slot_aux); -} - -fn new_label() -> int { - lbl := g_next_label; - g_next_label = g_next_label + 1; - return lbl; -} - -fn bind_local(name_idx: int, var_idx: int) { - grow_ir_locals(g_ir_local_count + 1); - w64(g_ir_locals, g_ir_local_count * 16, name_idx); - w64(g_ir_locals, g_ir_local_count * 16 + 8, var_idx); - g_ir_local_count = g_ir_local_count + 1; -} - -fn find_local(name_idx: int) -> int { - i : ., mut = g_ir_local_count - 1; - loop { - if i < 0 { return -1; } - if r64(g_ir_locals, i * 16) == name_idx { return r64(g_ir_locals, i * 16 + 8); } - i = i - 1; - } - return -1; -} - -fn find_global(name_idx: int) -> int { - i : ., mut = g_ir_global_count - 1; - loop { - if i < 0 { return -1; } - if r64(g_ir_globals, i * 24) == name_idx { return r64(g_ir_globals, i * 24 + 8); } - i = i - 1; - } - return -1; -} + df_create_node(opcode, dest, src1, src2, src3, g_sh_slot_term, g_sh_slot_aux) + +fn new_label() -> int: + lbl := g_next_label + g_next_label = g_next_label + 1 + return lbl + +fn bind_local(name_idx: int, var_idx: int): + grow_ir_locals(g_ir_local_count + 1) + w64(g_ir_locals, g_ir_local_count * 16, name_idx) + w64(g_ir_locals, g_ir_local_count * 16 + 8, var_idx) + g_ir_local_count = g_ir_local_count + 1 + +fn find_local(name_idx: int) -> int: + i : ., mut = g_ir_local_count - 1 + loop: + if i < 0: + return -1 + if r64(g_ir_locals, i * 16) == name_idx: + return r64(g_ir_locals, i * 16 + 8) + i = i - 1 + return -1 + +fn find_global(name_idx: int) -> int: + i : ., mut = g_ir_global_count - 1 + loop: + if i < 0: + return -1 + if r64(g_ir_globals, i * 24) == name_idx: + return r64(g_ir_globals, i * 24 + 8) + i = i - 1 + return -1 // Return the literal initializer AST node for an immutable module-level // constant. The ELF backend has no data initializers, so leaving these as // BSS globals turns values such as T_FN and ESZ_TOKEN into zero at runtime. -fn find_global_const_node(name_idx: int) -> int { - i : ., mut = g_global_let_count - 1; - loop { - if i < 0 { break; } - node := r64(g_global_lets, i * 8); - if ast_a(node) == name_idx && ast_data(node) == 0 { - value_node := ast_c(node); - if value_node >= 0 { - value_kind := ast_kind(value_node); - if value_kind == EXPR_INT || value_kind == EXPR_BOOL || - value_kind == EXPR_DEX { - return value_node; - } - } - } - i = i - 1; - } - - return -1; -} - -fn push_ir_scope() { - grow_ir_local_scopes(g_ir_local_depth + 1); - w64(g_ir_local_scopes, g_ir_local_depth * 8, g_ir_local_count); - g_ir_local_depth = g_ir_local_depth + 1; -} - -fn pop_ir_scope() { - g_ir_local_depth = g_ir_local_depth - 1; - g_ir_local_count = r64(g_ir_local_scopes, g_ir_local_depth * 8); -} - -fn is_ptr_var(var_idx: int) -> int { - if var_idx < 0 { return 0; } - ti := irv_type(var_idx); - if ti == TI_DEX_S { return 0; } // 哨兵类型:不查类型表(终审 M1:8 为占位表项,用户类型从 9 起) - if ti >= 0 { - tk := get_type_kind(ti); - if tk == TYP_PTR || tk == TYP_REF { return 1; } - } - prod := r64(g_df_var_producer, var_idx * 8); - if prod < 0 { return 0; } - prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE); - if prod_op == IR_ALLOC { - ti := irv_type(var_idx); - if ti == TI_INT || ti == TI_DEX || ti == TI_BOOL || ti == TI_CHAR { - return 0; - } - return 1; - } - if prod_op == IR_ADDR_INDEX || prod_op == IR_REF || - prod_op == IR_ALLOC_STRUCT || prod_op == IR_ALLOC_ARRAY { - return 1; - } - return 0; -} - -fn is_byte_buf_var(var_idx: int) -> int { +fn find_global_const_node(name_idx: int) -> int: + i : ., mut = g_global_let_count - 1 + loop: + if i < 0: + break + node := r64(g_global_lets, i * 8) + if ast_a(node) == name_idx && ast_data(node) == 0: + value_node := ast_c(node) + if value_node >= 0: + value_kind := ast_kind(value_node) + if value_kind == EXPR_INT || value_kind == EXPR_BOOL || value_kind == EXPR_DEX: + return value_node + i = i - 1 + + return -1 + +fn push_ir_scope(): + grow_ir_local_scopes(g_ir_local_depth + 1) + w64(g_ir_local_scopes, g_ir_local_depth * 8, g_ir_local_count) + g_ir_local_depth = g_ir_local_depth + 1 + +fn pop_ir_scope(): + g_ir_local_depth = g_ir_local_depth - 1 + g_ir_local_count = r64(g_ir_local_scopes, g_ir_local_depth * 8) + +fn is_ptr_var(var_idx: int) -> int: + if var_idx < 0: + return 0 + ti := irv_type(var_idx) + if ti == TI_DEX_S: + return 0 + // 哨兵类型:不查类型表(终审 M1:8 为占位表项,用户类型从 9 起) + if ti >= 0: + tk := get_type_kind(ti) + if tk == TYP_PTR || tk == TYP_REF: + return 1 + prod := r64(g_df_var_producer, var_idx * 8) + if prod < 0: + return 0 + prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE) + if prod_op == IR_ALLOC: + ti := irv_type(var_idx) + if ti == TI_INT || ti == TI_DEX || ti == TI_BOOL || ti == TI_CHAR: + return 0 + return 1 + if prod_op == IR_ADDR_INDEX || prod_op == IR_REF || prod_op == IR_ALLOC_STRUCT || prod_op == IR_ALLOC_ARRAY: + return 1 + return 0 + +fn is_byte_buf_var(var_idx: int) -> int: // Raw byte buffers produced by alloc() (TI_UNIT internal sentinel, // Core `string`) are byte-addressed: `buf + n` must NOT scale n by // the 8-byte element size. - if var_idx < 0 { return 0; } - if irv_type(var_idx) != TI_UNIT { return 0; } - prod := r64(g_df_var_producer, var_idx * 8); - if prod < 0 { return 0; } - prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE); - if prod_op == IR_ALLOC { return 1; } - if prod_op == IR_CALL { - func_ni := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S3); - if func_ni >= 0 && istr_get(func_ni) == "alloc" { return 1; } - } - return 0; -} - -fn ir_call_return_type(func_ni: int) -> int { - if func_ni < 0 { return TI_UNIT; } + if var_idx < 0: + return 0 + if irv_type(var_idx) != TI_UNIT: + return 0 + prod := r64(g_df_var_producer, var_idx * 8) + if prod < 0: + return 0 + prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE) + if prod_op == IR_ALLOC: + return 1 + if prod_op == IR_CALL: + func_ni := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_S3) + if func_ni >= 0 && istr_get(func_ni) == "alloc": + return 1 + return 0 + +fn ir_call_return_type(func_ni: int) -> int: + if func_ni < 0: + return TI_UNIT // alloc() produces a raw byte buffer. Keep the existing internal pointer // sentinel until Core has a distinct raw-buffer type. - if istr_get(func_ni) == "alloc" { return TI_UNIT; } - bi : ., mut = 0; - loop { - if bi >= g_rt_builtin_count { break; } - if r64(g_rt_builtin_names, bi * 8) == func_ni { - return r64(g_rt_builtin_ret_types, bi * 8); - } - bi = bi + 1; - } - fi := find_func(func_ni); - if fi >= 0 { - rt := fi_return_type(fi); - if rt == TY_INT { return TI_INT; } - if rt == TY_DEX { + if istr_get(func_ni) == "alloc": + return TI_UNIT + bi : ., mut = 0 + loop: + if bi >= g_rt_builtin_count: + break + if r64(g_rt_builtin_names, bi * 8) == func_ni: + return r64(g_rt_builtin_ret_types, bi * 8) + bi = bi + 1 + fi := find_func(func_ni) + if fi >= 0: + rt := fi_return_type(fi) + if rt == TY_INT: + return TI_INT + if rt == TY_DEX: // dex 边界规则(数值迁移 Task 4):Core 函数返回精确形式(缩放整数); // extern 函数保留 TI_DEX(binary64 位模式——C ABI / apx 授权 FFI) - if fi_ast_node(fi) >= 0 && ast_kind(fi_ast_node(fi)) == EXPR_EXTERN { - return TI_DEX; - } - return TI_DEX_S; - } - if rt == TY_BOOL { return TI_BOOL; } - if rt == TY_STRING { return TI_STR; } - if rt == TY_UNIT { return TI_UNIT; } - if rt == TY_CHAR { return TI_CHAR; } - } - si := find_gsym(func_ni); - if si < 0 { return TI_UNIT; } - if sym_kind(si) == SYM_FN { return sym_type(si); } - if sym_kind(si) == SYM_SO_FN { - type_enc := sym_node(si); - ret_code := type_enc - (type_enc / 100) * 100; - if ret_code == 0 { return TI_INT; } - if ret_code == 1 { return TI_STR; } - if ret_code == 2 { return TI_UNIT; } - if ret_code == 3 { return TI_DEX; } - if ret_code == 4 { return TI_BOOL; } - } - return TI_UNIT; -} + if fi_ast_node(fi) >= 0 && ast_kind(fi_ast_node(fi)) == EXPR_EXTERN: + return TI_DEX + return TI_DEX_S + if rt == TY_BOOL: + return TI_BOOL + if rt == TY_STRING: + return TI_STR + if rt == TY_UNIT: + return TI_UNIT + if rt == TY_CHAR: + return TI_CHAR + si := find_gsym(func_ni) + if si < 0: + return TI_UNIT + if sym_kind(si) == SYM_FN: + return sym_type(si) + if sym_kind(si) == SYM_SO_FN: + type_enc := sym_node(si) + ret_code := type_enc - (type_enc / 100) * 100 + if ret_code == 0: + return TI_INT + if ret_code == 1: + return TI_STR + if ret_code == 2: + return TI_UNIT + if ret_code == 3: + return TI_DEX + if ret_code == 4: + return TI_BOOL + return TI_UNIT // --- Track string constants --- -fn track_str(str_idx: int) { - i : ., mut = 0; - loop { - if i >= g_ir_str_const_count { break; } - if r64(g_ir_str_consts, i * 8) == str_idx { return; } - i = i + 1; - } - grow_ir_str_consts(g_ir_str_const_count + 1); - w64(g_ir_str_consts, g_ir_str_const_count * 8, str_idx); - g_ir_str_const_count = g_ir_str_const_count + 1; -} +fn track_str(str_idx: int): + i : ., mut = 0 + loop: + if i >= g_ir_str_const_count: + break + if r64(g_ir_str_consts, i * 8) == str_idx: + return + i = i + 1 + grow_ir_str_consts(g_ir_str_const_count + 1) + w64(g_ir_str_consts, g_ir_str_const_count * 8, str_idx) + g_ir_str_const_count = g_ir_str_const_count + 1 // --- Loop label stack --- -fn push_loop_labels(header: int, exit: int) { - grow_ir_loop_stacks(g_ir_loop_depth + 1); - w64(g_ir_loop_header, g_ir_loop_depth * 8, header); - w64(g_ir_loop_exit, g_ir_loop_depth * 8, exit); - g_ir_loop_depth = g_ir_loop_depth + 1; -} +fn push_loop_labels(header: int, exit: int): + grow_ir_loop_stacks(g_ir_loop_depth + 1) + w64(g_ir_loop_header, g_ir_loop_depth * 8, header) + w64(g_ir_loop_exit, g_ir_loop_depth * 8, exit) + g_ir_loop_depth = g_ir_loop_depth + 1 -fn pop_loop_labels() { - g_ir_loop_depth = g_ir_loop_depth - 1; -} +fn pop_loop_labels(): + g_ir_loop_depth = g_ir_loop_depth - 1 // 枚举变体名查找(F15):name_idx 是否为任一枚举的变体名(裸引用 `c := Red`)。 // 匹配返回 name_idx 本身;非变体名返回 -1。checker 的 collect_decls 把每个 // 变体名注册为 SYM_FN(指向枚举类型)——裸变体经类型检查后到达 ir_gen。 -fn find_enum_variant(name_idx: int) -> int { - ei : ., mut = 0; - loop { - if ei >= g_enum_count { break; } - vi : ., mut = 0; - loop { - if vi >= ei_variant_count(ei) { break; } - if ei_variant_name(ei, vi) == name_idx { return name_idx; } - vi = vi + 1; - } - ei = ei + 1; - } - return -1; -} - -fn get_variant_name_idx(qualified_ni: int) -> int { - s := istr_get(qualified_ni); - slen := str_len(s); - dot_pos : ., mut = -1; - i : ., mut = 0; - loop { - if i >= slen { break; } - c := get_char(s, i); - if str_eq(c, ".") != 0 { dot_pos = i; } - i = i + 1; - } - if dot_pos >= 0 { - variant_name := str_sub(s, dot_pos + 1, slen - dot_pos - 1); - return str_intern(variant_name); - } - return qualified_ni; -} +fn find_enum_variant(name_idx: int) -> int: + ei : ., mut = 0 + loop: + if ei >= g_enum_count: + break + vi : ., mut = 0 + loop: + if vi >= ei_variant_count(ei): + break + if ei_variant_name(ei, vi) == name_idx: + return name_idx + vi = vi + 1 + ei = ei + 1 + return -1 + +fn get_variant_name_idx(qualified_ni: int) -> int: + s := istr_get(qualified_ni) + slen := str_len(s) + dot_pos : ., mut = -1 + i : ., mut = 0 + loop: + if i >= slen: + break + c := get_char(s, i) + if str_eq(c, ".") != 0: + dot_pos = i + i = i + 1 + if dot_pos >= 0: + variant_name := str_sub(s, dot_pos + 1, slen - dot_pos - 1) + return str_intern(variant_name) + return qualified_ni // --- Type metadata helpers for @ builtins --- // Resolve a type expression node to a TI_* type index. // Handles type nodes (ast_kind==0 from parse_type) and EXPR_IDENT // (basic type names not in the symbol table). -fn ti_from_type_expr(node: int) -> int { - if node < 0 { return TI_UNIT; } +fn ti_from_type_expr(node: int) -> int: + if node < 0: + return TI_UNIT // Type node from parse_type: ast_kind == 0, type_val = TY_* - if ast_kind(node) == 0 { - tv := ast_type_val(node); - if tv == TY_INT { return TI_INT; } - if tv == TY_DEX { return TI_DEX; } - if tv == TY_BOOL { return TI_BOOL; } - if tv == TY_STRING { return TI_STR; } - if tv == TY_CHAR { return TI_CHAR; } - if tv == TY_UNIT { return TI_UNIT; } - return TI_UNIT; - } + if ast_kind(node) == 0: + tv := ast_type_val(node) + if tv == TY_INT: + return TI_INT + if tv == TY_DEX: + return TI_DEX + if tv == TY_BOOL: + return TI_BOOL + if tv == TY_STRING: + return TI_STR + if tv == TY_CHAR: + return TI_CHAR + if tv == TY_UNIT: + return TI_UNIT + return TI_UNIT // EXPR_IDENT from parse_expr: int_val = name string index - if ast_kind(node) == EXPR_IDENT { - ni := ast_int_val(node); - name := istr_get(ni); - if str_eq(name, "int") != 0 { return TI_INT; } - if str_eq(name, "dex") != 0 { return TI_DEX; } - if str_eq(name, "bool") != 0 { return TI_BOOL; } - if str_eq(name, "string") != 0 { return TI_STR; } - if str_eq(name, "char") != 0 { return TI_CHAR; } - if str_eq(name, "unit") != 0 { return TI_UNIT; } + if ast_kind(node) == EXPR_IDENT: + ni := ast_int_val(node) + name := istr_get(ni) + if str_eq(name, "int") != 0: + return TI_INT + if str_eq(name, "dex") != 0: + return TI_DEX + if str_eq(name, "bool") != 0: + return TI_BOOL + if str_eq(name, "string") != 0: + return TI_STR + if str_eq(name, "char") != 0: + return TI_CHAR + if str_eq(name, "unit") != 0: + return TI_UNIT // Named types (structs, enums): look up in symbol table - si := find_gsym(ni); - if si >= 0 && sym_kind(si) == SYM_TYPE { return sym_type(si); } - } + si := find_gsym(ni) + if si >= 0 && sym_kind(si) == SYM_TYPE: + return sym_type(si) // Complex type expressions: delegate to checker's resolver - return res_type_node(node); -} + return res_type_node(node) // Type size in bytes -fn type_size(ti: int) -> int { - if ti == TI_DEX_S { return 8; } // 哨兵类型:8 字节槽(不查类型表;终审 M1:8 为占位表项,用户类型从 9 起) - if ti == TI_CHAR { return 4; } // not in type table - if ti < 0 || ti >= g_type_count { return 8; } - k := get_type_kind(ti); - if k == TYP_BASE { - d := get_type_data(ti); - if d == TY_INT { return 8; } - if d == TY_DEX { return 8; } - if d == TY_BOOL { return 1; } - if d == TY_STRING { return 8; } - if d == TY_UNIT { return 0; } - if d == TY_CHAR { return 4; } - return 8; - } - if k == TYP_ARRAY { - elem := get_type_data(ti); - cnt := get_type_extra(ti); - return type_size(elem) * cnt; - } - if k == TYP_PTR || k == TYP_REF { return 8; } - if k == TYP_SLICE { return 16; } - if k == TYP_NAMED { - name_ni := get_type_data(ti); - si : ., mut = 0; - loop { - if si >= g_struct_count { break; } - if si_name(si) == name_ni { return si_field_count(si) * 8; } - si = si + 1; - } - return 8; - } - return 8; -} - -fn ptr_pointee_type(var_idx: int) -> int { - if var_idx < 0 { return TI_INT; } - ti := irv_type(var_idx); - if ti >= 0 { - k := get_type_kind(ti); - if k == TYP_PTR || k == TYP_REF { return get_type_data(ti); } - } - return TI_INT; -} - -fn ptr_access_width(var_idx: int) -> int { - width := type_size(ptr_pointee_type(var_idx)); - if width <= 0 { return 8; } - return width; -} +fn type_size(ti: int) -> int: + if ti == TI_DEX_S: + return 8 + // 哨兵类型:8 字节槽(不查类型表;终审 M1:8 为占位表项,用户类型从 9 起) + if ti == TI_CHAR: + return 4 + // not in type table + if ti < 0 || ti >= g_type_count: + return 8 + k := get_type_kind(ti) + if k == TYP_BASE: + d := get_type_data(ti) + if d == TY_INT: + return 8 + if d == TY_DEX: + return 8 + if d == TY_BOOL: + return 1 + if d == TY_STRING: + return 8 + if d == TY_UNIT: + return 0 + if d == TY_CHAR: + return 4 + return 8 + if k == TYP_ARRAY: + elem := get_type_data(ti) + cnt := get_type_extra(ti) + return type_size(elem) * cnt + if k == TYP_PTR || k == TYP_REF: + return 8 + if k == TYP_SLICE: + return 16 + if k == TYP_NAMED: + name_ni := get_type_data(ti) + si : ., mut = 0 + loop: + if si >= g_struct_count: + break + if si_name(si) == name_ni: + return si_field_count(si) * 8 + si = si + 1 + return 8 + return 8 + +fn ptr_pointee_type(var_idx: int) -> int: + if var_idx < 0: + return TI_INT + ti := irv_type(var_idx) + if ti >= 0: + k := get_type_kind(ti) + if k == TYP_PTR || k == TYP_REF: + return get_type_data(ti) + return TI_INT + +fn ptr_access_width(var_idx: int) -> int: + width := type_size(ptr_pointee_type(var_idx)) + if width <= 0: + return 8 + return width // Type alignment in bytes -fn type_align(ti: int) -> int { - if ti == TI_DEX_S { return 8; } // 哨兵类型:8 字节对齐(不查类型表;终审 M1:8 为占位表项) - if ti == TI_CHAR { return 4; } - if ti < 0 || ti >= g_type_count { return 8; } - k := get_type_kind(ti); - if k == TYP_BASE { - d := get_type_data(ti); - if d == TY_INT { return 8; } - if d == TY_DEX { return 8; } - if d == TY_BOOL { return 1; } - if d == TY_STRING { return 8; } - if d == TY_CHAR { return 4; } - return 8; - } - if k == TYP_ARRAY { return type_align(get_type_data(ti)); } - if k == TYP_PTR || k == TYP_REF { return 8; } - if k == TYP_SLICE { return 8; } - if k == TYP_NAMED { return 8; } - return 8; -} +fn type_align(ti: int) -> int: + if ti == TI_DEX_S: + return 8 + // 哨兵类型:8 字节对齐(不查类型表;终审 M1:8 为占位表项) + if ti == TI_CHAR: + return 4 + if ti < 0 || ti >= g_type_count: + return 8 + k := get_type_kind(ti) + if k == TYP_BASE: + d := get_type_data(ti) + if d == TY_INT: + return 8 + if d == TY_DEX: + return 8 + if d == TY_BOOL: + return 1 + if d == TY_STRING: + return 8 + if d == TY_CHAR: + return 4 + return 8 + if k == TYP_ARRAY: + return type_align(get_type_data(ti)) + if k == TYP_PTR || k == TYP_REF: + return 8 + if k == TYP_SLICE: + return 8 + if k == TYP_NAMED: + return 8 + return 8 // Resolve a type index to a struct info index. // Returns -1 if the type is not a struct type. -fn ti_resolve_struct(ti: int) -> int { - if ti < 0 || ti >= g_type_count { return -1; } - k := get_type_kind(ti); - if k != TYP_NAMED { return -1; } - name_ni := get_type_data(ti); - if name_ni < 0 { return -1; } - name := istr_get(name_ni); - si : ., mut = 0; - loop { - if si >= g_struct_count { break; } - sn_ni := si_name(si); - sn := istr_get(sn_ni); - if str_eq(sn, name) != 0 { return si; } - si = si + 1; - } - return -1; -} +fn ti_resolve_struct(ti: int) -> int: + if ti < 0 || ti >= g_type_count: + return -1 + k := get_type_kind(ti) + if k != TYP_NAMED: + return -1 + name_ni := get_type_data(ti) + if name_ni < 0: + return -1 + name := istr_get(name_ni) + si : ., mut = 0 + loop: + if si >= g_struct_count: + break + sn_ni := si_name(si) + sn := istr_get(sn_ni) + if str_eq(sn, name) != 0: + return si + si = si + 1 + return -1 // Check if a struct type has a field by name -fn ti_has_field(ti: int, name: string) -> int { - si := ti_resolve_struct(ti); - if si < 0 { return 0; } - fc := si_field_count(si); - fi : ., mut = 0; - loop { - if fi >= fc { break; } - fn_ni := si_field_name(si, fi); - fname := istr_get(fn_ni); - if str_eq(fname, name) != 0 { return 1; } - fi = fi + 1; - } - return 0; -} +fn ti_has_field(ti: int, name: string) -> int: + si := ti_resolve_struct(ti) + if si < 0: + return 0 + fc := si_field_count(si) + fi : ., mut = 0 + loop: + if fi >= fc: + break + fn_ni := si_field_name(si, fi) + fname := istr_get(fn_ni) + if str_eq(fname, name) != 0: + return 1 + fi = fi + 1 + return 0 // Get field byte offset (each field is 8 bytes) -fn ti_field_offset(ti: int, name: string) -> int { - si := ti_resolve_struct(ti); - if si < 0 { return -1; } - fc := si_field_count(si); - fi : ., mut = 0; - loop { - if fi >= fc { break; } - fn_ni := si_field_name(si, fi); - fname := istr_get(fn_ni); - if str_eq(fname, name) != 0 { return fi * 8; } - fi = fi + 1; - } - return -1; -} +fn ti_field_offset(ti: int, name: string) -> int: + si := ti_resolve_struct(ti) + if si < 0: + return -1 + fc := si_field_count(si) + fi : ., mut = 0 + loop: + if fi >= fc: + break + fn_ni := si_field_name(si, fi) + fname := istr_get(fn_ni) + if str_eq(fname, name) != 0: + return fi * 8 + fi = fi + 1 + return -1 // Check if a function name refers to a hotpatch function (has @hotpatch versions) -fn is_hotpatch_func(name_idx: int) -> int { - count : ., mut = 0; - i : ., mut = 0; - loop { - if i >= g_func_count { break; } - if fi_name(i) == name_idx { - fn_node := fi_ast_node(i); - if fn_node >= 0 { - hotpatch_ver := ast_int_val(fn_node) / 256; - if hotpatch_ver > 0 { count = count + 1; } - } - } - i = i + 1; - } - if count > 0 { return 1; } - return 0; -} +fn is_hotpatch_func(name_idx: int) -> int: + count : ., mut = 0 + i : ., mut = 0 + loop: + if i >= g_func_count: + break + if fi_name(i) == name_idx: + fn_node := fi_ast_node(i) + if fn_node >= 0: + hotpatch_ver := ast_int_val(fn_node) / 256 + if hotpatch_ver > 0: + count = count + 1 + i = i + 1 + if count > 0: + return 1 + return 0 // Helper: if a variable's producer is IR_LAZY_THUNK, emit IR_LAZY_FORCE // to extract the real value and return the forced variable. -fn force_if_thunk(var_idx: int) -> int { - if var_idx < 0 { return var_idx; } - prod := r64(g_df_var_producer, var_idx * 8); - if prod >= 0 { - prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE); - if prod_op == IR_LAZY_THUNK { - forced := new_ir_var("_forced", irv_type(var_idx)); - emit(IR_LAZY_FORCE, forced, var_idx, 0, 0, 0); - return forced; - } - } - return var_idx; -} +fn force_if_thunk(var_idx: int) -> int: + if var_idx < 0: + return var_idx + prod := r64(g_df_var_producer, var_idx * 8) + if prod >= 0: + prod_op := r64(g_df_nodes, prod * ESZ_DFNODE + OFF_DF_OPCODE) + if prod_op == IR_LAZY_THUNK: + forced := new_ir_var("_forced", irv_type(var_idx)) + emit(IR_LAZY_FORCE, forced, var_idx, 0, 0, 0) + return forced + return var_idx // --- dex 定点精确运算辅助(数值迁移 Task 4)--- // dex 值有两种 IR 形式: @@ -1139,76 +1236,76 @@ fn force_if_thunk(var_idx: int) -> int { // binary64)。实现:F2I 本身向零截断——正数先 +0.5、负数先 −0.5(分支按 m < 0 分流, // 与字面量 str_to_scaled 的半进一致;半进 = 绝对值半上,-0.5 → -1)。此舍入同时吸收 // str_to_f64_bits 字面量转换的 ~2ulp 截断误差(打印/边界 6 位精度下不可见)。 -fn dex_bits_to_scaled(var: int) -> int { - if irv_type(var) != TI_DEX { return var; } - c := new_ir_var("_dxs", TI_DEX); - emit(IR_CONST, c, 4696837146684686336, 0, 0, TI_DEX); // 1e6 的 binary64 位模式 - m := new_ir_var("_dxm", TI_DEX); - emit(IR_BINARY, m, var, c, OP_MUL, TI_DEX); - zero := new_ir_var("_dx0", TI_DEX); - emit(IR_CONST, zero, 0, 0, 0, TI_DEX); - negc := new_ir_var("_dxc", TI_INT); - emit(IR_BINARY, negc, m, zero, OP_LT, TI_DEX); // m < 0 → int 0/1(comisd 路径) - half := new_ir_var("_dxh", TI_DEX); - emit(IR_CONST, half, 4602678819172646912, 0, 0, TI_DEX); // 0.5 的 binary64 位模式(0x3FE0000000000000) - pos_lbl := new_label(); - neg_lbl := new_label(); - merge_lbl := new_label(); - mrg := new_ir_var("_dxmrg", TI_DEX); - emit(IR_BRANCH, -1, negc, neg_lbl, pos_lbl, 0); - emit(IR_LABEL, -1, pos_lbl, 0, 0, 0); - rp := new_ir_var("_dxrp", TI_DEX); - emit(IR_BINARY, rp, m, half, OP_ADD, TI_DEX); // m ≥ 0:+0.5 - emit(IR_STORE, -1, mrg, rp, 0, 0); - emit(IR_JUMP, -1, merge_lbl, 0, 0, 0); - emit(IR_LABEL, -1, neg_lbl, 0, 0, 0); - rn := new_ir_var("_dxrn", TI_DEX); - emit(IR_BINARY, rn, m, half, OP_SUB, TI_DEX); // m < 0:−0.5 - emit(IR_STORE, -1, mrg, rn, 0, 0); - emit(IR_LABEL, -1, merge_lbl, 0, 0, 0); - r := new_ir_var("_dxsc", TI_DEX_S); - emit(IR_F2I, r, mrg, 0, 0, TI_DEX); - return r; -} +fn dex_bits_to_scaled(var: int) -> int: + if irv_type(var) != TI_DEX: + return var + c := new_ir_var("_dxs", TI_DEX) + emit(IR_CONST, c, 4696837146684686336, 0, 0, TI_DEX) // 1e6 的 binary64 位模式 + m := new_ir_var("_dxm", TI_DEX) + emit(IR_BINARY, m, var, c, OP_MUL, TI_DEX) + zero := new_ir_var("_dx0", TI_DEX) + emit(IR_CONST, zero, 0, 0, 0, TI_DEX) + negc := new_ir_var("_dxc", TI_INT) + emit(IR_BINARY, negc, m, zero, OP_LT, TI_DEX) // m < 0 → int 0/1(comisd 路径) + half := new_ir_var("_dxh", TI_DEX) + emit(IR_CONST, half, 4602678819172646912, 0, 0, TI_DEX) // 0.5 的 binary64 位模式(0x3FE0000000000000) + pos_lbl := new_label() + neg_lbl := new_label() + merge_lbl := new_label() + mrg := new_ir_var("_dxmrg", TI_DEX) + emit(IR_BRANCH, -1, negc, neg_lbl, pos_lbl, 0) + emit(IR_LABEL, -1, pos_lbl, 0, 0, 0) + rp := new_ir_var("_dxrp", TI_DEX) + emit(IR_BINARY, rp, m, half, OP_ADD, TI_DEX) // m ≥ 0:+0.5 + emit(IR_STORE, -1, mrg, rp, 0, 0) + emit(IR_JUMP, -1, merge_lbl, 0, 0, 0) + emit(IR_LABEL, -1, neg_lbl, 0, 0, 0) + rn := new_ir_var("_dxrn", TI_DEX) + emit(IR_BINARY, rn, m, half, OP_SUB, TI_DEX) // m < 0:−0.5 + emit(IR_STORE, -1, mrg, rn, 0, 0) + emit(IR_LABEL, -1, merge_lbl, 0, 0, 0) + r := new_ir_var("_dxsc", TI_DEX_S) + emit(IR_F2I, r, mrg, 0, 0, TI_DEX) + return r // 缩放整数(TI_DEX_S)→ bits(TI_DEX):I2F(scaled) / S // 字面量节点(EXPR_DEX)直接重发射为 bits 常量(与 lexer 位模式一致,免转换序列) -fn dex_scaled_to_bits(var: int, node: int) -> int { - if irv_type(var) != TI_DEX_S { return var; } - if node >= 0 && ast_kind(node) == EXPR_DEX { - v := new_ir_var("dex", TI_DEX); - emit(IR_CONST, v, ast_a(node), 0, 0, TI_DEX); - return v; - } - f := new_ir_var("_dxf", TI_DEX); - emit(IR_I2F, f, var, 0, 0, TI_DEX); - c := new_ir_var("_dxsc", TI_DEX); - emit(IR_CONST, c, 4696837146684686336, 0, 0, TI_DEX); // 1e6 bits - d := new_ir_var("_dxdiv", TI_DEX); - emit(IR_BINARY, d, f, c, OP_DIV, TI_DEX); - return d; -} +fn dex_scaled_to_bits(var: int, node: int) -> int: + if irv_type(var) != TI_DEX_S: + return var + if node >= 0 && ast_kind(node) == EXPR_DEX: + v := new_ir_var("dex", TI_DEX) + emit(IR_CONST, v, ast_a(node), 0, 0, TI_DEX) + return v + f := new_ir_var("_dxf", TI_DEX) + emit(IR_I2F, f, var, 0, 0, TI_DEX) + c := new_ir_var("_dxsc", TI_DEX) + emit(IR_CONST, c, 4696837146684686336, 0, 0, TI_DEX) // 1e6 bits + d := new_ir_var("_dxdiv", TI_DEX) + emit(IR_BINARY, d, f, c, OP_DIV, TI_DEX) + return d // int 操作数 → 定点缩放(×S):精确路径的 int 隐式对齐(与 apx 路径的 I2F 同位) -fn dex_scale_int(var: int) -> int { - if irv_type(var) != TI_INT { return var; } - c := new_ir_var("_dsc", TI_INT); - emit(IR_CONST, c, 1000000, 0, 0, TI_INT); - t := new_ir_var("_dxt", TI_DEX_S); - emit(IR_BINARY, t, var, c, OP_MUL, TI_INT); - return t; -} +fn dex_scale_int(var: int) -> int: + if irv_type(var) != TI_INT: + return var + c := new_ir_var("_dsc", TI_INT) + emit(IR_CONST, c, 1000000, 0, 0, TI_INT) + t := new_ir_var("_dxt", TI_DEX_S) + emit(IR_BINARY, t, var, c, OP_MUL, TI_INT) + return t // 存储到 dex 槽位前按槽位形式转换(数值迁移 Task 4): // TI_DEX 槽(apx 变量)← 缩放值:scaled → bits(字面量重发射,计算值 I2F/S) // TI_DEX_S 槽(精确变量)← bits 值:bits → scaled(apx 结果按定点 6 位舍入入精确世界) -fn dex_store_adjust(target: int, val: int, val_node: int) -> int { - tt := irv_type(target); - vt := irv_type(val); - if tt == TI_DEX && vt == TI_DEX_S { return dex_scaled_to_bits(val, val_node); } - if tt == TI_DEX_S && vt == TI_DEX { return dex_bits_to_scaled(val); } - return val; -} +fn dex_store_adjust(target: int, val: int, val_node: int) -> int: + tt := irv_type(target) + vt := irv_type(val) + if tt == TI_DEX && vt == TI_DEX_S: + return dex_scaled_to_bits(val, val_node) + if tt == TI_DEX_S && vt == TI_DEX: + return dex_bits_to_scaled(val) + return val // 聚合/指针槽写点规范化(apx 批 T3):**聚合面不存在 apx 形式**——`apx` 是 LET 专属 // 标签(parser.cr:819),字段 / 数组·切片元素 / 元组元素 / 枚举载荷 / 指针 pointee @@ -1216,35 +1313,41 @@ fn dex_store_adjust(target: int, val: int, val_node: int) -> int { // scaled;非 apx 值原样返回(**零 IR** ⇒ 非 apx 程序逐字节不变)。 // 纪律(Global Constraint 12):本判定**不含任何类型表查询**(不调 res_type_node/ // alloc_type)——ir_gen 路径新增 alloc_type 站点会破坏暖缓存「不可写条目」不变式。 -fn dex_slot_norm(val: int) -> int { - if val < 0 { return val; } - if irv_type(val) != TI_DEX { return val; } - return dex_bits_to_scaled(val); -} +fn dex_slot_norm(val: int) -> int: + if val < 0: + return val + if irv_type(val) != TI_DEX: + return val + return dex_bits_to_scaled(val) // 声明类型**节点**是否 `dex?`(可选 dex)——**节点级零 alloc**(先例 `agg_read_form_is_dex:417` / // `reg_one_global` 的 `ast_kind(ltn)==0 && ast_type_val(ltn)==TY_DEX`)。`dex?` 的类型节点 = // `EXPR_OPTIONAL`,其内层是基类型节点 `dex`(`ast_kind==0 && ast_type_val==TY_DEX`)。 // 用途(批 5 · R1):写点/槽型按**声明**定形式(G1 裁决 = scaled),而非按值型反推。 -fn dex_opt_type_node(tn: int) -> int { - if tn < 0 { return 0; } - if ast_kind(tn) != EXPR_OPTIONAL { return 0; } - inner := ast_a(tn); - if inner < 0 || ast_kind(inner) != 0 { return 0; } - if ast_type_val(inner) == TY_DEX { return 1; } - return 0; -} +fn dex_opt_type_node(tn: int) -> int: + if tn < 0: + return 0 + if ast_kind(tn) != EXPR_OPTIONAL: + return 0 + inner := ast_a(tn) + if inner < 0 || ast_kind(inner) != 0: + return 0 + if ast_type_val(inner) == TY_DEX: + return 1 + return 0 // 类型**行**是否 `dex?`(`TYP_OPTIONAL` ∧ `data == TI_DEX`)——**纯表读零 alloc**(先例 // `ti_is_optional:328` / `elem_ti_of_decl:343`)。用途(批 5 · G2 读点定型):optional 声明的 // 载荷读槽取**声明面**形式——`agg_payload_read_form` 只认枚举行,内建 `Some` 面无行 ⇒ 恒 TI_INT // (`dex?` 载荷按值参与 dex 运算会被当 int 再 ×S)。G2 红线:**不得**调 `res_type_node`/`alloc_type`。 -fn dex_opt_slot_ti(ti: int) -> int { - if ti < 0 || ti >= g_type_count { return 0; } - if get_type_kind(ti) != TYP_OPTIONAL { return 0; } - if get_type_data(ti) == TI_DEX { return 1; } - return 0; -} +fn dex_opt_slot_ti(ti: int) -> int: + if ti < 0 || ti >= g_type_count: + return 0 + if get_type_kind(ti) != TYP_OPTIONAL: + return 0 + if get_type_data(ti) == TI_DEX: + return 1 + return 0 // 批 8(静默面收口 · 条目 1):dex 实参按**被调方**形参链对齐——**可复用版**(泛型实例化后按实例再跑)。 // ⚠ **本抽取在本批(批 8)未生效**:实例形参链未替换(`monomorph.cr` 的 `EXPR_FN` 克隆只克隆体 ⇒ 门恒假) @@ -1255,54 +1358,54 @@ fn dex_opt_slot_ti(ti: int) -> int { // `arg_vars[0]`,而 `self` 在方法形参链中亦占第 0 位(parser 物化 EXPR_PARAM,parser.cr `self` 分支) // ⇒ 同对齐。**幂等**:转换只对 `irv_type(av) == TI_DEX` 生效 ⇒ 已转换(TI_DEX_S)者不会被二次转换 // (这是「重定向前后各跑一遍」安全的前提)。**本函数不得重分配 arg_vars**(只写元素;句柄按值传入)。 -fn dex_align_call_args(cfi: int, ac: int, arg_vars: string, arg_nodes: string, arg_nodes_cap: int) { - cfn := fi_ast_node(cfi); - cfn_ext : ., mut = 0; - if cfn >= 0 && ast_kind(cfn) == EXPR_EXTERN { cfn_ext = 1; } - if cfn < 0 { return; } - if cfn_ext == 0 && ast_kind(cfn) != EXPR_FN { return; } - cpi : ., mut = 0; - cpn : ., mut = ast_b(cfn); +fn dex_align_call_args(cfi: int, ac: int, arg_vars: string, arg_nodes: string, arg_nodes_cap: int): + cfn := fi_ast_node(cfi) + cfn_ext : ., mut = 0 + if cfn >= 0 && ast_kind(cfn) == EXPR_EXTERN: + cfn_ext = 1 + if cfn < 0: + return + if cfn_ext == 0 && ast_kind(cfn) != EXPR_FN: + return + cpi : ., mut = 0 + cpn : ., mut = ast_b(cfn) // 实参节点与实参 var **同表锁步**取(`arg_nodes[cpi]` 与 `arg_vars[cpi]` 同索引写入, // 接收者亦在内)——方法调用下 EXPR_ARG 链**不含接收者**,若按链另走游标会滞后一位 // (批 5 实测:node 仅服务于 extern 字面量重发射,Core 分支不用;仍按锁步改正以免埋雷)。 - loop { - if cpi >= ac { break; } - if cpn < 0 { break; } - dd := ast_data(cpn); + loop: + if cpi >= ac: + break + if cpn < 0: + break + dd := ast_data(cpn) // 批 5(opt-dex · R3):`dex?` 形参也进环——修复前门只认基类型节点(`type_val == TI_DEX`), // `dex?` 的 `type_val` = 0 ⇒ apx 实参不转换 ⇒ 与 callee 槽型(本批已改 TI_DEX_S)口径一致; // extern 侧不扩(C ABI 无可选表示,`.so` 面登记未覆盖面)。 // 批 8(条目 1):泛型声明的 `T?`(inner = 泛型参数)判据为**假** ⇒ 调用点在**重定向后** // 用**实例**形参链(inner = 具体 dex)再跑一遍本环。 - if ast_type_val(cpn) == TI_DEX || - (cfn_ext == 0 && dex_opt_type_node(ast_data(cpn)) != 0) { - av := r64(arg_vars, cpi * 8); - if av >= 0 { - if cfn_ext != 0 { + if ast_type_val(cpn) == TI_DEX || (cfn_ext == 0 && dex_opt_type_node(ast_data(cpn)) != 0): + av := r64(arg_vars, cpi * 8) + if av >= 0: + if cfn_ext != 0: // extern:scaled → bits(字面量直接重发射位模式常量) - if irv_type(av) == TI_DEX_S { - arg_node : ., mut = -1; - if cpi < arg_nodes_cap { arg_node = r64(arg_nodes, cpi * 8); } - av = dex_scaled_to_bits(av, arg_node); - w64(arg_vars, cpi * 8, av); - } - } else if irv_type(av) == TI_DEX { + if irv_type(av) == TI_DEX_S: + arg_node : ., mut = -1 + if cpi < arg_nodes_cap: + arg_node = r64(arg_nodes, cpi * 8) + av = dex_scaled_to_bits(av, arg_node) + w64(arg_vars, cpi * 8, av) + else if irv_type(av) == TI_DEX: // Core 函数:apx bits → scaled - av = dex_bits_to_scaled(av); - w64(arg_vars, cpi * 8, av); - } - } - } - cpi = cpi + 1; - cpn = cpn + 1; - loop { - if cpn >= g_ast_count { break; } - if ast_kind(cpn) == EXPR_PARAM { break; } - cpn = cpn + 1; - } - } -} + av = dex_bits_to_scaled(av) + w64(arg_vars, cpi * 8, av) + cpi = cpi + 1 + cpn = cpn + 1 + loop: + if cpn >= g_ast_count: + break + if ast_kind(cpn) == EXPR_PARAM: + break + cpn = cpn + 1 // 聚合读的**声明面** dex-ness(apx 批 T3 · 比较/相等点专用): // #2026-09-16-16 未修 ⇒ 聚合读的结果槽 IR 型恒 TI_INT、**声明型被抹** ⇒ 下游「按值型触发」的 @@ -1311,137 +1414,137 @@ fn dex_align_call_args(cfi: int, ac: int, arg_vars: string, arg_nodes: string, a // EXPR_FIELD ⇒ 结构体字段的声明类型节点(数字元组下标 ast_type_val>0 不判——元组无声明面) // EXPR_INDEX ⇒ **全局**定长数组/切片的元素声明类型节点(局部数组无节点级声明面 ⇒ 不判) // 返回 1 = 声明为 dex(⇒ 槽内规范形式 = **精确/scaled**,由本批写点保证)· 0 = 非 dex / 不可得。 -fn dex_decl_form_of_expr(node: int) -> int { - if node < 0 { return 0; } - k := ast_kind(node); - if k == EXPR_FIELD { - if ast_type_val(node) > 0 { return 0; } - si := find_struct(ast_c(node)); - if si < 0 { return 0; } - fi : ., mut = ast_data(node); - if fi < 0 { return 0; } - tn := si_field_type_node(si, fi); - if tn >= 0 && ast_kind(tn) == 0 && ast_type_val(tn) == TY_DEX { return 1; } - return 0; - } - if k == EXPR_INDEX { - an := ast_a(node); - if an < 0 || ast_kind(an) != EXPR_IDENT { return 0; } - ni := ast_int_val(an); - gi : ., mut = 0; - loop { - if gi >= g_global_let_count { break; } - lnode := r64(g_global_lets, gi * 8); - if ast_a(lnode) == ni { - tn := ast_b(lnode); - if tn >= 0 && ast_kind(tn) == EXPR_ARRAY { - etn := ast_a(tn); - if etn >= 0 && ast_kind(etn) == 0 && ast_type_val(etn) == TY_DEX { return 1; } - } - break; - } - gi = gi + 1; - } - return 0; - } - return 0; -} +fn dex_decl_form_of_expr(node: int) -> int: + if node < 0: + return 0 + k := ast_kind(node) + if k == EXPR_FIELD: + if ast_type_val(node) > 0: + return 0 + si := find_struct(ast_c(node)) + if si < 0: + return 0 + fi : ., mut = ast_data(node) + if fi < 0: + return 0 + tn := si_field_type_node(si, fi) + if tn >= 0 && ast_kind(tn) == 0 && ast_type_val(tn) == TY_DEX: + return 1 + return 0 + if k == EXPR_INDEX: + an := ast_a(node) + if an < 0 || ast_kind(an) != EXPR_IDENT: + return 0 + ni := ast_int_val(an) + gi : ., mut = 0 + loop: + if gi >= g_global_let_count: + break + lnode := r64(g_global_lets, gi * 8) + if ast_a(lnode) == ni: + tn := ast_b(lnode) + if tn >= 0 && ast_kind(tn) == EXPR_ARRAY: + etn := ast_a(tn) + if etn >= 0 && ast_kind(etn) == 0 && ast_type_val(etn) == TY_DEX: + return 1 + break + gi = gi + 1 + return 0 + return 0 // --- IR generation for expressions --- // Returns the IR variable index holding the result -fn gen_expr(node: int) -> int { - if node < 0 { return -1; } +fn gen_expr(node: int) -> int: + if node < 0: + return -1 - if ast_kind(node) == EXPR_NONE { + if ast_kind(node) == EXPR_NONE: // Wrapper node: forward to inner expression (used in struct literals) - if ast_a(node) >= 0 && ast_a(node) != node { return gen_expr(ast_a(node)); } - return -1; - } + if ast_a(node) >= 0 && ast_a(node) != node: + return gen_expr(ast_a(node)) + return -1 // Literals - if ast_kind(node) == EXPR_INT { - v := new_ir_var("int", TI_INT); - emit(IR_CONST, v, ast_int_val(node), 0, 0, TI_INT); - return v; - } - if ast_kind(node) == EXPR_DEX { + if ast_kind(node) == EXPR_INT: + v := new_ir_var("int", TI_INT) + emit(IR_CONST, v, ast_int_val(node), 0, 0, TI_INT) + return v + if ast_kind(node) == EXPR_DEX: // 精确字面量(数值迁移 Task 4):定点缩放整数常量(TI_DEX_S)。 // apx 场景(变量级 apx 标签的运算)在运算点按 node.a 的 binary64 位模式重发射。 - v := new_ir_var("dex", TI_DEX_S); - emit(IR_CONST, v, ast_int_val(node), 0, 0, TI_DEX_S); - return v; - } - if ast_kind(node) == EXPR_BOOL { - v := new_ir_var("bool", TI_BOOL); - emit(IR_CONST, v, ast_int_val(node), 0, 0, TI_BOOL); - return v; - } - if ast_kind(node) == EXPR_STRING { - v := new_ir_var("str", TI_STR); - str_idx := ast_int_val(node); - track_str(str_idx); - emit(IR_CONST, v, str_idx, 0, 0, TI_STR); - return v; - } + v := new_ir_var("dex", TI_DEX_S) + emit(IR_CONST, v, ast_int_val(node), 0, 0, TI_DEX_S) + return v + if ast_kind(node) == EXPR_BOOL: + v := new_ir_var("bool", TI_BOOL) + emit(IR_CONST, v, ast_int_val(node), 0, 0, TI_BOOL) + return v + if ast_kind(node) == EXPR_STRING: + v := new_ir_var("str", TI_STR) + str_idx := ast_int_val(node) + track_str(str_idx) + emit(IR_CONST, v, str_idx, 0, 0, TI_STR) + return v // 插值洞兜底(批 8 插值展开):**洞应在 checker 就被就地改写**(见 checker.cr EXPR_INTERP_HOLE // 分支:string 恒等 / int→int_str / bool→bool_str,其它 P028)。若仍有洞走到发射面,说明 // checker 漏走了某条路径(extern 早退 / 实例体 / 未来新路径)⇒ **响亮拒绝**(P029), // **绝不**静默当空值或身份——那正是本批要消灭的静默类。 - if ast_kind(node) == EXPR_INTERP_HOLE { - check_error(EC_P_INTERP_HOLE_LEAK, "internal: string interpolation hole reached codegen (checker rewrite missing)", ast_line(node), ast_col(node)); - v := new_ir_var("interp_leak", TI_STR); - emit(IR_CONST, v, str_intern(""), 0, 0, TI_STR); - return v; - } - - if ast_kind(node) == EXPR_CHAR { - v := new_ir_var("char", TI_CHAR); - str_idx := ast_int_val(node); - track_str(str_idx); - emit(IR_CONST, v, str_idx, 0, 0, TI_CHAR); - return v; - } + if ast_kind(node) == EXPR_INTERP_HOLE: + check_error(EC_P_INTERP_HOLE_LEAK, "internal: string interpolation hole reached codegen (checker rewrite missing)", ast_line(node), ast_col(node)) + v := new_ir_var("interp_leak", TI_STR) + emit(IR_CONST, v, str_intern(""), 0, 0, TI_STR) + return v + + if ast_kind(node) == EXPR_CHAR: + v := new_ir_var("char", TI_CHAR) + str_idx := ast_int_val(node) + track_str(str_idx) + emit(IR_CONST, v, str_idx, 0, 0, TI_CHAR) + return v // Identifier: local or global variable - if ast_kind(node) == EXPR_IDENT { - name_idx := ast_int_val(node); - lv := find_local(name_idx); - if lv >= 0 { return lv; } - const_node := find_global_const_node(name_idx); + if ast_kind(node) == EXPR_IDENT: + name_idx := ast_int_val(node) + lv := find_local(name_idx) + if lv >= 0: + return lv + const_node := find_global_const_node(name_idx) // 容量批 T2:**可选全局槽不得常量折叠**——字面量初值(`g : int? = 5`)的读点若被 // 折成裸常量 5,则 match 的 tag 读会解引用该裸值(双路径 139,实测 e2_global_bare)。 // 折叠面只对非可选全局生效(零足迹);可选全局由运行期初始化写入装箱对象。 - if const_node >= 0 && g_optrep_on != 0 && global_decl_optional(name_idx) != 0 { const_node = -1; } - if const_node >= 0 { - const_type : ., mut = TI_INT; - if ast_kind(const_node) == EXPR_BOOL { const_type = TI_BOOL; } - if ast_kind(const_node) == EXPR_DEX { const_type = TI_DEX_S; } // 定点缩放常量 - cv := new_ir_var("const", const_type); - emit(IR_CONST, cv, ast_int_val(const_node), 0, 0, const_type); - return cv; - } - gv := find_global(name_idx); - if gv >= 0 { return gv; } + if const_node >= 0 && g_optrep_on != 0 && global_decl_optional(name_idx) != 0: + const_node = -1 + if const_node >= 0: + const_type : ., mut = TI_INT + if ast_kind(const_node) == EXPR_BOOL: + const_type = TI_BOOL + if ast_kind(const_node) == EXPR_DEX: + const_type = TI_DEX_S + // 定点缩放常量 + cv := new_ir_var("const", const_type) + emit(IR_CONST, cv, ast_int_val(const_node), 0, 0, const_type) + return cv + gv := find_global(name_idx) + if gv >= 0: + return gv // F15:枚举裸变体(c := Red,不带括号)——发射无 payload 的 MAKE_ENUM // (s1=变体名 ni、s2=0),与 EXPR_ENUM_CONSTRUCTOR 的 `Red()` 调用形式 // 同机制(tag = 变体名驻留索引,match 按名字比较)。修复前落为下方 // "unresolved" 哑变量 → 后续 LOAD_ENUM_TAG 解引用垃圾值 → SIGSEGV(139)。 - if find_enum_variant(name_idx) >= 0 { - s := new_ir_var("enum", TI_UNIT); - emit(IR_MAKE_ENUM, s, name_idx, 0, 0, 0); - return s; - } + if find_enum_variant(name_idx) >= 0: + s := new_ir_var("enum", TI_UNIT) + emit(IR_MAKE_ENUM, s, name_idx, 0, 0, 0) + return s // Could be a function name being used as a value - return dummy - v := new_ir_var("unresolved", TI_UNIT); - return v; - } + v := new_ir_var("unresolved", TI_UNIT) + return v // Binary operation - if ast_kind(node) == EXPR_BINARY { - left := ast_a(node); - right := ast_b(node); - op := ast_c(node); + if ast_kind(node) == EXPR_BINARY: + left := ast_a(node) + right := ast_b(node) + op := ast_c(node) // R2 P5 Task 4(D25):`EXPR_BINARY + OP_ASSIGN` 赋值分支**已删**——不可达 // (parser 不产该组合:`tok2op` 零 OP_ASSIGN;`T_EQ` → EXPR_ASSIGN;`+=` 族构造 @@ -1449,708 +1552,674 @@ fn gen_expr(node: int) -> int { // 赋值发射面在下方 `EXPR_ASSIGN` 分支(gen_expr 的另一 arm),逐字未动。 // Regular binary - left_var := gen_expr(left); - left_var = force_if_thunk(left_var); + left_var := gen_expr(left) + left_var = force_if_thunk(left_var) // Logical operators must short-circuit. Eagerly generating the // right side breaks guard expressions such as // `fi >= 0 && fi_generic_count(fi) > 0`. - if op == OP_AND || op == OP_OR { - right_lbl := new_label(); - short_lbl := new_label(); - merge_lbl := new_label(); - logic_result := new_ir_var("logic", TI_BOOL); - if op == OP_AND { - emit(IR_BRANCH, -1, left_var, right_lbl, short_lbl, 0); - } else { - emit(IR_BRANCH, -1, left_var, short_lbl, right_lbl, 0); - } - - emit(IR_LABEL, -1, short_lbl, 0, 0, 0); - short_value := new_ir_var("logic_short", TI_BOOL); - if op == OP_AND { emit(IR_CONST, short_value, 0, 0, 0, TI_BOOL); } - else { emit(IR_CONST, short_value, 1, 0, 0, TI_BOOL); } - emit(IR_STORE, -1, logic_result, short_value, 0, 0); - emit(IR_JUMP, -1, merge_lbl, 0, 0, 0); - - emit(IR_LABEL, -1, right_lbl, 0, 0, 0); - right_value := gen_expr(right); - right_value = force_if_thunk(right_value); - emit(IR_STORE, -1, logic_result, right_value, 0, 0); - emit(IR_JUMP, -1, merge_lbl, 0, 0, 0); - - emit(IR_LABEL, -1, merge_lbl, 0, 0, 0); - return logic_result; - } - right_var := gen_expr(right); - right_var = force_if_thunk(right_var); - lt := irv_type(left_var); - rt := irv_type(right_var); + if op == OP_AND || op == OP_OR: + right_lbl := new_label() + short_lbl := new_label() + merge_lbl := new_label() + logic_result := new_ir_var("logic", TI_BOOL) + if op == OP_AND: + emit(IR_BRANCH, -1, left_var, right_lbl, short_lbl, 0) + else: + emit(IR_BRANCH, -1, left_var, short_lbl, right_lbl, 0) + + emit(IR_LABEL, -1, short_lbl, 0, 0, 0) + short_value := new_ir_var("logic_short", TI_BOOL) + if op == OP_AND: + emit(IR_CONST, short_value, 0, 0, 0, TI_BOOL) + else: + emit(IR_CONST, short_value, 1, 0, 0, TI_BOOL) + emit(IR_STORE, -1, logic_result, short_value, 0, 0) + emit(IR_JUMP, -1, merge_lbl, 0, 0, 0) + + emit(IR_LABEL, -1, right_lbl, 0, 0, 0) + right_value := gen_expr(right) + right_value = force_if_thunk(right_value) + emit(IR_STORE, -1, logic_result, right_value, 0, 0) + emit(IR_JUMP, -1, merge_lbl, 0, 0, 0) + + emit(IR_LABEL, -1, merge_lbl, 0, 0, 0) + return logic_result + right_var := gen_expr(right) + right_var = force_if_thunk(right_var) + lt := irv_type(left_var) + rt := irv_type(right_var) // Unwrap dyn operands: extract the underlying value for binary ops - if lt == TI_DYN { - uv := new_ir_var("_dynval", TI_UNIT); - emit(IR_DYN_VAL, uv, left_var, 0, 0, 0); - left_var = uv; - lt = irv_type(left_var); - } - if rt == TI_DYN { - uv := new_ir_var("_dynval", TI_UNIT); - emit(IR_DYN_VAL, uv, right_var, 0, 0, 0); - right_var = uv; - rt = irv_type(right_var); - } + if lt == TI_DYN: + uv := new_ir_var("_dynval", TI_UNIT) + emit(IR_DYN_VAL, uv, left_var, 0, 0, 0) + left_var = uv + lt = irv_type(left_var) + if rt == TI_DYN: + uv := new_ir_var("_dynval", TI_UNIT) + emit(IR_DYN_VAL, uv, right_var, 0, 0, 0) + right_var = uv + rt = irv_type(right_var) // 批 8(静默面收口 · 条目 2):可选值 `==`/`!=` **按值比较**(表示透明)。 // 修复前走通用二元路径逐槽比**原始值**:裸(rep=0,槽值=载荷)⇒ 比载荷(正确); // 装箱(Some/None 对象)⇒ 比**指针** ⇒ `n==None` / 两个 None / `Some(7)==Some(7)` **恒假**(静默错值)。 // 本点把两侧归一为 (absent, payload) 后按值比:缺省性不同 ⇒ 不等;同缺省 ⇒ 相等;同在 ⇒ 比载荷。 // 触发面**保守**(`opt_cmp_optish`:带表示位 / Some|None 构造子 / 可选声明面)⇒ 非可选比较零变化(判据 ⑤)。 - if (op == OP_EQ || op == OP_NE) && g_optrep_on != 0 { - lo := opt_cmp_optish(left, left_var); - ro := opt_cmp_optish(right, right_var); - if lo != 0 || ro != 0 { - lt2 : ., mut = TI_INT; - if left_var >= 0 { lt2 = irv_type(left_var); } - rt2 : ., mut = TI_INT; - if right_var >= 0 { rt2 = irv_type(right_var); } - abs_l := new_ir_var("absl", TI_INT); - val_l := new_ir_var("vall", lt2); - abs_r := new_ir_var("absr", TI_INT); - val_r := new_ir_var("valr", rt2); - opt_cmp_norm(left, left_var, abs_l, val_l); - opt_cmp_norm(right, right_var, abs_r, val_r); - zb := new_ir_var("_cz", TI_INT); - emit(IR_CONST, zb, 0, 0, 0, TI_INT); + if (op == OP_EQ || op == OP_NE) && g_optrep_on != 0: + lo := opt_cmp_optish(left, left_var) + ro := opt_cmp_optish(right, right_var) + if lo != 0 || ro != 0: + lt2 : ., mut = TI_INT + if left_var >= 0: + lt2 = irv_type(left_var) + rt2 : ., mut = TI_INT + if right_var >= 0: + rt2 = irv_type(right_var) + abs_l := new_ir_var("absl", TI_INT) + val_l := new_ir_var("vall", lt2) + abs_r := new_ir_var("absr", TI_INT) + val_r := new_ir_var("valr", rt2) + opt_cmp_norm(left, left_var, abs_l, val_l) + opt_cmp_norm(right, right_var, abs_r, val_r) + zb := new_ir_var("_cz", TI_INT) + emit(IR_CONST, zb, 0, 0, 0, TI_INT) // peq = 载荷相等(两侧皆缺省时其值无意义——由 both_abs 兜底) - peq : ., mut = -1; - if lt2 == TI_STR || rt2 == TI_STR { - eq0 := new_ir_var("_eq0", lt2); - eq1 := new_ir_var("_eq1", rt2); - emit(IR_STORE, -1, eq0, val_l, 0, 0); - emit(IR_STORE, -1, eq1, val_r, 0, 0); - peq = new_ir_var("str_eq", TI_BOOL); - emit(IR_CALL, peq, eq0, 2, str_intern("str_eq"), TI_BOOL); - } else { - peq = new_ir_var("peq", TI_INT); - emit(IR_BINARY, peq, val_l, val_r, OP_EQ, 0); - } - both_abs := new_ir_var("bothz", TI_INT); - emit(IR_BINARY, both_abs, abs_l, abs_r, OP_AND, 0); - eqv := new_ir_var("eqv", TI_INT); - emit(IR_BINARY, eqv, both_abs, peq, OP_OR, 0); - abs_eq := new_ir_var("abeq", TI_INT); - emit(IR_BINARY, abs_eq, abs_l, abs_r, OP_EQ, 0); - eqi := new_ir_var("eqi", TI_INT); - emit(IR_BINARY, eqi, abs_eq, eqv, OP_AND, 0); - if op == OP_EQ { - res := new_ir_var("optcmp", TI_BOOL); - emit(IR_BINARY, res, eqi, zb, OP_NE, TI_BOOL); - return res; - } - res := new_ir_var("optcmp", TI_BOOL); - emit(IR_BINARY, res, eqi, zb, OP_EQ, TI_BOOL); - return res; - } - } + peq : ., mut = -1 + if lt2 == TI_STR || rt2 == TI_STR: + eq0 := new_ir_var("_eq0", lt2) + eq1 := new_ir_var("_eq1", rt2) + emit(IR_STORE, -1, eq0, val_l, 0, 0) + emit(IR_STORE, -1, eq1, val_r, 0, 0) + peq = new_ir_var("str_eq", TI_BOOL) + emit(IR_CALL, peq, eq0, 2, str_intern("str_eq"), TI_BOOL) + else: + peq = new_ir_var("peq", TI_INT) + emit(IR_BINARY, peq, val_l, val_r, OP_EQ, 0) + both_abs := new_ir_var("bothz", TI_INT) + emit(IR_BINARY, both_abs, abs_l, abs_r, OP_AND, 0) + eqv := new_ir_var("eqv", TI_INT) + emit(IR_BINARY, eqv, both_abs, peq, OP_OR, 0) + abs_eq := new_ir_var("abeq", TI_INT) + emit(IR_BINARY, abs_eq, abs_l, abs_r, OP_EQ, 0) + eqi := new_ir_var("eqi", TI_INT) + emit(IR_BINARY, eqi, abs_eq, eqv, OP_AND, 0) + if op == OP_EQ: + res := new_ir_var("optcmp", TI_BOOL) + emit(IR_BINARY, res, eqi, zb, OP_NE, TI_BOOL) + return res + res := new_ir_var("optcmp", TI_BOOL) + emit(IR_BINARY, res, eqi, zb, OP_EQ, TI_BOOL) + return res // String equality compares contents, not pointer values. - if (op == OP_EQ || op == OP_NE) && (lt == TI_STR || rt == TI_STR) { - eq_ni := str_intern("str_eq"); - eq_arg0 := new_ir_var("_eq0", lt); - eq_arg1 := new_ir_var("_eq1", rt); - emit(IR_STORE, -1, eq_arg0, left_var, 0, 0); - emit(IR_STORE, -1, eq_arg1, right_var, 0, 0); - eq_value := new_ir_var("str_eq", TI_BOOL); - emit(IR_CALL, eq_value, eq_arg0, 2, eq_ni, TI_BOOL); - if op == OP_EQ { return eq_value; } - zero_value := new_ir_var("zero", TI_INT); - emit(IR_CONST, zero_value, 0, 0, 0, TI_INT); - ne_value := new_ir_var("str_ne", TI_BOOL); - emit(IR_BINARY, ne_value, eq_value, zero_value, OP_EQ, TI_BOOL); - return ne_value; - } + if (op == OP_EQ || op == OP_NE) && (lt == TI_STR || rt == TI_STR): + eq_ni := str_intern("str_eq") + eq_arg0 := new_ir_var("_eq0", lt) + eq_arg1 := new_ir_var("_eq1", rt) + emit(IR_STORE, -1, eq_arg0, left_var, 0, 0) + emit(IR_STORE, -1, eq_arg1, right_var, 0, 0) + eq_value := new_ir_var("str_eq", TI_BOOL) + emit(IR_CALL, eq_value, eq_arg0, 2, eq_ni, TI_BOOL) + if op == OP_EQ: + return eq_value + zero_value := new_ir_var("zero", TI_INT) + emit(IR_CONST, zero_value, 0, 0, 0, TI_INT) + ne_value := new_ir_var("str_ne", TI_BOOL) + emit(IR_BINARY, ne_value, eq_value, zero_value, OP_EQ, TI_BOOL) + return ne_value // String concatenation — call concat() instead of IR_BINARY - if op == OP_ADD { - if lt == TI_STR || rt == TI_STR { - concat_ni := str_intern("concat"); + if op == OP_ADD: + if lt == TI_STR || rt == TI_STR: + concat_ni := str_intern("concat") // Pack both args into consecutive vars so ELF backend finds them - packed0 := new_ir_var("_cat0", lt); - packed1 := new_ir_var("_cat1", rt); - emit(IR_STORE, -1, packed0, left_var, 0, 0); - emit(IR_STORE, -1, packed1, right_var, 0, 0); - v := new_ir_var("str", TI_STR); - emit(IR_CALL, v, packed0, 2, concat_ni, TI_STR); - return v; - } - } + packed0 := new_ir_var("_cat0", lt) + packed1 := new_ir_var("_cat1", rt) + emit(IR_STORE, -1, packed0, left_var, 0, 0) + emit(IR_STORE, -1, packed1, right_var, 0, 0) + v := new_ir_var("str", TI_STR) + emit(IR_CALL, v, packed0, 2, concat_ni, TI_STR) + return v // apx 批 T3(L10 · 比较/运算点的**声明面**查表):聚合读的结果槽 IR 型恒 TI_INT // (#2026-09-16-16:读点定型丢失声明型)⇒ 当操作数节点是聚合读**且声明面为 dex** 时,槽内 // 规范形式 = **精确(scaled)**(由本批写点保证)⇒ 按 TI_DEX_S 参与分流——否则 // 会落「TI_INT 操作数 I2F」支,把 scaled 整数当整数升 double(实测 b8 红 0)。 // **作用域**:只覆盖本分流点;**不改读点定型**(那是 #2026-09-16-16 的爆炸半径,#2026-09-16-29/#2026-09-16-16 另批)。 - if lt == TI_INT && dex_decl_form_of_expr(left) != 0 { lt = TI_DEX_S; } - if rt == TI_INT && dex_decl_form_of_expr(right) != 0 { rt = TI_DEX_S; } - fti : int = TI_INT; + if lt == TI_INT && dex_decl_form_of_expr(left) != 0: + lt = TI_DEX_S + if rt == TI_INT && dex_decl_form_of_expr(right) != 0: + rt = TI_DEX_S + fti : int = TI_INT // Pointer arithmetic: use PTR_ADD/PTR_SUB/PTR_DIFF instead of standard opcodes. // Raw byte buffers from alloc() are byte-addressed — plain ADD/SUB, no scaling. - if is_ptr_var(left_var) != 0 || is_ptr_var(right_var) != 0 { - buf_left := is_byte_buf_var(left_var); - buf_right := is_byte_buf_var(right_var); - if buf_left == 0 && buf_right == 0 { - if op == OP_ADD { op = OP_PTR_ADD; } - else if op == OP_SUB { - if is_ptr_var(left_var) != 0 && is_ptr_var(right_var) != 0 { - op = OP_PTR_DIFF; - } else { - op = OP_PTR_SUB; - } - } - } - } - if op == OP_PTR_ADD || op == OP_PTR_SUB { - if is_ptr_var(left_var) != 0 { fti = irv_type(left_var); } - else if is_ptr_var(right_var) != 0 { fti = irv_type(right_var); } - } + if is_ptr_var(left_var) != 0 || is_ptr_var(right_var) != 0: + buf_left := is_byte_buf_var(left_var) + buf_right := is_byte_buf_var(right_var) + if buf_left == 0 && buf_right == 0: + if op == OP_ADD: + op = OP_PTR_ADD + else if op == OP_SUB: + if is_ptr_var(left_var) != 0 && is_ptr_var(right_var) != 0: + op = OP_PTR_DIFF + else: + op = OP_PTR_SUB + if op == OP_PTR_ADD || op == OP_PTR_SUB: + if is_ptr_var(left_var) != 0: + fti = irv_type(left_var) + else if is_ptr_var(right_var) != 0: + fti = irv_type(right_var) // dex 运算分流(数值迁移 Task 4): // 有 TI_DEX(apx 形式)操作数 → binary64 快路径(SSE2,IEEE 754——apx 标准答案) // 有 TI_DEX_S(定点形式)操作数 → 精确路径(缩放整数指令序列) - if lt == TI_DEX || rt == TI_DEX { - fti = TI_DEX; + if lt == TI_DEX || rt == TI_DEX: + fti = TI_DEX // apx 路径操作数对齐:字面量 → 重发射 bits 常量;定点(TI_DEX_S)→ // I2F/S 转 bits(按精确值参与——apx 授权的近似);int → I2F(隐式转换) - if lt == TI_DEX_S { left_var = dex_scaled_to_bits(left_var, left); } - else if lt == TI_INT { - t1 := new_ir_var("_f0", TI_DEX); - emit(IR_I2F, t1, left_var, 0, 0, TI_DEX); - left_var = t1; - } - if rt == TI_DEX_S { right_var = dex_scaled_to_bits(right_var, right); } - else if rt == TI_INT { - t2 := new_ir_var("_f1", TI_DEX); - emit(IR_I2F, t2, right_var, 0, 0, TI_DEX); - right_var = t2; - } - v := new_ir_var("bin", fti); - emit(IR_BINARY, v, left_var, right_var, op, fti); - return v; - } - if lt == TI_DEX_S || rt == TI_DEX_S { - fti = TI_DEX_S; + if lt == TI_DEX_S: + left_var = dex_scaled_to_bits(left_var, left) + else if lt == TI_INT: + t1 := new_ir_var("_f0", TI_DEX) + emit(IR_I2F, t1, left_var, 0, 0, TI_DEX) + left_var = t1 + if rt == TI_DEX_S: + right_var = dex_scaled_to_bits(right_var, right) + else if rt == TI_INT: + t2 := new_ir_var("_f1", TI_DEX) + emit(IR_I2F, t2, right_var, 0, 0, TI_DEX) + right_var = t2 + v := new_ir_var("bin", fti) + emit(IR_BINARY, v, left_var, right_var, op, fti) + return v + if lt == TI_DEX_S || rt == TI_DEX_S: + fti = TI_DEX_S // 精确路径操作数对齐:int → ×S(隐式缩放);定点(TI_DEX_S)直接参与 - if lt == TI_INT { left_var = dex_scale_int(left_var); } - if rt == TI_INT { right_var = dex_scale_int(right_var); } - if op == OP_MUL { + if lt == TI_INT: + left_var = dex_scale_int(left_var) + if rt == TI_INT: + right_var = dex_scale_int(right_var) + if op == OP_MUL: // (a×b)/S:先乘后缩回(中间值 a·b ≤ 9.2e18 → |值| ≤ 3.03e3 级,文档化) - p := new_ir_var("_dxm", TI_DEX_S); - emit(IR_BINARY, p, left_var, right_var, OP_MUL, TI_INT); - c := new_ir_var("_dxs", TI_INT); - emit(IR_CONST, c, 1000000, 0, 0, TI_INT); - v := new_ir_var("bin", TI_DEX_S); - emit(IR_BINARY, v, p, c, OP_DIV, TI_INT); - return v; - } - if op == OP_DIV { + p := new_ir_var("_dxm", TI_DEX_S) + emit(IR_BINARY, p, left_var, right_var, OP_MUL, TI_INT) + c := new_ir_var("_dxs", TI_INT) + emit(IR_CONST, c, 1000000, 0, 0, TI_INT) + v := new_ir_var("bin", TI_DEX_S) + emit(IR_BINARY, v, p, c, OP_DIV, TI_INT) + return v + if op == OP_DIV: // (a×S)/b:先放大再除(中间值 a·S ≤ 9.2e18 → |a| ≤ 9.2e6,向零截断) - c := new_ir_var("_dxs", TI_INT); - emit(IR_CONST, c, 1000000, 0, 0, TI_INT); - t := new_ir_var("_dxn", TI_DEX_S); - emit(IR_BINARY, t, left_var, c, OP_MUL, TI_INT); - v := new_ir_var("bin", TI_DEX_S); - emit(IR_BINARY, v, t, right_var, OP_DIV, TI_INT); - return v; - } - if op == OP_MOD { + c := new_ir_var("_dxs", TI_INT) + emit(IR_CONST, c, 1000000, 0, 0, TI_INT) + t := new_ir_var("_dxn", TI_DEX_S) + emit(IR_BINARY, t, left_var, c, OP_MUL, TI_INT) + v := new_ir_var("bin", TI_DEX_S) + emit(IR_BINARY, v, t, right_var, OP_DIV, TI_INT) + return v + if op == OP_MOD: // a mod b = a - trunc(a/b)·b(截断除法恒等式,缩放形式) - c := new_ir_var("_dxs", TI_INT); - emit(IR_CONST, c, 1000000, 0, 0, TI_INT); - t1 := new_ir_var("_dxn", TI_DEX_S); - emit(IR_BINARY, t1, left_var, c, OP_MUL, TI_INT); - t2 := new_ir_var("_dxq", TI_DEX_S); - emit(IR_BINARY, t2, t1, right_var, OP_DIV, TI_INT); - t3 := new_ir_var("_dxi", TI_DEX_S); - emit(IR_BINARY, t3, t2, c, OP_DIV, TI_INT); // trunc(a/b)(纯整数) - t4 := new_ir_var("_dxr", TI_DEX_S); - emit(IR_BINARY, t4, t3, right_var, OP_MUL, TI_INT); - v := new_ir_var("bin", TI_DEX_S); - emit(IR_BINARY, v, left_var, t4, OP_SUB, TI_INT); - return v; - } - if op == OP_EQ || op == OP_NE || op == OP_LT || op == OP_GT || - op == OP_LE || op == OP_GE { + c := new_ir_var("_dxs", TI_INT) + emit(IR_CONST, c, 1000000, 0, 0, TI_INT) + t1 := new_ir_var("_dxn", TI_DEX_S) + emit(IR_BINARY, t1, left_var, c, OP_MUL, TI_INT) + t2 := new_ir_var("_dxq", TI_DEX_S) + emit(IR_BINARY, t2, t1, right_var, OP_DIV, TI_INT) + t3 := new_ir_var("_dxi", TI_DEX_S) + emit(IR_BINARY, t3, t2, c, OP_DIV, TI_INT) // trunc(a/b)(纯整数) + t4 := new_ir_var("_dxr", TI_DEX_S) + emit(IR_BINARY, t4, t3, right_var, OP_MUL, TI_INT) + v := new_ir_var("bin", TI_DEX_S) + emit(IR_BINARY, v, left_var, t4, OP_SUB, TI_INT) + return v + if op == OP_EQ || op == OP_NE || op == OP_LT || op == OP_GT || op == OP_LE || op == OP_GE: // 比较:缩放整数比较,结果 0/1(int——非 dex 值) - v := new_ir_var("cmp", TI_INT); - emit(IR_BINARY, v, left_var, right_var, op, TI_INT); - return v; - } + v := new_ir_var("cmp", TI_INT) + emit(IR_BINARY, v, left_var, right_var, op, TI_INT) + return v // ADD/SUB 及余下:缩放整数直接运算 - v := new_ir_var("bin", TI_DEX_S); - emit(IR_BINARY, v, left_var, right_var, op, TI_INT); - return v; - } - v := new_ir_var("bin", fti); - emit(IR_BINARY, v, left_var, right_var, op, fti); - return v; - } + v := new_ir_var("bin", TI_DEX_S) + emit(IR_BINARY, v, left_var, right_var, op, TI_INT) + return v + v := new_ir_var("bin", fti) + emit(IR_BINARY, v, left_var, right_var, op, fti) + return v // Assignment - if ast_kind(node) == EXPR_ASSIGN { - target := ast_a(node); + if ast_kind(node) == EXPR_ASSIGN: + target := ast_a(node) // Unwrap EXPR_NONE wrapper (added by checker/optimizer to // mark rewritten nodes). Without unwrapping, the target // checks below would miss wrapped UOP_DEREF or INDEX nodes. - if ast_kind(target) == EXPR_NONE && ast_a(target) >= 0 { - target = ast_a(target); - } - val_node := ast_b(node); - val_var := gen_expr(val_node); - val_var = force_if_thunk(val_var); - if ast_kind(target) == EXPR_IDENT { - name_idx := ast_int_val(target); - lv := find_local(name_idx); - if lv >= 0 { - if irv_type(lv) == TI_DYN { + if ast_kind(target) == EXPR_NONE && ast_a(target) >= 0: + target = ast_a(target) + val_node := ast_b(node) + val_var := gen_expr(val_node) + val_var = force_if_thunk(val_var) + if ast_kind(target) == EXPR_IDENT: + name_idx := ast_int_val(target) + lv := find_local(name_idx) + if lv >= 0: + if irv_type(lv) == TI_DYN: // Dyn variable assignment: pack value with type tag - tag := irv_type(val_var); - if tag < 0 { tag = TI_INT; } - emit(IR_DYN_PACK, lv, val_var, tag, 0, 0); - } else { - val_var = dex_store_adjust(lv, val_var, val_node); + tag := irv_type(val_var) + if tag < 0: + tag = TI_INT + emit(IR_DYN_PACK, lv, val_var, tag, 0, 0) + else: + val_var = dex_store_adjust(lv, val_var, val_node) // F11:切片长度沿赋值传播(字面量/运行时界长度变量同步;源无记录则清除) - slice_len_copy_to(lv, val_var); + slice_len_copy_to(lv, val_var) // (A) 批(INV-1):取址槽恒装箱(同 LET 写点;名字索引判定) - rpv0 := irv_rep(lv); - forced2 := g_optrep_on != 0 && rpv0 >= 0 && addr_taken_of(name_idx) != 0; - if forced2 != 0 { val_var = box_for_slot_flag(val_node, val_var, 1); } -emit(IR_STORE, -1, lv, val_var, 0, 0); + rpv0 := irv_rep(lv) + forced2 := g_optrep_on != 0 && rpv0 >= 0 && addr_taken_of(name_idx) != 0 + if forced2 != 0: + val_var = box_for_slot_flag(val_node, val_var, 1) + emit(IR_STORE, -1, lv, val_var, 0, 0) // 可选表示(R2 P4 Task 5):赋值写点置位(同 LET——解包点据此分派) - if rpv0 >= 0 { - if forced2 != 0 { emit_rep_set(rpv0, oe_boxed()); } - else { emit_rep_set(rpv0, rep_enc_of_expr(val_node, val_var)); } - } - } - } else { - gv := find_global(name_idx); - if gv >= 0 { - val_var = dex_store_adjust(gv, val_var, val_node); + if rpv0 >= 0: + if forced2 != 0: + emit_rep_set(rpv0, oe_boxed()) + else: + emit_rep_set(rpv0, rep_enc_of_expr(val_node, val_var)) + else: + gv := find_global(name_idx) + if gv >= 0: + val_var = dex_store_adjust(gv, val_var, val_node) // 容量批 T2:可选全局槽写点规范化(裸值装箱;目标不可选 ⇒ 零 IR) - if g_optrep_on != 0 { val_var = box_for_optional_slot(val_node, val_var, global_decl_ti(name_idx)); } - emit(IR_STORE, -1, gv, val_var, 0, 0); - } - } - return val_var; - } - if ast_kind(target) == EXPR_FIELD { - obj_var := gen_expr(ast_a(target)); - obj_var = force_if_thunk(obj_var); - fi := ast_data(target); + if g_optrep_on != 0: + val_var = box_for_optional_slot(val_node, val_var, global_decl_ti(name_idx)) + emit(IR_STORE, -1, gv, val_var, 0, 0) + return val_var + if ast_kind(target) == EXPR_FIELD: + obj_var := gen_expr(ast_a(target)) + obj_var = force_if_thunk(obj_var) + fi := ast_data(target) // 容量批 T2:可选字段写点规范化(字段声明类型取自 checker 记的 ast_c 结构体名) - val_var = dex_slot_norm(val_var); // apx 批 T3:聚合面恒精确(§0 推论);先归形式后装箱 - if g_optrep_on != 0 { val_var = box_for_optional_slot(val_node, val_var, field_ti_of_node(target, fi)); } - emit(IR_STORE_FIELD, -1, obj_var, val_var, fi, 0); - return val_var; - } - if ast_kind(target) == EXPR_INDEX { - arr_var := gen_expr(ast_a(target)); - arr_var = force_if_thunk(arr_var); - idx_node := ast_b(target); + val_var = dex_slot_norm(val_var) // apx 批 T3:聚合面恒精确(§0 推论);先归形式后装箱 + if g_optrep_on != 0: + val_var = box_for_optional_slot(val_node, val_var, field_ti_of_node(target, fi)) + emit(IR_STORE_FIELD, -1, obj_var, val_var, fi, 0) + return val_var + if ast_kind(target) == EXPR_INDEX: + arr_var := gen_expr(ast_a(target)) + arr_var = force_if_thunk(arr_var) + idx_node := ast_b(target) // 容量批 T2:可选元素写点规范化(元素类型 = 数组/切片声明类型的内层; // 全局数组的声明面在 g_global_lets ⇒ ident 形目标回退查全局声明) - et := elem_ti_of(arr_var); - if et < 0 { - anode := ast_a(target); - if anode >= 0 && ast_kind(anode) == EXPR_IDENT { - et = elem_ti_of_decl(global_decl_ti(ast_int_val(anode))); - } - } - val_var = dex_slot_norm(val_var); // apx 批 T3:元素槽恒精确 - if g_optrep_on != 0 { val_var = box_for_optional_slot(val_node, val_var, et); } + et := elem_ti_of(arr_var) + if et < 0: + anode := ast_a(target) + if anode >= 0 && ast_kind(anode) == EXPR_IDENT: + et = elem_ti_of_decl(global_decl_ti(ast_int_val(anode))) + val_var = dex_slot_norm(val_var) // apx 批 T3:元素槽恒精确 + if g_optrep_on != 0: + val_var = box_for_optional_slot(val_node, val_var, et) // F1:写路径越界守卫钩子(修复前完全没有——见 compcert-round4 F1) - arr_len_lit : ., mut = arr_len_lit_of(arr_var); - if ast_kind(idx_node) == EXPR_INT { - emit_string_lit_bounds(arr_var, ast_int_val(idx_node)); - emit_slice_lit_bounds(arr_var, ast_int_val(idx_node)); - if pass_before_array_access(arr_var, -1, ast_int_val(idx_node), arr_len_lit) == 0 { - emit(IR_STORE_INDEX, -1, arr_var, val_var, ast_int_val(idx_node), 0); - } - } else { - idx_var := gen_expr(idx_node); - idx_var = force_if_thunk(idx_var); - emit_slice_bounds(arr_var, idx_var); - if pass_before_array_access(arr_var, idx_var, -1, arr_len_lit) == 0 { - emit(IR_STORE_INDEX_VAR, val_var, arr_var, idx_var, 0, 0); - } - } - return val_var; - } - if ast_kind(target) == EXPR_UNARY && ast_c(target) == UOP_DEREF { - ptr_var := gen_expr(ast_a(target)); - ptr_var = force_if_thunk(ptr_var); + arr_len_lit : ., mut = arr_len_lit_of(arr_var) + if ast_kind(idx_node) == EXPR_INT: + emit_string_lit_bounds(arr_var, ast_int_val(idx_node)) + emit_slice_lit_bounds(arr_var, ast_int_val(idx_node)) + if pass_before_array_access(arr_var, -1, ast_int_val(idx_node), arr_len_lit) == 0: + emit(IR_STORE_INDEX, -1, arr_var, val_var, ast_int_val(idx_node), 0) + else: + idx_var := gen_expr(idx_node) + idx_var = force_if_thunk(idx_var) + emit_slice_bounds(arr_var, idx_var) + if pass_before_array_access(arr_var, idx_var, -1, arr_len_lit) == 0: + emit(IR_STORE_INDEX_VAR, val_var, arr_var, idx_var, 0, 0) + return val_var + if ast_kind(target) == EXPR_UNARY && ast_c(target) == UOP_DEREF: + ptr_var := gen_expr(ast_a(target)) + ptr_var = force_if_thunk(ptr_var) // (A) 批(INV-2):**指针写且 pointee 可选 ⇒ 装箱**——一致性由 INV-1(取址槽恒装箱) // 与 E-2(聚合恒装箱)保证;越界面 = REP-2(指针算术)/ extern(登记) // 批 5(opt-dex · R2 序修正):**先归形式、后可选装箱**——装箱载荷须为规范形式; // 反序时 `dex_slot_norm` 落在箱对象(TI_INT)上 = 空转(可选 dex 载荷留 bits)。 - val_var = dex_slot_norm(val_var); // apx 批 T3:pointee 槽恒精确(`*p = d` 实测 RED) - if g_optrep_on != 0 && ti_is_optional(ptr_pointee_type(ptr_var)) != 0 { - val_var = box_for_slot_flag(val_node, val_var, 1); - } - emit(IR_STORE_PTR, -1, ptr_var, val_var, 0, ptr_access_width(ptr_var)); - return val_var; - } - return val_var; - } + val_var = dex_slot_norm(val_var) // apx 批 T3:pointee 槽恒精确(`*p = d` 实测 RED) + if g_optrep_on != 0 && ti_is_optional(ptr_pointee_type(ptr_var)) != 0: + val_var = box_for_slot_flag(val_node, val_var, 1) + emit(IR_STORE_PTR, -1, ptr_var, val_var, 0, ptr_access_width(ptr_var)) + return val_var + return val_var // Unary operation - if ast_kind(node) == EXPR_UNARY { - op := ast_c(node); - if op == UOP_REF { - inner := ast_a(node); + if ast_kind(node) == EXPR_UNARY: + op := ast_c(node) + if op == UOP_REF: + inner := ast_a(node) // &arr[i]: compute address directly, don't load then take addr - if ast_kind(inner) == EXPR_INDEX { - arr_var := gen_expr(ast_a(inner)); - arr_var = force_if_thunk(arr_var); - idx_var := gen_expr(ast_b(inner)); - idx_var = force_if_thunk(idx_var); - elem_ti : ., mut = TI_INT; + if ast_kind(inner) == EXPR_INDEX: + arr_var := gen_expr(ast_a(inner)) + arr_var = force_if_thunk(arr_var) + idx_var := gen_expr(ast_b(inner)) + idx_var = force_if_thunk(idx_var) + elem_ti : ., mut = TI_INT // (A) 批:元素类型**声见面优先**(T2 的 elem_ti_of:decl 表优先,退回运行期类型) - de := elem_ti_of(arr_var); - if de >= 0 { elem_ti = de; } - else { - arr_ti := irv_type(arr_var); - if arr_ti >= 0 { - arr_kind := get_type_kind(arr_ti); - if arr_kind == TYP_ARRAY || arr_kind == TYP_SLICE { - elem_ti = get_type_data(arr_ti); - } - } - } + de := elem_ti_of(arr_var) + if de >= 0: + elem_ti = de + else: + arr_ti := irv_type(arr_var) + if arr_ti >= 0: + arr_kind := get_type_kind(arr_ti) + if arr_kind == TYP_ARRAY || arr_kind == TYP_SLICE: + elem_ti = get_type_data(arr_ti) // S3 同批(2026-09-20,裁 (甲)):`&arr[i]` 与 `&x` 是**同一种语法现象(取址)** ⇒ 同判 // **`TYP_REF`**。两套模型并存(`&x`=REF 而 `&arr[i]`=PTR)= 本批在收的「声明与事实不符」的变体。 // **checker 侧已被 S1 覆盖**(`UOP_REF` 对非 `EXPR_IDENT` 操作数走 `else` 分支后同样 // `return alloc_type(TYP_REF, inner, is_mut)`)⇒ **本处是 ir_gen 侧唯一剩下的点**。 // `extra` 同 `&x`:取 `is_mut`(`&mut arr[i]` 与 `&arr[i]` 须同 `&x`/`&mut x` 一样可分)。 - v := new_ir_var("addr", alloc_type(TYP_REF, elem_ti, ast_int_val(node))); - emit(IR_ADDR_INDEX, v, arr_var, idx_var, 3, 0); - return v; - } - op_var := gen_expr(ast_a(node)); - op_var = force_if_thunk(op_var); + v := new_ir_var("addr", alloc_type(TYP_REF, elem_ti, ast_int_val(node))) + emit(IR_ADDR_INDEX, v, arr_var, idx_var, 3, 0) + return v + op_var := gen_expr(ast_a(node)) + op_var = force_if_thunk(op_var) // (A) 批:pointee 类型**声见面优先**(字面量推出的 IR 类型对可选槽退化为对象占位), // 且**取址槽(INV-1 恒装箱)⇒ pointee 记为 TYP_OPTIONAL**(装载侧 W5 据此装箱; // 非可选取址槽不受影响) // 取址目标的**源名索引**取自操作数(EXPR_UNARY 的 int_val 是 is_mut 位,不是名索引) - ni_src : ., mut = -1; - if ast_kind(ast_a(node)) == EXPR_IDENT { ni_src = ast_int_val(ast_a(node)); } - pti := slot_decl_ti(op_var); - if pti < 0 { pti = irv_type(op_var); } - if ni_src >= 0 { + ni_src : ., mut = -1 + if ast_kind(ast_a(node)) == EXPR_IDENT: + ni_src = ast_int_val(ast_a(node)) + pti := slot_decl_ti(op_var) + if pti < 0: + pti = irv_type(op_var) + if ni_src >= 0: // 全局槽:声明面在 g_global_lets(E-2 的 global_decl_ti)——局部表未登记全局。 // **只升级不降级**:全局声明可选 ⇒ 记可选;否则保留上面已得的类型 // (全局 IR var 本身可能已是可选类型,直接取声明面会把它覆盖成非可选 ⇒ W5 不装箱)。 - gti := global_decl_ti(ni_src); - if ti_is_optional(gti) != 0 { pti = gti; } - } - if g_optrep_on != 0 && ni_src >= 0 && addr_taken_of(ni_src) != 0 { + gti := global_decl_ti(ni_src) + if ti_is_optional(gti) != 0: + pti = gti + if g_optrep_on != 0 && ni_src >= 0 && addr_taken_of(ni_src) != 0: // 取址目标具备可选能力(有表示位 / 声明为可选)⇒ pointee 记 TYP_OPTIONAL: // 装载侧 IR_STORE_PTR(W5)据 pointee 是否可选决定装箱。非可选槽 rep<0 // 且声明非可选 ⇒ 两种形态都不触发(零足迹)。 - if irv_rep(op_var) >= 0 || ti_is_optional(pti) != 0 { - if ti_is_optional(pti) == 0 { - inner3 := pti; if inner3 < 0 { inner3 = TI_INT; } - pti = alloc_type(TYP_OPTIONAL, inner3, 0); - } - } - } + if irv_rep(op_var) >= 0 || ti_is_optional(pti) != 0: + if ti_is_optional(pti) == 0: + inner3 := pti + if inner3 < 0: + inner3 = TI_INT + pti = alloc_type(TYP_OPTIONAL, inner3, 0) // S1 同批(2026-09-20):**IR 变量型也必须一起改**——`checker` 侧只决定语义视图, // 而 `region_check` / `provenance_verify` / `ptr_analysis` 读的是 **`irv_type()`** // (本行)。只改 `checker.cr:2966` ⇒ 三道安全门看到的仍是 `TYP_PTR` ⇒ // S6 的 (a) 扩法会**对着一个永远不出现的 kind 生效**(静默空转)。 // `extra` 同 checker:取 `is_mut`(即下面 emit 的 s2 实参,同一个值)。 - v := new_ir_var("ref", alloc_type(TYP_REF, pti, ast_int_val(node))); - emit(IR_REF, v, op_var, ast_int_val(node), 0, 0); - return v; - } - if op == UOP_DEREF { - inner_var := gen_expr(ast_a(node)); - inner_var = force_if_thunk(inner_var); - dv := new_ir_var("deref", ptr_pointee_type(inner_var)); - emit(IR_DEREF, dv, inner_var, -1, 0, ptr_access_width(inner_var)); - return dv; - } - op_var := gen_expr(ast_a(node)); - op_var = force_if_thunk(op_var); - vt : ., mut = TI_INT; - if op == UOP_NEG { + v := new_ir_var("ref", alloc_type(TYP_REF, pti, ast_int_val(node))) + emit(IR_REF, v, op_var, ast_int_val(node), 0, 0) + return v + if op == UOP_DEREF: + inner_var := gen_expr(ast_a(node)) + inner_var = force_if_thunk(inner_var) + dv := new_ir_var("deref", ptr_pointee_type(inner_var)) + emit(IR_DEREF, dv, inner_var, -1, 0, ptr_access_width(inner_var)) + return dv + op_var := gen_expr(ast_a(node)) + op_var = force_if_thunk(op_var) + vt : ., mut = TI_INT + if op == UOP_NEG: // 一元负保持数值操作数类型:dex 精确(TI_DEX_S)→ 缩放整数取负 ✓; // dex apx(TI_DEX)→ 整型取负(binary64 符号位翻转未实现——既有 apx // 限制,数值迁移 Task 4 文档化;apx 负值请用 0 - x 表达) - ot := irv_type(op_var); - if ot == TI_DEX_S || ot == TI_DEX || ot == TI_INT { vt = ot; } - } - v := new_ir_var("un", vt); - emit(IR_UNARY, v, op_var, 0, op, 0); - return v; - } + ot := irv_type(op_var) + if ot == TI_DEX_S || ot == TI_DEX || ot == TI_INT: + vt = ot + v := new_ir_var("un", vt) + emit(IR_UNARY, v, op_var, 0, op, 0) + return v // Function call - if ast_kind(node) == EXPR_GO { - body := ast_b(node); - range_node := ast_data(node); // 0 = single, EXPR_RANGE node = range go - if range_node <= 0 { + if ast_kind(node) == EXPR_GO: + body := ast_b(node) + range_node := ast_data(node) // 0 = single, EXPR_RANGE node = range go + if range_node <= 0: // Single go: emit call to sched_go(@addr(f), arg) // sched_go creates a goroutine via g_new + sched_enqueue and returns a channel - if ast_kind(body) == EXPR_CALL { - func_node := ast_a(body); - first_arg := ast_b(body); - func_ni : ., mut = -1; - if ast_kind(func_node) == EXPR_IDENT { - func_ni = ast_int_val(func_node); - } else if ast_kind(func_node) == EXPR_FIELD { - func_ni = ast_data(body); - } + if ast_kind(body) == EXPR_CALL: + func_node := ast_a(body) + first_arg := ast_b(body) + func_ni : ., mut = -1 + if ast_kind(func_node) == EXPR_IDENT: + func_ni = ast_int_val(func_node) + else if ast_kind(func_node) == EXPR_FIELD: + func_ni = ast_data(body) // Evaluate the first argument (if any) - arg_var : ., mut = -1; - if first_arg >= 0 { - arg_var = gen_expr(ast_a(first_arg)); - arg_var = force_if_thunk(arg_var); - } + arg_var : ., mut = -1 + if first_arg >= 0: + arg_var = gen_expr(ast_a(first_arg)) + arg_var = force_if_thunk(arg_var) // Function address via IR_FNADDR — the movabs placeholder is // patched to the function's absolute VA at ELF link time // (elf.cr Phase 3). goroutine_entry_wrapper reads it back // from G+56 (saved_fn) and calls saved_fn(saved_arg). - fnaddr_var := new_ir_var("_go_fnaddr", TI_INT); - emit(IR_FNADDR, fnaddr_var, func_ni, 0, 0, 0); + fnaddr_var := new_ir_var("_go_fnaddr", TI_INT) + emit(IR_FNADDR, fnaddr_var, func_ni, 0, 0, 0) // Create contiguous argument variables for the sched_go call: // arg0 = fn address, arg1 = arg value (0 when no arg) - packed0 := new_ir_var("_go_fna", TI_INT); - emit(IR_STORE, -1, packed0, fnaddr_var, 0, 0); - packed1 := new_ir_var("_go_arg", TI_INT); - if arg_var >= 0 { - emit(IR_STORE, -1, packed1, arg_var, 0, 0); - } else { - emit(IR_CONST, packed1, 0, 0, 0, TI_INT); - } - dest := new_ir_var("_go_ch", TI_INT); - sched_go_ni := str_intern("sched_go"); - emit(IR_CALL, dest, packed0, 2, sched_go_ni, TI_INT); - return dest; - } - return gen_expr(body); - } + packed0 := new_ir_var("_go_fna", TI_INT) + emit(IR_STORE, -1, packed0, fnaddr_var, 0, 0) + packed1 := new_ir_var("_go_arg", TI_INT) + if arg_var >= 0: + emit(IR_STORE, -1, packed1, arg_var, 0, 0) + else: + emit(IR_CONST, packed1, 0, 0, 0, TI_INT) + dest := new_ir_var("_go_ch", TI_INT) + sched_go_ni := str_intern("sched_go") + emit(IR_CALL, dest, packed0, 2, sched_go_ni, TI_INT) + return dest + return gen_expr(body) // Range go: go var start..end expr → collect results into array - iter_ni := ast_c(node); // loop variable name - range_count := ast_b(range_node) - ast_a(range_node); - if range_count <= 0 { return -1; } + iter_ni := ast_c(node) // loop variable name + range_count := ast_b(range_node) - ast_a(range_node) + if range_count <= 0: + return -1 // Allocate results array - arr_var := new_ir_var("go_arr", TI_UNIT); - emit(IR_ALLOC_ARRAY, arr_var, range_count, 0, 0, 0); + arr_var := new_ir_var("go_arr", TI_UNIT) + emit(IR_ALLOC_ARRAY, arr_var, range_count, 0, 0, 0) // Spawn each iteration - if ast_kind(body) == EXPR_CALL { - func_node := ast_a(body); - func_ni : ., mut = -1; - if ast_kind(func_node) == EXPR_IDENT { func_ni = ast_int_val(func_node); } + if ast_kind(body) == EXPR_CALL: + func_node := ast_a(body) + func_ni : ., mut = -1 + if ast_kind(func_node) == EXPR_IDENT: + func_ni = ast_int_val(func_node) // Extract the call arg that uses the iter variable - fi : ., mut = 0; - loop { if fi >= range_count { break; } + fi : ., mut = 0 + loop: + if fi >= range_count: + break // For each i, spawn with i as the iter var's value - val_var := new_ir_var("go_val", TI_UNIT); - emit(IR_CONST, val_var, ast_a(range_node) + fi, 0, 0, TI_INT); - dest2 := new_ir_var("go_fut", TI_UNIT); - emit(IR_SPAWN, dest2, val_var, 1, func_ni, -1); - emit(IR_STORE_INDEX, -1, arr_var, dest2, fi, 0); - fi = fi + 1; } - } - return arr_var; - } - - if ast_kind(node) == EXPR_CALL { - func_node := ast_a(node); - first_arg := ast_b(node); - arg_count := ast_c(node); - call_flags := ast_type_val(node); - is_module_call := call_flags == CALL_FLAG_MODULE || call_flags == CALL_FLAG_MODULE + CALL_FLAG_INLINE; - is_inline_call := call_flags == CALL_FLAG_INLINE || call_flags == CALL_FLAG_MODULE + CALL_FLAG_INLINE; - arg_vars : string, mut; arg_vars_cap : int, mut; + val_var := new_ir_var("go_val", TI_UNIT) + emit(IR_CONST, val_var, ast_a(range_node) + fi, 0, 0, TI_INT) + dest2 := new_ir_var("go_fut", TI_UNIT) + emit(IR_SPAWN, dest2, val_var, 1, func_ni, -1) + emit(IR_STORE_INDEX, -1, arr_var, dest2, fi, 0) + fi = fi + 1 + return arr_var + + if ast_kind(node) == EXPR_CALL: + func_node := ast_a(node) + first_arg := ast_b(node) + arg_count := ast_c(node) + call_flags := ast_type_val(node) + is_module_call := call_flags == CALL_FLAG_MODULE || call_flags == CALL_FLAG_MODULE + CALL_FLAG_INLINE + is_inline_call := call_flags == CALL_FLAG_INLINE || call_flags == CALL_FLAG_MODULE + CALL_FLAG_INLINE + arg_vars : string, mut + arg_vars_cap : int, mut // R2 P4 Task 5:实参**节点**并行表(表示面写信道按实参位判表示需要节点—— // 值 var 的类型不足以区分裸 T 与装箱 T?;方法调用时 arg 0 = 接收者节点) - arg_nodes : string, mut; arg_nodes_cap : int, mut; - ac : ., mut = 0; - arg_vars = alloc(64 * 8); arg_vars_cap = 64; - arg_nodes = alloc(64 * 8); arg_nodes_cap = 64; - func_ni : ., mut = -1; + arg_nodes : string, mut + arg_nodes_cap : int, mut + ac : ., mut = 0 + arg_vars = alloc(64 * 8) + arg_vars_cap = 64 + arg_nodes = alloc(64 * 8) + arg_nodes_cap = 64 + func_ni : ., mut = -1 // @builtin(args) — parser wraps @foo(args) as EXPR_CALL(func=EXPR_AT, ...) // so we detect EXPR_AT here and handle it before the normal call dispatch. - if ast_kind(func_node) == EXPR_AT { - name_ni := ast_a(func_node); - name := istr_get(name_ni); + if ast_kind(func_node) == EXPR_AT: + name_ni := ast_a(func_node) + name := istr_get(name_ni) // @sizeOf(T): emit IR_CONST with type size - if str_eq(name, "sizeOf") != 0 { - ti := ti_from_type_expr(ast_a(first_arg)); - sz := type_size(ti); - v := new_ir_var("_sizeof", TI_INT); - emit(IR_CONST, v, sz, 0, 0, TI_INT); - return v; - } + if str_eq(name, "sizeOf") != 0: + ti := ti_from_type_expr(ast_a(first_arg)) + sz := type_size(ti) + v := new_ir_var("_sizeof", TI_INT) + emit(IR_CONST, v, sz, 0, 0, TI_INT) + return v // @alignOf(T): emit IR_CONST with type alignment - if str_eq(name, "alignOf") != 0 { - ti := ti_from_type_expr(ast_a(first_arg)); - al := type_align(ti); - v := new_ir_var("_alignof", TI_INT); - emit(IR_CONST, v, al, 0, 0, TI_INT); - return v; - } + if str_eq(name, "alignOf") != 0: + ti := ti_from_type_expr(ast_a(first_arg)) + al := type_align(ti) + v := new_ir_var("_alignof", TI_INT) + emit(IR_CONST, v, al, 0, 0, TI_INT) + return v // @fields(T): emit string array of field names - if str_eq(name, "fields") != 0 { - ti := ti_from_type_expr(ast_a(first_arg)); - si := ti_resolve_struct(ti); - v := new_ir_var("_fields", TI_STR); - if si >= 0 { - fc := si_field_count(si); + if str_eq(name, "fields") != 0: + ti := ti_from_type_expr(ast_a(first_arg)) + si := ti_resolve_struct(ti) + v := new_ir_var("_fields", TI_STR) + if si >= 0: + fc := si_field_count(si) // Build a string constant: comma-separated field names - fields_str : ., mut = ""; - fi : ., mut = 0; - loop { - if fi >= fc { break; } - fname := istr_get(si_field_name(si, fi)); - if fi > 0 { fields_str = fields_str + ","; } - fields_str = fields_str + fname; - fi = fi + 1; - } - ni := str_intern(fields_str); - track_str(ni); - emit(IR_CONST, v, ni, 0, 0, TI_STR); - } else { - emit(IR_CONST, v, 0, 0, 0, TI_STR); - } - return v; - } + fields_str : ., mut = "" + fi : ., mut = 0 + loop: + if fi >= fc: + break + fname := istr_get(si_field_name(si, fi)) + if fi > 0: + fields_str = fields_str + "," + fields_str = fields_str + fname + fi = fi + 1 + ni := str_intern(fields_str) + track_str(ni) + emit(IR_CONST, v, ni, 0, 0, TI_STR) + else: + emit(IR_CONST, v, 0, 0, 0, TI_STR) + return v // @hasField(T, name): check field existence - if str_eq(name, "hasField") != 0 { - ti := ti_from_type_expr(ast_a(first_arg)); - name_arg := ast_b(first_arg); - name_expr := ast_a(name_arg); - fn_name := istr_get(ast_int_val(name_expr)); - exists := ti_has_field(ti, fn_name); - v := new_ir_var("_hasf", TI_BOOL); - emit(IR_CONST, v, exists, 0, 0, TI_BOOL); - return v; - } + if str_eq(name, "hasField") != 0: + ti := ti_from_type_expr(ast_a(first_arg)) + name_arg := ast_b(first_arg) + name_expr := ast_a(name_arg) + fn_name := istr_get(ast_int_val(name_expr)) + exists := ti_has_field(ti, fn_name) + v := new_ir_var("_hasf", TI_BOOL) + emit(IR_CONST, v, exists, 0, 0, TI_BOOL) + return v // @field(T, name): get field offset - if str_eq(name, "field") != 0 { - ti := ti_from_type_expr(ast_a(first_arg)); - name_arg := ast_b(first_arg); - name_expr := ast_a(name_arg); - fn_name := istr_get(ast_int_val(name_expr)); - off := ti_field_offset(ti, fn_name); - v := new_ir_var("_fldoff", TI_INT); - emit(IR_CONST, v, off, 0, 0, TI_INT); - return v; - } + if str_eq(name, "field") != 0: + ti := ti_from_type_expr(ast_a(first_arg)) + name_arg := ast_b(first_arg) + name_expr := ast_a(name_arg) + fn_name := istr_get(ast_int_val(name_expr)) + off := ti_field_offset(ti, fn_name) + v := new_ir_var("_fldoff", TI_INT) + emit(IR_CONST, v, off, 0, 0, TI_INT) + return v // @typeInfo(T): emit type description string - if str_eq(name, "typeInfo") != 0 { - ti := ti_from_type_expr(ast_a(first_arg)); - type_str : ., mut = ""; - k := get_type_kind(ti); - if k == TYP_NAMED { - name_ni := get_type_data(ti); - type_str = istr_get(name_ni); - } else if ti == TI_INT { type_str = "int"; } - else if ti == TI_BOOL { type_str = "bool"; } - else if ti == TI_DEX || ti == TI_DEX_S { type_str = "dex"; } - else if ti == TI_STR { type_str = "string"; } - else if ti == TI_CHAR { type_str = "char"; } - else if ti == TI_UNIT { type_str = "unit"; } - else { type_str = "unknown"; } - ni := str_intern(type_str); - track_str(ni); - v := new_ir_var("_tinfo", TI_STR); - emit(IR_CONST, v, ni, 0, 0, TI_STR); - return v; - } + if str_eq(name, "typeInfo") != 0: + ti := ti_from_type_expr(ast_a(first_arg)) + type_str : ., mut = "" + k := get_type_kind(ti) + if k == TYP_NAMED: + name_ni := get_type_data(ti) + type_str = istr_get(name_ni) + else if ti == TI_INT: + type_str = "int" + else if ti == TI_BOOL: + type_str = "bool" + else if ti == TI_DEX || ti == TI_DEX_S: + type_str = "dex" + else if ti == TI_STR: + type_str = "string" + else if ti == TI_CHAR: + type_str = "char" + else if ti == TI_UNIT: + type_str = "unit" + else: + type_str = "unknown" + ni := str_intern(type_str) + track_str(ni) + v := new_ir_var("_tinfo", TI_STR) + emit(IR_CONST, v, ni, 0, 0, TI_STR) + return v // @raw_int(expr): 显式转换——dex 表达式 → 其定点缩放整数原值(int)。 // 数值迁移 Task 4:dex.cr 的打印等辅助以此访问缩放表示的原始整数; // apx 值(TI_DEX bits)先按边界规则转 scaled(F2I(bits×S))。 // 结果必须复制为 TI_INT 定型变量——直接返回内层变量会携带其 dex 类型 // (TI_DEX_S),后续 int 运算被误分派到 dex 精确路径。 - if str_eq(name, "raw_int") != 0 { - inner_var := gen_expr(ast_a(first_arg)); - inner_var = force_if_thunk(inner_var); - if irv_type(inner_var) == TI_DEX { - inner_var = dex_bits_to_scaled(inner_var); - } - rv := new_ir_var("_raw", TI_INT); - emit(IR_STORE, -1, rv, inner_var, 0, 0); - return rv; - } + if str_eq(name, "raw_int") != 0: + inner_var := gen_expr(ast_a(first_arg)) + inner_var = force_if_thunk(inner_var) + if irv_type(inner_var) == TI_DEX: + inner_var = dex_bits_to_scaled(inner_var) + rv := new_ir_var("_raw", TI_INT) + emit(IR_STORE, -1, rv, inner_var, 0, 0) + return rv // @comptime(expr): force compile-time evaluation - if str_eq(name, "comptime") != 0 { - inner_expr := ast_a(first_arg); + if str_eq(name, "comptime") != 0: + inner_expr := ast_a(first_arg) // Generate IR for the inner expression - inner_var := gen_expr(inner_expr); - inner_var = force_if_thunk(inner_var); + inner_var := gen_expr(inner_expr) + inner_var = force_if_thunk(inner_var) // If the inner expression is a constant, it's already folded. // For runtime-dependent exprs, we'd need the interpreter. // For now: gen IR and return — the existing constant folding // (inline IR_CONST from @sizeOf etc.) handles pure compile-time exprs. // Future: invoke ir_interpret_expr for true forced evaluation. - return inner_var; - } + return inner_var // @inline(fn): emit IR_INLINE hint - if str_eq(name, "inline") != 0 { - fn_var := gen_expr(ast_a(first_arg)); - fn_var = force_if_thunk(fn_var); - emit(IR_INLINE, -1, fn_var, 0, 0, 0); - return fn_var; - } + if str_eq(name, "inline") != 0: + fn_var := gen_expr(ast_a(first_arg)) + fn_var = force_if_thunk(fn_var) + emit(IR_INLINE, -1, fn_var, 0, 0, 0) + return fn_var // @NoBoundsCheck: emit annotation (no args) - if str_eq(name, "NoBoundsCheck") != 0 { - emit(IR_NO_BOUNDS_CHECK, -1, 0, 0, 0, 0); - return -1; - } + if str_eq(name, "NoBoundsCheck") != 0: + emit(IR_NO_BOUNDS_CHECK, -1, 0, 0, 0, 0) + return -1 // @fast: emit annotation (no args) - if str_eq(name, "fast") != 0 { - emit(IR_FAST, -1, 0, 0, 0, 0); - return -1; - } + if str_eq(name, "fast") != 0: + emit(IR_FAST, -1, 0, 0, 0, 0) + return -1 // @unroll(n): emit loop unroll hint - if str_eq(name, "unroll") != 0 { - unroll_count := ast_int_val(ast_a(first_arg)); - emit(IR_UNROLL, -1, unroll_count, 0, 0, 0); - return -1; - } + if str_eq(name, "unroll") != 0: + unroll_count := ast_int_val(ast_a(first_arg)) + emit(IR_UNROLL, -1, unroll_count, 0, 0, 0) + return -1 // @section(name): emit code section hint - if str_eq(name, "section") != 0 { - name_expr := ast_a(ast_a(first_arg)); - name_ni := ast_int_val(name_expr); - track_str(name_ni); - emit(IR_SECTION, -1, name_ni, 0, 0, 0); - return -1; - } + if str_eq(name, "section") != 0: + name_expr := ast_a(ast_a(first_arg)) + name_ni := ast_int_val(name_expr) + track_str(name_ni) + emit(IR_SECTION, -1, name_ni, 0, 0, 0) + return -1 // @addr(fn): get function address (patched at ELF link time) - if str_eq(name, "addr") != 0 { - fn_expr := ast_a(first_arg); - if ast_kind(fn_expr) == EXPR_IDENT { - fn_ni := ast_int_val(fn_expr); - v := new_ir_var("_fnaddr", TI_INT); - emit(IR_FNADDR, v, fn_ni, 0, 0, 0); - return v; - } - return -1; - } + if str_eq(name, "addr") != 0: + fn_expr := ast_a(first_arg) + if ast_kind(fn_expr) == EXPR_IDENT: + fn_ni := ast_int_val(fn_expr) + v := new_ir_var("_fnaddr", TI_INT) + emit(IR_FNADDR, v, fn_ni, 0, 0, 0) + return v + return -1 // ── 2(a) 视图内建:**真直通**(零指令、零新变量)——同一个 64 位字,只换看法 ── // 为什么**不**沿用本项目 `@raw_int` 的「新建变量 + IR_STORE」写法: @@ -2163,41 +2232,61 @@ emit(IR_STORE, -1, lv, val_var, 0, 0); // 类型在哪换:**checker 侧**(`@str_of` 返回 TI_STR / `@ptr_of` 返回 TI_INT), // 即「表达式的类型」而不是「变量的类型」;调用边界按**被调函数形参类型**编组, // int/string 同属 GP 字 ⇒ 两侧一致。 - if str_eq(name, "str_of") != 0 || str_eq(name, "ptr_of") != 0 { - inner := gen_expr(ast_a(first_arg)); - return force_if_thunk(inner); - } + if str_eq(name, "str_of") != 0 || str_eq(name, "ptr_of") != 0: + inner := gen_expr(ast_a(first_arg)) + return force_if_thunk(inner) - return -1; - } + return -1 // Module or method call: obj.method(args) - if ast_kind(func_node) == EXPR_FIELD { - func_ni = ast_data(node); // function name (set by checker for module calls) - if !is_module_call { + if ast_kind(func_node) == EXPR_FIELD: + func_ni = ast_data(node) // function name (set by checker for module calls) + if !is_module_call: // Method call: self is first arg - obj_node := ast_a(func_node); - self_var := gen_expr(obj_node); - self_var = force_if_thunk(self_var); - if ac >= arg_vars_cap { nc := arg_vars_cap * 2; nb := alloc(nc * 8); _dyncpy(arg_vars, arg_vars_cap * 8, nb); arg_vars = nb; arg_vars_cap = nc; } w64(arg_vars, ac * 8, self_var); - if ac >= arg_nodes_cap { nc := arg_nodes_cap * 2; nb := alloc(nc * 8); _dyncpy(arg_nodes, arg_nodes_cap * 8, nb); arg_nodes = nb; arg_nodes_cap = nc; } w64(arg_nodes, ac * 8, obj_node); - ac = ac + 1; - } - } else if ast_kind(func_node) == EXPR_IDENT { - func_ni = ast_int_val(func_node); - } + obj_node := ast_a(func_node) + self_var := gen_expr(obj_node) + self_var = force_if_thunk(self_var) + if ac >= arg_vars_cap: + nc := arg_vars_cap * 2 + nb := alloc(nc * 8) + _dyncpy(arg_vars, arg_vars_cap * 8, nb) + arg_vars = nb + arg_vars_cap = nc + w64(arg_vars, ac * 8, self_var) + if ac >= arg_nodes_cap: + nc := arg_nodes_cap * 2 + nb := alloc(nc * 8) + _dyncpy(arg_nodes, arg_nodes_cap * 8, nb) + arg_nodes = nb + arg_nodes_cap = nc + w64(arg_nodes, ac * 8, obj_node) + ac = ac + 1 + else if ast_kind(func_node) == EXPR_IDENT: + func_ni = ast_int_val(func_node) // Generate remaining args (walk EXPR_ARG chain) - an : ., mut = first_arg; - loop { - if an < 0 { break; } - arg_var := gen_expr(ast_a(an)); - arg_var = force_if_thunk(arg_var); - if ac >= arg_vars_cap { nc := arg_vars_cap * 2; nb := alloc(nc * 8); _dyncpy(arg_vars, arg_vars_cap * 8, nb); arg_vars = nb; arg_vars_cap = nc; } w64(arg_vars, ac * 8, arg_var); - if ac >= arg_nodes_cap { nc := arg_nodes_cap * 2; nb := alloc(nc * 8); _dyncpy(arg_nodes, arg_nodes_cap * 8, nb); arg_nodes = nb; arg_nodes_cap = nc; } w64(arg_nodes, ac * 8, ast_a(an)); - ac = ac + 1; - an = ast_b(an); - } + an : ., mut = first_arg + loop: + if an < 0: + break + arg_var := gen_expr(ast_a(an)) + arg_var = force_if_thunk(arg_var) + if ac >= arg_vars_cap: + nc := arg_vars_cap * 2 + nb := alloc(nc * 8) + _dyncpy(arg_vars, arg_vars_cap * 8, nb) + arg_vars = nb + arg_vars_cap = nc + w64(arg_vars, ac * 8, arg_var) + if ac >= arg_nodes_cap: + nc := arg_nodes_cap * 2 + nb := alloc(nc * 8) + _dyncpy(arg_nodes, arg_nodes_cap * 8, nb) + arg_nodes = nb + arg_nodes_cap = nc + w64(arg_nodes, ac * 8, ast_a(an)) + ac = ac + 1 + an = ast_b(an) // dex 边界规则(数值迁移 Task 4 + 终审 M2):dex 参数在调用点按被调方形式对齐—— // Core 函数:一律精确形式(scaled),apx 位模式参数转 scaled(F2I(bits×S)); // extern 函数:C ABI 契约(module.cr:dex 编码 3 = binary64 跨 C 边界), @@ -2213,14 +2302,14 @@ emit(IR_STORE, -1, lv, val_var, 0, 0); // · 实测依据:方法调用 b1/b1b 红 49/15 · 模块限定调用 m1b 红(ELF=4,期望 7) // —— 二者同因(旧门的 `EXPR_IDENT` 硬限制)。 // 批 8(条目 1):环已抽为 `dex_align_call_args`(可复用——重定向后按实例签名再跑一遍) - if func_ni >= 0 { - cfi := find_func(func_ni); - if cfi >= 0 { dex_align_call_args(cfi, ac, arg_vars, arg_nodes, arg_nodes_cap); } - } + if func_ni >= 0: + cfi := find_func(func_ni) + if cfi >= 0: + dex_align_call_args(cfi, ac, arg_vars, arg_nodes, arg_nodes_cap) // Generic function: redirect to monomorphized (specialized) version - if func_ni >= 0 && (ast_kind(func_node) == EXPR_IDENT) { - gen_fi := find_func(func_ni); - if gen_fi >= 0 && fi_generic_count(gen_fi) > 0 { + if func_ni >= 0 && (ast_kind(func_node) == EXPR_IDENT): + gen_fi := find_func(func_ni) + if gen_fi >= 0 && fi_generic_count(gen_fi) > 0: // ─── R2 P3 Task 5(Step 4):实例键类型项化 ─── // 优先:checker 登记的**调用点绑定段**(g_gen_binds;节点 int_val = 段起始+1, // 0 = 无)——按被调方泛型形参**声明序**给 ti,键 = `inst_key_of_ti` 规范结构名 @@ -2228,113 +2317,126 @@ emit(IR_STORE, -1, lv, val_var, 0, 0); // 数一致 + 全绑定 + 全具体(否则回落旧路径;半解实例比旧路径更坏)。 // 回落(旧路径,**逐字保留**):键由**实参 IR 变量类型**拼名串(非原生 → "int" // 兜底),替换走名字路径——`gen_create_instance(func, args, -1)`。 - gc_g := fi_generic_count(gen_fi); - biv := ast_int_val(node); - type_args : ., mut = ""; - bstart : ., mut = -1; - if biv > 0 { - bs := biv - 1; - if bs < g_gen_binds_count { - bcnt := r64(g_gen_binds, bs * 8); - if bcnt == gc_g && bs + 1 + bcnt <= g_gen_binds_count { - ok_b : ., mut = 1; - gi_b : ., mut = 0; - loop { - if gi_b >= bcnt { break; } - bt := r64(g_gen_binds, (bs + 1 + gi_b) * 8); - if bt < 0 { ok_b = 0; break; } - if inst_ti_concrete(bt) == 0 { ok_b = 0; break; } - if inst_type_node_of_ti(bt) < 0 { ok_b = 0; break; } - if gi_b > 0 { type_args = type_args + ","; } - type_args = type_args + inst_key_of_ti(bt); - gi_b = gi_b + 1; - } - if ok_b != 0 { bstart = bs; } - } - } - } - if bstart < 0 { + gc_g := fi_generic_count(gen_fi) + biv := ast_int_val(node) + type_args : ., mut = "" + bstart : ., mut = -1 + if biv > 0: + bs := biv - 1 + if bs < g_gen_binds_count: + bcnt := r64(g_gen_binds, bs * 8) + if bcnt == gc_g && bs + 1 + bcnt <= g_gen_binds_count: + ok_b : ., mut = 1 + gi_b : ., mut = 0 + loop: + if gi_b >= bcnt: + break + bt := r64(g_gen_binds, (bs + 1 + gi_b) * 8) + if bt < 0: + ok_b = 0 + break + if inst_ti_concrete(bt) == 0: + ok_b = 0 + break + if inst_type_node_of_ti(bt) < 0: + ok_b = 0 + break + if gi_b > 0: + type_args = type_args + "," + type_args = type_args + inst_key_of_ti(bt) + gi_b = gi_b + 1 + if ok_b != 0: + bstart = bs + if bstart < 0: // 旧路径:逐实参类型名串(**不得**改动——checker 未给绑定时的唯一退路) - type_args = ""; - ai : ., mut = 0; - loop { - if ai >= ac { break; } - av := r64(arg_vars, ai * 8); - ti := TI_INT; - if av >= 0 { ti = irv_type(av); } - if ai > 0 { type_args = type_args + ","; } - if ti == TI_INT { type_args = type_args + "int"; } - else if ti == TI_STR { type_args = type_args + "string"; } - else if ti == TI_BOOL { type_args = type_args + "bool"; } - else if ti == TI_CHAR { type_args = type_args + "char"; } - else if ti == TI_DEX || ti == TI_DEX_S { type_args = type_args + "dex"; } - else if ti == TI_UNIT { type_args = type_args + "unit"; } - else { type_args = type_args + "int"; } - ai = ai + 1; - } - } + type_args = "" + ai : ., mut = 0 + loop: + if ai >= ac: + break + av := r64(arg_vars, ai * 8) + ti := TI_INT + if av >= 0: + ti = irv_type(av) + if ai > 0: + type_args = type_args + "," + if ti == TI_INT: + type_args = type_args + "int" + else if ti == TI_STR: + type_args = type_args + "string" + else if ti == TI_BOOL: + type_args = type_args + "bool" + else if ti == TI_CHAR: + type_args = type_args + "char" + else if ti == TI_DEX || ti == TI_DEX_S: + type_args = type_args + "dex" + else if ti == TI_UNIT: + type_args = type_args + "unit" + else: + type_args = type_args + "int" + ai = ai + 1 // Find or create specialized function instance - spec_ni : ., mut = -1; - if bstart >= 0 { spec_ni = gen_find_or_create_bind(gen_fi, type_args, bstart); } - else { spec_ni = gen_find_or_create(gen_fi, type_args); } - if spec_ni >= 0 { - func_ni = fi_name(spec_ni); + spec_ni : ., mut = -1 + if bstart >= 0: + spec_ni = gen_find_or_create_bind(gen_fi, type_args, bstart) + else: + spec_ni = gen_find_or_create(gen_fi, type_args) + if spec_ni >= 0: + func_ni = fi_name(spec_ni) // 批 8(条目 1):泛型声明的形参是 `T?`(inner = 泛型参数 ⇒ 判据**假**)⇒ 上面的环 // 对泛型实参空转;重定向后用**实例**形参链(inner = 具体 dex ⇒ 判据真)再跑一遍。 // 幂等性见 `dex_align_call_args` 头注(已转换者 IR 型 = TI_DEX_S ⇒ 不重转)。 - cfi_i := find_func(func_ni); - if cfi_i >= 0 { dex_align_call_args(cfi_i, ac, arg_vars, arg_nodes, arg_nodes_cap); } + cfi_i := find_func(func_ni) + if cfi_i >= 0: + dex_align_call_args(cfi_i, ac, arg_vars, arg_nodes, arg_nodes_cap) // Fall through to normal IR_CALL emission - } - } - } - if is_inline_call && func_ni >= 0 { - emit(IR_INLINE, -1, func_ni, 0, 0, 0); - } + if is_inline_call && func_ni >= 0: + emit(IR_INLINE, -1, func_ni, 0, 0, 0) // Check SO function dispatch (variadic expansion, auto_str, etc.) - handled := dispatch_call(func_ni, ac, arg_vars); - if handled >= 0 { return handled; } + handled := dispatch_call(func_ni, ac, arg_vars) + if handled >= 0: + return handled // For method calls (EXPR_FIELD), func_ni was set by checker // Use it directly - call_ti := ir_call_return_type(func_ni); - dest := new_ir_var("call", call_ti); - first_arg_var := -1; - need_pack : ., mut = 0; - if ac > 0 { - prev := r64(arg_vars, 0 * 8); - first_arg_var = prev; - ai : ., mut = 1; - loop { - if ai >= ac { break; } - cur := r64(arg_vars, ai * 8); - if cur != prev + 1 { need_pack = 1; break; } - prev = cur; - ai = ai + 1; - } - } - if need_pack != 0 { - ai : ., mut = 0; - loop { - if ai >= ac { break; } - av := r64(arg_vars, ai * 8); - at := TI_INT; - if av >= 0 { at = irv_type(av); } - packed := new_ir_var("_arg", at); - if ai == 0 { first_arg_var = packed; } - emit(IR_STORE, -1, packed, av, 0, 0); - ai = ai + 1; - } - } + call_ti := ir_call_return_type(func_ni) + dest := new_ir_var("call", call_ti) + first_arg_var := -1 + need_pack : ., mut = 0 + if ac > 0: + prev := r64(arg_vars, 0 * 8) + first_arg_var = prev + ai : ., mut = 1 + loop: + if ai >= ac: + break + cur := r64(arg_vars, ai * 8) + if cur != prev + 1: + need_pack = 1 + break + prev = cur + ai = ai + 1 + if need_pack != 0: + ai : ., mut = 0 + loop: + if ai >= ac: + break + av := r64(arg_vars, ai * 8) + at := TI_INT + if av >= 0: + at = irv_type(av) + packed := new_ir_var("_arg", at) + if ai == 0: + first_arg_var = packed + emit(IR_STORE, -1, packed, av, 0, 0) + ai = ai + 1 // Dyn method dispatch: receiver is a dyn value, emit dynamic dispatch - if ast_kind(func_node) == EXPR_FIELD && ac > 0 && func_ni >= 0 { - dyn_receiver := first_arg_var; - if dyn_receiver >= 0 && irv_type(dyn_receiver) == TI_DYN { - dyn_dest := new_ir_var("_dyncall", TI_UNIT); - emit(IR_DYN_DISPATCH, dyn_dest, dyn_receiver, func_ni, 0, 0); - return dyn_dest; - } - } + if ast_kind(func_node) == EXPR_FIELD && ac > 0 && func_ni >= 0: + dyn_receiver := first_arg_var + if dyn_receiver >= 0 && irv_type(dyn_receiver) == TI_DYN: + dyn_dest := new_ir_var("_dyncall", TI_UNIT) + emit(IR_DYN_DISPATCH, dyn_dest, dyn_receiver, func_ni, 0, 0) + return dyn_dest // Hotpatch function call: emit IR_HOTPATCH_ROUTE instead of IR_CALL // R2 P5 Task 2(F1 裁决):第 6 实参**必须显式给**。修复前本调用点只传 5 参, @@ -2345,578 +2447,568 @@ emit(IR_STORE, -1, lv, val_var, 0, 0); // 已裁决偏差登记:含 hotpatch 的语料该节点码 4→0(该值本是垃圾、零消费者; // canary 语料 ptr_arith 不含 hotpatch ⇒ 不受影响)。把未定义行为烘进分类表 // 不可接受——分类表要求「每格有依据」。 - if func_ni >= 0 && is_hotpatch_func(func_ni) != 0 { - emit(IR_HOTPATCH_ROUTE, dest, func_ni, first_arg_var, ac, 0); - return dest; - } + if func_ni >= 0 && is_hotpatch_func(func_ni) != 0: + emit(IR_HOTPATCH_ROUTE, dest, func_ni, first_arg_var, ac, 0) + return dest // Extern function call: emit IR_CALL_EXTERN for FFI dispatch - if func_ni >= 0 { - fi := find_func(func_ni); - if fi >= 0 { - fn_node := fi_ast_node(fi); - if fn_node >= 0 && ast_kind(fn_node) == EXPR_EXTERN { - emit(IR_CALL_EXTERN, dest, func_ni, first_arg_var, ac, 0); - return dest; - } - } - } + if func_ni >= 0: + fi := find_func(func_ni) + if fi >= 0: + fn_node := fi_ast_node(fi) + if fn_node >= 0 && ast_kind(fn_node) == EXPR_EXTERN: + emit(IR_CALL_EXTERN, dest, func_ni, first_arg_var, ac, 0) + return dest // 可选表示(R2 P4 Task 5):实参表示写信道——逐实参位写(被调序言最早处读; // 写点 = 全部实参求值之后、IR_CALL 紧邻之前 ⇒ 嵌套调用不覆写信道)。 - if g_optrep_on != 0 && g_optrep_arg_count > 0 { - ai3 : ., mut = 0; - loop { - if ai3 >= ac { break; } - if ai3 >= g_optrep_arg_count { break; } - av3 := r64(arg_vars, ai3 * 8); - an3 : ., mut = -1; - if ai3 < arg_nodes_cap { an3 = r64(arg_nodes, ai3 * 8); } - emit_rep_set(g_optrep_arg_cell0 + ai3, rep_enc_of_expr(an3, av3)); - ai3 = ai3 + 1; - } - } - emit(IR_CALL, dest, first_arg_var, ac, func_ni, call_ti); + if g_optrep_on != 0 && g_optrep_arg_count > 0: + ai3 : ., mut = 0 + loop: + if ai3 >= ac: + break + if ai3 >= g_optrep_arg_count: + break + av3 := r64(arg_vars, ai3 * 8) + an3 : ., mut = -1 + if ai3 < arg_nodes_cap: + an3 = r64(arg_nodes, ai3 * 8) + emit_rep_set(g_optrep_arg_cell0 + ai3, rep_enc_of_expr(an3, av3)) + ai3 = ai3 + 1 + emit(IR_CALL, dest, first_arg_var, ac, func_ni, call_ti) // 可选表示(R2 P4 Task 5):被调返回可选 ⇒ 1) 读返回信道(读点必须**紧跟真实 // 调用**:调用点与返回点同进程同栈、其间无写入);2) **禁惰性 thunk**——thunk 把 // 调用推迟到 force 点,读点即悬空(实测踩过:`v := g()` 的 g 判纯 ⇒ thunk ⇒ 表示位 // 回落装箱 ⇒ 裸值返回解包崩)。代价 = 仅「返回可选」的被调不做 thunk 延迟。 - ret_opt : ., mut = 0; - if g_optrep_on != 0 && g_optrep_ret_cell >= 0 { ret_opt = callee_ret_optional(func_ni); } + ret_opt : ., mut = 0 + if g_optrep_on != 0 && g_optrep_ret_cell >= 0: + ret_opt = callee_ret_optional(func_ni) // Lazy thunk: if calling a pure function with single use, wrap as thunk - if func_ni >= 0 && ret_opt == 0 { - call_fi := find_func(func_ni); - if call_fi >= 0 && fi_ispure(call_fi) != 0 { - grow_var_use_count(dest + 1); - use_count := r64(g_var_use_count, dest * 8); - if use_count <= 1 { - thunk_var := new_ir_var("_lazy", irv_type(dest)); - emit(IR_LAZY_THUNK, thunk_var, dest, 0, 0, 0); - return thunk_var; - } - } - } - if ret_opt != 0 { - rvr := new_ir_var("call_rep", TI_INT); - emit(IR_LOAD, rvr, g_optrep_ret_cell, 0, 0, TI_INT); - irv_set_rep(dest, rvr); - } - return dest; - } + if func_ni >= 0 && ret_opt == 0: + call_fi := find_func(func_ni) + if call_fi >= 0 && fi_ispure(call_fi) != 0: + grow_var_use_count(dest + 1) + use_count := r64(g_var_use_count, dest * 8) + if use_count <= 1: + thunk_var := new_ir_var("_lazy", irv_type(dest)) + emit(IR_LAZY_THUNK, thunk_var, dest, 0, 0, 0) + return thunk_var + if ret_opt != 0: + rvr := new_ir_var("call_rep", TI_INT) + emit(IR_LOAD, rvr, g_optrep_ret_cell, 0, 0, TI_INT) + irv_set_rep(dest, rvr) + return dest // Block - if ast_kind(node) == EXPR_BLOCK { - stmt_start := ast_a(node); - stmt_count := ast_b(node); - last : ., mut = -1; - push_ir_scope(); - i : ., mut = 0; - loop { - if i >= stmt_count { break; } - sn := r64(g_block_stmts, (stmt_start + i) * 8); - last = gen_expr(sn); - i = i + 1; - } - pop_ir_scope(); - return last; - } + if ast_kind(node) == EXPR_BLOCK: + stmt_start := ast_a(node) + stmt_count := ast_b(node) + last : ., mut = -1 + push_ir_scope() + i : ., mut = 0 + loop: + if i >= stmt_count: + break + sn := r64(g_block_stmts, (stmt_start + i) * 8) + last = gen_expr(sn) + i = i + 1 + pop_ir_scope() + return last // If expression - if ast_kind(node) == EXPR_IF { - sg_push(SG_IF); // conditional region: covers [condition, merge) - cond := ast_a(node); - then_node := ast_b(node); - else_node := ast_c(node); - cond_var := gen_expr(cond); - cond_var = force_if_thunk(cond_var); - then_lbl := new_label(); - else_lbl := new_label(); - merge_lbl := new_label(); - if else_node >= 0 { - emit(IR_BRANCH, -1, cond_var, then_lbl, else_lbl, 0); - } else { - emit(IR_BRANCH, -1, cond_var, then_lbl, merge_lbl, 0); - } - emit(IR_LABEL, -1, then_lbl, 0, 0, 0); - gen_expr(then_node); - emit(IR_JUMP, -1, merge_lbl, 0, 0, 0); - if else_node >= 0 { - emit(IR_LABEL, -1, else_lbl, 0, 0, 0); - gen_expr(else_node); - emit(IR_JUMP, -1, merge_lbl, 0, 0, 0); - } - emit(IR_LABEL, -1, merge_lbl, 0, 0, 0); - sg_pop(); - return -1; - } + if ast_kind(node) == EXPR_IF: + sg_push(SG_IF) // conditional region: covers [condition, merge) + cond := ast_a(node) + then_node := ast_b(node) + else_node := ast_c(node) + cond_var := gen_expr(cond) + cond_var = force_if_thunk(cond_var) + then_lbl := new_label() + else_lbl := new_label() + merge_lbl := new_label() + if else_node >= 0: + emit(IR_BRANCH, -1, cond_var, then_lbl, else_lbl, 0) + else: + emit(IR_BRANCH, -1, cond_var, then_lbl, merge_lbl, 0) + emit(IR_LABEL, -1, then_lbl, 0, 0, 0) + gen_expr(then_node) + emit(IR_JUMP, -1, merge_lbl, 0, 0, 0) + if else_node >= 0: + emit(IR_LABEL, -1, else_lbl, 0, 0, 0) + gen_expr(else_node) + emit(IR_JUMP, -1, merge_lbl, 0, 0, 0) + emit(IR_LABEL, -1, merge_lbl, 0, 0, 0) + sg_pop() + return -1 // Loop - if ast_kind(node) == EXPR_LOOP { - header_lbl := new_label(); - body_lbl := new_label(); - exit_lbl := new_label(); - emit(IR_JUMP, -1, header_lbl, 0, 0, 0); + if ast_kind(node) == EXPR_LOOP: + header_lbl := new_label() + body_lbl := new_label() + exit_lbl := new_label() + emit(IR_JUMP, -1, header_lbl, 0, 0, 0) // SG_LOOP region covers [header, exit) — the back-edge jump to the // header lands on the region enter (region iteration in interp.cr). - sg_alloc_push(SG_LOOP); - arena_var := new_ir_var("_arena", TI_INT); - w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var); - emit(IR_LABEL, -1, header_lbl, 0, 0, 0); - emit(IR_JUMP, -1, body_lbl, 0, 0, 0); - emit(IR_LABEL, -1, body_lbl, 0, 0, 0); - emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0); - arena_instr := g_ir_instr_count - 1; - push_ir_scope(); + sg_alloc_push(SG_LOOP) + arena_var := new_ir_var("_arena", TI_INT) + w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var) + emit(IR_LABEL, -1, header_lbl, 0, 0, 0) + emit(IR_JUMP, -1, body_lbl, 0, 0, 0) + emit(IR_LABEL, -1, body_lbl, 0, 0, 0) + emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0) + arena_instr := g_ir_instr_count - 1 + push_ir_scope() // `continue` must jump to the post label (not the header) so the // arena reset runs on the continue path too — symmetric with `for`. - post_lbl := new_label(); - push_loop_labels(post_lbl, exit_lbl); - gen_expr(ast_a(node)); - pop_loop_labels(); - pop_ir_scope(); - total := r64(g_sg_alloc_total, g_sg_count - 1); - if total > 0 { iri_set_s1(arena_instr, total); } - emit(IR_LABEL, -1, post_lbl, 0, 0, 0); - emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0); // arena reused per iteration - emit(IR_JUMP, -1, header_lbl, 0, 0, 0); - emit(IR_LABEL, -1, exit_lbl, 0, 0, 0); - sg_pop(); // close loop region (arena already reset above) - return -1; - } + post_lbl := new_label() + push_loop_labels(post_lbl, exit_lbl) + gen_expr(ast_a(node)) + pop_loop_labels() + pop_ir_scope() + total := r64(g_sg_alloc_total, g_sg_count - 1) + if total > 0: + iri_set_s1(arena_instr, total) + emit(IR_LABEL, -1, post_lbl, 0, 0, 0) + emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0) // arena reused per iteration + emit(IR_JUMP, -1, header_lbl, 0, 0, 0) + emit(IR_LABEL, -1, exit_lbl, 0, 0, 0) + sg_pop() // close loop region (arena already reset above) + return -1 // While loop - if ast_kind(node) == EXPR_WHILE { - cond := ast_a(node); - body := ast_b(node); - header_lbl := new_label(); - body_lbl := new_label(); - exit_lbl := new_label(); + if ast_kind(node) == EXPR_WHILE: + cond := ast_a(node) + body := ast_b(node) + header_lbl := new_label() + body_lbl := new_label() + exit_lbl := new_label() // Keep while loops on the same SG_LOOP protocol as loop/for: the // region owns the condition, body, back-edge, and exit label so sg_pop // can add the termination dependency and advance the state chain. - sg_push(SG_LOOP); - arena_var := new_ir_var("_arena", TI_INT); - w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var); - emit(IR_LABEL, -1, header_lbl, 0, 0, 0); - cond_var := gen_expr(cond); - cond_var = force_if_thunk(cond_var); - emit(IR_BRANCH, -1, cond_var, body_lbl, exit_lbl, 0); - emit(IR_LABEL, -1, body_lbl, 0, 0, 0); - emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0); - arena_instr := g_ir_instr_count - 1; - push_ir_scope(); + sg_push(SG_LOOP) + arena_var := new_ir_var("_arena", TI_INT) + w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var) + emit(IR_LABEL, -1, header_lbl, 0, 0, 0) + cond_var := gen_expr(cond) + cond_var = force_if_thunk(cond_var) + emit(IR_BRANCH, -1, cond_var, body_lbl, exit_lbl, 0) + emit(IR_LABEL, -1, body_lbl, 0, 0, 0) + emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0) + arena_instr := g_ir_instr_count - 1 + push_ir_scope() // Continue must pass through the reset point before rechecking cond. - post_lbl := new_label(); - push_loop_labels(post_lbl, exit_lbl); - gen_expr(body); - pop_loop_labels(); - pop_ir_scope(); - total := r64(g_sg_alloc_total, g_sg_count - 1); - if total > 0 { iri_set_s1(arena_instr, total); } - emit(IR_LABEL, -1, post_lbl, 0, 0, 0); - emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0); - emit(IR_JUMP, -1, header_lbl, 0, 0, 0); - emit(IR_LABEL, -1, exit_lbl, 0, 0, 0); - sg_pop(); // close loop region (arena already reset above) - return -1; - } + post_lbl := new_label() + push_loop_labels(post_lbl, exit_lbl) + gen_expr(body) + pop_loop_labels() + pop_ir_scope() + total := r64(g_sg_alloc_total, g_sg_count - 1) + if total > 0: + iri_set_s1(arena_instr, total) + emit(IR_LABEL, -1, post_lbl, 0, 0, 0) + emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0) + emit(IR_JUMP, -1, header_lbl, 0, 0, 0) + emit(IR_LABEL, -1, exit_lbl, 0, 0, 0) + sg_pop() // close loop region (arena already reset above) + return -1 // For loop: for var in start..end { body } - if ast_kind(node) == EXPR_FOR { - var_ni := ast_a(node); - iter := ast_b(node); - body := ast_c(node); - start_var := -1; - end_var := -1; - if ast_kind(iter) == EXPR_RANGE { - start_var = gen_expr(ast_a(iter)); - start_var = force_if_thunk(start_var); - end_var = gen_expr(ast_b(iter)); - end_var = force_if_thunk(end_var); - } else { + if ast_kind(node) == EXPR_FOR: + var_ni := ast_a(node) + iter := ast_b(node) + body := ast_c(node) + start_var := -1 + end_var := -1 + if ast_kind(iter) == EXPR_RANGE: + start_var = gen_expr(ast_a(iter)) + start_var = force_if_thunk(start_var) + end_var = gen_expr(ast_b(iter)) + end_var = force_if_thunk(end_var) + else: // Non-range iterable: evaluate and use 0..iter - s := new_ir_var("start", TI_INT); - emit(IR_CONST, s, 0, 0, 0, TI_INT); - start_var = s; - end_var = gen_expr(iter); - end_var = force_if_thunk(end_var); - } + s := new_ir_var("start", TI_INT) + emit(IR_CONST, s, 0, 0, 0, TI_INT) + start_var = s + end_var = gen_expr(iter) + end_var = force_if_thunk(end_var) // Create loop variable, init to start - ivar := new_ir_var("for_i", TI_INT); - emit(IR_ALLOC, ivar, 0, 0, 0, TI_INT); - emit(IR_STORE, -1, ivar, start_var, 0, 0); - bind_local(var_ni, ivar); - header_lbl := new_label(); - body_lbl := new_label(); - exit_lbl := new_label(); + ivar := new_ir_var("for_i", TI_INT) + emit(IR_ALLOC, ivar, 0, 0, 0, TI_INT) + emit(IR_STORE, -1, ivar, start_var, 0, 0) + bind_local(var_ni, ivar) + header_lbl := new_label() + body_lbl := new_label() + exit_lbl := new_label() // The SG_FOR region covers [header, exit): the back-edge jump to the // header is then a jump to the region enter, so the interpreter can // drive loop iteration from region boundaries (region iteration). - sg_alloc_push(SG_FOR); - arena_var := new_ir_var("_arena", TI_INT); - w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var); + sg_alloc_push(SG_FOR) + arena_var := new_ir_var("_arena", TI_INT) + w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var) // Header: check ivar < end, branch to exit if false - emit(IR_LABEL, -1, header_lbl, 0, 0, 0); - cond_var := new_ir_var("for_cond", TI_INT); - emit(IR_BINARY, cond_var, ivar, end_var, OP_LT, 0); - emit(IR_BRANCH, -1, cond_var, body_lbl, exit_lbl, 0); + emit(IR_LABEL, -1, header_lbl, 0, 0, 0) + cond_var := new_ir_var("for_cond", TI_INT) + emit(IR_BINARY, cond_var, ivar, end_var, OP_LT, 0) + emit(IR_BRANCH, -1, cond_var, body_lbl, exit_lbl, 0) // Body - emit(IR_LABEL, -1, body_lbl, 0, 0, 0); - emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0); - arena_instr := g_ir_instr_count - 1; - push_ir_scope(); + emit(IR_LABEL, -1, body_lbl, 0, 0, 0) + emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0) + arena_instr := g_ir_instr_count - 1 + push_ir_scope() // `continue` must jump to the post (increment) label, not the header — // otherwise the loop variable never advances and the loop spins. - post_lbl := new_label(); - push_loop_labels(post_lbl, exit_lbl); - gen_expr(body); - pop_loop_labels(); - pop_ir_scope(); - total := r64(g_sg_alloc_total, g_sg_count - 1); - if total > 0 { iri_set_s1(arena_instr, total); } + post_lbl := new_label() + push_loop_labels(post_lbl, exit_lbl) + gen_expr(body) + pop_loop_labels() + pop_ir_scope() + total := r64(g_sg_alloc_total, g_sg_count - 1) + if total > 0: + iri_set_s1(arena_instr, total) // Increment ivar and jump to header (arena reset runs on every path, // including the continue path, so per-iteration memory is reused) - emit(IR_LABEL, -1, post_lbl, 0, 0, 0); - emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0); - one_var := new_ir_var("one", TI_INT); - emit(IR_CONST, one_var, 1, 0, 0, TI_INT); - inc_var := new_ir_var("inc", TI_INT); - emit(IR_BINARY, inc_var, ivar, one_var, OP_ADD, 0); - emit(IR_STORE, -1, ivar, inc_var, 0, 0); - emit(IR_JUMP, -1, header_lbl, 0, 0, 0); + emit(IR_LABEL, -1, post_lbl, 0, 0, 0) + emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0) + one_var := new_ir_var("one", TI_INT) + emit(IR_CONST, one_var, 1, 0, 0, TI_INT) + inc_var := new_ir_var("inc", TI_INT) + emit(IR_BINARY, inc_var, ivar, one_var, OP_ADD, 0) + emit(IR_STORE, -1, ivar, inc_var, 0, 0) + emit(IR_JUMP, -1, header_lbl, 0, 0, 0) // Exit - emit(IR_LABEL, -1, exit_lbl, 0, 0, 0); - sg_pop(); // close loop region (arena already reset above) - return -1; - } + emit(IR_LABEL, -1, exit_lbl, 0, 0, 0) + sg_pop() // close loop region (arena already reset above) + return -1 // Match expression - if ast_kind(node) == EXPR_MATCH { - match_expr := ast_a(node); - first_arm := ast_b(node); - match_val := gen_expr(match_expr); - match_val = force_if_thunk(match_val); + if ast_kind(node) == EXPR_MATCH: + match_expr := ast_a(node) + first_arm := ast_b(node) + match_val := gen_expr(match_expr) + match_val = force_if_thunk(match_val) // Allocate a result variable for the match expression value - result_var := new_ir_var("match_res", TI_INT); - emit(IR_ALLOC, result_var, 0, 0, 0, TI_INT); + result_var := new_ir_var("match_res", TI_INT) + emit(IR_ALLOC, result_var, 0, 0, 0, TI_INT) // 容量批 T2(裁-CAP-1 (a) 的 match 面 = 裁决 (i) 表示位案):结果槽配**表示位** // (与既有局部机制同源;默认 1 = 装箱),各臂写点置位 ⇒ 消费点(LET/返回/解包) // 自动继承正确表示。修复前:臂写裸值时无表示 ⇒ 消费侧落 `oe_boxed()` 装箱假定 // ⇒ 双路径 139(T1 实测 e2_matchres_bare)。 - mrep_var : ., mut = -1; - if g_optrep_on != 0 { - mrep_var = new_ir_var("match_res_rep", TI_INT); - emit(IR_CONST, mrep_var, 1, 0, 0, TI_INT); - irv_set_rep(result_var, mrep_var); - } - merge_lbl := new_label(); - an : ., mut = first_arm; - loop { - if an < 0 { break; } - arm_pat := ast_a(an); - arm_body := ast_b(an); - pat_kind := -1; - if arm_pat >= 0 { pat_kind = ast_kind(arm_pat); } - is_wildcard := 0; - if pat_kind == EXPR_WILDCARD { is_wildcard = 1; } + mrep_var : ., mut = -1 + if g_optrep_on != 0: + mrep_var = new_ir_var("match_res_rep", TI_INT) + emit(IR_CONST, mrep_var, 1, 0, 0, TI_INT) + irv_set_rep(result_var, mrep_var) + merge_lbl := new_label() + an : ., mut = first_arm + loop: + if an < 0: + break + arm_pat := ast_a(an) + arm_body := ast_b(an) + pat_kind := -1 + if arm_pat >= 0: + pat_kind = ast_kind(arm_pat) + is_wildcard := 0 + if pat_kind == EXPR_WILDCARD: + is_wildcard = 1 // 可选表示位(R2 P4 Task 5):臂条件与臂体绑定共用(声明在臂作用域) - rep_v : ., mut = -1; - body_lbl := new_label(); - fall_lbl : ., mut = merge_lbl; - has_next := 0; - if ast_c(an) >= 0 { has_next = 1; } - if is_wildcard == 1 { - emit(IR_JUMP, -1, body_lbl, 0, 0, 0); - } else if pat_kind == EXPR_ENUMPAT { - variant_ni := get_variant_name_idx(ast_a(arm_pat)); + rep_v : ., mut = -1 + body_lbl := new_label() + fall_lbl : ., mut = merge_lbl + has_next := 0 + if ast_c(an) >= 0: + has_next = 1 + if is_wildcard == 1: + emit(IR_JUMP, -1, body_lbl, 0, 0, 0) + else if pat_kind == EXPR_ENUMPAT: + variant_ni := get_variant_name_idx(ast_a(arm_pat)) // R2 P4 Task 5:**解包侧判表示**——scrutinee 配表示位(可选槽)时按位分派: // 裸值(0)→ 值即载荷:Some 模式命中臂体(**不读 tag**——裸值非对象, // 读 tag 即 SIGSEGV = 原红态);None 模式不命中(裸值非 null)。 // 装箱(≠0)→ 既有 tag 分派(逐字不变)。 // 无表示位(非可选槽 / 未覆盖面)→ 既有路径逐字不变(装箱假定)。 - if g_optrep_on != 0 && match_val >= 0 { rep_v = irv_rep(match_val); } - if rep_v < 0 { - tag_var := new_ir_var("tag", TI_INT); - emit(IR_LOAD_ENUM_TAG, tag_var, match_val, 0, 0, 0); - vtag := new_ir_var("vtag", TI_INT); - emit(IR_CONST, vtag, variant_ni, 0, 0, TI_INT); - cmp_var := new_ir_var("cmp", TI_INT); - emit(IR_BINARY, cmp_var, tag_var, vtag, OP_EQ, 0); - if has_next == 1 { fall_lbl = new_label(); } - emit(IR_BRANCH, -1, cmp_var, body_lbl, fall_lbl, 0); - } else { - is_some_pat : ., mut = 0; - if str_eq(istr_get(variant_ni), "Some") != 0 { is_some_pat = 1; } - tag_lbl := new_label(); - if has_next == 1 { fall_lbl = new_label(); } - zb := new_ir_var("_rz", TI_INT); - emit(IR_CONST, zb, 0, 0, 0, TI_INT); - isb := new_ir_var("rep_isbare", TI_INT); - if is_some_pat != 0 { emit(IR_BINARY, isb, rep_v, zb, OP_EQ, 0); } - else { emit(IR_BINARY, isb, rep_v, zb, OP_NE, 0); } + if g_optrep_on != 0 && match_val >= 0: + rep_v = irv_rep(match_val) + if rep_v < 0: + tag_var := new_ir_var("tag", TI_INT) + emit(IR_LOAD_ENUM_TAG, tag_var, match_val, 0, 0, 0) + vtag := new_ir_var("vtag", TI_INT) + emit(IR_CONST, vtag, variant_ni, 0, 0, TI_INT) + cmp_var := new_ir_var("cmp", TI_INT) + emit(IR_BINARY, cmp_var, tag_var, vtag, OP_EQ, 0) + if has_next == 1: + fall_lbl = new_label() + emit(IR_BRANCH, -1, cmp_var, body_lbl, fall_lbl, 0) + else: + is_some_pat : ., mut = 0 + if str_eq(istr_get(variant_ni), "Some") != 0: + is_some_pat = 1 + tag_lbl := new_label() + if has_next == 1: + fall_lbl = new_label() + zb := new_ir_var("_rz", TI_INT) + emit(IR_CONST, zb, 0, 0, 0, TI_INT) + isb := new_ir_var("rep_isbare", TI_INT) + if is_some_pat != 0: + emit(IR_BINARY, isb, rep_v, zb, OP_EQ, 0) + else: + emit(IR_BINARY, isb, rep_v, zb, OP_NE, 0) // Some:裸 → 直接命中;装箱 → 落 tag 比对。None:裸 → 不命中(落 fall); // 装箱 → 落 tag 比对。 - if is_some_pat != 0 { emit(IR_BRANCH, -1, isb, body_lbl, tag_lbl, 0); } - else { emit(IR_BRANCH, -1, isb, tag_lbl, fall_lbl, 0); } - emit(IR_LABEL, -1, tag_lbl, 0, 0, 0); - tag_var := new_ir_var("tag", TI_INT); - emit(IR_LOAD_ENUM_TAG, tag_var, match_val, 0, 0, 0); - vtag := new_ir_var("vtag", TI_INT); - emit(IR_CONST, vtag, variant_ni, 0, 0, TI_INT); - cmp_var := new_ir_var("cmp", TI_INT); - emit(IR_BINARY, cmp_var, tag_var, vtag, OP_EQ, 0); - emit(IR_BRANCH, -1, cmp_var, body_lbl, fall_lbl, 0); - } - } else if pat_kind == EXPR_INT { - pat_val := new_ir_var("pval", TI_INT); - emit(IR_CONST, pat_val, ast_int_val(arm_pat), 0, 0, TI_INT); - cmp_var := new_ir_var("cmp", TI_INT); - emit(IR_BINARY, cmp_var, match_val, pat_val, OP_EQ, 0); - if has_next == 1 { fall_lbl = new_label(); } - emit(IR_BRANCH, -1, cmp_var, body_lbl, fall_lbl, 0); - } else if pat_kind == EXPR_BOOL { - pat_val := new_ir_var("pval", TI_INT); - pat_bool : ., mut = 0; - if ast_int_val(arm_pat) != 0 { pat_bool = 1; } - emit(IR_CONST, pat_val, pat_bool, 0, 0, TI_INT); - cmp_var := new_ir_var("cmp", TI_INT); - emit(IR_BINARY, cmp_var, match_val, pat_val, OP_EQ, 0); - if has_next == 1 { fall_lbl = new_label(); } - emit(IR_BRANCH, -1, cmp_var, body_lbl, fall_lbl, 0); - } - emit(IR_LABEL, -1, body_lbl, 0, 0, 0); - push_ir_scope(); - if pat_kind == EXPR_ENUMPAT { - sub_count := ast_c(arm_pat); - fi : ., mut = 0; - loop { - if fi >= sub_count { break; } - fv := new_ir_var("fld", TI_INT); + if is_some_pat != 0: + emit(IR_BRANCH, -1, isb, body_lbl, tag_lbl, 0) + else: + emit(IR_BRANCH, -1, isb, tag_lbl, fall_lbl, 0) + emit(IR_LABEL, -1, tag_lbl, 0, 0, 0) + tag_var := new_ir_var("tag", TI_INT) + emit(IR_LOAD_ENUM_TAG, tag_var, match_val, 0, 0, 0) + vtag := new_ir_var("vtag", TI_INT) + emit(IR_CONST, vtag, variant_ni, 0, 0, TI_INT) + cmp_var := new_ir_var("cmp", TI_INT) + emit(IR_BINARY, cmp_var, tag_var, vtag, OP_EQ, 0) + emit(IR_BRANCH, -1, cmp_var, body_lbl, fall_lbl, 0) + else if pat_kind == EXPR_INT: + pat_val := new_ir_var("pval", TI_INT) + emit(IR_CONST, pat_val, ast_int_val(arm_pat), 0, 0, TI_INT) + cmp_var := new_ir_var("cmp", TI_INT) + emit(IR_BINARY, cmp_var, match_val, pat_val, OP_EQ, 0) + if has_next == 1: + fall_lbl = new_label() + emit(IR_BRANCH, -1, cmp_var, body_lbl, fall_lbl, 0) + else if pat_kind == EXPR_BOOL: + pat_val := new_ir_var("pval", TI_INT) + pat_bool : ., mut = 0 + if ast_int_val(arm_pat) != 0: + pat_bool = 1 + emit(IR_CONST, pat_val, pat_bool, 0, 0, TI_INT) + cmp_var := new_ir_var("cmp", TI_INT) + emit(IR_BINARY, cmp_var, match_val, pat_val, OP_EQ, 0) + if has_next == 1: + fall_lbl = new_label() + emit(IR_BRANCH, -1, cmp_var, body_lbl, fall_lbl, 0) + emit(IR_LABEL, -1, body_lbl, 0, 0, 0) + push_ir_scope() + if pat_kind == EXPR_ENUMPAT: + sub_count := ast_c(arm_pat) + fi : ., mut = 0 + loop: + if fi >= sub_count: + break + fv := new_ir_var("fld", TI_INT) // TODO #2026-09-16-16 批 2:载荷读定型取**声明面形式**(dex 载荷 ⇒ TI_DEX_S) // 批 5(opt-dex · G2):optional 声明的载荷(内建 `Some` 面无枚举行 ⇒ // `agg_payload_read_form` 恒 TI_INT)改由 **scrutinee 的声明行**补判—— // `irv_decl_ti(match_val)` 是 LET 期登记的 `TYP_OPTIONAL` 行(`:2573`), // `dex_opt_slot_ti` 纯表读(**零 alloc_type** = G2 红线)。否则 `dex?` // 载荷入 dex 运算会被当 int 再 ×S(`dex_scale_int`)。 - fv_ti : ., mut = agg_payload_read_form(arm_pat, fi); - if fv_ti == TI_INT && match_val >= 0 { - if dex_opt_slot_ti(irv_decl_ti(match_val)) != 0 { fv_ti = TI_DEX_S; } - } - irv_set_type(fv, fv_ti); - if rep_v < 0 { - emit(IR_LOAD_FIELD, fv, match_val, 0, fi + 1, 0); // +1 for tag offset - } else { + fv_ti : ., mut = agg_payload_read_form(arm_pat, fi) + if fv_ti == TI_INT && match_val >= 0: + if dex_opt_slot_ti(irv_decl_ti(match_val)) != 0: + fv_ti = TI_DEX_S + irv_set_type(fv, fv_ti) + if rep_v < 0: + emit(IR_LOAD_FIELD, fv, match_val, 0, fi + 1, 0) // +1 for tag offset + else: // 解包侧判表示:裸值(0)→ 槽值**即**载荷(直取,不解引用); // 装箱(≠0)→ 字段 fi+1(既有语义)。裸分支须**跳过**装 // 箱分支的字段读(end_lbl)——否则裸值仍被解引用(原红态)。 - bare_lbl := new_label(); - boxed_lbl := new_label(); - end_lbl := new_label(); - zb2 := new_ir_var("_rz", TI_INT); - emit(IR_CONST, zb2, 0, 0, 0, TI_INT); - ib2 := new_ir_var("rep_isbare", TI_INT); - emit(IR_BINARY, ib2, rep_v, zb2, OP_EQ, 0); - emit(IR_BRANCH, -1, ib2, bare_lbl, boxed_lbl, 0); - emit(IR_LABEL, -1, bare_lbl, 0, 0, 0); - emit(IR_STORE, -1, fv, match_val, 0, 0); - emit(IR_JUMP, -1, end_lbl, 0, 0, 0); - emit(IR_LABEL, -1, boxed_lbl, 0, 0, 0); - emit(IR_LOAD_FIELD, fv, match_val, 0, fi + 1, 0); - emit(IR_LABEL, -1, end_lbl, 0, 0, 0); - } - spn := ast_b(arm_pat) + fi; - if spn >= 0 && ast_kind(spn) == EXPR_IDENT { - bind_local(ast_int_val(spn), fv); - } - fi = fi + 1; - } - } - body_val := gen_expr(arm_body); - body_val = force_if_thunk(body_val); - if body_val >= 0 { - emit(IR_STORE, -1, result_var, body_val, 0, 0); + bare_lbl := new_label() + boxed_lbl := new_label() + end_lbl := new_label() + zb2 := new_ir_var("_rz", TI_INT) + emit(IR_CONST, zb2, 0, 0, 0, TI_INT) + ib2 := new_ir_var("rep_isbare", TI_INT) + emit(IR_BINARY, ib2, rep_v, zb2, OP_EQ, 0) + emit(IR_BRANCH, -1, ib2, bare_lbl, boxed_lbl, 0) + emit(IR_LABEL, -1, bare_lbl, 0, 0, 0) + emit(IR_STORE, -1, fv, match_val, 0, 0) + emit(IR_JUMP, -1, end_lbl, 0, 0, 0) + emit(IR_LABEL, -1, boxed_lbl, 0, 0, 0) + emit(IR_LOAD_FIELD, fv, match_val, 0, fi + 1, 0) + emit(IR_LABEL, -1, end_lbl, 0, 0, 0) + spn := ast_b(arm_pat) + fi + if spn >= 0 && ast_kind(spn) == EXPR_IDENT: + bind_local(ast_int_val(spn), fv) + fi = fi + 1 + body_val := gen_expr(arm_body) + body_val = force_if_thunk(body_val) + if body_val >= 0: + emit(IR_STORE, -1, result_var, body_val, 0, 0) // 容量批 T2:结果槽表示位置位(同 LET/赋值的写点口径——解包点据此分派) - if mrep_var >= 0 { emit_rep_set(mrep_var, rep_enc_of_expr(arm_body, body_val)); } - } - pop_ir_scope(); - emit(IR_JUMP, -1, merge_lbl, 0, 0, 0); - if is_wildcard == 0 { - if has_next == 1 { - emit(IR_LABEL, -1, fall_lbl, 0, 0, 0); - } - } - an = ast_c(an); - } - emit(IR_LABEL, -1, merge_lbl, 0, 0, 0); - return result_var; - } + if mrep_var >= 0: + emit_rep_set(mrep_var, rep_enc_of_expr(arm_body, body_val)) + pop_ir_scope() + emit(IR_JUMP, -1, merge_lbl, 0, 0, 0) + if is_wildcard == 0: + if has_next == 1: + emit(IR_LABEL, -1, fall_lbl, 0, 0, 0) + an = ast_c(an) + emit(IR_LABEL, -1, merge_lbl, 0, 0, 0) + return result_var // Let binding - if ast_kind(node) == EXPR_LET { - var_ni := ast_a(node); - type_node := ast_b(node); - val_node := ast_c(node); - is_apx := ast_int_val(node); // apx 标签位(parser 存入 iv 字段) + if ast_kind(node) == EXPR_LET: + var_ni := ast_a(node) + type_node := ast_b(node) + val_node := ast_c(node) + is_apx := ast_int_val(node) // apx 标签位(parser 存入 iv 字段) // Detect dyn variable (type annotation is `dyn`) - is_dyn_var : ., mut = 0; - if type_node >= 0 && ast_kind(type_node) == 0 && ast_type_val(type_node) == TI_DYN { - is_dyn_var = 1; - } - var := new_ir_var(istr_get(var_ni), TI_UNIT); - declared_ti : ., mut = TI_UNIT; - if type_node >= 0 { declared_ti = res_type_node(type_node); } + is_dyn_var : ., mut = 0 + if type_node >= 0 && ast_kind(type_node) == 0 && ast_type_val(type_node) == TI_DYN: + is_dyn_var = 1 + var := new_ir_var(istr_get(var_ni), TI_UNIT) + declared_ti : ., mut = TI_UNIT + if type_node >= 0: + declared_ti = res_type_node(type_node) // 容量批 T2:登记声明类型(元素写点判定目标元素类型用——声明的 `[T?;N]` 才是 // 权威;字面量推出的元素类型对可选元素退化为对象占位 TI_UNIT) - if g_optrep_on != 0 && type_node >= 0 { irv_set_decl_ti(var, declared_ti); } + if g_optrep_on != 0 && type_node >= 0: + irv_set_decl_ti(var, declared_ti) // 可选表示(R2 P4 Task 5):显式 `T?` 标注的槽配表示位(默认 1 = 装箱)。 // 推断槽(无标注)在初值求值后按初值表示面补配(`v := g()` / `x := Some(1)`)。 - rep_var : ., mut = opt_rep_slot(declared_ti, istr_get(var_ni)); - if rep_var >= 0 { irv_set_rep(var, rep_var); } + rep_var : ., mut = opt_rep_slot(declared_ti, istr_get(var_ni)) + if rep_var >= 0: + irv_set_rep(var, rep_var) // `dex` is the source-level type; its IR slot has two forms. Only an // explicitly tagged `apx` declaration uses binary64 bits. - target_ti : ., mut = declared_ti; + target_ti : ., mut = declared_ti // 批 5(opt-dex · R1):`dex?` 声明的**规范槽形式 = scaled**(G1 裁决:装箱对象是聚合类 // 载体、无形式位可挂;rep 位 1 比特承载不了 2 位信息)⇒ 槽型由**声明**给定。 // 修复前:门 `declared_ti == TI_DEX` 对 `dex?`(TYP_OPTIONAL 行)不触发,槽型退化为 // 「随值」(:2577-2579 的值型采纳)⇒ apx 源直接把 bits 存进槽(实测 ELF/interp 15)。 - dex_opt : ., mut = 0; - if type_node >= 0 { dex_opt = dex_opt_type_node(type_node); } - if declared_ti == TI_DEX { - if is_apx != 0 { target_ti = TI_DEX; } - else { target_ti = TI_DEX_S; } - irv_set_type(var, target_ti); - } else if dex_opt != 0 { - target_ti = TI_DEX_S; - irv_set_type(var, TI_DEX_S); - } - is_arr : ., mut = 0; - if type_node >= 0 && val_node < 0 { - if ast_kind(type_node) == 19 { - sz := ast_int_val(type_node); - if sz > 0 { - emit(IR_ALLOC_ARRAY, var, sz, 8, 0, 0); is_arr = 1; + dex_opt : ., mut = 0 + if type_node >= 0: + dex_opt = dex_opt_type_node(type_node) + if declared_ti == TI_DEX: + if is_apx != 0: + target_ti = TI_DEX + else: + target_ti = TI_DEX_S + irv_set_type(var, target_ti) + else if dex_opt != 0: + target_ti = TI_DEX_S + irv_set_type(var, TI_DEX_S) + is_arr : ., mut = 0 + if type_node >= 0 && val_node < 0: + if ast_kind(type_node) == 19: + sz := ast_int_val(type_node) + if sz > 0: + emit(IR_ALLOC_ARRAY, var, sz, 8, 0, 0) + is_arr = 1 // F1:记录数组类型(TYP_ARRAY extra=size)——直接索引越界 // 检查(arr_len_lit_of)依赖该长度信息。 - irv_set_type(var, res_type_node(type_node)); - } - } - } + irv_set_type(var, res_type_node(type_node)) // For dyn vars with initializer: skip allocation (value is packed below) - if is_dyn_var == 0 || val_node < 0 { - if is_arr == 0 { emit(IR_ALLOC, var, 0, 0, 0, TI_UNIT); } - } - if val_node >= 0 { - val_var := gen_expr(val_node); - val_var = force_if_thunk(val_var); + if is_dyn_var == 0 || val_node < 0: + if is_arr == 0: + emit(IR_ALLOC, var, 0, 0, 0, TI_UNIT) + if val_node >= 0: + val_var := gen_expr(val_node) + val_var = force_if_thunk(val_var) // 可选表示:推断槽按初值表示面补配表示位(有表示位可拷贝 / Some/None 构造 / // 未覆盖面回落值——回落配位无害:默认 1 = 装箱 = 既有语义) - if rep_var < 0 && g_optrep_on != 0 && rep_enc_of_expr(val_node, val_var) != oe_bare() { - rep_var = new_ir_var(istr_get(var_ni) + "_rep", TI_INT); - irv_set_rep(var, rep_var); - } + if rep_var < 0 && g_optrep_on != 0 && rep_enc_of_expr(val_node, val_var) != oe_bare(): + rep_var = new_ir_var(istr_get(var_ni) + "_rep", TI_INT) + irv_set_rep(var, rep_var) // An `apx` dex local stores binary64 bits, unlike the default // scaled-integer dex form. The annotation alone is not enough: // switch the slot type and convert the initializer before later // binary operations inspect its type. - if declared_ti == TI_DEX { - val_var = dex_store_adjust(var, val_var, val_node); - } else if dex_opt != 0 { + if declared_ti == TI_DEX: + val_var = dex_store_adjust(var, val_var, val_node) + else if dex_opt != 0: // 批 5(opt-dex · R1):`dex?` 初值入箱/入槽前先归规范形式(bits → scaled)。 // 后续所有写点(赋值 / 指针写 / 聚合 / 装箱)都是「目标槽型驱动」⇒ 槽型定为 // TI_DEX_S 后既有的 dex_store_adjust 路径自动生效(无需逐点补接线)。 - val_var = dex_slot_norm(val_var); - } else if declared_ti == TI_UNIT { - target_ti = irv_type(val_var); - irv_set_type(var, target_ti); - } - if is_dyn_var != 0 { + val_var = dex_slot_norm(val_var) + else if declared_ti == TI_UNIT: + target_ti = irv_type(val_var) + irv_set_type(var, target_ti) + if is_dyn_var != 0: // Dyn variable: pack value with its type tag - dyn_var := new_ir_var("_dyn", TI_DYN); - tag := irv_type(val_var); - if tag < 0 { tag = TI_INT; } - emit(IR_DYN_PACK, dyn_var, val_var, tag, 0, 0); - bind_local(var_ni, dyn_var); - if is_apx != 0 { emit(IR_APPROX, -1, 0, 0, 0, 0); } - return dyn_var; - } + dyn_var := new_ir_var("_dyn", TI_DYN) + tag := irv_type(val_var) + if tag < 0: + tag = TI_INT + emit(IR_DYN_PACK, dyn_var, val_var, tag, 0, 0) + bind_local(var_ni, dyn_var) + if is_apx != 0: + emit(IR_APPROX, -1, 0, 0, 0, 0) + return dyn_var // Preserve the initializer type so later operations can select // type-specific lowering (notably string + -> concat()). // 批 5(opt-dex · R1):`dex?` 槽**不**采纳值型(槽型由声明给定 TI_DEX_S)—— // 否则 `x : dex? = Some(...)`(值 = 箱对象 TI_INT)会把槽型改回 TI_INT, // 令「裸载荷 = scaled」这一规范面在下游再次丢失。 - if declared_ti != TI_DEX && dex_opt == 0 { - irv_set_type(var, irv_type(val_var)); - } + if declared_ti != TI_DEX && dex_opt == 0: + irv_set_type(var, irv_type(val_var)) // F11:切片长度沿 LET 初始化传播(s := arr[0..2] → s 带长度 2; // 运行时界 slice 同步长度变量——slice_len_copy_to) - slice_len_copy_to(var, val_var); + slice_len_copy_to(var, val_var) // (A) T3(裁-T3-1):**推断**声明(无注解)但值面已判可选聚合 ⇒ 声明面继承到 // **绑定 var**(字面量/切片站点登记在**值 var** 上;元素写点的目标是绑定 var) - if g_optrep_on != 0 && type_node < 0 { - vd := irv_decl_ti(val_var); - if vd >= 0 { irv_set_decl_ti(var, vd); } - } + if g_optrep_on != 0 && type_node < 0: + vd := irv_decl_ti(val_var) + if vd >= 0: + irv_set_decl_ti(var, vd) // (A) 批(INV-1):**取址槽恒装箱**——该槽地址被取过 ⇒ 写点装箱 + 表示位钉 1 //(指针写/直接写两路的表示必须一致;解包侧恒走装箱分支) - forced := g_optrep_on != 0 && rep_var >= 0 && addr_taken_of(var_ni) != 0; - if forced != 0 { val_var = box_for_slot_flag(val_node, val_var, 1); } - emit(IR_STORE, -1, var, val_var, 0, 0); + forced := g_optrep_on != 0 && rep_var >= 0 && addr_taken_of(var_ni) != 0 + if forced != 0: + val_var = box_for_slot_flag(val_node, val_var, 1) + emit(IR_STORE, -1, var, val_var, 0, 0) // 可选表示:写点置位(静态已知常量 / 源表示位拷贝)——解包点据此分派 - if rep_var >= 0 { - if forced != 0 { emit_rep_set(rep_var, oe_boxed()); } - else { emit_rep_set(rep_var, rep_enc_of_expr(val_node, val_var)); } - } - } - bind_local(var_ni, var); - if is_apx != 0 { emit(IR_APPROX, -1, 0, 0, 0, 0); } - return var; - } + if rep_var >= 0: + if forced != 0: + emit_rep_set(rep_var, oe_boxed()) + else: + emit_rep_set(rep_var, rep_enc_of_expr(val_node, val_var)) + bind_local(var_ni, var) + if is_apx != 0: + emit(IR_APPROX, -1, 0, 0, 0, 0) + return var // Return - if ast_kind(node) == EXPR_YIELD { - val_node := ast_a(node); - val_var : ., mut = -1; - if val_node >= 0 { val_var = gen_expr(val_node); val_var = force_if_thunk(val_var); } - emit(IR_YIELD, -1, val_var, 0, 0, 0); - return -1; // yield suspends — no return value for caller - } - - if ast_kind(node) == EXPR_AWAIT { - val_node := ast_a(node); - val_var := gen_expr(val_node); - val_var = force_if_thunk(val_var); - dest := new_ir_var("await", TI_UNIT); - emit(IR_AWAIT, dest, val_var, 0, 0, 0); - return dest; - } - - if ast_kind(node) == EXPR_RETURN { - if ast_a(node) >= 0 { - val_node := ast_a(node); - val_var := gen_expr(val_node); - val_var = force_if_thunk(val_var); + if ast_kind(node) == EXPR_YIELD: + val_node := ast_a(node) + val_var : ., mut = -1 + if val_node >= 0: + val_var = gen_expr(val_node) + val_var = force_if_thunk(val_var) + emit(IR_YIELD, -1, val_var, 0, 0, 0) + return -1 // yield suspends — no return value for caller + + if ast_kind(node) == EXPR_AWAIT: + val_node := ast_a(node) + val_var := gen_expr(val_node) + val_var = force_if_thunk(val_var) + dest := new_ir_var("await", TI_UNIT) + emit(IR_AWAIT, dest, val_var, 0, 0, 0) + return dest + + if ast_kind(node) == EXPR_RETURN: + if ast_a(node) >= 0: + val_node := ast_a(node) + val_var := gen_expr(val_node) + val_var = force_if_thunk(val_var) // dex 边界规则(数值迁移 Task 4):函数返回一律精确形式(缩放整数)—— // apx 位模式在返回点转 scaled(F2I(bits×S),按定点 6 位舍入) // 批 5(opt-dex · R3):`-> dex?` 的 `g_cur_ret_ti` 亦为 0(`unpack_type` 塌陷) // ⇒ 追加**返回类型节点**判据(`g_cur_ret_dex_opt`,由 ir_gen_func 设置)—— // 否则 apx 源经 `-> dex?` 返回时不转换(实测 ELF/interp 双路径 15)。 - if (g_cur_ret_ti == TI_DEX || g_cur_ret_dex_opt != 0) && irv_type(val_var) == TI_DEX { - val_var = dex_bits_to_scaled(val_var); - } + if (g_cur_ret_ti == TI_DEX || g_cur_ret_dex_opt != 0) && irv_type(val_var) == TI_DEX: + val_var = dex_bits_to_scaled(val_var) // 可选表示(R2 P4 Task 5):返回点写返回信道——值求值**完成后**、IR_RETURN // 紧邻处(其间无调用 ⇒ 嵌套调用不覆写信道;调用点紧跟 IR_CALL 读)。 - if g_cur_ret_opt != 0 { - emit_rep_set(g_optrep_ret_cell, rep_enc_of_expr(val_node, val_var)); - } - emit(IR_RETURN, -1, val_var, 0, 0, 0); - } else { - emit(IR_RETURN, -1, -1, 0, 0, 0); - } - return -1; - } + if g_cur_ret_opt != 0: + emit_rep_set(g_optrep_ret_cell, rep_enc_of_expr(val_node, val_var)) + emit(IR_RETURN, -1, val_var, 0, 0, 0) + else: + emit(IR_RETURN, -1, -1, 0, 0, 0) + return -1 // Field access - if ast_kind(node) == EXPR_FIELD { - obj_var := gen_expr(ast_a(node)); - obj_var = force_if_thunk(obj_var); + if ast_kind(node) == EXPR_FIELD: + obj_var := gen_expr(ast_a(node)) + obj_var = force_if_thunk(obj_var) // ── S4(2026-09-21):**镜像 checker 的 REF 自动解引用**(`checker.cr:3725`)── // checker 对 `TYP_REF` 对象解包后按结构体查字段 ⇒ **接受** `p.v`;而本分支此前 // **不发解引用** ⇒ `IR_LOAD_FIELD` 把「地址」当聚合读 ⇒ **静默错值** @@ -2927,125 +3019,112 @@ emit(IR_STORE, -1, lv, val_var, 0, 0); // // 发射序**逐字镜像** `UOP_DEREF` 分支(`IR_DEREF` + `ptr_pointee_type` + `ptr_access_width`) // ——该序已被 `(*p).v`(实测 **42** ✓)证明正确 ⇒ 不自创新序。 - if get_type_kind(irv_type(obj_var)) == TYP_REF { - dv := new_ir_var("autoderef", ptr_pointee_type(obj_var)); - emit(IR_DEREF, dv, obj_var, -1, 0, ptr_access_width(obj_var)); - obj_var = dv; - } - v := new_ir_var("field", TI_INT); - fi : ., mut = ast_type_val(node); - if fi > 0 { - fi = fi - 1; // numeric tuple index (parser stored +1) - } else { - fi = ast_data(node); // struct field index (from checker) - } + if get_type_kind(irv_type(obj_var)) == TYP_REF: + dv := new_ir_var("autoderef", ptr_pointee_type(obj_var)) + emit(IR_DEREF, dv, obj_var, -1, 0, ptr_access_width(obj_var)) + obj_var = dv + v := new_ir_var("field", TI_INT) + fi : ., mut = ast_type_val(node) + if fi > 0: + fi = fi - 1 // numeric tuple index (parser stored +1) + else: + fi = ast_data(node) // struct field index (from checker) // TODO #2026-09-16-16 批 2:读点定型取**声明面形式**(dex 声明 ⇒ TI_DEX_S)——零 alloc 节点判, // 非 dex 形态恒 TI_INT ⇒ 零足迹。**必须在 fi 解出之后**(字段位序)。 - irv_set_type(v, agg_field_read_form(node, fi)); - emit(IR_LOAD_FIELD, v, obj_var, 0, fi, 0); - return v; - } + irv_set_type(v, agg_field_read_form(node, fi)) + emit(IR_LOAD_FIELD, v, obj_var, 0, fi, 0) + return v // Index - if ast_kind(node) == EXPR_INDEX { - arr_var := gen_expr(ast_a(node)); - arr_var = force_if_thunk(arr_var); - idx_node := ast_b(node); - idx_kind := ast_kind(idx_node); - arr_len_lit : ., mut = arr_len_lit_of(arr_var); + if ast_kind(node) == EXPR_INDEX: + arr_var := gen_expr(ast_a(node)) + arr_var = force_if_thunk(arr_var) + idx_node := ast_b(node) + idx_kind := ast_kind(idx_node) + arr_len_lit : ., mut = arr_len_lit_of(arr_var) // Range index: arr[low..high] → slice (pointer to arr[low]) - if idx_kind == EXPR_RANGE { - low_node := ast_a(idx_node); - high_node := ast_b(idx_node); - low_var := gen_expr(low_node); - low_var = force_if_thunk(low_var); - high_var := gen_expr(high_node); - high_var = force_if_thunk(high_var); + if idx_kind == EXPR_RANGE: + low_node := ast_a(idx_node) + high_node := ast_b(idx_node) + low_var := gen_expr(low_node) + low_var = force_if_thunk(low_var) + high_var := gen_expr(high_node) + high_var = force_if_thunk(high_var) // F11:创建期守卫——high ≤ arr_len、low ≤ arr_len(low ≤ high 的 // 运行时检查需切片运行时长度,见报告设计缺口;字面量界由 checker 拦截)。 - if arr_len_lit > 0 { - if ast_kind(low_node) == EXPR_INT { - if ast_int_val(low_node) < 0 || ast_int_val(low_node) > arr_len_lit { - emit(IR_BOUNDS_CHECK, -1, low_var, arr_len_lit + 1, 0, 0); - } - } else { - emit(IR_BOUNDS_CHECK, -1, low_var, arr_len_lit + 1, 0, 0); - } - if ast_kind(high_node) == EXPR_INT { - if ast_int_val(high_node) < 0 || ast_int_val(high_node) > arr_len_lit { - emit(IR_BOUNDS_CHECK, -1, high_var, arr_len_lit + 1, 0, 0); - } - } else { - emit(IR_BOUNDS_CHECK, -1, high_var, arr_len_lit + 1, 0, 0); - } - } - v := new_ir_var("slice", TI_INT); - emit(IR_SLICE, v, arr_var, low_var, high_var, 0); + if arr_len_lit > 0: + if ast_kind(low_node) == EXPR_INT: + if ast_int_val(low_node) < 0 || ast_int_val(low_node) > arr_len_lit: + emit(IR_BOUNDS_CHECK, -1, low_var, arr_len_lit + 1, 0, 0) + else: + emit(IR_BOUNDS_CHECK, -1, low_var, arr_len_lit + 1, 0, 0) + if ast_kind(high_node) == EXPR_INT: + if ast_int_val(high_node) < 0 || ast_int_val(high_node) > arr_len_lit: + emit(IR_BOUNDS_CHECK, -1, high_var, arr_len_lit + 1, 0, 0) + else: + emit(IR_BOUNDS_CHECK, -1, high_var, arr_len_lit + 1, 0, 0) + v := new_ir_var("slice", TI_INT) + emit(IR_SLICE, v, arr_var, low_var, high_var, 0) // (A) T3(裁-T3-1):源数组元素**可选** ⇒ 切片登记声明面(切片元素写点据此装箱; // 非可选不登记 ⇒ 零足迹。切片 var 的 IR 型面不动——避免影响 dtype/宽度等消费者) - if g_optrep_on != 0 { - sti := elem_ti_of(arr_var); - if ti_is_optional(sti) != 0 { irv_set_decl_ti(v, alloc_type(TYP_SLICE, sti, 0)); } - } + if g_optrep_on != 0: + sti := elem_ti_of(arr_var) + if ti_is_optional(sti) != 0: + irv_set_decl_ti(v, alloc_type(TYP_SLICE, sti, 0)) // F11:字面量界 → 登记切片编译期长度(解引用处 arr_len_lit 用); // 运行时界 → 计算 len = high − low 并登记长度变量(解引用处发射 // 动态边界检查——见 emit_slice_*_bounds)。 - if ast_kind(low_node) == EXPR_INT && ast_kind(high_node) == EXPR_INT { - sl := ast_int_val(high_node) - ast_int_val(low_node); - if sl >= 0 { slice_len_set(v, sl); } - } else { - len_var := new_ir_var("slice_len", TI_INT); - emit(IR_BINARY, len_var, high_var, low_var, OP_SUB, TI_INT); - slice_len_var_set(v, len_var); - } - return v; - } - v := new_ir_var("elem", TI_INT); + if ast_kind(low_node) == EXPR_INT && ast_kind(high_node) == EXPR_INT: + sl := ast_int_val(high_node) - ast_int_val(low_node) + if sl >= 0: + slice_len_set(v, sl) + else: + len_var := new_ir_var("slice_len", TI_INT) + emit(IR_BINARY, len_var, high_var, low_var, OP_SUB, TI_INT) + slice_len_var_set(v, len_var) + return v + v := new_ir_var("elem", TI_INT) // TODO #2026-09-16-16 批 2:元素读定型取**声明面形式**(元素 ti 为 dex ⇒ TI_DEX_S;纯表读) - irv_set_type(v, agg_elem_read_form(arr_var)); - if idx_kind == EXPR_INT { - emit_string_lit_bounds(arr_var, ast_int_val(idx_node)); - emit_slice_lit_bounds(arr_var, ast_int_val(idx_node)); - if pass_before_array_access(arr_var, -1, ast_int_val(idx_node), arr_len_lit) == 0 { - emit(IR_LOAD_INDEX, v, arr_var, 0, ast_int_val(idx_node), 0); - } - } else { - idx_var := gen_expr(idx_node); - idx_var = force_if_thunk(idx_var); - emit_string_bounds(arr_var, idx_var); - emit_slice_bounds(arr_var, idx_var); - if pass_before_array_access(arr_var, idx_var, -1, arr_len_lit) == 0 { - emit(IR_LOAD_INDEX_VAR, v, arr_var, idx_var, 0, 0); - } - } - return v; - } + irv_set_type(v, agg_elem_read_form(arr_var)) + if idx_kind == EXPR_INT: + emit_string_lit_bounds(arr_var, ast_int_val(idx_node)) + emit_slice_lit_bounds(arr_var, ast_int_val(idx_node)) + if pass_before_array_access(arr_var, -1, ast_int_val(idx_node), arr_len_lit) == 0: + emit(IR_LOAD_INDEX, v, arr_var, 0, ast_int_val(idx_node), 0) + else: + idx_var := gen_expr(idx_node) + idx_var = force_if_thunk(idx_var) + emit_string_bounds(arr_var, idx_var) + emit_slice_bounds(arr_var, idx_var) + if pass_before_array_access(arr_var, idx_var, -1, arr_len_lit) == 0: + emit(IR_LOAD_INDEX_VAR, v, arr_var, idx_var, 0, 0) + return v // Enum constructor - if ast_kind(node) == EXPR_ENUM_CONSTRUCTOR { - name_idx := ast_a(node); - s := new_ir_var("enum", TI_UNIT); - emit(IR_MAKE_ENUM, s, name_idx, ast_c(node), 0, 0); - ai : ., mut = 0; - an : ., mut = ast_b(node); // EXPR_ARG chain - loop { - if an < 0 { break; } - val_var := gen_expr(ast_a(an)); - val_var = force_if_thunk(val_var); + if ast_kind(node) == EXPR_ENUM_CONSTRUCTOR: + name_idx := ast_a(node) + s := new_ir_var("enum", TI_UNIT) + emit(IR_MAKE_ENUM, s, name_idx, ast_c(node), 0, 0) + ai : ., mut = 0 + an : ., mut = ast_b(node) // EXPR_ARG chain + loop: + if an < 0: + break + val_var := gen_expr(ast_a(an)) + val_var = force_if_thunk(val_var) // 容量批 T2:可选载荷写点规范化(载荷类型 = 变体声明面;`Some`/`None` 关键字 // 形不带变体行 ⇒ enum_payload_ti 返回 -1 ⇒ 原样,不装箱) // 批 5(opt-dex · R2 序修正):先归形式、后装箱(同上——反序 = 漏斗空转) - val_var = dex_slot_norm(val_var); // apx 批 T3:载荷槽恒精确 - if g_optrep_on != 0 { val_var = box_for_optional_slot(ast_a(an), val_var, enum_payload_ti(name_idx, ai)); } - emit(IR_STORE_FIELD, -1, s, val_var, ai + 1, 0); // +1 for tag offset - an = ast_b(an); - ai = ai + 1; - } - return s; - } + val_var = dex_slot_norm(val_var) // apx 批 T3:载荷槽恒精确 + if g_optrep_on != 0: + val_var = box_for_optional_slot(ast_a(an), val_var, enum_payload_ti(name_idx, ai)) + emit(IR_STORE_FIELD, -1, s, val_var, ai + 1, 0) // +1 for tag offset + an = ast_b(an) + ai = ai + 1 + return s // Struct literal - if ast_kind(node) == EXPR_STRUCT { + if ast_kind(node) == EXPR_STRUCT: // F5 契约(见 parser.cr struct 分支):a=name idx、b=首 wrapper(连续)、c=字段数; // wrapper.a=字段值节点(gen_expr 对 EXPR_NONE 前向)。逐 wrapper 解引用,不得按偏移 // 直取相邻节点当字段值——复合字段值子树占多槽会错位(静默错误值)。 @@ -3053,257 +3132,248 @@ emit(IR_STORE, -1, lv, val_var, 0, 0); // 回落)。**存字段位按名字解出**(与 Python bootstrap 的 gen_struct_lit 同语义)—— // 修复前按 wrapper 序直取 fi = 声明位序绑定 ⇒ P{b:11, a:22} 静默得 a=11。发出顺序 // 仍是**源序**(求值顺序 = 源码书写顺序,与 bootstrap 一致)。 - name_ni := ast_a(node); - s := new_ir_var("struct", TI_UNIT); - emit(IR_ALLOC_STRUCT, s, 0, 0, name_ni, 0); - si := find_struct_by_name(name_ni); - fi : ., mut = 0; - fn2 : ., mut = ast_b(node); - loop { - if fi >= ast_c(node) { break; } - if fn2 >= 0 { + name_ni := ast_a(node) + s := new_ir_var("struct", TI_UNIT) + emit(IR_ALLOC_STRUCT, s, 0, 0, name_ni, 0) + si := find_struct_by_name(name_ni) + fi : ., mut = 0 + fn2 : ., mut = ast_b(node) + loop: + if fi >= ast_c(node): + break + if fn2 >= 0: // fn2 = wrapper node (kind=EXPR_NONE, a=value expr, b=field name idx) - val_var := gen_expr(fn2); - val_var = force_if_thunk(val_var); - field_idx : ., mut = fi; - nn := ast_b(fn2); - if si >= 0 && nn >= 0 { - jdi := struct_field_index_by_name(si, nn); - if jdi >= 0 { field_idx = jdi; } - } + val_var := gen_expr(fn2) + val_var = force_if_thunk(val_var) + field_idx : ., mut = fi + nn := ast_b(fn2) + if si >= 0 && nn >= 0: + jdi := struct_field_index_by_name(si, nn) + if jdi >= 0: + field_idx = jdi // 容量批 T2:可选字段写点规范化(字面量形;元素值节点 = wrapper.a) // 批 5(opt-dex · R2 序修正):先归形式、后装箱(同上) - val_var = dex_slot_norm(val_var); // apx 批 T3:字段槽恒精确 - if g_optrep_on != 0 { val_var = box_for_optional_slot(ast_a(fn2), val_var, struct_row_field_ti(si, field_idx)); } - emit(IR_STORE_FIELD, -1, s, val_var, field_idx, 0); - fn2 = fn2 + 1; - } - fi = fi + 1; - } - return s; - } + val_var = dex_slot_norm(val_var) // apx 批 T3:字段槽恒精确 + if g_optrep_on != 0: + val_var = box_for_optional_slot(ast_a(fn2), val_var, struct_row_field_ti(si, field_idx)) + emit(IR_STORE_FIELD, -1, s, val_var, field_idx, 0) + fn2 = fn2 + 1 + fi = fi + 1 + return s // Array literal - if ast_kind(node) == EXPR_ARRAY { + if ast_kind(node) == EXPR_ARRAY: // F5 契约(见 parser.cr 下标分支):a=首 wrapper(连续)、b=元素个数;wrapper.a=元素值 // 节点(gen_expr 对 EXPR_NONE 前向)。逐 wrapper 解引用,不得按偏移直取相邻节点。 - v := new_ir_var("arr", TI_UNIT); - emit(IR_ALLOC_ARRAY, v, ast_b(node), 0, 0, 0); - elem_ti : ., mut = TI_INT; + v := new_ir_var("arr", TI_UNIT) + emit(IR_ALLOC_ARRAY, v, ast_b(node), 0, 0, 0) + elem_ti : ., mut = TI_INT // (A) T3(裁-T3-1):**数组级元素可选性预扫**——元素序在后的 Some/None 也必须影响 // 在前的裸元素(`[2, Some(1)]`)⇒ 装箱判定不能只按逐元素形态。 - elem_opt_ti : ., mut = -1; - if g_optrep_on != 0 { - pn : ., mut = ast_a(node); - pi : ., mut = 0; - loop { - if pi >= ast_b(node) { break; } - if pn >= 0 { - pet := elem_ti_of_node(ast_a(pn)); - if pet >= 0 { elem_opt_ti = pet; } - } - pn = pn + 1; // wrapper 连续(F5 契约) - pi = pi + 1; - } - } - ei : ., mut = 0; - en : ., mut = ast_a(node); - loop { - if ei >= ast_b(node) { break; } - if en >= 0 { - e_var := gen_expr(en); - e_var = force_if_thunk(e_var); - if ei == 0 { elem_ti = irv_type(e_var); } // 先取原元素类型(装箱前) + elem_opt_ti : ., mut = -1 + if g_optrep_on != 0: + pn : ., mut = ast_a(node) + pi : ., mut = 0 + loop: + if pi >= ast_b(node): + break + if pn >= 0: + pet := elem_ti_of_node(ast_a(pn)) + if pet >= 0: + elem_opt_ti = pet + pn = pn + 1 // wrapper 连续(F5 契约) + pi = pi + 1 + ei : ., mut = 0 + en : ., mut = ast_a(node) + loop: + if ei >= ast_b(node): + break + if en >= 0: + e_var := gen_expr(en) + e_var = force_if_thunk(e_var) + if ei == 0: + elem_ti = irv_type(e_var) + // 先取原元素类型(装箱前) // 容量批 T2:可选元素写点规范化(字面量形;元素槽无声明面 ⇒ 按元素 // 表达式可选性保守判定——ident/调用覆盖面,其余形态登记)。 // 注意:数组字面量的 en 是 **wrapper** 节点(值在 ast_a)——须解引用后判定。 // (A) T3:数组级可选(预扫得)⇒ 逐元素判定亦须为真(裸元素装箱)。 // 批 5(opt-dex · R2 序修正):先归形式、后装箱(同上) - e_var = dex_slot_norm(e_var); // apx 批 T3:元素槽恒精确 - if g_optrep_on != 0 { - eo := elem_node_optional(ast_a(en)); - if elem_opt_ti >= 0 { eo = 1; } - e_var = box_for_slot_flag(ast_a(en), e_var, eo); - } - emit(IR_STORE_INDEX, -1, v, e_var, ei, 0); - en = en + 1; - } - ei = ei + 1; - } - irv_set_type(v, alloc_type(TYP_ARRAY, elem_ti, ast_b(node))); + e_var = dex_slot_norm(e_var) // apx 批 T3:元素槽恒精确 + if g_optrep_on != 0: + eo := elem_node_optional(ast_a(en)) + if elem_opt_ti >= 0: + eo = 1 + e_var = box_for_slot_flag(ast_a(en), e_var, eo) + emit(IR_STORE_INDEX, -1, v, e_var, ei, 0) + en = en + 1 + ei = ei + 1 + irv_set_type(v, alloc_type(TYP_ARRAY, elem_ti, ast_b(node))) // (A) T3(裁-T3-1):**可选元素数组 ⇒ 登记声明面**(元素写点 `elem_ti_of` 据此装箱; // 非可选不登记 ⇒ 与既有语料/非可选程序零足迹)。IR 型面不动(只登记声明面)。 - if g_optrep_on != 0 && elem_opt_ti >= 0 { - irv_set_decl_ti(v, alloc_type(TYP_ARRAY, elem_opt_ti, ast_b(node))); - } - return v; - } + if g_optrep_on != 0 && elem_opt_ti >= 0: + irv_set_decl_ti(v, alloc_type(TYP_ARRAY, elem_opt_ti, ast_b(node))) + return v // Range expression (evaluates both ends, returns end) - if ast_kind(node) == EXPR_RANGE { - start_var := gen_expr(ast_a(node)); - start_var = force_if_thunk(start_var); - end_var := gen_expr(ast_b(node)); - end_var = force_if_thunk(end_var); - return end_var; - } + if ast_kind(node) == EXPR_RANGE: + start_var := gen_expr(ast_a(node)) + start_var = force_if_thunk(start_var) + end_var := gen_expr(ast_b(node)) + end_var = force_if_thunk(end_var) + return end_var // Break / Continue - if ast_kind(node) == EXPR_BREAK { - if g_ir_loop_depth > 0 { - emit(IR_JUMP, -1, r64(g_ir_loop_exit, (g_ir_loop_depth - 1) * 8), 0, 0, 0); - } - return -1; - } - if ast_kind(node) == EXPR_CONTINUE { - if g_ir_loop_depth > 0 { - emit(IR_JUMP, -1, r64(g_ir_loop_header, (g_ir_loop_depth - 1) * 8), 0, 0, 0); - } - return -1; - } - - if ast_kind(node) == EXPR_WILDCARD { return -1; } - if ast_kind(node) == EXPR_ENUMPAT { return -1; } - if ast_kind(node) == EXPR_MOVE { - return gen_expr(ast_a(node)); - } - if ast_kind(node) == EXPR_UNSAFE { - sg_alloc_push(SG_UNSAFE); - arena_var := new_ir_var("_arena", TI_INT); - w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var); - emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0); - arena_instr := g_ir_instr_count - 1; - ret := gen_expr(ast_a(node)); - total := r64(g_sg_alloc_total, g_sg_count - 1); - if total > 0 { iri_set_s1(arena_instr, total); } - sg_alloc_pop(); - return ret; - } - if ast_kind(node) == EXPR_AS { - inner_var := gen_expr(ast_a(node)); - inner_var = force_if_thunk(inner_var); - target_ti := ti_from_type_expr(ast_b(node)); - if get_type_kind(target_ti) == TYP_PTR { - source_ti := irv_type(inner_var); - source_kind := get_type_kind(source_ti); - asp : ., mut = 1; - if source_kind == TYP_PTR { - asp = get_type_extra(source_ti); - } else if source_kind == TYP_REF || is_byte_buf_var(inner_var) != 0 { - asp = 0; - } - target_ti = alloc_type(TYP_PTR, get_type_data(target_ti), asp); - } - cast_var := new_ir_var("_cast", target_ti); - emit(IR_LOAD, cast_var, inner_var, 0, 0, target_ti); - return cast_var; - } - if ast_kind(node) == EXPR_TRY { + if ast_kind(node) == EXPR_BREAK: + if g_ir_loop_depth > 0: + emit(IR_JUMP, -1, r64(g_ir_loop_exit, (g_ir_loop_depth - 1) * 8), 0, 0, 0) + return -1 + if ast_kind(node) == EXPR_CONTINUE: + if g_ir_loop_depth > 0: + emit(IR_JUMP, -1, r64(g_ir_loop_header, (g_ir_loop_depth - 1) * 8), 0, 0, 0) + return -1 + + if ast_kind(node) == EXPR_WILDCARD: + return -1 + if ast_kind(node) == EXPR_ENUMPAT: + return -1 + if ast_kind(node) == EXPR_MOVE: + return gen_expr(ast_a(node)) + if ast_kind(node) == EXPR_UNSAFE: + sg_alloc_push(SG_UNSAFE) + arena_var := new_ir_var("_arena", TI_INT) + w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var) + emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0) + arena_instr := g_ir_instr_count - 1 + ret := gen_expr(ast_a(node)) + total := r64(g_sg_alloc_total, g_sg_count - 1) + if total > 0: + iri_set_s1(arena_instr, total) + sg_alloc_pop() + return ret + if ast_kind(node) == EXPR_AS: + inner_var := gen_expr(ast_a(node)) + inner_var = force_if_thunk(inner_var) + target_ti := ti_from_type_expr(ast_b(node)) + if get_type_kind(target_ti) == TYP_PTR: + source_ti := irv_type(inner_var) + source_kind := get_type_kind(source_ti) + asp : ., mut = 1 + if source_kind == TYP_PTR: + asp = get_type_extra(source_ti) + else if source_kind == TYP_REF || is_byte_buf_var(inner_var) != 0: + asp = 0 + target_ti = alloc_type(TYP_PTR, get_type_data(target_ti), asp) + cast_var := new_ir_var("_cast", target_ti) + emit(IR_LOAD, cast_var, inner_var, 0, 0, target_ti) + return cast_var + if ast_kind(node) == EXPR_TRY: // R2 P4 Task 5:`?` 解包 = 解包点之一 ⇒ 同规则判表示:裸值(0)→ 槽值即载荷 // (直取);装箱(≠0)→ 字段 1(tag 之后)。无表示位(未覆盖面/非可选)→ 既有 // 行为**逐字不变**(原样返回内层表达式值)。 - inner := gen_expr(ast_a(node)); - if g_optrep_on != 0 && inner >= 0 { - rv := irv_rep(inner); - if rv >= 0 { - dest := new_ir_var("tryv", irv_type(inner)); - bl := new_label(); - xl := new_label(); - xend := new_label(); - zb := new_ir_var("_rz", TI_INT); - emit(IR_CONST, zb, 0, 0, 0, TI_INT); - ib := new_ir_var("rep_isbare", TI_INT); - emit(IR_BINARY, ib, rv, zb, OP_EQ, 0); - emit(IR_BRANCH, -1, ib, bl, xl, 0); - emit(IR_LABEL, -1, bl, 0, 0, 0); - emit(IR_STORE, -1, dest, inner, 0, 0); - emit(IR_JUMP, -1, xend, 0, 0, 0); - emit(IR_LABEL, -1, xl, 0, 0, 0); - emit(IR_LOAD_FIELD, dest, inner, 0, 1, 0); - emit(IR_LABEL, -1, xend, 0, 0, 0); - return dest; - } - } - return inner; - } - if ast_kind(node) == EXPR_STRUCTPAT { - return -1; - } - if ast_kind(node) == EXPR_STMT { - gen_expr(ast_a(node)); - return -1; - } - if ast_kind(node) == EXPR_TUPLE { + inner := gen_expr(ast_a(node)) + if g_optrep_on != 0 && inner >= 0: + rv := irv_rep(inner) + if rv >= 0: + dest := new_ir_var("tryv", irv_type(inner)) + bl := new_label() + xl := new_label() + xend := new_label() + zb := new_ir_var("_rz", TI_INT) + emit(IR_CONST, zb, 0, 0, 0, TI_INT) + ib := new_ir_var("rep_isbare", TI_INT) + emit(IR_BINARY, ib, rv, zb, OP_EQ, 0) + emit(IR_BRANCH, -1, ib, bl, xl, 0) + emit(IR_LABEL, -1, bl, 0, 0, 0) + emit(IR_STORE, -1, dest, inner, 0, 0) + emit(IR_JUMP, -1, xend, 0, 0, 0) + emit(IR_LABEL, -1, xl, 0, 0, 0) + emit(IR_LOAD_FIELD, dest, inner, 0, 1, 0) + emit(IR_LABEL, -1, xend, 0, 0, 0) + return dest + return inner + if ast_kind(node) == EXPR_STRUCTPAT: + return -1 + if ast_kind(node) == EXPR_STMT: + gen_expr(ast_a(node)) + return -1 + if ast_kind(node) == EXPR_TUPLE: // Tuple: allocate array for N elements, store each // F5 契约:a=首 wrapper(g_ast 中连续)、b=元素个数;wrapper.a = 元素值节点 // (复合元素值节点不连续,须经 wrapper 解引用——见 checker.cr EXPR_TUPLE 注)。 - elem_idx := ast_a(node); - ec : ., mut = ast_b(node); - tv := new_ir_var("tuple", TI_INT); - emit(IR_ALLOC_ARRAY, tv, ec, 0, 8, 0); // alloc N * 8 bytes + elem_idx := ast_a(node) + ec : ., mut = ast_b(node) + tv := new_ir_var("tuple", TI_INT) + emit(IR_ALLOC_ARRAY, tv, ec, 0, 8, 0) // alloc N * 8 bytes // Store each element at its offset - e : ., mut = 0; - loop { - if e >= ec { break; } - en : ., mut = -1; - if elem_idx >= 0 { en = ast_a(elem_idx + e); } - elem_var := gen_expr(en); - elem_var = force_if_thunk(elem_var); + e : ., mut = 0 + loop: + if e >= ec: + break + en : ., mut = -1 + if elem_idx >= 0: + en = ast_a(elem_idx + e) + elem_var := gen_expr(en) + elem_var = force_if_thunk(elem_var) // 容量批 T2:可选元素写点规范化(元组元素槽无声明面 ⇒ 按元素表达式可选性 // 保守判定;ident/调用覆盖面,其余形态登记) - if g_optrep_on != 0 { elem_var = box_for_slot_flag(en, elem_var, elem_node_optional(en)); } - elem_var = dex_slot_norm(elem_var); // apx 批 T3:元组元素槽恒精确 - emit(IR_STORE_FIELD, -1, tv, elem_var, e, 0); - e = e + 1; - } - return tv; - } + if g_optrep_on != 0: + elem_var = box_for_slot_flag(en, elem_var, elem_node_optional(en)) + elem_var = dex_slot_norm(elem_var) // apx 批 T3:元组元素槽恒精确 + emit(IR_STORE_FIELD, -1, tv, elem_var, e, 0) + e = e + 1 + return tv - return -1; -} + return -1 // --- Generate IR for one function --- -fn ir_gen_func(fi: int) { +fn ir_gen_func(fi: int): // Skip generic functions — they will be monomorphized at call sites - if fi_generic_count(fi) > 0 { return; } - fn_node := fi_ast_node(fi); - name_idx := ast_a(fn_node); - first_param := ast_b(fn_node); - param_count := ast_c(fn_node); + if fi_generic_count(fi) > 0: + return + fn_node := fi_ast_node(fi) + name_idx := ast_a(fn_node) + first_param := ast_b(fn_node) + param_count := ast_c(fn_node) // 返回类型:从 FuncInfo 取原始 TY_* 常量(ast_type_val(fn_node) 是返回类型 // 节点下标而非类型常量——错读会使 g_cur_ret_ti 不等于 TI_DEX,apx 返回点 // bits→scaled 转换失效,仅在 dex 类型节点下标恰为 1 时碰巧生效) - ret_ti := fi_return_type(fi); - body := ast_data(fn_node); + ret_ti := fi_return_type(fi) + body := ast_data(fn_node) // Record function metadata - func_idx := g_ir_func_count; - grow_ir_func_meta(func_idx + 1); - w64(g_ir_func_name_idx, func_idx * 8, name_idx); - w64(g_ir_func_ret_type, func_idx * 8, ret_ti); - w64(g_ir_func_instr_start, func_idx * 8, g_ir_instr_count); - w64(g_ir_func_var_start, func_idx * 8, g_ir_var_count); - w64(g_ir_func_param_count, func_idx * 8, param_count); + func_idx := g_ir_func_count + grow_ir_func_meta(func_idx + 1) + w64(g_ir_func_name_idx, func_idx * 8, name_idx) + w64(g_ir_func_ret_type, func_idx * 8, ret_ti) + w64(g_ir_func_instr_start, func_idx * 8, g_ir_instr_count) + w64(g_ir_func_var_start, func_idx * 8, g_ir_var_count) + w64(g_ir_func_param_count, func_idx * 8, param_count) // Create IR vars for params - pi : ., mut = 0; - pn : ., mut = first_param; - loop { - if pi >= param_count { break; } - if pn < 0 { break; } - pname_idx := ast_a(pn); - pname := istr_get(pname_idx); - param_type : ., mut = ast_type_val(pn); - if param_type < 0 { param_type = TI_INT; } + pi : ., mut = 0 + pn : ., mut = first_param + loop: + if pi >= param_count: + break + if pn < 0: + break + pname_idx := ast_a(pn) + pname := istr_get(pname_idx) + param_type : ., mut = ast_type_val(pn) + if param_type < 0: + param_type = TI_INT // dex 边界规则(数值迁移 Task 4):参数一律精确形式(缩放整数,整数寄存器传递) - if param_type == TI_DEX { param_type = TI_DEX_S; } + if param_type == TI_DEX: + param_type = TI_DEX_S // 批 5(opt-dex · R3):`dex?` 形参槽型 —— 修复前 `unpack_type(EXPR_OPTIONAL)` 返 0 // (parser.cr:150-153)⇒ `EXPR_PARAM.type_val` = 0 = `TI_INT` ⇒ 槽型按 int 建、 // 而调用点按实参 var 的 `TI_DEX` 分类为 binary64(XMM)⇒ **ABI 失配**(按 XMM 传、 // 按 GP 读 = 垃圾值 + 双路径分歧)。槽型按**声明面节点**定 = `TI_DEX_S`(GP 类, // 与调用点转换后的实参一致)。 - else if dex_opt_type_node(ast_data(pn)) != 0 { param_type = TI_DEX_S; } + else if dex_opt_type_node(ast_data(pn)) != 0: + param_type = TI_DEX_S // ── S4 形参半(2026-09-21):`&T` 形参槽型按**声明面节点**定(照上行 `dex?` 先例同形)── // **背景(预存缺陷)**:`ast_type_val(pn)` 对 `&T` = **0**(`EXPR_REFTYPE` 节点未填写类型索引; // 上面 `if param_type < 0` 护栏拦不住 0)⇒ 槽型退化成 `TI_INT` ⇒ **REF 身份在 IR 形参定型处丢失** @@ -3312,131 +3382,133 @@ fn ir_gen_func(fi: int) { // **只查不建**:`checker` 解析签名时**已**为该 `&T` 建过 REF 行(实测类型表中存在 `kind 3`) // ⇒ 线性查找即可 ⇒ **零新增类型行**。⚠ `alloc_type` 是**裸分配器、不去重**(`checker.cr:10` 注) // ⇒ 若在此另分配一行,会写进 TYPE 段 ⇒ 动产物字节 ⇒ 那正是本笔要避免的。 - else if ast_kind(ast_data(pn)) == EXPR_REFTYPE { - rinner := ti_from_type_expr(ast_a(ast_data(pn))); - rmf := ast_int_val(ast_data(pn)); - ri : ., mut = 0; - loop { if ri >= g_type_count { break; } - if get_type_kind(ri) == TYP_REF && get_type_data(ri) == rinner && get_type_extra(ri) == rmf { - param_type = ri; - break; - } - ri = ri + 1; - } - } - pvar := new_ir_var(pname, param_type); + else if ast_kind(ast_data(pn)) == EXPR_REFTYPE: + rinner := ti_from_type_expr(ast_a(ast_data(pn))) + rmf := ast_int_val(ast_data(pn)) + ri : ., mut = 0 + loop: + if ri >= g_type_count: + break + if get_type_kind(ri) == TYP_REF && get_type_data(ri) == rinner && get_type_extra(ri) == rmf: + param_type = ri + break + ri = ri + 1 + pvar := new_ir_var(pname, param_type) // Bind param name - bind_local(pname_idx, pvar); + bind_local(pname_idx, pvar) // (乙) A1 判据通道(`--dump-params`,隐藏):**槽型直读** = 判据 P2 的仪器 // (现 CLI 无 IR 变量槽型直读:`cir` 文本 dump 只有逐指令、`--dump-tk-terms` 是 // DFNode.TK **派生面**、`alloc d : unit` 那行是 decl 面)。纯表读 // (`irv_type`/`ast_type_val`/`istr_get` + `int_str`)⇒ 零 alloc 副作用、 // **rc 中性 + 零产物**(用不用该 flag 产物逐字节不变)。 // `decl` = 声明面节点 `type_val`:泛型形参 = 0 ⇒ 与 `slot` 并排即「擦除」的直接证据。 - if g_dump_params_on != 0 { - print("PARAM "); print(istr_get(name_idx)); - print(" p"); print(int_str(pi)); - print(" "); print(pname); - print(" slot="); print(int_str(irv_type(pvar))); - print(" decl="); print(int_str(ast_type_val(pn))); - print("\n"); - } + if g_dump_params_on != 0: + print("PARAM ") + print(istr_get(name_idx)) + print(" p") + print(int_str(pi)) + print(" ") + print(pname) + print(" slot=") + print(int_str(irv_type(pvar))) + print(" decl=") + print(int_str(ast_type_val(pn))) + print("\n") // 可选表示(R2 P4 Task 5):形参表示位——**序言最早处**从实参信道读(先于任何 // 可能改写信道的调用;调用点在 IR_CALL 前写)。形参类型节点 = EXPR_PARAM.data。 - ptn := ast_data(pn); + ptn := ast_data(pn) // 容量批 T2:形参声明类型登记(元素写点判定用;与表示位面互不干扰) - if g_optrep_on != 0 && ptn >= 0 { irv_set_decl_ti(pvar, res_type_node(ptn)); } - if g_optrep_on != 0 && g_optrep_arg_count > 0 && ptn >= 0 && pi < g_optrep_arg_count { - pti := res_type_node(ptn); - if pti >= 0 && get_type_kind(pti) == TYP_OPTIONAL { - prv := new_ir_var(pname + "_prep", TI_INT); - emit(IR_LOAD, prv, g_optrep_arg_cell0 + pi, 0, 0, TI_INT); - irv_set_rep(pvar, prv); + if g_optrep_on != 0 && ptn >= 0: + irv_set_decl_ti(pvar, res_type_node(ptn)) + if g_optrep_on != 0 && g_optrep_arg_count > 0 && ptn >= 0 && pi < g_optrep_arg_count: + pti := res_type_node(ptn) + if pti >= 0 && get_type_kind(pti) == TYP_OPTIONAL: + prv := new_ir_var(pname + "_prep", TI_INT) + emit(IR_LOAD, prv, g_optrep_arg_cell0 + pi, 0, 0, TI_INT) + irv_set_rep(pvar, prv) // (A) 批(INV-1):**取址形参**恒装箱——序言内条件装箱(信道 rep = 0 裸值 ⇒ 装箱) // 并把表示位钉 1(后续含指针写在内的一切写点都由 W3/W2 保持该不变量) - if addr_taken_of(pname_idx) != 0 { - zb := new_ir_var("_rz", TI_INT); - emit(IR_CONST, zb, 0, 0, 0, TI_INT); - isb := new_ir_var("prep_isbare", TI_INT); - emit(IR_BINARY, isb, prv, zb, OP_EQ, 0); - bare_lbl := new_label(); - end_lbl := new_label(); - emit(IR_BRANCH, -1, isb, bare_lbl, end_lbl, 0); - emit(IR_LABEL, -1, bare_lbl, 0, 0, 0); - boxed := emit_box_some(pvar); - emit(IR_STORE, -1, pvar, boxed, 0, 0); - one := new_ir_var("prep_one", TI_INT); - emit(IR_CONST, one, 1, 0, 0, TI_INT); - emit(IR_STORE, -1, prv, one, 0, 0); - emit(IR_LABEL, -1, end_lbl, 0, 0, 0); - } - } - } - pi = pi + 1; + if addr_taken_of(pname_idx) != 0: + zb := new_ir_var("_rz", TI_INT) + emit(IR_CONST, zb, 0, 0, 0, TI_INT) + isb := new_ir_var("prep_isbare", TI_INT) + emit(IR_BINARY, isb, prv, zb, OP_EQ, 0) + bare_lbl := new_label() + end_lbl := new_label() + emit(IR_BRANCH, -1, isb, bare_lbl, end_lbl, 0) + emit(IR_LABEL, -1, bare_lbl, 0, 0, 0) + boxed := emit_box_some(pvar) + emit(IR_STORE, -1, pvar, boxed, 0, 0) + one := new_ir_var("prep_one", TI_INT) + emit(IR_CONST, one, 1, 0, 0, TI_INT) + emit(IR_STORE, -1, prv, one, 0, 0) + emit(IR_LABEL, -1, end_lbl, 0, 0, 0) + pi = pi + 1 // Scan past type nodes to next EXPR_PARAM - pn = pn + 1; - loop { - if pn >= g_ast_count { break; } - if ast_kind(pn) == EXPR_PARAM { break; } - pn = pn + 1; - } - } + pn = pn + 1 + loop: + if pn >= g_ast_count: + break + if ast_kind(pn) == EXPR_PARAM: + break + pn = pn + 1 // Function-level arena (df_begin_func already pushed SG_FUNC) - grow_sg_alloc(g_sg_count + 1); - grow_sg_arena_var(g_sg_count + 1); - w64(g_sg_alloc_total, (g_sg_count - 1) * 8, 0); - arena_var := new_ir_var("_arena", TI_INT); - w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var); - emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0); - arena_instr := g_ir_instr_count - 1; + grow_sg_alloc(g_sg_count + 1) + grow_sg_arena_var(g_sg_count + 1) + w64(g_sg_alloc_total, (g_sg_count - 1) * 8, 0) + arena_var := new_ir_var("_arena", TI_INT) + w64(g_sg_arena_var, (g_sg_count - 1) * 8, arena_var) + emit(IR_ARENA_NEW, arena_var, 0, 0, 0, 0) + arena_instr := g_ir_instr_count - 1 // 程序启动期全局初始化(2026-09-10 R1 ②):只在 main 序言注入——run 与 build // 两路径都从 main 进入(interp.cr 按名查找 main;ELF _start call main),因此 // 无需新 IR 函数/新 .ccr 段/新 _start 指令 = 无序列化与字节布局扰动。 // 无需运行期初始化的程序不发射任何指令(零变化)。 - if str_eq(istr_get(name_idx), "main") != 0 { inject_global_inits(); } + if str_eq(istr_get(name_idx), "main") != 0: + inject_global_inits() // Generate body(记录返回 TI——EXPR_RETURN 的 dex 边界转换用) - g_cur_ret_ti = ret_ti; + g_cur_ret_ti = ret_ti // 批 5(opt-dex · R3):返回类型节点是否 `dex?`(节点级零 alloc)。`-> dex?` 的 // `ret_ti`(= `fi_return_type` 裸码)与 `type_val` 均为 0(`unpack_type(EXPR_OPTIONAL)`) // ⇒ 返回点 dex 转换门 `g_cur_ret_ti == TI_DEX` 恒假 ⇒ 需本标志补位。 - g_cur_ret_dex_opt = 0; - rtn_d := ast_type_val(fn_node); - if rtn_d >= 0 && dex_opt_type_node(rtn_d) != 0 { g_cur_ret_dex_opt = 1; } + g_cur_ret_dex_opt = 0 + rtn_d := ast_type_val(fn_node) + if rtn_d >= 0 && dex_opt_type_node(rtn_d) != 0: + g_cur_ret_dex_opt = 1 // 可选表示(R2 P4 Task 5):本函数返回可选时,返回点写返回信道(见 EXPR_RETURN)。 // 判据走**返回类型节点**(ast_type_val(fn_node) = 返回类型节点下标——见上方 ret_ti // 注释)而非 fi_return_type 裸码(`T?` 的类型节点 type_val = 0 ⇒ 恒判否)。 - g_cur_ret_opt = 0; - if g_optrep_on != 0 && g_optrep_ret_cell >= 0 { - rtn := ast_type_val(fn_node); - if rtn >= 0 { - rti := res_type_node(rtn); - if rti >= 0 && rti < g_type_count && get_type_kind(rti) == TYP_OPTIONAL { g_cur_ret_opt = 1; } - } - } - if body >= 0 { - gen_expr(body); - } - g_cur_ret_ti = -1; - g_cur_ret_opt = 0; - g_cur_ret_dex_opt = 0; + g_cur_ret_opt = 0 + if g_optrep_on != 0 && g_optrep_ret_cell >= 0: + rtn := ast_type_val(fn_node) + if rtn >= 0: + rti := res_type_node(rtn) + if rti >= 0 && rti < g_type_count && get_type_kind(rti) == TYP_OPTIONAL: + g_cur_ret_opt = 1 + if body >= 0: + gen_expr(body) + g_cur_ret_ti = -1 + g_cur_ret_opt = 0 + g_cur_ret_dex_opt = 0 // Patch arena size and reset before return - total := r64(g_sg_alloc_total, (g_sg_count - 1) * 8); - if total > 0 { iri_set_s1(arena_instr, total); } - emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0); + total := r64(g_sg_alloc_total, (g_sg_count - 1) * 8) + if total > 0: + iri_set_s1(arena_instr, total) + emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0) // Add return at end if not already terminated(可达 = 兜底 return;不可达 = 死码, // 两后端同语义不执行)。可选返回点写装箱默认值(与 ABI 返回寄存器的未定义值同档)。 - if g_cur_ret_opt != 0 { emit_rep_set(g_optrep_ret_cell, oe_boxed()); } - emit(IR_RETURN, -1, -1, 0, 0, 0); + if g_cur_ret_opt != 0: + emit_rep_set(g_optrep_ret_cell, oe_boxed()) + emit(IR_RETURN, -1, -1, 0, 0, 0) - w64(g_ir_func_instr_count, func_idx * 8, g_ir_instr_count - r64(g_ir_func_instr_start, func_idx * 8)); - w64(g_ir_func_var_count, func_idx * 8, g_ir_var_count - r64(g_ir_func_var_start, func_idx * 8)); - g_ir_func_count = func_idx + 1; -} + w64(g_ir_func_instr_count, func_idx * 8, g_ir_instr_count - r64(g_ir_func_instr_start, func_idx * 8)) + w64(g_ir_func_var_count, func_idx * 8, g_ir_var_count - r64(g_ir_func_var_start, func_idx * 8)) + g_ir_func_count = func_idx + 1 // --- Initialize global IR vars from global lets --- @@ -3445,651 +3517,684 @@ fn ir_gen_func(fi: int) { // NB: applies to mutable AND immutable lets (mut/const init values both // need to be written at startup — unlike find_global_const_node which // only folds immutable constants at compile time). -fn global_init_val(name_idx: int) -> int { - i : ., mut = g_global_let_count - 1; - loop { - if i < 0 { break; } - node := r64(g_global_lets, i * 8); - if ast_a(node) == name_idx { - value_node := ast_c(node); - if value_node >= 0 { - vk := ast_kind(value_node); - if vk == EXPR_INT || vk == EXPR_BOOL { - return ast_int_val(value_node); - } - if vk == EXPR_DEX { +fn global_init_val(name_idx: int) -> int: + i : ., mut = g_global_let_count - 1 + loop: + if i < 0: + break + node := r64(g_global_lets, i * 8) + if ast_a(node) == name_idx: + value_node := ast_c(node) + if value_node >= 0: + vk := ast_kind(value_node) + if vk == EXPR_INT || vk == EXPR_BOOL: + return ast_int_val(value_node) + if vk == EXPR_DEX: // dex 全局常量:定点缩放整数(精确形式初始值;apx 位模式由 // reg_one_global 从节点 a 取——见该函数) - return ast_int_val(value_node); - } - if vk == EXPR_UNARY && ast_c(value_node) == UOP_NEG { - inner := ast_a(value_node); - if ast_kind(inner) == EXPR_INT || ast_kind(inner) == EXPR_BOOL { - return 0 - ast_int_val(inner); - } - if ast_kind(inner) == EXPR_DEX { - return 0 - ast_int_val(inner); - } - } - } - } - i = i - 1; - } - return 0; -} + return ast_int_val(value_node) + if vk == EXPR_UNARY && ast_c(value_node) == UOP_NEG: + inner := ast_a(value_node) + if ast_kind(inner) == EXPR_INT || ast_kind(inner) == EXPR_BOOL: + return 0 - ast_int_val(inner) + if ast_kind(inner) == EXPR_DEX: + return 0 - ast_int_val(inner) + i = i - 1 + return 0 // 类型节点 → `[T; N]` 的元素数 N(`[T]` 切片 = 0);非聚合 = -1。 // 类型别名解析一层:`type Arr = [int;2]; g : Arr;` 的声明类型节点是 EXPR_IDENT // (parser.cr parse_type 的用户类型分支),须经 g_type_aliases({name_idx, type_node} // 16B/条)回到底层 EXPR_ARRAY——否则同一「定长数组全局」类仍留 SIGSEGV。 -fn agg_elem_count_of(tn: int) -> int { - if tn < 0 { return -1; } - if ast_kind(tn) == EXPR_ARRAY { return ast_int_val(tn); } - if ast_kind(tn) == EXPR_IDENT { - ni := ast_int_val(tn); - ai : ., mut = 0; - loop { - if ai >= g_type_alias_count { break; } - if r64(g_type_aliases, ai * 16) == ni { - rt := r64(g_type_aliases, ai * 16 + 8); - if rt >= 0 && ast_kind(rt) == EXPR_ARRAY { return ast_int_val(rt); } - break; - } - ai = ai + 1; - } - } - return -1; -} +fn agg_elem_count_of(tn: int) -> int: + if tn < 0: + return -1 + if ast_kind(tn) == EXPR_ARRAY: + return ast_int_val(tn) + if ast_kind(tn) == EXPR_IDENT: + ni := ast_int_val(tn) + ai : ., mut = 0 + loop: + if ai >= g_type_alias_count: + break + if r64(g_type_aliases, ai * 16) == ni: + rt := r64(g_type_aliases, ai * 16 + 8) + if rt >= 0 && ast_kind(rt) == EXPR_ARRAY: + return ast_int_val(rt) + break + ai = ai + 1 + return -1 // 文件级 let 是否需要「运行期初始化」(2026-09-10 语言面收窄 §1.3 / R1 ②)。 // 判据(与 global_init_val 互补——它只认编译期标量常量,其余静默归 0): // ① 声明类型是聚合(`[T; N]`/`[T]`,含类型别名一层解析)→ 必须运行期分配存储; // ② 初值存在且不是 int/bool/dex 字面量(含负号字面量)→ 必须运行期求值。 -fn global_needs_runtime_init(name_idx: int) -> int { - i : ., mut = g_global_let_count - 1; - loop { - if i < 0 { break; } - node := r64(g_global_lets, i * 8); - if ast_a(node) == name_idx { +fn global_needs_runtime_init(name_idx: int) -> int: + i : ., mut = g_global_let_count - 1 + loop: + if i < 0: + break + node := r64(g_global_lets, i * 8) + if ast_a(node) == name_idx: // 容量批 T2:可选全局槽**必须**走运行期初始化——静态度量(.quad 裸值)写进槽后 // 读侧按装箱解引用 ⇒ 双路径 139(实测 e2_global_bare)。装箱在 inject_global_inits // 内完成;非可选全局不受影响(零足迹)。 - if g_optrep_on != 0 && ti_is_optional(global_decl_ti(name_idx)) != 0 { return 1; } - if agg_elem_count_of(ast_b(node)) >= 0 { return 1; } - vn := ast_c(node); - if vn < 0 { return 0; } - vk := ast_kind(vn); - if vk == EXPR_INT || vk == EXPR_BOOL || vk == EXPR_DEX { return 0; } - if vk == EXPR_UNARY && ast_c(vn) == UOP_NEG { - inner := ast_a(vn); - ik := ast_kind(inner); - if ik == EXPR_INT || ik == EXPR_BOOL || ik == EXPR_DEX { return 0; } - } - return 1; - } - i = i - 1; - } - return 0; -} + if g_optrep_on != 0 && ti_is_optional(global_decl_ti(name_idx)) != 0: + return 1 + if agg_elem_count_of(ast_b(node)) >= 0: + return 1 + vn := ast_c(node) + if vn < 0: + return 0 + vk := ast_kind(vn) + if vk == EXPR_INT || vk == EXPR_BOOL || vk == EXPR_DEX: + return 0 + if vk == EXPR_UNARY && ast_c(vn) == UOP_NEG: + inner := ast_a(vn) + ik := ast_kind(inner) + if ik == EXPR_INT || ik == EXPR_BOOL || ik == EXPR_DEX: + return 0 + return 1 + i = i - 1 + return 0 // 按 name_idx 查已注册的全局 IR var(未注册 = -1)。 -fn global_var_of(name_idx: int) -> int { - gi : ., mut = 0; - loop { - if gi >= g_ir_global_count { break; } - if r64(g_ir_globals, gi * 24) == name_idx { return r64(g_ir_globals, gi * 24 + 8); } - gi = gi + 1; - } - return -1; -} +fn global_var_of(name_idx: int) -> int: + gi : ., mut = 0 + loop: + if gi >= g_ir_global_count: + break + if r64(g_ir_globals, gi * 24) == name_idx: + return r64(g_ir_globals, gi * 24 + 8) + gi = gi + 1 + return -1 // 把需要运行期初始化的文件级 let 降级为 IR 序列(写进当前函数 = main 序言)。 // 顺序 = g_global_lets 源序(跨全局依赖如 `b : [int;2] = a;` 因此正确)。 -fn inject_global_inits() { - i : ., mut = 0; - loop { - if i >= g_global_let_count { break; } - lnode := r64(g_global_lets, i * 8); - name_idx := ast_a(lnode); - if global_needs_runtime_init(name_idx) != 0 { - gv := global_var_of(name_idx); - if gv >= 0 { - vn := ast_c(lnode); - v : ., mut = -1; - if vn >= 0 { - v = gen_expr(vn); - v = force_if_thunk(v); - } else { +fn inject_global_inits(): + i : ., mut = 0 + loop: + if i >= g_global_let_count: + break + lnode := r64(g_global_lets, i * 8) + name_idx := ast_a(lnode) + if global_needs_runtime_init(name_idx) != 0: + gv := global_var_of(name_idx) + if gv >= 0: + vn := ast_c(lnode) + v : ., mut = -1 + if vn >= 0: + v = gen_expr(vn) + v = force_if_thunk(v) + else: // 无初值聚合:整流分配(零初始化由 alloc 语义保证——rt.s 的 rep stosb; // 解释器 IR_ALLOC_ARRAY 显式清零)。仅 `[T; N]`(N ≥ 1)注入;`[T]` // (切片无长度,N = 0)不注入——保持 BSS 零 = 空切片/哑指针, // 空切片解引用属独立 null 陷阱类,不在本批。 - cnt := agg_elem_count_of(ast_b(lnode)); - if cnt > 0 { - v = new_ir_var("ginit", TI_UNIT); - emit(IR_ALLOC_ARRAY, v, cnt, 0, 0, 0); - irv_set_type(v, alloc_type(TYP_ARRAY, TI_INT, cnt)); - } - } - if v >= 0 { + cnt := agg_elem_count_of(ast_b(lnode)) + if cnt > 0: + v = new_ir_var("ginit", TI_UNIT) + emit(IR_ALLOC_ARRAY, v, cnt, 0, 0, 0) + irv_set_type(v, alloc_type(TYP_ARRAY, TI_INT, cnt)) + if v >= 0: // 容量批 T2:可选全局槽**初值**写点规范化(与赋值点 :1155 是两处独立 // 代码点——初值走 inject_global_inits,赋值走 EXPR_ASSIGN) // 批 5(opt-dex · R2 序修正):先归形式、后装箱(同上——反序 = 漏斗空转) - v = dex_store_adjust(gv, v, vn); // apx 批 T3:全局初值按槽声明型(含 apx 全局) - if g_optrep_on != 0 { v = box_for_optional_slot(vn, v, global_decl_ti(name_idx)); } - emit(IR_STORE, -1, gv, v, 0, 0); - } - } - } - i = i + 1; - } -} + v = dex_store_adjust(gv, v, vn) // apx 批 T3:全局初值按槽声明型(含 apx 全局) + if g_optrep_on != 0: + v = box_for_optional_slot(vn, v, global_decl_ti(name_idx)) + emit(IR_STORE, -1, gv, v, 0, 0) + i = i + 1 // Register one IR global, deduplicated by name_idx. -fn reg_one_global(name_idx: int) { - found : ., mut = 0; - gi : ., mut = 0; - loop { if gi >= g_ir_global_count { break; } - if r64(g_ir_globals, gi * 24) == name_idx { found = 1; break; } - gi = gi + 1; } - if found == 0 { - name := istr_get(name_idx); +fn reg_one_global(name_idx: int): + found : ., mut = 0 + gi : ., mut = 0 + loop: + if gi >= g_ir_global_count: + break + if r64(g_ir_globals, gi * 24) == name_idx: + found = 1 + break + gi = gi + 1 + if found == 0: + name := istr_get(name_idx) // dex 全局变量(数值迁移 Task 4):精确(TI_DEX_S,缩放整数初始值)或 // apx(TI_DEX,binary64 位模式初始值)——按声明 LET 的类型节点与 apx 位 - gtype : ., mut = TI_INT; - is_dex_global : ., mut = 0; - gli : ., mut = 0; - loop { - if gli >= g_global_let_count { break; } - lnode := r64(g_global_lets, gli * 8); - if ast_a(lnode) == name_idx { - ltn := ast_b(lnode); - if ltn >= 0 && ast_kind(ltn) == 0 && ast_type_val(ltn) == TY_DEX { - if ast_int_val(lnode) != 0 { gtype = TI_DEX; } else { gtype = TI_DEX_S; } - is_dex_global = 1; - } else if ltn >= 0 && dex_opt_type_node(ltn) != 0 { + gtype : ., mut = TI_INT + is_dex_global : ., mut = 0 + gli : ., mut = 0 + loop: + if gli >= g_global_let_count: + break + lnode := r64(g_global_lets, gli * 8) + if ast_a(lnode) == name_idx: + ltn := ast_b(lnode) + if ltn >= 0 && ast_kind(ltn) == 0 && ast_type_val(ltn) == TY_DEX: + if ast_int_val(lnode) != 0: + gtype = TI_DEX + else: + gtype = TI_DEX_S + is_dex_global = 1 + else if ltn >= 0 && dex_opt_type_node(ltn) != 0: // 批 5(opt-dex · R1):`dex?` 全局槽 = **规范形式 scaled**(G1 裁决)。 // 修复前本门只认基类型节点 `dex` ⇒ `dex?` 全局落 TI_INT 槽, // 赋值/初值的 dex_store_adjust 因目标型不匹配而空转(实测 15)。 // is_dex_global 不置 1:其唯一消费者(:3320)只服务 apx 位模式全局。 - gtype = TI_DEX_S; - } - break; - } - gli = gli + 1; - } - gvar := new_ir_var(name, gtype); - grow_ir_globals(g_ir_global_count + 1); - w64(g_ir_globals, g_ir_global_count * 24, name_idx); - w64(g_ir_globals, g_ir_global_count * 24 + 8, gvar); + gtype = TI_DEX_S + break + gli = gli + 1 + gvar := new_ir_var(name, gtype) + grow_ir_globals(g_ir_global_count + 1) + w64(g_ir_globals, g_ir_global_count * 24, name_idx) + w64(g_ir_globals, g_ir_global_count * 24 + 8, gvar) // Const initializer — emitted by the ELF backend's _init_globals. - iv : int = global_init_val(name_idx); - if is_dex_global != 0 && gtype == TI_DEX { + iv : int = global_init_val(name_idx) + if is_dex_global != 0 && gtype == TI_DEX: // apx 全局:初始值为 binary64 位模式(缩放值 → bits 从节点 a 取) - i2 : ., mut = 0; - loop { - if i2 >= g_global_let_count { break; } - lnode2 := r64(g_global_lets, i2 * 8); - if ast_a(lnode2) == name_idx { - vn := ast_c(lnode2); - if vn >= 0 && ast_kind(vn) == EXPR_DEX { iv = ast_a(vn); } - break; - } - i2 = i2 + 1; - } - } - w64(g_ir_globals, g_ir_global_count * 24 + 16, iv); - g_ir_global_count = g_ir_global_count + 1; - } -} - -fn ir_gen_globals() { + i2 : ., mut = 0 + loop: + if i2 >= g_global_let_count: + break + lnode2 := r64(g_global_lets, i2 * 8) + if ast_a(lnode2) == name_idx: + vn := ast_c(lnode2) + if vn >= 0 && ast_kind(vn) == EXPR_DEX: + iv = ast_a(vn) + break + i2 = i2 + 1 + w64(g_ir_globals, g_ir_global_count * 24 + 16, iv) + g_ir_global_count = g_ir_global_count + 1 + +fn ir_gen_globals(): // The parser records only file-scope declarations in g_global_lets. // Do not scan every EXPR_LET here: that also includes function locals. - i : ., mut = 0; - loop { - if i >= g_global_let_count { break; } - node := r64(g_global_lets, i * 8); - reg_one_global(ast_a(node)); - i = i + 1; - } + i : ., mut = 0 + loop: + if i >= g_global_let_count: + break + node := r64(g_global_lets, i * 8) + reg_one_global(ast_a(node)) + i = i + 1 // Manually register ir_gen.cr's own globals — the parser's auto-detection // of file-scope declarations is known to miss some (see CLAUDE.md Known Issues). - reg_one_global(str_intern("g_sg_alloc_total")); - reg_one_global(str_intern("g_sg_alloc_cap")); - reg_one_global(str_intern("g_sg_arena_var")); - reg_one_global(str_intern("g_sg_arena_var_cap")); - reg_one_global(str_intern("g_ir_source_hash")); - reg_one_global(str_intern("g_ir_source_hash_ready")); - reg_one_global(str_intern("g_cir_write_buf")); - reg_one_global(str_intern("g_cir_write_pos")); - reg_one_global(str_intern("g_cir_write_cap")); + reg_one_global(str_intern("g_sg_alloc_total")) + reg_one_global(str_intern("g_sg_alloc_cap")) + reg_one_global(str_intern("g_sg_arena_var")) + reg_one_global(str_intern("g_sg_arena_var_cap")) + reg_one_global(str_intern("g_ir_source_hash")) + reg_one_global(str_intern("g_ir_source_hash_ready")) + reg_one_global(str_intern("g_cir_write_buf")) + reg_one_global(str_intern("g_cir_write_pos")) + reg_one_global(str_intern("g_cir_write_cap")) // v21 生成期 intern 日志(cir_cache.cr/dyn_arr.cr/globals.cr 共用;**新增编译器侧全局 // 必须在此登记**——parser 的 file-scope 自动发现已知会漏,漏登记 ⇒ 赋值静默丢弃/错槽)。 - reg_one_global(str_intern("g_cir_rec_on")); - reg_one_global(str_intern("g_cir_rec_ids")); - reg_one_global(str_intern("g_cir_rec_count")); - reg_one_global(str_intern("g_cir_rec_cap")); - reg_one_global(str_intern("g_cir_rec_base")); - reg_one_global(str_intern("g_cir_skip_journal")); + reg_one_global(str_intern("g_cir_rec_on")) + reg_one_global(str_intern("g_cir_rec_ids")) + reg_one_global(str_intern("g_cir_rec_count")) + reg_one_global(str_intern("g_cir_rec_cap")) + reg_one_global(str_intern("g_cir_rec_base")) + reg_one_global(str_intern("g_cir_skip_journal")) // Runtime globals needed by emit_alloc_body and emit_start. // These MUST exist in BSS for every program, even without rt.cr included. - reg_one_global(str_intern("g_heap_ptr")); - reg_one_global(str_intern("g_heap_end")); - reg_one_global(str_intern("g_current_arena")); - reg_one_global(str_intern("g_arena_cursors")); - reg_one_global(str_intern("g_arena_sizes")); - reg_one_global(str_intern("g_arena_parents")); - reg_one_global(str_intern("g_arena_max_size")); - reg_one_global(str_intern("g_arena_count")); - reg_one_global(str_intern("g_arena_cap")); - reg_one_global(str_intern("g_arena_pool_data")); - reg_one_global(str_intern("g_arena_free_list")); - reg_optrep_globals(); -} + reg_one_global(str_intern("g_heap_ptr")) + reg_one_global(str_intern("g_heap_end")) + reg_one_global(str_intern("g_current_arena")) + reg_one_global(str_intern("g_arena_cursors")) + reg_one_global(str_intern("g_arena_sizes")) + reg_one_global(str_intern("g_arena_parents")) + reg_one_global(str_intern("g_arena_max_size")) + reg_one_global(str_intern("g_arena_count")) + reg_one_global(str_intern("g_arena_cap")) + reg_one_global(str_intern("g_arena_pool_data")) + reg_one_global(str_intern("g_arena_free_list")) + reg_optrep_globals() // 表示面初始化(**两条 IR 生成入口都必须先调**:ir_gen_all 批量路径 + main.cr 文件路径 // (逐函数 + .cir 缓存)——后者不经过本文件的批量入口,漏调即侧表未分配)。位置: // **先于 ir_gen_globals**(隐藏信道的 var 行序 = 全局行序依赖)。 -fn optrep_begin() { - g_ir_var_rep = ""; - g_ir_var_rep_cap = 0; - g_ir_var_decl_ti = ""; - g_ir_var_decl_cap = 0; - g_optrep_ret_cell = -1; - g_optrep_arg_cell0 = -1; - g_optrep_arg_count = 0; - g_cur_ret_opt = 0; - optrep_prescan(); - optrep_addr_prescan(); -} +fn optrep_begin(): + g_ir_var_rep = "" + g_ir_var_rep_cap = 0 + g_ir_var_decl_ti = "" + g_ir_var_decl_cap = 0 + g_optrep_ret_cell = -1 + g_optrep_arg_cell0 = -1 + g_optrep_arg_count = 0 + g_cur_ret_opt = 0 + optrep_prescan() + optrep_addr_prescan() // (A) 批(裁-REP-4):**取址面预扫**——收集一切「取址 ident」的名字索引(照 optrep_prescan // 先例;全 AST 一遍)。判据面 = `&ident`(`UOP_REF` 的 operand 为 `EXPR_IDENT`);其余取址 // 形态见计划 §2.3 引理 1(`&arr[i]` = 聚合面已恒装箱;`&<其它表达式>` = 临时量非槽;函数地址 // 非槽;指针算术 = REP-2 边界;extern = 登记)。 -fn grow_addr_taken(needed: int) { - if needed <= g_addr_taken_cap { return; } - nc := g_addr_taken_cap * 2; if nc < 32 { nc = 32; } if nc < needed { nc = needed + 32; } - nb := alloc(nc * 8); _dyncpy(g_addr_taken_names, g_addr_taken_cap * 8, nb); - g_addr_taken_names = nb; g_addr_taken_cap = nc; -} -fn addr_taken_add(ni: int) { - if ni < 0 { return; } - if addr_taken_of(ni) != 0 { return; } // 去重(线性扫;量级 = 源码里 &ident 的条数) - grow_addr_taken(g_addr_taken_count + 1); - w64(g_addr_taken_names, g_addr_taken_count * 8, ni); - g_addr_taken_count = g_addr_taken_count + 1; -} -fn addr_taken_of(ni: int) -> int { - if ni < 0 { return 0; } - i : ., mut = 0; - loop { - if i >= g_addr_taken_count { return 0; } - if r64(g_addr_taken_names, i * 8) == ni { return 1; } - i = i + 1; - } - return 0; -} -fn optrep_addr_prescan() { - g_addr_taken_count = 0; - i : ., mut = 0; - loop { - if i >= g_ast_count { break; } - if ast_kind(i) == EXPR_UNARY && ast_c(i) == UOP_REF { - opn := ast_a(i); - if opn >= 0 && ast_kind(opn) == EXPR_IDENT { - addr_taken_add(ast_int_val(opn)); - } - } - i = i + 1; - } -} +fn grow_addr_taken(needed: int): + if needed <= g_addr_taken_cap: + return + nc := g_addr_taken_cap * 2 + if nc < 32: + nc = 32 + if nc < needed: + nc = needed + 32 + nb := alloc(nc * 8) + _dyncpy(g_addr_taken_names, g_addr_taken_cap * 8, nb) + g_addr_taken_names = nb + g_addr_taken_cap = nc +fn addr_taken_add(ni: int): + if ni < 0: + return + if addr_taken_of(ni) != 0: + return + // 去重(线性扫;量级 = 源码里 &ident 的条数) + grow_addr_taken(g_addr_taken_count + 1) + w64(g_addr_taken_names, g_addr_taken_count * 8, ni) + g_addr_taken_count = g_addr_taken_count + 1 +fn addr_taken_of(ni: int) -> int: + if ni < 0: + return 0 + i : ., mut = 0 + loop: + if i >= g_addr_taken_count: + return 0 + if r64(g_addr_taken_names, i * 8) == ni: + return 1 + i = i + 1 + return 0 +fn optrep_addr_prescan(): + g_addr_taken_count = 0 + i : ., mut = 0 + loop: + if i >= g_ast_count: + break + if ast_kind(i) == EXPR_UNARY && ast_c(i) == UOP_REF: + opn := ast_a(i) + if opn >= 0 && ast_kind(opn) == EXPR_IDENT: + addr_taken_add(ast_int_val(opn)) + i = i + 1 // 表示面启用扫描(**零足迹门**):AST 含任一 `T?` 类型节点(EXPR_OPTIONAL)或任一 // `Some`/`None` 构造(关键字名分派,与 checker 同规约:用户变体同名时上方 SYM_FN 优先, // 但扫描**宽于**实际使用只会多启用一层空机器、不会漏启用——判据面为「启用 ⇒ 表示面完整」)。 -fn optrep_prescan() { - g_optrep_on = 0; - i : ., mut = 0; - loop { - if i >= g_ast_count { break; } - k := ast_kind(i); - if k == EXPR_OPTIONAL { g_optrep_on = 1; break; } - if k == EXPR_ENUM_CONSTRUCTOR { - nm := istr_get(ast_a(i)); - if str_eq(nm, "Some") != 0 || str_eq(nm, "None") != 0 { g_optrep_on = 1; break; } - } - i = i + 1; - } -} +fn optrep_prescan(): + g_optrep_on = 0 + i : ., mut = 0 + loop: + if i >= g_ast_count: + break + k := ast_kind(i) + if k == EXPR_OPTIONAL: + g_optrep_on = 1 + break + if k == EXPR_ENUM_CONSTRUCTOR: + nm := istr_get(ast_a(i)) + if str_eq(nm, "Some") != 0 || str_eq(nm, "None") != 0: + g_optrep_on = 1 + break + i = i + 1 // 隐藏全局注册(照 reg_one_global 形态但不查 g_global_lets——编译器内部名,零初值)。 // var_idx == 行序(save_ccr 的全局行序守卫)由「本函数只在 ir_gen_globals 尾部调用、 // 此后不再注册全局」保证。 -fn reg_hidden_global(name_ni: int) -> int { - gvar := new_ir_var(istr_get(name_ni), TI_INT); - grow_ir_globals(g_ir_global_count + 1); - w64(g_ir_globals, g_ir_global_count * 24, name_ni); - w64(g_ir_globals, g_ir_global_count * 24 + 8, gvar); - w64(g_ir_globals, g_ir_global_count * 24 + 16, 0); - g_ir_global_count = g_ir_global_count + 1; - return gvar; -} +fn reg_hidden_global(name_ni: int) -> int: + gvar := new_ir_var(istr_get(name_ni), TI_INT) + grow_ir_globals(g_ir_global_count + 1) + w64(g_ir_globals, g_ir_global_count * 24, name_ni) + w64(g_ir_globals, g_ir_global_count * 24 + 8, gvar) + w64(g_ir_globals, g_ir_global_count * 24 + 16, 0) + g_ir_global_count = g_ir_global_count + 1 + return gvar // 可选表示的跨函数信道注册(仅在 g_optrep_on 时):返回信道单元 + 每形参位一个实参 // 信道单元(连续 var 索引;被调按形参位读、调用点按实参位写)。 -fn reg_optrep_globals() { - g_optrep_ret_cell = -1; - g_optrep_arg_cell0 = -1; - g_optrep_arg_count = 0; - if g_optrep_on == 0 { return; } - maxp : ., mut = 0; - fi2 : ., mut = 0; - loop { - if fi2 >= g_func_count { break; } - pc := fi_param_count(fi2); - if pc > maxp { maxp = pc; } - fi2 = fi2 + 1; - } - if maxp > 64 { maxp = 64; } - g_optrep_ret_cell = reg_hidden_global(str_intern("__optrep_ret")); - j : ., mut = 0; - loop { - if j >= maxp { break; } - cv := reg_hidden_global(str_intern("__optrep_arg" + int_str(j))); - if j == 0 { g_optrep_arg_cell0 = cv; } - j = j + 1; - } - g_optrep_arg_count = maxp; -} +fn reg_optrep_globals(): + g_optrep_ret_cell = -1 + g_optrep_arg_cell0 = -1 + g_optrep_arg_count = 0 + if g_optrep_on == 0: + return + maxp : ., mut = 0 + fi2 : ., mut = 0 + loop: + if fi2 >= g_func_count: + break + pc := fi_param_count(fi2) + if pc > maxp: + maxp = pc + fi2 = fi2 + 1 + if maxp > 64: + maxp = 64 + g_optrep_ret_cell = reg_hidden_global(str_intern("__optrep_ret")) + j : ., mut = 0 + loop: + if j >= maxp: + break + cv := reg_hidden_global(str_intern("__optrep_arg" + int_str(j))) + if j == 0: + g_optrep_arg_cell0 = cv + j = j + 1 + g_optrep_arg_count = maxp // --- AST walk: patch method call names for monomorphization --- -fn ast_patch_node(node: int, subst_from: string, subst_to: string) { - if node < 0 { return; } - k := ast_kind(node); - if k == EXPR_CALL { - func_node := ast_a(node); - if ast_kind(func_node) == EXPR_FIELD { - data_ni := ast_data(node); - if data_ni >= 0 { - data_str := istr_get(data_ni); - dlen := str_len(data_str); - flen := str_len(subst_from); - if dlen >= flen { - matches : ., mut = 1; - dci : ., mut = 0; - loop { - if dci >= flen { break; } - if load8(data_str, dci) != load8(subst_from, dci) { matches = 0; break; } - dci = dci + 1; - } - if matches != 0 && (dlen == flen || load8(data_str, flen) == 46) { - rest := str_sub(data_str, flen, dlen - flen); - new_name := subst_to + rest; - ast_set_data(node, str_intern(new_name)); - } - } - } - } - } +fn ast_patch_node(node: int, subst_from: string, subst_to: string): + if node < 0: + return + k := ast_kind(node) + if k == EXPR_CALL: + func_node := ast_a(node) + if ast_kind(func_node) == EXPR_FIELD: + data_ni := ast_data(node) + if data_ni >= 0: + data_str := istr_get(data_ni) + dlen := str_len(data_str) + flen := str_len(subst_from) + if dlen >= flen: + matches : ., mut = 1 + dci : ., mut = 0 + loop: + if dci >= flen: + break + if load8(data_str, dci) != load8(subst_from, dci): + matches = 0 + break + dci = dci + 1 + if matches != 0 && (dlen == flen || load8(data_str, flen) == 46): + rest := str_sub(data_str, flen, dlen - flen) + new_name := subst_to + rest + ast_set_data(node, str_intern(new_name)) // Recurse into children based on node kind - if k == EXPR_BLOCK { - ss := ast_a(node); sc := ast_b(node); - i2 : ., mut = 0; - loop { if i2 >= sc { break; } - sn2 := r64(g_block_stmts, (ss + i2) * 8); - ast_patch_node(sn2, subst_from, subst_to); - i2 = i2 + 1; } - } else if k == EXPR_IF || k == EXPR_LOOP || k == EXPR_WHILE || k == EXPR_UNSAFE { - if ast_a(node) >= 0 { ast_patch_node(ast_a(node), subst_from, subst_to); } - if k == EXPR_IF { - if ast_b(node) >= 0 { ast_patch_node(ast_b(node), subst_from, subst_to); } - if ast_c(node) >= 0 { ast_patch_node(ast_c(node), subst_from, subst_to); } - } - } else if k == EXPR_BINARY || k == EXPR_ASSIGN || k == EXPR_RANGE || k == EXPR_AS { - if ast_a(node) >= 0 { ast_patch_node(ast_a(node), subst_from, subst_to); } - if ast_b(node) >= 0 { ast_patch_node(ast_b(node), subst_from, subst_to); } - } else if k == EXPR_CALL || k == EXPR_ENUM_CONSTRUCTOR { - if ast_a(node) >= 0 { ast_patch_node(ast_a(node), subst_from, subst_to); } - an3 := ast_b(node); ac3 := ast_c(node); - ai3 : ., mut = 0; - loop { if ai3 >= ac3 { break; } if an3 >= 0 { ast_patch_node(an3, subst_from, subst_to); an3 = an3 + 1; } ai3 = ai3 + 1; } - } else if k == EXPR_MATCH { - if ast_a(node) >= 0 { ast_patch_node(ast_a(node), subst_from, subst_to); } - an4 := ast_b(node); - loop { if an4 < 0 { break; } - if ast_a(an4) >= 0 { ast_patch_node(ast_a(an4), subst_from, subst_to); } - if ast_b(an4) >= 0 { ast_patch_node(ast_b(an4), subst_from, subst_to); } - an4 = ast_c(an4); } - } else if k == EXPR_FOR { - if ast_b(node) >= 0 { ast_patch_node(ast_b(node), subst_from, subst_to); } - if ast_c(node) >= 0 { ast_patch_node(ast_c(node), subst_from, subst_to); } - } else if k == EXPR_LET { - if ast_c(node) >= 0 { ast_patch_node(ast_c(node), subst_from, subst_to); } - } else if k == EXPR_STMT { - if ast_a(node) >= 0 { ast_patch_node(ast_a(node), subst_from, subst_to); } - } else if k == EXPR_STRUCT { + if k == EXPR_BLOCK: + ss := ast_a(node) + sc := ast_b(node) + i2 : ., mut = 0 + loop: + if i2 >= sc: + break + sn2 := r64(g_block_stmts, (ss + i2) * 8) + ast_patch_node(sn2, subst_from, subst_to) + i2 = i2 + 1 + else if k == EXPR_IF || k == EXPR_LOOP || k == EXPR_WHILE || k == EXPR_UNSAFE: + if ast_a(node) >= 0: + ast_patch_node(ast_a(node), subst_from, subst_to) + if k == EXPR_IF: + if ast_b(node) >= 0: + ast_patch_node(ast_b(node), subst_from, subst_to) + if ast_c(node) >= 0: + ast_patch_node(ast_c(node), subst_from, subst_to) + else if k == EXPR_BINARY || k == EXPR_ASSIGN || k == EXPR_RANGE || k == EXPR_AS: + if ast_a(node) >= 0: + ast_patch_node(ast_a(node), subst_from, subst_to) + if ast_b(node) >= 0: + ast_patch_node(ast_b(node), subst_from, subst_to) + else if k == EXPR_CALL || k == EXPR_ENUM_CONSTRUCTOR: + if ast_a(node) >= 0: + ast_patch_node(ast_a(node), subst_from, subst_to) + an3 := ast_b(node) + ac3 := ast_c(node) + ai3 : ., mut = 0 + loop: + if ai3 >= ac3: + break + if an3 >= 0: + ast_patch_node(an3, subst_from, subst_to) + an3 = an3 + 1 + ai3 = ai3 + 1 + else if k == EXPR_MATCH: + if ast_a(node) >= 0: + ast_patch_node(ast_a(node), subst_from, subst_to) + an4 := ast_b(node) + loop: + if an4 < 0: + break + if ast_a(an4) >= 0: + ast_patch_node(ast_a(an4), subst_from, subst_to) + if ast_b(an4) >= 0: + ast_patch_node(ast_b(an4), subst_from, subst_to) + an4 = ast_c(an4) + else if k == EXPR_FOR: + if ast_b(node) >= 0: + ast_patch_node(ast_b(node), subst_from, subst_to) + if ast_c(node) >= 0: + ast_patch_node(ast_c(node), subst_from, subst_to) + else if k == EXPR_LET: + if ast_c(node) >= 0: + ast_patch_node(ast_c(node), subst_from, subst_to) + else if k == EXPR_STMT: + if ast_a(node) >= 0: + ast_patch_node(ast_a(node), subst_from, subst_to) + else if k == EXPR_STRUCT: // a=type_name_ni, b=first wrapper(连续), c=field_count;wrapper.a=字段值节点 // (F5 契约,见 parser.cr struct 字面量分支)——须解引用 wrapper 再递归, // 旧代码把 EXPR_NONE wrapper 本身交给 ast_patch_node(无该 kind 分支)= 空转, // 泛型实例体内 struct 字面量字段中的方法调用名得不到替换。 - an5 := ast_b(node); ac5 := ast_c(node); - ai5 : ., mut = 0; - loop { - if ai5 >= ac5 { break; } - if an5 >= 0 { - vn5 : ., mut = -1; - if ast_kind(an5) == EXPR_NONE { vn5 = ast_a(an5); } - if vn5 >= 0 { ast_patch_node(vn5, subst_from, subst_to); } - an5 = an5 + 1; - } - ai5 = ai5 + 1; - } - } else if k == EXPR_ARRAY { + an5 := ast_b(node) + ac5 := ast_c(node) + ai5 : ., mut = 0 + loop: + if ai5 >= ac5: + break + if an5 >= 0: + vn5 : ., mut = -1 + if ast_kind(an5) == EXPR_NONE: + vn5 = ast_a(an5) + if vn5 >= 0: + ast_patch_node(vn5, subst_from, subst_to) + an5 = an5 + 1 + ai5 = ai5 + 1 + else if k == EXPR_ARRAY: // a=first wrapper(连续), b=elem_count;wrapper.a=元素值节点(F5 契约,见 parser.cr 下标分支) - an6 := ast_a(node); ac6 := ast_b(node); - ai6 : ., mut = 0; - loop { - if ai6 >= ac6 { break; } - if an6 >= 0 { - vn6 : ., mut = -1; - if ast_kind(an6) == EXPR_NONE { vn6 = ast_a(an6); } - if vn6 >= 0 { ast_patch_node(vn6, subst_from, subst_to); } - an6 = an6 + 1; - } - ai6 = ai6 + 1; - } - } else if k == EXPR_TUPLE { + an6 := ast_a(node) + ac6 := ast_b(node) + ai6 : ., mut = 0 + loop: + if ai6 >= ac6: + break + if an6 >= 0: + vn6 : ., mut = -1 + if ast_kind(an6) == EXPR_NONE: + vn6 = ast_a(an6) + if vn6 >= 0: + ast_patch_node(vn6, subst_from, subst_to) + an6 = an6 + 1 + ai6 = ai6 + 1 + else if k == EXPR_TUPLE: // a=first wrapper(连续), b=elem_count;wrapper.a=元素值节点(F5 契约) - an6 := ast_a(node); ac6 := ast_b(node); - ai6 : ., mut = 0; - loop { - if ai6 >= ac6 { break; } - if an6 >= 0 { - vn6 : ., mut = -1; - if ast_kind(an6) == EXPR_NONE { vn6 = ast_a(an6); } - if vn6 >= 0 { ast_patch_node(vn6, subst_from, subst_to); } - an6 = an6 + 1; - } - ai6 = ai6 + 1; - } - } else if k == EXPR_FIELD || k == EXPR_INDEX || k == EXPR_UNARY || k == EXPR_RETURN || k == EXPR_TRY || k == EXPR_MOVE { - if ast_a(node) >= 0 { ast_patch_node(ast_a(node), subst_from, subst_to); } - } -} - -fn find_or_create_mono_func(fi: int, call_node: int) -> int { + an6 := ast_a(node) + ac6 := ast_b(node) + ai6 : ., mut = 0 + loop: + if ai6 >= ac6: + break + if an6 >= 0: + vn6 : ., mut = -1 + if ast_kind(an6) == EXPR_NONE: + vn6 = ast_a(an6) + if vn6 >= 0: + ast_patch_node(vn6, subst_from, subst_to) + an6 = an6 + 1 + ai6 = ai6 + 1 + else if k == EXPR_FIELD || k == EXPR_INDEX || k == EXPR_UNARY || k == EXPR_RETURN || k == EXPR_TRY || k == EXPR_MOVE: + if ast_a(node) >= 0: + ast_patch_node(ast_a(node), subst_from, subst_to) + +fn find_or_create_mono_func(fi: int, call_node: int) -> int: // Create a monomorphized version of generic function fi for the given call site. // Only creates the FuncInfo entry — IR generation happens in pass 2 of ir_gen_all. - fn_node := fi_ast_node(fi); - body := ast_data(fn_node); - first_param := ast_b(fn_node); - param_count := ast_c(fn_node); - orig_ret_type := ast_int_val(fn_node); - orig_ret_node := ast_type_val(fn_node); + fn_node := fi_ast_node(fi) + body := ast_data(fn_node) + first_param := ast_b(fn_node) + param_count := ast_c(fn_node) + orig_ret_type := ast_int_val(fn_node) + orig_ret_node := ast_type_val(fn_node) - gen_name_ni := fi_generic_name(fi, 0); - gen_name := istr_get(gen_name_ni); + gen_name_ni := fi_generic_name(fi, 0) + gen_name := istr_get(gen_name_ni) // Get concrete type name from call node (stored by checker) - concrete_type_ni : ., mut = ast_int_val(call_node); - concrete_type_name : ., mut = istr_get(concrete_type_ni); + concrete_type_ni : ., mut = ast_int_val(call_node) + concrete_type_name : ., mut = istr_get(concrete_type_ni) // Create mangled name: "funcname$genericname.concretetype" - orig_fn_name := istr_get(fi_name(fi)); - mangled_name : ., mut = orig_fn_name + "$"; - mangled_name = mangled_name + gen_name + "." + concrete_type_name; - mangled_ni := str_intern(mangled_name); + orig_fn_name := istr_get(fi_name(fi)) + mangled_name : ., mut = orig_fn_name + "$" + mangled_name = mangled_name + gen_name + "." + concrete_type_name + mangled_ni := str_intern(mangled_name) // Check if already exists - existing := find_func(mangled_ni); - if existing >= 0 { return existing; } + existing := find_func(mangled_ni) + if existing >= 0: + return existing // Create new EXPR_PARAM nodes with concrete param types - new_first_param : ., mut = -1; - ppi : ., mut = 0; - ppn : ., mut = first_param; - loop { - if ppi >= param_count { break; } - if ppn < 0 { break; } - pname_ni := ast_a(ppn); - self_mode := ast_int_val(ppn); - orig_type_val := ast_type_val(ppn); - orig_type_node := ast_data(ppn); + new_first_param : ., mut = -1 + ppi : ., mut = 0 + ppn : ., mut = first_param + loop: + if ppi >= param_count: + break + if ppn < 0: + break + pname_ni := ast_a(ppn) + self_mode := ast_int_val(ppn) + orig_type_val := ast_type_val(ppn) + orig_type_node := ast_data(ppn) // Replace type node if it references the generic param - new_type_node : ., mut = orig_type_node; - if orig_type_node >= 0 && ast_kind(orig_type_node) == EXPR_IDENT && ast_int_val(orig_type_node) == gen_name_ni { + new_type_node : ., mut = orig_type_node + if orig_type_node >= 0 && ast_kind(orig_type_node) == EXPR_IDENT && ast_int_val(orig_type_node) == gen_name_ni: // Create new type node referencing concrete type name - new_type_node = alloc_node(EXPR_IDENT, 0, 0, 0, concrete_type_ni, 0, 0, 0, 0); - } - - np := alloc_node(EXPR_PARAM, pname_ni, 0, 0, self_mode, orig_type_val, new_type_node, 0, 0); - if ppi == 0 { new_first_param = np; } - ppi = ppi + 1; - ppn = ppn + 1; - loop { if ppn >= g_ast_count { break; } if ast_kind(ppn) == EXPR_PARAM { break; } ppn = ppn + 1; } - } + new_type_node = alloc_node(EXPR_IDENT, 0, 0, 0, concrete_type_ni, 0, 0, 0, 0) + + np := alloc_node(EXPR_PARAM, pname_ni, 0, 0, self_mode, orig_type_val, new_type_node, 0, 0) + if ppi == 0: + new_first_param = np + ppi = ppi + 1 + ppn = ppn + 1 + loop: + if ppn >= g_ast_count: + break + if ast_kind(ppn) == EXPR_PARAM: + break + ppn = ppn + 1 // Create new EXPR_FN node - new_fn_node := alloc_node(EXPR_FN, mangled_ni, new_first_param, param_count, orig_ret_type, orig_ret_node, body, 0, 0); + new_fn_node := alloc_node(EXPR_FN, mangled_ni, new_first_param, param_count, orig_ret_type, orig_ret_node, body, 0, 0) // Patch body: replace "gen_name.method" → "concrete_type_name.method" - if body >= 0 { - ast_patch_node(body, gen_name, concrete_type_name); - } + if body >= 0: + ast_patch_node(body, gen_name, concrete_type_name) // Register new function - new_fi := add_func(mangled_name, param_count, orig_ret_type, new_fn_node); - if new_fi >= 0 { + new_fi := add_func(mangled_name, param_count, orig_ret_type, new_fn_node) + if new_fi >= 0: // Copy generic constraint info (non-generic now, but keep for reference) - fi_set_generic_count(new_fi, 0); - } + fi_set_generic_count(new_fi, 0) - return new_fi; -} + return new_fi // --- Main entry --- -fn ir_gen_all() { - 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; +fn ir_gen_all(): + 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 // 可选表示面:侧表复位 + 启用扫描(先于全局注册——隐藏信道的 var 行序依赖) - optrep_begin(); + optrep_begin() // Initialize dataflow graph - init_df(); + init_df() // Initialize globals - ir_gen_globals(); - - i : ., mut = 0; - loop { - if i >= g_func_count { break; } - if fi_generic_count(i) > 0 { i = i + 1; continue; } - ir_func_idx := g_ir_func_count; - df_begin_func(ir_func_idx); - ir_gen_func(i); - df_end_func(ir_func_idx); - i = i + 1; - } + ir_gen_globals() + + i : ., mut = 0 + loop: + if i >= g_func_count: + break + if fi_generic_count(i) > 0: + i = i + 1 + continue + ir_func_idx := g_ir_func_count + df_begin_func(ir_func_idx) + ir_gen_func(i) + df_end_func(ir_func_idx) + i = i + 1 // 纯度 + state 链最终化(全部 IR 体就绪后;理由见 checker.cr compute_all_purity // 与 dataflow.cr df_replay_state_chain 头注)。文件路径的同点调用在 main.cr。 - df_state_finalize(); -} + df_state_finalize() // Compute function body fingerprint: hash of the function body source text. // Used for cache hit detection. If the body hasn't changed, the output IR // is identical and can be restored from cache. -fn func_fingerprint(func_node: int) -> int { +fn func_fingerprint(func_node: int) -> int: // func_node = EXPR_FUNC node // Body starts at ast_data(func_node) - body := ast_data(func_node); - if body < 0 { return 0; } + body := ast_data(func_node) + if body < 0: + return 0 // For fingerprinting, hash the function's AST line/col range in source // This is simpler than extracting the exact body bytes: // hash AST node kind chain from the body - if g_ir_source_hash_ready == 0 { - source_hash : ., mut = 2166136261; - source_pos : ., mut = 0; - source_len := str_len(g_source); - loop { - if source_pos >= source_len { break; } - source_hash = source_hash * 16777619 + load8(g_source, source_pos); - source_pos = source_pos + 1; - } - g_ir_source_hash = source_hash; - g_ir_source_hash_ready = 1; - } - h : ., mut = g_ir_source_hash; + if g_ir_source_hash_ready == 0: + source_hash : ., mut = 2166136261 + source_pos : ., mut = 0 + source_len := str_len(g_source) + loop: + if source_pos >= source_len: + break + source_hash = source_hash * 16777619 + load8(g_source, source_pos) + source_pos = source_pos + 1 + g_ir_source_hash = source_hash + g_ir_source_hash_ready = 1 + h : ., mut = g_ir_source_hash // Walk the body AST and hash node kinds + values // For a simple first pass: hash the function's token stream range - start_line := ast_line(func_node); - start_col := ast_col(func_node); + start_line := ast_line(func_node) + start_col := ast_col(func_node) // Use g_line/position info to hash source bytes for this function // For now: simple hash of function name + param count + body node - h = h * 16777619 + (ast_kind(func_node) % 256); - h = h * 16777619 + (ast_a(func_node) % 256); // name_ni - h = h * 16777619 + (ast_c(func_node) % 256); // param count - if body >= 0 { h = h * 16777619 + (ast_kind(body) % 256); } - return h; -} + h = h * 16777619 + (ast_kind(func_node) % 256) + h = h * 16777619 + (ast_a(func_node) % 256) // name_ni + h = h * 16777619 + (ast_c(func_node) % 256) // param count + if body >= 0: + h = h * 16777619 + (ast_kind(body) % 256) + return h // Compute function signature fingerprint: hash of name + param types + return type. // Used to detect when callers need recompilation. -fn sig_fingerprint(func_node: int) -> int { - h : ., mut = 2166136261; +fn sig_fingerprint(func_node: int) -> int: + h : ., mut = 2166136261 // Name - name_ni := ast_a(func_node); - name := istr_get(name_ni); - ni : ., mut = 0; - loop { if ni >= str_len(name) { break; } - h = h * 16777619 + (load8(name, ni) % 256); - ni = ni + 1; } + name_ni := ast_a(func_node) + name := istr_get(name_ni) + ni : ., mut = 0 + loop: + if ni >= str_len(name): + break + h = h * 16777619 + (load8(name, ni) % 256) + ni = ni + 1 // Param types - param := ast_b(func_node); - param_count := ast_c(func_node); - pi : ., mut = 0; - loop { if pi >= param_count { break; } - pt := ast_type_val(param); - h = h * 16777619 + (pt % 256); - pi = pi + 1; - param = param + 1; - } + param := ast_b(func_node) + param_count := ast_c(func_node) + pi : ., mut = 0 + loop: + if pi >= param_count: + break + pt := ast_type_val(param) + h = h * 16777619 + (pt % 256) + pi = pi + 1 + param = param + 1 // Return type - ret_type := ast_type_val(func_node); - h = h * 16777619 + (ret_type % 256); - return h; -} + ret_type := ast_type_val(func_node) + h = h * 16777619 + (ret_type % 256) + return h diff --git a/src/compiler/lexer.cr b/src/compiler/lexer.cr index c703e6e4..309558fe 100644 --- a/src/compiler/lexer.cr +++ b/src/compiler/lexer.cr @@ -2,199 +2,287 @@ // Character comparisons use ASCII code constants rather than string allocs. // Global compiler state -g_source : string, mut; -g_source_len : int, mut; // cached str_len(g_source), set in tokenize() -g_pos : int, mut; -g_line : int, mut; -g_col : int, mut; +g_source : string, mut +g_source_len : int, mut // cached str_len(g_source), set in tokenize() +g_pos : int, mut +g_line : int, mut +g_col : int, mut // Character constants -C_SP : int = 32; C_TB : int = 9; C_LF : int = 10; C_CR : int = 13; -C_NL : int = 10; -C_SLASH : int = 47; C_STAR : int = 42; -C_BSLASH : int = 92; C_SQUOTE : int = 39; C_DQUOTE : int = 34; -C_LPAREN : int = 40; C_RPAREN : int = 41; -C_LBRACE : int = 123; C_RBRACE : int = 125; -C_LBRACK : int = 91; C_RBRACK : int = 93; -C_COMMA : int = 44; C_SEMI : int = 59; C_COLON : int = 58; -C_DOT : int = 46; C_EQ : int = 61; C_BANG : int = 33; -C_LT : int = 60; C_GT : int = 62; C_PLUS : int = 43; -C_DASH : int = 45; C_PERCENT : int = 37; C_AMP : int = 38; -C_PIPE : int = 124; C_UNDER : int = 95; C_AT : int = 64; -C_QUES : int = 63; +C_SP : int = 32 +C_TB : int = 9 +C_LF : int = 10 +C_CR : int = 13 +C_NL : int = 10 +C_SLASH : int = 47 +C_STAR : int = 42 +C_BSLASH : int = 92 +C_SQUOTE : int = 39 +C_DQUOTE : int = 34 +C_LPAREN : int = 40 +C_RPAREN : int = 41 +C_LBRACE : int = 123 +C_RBRACE : int = 125 +C_LBRACK : int = 91 +C_RBRACK : int = 93 +C_COMMA : int = 44 +C_SEMI : int = 59 +C_COLON : int = 58 +C_DOT : int = 46 +C_EQ : int = 61 +C_BANG : int = 33 +C_LT : int = 60 +C_GT : int = 62 +C_PLUS : int = 43 +C_DASH : int = 45 +C_PERCENT : int = 37 +C_AMP : int = 38 +C_PIPE : int = 124 +C_UNDER : int = 95 +C_AT : int = 64 +C_QUES : int = 63 -fn is_digit(c: int) -> int { - if c >= 48 && c <= 57 { return 1; } - return 0; -} -fn is_alpha(c: int) -> int { - if (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c == 95 { return 1; } - return 0; -} -fn is_ident_char(c: int) -> int { - if is_alpha(c) != 0 || is_digit(c) != 0 { return 1; } - return 0; -} +fn is_digit(c: int) -> int: + if c >= 48 && c <= 57: + return 1 + return 0 +fn is_alpha(c: int) -> int: + if (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c == 95: + return 1 + return 0 +fn is_ident_char(c: int) -> int: + if is_alpha(c) != 0 || is_digit(c) != 0: + return 1 + return 0 -fn add_error(msg: string) { - mi := str_intern(msg); - grow_errors(g_error_count + 1); - w64(g_errors, g_error_count * 8, mi); - g_error_count = g_error_count + 1; -} +fn add_error(msg: string): + mi := str_intern(msg) + grow_errors(g_error_count + 1) + w64(g_errors, g_error_count * 8, mi) + g_error_count = g_error_count + 1 -fn cur_char() -> int { +fn cur_char() -> int: // Use str_len(g_source) instead of g_source_len to avoid // global variable patching bug in self-hosted ELF backend. // g_source_len is stored to a wrong BSS address in tokenize(), // causing cur_char() to always see it as 0 (EOF). - src_len := str_len(g_source); - if g_pos >= src_len { return 0; } - return load8(g_source, g_pos); -} + src_len := str_len(g_source) + if g_pos >= src_len: + return 0 + return load8(g_source, g_pos) -fn peek() -> int { - src_len := str_len(g_source); - if g_pos + 1 >= src_len { return 0; } - return load8(g_source, g_pos + 1); -} +fn peek() -> int: + src_len := str_len(g_source) + if g_pos + 1 >= src_len: + return 0 + return load8(g_source, g_pos + 1) -fn cur_char_at(src: string, pos: int, max_len: int) -> int { - if pos >= max_len { return 0; } - return load8(src, pos); -} -fn peek_at(src: string, pos: int, max_len: int) -> int { - if pos + 1 >= max_len { return 0; } - return load8(src, pos + 1); -} +fn cur_char_at(src: string, pos: int, max_len: int) -> int: + if pos >= max_len: + return 0 + return load8(src, pos) +fn peek_at(src: string, pos: int, max_len: int) -> int: + if pos + 1 >= max_len: + return 0 + return load8(src, pos + 1) -fn lookup_keyword(s: string) -> int { - if s == "fn" { return T_FN; } - if s == "mut" { return T_MUT; } - if s == "return" { return T_RETURN; } - if s == "if" { return T_IF; } - if s == "else" { return T_ELSE; } - if s == "loop" { return T_LOOP; } - if s == "while" { return T_WHILE; } - if s == "for" { return T_FOR; } - if s == "break" { return T_BREAK; } - if s == "continue" { return T_CONTINUE; } - if s == "true" { return T_TRUE; } - if s == "false" { return T_FALSE; } - if s == "struct" { return T_STRUCT; } - if s == "enum" { return T_ENUM; } - if s == "extern" { return T_EXTERN; } - if s == "impl" { return T_IMPL; } - if s == "match" { return T_MATCH; } - if s == "import" { return T_IMPORT; } - if s == "pub" { return T_PUB; } - if s == "go" { return T_GO; } - if s == "await" { return T_AWAIT; } - if s == "unsafe" { return T_UNSAFE; } - if s == "flow" { return T_FLOW; } - if s == "yield" { return T_YIELD; } - if s == "interface" { return T_INTERFACE; } - if s == "type" { return T_TYPE; } - if s == "mod" { return T_MOD; } - if s == "as" { return T_AS; } - if s == "auto" { return T_AUTO; } - if s == "fileid" { return T_FILEID; } - if s == "move" { return T_MOVE; } - if s == "self" { return T_SELF; } - if s == "in" { return T_IN; } - if s == "None" { return T_NONE; } - if s == "Some" { return T_SOME; } - if s == "unit" { return T_UNIT; } - return T_IDENT; -} +fn lookup_keyword(s: string) -> int: + if s == "fn": + return T_FN + if s == "mut": + return T_MUT + if s == "return": + return T_RETURN + if s == "if": + return T_IF + if s == "else": + return T_ELSE + if s == "loop": + return T_LOOP + if s == "while": + return T_WHILE + if s == "for": + return T_FOR + if s == "break": + return T_BREAK + if s == "continue": + return T_CONTINUE + if s == "true": + return T_TRUE + if s == "false": + return T_FALSE + if s == "struct": + return T_STRUCT + if s == "enum": + return T_ENUM + if s == "extern": + return T_EXTERN + if s == "impl": + return T_IMPL + if s == "match": + return T_MATCH + if s == "import": + return T_IMPORT + if s == "pub": + return T_PUB + if s == "go": + return T_GO + if s == "await": + return T_AWAIT + if s == "unsafe": + return T_UNSAFE + if s == "flow": + return T_FLOW + if s == "yield": + return T_YIELD + if s == "interface": + return T_INTERFACE + if s == "type": + return T_TYPE + if s == "mod": + return T_MOD + if s == "as": + return T_AS + if s == "auto": + return T_AUTO + if s == "fileid": + return T_FILEID + if s == "move": + return T_MOVE + if s == "self": + return T_SELF + if s == "in": + return T_IN + if s == "None": + return T_NONE + if s == "Some": + return T_SOME + if s == "unit": + return T_UNIT + return T_IDENT // 2^k(纯整数,k >= 0) -fn pow2i(k: int) -> int { - v : int = 1; i : ., mut = 0; - loop { if i >= k { break; } v = v * 2; i = i + 1; } - return v; -} +fn pow2i(k: int) -> int: + v : int = 1 + i : ., mut = 0 + loop: + if i >= k: + break + v = v * 2 + i = i + 1 + return v // decimal string → IEEE 754 binary64 位模式(纯整数近似,≤18 位有效数字) // 实现:value = ip + fp/den → 整数部分位 + 64 位长除小数 → 53 位尾数窗口 // 精度:截断(无舍入),≤18 位有效数字内 ~2ulp -fn str_to_f64_bits(s: string) -> int { - sl := str_len(s); - i : ., mut = 0; - neg : int = 0; - if i < sl && load8(s, i) == 45 { neg = 1; i = i + 1; } - ip : int = 0; fp : int = 0; den : int = 1; sd : int = 0; - ip_digits : ., mut = 0; fp_digits : ., mut = 0; - too_wide : ., mut = 0; - loop { if i >= sl { break; } - c := load8(s, i); - if c == 46 { sd = 1; i = i + 1; continue; } - if c < 48 || c > 57 { break; } - if sd != 0 { - fp_digits = fp_digits + 1; - if fp_digits <= 18 { fp = fp * 10 + (c - 48); den = den * 10; } - } else { - ip_digits = ip_digits + 1; - if ip_digits <= 19 { - digit_ip := c - 48; - if ip > 922337203685477580 || - (ip == 922337203685477580 && digit_ip > 7 + neg) { - too_wide = 1; - } else { ip = ip * 10 + digit_ip; } - } else { too_wide = 1; } - } - i = i + 1; } - if too_wide != 0 { add_error("decimal literal integer part is too wide"); return 0; } - if ip == 0 && fp == 0 { - if neg != 0 { return (-9223372036854775807 - 1); } - return 0; - } +fn str_to_f64_bits(s: string) -> int: + sl := str_len(s) + i : ., mut = 0 + neg : int = 0 + if i < sl && load8(s, i) == 45: + neg = 1 + i = i + 1 + ip : int = 0 + fp : int = 0 + den : int = 1 + sd : int = 0 + ip_digits : ., mut = 0 + fp_digits : ., mut = 0 + too_wide : ., mut = 0 + loop: + if i >= sl: + break + c := load8(s, i) + if c == 46: + sd = 1 + i = i + 1 + continue + if c < 48 || c > 57: + break + if sd != 0: + fp_digits = fp_digits + 1 + if fp_digits <= 18: + fp = fp * 10 + (c - 48) + den = den * 10 + else: + ip_digits = ip_digits + 1 + if ip_digits <= 19: + digit_ip := c - 48 + if ip > 922337203685477580 || (ip == 922337203685477580 && digit_ip > 7 + neg): + too_wide = 1 + else: + ip = ip * 10 + digit_ip + else: + too_wide = 1 + i = i + 1 + if too_wide != 0: + add_error("decimal literal integer part is too wide") + return 0 + if ip == 0 && fp == 0: + if neg != 0: + return (-9223372036854775807 - 1) + return 0 // 小数 64 位(长除:r=fp,每轮 r×2 vs den) - frac64 : int = 0; - r : ., mut = fp; - bits : ., mut = 0; - loop { if bits >= 64 { break; } - if r >= 4611686018427387904 { r = r / 2; den = den / 2; } - r = r * 2; - frac64 = frac64 * 2; - if r >= den { r = r - den; frac64 = frac64 + 1; } - bits = bits + 1; } + frac64 : int = 0 + r : ., mut = fp + bits : ., mut = 0 + loop: + if bits >= 64: + break + if r >= 4611686018427387904: + r = r / 2 + den = den / 2 + r = r * 2 + frac64 = frac64 * 2 + if r >= den: + r = r - den + frac64 = frac64 + 1 + bits = bits + 1 // 整数部分位宽 - bi : ., mut = 0; t2 : ., mut = ip; - loop { if t2 == 0 { break; } t2 = t2 / 2; bi = bi + 1; } - mant : int = 0; - exp : int = 0; - if bi > 0 { - sh := 53 - bi; - if sh >= 0 { - mant = (ip * pow2i(sh)) + (frac64 / pow2i(64 - sh)); - } else { + bi : ., mut = 0 + t2 : ., mut = ip + loop: + if t2 == 0: + break + t2 = t2 / 2 + bi = bi + 1 + mant : int = 0 + exp : int = 0 + if bi > 0: + sh := 53 - bi + if sh >= 0: + mant = (ip * pow2i(sh)) + (frac64 / pow2i(64 - sh)) + else: // Avoid pow2i of a negative value for integer parts wider than // the binary64 significand. - mant = ip / pow2i(0 - sh); - } - exp = 1023 + (bi - 1); - } else { + mant = ip / pow2i(0 - sh) + exp = 1023 + (bi - 1) + else: // 纯小数:frac64 的最高位 - bf : ., mut = 0; t2 = frac64; - loop { if t2 == 0 { break; } t2 = t2 / 2; bf = bf + 1; } - if bf == 0 { - if neg != 0 { return (-9223372036854775807 - 1); } - return 0; - } - sh := 53 - bf; - if sh >= 0 { mant = frac64 * pow2i(sh); } - else { mant = frac64 / pow2i(-sh); } - exp = 1023 + (bf - 65); - } + bf : ., mut = 0 + t2 = frac64 + loop: + if t2 == 0: + break + t2 = t2 / 2 + bf = bf + 1 + if bf == 0: + if neg != 0: + return (-9223372036854775807 - 1) + return 0 + sh := 53 - bf + if sh >= 0: + mant = frac64 * pow2i(sh) + else: + mant = frac64 / pow2i(-sh) + exp = 1023 + (bf - 65) // 组装(mant 截断到 52 位——无舍入) - bits64 : int = 0; - if exp > 0 && exp < 2047 { - bits64 = (mant % 4503599627370496) + exp * 4503599627370496; - } - if neg != 0 { bits64 = bits64 + (-9223372036854775807 - 1); } - return bits64; -} + bits64 : int = 0 + if exp > 0 && exp < 2047: + bits64 = (mant % 4503599627370496) + exp * 4503599627370496 + if neg != 0: + bits64 = bits64 + (-9223372036854775807 - 1) + return bits64 // Parse an integer literal after tokenization. Supports decimal separators // and 0x/0o/0b prefixes; out-of-shape literals are rejected as lexer errors. @@ -202,497 +290,743 @@ fn str_to_f64_bits(s: string) -> int { // 「integer literal overflow」是编码层限制错误(编译器内部表示 = 经典 64 位机器字 // 投影,超形状 = 该投影无载体),不是语义溢出事件——语义层无溢出概念。表示升级 // (扩展/多字)为 hw-map/远期事项,见 specs/2026-09-06-int-unbounded-semantics.md。 -fn str_int_literal(s: string) -> int { - sl := str_len(s); - base : ., mut = 10; - start : ., mut = 0; - if sl >= 2 && load8(s, 0) == 48 { - pfx := load8(s, 1); - if pfx == 120 || pfx == 88 { base = 16; start = 2; } - else if pfx == 111 || pfx == 79 { base = 8; start = 2; } - else if pfx == 98 || pfx == 66 { base = 2; start = 2; } - } - value : ., mut = 0; - digits : ., mut = 0; - i : ., mut = start; - loop { - if i >= sl { break; } - c := load8(s, i); - if c == 95 { i = i + 1; continue; } - d : ., mut = -1; - if c >= 48 && c <= 57 { d = c - 48; } - else if c >= 65 && c <= 70 { d = c - 55; } - else if c >= 97 && c <= 102 { d = c - 87; } - if d < 0 || d >= base { add_error("invalid integer literal"); return 0; } +fn str_int_literal(s: string) -> int: + sl := str_len(s) + base : ., mut = 10 + start : ., mut = 0 + if sl >= 2 && load8(s, 0) == 48: + pfx := load8(s, 1) + if pfx == 120 || pfx == 88: + base = 16 + start = 2 + else if pfx == 111 || pfx == 79: + base = 8 + start = 2 + else if pfx == 98 || pfx == 66: + base = 2 + start = 2 + value : ., mut = 0 + digits : ., mut = 0 + i : ., mut = start + loop: + if i >= sl: + break + c := load8(s, i) + if c == 95: + i = i + 1 + continue + d : ., mut = -1 + if c >= 48 && c <= 57: + d = c - 48 + else if c >= 65 && c <= 70: + d = c - 55 + else if c >= 97 && c <= 102: + d = c - 87 + if d < 0 || d >= base: + add_error("invalid integer literal") + return 0 // 溢出守卫按 base 校准:固定 i64max/10 阈值只对十进制有效——base 16 // 累积值在最后一次 ×16 直接环绕(0x8000000000000000 → i64min 绕开守卫)。 // 阈值必须 = i64max/base(base 10 的末位 d>7 边界保持)。 - if base == 10 { - if value > 922337203685477580 || - (value == 922337203685477580 && d > 7) { - add_error("integer literal overflow"); return 0; - } - } else if base == 16 { - if value > 576460752303423487 { add_error("integer literal overflow"); return 0; } - } else if base == 8 { - if value > 1152921504606846975 { add_error("integer literal overflow"); return 0; } - } else { - if value > 4611686018427387903 { add_error("integer literal overflow"); return 0; } - } - value = value * base + d; - digits = digits + 1; - i = i + 1; - } - if digits == 0 { add_error("integer literal requires digits"); return 0; } - return value; -} + if base == 10: + if value > 922337203685477580 || (value == 922337203685477580 && d > 7): + add_error("integer literal overflow") + return 0 + else if base == 16: + if value > 576460752303423487: + add_error("integer literal overflow") + return 0 + else if base == 8: + if value > 1152921504606846975: + add_error("integer literal overflow") + return 0 + else: + if value > 4611686018427387903: + add_error("integer literal overflow") + return 0 + value = value * base + d + digits = digits + 1 + i = i + 1 + if digits == 0: + add_error("integer literal requires digits") + return 0 + return value // decimal string → 定点缩放整数(数值迁移 Task 4:dex 精确字面量解析) // S = 10^6(6 位小数)。整数部分 × S + 小数 6 位;第 7 位小数起四舍五入(半进, // 与 float_str_bits 的舍入规则一致)。负号直接处理('-' 前缀)。 // 溢出:|整数部分| ≤ 9.2e12(×S 越界 = 环绕,与 int 溢出一致——文档化限制)。 -fn str_to_scaled(s: string) -> int { - sl := str_len(s); - i : ., mut = 0; - neg : int = 0; - if i < sl && load8(s, i) == 45 { neg = 1; i = i + 1; } - ip : int = 0; fp : int = 0; nd : int = 0; sd : int = 0; round_up : int = 0; - loop { - if i >= sl { break; } - c := load8(s, i); - if c == 46 { sd = 1; i = i + 1; continue; } - if c < 48 || c > 57 { break; } - if sd != 0 { - nd = nd + 1; - if nd <= 6 { fp = fp * 10 + (c - 48); } - else if nd == 7 { if c >= 53 { round_up = 1; } } - } else { - ip = ip * 10 + (c - 48); - } - i = i + 1; - } - if round_up != 0 { - fp = fp + 1; - if fp >= 1000000 { fp = 0; ip = ip + 1; } - } +fn str_to_scaled(s: string) -> int: + sl := str_len(s) + i : ., mut = 0 + neg : int = 0 + if i < sl && load8(s, i) == 45: + neg = 1 + i = i + 1 + ip : int = 0 + fp : int = 0 + nd : int = 0 + sd : int = 0 + round_up : int = 0 + loop: + if i >= sl: + break + c := load8(s, i) + if c == 46: + sd = 1 + i = i + 1 + continue + if c < 48 || c > 57: + break + if sd != 0: + nd = nd + 1 + if nd <= 6: + fp = fp * 10 + (c - 48) + else if nd == 7: + if c >= 53: + round_up = 1 + else: + ip = ip * 10 + (c - 48) + i = i + 1 + if round_up != 0: + fp = fp + 1 + if fp >= 1000000: + fp = 0 + ip = ip + 1 // 小数位补齐到 6 位:fp 是原始数字(如 "3.14" → 14),×10^(6-nd) - if nd < 6 { - pad : ., mut = 6 - nd; - loop { - if pad <= 0 { break; } - fp = fp * 10; - pad = pad - 1; - } - } - v := ip * 1000000 + fp; - if neg != 0 { return 0 - v; } - return v; -} + if nd < 6: + pad : ., mut = 6 - nd + loop: + if pad <= 0: + break + fp = fp * 10 + pad = pad - 1 + v := ip * 1000000 + fp + if neg != 0: + return 0 - v + return v -fn add_tok(kind: int, lex: int, start_line: int, start_col: int) { - grow_tokens(g_token_count + 1); - tp := g_token_count * ESZ_TOKEN; - w64(g_tokens, tp + OFF_TK_KIND, kind); - w64(g_tokens, tp + OFF_TK_LEXEME, lex); - w64(g_tokens, tp + OFF_TK_INTVAL, 0); - w64(g_tokens, tp + OFF_TK_LINE, start_line); - w64(g_tokens, tp + OFF_TK_COL, start_col); - g_token_count = g_token_count + 1; -} +fn add_tok(kind: int, lex: int, start_line: int, start_col: int): + grow_tokens(g_token_count + 1) + tp := g_token_count * ESZ_TOKEN + w64(g_tokens, tp + OFF_TK_KIND, kind) + w64(g_tokens, tp + OFF_TK_LEXEME, lex) + w64(g_tokens, tp + OFF_TK_INTVAL, 0) + w64(g_tokens, tp + OFF_TK_LINE, start_line) + w64(g_tokens, tp + OFF_TK_COL, start_col) + g_token_count = g_token_count + 1 -fn add_tok_int(kind: int, ival: int, start_line: int, start_col: int) { - grow_tokens(g_token_count + 1); - tp := g_token_count * ESZ_TOKEN; - w64(g_tokens, tp + OFF_TK_KIND, kind); - w64(g_tokens, tp + OFF_TK_LEXEME, -1); - w64(g_tokens, tp + OFF_TK_INTVAL, ival); - w64(g_tokens, tp + OFF_TK_LINE, start_line); - w64(g_tokens, tp + OFF_TK_COL, start_col); - g_token_count = g_token_count + 1; -} +fn add_tok_int(kind: int, ival: int, start_line: int, start_col: int): + grow_tokens(g_token_count + 1) + tp := g_token_count * ESZ_TOKEN + w64(g_tokens, tp + OFF_TK_KIND, kind) + w64(g_tokens, tp + OFF_TK_LEXEME, -1) + w64(g_tokens, tp + OFF_TK_INTVAL, ival) + w64(g_tokens, tp + OFF_TK_LINE, start_line) + w64(g_tokens, tp + OFF_TK_COL, start_col) + g_token_count = g_token_count + 1 -fn add_tok_str(kind: int, s: string, start_line: int, start_col: int) { - grow_tokens(g_token_count + 1); - tp := g_token_count * ESZ_TOKEN; - w64(g_tokens, tp + OFF_TK_KIND, kind); - si := str_intern(s); - w64(g_tokens, tp + OFF_TK_LEXEME, si); - w64(g_tokens, tp + OFF_TK_INTVAL, 0); - w64(g_tokens, tp + OFF_TK_LINE, start_line); - w64(g_tokens, tp + OFF_TK_COL, start_col); - g_token_count = g_token_count + 1; -} +fn add_tok_str(kind: int, s: string, start_line: int, start_col: int): + grow_tokens(g_token_count + 1) + tp := g_token_count * ESZ_TOKEN + w64(g_tokens, tp + OFF_TK_KIND, kind) + si := str_intern(s) + w64(g_tokens, tp + OFF_TK_LEXEME, si) + w64(g_tokens, tp + OFF_TK_INTVAL, 0) + w64(g_tokens, tp + OFF_TK_LINE, start_line) + w64(g_tokens, tp + OFF_TK_COL, start_col) + g_token_count = g_token_count + 1 // int_val + lexeme 双载令牌(dex 字面量用:int_val = 缩放整数,lexeme = 原数字串) -fn add_tok_int_lex(kind: int, ival: int, lexeme_ni: int, start_line: int, start_col: int) { - grow_tokens(g_token_count + 1); - tp := g_token_count * ESZ_TOKEN; - w64(g_tokens, tp + OFF_TK_KIND, kind); - w64(g_tokens, tp + OFF_TK_LEXEME, lexeme_ni); - w64(g_tokens, tp + OFF_TK_INTVAL, ival); - w64(g_tokens, tp + OFF_TK_LINE, start_line); - w64(g_tokens, tp + OFF_TK_COL, start_col); - g_token_count = g_token_count + 1; -} +fn add_tok_int_lex(kind: int, ival: int, lexeme_ni: int, start_line: int, start_col: int): + grow_tokens(g_token_count + 1) + tp := g_token_count * ESZ_TOKEN + w64(g_tokens, tp + OFF_TK_KIND, kind) + w64(g_tokens, tp + OFF_TK_LEXEME, lexeme_ni) + w64(g_tokens, tp + OFF_TK_INTVAL, ival) + w64(g_tokens, tp + OFF_TK_LINE, start_line) + w64(g_tokens, tp + OFF_TK_COL, start_col) + g_token_count = g_token_count + 1 -fn skip_ws(src: string, pos: int, max_len: int) -> int { +fn skip_ws(src: string, pos: int, max_len: int) -> int: // Account for the token/comment consumed since the previous call, then // consume whitespace. g_pos is the last byte reflected in line/column. - tracked : ., mut = g_pos; - loop { - if tracked >= pos { break; } - c0 := cur_char_at(src, tracked, max_len); - if c0 == 10 { g_line = g_line + 1; g_col = 1; } - else { g_col = g_col + 1; } - tracked = tracked + 1; - } - loop { - c := cur_char_at(src, pos, max_len); - if c == 32 || c == 9 || c == 13 || c == 10 { - if c == 10 { g_line = g_line + 1; g_col = 1; } - else { g_col = g_col + 1; } - pos = pos + 1; - } - else { break; } - } - g_pos = pos; - return pos; -} + tracked : ., mut = g_pos + loop: + if tracked >= pos: + break + c0 := cur_char_at(src, tracked, max_len) + if c0 == 10: + g_line = g_line + 1 + g_col = 1 + else: + g_col = g_col + 1 + tracked = tracked + 1 + loop: + c := cur_char_at(src, pos, max_len) + if c == 32 || c == 9 || c == 13 || c == 10: + if c == 10: + g_line = g_line + 1 + g_col = 1 + else: + g_col = g_col + 1 + pos = pos + 1 + else: + break + g_pos = pos + return pos -fn tokenize(_src: string) { - g_token_count = 0; +fn tokenize(_src: string): + g_token_count = 0 // 注意:不再清零 g_error_count——res_imports 会重 tokenize(拼接 import // 前后两轮),清零会把首轮词法守卫错误(整数字面量溢出等)吞掉。错误 // 清理由 run_frontend 会话起点负责(错误累积跨多轮 tokenize)。 - _pos : ., mut = 0; - g_pos = 0; - g_line = 1; - g_col = 1; - _slen : ., mut = str_len(_src); - _pos = skip_ws(_src, _pos, _slen); + _pos : ., mut = 0 + g_pos = 0 + g_line = 1 + g_col = 1 + _slen : ., mut = str_len(_src) + _pos = skip_ws(_src, _pos, _slen) - loop { - if _pos >= _slen { break; } - c := cur_char_at(_src, _pos, _slen); - start_line : ., mut = g_line; - start_col : ., mut = g_col; + loop: + if _pos >= _slen: + break + c := cur_char_at(_src, _pos, _slen) + start_line : ., mut = g_line + start_col : ., mut = g_col // Comments - if c == 47 && peek_at(_src, _pos, _slen) == 47 { - _pos = _pos + 2; - loop { - if _pos >= _slen { break; } - if cur_char_at(_src, _pos, _slen) == 10 { _pos = _pos + 1; break; } - _pos = _pos + 1; - } - _pos = skip_ws(_src, _pos, _slen); - continue; - } - if c == 47 && peek_at(_src, _pos, _slen) == 42 { - _pos = _pos + 2; - loop { - if _pos >= _slen { break; } - if cur_char_at(_src, _pos, _slen) == 42 && peek_at(_src, _pos, _slen) == 47 { _pos = _pos + 2; break; } - _pos = _pos + 1; - } - _pos = skip_ws(_src, _pos, _slen); - continue; - } + if c == 47 && peek_at(_src, _pos, _slen) == 47: + _pos = _pos + 2 + loop: + if _pos >= _slen: + break + if cur_char_at(_src, _pos, _slen) == 10: + _pos = _pos + 1 + break + _pos = _pos + 1 + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 47 && peek_at(_src, _pos, _slen) == 42: + _pos = _pos + 2 + loop: + if _pos >= _slen: + break + if cur_char_at(_src, _pos, _slen) == 42 && peek_at(_src, _pos, _slen) == 47: + _pos = _pos + 2 + break + _pos = _pos + 1 + _pos = skip_ws(_src, _pos, _slen) + continue // Identifier - if is_alpha(c) != 0 { - start := _pos; - _pos = _pos + 1; - loop { - c2 := cur_char_at(_src, _pos, _slen); - if is_ident_char(c2) != 0 { _pos = _pos + 1; } else { break; } - } - ident := str_sub(_src, start, _pos - start); - kind := lookup_keyword(ident); - add_tok_str(kind, ident, start_line, start_col); - _pos = skip_ws(_src, _pos, _slen); - continue; - } + if is_alpha(c) != 0: + start := _pos + _pos = _pos + 1 + loop: + c2 := cur_char_at(_src, _pos, _slen) + if is_ident_char(c2) != 0: + _pos = _pos + 1 + else: + break + ident := str_sub(_src, start, _pos - start) + kind := lookup_keyword(ident) + add_tok_str(kind, ident, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue // Number - if is_digit(c) != 0 || (c == 46 && is_digit(peek_at(_src, _pos, _slen)) != 0) { - start := _pos; - if c == 46 { _pos = _pos + 1; c = cur_char_at(_src, _pos, _slen); } - loop { - if is_digit(cur_char_at(_src, _pos, _slen)) != 0 { _pos = _pos + 1; } - else { break; } - } + if is_digit(c) != 0 || (c == 46 && is_digit(peek_at(_src, _pos, _slen)) != 0): + start := _pos + if c == 46: + _pos = _pos + 1 + c = cur_char_at(_src, _pos, _slen) + loop: + if is_digit(cur_char_at(_src, _pos, _slen)) != 0: + _pos = _pos + 1 + else: + break // Hex/octal/binary prefix - if c == 48 && _pos - start == 1 { - nx := cur_char_at(_src, _pos, _slen); + if c == 48 && _pos - start == 1: + nx := cur_char_at(_src, _pos, _slen) // 三条进制前缀循环均**不再接受** '_'(2026-09-10 语言面收窄 §2): // 遗留 '_' 由下方后缀段落统一响亮报错(不静默消费)。 - if nx == 120 || nx == 88 { _pos = _pos + 1; loop { hc := cur_char_at(_src, _pos, _slen); if is_digit(hc) != 0 || (hc >= 65 && hc <= 70) || (hc >= 97 && hc <= 102) { _pos = _pos + 1; } else { break; } } } - else if nx == 111 || nx == 79 { _pos = _pos + 1; loop { oc := cur_char_at(_src, _pos, _slen); if (oc >= 48 && oc <= 55) { _pos = _pos + 1; } else { break; } } } - else if nx == 98 || nx == 66 { _pos = _pos + 1; loop { bc := cur_char_at(_src, _pos, _slen); if bc == 48 || bc == 49 { _pos = _pos + 1; } else { break; } } } - bad_prefix_digit : ., mut = 0; - badc := cur_char_at(_src, _pos, _slen); - if is_ident_char(badc) != 0 { bad_prefix_digit = 1; } - if bad_prefix_digit != 0 { add_error("invalid digit in integer literal"); } - } + if nx == 120 || nx == 88: + _pos = _pos + 1 + loop: + hc := cur_char_at(_src, _pos, _slen) + if is_digit(hc) != 0 || (hc >= 65 && hc <= 70) || (hc >= 97 && hc <= 102): + _pos = _pos + 1 + else: + break + else if nx == 111 || nx == 79: + _pos = _pos + 1 + loop: + oc := cur_char_at(_src, _pos, _slen) + if (oc >= 48 && oc <= 55): + _pos = _pos + 1 + else: + break + else if nx == 98 || nx == 66: + _pos = _pos + 1 + loop: + bc := cur_char_at(_src, _pos, _slen) + if bc == 48 || bc == 49: + _pos = _pos + 1 + else: + break + bad_prefix_digit : ., mut = 0 + badc := cur_char_at(_src, _pos, _slen) + if is_ident_char(badc) != 0: + bad_prefix_digit = 1 + if bad_prefix_digit != 0: + add_error("invalid digit in integer literal") // Float: only consume the '.' when it does not start a '..' // range operator (otherwise `0..4` lexes as `0.` `.4` and the // range is silently lost — the for-loop body never executes). - has_dot : ., mut = 0; - if cur_char_at(_src, _pos, _slen) == 46 && peek_at(_src, _pos, _slen) != 46 { - _pos = _pos + 1; - has_dot = 1; - loop { if is_digit(cur_char_at(_src, _pos, _slen)) != 0 { _pos = _pos + 1; } else { break; } } - } + has_dot : ., mut = 0 + if cur_char_at(_src, _pos, _slen) == 46 && peek_at(_src, _pos, _slen) != 46: + _pos = _pos + 1 + has_dot = 1 + loop: + if is_digit(cur_char_at(_src, _pos, _slen)) != 0: + _pos = _pos + 1 + else: + break // 数字词法收窄(2026-09-10 用户裁决,语言面收窄 §2):`_` 分隔符与宽度后缀 // (f32/f64/i8..u64)**均不支持**——一律响亮报错且**不消费**残余字符 // (按标识符继续 tokenize,使后续解析给出第二重信号,不静默、不猜)。 // 修复前:`_` 被 is_alpha(95) 当后缀静默消费 → T_INT 取「无值」= 0 // (`x := 1_000` 静默成 0 = 实质误编译);宽度后缀同样静默丢弃。 - sx := cur_char_at(_src, _pos, _slen); - if sx == 95 { - add_error("invalid character '_' in numeric literal (digit separators not supported)"); - } else if is_alpha(sx) != 0 { - add_error("invalid suffix on numeric literal (width suffixes retired 2026-09-10)"); - } - num_str := str_sub(_src, start, _pos - start); + sx := cur_char_at(_src, _pos, _slen) + if sx == 95: + add_error("invalid character '_' in numeric literal (digit separators not supported)") + else if is_alpha(sx) != 0: + add_error("invalid suffix on numeric literal (width suffixes retired 2026-09-10)") + num_str := str_sub(_src, start, _pos - start) // dex 字面量(含小数点):int_val = 定点缩放整数(精确解析,数值迁移 // Task 4——十进制 → 缩放整数,非二进制近似);lexeme 槽 = 原数字串 // (parser 在 apx 场景需要 binary64 位模式:str_to_f64_bits(num_str))。 - if has_dot != 0 { - add_tok_int_lex(T_DEX, str_to_scaled(num_str), str_intern(num_str), start_line, start_col); - } else { - add_tok_int(T_INT, str_int_literal(num_str), start_line, start_col); - } - _pos = skip_ws(_src, _pos, _slen); - continue; - } + if has_dot != 0: + add_tok_int_lex(T_DEX, str_to_scaled(num_str), str_intern(num_str), start_line, start_col) + else: + add_tok_int(T_INT, str_int_literal(num_str), start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue // 字符串字面量(含 `${...}` 插值)。含插值的字面量**分段发 token**:段 = T_STRING、洞 = T_INTERP, // 由 parser 组装为 `seg + conv(hole)` 链、checker 按洞类型就地改写转换(见 ast.cr EXPR_INTERP_HOLE)。 // **无洞字面量与旧实现逐字相同**(单个 T_STRING、同 line/col、iv=0)⇒ 产物零足迹。 - if c == 34 { - _pos = _pos + 1; - sp : ., mut = _pos; // 串内容起点(同行内换算列;串内不跨行) - seg_pos : ., mut = sp; // 当前段起点 - run_start : ., mut = g_token_count; // 本字面量首 token(末尾回填 iv) - str_val : ., mut = ""; - has_hole : ., mut = 0; - loop { - cc := cur_char_at(_src, _pos, _slen); - if cc == 0 || cc == 10 { break; } - if cc == 34 { _pos = _pos + 1; break; } - if cc == 92 { - _pos = _pos + 1; - esc := cur_char_at(_src, _pos, _slen); - if esc == 110 { str_val = str_val + chr(10); } - else if esc == 116 { str_val = str_val + chr(9); } - else if esc == 114 { str_val = str_val + chr(13); } - else if esc == 48 { str_val = str_val + chr(0); } - else if esc == 39 { str_val = str_val + "'"; } - else if esc == 92 { str_val = str_val + chr(92); } - else if esc == 34 { str_val = str_val + chr(34); } - else if esc == 120 { - _pos = _pos + 1; hi := cur_char_at(_src, _pos, _slen); _pos = _pos + 1; lo := cur_char_at(_src, _pos, _slen); - hex_str := chr(hi) + chr(lo); - if hex_str == "00" { str_val = str_val + chr(0); } - else if hex_str == "0a" || hex_str == "0A" { str_val = str_val + chr(10); } - else { str_val = str_val + "?"; } - } - else { str_val = str_val + chr(esc); } - } else if cc == 36 && peek_at(_src, _pos, _slen) == 123 { + if c == 34: + _pos = _pos + 1 + sp : ., mut = _pos // 串内容起点(同行内换算列;串内不跨行) + seg_pos : ., mut = sp // 当前段起点 + run_start : ., mut = g_token_count // 本字面量首 token(末尾回填 iv) + str_val : ., mut = "" + has_hole : ., mut = 0 + loop: + cc := cur_char_at(_src, _pos, _slen) + if cc == 0 || cc == 10: + break + if cc == 34: + _pos = _pos + 1 + break + if cc == 92: + _pos = _pos + 1 + esc := cur_char_at(_src, _pos, _slen) + if esc == 110: + str_val = str_val + chr(10) + else if esc == 116: + str_val = str_val + chr(9) + else if esc == 114: + str_val = str_val + chr(13) + else if esc == 48: + str_val = str_val + chr(0) + else if esc == 39: + str_val = str_val + "'" + else if esc == 92: + str_val = str_val + chr(92) + else if esc == 34: + str_val = str_val + chr(34) + else if esc == 120: + _pos = _pos + 1 + hi := cur_char_at(_src, _pos, _slen) + _pos = _pos + 1 + lo := cur_char_at(_src, _pos, _slen) + hex_str := chr(hi) + chr(lo) + if hex_str == "00": + str_val = str_val + chr(0) + else if hex_str == "0a" || hex_str == "0A": + str_val = str_val + chr(10) + else: + str_val = str_val + "?" + else: + str_val = str_val + chr(esc) + else if cc == 36 && peek_at(_src, _pos, _slen) == 123: // ── 插值洞 `${...}` ──────────────────────────────────────────── // 扫描 = **花括号配平**(`${S{f=1}}` 取到配对 `}`;旧「跳至首个 `}`」规则会截断), // 洞内字符串字面量(含转义)整体跳过;换行/EOF 终止 ⇒ 未闭合由 parser 报 P027。 - if str_len(str_val) > 0 { - col : ., mut = start_col; - if seg_pos != sp { col = start_col + 1 + (seg_pos - sp); } - add_tok_str(T_STRING, str_val, start_line, col); - } - str_val = ""; - has_hole = 1; - hs : ., mut = _pos + 2; - hp : ., mut = hs; - depth : ., mut = 1; - loop { - hc := cur_char_at(_src, hp, _slen); - if hc == 0 || hc == 10 { break; } - if hc == 34 { - hp = hp + 1; - loop { - sc := cur_char_at(_src, hp, _slen); - if sc == 0 || sc == 10 { break; } - if sc == 92 { hp = hp + 2; continue; } - hp = hp + 1; - if sc == 34 { break; } - } - continue; - } + if str_len(str_val) > 0: + col : ., mut = start_col + if seg_pos != sp: + col = start_col + 1 + (seg_pos - sp) + add_tok_str(T_STRING, str_val, start_line, col) + str_val = "" + has_hole = 1 + hs : ., mut = _pos + 2 + hp : ., mut = hs + depth : ., mut = 1 + loop: + hc := cur_char_at(_src, hp, _slen) + if hc == 0 || hc == 10: + break + if hc == 34: + hp = hp + 1 + loop: + sc := cur_char_at(_src, hp, _slen) + if sc == 0 || sc == 10: + break + if sc == 92: + hp = hp + 2 + continue + hp = hp + 1 + if sc == 34: + break + continue // 洞内 **char 字面量** 整体跳过(`'{'` 里的 `{` 不得参与配平——对抗复核点名的漏点①) - if hc == 39 { - hp = hp + 1; - loop { - cc2 := cur_char_at(_src, hp, _slen); - if cc2 == 0 || cc2 == 10 { break; } - if cc2 == 92 { hp = hp + 2; continue; } - hp = hp + 1; - if cc2 == 39 { break; } - } - continue; - } + if hc == 39: + hp = hp + 1 + loop: + cc2 := cur_char_at(_src, hp, _slen) + if cc2 == 0 || cc2 == 10: + break + if cc2 == 92: + hp = hp + 2 + continue + hp = hp + 1 + if cc2 == 39: + break + continue // 洞内 **行注释** 整体跳过(漏点②) - if hc == 47 && cur_char_at(_src, hp + 1, _slen) == 47 { - loop { - cc3 := cur_char_at(_src, hp, _slen); - if cc3 == 0 || cc3 == 10 { break; } - hp = hp + 1; - } - continue; - } + if hc == 47 && cur_char_at(_src, hp + 1, _slen) == 47: + loop: + cc3 := cur_char_at(_src, hp, _slen) + if cc3 == 0 || cc3 == 10: + break + hp = hp + 1 + continue // 洞内 **块注释** 整体跳过(漏点③) - if hc == 47 && cur_char_at(_src, hp + 1, _slen) == 42 { - hp = hp + 2; - loop { - cc4 := cur_char_at(_src, hp, _slen); - if cc4 == 0 { break; } - if cc4 == 42 && cur_char_at(_src, hp + 1, _slen) == 47 { hp = hp + 2; break; } - hp = hp + 1; - } - continue; - } - if hc == 123 { depth = depth + 1; } - if hc == 125 { depth = depth - 1; if depth == 0 { break; } } - hp = hp + 1; - } - cflag : ., mut = 4; // iv bit2 = 洞已闭合 - if cur_char_at(_src, hp, _slen) != 125 { cflag = 0; } - ti := g_token_count; - add_tok_str(T_INTERP, str_sub(_src, hs, hp - hs), start_line, start_col + 1 + (hs - sp)); - w64(g_tokens, ti * ESZ_TOKEN + OFF_TK_INTVAL, cflag); - _pos = hp; - if cflag != 0 { _pos = _pos + 1; } - seg_pos = _pos; - continue; - } else { - str_val = str_val + chr(cc); - } - _pos = _pos + 1; - } - if str_len(str_val) > 0 || has_hole == 0 { - col2 : ., mut = start_col; - if seg_pos != sp { col2 = start_col + 1 + (seg_pos - sp); } - add_tok_str(T_STRING, str_val, start_line, col2); - } - if has_hole != 0 { + if hc == 47 && cur_char_at(_src, hp + 1, _slen) == 42: + hp = hp + 2 + loop: + cc4 := cur_char_at(_src, hp, _slen) + if cc4 == 0: + break + if cc4 == 42 && cur_char_at(_src, hp + 1, _slen) == 47: + hp = hp + 2 + break + hp = hp + 1 + continue + if hc == 123: + depth = depth + 1 + if hc == 125: + depth = depth - 1 + if depth == 0: + break + hp = hp + 1 + cflag : ., mut = 4 // iv bit2 = 洞已闭合 + if cur_char_at(_src, hp, _slen) != 125: + cflag = 0 + ti := g_token_count + add_tok_str(T_INTERP, str_sub(_src, hs, hp - hs), start_line, start_col + 1 + (hs - sp)) + w64(g_tokens, ti * ESZ_TOKEN + OFF_TK_INTVAL, cflag) + _pos = hp + if cflag != 0: + _pos = _pos + 1 + seg_pos = _pos + continue + else: + str_val = str_val + chr(cc) + _pos = _pos + 1 + if str_len(str_val) > 0 || has_hole == 0: + col2 : ., mut = start_col + if seg_pos != sp: + col2 = start_col + 1 + (seg_pos - sp) + add_tok_str(T_STRING, str_val, start_line, col2) + if has_hole != 0: // 回填 run 内各 part 的 iv:+1 = 属插值字面量 · +2 = 其后还有 part(洞闭合位 4 保留)。 // ⚠ 用加法不用按位或:**bootstrap 后端不支持 `|`/`&`**(`NotImplementedError: Binary op |`,实测)。 // 目的:parser 只把**同一字面量**的 part 连成一条链(`"${x}" "y"` 是两个字面量,不连)。 - ri : ., mut = run_start; - loop { - if ri >= g_token_count { break; } - iv : ., mut = r64(g_tokens, ri * ESZ_TOKEN + OFF_TK_INTVAL); - iv = iv + 1; - if ri + 1 < g_token_count { iv = iv + 2; } - w64(g_tokens, ri * ESZ_TOKEN + OFF_TK_INTVAL, iv); - ri = ri + 1; - } - } - _pos = skip_ws(_src, _pos, _slen); - continue; - } + ri : ., mut = run_start + loop: + if ri >= g_token_count: + break + iv : ., mut = r64(g_tokens, ri * ESZ_TOKEN + OFF_TK_INTVAL) + iv = iv + 1 + if ri + 1 < g_token_count: + iv = iv + 2 + w64(g_tokens, ri * ESZ_TOKEN + OFF_TK_INTVAL, iv) + ri = ri + 1 + _pos = skip_ws(_src, _pos, _slen) + continue // Char literal - if c == 39 { - _pos = _pos + 1; - ch : ., mut = chr(0); - if cur_char_at(_src, _pos, _slen) == 92 { - _pos = _pos + 1; - esc2 := cur_char_at(_src, _pos, _slen); - if esc2 == 110 { ch = chr(10); } - else if esc2 == 116 { ch = chr(9); } - else if esc2 == 114 { ch = chr(13); } - else if esc2 == 48 { ch = chr(0); } - else if esc2 == 39 { ch = "'"; } - else if esc2 == 92 { ch = chr(92); } - else if esc2 == 34 { ch = chr(34); } - else if esc2 == 120 { - _pos = _pos + 1; hi2 := cur_char_at(_src, _pos, _slen); _pos = _pos + 1; lo2 := cur_char_at(_src, _pos, _slen); - if chr(hi2) + chr(lo2) == "00" { ch = chr(0); } - else { ch = "?"; } - } - else { ch = chr(esc2); } - _pos = _pos + 1; - } else { - ch = chr(cur_char_at(_src, _pos, _slen)); - _pos = _pos + 1; - } - if cur_char_at(_src, _pos, _slen) == 39 { _pos = _pos + 1; } - add_tok_str(T_CHAR, ch, start_line, start_col); - _pos = skip_ws(_src, _pos, _slen); - continue; - } + if c == 39: + _pos = _pos + 1 + ch : ., mut = chr(0) + if cur_char_at(_src, _pos, _slen) == 92: + _pos = _pos + 1 + esc2 := cur_char_at(_src, _pos, _slen) + if esc2 == 110: + ch = chr(10) + else if esc2 == 116: + ch = chr(9) + else if esc2 == 114: + ch = chr(13) + else if esc2 == 48: + ch = chr(0) + else if esc2 == 39: + ch = "'" + else if esc2 == 92: + ch = chr(92) + else if esc2 == 34: + ch = chr(34) + else if esc2 == 120: + _pos = _pos + 1 + hi2 := cur_char_at(_src, _pos, _slen) + _pos = _pos + 1 + lo2 := cur_char_at(_src, _pos, _slen) + if chr(hi2) + chr(lo2) == "00": + ch = chr(0) + else: + ch = "?" + else: + ch = chr(esc2) + _pos = _pos + 1 + else: + ch = chr(cur_char_at(_src, _pos, _slen)) + _pos = _pos + 1 + if cur_char_at(_src, _pos, _slen) == 39: + _pos = _pos + 1 + add_tok_str(T_CHAR, ch, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue // Multi-char operators - if c == 61 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_EQEQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 33 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_BANGEQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 60 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_LTEQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 62 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_GTEQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 38 && peek_at(_src, _pos, _slen) == 38 { _pos = _pos + 2; add_tok(T_ANDAND, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 124 && peek_at(_src, _pos, _slen) == 124 { _pos = _pos + 2; add_tok(T_PIPEPIPE, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 45 && peek_at(_src, _pos, _slen) == 62 { _pos = _pos + 2; add_tok(T_ARROW, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 61 && peek_at(_src, _pos, _slen) == 62 { _pos = _pos + 2; add_tok(T_FATARROW, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 58 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_COLON_EQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 58 && peek_at(_src, _pos, _slen) == 58{ _pos = _pos + 2; add_tok(T_PATHSEP, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 46 && peek_at(_src, _pos, _slen) == 46 { - _pos = _pos + 2; - if cur_char_at(_src, _pos, _slen) == 46 { _pos = _pos + 1; add_tok(T_DOTDOTDOT, -1, start_line, start_col); } - else { add_tok(T_DOTDOT, -1, start_line, start_col); } - _pos = skip_ws(_src, _pos, _slen); continue; } + if c == 61 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_EQEQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 33 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_BANGEQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 60 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_LTEQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 62 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_GTEQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 38 && peek_at(_src, _pos, _slen) == 38: + _pos = _pos + 2 + add_tok(T_ANDAND, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 124 && peek_at(_src, _pos, _slen) == 124: + _pos = _pos + 2 + add_tok(T_PIPEPIPE, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 45 && peek_at(_src, _pos, _slen) == 62: + _pos = _pos + 2 + add_tok(T_ARROW, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 61 && peek_at(_src, _pos, _slen) == 62: + _pos = _pos + 2 + add_tok(T_FATARROW, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 58 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_COLON_EQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 58 && peek_at(_src, _pos, _slen) == 58: + _pos = _pos + 2 + add_tok(T_PATHSEP, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 46 && peek_at(_src, _pos, _slen) == 46: + _pos = _pos + 2 + if cur_char_at(_src, _pos, _slen) == 46: + _pos = _pos + 1 + add_tok(T_DOTDOTDOT, -1, start_line, start_col) + else: + add_tok(T_DOTDOT, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue // Compound assignment operators - if c == 43 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_PLUS_EQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 45 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_MINUS_EQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 42 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_STAR_EQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 47 && peek_at(_src, _pos, _slen) == 61 { _pos = _pos + 2; add_tok(T_SLASH_EQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } + if c == 43 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_PLUS_EQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 45 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_MINUS_EQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 42 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_STAR_EQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 47 && peek_at(_src, _pos, _slen) == 61: + _pos = _pos + 2 + add_tok(T_SLASH_EQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue // Single-char tokens - if c == 40 { _pos = _pos + 1; add_tok(T_LPAREN, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 41 { _pos = _pos + 1; add_tok(T_RPAREN, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 123 { _pos = _pos + 1; add_tok(T_LBRACE, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 125 { _pos = _pos + 1; add_tok(T_RBRACE, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 91 { _pos = _pos + 1; add_tok(T_LBRACKET, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 93 { _pos = _pos + 1; add_tok(T_RBRACKET, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 44 { _pos = _pos + 1; add_tok(T_COMMA, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 59 { _pos = _pos + 1; add_tok(T_SEMI, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 58 { _pos = _pos + 1; add_tok(T_COLON, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 46 { _pos = _pos + 1; add_tok(T_DOT, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 61 { _pos = _pos + 1; add_tok(T_EQ, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 33 { _pos = _pos + 1; add_tok(T_BANG, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 60 { _pos = _pos + 1; add_tok(T_LT, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 62 { _pos = _pos + 1; add_tok(T_GT, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 43 { _pos = _pos + 1; add_tok(T_PLUS, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 45 { _pos = _pos + 1; add_tok(T_MINUS, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 42 { _pos = _pos + 1; add_tok(T_STAR, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 47 { _pos = _pos + 1; add_tok(T_SLASH, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 37 { _pos = _pos + 1; add_tok(T_PERCENT, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 38 { _pos = _pos + 1; add_tok(T_AMPERSAND, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 95 { _pos = _pos + 1; add_tok(T_UNDERSCORE, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 64 { _pos = _pos + 1; add_tok(T_AT, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } - if c == 63 { _pos = _pos + 1; add_tok(T_QUESTION, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } + if c == 40: + _pos = _pos + 1 + add_tok(T_LPAREN, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 41: + _pos = _pos + 1 + add_tok(T_RPAREN, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 123: + _pos = _pos + 1 + add_tok(T_LBRACE, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 125: + _pos = _pos + 1 + add_tok(T_RBRACE, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 91: + _pos = _pos + 1 + add_tok(T_LBRACKET, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 93: + _pos = _pos + 1 + add_tok(T_RBRACKET, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 44: + _pos = _pos + 1 + add_tok(T_COMMA, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 59: + _pos = _pos + 1 + add_tok(T_SEMI, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 58: + _pos = _pos + 1 + add_tok(T_COLON, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 46: + _pos = _pos + 1 + add_tok(T_DOT, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 61: + _pos = _pos + 1 + add_tok(T_EQ, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 33: + _pos = _pos + 1 + add_tok(T_BANG, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 60: + _pos = _pos + 1 + add_tok(T_LT, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 62: + _pos = _pos + 1 + add_tok(T_GT, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 43: + _pos = _pos + 1 + add_tok(T_PLUS, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 45: + _pos = _pos + 1 + add_tok(T_MINUS, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 42: + _pos = _pos + 1 + add_tok(T_STAR, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 47: + _pos = _pos + 1 + add_tok(T_SLASH, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 37: + _pos = _pos + 1 + add_tok(T_PERCENT, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 38: + _pos = _pos + 1 + add_tok(T_AMPERSAND, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 95: + _pos = _pos + 1 + add_tok(T_UNDERSCORE, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 64: + _pos = _pos + 1 + add_tok(T_AT, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue + if c == 63: + _pos = _pos + 1 + add_tok(T_QUESTION, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue // 批 6(T1 词法面):`#` = 规约标注 sigil(`#check(expr)` / `#ensure(expr)` 的首字符)。 // **有意的行为变更**:修复前 `#` 走下方 Unknown 分支被**静默丢弃**(本函数尾), // 带标注的源会被 parse_body 误解析成静默错产物(T0 §10.2 实测:build rc=0 + 运行返回错值)。 // 零足迹依据(T0 实测):全仓 182 个 .cr 的**裸 `#` = 0**(注释/字符串内的 `#` 不达本行) // ⇒ 本分支对既有语料**构造性零扰动**。后随字符由 parser 校验(必须 IDENT)。 - if c == 35 { _pos = _pos + 1; add_tok(T_HASH, -1, start_line, start_col); _pos = skip_ws(_src, _pos, _slen); continue; } + if c == 35: + _pos = _pos + 1 + add_tok(T_HASH, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue // Unknown - _pos = _pos + 1; - _pos = skip_ws(_src, _pos, _slen); - } + _pos = _pos + 1 + _pos = skip_ws(_src, _pos, _slen) - add_tok(T_EOF, -1, g_line, g_col); + add_tok(T_EOF, -1, g_line, g_col) // Sync back globals - g_pos = _pos; - g_source_len = _slen; -} + g_pos = _pos + g_source_len = _slen diff --git a/src/compiler/main.cr b/src/compiler/main.cr index 6fd1cbfc..15f8692f 100644 --- a/src/compiler/main.cr +++ b/src/compiler/main.cr @@ -2,142 +2,144 @@ // Compiler entry point: CLI, pipeline orchestration, and test API. // Global flags for project/directory mode -g_is_project_mode : int, mut; -g_ccr_out_path : string, mut; -g_cir_out_path : string, mut; -g_binary_out_path : string, mut; - -fn is_cr_file(path: string) -> int { - slen := str_len(path); - if slen < 3 { return 0; } - ext := str_sub(path, slen - 3, 3); - if str_eq(ext, ".cr") != 0 { return 1; } - return 0; -} - -fn read_source_file(path: string) -> string { - g_source_dir = dirname(path); - source := read_file(path); - if str_len(source) > 0 { - } - return source; -} - -fn read_project_dir(dir: string) -> string { - source := load_project(dir); - g_source_dir = g_project_source_dir; - if str_len(source) > 0 { - return source; - } - println("error: no main.cr found in directory"); - return ""; -} - -fn is_decl_stmt(s: string) -> int { - slen := str_len(s); - i : ., mut = 0; - loop { - if i >= slen { return 0; } - cb := load8(s, i); - if cb == 32 || cb == 9 || cb == 10 || cb == 13 { i = i + 1; } - else { break; } - } - if i < slen { - cb := load8(s, i); - if (cb >= 97 && cb <= 122) || (cb >= 65 && cb <= 90) || cb == 95 { - j : ., mut = i + 1; - loop { - if j >= slen { return 0; } - c2b := load8(s, j); - if c2b == 32 || c2b == 9 || c2b == 10 || c2b == 13 { j = j + 1 } - else if c2b == 58 { return 1; } - else if (c2b >= 97 && c2b <= 122) || (c2b >= 65 && c2b <= 90) || (c2b >= 48 && c2b <= 57) || c2b == 95 { j = j + 1 } - else { return 0; } - } - } - } - return 0; -} +g_is_project_mode : int, mut +g_ccr_out_path : string, mut +g_cir_out_path : string, mut +g_binary_out_path : string, mut + +fn is_cr_file(path: string) -> int: + slen := str_len(path) + if slen < 3: + return 0 + ext := str_sub(path, slen - 3, 3) + if str_eq(ext, ".cr") != 0: + return 1 + return 0 + +fn read_source_file(path: string) -> string: + g_source_dir = dirname(path) + source := read_file(path) + + + return source + +fn read_project_dir(dir: string) -> string: + source := load_project(dir) + g_source_dir = g_project_source_dir + if str_len(source) > 0: + return source + println("error: no main.cr found in directory") + return "" + +fn is_decl_stmt(s: string) -> int: + slen := str_len(s) + i : ., mut = 0 + loop: + if i >= slen: + return 0 + cb := load8(s, i) + if cb == 32 || cb == 9 || cb == 10 || cb == 13: + i = i + 1 + else: + break + if i < slen: + cb := load8(s, i) + if (cb >= 97 && cb <= 122) || (cb >= 65 && cb <= 90) || cb == 95: + j : ., mut = i + 1 + loop: + if j >= slen: + return 0 + c2b := load8(s, j) + if c2b == 32 || c2b == 9 || c2b == 10 || c2b == 13: + j = j + 1 + else if c2b == 58: + return 1 + else if (c2b >= 97 && c2b <= 122) || (c2b >= 65 && c2b <= 90) || (c2b >= 48 && c2b <= 57) || c2b == 95: + j = j + 1 + else: + return 0 + return 0 // Detect imports (uses res_imports which is already called before this point) -fn detect_imports(src: string) -> int { - sl := str_len(src); i : ., mut = 0; cnt : ., mut = 0; - loop { if i + 6 >= sl { break; } - if load8(src,i) == 105 && load8(src,i+1) == 109 && - load8(src,i+2) == 112 && load8(src,i+3) == 111 && - load8(src,i+4) == 114 && load8(src,i+5) == 116 { - cnt = cnt + 1; - i = i + 6; continue; } - i = i + 1; } - return cnt; -} +fn detect_imports(src: string) -> int: + sl := str_len(src) + i : ., mut = 0 + cnt : ., mut = 0 + loop: + if i + 6 >= sl: + break + if load8(src,i) == 105 && load8(src,i+1) == 109 && load8(src,i+2) == 112 && load8(src,i+3) == 111 && load8(src,i+4) == 114 && load8(src,i+5) == 116: + cnt = cnt + 1 + i = i + 6 + continue + i = i + 1 + return cnt // Read source from a file path or project directory; returns 0 on success -fn read_source_or_project(src_path: string) -> int { - sl := str_len(src_path); - g_is_project_mode = 0; - if sl >= 4 { - ext := str_sub(src_path, sl - 3, 3); - if str_eq(ext, ".cr") == 0 { g_is_project_mode = 1; } - } else { - g_is_project_mode = 1; - } - - if g_is_project_mode != 0 { - g_source = read_project_dir(src_path); - if str_len(g_source) > 0 { - return 0; - } - g_is_project_mode = 0; - g_source = read_file(src_path); - if str_len(g_source) == 0 { - print("error: cannot read "); - println(src_path); - return 1; - } - g_source_dir = dirname(src_path); - return 0; - } - - g_source = read_file(src_path); - if str_len(g_source) == 0 { - print("error: cannot read "); - println(src_path); - return 1; - } - g_source_dir = dirname(src_path); - return 0; -} - -fn read_static_runtime_source() -> string { - source := read_file("src/runtime/rt.cr"); - if str_len(source) > 0 { return source; } - - exe_path := get_exe_path(); - exe_dir := dirname(exe_path); - if str_len(exe_dir) > 0 { - source = read_file(exe_dir + "../src/runtime/rt.cr"); - } - return source; -} +fn read_source_or_project(src_path: string) -> int: + sl := str_len(src_path) + g_is_project_mode = 0 + if sl >= 4: + ext := str_sub(src_path, sl - 3, 3) + if str_eq(ext, ".cr") == 0: + g_is_project_mode = 1 + else: + g_is_project_mode = 1 + + if g_is_project_mode != 0: + g_source = read_project_dir(src_path) + if str_len(g_source) > 0: + return 0 + g_is_project_mode = 0 + g_source = read_file(src_path) + if str_len(g_source) == 0: + print("error: cannot read ") + println(src_path) + return 1 + g_source_dir = dirname(src_path) + return 0 + + g_source = read_file(src_path) + if str_len(g_source) == 0: + print("error: cannot read ") + println(src_path) + return 1 + g_source_dir = dirname(src_path) + return 0 + +fn read_static_runtime_source() -> string: + source := read_file("src/runtime/rt.cr") + if str_len(source) > 0: + return source + + exe_path := get_exe_path() + exe_dir := dirname(exe_path) + if str_len(exe_dir) > 0: + source = read_file(exe_dir + "../src/runtime/rt.cr") + return source // Run the shared frontend pipeline: tokenize → resolve → parse → check // Returns 0 on success, 1 on error. -fn run_frontend() -> int { - g_error_count = 0; // 会话起点清词法/语法错误(tokenize 多轮累积,见 lexer.cr) - println("[1/5] tokenize..."); - tokenize(g_source); - println("[2/5] resolve imports..."); - res_imports(); - println("[3/5] parse..."); - parse_all(); - if g_diag_count > 0 { print_diagnostics(); return 1; } - if g_error_count > 0 { print_parse_errors(); return 1; } - println("[4/5] type check..."); - check_all(); +fn run_frontend() -> int: + g_error_count = 0 // 会话起点清词法/语法错误(tokenize 多轮累积,见 lexer.cr) + println("[1/5] tokenize...") + tokenize(g_source) + println("[2/5] resolve imports...") + res_imports() + println("[3/5] parse...") + parse_all() + if g_diag_count > 0: + print_diagnostics() + return 1 + if g_error_count > 0: + print_parse_errors() + return 1 + println("[4/5] type check...") + check_all() // 批 6(T4):VC 清单 dump——**位置 = fail-closed 闸门之前**:红态下也照常列出(红条目显式标 red, // 不静默省略;「没列出来」与「列出来是红的」可区分)。只打印 ⇒ 不改 rc/产物。 - if cli_has("dump-vcs") != 0 { print(vcs_dump()); } + if cli_has("dump-vcs") != 0: + print(vcs_dump()) // Type-check diagnostics:**fail-closed(FC 批 T2;维护者裁)= 默认阻断 + 豁免登记表**。 // 判据(成文化)= 「判定继续 ⇒ 产出静默错产物」——五组先例:R002 常量档越界(F2)· // TS01-04+TK02 聚合字面量三校验(TODO #2026-09-11-11)· TM03 match 非穷尽(#2026-09-11-13,修复前缺臂 ⇒ 未匹配值 @@ -146,42 +148,39 @@ fn run_frontend() -> int { // 豁免表 = `diag.cr::diag_gate_exempt`(码级 + 位点证据/理由/退出条件三字段;只减不增)。 // `scope`(裁-FC-1 = (C)):本处**只以 GATE_SCOPE_BUILD 调用**;`check` 分支的 rc 规则 // (下方「计数 > 0」)不消费本表 ⇒ **check 面基线零变化**(72 档 34×0/38×1 不换代)。 - if g_diag_count > 0 { - hard : ., mut = 0; - di : ., mut = 0; - n_block : ., mut = 0; // --diag-gate-report 用(默认关时恒 0,零行为影响) - rep : ., mut = ""; - loop { - if di >= g_diag_count { break; } - ec := r64(g_diags, di * DIAG_REC_SIZE); + if g_diag_count > 0: + hard : ., mut = 0 + di : ., mut = 0 + n_block : ., mut = 0 // --diag-gate-report 用(默认关时恒 0,零行为影响) + rep : ., mut = "" + loop: + if di >= g_diag_count: + break + ec := r64(g_diags, di * DIAG_REC_SIZE) // 默认阻断:**不在豁免表内 ⇒ hard = 1**(表 = diag.cr;只减不增)。 - if diag_gate_exempt(ec, GATE_SCOPE_BUILD) == 0 { - hard = 1; - n_block = n_block + 1; - if str_len(rep) > 0 { rep = rep + ","; } - rep = rep + error_cat_prefix(ec / 1000) + pad_diag_num(ec % 1000); - } - di = di + 1; - } + if diag_gate_exempt(ec, GATE_SCOPE_BUILD) == 0: + hard = 1 + n_block = n_block + 1 + if str_len(rep) > 0: + rep = rep + "," + rep = rep + error_cat_prefix(ec / 1000) + pad_diag_num(ec % 1000) + di = di + 1 // 隐藏通道(--diag-gate-report,默认关;同 --verify-* 家族纪律):**只读报告**—— // 逐条列出会被闸门阻断的码 + 计数。开/关两态 **rc 与产物逐字节同**(本行仅追加输出)。 - if cli_has("diag-gate-report") != 0 { - print("[diag-gate] face=build blocked="); - print(int_str(n_block)); - print(" total="); - print(int_str(g_diag_count)); - print(" codes="); - println(rep); - } - print_diagnostics(); - if hard != 0 { + if cli_has("diag-gate-report") != 0: + print("[diag-gate] face=build blocked=") + print(int_str(n_block)) + print(" total=") + print(int_str(g_diag_count)) + print(" codes=") + println(rep) + print_diagnostics() + if hard != 0: // 进度行在此(诊断之后、返回之前)打印,与原位置同序:S0 期本行只覆盖 hard==0 路径, // 本批使**被阻断路径也打印**(否则 25 档语料的日志会缺行)。唯一可见差异 = 「诊断码 // 全在旧硬名单」的档(S0 提前返回无本行;本批打印)——72 档语料内 0 档、探针 1 档。 - println("[5/5] frontend done"); - return 1; - } - } + println("[5/5] frontend done") + return 1 // AST-level constant folding and optimization (O1+) /* if g_opt_level >= 1 && g_func_count > 0 { @@ -192,372 +191,363 @@ if g_opt_level >= 1 && g_func_count > 0 { ast_optimize_body(body); fi = fi + 1; } } - + */ - println("[5/5] frontend done"); + println("[5/5] frontend done") // R2 P2a Task 3(C-4):侧表 ↔ res_type_node 管线内断言(隐藏调试通道,默认关)。 // 必须跑在 check_all 之后(类型表/侧表已成型);不一致 → rc≠0(判据可挂)。默认关 = // 一次全局读 + 返回(产物/输出零影响)。 - if cli_has("verify-named-dedup") != 0 { - if named_dedup_verify() != 0 { return 1; } - } + if cli_has("verify-named-dedup") != 0: + if named_dedup_verify() != 0: + return 1 // R2 P3 Task 4:枚举载荷**类型节点**列入库断言(隐藏调试通道,默认关;与上一条同址同式)。 // 断言 = 每个载荷槽都有类型节点(parser 同写;缺口复发即 rc≠0);`collapses` 计数 = 裸码 // 列丢失真实载荷类型的槽数(信息量,非失败)。见 ty_shadow.cr 的 sh_evp_verify。 - if cli_has("verify-evp-nodes") != 0 { - if sh_evp_verify() != 0 { return 1; } - } - return 0; -} + if cli_has("verify-evp-nodes") != 0: + if sh_evp_verify() != 0: + return 1 + return 0 // Determine default output path from source path (strip .cr, add extension) -fn default_out_path(src_path: string, ext: string) -> string { - out : ., mut = ""; - if g_is_project_mode != 0 { - out = g_project_name + ext; - } else { - out = src_path; - sl := str_len(src_path); - if sl > 3 { - e := str_sub(src_path, sl - 3, 3); - if str_eq(e, ".cr") != 0 { - out = str_sub(src_path, 0, sl - 3) + ext; - } - } - } - return out; -} +fn default_out_path(src_path: string, ext: string) -> string: + out : ., mut = "" + if g_is_project_mode != 0: + out = g_project_name + ext + else: + out = src_path + sl := str_len(src_path) + if sl > 3: + e := str_sub(src_path, sl - 3, 3) + if str_eq(e, ".cr") != 0: + out = str_sub(src_path, 0, sl - 3) + ext + return out // **R2 P5 Task 5 删除**:`sh_finish`(R2 P1 影子对拍收尾 = 摘要行 + `--type-shadow-dump` 时的 // 差异条目转储)与其两处调用点(run/build 路径各一)随影子通道整体下线;`--type-shadow` / // `--type-shadow-dump` 两个 CLI 通道同删(D27)。运行期不再有任何影子收尾钩子。 -fn corec_main() -> int { - cli_init("corec", "Core compiler frontend"); - cli_cmd("build", "Compile .cr or directory to ELF binary"); - cli_cmd("check", "Type-check only, no output"); - cli_cmd("cir", "Output dataflow graph (.cir)"); - cli_cmd("ccr", "Output linear CFG (.ccr)"); - cli_cmd("run", "Execute code directly (interpreter mode)"); - cli_cmd("clean-cache", "Delete incremental compilation cache"); - cli_cmd("selftest-types", "Run type-engine self tests (R2 P0)"); - cli_cmd("selftest-purity", "Run effect-purity self tests (Task 1)"); - cli_flag("output", "o", "Output path"); - cli_flag_bool("static", "", "Static linking (embed runtime)"); - cli_flag("opt-level", "O", "Optimization level (0,1,2,3; default=1) — O1 CSE(corec 进程内);O2 寄存器分配+判定在 corearch(corec build 透传 --opt-level,.ccr 不承载分配结果)"); - cli_flag_bool("inject-var-shift", "", "Hidden debug: shift func0 var decl block left by 1, then save (GC-4 test hook)"); - cli_flag_bool("inject-cir-skip-journal", "", "Hidden debug: skip .cir intern-journal replay at load (v21 mutation hook; NOT for real builds)"); - cli_flag_bool("dump-types", "", "Hidden debug: dump TYPE segment content (row table + term DAG + cross-process judgment probe) after populate (R2 P4 Task 2 test channel)"); - cli_flag_bool("dump-ifaces", "", "Hidden debug: dump IFACE segment content (entry table + shapes + user ifaces + impls + method table + cross-segment term probe) after populate (R2 P4 Task 3 test channel)"); - cli_flag_bool("dump-tk-terms", "", "Hidden debug: dump per-DFNode tk + type-term slot (cir; R2 P4 Task 4 test channel — cold/warm snapshot symmetry)"); +fn corec_main() -> int: + cli_init("corec", "Core compiler frontend") + cli_cmd("build", "Compile .cr or directory to ELF binary") + cli_cmd("check", "Type-check only, no output") + cli_cmd("cir", "Output dataflow graph (.cir)") + cli_cmd("ccr", "Output linear CFG (.ccr)") + cli_cmd("run", "Execute code directly (interpreter mode)") + cli_cmd("clean-cache", "Delete incremental compilation cache") + cli_cmd("selftest-types", "Run type-engine self tests (R2 P0)") + cli_cmd("selftest-purity", "Run effect-purity self tests (Task 1)") + cli_flag("output", "o", "Output path") + cli_flag_bool("static", "", "Static linking (embed runtime)") + cli_flag("opt-level", "O", "Optimization level (0,1,2,3; default=1) — O1 CSE(corec 进程内);O2 寄存器分配+判定在 corearch(corec build 透传 --opt-level,.ccr 不承载分配结果)") + cli_flag_bool("inject-var-shift", "", "Hidden debug: shift func0 var decl block left by 1, then save (GC-4 test hook)") + cli_flag_bool("inject-cir-skip-journal", "", "Hidden debug: skip .cir intern-journal replay at load (v21 mutation hook; NOT for real builds)") + cli_flag_bool("dump-types", "", "Hidden debug: dump TYPE segment content (row table + term DAG + cross-process judgment probe) after populate (R2 P4 Task 2 test channel)") + cli_flag_bool("dump-ifaces", "", "Hidden debug: dump IFACE segment content (entry table + shapes + user ifaces + impls + method table + cross-segment term probe) after populate (R2 P4 Task 3 test channel)") + cli_flag_bool("dump-tk-terms", "", "Hidden debug: dump per-DFNode tk + type-term slot (cir; R2 P4 Task 4 test channel — cold/warm snapshot symmetry)") // **R2 P5 Task 5 删除**:`--type-shadow` / `--type-shadow-dump`(R2 P1 影子对拍的两个隐藏 // 通道)随影子层整体下线(D27/TODO #2026-09-11-8 同族清偿);判定路径不再有开关(无条件经引擎)。 - cli_flag_bool("verify-named-dedup", "", "R2 P2a: assert side-table == res_type_node for all named types (debug)"); - cli_flag_bool("verify-evp-nodes", "", "R2 P3 T4: assert enum variant payload type nodes recorded (debug)"); - cli_flag_bool("diag-gate-report", "", "FC T2: report fail-closed gate verdicts per compile (debug; default off — 不改 rc/产物)"); - cli_flag_bool("dump-vcs", "", "批 6 T4: dump spec VC list (#check/#ensure) — hidden debug channel; stdout only, no artifact, rc untouched"); - cli_flag_bool("dump-params", "", "(乙) A1: dump per-param slot type at prologue (`PARAM fn p name slot= decl=`) — hidden debug channel; stdout only, no artifact, rc untouched"); - - if cli_parse() != 0 { return 1; } - if cli_has("dump-params") != 0 { g_dump_params_on = 1; } + cli_flag_bool("verify-named-dedup", "", "R2 P2a: assert side-table == res_type_node for all named types (debug)") + cli_flag_bool("verify-evp-nodes", "", "R2 P3 T4: assert enum variant payload type nodes recorded (debug)") + cli_flag_bool("diag-gate-report", "", "FC T2: report fail-closed gate verdicts per compile (debug; default off — 不改 rc/产物)") + cli_flag_bool("dump-vcs", "", "批 6 T4: dump spec VC list (#check/#ensure) — hidden debug channel; stdout only, no artifact, rc untouched") + cli_flag_bool("dump-params", "", "(乙) A1: dump per-param slot type at prologue (`PARAM fn p name slot= decl=`) — hidden debug channel; stdout only, no artifact, rc untouched") + + if cli_parse() != 0: + return 1 + if cli_has("dump-params") != 0: + g_dump_params_on = 1 // Parse -O flag (default O1) - g_opt_level = 1; - 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; } } - cmd := cli_cmd_name(); - - if str_len(cmd) == 0 { - cli_help(); - println(""); - println("examples:"); - println(" corec build file.cr compile to ELF binary"); - println(" corec check file.cr type-check only"); - println(" corec cir file.cr dump dataflow graph"); - println(" corec ccr file.cr dump linear CFG"); - println(" corec run 'code' execute directly"); - return 1; - } + g_opt_level = 1 + 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 + cmd := cli_cmd_name() + + if str_len(cmd) == 0: + cli_help() + println("") + println("examples:") + println(" corec build file.cr compile to ELF binary") + println(" corec check file.cr type-check only") + println(" corec cir file.cr dump dataflow graph") + println(" corec ccr file.cr dump linear CFG") + println(" corec run 'code' execute directly") + return 1 // === run subcommand — inline code, no file === - 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)); + 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 +572,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) + 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..3dbffbcc 100644 --- a/src/compiler/module.cr +++ b/src/compiler/module.cr @@ -6,216 +6,211 @@ // 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) + + + 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 +218,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 +432,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) // 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: + 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 +598,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 +624,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 +647,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) + 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) + + 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..61bdb7fe 100644 --- a/src/compiler/parser.cr +++ b/src/compiler/parser.cr @@ -1,399 +1,400 @@ // 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; +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_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 // --- 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_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 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) // 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() + 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)) + 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() // 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(); + 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() // 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() + 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,88 +402,85 @@ 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: + 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() // 节点字段(数值迁移 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) { + 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 链走 @@ -490,47 +488,42 @@ fn parse_primary() -> int { // 的 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)); - } + 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(); + 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() // 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) + if check(T_LBRACE) && g_parse_no_struct_literal == 0: + advance_tok() // 契约(F5 修复,与元组分支同款):EXPR_STRUCT = a=类型名 idx、b=首 wrapper、c=字段数; // wrapper 在 g_ast 中**连续**(kind=EXPR_NONE,wrapper.a=该字段的值节点)→ 消费者 // 经 EXPR_NONE 前向解引用取值。字段值节点自身对复合表达式(调用 / 字面量 / 嵌套聚合) @@ -540,57 +533,58 @@ 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)) + 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): // Tuple: (e1, e2, ...) // 契约(F5 修复):EXPR_TUPLE = a=首 wrapper、b=元素个数;wrapper 在 g_ast 中 // **连续**,每个 wrapper(kind=EXPR_NONE)的 a = 该元素的值节点 → 消费者经 @@ -598,102 +592,99 @@ 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 + 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 // 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 +693,235 @@ 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): + 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 + 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() // 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 >= 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 // x := expr - if tok_k(p + 1) == T_COLON_EQ { return true; } + 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: + 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 || 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() + 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: // 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: + 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: // 未知标签: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() + 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 ; // 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 +936,64 @@ 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(): + 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: // 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 +1001,330 @@ 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(); + 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; + 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 !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) // 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)) + 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 // --- 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): + 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 +1333,251 @@ 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): + 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 // 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) + + 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) // 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 +1593,629 @@ 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 { +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: 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(); // ')' - spec_add(fn_ni, kind, expr, at_line, at_col); - } -} - -fn parse_ffi_annotation() -> int { + "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: // 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; + 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 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() // extern fn declaration (FFI) - if check(T_EXTERN) { - t := cur_tok(); - advance_tok(); - ffi_lang_ni : ., mut = -1; + 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_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)); + 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; - } + if check(T_SEMI): + advance_tok() + return // fn / flow fn - if check(T_FN) || check(T_FLOW) { - is_flow : ., mut = 0; + 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 { + 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) + // 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) + 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 // 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 check(T_RBRACE) || check(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) + 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 // 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) + 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 // 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 check(T_RBRACE) || check(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) + advance_tok() + 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) + advance_tok() // { // 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 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() // ( // 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) + advance_tok() // ; // 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; - } + 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 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) // 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() + advance_tok() // } // 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)) + 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 // 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) { + 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; - } + 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 // 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 + 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 { + 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(); + 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() // 批 8(静默面收口 · 条目 4 前置):**消费整条 import 语句**。 // 修复前只吞 `import` 关键字本身,其后的路径/别名 token 落进 `parse_declaration` 尾部兜底被 // **静默吞**——全语料(含 `_import.cr` 与注入的运行时源)普遍如此 ⇒ 条目 4 的顶层硬错若 @@ -2171,30 +2223,36 @@ 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): + 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 // 插值洞表达式统一解析(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..32f806da 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) + 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 { 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" // 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 { 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" // 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 { 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" - 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..33f92301 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 差分编码(相对上一令牌 @@ -979,217 +1204,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_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 // 名字是否为内置类型名(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..ee444689 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) + 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/tools/v4_frontend_probe.py b/tools/v4_frontend_probe.py index c351ae1e..097c0b41 100644 --- a/tools/v4_frontend_probe.py +++ b/tools/v4_frontend_probe.py @@ -710,9 +710,16 @@ def cmd_ast_freeze(rev): def selfhost_keywords(text): - """自源 `src/compiler/lexer.cr` 的 `lookup_keyword` 表(抽法沿用施工计划 §十二 的脚本)。""" + """自源 `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'):] - blk = blk[:blk.index('\n}\n') + 3] + nxt = re.search(r'\nfn ', blk) + if nxt: + blk = blk[:nxt.start()] return set(re.findall(r'if s == "([^"]+)"', blk)) diff --git a/tools/v4_migrate.py b/tools/v4_migrate.py new file mode 100644 index 00000000..295d1d07 --- /dev/null +++ b/tools/v4_migrate.py @@ -0,0 +1,853 @@ +#!/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 + + +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': [], 'return_filled': [], 'hoisted': []} + unresolved = [] + + # ── 裁定 1:空 region ── + ops = [] # (start, end, replacement) —— 所有裁定 1/2 的文本编辑统一走这里 + 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, '')) # 删配对 `}` + 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, '')) + 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, '')) # 删配对 `}` + 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)) + + # 统一**降序**下沉:所有替换/插入一次性按起点从大到小落, + # 保证先落的(更靠后)不会挪动后落的(更靠前)的偏移。 + for start, end, rep in sorted(ops, key=lambda e: -e[0]): + src = src[:start] + rep + src[end:] + return src, recs, unresolved + + +# ── 改写 ────────────────────────────────────────────────────────────────────── +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': + cur = cur.rstrip() + ':' + flush() + 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 前端解析 ─────────────────────────────────────────────────────────── +def v4_parse_ok(text, filename=''): + 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'(?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('--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('--baseline', default=None, + help='改前原文快照目录(同相对路径)') + c.set_defaults(func=cmd_check) + + args = ap.parse_args() + return args.func(args) + + +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 From 4ad482d4ff3179aeed7601eba5f989c38656ede2 Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 17:49:36 +0800 Subject: [PATCH 03/15] =?UTF-8?q?v4=20=E8=BF=81=E7=A7=BB=EF=BC=88=E6=89=B9?= =?UTF-8?q?=E5=86=85=C2=B7=E7=AC=AC=E4=B8=89=E7=AC=94=EF=BC=89=EF=BC=9A?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E4=BD=8D=E7=BD=AE=E8=AF=AD=E4=B9=89=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=88=E6=B6=88=20T4=20=E8=AF=AD=E4=B9=89=E6=BC=82?= =?UTF-8?q?=E7=A7=BB=EF=BC=89+=20T4=20=E7=A9=BA=E8=A1=8C=E6=94=B6=E6=8B=A2?= =?UTF-8?q?=E6=94=B6=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 问题(上一笔 T4 暴露的语义漂移) T4 把语料从 v3(`{}` + `;`)改写成 v4(`:` + layout)后,全量构建虽过(BUILD SUCCESS), 但 checker 刷出 **450 条 `Function …: expected return type …` + 308 条 `If branches have different types`**。根因:v4 没有 `;` ⇒ 语句末的裸表达式被当成 **region 尾值**(`Block.expr`), 而 v3 里它是 `ExprStmt` ⇒ 块类型改变 ⇒ 函数推断返回类型改变。 **token 级判据(T4 的 V2)天然看不见它**(token 流完全相同,差的是 AST 形状)。 ## 修法:位置语义 依据 = v4 目标语法 §7.4(函数无隐式尾返回)+ §4.1(region 作声明右值取尾值)+ **v3 逐形等价**: - **表达式位**(声明/赋值右值、`return` 的值、调用实参、索引、括号内、match 臂体等, 统一走 `_want_value_expr()` 入口)⇒ **保留尾值**。 - **语句位**(`parse_stmt`、函数体、`loop`/`while`/`for` 体)⇒ 末项裸表达式包 `ExprStmt`; **例外(v3 等价)**:**块状末项**(`If`/`Match`/`Loop`/`For`/`Unsafe`/`Flow`)**保尾值**—— v3 的 `;` 只终止**普通**表达式语句,块状语句从不带 `;`,它本来就是 v3 的暂定尾表达式。 (对块状语句说「等价 v3 带 `;`」是凭空补一个 v3 没有的 `;`。此条是实施者发现「我给的规则① 与我列的验收③互相矛盾」后**停下上报**、由我裁定采纳的。) ## 读数(均实测;我对主判据做了独立复跑) - **两类类型告警 758 → 20**(`expected return type` 450→7 · `If branches` 308→13); 对 (单元, 消息) 多重集做差:**新增 0 条**。残余 20 条根因与尾值无关(`loop:` 尾项被判 unit、 `ReturnStmt` 被判其值类型),v3 同报。 - **三产物 sha256 与改前逐字节相同** ⇒ **纯判定面修复、发射面零变化**(T4 语料语义未动)。 - 全量构建 `=== BUILD SUCCESS ===` + 三条 `[GUARD] error[ = 0`。 - **T1/T2 探针 94 条 / 1 FAIL**(唯一 FAIL 仍是批末判据 J-T1-2)——**我独立复跑确认**。 - 四格对照(我独立复跑):v3 if尾随 0 / v3 赋值尾随 1 = v4 if尾随 0 / v4 赋值尾随 1 ⇒ 逐格等价。 - 反向对照:改前 parser 在同串上报 `If branches have different types` ⇒ 判据非空转。 ## 本笔另含(T4 收口) - **空行收拢(按删除缝)**:裁定删掉的整条 `if … { }` 在同一 region 内留下的连续 ≥2 空行收成 1。 **只收 3 处**(main.cr · module.cr · interp.cr)——先测出语料本就有 **11 档**存在「连续 2 空行」的 **原有写法**,全局收拢会平白吃掉原文空行、让 V4b 假性下降。反向对照:≥2 空行多重集的变化档数 = 0。 - `tools/v4_migrate.py`:按缝收拢逻辑 + `V4B_BLANK_DROP_EXEMPT` 常量(注释写明**应为空集**)。 - `docs/core-language-syntax_v4.md` §4.1:`if` 作右值的例子**降为设计态/未实现**——实测 `total := if ready: … else: …` 能解析能过检,但发射面丢值(`ir_gen.py` 的 `gen_if` 无条件 `return None`;**既有缺陷**,改前 parser 同样复现)。可运行的是 `t := unsafe: ` 形。 ## 另案(未动,已登记) - `tests/bootstrap/{test_pipeline,test_borrow,test_generics}.py` 三档红 = 内联源码仍是 v3 形 (改前/改后 parser 对 7 档归一化输出逐条相同 ⇒ 与本次改动无关)⇒ 属 **T6** 迁移面。 - 块值 `if` 的发射面缺口(上条 §4.1 注)⇒ 另开 TODO。 ## 批内位置 T0 ✓ · T1/T2 ✓ · T3 ✓ · **T4 ✓**(+ 本笔位置语义闭合)· **T5 待起** · T6 · T7。 --- bootstrap/corec/frontend/parser.py | 134 +++++++++++++++++++++++------ docs/core-language-syntax_v4.md | 12 +-- src/compiler/interp.cr | 1 - src/compiler/main.cr | 1 - src/compiler/module.cr | 1 - tools/v4_migrate.py | 64 +++++++++++++- 6 files changed, 177 insertions(+), 36 deletions(-) diff --git a/bootstrap/corec/frontend/parser.py b/bootstrap/corec/frontend/parser.py index 264c16be..b8b0b190 100644 --- a/bootstrap/corec/frontend/parser.py +++ b/bootstrap/corec/frontend/parser.py @@ -37,6 +37,34 @@ def __init__(self, tokens: list): self.tokens = tokens self.pos = 0 self.const_values = {} + # `want_value` = **位置语义**标志(v4 权威依据 `docs/core-language-syntax_v4.md` + # §7.4「函数没有 implicit tail return」+ §4.1「region 作声明右值取尾值」)。 + # + # 起因:v4 无 `;` ⇒ v3 里 `x = 1;` 的 ExprStmt 形态消失,语句末的裸表达式会被 + # parse_block 一律当**尾值**(Block.expr)⇒ 块类型由 unit 变 int ⇒ 函数推断返回 + # 类型漂移 ⇒ checker 刷 `expected return type` / `If branches have different types`。 + # + # 规则(唯一措辞): + # ① **语句位** region(函数体、if/else 语句体、loop/for/while 体、独立的 + # `unsafe:`/`flow:` 语句)末项裸表达式 ⇒ 包 ExprStmt(等价 v3 带 `;`),region 无值。 + # **例外 = 块状末项**(`if`/`match`/`loop`/`for`/`unsafe`/`flow`):v3 的 `;` 只终止 + # 普通表达式语句,块状语句在 v3 里**从不带 `;`** ⇒ 当时就是「暂定尾表达式」⇒ + # 保持 Block.expr。T4 是机械形状改写(只有 `{}`→缩进、`;`→换行)⇒ 它不该改变这一点; + # 一律包 ExprStmt 等于凭空补一个 v3 没有的 `;`(实证见 `parse_block` 的例外注释)。 + # ② **表达式位** region(声明/赋值右值、return 值、调用实参、括号内、索引、 + # 二元/一元操作数、match 臂 `=> Expr`)⇒ 保留 Block.expr; + # ③ 递归:`if`/`unsafe`/`flow` 的 region 位置 = **该表达式自身**的位置 + # (`x := if c: a else: b` 两臂在表达式位;语句位 `if c: … else: …` 两臂在语句位)。 + # + # 机制:表达式位入口置 True(`_want_value_expr()`),语句位入口(`parse_stmt`)置 False; + # `parse_block` 进入时读该标志决定尾值去留,并把标志复位为 False(嵌套 region 默认语句位), + # 退出时**恢复**为进入值(同层兄弟 region 位置不变)。 + self.want_value = False + + def _want_value_expr(self) -> Expr: + """表达式位入口:置 `want_value` 后解析一个表达式(region 在此保尾值)。""" + self.want_value = True + return self.parse_expr() def _scan_constants(self): """Pre-scan for 'NAME: TYPE = VALUE' declarations to resolve array sizes. @@ -176,7 +204,7 @@ def _parse_var_decl_names_tags_type(self): if self.check(TokenType.COLON_EQ): # x := expr → x : auto = expr self.advance() - values = [self.parse_expr()] + values = [self._want_value_expr()] # 声明右值 = 表达式位(规则 ②) return names, tags, None, values self.expect(TokenType.COLON_DECL) if self.check(TokenType.AUTO) or self.check(TokenType.DOT): @@ -205,10 +233,10 @@ def _parse_var_decl_names_tags_type(self): values = [] if self.check(TokenType.EQ): self.advance() - values.append(self.parse_expr()) + values.append(self._want_value_expr()) # 声明右值 = 表达式位(规则 ②) while self.check(TokenType.COMMA): self.advance() - values.append(self.parse_expr()) + values.append(self._want_value_expr()) return names, tags, typ, values # ─── 顶层 ─── @@ -314,13 +342,16 @@ def parse_function_decl(self, is_pub, is_flow=False): self._skip_spec_annotations() if self.check(TokenType.EQ): self.advance() - body = self.parse_expr() + body = self._want_value_expr() # `fn f() = expr` 的值 = 表达式位(规则 ②) self._end_decl() return FunctionDecl(is_pub, name, generics, params, ret, body) # D9/D10(T0 布局规格 §2.2):有体 ⇒ 行尾 `:`(COLON_BLOCK)开 region; # 无体(`extern fn read(fd: int) -> int`)⇒ 行边界,无 `:`。 if self._at_line_end(): return FunctionDecl(is_pub, name, generics, params, ret, None) + # 规则 ①:函数体 region **恒为语句位**(§7.4「函数没有 implicit tail return」)⇒ + # 末项裸表达式包 ExprStmt,块类型 unit ⇒ 返回值只经显式 `return`。 + self.want_value = False body = self.parse_block() if is_flow: body = Flow(body) @@ -497,7 +528,7 @@ def parse_assignment(self): left = self.parse_logical_or() if self.check(TokenType.EQ): self.advance() - right = self.parse_assignment() + right = self._want_value_expr() # 赋值右值 = 表达式位(规则 ②) return BinaryOp(left, "=", right) return left @@ -578,20 +609,20 @@ def parse_call_or_field(self) -> Expr: self.advance() args = [] if not self.check(TokenType.RPAREN): - args.append(self.parse_expr()) + args.append(self._want_value_expr()) # 实参 = 表达式位(规则 ②) while self.check(TokenType.COMMA): self.advance() - args.append(self.parse_expr()) + args.append(self._want_value_expr()) self.expect(TokenType.RPAREN) node = EnumConstructor([node.name], args) else: self.advance() args = [] if not self.check(TokenType.RPAREN): - args.append(self.parse_expr()) + args.append(self._want_value_expr()) # 实参 = 表达式位(规则 ②) while self.check(TokenType.COMMA): self.advance() - args.append(self.parse_expr()) + args.append(self._want_value_expr()) self.expect(TokenType.RPAREN) node = Call(node, args) elif self.check(TokenType.DOT): @@ -603,17 +634,17 @@ def parse_call_or_field(self) -> Expr: # Distinguish between index expression and array literal if self.check(TokenType.RBRACK) or (self.cur().type in (TokenType.INT_LIT, TokenType.STRING_LIT, TokenType.IDENT, TokenType.LPAREN, TokenType.MINUS, TokenType.BANG)): # index expression: node[idx] - idx = self.parse_expr() + idx = self._want_value_expr() # 下标 = 表达式位(规则 ②) self.expect(TokenType.RBRACK) node = Index(node, idx) else: # array literal [e1, e2, ...] elements = [] if not self.check(TokenType.RBRACK): - elements.append(self.parse_expr()) + elements.append(self._want_value_expr()) while self.check(TokenType.COMMA): self.advance() - elements.append(self.parse_expr()) + elements.append(self._want_value_expr()) self.expect(TokenType.RBRACK) node = ArrayLit(elements) elif self.check(TokenType.QUESTION): @@ -636,10 +667,10 @@ def parse_primary(self) -> Expr: self.advance() args: List[Expr] = [] if not self.check(TokenType.RPAREN): - args.append(self.parse_expr()) + args.append(self._want_value_expr()) # 实参 = 表达式位(规则 ②) while self.check(TokenType.COMMA): self.advance() - args.append(self.parse_expr()) + args.append(self._want_value_expr()) self.expect(TokenType.RPAREN) return Builtin(first, args) if self.check(TokenType.IDENT): @@ -680,7 +711,7 @@ def parse_primary(self) -> Expr: if not self.check(TokenType.EQ): self.error("struct literal field separator must be '=' [P030]") self.advance() - val = self.parse_expr() + val = self._want_value_expr() # 字段值 = 表达式位(规则 ②) fields.append((fname, val)) if self.check(TokenType.COMMA): self.advance() @@ -692,7 +723,7 @@ def parse_primary(self) -> Expr: if self.check(TokenType.RBRACK): self.advance() return ArrayLit([]) - first = self.parse_expr() + first = self._want_value_expr() # 数组元素 = 表达式位(规则 ②) if self.check(TokenType.SEMI): # [value; count] — repeated array self.advance() @@ -703,12 +734,12 @@ def parse_primary(self) -> Expr: elements = [first] while self.check(TokenType.COMMA): self.advance() - elements.append(self.parse_expr()) + elements.append(self._want_value_expr()) self.expect(TokenType.RBRACK) return ArrayLit(elements) if self.check(TokenType.LPAREN): self.advance() - e = self.parse_expr() + e = self._want_value_expr() # 括号内 = 表达式位(规则 ②) self.expect(TokenType.RPAREN) return e if self.check(TokenType.LBRACE): @@ -761,6 +792,10 @@ def parse_block(self) -> Block: 其余各项按语句处理 —— 即原 `parse_block` 的「暂定尾表达式」逻辑原样保留, 只是「还有下一项」的判据由「不是 `}`」变成「不是 DEDENT」。 """ + # 位置语义(§7.4 + §4.1,见 `__init__` 的 `want_value`):本 region 的尾值去留 + # 由**进入时**的标志决定;体内嵌套 region 一律先复位为语句位,退出时恢复。 + want = self.want_value + self.want_value = False self._expect_region() stmts = [] expr = None @@ -781,9 +816,31 @@ def parse_block(self) -> Block: stmts.append(ExprStmt(expr)) expr = item self.expect(TokenType.DEDENT) + self.want_value = want + if not want and expr is not None and not self._is_block_like(expr): + # 语句位 region + 末项是**普通**裸表达式 ⇒ 包 ExprStmt(等价 v3 的 `expr;`), + # region 视为无值。 + # + # ⚠ 例外(**不是放宽,是 v3 等价性的忠实面**):v3 的 `;` 只终止**普通**表达式 + # 语句;块状语句(`if`/`match`/`loop`/`for`/`unsafe`/`flow`)在 v3 里**从不带 `;`** + # ⇒ 它们当时就是 parse_stmt 的「暂定尾表达式」⇒ 保持 Block.expr。T4 是**机械形状 + # 改写**(只有 `{}`→缩进、`;`→换行两类)⇒ 它无法、也不该改变这一点。 + # 若在此一律包 ExprStmt,等于凭空给 v3 的块状语句补一个它没有的 `;` ⇒ 语义漂移 + # (实证:`tools/v4_frontend_probe.py features` 的 `if / else`、`enum + match`×2、 + # `unsafe region` 四例会立刻报 `expected return type …, got unit`)。 + stmts.append(ExprStmt(expr)) + expr = None return Block(stmts, expr) + @staticmethod + def _is_block_like(expr: Expr) -> bool: + """块状(v3 里不带 `;` 的)语句形态——判据见 `parse_block` 的例外注释。""" + return isinstance(expr, (If, Match, Loop, For, Unsafe, Flow)) + def parse_stmt(self): + # 语句位入口(规则 ①):本语句整体在语句位 ⇒ 先复位;语句内的表达式位由各入口重 + # 置 True(声明的右值 / return 值 / 实参 / 括号 / 索引 …)。 + self.want_value = False if self.check(TokenType.IDENT) and self._is_var_decl_start(): names, tags, typ, values = self._parse_var_decl_names_tags_type() self._end_decl() @@ -793,7 +850,7 @@ def parse_stmt(self): val = None # A6:关键字之后**同一逻辑行内**无 token ⇒ 无值(行边界取代 `;`/`}`) if not self._at_line_end(): - val = self.parse_expr() + val = self._want_value_expr() # 表达式位:return 的值(规则 ②) self._consume_newlines() return ReturnStmt(val) elif self.check(TokenType.BREAK): @@ -810,21 +867,30 @@ def parse_stmt(self): return self.parse_expr() def parse_if_expr(self): + # 规则 ③:两臂 region 的位置 = **本 if 表达式自身**的位置(进入时捕获,逐臂沿用; + # `else if` 递归时同样把该位置传下去)。条件恒为表达式位。 + want = self.want_value self.expect(TokenType.IF) - cond = self.parse_expr() + cond = self._want_value_expr() + self.want_value = want then = self.parse_block() else_branch = None if self.check(TokenType.ELSE): self.advance() + self.want_value = want if self.check(TokenType.IF): else_branch = self.parse_if_expr() else: else_branch = self.parse_block() + self.want_value = want return If(cond, then, else_branch) def parse_match_expr(self): + # 被匹配的值与臂体 `=> Expr` 恒为表达式位(规则 ②);臂体不是 region(此处只吃 + # 单行表达式),故其内嵌 region 按表达式位保留尾值。 + want = self.want_value self.expect(TokenType.MATCH) - expr = self.parse_expr() + expr = self._want_value_expr() self._expect_region() arms = [] while True: @@ -846,11 +912,12 @@ def parse_match_expr(self): self.advance() pat = self.parse_pattern() self.expect(TokenType.FAT_ARROW) # 使用 => - body = self.parse_expr() + body = self._want_value_expr() arms.append(MatchArm(pat, body)) if self.check(TokenType.COMMA): self.advance() self.expect(TokenType.DEDENT) + self.want_value = want return Match(expr, arms) def parse_pattern(self) -> Pattern: if self.check(TokenType.UNDERSCORE) or self.cur().lexeme == '_': @@ -912,14 +979,24 @@ def parse_pattern(self) -> Pattern: return IdentPattern(name) # 变量绑定 self.error(f"Unexpected token in pattern: {self.cur().lexeme}") def parse_loop_expr(self): + # 规则 ①:loop 体恒为**语句位** region(v3 里体末语句必带 `;` ⇒ 块类型 unit; + # 本解析器无 `break value`,循环亦无值通道)⇒ 末项裸表达式包 ExprStmt。 + # 标志 save/restore:同层兄弟 region(如 `a + + `)位置不受影响。 + want = self.want_value self.expect(TokenType.LOOP) - return Loop(self.parse_block()) + self.want_value = False + blk = self.parse_block() + self.want_value = want + return Loop(blk) def parse_while_expr(self): """Desugar: while cond { body } → loop { if !cond { break; } body }""" + want = self.want_value self.expect(TokenType.WHILE) - cond = self.parse_expr() + cond = self._want_value_expr() + self.want_value = False body = self.parse_block() + self.want_value = want # Build: if !cond { break; } not_cond = UnaryOp("!", cond) break_block = Block([BreakStmt()], None) @@ -930,11 +1007,16 @@ def parse_while_expr(self): return Loop(new_block) def parse_for_expr(self): + # 规则 ①:for 体恒为语句位 region;被迭代表达式恒为表达式位。 + want = self.want_value self.expect(TokenType.FOR) var = self.expect(TokenType.IDENT).lexeme self.expect(TokenType.IN) - iter = self.parse_expr() - return For(var, iter, self.parse_block()) + iter = self._want_value_expr() + self.want_value = False + blk = self.parse_block() + self.want_value = want + return For(var, iter, blk) def parse_struct_decl(self, is_pub): self.expect(TokenType.STRUCT) diff --git a/docs/core-language-syntax_v4.md b/docs/core-language-syntax_v4.md index 81098522..62798ab9 100644 --- a/docs/core-language-syntax_v4.md +++ b/docs/core-language-syntax_v4.md @@ -392,16 +392,16 @@ v4 不使用显式 `move`。region、借用有效性、escape、capture 与存 ```core raw := unsafe: @str_of(buf) - -total := if ready: - compute() -else: - 0 ``` -这条形式的用途是把**只能以 region 书写**的构造(`unsafe`、带 region 的分支)放进一个值的位置。 +这条形式的用途是把**只能以 region 书写**的构造(`unsafe` 等)放进一个值的位置。 它不引入新的表达式种类:region 仍是 region,只是在右值位被读取其尾值。 +⚠ **实现态(2026-10-11 实测)**:目前只有 `unsafe` region 作右值能真正取到值(运行期验证过)。 +`total := if ready: … else: …` 这类**块值 `if`** 能解析、能过检,但**发射面丢值**—— +`bootstrap/corec/frontend/ir_gen.py` 的 `gen_if` 无条件 `return None`(既有缺陷,与 v4 迁移无关)。 +⇒ 该形在文档里按**设计态**记,未实现前不要依赖。 + ⚠ 反向不成立:`f(unsafe: …)` —— 把 region 直接塞进**实参位** —— 不是合法文本(实参位是表达式位, region 不是表达式)。需要时先把 region 的值绑定到一个名字,再把名字传进去。 diff --git a/src/compiler/interp.cr b/src/compiler/interp.cr index e850507f..798c8ff9 100644 --- a/src/compiler/interp.cr +++ b/src/compiler/interp.cr @@ -903,7 +903,6 @@ fn ir_interpret() -> int: if d >= 0: w64(g_ir_vals, d * 8, 0) - // IR_DYN_PACK (43):dyn 变量双槽 [value, tag]——slot[d]=值、slot[d+1]=tag(对照 ELF slot+0/+8) if op == 43: if d >= 0 && s1 >= 0: diff --git a/src/compiler/main.cr b/src/compiler/main.cr index 15f8692f..3e2accb9 100644 --- a/src/compiler/main.cr +++ b/src/compiler/main.cr @@ -20,7 +20,6 @@ fn read_source_file(path: string) -> string: g_source_dir = dirname(path) source := read_file(path) - return source fn read_project_dir(dir: string) -> string: diff --git a/src/compiler/module.cr b/src/compiler/module.cr index 3dbffbcc..76ee4980 100644 --- a/src/compiler/module.cr +++ b/src/compiler/module.cr @@ -169,7 +169,6 @@ fn load_imports(dir_path: string) -> string: imp_path : ., mut = dir_path + "_import.cr" content := module_get_source(imp_path) - return content fn reg_fileid(fileid_str: string, path: string) -> int: diff --git a/tools/v4_migrate.py b/tools/v4_migrate.py index 295d1d07..4dac395a 100644 --- a/tools/v4_migrate.py +++ b/tools/v4_migrate.py @@ -274,11 +274,12 @@ def pre_transform(src, filename): toks[-1].start = len(src) toks[-1].end = len(src) brace_kind, semi_kind, brace_match, _ = classify(toks) - recs = {'deleted_if': [], 'return_filled': [], 'hoisted': []} + 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: @@ -316,6 +317,7 @@ def pre_transform(src, filename): 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: @@ -328,6 +330,7 @@ def pre_transform(src, filename): 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': @@ -339,6 +342,7 @@ def pre_transform(src, filename): 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;` @@ -401,9 +405,67 @@ def pre_transform(src, filename): # 保证先落的(更靠后)不会挪动后落的(更靠前)的偏移。 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`。""" From 11af17cbfa5c7e56fc5767359e5e54fa1b0c681b Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 17:59:19 +0800 Subject: [PATCH 04/15] =?UTF-8?q?v4=20=E8=BF=81=E7=A7=BB=EF=BC=88=E6=89=B9?= =?UTF-8?q?=E5=86=85=C2=B7=E7=AC=AC=E4=B8=89=E7=AC=94=E8=A1=A5=EF=BC=89?= =?UTF-8?q?=EF=BC=9A=E4=BD=8D=E7=BD=AE=E8=AF=AD=E4=B9=89=E8=A7=84=E5=88=99?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E9=87=8A=E6=8E=AA=E8=BE=9E=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=E2=80=94=E2=80=94=E5=8F=A3=E5=BE=84=E5=86=99=E6=AD=BB=E4=B8=BA?= =?UTF-8?q?=E3=80=8C=E4=BD=8D=E7=BD=AE=E6=A0=87=E5=BF=97=20=E2=88=A7=20?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E7=A7=8D=E7=B1=BB=E3=80=8D=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E9=80=90=E5=AD=97=E5=BC=95=E7=94=A8=E5=9B=9B=E6=A0=BC=E5=AE=9E?= =?UTF-8?q?=E6=B5=8B=E4=B8=8E=E5=8F=8D=E5=90=91=E5=AE=9E=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 纯注释改动(行为与 4ad482d4 逐字节一致:探针 94/1 复跑确认)。 - 规则①②③在 __init__ 里按最终口径重述:语句位控制流尾项保留 Block.expr,其余包 ExprStmt; 表达式位一律保留尾值;收尾由「位置 ∧ 种类」共同决定。 - _is_block_like 的 docstring 补齐依据(v3 里控制流语句本来不带 ; ⇒ 本来就是块尾值; 真正分叉的只是「带 ; 的表达式语句」),并留下「一律包 ExprStmt ⇒ 探针 94/5 转红」的反向实证, 防止后人改回字面形。 - Flow 保留在集合内(同为开 region、以 DEDENT 收尾的块状形;实测 src/ 里 `flow:` 语句命中 0 ⇒ 零影响)。 --- bootstrap/corec/frontend/parser.py | 54 ++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/bootstrap/corec/frontend/parser.py b/bootstrap/corec/frontend/parser.py index b8b0b190..878066a6 100644 --- a/bootstrap/corec/frontend/parser.py +++ b/bootstrap/corec/frontend/parser.py @@ -46,13 +46,16 @@ def __init__(self, tokens: list): # # 规则(唯一措辞): # ① **语句位** region(函数体、if/else 语句体、loop/for/while 体、独立的 - # `unsafe:`/`flow:` 语句)末项裸表达式 ⇒ 包 ExprStmt(等价 v3 带 `;`),region 无值。 - # **例外 = 块状末项**(`if`/`match`/`loop`/`for`/`unsafe`/`flow`):v3 的 `;` 只终止 - # 普通表达式语句,块状语句在 v3 里**从不带 `;`** ⇒ 当时就是「暂定尾表达式」⇒ - # 保持 Block.expr。T4 是机械形状改写(只有 `{}`→缩进、`;`→换行)⇒ 它不该改变这一点; - # 一律包 ExprStmt 等于凭空补一个 v3 没有的 `;`(实证见 `parse_block` 的例外注释)。 + # `unsafe:`/`flow:` 语句)的末项收尾 = **按节点种类**: + # · 控制流类(`If`/`Loop`/`For`/`Match`/`Unsafe`,另含 `Flow`)⇒ **保留 + # `Block.expr`(尾值)**——v3 里控制流语句本来就不带 `;`(以 `}` 收尾)⇒ + # 本来就是块的尾值; + # · 其余(赋值/调用/二元/一元/字面量/`Ident`/索引…)⇒ 包 `ExprStmt` + # (等价 v3 带 `;` 的表达式语句),region 视为无值。 + # 判据 = **v3 逐形等价**(维护者四格实测),详见 `_is_block_like` 的 docstring。 # ② **表达式位** region(声明/赋值右值、return 值、调用实参、括号内、索引、 - # 二元/一元操作数、match 臂 `=> Expr`)⇒ 保留 Block.expr; + # 二元/一元操作数、match 臂 `=> Expr`)⇒ 一律保留 Block.expr; + # ⇒ 收尾最终由 **位置标志 ∧ 节点种类** 两个条件共同决定。 # ③ 递归:`if`/`unsafe`/`flow` 的 region 位置 = **该表达式自身**的位置 # (`x := if c: a else: b` 两臂在表达式位;语句位 `if c: … else: …` 两臂在语句位)。 # @@ -818,23 +821,40 @@ def parse_block(self) -> Block: self.expect(TokenType.DEDENT) self.want_value = want if not want and expr is not None and not self._is_block_like(expr): - # 语句位 region + 末项是**普通**裸表达式 ⇒ 包 ExprStmt(等价 v3 的 `expr;`), - # region 视为无值。 - # - # ⚠ 例外(**不是放宽,是 v3 等价性的忠实面**):v3 的 `;` 只终止**普通**表达式 - # 语句;块状语句(`if`/`match`/`loop`/`for`/`unsafe`/`flow`)在 v3 里**从不带 `;`** - # ⇒ 它们当时就是 parse_stmt 的「暂定尾表达式」⇒ 保持 Block.expr。T4 是**机械形状 - # 改写**(只有 `{}`→缩进、`;`→换行两类)⇒ 它无法、也不该改变这一点。 - # 若在此一律包 ExprStmt,等于凭空给 v3 的块状语句补一个它没有的 `;` ⇒ 语义漂移 - # (实证:`tools/v4_frontend_probe.py features` 的 `if / else`、`enum + match`×2、 - # `unsafe region` 四例会立刻报 `expected return type …, got unit`)。 + # 语句位 region + 末项是**普通**裸表达式(赋值/调用/二元/一元/字面量/`Ident`/索引…) + # ⇒ 包 ExprStmt(等价 v3 的 `expr;`),region 视为无值。 stmts.append(ExprStmt(expr)) expr = None return Block(stmts, expr) @staticmethod def _is_block_like(expr: Expr) -> bool: - """块状(v3 里不带 `;` 的)语句形态——判据见 `parse_block` 的例外注释。""" + """语句位 region 的**控制流**尾项 —— 判据 = **v3 逐形等价**(维护者裁定)。 + + 口径(唯一措辞):收尾判定 = **位置标志 ∧ 节点种类**两个条件共同决定 —— + 位置为语句位时,**控制流类**尾项(`If`/`Loop`/`For`/`Match`/`Unsafe`)**保留为 + `Block.expr`(尾值)**;其余一律包 `ExprStmt`。表达式位(`want_value=True`)则一切照旧 + 保留尾值(`x := if c: a else: b` 的分支尾值必须是值)。 + + 依据 = v3 的**实际形态**:v3 里控制流语句本来就不带 `;`(`if`/`loop`/`while`/`for`/ + `match`/`unsafe` 以 `}` 收尾)⇒ 它们在 v3 里**本来就是块的尾值**;真正分叉的只是 + 「**带 `;` 的表达式语句**」——那才是 v3 的 `ExprStmt`。`;` 退场后,唯一能复原这层区分 + 的判据就是**节点种类**。T4 是机械形状改写(只有 `{}`→缩进、`;`→换行两类)⇒ 它不该、 + 也无法改变这层区分。 + + 维护者四格实测(v3 前端 @ bb8cb3537584 + v3 文本 / v4 前端 + v4 文本): + v3: 尾随 `if 1 > 0 { return 1; } else { return 2; }` → **0 条**类型告警 + v3: 尾随 `y = y + 1;` → **1 条**(expected int, got unit) + v4: 尾随 `if …` → **0 条**(同上) + v4: 尾随 `y = y + 1` → **1 条**(同上) + 一律包 ExprStmt(不看种类)会打破第一格:尾随 `if` 变 1 条 = **回归**,且 + `tools/v4_frontend_probe.py features` 的 `if / else`、`enum + match`×2、`unsafe region` + 四例立刻转红(实测 94 条里 5 FAIL)。 + + `Flow` 一并纳入:同为「开 region、以 `}`/DEDENT 收尾」的块状形,v3 亦不带 `;`。 + (实测 `src/**` 无任何 `flow:` 语句 ⇒ 本项对现行语料零影响,仅为形状自洽。) + `while` 无独立节点(`parse_while_expr` 直接 desugar 成 `Loop`)⇒ 已被覆盖。 + """ return isinstance(expr, (If, Match, Loop, For, Unsafe, Flow)) def parse_stmt(self): From 1270cdbf7da6884f2210bcccfb6676c2bd07f7e3 Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 18:01:03 +0800 Subject: [PATCH 05/15] =?UTF-8?q?docs(TODO):=20=E7=99=BB=E8=AE=B0=20#2026-?= =?UTF-8?q?10-11-1=EF=BC=88=E6=88=98=E6=9C=AF=E3=80=8C=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E3=80=8D=E8=AF=AD=E6=B3=95=E5=BE=85=E9=87=8D?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=EF=BC=89+=20#2026-10-11-2=EF=BC=88=E5=9D=97?= =?UTF-8?q?=E5=80=BC=20if=20=E5=8F=91=E5=B0=84=E9=9D=A2=E7=BC=BA=E5=8F=A3?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两条均为 v4 迁移施工期产出,**只登记未修**;迁移对照表两行旧号列写 `—`。 - **#2026-10-11-1**:维护者裁定 `#` 族**只有使用面** ⇒ `#tag`(全族里唯一「用 # 声明新东西」的构造)属**范畴错误、该删而非改名**; 连带两条结构性毛病(体是竖排序列而语义是**集合**=形状说谎;可复用名被关进标签族、不能 import/文档化/单测)。 两个候选方向(未拍):**不留** = §10.8 整节删、复用只走库 + `spec fn`;**留** = 必须长成一个**非 `#`** 的声明形。 卡住的面:`docs/core-language-syntax_v4.md` §10.8 + `docs/maintainer/design/spec-design.md:203`(旧形 `#tag sorted = { … }`,同面两形不一致)。 - **#2026-10-11-2**:`x := if c: 1 else: 2` 能解析能过检但**运行期得 None**;根因 = `bootstrap/corec/frontend/ir_gen.py` 的 `gen_if` **无条件 return None**。 **既有缺陷、与迁移无关**(同片段走改前 parser 同样得 None);旁证 = `t := unsafe:` + `7` ⇒ 运行期 7(region 作右值这条通道是通的)。 ⇒ v4 文档 §4.1 的 `total := if ready: …` 例子已降为「设计态/未实现」并注明根因。 判据:`python3 tests/harness/test_todo_id_migration.py` → **6/6 PASS**(J1 残留 0 · J2 悬空 0 · J3 映射完备 153/153 · J6 同日段唯一)。 --- TODO.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/TODO.md b/TODO.md index 750f9ca9..71783faa 100644 --- a/TODO.md +++ b/TODO.md @@ -186,6 +186,8 @@ | — | `#2026-09-22-1` | 2026-09-22 | 批 8 裁定二 S4 · `b8-e1` 实测 | ⚠【**静默错值 · 本批修复**】`REF.f` 字段**自动解引用**误编译(**local 形态**):`checker` 对 `TYP_REF` 对象解包后按结构体查字段(`checker.cr:3725`)⇒ **接受** `p.v`;而 `ir_gen` 的 `EXPR_FIELD` **不发解引用** ⇒ `IR_LOAD_FIELD` 把「地址」当聚合读 ⇒ **静默错值**(实测 `p := &s; p.v` 得 **8** 而非 42;`(*p).v` 得 **42** ⇒ 缺陷 = 缺那一条 `IR_DEREF`)。**裁定二的作用 = 把「响亮拒绝」换成「静默错值」**:`p := &s; p.v` 由 **pre 的 `check=1`** 变为 **post 的 accept + 静默 8**;**本批修回 42**(`ir_gen` 镜像 checker 的 REF 解包;**只对 REF**——实测 `p as *S` 后 `p.v` 仍 check=1)。**与 `#2026-09-22-2` 根因不同,不合并**(本条 = ir_gen 缺解包;那条 = 形参定型丢 REF)。 | | — | `#2026-09-22-2` | 2026-09-22 | 批 8 裁定二 S4 · `b8-e1` 实测 | ⚠【**预存缺陷 · 静默错值 · 本批修复**】`&S` / `&mut S` **形参形态**的 `r.v` 误编译:**根因 = REF 身份在 IR 形参定型处丢失**——`ir_gen.cr:3296` 取 `ast_type_val(pn)`,而 `&S` 节点(`EXPR_REFTYPE`)**`type_val = 0`** ⇒ 槽型退化成 `TI_INT`(`if param_type < 0` 护栏**拦不住 0**)⇒ `EXPR_FIELD` 看不到 REF ⇒ 静默错值(实测 `fn f(r: &S){r.v}` 得 **8** 而非 42;`--dump-params` 实证 `PARAM f p0 r slot=0 decl=0`,对照 `string` 参数 `slot=3` ✓)。**两代皆错**(pre/post 均 run=8)⇒ **存在早于裁定二、裁定二未触及形参面**。**修法有先例**:`ir_gen.cr:3305`(批 5 `dex?` 同形特判——某形态 `unpack_type` 返 0 ⇒ 槽型退化 ⇒ **按声明面节点另定槽型**),注释原文照引。**ABI 零影响(实测)**:`callseq.cr`/`frame.cr` 全部 **9 处**分类点皆为 `== TI_DEX ⇒ xmm 类,其余 ⇒ GP 类` 恒等式,而 **`TI_DEX = 1`**、**REF 行下标 ≥ 9** ⇒ **REF 天然落 GP** ⇒ 改槽型**不改 ABI 类**。**实现取「只查不建」**:checker 解析签名时已建过该 REF 行(实测类型表中存在 `kind 3`)⇒ 线性查找即可 ⇒ **零新增类型行**(⚠ `alloc_type` 是**裸分配器、不去重**,另分配会写进 TYPE 段)。**禁止事项**:在**无 ABI 判据**时凭「补一支特判」直接改槽型(会造出 `dex?` 那次的同形失配)。**与 `#2026-09-22-1` 互指,根因不同不合并**。 | | — | `#2026-09-24-1` | 2026-09-24 | v4 迁移差距分析 + 协调者实测 | 【**声明但不校验 / 有码但不 raise**】前端静默面清单(**5 处,均实测**):① **`EC_TF_MISSING_RET`(TF02, `ast.cr:404`) 零 raise 点**(全仓 1 命中)⇒ 缺 return 由 TF01「Function return type mismatch」拦住,**消息不指真实原因**(实测四档:空体 / 以 unit 调用收尾 / `if` 无 `else` / `loop` 里 `break` 出走 ⇒ **全 `check` rc=1 报 TF01,`build` rc=1 + 零产物**)——**非健全性漏洞,是诊断不精确**;② **`pub` 零读点**(`parser.cr:840` 声明 + `:875` 赋值,无读取点)⇒ 写了不生效且**不报错**;③ **match 臂的 `=>` 不校验**(`parser.cr:1115` 裸 `advance_tok()`)⇒ 分隔符写什么都收;④ **struct 字面量字段分隔符盲跳**(`parser.cr:552-554`,第二个 `advance_tok()` 返回值丢弃)⇒ `=` 与 `:` 两形都收(**已由 v4 迁移 T0 规格覆盖(T5 修),本条目不另立修法**);⑤ **类型位的 `.`/`auto` 全拒且消息错**(六档实测:形参 / 字段 / 枚举载荷 / 切片元素 / 返回位皆 rc=1,报 `expected type after '->'`,而那句是**返回型的模板**,形参位也报)。**本条目只登记,未修**(④ 除外,见上)。 | +| — | `#2026-10-11-1` | 2026-10-11 | v4 迁移施工期 + 维护者口述 | 【**设计·未决**】v4 规约的战术「策略定义」语法(现形 `#tag`)待重设计——维护者裁定 `#` 族**只有使用面**(`#simp`/`#induct(x)` 都读作「在这里用一个战术」),而 `#tag` 是**唯一一个「用 `#` 声明新东西」的构造** ⇒ 范畴错误,**该删而非改名**;连带「策略体是竖排序列、而语义是**集合**」的形状说谎、以及可复用名被关在标签族里(不能 `import`/文档化/单测)。两个候选方向(维护者未拍):**不留** = §10.8 整节删、复用只走库(`import std::proof::arithmetic` 后 `#arithmetic`,名字解析走 import 作用域)+ `spec fn`;**留** = 必须长成一个**非 `#`** 的声明形。**本条目只登记,未改 `docs/core-language-syntax_v4.md` §10.8**。 | +| — | `#2026-10-11-2` | 2026-10-11 | v4 迁移 T4 施工期实测 | 【**既有缺陷 · 发射面**】块值 `if` 取不到值——`bootstrap/corec/frontend/ir_gen.py` 的 `gen_if` **无条件 `return None`**(函数体 `cond = gen_expr(...)` → 两支 `gen_expr` → 建 merge 块 → `return None`,从不把分支值物化到槽位)⇒ `x := if c: 1 else: 2` 运行期得 `None`。**与 v4 迁移无关**:同一片段走改前 parser 同样得 `None`。旁证(可运行的表达式位 region 载体):`t := unsafe:` + `7` + `return t` ⇒ 运行期 **7**(`gen_block` 尾值直通,`ir_gen.py:438-444`)。⇒ `docs/core-language-syntax_v4.md` §4.1 的 `total := if ready: …` 例子已降为**「设计态/未实现」**并注明根因;**未修**。 | ## 触发器约定(2026-09-18 立;存量扫描产出) @@ -2139,6 +2141,39 @@ fn f(x: int) -> int { loop { if x > 0 { break; } } } // loop 里 break 出走 **与既有条目的关系**:同族先例 = 实参面无校验(TF05/06 零 raise、TF07 raise = 3 处),判断口径同:**「有码但不 raise / 接受但不校验」是一类固定失效形态,逐处查 raise 点与读点,别只看码表**。 +### 2026-10-11-1. 【设计·未决】v4 规约的战术「策略定义」语法(现形 `#tag`)待重设计——`#` 族应**只有使用面**(维护者口述裁定;**本节只登记设计问题,未动文档**;取号基准 = 当天已有最大 N 无 ⇒ 1) + +**维护者原话(2026-10-11)**:「这个标签我是打算做成战术的,应该就是使用」「标签是没问题但就是套来套去感觉很不对」「为什么必须要用包裹起来?」。 + +**把这句话读成硬约束**:`#` 这个符号族里**只能有「使用」**,不能有「定义」;任何 `#xxx` 都必须读作「在这里用一个战术」。⇒ `#tag` **不是措辞问题,是范畴错误**——它是全族里**唯一**一个「用 `#` 声明新东西」的构造 ⇒ **该删,而非改名或换壳**。 + +**`#tag` 现形(`docs/core-language-syntax_v4.md` §10.8)的三条结构性毛病**: + +| # | 毛病 | 说明 | +|---|---|---| +| ① | **`#` 同时当「使用」与「定义」** | `#simp` 是「向证明引擎提一个能力」,`#tag` 却是「在源码里声明一个新名字」。读者看到 `#` 无法从形式上判断是提示还是声明——**层级被压平**。 | +| ② | **形状在说谎** | 文档说体是「**能力集合**,不是命令序列」,写法却是**竖排多行**——竖排是序列的形状。集合写成序列。 | +| ③ | **名字被关在标签族里** | 一个可复用的策略本该像 `spec fn`/`struct` 那样能 `import`、能文档化、能单独引用;关在 `#tag` 里三样都做不到。 | + +**两个候选方向(维护者未拍)**: + +- **不留**(本节作者倾向):§10.8 **整节删除**。复用只走两条**既有**通道——(a) **库**:`import std::proof::arithmetic` 之后 `#arithmetic` 可用,名字解析走 import 作用域(与 `math::add` 同族;§10.10 本来就已经写了「战术库含 strategy tags、第三方库用普通 Core 模块与包管理机制」);(b) **命题复用**:`spec fn` + 证明结果缓存(§10.5)。理由:拿名字换来的信息量近乎为零,而文档自己把自动化排在第一位(「普通情况下不要求用户手写战术」)。 +- **留**:必须有一个**非 `#`** 的声明形来承载「用户自定义一档、起名、到处引用」——那时才需要讨论该叫什么词、体写成 region 还是别的。**`#` 侧一个字不动(纯使用)**。 + +**这条卡住的面**:`docs/core-language-syntax_v4.md` §10.8 的措辞、`docs/maintainer/design/spec-design.md:203` 的旧形(`#tag sorted = { … }`,与 §10.8 已经不一致,属同一面的两个形)。 + +### 2026-10-11-2. 【既有缺陷 · 发射面】块值 `if` 取不到值——`gen_if` 无条件 `return None`(v4 迁移 T4 施工期实测;**既有缺陷,与迁移无关**;取号基准 = 1) + +**现象**:`x := if c: 1 else: 2`(多行 layout 形)**能解析、能过检**,但**运行期得 `None`**。 + +**根因**:`bootstrap/corec/frontend/ir_gen.py` 的 `gen_if` **无条件 `return None`** —— 函数体为 `cond = gen_expr(...)` → 两支分别 `gen_expr` → 建 merge 块 → `return None`,**从不把分支值物化到任何槽位**。`gen_let` 收到 `val_ir = None` 后为该局部新开临时槽 ⇒ 声明得到空值。 + +**与 v4 迁移无关(实证)**:同一片段走**改前 parser** 同样得 `None`。⇒ 既有缺陷,不是 T4 或位置语义修复引入的回归。 + +**可运行的旁证(表达式位 region 的值通道是通的)**:`t := unsafe:` + `7` + `return t` ⇒ 运行期 **7**(`gen_block` 尾值直通,`ir_gen.py:438-444`)。即「region 作声明右值」这条通道本身没问题,缺的是 `if` 这一支的实现。 + +**影响面**:`docs/core-language-syntax_v4.md` §4.1 原写的 `total := if ready: … else: …` 例子**已降为「设计态/未实现」**并注明根因。**未修**(修法在 `gen_if`,属发射面,超出 v4 迁移批量范围)。 + ### 2026-09-22-1. ⚠ **【静默错值】`REF.f` 字段自动解引用误编译(local 形态)**(批 8 裁定二 S4;**本批修复**;取号基准 = 当天已有最大 N 无 ⇒ 1) **症状**:`p := &s; p.v` **编译干净**(check=0 / build=0)但 **run 读到 8**——而 `s.v` 是 42。 From 88d5c32c1fb615ad7156a614816c821ba1dd356f Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 18:02:48 +0800 Subject: [PATCH 06/15] =?UTF-8?q?v4=20=E8=BF=81=E7=A7=BB=EF=BC=88=E6=89=B9?= =?UTF-8?q?=E5=86=85=C2=B7=E7=AC=AC=E5=9B=9B=E7=AC=94=EF=BC=89=EF=BC=9AT5?= =?UTF-8?q?=20=E8=87=AA=E6=BA=90=E5=89=8D=E7=AB=AF=20layout=20=E6=9C=BA?= =?UTF-8?q?=E4=BB=B6=E7=A7=BB=E6=A4=8D=20+=20=E4=BD=8D=E7=BD=AE=E8=AF=AD?= =?UTF-8?q?=E4=B9=89=E9=95=9C=E5=83=8F=20+=20`never`=20=E8=AF=AD=E4=B9=89?= =?UTF-8?q?=EF=BC=88=E4=B8=A4=E5=89=8D=E7=AB=AF=E5=90=8C=E6=94=B9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 交付(12 档,+1163 / −232) - **`src/compiler/ast.cr`**:token 常量 `T_NEWLINE=103 / T_INDENT=104 / T_DEDENT=105 / T_COLON_BLOCK=106 / T_COLON_DECL=107`(**既有 0..102 一个未动**,从空洞外起)+ `T_NEVER=108 / T_CATCH=109 / T_FAIL=110 / T_SPEC=111 / T_PIPE=112`;`dyn` 复用既有 `T_DYN=99`(该号此前零发射点);解析器码 `EC_P_STRUCT_LIT_SEP = 1030`。 - **`src/compiler/lexer.cr`**:布局机件(缩进栈 / `g_bracket_depth` / `layout_skip_blank` / `colon_at_line_end` / `layout_break` / `finish_layout`;更浅且不匹配任何外层列 ⇒ **响亮报错**,不静默对齐); 关键字表 **36 → 39**(去 `None`/`Some`/`move`,加 `catch`/`dyn`/`fail`/`never`/`none`/`spec`); `tokenize(_src, layout_bypass)` 旁路改**显式形参**(使 call site 原文即判据载体)。 - **`src/compiler/parser.cr`**:region 产生式 + 位置语义(`g_want_value`)+ 行边界三态 + struct 字面量分隔符 **盲跳 → 校验 `=`**(未选定形响亮 `P030`)+ `match` 臂 `|` 前缀两形都收 + 删 `T_MOVE` 分支。 - **`never` 语义(两前端同改)**:以**发散语句**收尾的路径(`return`/`break`/`continue`)其类型 = `never` (不再是「所返回值的类型」),且 `never` 与任何类型相容;落点在**组合函数层** (`bootstrap/corec/frontend/type_checker.py` 的 `_compat` / `src/compiler/checker.cr` 的 `type_compat_strict`)。 - **`tokenize()` 调用点逐处复核(J-T5-1)**:实算 **10 处**(裸 grep 13 − 定义 1 − 注释 3 = 9,+ `lsp/lsp.cr:179`; 计划 §7.2 的「12」是旧口径,T0 §5.4 已更正为 9/10)。**唯一需要旁路的是 `parser.cr` 的 `interp_parse_holes`** (洞是从源切出的表达式、无 layout 上下文;不旁路会伪造缩进状态并改写外层缩进栈)。其余 9 处**不旁路**, 逐处给出理由(其后都有 `res_imports`/`parse_all` 等 layout 消费者)。 ## 判据(我独立复跑主门) | 门 | 读数 | |---|---| | **J-T5-3** `./build/corec clean-cache` + `check src/compiler` | **rc=0 · 零诊断 · `ok`**(改前 12638 条诊断)——**我自跑复核** | | 同一门 CI 形态 `CI_JOB_NAME=check src/ci/run.sh` | rc=0 | | **J-T5-2** `corec2`/`corec3` 两次构建 + `cmp` | **IDENTICAL**——**我自跑复核**(corec2 编 arith 运行 = 110) | | **T1/T2 探针**(含新增 `positions` 52 条) | **146 条 ALL PASS**——**我自跑复核**(J-T1-2 真绿:两表皆 39) | | J-T0-5 零构建半 | `tools/v4_layout_probe.py tokenize-sites --require-bypass` ⇒ rc=0 · YES | | 两套前端诊断集一致 | 35 条差分样例逐条同判 | | v3↔v4 逐字节等价 | 10 组同程序对(v3 文本走代 0 vs v4 文本走 T5)**10/10 输出逐字节同** | | 反向对照 | ① 代 0 读 v4 ⇒ 4/4 rc=1 零产物;② 破坏「行尾 `:`」判定 ⇒ 3/3 BUILDFAIL;③ 摘洞内旁路 ⇒ `P27`;④ 撤 `never` 相容 ⇒ 两前端各自把诊断**全部打回**(自源 `ICE04` / bootstrap 两条齐回) | **语料一字未动** —— 裁定的 `never` 语义把 2 条 `TC02` 全部消解,故「改 `main.cr` 语料」的候选作废。 (`main.cr` 本笔的两处改动是 `tokenize(g_source, 0)` 的**签名扩展**,非语义改动。) ## 施工期挖出的两条(前者已登记另案,后者见 TODO) 1. **改前 12638 条诊断的头号根因 = 「把注释的列当成 anchor」**:`ast.cr` 里 `TY_DEX_S … // 注释续行` 处 伪造出 `INDENT(22)`。⇒ 布局扫描器必须**先吃空白+注释再判行首**(纯空行/纯注释行成 no-op;T0 §1.1 判定①同面)。 2. **`never ⊆ X` 在类型项引擎里是未覆盖面**:`ty_sub(never, named)` 返回 **-1** ⇒ `error[ICE04] (uncovered face)`。 本批只在**组合层**兑现语义 ⇒ **两层对「`never` 作子类型」的认定当前不一致**(组合层收、引擎层 -1)。 当前 `src/**` 零命中(三绿即证),但属**潜在缺口**,另案登记。 3. **两套前端的 block-like kind 清单本就该不同**:自源侧 `EXPR_WHILE` 是独立 kind(Python 侧 desugar 成 `Loop`), `Flow` 在自源侧不是表达式节点 ⇒ 判据锚在**语义**(v3 逐形等价),**不锚 kind 名**。已写进 `is_block_like` 头注并注明 「禁止为『两边清单长得一样』而增删」。 ## 另案(未动,逐条留痕) - `fail`/`catch` **两套前端均无产生式** ⇒ 本批「发散出口」只覆盖 `return`/`break`/`continue`(计划 §十.5 定其语义属另一批)。 - **bootstrap 的 `none` 拼写面**:`src/**` 真实使用 0 处;但 `tests/bootstrap/test_pipeline.py` 的 `'V4 lowercase none'` 用例与 `tests/selfhost/test_compile.py:179` 真用 ⇒ 自源 rc=0/运行 42 ✓、bootstrap `Undefined name: none` ✗ ⇒ 已固化进判据档的真实分歧,另行处置。 - `tests/selfhost/`(78 档)2 绿 / 76 红,**逐档归因 = 内联语料仍是 v3 形**(T6 面);`tests/bootstrap/*.py` 同因。 --- bootstrap/corec/frontend/type_checker.py | 26 +- src/compiler/ast.cr | 29 ++ src/compiler/checker.cr | 19 +- src/compiler/dump.cr | 4 +- src/compiler/lexer.cr | 273 +++++++++-- src/compiler/main.cr | 4 +- src/compiler/module.cr | 8 +- src/compiler/parser.cr | 571 ++++++++++++++++------- src/compiler/purity_selftest.cr | 2 +- src/lsp/analysis.cr | 12 +- src/lsp/lsp.cr | 2 +- tools/v4_frontend_probe.py | 443 +++++++++++++++++- 12 files changed, 1162 insertions(+), 231 deletions(-) diff --git a/bootstrap/corec/frontend/type_checker.py b/bootstrap/corec/frontend/type_checker.py index 5a734ba6..6ff628c0 100644 --- a/bootstrap/corec/frontend/type_checker.py +++ b/bootstrap/corec/frontend/type_checker.py @@ -232,7 +232,7 @@ def _check_function(self, decl: FunctionDecl): self.symtab.define(name, SymbolKind.PARAM, typ) if decl.body: inferred = self._infer_expr(decl.body) - if not self._type_equal(inferred, decl.return_type): + if not self._compat(inferred, decl.return_type): # Relaxed check: try to unify unresolved generic params if not self._unify_return_type(inferred, decl.return_type): self.errors.append(f"Function {decl.name}: expected return type {decl.return_type}, got {inferred}") @@ -461,7 +461,7 @@ def _infer_expr(self, expr: Expr) -> Type: else_t = self._infer_expr(expr.else_branch) self._pop_borrow_scope() self.symtab.pop_scope() - if not self._type_equal(then_t, else_t): + if not self._compat(then_t, else_t): self.errors.append(f"If branches have different types: {then_t} vs {else_t}") return BaseType('never') return then_t @@ -504,15 +504,16 @@ def _infer_expr(self, expr: Expr) -> Type: if arm_types: first = arm_types[0] for t in arm_types[1:]: - if not self._type_equal(first, t): + if not self._compat(first, t): self.errors.append("Match arms have different types") return BaseType('never') return first return BaseType('unit') elif isinstance(expr, ReturnStmt): + # v4 裁定:发散出口 ⇒ never(值仍须推断,否则返回值内的诊断整段消失) if expr.value: - return self._infer_expr(expr.value) - return BaseType('unit') + self._infer_expr(expr.value) + return BaseType('never') elif isinstance(expr, ExprStmt): self._infer_expr(expr.expr) # check for side effects return BaseType('unit') @@ -543,7 +544,7 @@ def _infer_expr(self, expr: Expr) -> Type: self._record_borrow_holder(name, borrowed_name, expr.values[i].op == '&mut') return BaseType('unit') elif isinstance(expr, BreakStmt) or isinstance(expr, ContinueStmt): - return BaseType('unit') + return BaseType('never') # v4 裁定:发散出口 ⇒ never(原 unit) elif isinstance(expr, Go): self._infer_expr(expr.expr) return BaseType('unit') @@ -726,6 +727,19 @@ def _substitute_type(self, typ: Type, mapping: dict) -> Type: return GenericApplyType(typ.path, args) return typ + def _is_never(self, t) -> bool: + return isinstance(t, BaseType) and t.name == 'never' + + def _compat(self, t1, t2) -> bool: + """分支合一/返回位相容判定(v4 裁定 2026-10-11): + 两侧类型相同 **或** 任一侧为 `never` ⇒ 相容(`never` 作子类型)。 + 依据 = docs/core-language-syntax_v4.md §3.1:`never`(发散类型)是基本类型, + 且以发散语句(return/break/continue)收尾的路径其类型即 `never`。 + """ + if self._is_never(t1) or self._is_never(t2): + return True + return self._type_equal(t1, t2) + def _type_equal(self, t1, t2) -> bool: if t1 is None or t2 is None: return True diff --git a/src/compiler/ast.cr b/src/compiler/ast.cr index c03e89df..018457b2 100644 --- a/src/compiler/ast.cr +++ b/src/compiler/ast.cr @@ -105,6 +105,33 @@ T_EXTERN : int = 100 // extern "C" / foreign function declaration T_HASH : int = 101 T_INTERP : int = 102 // 字符串插值洞 token(批 8 插值展开):lexeme = 洞内原文,iv bit0/bit1 = 同一字面量的 part 链,bit2 = 洞已闭合 +// ── v4 布局(layout)与 `:` 双义(T5;出处 = 施工计划 §四.1 项 1/2 + T0 布局规格 §1/§2)── +// 取号同 T_HASH:**既有 0..102 一个不动**,从 103 起取空洞外的下一个自由号。 +// T_NEWLINE:一个「有 token 的逻辑行」结束时发出(纯空行/纯注释行**不发**,规格 §1.1 ①-1/①-2)。 +// T_INDENT :换行后首个 token 的列**深于**缩进栈顶 ⇒ 压栈并发出。 +// T_DEDENT :更浅 ⇒ 逐层弹出并各发一个;不匹配任何外层列 ⇒ 响亮报错(不静默对齐)。 +// 括号 `( ) [ ] { }` 内不参与布局(隐式续行;`{ }` 是字面量定界符,规格 §4.1)。 +T_NEWLINE : int = 103 +T_INDENT : int = 104 +T_DEDENT : int = 105 +// `:` 的行内/行尾由**词法位置**决定(裁 (b),T0 布局规格 §2.1)——二者互斥且穷尽 ⇒ parser 侧零前瞻。 +// T_COLON_BLOCK:`:` 之后到该**物理行行尾**无任何 token(空白/注释不计,§2.3)⇒ region 开启。 +// T_COLON_DECL :行内 `:` = 类型标注 / import 别名 / 字段 / 形参 / 泛型约束分隔符。 +// 原 T_COLON(30) 由这两个 token 取代(**保留编号、不再发射**——「勿重编号」)。 +T_COLON_BLOCK : int = 106 +T_COLON_DECL : int = 107 +// v4 关键字 36 → 39 的新增五员(T5;出处 = 施工计划 §一.5 的三表机械差集 + §四.1 项 7/8)。 +// `never`/`dyn` 由**词素比对提升进关键字表**(v4 要求它们是关键字,不是可重名的词素)—— +// `dyn` 复用既有的 T_DYN(99)(该号此前定义为 token kind 但零发射点);`never` 取新号。 +T_NEVER : int = 108 +T_CATCH : int = 109 +T_FAIL : int = 110 +T_SPEC : int = 111 +// v4 的 `|`(match 臂前缀 / alternative):原自源 lexer **无单竖线分支** ⇒ `|` 落 Unknown 被 +// 静默丢弃(`||` 走 T_PIPEPIPE,不受影响)。v4 目标形的臂前缀 = `|`(docs/core-language-syntax_v4.md +// 的 match 例)⇒ 必须有真 token 才可判;与 bootstrap 的 TokenType.PIPE 对齐(T5 新增)。 +T_PIPE : int = 112 + // W_I8..W_F64(1..10)原为「宽度标注」值域,仅供宽度后缀 token 分支使用。 // 2026-09-10 语言面收窄 §2 随死分支一并删除。**勿重编号**。 @@ -353,6 +380,8 @@ EC_P_APX_TAG : int = 1026 // P026 `apx` 标签不适用于该声明( EC_P_INTERP_UNCLOSED : int = 1027 // P027 **畸形插值**(`${` 无配对 `}` / `${}` 空洞 / 洞内尾随垃圾;此前静默吞到行尾) EC_P_INTERP_TYPE : int = 1028 // P028 插值洞类型不可插值(白名单 = string/int/dex/bool/char;fail-closed) EC_P_INTERP_HOLE_LEAK : int = 1029 // P029 **内部不变量破坏**:插值洞到达发射面(checker 未改写;见 ir_gen 兜底) +EC_P_STRUCT_LIT_SEP : int = 1030 // P030 结构体字面量/模式的字段分隔符必须是 `=`(v4 单形;`:` 形响亮拒绝) + // 出处 = T0 布局规格 §4.2(该条**指定**新码为 1030)。 // N0xx — Name Resolution EC_N_UNDEFINED : int = 2001 // N001 Undefined name diff --git a/src/compiler/checker.cr b/src/compiler/checker.cr index 13cb5551..2abc1dbd 100644 --- a/src/compiler/checker.cr +++ b/src/compiler/checker.cr @@ -455,6 +455,14 @@ fn array_len_constraint_sym(ti_a: int, ti_b: int) -> int: // P5 Task 5 下线,本条 = 判定面单点纪律的继承)。 // 参序 =(源,目标)——见 array_len_walk 上方的归一说明。 fn type_compat_strict(ti_a: int, ti_b: int) -> int: + // v4(维护者裁定 2026-10-11):**`never` 与任何类型相容**(`never` 作子类型)。 + // 依据 = docs/core-language-syntax_v4.md §3.1 把 `never`(发散类型)列为基本类型, + // 且「以发散语句(`return`/`break`/`continue`/`fail`)收尾的路径」其类型即 `never` + // (见 infer_expr 的 EXPR_RETURN/EXPR_BREAK/EXPR_CONTINUE 格)⇒ 分支合一处的 + // 「unit vs never」「int vs never」必须放行,否则「一支赋值、一支 return」这类 + // **完全正常**的语句位 if 会被误报 TC02(实测:本仓 src/compiler/main.cr 的 is_decl_stmt)。 + if ti_a == TI_NEVER || ti_b == TI_NEVER: + return 1 if !type_equal(ti_a, ti_b): // ─── R2 P3 Task 4:**可选目标的子类型注入**(`T ⊆ T?`、`null ⊆ T?`)─── // 语义(spec §5.4):`T?` = `T ∪ null` ⇒ 裸 T 值与 None 值**本来就该**流进 T? 的槽 @@ -3664,9 +3672,12 @@ fn infer_expr(node: int) -> int: return TI_UNIT if ast_kind(node) == EXPR_RETURN: + // v4(裁定 2026-10-11):以发散语句收尾的路径,其类型 = **never**(**不再是**所返回 + // 值的类型)。值仍**必须推断** —— 否则 `return foo()` 里的未定义名/类型错等诊断会 + // 整段消失(那是把一个响亮面换成静默面);推断结果只是不参与本节点类型。 if ast_a(node) >= 0: - return infer_expr(ast_a(node)) - return TI_UNIT + infer_expr(ast_a(node)) + return TI_NEVER if ast_kind(node) == EXPR_ENUM_CONSTRUCTOR: name_idx := ast_a(node) @@ -4055,9 +4066,9 @@ fn infer_expr(node: int) -> int: return alloc_type(TYP_ARRAY, elem_ti, ast_b(node)) if ast_kind(node) == EXPR_BREAK: - return TI_UNIT + return TI_NEVER // v4 裁定:发散出口 ⇒ never(原 TI_UNIT) if ast_kind(node) == EXPR_CONTINUE: - return TI_UNIT + return TI_NEVER // 同上 if ast_kind(node) == EXPR_WILDCARD: return TI_UNIT if ast_kind(node) == EXPR_MOVE: diff --git a/src/compiler/dump.cr b/src/compiler/dump.cr index 808c269a..bc784222 100644 --- a/src/compiler/dump.cr +++ b/src/compiler/dump.cr @@ -231,7 +231,7 @@ fn cmd_ir(src_path: string) -> int: return 1 g_source_dir = dirname(src_path) g_error_count = 0 // 会话起点(tokenize 多轮累积词法错误,见 lexer.cr) - tokenize(g_source) + tokenize(g_source, 0) g_str_count = 0 res_imports() parse_all() @@ -453,7 +453,7 @@ fn cmd_cir(src_path: string) -> int: return 1 g_source_dir = dirname(src_path) g_error_count = 0 // 会话起点(tokenize 多轮累积词法错误,见 lexer.cr) - tokenize(g_source) + tokenize(g_source, 0) g_str_count = 0 res_imports() parse_all() diff --git a/src/compiler/lexer.cr b/src/compiler/lexer.cr index 309558fe..501621ff 100644 --- a/src/compiler/lexer.cr +++ b/src/compiler/lexer.cr @@ -8,6 +8,24 @@ g_pos : int, mut g_line : int, mut g_col : int, mut +// ── v4 布局(layout)状态(T5;出处 = 施工计划 §四.1 项 3 + T0 布局规格 §1/§2)────── +// 缩进栈:**空栈起**,由首个非空行的首个 token 建立基准 anchor(规格 §1.1 ①-1 第 3 条) +// —— 基准层不出 INDENT/DEDENT,故它**在栈里占一层**(栈长 >= 1 表示已建基)。 +g_indent_stack : string, mut +g_indent_cap : int, mut +g_indent_len : int, mut +// 括号/花括号深度:>0 时**不参与布局**(隐式续行)。`{ }` 一并计入 ⇒ +// 结构体字面量内部不产生 layout(规格 §4.1「字面量内部不参与 layout region」)。 +g_bracket_depth : int, mut +// 当前逻辑行是否已产出 token(决定换行时是否发 NEWLINE;纯空行/纯注释行不发)。 +g_line_has_token : int, mut +// 上一个「属于某个 token」的物理行号——换行判定用(比跨行空白标志更稳)。 +g_last_tok_line : int, mut +// 布局旁路旗标(T0 布局规格 §5.2):0 = 发射 INDENT/DEDENT(默认,fail-closed); +// 1 = **不发射,且不读不写缩进栈**。凡「调用后 token 流不由 parse_all/parse_expr 消费」 +// 的 tokenize() 调用点必须置 1(洞内重入 / 转储 / 自测 / LSP 分析)。 +g_layout_bypass : int, mut + // Character constants C_SP : int = 32 C_TB : int = 9 @@ -147,18 +165,28 @@ fn lookup_keyword(s: string) -> int: return T_AUTO if s == "fileid": return T_FILEID - if s == "move": - return T_MOVE + // v4(T5,施工计划 §四.1 项 7/8):36 → 39。去 `None`/`Some`/`move` + // (前二者退役为普通标识符——`Some(x)` 仍经 parse_postfix 的「首字母大写 ⇒ + // 枚举构造器」分支解,与 bootstrap 侧同判;`move` 退场),加 + // `catch`/`dyn`/`fail`/`never`/`none`/`spec`。逐元素目标 = bootstrap/corec/syntax/tokens.py 的 KEYWORDS。 if s == "self": return T_SELF if s == "in": return T_IN - if s == "None": - return T_NONE - if s == "Some": - return T_SOME if s == "unit": return T_UNIT + if s == "none": + return T_NONE + if s == "never": + return T_NEVER + if s == "dyn": + return T_DYN + if s == "catch": + return T_CATCH + if s == "fail": + return T_FAIL + if s == "spec": + return T_SPEC return T_IDENT // 2^k(纯整数,k >= 0) @@ -448,6 +476,123 @@ fn add_tok_int_lex(kind: int, ival: int, lexeme_ni: int, start_line: int, start_ w64(g_tokens, tp + OFF_TK_COL, start_col) g_token_count = g_token_count + 1 +// ── v4 布局(layout)机件(T5;判定出处 = T0 布局规格 §1/§2)────────────────────── +// 实现约束(规格 §2.3,写死):判定 ① 的 anchor 计算与判定 ② 的行尾判定**必须共用同一个** +// 注释/字符串感知扫描器——两处各写一份必然漂。故本区**只有** `layout_skip_blank` 一份 +// 「跳过空白与注释」的实现:`colon_at_line_end`(只读前瞻)建在它之上。 + +// 从 idx 起跳过空白与注释(`//` 行注释 · 可跨行 `/* */` 块注释)。 +// 返回 (新下标, 是否跨过至少一个物理行边界) —— 二元返回用 out 参数编码: +// 返回值为新下标,跨行标志写进 g_layout_saw_nl(**调用方须在读前清零**,同款先例 = 仓内 +// 「一次调用一次用」的临时全局;不引入元组类型)。 +g_layout_saw_nl : int, mut + +fn layout_skip_blank(src: string, idx: int, max_len: int) -> int: + i : ., mut = idx + g_layout_saw_nl = 0 + loop: + if i >= max_len: + break + c := cur_char_at(src, i, max_len) + if c == 32 || c == 9 || c == 13: + i = i + 1 + continue + if c == 10: + g_layout_saw_nl = 1 + i = i + 1 + continue + if c == 47 && cur_char_at(src, i + 1, max_len) == 47: + loop: + if i >= max_len: + break + if cur_char_at(src, i, max_len) == 10: + break + i = i + 1 + continue + if c == 47 && cur_char_at(src, i + 1, max_len) == 42: + i = i + 2 + loop: + if i >= max_len: + break + if cur_char_at(src, i, max_len) == 10: + g_layout_saw_nl = 1 + if cur_char_at(src, i, max_len) == 42 && cur_char_at(src, i + 1, max_len) == 47: + i = i + 2 + break + i = i + 1 + continue + break + return i + +// 裁定 ②(词法位置决定,T0 布局规格 §2.1/§2.3):`:` **是行尾的** ⟺ 该 `:` 之后、 +// 到该**物理行行尾**为止,**不存在任何 token**(空白不计 · 注释不计 ⇒ §2.3 的四格: +// `// note` / `/* note */` / 跨行块注释都判**行尾**;`x : int = 5 // note` 判**行内**)。 +// 调用点保证 pos 正好在 `:` **之后**。 +fn colon_at_line_end(src: string, pos: int, max_len: int) -> int: + i := layout_skip_blank(src, pos, max_len) + if g_layout_saw_nl != 0: + // 跨过行边界(含跨行块注释)⇒ 本物理行 `:` 之后已无余物 + return 1 + if i >= max_len: + return 1 + return 0 + +fn ind_top() -> int: + return r64(g_indent_stack, (g_indent_len - 1) * 8) + +fn ind_push(col: int): + if g_indent_len >= g_indent_cap: + ncap : ., mut = g_indent_cap * 2 + if ncap < 16: + ncap = 16 + nv := alloc(ncap * 8) + if g_indent_cap > 0: + _dyncpy(g_indent_stack, g_indent_cap * 8, nv) + g_indent_stack = nv + g_indent_cap = ncap + w64(g_indent_stack, g_indent_len * 8, col) + g_indent_len = g_indent_len + 1 + +// 越过物理行边界(且不在括号内)时,发出 NEWLINE 与 INDENT/DEDENT。 +// 判定出处:§1.1 ①-1/①-2(空行与只含注释的行**不产生 token**、不改变 anchor, +// 故调用点只在「上一逻辑行确实产出过 token」时才进来);①-3(anchor 列 ≡ 该行 +// **首个 token** 的列,由 advance 的既有列维护给出);①-1 第 3 条(首个非空行建基)。 +fn layout_break(): + add_tok(T_NEWLINE, -1, g_line, g_col) + g_line_has_token = 0 + col := g_col + top := ind_top() + if col > top: + ind_push(col) + add_tok(T_INDENT, -1, g_line, col) + else if col < top: + loop: + if g_indent_len <= 1: + break + if ind_top() <= col: + break + g_indent_len = g_indent_len - 1 + add_tok(T_DEDENT, -1, g_line, col) + if ind_top() != col: + if g_indent_len == 1: + // 「比单元基准锚点更浅」——T0 §6.1 A2 定义的那个 layout 错误 + add_error("layout anchor " + int_str(col) + " is shallower than the unit base anchor " + int_str(ind_top())) + else: + // 不匹配任何外层列 ⇒ 响亮报错(**不得**静默对齐到最近一层——那是猜) + add_error("inconsistent dedent: column " + int_str(col) + " matches no open indent level") + +// 源尾收尾:补发最后一个 NEWLINE,并弹出全部未闭合的缩进层(各发一个 DEDENT)。 +// 基准层(栈底 = 首行 anchor)**不发 DEDENT**——它没有对应的 INDENT。 +fn finish_layout(): + if g_line_has_token != 0: + add_tok(T_NEWLINE, -1, g_line, g_col) + g_line_has_token = 0 + loop: + if g_indent_len <= 1: + break + g_indent_len = g_indent_len - 1 + add_tok(T_DEDENT, -1, g_line, g_col) + fn skip_ws(src: string, pos: int, max_len: int) -> int: // Account for the token/comment consumed since the previous call, then // consume whitespace. g_pos is the last byte reflected in line/column. @@ -476,7 +621,13 @@ fn skip_ws(src: string, pos: int, max_len: int) -> int: g_pos = pos return pos -fn tokenize(_src: string): +// 第二形参 = 布局旁路旗标(T0 布局规格 §5.2):0 = 发射 INDENT/DEDENT(默认,fail-closed); +// 1 = **不发射,且不读不写缩进栈**。**显式形参**而非纯全局:判据 J-T0-5 的零构建半读 +// call site 原文,要求旁路在**调用点可见**(隐含全局会被读成「视情况」)。 +// 规则(可机械判定):一个调用点必须传 1 ⟺ 该调用之后、在同一控制流里该 token 流**不由** +// `parse_all` / `parse_expr` 消费(⟺ 只做转储、重扫、自测、LSP 分析,或是重入路径)。 +fn tokenize(_src: string, layout_bypass: int): + g_layout_bypass = layout_bypass g_token_count = 0 // 注意:不再清零 g_error_count——res_imports 会重 tokenize(拼接 import // 前后两轮),清零会把首轮词法守卫错误(整数字面量溢出等)吞掉。错误 @@ -485,40 +636,68 @@ fn tokenize(_src: string): g_pos = 0 g_line = 1 g_col = 1 + // v4 布局状态复位(T0 布局规格 §5.2):旁路时不读不写缩进栈 —— 只清零记账量。 + g_indent_len = 0 + g_bracket_depth = 0 + g_line_has_token = 0 + g_last_tok_line = 0 _slen : ., mut = str_len(_src) _pos = skip_ws(_src, _pos, _slen) loop: + // 先吃掉**注释与其后的空白/空行**,使下面的「行首」判定落在**真 token** 上。 + // 为什么必须先吃(判定 ①-2 的机械实现):纯空行与纯注释行是 no-op(不产生 token、 + // 不改变 anchor)。若在注释字符处判行首,会把**注释的列**当 anchor ⇒ 一行行尾注释 + // 后接一行缩进注释就会伪造 INDENT(实测:本仓 ast.cr 的 `TY_DEX_S : int = 8 // …` + // 续行注释触发 INDENT(22))。bootstrap 的 `skip_whitespace_and_comments` 把注释 + // 收在其内部,故天然没有这一格 ⇒ 本循环照同一语义重组(**不是**另写一份判定)。 + loop: + _pos = skip_ws(_src, _pos, _slen) + if _pos >= _slen: + break + cc := cur_char_at(_src, _pos, _slen) + if cc == 47 && cur_char_at(_src, _pos + 1, _slen) == 47: + _pos = _pos + 2 + loop: + if _pos >= _slen: + break + if cur_char_at(_src, _pos, _slen) == 10: + _pos = _pos + 1 + break + _pos = _pos + 1 + continue + if cc == 47 && cur_char_at(_src, _pos + 1, _slen) == 42: + _pos = _pos + 2 + loop: + if _pos >= _slen: + break + if cur_char_at(_src, _pos, _slen) == 42 && cur_char_at(_src, _pos + 1, _slen) == 47: + _pos = _pos + 2 + break + _pos = _pos + 1 + continue + break if _pos >= _slen: break + // 布局发射(判定出处 = T0 布局规格 §1/§2): + // - 只在括号外(`()`/`[]`/`{}` 内是隐式续行,不参与 layout); + // - 只在「上一逻辑行确实产出过 token」时发 NEWLINE ⇒ 纯空行与纯注释行天然成为 + // no-op(规格 ①-1/①-2); + // - anchor 列 = 本 token 的列(规格 ①-3),由 skip_ws 的既有列维护给出; + // - 旁路旗标(g_layout_bypass)置位时整段跳过(洞内重入 / 转储 / 自测 / LSP)。 + if g_layout_bypass == 0: + if g_bracket_depth == 0 && g_line_has_token != 0 && g_line != g_last_tok_line: + layout_break() + g_line_has_token = 1 + g_last_tok_line = g_line + if g_indent_len == 0: + // ①-1 第 3 条:**首个非空行建立 anchor**(该行的首个 token 即基准列)。 + // 基准层不发 INDENT —— 否则顶层代码会整体被多包一层。 + ind_push(g_col) c := cur_char_at(_src, _pos, _slen) start_line : ., mut = g_line start_col : ., mut = g_col - // Comments - if c == 47 && peek_at(_src, _pos, _slen) == 47: - _pos = _pos + 2 - loop: - if _pos >= _slen: - break - if cur_char_at(_src, _pos, _slen) == 10: - _pos = _pos + 1 - break - _pos = _pos + 1 - _pos = skip_ws(_src, _pos, _slen) - continue - if c == 47 && peek_at(_src, _pos, _slen) == 42: - _pos = _pos + 2 - loop: - if _pos >= _slen: - break - if cur_char_at(_src, _pos, _slen) == 42 && peek_at(_src, _pos, _slen) == 47: - _pos = _pos + 2 - break - _pos = _pos + 1 - _pos = skip_ws(_src, _pos, _slen) - continue - // Identifier if is_alpha(c) != 0: start := _pos @@ -843,6 +1022,14 @@ fn tokenize(_src: string): add_tok(T_PIPEPIPE, -1, start_line, start_col) _pos = skip_ws(_src, _pos, _slen) continue + // v4 单竖线(T5):原代码**无此分支** ⇒ 裸 `|` 落 Unknown 分支被静默丢弃。 + // v4 的 match 臂前缀 = `|`(docs/core-language-syntax_v4.md 的 match 例)⇒ 显式收下。 + // 零足迹依据:全仓 `src/**` 的裸 `|` **零处**(注释/字符串内的 `|` 不达本行)。 + if c == 124: + _pos = _pos + 1 + add_tok(T_PIPE, -1, start_line, start_col) + _pos = skip_ws(_src, _pos, _slen) + continue if c == 45 && peek_at(_src, _pos, _slen) == 62: _pos = _pos + 2 add_tok(T_ARROW, -1, start_line, start_col) @@ -896,33 +1083,44 @@ fn tokenize(_src: string): continue // Single-char tokens + // 括号深度(T0 布局规格 §4.1):`( ) [ ] { }` **都计入** ⇒ 括号内是隐式续行、 + // 不发 layout;`{ }` 一并计入 ⇒ 结构体字面量内部不产生 layout region。 if c == 40: _pos = _pos + 1 + g_bracket_depth = g_bracket_depth + 1 add_tok(T_LPAREN, -1, start_line, start_col) _pos = skip_ws(_src, _pos, _slen) continue if c == 41: _pos = _pos + 1 + if g_bracket_depth > 0: + g_bracket_depth = g_bracket_depth - 1 add_tok(T_RPAREN, -1, start_line, start_col) _pos = skip_ws(_src, _pos, _slen) continue if c == 123: _pos = _pos + 1 + g_bracket_depth = g_bracket_depth + 1 add_tok(T_LBRACE, -1, start_line, start_col) _pos = skip_ws(_src, _pos, _slen) continue if c == 125: _pos = _pos + 1 + if g_bracket_depth > 0: + g_bracket_depth = g_bracket_depth - 1 add_tok(T_RBRACE, -1, start_line, start_col) _pos = skip_ws(_src, _pos, _slen) continue if c == 91: _pos = _pos + 1 + g_bracket_depth = g_bracket_depth + 1 add_tok(T_LBRACKET, -1, start_line, start_col) _pos = skip_ws(_src, _pos, _slen) continue if c == 93: _pos = _pos + 1 + if g_bracket_depth > 0: + g_bracket_depth = g_bracket_depth - 1 add_tok(T_RBRACKET, -1, start_line, start_col) _pos = skip_ws(_src, _pos, _slen) continue @@ -937,8 +1135,15 @@ fn tokenize(_src: string): _pos = skip_ws(_src, _pos, _slen) continue if c == 58: + // 裁定 ②(词法位置决定,T0 布局规格 §2.1):行尾 `:` ⇒ T_COLON_BLOCK(region 开启); + // 行内 `:` ⇒ T_COLON_DECL(类型标注 / import 别名 / 字段 / 形参 / 泛型约束分隔符)。 + // 二者互斥且穷尽 ⇒ parser 侧零前瞻。`:=` / `::` 已在上方多字符分支消费,**不受影响**。 + le := colon_at_line_end(_src, _pos + 1, _slen) _pos = _pos + 1 - add_tok(T_COLON, -1, start_line, start_col) + if le != 0: + add_tok(T_COLON_BLOCK, -1, start_line, start_col) + else: + add_tok(T_COLON_DECL, -1, start_line, start_col) _pos = skip_ws(_src, _pos, _slen) continue if c == 46: @@ -1026,6 +1231,10 @@ fn tokenize(_src: string): _pos = _pos + 1 _pos = skip_ws(_src, _pos, _slen) + // 源尾收尾(T0 布局规格 §1):补发末行 NEWLINE + 弹出全部未闭合缩进层(各一个 DEDENT)。 + // 旁路时同样不发射(不读不写缩进栈)。 + if g_layout_bypass == 0: + finish_layout() add_tok(T_EOF, -1, g_line, g_col) // Sync back globals g_pos = _pos diff --git a/src/compiler/main.cr b/src/compiler/main.cr index 3e2accb9..df02a46a 100644 --- a/src/compiler/main.cr +++ b/src/compiler/main.cr @@ -122,7 +122,7 @@ fn read_static_runtime_source() -> string: fn run_frontend() -> int: g_error_count = 0 // 会话起点清词法/语法错误(tokenize 多轮累积,见 lexer.cr) println("[1/5] tokenize...") - tokenize(g_source) + tokenize(g_source, 0) println("[2/5] resolve imports...") res_imports() println("[3/5] parse...") @@ -737,7 +737,7 @@ fn corec_main() -> int: // Full compilation: source -> assembly (used by tests and programmatic API) fn compile_source(source: string) -> string: g_source = source - tokenize(g_source) + tokenize(g_source, 0) res_imports() parse_all() check_all() diff --git a/src/compiler/module.cr b/src/compiler/module.cr index 76ee4980..36ebc794 100644 --- a/src/compiler/module.cr +++ b/src/compiler/module.cr @@ -495,7 +495,7 @@ fn res_imports(): if str_len(import_core_acc) > 0: g_source = import_core_acc + "\n" + g_source - tokenize(g_source) + tokenize(g_source, 0) // Determine main file's fileid main_fileid_str : ., mut = get_fileid(g_source) @@ -547,7 +547,7 @@ fn res_imports(): else: break alias_str : ., mut = "" - if pos < g_token_count && r64(g_tokens, pos * ESZ_TOKEN + OFF_TK_KIND) == T_COLON: + 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)) @@ -713,7 +713,7 @@ fn res_imports(): if str_len(pass_src) > 0: g_source = g_source + pass_src - tokenize(g_source) + tokenize(g_source, 0) total_accumulated = total_accumulated + pass_bytes // Strip _import.cr preamble to prevent re-parsing import tokens as code. @@ -722,6 +722,6 @@ fn res_imports(): 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) + tokenize(g_source, 0) build_line_fileid() diff --git a/src/compiler/parser.cr b/src/compiler/parser.cr index 61bdb7fe..4f1e4249 100644 --- a/src/compiler/parser.cr +++ b/src/compiler/parser.cr @@ -8,8 +8,8 @@ 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 +// 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) @@ -45,6 +45,95 @@ fn expect(k: int) -> int: 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 层与头部终结不可区分,正是靠这里兜住。 +fn expect_region_head(): + if tok_k(cur_tok()) == T_COLON_BLOCK: + advance_tok() + else: + add_error("expected ':' to open a region, got '" + tok_lx(cur_tok()) + "'") + return + skip_newlines() + if tok_k(cur_tok()) == T_INDENT: + advance_tok() + else: + add_error("expected an indented region after ':'") + +// 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() @@ -88,6 +177,15 @@ fn parse_type() -> int: 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() @@ -102,10 +200,6 @@ fn parse_type() -> int: 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) // Check for generic args: Box[int,...] or Box @@ -242,6 +336,10 @@ fn parse_binary(mp: int) -> int: 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 @@ -278,10 +376,8 @@ fn parse_unary() -> int: 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)) + // v4(§一.5):`move` 已从关键字表退场 ⇒ lexer 不再发射 T_MOVE,本分支一并删除 + // (原 EXPR_MOVE 构造在 v4 下**不可达**;`move x` 现按普通标识符解析并响亮报错,不静默)。 if tok_k(t) == T_STAR: advance_tok() op := parse_unary() @@ -316,6 +412,7 @@ fn parse_postfix() -> int: ac : ., mut = 0 if !check(T_RPAREN): // Wrap each argument in EXPR_ARG(a=expr, b=next_arg) linked list + 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 @@ -324,6 +421,7 @@ fn parse_postfix() -> int: 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) @@ -379,6 +477,7 @@ fn parse_postfix() -> int: 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)) @@ -441,7 +540,15 @@ fn interp_parse_holes(): if ast_kind(i) == EXPR_INTERP_HOLE: txt := istr_get(ast_data(i)) if str_len(txt) > 0: - tokenize(txt) + // 洞内重入(**全仓唯一的重入点**,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₁ 顶层兜底的 @@ -475,40 +582,16 @@ fn parse_primary() -> int: 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)) - 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)) + // `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: @@ -522,7 +605,9 @@ fn parse_primary() -> int: advance_tok() name := tok_lx(t) ni := str_intern(name) - if check(T_LBRACE) && g_parse_no_struct_literal == 0: + // 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=该字段的值节点)→ 消费者 @@ -545,7 +630,15 @@ fn parse_primary() -> int: break ft := advance_tok() fni := str_intern(tok_lx(ft)) - advance_tok() + // 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) @@ -555,6 +648,7 @@ fn parse_primary() -> int: _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 @@ -580,10 +674,8 @@ fn parse_primary() -> int: 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 + g_want_value = 1 // 括号内 = 表达式位 e := parse_expr() - g_parse_no_struct_literal = saved_nsl if check(T_COMMA): // Tuple: (e1, e2, ...) // 契约(F5 修复):EXPR_TUPLE = a=首 wrapper、b=元素个数;wrapper 在 g_ast 中 @@ -604,6 +696,7 @@ fn parse_primary() -> int: _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): @@ -631,7 +724,13 @@ fn parse_primary() -> int: 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() + // 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: @@ -642,7 +741,9 @@ fn parse_primary() -> int: return parse_for_expr() if tok_k(t) == T_GO: t2 := advance_tok() - if check(T_SEMI) || check(T_RBRACE) || check(T_EOF): + // 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 @@ -697,6 +798,7 @@ fn parse_primary() -> int: 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): @@ -728,6 +830,7 @@ fn parse_primary() -> int: _dyncpy(vals, cap * 8, nv) vals = nv cap = ncap + g_want_value = 1 // 数组元素 = 表达式位 w64(vals, ec * 8, parse_expr()) // 元素值(子树自占若干槽) ec = ec + 1 advance_tok() @@ -751,37 +854,83 @@ fn parse_primary() -> int: 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 + 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 + // v4 region:吃 `T_COLON_BLOCK` + NEWLINE + `T_INDENT` … `T_DEDENT`(取代原 `{` … `}`)。 + // 尾表达式判定(T0 布局规格 §6.2 A1):**region 的最后一项 = 该 region 的值**, + // 其余各项按语句处理 —— 「还有下一项」的判据由「不是 `}`」变成「不是 DEDENT」。 + // 位置语义见 g_want_value 的头注:进入时读标志决定尾值去留,**体内嵌套 region 一律 + // 先复位为语句位**(parse_stmt / 各 region 产生式各自复位),退出时恢复为进入值。 + t := cur_tok() + want := g_want_value + g_want_value = 0 + expect_region_head() + g_pb_stmts = alloc(256 * 8) + g_pb_cap = 256 + g_pb_count = 0 + have_expr : ., mut = -1 loop: - if check(T_RBRACE) || check(T_EOF): + 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() - 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() + 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: + if i >= g_pb_count: break grow_block_stmts(g_block_stmt_count + 1) - w64(g_block_stmts, g_block_stmt_count * 8, r64(local_stmts, i * 8)) + 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, sc, 0, 0, 0, 0, tok_ln(t), tok_cl(t)) + 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() @@ -790,8 +939,10 @@ fn is_new_var_decl() -> bool: // x := expr if tok_k(p + 1) == T_COLON_EQ: return true - // x : type ... - if tok_k(p + 1) == T_COLON: + // 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: @@ -800,7 +951,7 @@ fn is_new_var_decl() -> bool: 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): + 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 @@ -843,12 +994,14 @@ fn parse_new_var_decl() -> int: 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: @@ -865,7 +1018,9 @@ fn parse_new_var_decl() -> int: if check(T_COMMA): advance_tok() loop: - if check(T_EQ) || check(T_SEMI) || check(T_EOF): + // 标签表终止面(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) @@ -899,18 +1054,18 @@ fn parse_new_var_decl() -> int: 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 - if check(T_SEMI): - advance_tok() - // optional ; + // 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 @@ -965,29 +1120,40 @@ fn parse_new_var_decl() -> int: // `pub`。花括号配平从函数体的 `{` 起算(depth 0→1),体内嵌套块/struct 字面量的花括号 // 成对计入,不会在 depth 归零前误判结束。 fn skip_nested_fn(): + // v4:体的两种形态都以**行边界**收尾 —— `:` + INDENT…DEDENT 的 region,或 `= expr` 行内体。 + // 花括号配平换成缩进配平(T0 布局规格 §6.2 A5:原 `;` 收尾 ⇒ region 收尾)。 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 + 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_RBRACE: - advance_tok() + if k == T_INDENT: + depth = depth + 1 + else if k == T_DEDENT: depth = depth - 1 - if depth <= 0: - return - continue - if k == T_SEMI && seen_brace == 0: - advance_tok() - return advance_tok() + if depth == 0: + return fn parse_stmt() -> int: + // 语句位入口(位置语义规则 ①):本语句整体在语句位 ⇒ 先复位;语句内的表达式位由 + // 各入口重置为 1(声明/赋值右值、return 值、实参、下标、括号内、字面量字段值…)。 + g_want_value = 0 // Drain batch extras from previous call if g_extra_let_count > 0: g_extra_let_count = g_extra_let_count - 1 @@ -1017,98 +1183,110 @@ fn parse_stmt() -> int: if tok_k(t) == T_RETURN: advance_tok() val : ., mut = -1 - if !check(T_SEMI) && !check(T_RBRACE): + // A6(T0 布局规格 §6.2):关键字之后**同一逻辑行内**无 token ⇒ 无值(行边界取代 `;`) + if at_line_end() == 0: + g_want_value = 1 // return 的值 = 表达式位 val = parse_expr() - if check(T_SEMI): - advance_tok() + 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 !check(T_SEMI) && !check(T_RBRACE): + if at_line_end() == 0: + g_want_value = 1 val = parse_expr() - if check(T_SEMI): - advance_tok() + 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() - if check(T_SEMI): - 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() - if check(T_SEMI): - advance_tok() + skip_newlines() 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 + // A1:裸表达式**暂定**为 region 尾值;块循环在「后面还有一项」时再包成 EXPR_STMT。 + // v4 无 `;` ⇒ 不再有「显式语句」形态(原 `if check(T_SEMI): return EXPR_STMT(e)` 分支淘汰)。 + return parse_expr() 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 + want := g_want_value + g_want_value = 1 // 条件恒为表达式位 cond := parse_expr() - g_parse_no_struct_literal = saved_nsl - tb := parse_block() + 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() + advance_tok() // in + want := g_want_value + g_want_value = 1 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() + 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() - g_parse_no_struct_literal = 1 + want := g_want_value + g_want_value = 1 expr := parse_expr() - g_parse_no_struct_literal = 0 - advance_tok() + g_want_value = 0 + expect_region_head() af := -1 al : ., mut = -1 // last arm index ac : ., mut = 0 loop: - if check(T_RBRACE) || check(T_EOF): + 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() - advance_tok() + if check(T_FATARROW): + advance_tok() + else: + add_error("expected '=>' in match arm") + g_want_value = 1 body := parse_expr() if check(T_COMMA): advance_tok() @@ -1120,7 +1298,8 @@ fn parse_match_expr() -> int: // link previous arm to this one al = n ac = ac + 1 - advance_tok() + 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: @@ -1142,7 +1321,15 @@ fn parse_pattern() -> int: 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: + 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) @@ -1198,7 +1385,13 @@ fn parse_pattern() -> int: break ft := advance_tok() fni := str_intern(tok_lx(ft)) - advance_tok() // = + // 同 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) @@ -1289,7 +1482,7 @@ fn parse_generics_into(names: string, constrs: string) -> int: w64(names, gc * 8, @ptr_of(tok_lx(gt))) // Check for constraint: T: Interface w64(constrs, gc * 8, -1) - if check(T_COLON): + if check(T_COLON_DECL): advance_tok() ct := advance_tok() w64(constrs, gc * 8, str_intern(tok_lx(ct))) @@ -1461,7 +1654,7 @@ fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_v 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): + if check(T_COLON_DECL): advance_tok() parse_type() if !check(T_COMMA): @@ -1476,7 +1669,7 @@ fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_v 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): + if check(T_COLON_DECL): advance_tok() parse_type() if !check(T_COMMA): @@ -1490,7 +1683,7 @@ fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_v 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): + if check(T_COLON_DECL): advance_tok() parse_type() if !check(T_COMMA): @@ -1538,12 +1731,20 @@ fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_v parse_spec_annotations(fn_ni) body : ., mut = -1 - if check(T_LBRACE): - body = parse_block() - else: - advance_tok() // = + // 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() - advance_tok() // ; + else: + g_want_value = 0 + body = parse_block() 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 @@ -1739,9 +1940,8 @@ fn parse_declaration(): 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() + // v4(T0 布局规格 §6.2 B2):extern 声明末的可选 `;` 退场 ⇒ 收尾 = 行边界。 + end_decl() return // fn / flow fn @@ -1780,7 +1980,7 @@ fn parse_declaration(): sg_constrs = alloc(64 * 8) sg_constrs_cap = 64 sg_count := parse_generics_into(sg_names, sg_constrs) - advance_tok() // { + expect_region_head() si := add_struct(name) if si >= 0: @@ -1799,7 +1999,8 @@ fn parse_declaration(): save_struct_gen_constrs(si, sg_constrs, sg_count) fc : ., mut = 0 loop: - if check(T_RBRACE) || check(T_EOF): + skip_newlines() + if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF: break ft := advance_tok() fn2 := tok_lx(ft) @@ -1807,7 +2008,10 @@ fn parse_declaration(): // 容量批 T3(裁-CAP-2 (a)):字段**无硬上限**(侧表;第 17 字段起照常写入) // ⇒ 旧 P023 闸与槽上限分支一并删除(不再存在越界写对象)。 si_set_field_name(si, fc, fni) - advance_tok() + 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) @@ -1816,7 +2020,7 @@ fn parse_declaration(): advance_tok() w64(g_structs, si * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, fc) si_commit_fields(si, fc) // 提交字段区(高水位 = base + fc) - advance_tok() + close_region() return // enum @@ -1833,7 +2037,7 @@ fn parse_declaration(): eg_constrs = alloc(64 * 8) eg_constrs_cap = 64 eg_count := parse_generics_into(eg_names, eg_constrs) - advance_tok() + expect_region_head() ei := add_enum(name) if ei >= 0: @@ -1850,7 +2054,8 @@ fn parse_declaration(): save_enum_gen_constrs(ei, eg_constrs, eg_count) vc : ., mut = 0 loop: - if check(T_RBRACE) || check(T_EOF): + skip_newlines() + if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF: break vt := advance_tok() vname := tok_lx(vt) @@ -1881,7 +2086,7 @@ fn parse_declaration(): advance_tok() w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, vc) ei_commit_variants(ei, vc) // 提交变体区(高水位 = base + vc) - advance_tok() + close_region() return // interface declaration @@ -1899,7 +2104,7 @@ fn parse_declaration(): ig_dummy = alloc(64 * 8) ig_dummy_cap = 64 ig_count := parse_generics_into(ig_names, ig_dummy) - advance_tok() // { + expect_region_head() // Allocate interface entry grow_ifaces(g_iface_count + 1) @@ -1916,7 +2121,8 @@ fn parse_declaration(): method_count : ., mut = 0 loop: - if check(T_RBRACE) || check(T_EOF): + skip_newlines() + if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF: break if check(T_FN): advance_tok() // fn @@ -1991,7 +2197,8 @@ fn parse_declaration(): rn2 := parse_type() ret_node = rn2 ret_ti = unpack_type(rn2) - advance_tok() // ; + // D11(T0 布局规格 §2.2):接口方法**无体**、**无 `:`** ⇒ 收尾 = 行边界(原 `;`)。 + end_decl() // Store method in interface entry (with overflow checks) // R2 P3b Task 6(Step 1):上限**显式登记保留**(单源常量 MAX_IFACE_METHODS)—— @@ -2031,10 +2238,10 @@ fn parse_declaration(): advance_tok() w64(g_ifaces, iface_base + OFF_IF_METHOD_COUNT, method_count) g_iface_count = g_iface_count + 1 - advance_tok() // } + close_region() return - // impl block (impl Type { ... } or impl Interface for Type { ... }) + // impl block (impl Type: ... or impl Interface for Type: ...) if check(T_IMPL): t := advance_tok() first_nt := advance_tok() @@ -2049,9 +2256,10 @@ fn parse_declaration(): type_nt := advance_tok() type_name = tok_lx(type_nt) type_ni = str_intern(type_name) - advance_tok() // { + expect_region_head() loop: - if check(T_RBRACE) || check(T_EOF): + skip_newlines() + if tok_k(cur_tok()) == T_DEDENT || tok_k(cur_tok()) == T_EOF: break if check(T_FN): ft := advance_tok() @@ -2069,7 +2277,7 @@ fn parse_declaration(): g_method_count = g_method_count + 1 else: advance_tok() - advance_tok() // } + close_region() // Store impl-for relationship after processing all methods if trait_ni >= 0: grow_impl_for(g_impl_for_count + 1) @@ -2083,9 +2291,12 @@ fn parse_declaration(): advance_tok() nt := advance_tok() name_idx := str_intern(tok_lx(nt)) - advance_tok() + if check(T_EQ): + advance_tok() + else: + add_error("expected '=' in type alias") type_node := parse_type() - advance_tok() // ; + 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) @@ -2110,23 +2321,26 @@ fn parse_declaration(): 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() + // 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 := advance_tok() - if tok_k(tk) == T_RBRACE: + tk := tok_k(cur_tok()) + if tk == T_EOF: + break + if tk == T_DEDENT: depth = depth - 1 - else if tok_k(tk) == T_LBRACE: + else if tk == T_INDENT: depth = depth + 1 - else if tok_k(tk) == T_EOF: - break - else: - if check(T_SEMI): advance_tok() return @@ -2149,6 +2363,7 @@ fn parse_declaration(): 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 之后 / 顶层任意处)⇒ **响亮拒绝**。 @@ -2205,13 +2420,24 @@ fn parse_all(): g_gen_param_count = 0 g_gen_param_cap = 0 + g_want_value = 0 ci : ., mut = 0 loop: - // Skip import/fileid tokens + // 顶层行边界(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 @@ -2236,14 +2462,13 @@ fn parse_all(): advance_tok() continue break - if check(T_COLON): + if check(T_COLON_DECL): advance_tok() if check(T_IDENT): advance_tok() if is_fileid && check(T_INT): advance_tok() - if check(T_SEMI): - advance_tok() + // v4:import/fileid 声明末的可选 `;` 退场(T0 布局规格 §6.2 B4)⇒ 收尾 = 行边界。 t_cur := cur_tok() t_kind := tok_k(t_cur) if t_kind == T_EOF: diff --git a/src/compiler/purity_selftest.cr b/src/compiler/purity_selftest.cr index 32f806da..4a6915e9 100644 --- a/src/compiler/purity_selftest.cr +++ b/src/compiler/purity_selftest.cr @@ -41,7 +41,7 @@ fn ps_compile(src: string) -> int: g_source = src g_error_count = 0 g_source_dir = "" - tokenize(g_source) + tokenize(g_source, 0) res_imports() parse_all() if g_error_count > 0: diff --git a/src/lsp/analysis.cr b/src/lsp/analysis.cr index 33f92301..64e14b12 100644 --- a/src/lsp/analysis.cr +++ b/src/lsp/analysis.cr @@ -1180,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 命中的结构体/枚举名) @@ -1205,9 +1207,9 @@ fn analysis_document_symbol() -> string: // 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: + 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: + 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 diff --git a/src/lsp/lsp.cr b/src/lsp/lsp.cr index ee444689..822dcdb1 100644 --- a/src/lsp/lsp.cr +++ b/src/lsp/lsp.cr @@ -176,7 +176,7 @@ fn lsp_check_file(path: string, src: string): g_source = src g_source_dir = dirname(path) reset_frontend_state() - tokenize(g_source) + tokenize(g_source, 0) res_imports() // res_imports 把主文件注册到 g_files[0] 时路径为空串——补上真实路径 // (供 publishDiagnostics 的 file_id → uri 映射;path 为稳定堆字符串)。 diff --git a/tools/v4_frontend_probe.py b/tools/v4_frontend_probe.py index 097c0b41..9fdc867a 100644 --- a/tools/v4_frontend_probe.py +++ b/tools/v4_frontend_probe.py @@ -26,11 +26,16 @@ 反向对照纪律(本仓既有):每条判据都要有一条「改坏一处 ⇒ 必红」的机械证据; `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')) @@ -43,6 +48,7 @@ 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 @@ -66,7 +72,8 @@ def check(cond, label, detail=''): # 触发场景:夹具列表被删空 / 抽取正则失配 ⇒ 判据跑了 0 条却「全绿」。 CHECK_FLOOR = { 'features': 25, 'layout': 8, 'colon': 17, 'structlit': 3, 'typenames': 7, - 'semi': 5, 'ast-freeze': 5, 'keywords': 5, 'mutations': 4, 'all': 60, + 'semi': 5, 'ast-freeze': 5, 'keywords': 5, 'mutations': 4, + 'positions': 48, 'all': 140, } @@ -768,6 +775,438 @@ def cmd_keywords(rev=None): 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(): @@ -821,6 +1260,8 @@ def main(argv): 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 From a567638f98555cbe5b469e54d62fb5591a306d61 Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 18:45:34 +0800 Subject: [PATCH 07/15] =?UTF-8?q?docs(TODO):=20=E7=99=BB=E8=AE=B0=20#2026-?= =?UTF-8?q?10-11-3=E2=80=94=E2=80=94`never=20=E2=8A=86=20X`=20=E5=9C=A8?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=BC=95=E6=93=8E=20`ty=5Fsub`=20=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=20-1=EF=BC=88ICE04=EF=BC=89=EF=BC=9B=E7=BB=84?= =?UTF-8?q?=E5=90=88=E5=B1=82=E4=B8=8E=E5=BC=95=E6=93=8E=E5=B1=82=E8=AE=A4?= =?UTF-8?q?=E5=AE=9A=E4=B8=8D=E4=B8=80=E8=87=B4=EF=BC=88v4=20T5=20?= =?UTF-8?q?=E6=96=BD=E5=B7=A5=E6=9C=9F=E5=AE=9E=E5=90=8D=EF=BC=8C=E6=9C=AC?= =?UTF-8?q?=E6=89=B9=E5=8F=AA=E5=9C=A8=E7=BB=84=E5=90=88=E5=B1=82=E5=85=91?= =?UTF-8?q?=E7=8E=B0=EF=BC=8C=E6=9C=AA=E7=A2=B0=20ty=5Fsub=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 判据:`python3 tests/harness/test_todo_id_migration.py` → 6/6 PASS。 --- TODO.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/TODO.md b/TODO.md index 71783faa..b1ea8fd5 100644 --- a/TODO.md +++ b/TODO.md @@ -187,6 +187,7 @@ | — | `#2026-09-22-2` | 2026-09-22 | 批 8 裁定二 S4 · `b8-e1` 实测 | ⚠【**预存缺陷 · 静默错值 · 本批修复**】`&S` / `&mut S` **形参形态**的 `r.v` 误编译:**根因 = REF 身份在 IR 形参定型处丢失**——`ir_gen.cr:3296` 取 `ast_type_val(pn)`,而 `&S` 节点(`EXPR_REFTYPE`)**`type_val = 0`** ⇒ 槽型退化成 `TI_INT`(`if param_type < 0` 护栏**拦不住 0**)⇒ `EXPR_FIELD` 看不到 REF ⇒ 静默错值(实测 `fn f(r: &S){r.v}` 得 **8** 而非 42;`--dump-params` 实证 `PARAM f p0 r slot=0 decl=0`,对照 `string` 参数 `slot=3` ✓)。**两代皆错**(pre/post 均 run=8)⇒ **存在早于裁定二、裁定二未触及形参面**。**修法有先例**:`ir_gen.cr:3305`(批 5 `dex?` 同形特判——某形态 `unpack_type` 返 0 ⇒ 槽型退化 ⇒ **按声明面节点另定槽型**),注释原文照引。**ABI 零影响(实测)**:`callseq.cr`/`frame.cr` 全部 **9 处**分类点皆为 `== TI_DEX ⇒ xmm 类,其余 ⇒ GP 类` 恒等式,而 **`TI_DEX = 1`**、**REF 行下标 ≥ 9** ⇒ **REF 天然落 GP** ⇒ 改槽型**不改 ABI 类**。**实现取「只查不建」**:checker 解析签名时已建过该 REF 行(实测类型表中存在 `kind 3`)⇒ 线性查找即可 ⇒ **零新增类型行**(⚠ `alloc_type` 是**裸分配器、不去重**,另分配会写进 TYPE 段)。**禁止事项**:在**无 ABI 判据**时凭「补一支特判」直接改槽型(会造出 `dex?` 那次的同形失配)。**与 `#2026-09-22-1` 互指,根因不同不合并**。 | | — | `#2026-09-24-1` | 2026-09-24 | v4 迁移差距分析 + 协调者实测 | 【**声明但不校验 / 有码但不 raise**】前端静默面清单(**5 处,均实测**):① **`EC_TF_MISSING_RET`(TF02, `ast.cr:404`) 零 raise 点**(全仓 1 命中)⇒ 缺 return 由 TF01「Function return type mismatch」拦住,**消息不指真实原因**(实测四档:空体 / 以 unit 调用收尾 / `if` 无 `else` / `loop` 里 `break` 出走 ⇒ **全 `check` rc=1 报 TF01,`build` rc=1 + 零产物**)——**非健全性漏洞,是诊断不精确**;② **`pub` 零读点**(`parser.cr:840` 声明 + `:875` 赋值,无读取点)⇒ 写了不生效且**不报错**;③ **match 臂的 `=>` 不校验**(`parser.cr:1115` 裸 `advance_tok()`)⇒ 分隔符写什么都收;④ **struct 字面量字段分隔符盲跳**(`parser.cr:552-554`,第二个 `advance_tok()` 返回值丢弃)⇒ `=` 与 `:` 两形都收(**已由 v4 迁移 T0 规格覆盖(T5 修),本条目不另立修法**);⑤ **类型位的 `.`/`auto` 全拒且消息错**(六档实测:形参 / 字段 / 枚举载荷 / 切片元素 / 返回位皆 rc=1,报 `expected type after '->'`,而那句是**返回型的模板**,形参位也报)。**本条目只登记,未修**(④ 除外,见上)。 | | — | `#2026-10-11-1` | 2026-10-11 | v4 迁移施工期 + 维护者口述 | 【**设计·未决**】v4 规约的战术「策略定义」语法(现形 `#tag`)待重设计——维护者裁定 `#` 族**只有使用面**(`#simp`/`#induct(x)` 都读作「在这里用一个战术」),而 `#tag` 是**唯一一个「用 `#` 声明新东西」的构造** ⇒ 范畴错误,**该删而非改名**;连带「策略体是竖排序列、而语义是**集合**」的形状说谎、以及可复用名被关在标签族里(不能 `import`/文档化/单测)。两个候选方向(维护者未拍):**不留** = §10.8 整节删、复用只走库(`import std::proof::arithmetic` 后 `#arithmetic`,名字解析走 import 作用域)+ `spec fn`;**留** = 必须长成一个**非 `#`** 的声明形。**本条目只登记,未改 `docs/core-language-syntax_v4.md` §10.8**。 | +| — | `#2026-10-11-3` | 2026-10-11 | v4 迁移 T5 施工期实测 | 【**未覆盖面 · 类型引擎**】`never ⊆ X` 在 `ty_sub` 里返回 **-1** ⇒ `error[ICE04] type judgment indeterminate: never vs named#21 (uncovered face)`(引擎 -1 ⇒ 硬错)。⇒ **组合层与引擎层对「`never` 作子类型」的认定不一致**:组合层(`type_compat_strict` / `_compat`)按 2026-10-11 裁定**收**(任一侧 never ⇒ 相容);引擎层(`type_terms.cr`/`type_engine.cr` 的 `ty_sub`)**判不出**。当前 `src/**` 零命中(`check src/compiler` / `corec2==corec3` / T1-T2 探针 146 条三绿即证),但属**潜在缺口**——任何绕过组合函数直接问引擎的路径(如 `ti_subsumes` 的 OPTIONAL 注入面、`type_equal_engine` 的采样面)对 `never` 仍可能得 -1。**本批只在组合层兑现语义,未碰 `ty_sub`**(那一层属 R2 类型项引擎本体,有自己的语义与判据网,须单开一笔)。 | | — | `#2026-10-11-2` | 2026-10-11 | v4 迁移 T4 施工期实测 | 【**既有缺陷 · 发射面**】块值 `if` 取不到值——`bootstrap/corec/frontend/ir_gen.py` 的 `gen_if` **无条件 `return None`**(函数体 `cond = gen_expr(...)` → 两支 `gen_expr` → 建 merge 块 → `return None`,从不把分支值物化到槽位)⇒ `x := if c: 1 else: 2` 运行期得 `None`。**与 v4 迁移无关**:同一片段走改前 parser 同样得 `None`。旁证(可运行的表达式位 region 载体):`t := unsafe:` + `7` + `return t` ⇒ 运行期 **7**(`gen_block` 尾值直通,`ir_gen.py:438-444`)。⇒ `docs/core-language-syntax_v4.md` §4.1 的 `total := if ready: …` 例子已降为**「设计态/未实现」**并注明根因;**未修**。 | ## 触发器约定(2026-09-18 立;存量扫描产出) @@ -2162,6 +2163,35 @@ fn f(x: int) -> int { loop { if x > 0 { break; } } } // loop 里 break 出走 **这条卡住的面**:`docs/core-language-syntax_v4.md` §10.8 的措辞、`docs/maintainer/design/spec-design.md:203` 的旧形(`#tag sorted = { … }`,与 §10.8 已经不一致,属同一面的两个形)。 +### 2026-10-11-3. 【未覆盖面 · 类型引擎】`never ⊆ X` 在 `ty_sub` 返回 -1 ⇒ ICE04;组合层与引擎层对「`never` 作子类型」的认定不一致(v4 迁移 T5 施工期实名;本批只在组合层兑现;取号基准 = 2) + +**怎么发现的**:v4 迁移 T5 施工期,`src/compiler/main.cr` 的 `is_decl_stmt` 有 2 条 `error[TC02]`(内层 if 链 = 赋值支 unit vs `return` 支 int)。裁定的修法是**补 `never` 语义**——以发散语句(`return`/`break`/`continue`)收尾的路径其类型 = `never`,且 `never` 与任何类型相容。 + +**修法的落点与它逼出的事实**:落点在**组合函数层**(`bootstrap/corec/frontend/type_checker.py` 的 `_compat`、`src/compiler/checker.cr` 的 `type_compat_strict`)—— 2 条 TC02 当即消解,语料一字未动。但**反向对照**(撤掉组合层那行相容)把引擎面照了出来: + +``` +error[ICE04]: type judgment indeterminate: never vs named#21 (uncovered face) + --> 0:0 +``` + +即 **`ty_sub(never, named)` 返回 -1(未覆盖)**,触发 ICE04 硬错(引擎 -1 ⇒ 硬错,`main.cr` 硬名单)。 + +**不一致的确切形状**: + +| 层 | 落点 | 对 `never ⊆ X` 的认定 | +|---|---|---| +| 组合函数层 | `type_compat_strict` / `_compat` | **收**(任一侧 `never` ⇒ 相容 = 1)——本批按裁定兑现 | +| 类型项引擎本体 | `type_terms.cr` / `type_engine.cr` 的 `ty_sub` | **判不出**(返回 **-1**) | + +⇒ **正向面**:`never` 参与的一切**组合函数**判定(分支合一 / 返回位 / 赋值位 / 实参位…)已按裁定放行。 +**残留面**:任何**绕过组合函数、直接问引擎**的路径(如 `ti_subsumes` 的 OPTIONAL 注入面、`type_equal_engine` 的采样面)对 `never` 仍可能得 -1。 + +**当前是否已踩到**:**否**。`src/**` 零命中——`./build/corec check src/compiler` **rc=0 零诊断**、`corec2 == corec3` IDENTICAL、T1/T2 探针 **146 条 ALL PASS** 三绿即证。⇒ 这是**潜在缺口,不是已覆盖面**。 + +**落点建议(供将来开笔时点名)**:`ty_sub` 的 `AK_NEVER` 分支加「`never ⊆ X` 恒真」。 +**判据形状建议**:锚 `ICE04` 的措辞 + 一条正控(`fn f() -> int: if c: return 1 else: x = 1` 必 rc=0)+ 一条反向(撤该分支 ⇒ `ICE04` 必回;本条目已给可复现读数)。 +**为什么本批不碰**:`ty_sub` 属 **R2 类型项引擎本体**,有自己的语义与判据网;顺手改它会把「引擎判定面」与「迁移面」混成一笔。**维护者 2026-10-11 裁定:另案。** + ### 2026-10-11-2. 【既有缺陷 · 发射面】块值 `if` 取不到值——`gen_if` 无条件 `return None`(v4 迁移 T4 施工期实测;**既有缺陷,与迁移无关**;取号基准 = 1) **现象**:`x := if c: 1 else: 2`(多行 layout 形)**能解析、能过检**,但**运行期得 `None`**。 From 5f24e202bff53a3751698470e7fea2c9d8549f0a Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 18:47:33 +0800 Subject: [PATCH 08/15] =?UTF-8?q?v4=20=E8=BF=81=E7=A7=BB=EF=BC=88=E6=89=B9?= =?UTF-8?q?=E5=86=85=C2=B7=E7=AC=AC=E5=9B=9B=E7=AC=94=E8=A1=A5=EF=BC=89?= =?UTF-8?q?=EF=BC=9Abootstrap=20=E4=B8=A4=E5=A4=84=E6=AC=A0=E8=B4=A6?= =?UTF-8?q?=E6=94=B6=E5=8F=A3=E2=80=94=E2=80=94`none`=20=E4=BD=9C=E5=80=BC?= =?UTF-8?q?=20+=20=E5=9F=BA=E6=9C=AC=E7=B1=BB=E5=9E=8B=20`T=3F`=20?= =?UTF-8?q?=E7=9A=84=E8=AF=AD=E6=B3=95=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 1. `none` 作值(T1/T2 面欠账) `parse_primary` 的 `T_NONE`/`T_SELF` 合成一格 ⇒ **拆开**:`T_NONE` 归一到 canonical 零载荷变体 `EnumConstructor(['None'], [])`(与自源同语义)。 `NameResolver` 内建表**不需要**补 `none` —— 归一路径根本不经过名字解析,且补一个 `Ident('none')` 反而会让节点缺 `__variant`、断掉 desugar 臂比较与 `ir_gen` 的 `MakeEnum` (**这是实施者对我的方案的一处正确更正**,我采纳)。 - 正:判据档原样源(`value := none` + `| none => 42`)⇒ resolver=[] · checker=[] · **运行 42**(与自源同值) - 反:把该格改回「当标识符」⇒ `Undefined name: none` + `Comparison not allowed` 齐回 ## 2. 基本类型 `T?` 的**语法面** 依据 = v4 文档 §3.2 原文(`value : int? = 5`)+ 两前端同语义。 `parse_type` 收尾结构重排:`never`/`dyn`(关键字令牌)· `base_types` · `unit` · `PathType`+泛型实参 **四族并入同一条 if/elif/else 链**,链后**唯一一个** `?` 处理点(四族共用)。 选「并入同一条尾部」而非「早退前再写一份 `?`」= 避免同一判定两份实现(T0 §2.3 明令)。 - **接受矩阵 10/10 与自源逐格一致**(`int?`/`dex?`/`bool?`/`string?`/`char?`/`unit?`/`never?`/`dyn?`/ `Self?`/`Foo?`)——**我独立复跑**。中途只改 `base_types` 一族时,矩阵暴露 `never?`/`dyn?` 两格残余 (它们是关键字令牌、走另一条早退)⇒ 一并并入同链,残余清零。**这条是被矩阵逼出来的,不是看出来的。** - 反:撤掉「`?` 唯一处理点」⇒ 四格全部复现原错 ## 3. ⚠ 本笔**未达成**的部分(另案,非本笔范围) 四格现在**解析全过**但**check 全不过**:bootstrap 的 `type_checker.py` 里 `OptionalType` **0 处命中** (`grep` 一命令可复现)⇒ bootstrap **完全没有 `T?` 的语义面**(无 `T ⊆ T?` 注入、无 `none : T?`、 无可选值 match 面)。那是把自源 R2 P3 Task 4 的可选表示机制(`TYP_NULL`/`TYP_OPTIONAL`/`g_optrep_on`/ `IR_MAKE_ENUM`/match 两分支面)搬到 Python —— **一笔独立的批**,不是「补几行」。 ⇒ 本笔只兑现**语法面**;语义面登记另案(见 TODO)。 ## 4. 实施者对我一处前提的更正(采纳) 我派活时写的「不修就卡 T6」**不成立**:T6 语料走**自源**编译器(`tests/suite/*.cr` 由 `./build/corec` 编译、`tests/selfhost/*.py` 驱动 `./build/corec`),只有 `tests/bootstrap/*.py` 驱动 Python 前端, 而该目录 `T?` 用量 **0**(实测 grep 空)。 ⇒ 本修的**有效依据是另两条**(都成立):① 两前端同语义(本批硬判据);② v4 文档 §3.2 的目标形。 ## 5. 复跑读数(我独立复核前三条) `tools/v4_frontend_probe.py` **146 条 ALL PASS** ✓ · `clean-cache` + `check src/compiler` **rc=0 零诊断** ✓ · 7 档 harness 机械门 **7/7 rc=0** ✓ · `T?` 形参位 10 格解析 **10/10** ✓。 ## 6. 顺带实名一条**既有缺陷**(代 0 同病,但**会卡 T6**) `enum E: V(int?)` **能编过但运行 rc=139(SIGSEGV)**;`/tmp/v3ws` 的代 0 编译器对 v3 形 `enum E { V(int?) }` **同样 139** ⇒ **非 T5 引入**。 ⇒ 但 `tests/suite/opt_dex_test.cr:20` 逐字 `enum EOpt { V(dex?) }` ⇒ **T6 会撞上**。另案登记(见 TODO)。 --- bootstrap/corec/frontend/parser.py | 57 ++++++++++++++++-------- bootstrap/corec/frontend/type_checker.py | 17 ++++--- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/bootstrap/corec/frontend/parser.py b/bootstrap/corec/frontend/parser.py index 878066a6..7bc61717 100644 --- a/bootstrap/corec/frontend/parser.py +++ b/bootstrap/corec/frontend/parser.py @@ -485,32 +485,46 @@ def parse_type(self): # v4:`never` / `dyn` 从「词素比对」**提升为关键字**(计划 §一.5 注 1 / §7.1 项 8) # ⇒ 必须在此显式收下,否则它们会掉进 `parse_path()` 的 `expect(IDENT)` 而响亮报错。 # 语义与自源原生名表一致(`checker.cr:1186` 的 8 个基类型名含 never/dyn ⇒ TY_NEVER / TI_DYN)。 - if self.check(TokenType.NEVER): - self.advance() - return BaseType('never') - if self.check(TokenType.DYN): - self.advance() - return BaseType('dyn') # v4:`Self` 不再进关键字表(计划 §一.5 的 `bootstrap − v4` 差集含 `Self`) # ⇒ 它以 IDENT 到达;保留「`&Self` 是原生名不是泛型形参」的既有行为 # (先例:`never` 今天也走这条 base_types 路径)。**若漏掉本格**, # `&Self` 会变成 `PathType(['Self'])`,而 type_checker 的 `_is_generic_type` # 把「单元素 PathType」当泛型形参 ⇒ 静默错判(不是报错)。 base_types = {'int','dex','bool','string','char','unit','never','Self'} - if self.check(TokenType.IDENT) and self.cur().lexeme in base_types: - return BaseType(self.advance().lexeme) - if self.check(TokenType.UNIT): + # ⚠ 基本类型**不早退**(2026-10-11 修;出处 = docs/core-language-syntax_v4.md §3.2 + # 的两行原文 `parent : User? = none` / `value : int? = 5`)。 + # 修前:本格直接 `return BaseType(...)`,而 `?` 的处理在函数**尾部**、只管 `PathType` + # ⇒ `int?` 落到「expected end of line, got '?'」(`Foo?` 却正常)——基本类型与路径类型 + # **两条不同的收尾路**,两前端在这一格分歧,且卡 T6 语料(`g : dex?, mut = None` / + # `struct SOpt { f: dex? }` / `enum EOpt { V(dex?) }` / `empty : int? = none`)。 + # **选「并入同一条尾部」而不是「在早退前再写一份 `?` 处理」**:后者 = 同一判定两份实现 + # (本仓 T0 §2.3 明令禁止的形态,必然漂);前者 `?` 处理**只有一处**,基本类型与路径类型 + # 共用,新增接受面恰好是 `T?`(含 `unit?`/`never?`——自源同收)。 + # `never`/`dyn` 是**关键字令牌**(上方 base_types 那格看不到它们)⇒ 同链并列一格。 + # 自源对 `never?`/`dyn?` 与 `int?` 同判(实测 `fn f(a: never?) -> int` ⇒ rc=0) + # ⇒ 本侧必须同收,否则留残余分歧。 + if self.check(TokenType.NEVER): self.advance() - return BaseType('unit') - typ = PathType(self.parse_path()) - if self.check(TokenType.LBRACK): + typ = BaseType('never') + elif self.check(TokenType.DYN): self.advance() - args = [self.parse_type()] - while self.check(TokenType.COMMA): + typ = BaseType('dyn') + elif self.check(TokenType.IDENT) and self.cur().lexeme in base_types: + typ = BaseType(self.advance().lexeme) + elif self.check(TokenType.UNIT): + self.advance() + typ = BaseType('unit') + else: + typ = PathType(self.parse_path()) + if self.check(TokenType.LBRACK): self.advance() - args.append(self.parse_type()) - self.expect(TokenType.RBRACK) - return GenericApplyType(typ.path, args) + args = [self.parse_type()] + while self.check(TokenType.COMMA): + self.advance() + args.append(self.parse_type()) + self.expect(TokenType.RBRACK) + typ = GenericApplyType(typ.path, args) + # `T?` 的唯一处理点(基本类型与路径类型同路) if self.check(TokenType.QUESTION): self.advance() return OptionalType(typ) @@ -682,7 +696,14 @@ def parse_primary(self) -> Expr: symbol = self.expect(TokenType.IDENT).lexeme return Ident(f"@{first}.{file_id}::{symbol}") return Builtin(first, []) - if self.check(TokenType.NONE) or self.check(TokenType.SELF): + if self.check(TokenType.NONE): + # v4(docs/core-language-syntax_v4.md §1.4/§59):`none` 是 `T?` 的**无值形态**关键字, + # canonical 变体名 = `None`。归一到 canonical 名(与自源 `parser.cr` 的 + # `T_NONE` → `EXPR_ENUM_CONSTRUCTOR(str_intern("None"))` **同语义**);零载荷。 + # ⚠ 拼写面归一必须在此**单点**完成:`None`(旧大写)已退役为普通标识符,两者不同判。 + self.advance() + return EnumConstructor(['None'], []) + if self.check(TokenType.SELF): return Ident(self.advance().lexeme) if self.check(TokenType.INT_LIT): return Literal(int(self.advance().lexeme), 'int') diff --git a/bootstrap/corec/frontend/type_checker.py b/bootstrap/corec/frontend/type_checker.py index 6ff628c0..22ec67ba 100644 --- a/bootstrap/corec/frontend/type_checker.py +++ b/bootstrap/corec/frontend/type_checker.py @@ -130,12 +130,17 @@ def _declare_builtins(self): opt = EnumDecl(True, 'Option', ['T'], [('Some', [PathType(['T'])]), ('None', [])]) self._declare_enum(opt) - # ⚠ v4 的 `none` 拼写**不在此注册**(曾经试过,已撤):本函数的符号表注册 - # **不可达** —— 裸 `none` 在表达式位会先被 `NameResolver` 以 `Undefined name` 拦下 - # (`name_resolver.py:98`,其内建表里没有 none/None)。半接线 = 「看着支持、其实永不生效」 - # 的空壳,比不接线更坏。⇒ 拼写面(`None`→`none`)是 **T5** 的重命名面; - # 今日现状(改前改后一致):裸 `none`/`None` 作**值**未实现,**响亮失败**。 - # 语料影响 = 0:`src/**` 的 74 处 `None` 全在注释/字符串里,无代码面裸 None。 + # v4 拼写面(`none`)**已接通**(2026-10-11,T5 收尾):本注册原先**不可达** + # —— 裸 `none` 在表达式位被 `parser.parse_primary` 归到一个 `Ident('none')`, + # 而 `NameResolver` 内建表里没有该名 ⇒ 以 `Undefined name` 拦下(旧注释的实况)。 + # 现改为在 parse_primary 的 `T_NONE` 格**归一到 canonical 变体** + # `EnumConstructor(['None'], [])` —— 与自源 `src/compiler/parser.cr` 的 + # `T_NONE → EXPR_ENUM_CONSTRUCTOR(str_intern("None"))` **同语义**; + # 该节点由**本函数的 Option 注册**解(`symtab.lookup('None')` 命中), + # 且 `__variant` 标签 = `None` ⇒ desugar 的臂比较与 ir_gen 的 MakeEnum 都成立。 + # ⇒ **不需要**另在内建表补一个 `none` 值名:`Ident('none')` 没有 `__variant` + # 字段,走那条路反而会打断 match 的 desugar 面。 + # 语料影响 = 0:`src/**` 无代码面裸 `none`/`None`(全在注释/字符串里)。 if not self.symtab.lookup('Result'): res = EnumDecl(True, 'Result', ['T', 'E'], [('Ok', [PathType(['T'])]), ('Err', [PathType(['E'])])]) From be7599662cdaecc6fe2e8e4d9d4d42c27f687649 Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 18:55:23 +0800 Subject: [PATCH 09/15] =?UTF-8?q?docs(TODO):=20=E7=99=BB=E8=AE=B0=20#2026-?= =?UTF-8?q?10-11-4=EF=BC=88bootstrap=20=E7=BC=BA=20T=3F=20=E8=AF=AD?= =?UTF-8?q?=E4=B9=89=E9=9D=A2=EF=BC=89+=20#2026-10-11-5=EF=BC=88=E5=B8=A6?= =?UTF-8?q?=E5=8F=AF=E9=80=89=E8=BD=BD=E8=8D=B7=E7=9A=84=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=E5=8F=98=E4=BD=93=E8=BF=90=E8=A1=8C=20SIGSEGV=EF=BC=8C?= =?UTF-8?q?=E4=BB=A3=200=20=E5=90=8C=E7=97=85=EF=BC=8C=E4=BC=9A=E5=8D=A1?= =?UTF-8?q?=20T6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两条均 v4 迁移 T5 施工期实名,**只登记未修**;迁移对照表两行旧号列写 `—`。 - **#2026-10-11-4**:`grep -rn OptionalType bootstrap/` ⇒ type_checker.py 零命中 ⇒ bootstrap 的 `T?` **语法面已通、语义面全缺** (无 `T ⊆ T?` 注入、无 `none : T?`、无可选值 match 面)⇒ 四格解析全过、check 全不过。修法 = 搬自源 R2 P3 Task 4 的可选表示机制。**当前不阻塞**(tests/bootstrap 与 src 的 T? 用量皆 0)。 - **#2026-10-11-5**:`enum E: V(int?)` build rc=0 但 **run rc=139**;代 0(`/tmp/v3ws` @ 920b1cbb)v3 形同样 139 ⇒ 既有缺陷。 **但会卡 T6**:`tests/suite/opt_dex_test.cr:20` 逐字 `enum EOpt { V(dex?) }`。 判据:`python3 tests/harness/test_todo_id_migration.py` → 6/6 PASS。 --- TODO.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/TODO.md b/TODO.md index b1ea8fd5..39d1b2d6 100644 --- a/TODO.md +++ b/TODO.md @@ -187,6 +187,8 @@ | — | `#2026-09-22-2` | 2026-09-22 | 批 8 裁定二 S4 · `b8-e1` 实测 | ⚠【**预存缺陷 · 静默错值 · 本批修复**】`&S` / `&mut S` **形参形态**的 `r.v` 误编译:**根因 = REF 身份在 IR 形参定型处丢失**——`ir_gen.cr:3296` 取 `ast_type_val(pn)`,而 `&S` 节点(`EXPR_REFTYPE`)**`type_val = 0`** ⇒ 槽型退化成 `TI_INT`(`if param_type < 0` 护栏**拦不住 0**)⇒ `EXPR_FIELD` 看不到 REF ⇒ 静默错值(实测 `fn f(r: &S){r.v}` 得 **8** 而非 42;`--dump-params` 实证 `PARAM f p0 r slot=0 decl=0`,对照 `string` 参数 `slot=3` ✓)。**两代皆错**(pre/post 均 run=8)⇒ **存在早于裁定二、裁定二未触及形参面**。**修法有先例**:`ir_gen.cr:3305`(批 5 `dex?` 同形特判——某形态 `unpack_type` 返 0 ⇒ 槽型退化 ⇒ **按声明面节点另定槽型**),注释原文照引。**ABI 零影响(实测)**:`callseq.cr`/`frame.cr` 全部 **9 处**分类点皆为 `== TI_DEX ⇒ xmm 类,其余 ⇒ GP 类` 恒等式,而 **`TI_DEX = 1`**、**REF 行下标 ≥ 9** ⇒ **REF 天然落 GP** ⇒ 改槽型**不改 ABI 类**。**实现取「只查不建」**:checker 解析签名时已建过该 REF 行(实测类型表中存在 `kind 3`)⇒ 线性查找即可 ⇒ **零新增类型行**(⚠ `alloc_type` 是**裸分配器、不去重**,另分配会写进 TYPE 段)。**禁止事项**:在**无 ABI 判据**时凭「补一支特判」直接改槽型(会造出 `dex?` 那次的同形失配)。**与 `#2026-09-22-1` 互指,根因不同不合并**。 | | — | `#2026-09-24-1` | 2026-09-24 | v4 迁移差距分析 + 协调者实测 | 【**声明但不校验 / 有码但不 raise**】前端静默面清单(**5 处,均实测**):① **`EC_TF_MISSING_RET`(TF02, `ast.cr:404`) 零 raise 点**(全仓 1 命中)⇒ 缺 return 由 TF01「Function return type mismatch」拦住,**消息不指真实原因**(实测四档:空体 / 以 unit 调用收尾 / `if` 无 `else` / `loop` 里 `break` 出走 ⇒ **全 `check` rc=1 报 TF01,`build` rc=1 + 零产物**)——**非健全性漏洞,是诊断不精确**;② **`pub` 零读点**(`parser.cr:840` 声明 + `:875` 赋值,无读取点)⇒ 写了不生效且**不报错**;③ **match 臂的 `=>` 不校验**(`parser.cr:1115` 裸 `advance_tok()`)⇒ 分隔符写什么都收;④ **struct 字面量字段分隔符盲跳**(`parser.cr:552-554`,第二个 `advance_tok()` 返回值丢弃)⇒ `=` 与 `:` 两形都收(**已由 v4 迁移 T0 规格覆盖(T5 修),本条目不另立修法**);⑤ **类型位的 `.`/`auto` 全拒且消息错**(六档实测:形参 / 字段 / 枚举载荷 / 切片元素 / 返回位皆 rc=1,报 `expected type after '->'`,而那句是**返回型的模板**,形参位也报)。**本条目只登记,未修**(④ 除外,见上)。 | | — | `#2026-10-11-1` | 2026-10-11 | v4 迁移施工期 + 维护者口述 | 【**设计·未决**】v4 规约的战术「策略定义」语法(现形 `#tag`)待重设计——维护者裁定 `#` 族**只有使用面**(`#simp`/`#induct(x)` 都读作「在这里用一个战术」),而 `#tag` 是**唯一一个「用 `#` 声明新东西」的构造** ⇒ 范畴错误,**该删而非改名**;连带「策略体是竖排序列、而语义是**集合**」的形状说谎、以及可复用名被关在标签族里(不能 `import`/文档化/单测)。两个候选方向(维护者未拍):**不留** = §10.8 整节删、复用只走库(`import std::proof::arithmetic` 后 `#arithmetic`,名字解析走 import 作用域)+ `spec fn`;**留** = 必须长成一个**非 `#`** 的声明形。**本条目只登记,未改 `docs/core-language-syntax_v4.md` §10.8**。 | +| — | `#2026-10-11-5` | 2026-10-11 | v4 迁移 T5 施工期实测 | 【**既有缺陷 · 运行期 SIGSEGV**(代 0 同病)】`enum E: V(int?)`(带可选载荷的枚举变体)**能编过但运行 rc=139**;代 0 编译器(`/tmp/v3ws`,revision `920b1cbb`)对 v3 形 `enum E { V(int?) }` **同样 139** ⇒ **非 v4 迁移引入**。★ **但会卡 T6**:`tests/suite/opt_dex_test.cr:20` 逐字 `enum EOpt { V(dex?) }`。(T5 侧另有 `struct SOpt { f: dex? }` / `g : dex?, mut = None` 等真实用法 ⇒ 该档是可选面的集中语料。) | +| — | `#2026-10-11-4` | 2026-10-11 | v4 迁移 T5 施工期实测 | 【**能力面缺口**】bootstrap(Python 前端)**完全没有 `T?` 的语义面**:`grep -rn 'OptionalType' bootstrap/` ⇒ 只有 `parser.py:527`(构造)与 `syntax/ast.py:13`(类定义),**`type_checker.py` 零命中**。⇒ `T?` 现在**语法面已通**(T5 施工期把四族并入同一条尾部、`?` 唯一处理点,接受矩阵 10/10 与自源逐格一致),但**语义面全缺**:无 `T ⊆ T?` 注入、无 `none : T?` 的类型、无可选值 match 面 ⇒ 四格(标注位/形参位/字段位/枚举载荷位)**解析全过、check 全不过**。修法 = 把自源 R2 P3 Task 4 的可选表示机制(`TYP_NULL`/`TYP_OPTIONAL`/`g_optrep_on`/`IR_MAKE_ENUM`/match 两分支面)搬到 Python —— **一笔独立的批**。**当前不阻塞**:`tests/bootstrap/**` 的 `T?` 用量 = 0,`src/**` 代码面 = 0。 | | — | `#2026-10-11-3` | 2026-10-11 | v4 迁移 T5 施工期实测 | 【**未覆盖面 · 类型引擎**】`never ⊆ X` 在 `ty_sub` 里返回 **-1** ⇒ `error[ICE04] type judgment indeterminate: never vs named#21 (uncovered face)`(引擎 -1 ⇒ 硬错)。⇒ **组合层与引擎层对「`never` 作子类型」的认定不一致**:组合层(`type_compat_strict` / `_compat`)按 2026-10-11 裁定**收**(任一侧 never ⇒ 相容);引擎层(`type_terms.cr`/`type_engine.cr` 的 `ty_sub`)**判不出**。当前 `src/**` 零命中(`check src/compiler` / `corec2==corec3` / T1-T2 探针 146 条三绿即证),但属**潜在缺口**——任何绕过组合函数直接问引擎的路径(如 `ti_subsumes` 的 OPTIONAL 注入面、`type_equal_engine` 的采样面)对 `never` 仍可能得 -1。**本批只在组合层兑现语义,未碰 `ty_sub`**(那一层属 R2 类型项引擎本体,有自己的语义与判据网,须单开一笔)。 | | — | `#2026-10-11-2` | 2026-10-11 | v4 迁移 T4 施工期实测 | 【**既有缺陷 · 发射面**】块值 `if` 取不到值——`bootstrap/corec/frontend/ir_gen.py` 的 `gen_if` **无条件 `return None`**(函数体 `cond = gen_expr(...)` → 两支 `gen_expr` → 建 merge 块 → `return None`,从不把分支值物化到槽位)⇒ `x := if c: 1 else: 2` 运行期得 `None`。**与 v4 迁移无关**:同一片段走改前 parser 同样得 `None`。旁证(可运行的表达式位 region 载体):`t := unsafe:` + `7` + `return t` ⇒ 运行期 **7**(`gen_block` 尾值直通,`ir_gen.py:438-444`)。⇒ `docs/core-language-syntax_v4.md` §4.1 的 `total := if ready: …` 例子已降为**「设计态/未实现」**并注明根因;**未修**。 | @@ -2163,6 +2165,48 @@ fn f(x: int) -> int { loop { if x > 0 { break; } } } // loop 里 break 出走 **这条卡住的面**:`docs/core-language-syntax_v4.md` §10.8 的措辞、`docs/maintainer/design/spec-design.md:203` 的旧形(`#tag sorted = { … }`,与 §10.8 已经不一致,属同一面的两个形)。 +### 2026-10-11-5. 【既有缺陷 · 运行期 SIGSEGV】带可选载荷的枚举变体 `enum E: V(int?)` 运行 rc=139(**代 0 同病**;★ 会卡 T6;取号基准 = 4) + +**现象**:`enum E: V(int?)` **能编过(build rc=0)但运行 rc=139(SIGSEGV)**。 + +**非 v4 迁移引入(对拍实证)**: +``` +自源(v4 形 enum E: V(int?)) build rc=0 → run rc=139 +代 0(v3 形 enum E { V(int?), N }) build rc=0 → run rc=139 ← /tmp/v3ws 的 920b1cbb 编译器 +``` +⇒ 两代同病,属**既有缺陷**。 + +**★ 但它会卡 T6**:`tests/suite/opt_dex_test.cr:20` 逐字 `enum EOpt { V(dex?) }`。该档同时含 +`g : dex?, mut = None`、`struct SOpt { f: dex? }` ⇒ 是**可选面的集中语料**,T6 迁移到它时必然撞上。 + +**与 `#2026-10-11-4` 的关系**:那条是 **bootstrap(Python 前端)**缺 `T?` 语义;本条是**自源/代 0 编译器**在 +「可选载荷的枚举变体」上的**运行期**缺陷。两者**不同层**(前端 vs 后端/IR),不合并。 + +### 2026-10-11-4. 【能力面缺口】bootstrap(Python 前端)完全没有 `T?` 的语义面(语法面已通、语义面全缺;取号基准 = 3) + +**怎么发现的**:v4 迁移 T5 施工期修「基本类型 `T?`」的**语法面**时(依据 = v4 文档 §3.2 原文 `value : int? = 5`), +四格(标注位 / 形参位 / 字段位 / 枚举载荷位)**解析全过了,但 check 全不过**。 + +**一命令可复现的根因**: +``` +grep -rn "OptionalType" bootstrap/ +→ bootstrap/corec/frontend/parser.py:527 (构造) +→ bootstrap/corec/syntax/ast.py:13 (类定义) +→ type_checker.py:0 处 ← 语义面全缺 +``` + +**缺的三件**(对照自源已有的 R2 P3 Task 4): +1. **`T ⊆ T?` 注入**(`x : int? = 5` 现在报 `declared type OptionalType(int) but initialized with BaseType(int)`); +2. **`none : T?` 的类型**(现在报 `… initialized with PathType(['Option'])`); +3. **可选值的 match 面**(两分支判定)。 + +**修法**:把自源的可选表示机制(`TYP_NULL`/`TYP_OPTIONAL`/`g_optrep_on`/`IR_MAKE_ENUM`/match 两分支面) +搬到 Python 侧 —— **一笔独立的批**,不是「补几行」。 + +**当前是否阻塞**:**否**。`tests/bootstrap/**` 的 `T?` 用量 = **0**(实测 grep 空);`src/**` 的 Core 代码面 = **0** +(57 条命中全在注释/字符串)。⇒ 属**能力面差距**,不影响本批任何判据。 +**为什么另案**:它与「v4 迁移」不是同一件事——迁移要的是**同语义**,而这条是**一整块尚未移植的能力**。 + ### 2026-10-11-3. 【未覆盖面 · 类型引擎】`never ⊆ X` 在 `ty_sub` 返回 -1 ⇒ ICE04;组合层与引擎层对「`never` 作子类型」的认定不一致(v4 迁移 T5 施工期实名;本批只在组合层兑现;取号基准 = 2) **怎么发现的**:v4 迁移 T5 施工期,`src/compiler/main.cr` 的 `is_decl_stmt` 有 2 条 `error[TC02]`(内层 if 链 = 赋值支 unit vs `return` 支 int)。裁定的修法是**补 `never` 语义**——以发散语句(`return`/`break`/`continue`)收尾的路径其类型 = `never`,且 `never` 与任何类型相容。 From 25e70197b17868776c72bcd04b50861b09157e99 Mon Sep 17 00:00:00 2001 From: DslsDZC Date: Sun, 11 Oct 2026 18:59:21 +0800 Subject: [PATCH 10/15] =?UTF-8?q?v4=20=E8=BF=81=E7=A7=BB=EF=BC=88=E6=89=B9?= =?UTF-8?q?=E5=86=85=C2=B7=E7=AC=AC=E4=BA=94=E7=AC=94=EF=BC=89=EF=BC=9AT5?= =?UTF-8?q?=20=E5=85=AD=E9=A1=B9=E6=94=B9=E5=AE=9E=E7=8E=B0=20+=20?= =?UTF-8?q?=E5=88=A4=E6=8D=AE=E9=9D=A2=E4=BF=AE=E5=A4=8D=EF=BC=88never/?= =?UTF-8?q?=E7=A9=BA=20region=20=E4=BA=A4=E6=B1=87=EF=BC=89+=20T6=20?= =?UTF-8?q?=E8=AF=AD=E6=96=99=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 一、T5:六项「文档 vs 实现」冲突,全部按「以文档为准 ⇒ 改实现」落地(两套前端同改) | # | 文档依据 | 内容 | |---|---|---| | ① | §10.1 | `#check`/`#ensure` 写在 **region 开头**(inline 保留为**兼容**,文档只写 region 头);含 `need_eol` 补漏(同行 `return` 被当第二条 region 项) | | ② | §13.5/13.6/13.7 | **顶层前导 `@`** 注解(白名单 `hotpatch`/`ffi`/`preferredDomain`/`executionDomain`);笔误响亮报错 | | ③ | §11.3/§13.7 | **`flow name(...)`** 文档形(`flow fn` 保留兼容;2×2 矩阵两格全绿) | | ④ | §13.7 第三例 | **语句前导位 `@`**(`@preferredDomain(gpu)` 在 `loop:` 前);白名单 = **文档释文 + 语料实证**(含 `NoBoundsCheck`/`fast`/`unroll`/`section`),口径已写进**两处代码注释**并注明「禁止后人按章号再收窄」 | | ⑤ | §1.6(新裁) | **region 可为空**(7 个 region 头位全覆盖);**运行时硬证**:空 `loop:` ⇒ 运行 rc=124(真死循环,`never` 语义不破);空函数体 ⇒ `TF01`(无尾值为真) | | ⑥ | §7.3 | **`=>` 后开 region**(多行臂体);`=>:` 收为兼容(文档无此形) | **反向对照累计 7 条**(flow 文档形 · `need_eol` · 语句位 `@` · `never` 相容 · 空 region · match 臂体 region · `=>:`),全部必红。 ## 二、判据面:`never` 裁定 × 空 region 规格化的交汇(**四方互斥,见下**) T5 用**六行实测表**证明:**硬门(`check src/compiler` rc=0 零诊断)与四方钉子在本设计空间内互斥**——没有一行同时满足。⇒ 裁决(维护者 2026-10-11「按 T5 的建议」): - **(a) 位置规则保持现状** ⇒ **`nail2` 让**(`if 1<2: 1 else: "s"` 的 v3 `;`-less 语义在 v4 不可表达;三条救援路分别要 86/102/270 条诊断且破 `-> never` 惯用形); - **(b) `return ⇒ never` 保留** ⇒ **`nail3` 让**,但**新增判定面**把它要回:`EXPR_RETURN` 处取**当前函数声明返回型**做 `type_compat_strict`(承载 = `g_cur_fn_ret_ti` 显式上下文)⇒ `test_tc02_branch` **13/15 → 14/15**(唯一剩红 = 已裁定让的 `nail2`); - **(c) `TI_ERROR` 独立哨兵**(把「真 `never`」与「错误恢复」分家;收窄到 `infer_expr` 侧,`res_type_node` 全族不动)⇒ `nail4` **部分**:`q1/q2/q3` 如预期,`ta1` **仍未回归**(见三); - **`nail1` 空-region 判别式**(`then_ti == TI_NEVER ∧ else 是零项 EXPR_BLOCK`)⇒ F1–F7 逐格如预期(含 **F2 反向钉**与 **F7 回归钉**),构造性不碰 `src/compiler`(谓词在那两处恒假)。 ## 三、悬空账(**如实留档,不许人动**) - **`nail4`「同一节点第二推断来源」**:判别探针(`d1`/`d2`)证实 `undef_x` 的 ti **有第二个来源**(`EXPR_IDENT` 的 `UNDEFINED→TI_ERROR` 未参与赋值位那条链);4 项已排除、3 条候选(`collect_decls` 预登记 / `ast_set_type_val` 回填 / `res_type_node` 族)**未验完 ⇒ 按裁定挂起**。 ⚠ **代价已被量出**:3 档 `tests/probes/` **负例探针被静默接受**(`n05_recursive` rc=1`{TS03}`→rc=0 · `n10_named_vs_int`/`n21_t_assign_int` rc=1`{TA01}`→rc=0),同文本跨三次二进制读数差证「必在二进制侧」;且 **`probes_run.sh` 不在任何 CI job 里**(只在 `src/ci/run.sh:129` 的注释中被提及)⇒ **无自动门看着**。 - **`-> int` 返回 `bool`(新判定面暴露的既有偏差)**:检查闭包内 **3 处**(`type_engine.cr::lit_implies`)+ 闭包外 **8 处**(`src/kernel/**`,`build_kernel.py` 只编译不 lint)= **11 处 / 3 档**。语义上 = 本编译器「`bool ⊆ int` 可隐式」的既有约定 ⇒ **待维护者裁**(认可 ⇒ 豁免转长期项且应写进语言面;不认可 ⇒ 11 处源该改)。**当前代码保持豁免,只限这一对**。 - **不带码 `add_error` 被带码诊断遮蔽**(`main.cr:133-137` 的次序:`g_diag_count > 0` 先命中 ⇒ `print_parse_errors()` 永不到达);正控已证机制(唯一诊断不带码时才打印)。 - **`corec run` 包裹壳的 `;`-切分启发式**(`main.cr:356-391`,7 段内嵌源)——设计缺口,非字符串迁移。 ## 四、T6 语料迁移(`.cr` 135 档 + 内联 Core 85 档 `.py` + 63 档 `.md`) - **`.cr`**:已迁 **125** / no-op **5** / 未迁 **5**(`legacy_asm_backend`×4 按计划 §十 #10「不迁」+ `t2_neg_unclosed` 工具中止)。 **B1/B2**(pre = `920b1cbb`×v3 文本 · post = 钉版 sha `0e23a78a…`×v4 文本):① 严格等价 **113** · ③ 真空集 9(**不当绿灯**)· ④ 其余 13(未迁 5 · 改善方向 1 · **负例失效 3** · 二进制侧新增级联 3 · 代际面变化 1)。 **`E4/E6` 撤回**(用改语料绕前端缺口 = 把缺陷藏进语料)⇒ 待 T5 实现到位后 `opt_dex_test`/`apx_conversion_test` **双双回到严格等价**——**裁定的正确性由结果证明**。 - **内联 Core**:`.py` 绿档 **2/85 → 61/85**、**由绿转红 0**;`.md` 63 档**注释记号 1607→1607、空行 5829→5829 逐数不变**,384 块 0 违规;`rebuild.sh:71` 冒烟改 v4 形(实测 rc=42,**`[4/4]` 在 `PINNED_REV` 换代前必红 = 已知窗口态**)。 **构建窗口闭环**:`purity_selftest.cr` 23 段迁后 `tests/selfhost/test_purity.py` **rc=1 → rc=0**(改前实证 `expected ':' to open a region, got ''`)。 - **过渡形登记**:`E2`(`#check` inline)9 档 + `E3`(`@hotpatch` 并入声明行)1 档 ⇒ **目标形 = 文档形**,**翻转时点 = T7 窗口**(一次重建后两形都收)。维护者已同意。 ## 五、其它 - `src/` 空 region 处置:**2 处回流**(`main.cr::read_source_file` · `module.cr::load_imports` —— T4 按旧政策整条删掉时**连带删掉一次内存读**,回流后消掉该「已知偏差」);**其余 10 处保留删除**(无副作用的空 `if`,删除等价且更干净)。**口径留档:判据 = 改动是否变了可观察行为。** - `src/compiler/checker.cr` 本笔含 `TI_ERROR` 27 处 + `nail1` 判别式(逐行带理由注释)。 ## 六、判据(我独立复核的那些) `check src/compiler` **rc=0 零诊断** · `corec2 == corec3` **IDENTICAL** · `tools/v4_frontend_probe.py` **146 条 ALL PASS** · 7 档 harness **7/7**。 --- DEBUG_REPORT.md | 33 +- README.md | 23 +- README.zh-CN.md | 23 +- TODO.md | 62 +- bootstrap/corec/frontend/parser.py | 214 ++++- docs/developer/at-intrinsics.md | 10 +- docs/developer/concepts/memory.md | 10 +- docs/developer/quickstart.md | 10 +- docs/developer/syntax.md | 150 ++-- docs/developer/tutorial.md | 61 +- docs/maintainer/design/dataflow-design.md | 54 +- .../design/execution-mapping-design.md | 24 +- docs/maintainer/design/execution-model.md | 46 +- docs/maintainer/design/pointer-model.md | 25 +- docs/maintainer/design/region-model.md | 5 +- docs/maintainer/design/spec-design.md | 64 +- docs/maintainer/design/v4-layout-spec.md | 6 +- docs/maintainer/proposals/comptime.md | 12 +- docs/maintainer/proposals/concurrency.md | 8 +- docs/maintainer/proposals/dynamic-typing.md | 30 +- docs/maintainer/proposals/ffi.md | 12 +- docs/maintainer/proposals/generics.md | 15 +- docs/maintainer/proposals/lazy.md | 17 +- docs/maintainer/proposals/probabilistic.md | 16 +- docs/project-book.md | 14 +- .../plans/2026-07-28-arena-model.md | 426 +++++---- .../plans/2026-07-28-at-intrinsics.md | 377 ++++---- docs/superpowers/plans/2026-07-29-hotpatch.md | 140 +-- .../plans/2026-07-29-incremental-cache.md | 35 +- .../plans/2026-07-30-concurrency.md | 344 ++++--- .../plans/2026-07-30-dynamic-typing.md | 161 ++-- docs/superpowers/plans/2026-07-30-ffi.md | 67 +- docs/superpowers/plans/2026-07-30-generics.md | 109 +-- .../superpowers/plans/2026-07-30-lazy-eval.md | 38 +- .../plans/2026-08-08-region-cfg.md | 149 ++-- .../plans/2026-08-15-mctt-core-kernel.md | 50 +- docs/superpowers/plans/2026-08-16-corelsp.md | 5 +- .../plans/2026-09-05-lattice-ir-v6.md | 80 +- ...026-09-10-language-surface-narrowing-r1.md | 122 ++- .../plans/2026-09-10-r2-p0-type-engine.md | 580 +++++++----- .../plans/2026-09-10-r2-p1-shadow-parity.md | 279 +++--- .../plans/2026-09-10-r2-p2-replace.md | 76 +- .../plans/2026-09-11-r2-p2b-iface-ops.md | 50 +- .../plans/2026-09-11-r2-p3-capabilities.md | 16 +- .../plans/2026-09-12-r2-p4-carrier.md | 15 +- .../plans/2026-09-13-r2-p5-cleanup.md | 6 +- .../plans/2026-09-16-agg-read-type.md | 130 +-- .../plans/2026-09-17-silence-closure.md | 30 +- .../plans/2026-09-17-spec-grammar.md | 16 +- docs/superpowers/plans/2026-09-18-b8-e1-t0.md | 32 +- .../2026-09-20-mapping-layer-separation.md | 29 +- .../2026-09-23-compile-cost-and-recheck.md | 10 +- .../specs/2026-07-28-arena-model-design.md | 104 ++- .../specs/2026-07-28-at-intrinsics-design.md | 2 +- .../specs/2026-07-29-hotpatch-design.md | 8 +- .../2026-07-29-incremental-cache-design.md | 79 +- .../specs/2026-07-30-concurrency-design.md | 25 +- .../specs/2026-07-30-dynamic-typing-design.md | 41 +- .../specs/2026-07-30-ffi-design.md | 41 +- .../specs/2026-07-30-generics-design.md | 36 +- .../specs/2026-07-30-lazy-eval-design.md | 9 +- .../2026-07-30-probabilistic-pass-design.md | 48 +- ...026-08-13-graph-anchored-regions-design.md | 5 +- .../2026-09-17-silence-closure-t0-report.md | 11 +- examples/add/main.cr | 10 +- examples/complex/main.cr | 58 +- examples/test_max.cr | 11 +- examples/test_scale.cr | 23 +- examples/test_sum.cr | 16 +- examples/test_sumto.cr | 22 +- src/compiler/ast.cr | 9 + src/compiler/checker.cr | 128 ++- src/compiler/main.cr | 5 +- src/compiler/module.cr | 4 +- src/compiler/parser.cr | 326 +++++-- src/compiler/purity_selftest.cr | 46 +- tests/bootstrap/test_apx_tag.py | 52 +- tests/bootstrap/test_borrow.py | 40 +- tests/bootstrap/test_dex_arith.py | 125 +-- tests/bootstrap/test_dex_type.py | 17 +- tests/bootstrap/test_generics.py | 31 +- tests/bootstrap/test_modules.py | 4 +- tests/bootstrap/test_pipeline.py | 270 +++--- tests/fixtures/dex_ffi_test.cr | 7 +- tests/fixtures/so_index/use_ext.cr | 7 +- tests/hit/smoke_add.cr | 9 +- tests/hit/smoke_mem.cr | 13 +- tests/probes/n02_diff_named.cr | 17 +- tests/probes/n03_apply_twice.cr | 13 +- tests/probes/n04_apply_diff_args.cr | 13 +- tests/probes/n05_recursive.cr | 14 +- tests/probes/n09_t_vs_int.cr | 12 +- tests/probes/n10_named_vs_int.cr | 14 +- tests/probes/n12_alias.cr | 13 +- tests/probes/n13_arr_diff_named.cr | 17 +- tests/probes/n14_optional_diff_named.cr | 17 +- tests/probes/n15_apply_named_arg.cr | 20 +- tests/probes/n16_nested_apply.cr | 10 +- tests/probes/n17_ptr_named.cr | 13 +- tests/probes/n18_tuple_named.cr | 17 +- tests/probes/n19_ref_named.cr | 24 +- tests/probes/n20_apply_named_vs_int.cr | 13 +- tests/probes/n21_t_assign_int.cr | 10 +- tests/probes/n22_named_struct_field.cr | 17 +- tests/probes/n23_enum_named.cr | 17 +- tests/probes/p_annots.cr | 18 +- tests/probes/p_annots2.cr | 14 +- tests/probes/p_dex.cr | 13 +- tests/probes/p_dyn.cr | 14 +- tests/probes/p_enum.cr | 11 +- tests/probes/p_ffi.cr | 9 +- tests/probes/p_ffi2.cr | 9 +- tests/probes/p_go.cr | 12 +- tests/probes/p_i2f.cr | 12 +- tests/probes/p_opt.cr | 11 +- tests/probes/p_spawn.cr | 10 +- tests/probes/warm/alloc_witness.cr | 9 +- tests/probes/warm/plain.cr | 7 +- tests/probes/warm/tk01_oob_load.cr | 9 +- tests/probes/warm/tk01_oob_store.cr | 11 +- tests/probes/warm/tk01_width.cr | 11 +- tests/probes/warm/tu03_load.cr | 7 +- tests/probes/warm/tu03_store.cr | 9 +- tests/selfhost/test_agg_checks.py | 214 ++--- tests/selfhost/test_agg_read_type.py | 130 +-- tests/selfhost/test_agg_slots.py | 147 ++- tests/selfhost/test_apx_conversion.py | 287 +++--- tests/selfhost/test_apx_tag.py | 28 +- tests/selfhost/test_apx_tag_scope.py | 23 +- tests/selfhost/test_arg_inference_gap.py | 194 ++-- tests/selfhost/test_at_rename.py | 16 +- tests/selfhost/test_backend_bootstrap.py | 2 +- tests/selfhost/test_borrow.py | 55 +- tests/selfhost/test_cache_identity.py | 35 +- tests/selfhost/test_ccr_types.py | 83 +- tests/selfhost/test_ccr_v7.py | 120 +-- tests/selfhost/test_chan_handle_model.py | 9 +- tests/selfhost/test_cir_cache_narrow.py | 6 +- tests/selfhost/test_cir_str_domain_warm.py | 119 +-- tests/selfhost/test_cir_warm_path.py | 97 +- tests/selfhost/test_dex_arith.py | 104 +-- tests/selfhost/test_dex_type.py | 23 +- tests/selfhost/test_diag_gate.py | 39 +- tests/selfhost/test_directory_build.py | 11 +- tests/selfhost/test_enum_limit.py | 61 +- tests/selfhost/test_extern_opt.py | 22 +- tests/selfhost/test_generic_constr.py | 165 ++-- tests/selfhost/test_generic_param_erasure.py | 101 ++- tests/selfhost/test_global_init.py | 30 +- tests/selfhost/test_global_seams.py | 132 ++- tests/selfhost/test_hit_table.py | 71 +- tests/selfhost/test_iface_ops.py | 184 ++-- tests/selfhost/test_iface_satisfies.py | 291 ++++-- tests/selfhost/test_impl.py | 88 +- tests/selfhost/test_impl_iface.py | 377 +++++--- tests/selfhost/test_interp_float.py | 34 +- tests/selfhost/test_interp_parity.py | 64 +- tests/selfhost/test_let_check.py | 72 +- tests/selfhost/test_lexer_parity.py | 2 +- tests/selfhost/test_live_ranges.py | 126 +-- tests/selfhost/test_lsp.py | 33 +- tests/selfhost/test_match_exhaust.py | 53 +- tests/selfhost/test_mw_task1.py | 14 +- tests/selfhost/test_mw_task2.py | 25 +- tests/selfhost/test_mw_task3.py | 41 +- tests/selfhost/test_mw_task4.py | 149 +--- tests/selfhost/test_mw_task5.py | 26 +- tests/selfhost/test_mw_task6.py | 76 +- tests/selfhost/test_named_face.py | 88 +- tests/selfhost/test_native_float.py | 66 +- tests/selfhost/test_native_memory.py | 71 +- tests/selfhost/test_native_strings.py | 54 +- tests/selfhost/test_nested_fn.py | 93 +- tests/selfhost/test_opt_dex.py | 448 ++++++---- tests/selfhost/test_opt_eq.py | 102 ++- tests/selfhost/test_optional.py | 844 ++++++++++++++---- tests/selfhost/test_params_limit.py | 8 +- tests/selfhost/test_pointer_safety.py | 110 +-- tests/selfhost/test_raw_int_ptr.py | 20 +- tests/selfhost/test_region_cfg.py | 70 +- tests/selfhost/test_region_escape.py | 201 +---- tests/selfhost/test_s1p_liveness.py | 94 +- tests/selfhost/test_s1p_sentinel_skips.py | 52 +- tests/selfhost/test_slice_bounds.py | 84 +- tests/selfhost/test_string_interp.py | 29 +- tests/selfhost/test_tc02_branch.py | 43 +- tests/selfhost/test_tf01_fallthrough.py | 135 ++- tests/selfhost/test_toplevel_reject.py | 24 +- tests/selfhost/test_topt_pattern.py | 101 ++- tests/selfhost/test_tuple_slots.py | 168 ++-- tests/selfhost/test_view_builtins.py | 88 +- tests/selfhost/test_xcut_iface.py | 101 +-- tests/spec/delta_d0_annot.cr | 14 +- tests/spec/delta_d0_plain.cr | 14 +- tests/spec/delta_d9_annot.cr | 6 +- tests/spec/delta_d9_plain.cr | 6 +- tests/spec/t2_neg_after.cr | 7 +- tests/spec/t2_neg_before.cr | 6 +- tests/spec/t2_neg_collide.cr | 9 +- tests/spec/t2_neg_constfalse.cr | 6 +- tests/spec/t2_neg_empty.cr | 6 +- tests/spec/t2_neg_inbody.cr | 6 +- tests/spec/t2_neg_nolparen.cr | 6 +- tests/spec/t2_neg_nonident.cr | 6 +- tests/spec/t2_neg_stmt.cr | 13 +- tests/spec/t2_neg_unknowntag.cr | 6 +- tests/spec/t2_pos_check.cr | 10 +- tests/spec/t2_pos_dup.cr | 6 +- tests/spec/t2_pos_multi.cr | 12 +- tests/spec/t2_pos_plain.cr | 8 +- tests/spec/t3_neg_call_banned.cr | 9 +- tests/spec/t3_neg_domain.cr | 6 +- tests/spec/t3_neg_dup_false.cr | 11 +- tests/spec/t3_neg_ensure_false.cr | 6 +- tests/spec/t3_neg_ensure_nonbool.cr | 6 +- tests/spec/t3_neg_nonbool.cr | 6 +- tests/spec/t3_neg_result_shadow.cr | 6 +- tests/spec/t3_pos_both.cr | 11 +- tests/spec/t3_pos_check_param.cr | 10 +- tests/spec/t3_pos_ensure_result.cr | 10 +- tests/spec/t3_pos_ensure_true.cr | 10 +- tests/spec/t4_three_states.cr | 12 +- tests/spec/t4_xtalk.cr | 21 +- tests/spec/t4_yellow_only.cr | 10 +- tests/suite/apx_conversion_test.cr | 117 ++- tests/suite/arena_test.cr | 141 +-- tests/suite/at_test.cr | 142 +-- tests/suite/at_test_mini.cr | 23 +- tests/suite/at_test_mini2.cr | 39 +- tests/suite/at_test_mini3.cr | 58 +- tests/suite/at_test_mini4.cr | 26 +- tests/suite/at_test_mini5.cr | 26 +- tests/suite/at_test_mini6.cr | 26 +- tests/suite/at_test_mini7.cr | 20 +- tests/suite/at_test_mini8.cr | 23 +- tests/suite/at_test_mini9.cr | 26 +- tests/suite/at_test_struct.cr | 85 +- tests/suite/cache_test.cr | 21 +- tests/suite/chan_test.cr | 31 +- tests/suite/cli_view_test.cr | 26 +- tests/suite/conc_test.cr | 129 +-- tests/suite/dex_test.cr | 152 +++- tests/suite/dyn_test.cr | 68 +- tests/suite/ffi_test.cr | 13 +- tests/suite/fnaddr_test.cr | 16 +- tests/suite/generics_test.cr | 139 ++- tests/suite/global_seam_test.cr | 40 +- tests/suite/go_e2e_test.cr | 21 +- tests/suite/go_final_test.cr | 23 +- tests/suite/go_parallel_test.cr | 34 +- tests/suite/go_test.cr | 21 +- tests/suite/hotpatch_test.cr | 96 +- tests/suite/lazy_test.cr | 29 +- tests/suite/opt_dex_test.cr | 287 +++--- tests/suite/params_many.cr | 145 +-- tests/suite/ptr_arith.cr | 21 +- tests/suite/ptr_ref_first.cr | 14 +- tests/suite/syscall4_test.cr | 29 +- tests/test_flow.cr | 22 +- tests/test_go.cr | 14 +- tests/test_go_range.cr | 16 +- tools/baseline/rebuild.sh | 9 +- .../cir-str-domain/probes/label_collision.cr | 153 ++-- tools/cir-str-domain/probes/repro_6line.cr | 30 +- tools/cir-str-domain/probes/scope_concat.cr | 15 +- tools/cir-str-domain/probes/scope_fields.cr | 27 +- .../probes/scope_firstintern.cr | 17 +- tools/cir-str-domain/probes/scope_interp.cr | 17 +- tools/cir-str-domain/probes/scope_lit.cr | 16 +- tools/cir-str-domain/probes/scope_partial.cr | 11 +- tools/cir-str-domain/probes/scope_typeinfo.cr | 21 +- tools/cir-str-domain/probes/undefined_name.cr | 18 +- tools/v4_migrate.py | 211 ++++- tools/v4_migrate_inline.py | 702 +++++++++++++++ 274 files changed, 9779 insertions(+), 7406 deletions(-) create mode 100644 tools/v4_migrate_inline.py diff --git a/DEBUG_REPORT.md b/DEBUG_REPORT.md index 8d7f2189..23431192 100644 --- a/DEBUG_REPORT.md +++ b/DEBUG_REPORT.md @@ -93,12 +93,11 @@ **空函数 `tokenize` 验证:** ```core -fn tokenize() { - g_token_count = 0; - g_pos = 0; - add_token(T_EOF); - return; -} +fn tokenize(): + g_token_count = 0 + g_pos = 0 + add_token(T_EOF) + return ``` 将 `tokenize` 替换为空函数后,`corec2` **完全正常工作**——`tokenize` → `parse` → `check` → `IRgen` 全部通过,exit 0。确认问题仅在 `tokenize` 循环体内。 @@ -179,9 +178,9 @@ read-back 确认均写入正确值,然后 return 同时在 `corearch_main` 中 `elf_gen` 返回后、`syscall3(write)` 前再加标记: ```core -sz := elf_gen(g_elf_buf); -w32(g_elf_buf, 74717, 0xCAFEBABE); // 标记 3 -syscall3(1, fd, g_elf_buf, sz); +sz := elf_gen(g_elf_buf) +w32(g_elf_buf, 74717, 0xCAFEBABE) // 标记 3 +syscall3(1, fd, g_elf_buf, sz) ``` **最终二进制文件中的值:** @@ -214,21 +213,19 @@ syscall3(1, fd, g_elf_buf, sz); ```core // emit_instr (instr.cr:299) -fn emit_instr(instr_idx, buf, pos) { - cp := 0; +fn emit_instr(instr_idx, buf, pos): + cp := 0 ... - if op == IR_LOAD && d >= 0 { - w64(g_x86_rip_patch_pos, ..., pos + cp + 3); // <= ppos 在这里注册 - cp = cp + e2_lr(buf, pos+cp, 0); // <= LEA 在这里发射 + if op == IR_LOAD && d >= 0: + w64(g_x86_rip_patch_pos, ..., pos + cp + 3) // <= ppos 在这里注册 + cp = cp + e2_lr(buf, pos+cp, 0) // <= LEA 在这里发射 ... - } -} ``` 调用方(elf.cr:545): ```core -sz := emit_instr(inst_idx, buf, cp); // pos = cp (当前 buffer 位置) -cp = cp + sz; +sz := emit_instr(inst_idx, buf, cp) // pos = cp (当前 buffer 位置) +cp = cp + sz ``` **可能的原因:** diff --git a/README.md b/README.md index e04e2d1e..2a688d14 100644 --- a/README.md +++ b/README.md @@ -17,19 +17,16 @@ is represented as relations first, state/storage is mapped separately, and machi representation comes last. ```core -import io; - -fn fib(n: int) -> int { - if n < 2 { - return n; - } - return fib(n - 1) + fib(n - 2); -} - -fn main() -> int { - io.println_i(fib(10)); // 55 - return 0; -} +import io + +fn fib(n: int) -> int: + if n < 2: + return n + return fib(n - 1) + fib(n - 2) + +fn main() -> int: + io.println_i(fib(10)) // 55 + return 0 ``` Core is under active development. diff --git a/README.zh-CN.md b/README.zh-CN.md index 82b11e7b..bbb1e389 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -15,19 +15,16 @@ Core 的编译模型围绕 **graph → lattice → encoding** 组织:计算先 状态/存储单独映射,机器表示最后落地。 ```core -import io; - -fn fib(n: int) -> int { - if n < 2 { - return n; - } - return fib(n - 1) + fib(n - 2); -} - -fn main() -> int { - io.println_i(fib(10)); // 55 - return 0; -} +import io + +fn fib(n: int) -> int: + if n < 2: + return n + return fib(n - 1) + fib(n - 2) + +fn main() -> int: + io.println_i(fib(10)) // 55 + return 0 ``` Core 仍在积极开发中。 diff --git a/TODO.md b/TODO.md index 39d1b2d6..930399f8 100644 --- a/TODO.md +++ b/TODO.md @@ -1239,10 +1239,16 @@ - **现象(实测;批 5 终态构建 `build/corec`,只读分诊 12 探针之一)**:`g[T](t: T, x: T?)` 以 `T = dex` 实例化、实参为 **apx** 源时 ⇒ `check` rc=0 · `build` rc=0 · **ELF rc=142 / interp rc=15**(**期望 7/7**;`scaled` 实参对照 = **7/7**)⇒ **静默错值 + ELF≠interp(双路径分歧)**,与 `TODO #2026-09-16-29` 原始 RED(u11)**同严重级**;缺陷是 **apx 源特有**(与主族同形)。 - **最小复现(<10 行,可直接入探针)**: ```core - 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); } // 期望 7;实测 ELF 142 / interp 15 + 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) + // 期望 7;实测 ELF 142 / interp 15 ``` - **机理(`file:line`,读码)**:**调用侧环按「泛型声明」取形参型、callee 槽按「实例」取型** ⇒ 说法不一致: - 调用侧:`ir_gen.cr:1965` `cfi := find_func(func_ni)` → `fi_ast_node`(= **泛型声明**节点);转换门在 `:1985`(`dex_opt_type_node(ast_data(cpn))`)——而泛型声明的形参类型节点是 `T?`(inner = 泛型参数 `T` ⇒ 判据**假**)⇒ **实参不转换**(bits 原样传递); @@ -1262,8 +1268,18 @@ - **现象(实测)**:`n : int? = 7; if n == Some(7) { return 1; }` ⇒ **ELF rc=0**(未命中);`n : int? = None; if n == None { return 1; }` ⇒ **ELF rc=0**(**连 `None == None` 都不命中**);`n : int? = Some(7); if n == Some(7) {…}` ⇒ **ELF 0**。⇒ **`==` 对可选值恒假**(ELF 与 interp 同判 ⇒ 非双路径分歧,是**一致地错**)。 - **最小复现(两条,各 <5 行)**: ```core - fn main() -> int { n : int? = 7; if n == Some(7) { return 1; } return 0; } // 期望 1;实测 0 - fn main() -> int { n : int? = None; if n == None { return 1; } return 0; } // 期望 1;实测 0 + fn main() -> int: + n : int? = 7 + if n == Some(7): + return 1 + return 0 + // 期望 1;实测 0 + fn main() -> int: + n : int? = none + if n == none: + return 1 + return 0 + // 期望 1;实测 0 ``` - **机理**:**未定位**(本条目只登记,不做根因定位)。观测事实 = 可选值的 `==` 在「值与 `Some(...)`」「值与 `None`」两种形态下**均不成立**;未排除与可选表示(rep/装箱面)或 `EXPR_ENUM_CONSTRUCTOR` 比较路径相关——**勿据本条推断根因**。 - **判定**:**S(通用静默)**;作用面 = **所有可选(`int?` / `dex?` / 任意 `T?`)**,且 `if x == None` 是最自然写法 ⇒ 危害面**大于** `dex?` 专属面(分诊结论:本条比 `#2026-09-17-5` 更严重)。 @@ -1276,8 +1292,11 @@ - **现象(实测)**:`extern fn e_opt(x: dex?) -> int;` ⇒ **`check` rc=0(零诊断)**、`build` rc=0;运行期 **139**(未解析符号);对照 `extern fn e_int(x: int?) -> int;` ⇒ **同形同判**(check=0 / ELF 139)⇒ **非 dex 特有**。 - **最小复现(<5 行)**: ```core - extern fn e_opt(x: dex?) -> int; - fn main() -> int { d : dex, apx = 7.0; return e_opt(d); } // check=0(应拒未拒);运行期 139 + extern fn e_opt(x: dex?) -> int + fn main() -> int: + d : dex, apx = 7.0 + return e_opt(d) + // check=0(应拒未拒);运行期 139 ``` - **机理**:**未定位**(只登记)。可确认面 = 「`extern` 声明的形参类型不做可适用性校验」(C ABI **无可选表示**);`W4` 环对 extern 侧**显式不扩**(`ir_gen.cr:1985` 的 `cfn_ext == 0` 守卫)⇒ 即使要支持也无约定 —— 属**语义层面不应存在**的形态。 - **判定**:**L(运行期响亮 139)**,但**编译期零诊断 = fail-closed 缺口**(「不诊断」本身是洞;建议收敛为编译期硬错)。 @@ -1679,8 +1698,13 @@ - **最小复现(6 行、确定性、零依赖)**: ```core import io - struct Point { x: int, y: int } - fn main() -> int { f := @fields(Point); println(f); println(int_str(str_len(f))); return 0; } + struct Point: + x: int, y: int + fn main() -> int: + f := @fields(Point) + println(f) + println(int_str(str_len(f))) + return 0 ``` ```bash ./build/corec clean-cache @@ -2130,10 +2154,20 @@ **① 的实测四档**(`nice -n 19 ./build/corec check`;对照腿 = 正常带 `return` 的函数 rc=0): ```core -fn f(x: int) -> int {} // 空体 -fn f(x: int) -> int { g(x); } // 以 unit 调用收尾 -fn f(x: int) -> int { if x > 0 { return 1; } } // if 无 else,分支缺 return -fn f(x: int) -> int { loop { if x > 0 { break; } } } // loop 里 break 出走 +fn f(x: int) -> int: +// 空体 +fn f(x: int) -> int: + g(x) +// 以 unit 调用收尾 +fn f(x: int) -> int: + if x > 0: + return 1 +// if 无 else,分支缺 return +fn f(x: int) -> int: + loop: + if x > 0: + break +// loop 里 break 出走 ``` 四档皆 `check` rc=1,报的是 **TF01「Function return type mismatch」**;`build` rc=1 **+ 零产物**(门有效)。**注意报的不是 TF02** —— 那正是本条要登记的:TF02 有码、无人 raise。 diff --git a/bootstrap/corec/frontend/parser.py b/bootstrap/corec/frontend/parser.py index 7bc61717..2dc48150 100644 --- a/bootstrap/corec/frontend/parser.py +++ b/bootstrap/corec/frontend/parser.py @@ -128,15 +128,24 @@ def _end_decl(self): self._consume_newlines() def _expect_region(self): - """吃 region 头:`COLON_BLOCK` 行尾冒号 + 其后的 NEWLINE + `INDENT`。 + """吃 region 头:`COLON_BLOCK` 行尾冒号 + 其后的 NEWLINE + (可选)`INDENT`。 + 返回 True = 吃到 `INDENT`(region 有 items);**False = 空 region**(无 INDENT、无 items)。 token 次序由 lexer 的 `_layout_break` 决定:NEWLINE 先于 INDENT/DEDENT。 **行内 `:`(`COLON_DECL`)在此被响亮拒绝** —— 这正是 T0 布局规格 §2.2 要的 「行尾类型标注不是合法文本」的兜住点。 + + v4 裁定(2026-10-11,**推翻** T0 布局规格 §10.2 的「空 region 无法表达 + 逐处改写」): + **region 可以为空**。用途实证(T6b 报来、维护者采纳):`loop { }`(**永不返回**,与 + `loop:` + 裸 `return` **不等价**)与 `interface Empty { }`(**零方法接口**,合法且有意义) + 在「逐处改写」下无等价形。**只放宽零项这一格**:非零项 region 的缩进规则一个字不动。 """ self.expect(TokenType.COLON_BLOCK) self._consume_newlines() - self.expect(TokenType.INDENT) + if self.check(TokenType.INDENT): + self.advance() + return True + return False def _check_seq(self, types): """Check if the next tokens match the given type sequence.""" @@ -303,7 +312,47 @@ def parse_path(self): return parts # ─── 顶层声明 ─── + # v4 文档 §13:**声明前导** `@` 注解的白名单(§13 全量扫描的结果)。 + # §13.5 `@ffi("…")` → `extern fn`;§13.6 `@hotpatch(ver=N)` → `fn`; + # §13.7 `@preferredDomain(name)` → `fn`、`@executionDomain(name)` → `flow`。 + # 其余 `@` 名(§13.2 的 `@inline`/`@unroll`/`@section`/`@comptime`/`@fast`、 + # §13.3 `@addr`、§13.4 `@NoBoundsCheck`、§13.1 的查询族)在文档里**只作表达式/语句位** + # 出现(语料同:`tests/suite/at_test.cr:46` 的 `@NoBoundsCheck` 是 region 内语句, + # 走 parse_stmt→parse_expr)⇒ **不入白名单**(在声明前导位出现即响亮报错)。 + _LEAD_AT_NAMES = ('hotpatch', 'ffi', 'preferredDomain', 'executionDomain') + + def _skip_leading_at_annotations(self): + """消费顶层声明的**前导 `@` 注解链**(一至多条,各自独占一行;v4 §13 的声明前导形)。 + + **语义面 = 接受并跳过**:bootstrap 侧没有 hotpatch 版本表 / FFI 语言槽 / 执行域数据面 + (自源侧的 `@hotpatch` 版本进 `EXPR_FN` 的 iv 槽、`@ffi` 进 `ffi_lang_ni`)⇒ 本侧只保证 + 「能词法化、不报错、不影响产物」,与既有 `_skip_spec_annotations` 同口径。 + **不知名名字**与**未闭合括号**一律响亮报错 —— 「放宽 = 吞错」是静默面 + (`@hotpach(ver=1)` 的笔误若不报,注解就被静默丢弃)。 + """ + while self.check(TokenType.AT): + self.advance() # '@' + if not self.check(TokenType.IDENT): + self.error("expected annotation name after '@'") + name = self.advance().lexeme + if name not in self._LEAD_AT_NAMES: + self.error(f"Unknown top-level '@{name}' annotation (expected '@hotpatch' / " + f"'@ffi' / '@preferredDomain' / '@executionDomain')") + if self.check(TokenType.LPAREN): + depth = 1 + self.advance() + while depth > 0: + if self.check(TokenType.EOF): + self.error("unterminated '@' annotation: missing ')'") + if self.check(TokenType.LPAREN): + depth += 1 + elif self.check(TokenType.RPAREN): + depth -= 1 + self.advance() + self._consume_newlines() # 注解之间可换行(文档形) + def parse_top_level_decl(self): + self._skip_leading_at_annotations() is_pub = False if self.check(TokenType.PUB): is_pub = True @@ -330,6 +379,14 @@ def parse_top_level_decl(self): def parse_function_decl(self, is_pub, is_flow=False): if not is_flow: self.expect(TokenType.FN) + elif self.check(TokenType.FN): + # v4 文档形(2026-10-11 裁:文档是目标语法 ⇒ 改实现): + # `docs/core-language-syntax_v4.md:1232` `flow counter(start: int) -> int:`、 + # `:1406` `flow encode(input: Frame) -> Packet:` —— **无 `fn`**。 + # 本侧原先**只**认文档形;此处补收旧形 `flow fn name(...)` 为**兼容** + # (语料 `src/compiler/purity_selftest.cr:231` 用它;文档不写它、不为它新增用例)。 + # ⇒ 改后与自源**同收两形**(自源原先只认 `flow fn`,同批补齐文档形)。 + self.advance() name = self.expect(TokenType.IDENT).lexeme generics = self._parse_generics() self.expect(TokenType.LPAREN) @@ -342,7 +399,7 @@ def parse_function_decl(self, is_pub, is_flow=False): ret = BaseType('unit') # 批 6(裁-S7,bounded):规约标注链 `#check(...)` / `#ensure(...)`——**接受并跳过**。 # 位置与 self-hosted 侧一一对应(签名之后、body 之前);**零语义**。 - self._skip_spec_annotations() + self._skip_spec_annotations() # inline 形(兼容):注解后紧跟 `:`,不要求行尾 if self.check(TokenType.EQ): self.advance() body = self._want_value_expr() # `fn f() = expr` 的值 = 表达式位(规则 ②) @@ -355,12 +412,21 @@ def parse_function_decl(self, is_pub, is_flow=False): # 规则 ①:函数体 region **恒为语句位**(§7.4「函数没有 implicit tail return」)⇒ # 末项裸表达式包 ExprStmt,块类型 unit ⇒ 返回值只经显式 `return`。 self.want_value = False - body = self.parse_block() + # v4 文档 §10.1(**文档形**):规约注解位于函数 layout region 的**开头**(statements 之前) + # ⇒ 此处自己吃 region 头,先收 `#check`/`#ensure`,再进 statements。 + # inline 形(签名与 `:` 之间,见上方 `_skip_spec_annotations()` 的第 1 个调用点) + # **保留为兼容**:不在文档里,但 `tests/spec` 的干净档有工具产出。 + if not self._expect_region(): + # 空函数体(§10.2 裁定推翻后合法):零项 ⇒ 值 = 无值(块类型 unit)。 + body = Block([], None) + else: + self._skip_spec_annotations(need_eol=True) # 文档形:注解独占一行 + body = self.parse_block_items() if is_flow: body = Flow(body) return FunctionDecl(is_pub, name, generics, params, ret, body) - def _skip_spec_annotations(self): + def _skip_spec_annotations(self, need_eol=False): """批 6(裁-S7,bounded):消费 `#` IDENT `(` … `)` 标注链并**丢弃**(零语义)。 边界(维护者裁定):bootstrap 侧**只**保证「能词法化、不报错、不影响产物」—— @@ -368,11 +434,22 @@ def _skip_spec_annotations(self): 消费 = 平衡括号扫描(不解析表达式)⇒ 对内部形态(含 `result` 等 bootstrap 关键字) 一律容忍;形状错(缺 IDENT/缺括号/未闭合)**响亮报错**(fail-loud,不静默)。 """ + # 循环**末尾**的 `_consume_newlines()` 让注解链跨行成立(文档形 §10.1:每条独占一行)。 + # ⚠ 只跳「注解之间」,**不跳第一条之前** —— 首条之前若有 NEWLINE(无体声明的收尾), + # 在循环头吞掉它会让调用点的 `_at_line_end()` 误判「非行边界」(回归面)。 while self.check(TokenType.HASH): self.advance() # '#' if not self.check(TokenType.IDENT): self.error("expected annotation name after '#'") - self.advance() # check / ensure + an_name = self.advance().lexeme # check / ensure + # 名字白名单与自源同判(自源 = `parse_spec_annotations` 的 kind 分派 ⇒ 非此二者 + # 一律 EC_V_BAD_TAG/V02)。**这不是新增限制**:文档 §10.1 只给 `#check`/`#ensure` + # 两形;而「放宽 = 吞错」是静默面(`#foo(1)` 这类误写若不报,注解被静默丢弃)。 + # 语料实核:`src/**`+`tests/**` 的真代码里 `#` 注解**只有** check/ensure + # (`#include`/`#tag`/`#x` 全在注释、C 文件或 python f-string 内;唯一例外 + # `tests/spec/t2_neg_unknowntag.cr` 本就是**负例**,期望报错)。 + if an_name not in ('check', 'ensure'): + self.error(f"Unknown annotation '#{an_name}' (expected '#check' or '#ensure')") self.expect(TokenType.LPAREN) depth = 1 while depth > 0: @@ -383,6 +460,13 @@ def _skip_spec_annotations(self): elif self.check(TokenType.RPAREN): depth -= 1 self.advance() + # 文档形:注解必须**独占一行**(v4 行语义 = 一条语句一行)⇒ + # `#check(1 > 0) return 1` 同行是**非法文本**(负例档 + # `tests/spec/t2_neg_inbody.cr` 逐字如此,必须 rc=1)。 + # inline 形那侧(need_eol=False)注解后紧跟 `:` ⇒ 不能要行尾。 + if need_eol and not self._at_line_end(): + self.error(f"Expected end of line after '#{an_name}' annotation") + self._consume_newlines() # 注解之间可换行(文档形,见上方注) def _parse_generics(self): if self.check(TokenType.LBRACK): @@ -810,7 +894,17 @@ def parse_primary(self) -> Expr: self.error(f"Unexpected token: {self.cur().lexeme}") def parse_block(self) -> Block: - """v4 region:吃 `INDENT` … `DEDENT`(取代原 `{` … `}`)。 + """region 头 + 体(**所有** region 的通用入口)。空 region ⇒ `Block([], None)`。""" + if not self._expect_region(): + want = self.want_value + self.want_value = want + return Block([], None) # 空 region:零 items、无 DEDENT 可吃 + return self.parse_block_items() + + def parse_block_items(self) -> Block: + """体(**region 头已吃掉**)。拆出本函数只为「函数体 region 的**开头若干项** = + 规约注解」(v4 文档 §10.1,见 `parse_function_decl` 的调用点)——那里必须在 + statements 之前先把 `#check`/`#ensure` 收干净(`parse_block` 那条通用路做不到)。 尾表达式判定(T0 布局规格 §6.2 A1):**region 的最后一项 = 该 region 的值**, 其余各项按语句处理 —— 即原 `parse_block` 的「暂定尾表达式」逻辑原样保留, @@ -820,7 +914,6 @@ def parse_block(self) -> Block: # 由**进入时**的标志决定;体内嵌套 region 一律先复位为语句位,退出时恢复。 want = self.want_value self.want_value = False - self._expect_region() stmts = [] expr = None while True: @@ -878,10 +971,56 @@ def _is_block_like(expr: Expr) -> bool: """ return isinstance(expr, (If, Match, Loop, For, Unsafe, Flow)) + # 语句前导位 `@` 注解的白名单(与自源 `parser.cr::is_stmt_at_annotation` **逐名一致**)。 + # 实证清单 = 文档或语料在**语句/region 前导位**实际出现过的名字: + # §13.7 `preferredDomain` / `executionDomain`、§13.4 `NoBoundsCheck`、 + # §13.2 `fast` / `unroll` / `section`。 + # **不收** §13.1 查询族 / §13.3 `addr` / §13.2 `inline`(文档里都在**表达式位**)。 + # ⚠ **判据 = 「文档释文 + 语料实证」,不是「章号范围」**(维护者 2026-10-11 采纳; + # 与自源 `parser.cr::is_stmt_at_annotation` 同口径)。二者冲突时**以后者为准**: + # `NoBoundsCheck`(§13.4) / `fast`·`unroll`·`section`(§13.2) 章号属 §13.1–13.4, + # 但释文与语料都在**语句前导位**用它们 ⇒ 收。**禁止**后人按章号再收窄回去。 + _STMT_AT_NAMES = ('preferredDomain', 'executionDomain', 'NoBoundsCheck', + 'fast', 'unroll', 'section') + + def _skip_stmt_at_annotations(self): + """消费语句前导位的 `@` 注解链(各占一行)。**语义面 = 接受并跳过** + (bootstrap 侧无执行域/安全检查数据面,与顶层前导 `@` 同口径)。 + + **未知名不在此列** ⇒ 仍按表达式解析 ⇒ 由既有路径响亮拒绝(不静默)。 + 注解**独占一行**:违反即 `self.error`(响亮)。 + """ + while self.check(TokenType.AT): + nxt = self.tokens[self.pos + 1] if self.pos + 1 < len(self.tokens) else None + if nxt is None or nxt.type != TokenType.IDENT: + break + if nxt.lexeme not in self._STMT_AT_NAMES: + break + name = nxt.lexeme + self.advance() # '@' + self.advance() # 名字 + if self.check(TokenType.LPAREN): + depth = 1 + self.advance() + while depth > 0: + if self.check(TokenType.EOF): + self.error("unterminated '@' annotation: missing ')'") + if self.check(TokenType.LPAREN): + depth += 1 + elif self.check(TokenType.RPAREN): + depth -= 1 + self.advance() + if not self._at_line_end(): + self.error(f"Expected end of line after '@{name}' annotation") + self._consume_newlines() + def parse_stmt(self): # 语句位入口(规则 ①):本语句整体在语句位 ⇒ 先复位;语句内的表达式位由各入口重 # 置 True(声明的右值 / return 值 / 实参 / 括号 / 索引 …)。 self.want_value = False + # v4 §13.7 第三例 / §13.4:**语句前导位**的 `@` 注解(`@preferredDomain(gpu)` 前导 `loop:`)。 + # 必须在此消费,否则 `@` 落进表达式路(自源侧实测会被 checker 当未知名内建报 N01)。 + self._skip_stmt_at_annotations() if self.check(TokenType.IDENT) and self._is_var_decl_start(): names, tags, typ, values = self._parse_var_decl_names_tags_type() self._end_decl() @@ -932,9 +1071,11 @@ def parse_match_expr(self): want = self.want_value self.expect(TokenType.MATCH) expr = self._want_value_expr() - self._expect_region() + has_items = self._expect_region() # False = 空 region(§10.2 裁定推翻后合法) arms = [] while True: + if not has_items: + break self._consume_newlines() if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): break @@ -953,11 +1094,34 @@ def parse_match_expr(self): self.advance() pat = self.parse_pattern() self.expect(TokenType.FAT_ARROW) # 使用 => - body = self._want_value_expr() + # v4 文档 §7.3(逐字):「需要多行 arm body 时,`=>` 后换行并进入更深 layout」 + # ⇒ `=>` 后**行尾** ⟺ 臂体是一个 layout region;否则单表达式。 + # ⚠ 该 region **没有 `:`**(`=>` 已充当开启符)⇒ 不能走 `_expect_region`。 + # **兼容形 `=>:`**(`=>` 后紧跟 `:`):文档 §7.3 没有这一形(那里是 `=>` 后直接换行), + # 但 T6 语料机械改写成了它 ⇒ 按本批先例(`flow fn` 兼容形)收为兼容,与文档形同判。 + # 「臂体是 region」的判据必须在**消费 `:` 之前**定下 —— 消费后再问 `_at_line_end()` + # 会因为站在 INDENT 上而误判成「非行边界」(实测踩过)。 + is_region = False + if self.check(TokenType.COLON_BLOCK): + is_region = True + self.advance() + elif self._at_line_end(): + is_region = True + if is_region: + self._consume_newlines() + if self.check(TokenType.INDENT): + self.advance() + self.want_value = True # 臂体 = 表达式位 ⇒ region 保尾值 + body = self.parse_block_items() + else: + body = Block([], None) # 空 region(形态 D) + else: + body = self._want_value_expr() arms.append(MatchArm(pat, body)) if self.check(TokenType.COMMA): self.advance() - self.expect(TokenType.DEDENT) + if has_items: + self.expect(TokenType.DEDENT) self.want_value = want return Match(expr, arms) def parse_pattern(self) -> Pattern: @@ -1063,9 +1227,11 @@ def parse_struct_decl(self, is_pub): self.expect(TokenType.STRUCT) name = self.expect(TokenType.IDENT).lexeme generics = self._parse_generics() - self._expect_region() + has_items = self._expect_region() # False = 空 region(§10.2 裁定推翻后合法) fields = [] while True: + if not has_items: + break self._consume_newlines() if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): break @@ -1094,16 +1260,19 @@ def parse_struct_decl(self, is_pub): fields.append((fname, ftype)) if self.check(TokenType.COMMA): self.advance() - self.expect(TokenType.DEDENT) + if has_items: + self.expect(TokenType.DEDENT) return StructDecl(is_pub, name, generics, fields) def parse_enum_decl(self, is_pub): self.expect(TokenType.ENUM) name = self.expect(TokenType.IDENT).lexeme generics = self._parse_generics() - self._expect_region() + has_items = self._expect_region() # False = 空 region(§10.2 裁定推翻后合法) variants = [] while True: + if not has_items: + break self._consume_newlines() if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): break @@ -1125,16 +1294,19 @@ def parse_enum_decl(self, is_pub): variants.append((vname, types)) if self.check(TokenType.COMMA): self.advance() - self.expect(TokenType.DEDENT) + if has_items: + self.expect(TokenType.DEDENT) return EnumDecl(is_pub, name, generics, variants) def parse_interface_decl(self, is_pub): self.expect(TokenType.INTERFACE) name = self.expect(TokenType.IDENT).lexeme generics = self._parse_generics() - self._expect_region() + has_items = self._expect_region() # False = 空 region ⇒ **零方法接口**(合法且有意义) methods = [] while True: + if not has_items: + break self._consume_newlines() if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): break @@ -1150,7 +1322,8 @@ def parse_interface_decl(self, is_pub): # 三元组里加一个 body 槽 ⇒ 动 `ast.py` ⇒ 违 J-T1-1 冻结。此处**响亮报错**(不静默吞体)。 self._end_decl() methods.append((mname, params, ret)) - self.expect(TokenType.DEDENT) + if has_items: + self.expect(TokenType.DEDENT) return InterfaceDecl(is_pub, name, generics, methods) def parse_impl_decl(self): @@ -1162,14 +1335,17 @@ def parse_impl_decl(self): self.advance() trait = for_type for_type = self.parse_path() - self._expect_region() + has_items = self._expect_region() # False = 空 region methods = [] while True: + if not has_items: + break self._consume_newlines() if self.check(TokenType.DEDENT) or self.check(TokenType.EOF): break methods.append(self.parse_function_decl(False)) - self.expect(TokenType.DEDENT) + if has_items: + self.expect(TokenType.DEDENT) return ImplDecl(generics, trait, for_type, methods) def parse_type_alias(self): diff --git a/docs/developer/at-intrinsics.md b/docs/developer/at-intrinsics.md index 0a200bed..52e01a15 100644 --- a/docs/developer/at-intrinsics.md +++ b/docs/developer/at-intrinsics.md @@ -26,12 +26,10 @@ 示例——无运行时反射的序列化: ```core -fn serialize(buf: &[u8], obj: any) { - for name in @fields(typeof(obj)) { - val := @field(typeof(obj), name).get(obj); - write_field(buf, name, val); - } -} +fn serialize(buf: &[u8], obj: any): + for name in @fields(typeof(obj)): + val := @field(typeof(obj), name).get(obj) + write_field(buf, name, val) // 编译期展开,不涉及运行时反射调用 ``` diff --git a/docs/developer/concepts/memory.md b/docs/developer/concepts/memory.md index 99ba21e9..b9719866 100644 --- a/docs/developer/concepts/memory.md +++ b/docs/developer/concepts/memory.md @@ -15,13 +15,13 @@ Core 的内存管理与 Rust 不同路:Rust 用类型层的借用规则(需 - 子图结束 → 区域整体重置回收,O(1),无 GC 停顿 ```core -fn process_batch(items: [int]) -> int { +fn process_batch(items: [int]) -> int: // 本函数内的临时数据都活在函数区域 // 函数返回 → 整块回收,无需 free - total := 0; - for x in items { total = total + x; } - return total; -} + total := 0 + for x in items: + total = total + x + return total ``` `go` 启动的并发子图各有独立区域,退出整块回收。 diff --git a/docs/developer/quickstart.md b/docs/developer/quickstart.md index ce7976b5..b404b14c 100644 --- a/docs/developer/quickstart.md +++ b/docs/developer/quickstart.md @@ -21,12 +21,10 @@ python3 build_selfhost_native.py `examples/add/main.cr` 是最小完整程序: ```core -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) ``` `main` 的返回值 = 进程退出码(因此该程序「运行成功」 = 退出码 7)。 diff --git a/docs/developer/syntax.md b/docs/developer/syntax.md index 8f888841..f78b319f 100644 --- a/docs/developer/syntax.md +++ b/docs/developer/syntax.md @@ -108,9 +108,9 @@ auto fileid move self in None Some unit 默认使用文件名(不含 `.cr`)作为标识符,可在文件头部覆盖: ```core -fileid "my_helper"; +fileid "my_helper" -fn greet(name: string) -> string = "hi " + name; +fn greet(name: string) -> string = "hi " + name ``` 同一项目内标识符必须唯一,重复报错。 @@ -126,10 +126,10 @@ mod examples::pi; ### 3.3 导入 ```core -import math; // 同一项目的文件(文件标识符) -import math : m; // 重命名,之后用 m.符号 -import @acme math; // 外部项目 acme 中的 math 文件 -import @acme math : m; // 并重命名 +import math // 同一项目的文件(文件标识符) +import math : m // 重命名,之后用 m.符号 +import @acme math // 外部项目 acme 中的 math 文件 +import @acme math : m // 并重命名 ``` `@项目名` 前缀区分本地符号与外部项目符号,不可省略。项目名在项目根的 `Core.toml` 中声明(`name = "acme"`)。 @@ -137,9 +137,9 @@ import @acme math : m; // 并重命名 ### 3.4 符号访问 ```core -import math : m; +import math : m -result := m.add(3, 5); // 点号访问导入符号 +result := m.add(3, 5) // 点号访问导入符号 ``` 未导入时可用完整路径 `math::add(3, 5)` 直接访问(不推荐)。 @@ -150,16 +150,15 @@ result := m.add(3, 5); // 点号访问导入符号 ```core // _import.cr -import @acme math : m; -import @std io; +import @acme math : m +import @std io ``` ```core // main.cr——无需重复 import -fn main() { - result := m.add(3, 5); - io.println("result = {result}"); -} +fn main(): + result := m.add(3, 5) + io.println("result = {result}") ``` `_import.cr` 本身不生成代码,只起导入声明作用。 @@ -214,9 +213,9 @@ mutr : &mut Point; // 可变引用 变量与字段可带标签,`mut`(可变)/ `pub`(公开)/ `apx`(近似授权): ```core -count : int, mut = 0; // 可变 -pub_val : int, pub = 42; // 公开字段 -speed : dex, apx = 3.14; // apx:授权后端把 dex 运算降级为 binary64 快路径 +count : int, mut = 0 // 可变 +pub_val : int, pub = 42 // 公开字段 +speed : dex, apx = 3.14 // apx:授权后端把 dex 运算降级为 binary64 快路径 ``` `apx` 与 `mut` / `pub` 同族。不带 `apx` 时 `dex` 恒精确。 @@ -232,10 +231,10 @@ speed : dex, apx = 3.14; // apx:授权后端把 dex 运算降级为 binary6 类型推断占位,两者完全等价,可用于变量声明与返回类型: ```core -x : auto = 42; // 推断为 int -y : . = 3.14; // 推断为 dex -z : ., mut = 20; -a, b, c : auto, mut = 0; +x : auto = 42 // 推断为 int +y : . = 3.14 // 推断为 dex +z : ., mut = 20 +a, b, c : auto, mut = 0 ``` `auto` 更显式、`.` 更简洁——注意 `: ., mut` 模式中 `.` 是类型占位。 @@ -247,18 +246,18 @@ a, b, c : auto, mut = 0; 无 `let` 关键字。声明即语句,`:=` 推断类型(不可变),`: Type =` 显式类型: ```core -x := 42; // 推断为 int,不可变 -name : string = "Core"; // 显式类型 -count : int, mut = 0; // 显式 + 可变 -shared : auto, pub, mut = 42; // 全局公开可变 -a, b : int = 1, 2; // 批量声明 +x := 42 // 推断为 int,不可变 +name : string = "Core" // 显式类型 +count : int, mut = 0 // 显式 + 可变 +shared : auto, pub, mut = 42 // 全局公开可变 +a, b : int = 1, 2 // 批量声明 ``` `move` 显式移动所有权(默认借用语义,见第 1 章设计要点——无生命周期标注,引用有效性编译器全权推断): ```core -b := move a; // a 的所有权转移到 b,a 失效 -consume(move b); // 参数移动传入 +b := move a // a 的所有权转移到 b,a 失效 +consume(move b) // 参数移动传入 ``` 复制类型(`int`、`dex`、`bool` 等实现 Copy 接口的类型)赋值时自动复制,不需 `move`。 @@ -309,17 +308,17 @@ category := if x > 0 { "positive"; } else { "not positive"; }; ### 6.3 调用、字段与下标 ```core -result := m.add(3, 5); // 函数调用 -p.x; // 字段访问 -arr[0]; // 下标 +result := m.add(3, 5) // 函数调用 +p.x // 字段访问 +arr[0] // 下标 ``` ### 6.4 转换 `as` ```core -x : int = 3; -d : dex = x as dex; // 显式转换 -ptr : RawRef = addr as RawRef; +x : int = 3 +d : dex = x as dex // 显式转换 +ptr : RawRef = addr as RawRef ``` ### 6.5 错误传播 `?` @@ -327,10 +326,9 @@ ptr : RawRef = addr as RawRef; `?` 后缀:表达式失败时立即从当前函数返回错误,只能用于返回可传播错误类型(如 `Result`)的函数中: ```core -fn fetch() -> Result { - data := read_file("config.txt")?; // 出错则立刻返回 Err +fn fetch() -> Result: + data := read_file("config.txt")? // 出错则立刻返回 Err Ok(data) -} ``` ### 6.6 @ 内建调用 @@ -338,7 +336,7 @@ fn fetch() -> Result { `@` 开头是编译器内建原语(见第 13 章): ```core -n := @sizeOf(Point); +n := @sizeOf(Point) ``` --- @@ -406,9 +404,8 @@ match cmd { ### 7.4 返回 ```core -fn add(a: int, b: int) -> int { - return a + b; // 显式返回 -} +fn add(a: int, b: int) -> int: + return a + b // 显式返回 ``` ### 7.5 不安全块 @@ -429,11 +426,10 @@ unsafe { ### 8.1 函数定义 ```core -fn add(a: int, b: int) -> int { - return a + b; -} +fn add(a: int, b: int) -> int: + return a + b -fn pi() -> auto = 3.14159; // 单行形式;返回类型推断 +fn pi() -> auto = 3.14159 // 单行形式;返回类型推断 ``` `FunctionDecl = [ 'pub' ] 'fn' IDENT [ GenericParams ] '(' [ ParamList ] ')' '->' Type ( FunctionBody | '=' Expr ';' )`。参数 `Param = IDENT ':' Type`;末位参数可变参:`...name: Type`(收集剩余实参,见 stdlib variadic)。返回类型可以是 `auto`(或 `.`),由函数体推导。 @@ -443,16 +439,13 @@ fn pi() -> auto = 3.14159; // 单行形式;返回类型推断 `impl` 为类型挂接方法,接收者 `self` 是第一个参数: ```core -impl Point { - fn norm(&self) -> dex { +impl Point: + fn norm(&self) -> dex: (self.x * self.x + self.y * self.y).sqrt() - } - fn move_by(&mut self, dx: dex, dy: dex) { - self.x += dx; - self.y += dy; - } -} + fn move_by(&mut self, dx: dex, dy: dex): + self.x += dx + self.y += dy ``` 接收者形式:`self`(按值)/ `&self`(借用)/ `&mut self`(可变借用)。 @@ -466,15 +459,12 @@ impl Point { ### 9.1 接口声明与实现 ```core -interface Eq { - fn eq(&self, other: &Self) -> bool; -} +interface Eq: + fn eq(&self, other: &Self) -> bool -impl Eq for Point { - fn eq(&self, other: &Self) -> bool { +impl Eq for Point: + fn eq(&self, other: &Self) -> bool: self.x == other.x && self.y == other.y - } -} ``` 接口签名中的 `Self` 指实现类型本身。基础类型(`int` / `dex` / `string` 等)对标准接口(`Eq`、`Copy`、`Hash` 等)内建实现。 @@ -484,12 +474,10 @@ impl Eq for Point { 泛型参数 `[T]` 声明,接口绑定 `[T: Eq]` 约束 T 必须实现该接口: ```core -fn first[T: Eq](list: &[T]) -> T? { - if list.len() > 0 { - return Some(list[0]); - } - None -} +fn first[T: Eq](list: &[T]) -> T?: + if list.len() > 0: + return Some(list[0]) + none ``` 实例化时检查类型参数满足接口绑定,**编译期具体化**——无运行期字典。 @@ -509,15 +497,10 @@ type Point3 = (dex, dex, dex); ### 10.1 #check / #ensure ```core -fn divide(a: int, b: int) -> int? - #check(b != 0) - #ensure(result.is_some() implies (a / b) == result.unwrap()) -{ - if b == 0 { - return None; - } - return Some(a / b); -} +fn divide(a: int, b: int) -> int? #check(b != 0) #ensure(result.is_some() implies (a / b) == result.unwrap()): + if b == 0: + return none + return Some(a / b) ``` - `#check(...)` —— 调用方必须满足的前提条件 @@ -529,9 +512,8 @@ fn divide(a: int, b: int) -> int? `where` 实现内联轻量前置条件(行内形态,与 #check 同层;定稿形态以 spec-design 为准): ```core -fn sqrt(x: dex) -> dex where x >= 0 { +fn sqrt(x: dex) -> dex where x >= 0: // ... -} ``` 值约束按表达式形态分三档语义(编译期求值 / 生成验证义务 / 运行时检查): @@ -551,19 +533,19 @@ fn sqrt(x: dex) -> dex where x >= 0 { ### 11.1 异步启动 `go` ```core -handle := go some_work(arg1, arg2); // handle: Flow +handle := go some_work(arg1, arg2) // handle: Flow ``` ### 11.2 等待 `await` ```core -result := await handle; // 阻塞直到完成 +result := await handle // 阻塞直到完成 ``` 按需自动等待——当值被需要时自动等待: ```core -val := go fetch(url) + go fetch(other); // 两个 flow 自动等待 +val := go fetch(url) + go fetch(other) // 两个 flow 自动等待 ``` ### 11.3 长期执行流 `flow` / `yield` / `recv` @@ -593,10 +575,10 @@ for i in 0..5 { 指针是裸地址,与 C 同级自由,编译器通过格/图自动验证安全(详见 `docs/maintainer/design/pointer-model.md`): ```core -p := &arr[0]; // 取地址,编译器自动记录来源与偏移 -p = p + n; // 偏移,随便算 -x := *p; // 解引用,编译器验证 offset ∈ [0, len) -ptr := addr as RawRef; // 显式转换 +p := &arr[0] // 取地址,编译器自动记录来源与偏移 +p = p + n // 偏移,随便算 +x := *p // 解引用,编译器验证 offset ∈ [0, len) +ptr := addr as RawRef // 显式转换 ``` ### 12.2 unsafe 块 diff --git a/docs/developer/tutorial.md b/docs/developer/tutorial.md index 57fc9d83..41bbf495 100644 --- a/docs/developer/tutorial.md +++ b/docs/developer/tutorial.md @@ -32,11 +32,11 @@ Core 是少数不能归入「第一门语言」或「第 N 门语言」二元分 - 数学程序:数列、阶乘、质数检测(函数 + 循环) ```core -fn sum(a: [int]) -> int { - total : ., mut = 0; - for x in a { total = total + x; } - return total; -} +fn sum(a: [int]) -> int: + total : ., mut = 0 + for x in a: + total = total + x + return total ``` **关联**:`docs/developer/syntax.md`、`docs/maintainer/design/execution-model.md` §一(唯一执行模型:HDFG) @@ -65,14 +65,13 @@ fn sum(a: [int]) -> int { - 简易 REPL:读取-求值-循环(read + process + loop) ```core -fn counter() -> int { - i : ., mut = 0; - loop { - if i >= 5 { break; } - i = i + 1; - } - return i; -} +fn counter() -> int: + i : ., mut = 0 + loop: + if i >= 5: + break + i = i + 1 + return i ``` **关联**:`docs/maintainer/design/execution-model.md` §三(深入:执行模型与图的实现) @@ -102,15 +101,13 @@ fn counter() -> int { - 布局查询:结构体大小/对齐/字段偏移(@sizeOf/@alignOf/@fields——序列化与协议实现的基础) ```core -fn deref(arr: [int], i: int) -> int { - p := &arr[i]; // 来源 = arr,偏移 = i(编译器自动记录) - return *p; // 越界 → 编译期拦截或运行时检查 -} +fn deref(arr: [int], i: int) -> int: + p := &arr[i] // 来源 = arr,偏移 = i(编译器自动记录) + return *p // 越界 → 编译期拦截或运行时检查 -unsafe { - mmio := 0x7fff0000 as *int; // 外部地址:图边界入口 - *mmio = 42; -} +unsafe: + mmio := 0x7fff0000 as *int // 外部地址:图边界入口 + *mmio = 42 ``` **关联**:`docs/maintainer/design/pointer-model.md`、`docs/maintainer/design/memory-model.md` @@ -141,15 +138,13 @@ unsafe { - 并发任务池:批量独立任务并发执行(go + 结果通道聚合) ```core -flow worker(id: int) -> int { - yield id * 2; -} +flow worker(id: int) -> int: + yield id * 2 -fn main() -> int { - w := go worker(21); - v := await w; - return v; // 42 -} +fn main() -> int: + w := go worker(21) + v := await w + return v // 42 ``` **关联**:`docs/maintainer/proposals/concurrency.md`、`docs/maintainer/design/execution-model.md` §三(并发 GMP) @@ -177,12 +172,8 @@ fn main() -> int { **里程碑**:能给函数写前置/后置条件,用检查函数表达性质(有序性、排列性、不变量)。 ```core -fn divide(a: int, b: int) -> int - #check(b != 0) - #ensure(result * b <= a) -{ - return a / b; -} +fn divide(a: int, b: int) -> int #check(b != 0) #ensure(result * b <= a): + return a / b ``` **关联**:`docs/maintainer/design/spec-design.md`、`docs/developer/syntax.md` 第十章、`docs/maintainer/adr/adr-0001-corespec-crasm-retired.md`(格式退役决策)、`docs/superpowers/specs/`(验证管线设计稿) diff --git a/docs/maintainer/design/dataflow-design.md b/docs/maintainer/design/dataflow-design.md index 65ae4b94..8a8a41e4 100644 --- a/docs/maintainer/design/dataflow-design.md +++ b/docs/maintainer/design/dataflow-design.md @@ -39,15 +39,15 @@ Core 将一切执行抽象为 HDFG。 该图等价于传统的数据流程序图。 ```core -fn transform(x: int) -> int { x * 2 } -fn display(v: int) { println(v); } - -fn main() { - data := [1, 2, 3]; - for d in data { - go display(transform(d)); - } -} +fn transform(x: int) -> int: + x * 2 +fn display(v: int): + println(v) + +fn main(): + data := [1, 2, 3] + for d in data: + go display(transform(d)) ``` 图结构:data → transform 节点(多个实例) → display 节点(多个实例)。 @@ -112,27 +112,21 @@ flow load_balancer() { ## 5. 并行计算 π 的图表示例 ```core -flow worker(id, base, chunk) -> dex { - loop { - partial := leibniz_partial(offset, chunk); - yield partial; - offset += chunk * num_workers(); - } -} - -flow orchestrator(workers, chunk_size) { - flows : ., mut = [go worker(...), ...]; // 扇出多个 worker 节点 - loop { - for f in &flows { - pi += 4.0 * f.recv(); // 扇入:从每个 worker 收集部分和 - } - println(pi); - } -} - -fn main() { - go orchestrator(8, 10000); -} +flow worker(id, base, chunk) -> dex: + loop: + partial := leibniz_partial(offset, chunk) + yield partial + offset += chunk * num_workers() + +flow orchestrator(workers, chunk_size): + flows : ., mut = [go worker(...), ...] // 扇出多个 worker 节点 + loop: + for f in &flows: + pi += 4.0 * f.recv() // 扇入:从每个 worker 收集部分和 + println(pi) + +fn main(): + go orchestrator(8, 10000) ``` 图结构: diff --git a/docs/maintainer/design/execution-mapping-design.md b/docs/maintainer/design/execution-mapping-design.md index 7acf6678..f691318c 100644 --- a/docs/maintainer/design/execution-mapping-design.md +++ b/docs/maintainer/design/execution-mapping-design.md @@ -184,14 +184,14 @@ flow compute { ... } // automatic 原文支持:`fn` · `flow` · `loop`/`for` · 显式 region。 ```core -fn pipeline(...) { - prepare(); +fn pipeline(...): + prepare() @executionDomain(gpu) - flow compute { ... } + flow compute: + ... - finish(); -} + finish() ``` 产出: @@ -222,11 +222,12 @@ finish ``` @preferredDomain(gpu) -fn foo() { +fn foo(): ... @executionDomain(bigCpu) - flow x { ... } // 生效 = bigCpu,不继承 gpu -} + flow x: + ... + // 生效 = bigCpu,不继承 gpu ``` **规则**: @@ -238,10 +239,11 @@ fn foo() { ```core @executionDomain(gpu) -fn foo() { +fn foo(): @executionDomain(cpu) - flow x { ... } // 合法;自动产生 gpu→cpu 的 materialization -} + flow x: + ... + // 合法;自动产生 gpu→cpu 的 materialization ``` ⚠ 规则 3 与既有 `region_check` 的「活子图」义务**可能交互**(跨域后 Entry 的 kind 属性是否随域改变)——**未核实**,登记在 §十二。 diff --git a/docs/maintainer/design/execution-model.md b/docs/maintainer/design/execution-model.md index 85042c22..1f3a5300 100644 --- a/docs/maintainer/design/execution-model.md +++ b/docs/maintainer/design/execution-model.md @@ -64,12 +64,12 @@ state edge 是 DFEdge 中 kind=1 的边,kind=0 为普通的 data 边(边结 ### 并发原语 ```core -ch := make(chan int, 10); // 缓冲 channel,容量 10 -go f(args); // 异步启动,不等待 -ch2 := go g(args); // 返回 channel 句柄,用于接收返回值 -send(ch, 42); // 发送 -val := recv(ch); // 接收 -close(ch); // 关闭 +ch := make(chan int, 10) // 缓冲 channel,容量 10 +go f(args) // 异步启动,不等待 +ch2 := go g(args) // 返回 channel 句柄,用于接收返回值 +send(ch, 42) // 发送 +val := recv(ch) // 接收 +close(ch) // 关闭 ``` 这些语法与 stdlib 中 `chan_*` 函数的对应关系见 `docs/developer/syntax.md` 第十一章与 `chan.cr`。go 还支持范围批量形态(`go var start..end expr`,在 `parser.cr` 中 desugar)。 @@ -79,10 +79,14 @@ close(ch); // 关闭 每个 G 是一个用户态协程,栈固定为 16KB,绑定独立的 arena: ```core -struct Goroutine { - id: int; status: int; stack_ptr: int; stack_lo: int; - arena_id: int; chan_wait: int; next: int; // 链表(run/wait queue) -} +struct Goroutine: + id: int + status: int + stack_ptr: int + stack_lo: int + arena_id: int + chan_wait: int + next: int // 链表(run/wait queue) ``` G 的状态机有五个状态:`_Gidle`(未启动)、`_Grunnable`(在队列中)、`_Grunning`(执行中)、`_Gwaiting`(阻塞在 chan 的 send 或 recv)、`_Gdead`(已退出,待回收)。 @@ -100,9 +104,12 @@ G 的状态机有五个状态:`_Gidle`(未启动)、`_Grunnable`(在队 ### M:machine(OS 线程) ```core -struct Machine { - id: int; cur_g: int; runq_head: int; runq_tail: int; g0: int; // g0 = M 自身的系统 G -} +struct Machine: + id: int + cur_g: int + runq_head: int + runq_tail: int + g0: int // g0 = M 自身的系统 G ``` `sched_init` 注册主线程,主流程的 G 记为 G0;`sched_spawn_workers(n)` 派生多个 M,以 m_idx 标识。 @@ -116,10 +123,15 @@ struct Machine { channel 由环形缓冲与等待链表组成: ```core -struct Channel { - buf: string; cap: int; len: int; head: int; elemsize: int; - send_wait: int; recv_wait: int; closed: int; -} +struct Channel: + buf: string + cap: int + len: int + head: int + elemsize: int + send_wait: int + recv_wait: int + closed: int ``` send 的行为分四种情况:channel 已关闭则 panic;有等待接收的 G 则直接拷贝给接收者并唤醒它;缓冲未满则写入缓冲;缓冲已满则当前 G 阻塞,进入 send_wait。 diff --git a/docs/maintainer/design/pointer-model.md b/docs/maintainer/design/pointer-model.md index c34e736a..879c9df5 100644 --- a/docs/maintainer/design/pointer-model.md +++ b/docs/maintainer/design/pointer-model.md @@ -33,16 +33,15 @@ C 风格裸指针表达力强但无保障;Rust 用 borrow checker 换安全,代 开发者视角的语法与保证见 docs/developer/syntax.md 指针节;此处只列 pass 输入形状: ```core -p := &arr[0]; // REF/ADDR_INDEX → self-pointer -p = p + n; // 偏移(不影响 pts;偏移入 g_offsets) -x := *p; // DEREF → 读 alloc content -*p = v; // STORE_PTR → v 的 pts 写入 alloc content -q := cast(p); // 类型转换(pts 不变,视图变化) - -unsafe { - mmio := 0x7fff0000 as *int; // 图边界入口:整数转指针,asp=1 - *mmio = 42; -} +p := &arr[0] // REF/ADDR_INDEX → self-pointer +p = p + n // 偏移(不影响 pts;偏移入 g_offsets) +x := *p // DEREF → 读 alloc content +*p = v // STORE_PTR → v 的 pts 写入 alloc content +q := cast(p) // 类型转换(pts 不变,视图变化) + +unsafe: + mmio := 0x7fff0000 as *int // 图边界入口:整数转指针,asp=1 + *mmio = 42 ``` 类型双关(`*(dex*)&i`)不需要 unsafe——地址语义是条目标识 + 偏移(条款 6),经典映射是"字节序列 + 宽度 + 边界",provenance/offset/alloc_size 与类型无关;`cast` 保留值流,provenance 边不断。判据 = 边界 + 宽度。 @@ -107,9 +106,9 @@ unsafe { **ALLOC_AT(声明式放置,2026-08-13 定稿)**:`alloc_at(addr, size, align)` 是声明式进图节点——固定地址区域以(地址+大小+对齐)声明,与 ALLOC 同路径获得 provenance,之后全图追踪、照常验证: ```core -mmio := alloc_at(0x7fff0000, 4096, align(4096)); // MMIO 页 -*mmio = 42; // safe 代码即可,边界内照常验证 -p := mmio + 4096; // 越界 → 编译错误或运行时 check +mmio := alloc_at(0x7fff0000, 4096, align(4096)) // MMIO 页 +*mmio = 42 // safe 代码即可,边界内照常验证 +p := mmio + 4096 // 越界 → 编译错误或运行时 check ``` 声明是唯一信任点(等价受控图边界入口);与 2026-08-10 定论不冲突(0x 字面量仍只作 unsafe 外部入口)。 diff --git a/docs/maintainer/design/region-model.md b/docs/maintainer/design/region-model.md index 24254ac3..e6b3c44a 100644 --- a/docs/maintainer/design/region-model.md +++ b/docs/maintainer/design/region-model.md @@ -123,14 +123,13 @@ Core 采用**图锚定区域**的统一内存管理:区域(Region)锚定在 HDFG ```core // 1. 布局声明(例外入口)——默认布局全自动(字段顺序 + 自然对齐),用户不写任何东西; // layout(...) 仅当默认布局不合用时:packed(FFI)、强制对齐、硬件结构 -struct PackedHeader layout(packed, align(4)) { +struct PackedHeader layout(packed, align(4)): a: u8, // 偏移 0 b: u32, // 偏移 4 c: u16, // 偏移 8 -} // 2. 放置声明——地址是物理事实,只有用户知道;声明式进图,之后全图追踪 -mmio := alloc_at(0x7fff0000, 4096, align(4096)); +mmio := alloc_at(0x7fff0000, 4096, align(4096)) ``` - 不提供显式区域/回收语法(YAGNI) diff --git a/docs/maintainer/design/spec-design.md b/docs/maintainer/design/spec-design.md index 57d11469..8a869fac 100644 --- a/docs/maintainer/design/spec-design.md +++ b/docs/maintainer/design/spec-design.md @@ -73,19 +73,16 @@ CIC 提供 Coq 级别的全部表达力,逐项对应: ```core // 简单的范围 fn divide(a: int, b: int) -> int - #check(b != 0) - #ensure(result != None) -{ - if b == 0 { return None; } - return Some(a / b); -} +#check(b != 0) +#ensure(result != None): + if b == 0: + return None + return Some(a / b) // 引用外部检查函数 fn sort(a: [int]) -> [int] - #ensure(auto::sort_check(a, result)) -{ +#ensure(auto::sort_check(a, result)): // 冒泡排序实现 -} ``` ### `.csp` — 规约源(设计稿,见上方退役同步注记) @@ -107,21 +104,20 @@ fn sort(a: [int]) -> [int] #ensure(/* 用户填写后置条件 */) // 检查函数 —— 用 Core 语言写规约 -spec fn sort_check(input: [int], result: [int]) -> bool { +spec fn sort_check(input: [int], result: [int]) -> bool: // 编译器生成的骨架:已从图模式推导部分性质 // ① 长度守恒(已从图结构推导) - if result.len() != |input| { return false; } + if result.len() != |input|: + return false // ② 有序性(图有比较+交换模式,但需要用户确认) // TODO: 填写有序性检查 // ③ 排列性质(编译器无法完全推导,需要用户补全) // TODO: 填写排列检查 - return true; -} + return true // 类型不变量 -spec fn vec_invariant[T](v: Vec[T]) -> bool { - return v.len <= v.cap && v.data != null; -} +spec fn vec_invariant[T](v: Vec[T]) -> bool: + return v.len <= v.cap && v.data != null ``` 生成规则: @@ -196,13 +192,12 @@ fn transfer(from: &mut Account, to: &mut Account, amt: int) ```core // 在 .cr 中使用(设计定稿:规约内联于 .cr) fn foo() -> int - #pure - #check(x > 0) +#pure +#check(x > 0) // 自定义标签 -#tag sorted = { +#tag sorted =: forall i: 0 <= i < result.len() - 1 -> result[i] <= result[i+1] -} ``` `#` 风格: @@ -495,28 +490,23 @@ verify file.csr 内核级别的代码: ```core -spec fn pagetable_invariant(pt: &PageTable) -> bool { - for virt in pt.mappings { - entry := pt.mappings[virt]; +spec fn pagetable_invariant(pt: &PageTable) -> bool: + for virt in pt.mappings: + entry := pt.mappings[virt] // 虚拟地址到物理地址的映射 - if entry.present { + if entry.present: // 物理地址必须在有效范围 - if entry.phys < PHYS_START || entry.phys >= PHYS_END { - return false; - } + if entry.phys < PHYS_START || entry.phys >= PHYS_END: + return false // 用户态不能映射内核页 - if virt < USER_END && entry.privilege == KERNEL { - return false; - } - } - } - return true; -} + if virt < USER_END && entry.privilege == KERNEL: + return false + return true fn map_page(pt: &mut PageTable, virt: Addr, phys: Addr, flags: u64) - #check(PHYS_START <= phys && phys < PHYS_END) - #check(virt < USER_END) // 用户态进程不能映射内核地址 - #ensure(pagetable_invariant(pt)) +#check(PHYS_START <= phys && phys < PHYS_END) +#check(virt < USER_END) // 用户态进程不能映射内核地址 +#ensure(pagetable_invariant(pt)) ``` 即使在内核场景,规约仍是 Core 代码——变量、循环、分支。不是公式,是既能读也能写的代码。 diff --git a/docs/maintainer/design/v4-layout-spec.md b/docs/maintainer/design/v4-layout-spec.md index 4eafa3e4..b0d5eac2 100644 --- a/docs/maintainer/design/v4-layout-spec.md +++ b/docs/maintainer/design/v4-layout-spec.md @@ -341,9 +341,9 @@ fn g(): `[T0·实核]` `src/compiler/parser.cr:552-554`: ```core -ft := advance_tok(); -fni := str_intern(tok_lx(ft)); -advance_tok(); // ← 返回值被丢弃:`=` 与 `:` 两形今天都收 +ft := advance_tok() +fni := str_intern(tok_lx(ft)) +advance_tok() // ← 返回值被丢弃:`=` 与 `:` 两形今天都收 ``` ⇒ 若 T5 不把这一行改成带校验的消费,v4 下「两形都收」会**静默保留**,而 v4 是单形语言。 diff --git a/docs/maintainer/proposals/comptime.md b/docs/maintainer/proposals/comptime.md index 122774ae..7a82347e 100644 --- a/docs/maintainer/proposals/comptime.md +++ b/docs/maintainer/proposals/comptime.md @@ -51,13 +51,13 @@ w := fibonacci(user_input); // 参数运行时才确定 → 留给运行时 标记为 `comptime fn` 的函数,要求所有调用点在编译时可求值: ```core -comptime fn fibonacci(n: int) -> int { - if n <= 1 { return n; } - return fibonacci(n - 1) + fibonacci(n - 2); -} +comptime fn fibonacci(n: int) -> int: + if n <= 1: + return n + return fibonacci(n - 1) + fibonacci(n - 2) -x := fibonacci(40); // 编译时算 -y := fibonacci(user_input); // 编译错误:comptime fn 需要已知参数 +x := fibonacci(40) // 编译时算 +y := fibonacci(user_input) // 编译错误:comptime fn 需要已知参数 ``` ## 可编译时执行的条件 diff --git a/docs/maintainer/proposals/concurrency.md b/docs/maintainer/proposals/concurrency.md index 2598ce55..dccb9b96 100644 --- a/docs/maintainer/proposals/concurrency.md +++ b/docs/maintainer/proposals/concurrency.md @@ -31,7 +31,7 @@ flow counter() -> int { 激活一个 flow 实例,产生一个新的图节点,与调用者并行。 ```core -c := go counter(); +c := go counter() // 图上:counter 子图被实例化,新节点加入图 // 有 OS:新线程 // 无 OS:新节点加入就绪队列 @@ -60,10 +60,10 @@ flow numbers() { 等待一个 flow 实例的输出。 ```core -c := go counter(); -v := await c; // 等待 counter 输出一个值 +c := go counter() +v := await c // 等待 counter 输出一个值 // v = 0 -v = await c; // 等待 counter 输出下一个值 +v = await c // 等待 counter 输出下一个值 // v = 1 ``` diff --git a/docs/maintainer/proposals/dynamic-typing.md b/docs/maintainer/proposals/dynamic-typing.md index 63ccf1dc..a7b8c09d 100644 --- a/docs/maintainer/proposals/dynamic-typing.md +++ b/docs/maintainer/proposals/dynamic-typing.md @@ -11,11 +11,11 @@ ## 声明 ```core -x : dyn = 42; // 动态类型 -x : dyn = "hello"; // 同一个变量,类型变了 +x : dyn = 42 // 动态类型 +x : dyn = "hello" // 同一个变量,类型变了 -y : int = 42; // 静态类型,不能变 -z : auto = 42; // 自动推导,仍然是静态 +y : int = 42 // 静态类型,不能变 +z : auto = 42 // 自动推导,仍然是静态 ``` `dyn` 是类型关键字,与 `int`、`string` 平级。 @@ -42,16 +42,16 @@ y := x + 1; 编译器看图可知两边的类型,在边界自动插入转换代码。 ```core -x := "42"; -y := x + 1; +x := "42" +y := x + 1 // 图:x 是 string,+1 需要 int // 编译器:string_to_int 插在加法之前 // 运行时 x 全程是裸 string,没有装箱 ``` ```core -x := 42; -z := x + "hello"; +x := 42 +z := x + "hello" // 图:x 是 int,"hello" 是 string // int + string → int_to_string + 拼接 ``` @@ -69,8 +69,8 @@ z := x + "hello"; 图全量已知所有分支的类型,为每种可能生成对应的调用路径。 ```core -x : dyn = cond ? "hello" : 42; -x.len(); +x : dyn = cond ? "hello" : 42 +x.len() // 路径 A: string → 有 .len(),直接调 // 路径 B: int → 无 .len(),编译错误 // 全路径都有 → 编译期决议,零开销 @@ -86,7 +86,7 @@ x.len(); 当编译器需要为同一个变量生成不同路径的代码时,为这个变量生成一个 `(tag, value)` 栈上对: ```core -x : dyn = cond ? 42 : "hello"; +x : dyn = cond ? 42 : "hello" // 编译器:x 可能是 int 或 string // x 在栈上是 { tag: int|string, value: 8字节 } // 后续代码根据 tag 分派 @@ -101,16 +101,16 @@ x : dyn = cond ? 42 : "hello"; ### 声明 ```core -@hotpatch(canary="5%") fn handle(x: dyn) -> dyn; +@hotpatch(canary="5%") fn handle(x: dyn) -> dyn // 新版本先收 5% 流量 -@hotpatch(rollout="50%") fn handle(x: dyn) -> dyn; +@hotpatch(rollout="50%") fn handle(x: dyn) -> dyn // 确认稳定后扩到 50% -@hotpatch(rollout="100%") fn handle(x: dyn) -> dyn; +@hotpatch(rollout="100%") fn handle(x: dyn) -> dyn // 全量 -@hotpatch(drain="true") fn handle(x: dyn) -> dyn; +@hotpatch(drain="true") fn handle(x: dyn) -> dyn // 旧版本排水完成后回收 ``` diff --git a/docs/maintainer/proposals/ffi.md b/docs/maintainer/proposals/ffi.md index e6f003bf..40ad6fad 100644 --- a/docs/maintainer/proposals/ffi.md +++ b/docs/maintainer/proposals/ffi.md @@ -14,26 +14,26 @@ ### C FFI(默认,省略 `@ffi` 时等价) ```core -extern fn read_file(path: *const u8) -> *mut u8; +extern fn read_file(path: *const u8) -> *mut u8 // 等价于 C 的 char* read_file(const char* path) ``` ### 指定语言 ```core -@ffi("Python") extern fn py_call(obj: dyn, method: string) -> dyn; +@ffi("Python") extern fn py_call(obj: dyn, method: string) -> dyn // 编译器:参数转 PyObject*,refcount 管理,返回值转回 dyn -@ffi("Java") extern fn java_call(env: dyn, obj: dyn, method: string) -> dyn; +@ffi("Java") extern fn java_call(env: dyn, obj: dyn, method: string) -> dyn // 编译器:绑定当前线程 JNIEnv,exception 检查 -@ffi("Lua") extern fn lua_call(state: dyn, fn_name: string) -> dyn; +@ffi("Lua") extern fn lua_call(state: dyn, fn_name: string) -> dyn // 编译器:Lua stack 操作包装 -@ffi("Rust") extern fn process(data: *mut u8, len: i32); +@ffi("Rust") extern fn process(data: *mut u8, len: i32) // 等价于 C ABI,不需要额外处理 -@ffi("C") extern fn write(fd: i32, buf: *const u8, len: i32) -> i32; +@ffi("C") extern fn write(fd: i32, buf: *const u8, len: i32) -> i32 // 显式指定,和省略时一样 ``` diff --git a/docs/maintainer/proposals/generics.md b/docs/maintainer/proposals/generics.md index 399714ee..9ef43aa5 100644 --- a/docs/maintainer/proposals/generics.md +++ b/docs/maintainer/proposals/generics.md @@ -25,14 +25,12 @@ fn first(arr: [T]) -> T { ### 泛型 struct ```core -struct Box { +struct Box: val: T, -} -struct Pair { +struct Pair: first: A, second: B, -} ``` ### 泛型参数约束 @@ -91,13 +89,12 @@ add("a", "b"); // string 支持 + ```core // lib.cr -pub fn wrap(x: T) -> (T, T) { - return (x, x); -} +pub fn wrap(x: T) -> (T, T): + return (x, x) // main.cr -import lib; -p := lib.wrap(42); // lib 的泛型函数 main 中实例化 +import lib +p := lib.wrap(42) // lib 的泛型函数 main 中实例化 // 实例化发生在 main 的 ccr 中 ``` diff --git a/docs/maintainer/proposals/lazy.md b/docs/maintainer/proposals/lazy.md index 50a8ed6e..1253ddf8 100644 --- a/docs/maintainer/proposals/lazy.md +++ b/docs/maintainer/proposals/lazy.md @@ -11,12 +11,11 @@ 编译器看图决定一个节点是否需要惰性求值: ```core -result := if cond { +result := if cond: expensive1() // 只在 cond=true 时用到 -} else { +else: 0 // cond=false 时到这里 -} -print(result); +print(result) ``` | 条件 | 策略 | @@ -31,8 +30,8 @@ print(result); 惰性推导与此前的指针验证、编译期求值、概率推导一致:由编译器看图自动完成,不引入 `lazy` 关键字。 ```core -x := expensive(); // 编译器 auto: eager 或 lazy -y := cond ? x : 0; // 如果 x 只用在这里且无副作用 → 自动惰性 +x := expensive() // 编译器 auto: eager 或 lazy +y := cond ? x : 0 // 如果 x 只用在这里且无副作用 → 自动惰性 ``` ## 副作用标记 @@ -49,9 +48,9 @@ y := cond ? x : 0; // 如果 x 只用在这里且无副作用 → 自动惰 ## 惰性节点被多处使用 ```core -x := expensive(); // 编译器决定惰性 -y := cond ? x : 0; -z := x + 1; // x 这里也被用了 → 必须求值 +x := expensive() // 编译器决定惰性 +y := cond ? x : 0 +z := x + 1 // x 这里也被用了 → 必须求值 ``` 若编译器发现标注为惰性的节点实际有多条路径需要它,则自动升级为 eager;用户不感知。 diff --git a/docs/maintainer/proposals/probabilistic.md b/docs/maintainer/proposals/probabilistic.md index 6d8a0c05..cc878508 100644 --- a/docs/maintainer/proposals/probabilistic.md +++ b/docs/maintainer/proposals/probabilistic.md @@ -23,11 +23,10 @@ if random() < 0.3 { pass 沿值流传播权重,任何变量的分布信息均自动推导。 ```core -result := if random() < 0.05 { +result := if random() < 0.05: "rare" // 5% -} else { +else: "common" // 95% -}; // 图中下游使用 result 的节点知道: // result 是 {5% "rare", 95% "common"} @@ -38,9 +37,9 @@ result := if random() < 0.05 { `random()` 接受一个分布参数并返回样本。它与 `read_file()` 等价:编译器不做特殊对待,属库函数。 ```core -x := random(normal(0, 1)); // 标准正态分布 -y := random(uniform(0, 10)); // 均匀分布 -z := random(binomial(10, 0.5)); // 二项分布 +x := random(normal(0, 1)) // 标准正态分布 +y := random(uniform(0, 10)) // 均匀分布 +z := random(binomial(10, 0.5)) // 二项分布 ``` 运行时 `random(normal(0, 1))` 返回一个 double。编译期的概率 pass 观察 `random(...)` 返回值的后续使用,但不影响运行时。 @@ -50,12 +49,11 @@ z := random(binomial(10, 0.5)); // 二项分布 观测是贝叶斯更新。在 Core 中它不发生在运行时,而发生在编译期的图分析。约束可以写在规约中(.cr 内联,独立 `.corespec` 格式已退役,见 ADR-0001),也可以直接在条件分支中表达: ```core -sensor := random(normal(true_temp, 0.1)); -if sensor > 30 { +sensor := random(normal(true_temp, 0.1)) +if sensor > 30: // 编译器知道:sensor 的值 > 30 // 同时知道 sensor 服从 normal(true_temp, 0.1) // 后验:P(true_temp | sensor > 30) 在图上可推导 -} ``` 不引入 `@observe`,也不引入新语法,只用条件分支 + 规约。 diff --git a/docs/project-book.md b/docs/project-book.md index 0949f2d6..b2e383e5 100644 --- a/docs/project-book.md +++ b/docs/project-book.md @@ -255,14 +255,12 @@ region 边界,供验证工具证明终止性和循环正确性(终止性依 以下代码: ```core -fn add(x: int, y: int) -> int { - return x + y; -} - -fn main() { - result := add(3, 4); - println(result); -} +fn add(x: int, y: int) -> int: + return x + y + +fn main(): + result := add(3, 4) + println(result) ``` - 部署为单核嵌入式 → 编译器生成串行机器码,静态分配,零运行时。 diff --git a/docs/superpowers/plans/2026-07-28-arena-model.md b/docs/superpowers/plans/2026-07-28-arena-model.md index 170f3df6..dcb274c0 100644 --- a/docs/superpowers/plans/2026-07-28-arena-model.md +++ b/docs/superpowers/plans/2026-07-28-arena-model.md @@ -88,8 +88,8 @@ git commit -m "feat: add arena BSS globals (g_current_arena, g_arena_pool_data, 定位 IR opcode 段(约第 526-530 行),在 `IR_YIELD` 之后新增: ```core -IR_ARENA_NEW : int = 32; // dest=arena_var, src1=size_estimate -IR_ARENA_RESET : int = 33; // src1=arena_id (dest=-1) +IR_ARENA_NEW : int = 32 // dest=arena_var, src1=size_estimate +IR_ARENA_RESET : int = 33 // src1=arena_id (dest=-1) ``` - [ ] **步骤 2:在 dataflow.cr 的 df_opcode_name 中登记** @@ -215,105 +215,124 @@ git commit -m "feat: save/load IR_ARENA_NEW and IR_ARENA_RESET in ccr_io" // alloc() checks g_current_arena and uses the arena chunk when set. // ── Globals (accessed by emit_alloc_body ELF code) ── -g_current_arena : int, mut = -1; +g_current_arena : int, mut = -1 // 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_pool_data : string, mut; // pool base address (from alloc) -g_arena_max_size : int, mut; // default chunk size per arena -g_arena_free_list : int, mut = -1; // free list head (-1 = empty) -g_arena_count : int, mut = 0; // total slots allocated -g_arena_cap : int, mut = 0; // metadata array capacity +g_arena_pool_data : string, mut // pool base address (from alloc) +g_arena_max_size : int, mut // default chunk size per arena +g_arena_free_list : int, mut = -1 // free list head (-1 = empty) +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; } +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 // 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; -} + 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 // ── Public API ── -fn arena_init(pool_size: int, arena_size: int) { - 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; -} +fn arena_init(pool_size: int, arena_size: int): + 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 -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 ``` - [ ] **步骤 2:类型检查** @@ -343,45 +362,57 @@ git commit -m "feat: arena lifecycle allocator — init/new/reset with dynamic m ```core // Subgraph-level arena tracking for compile-time size estimation -g_sg_alloc_total : string, mut; // per-sg: cumulative alloc size -g_sg_alloc_cap : int, mut; -g_sg_arena_var : string, mut; // per-sg: IR var for arena ID -g_sg_arena_var_cap : int, mut; - -fn grow_sg_alloc(needed: int) { - if needed < g_sg_alloc_cap { return; } - nc := g_sg_alloc_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_sg_alloc_total, g_sg_alloc_cap * 8, nb); g_sg_alloc_total = nb; g_sg_alloc_cap = nc; } - -fn grow_sg_arena_var(needed: int) { - if needed < g_sg_arena_var_cap { return; } - nc := g_sg_arena_var_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_sg_arena_var, g_sg_arena_var_cap * 8, nb); g_sg_arena_var = nb; g_sg_arena_var_cap = nc; } +g_sg_alloc_total : string, mut // per-sg: cumulative alloc size +g_sg_alloc_cap : int, mut +g_sg_arena_var : string, mut // per-sg: IR var for arena ID +g_sg_arena_var_cap : int, mut + +fn grow_sg_alloc(needed: int): + if needed < g_sg_alloc_cap: + return + nc := g_sg_alloc_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_sg_alloc_total, g_sg_alloc_cap * 8, nb) + g_sg_alloc_total = nb + g_sg_alloc_cap = nc + +fn grow_sg_arena_var(needed: int): + if needed < g_sg_arena_var_cap: + return + nc := g_sg_arena_var_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_sg_arena_var, g_sg_arena_var_cap * 8, nb) + g_sg_arena_var = nb + g_sg_arena_var_cap = nc ``` - [ ] **步骤 2:添加 sg_alloc_push/pop 与 track_alloc_size** ```core -fn sg_alloc_push(kind: int) { - grow_sg_alloc(g_sg_count + 1); - grow_sg_arena_var(g_sg_count + 1); - w64(g_sg_alloc_total, g_sg_count * 8, 0); - sg_push(kind); -} - -fn sg_alloc_pop() { - total := r64(g_sg_alloc_total, (g_sg_count - 1) * 8); - arena_var := r64(g_sg_arena_var, (g_sg_count - 1) * 8); - sg_pop(); - emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0); -} - -fn track_alloc_size(size: int) { - if g_sg_count > 0 { - old := r64(g_sg_alloc_total, (g_sg_count - 1) * 8); - w64(g_sg_alloc_total, (g_sg_count - 1) * 8, old + size); - } -} +fn sg_alloc_push(kind: int): + grow_sg_alloc(g_sg_count + 1) + grow_sg_arena_var(g_sg_count + 1) + w64(g_sg_alloc_total, g_sg_count * 8, 0) + sg_push(kind) + +fn sg_alloc_pop(): + total := r64(g_sg_alloc_total, (g_sg_count - 1) * 8) + arena_var := r64(g_sg_arena_var, (g_sg_count - 1) * 8) + sg_pop() + emit(IR_ARENA_RESET, -1, arena_var, 0, 0, 0) + +fn track_alloc_size(size: int): + if g_sg_count > 0: + old := r64(g_sg_alloc_total, (g_sg_count - 1) * 8) + w64(g_sg_alloc_total, (g_sg_count - 1) * 8, old + size) ``` - [ ] **步骤 3:在 ir_gen_func 的函数入口与出口接入 arena** @@ -474,13 +505,14 @@ UNSAFE(约第 1005 行): ```core // Track allocation size for subgraph arena size estimation - if opcode == IR_ALLOC && src1 > 0 { track_alloc_size(src1); } - if opcode == IR_ALLOC_STRUCT { - // struct size = field_count * 8 (from name_ni in s3) - // For now, just track as default — refined in future passes - track_alloc_size(64); - } - if opcode == IR_ALLOC_ARRAY && src1 > 0 { track_alloc_size(src1 * 8); } + if opcode == IR_ALLOC && src1 > 0: + track_alloc_size(src1) + if opcode == IR_ALLOC_STRUCT: + // struct size = field_count * 8 (from name_ni in s3) + // For now, just track as default — refined in future passes + track_alloc_size(64) + if opcode == IR_ALLOC_ARRAY && src1 > 0: + track_alloc_size(src1 * 8) ``` - [ ] **步骤 6:提交** @@ -709,32 +741,33 @@ git commit -m "feat: emit_alloc_body dual-path arena alloc + chain expansion fal // This is a placeholder that expands into: // call arena_new (via PLT if available, or direct reloc) // We emit a call instruction that gets patched similarly to alloc calls. -fn emit_arena_new_impl(buf: string, pos: int) -> int { +fn emit_arena_new_impl(buf: string, pos: int) -> int: // mov edi, 0 (no size hint for now) - e2_w8(buf, pos, 191); e2_w32(buf, pos+1, 0); // mov edi, 0 + e2_w8(buf, pos, 191) + e2_w32(buf, pos+1, 0) // mov edi, 0 // call arena_new — placeholder, patched at link time - grow_alloc_patch(g_x86_alloc_patch_count + 1); - w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + 5); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - e2_w8(buf, pos+5, 232); e2_w32(buf, pos+6, 0); // call placeholder + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos + 5) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + e2_w8(buf, pos+5, 232) + e2_w32(buf, pos+6, 0) // call placeholder // ret - e2_w8(buf, pos+10, 195); // ret - return 11; -} + e2_w8(buf, pos+10, 195) // ret + return 11 // Emit arena_reset_impl — resets an arena slot. // Called from IR_ARENA_RESET. Takes arena ID in edi, void return. -fn emit_arena_reset_impl(buf: string, pos: int) -> int { +fn emit_arena_reset_impl(buf: string, pos: int) -> int: // edi already contains arena_id from caller // call arena_reset — placeholder, patched at link time - grow_alloc_patch(g_x86_alloc_patch_count + 1); - w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos); - g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1; - e2_w8(buf, pos, 232); e2_w32(buf, pos+1, 0); // call placeholder + grow_alloc_patch(g_x86_alloc_patch_count + 1) + w64(g_x86_alloc_patch_pos, g_x86_alloc_patch_count * 8, pos) + g_x86_alloc_patch_count = g_x86_alloc_patch_count + 1 + e2_w8(buf, pos, 232) + e2_w32(buf, pos+1, 0) // call placeholder // ret - e2_w8(buf, pos+5, 195); // ret - return 6; -} + e2_w8(buf, pos+5, 195) // ret + return 6 ``` - [ ] **步骤 5:在 elf_gen 中登记 arena_new_impl / arena_reset_impl** @@ -790,83 +823,108 @@ git commit -m "feat: ELF backend arena_new/reset opcode encoding + impl stubs" // Arena memory model test suite // Tests basic arena lifecycle, nesting, and alloc integration -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 ``` - [ ] **步骤 2:以解释器运行测试** diff --git a/docs/superpowers/plans/2026-07-28-at-intrinsics.md b/docs/superpowers/plans/2026-07-28-at-intrinsics.md index f23d9bdd..4597f0f2 100644 --- a/docs/superpowers/plans/2026-07-28-at-intrinsics.md +++ b/docs/superpowers/plans/2026-07-28-at-intrinsics.md @@ -33,7 +33,7 @@ Find the EXPR_ section (around `EXPR_AWAIT = 45`). Add after it: ```core -EXPR_AT : int = 46; // @builtin: a=name_ni, b=args_node, c=0, iv=0, tv=0, data=0 +EXPR_AT : int = 46 // @builtin: a=name_ni, b=args_node, c=0, iv=0, tv=0, data=0 ``` - [ ] **Step 2: Add IR opcode constants** @@ -41,9 +41,9 @@ EXPR_AT : int = 46; // @builtin: a=name_ni, b=args_node, c=0, iv=0, tv=0, da Find the IR opcode section (after `IR_ARENA_RESET = 33`). Add: ```core -IR_INLINE : int = 34; // src1=fn_var — inline hint -IR_NO_BOUNDS_CHECK : int = 35; // — skip bounds check for subsequent DEREFs -IR_FAST : int = 36; // — allow precision-for-speed optimizations +IR_INLINE : int = 34 // src1=fn_var — inline hint +IR_NO_BOUNDS_CHECK : int = 35 // — skip bounds check for subsequent DEREFs +IR_FAST : int = 36 // — allow precision-for-speed optimizations ``` - [ ] **Step 3: Commit** @@ -216,100 +216,89 @@ jj commit src/compiler/type_checker.cr -m "feat: type check EXPR_AT — validate Find the main `fn gen_expr(node)` function. Add before the `return -1` at the end: ```core - if ast_kind(node) == EXPR_AT { - name_ni := ast_a(node); - name := istr_get(name_ni); - args := ast_b(node); - - // @sizeOf(T): emit IR_CONST with type size - if str_eq(name, "sizeOf") != 0 { - ti := type_of(ast_a(args)); - sz := type_size(ti); - v := new_ir_var("_sizeof", TI_INT); - emit(IR_CONST, v, sz, 0, 0, TI_INT); - return v; - } - - // @alignOf(T): emit IR_CONST with type alignment - if str_eq(name, "alignOf") != 0 { - ti := type_of(ast_a(args)); - al := type_align(ti); - v := new_ir_var("_alignof", TI_INT); - emit(IR_CONST, v, al, 0, 0, TI_INT); - return v; - } - - // @fields(T): build string array of field names - if str_eq(name, "fields") != 0 { - ti := type_of(ast_a(args)); - arr_ni := build_field_name_array(ti); // build string array in string table - v := new_ir_var("_fields", TI_STR); - emit(IR_CONST, v, arr_ni, 0, 0, TI_STR); - return v; - } - - // @hasField(T, name): check field existence - if str_eq(name, "hasField") != 0 { - ti := type_of(ast_a(args)); - fn_node := ast_b(args); - fn_name := istr_get(ast_a(fn_node)); // field name expression - exists := ti_has_field(ti, fn_name); - v := new_ir_var("_hasf", TI_BOOL); - emit(IR_CONST, v, exists, 0, 0, TI_BOOL); - return v; - } - - // @field(T, name): get field offset - if str_eq(name, "field") != 0 { - ti := type_of(ast_a(args)); - fn_node := ast_b(args); - fn_name := istr_get(ast_a(fn_node)); - off := ti_field_offset(ti, fn_name); - v := new_ir_var("_fldoff", TI_INT); - emit(IR_CONST, v, off, 0, 0, TI_INT); - return v; - } - - // @typeInfo(T): build type info struct - if str_eq(name, "typeInfo") != 0 { - ti := type_of(ast_a(args)); - info_ni := build_type_info(ti); // store in compile-time table - v := new_ir_var("_tinfo", TI_INT); - emit(IR_CONST, v, info_ni, 0, 0, TI_INT); - return v; - } - - // @comptime(expr): invoke interpreter - if str_eq(name, "comptime") != 0 { - inner := ast_a(args); - // Generate IR for inner expr and evaluate via interpreter - inner_var := gen_expr(inner); - // Note: IR_CONST vars can be read directly. For complex exprs, - // the interpreter would evaluate them. For now, just gen the inner expr. - return inner_var; - } - - // @inline(fn): emit IR_INLINE hint - if str_eq(name, "inline") != 0 { - fn_var := gen_expr(ast_a(args)); - emit(IR_INLINE, -1, fn_var, 0, 0, 0); - return fn_var; - } - - // @no_bounds_check: emit annotation - if str_eq(name, "no_bounds_check") != 0 { - emit(IR_NO_BOUNDS_CHECK, -1, 0, 0, 0, 0); - return -1; - } - - // @fast: emit annotation - if str_eq(name, "fast") != 0 { - emit(IR_FAST, -1, 0, 0, 0, 0); - return -1; - } - - return -1; - } + if ast_kind(node) == EXPR_AT: + name_ni := ast_a(node) + name := istr_get(name_ni) + args := ast_b(node) + + // @sizeOf(T): emit IR_CONST with type size + if str_eq(name, "sizeOf") != 0: + ti := type_of(ast_a(args)) + sz := type_size(ti) + v := new_ir_var("_sizeof", TI_INT) + emit(IR_CONST, v, sz, 0, 0, TI_INT) + return v + + // @alignOf(T): emit IR_CONST with type alignment + if str_eq(name, "alignOf") != 0: + ti := type_of(ast_a(args)) + al := type_align(ti) + v := new_ir_var("_alignof", TI_INT) + emit(IR_CONST, v, al, 0, 0, TI_INT) + return v + + // @fields(T): build string array of field names + if str_eq(name, "fields") != 0: + ti := type_of(ast_a(args)) + arr_ni := build_field_name_array(ti) // build string array in string table + v := new_ir_var("_fields", TI_STR) + emit(IR_CONST, v, arr_ni, 0, 0, TI_STR) + return v + + // @hasField(T, name): check field existence + if str_eq(name, "hasField") != 0: + ti := type_of(ast_a(args)) + fn_node := ast_b(args) + fn_name := istr_get(ast_a(fn_node)) // field name expression + exists := ti_has_field(ti, fn_name) + v := new_ir_var("_hasf", TI_BOOL) + emit(IR_CONST, v, exists, 0, 0, TI_BOOL) + return v + + // @field(T, name): get field offset + if str_eq(name, "field") != 0: + ti := type_of(ast_a(args)) + fn_node := ast_b(args) + fn_name := istr_get(ast_a(fn_node)) + off := ti_field_offset(ti, fn_name) + v := new_ir_var("_fldoff", TI_INT) + emit(IR_CONST, v, off, 0, 0, TI_INT) + return v + + // @typeInfo(T): build type info struct + if str_eq(name, "typeInfo") != 0: + ti := type_of(ast_a(args)) + info_ni := build_type_info(ti) // store in compile-time table + v := new_ir_var("_tinfo", TI_INT) + emit(IR_CONST, v, info_ni, 0, 0, TI_INT) + return v + + // @comptime(expr): invoke interpreter + if str_eq(name, "comptime") != 0: + inner := ast_a(args) + // Generate IR for inner expr and evaluate via interpreter + inner_var := gen_expr(inner) + // Note: IR_CONST vars can be read directly. For complex exprs, + // the interpreter would evaluate them. For now, just gen the inner expr. + return inner_var + + // @inline(fn): emit IR_INLINE hint + if str_eq(name, "inline") != 0: + fn_var := gen_expr(ast_a(args)) + emit(IR_INLINE, -1, fn_var, 0, 0, 0) + return fn_var + + // @no_bounds_check: emit annotation + if str_eq(name, "no_bounds_check") != 0: + emit(IR_NO_BOUNDS_CHECK, -1, 0, 0, 0, 0) + return -1 + + // @fast: emit annotation + if str_eq(name, "fast") != 0: + emit(IR_FAST, -1, 0, 0, 0, 0) + return -1 + + return -1 ``` - [ ] **Step 2: Add helper functions for type metadata** @@ -318,39 +307,47 @@ At the top of the file or in a helper section, add: ```core // Type size lookup -fn type_size(ti: int) -> int { - if ti == TI_INT { return 8; } - if ti == TI_FLOAT { return 8; } - if ti == TI_BOOL { return 1; } - if ti == TI_CHAR { return 4; } - if ti == TI_STR { return 8; } // pointer - if ti == TI_UNIT { return 0; } +fn type_size(ti: int) -> int: + if ti == TI_INT: + return 8 + if ti == TI_FLOAT: + return 8 + if ti == TI_BOOL: + return 1 + if ti == TI_CHAR: + return 4 + if ti == TI_STR: + return 8 + // pointer + if ti == TI_UNIT: + return 0 // Struct: sum field sizes // For now, return 8 as default - return 8; -} + return 8 // Type alignment lookup -fn type_align(ti: int) -> int { - if ti == TI_INT { return 8; } - if ti == TI_FLOAT { return 8; } - if ti == TI_BOOL { return 1; } - if ti == TI_CHAR { return 4; } - if ti == TI_STR { return 8; } - return 8; -} +fn type_align(ti: int) -> int: + if ti == TI_INT: + return 8 + if ti == TI_FLOAT: + return 8 + if ti == TI_BOOL: + return 1 + if ti == TI_CHAR: + return 4 + if ti == TI_STR: + return 8 + return 8 // Check if type has a field -fn ti_has_field(ti: int, name: string) -> int { +fn ti_has_field(ti: int, name: string) -> int: // Search struct fields by name // For now, return 0 (false) — struct field lookup to be implemented - return 0; -} + return 0 // Get field offset -fn ti_field_offset(ti: int, name: string) -> int { - return 0; // placeholder -} +fn ti_field_offset(ti: int, name: string) -> int: + return 0 // placeholder ``` - [ ] **Step 3: Verify IR gen** @@ -465,63 +462,93 @@ jj commit src/arch/linux/ld/instr.cr src/arch/linux/ld/sizes.cr -m "feat: ELF ba ```core // @ builtins test suite -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; -} - -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; -} + if sz != 8: + 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 // Struct type for field tests -struct Point { x: int, y: int } - -fn test_sizeof_struct() -> int { - sz := @sizeOf(Point); - if sz < 8 { return 1; } // at least 2 ints - return 0; -} - -fn test_no_bounds_check() -> int { - @no_bounds_check; - return 0; // just verifies it compiles -} - -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_fields_basic() -> int { - flds := @fields(Point); - if str_len(flds) < 4 { return 1; } // at least contains field names - 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; } - 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; -} +struct Point: + x: int, y: int + +fn test_sizeof_struct() -> int: + sz := @sizeOf(Point) + if sz < 8: + return 1 + // at least 2 ints + return 0 + +fn test_no_bounds_check() -> int: + @no_bounds_check + return 0 // just verifies it compiles + +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_fields_basic() -> int: + flds := @fields(Point) + if str_len(flds) < 4: + return 1 + // at least contains field names + 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 + 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 ``` - [ ] **Step 2: Type-check the test** diff --git a/docs/superpowers/plans/2026-07-29-hotpatch.md b/docs/superpowers/plans/2026-07-29-hotpatch.md index cc57f6d7..5faa8d03 100644 --- a/docs/superpowers/plans/2026-07-29-hotpatch.md +++ b/docs/superpowers/plans/2026-07-29-hotpatch.md @@ -29,7 +29,7 @@ After `IR_SECTION : int = 38;`: ```core -IR_HOTPATCH_ROUTE : int = 39; // dest=result_var, s1=fn_name_ni, s2=first_arg, s3=arg_count +IR_HOTPATCH_ROUTE : int = 39 // dest=result_var, s1=fn_name_ni, s2=first_arg, s3=arg_count ``` - [ ] **Step 2: Add runtime globals to rt.cr** @@ -83,27 +83,25 @@ if g_ast_count > 0 { - [ ] **Step 2: Add helper to parse hotpatch args** ```core -fn extract_hotpatch_ver(args_node: int) -> int { - if args_node < 0 { return -1; } +fn extract_hotpatch_ver(args_node: int) -> int: + if args_node < 0: + return -1 // args_node is EXPR_ARG chain - arg := args_node; - loop { - if arg < 0 { break; } - expr := ast_a(arg); + arg := args_node + loop: + if arg < 0: + break + expr := ast_a(arg) // Expect EXPR_ASSIGN(name=expr): a=name_ni, b=value - 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); // EXPR_INT - } - } - arg = ast_b(arg); - } - return -1; -} + 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) // EXPR_INT + arg = ast_b(arg) + return -1 ``` - [ ] **Step 3: Commit** @@ -241,16 +239,19 @@ jj commit -m "feat: register IR_HOTPATCH_ROUTE in dataflow, opt, ccr_io" - [ ] **Step 1: Add runtime global vars in elf.cr** ```core -gv_hp_config : int, mut = -1; -gv_hp_inflight : int, mut = -1; +gv_hp_config : int, mut = -1 +gv_hp_inflight : int, mut = -1 ``` Add lookup in `elf_gen`: ```core -hp_ni := str_intern("g_hp_config"); hp_ni2 := str_intern("g_hp_inflight"); -if ni == hp_ni { gv_hp_config = r64(g_ir_globals, gvsi * 16 + 8); } -if ni == hp_ni2 { gv_hp_inflight = r64(g_ir_globals, gvsi * 16 + 8); } +hp_ni := str_intern("g_hp_config") +hp_ni2 := str_intern("g_hp_inflight") +if ni == hp_ni: + gv_hp_config = r64(g_ir_globals, gvsi * 16 + 8) +if ni == hp_ni2: + gv_hp_inflight = r64(g_ir_globals, gvsi * 16 + 8) ``` - [ ] **Step 2: Add encoding in instr.cr** @@ -309,39 +310,39 @@ jj commit -m "feat: ELF backend IR_HOTPATCH_ROUTE encoding + runtime globals" // Hotpatch runtime: config management, signal handling, drain tracking import toml -g_hp_config : string, mut; -g_hp_inflight : string, mut; +g_hp_config : string, mut +g_hp_inflight : string, mut // Read and apply .hotpatch.toml -fn hp_load_config() { - tc := read_file(".hotpatch.toml"); - if str_len(tc) > 0 { - cfg := parse_toml(tc); - g_hp_config = cfg; - } -} +fn hp_load_config(): + tc := read_file(".hotpatch.toml") + if str_len(tc) > 0: + cfg := parse_toml(tc) + g_hp_config = cfg // Increment in-flight counter for a version -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 in-flight counter -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 -fn hp_init() { - g_hp_config = ""; - g_hp_inflight = alloc(64 * 8); // 64 version slots +fn hp_init(): + g_hp_config = "" + g_hp_inflight = alloc(64 * 8) // 64 version slots // Zero-init - 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() ``` - [ ] **Step 2: Add SIGHUP handler in rt.s** @@ -382,29 +383,28 @@ jj commit -m "feat: hotpatch runtime — config load, SIGHUP handler, in-flight ```core import toml -fn test_hotpatch_config_load() -> int { - tc := read_file(".hotpatch.toml"); - if str_len(tc) > 0 { - cfg := parse_toml(tc); - if str_len(cfg) > 0 { return 0; } - } - return 1; -} +fn test_hotpatch_config_load() -> int: + tc := read_file(".hotpatch.toml") + if str_len(tc) > 0: + cfg := parse_toml(tc) + if str_len(cfg) > 0: + return 0 + return 1 -fn test_hotpatch_basic() -> int { +fn test_hotpatch_basic() -> int: // Test that @hotpatch compiles - @hotpatch(ver=1); - return 0; -} - -fn main() -> int { - r1 := test_hotpatch_basic(); - if r1 != 0 { return r1; } - r2 := test_hotpatch_config_load(); - if r2 != 0 { return r2; } - println("ALL PASS"); - return 0; -} + @hotpatch(ver=1) + return 0 + +fn main() -> int: + r1 := test_hotpatch_basic() + if r1 != 0: + return r1 + r2 := test_hotpatch_config_load() + if r2 != 0: + return r2 + println("ALL PASS") + return 0 ``` - [ ] **Step 2: Verify** diff --git a/docs/superpowers/plans/2026-07-29-incremental-cache.md b/docs/superpowers/plans/2026-07-29-incremental-cache.md index 4c45f8e0..dbaa13b7 100644 --- a/docs/superpowers/plans/2026-07-29-incremental-cache.md +++ b/docs/superpowers/plans/2026-07-29-incremental-cache.md @@ -481,13 +481,11 @@ Note: The actual implementation needs to adapt to the existing `ir_gen_all_funcs If needed, add helper to get the source file path for function ID construction. ```core -fn get_source_path() -> string { - return g_source_path; // already set during file loading -} +fn get_source_path() -> string: + return g_source_path // already set during file loading -fn fi_name_ni(fi: int) -> int { - return r64(g_ir_func_name_idx, fi * 8); -} +fn fi_name_ni(fi: int) -> int: + return r64(g_ir_func_name_idx, fi * 8) ``` - [ ] **Step 3: Verify compilation** @@ -552,23 +550,24 @@ jj commit -m "feat: clean-cache subcommand" // Compiles a simple program twice, verifies the second run is faster // (or at least produces the same output). -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; -} - -fn main() -> int { - r1 := test_cache_basic(); - if r1 != 0 { print("FAIL: "); println(int_str(r1)); return r1; } - println("ALL PASS"); - 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 ``` - [ ] **Step 2: Verify type-check** diff --git a/docs/superpowers/plans/2026-07-30-concurrency.md b/docs/superpowers/plans/2026-07-30-concurrency.md index 035bc265..f9841a04 100644 --- a/docs/superpowers/plans/2026-07-30-concurrency.md +++ b/docs/superpowers/plans/2026-07-30-concurrency.md @@ -119,42 +119,41 @@ import arena import sched // Goroutine lifecycle -g_next_id : int, mut = 1; +g_next_id : int, mut = 1 -fn g_new(entry_fn: int, arg: int, arg_type: int) -> int { +fn g_new(entry_fn: int, arg: int, arg_type: int) -> int: // Allocate stack (16KB) - stack := alloc(16384); - stack_top := stack + 16384 - 8; - + stack := alloc(16384) + stack_top := stack + 16384 - 8 + // Create new arena for this goroutine - aid := arena_new(); - + aid := arena_new() + // Initialize fiber - sp := fiber_init(stack_top, entry_fn); - + sp := fiber_init(stack_top, entry_fn) + // Allocate G struct - g := alloc(64); + g := alloc(64) // G layout: id(8), status(8), sp(8), stack_lo(8), arena_id(8), chan_wait(8), next(8) - 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, -1); // chan_wait = -1 - w64(g, 48, -1); // next = -1 - + 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, -1) // chan_wait = -1 + w64(g, 48, -1) // next = -1 + // Enqueue to scheduler - sched_enqueue(g); - - return g; -} + sched_enqueue(g) + + return g -fn g_free(g: int) { +fn g_free(g: int): // Reset arena - aid := r64(g, 32); - arena_reset(aid); -} + aid := r64(g, 32) + arena_reset(aid) ``` - [ ] **Step 2: Create sched.cr** @@ -162,76 +161,67 @@ fn g_free(g: int) { ```core // M:N scheduler — M OS threads, N goroutines -g_machines : string, mut; // M array -g_machine_count : int, mut; +g_machines : string, mut // M array +g_machine_count : int, mut -g_global_runq_head : int, mut = -1; // global run queue -g_global_runq_tail : int, mut = -1; +g_global_runq_head : int, mut = -1 // global run queue +g_global_runq_tail : int, mut = -1 -fn sched_init() { +fn sched_init(): // 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_machine_count = 1; -} - -fn sched_enqueue(g: int) { + 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_machine_count = 1 + +fn sched_enqueue(g: int): // Add to global run queue (simple for now) - if g_global_runq_head < 0 { - g_global_runq_head = g; - g_global_runq_tail = g; - } else { - w64(g_global_runq_tail, 48, g); // next = g - g_global_runq_tail = g; - } -} - -fn sched_dequeue() -> int { - g := g_global_runq_head; - if g >= 0 { - g_global_runq_head = r64(g, 48); // g.next - if g_global_runq_head < 0 { g_global_runq_tail = -1; } - w64(g, 48, -1); // clear next - } - return g; -} - -fn sched_yield() { + if g_global_runq_head < 0: + g_global_runq_head = g + g_global_runq_tail = g + else: + w64(g_global_runq_tail, 48, g) // next = g + g_global_runq_tail = g + +fn sched_dequeue() -> int: + g := g_global_runq_head + if g >= 0: + g_global_runq_head = r64(g, 48) // g.next + if g_global_runq_head < 0: + g_global_runq_tail = -1 + w64(g, 48, -1) // clear next + return g + +fn sched_yield(): // Current goroutine yields - m_idx := 0; // single M - cur_g := r64(g_machines, m_idx * 32 + 8); - + m_idx := 0 // single M + cur_g := r64(g_machines, m_idx * 32 + 8) + // Re-enqueue current G - if cur_g >= 0 { - w64(cur_g, 8, 0); // _Grunnable - sched_enqueue(cur_g); - } - + if cur_g >= 0: + w64(cur_g, 8, 0) // _Grunnable + sched_enqueue(cur_g) + // Schedule next - sched_schedule(); -} + sched_schedule() -fn sched_schedule() { - m_idx := 0; - next_g := sched_dequeue(); - if next_g >= 0 { - old_g := r64(g_machines, m_idx * 32 + 8); - w64(g_machines, m_idx * 32 + 8, next_g); - w64(next_g, 8, 1); // _Grunning - - if old_g >= 0 { +fn sched_schedule(): + m_idx := 0 + next_g := sched_dequeue() + if next_g >= 0: + old_g := r64(g_machines, m_idx * 32 + 8) + w64(g_machines, m_idx * 32 + 8, 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 - } -} ``` - [ ] **Step 3: Create chan.cr** @@ -239,82 +229,74 @@ fn sched_schedule() { ```core // Channel: typed FIFO, goroutine-safe -fn chan_make(elemsize: int, cap: int) -> int { - ch := alloc(56); - 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: int, val: int) { +fn chan_make(elemsize: int, cap: int) -> int: + ch := alloc(56) + 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: int, val: int): // Copy val into channel buffer - buf := r64(ch, 0); - cap := r64(ch, 8); - len := r64(ch, 16); - head := r64(ch, 24); - esize := r64(ch, 32); - - if len < cap { + buf := r64(ch, 0) + cap := r64(ch, 8) + len := r64(ch, 16) + head := r64(ch, 24) + esize := r64(ch, 32) + + if len < cap: // Buffer has space - tail := (head + len) % cap; - w64(buf, tail * esize, val); - w64(ch, 16, len + 1); - } else { + tail := (head + len) % cap + w64(buf, tail * esize, val) + w64(ch, 16, len + 1) + else: // Buffer full: block current goroutine // For now: simple blocking wait (yield + retry) // In full implementation: add to send_wait list - loop { - sched_yield(); - len := r64(ch, 16); - if len < cap { continue; } - tail := (head + len) % cap; - w64(buf, tail * esize, val); - w64(ch, 16, len + 1); - break; - } - } -} + loop: + sched_yield() + len := r64(ch, 16) + if len < cap: + continue + tail := (head + len) % cap + w64(buf, tail * esize, val) + w64(ch, 16, len + 1) + break + +fn chan_recv(ch: int) -> int: + buf := r64(ch, 0) + cap := r64(ch, 8) + len := r64(ch, 16) + head := r64(ch, 24) + esize := r64(ch, 32) + + if len > 0: + val := r64(buf, head * esize) + w64(ch, 24, (head + 1) % cap) + w64(ch, 16, len - 1) + return val -fn chan_recv(ch: int) -> int { - buf := r64(ch, 0); - cap := r64(ch, 8); - len := r64(ch, 16); - head := r64(ch, 24); - esize := r64(ch, 32); - - if len > 0 { - val := r64(buf, head * esize); - w64(ch, 24, (head + 1) % cap); - w64(ch, 16, len - 1); - return val; - } - // Buffer empty: block (yield + retry) - loop { - sched_yield(); - len := r64(ch, 16); - if len > 0 { - head := r64(ch, 24); - val := r64(buf, head * esize); - w64(ch, 24, (head + 1) % cap); - w64(ch, 16, len - 1); - return val; - } - } -} - -fn chan_close(ch: int) { - w64(ch, 56, 1); // closed = true + loop: + sched_yield() + len := r64(ch, 16) + if len > 0: + head := r64(ch, 24) + val := r64(buf, head * esize) + w64(ch, 24, (head + 1) % cap) + w64(ch, 16, len - 1) + return val + +fn chan_close(ch: int): + w64(ch, 56, 1) // closed = true // Wake up all waiting senders/receivers // ... (for now, just mark closed) -} ``` - [ ] **Step 4: Verify compilation** @@ -420,18 +402,19 @@ jj commit -m "feat: ELF backend IR_SPAWN/IR_YIELD encoding" ```core import io -fn test_go_basic() -> int { +fn test_go_basic() -> int: // Just verify go compiles - 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; -} + 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 ``` - [ ] **Step 2: Write channel test** @@ -439,21 +422,24 @@ fn main() -> int { ```core import io -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 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 ``` - [ ] **Step 3: Verify** diff --git a/docs/superpowers/plans/2026-07-30-dynamic-typing.md b/docs/superpowers/plans/2026-07-30-dynamic-typing.md index 66cb17e3..704e6b5e 100644 --- a/docs/superpowers/plans/2026-07-30-dynamic-typing.md +++ b/docs/superpowers/plans/2026-07-30-dynamic-typing.md @@ -28,26 +28,26 @@ After `TI_CHAR : int = 6;`: ```core -TI_DYN : int = 7; // dynamic type +TI_DYN : int = 7 // dynamic type ``` After `TYP_TUPLE : int = 10;`: ```core -TYP_DYN : int = 11; // data = type set bitmap (0 = single known type) +TYP_DYN : int = 11 // data = type set bitmap (0 = single known type) ``` After `IR_SECTION : int = 38;`: ```core -IR_DYN_TAG : int = 41; // dest=tag_var, s1=dyn_var — extract tag -IR_DYN_VAL : int = 42; // dest=val_var, s1=dyn_var — extract value -IR_DYN_PACK : int = 43; // dest=dyn_var, s1=val_var, s2=type_idx — pack dyn -IR_DYN_DISPATCH : int = 44; // s1=dyn_var, s2=dispatch_table_ni — dispatch by tag +IR_DYN_TAG : int = 41 // dest=tag_var, s1=dyn_var — extract tag +IR_DYN_VAL : int = 42 // dest=val_var, s1=dyn_var — extract value +IR_DYN_PACK : int = 43 // dest=dyn_var, s1=val_var, s2=type_idx — pack dyn +IR_DYN_DISPATCH : int = 44 // s1=dyn_var, s2=dispatch_table_ni — dispatch by tag ``` - [ ] **Step 2: Add token to keywords.cr** ```core -T_DYN : int = 48; +T_DYN : int = 48 ``` - [ ] **Step 3: Commit** @@ -94,35 +94,55 @@ jj commit src/compiler/parser.cr -m "feat: parse dyn keyword" ```core // Per-variable type set: bitmap of possible types for dyn variables -g_dyn_type_sets : string, mut; // dyn type info per variable -g_dyn_type_set_count : int, mut; -g_dyn_type_set_cap : int, mut; - -fn grow_dyn_type_sets(needed: int) { - if needed < g_dyn_type_set_cap { return; } - nc := g_dyn_type_set_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 8); _dyncpy(g_dyn_type_sets, g_dyn_type_set_cap * 8, nb); - g_dyn_type_sets = nb; g_dyn_type_set_cap = nc; -} +g_dyn_type_sets : string, mut // dyn type info per variable +g_dyn_type_set_count : int, mut +g_dyn_type_set_cap : int, mut + +fn grow_dyn_type_sets(needed: int): + if needed < g_dyn_type_set_cap: + return + nc := g_dyn_type_set_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 8) + _dyncpy(g_dyn_type_sets, g_dyn_type_set_cap * 8, nb) + g_dyn_type_sets = nb + g_dyn_type_set_cap = nc // Set a bit in the type set for a variable -fn dyn_set_type(var_idx: int, ti: int) { - grow_dyn_type_sets(var_idx + 1); - old := r64(g_dyn_type_sets, var_idx * 8); - bit := 1; - if ti >= 0 && ti < 64 { bit = 1; shl := ti; loop { if shl <= 0 { break; } bit = bit * 2; shl = shl - 1; } } - w64(g_dyn_type_sets, var_idx * 8, old + bit); -} +fn dyn_set_type(var_idx: int, ti: int): + grow_dyn_type_sets(var_idx + 1) + old := r64(g_dyn_type_sets, var_idx * 8) + bit := 1 + if ti >= 0 && ti < 64: + bit = 1 + shl := ti + loop: + if shl <= 0: + break + bit = bit * 2 + shl = shl - 1 + w64(g_dyn_type_sets, var_idx * 8, old + bit) // Check if a type is in the set -fn dyn_has_type(var_idx: int, ti: int) -> int { - if var_idx < 0 || var_idx >= g_dyn_type_set_count { return 0; } - set := r64(g_dyn_type_sets, var_idx * 8); - bit := 1; - if ti >= 0 && ti < 64 { bit = 1; shl := ti; loop { if shl <= 0 { break; } bit = bit * 2; shl = shl - 1; } } - if (set / bit) % 2 != 0 { return 1; } - return 0; -} +fn dyn_has_type(var_idx: int, ti: int) -> int: + if var_idx < 0 || var_idx >= g_dyn_type_set_count: + return 0 + set := r64(g_dyn_type_sets, var_idx * 8) + bit := 1 + if ti >= 0 && ti < 64: + bit = 1 + shl := ti + loop: + if shl <= 0: + break + bit = bit * 2 + shl = shl - 1 + if (set / bit) % 2 != 0: + return 1 + return 0 ``` - [ ] **Step 2: Track types at assignment** @@ -140,10 +160,9 @@ if target_type == TI_DYN { In if/else handling, after processing both branches, merge dyn type sets: ```core -fn merge_dyn_types(target_var: int, then_set: int, else_set: int) { +fn merge_dyn_types(target_var: int, then_set: int, else_set: int): // Union the type sets - w64(g_dyn_type_sets, target_var * 8, then_set + else_set); -} + w64(g_dyn_type_sets, target_var * 8, then_set + else_set) ``` - [ ] **Step 4: Validate method calls on dyn values** @@ -336,44 +355,50 @@ jj commit -m "feat: ELF backend dyn opcode encoding" ```core 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; -} - -fn test_dyn_multi_path() -> int { - cond : int = 1; - x : dyn = 0; - if cond != 0 { - x = 42; - } else { - x = "hello"; - } + 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" // x could be int or string // Just verify it compiles and runs - 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; -} + 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 ``` - [ ] **Step 2: Verify** diff --git a/docs/superpowers/plans/2026-07-30-ffi.md b/docs/superpowers/plans/2026-07-30-ffi.md index 8dd3ebc2..5959adcd 100644 --- a/docs/superpowers/plans/2026-07-30-ffi.md +++ b/docs/superpowers/plans/2026-07-30-ffi.md @@ -26,9 +26,9 @@ - [ ] **Step 1: Add T_EXTERN token and IR opcode** ```core -T_EXTERN : int = 100; -EXPR_EXTERN : int = 48; // a=name_ni, b=first_param, c=param_count, data=ffi_lang_ni -IR_CALL_EXTERN : int = 45; // dest=result_var, s1=func_name_ni, s2=first_arg, s3=arg_count +T_EXTERN : int = 100 +EXPR_EXTERN : int = 48 // a=name_ni, b=first_param, c=param_count, data=ffi_lang_ni +IR_CALL_EXTERN : int = 45 // dest=result_var, s1=func_name_ni, s2=first_arg, s3=arg_count ``` - [ ] **Step 2: Commit** @@ -85,22 +85,32 @@ if tok_k(cur_tok()) == T_EXTERN { - [ ] **Step 2: Parse @ffi("lang") annotation** ```core -fn parse_ffi_annotation() -> int { +fn parse_ffi_annotation() -> int: // Current token is T_AT - 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_STR { add_error("expected string literal"); return -1; } - lang_ni := tok_lx(cur_tok()); advance_tok(); - if tok_k(cur_tok()) != T_RPAREN { add_error("expected )"); return -1; } - advance_tok(); - return lang_ni; -} + if tok_k(cur_tok()) != T_LPAREN: + add_error("expected (") + return -1 + advance_tok() + if tok_k(cur_tok()) != T_STR: + add_error("expected string literal") + return -1 + lang_ni := tok_lx(cur_tok()) + advance_tok() + if tok_k(cur_tok()) != T_RPAREN: + add_error("expected )") + return -1 + advance_tok() + return lang_ni ``` - [ ] **Step 3: Commit** @@ -263,18 +273,19 @@ jj commit -m "feat: register IR_CALL_EXTERN in dataflow/opt/ccr" ```core import io -fn test_extern_decl() -> int { +fn test_extern_decl() -> int: // Just verifying extern fn compiles - extern fn getchar() -> int; - return 0; -} - -fn main() -> int { - r1 := test_extern_decl(); - if r1 != 0 { print("FAIL: "); println(int_str(r1)); return r1; } - println("ALL PASS"); - return 0; -} + extern fn getchar() -> int + return 0 + +fn main() -> int: + r1 := test_extern_decl() + if r1 != 0: + print("FAIL: ") + println(int_str(r1)) + return r1 + println("ALL PASS") + return 0 ``` - [ ] **Step 2: Verify** diff --git a/docs/superpowers/plans/2026-07-30-generics.md b/docs/superpowers/plans/2026-07-30-generics.md index ef857cd2..9234530d 100644 --- a/docs/superpowers/plans/2026-07-30-generics.md +++ b/docs/superpowers/plans/2026-07-30-generics.md @@ -150,48 +150,49 @@ jj commit -m "feat: checker generic param registration + type derivation" // a specialized copy registered in g_funcs/g_structs. // Instance cache: maps (func_name × type_args) → specialized func index -g_gen_instances : string, mut; -g_gen_instance_count : int, mut; -g_gen_instance_cap : int, mut; - -fn grow_gen_instances(needed: int) { - if needed < g_gen_instance_cap { return; } - nc := g_gen_instance_cap * 2; if nc < 64 { nc = 64; } if nc < needed { nc = needed + 64; } - nb := alloc(nc * 24); // 3 × 8 bytes per entry - _dyncpy(g_gen_instances, g_gen_instance_cap * 24, nb); - g_gen_instances = nb; g_gen_instance_cap = nc; -} +g_gen_instances : string, mut +g_gen_instance_count : int, mut +g_gen_instance_cap : int, mut + +fn grow_gen_instances(needed: int): + if needed < g_gen_instance_cap: + return + nc := g_gen_instance_cap * 2 + if nc < 64: + nc = 64 + if nc < needed: + nc = needed + 64 + nb := alloc(nc * 24) // 3 × 8 bytes per entry + _dyncpy(g_gen_instances, g_gen_instance_cap * 24, nb) + g_gen_instances = nb + g_gen_instance_cap = nc // Find or create a specialized instance. // func_ni = original generic function name 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 { +fn gen_find_or_create(func_ni: int, type_args: string) -> int: // Scan cache - i := 0; - loop { - if i >= g_gen_instance_count { break; } - if r64(g_gen_instances, i * 24) == func_ni { - existing_args := ...; // read type_args from cache entry - if str_eq(existing_args, type_args) != 0 { - return r64(g_gen_instances, i * 24 + 16); // return specialized func idx - } - } - i = i + 1; - } + i := 0 + loop: + if i >= g_gen_instance_count: + break + if r64(g_gen_instances, i * 24) == func_ni: + existing_args := ... // read type_args from cache entry + if str_eq(existing_args, type_args) != 0: + return r64(g_gen_instances, i * 24 + 16) // return specialized func idx + i = i + 1 // Not found: create new instance - return gen_create_instance(func_ni, type_args); -} + return gen_create_instance(func_ni, type_args) // Create a specialized copy of a generic function. -fn gen_create_instance(func_ni: int, type_args: string) -> int { +fn gen_create_instance(func_ni: int, type_args: string) -> int: // 1. Find the original generic function AST // 2. Clone the function AST node // 3. Replace all TYP_GENERIC_PARAM references with concrete types // 4. Register the new function in g_funcs // 5. Cache it // 6. Return the new function index -} ``` - [ ] **Step 2: Add to build system** @@ -247,36 +248,42 @@ jj commit src/compiler/ir_gen.cr -m "feat: IR gen generic call → specialized v ```core import io -fn identity(x: T) -> T { return x; } +fn identity(x: T) -> T: + return x -fn test_generic_fn() -> int { - x := identity(42); - if x != 42 { return 1; } - return 0; -} +fn test_generic_fn() -> int: + x := identity(42) + if x != 42: + return 1 + return 0 -struct Box { val: T } +struct Box: + val: T -fn test_generic_struct() -> int { - b := Box{val=100}; - if b.val != 100 { return 1; } - return 0; -} +fn test_generic_struct() -> int: + b := Box{val=100} + if b.val != 100: + return 1 + return 0 -fn test_multi_param() -> int { +fn test_multi_param() -> int: // struct Pair { first: A; second: B } // p := Pair{first=1, second="hello"} - return 0; -} - -fn main() -> int { - r1 := test_generic_fn(); - if r1 != 0 { print("FAIL generic_fn: "); println(int_str(r1)); return r1; } - r2 := test_generic_struct(); - if r2 != 0 { print("FAIL generic_struct: "); println(int_str(r2)); return r2; } - println("ALL PASS"); - return 0; -} + return 0 + +fn main() -> int: + r1 := test_generic_fn() + if r1 != 0: + print("FAIL generic_fn: ") + println(int_str(r1)) + return r1 + r2 := test_generic_struct() + if r2 != 0: + print("FAIL generic_struct: ") + println(int_str(r2)) + return r2 + println("ALL PASS") + return 0 ``` - [ ] **Step 2: Verify type-check** diff --git a/docs/superpowers/plans/2026-07-30-lazy-eval.md b/docs/superpowers/plans/2026-07-30-lazy-eval.md index 864221de..f7af80ff 100644 --- a/docs/superpowers/plans/2026-07-30-lazy-eval.md +++ b/docs/superpowers/plans/2026-07-30-lazy-eval.md @@ -27,8 +27,8 @@ **Step 1: Add IR opcodes to ast.cr** ```core -IR_LAZY_THUNK : int = 46; // dest=thunk_var, s1=expr_var — wrap as lazy thunk -IR_LAZY_FORCE : int = 47; // dest=val_var, s1=thunk_var — force evaluation +IR_LAZY_THUNK : int = 46 // dest=thunk_var, s1=expr_var — wrap as lazy thunk +IR_LAZY_FORCE : int = 47 // dest=val_var, s1=thunk_var — force evaluation ``` **Step 2: Add side-effect tracking to checker.cr** @@ -58,10 +58,9 @@ jj commit -m "feat: add IR_LAZY_THUNK/FORCE + pure function tracking" After all nodes are created, count how many consumers each producer has: ```core -fn compute_usage_counts() { +fn compute_usage_counts(): // For each edge, increment consumer count of the source node // Store in g_node_use_count[] -} ``` Variables used in only one branch of a conditional are candidates for laziness. @@ -153,24 +152,25 @@ jj commit -m "feat: lazy opcode registration + ELF encoding" ```core 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; -} - -fn main() -> int { - r1 := test_lazy_basic(); - if r1 != 0 { print("FAIL: "); println(int_str(r1)); return r1; } - println("ALL PASS"); - 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 ``` **Step 2: Verify** diff --git a/docs/superpowers/plans/2026-08-08-region-cfg.md b/docs/superpowers/plans/2026-08-08-region-cfg.md index 03d11ae7..e3d72dc9 100644 --- a/docs/superpowers/plans/2026-08-08-region-cfg.md +++ b/docs/superpowers/plans/2026-08-08-region-cfg.md @@ -73,12 +73,12 @@ Expected: FAIL — 断言 `'Region: if' in out` 失败(cir dump 尚无 Region `src/compiler/dataflow.cr:104-106` 常量区追加: ```core -SG_FUNC : int = 0; -SG_LOOP : int = 1; -SG_FOR : int = 2; -SG_FLOW : int = 3; -SG_UNSAFE : int = 4; -SG_IF : int = 5; // conditional region: covers [condition, merge) +SG_FUNC : int = 0 +SG_LOOP : int = 1 +SG_FOR : int = 2 +SG_FLOW : int = 3 +SG_UNSAFE : int = 4 +SG_IF : int = 5 // conditional region: covers [condition, merge) ``` - [ ] **Step 4: if/else 生成 SG_IF** @@ -173,21 +173,24 @@ Expected: FAIL(`cluster_for` 不存在) ```core // sg_pop:弹出最后一个 open(EXIT<0)的 region,而非 g_sg_count-1 -fn sg_pop() { - if g_sg_count <= 0 { return; } - idx : ., mut = -1; - pi := g_sg_count - 1; - loop { - if pi < 0 { break; } - if r64(g_sgs, pi * ESZ_SG + OFF_SG_EXIT) < 0 { idx = pi; break; } - pi = pi - 1; - } - if idx < 0 { return; } - w64(g_sgs, idx * ESZ_SG + OFF_SG_EXIT, g_df_node_count); +fn sg_pop(): + if g_sg_count <= 0: + return + idx : ., mut = -1 + pi := g_sg_count - 1 + loop: + if pi < 0: + break + if r64(g_sgs, pi * ESZ_SG + OFF_SG_EXIT) < 0: + idx = pi + break + pi = pi - 1 + if idx < 0: + return + w64(g_sgs, idx * ESZ_SG + OFF_SG_EXIT, g_df_node_count) w64(g_sgs, idx * ESZ_SG + OFF_SG_NCOUNT, - g_df_node_count - r64(g_sgs, idx * ESZ_SG + OFF_SG_NSTART)); - g_cur_sg = r64(g_sgs, idx * ESZ_SG + OFF_SG_PARENT); -} + g_df_node_count - r64(g_sgs, idx * ESZ_SG + OFF_SG_NSTART)) + g_cur_sg = r64(g_sgs, idx * ESZ_SG + OFF_SG_PARENT) ``` 验证修复(dump 断言):if 后跟尾代码的函数,`Region: if nodes A..B` 的 B 必须等于 merge label 处节点数(不吞尾代码)。测试:`tests/selfhost/test_region_cfg.py` 的 if/for 用例改为断言区域边界在函数指令跨度内(sanity 检查)。 @@ -205,13 +208,12 @@ g_cur_sg : int, mut; // currently open region id (-1 = none) ```core // df_create_node 内、g_df_node_count = nid 递增之前插入(约 68-90 行): -fn df_create_node(opcode: int, dest: int, src1: int, src2: int, src3: int, type_kind: int) -> int { - nid := g_df_node_count; - grow_df_nodes(nid + 1); - grow_df_node_region(nid + 1); - w64(g_df_node_region, nid * 8, g_cur_sg); +fn df_create_node(opcode: int, dest: int, src1: int, src2: int, src3: int, type_kind: int) -> int: + nid := g_df_node_count + grow_df_nodes(nid + 1) + grow_df_node_region(nid + 1) + w64(g_df_node_region, nid * 8, g_cur_sg) // ... 现有初始化不变 ... -} ``` (`grow_df_node_region` 照 `grow_df_nodes` 模式实现:cap 倍增、_dyncpy 复制。) @@ -453,13 +455,14 @@ OFF_DFE_KIND : int = 24; // 0=data (def-use), 1=state (ordering/termination) ```core // df_add_edge 改为带 kind 版本;原 df_add_edge 保持 0 参数语义内部调 df_add_edge_kind(..., 0) -fn df_add_edge_kind(from_id: int, to_id: int, kind: int) { - if from_id < 0 || to_id < 0 { return; } +fn df_add_edge_kind(from_id: int, to_id: int, kind: int): + if from_id < 0 || to_id < 0: + return // ... 原 df_add_edge 逻辑(grow_df_edges、写 from/to/next、g_df_edge_count 递增)... - w64(g_df_edges, (g_df_edge_count - 1) * ESZ_DFEDGE + OFF_DFE_KIND, kind); -} + w64(g_df_edges, (g_df_edge_count - 1) * ESZ_DFEDGE + OFF_DFE_KIND, kind) -fn df_add_edge(from_id: int, to_id: int) { df_add_edge_kind(from_id, to_id, 0); } +fn df_add_edge(from_id: int, to_id: int): + df_add_edge_kind(from_id, to_id, 0) ``` 副作用链(模块级变量,df_begin_func 重置): @@ -467,18 +470,22 @@ fn df_add_edge(from_id: int, to_id: int) { df_add_edge_kind(from_id, to_id, 0); ```core // df_begin_func 中:g_last_state_node = -1; // df_connect_srcs 内,opcode 判定为副作用时: -fn df_connect_state(node_id: int, opcode: int) { - is_side_effect : ., mut = 0; - if opcode == IR_STORE { is_side_effect = 1; } - if opcode == IR_STORE_FIELD { is_side_effect = 1; } - if opcode == IR_STORE_INDEX { is_side_effect = 1; } - if opcode == IR_STORE_INDEX_VAR { is_side_effect = 1; } - if opcode == IR_CALL && fi_ispure(find_func(/*当前函数*/)) == 0 { is_side_effect = 1; } - if is_side_effect != 0 { - if g_last_state_node >= 0 { df_add_edge_kind(g_last_state_node, node_id, 1); } - g_last_state_node = node_id; - } -} +fn df_connect_state(node_id: int, opcode: int): + is_side_effect : ., mut = 0 + if opcode == IR_STORE: + is_side_effect = 1 + if opcode == IR_STORE_FIELD: + is_side_effect = 1 + if opcode == IR_STORE_INDEX: + is_side_effect = 1 + if opcode == IR_STORE_INDEX_VAR: + is_side_effect = 1 + if opcode == IR_CALL && fi_ispure(find_func(/*当前函数*/)) == 0: + is_side_effect = 1 + if is_side_effect != 0: + if g_last_state_node >= 0: + df_add_edge_kind(g_last_state_node, node_id, 1) + g_last_state_node = node_id ``` (`IR_CALL` 的纯度判定:call 的 s3 是 func name idx——`fi_ispure` 需要 func index;实现时经 `find_func(s3)` 获得。非纯调用才进链。若 find_func 不可得(外部函数),保守进链。) @@ -589,26 +596,32 @@ Expected: 当前即 PASS(v2 未加,但 ELF 路径不受影响)——本测 `src/compiler/ccr_io.cr` 的 load:版本判断处(当前读取 version 的位置)改为: ```core - ver := <读出的 version 字段>; - // v4(无 SG 段):跳过 SG 读取,g_sg_count = 0 - // v5:按 Step 3 布局读取 SG 段并回填 g_sgs - if ver >= 5 { - sg_n := buf_read_i32(buf, pos); pos = pos + 4; - si = 0; - loop { - if si >= sg_n { break; } - grow_sg(si + 1); - f = si * ESZ_SG; - w64(g_sgs, f + OFF_SG_KIND, buf_read_i32(buf, pos)); pos = pos + 4; - w64(g_sgs, f + OFF_SG_ENTER, buf_read_i32(buf, pos)); pos = pos + 4; - w64(g_sgs, f + OFF_SG_EXIT, buf_read_i32(buf, pos)); pos = pos + 4; - w64(g_sgs, f + OFF_SG_PARENT, buf_read_i32(buf, pos)); pos = pos + 4; - w64(g_sgs, f + OFF_SG_NSTART, buf_read_i32(buf, pos)); pos = pos + 4; - w64(g_sgs, f + OFF_SG_NCOUNT, buf_read_i32(buf, pos)); pos = pos + 4; - si = si + 1; - } - g_sg_count = sg_n; - } + ver := <读出的 version 字段> + // v4(无 SG 段):跳过 SG 读取,g_sg_count = 0 + // v5:按 Step 3 布局读取 SG 段并回填 g_sgs + if ver >= 5: + sg_n := buf_read_i32(buf, pos) + pos = pos + 4 + si = 0 + loop: + if si >= sg_n: + break + grow_sg(si + 1) + f = si * ESZ_SG + w64(g_sgs, f + OFF_SG_KIND, buf_read_i32(buf, pos)) + pos = pos + 4 + w64(g_sgs, f + OFF_SG_ENTER, buf_read_i32(buf, pos)) + pos = pos + 4 + w64(g_sgs, f + OFF_SG_EXIT, buf_read_i32(buf, pos)) + pos = pos + 4 + w64(g_sgs, f + OFF_SG_PARENT, buf_read_i32(buf, pos)) + pos = pos + 4 + w64(g_sgs, f + OFF_SG_NSTART, buf_read_i32(buf, pos)) + pos = pos + 4 + w64(g_sgs, f + OFF_SG_NCOUNT, buf_read_i32(buf, pos)) + pos = pos + 4 + si = si + 1 + g_sg_count = sg_n ``` - [ ] **Step 5: 兼容性回归——旧 v4 文件** @@ -675,13 +688,11 @@ Expected: 当前即 PASS(B010 已在)——本测试为迁移后的守卫。 `src/compiler/region_check.cr:36-49` 的 `subgraph_containing(ni)`(当前线性扫 g_sgs 区间)改为: ```core -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; -} + if node_seq >= 0 && node_seq < g_df_node_count: + return r64(g_df_node_region, node_seq * 8) + return -1 ``` (调用处 `alloc_seq_to_sg` 仍保留其现有逻辑——两者语义对齐:region id == g_sgs 索引。) diff --git a/docs/superpowers/plans/2026-08-15-mctt-core-kernel.md b/docs/superpowers/plans/2026-08-15-mctt-core-kernel.md index 19f7a072..8c4bc07a 100644 --- a/docs/superpowers/plans/2026-08-15-mctt-core-kernel.md +++ b/docs/superpowers/plans/2026-08-15-mctt-core-kernel.md @@ -408,28 +408,38 @@ Expected: 确认 `str_len(s)`、`chr(n)`、`int_str(n)`、字符串比较/拼接 // src/kernel/term_io.cr —— 共享格式协议实现(Task 5) // 扁平 arena:g_kernel_nodes 五槽一组 {kind, a, b, c, d},索引 = 起始槽 // 槽 0..4 = 节点 0,槽 5..9 = 节点 1,…… -g_kernel_nodes : [int; 8192] = [0; 8192]; -g_kernel_count : int = 0; +g_kernel_nodes : [int; 8192] = [0; 8192] +g_kernel_count : int = 0 // 常量 -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; - -fn kern_new(k: int) -> int { - i := g_kernel_count * 5; - g_kernel_nodes[i] = k; g_kernel_nodes[i+1] = 0; g_kernel_nodes[i+2] = 0; - g_kernel_nodes[i+3] = 0; g_kernel_nodes[i+4] = 0; - g_kernel_count = g_kernel_count + 1; - return i; -} -fn kern_set(n: int, slot: int, v: int) { - g_kernel_nodes[n + slot] = v; -} -fn kern_get(n: int, slot: int) -> int { - return g_kernel_nodes[n + slot]; -} +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 + +fn kern_new(k: int) -> int: + i := g_kernel_count * 5 + g_kernel_nodes[i] = k + g_kernel_nodes[i+1] = 0 + g_kernel_nodes[i+2] = 0 + g_kernel_nodes[i+3] = 0 + g_kernel_nodes[i+4] = 0 + g_kernel_count = g_kernel_count + 1 + return i +fn kern_set(n: int, slot: int, v: int): + g_kernel_nodes[n + slot] = v +fn kern_get(n: int, slot: int) -> int: + return g_kernel_nodes[n + slot] ``` (解析与打印函数在本任务执行中补齐:`kernel_parse` 手写递归下降(跳过空白、读 `(token ...)`、数字用 `int_str` 反向解析——`str_to_int` 若无则用逐位 `(ch-'0')` 累加);`kernel_print` 按协议对节点递归打印,var/succ 等单子节点直接递归。测试先写。) diff --git a/docs/superpowers/plans/2026-08-16-corelsp.md b/docs/superpowers/plans/2026-08-16-corelsp.md index f9399377..c6581400 100644 --- a/docs/superpowers/plans/2026-08-16-corelsp.md +++ b/docs/superpowers/plans/2026-08-16-corelsp.md @@ -61,10 +61,9 @@ import globals // corelsp 入口 import _import -fn lsp_main() -> int { +fn lsp_main() -> int: // Task 1:骨架——完整帧循环在 Task 2 - return 0; -} + return 0 ``` - [ ] **Step 2: build_selfhost_native.py 加第三段(先例 = corearch 段,约 line 167-194)** diff --git a/docs/superpowers/plans/2026-09-05-lattice-ir-v6.md b/docs/superpowers/plans/2026-09-05-lattice-ir-v6.md index 139f218d..a5cf09a2 100644 --- a/docs/superpowers/plans/2026-09-05-lattice-ir-v6.md +++ b/docs/superpowers/plans/2026-09-05-lattice-ir-v6.md @@ -102,35 +102,42 @@ Expected: `0/1 passed (placeholder)`,exit 1 // 与 alloc_registers 共用——后者改读本表。 // 表布局:每函数一段,段内每「函数内 var」16B(段偏移 = 前缀 var 数累计,见 // live_range_slot——func_i 段起始 = Σ var_count[0..func_i),不乘固定稠密系数)。 -g_ir_live_ranges : string, mut; -g_live_range_cap : int, mut; - -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 { +g_ir_live_ranges : string, mut +g_live_range_cap : int, mut + +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: // 函数内 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; -} - -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); -} + 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_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) ``` `compute_live_ranges()` 实现:先按 Σ var_count 总量 grow 并首遍写 -1(区间未知 = -1,沿用 alloc_registers 的 iv_buf 初始化语义);再逐函数逐指令扫描:op/dest/s1/s2 落在 `[var_start, var_start+var_count)` 内则扩展区间(首见写 first,之后推进 last——与 opt.cr:210-241 逻辑逐行一致)。末尾把 `alloc_registers` 的重复扫描删除并改读 `live_first/live_last`。 @@ -239,14 +246,17 @@ jj commit -m 'feat: 条目版本化——STORE/ALLOC 定值切分版本条目( - [ ] **Step 2: 实现 entries_coexist** ```core -fn entries_coexist(func_i: int, e1: int, e2: int) -> int { +fn entries_coexist(func_i: int, e1: int, e2: int) -> int: // 存在区间 [s1,e1) 与 [s2,e2) 相交 ⟺ s1 < e2 && s2 < e1(半开区间) - s1 := ; en1 := ; - s2 := ; en2 := ; - if s1 < 0 || s2 < 0 { return 0; } - if s1 < en2 && s2 < en1 { return 1; } - return 0; -} + s1 := + en1 := + s2 := + en2 := + if s1 < 0 || s2 < 0: + return 0 + if s1 < en2 && s2 < en1: + return 1 + return 0 ``` - [ ] **Step 3: 跑测试 + 提交** diff --git a/docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md b/docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md index 9ee995b5..68c389ba 100644 --- a/docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md +++ b/docs/superpowers/plans/2026-09-10-language-surface-narrowing-r1.md @@ -473,77 +473,75 @@ sha256sum /tmp/r1t4_base_bin | tee /tmp/r1t4_base_sha // 判据(与 global_init_val 互补——它只认编译期标量常量,其余静默归 0): // ① 声明类型是聚合(语法节点 EXPR_ARRAY,含 `[T; N]` 与 `[T]`)→ 必须运行期分配存储; // ② 初值存在且不是 int/bool/dex 字面量(含负号字面量)→ 必须运行期求值。 -fn global_needs_runtime_init(name_idx: int) -> int { - i : ., mut = g_global_let_count - 1; - loop { - if i < 0 { break; } - node := r64(g_global_lets, i * 8); - if ast_a(node) == name_idx { - tn := ast_b(node); - if tn >= 0 && ast_kind(tn) == EXPR_ARRAY { return 1; } - vn := ast_c(node); - if vn < 0 { return 0; } - vk := ast_kind(vn); - if vk == EXPR_INT || vk == EXPR_BOOL || vk == EXPR_DEX { return 0; } - if vk == EXPR_UNARY && ast_c(vn) == UOP_NEG { - inner := ast_a(vn); - ik := ast_kind(inner); - if ik == EXPR_INT || ik == EXPR_BOOL || ik == EXPR_DEX { return 0; } - } - return 1; - } - i = i - 1; - } - return 0; -} +fn global_needs_runtime_init(name_idx: int) -> int: + i : ., mut = g_global_let_count - 1 + loop: + if i < 0: + break + node := r64(g_global_lets, i * 8) + if ast_a(node) == name_idx: + tn := ast_b(node) + if tn >= 0 && ast_kind(tn) == EXPR_ARRAY: + return 1 + vn := ast_c(node) + if vn < 0: + return 0 + vk := ast_kind(vn) + if vk == EXPR_INT || vk == EXPR_BOOL || vk == EXPR_DEX: + return 0 + if vk == EXPR_UNARY && ast_c(vn) == UOP_NEG: + inner := ast_a(vn) + ik := ast_kind(inner) + if ik == EXPR_INT || ik == EXPR_BOOL || ik == EXPR_DEX: + return 0 + return 1 + i = i - 1 + return 0 // 按 name_idx 查已注册的全局 IR var(未注册 = -1)。 -fn global_var_of(name_idx: int) -> int { - gi : ., mut = 0; - loop { - if gi >= g_ir_global_count { break; } - if r64(g_ir_globals, gi * 24) == name_idx { return r64(g_ir_globals, gi * 24 + 8); } - gi = gi + 1; - } - return -1; -} +fn global_var_of(name_idx: int) -> int: + gi : ., mut = 0 + loop: + if gi >= g_ir_global_count: + break + if r64(g_ir_globals, gi * 24) == name_idx: + return r64(g_ir_globals, gi * 24 + 8) + gi = gi + 1 + return -1 // 把需要运行期初始化的文件级 let 降级为 IR 序列(写进当前函数 = main 序言)。 // 顺序 = g_global_lets 源序(跨全局依赖如 `b : [int;2] = a;` 因此正确)。 -fn inject_global_inits() { - i : ., mut = 0; - loop { - if i >= g_global_let_count { break; } - lnode := r64(g_global_lets, i * 8); - name_idx := ast_a(lnode); - if global_needs_runtime_init(name_idx) != 0 { - gv := global_var_of(name_idx); - if gv >= 0 { - vn := ast_c(lnode); - v : ., mut = -1; - if vn >= 0 { - v = gen_expr(vn); - v = force_if_thunk(v); - } else { +fn inject_global_inits(): + i : ., mut = 0 + loop: + if i >= g_global_let_count: + break + lnode := r64(g_global_lets, i * 8) + name_idx := ast_a(lnode) + if global_needs_runtime_init(name_idx) != 0: + gv := global_var_of(name_idx) + if gv >= 0: + vn := ast_c(lnode) + v : ., mut = -1 + if vn >= 0: + v = gen_expr(vn) + v = force_if_thunk(v) + else: // 无初值聚合:整流分配(零初始化由 alloc 语义保证——rt.s:94-98 rep stosb; // 解释器 IR_ALLOC_ARRAY 显式清零 interp.cr:197-207)。 // 仅 `[T; N]`(N ≥ 1)注入;`[T]`(切片无长度,ast_int_val = 0)**不注入** // ——保持 BSS 零 = 空切片/哑指针,空切片解引用属独立 null 陷阱类,不在本批。 - tn := ast_b(lnode); - cnt : ., mut = 0; - if tn >= 0 { cnt = ast_int_val(tn); } - if cnt > 0 { - v = new_ir_var("ginit", TI_UNIT); - emit(IR_ALLOC_ARRAY, v, cnt, 0, 0, 0); - irv_set_type(v, alloc_type(TYP_ARRAY, TI_INT, cnt)); - } - } - if v >= 0 { emit(IR_STORE, -1, gv, v, 0, 0); } - } - } - i = i + 1; - } -} + tn := ast_b(lnode) + cnt : ., mut = 0 + if tn >= 0: + cnt = ast_int_val(tn) + if cnt > 0: + v = new_ir_var("ginit", TI_UNIT) + emit(IR_ALLOC_ARRAY, v, cnt, 0, 0, 0) + irv_set_type(v, alloc_type(TYP_ARRAY, TI_INT, cnt)) + if v >= 0: + emit(IR_STORE, -1, gv, v, 0, 0) + i = i + 1 ``` 在 `ir_gen_func`(`ir_gen.cr:2222`)内、`emit(IR_ARENA_NEW, …)`(`:2269-2271`)之后、`gen_expr(body)` 之前插入: diff --git a/docs/superpowers/plans/2026-09-10-r2-p0-type-engine.md b/docs/superpowers/plans/2026-09-10-r2-p0-type-engine.md index 15ed543a..4c043adb 100644 --- a/docs/superpowers/plans/2026-09-10-r2-p0-type-engine.md +++ b/docs/superpowers/plans/2026-09-10-r2-p0-type-engine.md @@ -181,30 +181,39 @@ g_ty_uncovered : int, mut; // 未覆盖面命中位(如 AK_NAMED 具 追加内容照 `grow_types` 先例: ```core -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×项数(重建式扩容,见 type_terms.cr 的 tt_reindex) - if needed < g_tt_index_cap { return; } - nc : ., mut = 1024; - loop { if nc >= needed { 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 + loop: + if nc >= needed: + 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() ``` - [ ] **Step 5: 类型项表 + 构造 API(`src/compiler/type_terms.cr`)** @@ -360,35 +369,45 @@ fn tt_atom(ak: int, ti: int, params: int) -> int { return tt_term(TT_ATOM, ak, t // 判据:corec selftest-types → 每例一行 PASS/FAIL,末行 "N/M type-engine cases passed",rc=0 全过。 // 说明:本文件只依赖 type_terms.cr / type_engine.cr 的公开 API(签名见计划 Task 1/Task 3)。 -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 type_selftest_run() -> int { - fails : ., mut = 0; - total : ., mut = 0; +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 type_selftest_run() -> int: + fails : ., mut = 0 + total : ., mut = 0 // --- P0 最小用例(Task 3/4 扩充为 spec §8 全类:子类型/等价/不相交/可空/反例/穷尽性/递归/参数化/预算)--- - a_int := tt_atom(AK_INT, TI_INT, -1); - a_str := tt_atom(AK_STRING, TI_STR, -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("unit.dedup", (tt_union(a_int, a_str) == tt_union(a_int, a_str)), 1); - total = total + 1; fails = fails + ts_check("unit.notnot", (tt_not(tt_not(a_int)) == a_int), 1); - - print(int_str(total - fails)); print("/"); print(int_str(total)); println(" type-engine cases passed"); - if fails != 0 { return 1; } - return 0; -} + a_int := tt_atom(AK_INT, TI_INT, -1) + a_str := tt_atom(AK_STRING, TI_STR, -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("unit.dedup", (tt_union(a_int, a_str) == tt_union(a_int, a_str)), 1) + total = total + 1 + fails = fails + ts_check("unit.notnot", (tt_not(tt_not(a_int)) == a_int), 1) + + print(int_str(total - fails)) + print("/") + print(int_str(total)) + println(" type-engine cases passed") + if fails != 0: + return 1 + return 0 ``` - [ ] **Step 7: `type_engine.cr` 最小桩(供 Step 6 编译通过;Task 3 补全判定)** @@ -396,17 +415,31 @@ fn type_selftest_run() -> int { ```core // R2 P0:类型项判定引擎(语义包含)。 // 本文件在 Task 3 补全;Task 1 只放原子类常量 + ty_sub 桩(保证骨架可编译可跑)。 -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; - -fn ty_sub(a: int, b: int) -> int { // 桩:Task 3 替换为真判定(三态 1/0/-1) - if a == b { return 1; } - if tt_tag(b) == TT_TOP { return 1; } - if tt_tag(a) == TT_BOT { return 1; } - return 0; -} +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 + +fn ty_sub(a: int, b: int) -> int: + // 桩:Task 3 替换为真判定(三态 1/0/-1) + if a == b: + return 1 + if tt_tag(b) == TT_TOP: + return 1 + if tt_tag(a) == TT_BOT: + return 1 + return 0 ``` - [ ] **Step 8: CLI 注册(`src/compiler/main.cr`)** @@ -489,29 +522,42 @@ nice -n 19 python3 build_selfhost_native.py && nice -n 19 ./build/corec selftest ```core // NNF:否定下推(De Morgan + 双重否定消除);μ 体内照推 -fn tt_nnf(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_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_CONS { return tt_cons(tt_nnf(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))); } - return i; // 字面:ATOM 参数已推 / VAR / NIL -} - -fn tt_nnf_neg(i: int) -> int { // 计算 ¬i 的 NNF(负位置) - 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)); } - 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 { return tt_mu(tt_a(i), tt_nnf_neg(tt_b(i))); } - return tt_not(i); // 字面取反:¬ATOM / ¬VAR -} +fn tt_nnf(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_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_CONS: + return tt_cons(tt_nnf(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))) + return i // 字面:ATOM 参数已推 / VAR / NIL + +fn tt_nnf_neg(i: int) -> int: + // 计算 ¬i 的 NNF(负位置) + 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)) + 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: + return tt_mu(tt_a(i), tt_nnf_neg(tt_b(i))) + return tt_not(i) // 字面取反:¬ATOM / ¬VAR ``` (`tt_nnf_list` 是新增的小工具函数,对 CONS 链逐元素调用 `tt_nnf`。) @@ -521,48 +567,48 @@ fn tt_nnf_neg(i: int) -> int { // 计算 ¬i 的 NNF(负位置) // DNF:把 NNF 形态分配到「union of inter-of-literals」。 // 入口先 tt_nnf;分配律在 INTER 节点上做(左右各自 DNF 后笛卡尔积)。 // 简化:单元素 union/inter 不建节点;∩ 左/右为 union 时展开(分配律);结果项去重靠 tt_term 的 DAG。 -fn tt_norm(i: int) -> int { return tt_dnf(tt_nnf(i)); } - -fn tt_dnf(i: int) -> int { - t := tt_tag(i); - if t == TT_UNION { return tt_union(tt_dnf(tt_a(i)), tt_dnf(tt_b(i))); } - if t == TT_INTER { - l := tt_dnf(tt_a(i)); r := tt_dnf(tt_b(i)); +fn tt_norm(i: int) -> int: + return tt_dnf(tt_nnf(i)) + +fn tt_dnf(i: int) -> int: + t := tt_tag(i) + if t == TT_UNION: + return tt_union(tt_dnf(tt_a(i)), tt_dnf(tt_b(i))) + if t == TT_INTER: + l := tt_dnf(tt_a(i)) + r := tt_dnf(tt_b(i)) // 分配律**两支都展开**:(A∪B)∩C → (A∩C) ∪ (B∩C) // (本计划初稿只展开一支 = 静默丢项;P0 Task 2 自测 norm.distributed 实证 got INTER want UNION) - if tt_tag(l) == TT_UNION { - return tt_union(tt_dnf(tt_inter(tt_a(l), r)), tt_dnf(tt_inter(tt_b(l), r))); - } - if tt_tag(r) == TT_UNION { - return tt_union(tt_dnf(tt_inter(l, tt_a(r))), tt_dnf(tt_inter(l, tt_b(r)))); - } - return tt_inter(l, r); // 已规范化(∩-链扁平) - } - if t == TT_MU { return tt_mu(tt_a(i), tt_dnf(tt_b(i))); } - return i; // 字面 -} + if tt_tag(l) == TT_UNION: + return tt_union(tt_dnf(tt_inter(tt_a(l), r)), tt_dnf(tt_inter(tt_b(l), r))) + if tt_tag(r) == TT_UNION: + return tt_union(tt_dnf(tt_inter(l, tt_a(r))), tt_dnf(tt_inter(l, tt_b(r)))) + return tt_inter(l, r) // 已规范化(∩-链扁平) + if t == TT_MU: + return tt_mu(tt_a(i), tt_dnf(tt_b(i))) + return i // 字面 // DNF 形态判定:UNION 的每个子项必须是「product 或 literal」(不得再嵌 UNION); // INTER 链的叶子必须全是 literal;literal = ATOM / ¬ATOM / VAR / ¬VAR / TOP_K / ⊥ -fn tt_is_dnf(i: int) -> int { - t := tt_tag(i); - if t == TT_UNION { - if tt_is_dnf(tt_a(i)) == 0 { return 0; } - return tt_is_dnf(tt_b(i)); - } +fn tt_is_dnf(i: int) -> int: + t := tt_tag(i) + if t == TT_UNION: + if tt_is_dnf(tt_a(i)) == 0: + return 0 + return tt_is_dnf(tt_b(i)) // 非 UNION 位置:不许出现 UNION(上面已递归剥掉),检查 product/literal 形态 - if t == TT_INTER { return tt_is_product_chain(i); } - return tt_is_literal(i); -} - -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 t == TT_INTER: + return tt_is_product_chain(i) + return tt_is_literal(i) + +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) ``` (`tt_is_literal` 已在 Task 3 Step 3 定义,**依赖顺序**如下:Task 2 落地时先补一个最小 `tt_is_literal`,其语义同 Task 3 版本;Task 3 再替换为最终版。两版语义必须一致。) @@ -612,37 +658,49 @@ fn ak_disjoint(x: int, y: int) -> int ```core // 深递归探针:μX₀. product<μX₁. product<… int>>(深度 256)——判定展开会耗尽小预算 - // (放在 type_selftest.cr 内,仅自测使用) - fn tt_mu_probe_deep() -> int { - acc : ., mut = tt_atom(AK_INT, TI_INT, -1); - d : ., mut = 0; - loop { - if d >= 256 { break; } - acc = tt_mu(0, tt_atom(AK_PRODUCT, -1, tt_cons(acc, tt_nil()))); - d = d + 1; - } - return acc; - } - - // --- 判定(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); - total = total + 1; fails = fails + ts_check("equiv.absorb", ty_equiv(tt_union(a_int, a_int), a_int), 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_mu_probe_deep(), a_int), -1); - total = total + 1; fails = fails + ts_check("budget.flag", ty_exhausted(), 1); - ty_budget_reset(200000); + // (放在 type_selftest.cr 内,仅自测使用) + fn tt_mu_probe_deep() -> int: + acc : ., mut = tt_atom(AK_INT, TI_INT, -1) + d : ., mut = 0 + loop: + if d >= 256: + break + acc = tt_mu(0, tt_atom(AK_PRODUCT, -1, tt_cons(acc, tt_nil()))) + d = d + 1 + return acc + + // --- 判定(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) + total = total + 1 + fails = fails + ts_check("equiv.absorb", ty_equiv(tt_union(a_int, a_int), a_int), 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_mu_probe_deep(), a_int), -1) + total = total + 1 + fails = fails + ts_check("budget.flag", ty_exhausted(), 1) + ty_budget_reset(200000) ``` - [ ] **Step 2: 运行确认「红」**(桩返回 0,断言 1 或 -1 的用例必然失败) @@ -652,36 +710,42 @@ fn ak_disjoint(x: int, y: int) -> int ```core // 原子类互斥(P0 公理表):不同原子类两两不相交;AK_DYN = ⊤(与所有类相交)。 // 例外:AK_NAMED 的具体行可能展开为其它类——P0 不展开(登记为未覆盖面),按未知处理。 -fn ak_disjoint(x: int, y: int) -> int { - if x == y { return 0; } - if x == AK_DYN || y == AK_DYN { return 0; } - if x == AK_NEVER || y == AK_NEVER { return 1; } - return 1; -} - -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 { return 1; } - if t == TT_NOT { - it := tt_tag(tt_a(i)); - if it == TT_ATOM || it == TT_VAR || it == TT_TOP_K { return 1; } - } - return 0; -} +fn ak_disjoint(x: int, y: int) -> int: + if x == y: + return 0 + if x == AK_DYN || y == AK_DYN: + return 0 + if x == AK_NEVER || y == AK_NEVER: + return 1 + return 1 + +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: + return 1 + if t == TT_NOT: + it := tt_tag(tt_a(i)) + if it == TT_ATOM || it == TT_VAR || it == TT_TOP_K: + return 1 + return 0 // 字面覆盖:literal p 是否蕴含 literal q(q 的语义包含 p 的) -fn lit_covers(p: int, q: int) -> int { - if p == q { return 1; } - pt := tt_tag(p); qt := tt_tag(q); +fn lit_covers(p: int, q: int) -> int: + if p == q: + return 1 + pt := tt_tag(p) + qt := tt_tag(q) // ⊤ₖ 覆盖同类原子 - if qt == TT_TOP_K { - if pt == TT_ATOM { return ty_ak_of(p) == tt_a(q); } - if pt == TT_TOP_K { return tt_a(p) == tt_a(q); } - return 0; - } - if pt == TT_NOT && qt != TT_NOT { return 0; } // ¬A 不蕴含正字面(除 A=B 已排除) - return 0; // 其余一律不覆盖(⊥ 早退由调用方 lits_contradictory 处理) -} + if qt == TT_TOP_K: + if pt == TT_ATOM: + return ty_ak_of(p) == tt_a(q) + if pt == TT_TOP_K: + return tt_a(p) == tt_a(q) + return 0 + if pt == TT_NOT && qt != TT_NOT: + return 0 + // ¬A 不蕴含正字面(除 A=B 已排除) + return 0 // 其余一律不覆盖(⊥ 早退由调用方 lits_contradictory 处理) ``` (`ty_ak_of(lit)` 的规则:ATOM 取 `tt_a(lit)`;`¬ATOM` 取 `tt_a(tt_a(lit))`。) @@ -689,75 +753,95 @@ fn lit_covers(p: int, q: int) -> int { ```core // 顶层入口:每次重置步数/耗尽位,规范化两侧,逐 product 覆盖判定 -fn ty_sub(a: int, b: int) -> int { - if a == b { return 1; } - nav := tt_norm(a); nbv := tt_norm(b); - if nav == nbv { return 1; } - if tt_tag(nbv) == TT_TOP { return 1; } - if tt_tag(nav) == TT_BOT { return 1; } +fn ty_sub(a: int, b: int) -> int: + if a == b: + return 1 + nav := tt_norm(a) + nbv := tt_norm(b) + if nav == nbv: + return 1 + if tt_tag(nbv) == TT_TOP: + return 1 + if tt_tag(nav) == TT_BOT: + return 1 // A = ⋃ products;每个 product 必须被 B 的某个 product 覆盖 - r := sub_union_covered(nav, nbv, 0); - if g_ty_exhausted != 0 { return -1; } - return r; -} + r := sub_union_covered(nav, nbv, 0) + if g_ty_exhausted != 0: + return -1 + return r // products 分解:DNF 形态下按 UNION 拆分,叶子 = product(∩-链)或字面 -fn prod_covered(p: int, b: int) -> int { +fn prod_covered(p: int, b: int) -> int: // b 拆 union:任一 product 覆盖即可 - if tt_tag(b) == TT_UNION { if prod_covered(p, tt_a(b)) == 1 { return 1; } return prod_covered(p, tt_b(b)); } + if tt_tag(b) == TT_UNION: + if prod_covered(p, tt_a(b)) == 1: + return 1 + return prod_covered(p, tt_b(b)) // p 与 b 均为 product/字面:收集双方字面集后做覆盖(b ⊆ p) // —— p 是待检查的「更小集合」,b 是候选「更大集合」:需要 b 的每个字面被 p 的某字面蕴含 - plits := lit_collect(p); blits := lit_collect(b); - bi : ., mut = 0; - loop { - if bi >= blits_count { break; } - bq := blits[bi]; + plits := lit_collect(p) + blits := lit_collect(b) + bi : ., mut = 0 + loop: + if bi >= blits_count: + break + bq := blits[bi] // ⊥ 早退:p 的字面集内部矛盾 → 空集,覆盖一切 - if lits_contradictory(plits) != 0 { return 1; } - if !lit_set_covers(plits, bq) { return 0; } - bi = bi + 1; - } - return 1; -} + if lits_contradictory(plits) != 0: + return 1 + if !lit_set_covers(plits, bq): + return 0 + bi = bi + 1 + return 1 ``` (实现者按此语义实现:`lit_collect` 把 product 拆成字面数组,µ 展开点见下;`lit_set_covers` 用 `lit_covers` 扫描;`lits_contradictory` 检查 `ATOM(k1)` 与 `ATOM(k2)`(k1≠k2 且互斥),或检查 `X` 与 `¬X`。) ```core // μ 展开 + memo(假设-判定,最大不动点):遇到 MU 单步展开,并在假设集中登记 (子项对) // 预算:每次 sub 调用 g_ty_steps += 1;超 g_ty_budget_max → g_ty_exhausted = 1,返回 -1 -fn sub_step(a: int, b: int) -> int { - g_ty_steps = g_ty_steps + 1; - if g_ty_steps > g_ty_budget_max { g_ty_exhausted = 1; return -1; } - mk := ty_memo_find(a, b); - if mk >= 0 { return r64(g_ty_memo_vals, mk * 8); } +fn sub_step(a: int, b: int) -> int: + g_ty_steps = g_ty_steps + 1 + if g_ty_steps > g_ty_budget_max: + g_ty_exhausted = 1 + return -1 + mk := ty_memo_find(a, b) + if mk >= 0: + return r64(g_ty_memo_vals, mk * 8) ... // 1) a 为 MU → 展开(tt_subst(a 的 var, a 的 body))后递归 // 2) b 为 MU → 展开后递归 // 3) 结果写 memo(三态值) - return r; -} + return r ``` - [ ] **Step 5: 实现 `ty_equiv` / `ty_disjoint` / `ty_inhabited` / 预算重置** ```core -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; -} -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_inhabited(a: int) -> int { - n := tt_norm(a); +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 +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_inhabited(a: int) -> int: + n := tt_norm(a) // DNF 下:存在一个 product,其字面集不矛盾且所有原子类两两相容 - return prod_inhabited_any(n); -} -fn ty_budget_reset(limit: int) { g_ty_steps = 0; g_ty_budget_max = limit; g_ty_exhausted = 0; } -fn ty_exhausted() -> int { return g_ty_exhausted; } + return prod_inhabited_any(n) +fn ty_budget_reset(limit: int): + g_ty_steps = 0 + g_ty_budget_max = limit + g_ty_exhausted = 0 +fn ty_exhausted() -> int: + return g_ty_exhausted ``` (`prod_inhabited_any`:UNION 拆分 + 每个 product 做 `lits_contradictory` 检查;`AK_NAMED` 具体行 P0 不展开——**登记为未覆盖面**,遇到即 `g_ty_exhausted` 语义之外的 `unknown`:返回 -1 并置一个 `g_ty_uncovered` 位,自测里不出现。) @@ -829,30 +913,32 @@ fn ty_exhaustive(domain: int, patterns: int) -> int // patterns = CONS 链;1 ```core // 反例 = A\B 的规范化项;不可满足(= ⊥)→ -1(无遗漏/无反例值) -fn tt_witness(a: int, b: int) -> int { - r := tt_norm(tt_inter(a, tt_not(b))); - if ty_inhabited(r) != 1 { return -1; } - if tt_tag(r) == TT_BOT { return -1; } - return r; -} +fn tt_witness(a: int, b: int) -> int: + r := tt_norm(tt_inter(a, tt_not(b))) + if ty_inhabited(r) != 1: + return -1 + if tt_tag(r) == TT_BOT: + return -1 + return r // 穷尽性:¬(⋃patterns) ∩ domain 可满足 → 有遗漏;witness = 遗漏的具体类型项 -fn ty_exhaust_witness(domain: int, patterns: int) -> int { - acc : ., mut = tt_bot(); - p : ., mut = patterns; - loop { - if tt_tag(p) != TT_CONS { break; } - acc = tt_union(acc, tt_a(p)); - p = tt_b(p); - } - return tt_witness(domain, acc); // domain \ ⋃patterns -} -fn ty_exhaustive(domain: int, patterns: int) -> int { - w := ty_exhaust_witness(domain, patterns); - if g_ty_exhausted != 0 { return -1; } - if w < 0 { return 1; } // 补集空 = 穷尽 - return 0; -} +fn ty_exhaust_witness(domain: int, patterns: int) -> int: + acc : ., mut = tt_bot() + p : ., mut = patterns + loop: + if tt_tag(p) != TT_CONS: + break + acc = tt_union(acc, tt_a(p)) + p = tt_b(p) + return tt_witness(domain, acc) // domain \ ⋃patterns +fn ty_exhaustive(domain: int, patterns: int) -> int: + w := ty_exhaust_witness(domain, patterns) + if g_ty_exhausted != 0: + return -1 + if w < 0: + return 1 + // 补集空 = 穷尽 + return 0 ``` - [ ] **Step 4: 跑测试(用例表到 spec §8 全类)** diff --git a/docs/superpowers/plans/2026-09-10-r2-p1-shadow-parity.md b/docs/superpowers/plans/2026-09-10-r2-p1-shadow-parity.md index 82b870a7..819f2023 100644 --- a/docs/superpowers/plans/2026-09-10-r2-p1-shadow-parity.md +++ b/docs/superpowers/plans/2026-09-10-r2-p1-shadow-parity.md @@ -83,124 +83,151 @@ fn sh_map_entries() -> int // 已翻译条目数 // 这正是 P1 要暴露的「未覆盖面」,与「收紧面」分开统计)。 // 缓存:g_shadow_map(16B/条:ti → term),线性探测开放寻址(与引擎表同式)。 -fn sh_map_cap_init() { - if g_shadow_map_cap <= 0 { - nc : ., mut = 1024; - nb := alloc(nc * 16); - i : ., mut = 0; - loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; } - g_shadow_map = nb; - g_shadow_map_cap = nc; - } -} +fn sh_map_cap_init(): + if g_shadow_map_cap <= 0: + nc : ., mut = 1024 + nb := alloc(nc * 16) + i : ., mut = 0 + loop: + if i >= nc: + break + w64(nb, i * 16, -1) + i = i + 1 + g_shadow_map = nb + g_shadow_map_cap = nc // ⚠️ 骨架修正(Task 1 评审 M6:**直接照抄初稿骨架会回归缺陷 ②③**): // · 探测前必须有**装填因子守卫**(否则 >cap 条目时探测永不落空 = 挂死) // · 扩容 = 重建 + **重放既有条目**(`sh_map_rehash`) // · 调用方**回写前必须重探**(递归翻译可能触发扩容/重建,写旧 slot 会写错槽) -fn sh_map_find(ti: int) -> int { // 命中返回槽位,未命中返回空槽位(不插入) - sh_map_cap_init(); - if (g_shadow_map_count + 1) * 2 >= g_shadow_map_cap { sh_map_rehash(); } // 守卫(探测前) - h : ., mut = ti % g_shadow_map_cap; - if h < 0 { h = 0 - h; } - p : ., mut = h; - loop { - k := r64(g_shadow_map, p * 16); - if k < 0 { return p; } - if k == ti { return p; } - p = p + 1; if p >= g_shadow_map_cap { p = 0; } - } -} +fn sh_map_find(ti: int) -> int: + // 命中返回槽位,未命中返回空槽位(不插入) + sh_map_cap_init() + if (g_shadow_map_count + 1) * 2 >= g_shadow_map_cap: + sh_map_rehash() + // 守卫(探测前) + h : ., mut = ti % g_shadow_map_cap + if h < 0: + h = 0 - h + p : ., mut = h + loop: + k := r64(g_shadow_map, p * 16) + if k < 0: + return p + if k == ti: + return p + p = p + 1 + if p >= g_shadow_map_cap: + p = 0 // 扩容:容量翻倍(≥2 的幂)+ 逐条重放(保留既有映射) -fn sh_map_rehash() { - old_map := g_shadow_map; - old_cap := g_shadow_map_cap; - nc : ., mut = old_cap * 2; - if nc < 1024 { nc = 1024; } - nb := alloc(nc * 16); - i : ., mut = 0; - loop { if i >= nc { break; } w64(nb, i * 16, -1); i = i + 1; } - g_shadow_map = nb; - g_shadow_map_cap = nc; - g_shadow_map_count = 0; - j : ., mut = 0; - loop { - if j >= old_cap { break; } - k := r64(old_map, j * 16); - if k >= 0 { - s := sh_map_slot_no_grow(k); // ⚠️ 重放必须用**无守卫**版(有守卫版会再触发 rehash → 递归) - w64(g_shadow_map, s * 16, k); - w64(g_shadow_map, s * 16 + 8, r64(old_map, j * 16 + 8)); - g_shadow_map_count = g_shadow_map_count + 1; - } - j = j + 1; - } -} +fn sh_map_rehash(): + old_map := g_shadow_map + old_cap := g_shadow_map_cap + nc : ., mut = old_cap * 2 + if nc < 1024: + nc = 1024 + nb := alloc(nc * 16) + i : ., mut = 0 + loop: + if i >= nc: + break + w64(nb, i * 16, -1) + i = i + 1 + g_shadow_map = nb + g_shadow_map_cap = nc + g_shadow_map_count = 0 + j : ., mut = 0 + loop: + if j >= old_cap: + break + k := r64(old_map, j * 16) + if k >= 0: + s := sh_map_slot_no_grow(k) // ⚠️ 重放必须用**无守卫**版(有守卫版会再触发 rehash → 递归) + w64(g_shadow_map, s * 16, k) + w64(g_shadow_map, s * 16 + 8, r64(old_map, j * 16 + 8)) + g_shadow_map_count = g_shadow_map_count + 1 + j = j + 1 // 无守卫探测(仅供 rehash 重放;外部一律走 sh_map_find) -fn sh_map_slot_no_grow(ti: int) -> int { - h : ., mut = ti % g_shadow_map_cap; - if h < 0 { h = 0 - h; } - p : ., mut = h; - loop { - k := r64(g_shadow_map, p * 16); - if k < 0 { return p; } - if k == ti { return p; } - p = p + 1; if p >= g_shadow_map_cap { p = 0; } - } -} - -fn sh_term_of_ti(ti: int) -> int { - if ti < 0 { return -1; } +fn sh_map_slot_no_grow(ti: int) -> int: + h : ., mut = ti % g_shadow_map_cap + if h < 0: + h = 0 - h + p : ., mut = h + loop: + k := r64(g_shadow_map, p * 16) + if k < 0: + return p + if k == ti: + return p + p = p + 1 + if p >= g_shadow_map_cap: + p = 0 + +fn sh_term_of_ti(ti: int) -> int: + if ti < 0: + return -1 // 预置常量:natives **按语义逐项分派**(⚠️ 数值不 1:1:TI_BOOL=2/TI_STR=3 vs // AK_STRING=2/AK_BOOL=3 下标互换——直接 tt_atom(ti,ti,-1) 会静默错标,Task 1 实测) - if ti == TI_INT { return tt_atom(AK_INT, ti, -1); } - if ti == TI_DEX { return tt_atom(AK_DEX, ti, -1); } - if ti == TI_BOOL { return tt_atom(AK_BOOL, ti, -1); } - if ti == TI_STR { return tt_atom(AK_STRING, ti, -1); } - if ti == TI_UNIT { return tt_atom(AK_UNIT, ti, -1); } - if ti == TI_NEVER { return tt_atom(AK_NEVER, ti, -1); } - if ti == TI_CHAR { return tt_atom(AK_CHAR, ti, -1); } - if ti == TI_DYN { return tt_atom(AK_DYN, ti, -1); } // 注意:dyn 位图按 ⊤ 近似(过宽)→ Task 3 须单列 dyn 类差异 - if ti == TI_DEX_S { return tt_atom(AK_DEX, ti, -1); } // 精确 dex 与 dex 同语义域 - slot := sh_map_find(ti); - k := r64(g_shadow_map, slot * 16); - if k == ti { - g_shadow_hits = g_shadow_hits + 1; - return r64(g_shadow_map, slot * 16 + 8); - } + if ti == TI_INT: + return tt_atom(AK_INT, ti, -1) + if ti == TI_DEX: + return tt_atom(AK_DEX, ti, -1) + if ti == TI_BOOL: + return tt_atom(AK_BOOL, ti, -1) + if ti == TI_STR: + return tt_atom(AK_STRING, ti, -1) + if ti == TI_UNIT: + return tt_atom(AK_UNIT, ti, -1) + if ti == TI_NEVER: + return tt_atom(AK_NEVER, ti, -1) + if ti == TI_CHAR: + return tt_atom(AK_CHAR, ti, -1) + if ti == TI_DYN: + return tt_atom(AK_DYN, ti, -1) + // 注意:dyn 位图按 ⊤ 近似(过宽)→ Task 3 须单列 dyn 类差异 + if ti == TI_DEX_S: + return tt_atom(AK_DEX, ti, -1) + // 精确 dex 与 dex 同语义域 + slot := sh_map_find(ti) + k := r64(g_shadow_map, slot * 16) + if k == ti: + g_shadow_hits = g_shadow_hits + 1 + return r64(g_shadow_map, slot * 16 + 8) // 未命中:按 kind 翻译(递归子项) - term : ., mut = -1; - k1 := get_type_kind(ti); - d1 := get_type_data(ti); - if k1 == TYP_ARRAY || k1 == TYP_SLICE { - el := sh_term_of_ti(d1); - if el >= 0 { term = tt_atom(AK_SEQUENCE, -1, tt_cons(el, tt_nil())); } - } else if k1 == TYP_PTR { - 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 { - in2 := sh_term_of_ti(d1); - if in2 >= 0 { term = tt_atom(AK_REF, -1, tt_cons(in2, tt_nil())); } - } else if k1 == TYP_TUPLE { + term : ., mut = -1 + k1 := get_type_kind(ti) + d1 := get_type_data(ti) + if k1 == TYP_ARRAY || k1 == TYP_SLICE: + el := sh_term_of_ti(d1) + if el >= 0: + term = tt_atom(AK_SEQUENCE, -1, tt_cons(el, tt_nil())) + else if k1 == TYP_PTR: + 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: + in2 := sh_term_of_ti(d1) + if in2 >= 0: + term = tt_atom(AK_REF, -1, tt_cons(in2, tt_nil())) + else if k1 == TYP_TUPLE: // 逐字段翻译(字段访问器与 g_tuple_* 布局见 checker.cr;实现时以实际访问器为准) - term = sh_tuple_to_product(ti); - } else if k1 == TYP_NAMED || k1 == TYP_GENERIC_PARAM || k1 == TYP_GENERIC_APPLY { - term = tt_atom(AK_NAMED, ti, -1); // 不展开 → UNKNOWN(P1 预期) - } else { - term = tt_atom(AK_NAMED, ti, -1); // 未知 kind 保守归入命名类 - } - if term < 0 { return -1; } + term = sh_tuple_to_product(ti) + else if k1 == TYP_NAMED || k1 == TYP_GENERIC_PARAM || k1 == TYP_GENERIC_APPLY: + term = tt_atom(AK_NAMED, ti, -1) // 不展开 → UNKNOWN(P1 预期) + else: + term = tt_atom(AK_NAMED, ti, -1) // 未知 kind 保守归入命名类 + if term < 0: + return -1 // ⚠️ 缓存表必须:① 装填因子守卫(表满时开放寻址探测永不落空 = 挂死——P0 C2 同族, // Task 1 实测:固定 1024 容量在编译器自身语料(数千 ti)下必挂);② 重建时重放既有 // 条目;③ **回写前重探**(递归翻译可能触发扩容/重建,直接写旧 slot 会写错槽)。 - slot2 := sh_map_find(ti); - w64(g_shadow_map, slot2 * 16, ti); - w64(g_shadow_map, slot2 * 16 + 8, term); - g_shadow_entries = g_shadow_entries + 1; - return term; -} + slot2 := sh_map_find(ti) + w64(g_shadow_map, slot2 * 16, ti) + w64(g_shadow_map, slot2 * 16 + 8, term) + g_shadow_entries = g_shadow_entries + 1 + return term ``` (`sh_tuple_to_product`:按 checker 侧 tuple 字段访问器逐字段 `sh_term_of_ti` 后串成 CONS 链——实现者按实际访问器落,签名 `fn sh_tuple_to_product(ti: int) -> int`。) @@ -254,11 +281,11 @@ fn sh_count_old_looser() -> int fn sh_count_unknown() -> int ```core // R2 P1 影子对拍包装:旧判定照常返回;影子判定只观察(--type-shadow 开时) -fn type_equal(t1: int, t2: int) -> bool { - r := type_equal_core(t1, t2); - if g_shadow_on != 0 { sh_compare(t1, t2, r ? 1 : 0); } - return r; -} +fn type_equal(t1: int, t2: int) -> bool: + r := type_equal_core(t1, t2) + if g_shadow_on != 0: + sh_compare(t1, t2, r ? 1 : 0) + return r ``` (`r ? 1 : 0`:**本语言无三元运算符**——用 `ok : ., mut = 0; if r { ok = 1; }` 显式写。) @@ -268,21 +295,31 @@ fn type_equal(t1: int, t2: int) -> bool { - [ ] **Step 3: 分类核心(`ty_shadow.cr`)** ```core -fn sh_compare(t1: int, t2: int, old_ok: int) -> void { - g_shadow_total = g_shadow_total + 1; - a := sh_term_of_ti(t1); - b := sh_term_of_ti(t2); - if a < 0 || b < 0 { g_shadow_unknown = g_shadow_unknown + 1; return; } - ty_budget_reset(200000); - e := ty_equiv(a, b); - ty_budget_reset(200000); // 影子运行不污染后续 - if e == -1 { g_shadow_unknown = g_shadow_unknown + 1; sh_record(0, t1, t2, old_ok); return; } +fn sh_compare(t1: int, t2: int, old_ok: int) -> void: + g_shadow_total = g_shadow_total + 1 + a := sh_term_of_ti(t1) + b := sh_term_of_ti(t2) + if a < 0 || b < 0: + g_shadow_unknown = g_shadow_unknown + 1 + return + ty_budget_reset(200000) + e := ty_equiv(a, b) + ty_budget_reset(200000) // 影子运行不污染后续 + if e == -1: + g_shadow_unknown = g_shadow_unknown + 1 + sh_record(0, t1, t2, old_ok) + return // 注意语义:旧 true ⇔ 引擎 1 - if e == old_ok { g_shadow_agree = g_shadow_agree + 1; return; } - if old_ok == 0 && e == 1 { g_shadow_old_stricter = g_shadow_old_stricter + 1; } // 旧拒新受 - else { g_shadow_old_looser = g_shadow_old_looser + 1; } // 旧受新拒 = 收紧面 - sh_record(1, t1, t2, old_ok); -} + if e == old_ok: + g_shadow_agree = g_shadow_agree + 1 + return + if old_ok == 0 && e == 1: + g_shadow_old_stricter = g_shadow_old_stricter + 1 + // 旧拒新受 + else: + g_shadow_old_looser = g_shadow_old_looser + 1 + // 旧受新拒 = 收紧面 + sh_record(1, t1, t2, old_ok) ``` `sh_record(flag, t1, t2, old)`:环形缓冲(前 256 条差异/未知)——每槽 `{site, t1, t2, old_ok, kind}`;满则只计数。 diff --git a/docs/superpowers/plans/2026-09-10-r2-p2-replace.md b/docs/superpowers/plans/2026-09-10-r2-p2-replace.md index db952532..9a6f6f16 100644 --- a/docs/superpowers/plans/2026-09-10-r2-p2-replace.md +++ b/docs/superpowers/plans/2026-09-10-r2-p2-replace.md @@ -61,29 +61,32 @@ fn named_dedup_rows(name_idx: int) -> int // 自测用:该名字当前占用 ```core // globals.cr -g_named_dedup : string, mut; g_named_dedup_cap : int, mut; g_named_dedup_count : int, mut; +g_named_dedup : string, mut +g_named_dedup_cap : int, mut +g_named_dedup_count : int, mut // checker.cr:侧表 = 开放寻址(16B/条 {name_idx, ti}),与影子侧表同式(含装填守卫 + 重建重放 + 回写前重探) -fn alloc_named_type(name_idx: int) -> int { - slot := named_dedup_slot(name_idx); // 含守卫/重放,见下 - if r64(g_named_dedup, slot * 16) == name_idx { return r64(g_named_dedup, slot * 16 + 8); } - ti := alloc_type(TYP_NAMED, name_idx, 0); - w64(g_named_dedup, slot * 16, name_idx); - w64(g_named_dedup, slot * 16 + 8, ti); - g_named_dedup_count = g_named_dedup_count + 1; - return ti; -} - -fn named_dedup_rows(name_idx: int) -> int { // 自测用:该名字在 g_types 里的行数 - n : ., mut = 0; - i : ., mut = 0; - loop { - if i >= g_type_count { break; } - if get_type_kind(i) == TYP_NAMED && get_type_data(i) == name_idx { n = n + 1; } - i = i + 1; - } - return n; -} +fn alloc_named_type(name_idx: int) -> int: + slot := named_dedup_slot(name_idx) // 含守卫/重放,见下 + if r64(g_named_dedup, slot * 16) == name_idx: + return r64(g_named_dedup, slot * 16 + 8) + ti := alloc_type(TYP_NAMED, name_idx, 0) + w64(g_named_dedup, slot * 16, name_idx) + w64(g_named_dedup, slot * 16 + 8, ti) + g_named_dedup_count = g_named_dedup_count + 1 + return ti + +fn named_dedup_rows(name_idx: int) -> int: + // 自测用:该名字在 g_types 里的行数 + n : ., mut = 0 + i : ., mut = 0 + loop: + if i >= g_type_count: + break + if get_type_kind(i) == TYP_NAMED && get_type_data(i) == name_idx: + n = n + 1 + i = i + 1 + return n ``` (`named_dedup_slot` = 开放寻址探测,**必须有装填因子守卫 + 重建重放 + 回写前重探**——照 `ty_shadow.cr` 的 `sh_map_*` 先例,勿重蹈 P0/P1 的表满死循环。) @@ -156,20 +159,25 @@ fn type_equal_legacy(t1: int, t2: int) -> bool // 替换前的结构判等( - [ ] **Step 1: 替换实现** ```core -fn type_equal(t1: int, t2: int) -> bool { - if t1 == t2 { return true; } // 同一行快路径 - a := sh_term_of_ti(t1); - b := sh_term_of_ti(t2); - if a < 0 || b < 0 { return type_equal_legacy(t1, t2); } // 桥接不了 → 回落 legacy(登记) - ty_budget_reset(200000); - e := ty_equiv(a, b); - ty_budget_reset(200000); - if e == 1 { return true; } - if e == 0 { return false; } +fn type_equal(t1: int, t2: int) -> bool: + if t1 == t2: + return true + // 同一行快路径 + a := sh_term_of_ti(t1) + b := sh_term_of_ti(t2) + if a < 0 || b < 0: + return type_equal_legacy(t1, t2) + // 桥接不了 → 回落 legacy(登记) + ty_budget_reset(200000) + e := ty_equiv(a, b) + ty_budget_reset(200000) + if e == 1: + return true + if e == 0: + return false // e == -1(未知):**不静默**——回落 legacy 并计数(unknown 政策),报告里单列 - g_replace_unknown = g_replace_unknown + 1; - return type_equal_legacy(t1, t2); -} + g_replace_unknown = g_replace_unknown + 1 + return type_equal_legacy(t1, t2) ``` (`g_replace_unknown` 计数器 + 摘要行扩展,供报告。) diff --git a/docs/superpowers/plans/2026-09-11-r2-p2b-iface-ops.md b/docs/superpowers/plans/2026-09-11-r2-p2b-iface-ops.md index 41362401..839191b3 100644 --- a/docs/superpowers/plans/2026-09-11-r2-p2b-iface-ops.md +++ b/docs/superpowers/plans/2026-09-11-r2-p2b-iface-ops.md @@ -146,9 +146,12 @@ // lit_code = **字面量定型**:AST 字面量 kind(EXPR_INT/EXPR_DEX/EXPR_STRING/EXPR_BOOL/EXPR_CHAR) // → 本条目(查表入口 = `iface_lit_ti`/`iface_lit_ak` 的**字典**,本字段为其中一项);-1 = 无字面量 // ops = 操作许可位集(bit(OP_*)/bit(UOP_*+20)/bit(IP_*);见 Task 4 的位下标约定) -ESZ_IFACE_ENTRY : int = 40; -OFF_IE_AK : int = 0; OFF_IE_TI : int = 8; OFF_IE_NAME : int = 16; -OFF_IE_LIT : int = 24; OFF_IE_OPS : int = 32; +ESZ_IFACE_ENTRY : int = 40 +OFF_IE_AK : int = 0 +OFF_IE_TI : int = 8 +OFF_IE_NAME : int = 16 +OFF_IE_LIT : int = 24 +OFF_IE_OPS : int = 32 fn iface_registry_init() // 幂等;由 init_types() 调用(尾部,原生 9 行 alloc 之后;表内容 = 常量,不缓存行号) fn iface_count() -> int // 条目数(恒 13;自测断言用) @@ -232,12 +235,15 @@ nice -n 19 python3 tests/selfhost/test_ccr_v7.py # 结构判据全绿 **Interfaces:** ```core // ty_shadow.cr 保留原签名(影子证据链的可比性依赖调用点不变),实现改委托: -fn sh_native_ak(ti: int) -> int { - if ti < 0 { return -1; } - if get_type_kind(ti) != TYP_BASE { return -1; } // **原门保留**(见下) - return iface_by_ty_code(get_type_data(ti)); -} -fn sh_base_ak(ty: int) -> int { return iface_by_ty_code(ty); } +fn sh_native_ak(ti: int) -> int: + if ti < 0: + return -1 + if get_type_kind(ti) != TYP_BASE: + return -1 + // **原门保留**(见下) + return iface_by_ty_code(get_type_data(ti)) +fn sh_base_ak(ty: int) -> int: + return iface_by_ty_code(ty) ``` (**`sh_native_ak` 不可直接换成 `iface_kind_of`**:原实现要求 `get_type_kind(ti) == TYP_BASE` 才回 AK,否则 -1(`ty_shadow.cr:67-71`);而 `iface_kind_of` 对 `TYP_DYN` 行回 `AK_DYN`、对结构行回 `AK_SEQUENCE` 等。原 `sh_native_ak(TI_DYN)` 回 **-1**,`TI_DYN` 由 `sh_term_of_ti` 的 `TYP_DYN` 分支另行处理(`:212-216`)⇒ 两者只在 `TYP_BASE` 行上重合,委托必须**显式保留该门**。) @@ -316,11 +322,24 @@ fn sh_base_ak(ty: int) -> int { return iface_by_ty_code(ty); } // / IP_COND=30(真值性,`if` 现状收 bool|int) // / IP_COND_BOOL=31(严格 bool,`while` 现状**只收 bool**——两条规则现状不同, // **不得合并为一个「更统一」的位**:合并 = 收紧 `if` 或放宽 `while`) -IP_UOP_BIAS : int = 20; -IP_INDEX : int = 25; IP_INDEX_RANGE : int = 26; IP_FIELD : int = 27; -IP_METHOD : int = 28; IP_AS : int = 29; IP_COND : int = 30; IP_COND_BOOL : int = 31; +IP_UOP_BIAS : int = 20 +IP_INDEX : int = 25 +IP_INDEX_RANGE : int = 26 +IP_FIELD : int = 27 +IP_METHOD : int = 28 +IP_AS : int = 29 +IP_COND : int = 30 +IP_COND_BOOL : int = 31 // 位构造照 dyn_set_type 的乘 2 循环(本语言无移位运算符): -fn iface_bit(n: int) -> int { b : ., mut = 1; k : ., mut = n; loop { if k <= 0 { break; } b = b * 2; k = k - 1; } return b; } +fn iface_bit(n: int) -> int: + b : ., mut = 1 + k : ., mut = n + loop: + if k <= 0: + break + b = b * 2 + k = k - 1 + return b ``` **站点侧的三种「门形状」(现状各异,**必须逐字保留**;表只出「原子类 × op」的单侧许可):** @@ -406,8 +425,9 @@ fn ty_code_to_ti(ty: int) -> int - [ ] **Step 2: `never` 单元格探针(**本计划未测**,须实测才可裁决)**: ```core // 探针 A:调用位点的 never 形参 - fn f[T](a: T, b: never) -> int { return 1; } - // 探针 B/C/D:嵌套位 [never;3] / *never / G[never]——经 res_call_type 递归 + fn f[T](a: T, b: never) -> int: + return 1 + // 探针 B/C/D:嵌套位 [never;3] / *never / G[never]——经 res_call_type 递归 ``` - 结果 **不可达** ⇒ 合一后 `res_call_type` 直接用 `if ti < 0 { ti = TI_UNIT; }`(与另表同形),差异消失,报告登记「不可达」。 - 结果 **可达** ⇒ **保留现状**:`res_call_type` 处显式 `|| tv == TY_NEVER`(一行 + 注记 + 探针文件),并把「`never` 形参在调用位点被当作 unit」登记为**待裁决项**(交 P3;语义争议按 spec §4 裁决 6 **停下上报**)。 diff --git a/docs/superpowers/plans/2026-09-11-r2-p3-capabilities.md b/docs/superpowers/plans/2026-09-11-r2-p3-capabilities.md index a501936c..f0a9bc9e 100644 --- a/docs/superpowers/plans/2026-09-11-r2-p3-capabilities.md +++ b/docs/superpowers/plans/2026-09-11-r2-p3-capabilities.md @@ -566,14 +566,14 @@ fn array_len_constraint_ok(a: int, b: int) -> int // 签名不变;补方向 **复现(最小 8 行)**: ``` -fn main() -> int { - x : int? = 5; - match x { - Some(v) => { return v; } - None => { return 0; } - } - return 0; -} +fn main() -> int: + x : int? = 5 + match x: + Some(v) =>: + return v + none =>: + return 0 + return 0 ``` **实测 rc(P3a 收官二进制 `./build/corec`,2026-09-12;cwd = 仓库根——`/tmp` cwd 会触发 import 解析假失败,勿用)**: diff --git a/docs/superpowers/plans/2026-09-12-r2-p4-carrier.md b/docs/superpowers/plans/2026-09-12-r2-p4-carrier.md index a385613e..e262f533 100644 --- a/docs/superpowers/plans/2026-09-12-r2-p4-carrier.md +++ b/docs/superpowers/plans/2026-09-12-r2-p4-carrier.md @@ -156,15 +156,18 @@ fn iface_kind_of(ti: int) -> int // 自 iface_regis **Interfaces:** ``` -CCR_VERSION : int = 8; // ccr_io.cr:107(7 → 8) -CCR_SEG_COUNT : int = 8; // ccr_io.cr:108(6 → 8;tag 7=TYPE 8=IFACE) -CCR_SEG_TYPE : int = 7; CCR_SEG_IFACE : int = 8; // 新增常量(数值权威 = 段序) +CCR_VERSION : int = 8 // ccr_io.cr:107(7 → 8) +CCR_SEG_COUNT : int = 8 // ccr_io.cr:108(6 → 8;tag 7=TYPE 8=IFACE) +CCR_SEG_TYPE : int = 7 +CCR_SEG_IFACE : int = 8 // 新增常量(数值权威 = 段序) fn ccr_type_seg_size() -> int // 4 + (段体缓冲长度),与写侧同一来源 fn ccr_iface_seg_size() -> int // 段体缓冲(D18 解耦:内容构造在 corec-only ccr_types.cr;本文件只搬运) -g_ccr_type_seg : string, mut; g_ccr_type_seg_len : int, mut; -g_ccr_iface_seg : string, mut; g_ccr_iface_seg_len : int, mut; +g_ccr_type_seg : string, mut +g_ccr_type_seg_len : int, mut +g_ccr_iface_seg : string, mut +g_ccr_iface_seg_len : int, mut ``` - [ ] **Step 1: 用例(红)**:`tests/selfhost/test_ccr_types.py` 新增 ≥6 例(本步先立「机制面」四条,内容面随 Task 2/3 增长):① 段表 = 8 段、tag 序 1..8、offset 连续、`end == fsize`;② `seg_count` 字段 = 8、version = 8;③ loader 拒收 **6 段**(把 T1 前的旧 8 段文件截成 6 段 / 或 `seg_cnt` 改成 6)与 **缺 TYPE 段**、**缺 IFACE 段**(byte mutation 删段/改 tag);④ 空壳两段(count = 0)时 corec `build` + corearch `--elf` 全链 rc=0、产物行为正确。**为何这几条**:加段四面的每条不变式各一正控 + 缺失拒绝(三态纪律)+ 端到端不回归。 @@ -228,7 +231,7 @@ fn ccr_type_selftest_dump() -> int // 自测/对拍通道:逐行打印( // 校验:name_ni/type_ni/method_ni 必须 < STR 段串数;term 索引必须 < TYPE 段项数(跨段引用域检查) // ── 扩列(裁决 3 + 7)── -IFACE_ENTRY_COUNT : int = 16; // 13 → 16:+AK_NULL(原生第九员,裁决 7 独立槽)+AK_SUM +AK_FN +IFACE_ENTRY_COUNT : int = 16 // 13 → 16:+AK_NULL(原生第九员,裁决 7 独立槽)+AK_SUM +AK_FN // 新行列值:{ak, ti_row = -1(无规范行), name_ni = 注册名, lit_code = -1, ops = 0} // ops = 0 的解释:null/sum/fn 无「操作许可」面(算术/逻辑/条件门对其全拒 = 现状行为,P2b 起 iface_permits(-1/未登记)=0 同值) // ⇒ 本三行为**纯信息面**:只改「可查询性」,不改任何判定(iface_kind_of 的行分派见 Step 3 边界) diff --git a/docs/superpowers/plans/2026-09-13-r2-p5-cleanup.md b/docs/superpowers/plans/2026-09-13-r2-p5-cleanup.md index 1a6d308c..44e5c421 100644 --- a/docs/superpowers/plans/2026-09-13-r2-p5-cleanup.md +++ b/docs/superpowers/plans/2026-09-13-r2-p5-cleanup.md @@ -186,9 +186,9 @@ **Interfaces:** ``` -ESZ_DFNODE : int = 72; // 字节数不变(D19) -OFF_DF_TK : int = 40; // ★语义变更:类型项引用(g_type_terms 行号;-1 = 无项)= 类型面唯一真源 -OFF_DF_AUX : int = 64; // 原 OFF_DF_TK_TERM 槽位改名:非类型辅码(旗标/宽度;0 = 无) +ESZ_DFNODE : int = 72 // 字节数不变(D19) +OFF_DF_TK : int = 40 // ★语义变更:类型项引用(g_type_terms 行号;-1 = 无项)= 类型面唯一真源 +OFF_DF_AUX : int = 64 // 原 OFF_DF_TK_TERM 槽位改名:非类型辅码(旗标/宽度;0 = 无) fn sh_tk_face_of_code(opcode: int, tk: int) -> int // 分类表(Task 0 表 A 的代码化):0 = 类型行 / 1 = 辅码 / 2 = 无 fn sh_tk_term_of_code(opcode: int, tk: int) -> int // 类型行 ⇒ sh_term_of_ti(tk);辅码/无 ⇒ -1(分类表驱动,取代 {CONST,BINARY} 硬清单) diff --git a/docs/superpowers/plans/2026-09-16-agg-read-type.md b/docs/superpowers/plans/2026-09-16-agg-read-type.md index 9ec45d38..5efce306 100644 --- a/docs/superpowers/plans/2026-09-16-agg-read-type.md +++ b/docs/superpowers/plans/2026-09-16-agg-read-type.md @@ -306,80 +306,90 @@ apx 批已转正的 B-3/B-4/B-5/B-6/B-8 探针(`tests/selfhost/test_apx_conver ```core // R1 · LET 中转丢型 -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 · match 臂载荷绑定 -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 · 聚合读写回 apx(binary64)槽 -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 实参(判定形态 = IR 断言,见 11.6) -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 // R7(非回归钉子)· Core 调用实参 -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(非回归钉子)· apx 批已转正的比较/raw 形 -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 ``` ### 11.3 改前实测(冻结基线编译 + `--static` 产物运行) diff --git a/docs/superpowers/plans/2026-09-17-silence-closure.md b/docs/superpowers/plans/2026-09-17-silence-closure.md index afb8b9d5..c9d9043c 100644 --- a/docs/superpowers/plans/2026-09-17-silence-closure.md +++ b/docs/superpowers/plans/2026-09-17-silence-closure.md @@ -122,11 +122,17 @@ ⇒ 静默错值 **+ ELF≠interp(双路径分歧)**,与批 5 原始 RED(u11)同严重级。 - **最小复现**: ```core - 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); } // 期望 7;实测 ELF 142 / interp 15 - // ⚠ 标注:`142`=样本非锚(非确定分布的一次采样);「期望 7」已作废 ⇒ 修后应为**硬错拒绝**(rc=1,见回填块 ③ 与 Ⅶ 支 1) + 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) + // 期望 7;实测 ELF 142 / interp 15 + // ⚠ 标注:`142`=样本非锚(非确定分布的一次采样);「期望 7」已作废 ⇒ 修后应为**硬错拒绝**(rc=1,见回填块 ③ 与 Ⅶ 支 1) ``` - **机理(`file:line`,读码)**: - 调用侧环取**泛型声明**的形参链:`ir_gen.cr:1965` `cfi := find_func(func_ni)` → `fi_ast_node(cfi)`;门在 `:1985` @@ -151,7 +157,12 @@ 两个值为 7 的可选比较 ⇒ **1** · `n == 7`(可选 vs 内层值)⇒ **1**。 - **最小复现**: ```core - fn main() -> int { n : int? = None; if n == None { return 1; } return 0; } // 期望 1;实测 0 + fn main() -> int: + n : int? = none + if n == none: + return 1 + return 0 + // 期望 1;实测 0 ``` - **机理(2026-09-18 重锚 + 定性更正)**:`==` 走 `gen_expr`(`ir_gen.cr:1192` 起)内的**通用落点 `:1465-1467`** (`emit(IR_BINARY, v, left_var, right_var, op, fti)`)**不读 rep 位** ⇒ **逐槽比较原始值**: @@ -183,8 +194,11 @@ 对照 `extern fn e(x: int?)` ⇒ **同形同判**(非 dex 特有)。 - **最小复现**: ```core - extern fn e_opt(x: dex?) -> int; - fn main() -> int { d : dex, apx = 7.0; return e_opt(d); } // check=0(应拒未拒);运行期 139 + extern fn e_opt(x: dex?) -> int + fn main() -> int: + d : dex, apx = 7.0 + return e_opt(d) + // check=0(应拒未拒);运行期 139 ``` - **机理(读码)**:`checker.cr:2167` `if ast_kind(fn_node) == EXPR_EXTERN { return; }` ⇒ **extern 声明的形参/体检查整段跳过** ⇒ 无「C ABI 可表示性」校验;`ir_gen.cr:1985` 的 `cfn_ext == 0` 守卫使实参环**对 extern 侧不扩**(无约定可依)。 diff --git a/docs/superpowers/plans/2026-09-17-spec-grammar.md b/docs/superpowers/plans/2026-09-17-spec-grammar.md index 9b622d92..e5649817 100644 --- a/docs/superpowers/plans/2026-09-17-spec-grammar.md +++ b/docs/superpowers/plans/2026-09-17-spec-grammar.md @@ -372,8 +372,10 @@ **探针** `/tmp/spec-t0/red_annot.cr`: ```core -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() ``` | 命令 | **实测结果** | @@ -498,9 +500,13 @@ B04 ×2(`ptr_arith` **= canary 载体本人** + `apx_conversion_test`)= **39 上文「corec 侧 = 响亮拒绝」**只在注解名恰好未定义时成立**。实测(`/tmp/spec-t1/collide.cr`): ```core -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/docs/superpowers/plans/2026-09-18-b8-e1-t0.md b/docs/superpowers/plans/2026-09-18-b8-e1-t0.md index 52477e80..36100bc0 100644 --- a/docs/superpowers/plans/2026-09-18-b8-e1-t0.md +++ b/docs/superpowers/plans/2026-09-18-b8-e1-t0.md @@ -30,10 +30,15 @@ **探针 P0(= 计划书原文逐字,`.b8e1-probes/p0_orig.cr`)**: ```core -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); } +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) ``` **取数(全部在 `/home/DslsDZC/core-b8e1-ws` 下跑,cwd = 仓根)**: @@ -165,9 +170,22 @@ raw=140737488342408 # 两次完全相同;= 0x7FFFFFFFE0C8(栈区地 **实测(develop `41a51d8d`,探针逐字照 TODO 条目)**: ```core -fn gid[T](x: T) -> T { return x; } -fn main() -> int { d : dex, apx = 7.0; r := gid(d); if r == 7.0 { return 0; } return 55; } // m4_bits -fn main() -> int { e : dex = 7.0; r := gid(e); if r == 7.0 { return 0; } return 56; } // m4_scaled +fn gid[T](x: T) -> T: + return x +fn main() -> int: + d : dex, apx = 7.0 + r := gid(d) + if r == 7.0: + return 0 + return 55 +// m4_bits +fn main() -> int: + e : dex = 7.0 + r := gid(e) + if r == 7.0: + return 0 + return 56 +// m4_scaled ``` | 探针 | check | build | ELF | interp | diff --git a/docs/superpowers/plans/2026-09-20-mapping-layer-separation.md b/docs/superpowers/plans/2026-09-20-mapping-layer-separation.md index f26e7904..302c14fd 100644 --- a/docs/superpowers/plans/2026-09-20-mapping-layer-separation.md +++ b/docs/superpowers/plans/2026-09-20-mapping-layer-separation.md @@ -216,19 +216,22 @@ jj --ignore-working-copy file show -r "$DEV" src/compiler/ptr_analysis.cr | grep **观测(最小、两腿可跑、rc 即读数)**——`corec run <内联源码>` 的 **rc = `main` 的返回值**(已自证:`return 42` ⇒ rc=42): ```core -fn main() -> int { - i : ., mut = 0; prev : ., mut = 0; gap : ., mut = 0; - loop { - if i >= 3 { break; } - s := alloc(8); - p : ., mut = 0; - unsafe { p = @ptr_of(s); } - if i > 0 { gap = p - prev; } - prev = p; - i = i + 1; - } - return gap; -} +fn main() -> int: + i : ., mut = 0 + prev : ., mut = 0 + gap : ., mut = 0 + loop: + if i >= 3: + break + s := alloc(8) + p : ., mut = 0 + unsafe: + p = @ptr_of(s) + if i > 0: + gap = p - prev + prev = p + i = i + 1 + return gap ``` **实测读数(本批实跑,非注释转述)**: diff --git a/docs/superpowers/plans/2026-09-23-compile-cost-and-recheck.md b/docs/superpowers/plans/2026-09-23-compile-cost-and-recheck.md index 99f86594..f89385d6 100644 --- a/docs/superpowers/plans/2026-09-23-compile-cost-and-recheck.md +++ b/docs/superpowers/plans/2026-09-23-compile-cost-and-recheck.md @@ -290,13 +290,11 @@ ``` src/compiler/region_check.cr:5-11 -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; -} + if node_seq >= 0 && node_seq < g_df_node_count: + return r64(g_df_node_region, node_seq * 8) + return -1 ``` - `g_df_node_region` 的**写点唯一**:`dataflow.cr:103` `w64(g_df_node_region, nid * 8, g_cur_sg);`(在 `df_create_node` 内,**每节点一次**)。 - ⇒ **修法是「去掉每调用全扫」,不是发明新算法。** diff --git a/docs/superpowers/specs/2026-07-28-arena-model-design.md b/docs/superpowers/specs/2026-07-28-arena-model-design.md index b260e331..d9459532 100644 --- a/docs/superpowers/specs/2026-07-28-arena-model-design.md +++ b/docs/superpowers/specs/2026-07-28-arena-model-design.md @@ -67,13 +67,15 @@ alloc(size): 嵌套示例: ``` -fn main() { // arena_new() → ai=0, g_current_arena=0 - x := alloc(32); // 从 arena 0 分配 - loop { // arena_new() → ai=1, g_current_arena=1, parent=0 - y := alloc(64); // 从 arena 1 分配 - } // arena_reset(1) → g_current_arena=0, cursor[1]=0 - z := alloc(16); // 从 arena 0 分配 -} // arena_reset(0) → g_current_arena=-1, cursor[0]=0 +fn main(): + // arena_new() → ai=0, g_current_arena=0 + x := alloc(32) // 从 arena 0 分配 + loop: + // arena_new() → ai=1, g_current_arena=1, parent=0 + y := alloc(64) // 从 arena 1 分配 + // arena_reset(1) → g_current_arena=0, cursor[1]=0 + z := alloc(16) // 从 arena 0 分配 +// arena_reset(0) → g_current_arena=-1, cursor[0]=0 ``` ## 组件设计 @@ -82,47 +84,43 @@ fn main() { // arena_new() → ai=0, g_current_arena=0 ```core // === 全局变量 === -g_current_arena : int, mut = -1; +g_current_arena : int, mut = -1 // Arena metadata arrays (allocated in arena_init, accessed by emit_alloc_body) -g_arena_cursors : string, mut; // int[] — element = cursor offset -g_arena_sizes : string, mut; // int[] — element = chunk max size -g_arena_parents : string, mut; // int[] — element = parent arena ID +g_arena_cursors : string, mut // int[] — element = cursor offset +g_arena_sizes : string, mut // int[] — element = chunk max size +g_arena_parents : string, mut // int[] — element = parent arena ID -g_arena_pool_data : string, mut; // pool base pointer (from alloc) -g_arena_max_size : int, mut; -g_arena_free_list : int, mut = -1; -g_arena_count : int, mut = 0; -g_arena_cap : int, mut = 0; // metadata 数组容量 +g_arena_pool_data : string, mut // pool base pointer (from alloc) +g_arena_max_size : int, mut +g_arena_free_list : int, mut = -1 +g_arena_count : int, mut = 0 +g_arena_cap : int, mut = 0 // metadata 数组容量 // === API === -fn arena_init(pool_size: int, arena_size: int) { +fn arena_init(pool_size: int, arena_size: int): // 从全局 bump heap 分配 pool 数据区。 // 此时 g_current_arena = -1,alloc() 走全局 bump 路径 - 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 { + 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: // 从 free list 取,或创建新 slot // 设置 parent = g_current_arena // 设置 g_current_arena = new_id // cursor = 0 // 返回 new_id -} -fn arena_reset(ai: int) { +fn arena_reset(ai: int): // cursor = 0 // g_current_arena = parent // 推入 free list -} -fn arena_avail(ai: int) -> int { +fn arena_avail(ai: int) -> int: // 返回剩余可用字节数 -} ``` `arena_alloc` 不需要作为独立的 Core 函数——现有 `alloc()` 已经 arena-aware。 @@ -166,8 +164,8 @@ heap_end: ### 4. 编译器 — 新增 IR 指令(`src/compiler/ast.cr`) ```core -IR_ARENA_NEW : int = 30; // arena_new dest, src1(size_estimate) -IR_ARENA_RESET : int = 31; // arena_reset src1 +IR_ARENA_NEW : int = 30 // arena_new dest, src1(size_estimate) +IR_ARENA_RESET : int = 31 // arena_reset src1 ``` `IR_ARENA_NEW` 的 `src1` 是编译器预估的 arena 大小(编译期常量或 0=默认)。后端的 `arena_new_impl` 用此值选取合适 chunk 大小或触发链式扩容。 @@ -226,28 +224,26 @@ IR_ARENA_RESET : int = 31; // arena_reset src1 ```core // ir_gen.cr 新增 -g_sg_alloc_total : string, mut; // per-subgraph allocation total -g_sg_alloc_cap : int, mut; - -fn sg_alloc_push(kind: int) { - grow_sg_alloc(g_sg_count + 1); - w64(g_sg_alloc_total, g_sg_count * 8, 0); - sg_push(kind); -} - -fn sg_alloc_pop() { - total := r64(g_sg_alloc_total, (g_sg_count - 1) * 8); - if total == 0 { total = 65536; } // default 64KB for dynamic-only - emit(IR_ARENA_NEW, arena_var, total, 0, 0, 0); - sg_pop(); -} - -fn track_alloc_size(size: int) { - if g_sg_count > 0 { - old := r64(g_sg_alloc_total, (g_sg_count - 1) * 8); - w64(g_sg_alloc_total, (g_sg_count - 1) * 8, old + size); - } -} +g_sg_alloc_total : string, mut // per-subgraph allocation total +g_sg_alloc_cap : int, mut + +fn sg_alloc_push(kind: int): + grow_sg_alloc(g_sg_count + 1) + w64(g_sg_alloc_total, g_sg_count * 8, 0) + sg_push(kind) + +fn sg_alloc_pop(): + total := r64(g_sg_alloc_total, (g_sg_count - 1) * 8) + if total == 0: + total = 65536 + // default 64KB for dynamic-only + emit(IR_ARENA_NEW, arena_var, total, 0, 0, 0) + sg_pop() + +fn track_alloc_size(size: int): + if g_sg_count > 0: + old := r64(g_sg_alloc_total, (g_sg_count - 1) * 8) + w64(g_sg_alloc_total, (g_sg_count - 1) * 8, old + size) ``` `track_alloc_size` 在每个 `emit(IR_ALLOC_X, ...)` 处调用。 diff --git a/docs/superpowers/specs/2026-07-28-at-intrinsics-design.md b/docs/superpowers/specs/2026-07-28-at-intrinsics-design.md index 8c968aee..3182ac88 100644 --- a/docs/superpowers/specs/2026-07-28-at-intrinsics-design.md +++ b/docs/superpowers/specs/2026-07-28-at-intrinsics-design.md @@ -33,7 +33,7 @@ 新增 `EXPR_AT` AST 节点: ```core -EXPR_AT : int = 46; // @内建: a=name_ni, b=args_node, c=0, iv=0, tv=0, data=0 +EXPR_AT : int = 46 // @内建: a=name_ni, b=args_node, c=0, iv=0, tv=0, data=0 ``` 在 `parse_primary` 中识别 `T_AT`: diff --git a/docs/superpowers/specs/2026-07-29-hotpatch-design.md b/docs/superpowers/specs/2026-07-29-hotpatch-design.md index d59b2075..6e19088a 100644 --- a/docs/superpowers/specs/2026-07-29-hotpatch-design.md +++ b/docs/superpowers/specs/2026-07-29-hotpatch-design.md @@ -16,7 +16,7 @@ Core 编译器的滚动更新(hotpatch)机制。通过 `@hotpatch` 注解支 ## IR 指令 ```core -IR_HOTPATCH_ROUTE : int = 39; // dest=result_var, s1=fn_name_ni, s2=first_arg, s3=arg_count +IR_HOTPATCH_ROUTE : int = 39 // dest=result_var, s1=fn_name_ni, s2=first_arg, s3=arg_count ``` `IR_HOTPATCH_ROUTE` 在调用点替代 `IR_CALL`。后端将其编译为: @@ -32,8 +32,10 @@ IR_HOTPATCH_ROUTE : int = 39; // dest=result_var, s1=fn_name_ni, s2=first_arg, **新增关键字**:`@hotpatch` 作为 `@` 内建原语扩展。 ```core -@hotpatch(ver=1) fn handle(x: dyn) -> dyn { body1 } -@hotpatch(ver=2) fn handle(x: dyn) -> dyn { body2 } +@hotpatch(ver=1) fn handle(x: dyn) -> dyn: + body1 +@hotpatch(ver=2) fn handle(x: dyn) -> dyn: + body2 ``` 解析器: diff --git a/docs/superpowers/specs/2026-07-29-incremental-cache-design.md b/docs/superpowers/specs/2026-07-29-incremental-cache-design.md index a97996e7..caa3ab28 100644 --- a/docs/superpowers/specs/2026-07-29-incremental-cache-design.md +++ b/docs/superpowers/specs/2026-07-29-incremental-cache-design.md @@ -55,15 +55,14 @@ Core 编译器的函数级增量缓存。默认开启,编译无感知——每 ## 指纹计算 ```core -fn function_fingerprint(func_node: int) -> int { +fn function_fingerprint(func_node: int) -> int: // 从 AST 中提取函数体原文区域 - body_node := ast_data(func_node); // body AST node - body_start := ast_pos(body_node); // 函数体在源文件中的起始位置 - body_end := ast_end(body_node); // 结束位置 - + body_node := ast_data(func_node) // body AST node + body_start := ast_pos(body_node) // 函数体在源文件中的起始位置 + body_end := ast_end(body_node) // 结束位置 + // 对原文做 hash - return hash_source_segment(g_source, body_start, body_end); -} + return hash_source_segment(g_source, body_start, body_end) ``` 使用现有 `str_hash` 函数(Fowler-Noll-Vo 或同类算法),该函数已存在于 `dyn_arr.cr`。 @@ -71,29 +70,28 @@ fn function_fingerprint(func_node: int) -> int { ### 签名指纹 ```core -fn sig_fingerprint(func_node: int) -> int { +fn sig_fingerprint(func_node: int) -> int: // 函数名 + 参数类型 + 返回类型 - name_ni := ast_a(func_node); - hash := str_hash(istr_get(name_ni)); - + name_ni := ast_a(func_node) + hash := str_hash(istr_get(name_ni)) + // 遍历参数 - param := ast_b(func_node); - param_count := ast_c(func_node); - pi := 0; - loop { - if pi >= param_count { break; } - param_type := ast_type_val(param); - hash = hash * 31 + param_type; // 将类型编码入 hash - pi = pi + 1; - param = param + 1; - } - + param := ast_b(func_node) + param_count := ast_c(func_node) + pi := 0 + loop: + if pi >= param_count: + break + param_type := ast_type_val(param) + hash = hash * 31 + param_type // 将类型编码入 hash + pi = pi + 1 + param = param + 1 + // 返回类型 - ret_type := ast_type_val(func_node); - hash = hash * 31 + ret_type; - - return hash; -} + ret_type := ast_type_val(func_node) + hash = hash * 31 + ret_type + + return hash ``` ## 编译管线集成(更新后的 `build` 流程) @@ -146,26 +144,27 @@ fn sig_fingerprint(func_node: int) -> int { ### save_cir_cache(path, func_idx) ```core -fn save_cir_cache(path: string, func_idx: int) { - fd := syscall3(2, path, 577, 420); // O_WRONLY|O_CREAT|O_TRUNC - if fd < 0 { return; } - - w_cir_cache(fd, func_idx); - syscall3(3, fd, 0, 0); -} +fn save_cir_cache(path: string, func_idx: int): + fd := syscall3(2, path, 577, 420) // O_WRONLY|O_CREAT|O_TRUNC + if fd < 0: + return + + w_cir_cache(fd, func_idx) + syscall3(3, fd, 0, 0) ``` ### load_cir_cache(path) -> int ```core -fn load_cir_cache(path: string) -> int { - buf := read_file(path); - if str_len(buf) < 32 { return -1; } // 太短,无效 - +fn load_cir_cache(path: string) -> int: + buf := read_file(path) + if str_len(buf) < 32: + return -1 + // 太短,无效 + // 验证 magic + version // 反序列化到 g_df_nodes/g_ir_instrs 等 - return 0; // 成功 -} + return 0 // 成功 ``` ## 实现清单 diff --git a/docs/superpowers/specs/2026-07-30-concurrency-design.md b/docs/superpowers/specs/2026-07-30-concurrency-design.md index 383696bb..7dff117c 100644 --- a/docs/superpowers/specs/2026-07-30-concurrency-design.md +++ b/docs/superpowers/specs/2026-07-30-concurrency-design.md @@ -34,7 +34,7 @@ P — 不分离,合并到 M ### G 结构 ```core -struct Goroutine { +struct Goroutine: id: int, status: int, stack_ptr: int, // 栈指针(固定 16KB 栈) @@ -42,19 +42,17 @@ struct Goroutine { arena_id: int, // 绑定的 arena chan_wait: int, // 阻塞在此 channel 上(_Gwaiting 时) next: int, // 链表(run queue / wait queue) -} ``` ### M 结构 ```core -struct Machine { +struct Machine: id: int, cur_g: int, // 当前运行的 G runq_head: int, // local run queue 头 runq_tail: int, // local run queue 尾 g0: int, // 系统 G(M 本身的栈) -} ``` ## Channel @@ -62,16 +60,16 @@ struct Machine { ### `chan T` 语法 ```core -ch := make(chan int, 10); // 缓冲 channel,容量 10 -send(ch, 42); // 发送 -val := recv(ch); // 接收 -close(ch); // 关闭 +ch := make(chan int, 10) // 缓冲 channel,容量 10 +send(ch, 42) // 发送 +val := recv(ch) // 接收 +close(ch) // 关闭 ``` ### channel 结构 ```core -struct Channel { +struct Channel: buf: string, // 环形缓冲区 cap: int, // 容量 len: int, // 当前元素数 @@ -80,7 +78,6 @@ struct Channel { send_wait: int, // 等待发送的 G 链表头 recv_wait: int, // 等待接收的 G 链表头 closed: int, // 是否已关闭 -} ``` ### Channel 操作 @@ -119,8 +116,8 @@ go f(args); **返回值**:`go f()` 返回一个 channel,用于接收 `f` 的返回值: ```core -ch := go f(args); -result := recv(ch); // 等待 f 完成并获取结果 +ch := go f(args) +result := recv(ch) // 等待 f 完成并获取结果 ``` ## 调度器 @@ -164,8 +161,8 @@ ret ## IR 指令 ```core -IR_SPAWN : int = 27; // 已有: dest=chan, s1=fn_ni, s2=first_arg, s3=arg_count -IR_YIELD : int = 28; // 已有: s1=value_var +IR_SPAWN : int = 27 // 已有: dest=chan, s1=fn_ni, s2=first_arg, s3=arg_count +IR_YIELD : int = 28 // 已有: s1=value_var ``` 上列编号保持不变。`IR_SPAWN` 在后端编译为 fiber 创建 + 队列投递。`IR_YIELD` 编译为 fiber 切换。 diff --git a/docs/superpowers/specs/2026-07-30-dynamic-typing-design.md b/docs/superpowers/specs/2026-07-30-dynamic-typing-design.md index 6a1eff5a..68dd97c8 100644 --- a/docs/superpowers/specs/2026-07-30-dynamic-typing-design.md +++ b/docs/superpowers/specs/2026-07-30-dynamic-typing-design.md @@ -18,9 +18,9 @@ ### 新增类型常量 ```core -T_DYN : int = 48; // token: dyn 关键字 -TI_DYN : int = 7; // 类型索引 -TYP_DYN : int = 11; // 类型种类: data = 该点已知的具体类型集合 +T_DYN : int = 48 // token: dyn 关键字 +TI_DYN : int = 7 // 类型索引 +TYP_DYN : int = 11 // 类型种类: data = 该点已知的具体类型集合 ``` `TYP_DYN` 的 `data` 字段在编译期追踪该点的可能类型集合。单路径时退化为 `TYP_BASE`/`TYP_NAMED`(零开销),多路径时保持 `TYP_DYN`。 @@ -46,7 +46,7 @@ g_type_set : string, mut; // 每变量: int[] 可能类型索引 在 `src/compiler/keywords.cr` 中添加: ```core -T_DYN : int = 48; +T_DYN : int = 48 ``` ### `parse_type` 中处理 @@ -61,7 +61,7 @@ if str_eq(lex, "dyn") != 0 { ### 变量声明 ```core -x : dyn = 42; +x : dyn = 42 ``` 标准 `:` 类型标注语法直接支持。解析器在 `parse_decl` 中遇到 `dyn` 时设置 `ast_type_val` 为 `TI_DYN`。 @@ -84,18 +84,17 @@ x : dyn = 42; ```core // 伪代码: 合并两个路径的类型集合 -fn merge_type_sets(target: int, path_a_set: int, path_b_set: int) { +fn merge_type_sets(target: int, path_a_set: int, path_b_set: int): // 如果两个路径的类型集合相同 → 无需变更 // 如果两个路径的类型集合不同 → 合并为 TYP_DYN // 单路径 → 退化为基础类型(零开销) -} ``` ### 方法/函数调用验证 ```core -x : dyn = cond ? 42 : "hello"; -x.len(); +x : dyn = cond ? 42 : "hello" +x.len() // 路径 A: 42 → int → 无 .len() → 编译错误 // 路径 B: "hello" → string → 有 .len() → OK // 结果: 编译错误(int 上没有 len 方法) @@ -108,10 +107,10 @@ x.len(); ### 新增 IR 指令 ```core -IR_DYN_TAG : int = 41; // dest=tag_var, s1=dyn_var — 提取 dyn 的 tag -IR_DYN_VAL : int = 42; // dest=val_var, s1=dyn_var — 提取 dyn 的 value(按已知类型) -IR_DYN_PACK : int = 43; // dest=dyn_var, s1=val_var, s2=type_idx — 打包成 dyn -IR_DYN_DISPATCH : int = 44; // s1=dyn_var, s2=type_list_ni — 按 tag 分派执行 +IR_DYN_TAG : int = 41 // dest=tag_var, s1=dyn_var — 提取 dyn 的 tag +IR_DYN_VAL : int = 42 // dest=val_var, s1=dyn_var — 提取 dyn 的 value(按已知类型) +IR_DYN_PACK : int = 43 // dest=dyn_var, s1=val_var, s2=type_idx — 打包成 dyn +IR_DYN_DISPATCH : int = 44 // s1=dyn_var, s2=type_list_ni — 按 tag 分派执行 ``` ### 变量宽度 @@ -128,15 +127,15 @@ ESZ_IRV_NEW : int = 32; // 旧 24 → 新 32(兼容现有 3 字段布局) ### 单路径优化 ```core -x : dyn = 42; // 编译期知道: x 的类型 = int(退化为裸值) -y := x + 1; // 直接加法,不需要 tag 检查 +x : dyn = 42 // 编译期知道: x 的类型 = int(退化为裸值) +y := x + 1 // 直接加法,不需要 tag 检查 ``` ```core -x : dyn = cond ? 42 : "hello"; +x : dyn = cond ? 42 : "hello" // 编译期知道: x ∈ {int, string} // x 在 IR 中是 { tag: int|string, value: 8bytes } -y := x + 1; +y := x + 1 // → 编译为: // if x.tag == int: y = x.value_int + 1 // if x.tag == string: y = str_to_int(x.value_str) + 1 @@ -230,13 +229,13 @@ jmp .type_error 边界转换在 IR gen 时静态插入: ```core -x : dyn = 42; -y := x + 1; // int + int → 直接加法(x 在这是裸 int) +x : dyn = 42 +y := x + 1 // int + int → 直接加法(x 在这是裸 int) ``` ```core -x : dyn = "42"; -y := x + 1; // string + int → str_to_int + 加法(自动插转换) +x : dyn = "42" +y := x + 1 // string + int → str_to_int + 加法(自动插转换) ``` 转换规则表(编译期,不依赖运行时): diff --git a/docs/superpowers/specs/2026-07-30-ffi-design.md b/docs/superpowers/specs/2026-07-30-ffi-design.md index 82b198f3..30cdbb86 100644 --- a/docs/superpowers/specs/2026-07-30-ffi-design.md +++ b/docs/superpowers/specs/2026-07-30-ffi-design.md @@ -16,17 +16,17 @@ ### `extern fn` 声明 ```core -extern fn read_file(path: *const u8) -> *mut u8; -extern fn write(fd: i32, buf: *const u8, len: i32) -> i32; -extern fn getchar() -> i32; +extern fn read_file(path: *const u8) -> *mut u8 +extern fn write(fd: i32, buf: *const u8, len: i32) -> i32 +extern fn getchar() -> i32 ``` ### `@ffi` 多语言注解 ```core -@ffi("C") extern fn printf(fmt: *const u8, ...) -> i32; -@ffi("Python") extern fn py_call(obj: dyn, method: string) -> dyn; -@ffi("Java") extern fn java_call(env: dyn, obj: dyn, method: string) -> dyn; +@ffi("C") extern fn printf(fmt: *const u8, ...) -> i32 +@ffi("Python") extern fn py_call(obj: dyn, method: string) -> dyn +@ffi("Java") extern fn java_call(env: dyn, obj: dyn, method: string) -> dyn ``` ## 类型映射 @@ -70,27 +70,25 @@ extern fn getchar() -> i32; **新增 Token**: ```core -T_EXTERN : int = 100; // extern 关键字 +T_EXTERN : int = 100 // extern 关键字 ``` **`parse_extern_fn`**:在 `parse_declaration` 中处理 `extern fn`: ```core -if tok_k(cur_tok()) == T_EXTERN { - advance_tok(); +if tok_k(cur_tok()) == T_EXTERN: + advance_tok() // 检查 @ffi("...") 注解 - ffi_lang : ., mut = "C"; - if tok_k(cur_tok()) == T_AT { + ffi_lang : ., mut = "C" + if tok_k(cur_tok()) == T_AT: // @ffi("Python") 解析 - ffi_lang = parse_ffi_annotation(); - } + ffi_lang = parse_ffi_annotation() // 解析 fn name(args) -> ret; - fn_node := parse_fn_declaration(); + fn_node := parse_fn_declaration() // 标记为 extern 函数 - ast_set_data(fn_node, str_intern(ffi_lang)); + ast_set_data(fn_node, str_intern(ffi_lang)) // 不解析函数体 - return fn_node; -} + return fn_node ``` ### 2. 检查器 @@ -125,14 +123,13 @@ if is_extern_func(func_ni) { ```core // 在 ldd.cr 中处理 extern 函数 -fn link_extern_func(func_ni: int) { +fn link_extern_func(func_ni: int): // 根据函数名查找 .so // 如果已经通过 reg_so_funcs 注册,直接使用 // 否则搜索默认路径 - lib_name := "lib" + get_func_module(func_ni) + ".so"; - ctx_add_so(lib_name); - ctx_add_plt(func_name, so_idx); -} + lib_name := "lib" + get_func_module(func_ni) + ".so" + ctx_add_so(lib_name) + ctx_add_plt(func_name, so_idx) ``` ## 已有基础设施(直接复用) diff --git a/docs/superpowers/specs/2026-07-30-generics-design.md b/docs/superpowers/specs/2026-07-30-generics-design.md index 5e248345..7e775362 100644 --- a/docs/superpowers/specs/2026-07-30-generics-design.md +++ b/docs/superpowers/specs/2026-07-30-generics-design.md @@ -27,24 +27,28 @@ y := first(arr); // T = 元素类型 ### 泛型结构体 ```core -struct Box { val: T } -struct Pair { first: A; second: B } +struct Box: + val: T +struct Pair: + first: A + second: B // 构造时推导 -b := Box{val=42}; // T = int -p := Pair{first=1, second="hi"}; // A=int, B=string +b := Box{val=42} // T = int +p := Pair{first=1, second="hi"} // A=int, B=string ``` ### 泛型方法 ```core -impl Box { - fn get(self) -> T { return self.val; } - fn set(self, val: T) { self.val = val; } -} - -b := Box{val=42}; -x := b.get(); // T = int +impl Box: + fn get(self) -> T: + return self.val + fn set(self, val: T): + self.val = val + +b := Box{val=42} +x := b.get() // T = int ``` ## 实现架构 @@ -98,23 +102,21 @@ x := b.get(); // T = int ```core // 实例表 -g_gen_instances : string, mut; // 缓存已特化的函数索引 -g_gen_instance_count : int, mut; +g_gen_instances : string, mut // 缓存已特化的函数索引 +g_gen_instance_count : int, mut // 查找或创建实例 -fn gen_find_instance(func_ni: int, type_args: string) -> int { +fn gen_find_instance(func_ni: int, type_args: string) -> int: // 扫描 g_gen_instances 查找已缓存的实例 // 如果找到,返回函数索引 // 如果没找到,创建新实例 -} // 生成特化版本 -fn gen_monomorphize(func_ni: int, type_args: string) -> int { +fn gen_monomorphize(func_ni: int, type_args: string) -> int: // 1. 复制函数 AST // 2. 将 T 替换为具体类型 // 3. 注册新函数到 g_funcs // 4. 返回新函数索引 -} ``` ### 4. IR 生成(`ir_gen.cr`) diff --git a/docs/superpowers/specs/2026-07-30-lazy-eval-design.md b/docs/superpowers/specs/2026-07-30-lazy-eval-design.md index 91a5ac62..4cd4b83c 100644 --- a/docs/superpowers/specs/2026-07-30-lazy-eval-design.md +++ b/docs/superpowers/specs/2026-07-30-lazy-eval-design.md @@ -46,17 +46,16 @@ ```core // checker.cr: 函数注册时分析函数体 -fn is_pure_func(func_node: int) -> int { +fn is_pure_func(func_node: int) -> int: // 扫描函数体 // 如果有 IO/FFI/unsafe 调用 → 返回 0 // 如果全为纯计算 → 返回 1 -} ``` 存储在 `g_funcs` 的新字段中: ```core -OFF_FN_ISPURE : int = 32; // 新字段,1=纯函数 +OFF_FN_ISPURE : int = 32 // 新字段,1=纯函数 ESZ_FN 增长为 40 ``` @@ -81,8 +80,8 @@ ESZ_FN 增长为 40 ### 新增 IR 操作 ```core -IR_LAZY_THUNK : int = 46; // dest=thunk_var, s1=expr_var — 包装为惰性 thunk -IR_LAZY_FORCE : int = 47; // dest=val_var, s1=thunk_var — 强制求值 +IR_LAZY_THUNK : int = 46 // dest=thunk_var, s1=expr_var — 包装为惰性 thunk +IR_LAZY_FORCE : int = 47 // dest=val_var, s1=thunk_var — 强制求值 ``` ### Thunk 表示 diff --git a/docs/superpowers/specs/2026-07-30-probabilistic-pass-design.md b/docs/superpowers/specs/2026-07-30-probabilistic-pass-design.md index 7f3a3dea..d6426cce 100644 --- a/docs/superpowers/specs/2026-07-30-probabilistic-pass-design.md +++ b/docs/superpowers/specs/2026-07-30-probabilistic-pass-design.md @@ -41,22 +41,19 @@ pass 流程: ## Step 1:`random()` 节点识别 ```core -fn scan_random_calls() { +fn scan_random_calls(): // 遍历所有 DF 节点 - ni := 0; - loop { - if ni >= g_df_node_count { break; } - op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE); - if op == IR_CALL { - fn_ni := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3); - fn_name := istr_get(fn_ni); - if str_eq(fn_name, "random") != 0 { - mark_random_node(ni); - } - } - ni = ni + 1; - } -} + ni := 0 + loop: + if ni >= g_df_node_count: + break + op := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_OPCODE) + if op == IR_CALL: + fn_ni := r64(g_df_nodes, ni * ESZ_DFNODE + OFF_DF_S3) + fn_name := istr_get(fn_ni) + if str_eq(fn_name, "random") != 0: + mark_random_node(ni) + ni = ni + 1 ``` ## Step 2:分支概率标注 @@ -64,12 +61,11 @@ fn scan_random_calls() { `random() < p` 模式在图中是 `IR_BRANCH s1=condition`。如果 `condition` 的上游是 `IR_BINARY(OP_LT, random_call, IR_CONST(p))`,则: ```core -fn tag_branch_weights() { +fn tag_branch_weights(): // 对每个 BRANCH 节点: // 检查 condition 是否来自 random() < const // 如果是: 在分支边上标注 probability = p // 如果不是: 标记为 unknown (不做优化) -} ``` 图上的表示: @@ -88,7 +84,7 @@ random() ──→ IR_CONST(0.3) 沿值流传播概率权重。原理与数据流分析相同——每个值的"可能概率"沿分支边与数据边传播: ```core -fn propagate_weights() { +fn propagate_weights(): // 对每个 PHI 节点(值汇合点): // 从汇合的两个分支取权重 // 权重相乘后作为该值的分布概率 @@ -96,16 +92,15 @@ fn propagate_weights() { // 示例: // result := if random() < 0.05 { "rare" } else { "common" } // → result 的分布: {5% "rare", 95% "common"} - + // 迭代直到不动点(和 PointerAnalysis 一样的模式) - changed := 1; - loop { - if changed == 0 { break; } - changed = 0; + changed := 1 + loop: + if changed == 0: + break + changed = 0 // 遍历所有 PHI/BINARY 节点 // 更新权重 - } -} ``` ## Step 4:观测约束 @@ -113,12 +108,11 @@ fn propagate_weights() { `if sensor > 30 { ... }` — 条件分支同时也是一个观测。pass 在该处标注: ```core -fn apply_observations() { +fn apply_observations(): // 找到条件分支中涉及 random() 返回值的 // 在分支边上标注后验约束 // P(true_temp | sensor > 30) // 之后的 PHI 节点使用后验而不是先验 -} ``` ## Step 5:图标注 diff --git a/docs/superpowers/specs/2026-08-13-graph-anchored-regions-design.md b/docs/superpowers/specs/2026-08-13-graph-anchored-regions-design.md index 8adf859b..664b9a24 100644 --- a/docs/superpowers/specs/2026-08-13-graph-anchored-regions-design.md +++ b/docs/superpowers/specs/2026-08-13-graph-anchored-regions-design.md @@ -103,15 +103,14 @@ RegionCheck 的 `cur_seq < exit_seq` 判定(`pointer-model.md` Pass 2)就是 // 1. 布局声明(例外入口)——默认布局全自动:编译器按类型推导自然布局 // (字段顺序 + 自然对齐),用户不写任何东西。 // layout(...) 仅当默认布局不合用时才需要:packed(FFI)、强制对齐、硬件结构。 -struct PackedHeader layout(packed, align(4)) { +struct PackedHeader layout(packed, align(4)): a: u8, // 偏移 0 b: u32, // 偏移 4 c: u16, // 偏移 8 -} // 2. 放置声明——地址是物理事实,只有用户知道。 // 声明式进图(地址+大小+对齐),之后全图追踪,ProvenanceVerify 照常验证。 -mmio := alloc_at(0x7fff0000, 4096, align(4096)); +mmio := alloc_at(0x7fff0000, 4096, align(4096)) ``` - v1 **不提供**显式区域/回收语法(YAGNI)。「指定回收」是编译器内部机制(IR 层生成回收点 = Cyclone early deallocation 的自动版)。 diff --git a/docs/superpowers/specs/2026-09-17-silence-closure-t0-report.md b/docs/superpowers/specs/2026-09-17-silence-closure-t0-report.md index 18e7756b..ebb5fe04 100644 --- a/docs/superpowers/specs/2026-09-17-silence-closure-t0-report.md +++ b/docs/superpowers/specs/2026-09-17-silence-closure-t0-report.md @@ -45,8 +45,15 @@ ```core // 直调形(本批实测 RED):期望「拒绝」(类型错误);修前 check=0 · build=0 · ELF 垃圾 / interp 15 -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); } +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) ``` - **(甲) 落点**:`checker.cr` 的 `unify_types` 丢弃点(F3 面)——按 lead 三阶段 S1(report-only)→ S2(修站点)→ S3(升硬错)。 - **(乙) 落点**:`monomorph.cr` `EXPR_FN` 分支**连形参链一起克隆**(`gen_clone_consecutive(b, c)`); diff --git a/examples/add/main.cr b/examples/add/main.cr index b85c85ed..797f1b4f 100644 --- a/examples/add/main.cr +++ b/examples/add/main.cr @@ -1,6 +1,4 @@ -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) diff --git a/examples/complex/main.cr b/examples/complex/main.cr index 49962bfd..b9b6c94e 100644 --- a/examples/complex/main.cr +++ b/examples/complex/main.cr @@ -1,37 +1,33 @@ -struct Point { +struct Point: x: int, y: int, -} -impl Point { - fn sum(self: Point) -> int { - return self.x + self.y; - } - fn scale(self: Point, factor: int) -> int { - return (self.x + self.y) * factor; - } -} +impl Point: + fn sum(self: Point) -> int: + return self.x + self.y + fn scale(self: Point, factor: int) -> int: + return (self.x + self.y) * factor -fn sum_to(n: int) -> int { - i : ., mut = 1; - s : ., mut = 0; - loop { - if i > n { break; } - s = s + i; - i = i + 1; - } - return s; -} +fn sum_to(n: int) -> int: + i : ., mut = 1 + s : ., mut = 0 + loop: + if i > n: + break + s = s + i + i = i + 1 + return s -fn max(a: int, b: int) -> int { - if a > b { return a; } else { return b; } -} +fn max(a: int, b: int) -> int: + if a > b: + return a + else: + return b -fn main() -> int { - p := = Point { x = 10, y = 20 }; - s := = p.sum(); - scaled := = p.scale(3); - loop_val := = sum_to(5); - biggest := = max(s, loop_val); - return biggest + scaled; -} +fn main() -> int: + p := = Point { x = 10, y = 20 } + s := = p.sum() + scaled := = p.scale(3) + loop_val := = sum_to(5) + biggest := = max(s, loop_val) + return biggest + scaled diff --git a/examples/test_max.cr b/examples/test_max.cr index 571a4d5b..d80e5340 100644 --- a/examples/test_max.cr +++ b/examples/test_max.cr @@ -1,4 +1,7 @@ -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) diff --git a/examples/test_scale.cr b/examples/test_scale.cr index d369b82c..eaea7515 100644 --- a/examples/test_scale.cr +++ b/examples/test_scale.cr @@ -1,11 +1,12 @@ -struct Point { x: int, y: int } -impl Point { - fn sum(self: Point) -> int { return self.x + self.y; } - fn scale(self: Point, factor: int) -> int { return (self.x + self.y) * factor; } -} -fn main() -> int { - p := = Point { x = 10, y = 20 }; - s := = p.sum(); - scaled := = p.scale(3); - return s + scaled; -} +struct Point: + x: int, y: int +impl Point: + fn sum(self: Point) -> int: + return self.x + self.y + fn scale(self: Point, factor: int) -> int: + return (self.x + self.y) * factor +fn main() -> int: + p := = Point { x = 10, y = 20 } + s := = p.sum() + scaled := = p.scale(3) + return s + scaled diff --git a/examples/test_sum.cr b/examples/test_sum.cr index 94094bd7..dfe1d74b 100644 --- a/examples/test_sum.cr +++ b/examples/test_sum.cr @@ -1,8 +1,8 @@ -struct Point { x: int, y: int } -impl Point { - fn sum(self: Point) -> int { return self.x + self.y; } -} -fn main() -> int { - p := = Point { x = 10, y = 20 }; - return p.sum(); -} +struct Point: + x: int, y: int +impl Point: + fn sum(self: Point) -> int: + return self.x + self.y +fn main() -> int: + p := = Point { x = 10, y = 20 } + return p.sum() diff --git a/examples/test_sumto.cr b/examples/test_sumto.cr index 4fc4557f..a0bfecfc 100644 --- a/examples/test_sumto.cr +++ b/examples/test_sumto.cr @@ -1,11 +1,11 @@ -fn sum_to(n: int) -> int { - i : ., mut = 1; - s : ., mut = 0; - loop { - if i > n { break; } - s = s + i; - i = i + 1; - } - return s; -} -fn main() -> int { return sum_to(5); } +fn sum_to(n: int) -> int: + i : ., mut = 1 + s : ., mut = 0 + loop: + if i > n: + break + s = s + i + i = i + 1 + return s +fn main() -> int: + return sum_to(5) diff --git a/src/compiler/ast.cr b/src/compiler/ast.cr index 018457b2..b3aa5c0a 100644 --- a/src/compiler/ast.cr +++ b/src/compiler/ast.cr @@ -309,6 +309,15 @@ TI_DYN : int = 7 // dynamic type // TI_DEX_S 仍不查类型表(type_size/type_align/is_ptr_var 处保留显式守卫,见 ir_gen.cr), // 值永远以 8 字节槽存储。 TI_DEX_S : int = 8 +// **错误恢复哨兵**(2026-10-11 裁定 (c),与 `TI_NEVER` 分家):`infer_expr` 的**错误路径** +// (未定义名 / 未定义函数 / `@` 内建形错…)一律返回它,**不再复用 `TI_NEVER`**。 +// 动机:`TI_NEVER` 一名两用(真类型 `never` / 错误哨兵)⇒ 「`never` 与任何类型相容」这条 +// 规则会把**错误**也放过(实测:`undef_x = 0` 的 TA01 静默丢失;两前端不一致)。 +// **取负数**(不占 `TI_` 的表项空间——0..8 已占、9 起是用户类型):所有读表入口对负数都有 +// 守卫(`get_type_kind`/`get_type_data`/`get_type_extra` 的 `ti >= 0` 检查;`sh_term_of_ti` +// 的 `if ti < 0: return -1`)⇒ **不会越界读**;且 `type_equal_engine` 已加哨兵早退, +// 不会把负数灌进引擎的 `ty_indeterminate_report`(ICE04)。 +TI_ERROR : int = -2 // Type table entry kinds TYP_BASE : int = 0 // data = TY_* constant diff --git a/src/compiler/checker.cr b/src/compiler/checker.cr index 2abc1dbd..529b6243 100644 --- a/src/compiler/checker.cr +++ b/src/compiler/checker.cr @@ -461,6 +461,17 @@ fn type_compat_strict(ti_a: int, ti_b: int) -> int: // (见 infer_expr 的 EXPR_RETURN/EXPR_BREAK/EXPR_CONTINUE 格)⇒ 分支合一处的 // 「unit vs never」「int vs never」必须放行,否则「一支赋值、一支 return」这类 // **完全正常**的语句位 if 会被误报 TC02(实测:本仓 src/compiler/main.cr 的 is_decl_stmt)。 + // 错误哨兵(裁定 (c))——**定向**处置: + // · 源侧是错误 ⇒ **放行**(「错误值」不再级联出第二条诊断:`x : int = nosuchname` + // 只报 N01,不叠 TA02——与 `tests/selfhost/test_tc02_branch.py::ta02_never_exempt_still` + // 的期望同向); + // · 目标侧是错误 ⇒ **不放行**(目标类型取不到就是真差异 ⇒ `undef_x = 0` 的 TA01 回来)。 + // 这是「`TI_ERROR` 与 `TI_NEVER` 分家」的**全部收益点**:旧实现把两者混为一体, + // 于是「源侧要放行、目标侧要拒绝」这对矛盾需求不可能同时满足。 + if ti_a == TI_ERROR: + return 1 + if ti_b == TI_ERROR: + return 0 if ti_a == TI_NEVER || ti_b == TI_NEVER: return 1 if !type_equal(ti_a, ti_b): @@ -596,6 +607,11 @@ fn ty_indeterminate_report(kind: int, t1: int, t2: int, a: int, b: int, unc: int fn type_equal_engine(t1: int, t2: int) -> bool: if t1 == t2: return true + // 错误哨兵**不进引擎**(裁定 (c)):`TI_ERROR` 取负数、无类型行 ⇒ 若放它下去, + // `sh_term_of_ti` 回 -1 会触发 `ty_indeterminate_report`(**ICE04 硬错**,fail-closed) + // ⇒ 任何「错误值参与等价判定」都会变成新诊断。此处早退 = 等价判否(且**不报**)。 + if t1 == TI_ERROR || t2 == TI_ERROR: + return false // 快路径:同一行 a := sh_term_of_ti(t1) b := sh_term_of_ti(t2) @@ -892,6 +908,16 @@ fn find_so_fn(name_idx: int) -> int: // Uses g_diags, g_diag_count from globals.cr (and ast.cr) // Old g_check_errors is replaced by structured g_diags. +// ── nail3(2026-10-11 裁定):逐 `return` 核对「返回值 vs **当前函数**的声明返回型」── +// 为什么需要**新通道**:`return` 的类型被裁定为 `never`(见 infer_expr 的 EXPR_RETURN 格) +// ⇒ 体类型恒 `never` ⇒ 与声明返回型恒相容 ⇒ **类型通道里不留任何可比信息**。 +// 故在 `EXPR_RETURN` 处**额外**取一次「当前函数的声明返回型」做比对(诊断面,不参与节点类型)。 +// 承载:save/restore 两个全局(与 `g_unsafe_depth` 同款的显式上下文约定;嵌套函数声明已被 +// P21 拒绝 ⇒ 无需真栈)。`g_cur_fn_ret_checked == 0` ⇒ **不判**(flow 函数 / 声明返回型是 +// 泛型形参 —— 与既有 TF01 体检查的守卫同口径)。 +g_cur_fn_ret_ti : int, mut +g_cur_fn_ret_checked : int, mut + fn check_error(code: int, msg: string, line: int, col: int): grow_diags(g_diag_count + 1) w64(g_diags, g_diag_count * DIAG_REC_SIZE, code) @@ -2333,7 +2359,6 @@ fn check_func(fi: int): pn = pn + 1 // Check body if body >= 0: - body_ti := infer_expr(body) ret_ti : ., mut = TI_UNIT // First check for named type via the stored type node (kind != 0) type_node := ast_type_val(fn_node) @@ -2345,6 +2370,21 @@ fn check_func(fi: int): ret_ti_mapped := ty_code_to_ti(return_type) if ret_ti_mapped >= 0 && ret_ti_mapped != TI_DYN: ret_ti = ret_ti_mapped + // nail3:**先算 ret_ti / flow 守卫,再推体** —— 逐 `return` 核对需要这两个值在手。 + // ⚠ 次序改动是安全的:`res_type_node`/`ty_code_to_ti`/`scan_for_yield` 都只看 + // **声明与 AST**,不依赖 `infer_expr(body)` 的结果。 + is_flow_fn : ., mut = 0 + if scan_for_yield(body) != 0: + is_flow_fn = 1 + saved_ret_ti := g_cur_fn_ret_ti + saved_ret_ok := g_cur_fn_ret_checked + g_cur_fn_ret_ti = ret_ti + g_cur_fn_ret_checked = 0 + if is_flow_fn == 0 && get_type_kind(ret_ti) != TYP_GENERIC_PARAM: + g_cur_fn_ret_checked = 1 + body_ti := infer_expr(body) + g_cur_fn_ret_ti = saved_ret_ti + g_cur_fn_ret_checked = saved_ret_ok compat := type_compat_strict(body_ti, ret_ti) // 落空分析(TF01 收口,见 stmt_cannot_fall_through 头注):体确定不能落空(如以 // 无 break 的 loop 收尾)⇒ 「块类型 = 末语句类型」推出的 unit 不是缺返回值的证据, @@ -2352,9 +2392,6 @@ fn check_func(fi: int): if compat != 1 && body_ti != TI_NEVER && stmt_cannot_fall_through(body) == 0: // Skip check if return type is generic param (can't verify at declaration) // Skip check for flow functions (yield instead of return) - is_flow_fn : ., mut = 0 - if body >= 0 && scan_for_yield(body) != 0: - is_flow_fn = 1 if !is_flow_fn && get_type_kind(ret_ti) != TYP_GENERIC_PARAM: diag_type_incompatible(compat, EC_TF_RETURN, "Function return type mismatch", ast_line(fn_node), ast_col(fn_node)) // 批 6(T3):规约标注面——**在 pop_scope 之前**(形参仍在作用域内,`#check(a > 0)` 才能定型) @@ -2914,7 +2951,7 @@ fn infer_expr(node: int) -> int: return sym_type(si) name := istr_get(name_idx) check_error(EC_N_UNDEFINED, "Undefined name '" + name + "'", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR if ast_kind(node) == EXPR_INTERP_HOLE: // 字符串插值洞(批 8 展开):**就地改写**本节点为「带类型转换的表达式」——父节点只存索引 // ⇒ 无需父指针(扁平 AST 的天然便利)。转换表(维护者签字):string 恒等 · int→`int_str` · @@ -3231,7 +3268,7 @@ fn infer_expr(node: int) -> int: if fi_generic_count(fi_m) == 0: if sym_type(si) == TI_UNIT: if fi_return_type(fi_m) == TY_NEVER: - return TI_NEVER + return TI_ERROR return sym_type(si) return TI_UNIT @@ -3307,7 +3344,7 @@ fn infer_expr(node: int) -> int: if fnd >= 0: if ast_kind(fnd) == EXPR_FN: infer_call_args(first_arg) // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) - return TI_NEVER + return TI_ERROR infer_call_args(first_arg) // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) // ── 批 8 PR-B · S1′(report-only;**新点 = 直调/方法调用解析尾**,2026-09-18)──── // 目的:测 (ii)「直调实参类型不校验」的**真实面**(旧 S1 接在 `infer_gen_call` 的泛型 @@ -3345,7 +3382,7 @@ fn infer_expr(node: int) -> int: name := istr_get(func_ni) check_error(EC_N_FUNC, "Undefined function '" + name + "'", ast_line(node), ast_col(node)) infer_call_args(first_arg) // TODO #2026-09-16-31:实参必须被推断(本 return 路径原先跳过) - return TI_NEVER + return TI_ERROR infer_call_args(first_arg) // 单一真源(与上述 4 处同一函数) return TI_INT // external/unknown functions @@ -3437,9 +3474,25 @@ fn infer_expr(node: int) -> int: // = 所返回值类型)⇒ 相容判定无对象 ⇒ 不报。 // **不对称是有意的**:then 支发散时 then_ti 本身即幻影(模型面,另案)⇒ 该形态继续报 // TC02(保留真信号)。谓词 = stmt_diverges(头注:只服务本判定点)。 - if compat != 1 && then_ti != TI_NEVER && else_ti != TI_NEVER: + // 错误哨兵豁免(裁定 (c)):原来这条豁免由 `TI_NEVER` 兼职承担,分家后 + // **错误**由 `TI_ERROR` 表示 ⇒ 必须补上,否则「then 支有错」会叠一条 TC02(级联)。 + if compat != 1 && then_ti != TI_NEVER && else_ti != TI_NEVER && then_ti != TI_ERROR && else_ti != TI_ERROR: if stmt_diverges(else_node) == 0: diag_type_incompatible(compat, EC_TC_IF_BRANCH, "If branches have different types", ast_line(node), ast_col(node)) + else if then_ti == TI_NEVER && ast_kind(else_node) == EXPR_BLOCK && ast_b(else_node) == 0: + // ── nail1 判别式(2026-10-11 裁定;设计已过目)────────────────────────── + // **then 支发散(`never`)+ else 支是「零项 region」** ⇒ 报 TC02(保留真信号)。 + // 为什么必须用**非类型**维度:本形与 `src/compiler/main.cr` 的 if#2 + // (`else if c2b == 58:` 那层)在 (a) 位置规则 + (b) `never` 裁定下**类型逐格相同** + // —— `(then_ti, else_ti)` 都是 `(never, unit)` —— 类型通道里没有任何可分之处。 + // 唯一可分者是 else 的**节点形态**:本形的 else 是 `EXPR_BLOCK` 且 items 数 `b == 0` + // (⑤「region 可为空」新引入的合法形);if#2 的 else 是 `EXPR_IF`,谓词**恒假** + // ⇒ **构造性地**不改变它的诊断集(硬门可直接验证)。 + // 语义依据:零项 region 是**能执行到终点、产出 unit** 的路径(只是没有语句), + // `return` 支是**执行不到终点**的路径 ⇒ 两者值语义不同 ⇒ 保留真信号。 + // **非对称是刻意的**:不加镜像(then 零项 + else 发散 ⇒ 报)——那正是 `k2` + // (`tc02_end2end_cmp` 一族,期望 rc=0)⇒ 必须静默;与既有守卫的既有非对称同向。 + diag_type_incompatible(compat, EC_TC_IF_BRANCH, "If branches have different types", ast_line(node), ast_col(node)) return then_ti return TI_UNIT @@ -3676,7 +3729,30 @@ fn infer_expr(node: int) -> int: // 值的类型)。值仍**必须推断** —— 否则 `return foo()` 里的未定义名/类型错等诊断会 // 整段消失(那是把一个响亮面换成静默面);推断结果只是不参与本节点类型。 if ast_a(node) >= 0: - infer_expr(ast_a(node)) + vt := infer_expr(ast_a(node)) + // nail3:逐 `return` 核对返回值 vs **当前函数**的声明返回型(新通道,见全局注释)。 + // 码 = TF01(`EC_TF_RETURN`,与体检查同码——措辞区分成因)。 + // 三个**假红风险面**的处置(裁定要求逐条打夹具): + // ① 泛型返回:`g_cur_fn_ret_checked == 0` 时不判(声明返回型是泛型形参); + // ② 错误传播:值侧是 `TI_ERROR` ⇒ `type_compat_strict` 源侧放行(不叠第二诊断); + // ③ `never` 值侧(如 `return boom()`):never 作源 ⇒ 放行(底类型)。 + // ④ **既存语料的 `bool`↔`int` 惯用法**(实测逼出来的第四格,非设计预列): + // `fn lit_implies(...) -> int: return tt_tag(lq) == TT_TOP` 一类 —— 比较表达式 + // 的类型是 `bool`,而声明返回型写 `int`。自源里这类**成片存在**(首轮实测 3 处, + // 全在 `type_engine.cr`)。改前它被 `return ⇒ never` 的体类型恒相容**掩盖**着, + // 体检查从未看见过这层差异 ⇒ 若本检查照判,自源当场 3 条假红。 + // 本检查的**目标面 = 类型族不匹配**(`string` vs `int` 一类,如 nail3 的正控), + // 不覆盖这个 0/1 惯用法 ⇒ 此处**显式豁免**(`bool` 与 `int` 互不为对方判错)。 + // ⚠ 豁免面**只限这一对**,不放宽任何其它组合(放宽它 = 把检查做成空壳)。 + bool_int_idiom : ., mut = 0 + if (vt == TI_BOOL && g_cur_fn_ret_ti == TI_INT) || (vt == TI_INT && g_cur_fn_ret_ti == TI_BOOL): + bool_int_idiom = 1 + if g_cur_fn_ret_checked != 0 && bool_int_idiom == 0: + c := type_compat_strict(vt, g_cur_fn_ret_ti) + if c != 1: + diag_type_incompatible(c, EC_TF_RETURN, + "Returned value type does not match the function's declared return type", + ast_line(node), ast_col(node)) return TI_NEVER if ast_kind(node) == EXPR_ENUM_CONSTRUCTOR: @@ -4155,11 +4231,11 @@ fn infer_expr(node: int) -> int: if str_eq(name, "sizeOf") != 0: if args < 0: check_error(EC_N_UNDEFINED, "@sizeOf requires a type argument", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR ti := res_type_node(args) if ti < 0: check_error(EC_N_UNDEFINED, "@sizeOf: unknown type", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR return TI_INT // @addr(fn) — function address, type int @@ -4171,18 +4247,18 @@ fn infer_expr(node: int) -> int: if str_eq(name, "alignOf") != 0: if args < 0: check_error(EC_N_UNDEFINED, "@alignOf requires a type argument", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR ti := res_type_node(args) if ti < 0: check_error(EC_N_UNDEFINED, "@alignOf: unknown type", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR return TI_INT // @fields(T) — 1 type argument, returns []string if str_eq(name, "fields") != 0: if args < 0: check_error(EC_N_UNDEFINED, "@fields requires a type argument", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR ti := res_type_node(args) return TI_STR @@ -4190,7 +4266,7 @@ fn infer_expr(node: int) -> int: if str_eq(name, "hasField") != 0: if args < 0 || ast_b(args) < 0: check_error(EC_N_UNDEFINED, "@hasField requires 2 args", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR ti := res_type_node(ast_a(args)) return TI_BOOL @@ -4198,7 +4274,7 @@ fn infer_expr(node: int) -> int: if str_eq(name, "field") != 0: if args < 0 || ast_b(args) < 0: check_error(EC_N_UNDEFINED, "@field requires 2 args", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR ti := res_type_node(ast_a(args)) return TI_INT @@ -4206,7 +4282,7 @@ fn infer_expr(node: int) -> int: if str_eq(name, "typeInfo") != 0: if args < 0: check_error(EC_N_UNDEFINED, "@typeInfo requires a type argument", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR ti := res_type_node(args) // 返回型 = **类型名串**(与 ir_gen 的发射面一致:该分支构造 `"int"`/`"bool"`/… 或命名行名字)。 // 契约出处 = `TODO.md` 的 `@` 内建清单「`@typeInfo(T)` — 类型名称字符串」。 @@ -4218,7 +4294,7 @@ fn infer_expr(node: int) -> int: if str_eq(name, "raw_int") != 0: if args < 0: check_error(EC_N_UNDEFINED, "@raw_int requires an expression", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR av := infer_expr(ast_a(args)) // 参数校验:**有「原值」语义的类型**才可取其原值—— // · dex(缩放位原值)· int(原值即其缩放值)· **地址型(地址字)**。 @@ -4247,14 +4323,14 @@ fn infer_expr(node: int) -> int: if av != TI_DEX && av != TI_INT && av != TI_NEVER: if !(av > TI_DEX_S && (get_type_kind(av) == TYP_PTR || get_type_kind(av) == TYP_REF)): check_error(EC_TF_ARG_TYPE, "@raw_int requires a dex (or int) or address (pointer/reference) expression", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR return TI_INT // @comptime(expr) — force compile-time eval if str_eq(name, "comptime") != 0: if args < 0: check_error(EC_N_UNDEFINED, "@comptime requires an expression", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR v := infer_expr(ast_a(args)) ast_set_type_val(node, v) return v @@ -4263,7 +4339,7 @@ fn infer_expr(node: int) -> int: if str_eq(name, "inline") != 0: if args < 0: check_error(EC_N_UNDEFINED, "@inline requires a function argument", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR v := infer_expr(ast_a(args)) ast_set_type_val(node, v) return v @@ -4304,19 +4380,19 @@ fn infer_expr(node: int) -> int: if str_eq(name, "ptr_of") != 0 || str_eq(name, "str_of") != 0: if g_unsafe_depth == 0: check_error(EC_N_UNDEFINED, "@" + name + " must appear inside an `unsafe` block", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR if args < 0: check_error(EC_N_UNDEFINED, "@" + name + " requires exactly 1 argument", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR av := infer_expr(ast_a(args)) if str_eq(name, "ptr_of") != 0: if av != TI_STR && av != TI_NEVER: check_error(EC_TF_ARG_TYPE, "@ptr_of requires a string expression", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR return TI_INT if av != TI_INT && av != TI_NEVER: check_error(EC_TF_ARG_TYPE, "@str_of requires an int expression", ast_line(node), ast_col(node)) - return TI_NEVER + return TI_ERROR return TI_STR check_error(EC_N_UNDEFINED, "unknown @ builtin: " + name, ast_line(node), ast_col(node)) diff --git a/src/compiler/main.cr b/src/compiler/main.cr index df02a46a..af2573a4 100644 --- a/src/compiler/main.cr +++ b/src/compiler/main.cr @@ -19,7 +19,10 @@ fn is_cr_file(path: string) -> int: fn read_source_file(path: string) -> string: g_source_dir = dirname(path) source := read_file(path) - + // 回流(2026-10-11):T4 施工期按**旧政策**(空 region 不可表达)把本处整条删掉, + // **连带删掉了一次内存读** ⇒ 列为「已知偏差」。现政策已改(region 可为空,⑤ 规格化) + // ⇒ 回流成 `if …:` + **空 region**(下一行同级 ⇒ 零项 region),把那处偏差消掉。 + if str_len(source) > 0: return source fn read_project_dir(dir: string) -> string: diff --git a/src/compiler/module.cr b/src/compiler/module.cr index 36ebc794..fa07f45c 100644 --- a/src/compiler/module.cr +++ b/src/compiler/module.cr @@ -168,7 +168,9 @@ fn parent_dir(dir: string) -> string: 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: diff --git a/src/compiler/parser.cr b/src/compiler/parser.cr index 4f1e4249..e953212f 100644 --- a/src/compiler/parser.cr +++ b/src/compiler/parser.cr @@ -86,17 +86,24 @@ fn end_decl(): // **行内 `:`(T_COLON_DECL)在此被响亮拒绝** —— 正是 T0 布局规格 §2.2 要的 // 「行尾类型标注不是合法文本」的兜住点;形参标注断行(`fn f(a:` + 续行 `int):`) // 在 lexer 层与头部终结不可区分,正是靠这里兜住。 -fn expect_region_head(): +// 返回 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 + return 0 skip_newlines() if tok_k(cur_tok()) == T_INDENT: advance_tok() - else: - add_error("expected an indented region after ':'") + return 1 + return 0 // region 收尾:消费 `T_DEDENT`;非 DEDENT(如 EOF)⇒ 响亮报错(不静默吞)。 fn close_region(): @@ -872,16 +879,25 @@ fn block_push(n: int): w64(g_pb_stmts, g_pb_count * 8, n) g_pb_count = g_pb_count + 1 +// region 头 + 体(**所有** region 的通用入口)。 fn parse_block() -> int: - // v4 region:吃 `T_COLON_BLOCK` + NEWLINE + `T_INDENT` … `T_DEDENT`(取代原 `{` … `}`)。 - // 尾表达式判定(T0 布局规格 §6.2 A1):**region 的最后一项 = 该 region 的值**, - // 其余各项按语句处理 —— 「还有下一项」的判据由「不是 `}`」变成「不是 DEDENT」。 - // 位置语义见 g_want_value 的头注:进入时读标志决定尾值去留,**体内嵌套 region 一律 - // 先复位为语句位**(parse_stmt / 各 region 产生式各自复位),退出时恢复为进入值。 - t := cur_tok() + 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 - expect_region_head() g_pb_stmts = alloc(256 * 8) g_pb_cap = 256 g_pb_count = 0 @@ -1150,10 +1166,84 @@ fn skip_nested_fn(): 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 @@ -1269,11 +1359,15 @@ fn parse_match_expr() -> int: g_want_value = 1 expr := parse_expr() g_want_value = 0 - expect_region_head() + // 空 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 @@ -1286,8 +1380,40 @@ fn parse_match_expr() -> int: advance_tok() else: add_error("expected '=>' in match arm") - g_want_value = 1 - body := parse_expr() + // 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)) @@ -1298,7 +1424,8 @@ fn parse_match_expr() -> int: // link previous arm to this one al = n ac = ac + 1 - close_region() + 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)) @@ -1728,7 +1855,7 @@ fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_v // T3:记录起点,`alloc_node(EXPR_FN, …)` 之后把本函数的标注行回填为 **fn_node 索引** //(唯一键——按函数名会串台:同名方法/多 impl)。 spec_start := g_spec_count - parse_spec_annotations(fn_ni) + parse_spec_annotations(fn_ni, 0) // inline 形(兼容):注解后紧跟 `:`,不要求行尾 body : ., mut = -1 // D9/D10(T0 布局规格 §2.2):有体 ⇒ 行尾 `:`(T_COLON_BLOCK)开 region; @@ -1744,7 +1871,18 @@ fn parse_body(fn_name: string, fn_ni: int, fn_line: int, fn_col: int, hotpatch_v body = parse_expr() else: g_want_value = 0 - body = parse_block() + // 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 @@ -1794,7 +1932,13 @@ 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): +// 两个位置共用本函数;`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 @@ -1825,7 +1969,20 @@ fn parse_spec_annotations(fn_ni: int): "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 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") @@ -1856,30 +2013,67 @@ fn parse_ffi_annotation() -> int: fn parse_declaration(): hotpatch_ver : ., mut = 0 - - // Handle @hotpatch(ver=N) annotation before function declarations - if check(T_AT): + 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() - 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 + 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): @@ -1890,8 +2084,8 @@ fn parse_declaration(): if check(T_EXTERN): t := cur_tok() advance_tok() - ffi_lang_ni : ., mut = -1 - // Check for @ffi("...") + 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 @@ -1944,18 +2138,28 @@ fn parse_declaration(): end_decl() return - // fn / flow fn + // 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 乱报)。 + // 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): - add_error("expected 'fn' after flow") - return - t := advance_tok() + if check(T_FN): + t = advance_tok() // 兼容形:定位令牌取 `fn` + else: + advance_tok() // 消费 'fn' nt := advance_tok() name := tok_lx(nt) ni := str_intern(name) @@ -1980,7 +2184,7 @@ fn parse_declaration(): sg_constrs = alloc(64 * 8) sg_constrs_cap = 64 sg_count := parse_generics_into(sg_names, sg_constrs) - expect_region_head() + has_items := expect_region_head() // 0 = 空 region(如 `struct S:` 后无可达更深的行) si := add_struct(name) if si >= 0: @@ -1999,6 +2203,8 @@ fn parse_declaration(): 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 @@ -2020,7 +2226,8 @@ fn parse_declaration(): advance_tok() w64(g_structs, si * ESZ_STRUCTINFO + OFF_SI_FIELD_COUNT, fc) si_commit_fields(si, fc) // 提交字段区(高水位 = base + fc) - close_region() + if has_items != 0: + close_region() return // enum @@ -2037,7 +2244,7 @@ fn parse_declaration(): eg_constrs = alloc(64 * 8) eg_constrs_cap = 64 eg_count := parse_generics_into(eg_names, eg_constrs) - expect_region_head() + has_items := expect_region_head() // 0 = 空 region ei := add_enum(name) if ei >= 0: @@ -2054,6 +2261,8 @@ fn parse_declaration(): 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 @@ -2086,7 +2295,8 @@ fn parse_declaration(): advance_tok() w64(g_enums, ei * ESZ_ENUMINFO + OFF_EI_VARIANT_COUNT, vc) ei_commit_variants(ei, vc) // 提交变体区(高水位 = base + vc) - close_region() + if has_items != 0: + close_region() return // interface declaration @@ -2104,7 +2314,7 @@ fn parse_declaration(): ig_dummy = alloc(64 * 8) ig_dummy_cap = 64 ig_count := parse_generics_into(ig_names, ig_dummy) - expect_region_head() + has_items := expect_region_head() // 0 = 空 region ⇒ **零方法接口**(合法且有意义) // Allocate interface entry grow_ifaces(g_iface_count + 1) @@ -2121,6 +2331,8 @@ fn parse_declaration(): 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 @@ -2238,7 +2450,8 @@ fn parse_declaration(): advance_tok() w64(g_ifaces, iface_base + OFF_IF_METHOD_COUNT, method_count) g_iface_count = g_iface_count + 1 - close_region() + if has_items != 0: + close_region() return // impl block (impl Type: ... or impl Interface for Type: ...) @@ -2256,8 +2469,10 @@ fn parse_declaration(): type_nt := advance_tok() type_name = tok_lx(type_nt) type_ni = str_intern(type_name) - expect_region_head() + 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 @@ -2277,7 +2492,8 @@ fn parse_declaration(): g_method_count = g_method_count + 1 else: advance_tok() - close_region() + 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) diff --git a/src/compiler/purity_selftest.cr b/src/compiler/purity_selftest.cr index 4a6915e9..adf7d6d9 100644 --- a/src/compiler/purity_selftest.cr +++ b/src/compiler/purity_selftest.cr @@ -203,33 +203,33 @@ fn purity_selftest_run() -> int: 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 ") 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 8c4c7b1a..04d364de 100644 --- a/tests/bootstrap/test_pipeline.py +++ b/tests/bootstrap/test_pipeline.py @@ -87,15 +87,16 @@ 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', ''' @@ -151,176 +152,169 @@ def test_raw(name, src, expected): # ── 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 ── @@ -333,52 +327,60 @@ def test_raw(name, src, expected): # ── 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/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/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/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/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_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..b5c8bca9 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 = [ @@ -61,15 +59,7 @@ def build_run(lit, extra_prelude="", extra_body=""): 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 +94,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: @@ -150,8 +140,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 +158,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 +181,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/delta_d0_annot.cr b/tests/spec/delta_d0_annot.cr index be518759..ca4f6f41 100644 --- a/tests/spec/delta_d0_annot.cr +++ b/tests/spec/delta_d0_annot.cr @@ -1,4 +1,10 @@ -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..47e2baca 100644 --- a/tests/spec/delta_d9_annot.cr +++ b/tests/spec/delta_d9_annot.cr @@ -1,2 +1,4 @@ -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..0d97f21f 100644 --- a/tests/spec/t2_pos_check.cr +++ b/tests/spec/t2_pos_check.cr @@ -1,6 +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_pos_dup.cr b/tests/spec/t2_pos_dup.cr index 8ef26fb7..bd22a335 100644 --- a/tests/spec/t2_pos_dup.cr +++ b/tests/spec/t2_pos_dup.cr @@ -1,2 +1,4 @@ -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..aa4a7baa 100644 --- a/tests/spec/t2_pos_multi.cr +++ b/tests/spec/t2_pos_multi.cr @@ -1,8 +1,4 @@ -fn f(a: int) -> int - #check(a >= 0) - #check(a <= 100) - #ensure(result >= 0) -{ - return a; -} -fn main() -> int { return f(7); } +fn f(a: int) -> int #check(a >= 0) #check(a <= 100) #ensure(result >= 0): + 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..ab1ba42e 100644 --- a/tests/spec/t3_pos_both.cr +++ b/tests/spec/t3_pos_both.cr @@ -1,7 +1,4 @@ -fn f(a: int) -> int - #check(a >= 0) - #ensure(result > a) -{ - return a + 1; -} -fn main() -> int { return f(1); } +fn f(a: int) -> int #check(a >= 0) #ensure(result > a): + 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..b3e2e717 100644 --- a/tests/spec/t3_pos_check_param.cr +++ b/tests/spec/t3_pos_check_param.cr @@ -1,6 +1,4 @@ -fn f(a: int) -> int - #check(a >= 0) -{ - return a; -} -fn main() -> int { return f(1); } +fn f(a: int) -> int #check(a >= 0): + 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..bbb5b859 100644 --- a/tests/spec/t4_xtalk.cr +++ b/tests/spec/t4_xtalk.cr @@ -1,9 +1,12 @@ -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..b3e2e717 100644 --- a/tests/spec/t4_yellow_only.cr +++ b/tests/spec/t4_yellow_only.cr @@ -1,6 +1,4 @@ -fn f(a: int) -> int - #check(a >= 0) -{ - return a; -} -fn main() -> int { return f(1); } +fn f(a: int) -> int #check(a >= 0): + 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..0b98f8db 100644 --- a/tests/suite/hotpatch_test.cr +++ b/tests/suite/hotpatch_test.cr @@ -5,65 +5,51 @@ import io import toml // Test: basic @hotpatch(ver=1) annotation compiles -@hotpatch(ver=1) -fn test_hotpatch_ver1() -> int { - return 42; -} +@hotpatch(ver=1) fn test_hotpatch_ver1() -> int: + return 42 // Test: @hotpatch(ver=2) with different version -@hotpatch(ver=2) -fn test_hotpatch_ver2() -> int { - return 99; -} +@hotpatch(ver=2) fn test_hotpatch_ver2() -> int: + return 99 // Test: @hotpatch shorthand (defaults to ver=1) -@hotpatch -fn test_hotpatch_shorthand() -> int { - return 7; -} +@hotpatch 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.sh b/tools/baseline/rebuild.sh index 64ba4c4c..17019207 100644 --- a/tools/baseline/rebuild.sh +++ b/tools/baseline/rebuild.sh @@ -68,7 +68,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/v4_migrate.py b/tools/v4_migrate.py index 4dac395a..7f8fdfc4 100644 --- a/tools/v4_migrate.py +++ b/tools/v4_migrate.py @@ -262,6 +262,98 @@ def _statement_start(toks, idx): 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)`。 @@ -401,6 +493,9 @@ def pre_transform(src, filename): '%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]): @@ -589,8 +684,28 @@ def _plain_gap(gap, force): split_pending = True elif t == T.LBRACE: if brace_kind[idx] == 'block': - cur = cur.rstrip() + ':' - flush() + # ── 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: @@ -645,7 +760,59 @@ def _plain_gap(gap, force): # ── 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: @@ -773,6 +940,23 @@ def file_metrics(text): } +def _has_v3_markers(src): + """输入里是否还有 v3 专属形状(**块** `{}` / **语句** `;`)。 + + T6a 追加(协调者第 2 条裁定):本工具是**一次性 v3→v4** 工具。对**已经是 v4 的文本** + 再跑一次,vendored v3 词法器会把它当 v3 读,发射器产出错形——实测重跑 + `tests/spec/t2_pos_check.cr`(已是 v4)得到 `fn f() -> 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 = [] @@ -791,7 +975,7 @@ def cmd_transform(args): if not files: print('no files', file=sys.stderr) return 2 - n_ok = n_abort = n_fail = 0 + n_ok = n_abort = n_fail = n_forced = n_refuse = 0 for p in files: src = open(p, encoding='utf-8').read() try: @@ -805,12 +989,19 @@ def cmd_transform(args): n_abort += 1 continue ok, err = v4_parse_ok(out, p) - if not ok: + 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) @@ -823,7 +1014,8 @@ def cmd_transform(args): extra += ' | %s=%s' % (k, ','.join(rep[k])) print('OK %-45s%s' % (p, extra)) n_ok += 1 - print('=== transform: ok=%d skip=%d fail=%d ===' % (n_ok, n_abort, n_fail)) + 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 @@ -895,6 +1087,12 @@ def main(): 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 占位(调试用)') @@ -903,11 +1101,14 @@ def main(): 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) 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())

From ce56e4211d582551dfb23913c4cc58505070065c Mon Sep 17 00:00:00 2001
From: DslsDZC 
Date: Sun, 11 Oct 2026 22:34:02 +0800
Subject: [PATCH 11/15] =?UTF-8?q?v4=20=E8=BF=81=E7=A7=BB=EF=BC=88=E6=89=B9?=
 =?UTF-8?q?=E5=86=85=C2=B7=E7=AC=AC=E5=85=AD=E7=AC=94=EF=BC=89=EF=BC=9AT7?=
 =?UTF-8?q?=20=E6=94=B6=E5=B0=BE=E9=87=8D=E9=94=81=20+=20=E8=BF=87?=
 =?UTF-8?q?=E6=B8=A1=E5=BD=A2=E7=BF=BB=E8=BD=AC=EF=BC=88E2=C3=979=20/=20E3?=
 =?UTF-8?q?=C3=971=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

重锁四类对象(逐条实测,见 tools/baseline/ 头注留痕):
1/2 canary 5 值 + .ccr 四条 —— **实测零变化 ⇒ 不重锁**(D1 确定性 5/5 绿 + F3 5/5 同)。
    归因:本批是前端形状迁移,不动发射器/后端;STR 段由被编译程序驱动而非编译器源排版。
    反向对照:把 pa_ccr 植回 2026-09-20 旧值 ⇒ canary_check.sh --verify-only 必红(2 项 FAIL)。
3/4 二进制 sha 白名单 3 条 + PINNED_REV —— 97f4394f(v3 末代) → 25e70197(v4 迁移 T6 收官)。
    依据 = v4 可读性硬约束(旧 rev 只认 v3 形,rebuild.sh:71 冒烟已改 v4 形 ⇒ 旧 rev 下必红)。
    自证:rebuild.sh 重建三 sha 与白名单逐条同 + 冒烟 42 + 与工作树自建二进制逐字节同。
    旧 rev/旧三 sha 留痕(rebuild.sh 注 + REBUILD.md 历史表)。

过渡形翻转(与本次重锁同批):
E2 —— 9 档 tests/spec/*.cr 正例的 inline `#check` 改文档 §10.1 的 region 头形;
E3 —— tests/suite/hotpatch_test.cr 的 `@hotpatch` 改文档 §13.6 的前导 `@` 形。
    翻转前后逐档 rc + 码集**逐格相同**;tests/selfhost/test_spec_grammar.py 48/48 绿。

收尾复跑(实跑读数):v4 探针 146 ALL PASS · check src/compiler rc=0 零诊断 ·
corec2 == corec3 IDENTICAL · canary 5/5 + carrier 7/7 · probes 29 档 20×0/9×1
(已知 3 档 rc 1→0:n05/n10/n21,checker 侧悬空账,非本面)· parity 76 档 43×0/33×1 两腿零差异。

判据面清理:parity_run.sh CORPUS_TOTAL=76 与实算一致(36+2+15+19+4);
REBUILD.md:77/82/130 的「75 档」加当时值标注 + 补 T7 自建基线分布;tests/spec/README.md 74→75 改 76。

已知遗留(预存,非本笔引入,T6 修订处同样红):tests/harness/{test_lsp_builtin_table,
test_criteria_mutations}.py 的锚点正则未随 v4 形状更新 ⇒ 各自 L1-L4 / M7-M10 红。
---
 tests/spec/README.md             |  2 +-
 tests/spec/delta_d0_annot.cr     |  3 ++-
 tests/spec/delta_d9_annot.cr     |  3 ++-
 tests/spec/t2_pos_check.cr       |  3 ++-
 tests/spec/t2_pos_dup.cr         |  4 +++-
 tests/spec/t2_pos_multi.cr       |  5 ++++-
 tests/spec/t3_pos_both.cr        |  4 +++-
 tests/spec/t3_pos_check_param.cr |  3 ++-
 tests/spec/t4_xtalk.cr           |  6 +++--
 tests/spec/t4_yellow_only.cr     |  3 ++-
 tests/suite/hotpatch_test.cr     |  9 +++++---
 tools/baseline/REBUILD.md        | 38 ++++++++++++++++++++++----------
 tools/baseline/canary_values.tsv | 35 +++++++++++++++++++++++++++++
 tools/baseline/rebuild.sh        | 20 +++++++++++++----
 14 files changed, 108 insertions(+), 30 deletions(-)

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 ca4f6f41..8133029f 100644
--- a/tests/spec/delta_d0_annot.cr
+++ b/tests/spec/delta_d0_annot.cr
@@ -2,7 +2,8 @@ fn check(x: bool) -> bool:
     return x
 fn g() -> bool:
     return true
-fn f(a: int) -> int #check(true):
+fn f(a: int) -> int:
+    #check(true)
     return a
 fn main() -> int:
     if check(g()):
diff --git a/tests/spec/delta_d9_annot.cr b/tests/spec/delta_d9_annot.cr
index 47e2baca..ce3204e1 100644
--- a/tests/spec/delta_d9_annot.cr
+++ b/tests/spec/delta_d9_annot.cr
@@ -1,4 +1,5 @@
-fn f(a: int) -> int #check(1 > 0):
+fn f(a: int) -> int:
+    #check(1 > 0)
     return a
 fn main() -> int:
     return f(1)
diff --git a/tests/spec/t2_pos_check.cr b/tests/spec/t2_pos_check.cr
index 0d97f21f..0fb5a49b 100644
--- a/tests/spec/t2_pos_check.cr
+++ b/tests/spec/t2_pos_check.cr
@@ -1,4 +1,5 @@
-fn f() -> int #check(1 >= 0):
+fn f() -> int:
+    #check(1 >= 0)
     return 1
 fn main() -> int:
     return f()
diff --git a/tests/spec/t2_pos_dup.cr b/tests/spec/t2_pos_dup.cr
index bd22a335..456883e0 100644
--- a/tests/spec/t2_pos_dup.cr
+++ b/tests/spec/t2_pos_dup.cr
@@ -1,4 +1,6 @@
-fn f() -> int #check(1 > 0) #check(1 > 0):
+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 aa4a7baa..b8b16cf7 100644
--- a/tests/spec/t2_pos_multi.cr
+++ b/tests/spec/t2_pos_multi.cr
@@ -1,4 +1,7 @@
-fn f(a: int) -> int #check(a >= 0) #check(a <= 100) #ensure(result >= 0):
+fn f(a: int) -> int:
+    #check(a >= 0)
+    #check(a <= 100)
+    #ensure(result >= 0)
     return a
 fn main() -> int:
     return f(7)
diff --git a/tests/spec/t3_pos_both.cr b/tests/spec/t3_pos_both.cr
index ab1ba42e..664a361e 100644
--- a/tests/spec/t3_pos_both.cr
+++ b/tests/spec/t3_pos_both.cr
@@ -1,4 +1,6 @@
-fn f(a: int) -> int #check(a >= 0) #ensure(result > a):
+fn f(a: int) -> int:
+    #check(a >= 0)
+    #ensure(result > a)
     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 b3e2e717..e472c833 100644
--- a/tests/spec/t3_pos_check_param.cr
+++ b/tests/spec/t3_pos_check_param.cr
@@ -1,4 +1,5 @@
-fn f(a: int) -> int #check(a >= 0):
+fn f(a: int) -> int:
+    #check(a >= 0)
     return a
 fn main() -> int:
     return f(1)
diff --git a/tests/spec/t4_xtalk.cr b/tests/spec/t4_xtalk.cr
index bbb5b859..b43cb3f8 100644
--- a/tests/spec/t4_xtalk.cr
+++ b/tests/spec/t4_xtalk.cr
@@ -3,10 +3,12 @@ struct A:
 struct B:
     v: int
 impl A:
-    fn get(self, alpha: int) -> int #check(alpha >= 0):
+    fn get(self, alpha: int) -> int:
+        #check(alpha >= 0)
         return self.v + alpha
 impl B:
-    fn get(self, beta: int) -> int #check(beta >= 0):
+    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 b3e2e717..e472c833 100644
--- a/tests/spec/t4_yellow_only.cr
+++ b/tests/spec/t4_yellow_only.cr
@@ -1,4 +1,5 @@
-fn f(a: int) -> int #check(a >= 0):
+fn f(a: int) -> int:
+    #check(a >= 0)
     return a
 fn main() -> int:
     return f(1)
diff --git a/tests/suite/hotpatch_test.cr b/tests/suite/hotpatch_test.cr
index 0b98f8db..72d7578b 100644
--- a/tests/suite/hotpatch_test.cr
+++ b/tests/suite/hotpatch_test.cr
@@ -5,15 +5,18 @@ import io
 import toml
 
 // Test: basic @hotpatch(ver=1) annotation compiles
-@hotpatch(ver=1) fn test_hotpatch_ver1() -> int:
+@hotpatch(ver=1)
+fn test_hotpatch_ver1() -> int:
     return 42
 
 // Test: @hotpatch(ver=2) with different version
-@hotpatch(ver=2) fn test_hotpatch_ver2() -> int:
+@hotpatch(ver=2)
+fn test_hotpatch_ver2() -> int:
     return 99
 
 // Test: @hotpatch shorthand (defaults to ver=1)
-@hotpatch fn test_hotpatch_shorthand() -> int:
+@hotpatch
+fn test_hotpatch_shorthand() -> int:
     return 7
 
 // Test: hotpatch config loading via toml
diff --git a/tools/baseline/REBUILD.md b/tools/baseline/REBUILD.md
index bf3ce410..30333272 100644
--- a/tools/baseline/REBUILD.md
+++ b/tools/baseline/REBUILD.md
@@ -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 17019207..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

From 0c327f38ce3342c166330b9decaa68798a5c0e96 Mon Sep 17 00:00:00 2001
From: DslsDZC 
Date: Mon, 12 Oct 2026 01:11:09 +0800
Subject: [PATCH 12/15] =?UTF-8?q?fix(v4=20=E8=BF=81=E7=A7=BB=E6=94=B6?=
 =?UTF-8?q?=E5=B0=BE):=20=E4=B8=89=E6=A1=A3=E5=88=A4=E6=8D=AE=E9=9D=A2?=
 =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E2=80=94=E2=80=94harness=20=E9=94=9A?=
 =?UTF-8?q?=E7=82=B9=E5=8E=BB=20v3=20=E5=BD=A2=20+=20T6=20=E6=8A=98?=
 =?UTF-8?q?=E5=8F=A0=E6=A8=A1=E6=9D=BF=E7=9A=84=E5=8D=95=E7=82=B9=E6=9C=BA?=
 =?UTF-8?q?=E6=A2=B0=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

## 1. `tests/selfhost/test_string_interp.py`(**我们这批引入的真缺陷**,会让 CI 整 job 断)
- **根因**:`build_run()` 的 Core 载荷模板在 T6 内联迁移时被**机械折叠成单行**,**`%s` 前多了 4 空格**
  ⇒ `extra_body=""` 时生成 **8 空格缩进的 `return 0`**(比上一行更深)⇒ v4 parser 报
  `error[P02]: unexpected dedent at top level`;另 `:130` 的 `extra_body` 仍是 v3 形带 `;`。**两处缺陷**。
- **归属**:`jj diff -r` 逐提交实核 ⇒ 仅落在第五笔 `25e70197`;干净 rev `920b1cbb` 模板**良构 v3**。
- **⚠ 严重性**:该档是 **`src/ci/run.sh:334` 的 `selfhost-tests` 挂点**,且 `run.sh:15` = **`set -euo pipefail`**
  ⇒ 该档 RC≠0 会**直接中止整个 `selfhost-tests` job**(不是单档红)。
- **修**:模板 `%s` 前**去掉那 4 空格**(恢复 v3 契约「`extra_body` 自带缩进」)+ `:130` 去 `;`。**期望值一字未动**。
- **读数**:`python3 tests/selfhost/test_string_interp.py` ⇒ **RC=0 · 失败项 [] · B 组 14/14 PASS**。
- **同款扫描**:全仓 `tests/*/*.py` 搜「`\n    %s` 折叠模板」= **仅此一处** ⇒ 单点机械错误,非普遍现象。

## 2. `tests/harness/test_lsp_builtin_table.py` + 3. `test_criteria_mutations.py`(锚点抽取去 v3 形)
两档因 v4 形状而**抽取为空**(预存红,非新引入):
- `annotation_names()` 原以「首个顶格 `}` 行」为体边界 ⇒ **v4 函数无闭括号** ⇒ 抽到 `None` ⇒ L3 红;
- `lsp_at_names()` 原以 `return out;` 为界 ⇒ v4 无 `;` ⇒ **抽到空集**;
- M7–M10 的 11 个锚 + `mut_self_item2` 真跑腿锚 = v3 形(`{`/`;`)⇒ `str.count` 全 0。
**修法:只改「抽取」层,断言一字未动**;边界判据统一改走新增的 `top_level_body()`
(「`fn` 行之后首个**顶格行**」= v3 的 `}` 与 v4 的下一顶层构造同为**排他**边界,取出同一段体)。
**M7 真跑腿探针载荷**同步改 v4 形 + `None`→`none`(**先实测再改**:在未突变树先编译,确认 rc=0 且回 30 才落笔)。

## 判据(实跑)
- `tests/harness/*.py` **7 档全 RC=0**(`criteria_mutations` 27/27 含真跑腿开 · `lsp_builtin_table` 4/4)。
- **含牙证明**:L4-①~④ 逐条实跑;M1–M6 的 20 个突变体;**M7–M10 的「咬合证明」**(内存内撤掉该判据所描述的守卫 ⇒ 锚归 0)
  ⇒ 证明**锚与突变同处**(判据咬的正是它自称咬的那处)。
- `nice -n 19 ./build/corec check src/compiler` ⇒ **RC=0 / `error[`=0**(证明未动 `src/**`)。

## 同族登记(**不改**,附后人防误读标注)
- `tests/harness/test_lsp_builtin_table.py:195` · `tests/harness/test_ir_ref_sites.py:90` —— 追加载荷为 v3 形,
  **形状陈旧但当前仍工作**(锚正则不涉 `;`/`}`)⇒ 登记不动,免得后人见 v3 形以为漏迁。
---
 tests/harness/test_criteria_mutations.py | 54 +++++++++++++++---------
 tests/harness/test_lsp_builtin_table.py  | 26 +++++++++---
 tests/selfhost/test_string_interp.py     |  8 +++-
 3 files changed, 60 insertions(+), 28 deletions(-)

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/selfhost/test_string_interp.py b/tests/selfhost/test_string_interp.py
index b5c8bca9..c52be453 100644
--- a/tests/selfhost/test_string_interp.py
+++ b/tests/selfhost/test_string_interp.py
@@ -58,8 +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') % (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
@@ -124,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' 长度)")

From c448dc36b30151e87a0836b49f76dc3942202767 Mon Sep 17 00:00:00 2001
From: DslsDZC 
Date: Mon, 12 Oct 2026 03:51:55 +0800
Subject: [PATCH 13/15] =?UTF-8?q?docs(TODO):=20=E7=99=BB=E8=AE=B0=20#2026-?=
 =?UTF-8?q?10-12-1..7=E2=80=94=E2=80=94v4=20=E8=BF=81=E7=A7=BB=E6=94=B6?=
 =?UTF-8?q?=E5=B0=BE=E7=9A=84=E4=B8=83=E7=AC=94=E6=82=AC=E7=A9=BA=E8=B4=A6?=
 =?UTF-8?q?=EF=BC=88=E7=BC=BA=E9=99=B7=202=20=C2=B7=20=E7=BA=A6=E5=AE=9A?=
 =?UTF-8?q?=E5=BE=85=E8=A3=81=201=20=C2=B7=20=E9=9D=99=E9=BB=98=E9=9D=A2?=
 =?UTF-8?q?=201=20=C2=B7=20=E8=AE=BE=E8=AE=A1=E7=BC=BA=E5=8F=A3=201=20?=
 =?UTF-8?q?=C2=B7=20=E5=8F=91=E5=B8=83=E6=AD=A5=E9=AA=A4=201=20=C2=B7=20?=
 =?UTF-8?q?=E7=99=BB=E8=AE=B0=E4=B8=8D=E5=8A=A8=201=20=C2=B7=20=E8=AF=AD?=
 =?UTF-8?q?=E6=96=99=E5=8F=A6=E6=A1=88=201=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

逐条(按标题行号 = 序号):
- **#2026-10-12-1**【缺陷·checker】`nail4` 同一节点**第二推断来源**(`undef_x = 0` 的 LHS ti 非错误哨兵);★ 代价 = **3 档 `tests/probes/` 负例探针静默接受**(`n05_recursive`/`n10_named_vs_int`/`n21_t_assign_int`)+ **`probes_run.sh` 不在任何 CI job 里** ⇒ 无自动门。已排除 4 项、剩 3 条候选未验 ⇒ **维护者裁定挂起**。
- **#2026-10-12-2**【既有约定·待裁】`-> int` 却 `return` `bool`:**11 处 / 3 档**(闭包内 3 `type_engine.cr::lit_implies` + 闭包外 8 `src/kernel/**`);「`bool ⊆ int` 可隐式」是否为**语言面规则**。**新判定面(nail3)的第一批战果**。
- **#2026-10-12-3**【诊断面·系统性静默】不带码 `add_error` 只要同批有带码诊断就**永远不打印**(`main.cr:133-137` 次序);正控已证机制。
- **#2026-10-12-4**【设计缺口】`corec run` 包裹壳按**行尾 `;`** 切分(`main.cr:356-391`);`has_main != 0` 时不执行 ⇒ 不影响 `rebuild.sh` 冒烟。
- **#2026-10-12-5**【**发布步骤·非缺陷**】`PINNED_REV` 与 squash 合入耦合:`25e70197` 不进 develop 历史 ⇒ **合入那一步须同批重指 + 重锁三 sha**。
- **#2026-10-12-6**【判据面·登记不动】两处 v3 形载荷(`test_lsp_builtin_table.py:195` · `test_ir_ref_sites.py:90`)——形状陈旧但**当前仍工作**,防后人误读为漏迁。
- **#2026-10-12-7**【语料面·另案】inline 过渡形**余 15 档**未翻文档形(负例本体 + `t3_pos_ensure_*`);两形都收 ⇒ 不阻塞。

判据:`python3 tests/harness/test_todo_id_migration.py` → **6/6 PASS**(J1 残留 0 · J2 悬空 0 · J3 映射完备 · J6 同日段唯一)。
---
 TODO.md | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/TODO.md b/TODO.md
index 930399f8..7dc2e5f0 100644
--- a/TODO.md
+++ b/TODO.md
@@ -187,6 +187,13 @@
 | — | `#2026-09-22-2` | 2026-09-22 | 批 8 裁定二 S4 · `b8-e1` 实测 | ⚠【**预存缺陷 · 静默错值 · 本批修复**】`&S` / `&mut S` **形参形态**的 `r.v` 误编译:**根因 = REF 身份在 IR 形参定型处丢失**——`ir_gen.cr:3296` 取 `ast_type_val(pn)`,而 `&S` 节点(`EXPR_REFTYPE`)**`type_val = 0`** ⇒ 槽型退化成 `TI_INT`(`if param_type < 0` 护栏**拦不住 0**)⇒ `EXPR_FIELD` 看不到 REF ⇒ 静默错值(实测 `fn f(r: &S){r.v}` 得 **8** 而非 42;`--dump-params` 实证 `PARAM f p0 r slot=0 decl=0`,对照 `string` 参数 `slot=3` ✓)。**两代皆错**(pre/post 均 run=8)⇒ **存在早于裁定二、裁定二未触及形参面**。**修法有先例**:`ir_gen.cr:3305`(批 5 `dex?` 同形特判——某形态 `unpack_type` 返 0 ⇒ 槽型退化 ⇒ **按声明面节点另定槽型**),注释原文照引。**ABI 零影响(实测)**:`callseq.cr`/`frame.cr` 全部 **9 处**分类点皆为 `== TI_DEX ⇒ xmm 类,其余 ⇒ GP 类` 恒等式,而 **`TI_DEX = 1`**、**REF 行下标 ≥ 9** ⇒ **REF 天然落 GP** ⇒ 改槽型**不改 ABI 类**。**实现取「只查不建」**:checker 解析签名时已建过该 REF 行(实测类型表中存在 `kind 3`)⇒ 线性查找即可 ⇒ **零新增类型行**(⚠ `alloc_type` 是**裸分配器、不去重**,另分配会写进 TYPE 段)。**禁止事项**:在**无 ABI 判据**时凭「补一支特判」直接改槽型(会造出 `dex?` 那次的同形失配)。**与 `#2026-09-22-1` 互指,根因不同不合并**。 |
 | — | `#2026-09-24-1` | 2026-09-24 | v4 迁移差距分析 + 协调者实测 | 【**声明但不校验 / 有码但不 raise**】前端静默面清单(**5 处,均实测**):① **`EC_TF_MISSING_RET`(TF02, `ast.cr:404`) 零 raise 点**(全仓 1 命中)⇒ 缺 return 由 TF01「Function return type mismatch」拦住,**消息不指真实原因**(实测四档:空体 / 以 unit 调用收尾 / `if` 无 `else` / `loop` 里 `break` 出走 ⇒ **全 `check` rc=1 报 TF01,`build` rc=1 + 零产物**)——**非健全性漏洞,是诊断不精确**;② **`pub` 零读点**(`parser.cr:840` 声明 + `:875` 赋值,无读取点)⇒ 写了不生效且**不报错**;③ **match 臂的 `=>` 不校验**(`parser.cr:1115` 裸 `advance_tok()`)⇒ 分隔符写什么都收;④ **struct 字面量字段分隔符盲跳**(`parser.cr:552-554`,第二个 `advance_tok()` 返回值丢弃)⇒ `=` 与 `:` 两形都收(**已由 v4 迁移 T0 规格覆盖(T5 修),本条目不另立修法**);⑤ **类型位的 `.`/`auto` 全拒且消息错**(六档实测:形参 / 字段 / 枚举载荷 / 切片元素 / 返回位皆 rc=1,报 `expected type after '->'`,而那句是**返回型的模板**,形参位也报)。**本条目只登记,未修**(④ 除外,见上)。 |
 | — | `#2026-10-11-1` | 2026-10-11 | v4 迁移施工期 + 维护者口述 | 【**设计·未决**】v4 规约的战术「策略定义」语法(现形 `#tag`)待重设计——维护者裁定 `#` 族**只有使用面**(`#simp`/`#induct(x)` 都读作「在这里用一个战术」),而 `#tag` 是**唯一一个「用 `#` 声明新东西」的构造** ⇒ 范畴错误,**该删而非改名**;连带「策略体是竖排序列、而语义是**集合**」的形状说谎、以及可复用名被关在标签族里(不能 `import`/文档化/单测)。两个候选方向(维护者未拍):**不留** = §10.8 整节删、复用只走库(`import std::proof::arithmetic` 后 `#arithmetic`,名字解析走 import 作用域)+ `spec fn`;**留** = 必须长成一个**非 `#`** 的声明形。**本条目只登记,未改 `docs/core-language-syntax_v4.md` §10.8**。 |
+| — | `#2026-10-12-7` | 2026-10-12 | v4 迁移 T7 施工期 | 【语料面 · 另案】`#check`/`#ensure` 的 **inline 过渡形余 15 档**未翻文档形(负例本体 + `t3_pos_ensure_*`)——**两形都收 ⇒ 不阻塞**;翻转会改负例语义,须与 `test_spec_grammar` 期望同批 |
+| — | `#2026-10-12-6` | 2026-10-12 | v4 迁移收尾 | 【判据面 · 登记不动】两处**v3 形载荷**:`tests/harness/test_lsp_builtin_table.py:195`(L4-④ 追加的假函数 `{ … ; }`)· `tests/harness/test_ir_ref_sites.py:90`(`emit(IR_REF, …);` 带 `;`)—— **形状陈旧但当前仍工作**(锚正则不涉 `;`/`}`),登记防后人误读为漏迁 |
+| — | `#2026-10-12-5` | 2026-10-12 | v4 迁移 T7 施工期 | 【**发布步骤 · 非缺陷**】`PINNED_REV` 与 **squash 合入**的耦合:T7 已把 `PINNED_REV` 从 `97f4394f` 换到 `25e70197`,但本仓 develop 走 **squash 合入** ⇒ `25e70197` **不进 develop 历史**,他人/换机重跑 `rebuild.sh` 必失败 ⇒ **合入那一步须同批重指 `PINNED_REV` + 重锁三 sha**(条件已写进 `rebuild.sh:22-25` / `REBUILD.md:44-46`) |
+| — | `#2026-10-12-4` | 2026-10-12 | v4 迁移 T6b 施工期 | 【设计缺口】`corec run <内联源>` 的**包裹壳**(`src/compiler/main.cr:356-391`,7 段内嵌源)按**行尾 `;`** 切 body/末表达式再包 `return` —— 壳的启发式本身是 **v3 形**;只改字面量会得「半 v4 壳」。**要真修得重设计 `run` 的内联包裹(换成 v4 的 layout 切分)**。注:`has_main != 0` 时该壳**不执行** ⇒ **不影响 `rebuild.sh` 冒烟** |
+| — | `#2026-10-12-3` | 2026-10-12 | v4 迁移 T5 施工期实名 | 【诊断面 · 系统性静默】**不带码的 `add_error` 只要同一次解析里还有任何带码诊断,就永远不打印**——`src/compiler/main.cr:133-137` 的**次序**:`if g_diag_count > 0: print_diagnostics(); return 1` **先命中** ⇒ 下一句 `if g_error_count > 0: print_parse_errors()` **永不到达**。**正控已证机制**(`struct S:` + `f int,` 唯一诊断不带码 ⇒ 输出**确实打印**)。与 `#2026-10-12-1`/`t2_neg_inbody` **同族:诊断报了、用户看不见** |
+| — | `#2026-10-12-2` | 2026-10-12 | v4 迁移 T5 nail3 施工期 | 【**既有约定 · 待裁**】`-> int` 却 `return` 一个 **`bool`** 表达式的站点:**检查闭包内 3 处**(`src/compiler/type_engine.cr::lit_implies` 421/426/428)+ **闭包外 8 处**(`src/kernel/{kernel_main,subtype}.cr` 的 `nf_sub_eq`/`nf_eq`/`kern_sub_nf`;⚠ `build_kernel.py` **只编译不 lint** ⇒ CI 本来就拦不住)= **11 处 / 3 档**。语义 = 本编译器「**`bool ⊆ int` 可隐式**」的既有约定 ⇒ **维护者待裁**:**认可** ⇒ 豁免转**长期项**且**应写进语言面**(`bool` 与 `int` 的关系),**而不是留在 checker 的一个 `if` 里**;**不认可** ⇒ 这 11 处**源该改**。当前代码**保持豁免,只限这一对**(注释已写明「放宽其它组合 = 把检查做成空壳」) |
+| — | `#2026-10-12-1` | 2026-10-12 | v4 迁移 T5/T6a 施工期实测 | 【**缺陷 · checker 面**】`nail4`:**同一节点存在第二推断来源**——`undef_x = 0` 的 LHS 的 `ti` **不是**错误哨兵(判别探针 `d1`/`d2` 实测 `tt = TI_INT`),而 `EXPR_IDENT` 的 `UNDEFINED → TI_ERROR` **未参与**赋值位那条链(同节点两处推断、各说各话)。已排除 4 项(负渲染 / `TI_DYN` 分支 / `compat` 规则缺失 / 源目颠倒),剩 **3 条候选未验**:`collect_decls` 预登记 → `ast_set_type_val` 回填 → `res_type_node` 族。★ **代价已量出**:**3 档 `tests/probes/` 负例探针被静默接受**(`n05_recursive` rc=1`{TS03}`→rc=0 · `n10_named_vs_int`/`n21_t_assign_int` rc=1`{TA01}`→rc=0;同文本跨三次二进制读数差证「必在二进制侧」),且 **`probes_run.sh` 不在任何 CI job 里**(全仓只在 `src/ci/run.sh:129` 的注释中被提及)⇒ **无自动门看着** |
 | — | `#2026-10-11-5` | 2026-10-11 | v4 迁移 T5 施工期实测 | 【**既有缺陷 · 运行期 SIGSEGV**(代 0 同病)】`enum E: V(int?)`(带可选载荷的枚举变体)**能编过但运行 rc=139**;代 0 编译器(`/tmp/v3ws`,revision `920b1cbb`)对 v3 形 `enum E { V(int?) }` **同样 139** ⇒ **非 v4 迁移引入**。★ **但会卡 T6**:`tests/suite/opt_dex_test.cr:20` 逐字 `enum EOpt { V(dex?) }`。(T5 侧另有 `struct SOpt { f: dex? }` / `g : dex?, mut = None` 等真实用法 ⇒ 该档是可选面的集中语料。) |
 | — | `#2026-10-11-4` | 2026-10-11 | v4 迁移 T5 施工期实测 | 【**能力面缺口**】bootstrap(Python 前端)**完全没有 `T?` 的语义面**:`grep -rn 'OptionalType' bootstrap/` ⇒ 只有 `parser.py:527`(构造)与 `syntax/ast.py:13`(类定义),**`type_checker.py` 零命中**。⇒ `T?` 现在**语法面已通**(T5 施工期把四族并入同一条尾部、`?` 唯一处理点,接受矩阵 10/10 与自源逐格一致),但**语义面全缺**:无 `T ⊆ T?` 注入、无 `none : T?` 的类型、无可选值 match 面 ⇒ 四格(标注位/形参位/字段位/枚举载荷位)**解析全过、check 全不过**。修法 = 把自源 R2 P3 Task 4 的可选表示机制(`TYP_NULL`/`TYP_OPTIONAL`/`g_optrep_on`/`IR_MAKE_ENUM`/match 两分支面)搬到 Python —— **一笔独立的批**。**当前不阻塞**:`tests/bootstrap/**` 的 `T?` 用量 = 0,`src/**` 代码面 = 0。 |
 | — | `#2026-10-11-3` | 2026-10-11 | v4 迁移 T5 施工期实测 | 【**未覆盖面 · 类型引擎**】`never ⊆ X` 在 `ty_sub` 里返回 **-1** ⇒ `error[ICE04] type judgment indeterminate: never vs named#21 (uncovered face)`(引擎 -1 ⇒ 硬错)。⇒ **组合层与引擎层对「`never` 作子类型」的认定不一致**:组合层(`type_compat_strict` / `_compat`)按 2026-10-11 裁定**收**(任一侧 never ⇒ 相容);引擎层(`type_terms.cr`/`type_engine.cr` 的 `ty_sub`)**判不出**。当前 `src/**` 零命中(`check src/compiler` / `corec2==corec3` / T1-T2 探针 146 条三绿即证),但属**潜在缺口**——任何绕过组合函数直接问引擎的路径(如 `ti_subsumes` 的 OPTIONAL 注入面、`type_equal_engine` 的采样面)对 `never` 仍可能得 -1。**本批只在组合层兑现语义,未碰 `ty_sub`**(那一层属 R2 类型项引擎本体,有自己的语义与判据网,须单开一笔)。 |
@@ -2199,6 +2206,90 @@ fn f(x: int) -> int:
 
 **这条卡住的面**:`docs/core-language-syntax_v4.md` §10.8 的措辞、`docs/maintainer/design/spec-design.md:203` 的旧形(`#tag sorted = { … }`,与 §10.8 已经不一致,属同一面的两个形)。
 
+### 2026-10-12-1. 【缺陷 · checker 面】`nail4`:同一节点存在**第二推断来源**(`undef_x = 0` 的 LHS ti 非错误哨兵);★ 代价 = 3 档负例探针静默接受且无 CI 门(v4 迁移 T5/T6a 施工期实测;**维护者裁定挂起**)
+
+**怎么发现的**:v4 迁移的 `(c) TI_ERROR` 独立哨兵落地后,`ta1`(`undef_x = 0` ⇒ 期望 `{N01, TA01}`)**未回归**(只剩 `{N01}`),而两条探针读数**不能同时为真**。
+
+**判别探针(T5 自造,非猜)**:`d1` = `i := 1` + `undef_x = i` ⇒ 若 `tt` 是错误哨兵则报 TA01、若是 `int` 则不报。**实测不报** ⇒ `tt = TI_INT`;而 v3 探针打在 `EXPR_IDENT` 上打印 `UNDEFINED`(即该分支必 `return TI_ERROR(-2)`,且同一节点只打印一次)。
+⇒ **`undef_x` 的 ti 存在第二个来源**:`EXPR_IDENT` 的 `UNDEFINED → TI_ERROR` **没有参与**赋值位那条链。
+
+**已排除 4 项(逐条带手段)**:负数渲染错(`int_str(-2) == "-2"` 实测为真)· `if tt == TI_DYN` 提前分支(`TI_DYN=7 ≠ -2`)· `type_compat_strict` 里从未走到 ERROR 规则(`:471-476` 逐行在位)· 源目颠倒(`d2` 用 string RHS 报 TA01 ⇒ 方向没错,错的是 `tt` 的取值来源)。
+
+**剩 3 条候选(未逐条验完 ⇒ 按裁定不修)**:① `collect_decls`(`checker.cr:1450`)**预登记** LHS(写入口 `def_sym`/`sym_set_type`,`:854`);② `infer_expr` 之外**按节点回填**(`ast_set_type_val`,`:4199/4291/4300`);③ `res_type_node` 族(`:1008` 起,`:1254` 另有一处 `return TI_NEVER` 未核语义)。
+
+**★ 代价(本条目最该被读到的一段)**:该缺口使 **3 档 `tests/probes/` 负例探针被静默接受** ——
+`n05_recursive`(`{TS03}`→rc=0)· `n10_named_vs_int`(`{TA01}`→rc=0)· `n21_t_assign_int`(`{TA01}`→rc=0)。
+同文本跨三次二进制读数差(`1→1→0`)证「**必在二进制侧**」;且 **`probes_run.sh` 不在 `src/ci/run.sh` 的任何 job 里**(全仓只在 `:129` 的注释中被提及)⇒ **无自动门看着**。
+⇒ 挂起的代价**不是「少一条诊断」,是「三个负例静默失效 + 无自动门」**。
+
+**维护者裁定(2026-10-11)**:**挂起**(T5 已用尽一轮排查)。**禁止**为凑回归改判定面语义——**先能解释「为什么两条路径给出不同 ti」才谈修**。
+
+### 2026-10-12-2. 【既有约定 · 待裁】`-> int` 却 `return` `bool`:11 处 / 3 档;「`bool ⊆ int` 可隐式」是否为**语言面规则**(v4 迁移 T5 `nail3` 施工期暴露;**新判定面的第一批战果**)
+
+**怎么发现的**:`nail3`(逐 `return` 核对返回值 vs 声明返回型)**首轮就把 `check src/compiler` 打红**(rc=1 · 3×TF01),全在 `type_engine.cr` —— 形如 `fn lit_implies(...) -> int: return tt_tag(lq) == TT_TOP`。**改前被「`return ⇒ never` ⇒ 体类型恒相容」掩盖着,从来没人看见这层差异。**
+
+**站点清单(11 处 / 3 档,两口径差集有唯一解释)**:
+
+| 组 | 位置 | 处数 | 是否在 CI 检查闭包内 |
+|---|---|---|---|
+| A | `src/compiler/type_engine.cr::lit_implies`(421/426/428) | 3 | **在**(`check src/compiler` 直接可见,**现在靠豁免才绿**) |
+| B | `src/kernel/{kernel_main.cr:35,37,48,54,56,58,60 · subtype.cr:14}`(`nf_sub_eq`/`nf_eq`/`kern_sub_nf`) | 8 | **不在**——`build_kernel.py` **只编译、不 lint** ⇒ **即使不豁免,CI 也拦不住这批** |
+
+**扫描边界(如实)**:静态判据只看**语法可判**的 `bool`(比较/逻辑/取反/调用声明返回 `bool` 的函数);推断型(`b := a==b` 后 `return b`)另做了二次扫描 ⇒ **候选 1 条经人工核为假阳**(两个同名不同变量)⇒ 该类**实测 0 处**。**多层传参 / 字段带回 / 匹配臂**再被 `return` 的路径**扫不到**(需真类型推断)⇒ **上表是下界**。
+
+**给维护者的两条可裁事实**:
+1. **语义上这是同一件事**:本编译器里 `bool` 就是 `0/1` 的 `int`(比较产 `bool`,`tt_a`/`kern_get` 一类产 `int`)⇒ 语料的既有约定 = 「**`bool ⊆ int` 可隐式**」。
+2. **两档性质不同**:A 组在检查闭包内(靠豁免才绿);B 组**不在任何 CI 检查闭包内**。
+
+**待裁**:**认可**该约定 ⇒ **豁免转长期项**,且**应写进语言面**(`bool` 与 `int` 的关系),**而不是留在 checker 的一个 `if` 里**;**不认可** ⇒ 这 **11 处源该改**(显式 `as int`,或改写成 `if …: return 1` / `return 0`)。
+**现状**:代码**保持豁免,且只限 `bool↔int` 这一对**(注释已写明「放宽其它组合 = 把检查做成空壳」)。
+
+### 2026-10-12-3. 【诊断面 · 系统性静默】**不带码的 `add_error` 只要同批有带码诊断就永远不打印**(`main.cr:133-137` 的**次序**;v4 迁移 T5 施工期实名;**未修**)
+
+**机制(逐字)**:
+```core
+if g_diag_count > 0:      // ← 带码诊断(P25…)先命中
+    print_diagnostics()
+    return 1
+if g_error_count > 0:     // ← print_parse_errors() 永远走不到
+    print_parse_errors()
+    return 1
+```
+⇒ **不带码的 `add_error` 消息,只要同一次解析里还有任何带码诊断,就永远不打印。**
+
+**正控(机制自证)**:`struct S:` ⏎ `    f int,`(唯一诊断 = **不带码**的「expected ':' after struct field name」)⇒ 输出**确实打印** `error: expected ':' after struct field name` ✓;而**带码诊断一起出现时它就不见了**。
+
+**当初的触发面**:`flow` 分支那句 `add_error("expected 'fn' after flow")` **被记录下来但打印不出来**(`grep -c` = 0)——该分支已随 `flow` 文档形实现消失,**但同一缺陷面在别处仍在**。
+**同族**:`#2026-10-12-1`(`TA01`)· `t2_neg_inbody`(Region 头实现漏洞,已修)—— **母题 = 诊断报了、用户看不见**。
+
+### 2026-10-12-4. 【设计缺口】`corec run <内联源>` 的**包裹壳**按**行尾 `;`** 切分(`src/compiler/main.cr:356-391`,7 段内嵌源;v4 迁移 T6b 施工期实名;**未修**)
+
+**现象**:`g_source = imports + "fn main() -> int {\n" + body + "\n" + last_expr + ";\nreturn 0;\n}\n"` —— 壳按**行尾 `;`** 把内联源切成 `body` / 末表达式,再包 `return`(`main.cr:337-393`)。
+**⇒ 只把字面量改 v4 会得到「半 v4 壳」**:用户内联文本仍按 `;` 切。**要真修得重设计 `run` 的内联包裹(换成 v4 的 layout 切分)**。
+**不阻塞的证据**:`has_main != 0` 时该壳**根本不执行** ⇒ **`rebuild.sh` 的冒烟(rc=42)不受它影响**(T6b 实测)。
+
+### 2026-10-12-5. 【**发布步骤 · 非缺陷**】`PINNED_REV` 与 **squash 合入**的耦合(v4 迁移 T7 施工期实名)
+
+**现状**:T7 已把 `PINNED_REV` 从 `97f4394f`(2026-09-14,**v4 之前** ⇒ 只认 v3 形)换到 **`25e70197`**(v4 迁移 T6 收官),并重锁了三 sha(旧值留痕于 `rebuild.sh:18-27` / `REBUILD.md:53`)。
+**问题**:本仓 develop 走 **squash 合入**(见 `CLAUDE.md` 的 GitFlow 节)⇒ **`25e70197` 不进 develop 历史** ⇒ 他人/换机重跑 `bash tools/baseline/rebuild.sh ` **必失败**。
+**处置(已写进条件)**:**合入那一步须同批**:① 重指 `PINNED_REV` 到合入后 develop 上的提交;② **重锁三 sha 白名单**(`rebuild.sh:22-25` / `REBUILD.md:44-46` 已逐字写明该条件)。
+**判据**:合入后 `nice -n 19 bash tools/baseline/rebuild.sh ` 能重建出**与白名单逐条相同**的三 sha。
+
+### 2026-10-12-6. 【判据面 · 登记不动】两处**v3 形载荷**(形状陈旧但**当前仍工作**)
+
+| 位置 | 载荷 | 为什么当前仍工作 |
+|---|---|---|
+| `tests/harness/test_lsp_builtin_table.py:195` | L4-④ 追加的假函数为 v3 形(`{ … ; }`) | L1 只用 `^fn (…)(` **行首匹配** ⇒ 不涉 `}`/`;` ⇒ L4-④ PASS |
+| `tests/harness/test_ir_ref_sites.py:90` | 追加的 `emit(IR_REF, w, op_var, 0, 0, 0);` 带 `;` | 锚正则 `emit\(IR_REF,\s*(…)` **不涉 `;`** ⇒ 4/4 PASS |
+
+**登记理由(防后人误读)**:**形状陈旧 ≠ 漏迁**——这两处**当前工作**,改它没有收益(改坏了反而多一处风险)。**见到 v3 形不要一律当漏迁**:先问「它的判据用不用那个形状」。
+
+### 2026-10-12-7. 【语料面 · 另案】`#check`/`#ensure` 的 **inline 过渡形余 15 档**未翻文档形
+
+**现状**:T7 已把 **9 档**(`delta_d0_annot`/`delta_d9_annot`/`t2_pos_check`/`t2_pos_dup`/`t2_pos_multi`/`t3_pos_both`/`t3_pos_check_param`/`t4_xtalk`/`t4_yellow_only`)翻成**文档 §10.1 的 region 头形**;**余 15 档**仍是 inline(`t2_neg_*`/`t3_neg_*` 的**负例本体** + `t3_pos_ensure_result`/`t3_pos_ensure_true` 的 inline `#ensure`)。
+**为什么不顺手做**:**两形都收**(实现侧 inline 保留为兼容)⇒ **不阻塞**;且那些是**负例本体**,翻它会**改负例语义**,须与 `test_spec_grammar` 的期望**同批**改。
+**判据(若开做)**:逐档给「inline 形 / 文档形」两态的 **rc + 码集逐格相同** + `test_spec_grammar` 全绿。
+
 ### 2026-10-11-5. 【既有缺陷 · 运行期 SIGSEGV】带可选载荷的枚举变体 `enum E: V(int?)` 运行 rc=139(**代 0 同病**;★ 会卡 T6;取号基准 = 4)
 
 **现象**:`enum E: V(int?)` **能编过(build rc=0)但运行 rc=139(SIGSEGV)**。

From 0b2d9c3b64dc478b95b8c887cbbd13f90c3d4067 Mon Sep 17 00:00:00 2001
From: DslsDZC 
Date: Mon, 12 Oct 2026 17:51:42 +0800
Subject: [PATCH 14/15] =?UTF-8?q?docs(v4=20=E8=AF=AD=E6=B3=95):=20=C2=A7?=
 =?UTF-8?q?=E5=8D=81=20=E8=A7=84=E7=BA=A6=E6=8C=89=E7=BB=B4=E6=8A=A4?=
 =?UTF-8?q?=E8=80=85=E6=9B=B4=E6=96=B0=E7=89=88=E8=90=BD=E7=9B=98=E2=80=94?=
 =?UTF-8?q?=E2=80=94**=E5=8F=96=E6=B6=88=20`spec=20fn`**=EF=BC=88=E6=89=80?=
 =?UTF-8?q?=E6=9C=89=E5=87=BD=E6=95=B0=E9=83=BD=E6=98=AF=20`fn`=EF=BC=8C?=
 =?UTF-8?q?=E5=A4=8D=E7=94=A8=E9=9D=A0=E5=87=BD=E6=95=B0=E5=A5=91=E7=BA=A6?=
 =?UTF-8?q?=20+=20`#apply`/`#rewrite`=EF=BC=89+=20**=E5=88=A0=E9=99=A4=20`?=
 =?UTF-8?q?#tag`**=EF=BC=88=E6=98=8E=E5=86=99=E3=80=8CCore=20=E4=B8=8D?=
 =?UTF-8?q?=E5=BC=95=E5=85=A5=E7=94=A8=E6=88=B7=E5=8F=AF=E8=A7=81=E7=9A=84?=
 =?UTF-8?q?=E7=AD=96=E7=95=A5=E5=AE=9A=E4=B9=89=E6=9C=BA=E5=88=B6=E3=80=8D?=
 =?UTF-8?q?=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

维护者 2026-10-12 给出更新后的 §十,逐字落盘(仅补齐标题层级)。相对旧版的三处实质变化:

1. **§10.3 由「`spec fn`」改为「可复用命题与纯函数」** —— **Core 不引入 `spec fn`,所有函数都是 `fn`**;规约表达式可调用**任何被编译器判定为纯、终止、可判定**的函数(纯性由 HDFG 自动推导,不需用户标记);有副作用/不终止/不可判定者出现在规约中 ⇒ **编译器直接报错**。
   ⇒ **函数契约本身就是可复用的命题**:已证明的函数经 `#apply`/`#rewrite` 引用,`#apply(append_assoc)` 引用的是那条**全称命题**。
   ⇒ 规约表达式中的**自由变量自动泛化为全称闭包**(`#ensure(append(xs, Nil) == xs)` ≡ `forall(xs: List) => …`)。
2. **`#tag` 整节删除**(原 §10.8)—— 改为明写「**Core 不引入用户可见的策略定义机制;战术库的扩展通过普通模块和导入完成**」。⇒ **这正是此前设计讨论里判为「范畴错误」的那一处**(`#` 族应只有使用面)**由维护者裁定落定**(TODO #2026-10-11-1 据此闭档,见该条更新)。
3. **战术标签重组为四类**:提示标签(`#induct`/`#cases`/`#unfold`/`#rewrite`/`#apply`/`#exists`)· 语义范围标签(`#graph.*`)· 判定与求解标签(`#ring`…`#smt`,**只能在 VERIFY 阶段执行**)· 预算标签(`#budget`)。

另:§1.3 关键字的注里删掉 `#tag` 并加注「战术标签里**没有**『策略/标签定义』这一形」。

§10 体量:旧 388 行 → 新 322 行。
---
 docs/core-language-syntax_v4.md | 329 +++++++++++++-------------------
 1 file changed, 132 insertions(+), 197 deletions(-)

diff --git a/docs/core-language-syntax_v4.md b/docs/core-language-syntax_v4.md
index 62798ab9..bef06df7 100644
--- a/docs/core-language-syntax_v4.md
+++ b/docs/core-language-syntax_v4.md
@@ -42,7 +42,7 @@ catch fail spec
 - `self` 用于方法接收者(`self` / `&self` / `&mut self`)。
 - `Self` 是接口/实现上下文中的类型名。
 - `@comptime` 等 `@` 形式属于内建原语,不作为普通关键字处理。
-- `#check` / `#ensure` / `#invariant` / `#variant` 属于规约指令;`#smt`、`#induct`、`#simp`、`#tag` 等属于证明战术标签。它们都不占用普通代码的全局关键字。
+- `#check` / `#ensure` / `#invariant` / `#variant` 属于规约指令;`#smt`、`#induct`、`#simp` 等属于证明战术标签。它们都不占用普通代码的全局关键字。(**注**:战术标签里**没有**「策略/标签定义」这一形——Core 不引入用户可见的策略定义机制,战术库的扩展走普通模块与导入,见 §10.6/§10.8。)
 - `forall`、`exists`、`result`、`old` 只在规约上下文中具有特殊含义,不作为普通代码的全局保留字。
 - v4 不使用 `move` 关键字。
 
@@ -824,9 +824,9 @@ type Point3 = (dex, dex, dex)
 
 ## 十、规约
 
-规约直接写在 `.cr` 中,不存在独立的 `.corespec` / `.csp` 源语言。规约只描述不能从实现唯一恢复、或需要主动保证的性质;能够从 HDFG 自动推导的性质不要求用户重复标注。`#` 同时承载规约指令与证明战术标签:前者产生证明目标,后者向证明引擎提供能力、领域知识与搜索约束。`#tag` 用于定义可复用的证明策略,不建立第二套宏语言。
+规约直接写在 `.cr` 中,不存在独立的 `.corespec` / `.csp` 源语言。规约只描述不能从实现唯一恢复、或需要主动保证的性质;能够从 HDFG 自动推导的性质不要求用户重复标注。`#` 同时承载规约指令与战术标签:前者产生证明目标,后者向证明引擎提供能力、领域知识与搜索约束。
 
-### 10.1 `#check` / `#ensure`
+### 10.1 规约指令 `#check` / `#ensure`
 
 函数规约位于函数 layout region 的开头:
 
@@ -855,6 +855,8 @@ fn transfer(from: &mut Account, to: &mut Account, amount: int):
     to.balance += amount
 ```
 
+`#check` / `#ensure` 是函数契约的一部分,不是附加的独立定理声明。证明一个函数,就是证明其前置条件蕴含后置条件。
+
 ### 10.2 循环规约 `#invariant` / `#variant`
 
 循环不变量和终止度量写在循环 region 开头:
@@ -876,14 +878,50 @@ loop:
 - `#invariant(expr)`:每次进入循环与完成一次迭代后都必须保持的性质。
 - `#variant(expr)`:用于终止性证明的递减度量。
 
-### 10.3 `spec fn`
+### 10.3 可复用命题与纯函数
+
+Core **不引入 `spec fn`**。**所有函数都是 `fn`**。规约表达式中可以调用任何被编译器判定为**纯、终止、可判定**的函数。纯性由 HDFG 自动推导,不需要用户标记。
 
 ```core
-spec fn valid(x: int) -> bool:
+fn valid(x: int) -> bool:
     return x >= 0
+
+fn divide(a: int, b: int) -> int?:
+    #check(b != 0)
+    #ensure(result != none)
+
+    if b == 0:
+        return none
+
+    return a / b
+```
+
+`valid` 是普通 `fn`,但编译器证明它纯、终止、可判定,因此可以在 `#check` / `#ensure` / `#invariant` 中调用:
+
+```core
+#ensure(forall(i: int) => i >= 0 ==> valid(i))
+```
+
+如果某个函数有副作用、不终止或不可判定,就不能出现在规约中,编译器直接报错。用户不需要主动标记 spec。
+
+函数契约本身就是可复用的命题。已证明的函数可以通过 `#apply` / `#rewrite` 在其他证明中引用:
+
+```core
+fn append_assoc(xs: List, ys: List, zs: List) -> bool:
+    #ensure(append(append(xs, ys), zs) == append(xs, append(ys, zs)))
+    return append(append(xs, ys), zs) == append(xs, append(ys, zs))
+
+fn append_nil(xs: List) -> bool:
+    #apply(append_assoc)
+    #ensure(append(xs, Nil) == xs)
+    return append(xs, Nil) == xs
 ```
 
-`spec fn` 使用与普通函数相同的 layout 和显式 `return` 规则,可以被 `#check`、`#ensure`、`#invariant` 等规约表达式调用。
+`#apply(append_assoc)` 引用的是已证明的函数契约,即全称命题:
+
+```text
+forall(xs: List, ys: List, zs: List) => append(append(xs, ys), zs) == append(xs, append(ys, zs))
+```
 
 ### 10.4 量词与蕴含
 
@@ -901,6 +939,8 @@ forall(name: Type) => SpecExpr
 exists(name: Type) => SpecExpr
 ```
 
+规约表达式中的自由变量自动泛化为全称闭包。例如 `#ensure(append(xs, Nil) == xs)` 自动等价于 `forall(xs: List) => append(xs, Nil) == xs`。
+
 `==>` 是规约层蕴含运算符,优先级低于 `||`,右结合:
 
 ```text
@@ -913,86 +953,66 @@ A ==> B ==> C
 A ==> (B ==> C)
 ```
 
-### 10.5 证明自动化与复杂度边界
+### 10.5 战术标签
 
-`spec fn` 描述**要证明什么**;证明战术标签描述证明引擎**可以使用什么能力、知识或搜索约束**。普通情况下不要求用户手写战术:验证器先根据目标结构自动选择适用能力,只有无法低成本唯一决定策略、需要缩小搜索空间或需要显式授权昂贵证明时才写标签。
+战术标签不是命令式 proof script。它们向证明引擎提供候选能力、领域提示或搜索限制;证明引擎根据目标结构、成本模型和已推导事实自动选择实际执行顺序,并可以在更便宜的方法已经关闭目标时忽略未使用的提示。
 
-```core
-spec fn distributive(a: int, b: int, c: int) -> bool:
-    return a * (b + c) == a * b + a * c
-```
+**提示标签**
 
-若目标可被代数正规化直接关闭,验证器可以自动使用对应战术;用户不需要重复写 `#ring`。
-
-Core 对自动化有一条硬复杂度边界:
+提示标签缩小证明搜索范围,验证器可以忽略。
 
 ```text
-ONLINE
-    允许普通 corec build 隐式执行
-    必须具有已知的最坏情况 O(N) 或图上的 O(V + E) 上界
-
-VERIFY
-    不要求线性最坏情况保证
-    只能在显式验证阶段执行
+#induct(x)        指定归纳对象
+#cases(x)         指定情况分析对象
+#unfold(f)        指定展开函数
+#rewrite(lemma)   指定重写引理
+#apply(lemma)     指定应用引理
+#exists(witness)  提供存在量词见证
 ```
 
-其中 `N` 表示当前处理对象的线性表示规模,`V` / `E` 表示 HDFG 的节点数与边数。普通构建不得因为某个规约或战术标签启动 SMT、归纳搜索、定理搜索或其他没有线性最坏情况保证的过程。
-
-因此:
-
-```text
-corec build
-    source
-      ↓
-    仅 ONLINE 分析
-      ↓
-    HDFG / CIR / codegen
+示例:
 
-corec verify
-    已生成的语义对象 + spec fn
-      ↓
-    ONLINE + VERIFY 战术
-      ↓
-    proof / certificate
-      ↓
-    CIC kernel
+```core
+fn append_nil(xs: List) -> bool:
+    #induct(xs)
+    #simp
+    #ensure(append(xs, Nil) == xs)
+    return append(xs, Nil) == xs
 ```
 
-已经验证的证明结果可以作为带依赖身份的 proof artifact 缓存;后续普通构建可以读取和校验其身份,但不能为了重新得到该结果而隐式启动 VERIFY 搜索。
+`#induct(xs)` 的含义是:如果当前证明需要归纳,将 `xs` 作为明确的归纳对象;它不要求验证器立刻执行归纳。如果化简或已有定理已经关闭目标,则不需要实际执行归纳。
+
+**语义范围标签**
 
-### 10.6 证明战术标签
+语义范围标签读取 HDFG 语义信息,将证明问题缩到有限图切片。这些标签只能读取、裁剪和分析 HDFG,并产生子目标、可验证事实或证书;不能修改源程序、HDFG 或 backend mapping。
 
-证明战术标签不是命令式 proof script。它们向证明引擎提供**候选能力、领域提示或搜索限制**;证明引擎仍可以根据目标结构选择实际执行顺序,并可以在更便宜的方法已经关闭目标时忽略未使用的提示。
+```text
+#graph.provenance(...)
+#graph.dependencies(...)
+#graph.reachability(...)
+#graph.scc(...)
+#graph.region(...)
+#graph.effects(...)
+#graph.alias(...)
+#graph.state(...)
+#graph.dataflow(...)
+#graph.slice(...)
+```
 
-例如:
+示例:
 
 ```core
-spec fn append_nil(xs: List) -> bool:
-    #induct(xs)
-    return append(xs, Nil) == xs
+fn output_independent(secret: ., output: .) -> bool:
+    #graph.dependencies(secret, output)
+    #ensure(no_dependency(secret, output))
+    return no_dependency(secret, output)
 ```
 
-`#induct(xs)` 的含义是:如果当前证明需要归纳,将 `xs` 作为明确的归纳对象;它不要求验证器在读取该行时立刻执行归纳。如果化简或已有定理已经关闭目标,则不需要实际执行归纳。
+如果相应分析属于已证明最坏情况线性的 ONLINE 能力,它可以在普通构建中生成语义事实;如果其证明过程需要非线性搜索,则只能在 VERIFY 阶段消费这些事实。
 
-基础战术库可以提供:
+**判定与求解标签**
 
-```text
-#intro
-#exact(...)
-#apply(...)
-#cases(...)
-#induct(...)
-#rewrite(...)
-#simp
-#unfold(...)
-#constructor
-#split
-#exists(...)
-#contradiction
-#auto
-```
-
-专用判定与求解战术可以提供:
+判定与求解标签提供专用证明能力。**它们只能在 VERIFY 阶段执行。**
 
 ```text
 #ring
@@ -1009,120 +1029,74 @@ spec fn append_nil(xs: List) -> bool:
 
 这些名字描述 proof capability,不意味着它们都能进入 ONLINE。每个战术必须登记自己的执行等级、适用目标、证据形式和成本信息。
 
-`#smt` 因此不再被定义为普通编译阶段的“证明通道开关”,而是一个 VERIFY 战术标签:
+`#smt` 是一个 VERIFY 战术标签:
 
 ```core
 #smt
-spec fn bounded(x: int, lo: int, hi: int) -> bool:
+fn bounded(x: int, lo: int, hi: int) -> bool:
+    #ensure(x >= lo && x <= hi)
     return x >= lo && x <= hi
 ```
 
 它表示当前目标允许或优先使用 SMT 证明能力;`corec build` 仍不会因此启动 SMT。
 
-### 10.7 Core 语义战术
-
-Core 的战术库不仅包含传统逻辑战术,还可以直接读取编译器已经拥有的 HDFG 语义信息。语义战术只能**读取、裁剪和分析** HDFG,并产生子目标、可验证事实或证书;不能通过证明标签修改源程序、HDFG 或 backend mapping。
+**预算标签**
 
-典型能力:
+预算标签只约束 VERIFY 搜索,不改变普通 `corec build` 的线性复杂度边界。
 
 ```text
-#graph.provenance(...)
-#graph.dependencies(...)
-#graph.reachability(...)
-#graph.scc(...)
-#graph.region(...)
-#graph.effects(...)
-#graph.alias(...)
-#graph.state(...)
-#graph.dataflow(...)
-#graph.slice(...)
-
-#derive(bounds)
-#derive(pure)
-#derive(deterministic)
-#derive(terminating)
-#derive(no_alias)
-#derive(noninterference)
-```
-
-例如:
-
-```core
-spec fn output_independent(secret: ., output: .) -> bool:
-    #graph.dependencies(secret, output)
-    return no_dependency(secret, output)
+#budget(fast)
+#budget(normal)
+#budget(deep)
 ```
 
-如果相应分析属于已证明最坏情况线性的 ONLINE 能力,它可以在普通构建中生成语义事实;如果其证明过程需要非线性搜索,则只能在 VERIFY 阶段消费这些事实。
+### 10.6 证明自动化与复杂度边界
 
-编译器自动推导的 `pure`、`deterministic`、`terminating`、`no_alloc`、`safe_index` 等性质首先属于内部 FactDB / 验证结果,不要求用户在普通源码中重复书写同名标签。只有需要给证明引擎增加无法自动恢复的信息时才使用显式战术标签。
-
-### 10.8 `#tag` 战术策略
-
-`#tag` 定义一个可复用的**证明策略(proof strategy)**。它不是宏,不进行源码文本展开、AST 替换或 hygienic substitution;标签体声明的是该策略可提供的战术能力和搜索约束。
-
-无参数策略:
+`fn` 描述要证明什么;战术标签描述证明引擎可以使用什么能力、知识或搜索约束。普通情况下不要求用户手写战术:验证器先根据目标结构自动选择适用能力,只有无法低成本唯一决定策略、需要缩小搜索空间或需要显式授权昂贵证明时才写标签。
 
 ```core
-#tag arithmetic:
-    #simp
-    #ring
-    #lia
-    #smt
+fn distributive(a: int, b: int, c: int) -> bool:
+    #ensure(a * (b + c) == a * b + a * c)
+    return a * (b + c) == a * b + a * c
 ```
 
-参数化策略:
+若目标可被代数正规化直接关闭,验证器可以自动使用对应战术;用户不需要重复写 `#ring`。
 
-```core
-#tag structural(x):
-    #induct(x)
-    #simp
-    #auto
-```
+Core 对自动化有一条硬复杂度边界:
 
-使用:
+```text
+ONLINE
+    允许普通 corec build 隐式执行
+    必须具有已知的最坏情况 O(N) 或图上的 O(V + E) 上界
 
-```core
-spec fn append_nil(xs: List) -> bool:
-    #structural(xs)
-    return append(xs, Nil) == xs
+VERIFY
+    不要求线性最坏情况保证
+    只能在显式验证阶段执行
 ```
 
-`#tag` 的标签体是**能力集合**,不是严格的命令序列。对某个多项式恒等式,`#arithmetic` 可能只实际运行 `ring`;对另一个目标可能先化简再进入 SMT。验证器依据目标分类、适用条件、确定性与成本模型选择实际路径。
+其中 `N` 表示当前处理对象的线性表示规模,`V` / `E` 表示 HDFG 的节点数与边数。普通构建不得因为某个规约或战术标签启动 SMT、归纳搜索、定理搜索或其他没有线性最坏情况保证的过程。
 
-目标语法:
+因此:
 
 ```text
-TagDecl      = '#tag' IDENT ['(' [TagParamList] ')'] ':' Layout
-TagParamList = IDENT (',' IDENT)*
-TagUse       = '#' TagPath ['(' [ArgList] ')']
-```
-
-`#tag` 参数不写普通 Core 运行时类型。参数的 proof-semantic role 由其在组成战术中的使用方式推导;这些内部角色不形成 `Goal`、`Proof`、`InductionSubject` 等用户可见类型。
-
-例如:
+corec build
+    source
+      ↓
+    仅 ONLINE 分析
+      ↓
+    HDFG / CIR / codegen
 
-```core
-#tag structural(x):
-    #induct(x)
-    #simp
+corec verify
+    已生成的语义对象 + 函数契约
+      ↓
+    ONLINE + VERIFY 战术
+      ↓
+    proof / certificate
+      ↓
+    CIC kernel
 ```
 
-`#induct(x)` 约束 `x` 必须能够作为归纳对象;该要求在策略使用位置进行静态检查。
-
-`#tag` 的硬规则:
-
-- 只允许出现在顶层;标签名位于独立的 tactic/tag namespace。
-- 内建战术名不能被用户 `#tag` 覆盖。
-- 标签体只能引用证明战术、证明提示或其他 `#tag` 策略。
-- `#check`、`#ensure`、`#invariant`、`#variant` 不允许进入 `#tag`;命题复用使用 `spec fn`。
-- 会改变信任边界的 `axiom`、`assume`、`admit` 一类能力不得被 `#tag` 隐藏。
-- 编译/优化/映射操作不属于 `#tag`;这类能力继续由普通语言或 `@` 编译/映射控制承担。
-- 自定义策略可以引用其他自定义策略;直接或间接形成递归环时属于静态错误。
-- 策略不产生运行时指令,不单独生成 HDFG 节点。
-- 策略不能把未证明命题变成已证明事实;所有最终结论仍必须具有 CIC 内核可复验的 proof / certificate,或显式受信机制所要求的证据。
-
-### 10.9 战术执行等级与成本传播
+已经验证的证明结果可以作为带依赖身份的 proof artifact 缓存;后续普通构建可以读取和校验其身份,但不能为了重新得到该结果而隐式启动 VERIFY 搜索。
 
 每个战术至少登记:
 
@@ -1136,44 +1110,15 @@ required_context
 produced_evidence
 ```
 
-组合策略的执行等级由其成员自动传播:
-
-```text
-class(strategy) = max(class(member tactics))
-```
-
-例如:
-
-```core
-#tag memory_linear:
-    #graph.provenance
-    #graph.region
-```
-
-如果两个组成战术都满足 ONLINE 要求,则整个策略仍是 ONLINE。
+组合策略的执行等级由其成员自动传播。但 **Core 不引入用户可见的策略定义机制**;战术库的扩展通过**普通模块和导入**完成。
 
-```core
-#tag algebra:
-    #simp
-    #ring
-    #smt
-```
-
-只要其中存在 VERIFY 战术,则整个策略是 VERIFY;它不能被伪装成普通构建中的线性自动分析。
-
-VERIFY 阶段仍按照成本模型优先选择高适用性、低成本、高确定性的战术,不默认穷举所有候选。
-
-必要时可以提供验证预算提示:
+编译器自动推导的 `pure`、`deterministic`、`terminating`、`no_alloc`、`safe_index` 等性质首先属于内部 FactDB / 验证结果,不要求用户在普通源码中重复书写同名标签。只有需要给证明引擎增加无法自动恢复的信息时才使用显式战术标签。
 
-```text
-#budget(fast)
-#budget(normal)
-#budget(deep)
-```
+### 10.7 证明对象与元编程不形成用户类型
 
-预算只约束 VERIFY 搜索,不改变普通 `corec build` 的线性复杂度边界。
+Core 不引入 `Fragment<...>`、`Relation`、`Goal<...>`、`Proof<...>`、`Rewrite<...>` 等用户可见元对象类型。证明状态、战术参数角色、证明项、语义切片与重写对象可以存在于验证器内部,但源码仍使用普通 Core 语法、`fn`、`#` 战术标签和 `@` 编译/映射控制表达。
 
-### 10.10 战术库与扩展
+### 10.8 战术库与扩展
 
 战术库可以包含:
 
@@ -1181,7 +1126,6 @@ VERIFY 阶段仍按照成本模型优先选择高适用性、低成本、高确
 primitive tactics
 semantic tactics
 decision procedures
-strategy tags
 lemma / rewrite databases
 goal classifiers
 reflection procedures
@@ -1199,16 +1143,7 @@ std::proof::memory
 std::proof::concurrency
 ```
 
-第三方战术库继续使用普通 Core 模块与包管理机制,不建立独立的 proof package manager。可见 theorem / lemma 数据库由普通 `import` 范围限制,避免默认把整个生态的规则都送入 proof search。
-
-
-### 10.11 元编程与证明对象不形成用户类型
-
-Core 不引入 `Fragment<...>`、`Relation`、`Goal<...>`、`Proof<...>`、`Rewrite<...>` 等用户可见元对象类型。证明状态、战术参数角色、证明项、语义切片与重写对象可以存在于验证器内部,但源码仍使用普通 Core 语法、`spec fn`、`#` 战术标签和 `@` 编译/映射控制表达。
-
-
-
----
+第三方战术库继续使用**普通 Core 模块与包管理机制**,不建立独立的 proof package manager。可见 theorem / lemma 数据库由普通 `import` 范围限制,避免默认把整个生态的规则都送入 proof search。
 
 ## 十一、并发与执行流
 

From 739a5d9fc3ed84f1afcdee8f1495399f82df1c60 Mon Sep 17 00:00:00 2001
From: DslsDZC 
Date: Mon, 12 Oct 2026 17:52:48 +0800
Subject: [PATCH 15/15] =?UTF-8?q?docs(TODO):=20#2026-10-11-1=20=E9=97=AD?=
 =?UTF-8?q?=E6=A1=A3=E2=80=94=E2=80=94=E7=BB=B4=E6=8A=A4=E8=80=85=202026-1?=
 =?UTF-8?q?0-12=20=E7=9A=84=20=C2=A7=E5=8D=81=20=E6=9B=B4=E6=96=B0?=
 =?UTF-8?q?=E7=89=88=E5=B7=B2=E7=AD=94=E5=A4=8D=E8=AF=A5=E8=AE=BE=E8=AE=A1?=
 =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=88`#tag`=20=E6=95=B4=E8=8A=82=E5=88=A0?=
 =?UTF-8?q?=E9=99=A4=20+=20`spec=20fn`=20=E5=8F=96=E6=B6=88=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

该条所记三条毛病(`#` 既使用又定义 / 形状说谎 / 名字关在标签族里)由「**不引入该构造**」一并消除;
原记录保留供追溯。判据:`tests/harness/test_todo_id_migration.py` → 6/6 PASS。
---
 TODO.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/TODO.md b/TODO.md
index 7dc2e5f0..81b263b1 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2187,6 +2187,12 @@ fn f(x: int) -> int:
 
 ### 2026-10-11-1. 【设计·未决】v4 规约的战术「策略定义」语法(现形 `#tag`)待重设计——`#` 族应**只有使用面**(维护者口述裁定;**本节只登记设计问题,未动文档**;取号基准 = 当天已有最大 N 无 ⇒ 1)
 
+> ✅ **已闭档(2026-10-12)**:维护者给出**更新后的 §十**并已逐字落盘到 `docs/core-language-syntax_v4.md`
+> (`#tag` **整节删除**;§10.6 明写「**Core 不引入用户可见的策略定义机制;战术库的扩展通过普通模块和导入完成**」;
+> 同时 **`spec fn` 也取消** —— 所有函数都是 `fn`,复用靠**函数契约 + `#apply`/`#rewrite`**)。
+> ⇒ 本节所记的三条毛病(`#` 既使用又定义 / 形状说谎 / 名字关在标签族里)**由「不引入该构造」一并消除**。
+> **以下原记录保留供追溯。**
+
 **维护者原话(2026-10-11)**:「这个标签我是打算做成战术的,应该就是使用」「标签是没问题但就是套来套去感觉很不对」「为什么必须要用包裹起来?」。
 
 **把这句话读成硬约束**:`#` 这个符号族里**只能有「使用」**,不能有「定义」;任何 `#xxx` 都必须读作「在这里用一个战术」。⇒ `#tag` **不是措辞问题,是范畴错误**——它是全族里**唯一**一个「用 `#` 声明新东西」的构造 ⇒ **该删,而非改名或换壳**。