core: add Core Direct string canaries (substring/charAt/replace); Stage‑B: alias table (ENV) support with BundleResolver; docs: Exit Code Policy tag→rc rules and checklist updates.

This commit is contained in:
nyash-codex
2025-11-02 16:24:50 +09:00
parent 8b006575c1
commit 0cd2342b05
14 changed files with 371 additions and 26 deletions

View File

@ -45,6 +45,19 @@ Exit Code Policy
- GateC(Core): numeric return is mapped to process exit code。タグ付きの失敗時は安定メッセージを出し、可能な限り非0で終了。
- VM backendRust Interpreter: 戻り値は標準出力に出す。プロセスの終了コードは戻り値と一致しない場合があるため、スモークは安定タグや標準出力の数値で検証するrcは参考
- 推奨: CIやスクリプトでは GateC(Core) を優先し rc を厳密化。開発時の対話検証は VM ルートで標準出力を検証。
Tag→RCCore Direct
- Core Direct`HAKO_CORE_DIRECT=1`)では、数値行が見つからない場合は rc≠0 を返すFailFast
- 代表タグ(例)
- `[core/string/bounds]` → rc=1
- `[core/array/oob_set]` → rc=1
- `[core/mir_call/method_unsupported]` → rc=1
Core Direct Toggle
- `HAKO_CORE_DIRECT=1`(互換: `NYASH_CORE_DIRECT`で、GateC(Core) の JSON 実行を "Core Dispatcher 直行" 子経路に切り替える。
- 形: 一時Hakoスクリプトに `include "lang/src/vm/core/dispatcher.hako"` を埋め込み、`NyVmDispatcher.run(json)` を実行。
- rc: 最後の数値行を rc にマップ。数値がない場合(タグ等)は rc≠0 とするFailFast
- 用途: Core の診断タグや rc を CI で直接検証したい時に使用。
- Runner Core toggle: `HAKO_NYVM_CORE=1` (or `NYASH_NYVM_CORE=1`) selects the
Core bridge for the nyvm wrapper path.
- GateC Core route: set `NYASH_GATE_C_CORE=1` (or `HAKO_GATE_C_CORE=1`) to

View File

@ -401,7 +401,7 @@ static box NyVmOpMirCall {
if method == "keys" {
local dst = me._read_dst(inst_json, "map keys")
if dst == null { return -1 }
// Build keys by scanning mem for receiver-specific entry slots
// Build keys by scanning mem for receiver-specific entry slots (non-null values only)
local keys_arr = new ArrayBox()
local prefix = me._map_entry_slot(recv_id, "")
// Iterate memory keys (MapBox.keys())
@ -416,8 +416,11 @@ static box NyVmOpMirCall {
if k.substring(0, prefix.length()) == prefix { ok = 1 }
}
if ok == 1 {
local tail = k.substring(prefix.length(), k.length())
keys_arr.push(tail)
local v = mem.get(k)
if v != null {
local tail = k.substring(prefix.length(), k.length())
keys_arr.push(tail)
}
}
i = i + 1
}
@ -473,7 +476,20 @@ static box NyVmOpMirCall {
return 0
}
if method == "clear" {
// clear(): set length to 0; entries are logically clearedTTL: metadataonly
// clear(): set length to 0 and remove all entries for this map from mem
local prefix = me._map_entry_slot(recv_id, "")
local all_keys = mem.keys()
local i = 0
local n = all_keys.length()
loop(i < n) {
local k = "" + all_keys.get(i)
local ok = 0
if k.length() >= prefix.length() {
if k.substring(0, prefix.length()) == prefix { ok = 1 }
}
if ok == 1 { mem.set(k, null) }
i = i + 1
}
me._map_len_set(state, recv_id, 0)
local dst_opt2 = me._read_optional_vid_field(inst_json, "dst")
if dst_opt2 != null { NyVmState.set_reg(state, dst_opt2, void) }