From 51bf7ff4104c3fc2ce086835a3c6eaabcd78ca1f Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Tue, 4 Nov 2025 20:51:15 +0900 Subject: [PATCH] docs(20.39): add Next Steps and mark hv1 unify + string scanner fix DONE; loop count_param: accept swapped < / <= (cmp Gt/Ge); add canaries for swapped_lt/lte --- CURRENT_TASK.md | 33 ++++++---------- .../internal/lower_loop_count_param_box.hako | 19 +++++++-- .../internal/lower_loop_simple_box.hako | 9 ++++- ...der_loop_swapped_lt_core_exec_canary_vm.sh | 39 +++++++++++++++++++ ...er_loop_swapped_lte_core_exec_canary_vm.sh | 39 +++++++++++++++++++ 5 files changed, 113 insertions(+), 26 deletions(-) create mode 100644 tools/smokes/v2/profiles/quick/core/phase2039/mirbuilder_loop_swapped_lt_core_exec_canary_vm.sh create mode 100644 tools/smokes/v2/profiles/quick/core/phase2039/mirbuilder_loop_swapped_lte_core_exec_canary_vm.sh diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 4037f81c..215638f5 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -21,6 +21,12 @@ Remaining (20.39 — typed IR & finalize) - Remove include fallback from scripts(直行のみ)。 - Sweep concatenations and update helpers. +Next Steps (ordered) +1) ループ比較の正規化拡張(>/>=/==/!= → Lt/Gt/Ge 正規化;左右スワップ++1調整、canary補強) +2) SSOT 拡張(compare/branch/jump/phi を cf_common に段階移行) +3) Unicode `\\uXXXX` 復号のトグル実装(既定OFF;canary追加) +4) hv1 一本化(main入口)と文字列スキャナ根治('対応+エスケープ拡張)を DONE に反映 + Hotfix Plan — Using/Prelude Unification (Self‑Host) - Problem: .hako を NyashParser に通す経路でパース落ち(Invalid expression)。 - Decision: プレリュードは“テキスト統合(merge_prelude_text)”に一本化。AST マージは撤退。 @@ -50,29 +56,14 @@ Acceptance - v1 φ/branch/jump の代表カナリーが IR 反復で strict PASS。tolerate ケースは期待と一致。 - Verify 既定が v1→Hakorune(Core fallback)で quick 緑維持。 - Hako 構文を Nyash VM で実行しようとした場合、入口で Fail‑Fast(診断メッセージ)。 +- hv1 直行は main 入口で早期退出し、プラグイン初期化ログが出ない(canaryで保証)。 Changes (this step) -- Docs: phase‑20.39 に計画と進捗(verify直行 DONE/concat-safety VM/Core DONE/build2 適用済み lowers)を反映。 -- Add typed IR box file(hakorune-vm.ir.types)と module export(構造のみ・参照用)。 -- Concat-safety: StrCast 追加、VM/Core の “"" + ” を置換(canaries 緑維持)。 -- V1PhiAdapterBox: robust incoming scan (multi‑pair, spaces/newlines) using array‑end scanner. -- V1SchemaBox: new block_segment_wo_phi(json, bid) to build IR segment without φ. -- V1SchemaBox: phi_table_for_block(json,bid) 追加(dst と incoming[[pred,val],…] を返す) -- NyVmDispatcherV1Box(FLOW): IR‑based loop(block_segment_wo_phi)+ entry φ は V1PhiTableBox.apply_table_at_entry で一括適用(scan は後退互換のfallbackに) -- Entry φ application: still centralized in V1PhiTableBox; added optional trace hooks (HAKO_V1_FLOW_TRACE=1). -- Canary updated to enable experiment flag: v1_hakovm_phi_simple_flow_canary_vm.sh sets HAKO_V1_ALLOW_PHI_EXPERIMENT=1. -- φ canaries 追加: multi‑incoming / multi‑phi / whitespace混在 → いずれも PASS -- v1 extern canaries(20.38): env.get / warn / error / emit / codegen を PASS 化(タグ+rc=0)。 -- hv1 inline prelude: prelude_v1.hako を path‑using に切替(inline -c での alias 揺れ回避)。 -- phase2038 hv1 inline canary ドライバは ALLOW_USING_FILE を付与し、preinclude で安定化を準備(現状は alias 未解決で SKIP)。 -- extern stub canaries(emit/codegen): include 依存を撤去し、rc=0 のみ確認に簡素化(タグ観測は hv1 inline カナリーへ委譲)。 -- test_runner の provider タグ用シムを撤去(hv1 inline が安定したため)。 -- vm.rs に hv1 ルーティング口を追加(opt-in、Fail‑Fast 緩和下で NYASH_VERIFY_JSON の inline を hv1 wrapper にルート)。 -- verify は env(NYASH_VERIFY_JSON)受け渡し+末尾数値抽出で rc を安定化。 -- Dispatcher(FLOW) は構造IRの反復へ完全切替(scan断片を撤去)。 -- V1Schema.get_function_ir: blocks/phi_table 構築を実装(op/text+一部フィールド抽出で dispatcher の負荷低減)。 -- Program(JSON v0) → MIR(JSON v0) bridge: Continue 降下の根治(増分注入→cond へ)。 -- test_runner: verify_program_via_builder_to_core(env 渡し+Rust CLI fallback)を導入。 +- hv1 direct を main 入口で早期退出に一本化(プラグイン初期化前で rc のみ出力)。 +- Tokenizer 根治: Stage‑3 でシングルクォート受理、エスケープ(\\/ \\b \\f \\' \\r)拡張。 +- SSOT: Builder BinOp を `emit_binop_to_dst` で発行(挙動不変)。 +- Loop 正規化: CountParam に `L i / L >= i (ascending) - if op != ">" && op != ">=" { return null } + // swapped (Int on lhs, Var i on rhs): + // L > i / L >= i → ascending(i < L / i < L+1)→ cmp="Lt"(limit +1 for >=) + // L < i / L <= i → descending(i > L / i >= L)→ cmp="Gt" / "Ge" + if op != ">" && op != ">=" && op != "<" && op != "<=" { return null } local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } local k_lim_t2 = s.indexOf("\"type\":\"Int\"", k_lhs) if k_lim_t2 >= 0 { @@ -91,8 +93,17 @@ static box LowerLoopCountParamBox { limit = PatternUtilBox.find_local_int_before(s, lname3, k_cmp) } if limit == null { return null } - if op == ">=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) } - cmp = "Lt" + if op == ">" { + cmp = "Lt" + } else if op == ">=" { + limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) + cmp = "Lt" + } else if op == "<" { + cmp = "Gt" + } else { + // op == "<=" + cmp = "Ge" + } } // Body increment: Local i = Binary('+', Var i, Int step) local k_body_i = s.indexOf("\"name\":\"" + varname + "\"", k_loop) diff --git a/lang/src/mir/builder/internal/lower_loop_simple_box.hako b/lang/src/mir/builder/internal/lower_loop_simple_box.hako index bb414168..db732882 100644 --- a/lang/src/mir/builder/internal/lower_loop_simple_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_simple_box.hako @@ -58,12 +58,19 @@ static box LowerLoopSimpleBox { return null } } else { - // swapped: we expect op to be '>' or '>=' + // swapped: L ? i if op == ">" { // L > i ≡ i < L } else if op == ">=" { // L >= i ≡ i <= L ≡ i < (L+1) limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) + } else if op == "<" { + // L < i ≡ i > L → for simple ascending loop (init=0, step=1) this pattern is not canonical; + // we treat as descending form not supported by simple box + return null + } else if op == "<=" { + // L <= i ≡ i >= L — same reason as above + return null } else { return null } diff --git a/tools/smokes/v2/profiles/quick/core/phase2039/mirbuilder_loop_swapped_lt_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2039/mirbuilder_loop_swapped_lt_core_exec_canary_vm.sh new file mode 100644 index 00000000..7f33625f --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2039/mirbuilder_loop_swapped_lt_core_exec_canary_vm.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Loop internal — swapped compare (Int < Var) → normalize to i > limit (descending); expect rc == 0 (no iterations) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_swapped_lt_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Int","value":3},"rhs":{"type":"Var","name":"i"}}, + "body": [ + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"-","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ] +} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_mir_rc "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_loop_swapped_lt_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_swapped_lt_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2039/mirbuilder_loop_swapped_lte_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2039/mirbuilder_loop_swapped_lte_core_exec_canary_vm.sh new file mode 100644 index 00000000..28b3d456 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2039/mirbuilder_loop_swapped_lte_core_exec_canary_vm.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Loop internal — swapped compare (Int <= Var) → normalize to i >= limit (descending); with i starts at 0, no iterations → rc==0 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_swapped_lte_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<=","lhs":{"type":"Int","value":3},"rhs":{"type":"Var","name":"i"}}, + "body": [ + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"-","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ] +} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_mir_rc "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_loop_swapped_lte_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_swapped_lte_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 +