From 8ffc4d044802eca24eea4eade5d661b1a819265d Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Sat, 15 Nov 2025 22:40:12 +0900 Subject: [PATCH] =?UTF-8?q?Phase=2025.1b:=20Step3=E5=AE=8C=E4=BA=86?= =?UTF-8?q?=EF=BC=88LoopForm=E5=AF=BE=E5=BF=9C=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step3実装内容(LoopForm → MIR導線確立): - FuncBodyBasicLowerBox._try_lower_loop追加: - Loop判定 → LowerLoopSumBcBox → LowerLoopSimpleBox の順に試行 - 成功時は_rebindで関数名をBox.method/arityに付け替え - 失敗時は[builder/funcs:unsupported:loopform]でFail-Fast - lowerメソッド冒頭でLoop優先処理: - Loop含む場合は_try_lower_loopを呼び、成功/失敗で明確に分岐 - Loopが無い場合のみ既存のLocal/If/Return処理に進む - PHI地獄防止ポリシー徹底: - FuncBodyBasicLowerBox/FuncLowering側でPHIやキャリアを直接いじらない - LoopForm制約外は必ずタグ付きでFail-Fast(Rust providerに退避可能) ドキュメント更新: - Phase 25.1b README: Step3をinitial-implementedに更新 - builder README: [builder/funcs:unsupported:loopform]タグ追加 - CURRENT_TASK.md: Step3進捗記録 スモークテスト: - selfhost_mir_loopform_basic_vm.sh追加(基本構造実装済み) - defs生成経路の詳細調整は継続タスク Next: Step4(MethodCall/ExternCall対応) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- CURRENT_TASK.md | 2 +- .../roadmap/phases/phase-25.1b/README.md | 20 +++++-- lang/src/mir/builder/README.md | 1 + .../builder/func_body/basic_lower_box.hako | 33 ++++++++++- .../selfhost_mir_loopform_basic_vm.sh | 58 +++++++++++++++++++ 5 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 tools/smokes/v2/profiles/quick/core/phase251/selfhost_mir_loopform_basic_vm.sh diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 43ae70b1..1a080b67 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -106,7 +106,7 @@ Update (2025-11-15 — Phase 25.1a: Stage1 build pipeline hotfix progress) - JSON 出力を jsonfrag ベースで構築し、functions 配列に複数関数を格納可能にする。 - 上記の完了後、selfhost-first を既定に戻し Stage1 CLI EXE の JSON stdout 契約(Rust/llvmlite と同等)を仕上げる。 - ループについては LoopForm 正規化を前提とし、LoopForm の制約を満たさない形(キャリア3変数以上・順序再配置不能など)は selfhost builder では扱わず、タグ付き Fail‑Fast で検知する(PHI ノード生成は既存 LoopForm/LowerLoop helper に一元化)。 - - docs: `docs/development/roadmap/phases/phase-25.1b/README.md` を design deep‑dive 版に更新し、FuncLoweringBox / MirBuilderBox の現状把握と拡張方針(Fail‑Fast ポリシー・LoopForm/PHI ポリシー・Step0〜6 の実装順序など)を整理済み。Step0(Fail‑Fast/観測導線)は 2025-11-15 実装済み(defs_only/no_match タグ+ `_lower_func_body` トレース)、Step1 は `HAKO_MIR_BUILDER_REQUIRE_MAIN=1` トグルによる main 必須チェックを inject_funcs に入れるところまで完了。Step2 の最初の差分として、`FuncBodyBasicLowerBox` を追加して Local/If/Return パターンを既存の minimal lowers で箱化し、`_lower_func_body` から段階的に呼び出せるようにした(Loop を含む場合は `[builder/funcs:unsupported:loop]` をトレース)。*** + - docs: `docs/development/roadmap/phases/phase-25.1b/README.md` を design deep‑dive 版に更新し、FuncLoweringBox / MirBuilderBox の現状把握と拡張方針(Fail‑Fast ポリシー・LoopForm/PHI ポリシー・Step0〜6 の実装順序など)を整理済み。Step0(Fail‑Fast/観測導線)は 2025-11-15 実装済み(defs_only/no_match タグ+ `_lower_func_body` トレース)、Step1 は `HAKO_MIR_BUILDER_REQUIRE_MAIN=1` トグルによる main 必須チェックを inject_funcs に入れるところまで完了。Step2 では `FuncBodyBasicLowerBox` を追加して Local/If/Return パターンを既存の minimal lowers で箱化し、`_lower_func_body` から段階的に呼び出せるようにした。Step3(LoopForm対応)も 2025-11-15 実装完了:`FuncBodyBasicLowerBox._try_lower_loop` から `LowerLoopSumBcBox`/`LowerLoopSimpleBox` を呼び、LoopForm正規化済みループをMIRに落とす導線を確立、PHI/キャリア処理は既存Loop lowersに完全委譲、制約外は `[builder/funcs:unsupported:loopform]` でFail-Fast。*** Update (2025-11-16 — Stage‑B using resolver alias 化 & 環境導線) - Stage‑B entry (`compiler_stageb.hako`) の `using "hako.compiler.entry.bundle_resolver"` / `using "lang/src/compiler/entry/using_resolver_box.hako"` を module alias (`hako.compiler.entry.bundle_resolver`, `lang.compiler.entry.using_resolver`) に置き換え、Stage‑3 パーサが string literal using を弾いていた問題を解消。 diff --git a/docs/development/roadmap/phases/phase-25.1b/README.md b/docs/development/roadmap/phases/phase-25.1b/README.md index d5140806..78d96993 100644 --- a/docs/development/roadmap/phases/phase-25.1b/README.md +++ b/docs/development/roadmap/phases/phase-25.1b/README.md @@ -174,12 +174,22 @@ Status: planning-only(実装着手前の設計・分析フェーズ) - Loop を含まない defs は selfhost builder で MIR 関数にできるようになり、Stage1 CLI の emit/build ハンドラの半分程度を selfhost パスで賄える。 ### Step 3 — Loop(LoopForm)の受理 -- 目的: LoopForm 正規化済みの while/for を MIR に落とす。 -- 作業: - - `lower_loop_simple_box` / `lower_loop_sum_bc_box` など既存 helper を FuncLoweringBox 側からも利用できるようにし、LoopForm のキャリアを MIR へ展開。 - - LoopForm の制約を満たさないケースは `[builder/funcs:unsupported:loopform]` で Fail-Fast。 +- Status: initial-implemented (2025-11-15). `FuncBodyBasicLowerBox` now calls `LowerLoopSumBcBox`/`LowerLoopSimpleBox` from `_try_lower_loop`, tags unsupported loops with `[builder/funcs:unsupported:loopform]`, and delegates all PHI/carrier handling to LoopForm lowers. +- 目的: LoopForm 正規化済みの while/for を MIR に落とす。ループの正規化・PHI設計はLoopForm/既存lower_loop系Boxに任せ、FuncLowering/MirBuilder側はそれを使うだけにする。 +- 作業内容(実装済み): + - `FuncBodyBasicLowerBox`に`_try_lower_loop`メソッド追加: + - Loop判定 → `LowerLoopSumBcBox.try_lower` → `LowerLoopSimpleBox.try_lower` の順に試す。 + - 成功時は`_rebind`で関数名を`Box.method/arity`に付け替え。 + - 失敗時は`[builder/funcs:unsupported:loopform]`でFail-Fast。 + - `lower`メソッド冒頭でLoop優先処理: + - Loop含む場合は`_try_lower_loop`を呼び、成功/失敗で明確に分岐。 + - Loopが無い場合のみ既存のLocal/If/Return処理に進む。 + - PHI地獄防止ポリシー徹底: + - FuncBodyBasicLowerBox/FuncLowering側でPHIやキャリアを直接いじらない。 + - LoopForm制約外は必ずタグ付きでFail-Fast(Rust providerに退避可能)。 - 成果物: - - `cmd_build_exe` の `loop(i < argc)` 等、Stage1 CLI の代表的な while/for パターンを selfhost builder で通せる。 + - `cmd_build_exe`の`loop(i < argc)`等、Stage1 CLIの代表的なwhile/forパターンをselfhost builderで通せる基礎が整った。 + - 次のステップ: LoopForm対応の動作確認スモークテスト追加、Step4(MethodCall/ExternCall)へ進む。 ### Step 4 — MethodCall / ExternCall パリティ - 目的: `hostbridge.extern_invoke` / `FileBox` / `ArrayBox` など Stage1 CLI で多用される呼び出しを selfhost builder でも再現。 diff --git a/lang/src/mir/builder/README.md b/lang/src/mir/builder/README.md index f4b6e901..ba262806 100644 --- a/lang/src/mir/builder/README.md +++ b/lang/src/mir/builder/README.md @@ -14,6 +14,7 @@ Tags (Fail‑Fast, stable) - `[mirbuilder/internal/unsupported] ...` — Program(JSON) shape not yet supported by internal lowers - `[builder/selfhost-first:unsupported:defs_only]` — only defs を lowering できる状態(main なし)のため中止 - `[builder/selfhost-first:unsupported:no_match]` — internal lowers / defs のどちらにもマッチせず中止 +- `[builder/funcs:unsupported:loopform]` — Loop を含むが LoopForm 制約に当てはまらないか、selfhost builder ではまだ扱えない Loop 構造のため中止(Rust provider に退避可能) - `[builder/funcs:fail:no-main]` — inject_funcs が main を含まない MIR に defs を差し込もうとしたため拒否(`HAKO_MIR_BUILDER_REQUIRE_MAIN=1` 時) - `[mirbuilder/delegate]` — delegate path selected(Runner/extern provider 経由) - `[mirbuilder/delegate/missing]` — delegate/provider not wired yet diff --git a/lang/src/mir/builder/func_body/basic_lower_box.hako b/lang/src/mir/builder/func_body/basic_lower_box.hako index 26e66e32..357f2c0c 100644 --- a/lang/src/mir/builder/func_body/basic_lower_box.hako +++ b/lang/src/mir/builder/func_body/basic_lower_box.hako @@ -14,6 +14,8 @@ using "hako.mir.builder.internal.lower_if_compare_fold_binints" as LowerIfCompar using "hako.mir.builder.internal.lower_if_compare_fold_varint" as LowerIfCompareFoldVarIntBox using "hako.mir.builder.internal.lower_if_compare_varint" as LowerIfCompareVarIntBox using "hako.mir.builder.internal.lower_if_compare_varvar" as LowerIfCompareVarVarBox +using "hako.mir.builder.internal.lower_loop_simple_box" as LowerLoopSimpleBox +using "hako.mir.builder.internal.lower_loop_sum_bc_box" as LowerLoopSumBcBox static box FuncBodyBasicLowerBox { lower(func_name, box_name, params_arr, body_json) { @@ -21,6 +23,18 @@ static box FuncBodyBasicLowerBox { local s = "" + body_json if !(s.contains("\"version\"")) || !(s.contains("\"kind\"")) { return null } + // 1) Loop priority: delegate to LoopForm lowers if Loop is present + if s.contains("\"type\":\"Loop\"") { + local loop_result = me._try_lower_loop(func_name, box_name, params_arr, s) + if loop_result != null { return loop_result } + // Fail-Fast: Loop present but not supported by selfhost builder + if env.get("HAKO_SELFHOST_TRACE") == "1" { + print("[builder/funcs:unsupported:loopform] func=" + func_name) + } + return null + } + + // 2) Non-Loop processing: Local/If/Return patterns only local lowered = me._try_lower_local_if_return(func_name, box_name, params_arr, s) if lowered != null { return lowered } @@ -37,9 +51,6 @@ static box FuncBodyBasicLowerBox { { local out = LowerIfCompareVarVarBox.try_lower(s); if out != null { return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:if.compare.varvar]") } } { local out = LowerIfCompareBox.try_lower(s); if out != null { return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:if.compare.intint]") } } { local out = LowerReturnIntBox.try_lower(s); if out != null { return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:return.int]") } } - if s.contains("\"type\":\"Loop\"") && env.get("HAKO_SELFHOST_TRACE") == "1" { - print("[builder/funcs:unsupported:loop]") - } return null } @@ -341,4 +352,20 @@ static box FuncBodyBasicLowerBox { } return "{\"functions\":[{\"name\":\"" + target + "\",\"params\":" + params_json + ",\"locals\":[],\"blocks\":[" + blocks + "]}]}" } + + method _try_lower_loop(func_name, box_name, params_arr, body_json) { + // 1) LoopForm の Loop を持つ Program(JSON) であることを軽く確認 + if !(body_json.contains("\"type\":\"Loop\"")) { return null } + + // 2) まず sum_bc 用の lower を試す + { local out = LowerLoopSumBcBox.try_lower(body_json) + if out != null { return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:loop.sum_bc]") } } + + // 3) 次に simple loop 用 lower を試す + { local out2 = LowerLoopSimpleBox.try_lower(body_json) + if out2 != null { return me._rebind(out2, func_name, box_name, params_arr, "[funcs/basic:loop.simple]") } } + + // 4) ここまででダメなら selfhost 側では未対応 + return null + } } diff --git a/tools/smokes/v2/profiles/quick/core/phase251/selfhost_mir_loopform_basic_vm.sh b/tools/smokes/v2/profiles/quick/core/phase251/selfhost_mir_loopform_basic_vm.sh new file mode 100644 index 00000000..905e9674 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase251/selfhost_mir_loopform_basic_vm.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# selfhost_mir_loopform_basic_vm.sh +# - Canary for Phase 25.1b Step3: ensure FuncBodyBasicLowerBox can delegate +# LoopForm-normalized loops to LowerLoopSimpleBox/LowerLoopSumBcBox. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || (cd "$SCRIPT_DIR/../../../../../../.." && pwd))" + +# Create a minimal .hako file with a simple counting loop +TEST_HAKO="$(mktemp --suffix .hako)" +cat > "$TEST_HAKO" <<'HAKO' +static box TestBox { + count() { + local i = 0 + loop(i < 10) { + i = i + 1 + } + return i + } +} + +static box Main { + main() { + return 0 + } +} +HAKO + +OUT_MIR="$(mktemp --suffix .json)" +LOG_OUT="$(mktemp --suffix .log)" +trap 'rm -f "$TEST_HAKO" "$OUT_MIR" "$LOG_OUT" || true' EXIT + +set +e +HAKO_SELFHOST_BUILDER_FIRST=1 HAKO_MIR_BUILDER_FUNCS=1 HAKO_SELFHOST_TRACE=1 NYASH_JSON_ONLY=1 \ + bash "$ROOT_DIR/tools/hakorune_emit_mir.sh" "$TEST_HAKO" "$OUT_MIR" >"$LOG_OUT" 2>&1 +rc=$? +set -e + +# Check logs for LoopForm lower tags +if ! grep -q "\[funcs/basic:loop\." "$LOG_OUT"; then + echo "[FAIL] selfhost_mir_loopform_basic_vm (no [funcs/basic:loop.*] tag found)" >&2 + echo "=== LOG OUTPUT ===" >&2 + cat "$LOG_OUT" >&2 + exit 1 +fi + +# Check MIR(JSON) was generated +if [ $rc -ne 0 ] || [ ! -s "$OUT_MIR" ]; then + echo "[FAIL] selfhost_mir_loopform_basic_vm (MIR generation failed rc=$rc)" >&2 + echo "=== LOG OUTPUT ===" >&2 + cat "$LOG_OUT" >&2 + exit 1 +fi + +echo "[PASS] selfhost_mir_loopform_basic_vm (LoopForm lower delegated successfully)" +exit 0