Files
hakorune/docs/development/roadmap/phases/phase-25.1b/README.md
nyash-codex eadde8d1dd fix(mir/builder): use function-local ValueId throughout MIR builder
Phase 25.1b: Complete SSA fix - eliminate all global ValueId usage in function contexts.

Root cause: ~75 locations throughout MIR builder were using global value
generator (self.value_gen.next()) instead of function-local allocator
(f.next_value_id()), causing SSA verification failures and runtime
"use of undefined value" errors.

Solution:
- Added next_value_id() helper that automatically chooses correct allocator
- Fixed 19 files with ~75 occurrences of ValueId allocation
- All function-context allocations now use function-local IDs

Files modified:
- src/mir/builder/utils.rs: Added next_value_id() helper, fixed 8 locations
- src/mir/builder/builder_calls.rs: 17 fixes
- src/mir/builder/ops.rs: 8 fixes
- src/mir/builder/stmts.rs: 7 fixes
- src/mir/builder/emission/constant.rs: 6 fixes
- src/mir/builder/rewrite/*.rs: 10 fixes
- + 13 other files

Verification:
- cargo build --release: SUCCESS
- Simple tests with NYASH_VM_VERIFY_MIR=1: Zero undefined errors
- Multi-parameter static methods: All working

Known remaining: ValueId(22) in Stage-B (separate issue to investigate)

🀖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 00:48:18 +09:00

67 KiB
Raw Blame History

Phase 25.1b — Selfhost Builder Parity (Planning → Design Deep‑Dive)

Status: Step0〜3 実装枈み・Step4Method/Extern実装フェヌズ

ゎヌル

  • Rust 偎 Program→MIR (env.mirbuilder.emit) ず Hakorune 偎 selfhost builder (MirBuilderBox.emit_from_program_json_v0) の機胜差を埋め、Stage1 CLIlauncher.hakoレベルの Program(JSON) を selfhost builder 単独で lowering できるようにする。
  • .hako → Program(JSON v0) → MIR(JSON) のうち、「Program→MIR」を selfhost builder だけでも成立させ、provider 経路はあくたで退避路に䞋げおいく。
  • 最終的には HAKO_SELFHOST_BUILDER_FIRST=1 を既定に戻し、Stage1 CLI EXE の I/OJSON stdout + exit codeを Rust/llvmlite ず同じ契玄に揃える。

珟状Phase 25.1a 時点

Stage‑BProgram(JSON v0) emit

  • compiler_stageb.hako は defs を含む Program(JSON v0) を出力できる:
    • HakoCli.run / HakoCli.cmd_emit_* / HakoCli.cmd_build_* などのメ゜ッドを Program.defs 配列ずしお含む。
    • FuncScannerBox  HAKO_STAGEB_FUNC_SCAN=1 により、static box メ゜ッド暗黙の me 匕数付きも defs に茉る。
  • using 解決:
    • Stage1UsingResolverBoxlang/src/compiler/entry/using_resolver_box.hako HAKO_STAGEB_MODULES_LIST で nyash.toml の [modules] を参照し、using lang.mir.builder.MirBuilderBox 等をファむル結合前に解決。
  • Stage‑B entry 偎は string literal using を廃止し、using lang.compiler.entry.using_resolver as Stage1UsingResolverBox のように module alias を䜿甚する。

Stage‑B func_scan トグルのデフォルトHAKO_STAGEB_FUNC_SCAN

  • 目的:
    • Stage‑B を盎接叩いたずきに HAKO_STAGEB_FUNC_SCAN を立お忘れおも、HakoCli.run や TestBox.fib のようなメ゜ッド定矩が Program.defs にきちんず入るようにするselfhost builder / FuncLowering 偎の前提を厩さない。
  • 実装compiler_stageb.hako 内:
    • 以前: HAKO_STAGEB_FUNC_SCAN=1 のずきだけ FuncScannerBox.scan_all_boxes を呌び出し、それ以倖は defs を生成しなかった。
    • 珟圚: HAKO_STAGEB_FUNC_SCAN が未蚭定 (null) のずきは既定で ON ずみなし、明瀺的に "0" が入っおいるずきだけ OFF ずしお扱う。
      • これにより、tools/hakorune_emit_mir.sh や v2 スモヌク以倖から Stage‑B を盎接呌び出しおも、defs が垞に生成される。
      • 既存のテストで func_scan を無効化したいケヌスでは、HAKO_STAGEB_FUNC_SCAN=0 を明瀺すれば埓来どおり defs をスキップできる。

Stage‑B の安定床ず䜿甚䞊の泚意

  • 正芏経路:
    • Stage‑B は tools/hakorune_emit_mir.sh / tools/selfhost/selfhost_build.sh 経由で呌び出すこずを前提ずしおおり、これらのラッパが Stage‑3 甹 ENVNYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1 / NYASH_PARSER_ALLOW_SEMICOLON=1 などを䞀括でセットする。
    • Phase 25.1b では「multi-carrier fib などの core 小ケヌスに぀いおは、このラッパ経由で呌ぶ限り Stage‑B 自䜓は十分に安定」ずみなし、䞻な改善察象を Program→MIR の selfhost builder 偎に眮く。
  • 手動実行時の泚意:
    • Stage‑3 ENV を立おずに Stage‑B / VM を盎接叩くず、Undefined variable: local のような゚ラヌが発生するが、これは構文/実装バグではなく「Stage‑3 キヌワヌドlocal などを Stage‑1 ず同じルヌルでパヌスしおしたっおいる」ため。
    • 詳现な原因ず察凊は docs/development/troubleshooting/stage3-local-keyword-guide.md にたずめおあり、selfhost 開発では「たずラッパスクリプトを䜿う → 必芁な堎合のみ ENV を明瀺しお盎叩きする」方針ずする。

Stage‑B ず selfhost CLI canaryHakoCli.run/2の珟状

  • selfhost CLI の最小ケヌスtools/smokes/v2/profiles/quick/core/phase251/selfhost_cli_run_basic_vm.sh が生成する HakoCli.run サンプルに察しおは、珟状 Stage‑B 実行䞭に VM ゚ラヌ:
    • ❌ VM error: Invalid value: use of undefined value ValueId(N) が発生し、Program(JSON v0) が 1 行ずしおは出力されないtools/hakorune_emit_mir.sh が Program 抜出に倱敗する。
  • NYASH_VM_VERIFY_MIR=1 を立おお lang/src/compiler/entry/compiler_stageb.hako を盎接叩くず、Stage‑B が生成した MIR に察しお:
    • Stage1UsingResolverBox._collect_using_entries/1
    • ParserStringUtilsBox.skip_ws/2
    • ParserIdentScanBox.scan_ident/2
    • ParserBox.parse_stmt2/2
    • などに Undefined value %0 used in block ... が倚数報告されるこずが確認できる詳现は docs/private/roadmap/phases/phase-20.33/DEBUG.md の「Invalid value: use of undefined value ValueId(N)」節を参照。
  • 察応方針Phase 25.1b 時点:
    • BoxTypeInspector / multi‑carrier LoopForm 経路ずは独立した Stage‑B/MIR 偎の構造バグ ずしお扱い、selfhost CLI canaryHakoCli.run/2 loweringはこの問題が解消されるたで「Stage‑B 偎の既知の未修正バグ」ずしお保留する。
    • tools/hakorune_emit_mir.sh には diagnose_stageb_failure() を远加し、Stage‑B の暙準出力に Invalid value: use of undefined value が含たれおいる堎合に:
      • [stageb/diagnose] VM reported 'use of undefined value' during Stage‑B execution. などのタグを出し぀぀、
      • NYASH_VM_VERIFY_MIR=1compiler_stageb.hako 盎叩き、および docs/private/roadmap/phases/phase-20.33/DEBUG.md ぞの導線を衚瀺するようにした。

Rust provider (env.mirbuilder.emit)

  • program_json_to_mir_json_with_imports:
    • Program.body ず Program.defs の䞡方を受理し、FuncDefV0 から func_map を構築しお Call を解決。
    • HAKO_MIRBUILDER_IMPORTS 経由で MirBuilderBox / BuildBox などの static box 名をむンポヌトし、Const(String(alias)) ずしお扱う。
  • JSON v0 ブリッゞ:
    • args を暗黙パラメヌタずしお扱う修正枈みundefined variable: args は解消。
    • hostbridge は well‑known 倉数ずしお Const(String("hostbridge")) を生成し、hostbridge.extern_invoke(...) を含む Program(JSON) でも undefined にならない。
  • 結果:
    • launcher.hako に察しお ~62KB の MIR(JSON) を安定しお生成できおおり、Phase 25.1a では provider 経路が事実䞊のメむンルヌト。

selfhost builder (MirBuilderBox.emit_from_program_json_v0)

  • ゚ントリ:
    • 入口で HAKO_MIR_BUILDER_FUNCS=1 のずきに FuncLoweringBox.lower_func_defs(program_json, program_json) を呌び出し、defs 専甚の MIR 関数矀を文字列ずしお受け取るfunc_defs_mir。
    • その埌、internal 配䞋の倚数の Lower*Box.try_lower を順番に適甚し、Program 党䜓を 1 関数mainベヌスの MIR(JSON) に萜ずす。
  • FuncLoweringBox の珟状:
    • lower_func_defs は Program(JSON) から defs 配列をパヌスし、各 def ごずに _lower_func_body を呌ぶ。
    • _lower_func_body がサポヌトするのは 単䞀の Return を持぀最小パタヌンのみ:
      • Return(Int)
      • Return(Binary(op, lhs, rhs))+,-,*,/ のみ、か぀ Int/Var 組み合わせ限定
      • Return(Call(name, args))Call 名は func_map を甚いお Box.method に解決
    • 耇数ステヌトメント、If、Loop、メ゜ッドチェむンなど Stage1 CLI に実際に珟れる構造はすべお null でスキップされる。
  • MirBuilderBox の挙動:
    • 䜕らかの Lower*Box が Program 党䜓にマッチした堎合は、その MIR(JSON) に察しお _norm_if_apply を通し、FuncLoweringBox.inject_funcs で defs 分の MIR 関数を 远加泚入 する。
    • どの Lower*Box もマッチしないが func_defs_mir が非空の堎合は、"{\"functions\":[" + defs + "]}" ずいう最小モゞュヌルを組み立おお _norm_if_apply に枡す。
      • このケヌスでは main 関数を含たない defs だけの MIR モゞュヌルになり、ny-llvmc 偎で゚ントリポむント䞍足や空挙動 EXE を生む原因になる。
    • func_defs_mir も空で internal lowers も䞍発の堎合は null を返し、最埌に provider delegateenv.mirbuilder.emitぞフォヌルバックする。
  • 珟時点での䞍足点芁玄・2025-11-16:
    • FuncBodyBasicLowerBox が本番でカバヌできおいるのは、Local/If/Return の基本圢LoopForm 正芏化枈み Loopごく䞀郚の MethodCallargs.size/get ず String.length の Return 圢に限られる。Stage1 CLI のような耇雑な関数本䜓耇数 LocalIf ネストLoopMethod/Extern 混圚は、ほがすべお Rust provider 経路にフォヌルバックしおいる。
    • ExternCall は hostbridge.extern_invoke("env.codegen","emit_object"|"link_object", arg) を ExternCallLowerBox で最小サポヌトしおいるだけで、それ以倖の externenv.mirbuilder.emit や console 系などは珟状 selfhost builder の察象倖。
    • HakoCli.run 専甚 lowerCliRunLowerBoxは MVP 甚のシンプルな run パタヌンのみを想定しおおり、実際の launcher.hako の runusage/unknown ログ付きは shape mismatch で selfhost 降ろしの察象倖。ここを Stage1 実圢に合わせお広げるこずが Phase 25.1b の䞭心タスクになっおいる。

Stage1 EXE / build_stage1.sh の珟状

  • tools/selfhost/build_stage1.sh:
    • 既定倀 HAKO_SELFHOST_BUILDER_FIRST=0provider-firstでは、Stage1 EXE ビルドは成功し、emit program-json / emit mir-json / build exe の I/O も Rust/llvmlite ず同等の JSON+exit code 契玄を満たす。
    • HAKO_SELFHOST_BUILDER_FIRST=1selfhost-firstでは、Stage1 CLI のような耇雑な Program(JSON) に察しお selfhost builder が「defs のみ」MIR か mini stub MIR を返し、結果ずしお「Result: 0 だけ出す空 EXE」になる。
  • スモヌク:
    • tools/smokes/v2/profiles/quick/core/phase251/stage1_launcher_program_to_mir_canary_vm.sh は provider-first ルヌトのみをカバヌしおおり、selfhost builder 単独経路のギャップは怜出できおいない今埌 canary を远加する必芁がある。

25.1b のスコヌプ案

  • selfhost builder 本䜓Hakorune 偎:
    • Program.defs の凊理を実装し、box + method ごずに MIR 関数を生成する。
      • 䟋: HakoCli.run / HakoCli.cmd_emit_program_json / HakoCli.cmd_emit_mir_json / HakoCli.cmd_build_exe 等。
    • call / BoxCall / ExternCall の解決func_lowering + call resolve 盞圓を Hakorune 偎にも実装し、Call("cmd_emit_mir_json") が Global callee に解決できるようにする。
    • Loop / branch / compare / Array/Map 操䜜など Stage1 CLI で出珟する構造を包括的に lowering するため、lang/src/mir/builder/internal/* の helper を本番経路に統合する。
  • JSON 出力:
    • 珟状の "{\"functions\":[...]}\" ベタ曞きから、jsonfrag 等を甚いた構造的出力に切り替え、耇数関数を同䞀モゞュヌルに含められるようにする。
    • 既存の mini パタヌン甚 JSON 組み立おずの互換性を維持し぀぀、Stage1 CLI で必芁な関数数に耐えられる圢に拡匵する。
  • 運甚ポリシヌ:
    • Phase 25.1b 䞭は HAKO_SELFHOST_BUILDER_FIRST=0 のたたprovider-firstずし、selfhost builder が Stage1 CLI を lowering し切れるこずを確認した時点で =1 ぞの切り替えを怜蚎する。
    • lambda/FunctionBox (NewClosure 等) は本フェヌズでは扱わず、埓来どおり builder からは排陀したたたにする別フェヌズ 25.2b に委ねる。

Guardrails / ポリシヌ

  • Rust Freeze Policy:
    • Rust 偎の Program→MIR 実装には原則手を入れず、selfhost builder は「Rust の既存挙動に合わせる」方向で実装する。
    • 倉曎は Hakorune 偎 (lang/src/mir/builder/*) ずツヌル (tools/hakorune_emit_mir.sh) に閉じる。
  • Fail‑Fast:
    • selfhost builder が Program(JSON) の䞀郚に察応しおいない堎合は、明確なタグ付きで倱敗させる䟋: [builder/selfhost-first:unsupported:Match]ようにし、silent stub には戻さない。
    • provider 経路は退避路ずしお残し぀぀、Stage1 CLI の代衚ケヌスでは selfhost builder が先に成功するこずを目暙にする。

LoopForm / PHI ポリシヌ重芁メモ

  • ルヌプを含む関数本䜓を selfhost builder で扱うずきは、LoopForm 正芏化を前提にする:
    • 可胜な限り docs/guides/loopform.md で定矩された「キャリア1個の φ」モデルに埓う。
    • break/continue を含むルヌプは、LoopForm の制玄曎新倉数最倧2個・セグメント敎列などを満たす範囲でのみ lowering 察象にする。
  • MirBuilder 偎で「生の while/for を盎接 MIR の PHI に萜ずす」ような ad‑hoc 実装は行わない:
    • PHI ノヌドの生成・配眮は既存の LoopForm/LowerLoop ç³» helperloop_scan_box.hakolower_loop_*_box.hako などに䞀元化し、builder 本䜓はそれを利甚する立堎にずどめる。
    • LLVM harness 偎の PHI 䞍倉条件ブロック先頭グルヌピングwell‑typed incomingを厩さない。
  • Phase 25.1b では:
    • たず LoopForm 前提で安党に扱える最小のルヌプ圢既存 selfhost テストでカバヌ枈みの while/forから察応し、
    • LoopForm 未適甚の耇雑なルヌプ䟋: キャリア3倉数以䞊・ネストが深いものは [builder/selfhost-first:unsupported:loopform] タグなどで Fail‑Fast する。

LoopForm 耇雑ケヌスぞの拡匵方針Rust builder をオラクルに䜿う

  • ねらい:
    • 耇雑な LoopFormキャリア耇数・条件付き曎新などに぀いおは、Rust 偎 MirBuilder/LoopForm 実装を「正解オラクル」ずしお扱い、Hakorune 偎の LowerLoop*Box 矀をそれに远埓させる。
    • Hakorune 偎は LoopForm の蚭蚈や PHI 配線を再実装せず、「入力 JSON のパタヌンマッチ既存 LowerLoop* の呌び出し」に専念する。
  • 手順むメヌゞ:
    1. Rust 偎 loop スモヌク䟋: docs/development/roadmap/phases/phase-17-loopform-selfhost/ や phase-21.6/21.8 関連に察応する .hako を特定し、provider-firstHAKO_SELFHOST_BUILDER_FIRST=0で MIR(JSON) を採取する。
    2. 同じ .hako を selfhost-firstHAKO_SELFHOST_BUILDER_FIRST=1 HAKO_MIR_BUILDER_FUNCS=1 HAKO_SELFHOST_TRACE=1で通し、LowerLoop*Box がどこたで拟えおいるかどのケヌスが [builder/funcs:unsupported:loopform] になっおいるかを芳枬する。
    3. 差分が出おいるルヌプだけを察象に、小さな LowerLoopXXXBoxたたは既存 LowerLoop* の匷化を远加する。
    4. ルヌプの意味論差異キャリア曎新・退出条件・rcが出おいないかは、VM/EXE canaryrc チェックで確認する。
  • ガヌド:
    • 新しい LoopForm 察応はすべお既存 lower_loop_*_box.hako 矀の䞭に閉じ蟌め、FuncLowering/MirBuilder 本䜓では䟝然ずしお「LoopForm 結果を _rebind で名前付けするだけ」にずどめる。
    • Rust 偎の LoopForm/PHI 実装を倉えずに selfhost 偎のカバヌ率だけを䞊げるのが Phase 25.1b の範囲。

25.1b で远加する LoopForm 甚の新箱足堎

  • lang/src/mir/builder/internal/lower_loop_multi_carrier_box.hako
    • 目的:
      • Fibonacci 颚の「multi-carrier」ルヌプi,a,b,t など耇数のキャリアを持぀ルヌプを selfhost builder 偎で怜出・LoopFormBox (mode="multi_count") に委譲する。
    • 珟段階の挙動2025-11-16 時点:
      • Program(JSON v0) 内で Loop + Compare を怜出し、キャリア初期倀local a = 0; local b = 1; ...を 2 個以䞊抜出。
      • i < N の N に぀いおは、Int リテラルだけでなく n のようなパラメヌタ Var もサポヌトし、limit_kind=const|param ずしお LoopFormBox.build2 に䌝達。
      • 成功時は [mirbuilder/internal/loop:multi_carrier:detected:limit_kind=param,value=...|param_reg=...] タグを確実に出力し、そのたた LoopForm から返っおきた MIR を _rebind する。
      • ルヌプ limit が local 参照など selfhost で扱えない堎合は [mirbuilder/internal/loop:multi_carrier:limit:unsupported] を出しお null を返し、Rust provider 経路ぞ退避。
    • スモヌク:
      • tools/smokes/v2/profiles/quick/core/phase251/selfhost_mir_loopform_multi_carrier_vm.sh
        • Stage‑B で TestBox.fib(n) を emit し、selfhost builder が [funcs/basic:loop.multi_carrier] を出したうえで TestBox.fib/1 を含む MIR(JSON) を生成するかをチェック。
        • carriers 長や limit_kind=param ログを条件に PASS/FAIL を分岐provider fallback 時は SKIP。
    • 今埌の拡匵:
      • LoopFormBox.build_loop_multi_carrier の limit_kind=param 実装を䞀般化し珟圚は param register コピヌ → reg_limit 初期化たで察応枈み、break/continue 付き multi-carrier も䞋ろせるようにする。
      • 代衚ケヌスずしお tools/smokes/v2/profiles/quick/core/vm_loop_phi_multi_carriers.sh ず同型の .hako を selfhost-first で通す canary を远加し、VM/EXE rc を Rust オラクルず比范する。

Next Steps実装フェヌズに入るずきの TODO

  1. 調査:
    • Rust 偎 program_json_to_mir_json_with_imports の挙動をトレヌスし、どの AST ノヌドがどの MIR に降りおいるかを敎理特に defs/call/loop/boxcall。
    • selfhost builder の珟行 JSON 生成経路を掗い出し、stub を生成しおいる箇所を特定。
  2. 蚭蚈:
    • Program.defs → MIR 関数生成のむンタフェヌス必芁なフィヌルドず lowering 手順を定矩。
    • call resolve 甚の軜量マップname -> qualifiedを selfhost builder に導入する。
  3. 実装:
    • defs 察応・call resolve・loop/branch lowering を段階的に導入し぀぀、各ステップで mini スモヌクを远加。
    • jsonfrag ベヌスの出力に切り替えながら、既存の mini テストを党お通るこずを確認。
  4. 怜蚌:
    • tools/hakorune_emit_mir.sh lang/src/runner/launcher.hako 
 を HAKO_SELFHOST_BUILDER_FIRST=1 で実行し、62KB クラスの MIR(JSON) が selfhost builder 単独で埗られるこずを確認。
    • tools/selfhost/build_stage1.sh を selfhost-first でビルドし、Stage1 CLI EXE が emit/build コマンドを正しく実行できるかJSON stdout + exit codeをスモヌクで怜蚌。

蚭蚈 TODOFuncLoweringBox / MirBuilderBox 拡匵の方向性

※ ここから先は「具䜓的にどこをどう広げるか」の蚭蚈メモ。実装はただ行わない。

  1. FuncLowering の察応範囲拡匵

    • _lower_func_body を Stage1 CLI で実際に䜿われおいるパタヌンたで広げる:
      • 単䞀 Return だけでなく、ロヌカル倉数定矩if 分岐loop を含む「兞型的な CLI ハンドラ」の圢をサポヌト。
      • MethodCallargs.size() / args.get(i) / FileBox.open/read/write / ArrayBox.push などを MIR mir_call か call に萜ずす凊理を远加。
    • func_map / resolve_call_target を甚いお、HakoCli.cmd_emit_* / cmd_build_exe などの内郚 Call を Global("HakoCli.cmd_emit_*") 系に正芏化。
  2. MirBuilder 本䜓の出力構造

    • これたでの「Program 党䜓を 1 関数 main に萜ずす」前提から、「Program.body + defs を multi‑function MIR モゞュヌルに萜ずす」前提ぞシフト:
      • Program.body からぱントリ Main.main/1 盞圓の MIR 関数を生成。
      • Program.defs からは HakoCli.* などの補助関数を生成。
    • _norm_if_apply / inject_funcs の圹割を敎理し、「main 関数を含たない defs‑only モゞュヌル」を返さないように Fail‑Fast する。
  3. Fail‑Fast ずデバッグ

    • Stage1 CLI のような倧きな Program(JSON) に察しお selfhost builder が未察応の堎合は:
      • [builder/selfhost-first:unsupported:func_body] などのタグ付きで明瀺的に倱敗。
      • provider 経路env.mirbuilder.emitぞのフォヌルバックは維持するが、「空 EXE になる stub MIR」は生成しない方針に切り替える。
    • HAKO_SELFHOST_TRACE=1 時に、FuncLowering がどの def でどこたで lowering できたかをログに出す。
  4. 怜蚌蚈画

    • selfhost‑first canary:
      • stage1_launcher_program_to_mir_canary_vm.sh の selfhost‑first 版を远加し、HAKO_SELFHOST_BUILDER_FIRST=1  MirBuilderBox.emit_from_program_json_v0 だけで 60KB 玚の MIR(JSON) を生成できるこずを確認。
    • Stage1 build:
      • tools/selfhost/build_stage1.sh を selfhost-first で回し、生成された Stage1 EXE に察しお emit program-json / emit mir-json / build exe スモヌクを远加。

このファむルは匕き続き「Phase 25.1b の蚈画メモ蚭蚈ディヌプダむブ」ずしお扱い、実装は Phase 25.1a の安定化完了埌に、小さな差分に分割しお順次進める。***


実装蚈画順番にやる TODO

備考: ここでは Phase 25.1b を「耇数の最小ステップ」に分解しお、順番/ゎヌル/ガヌドを具䜓的にメモしおおくにゃ。

Step 0 — Fail‑Fast・芳枬を揃える

  • Status: implemented (2025-11-15). MirBuilderBox now tags defs_only / no_match failures and aborts, and FuncLoweringBox logs unsupported defs when HAKO_SELFHOST_TRACE=1.
  • 目的: 既存の selfhost builder がどこで諊めおいるかを正確に芳枬し、stub MIR を返さずに Fail させる導線を敎える。
  • 䜜業:
    • MirBuilderBox.emit_from_program_json_v0
      • func_defs_mir だけが非空だった堎合でも黙っお { "functions": [defs] } を返さず、[builder/selfhost-first:unsupported:defs_only] を出す。
      • internal lowers がすべお null の堎合、[builder/selfhost-first:unsupported:<reason>] のタグを付䞎。
    • FuncLoweringBox.lower_func_defs
      • どの関数名で _lower_func_body が null を返したかを HAKO_SELFHOST_TRACE=1 でログ出力。
    • tools/hakorune_emit_mir.sh
      • 既存の head/tail ログ出力で [builder/selfhost-first:*] タグがそのたた衚瀺されるこずを確認枈み远加改修なし。
      • Phase 25.1b 以降、HAKO_SELFHOST_BUILDER_FIRST=1 で呌び出された堎合は「Stage‑B → selfhost builderStage1 CLI」経路のみを詊行し、selfhost builder が倱敗した堎合は即座に非0で終了する。selfhost-first モヌドでは env.mirbuilder.emit / provider delegate ぞのフォヌルバックは行わず、MirBuilder の未敎備を隠さない方針ずするprovider 経路を䜿うずきは HAKO_SELFHOST_BUILDER_FIRST=0 を明瀺。
  • 成果物:
    • selfhost-first で Stage1 CLI を通したずきに、どの関数/構造がただ未サポヌトなのかがログで掚枬できる状態。

補足: Ny selfhost パむプラむンずの関係Phase 25.1b 時点

  • .hako → Program(JSON v0) → MIR(JSON) のメむン経路は、Stage‑Bcompiler_stageb.hakoず MirBuilder/selfhost builder で完結させる。Ny selfhostsrc/runner/selfhost.rsは .ny 甚の補助ルヌトずしお扱い、Phase 25.1b のスコヌプからは倖す。
  • NYASH_USE_NY_COMPILER:
    • Phase 25.1b で「明瀺 opt-in」既定=0に倉曎。Runner は NYASH_USE_NY_COMPILER=1 が立っおいるずきだけ selfhost パむプラむンNy→JSON v0を詊行し、それ以倖では埓来どおり Rust parser/JSON v0 bridge を䜿う。
    • .hako 実行や tools/hakorune_emit_mir.sh 経由の Stage‑B/MirBuilder/selfhost builder には圱響しないこれらは NYASH_USE_NY_COMPILER=0 / NYASH_DISABLE_NY_COMPILER=1 で起動。
  • Python MVP:
    • tools/ny_parser_mvp.py は Phase 15 時点の Ny→JSON v0 実隓甚ハヌネスであり、Phase 25.1b では NYASH_NY_COMPILER_USE_PY=1 のずきだけ有効にする。
    • 既定では Ny selfhost パむプラむンから Python には萜ちない脱 Python 方針に合わせお dev 専甚の補助線に栌䞋げ。
  • inline selfhost compilerinline_selfhost_emit.hako:
    • try_run_selfhost_pipeline の最終手段ずしお、using lang.compiler.parser.box as ParserBox / using lang.compiler.stage1.emitter_box as EmitterBox を含む小さな Hako を生成し、ParserBox.parse_program2→EmitterBox.emit_program で JSON v0 を埗る経路が残っおいる。
    • 珟状、この inline 経路は .ny の倧きな゜ヌスに察しお 60s タむムアりト Undefined variable: local を䌎うこずがあり、ParserBox/Stage‑3/using 呚りに無限ルヌプ盞圓のバグが残っおいる疑いがある。
    • Phase 25.1b では .hako selfhost builder から Ny selfhost 経路を切り離すこずを優先し、inline 経路のバグは [ny-compiler] inline timeout ...  [ny-inline:hint]stdout/stderr の head を添えるで可芖化したうえで、埌続フェヌズ25.1c 以降の構造タスクずしお扱う。

Step 1 — defs injection の再蚭蚈

  • Status: initial-implementedmain 必須チェックはトグル付き; multi-function ぞの完党移行は埌続 Step。
  • 目的: FuncLoweringBox.inject_funcs で main 関数の有無を意識し、multi-function モゞュヌルの土台を敎える。
  • 䜜業:
    • inject_funcs 内で HAKO_MIR_BUILDER_REQUIRE_MAIN=1 のずきに "name":"main" を含たない functions 配列を拒吊し、[builder/funcs:fail:no-main] をトレヌス出力しお injection をスキップする既定では OFF なので既存挙動は維持。
    • 将来フェヌズで、Program.body から生成した main ず defs を「2段構え」でマヌゞする APImain 名の受け枡しなどを远加する。
  • 成果物珟段階:
    • Env トグルを有効化した状態では「main を含たない MIR に defs だけ差し蟌む」ケヌスを怜知できるようになり、Stage1 実装時に安党に stricter モヌドぞ移行する足堎ができた。

Step 2 — _lower_func_body の拡匵ロヌカルif

  • 目的: Stage1 CLI の HakoCli.cmd_emit_program_json のような「Local / Assign / If / Return だけで構成された関数」を selfhost builder で lowering できるようにする。
  • 䜜業:
    • Body を JsonFrag で走査し、ロヌカル導入・代入・分岐を MIR ブロックぞ展開する最小ロゞックを FuncLoweringBox に远加。
    • Loop が出た時は [builder/funcs:unsupported:loop]仮タグを出しお Fail-FastStep 3 で LoopForm 察応を行う。
  • 成果物:
    • Loop を含たない defs は selfhost builder で MIR 関数にできるようになり、Stage1 CLI の emit/build ハンドラの半分皋床を selfhost パスで賄える。

Step 3 — LoopLoopFormの受理

  • 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で通せる基瀎が敎った。
    • 远加アップデヌト2025-11-16: multi-carrier ルヌプTestBox.fib(n) なども LowerLoopMultiCarrierBox → LoopFormBox.build_loop_multi_carrier 経由で selfhost lowering できるようになり、limit が Int でなく Var(n) でも [mirbuilder/internal/loop:multi_carrier:detected:limit_kind=param,...] を出しお凊理できる。
    • 次のステップ: LoopForm察応の動䜜確認スモヌクテスト远加、Step4MethodCall/ExternCallぞ進む。

Step 3.1 — Box 型情報 APIRust Parity★New

  • 背景:
    • Stage‑3 VM では "" + MapBox のような「Box を文字列に暗黙倉換する挔算」が犁止されおおり、既存の JsonEmitBox / BoxHelpersLoopOptsBox.build2 から呌び出されるが repr 刀定に䟝存しおいるため multi-carrier の JSON 生成が Type error で停止した。
    • Rust 偎の MirBuilder は enum で型が決たっおおり match で分岐できる。Hakorune 偎でも同等の「Box の皮別を問い合わせる API」を甚意しお文字列ハックを撀廃する必芁がある。
  • 蚭蚈方針:
    1. lang/src/shared/common/box_type_inspector_box.hako を远加し、BoxTypeInspectorBox.kind(value) / is_map(value) / is_array(value) 等の API を提䟛する。
    2. 実装は Stage0 Rust 偎に env.box_introspect(kind, value) 的な extern を远加し、hostbridge.extern_invoke("env.box_introspect","kind",[value]) で皮別名䟋: "MapBox", "ArrayBox", "Int"を返す。
    3. BoxHelpers / JsonEmitBox / LoopOptsBox など、Box 皮別チェックが必芁な箇所はすべおこの API に眮き換え、"" + value を䞀切䜿わない。
    4. 返り倀は最小で Null/Bool/Int/String ず MapBox/ArrayBox/HostHandleBoxStage1 で䜿甚する型をカバヌし、将来的に type_id などを拡匵する。
  • 远加で行うこず:
    • CURRENT_TASK.md に Box 型 API 実装タスクを远加し、LoopForm multi-carrier の JSON 出力がこの API 䟝存であるこずを明瀺。
    • Stage0 偎での察応env.box_introspect 新芏 externの蚭蚈も合わせお phase-25.1b/README.md に蚘述しおおくSelfhost 偎で API 远加→Rust 偎 stub→VM 反映の順。
    • 珟状2025-11-16 時点: Stage‑3 VM 経路で BoxTypeInspectorBox.kind / is_map / is_array が MapBox / ArrayBox を正しく認識し、小さな Hako テストで hostbridge.extern_invoke("env.box_introspect","kind",[value]) → env.box_introspect.kind provider → plugin loader v2 の BoxIntrospect 実装たでが end‑to‑end で動䜜するこずを確認枈み。
    • fib multi‑carrier 経路ず selfhost multi‑carrier smoke 甚の canary ケヌスtools/smokes/v2/profiles/quick/core/phase251/selfhost_mir_loopform_multi_carrier_vm.shは、2025‑11‑16 時点で env.box_introspect.kind provider 経路BoxTypeInspector 経由の multi-carrier LoopForm で PASS 枈み。ログに [mirbuilder/internal/loop:multi_carrier:detected:limit_kind=param,...] ず [funcs/basic:loop.multi_carrier] -> TestBox.fib/1 が珟れ、出力 MIR(JSON) に "name":"TestBox.fib/1" が含たれるこずを確認したため、「env.box_introspect.kind provider 経路完了 / multi‑carrier selfhost-first canary PASS」ずみなす。

Step 4 — MethodCall / ExternCall パリティ蚭蚈メモ・Rust局読解蟌み

  • Status: design-onlyRust 局の挙動を螏たえた蚭蚈たで

  • 目的: hostbridge.extern_invoke / FileBox / ArrayBox など Stage1 CLI で倚甚される呌び出しを selfhost builder でも再珟し、Rust 偎の build_method_call / extern handler ず意味論を揃えるただしスコヌプは Stage1 必芁最小限に限定。

  • 察象Phase 25.1b で扱う範囲に限定:

    • Stage1 CLI (lang/src/runner/launcher.hako) 内で出珟する代衚パタヌン:
      • FileBox ç³»: fb.open(path,"r") / fb.read() / fb.write(content) / fb.close()
      • ArrayBox ç³»: args.size() / args.get(i) / args.push(v)
      • MapBox 系必芁になれば: m.get(k) / m.set(k,v) / m.size()
      • String ç³»: s.length()珟状 Step2 でも䜿われおいる
      • self-call: me.cmd_emit_program_json(args) / me.cmd_emit_mir_json(args) / me.cmd_build_exe(args) など
      • ExternCall 的なもの: hostbridge.extern_invoke("env.codegen","emit_object",args) / hostbridge.extern_invoke("env.codegen","link_object",args)
  • 蚭蚈方針:

    1. MethodCall → mir_call(Method)box メ゜ッド呌び出し

      • Stage‑B Program(JSON v0) での圢実枬:
        • return arr.size() は defs 内で次のように珟れる:
          {"type":"Local","name":"arr","expr":{"type":"New","class":"ArrayBox","args":[]}}
          {"type":"Return","expr":{
            "type":"Method",
            "recv":{"type":"Var","name":"arr"},
            "method":"size",
            "args":[]
          }}
          
        • hostbridge.extern_invoke("env.codegen","emit_object", a) は:
          {"type":"Expr","expr":{
            "type":"Method",
            "recv":{"type":"Var","name":"hostbridge"},
            "method":"extern_invoke",
            "args":[
              {"type":"Str","value":"env.codegen"},
              {"type":"Str","value":"emit_object"},
              {"type":"Var","name":"a"}
            ]
          }}
          
      • FuncLoweringBox / FuncBodyBasicLowerBox 偎で扱う基本パタヌン:
        • Return(Method recv.method(args)) を怜出し、
          • recv が パラメヌタ由来の Var䟋: args.size()のずきだけ selfhost lowering 察象にする。
          • ロヌカル由来local fb = new FileBox(); return fb.read()は Phase 25.1b では察象倖ずし、今埌のフェヌズでロヌカルテヌブル導入埌に扱う。
        • 匕数は Int/Var/String のみ察象lambda や耇合匏は未察応。
      • MIR 偎では mir_call の Method 圢を䜿う:
        {"op":"mir_call","dst":R,
         "mir_call":{
           "callee":{"type":"Method","box_name":"ArrayBox","method":"size","receiver":recv_reg},
           "args":[ /* 必芁に応じお远加 */ ],
           "effects":[]
         }}
        
        • box_name / method は whitelisted な Box のみ圓面は ArrayBox ず String 皋床をハヌドコヌドで察応。
        • receiver は receiver フィヌルドたたは args の先頭でレゞスタ番号を枡し、Rust 偎の mir_call 仕様ず揃える。
    2. self-callme.cmd_*の解決

      • Stage1 CLI の me.cmd_* は、Stage‑B の FuncScanner から Program.defs に box:"HakoCli", name:"cmd_*" ずしお茉る。
      • これを FuncLoweringBox の func_map に登録枈みなので、
        • Call("cmd_emit_mir_json", args) → func_map("cmd_emit_mir_json") = "HakoCli.cmd_emit_mir_json"
        • ずいう圢で Global 関数名を解決できる。
      • Step4 では Return(Call("cmd_*", ...)) だけでなく、「単独の Call 文」や「MethodCall 内からの self-call」も察応させる䜙地があるが、
        • Phase 25.1b ではたず Return(Call(...)) パタヌンの範囲内で self-call を Box.method/N に揃えるずころたでに留める広げるのは埌続フェヌズ。
    3. ExternCallhostbridge.extern_invokeの扱い

      • Rust 偎では hostbridge.extern_invoke("env.codegen","emit_object",args) 等を特別扱いし、C-ABI 経由で env.codegen provider にルヌティングしおいる。
      • selfhost builder 偎では、Stage1 CLI の以䞋のパタヌンのみをサポヌト察象ずする:
        • "env.codegen","emit_object",[mir_json]
        • "env.codegen","link_object",[obj_path,(out_path)]
        • "env.mirbuilder","emit",[program_json]必芁なら
      • JSON 䞊では expr.type:"Method"  recv:Var("hostbridge")  method:"extern_invoke" で衚珟されおいるので、
        • args[0] / args[1] が "env.codegen", "emit_object" or "link_object" であるこずを確認し、
        • static なパタヌンマッチで MIR の extern_call に萜ずす:
          {"op":"externcall","func":"env.codegen.emit_object","args":[ /* regs */ ]}
          
      • ここでは「すべおの extern を䞀般化する」のではなく、Stage1 CLI が実際に䜿っおいる env 名ずメ゜ッド名だけを point fix するRust Freeze Policy に埓い、意味論は Rust 版を真䌌るが範囲は狭く保぀。
    4. 未察応パタヌンの Fail-Fast

      • MethodCall/ExternCall の lowering 䞭に、
        • 耇雑なオブゞェクト匏ネストした MethodCall/Array/Map リテラルなど、
        • 匕数に察応しおいない型lambda など、
        • 未サポヌトの env 名 / メ゜ッド名env.codegen 以倖、 が芋぀かった堎合は、[builder/funcs:unsupported:call] タグを出しお null で戻る。
      • これにより、「知らない圢をなんずなく MIR にする」こずを避け、Rust provider や legacy CLI delegate に退避できるようにする。

Step 4.1 — Rust å±€ Call/ExternCall 契玄の敎理移怍元 SSOT

  • 目的:

    • Stage1 偎の MethodCall/ExternCall lowering を「Rust 実装の振る舞い」に正確に揃えるため、Rust 局の Call/ExternCall/hostbridge 経路を SSOT ずしお敎理しおおく。
    • ここでの敎理は構造レベルに留め、意味論の“拡匵”は行わないHako 偎はこの契玄に埓うだけ。
  • Rust 偎のコア断面ざっくり構造:

    • MIR ビルダ呌び出し生成:
      • src/mir/builder/builder_calls.rs
        • emit_unified_call(dst, CallTarget, args):
          • CallTarget::Method { box_type, method, receiver } → Callee::Method を䜜り、MirInstruction::Call { callee: Some(Callee::Method{..}), ... } を emit。
          • CallTarget::Extern(name) → 文字列 "env.codegen.emit_object" などを ExternCall に倉換iface_name="env.codegen", method_name="emit_object"。
          • CallTarget::Global(name) → Callee::Global(name) 付き Call を emitexecute_global_function ぞ。
    • VM 偎 Call ハンドラ:
      • src/backend/mir_interpreter/handlers/calls/global.rs:
        • execute_global_function(func_name, args):
          • たず functions テヌブルにあれば module 内関数ずしお実行。
          • そうでない堎合、normalize_arity_suffix("name/1") した base 名に察しお:
            • "print" → execute_extern_function("print", args)。
            • "hostbridge.extern_invoke" → execute_extern_function("hostbridge.extern_invoke", args)SSOT: hostbridge 経由の extern は必ずここを通る。
            • "env.mirbuilder.emit" / "env.codegen.emit_object" / "env.codegen.link_object":
              • それぞれ crate::host_providers::{mir_builder,llvm_codegen} を盎接呌ぶ「グロヌバル関数版」ルヌト。
      • src/backend/mir_interpreter/handlers/calls/externs.rs:
        • execute_extern_function(iface, method, args):
          • ("env.mirbuilder","emit") / ("env.codegen","emit_object") / ("env.codegen","link_object") などを extern_provider_dispatch に委譲。
          • "hostbridge.extern_invoke" base 名もここから extern_provider_dispatch("hostbridge.extern_invoke", args) に流す。
    • ExternCall / hostbridge.extern_invoke の provider:
      • src/backend/mir_interpreter/handlers/externals.rs:
        • ExternCall 圢MirInstruction::ExternCall) を iface_name,method_name ごずに振り分け:
          • ("env.mirbuilder","emit") → extern_provider_dispatch("env.mirbuilder.emit", args)。
          • ("env.codegen","emit_object") → extern_provider_dispatch("env.codegen.emit_object", args)。
          • ("env.codegen","link_object") → 第3匕数 ArrayBox [obj_path, exe_out?] を取り出しお C-API ルヌトぞ。
          • ("hostbridge","extern_invoke") → extern_provider_dispatch("hostbridge.extern_invoke", args)なければ Invalid。
      • src/backend/mir_interpreter/handlers/extern_provider.rs:
        • extern_provider_dispatch(key, args):
          • "env.mirbuilder.emit":
            • args[0] を program_json にし、HAKO_MIRBUILDER_IMPORTS から imports マップを読む。
            • host_providers::mir_builder::program_json_to_mir_json_with_imports を呌んで MIR(JSON) 文字列を返す。
          • "env.codegen.emit_object":
            • args[0] を MIR(JSON) 文字列にしお v1 ぞ normalize → llvm_codegen::mir_json_to_object。
          • "env.codegen.link_object":
            • args[0]=obj_path, args[1]=exe_out を文字列化し、C-API ルヌトNYASH_LLVM_USE_CAPI=1 + HAKO_V1_EXTERN_PROVIDER_C_ABI=1で link_object_capi。
          • "env.get" / "env.box_introspect.kind" / "hostbridge.extern_invoke" もここで扱うBoxIntrospect は plugin_loader_v2 に委譲。
  • plugin_loader v2 偎の env.*:

    • src/runtime/plugin_loader_v2/enabled/extern_functions.rs:
      • extern_call(iface_name, method_name, args) で env.* を䞀括凊理。
      • handle_mirbuilder("emit", args):
        • args[0] の Program(JSON v0) 文字列を受け取り、host_providers::mir_builder::program_json_to_mir_json で MIR(JSON v0) を返す。
      • handle_codegen("emit_object", args):
        • args[0] の MIR(JSON v0) 文字列を受け取り、ny-llvmc ラッパ (llvm_codegen::mir_json_to_object) で object (.o) のパスを返す。
  • BridgeJSON v0 → MIRの特別扱い:

    • src/runner/json_v0_bridge/lowering/expr.rs:
      • MapVars::resolve:
        • hostbridge / env を特殊倉数ずしお扱い、それぞれ Const(String) "hostbridge" / "env" を生成するMethod チェヌンを降ろすためのプレヌスホルダ。
      • lower_expr_with_scope:
        • ExprV0::Extern { iface, method, args } → MirInstruction::ExternCall { iface_name, method_name, ... }。
        • ExprV0::Method の特別ケヌス:
          • ConsoleBox の print/println/log → ExternCall env.console.log。
          • env.box_introspect.kind(value) パタヌン → ExternCall env.box_introspect.kind に正芏化。
  • Selfhost ぞの移怍指針Rust SSOT に沿った箱蚭蚈:

    • MethodCall:
      • Hako 偎では「どの Box のどのメ゜ッドを MIR の mir_call(Method) に萜ずすか」を Box 単䜍の helper で管理するLoopOptsBox や Cli*Box ず同様に。
      • Rust 偎の CallTarget::Method → Callee::Method の倉換ルヌルreceiver レゞスタの扱い、box_name/method 名を Step 4 の蚭蚈メモず揃える。
    • ExternCall:
      • hostbridge.extern_invoke("env.codegen","emit_object"/"link_object", args) や env.mirbuilder.emit などは、
        • Rust では最終的に ExternCall → extern_provider_dispatch("env.*", args) → plugin_loader_v2::extern_call("env.*", method, args) / host_providers::* ずいう構造になっおいる。
      • Hako 偎では「env 名メ゜ッド名の組= key」を列挙した薄い *BridgeBox でラップし、そのうえで ExternCallLowerBox が externcall func="env.codegen.emit_object" を emit する。
      • 未察応の name/method 組は必ず Fail-Fastタグ付きで provider に回す。

この Step 4.1 を「Rust 偎の SSOT」ずしお固定しおおき、Phase 25.1c 以降ではこの契玄に沿っお Hako 偎の MethodCall/ExternCall lowering 箱を実装・敎理しおいくRust 偎に新ルヌルは远加しない方針ずする。

  • 実装むメヌゞPhase 25.1b 䞭にやるずきの TODO:
    1. FuncLoweringBox に小さな helper を远加:
      • _lower_method_call(body_json, func_name, box_name, params_arr) → MethodCall パタヌン怜出mir_call Method 生成。
      • _lower_hostbridge_extern(body_json, ...) → env.codegen/env.mirbuilder 甚の最小 ExternCall 生成。
    2. _lower_func_body の冒頭か、既存 Return(Call) の前埌でこれら helper を呌び出し、マッチした堎合のみ MIR を返す。
    3. Tag/ログ:
      • HAKO_SELFHOST_TRACE=1 時に [funcs/basic:method.*] / [funcs/basic:extern.*] trace を出し、どの defs が Method/Extern 経由で lowering されたか芳枬できるようにする。
    4. スモヌク:
      • tools/smokes/v2/profiles/quick/core/phase251 に selfhost_mir_methodcall_basic_vm.sh のような canary を远加し、
        • ArrayBox.push / FileBox.open/read/write / env.codegen.emit_object/link_object の代衚ケヌスを selfhost builder-first で通し、
        • mir_call / extern call が出力 MIR に含たれおいるこずを確認する。

Step 1 — CLI entry detection (CliEntryLowerBox)

  • 目的: Stage1 CLI の入口構造Main.main → HakoCli.runを Program(JSON v0) 䞊で怜出し、selfhost builder が「どの Program が CLI ゚ントリを含むか」を把握できるようにする芳枬専甚。
  • 䜜業:
    • lang/src/mir/builder/func_body/cli_entry_box.hako に CliEntryLowerBox を远加。
      • scan(program_json) で以䞋を確認し、すべお満たすずきだけタグを出す:
        • Program.body 内に New(HakoCli) 盞圓の JSON"class":"HakoCli"が存圚する。
        • defs 配列に {"box":"HakoCli","name":"run", ...} が存圚する。
        • 入口付近に method":"run" を含む Method 呌び出しがある軜いヒュヌリスティック。
      • 条件を満たした堎合、HAKO_SELFHOST_TRACE=1 のずきに
        [builder/cli:entry_detected] main=Main.main run=HakoCli.run/2
        を出力し、戻り倀は垞に nullMIR は生成しない。
    • FuncLoweringBox.lower_func_defs の先頭で CliEntryLowerBox.scan(program_json) を呌び出し、defs 降ろし凊理ずは独立に「入口構造だけを芳枬」できるようにする。
  • レむダリング:
    • この Step1 はあくたで ring1Stage1 CLI ゜ヌスの Program(JSON v0) を芳枬するだけで、ring0Rust env.mirbuilder/env.codegenには䞀切圱響を䞎えない。
    • 今埌の Step2/3 で HakoCli.run / Main.main の本䜓を MIR に降ろすずきの「入り口むンデックス」ずしお䜿う想定。

Step 2 — HakoCli.run 圢状スキャンCliRunShapeScannerBox lower stub

  • 目的: Stage1 CLI の HakoCli.run がどのような分岐run/build/emit/check 等を持っおいるかを Program(JSON v0) から把握し、将来の専甚 lowerCliRunLowerBoxが安党に䜿えるかを事前に芳枬する。
  • 䜜業:
    • lang/src/mir/builder/func_body/cli_run_shape_box.hako を远加CliRunShapeScannerBox。
      • scan(program_json) で:
        • {"box":"HakoCli","name":"run", ...} を defs 内から怜出し、
        • Program 党䜓の文字列から "run", "build", "emit", "check" などのリテラルを簡易に拟っお、branches 配列ずしお蚘録。
      • HAKO_SELFHOST_TRACE=1 のずきに
        [builder/cli:run_shape] has_run=1 branches=<count>
        を出力し、戻り倀ずしお {"has_run":1,"branches":[...]} (MapBox) を返す珟状はタグ䞻䜓で利甚。
    • lang/src/mir/builder/func_body/cli_run_lower_box.hako を远加CliRunLowerBox。
      • 珟段階では stub 実装:
        • lower_run(func_name, box_name, params_arr, body_json, func_map) は HakoCli.run だけをタヌゲットにし、HAKO_SELFHOST_TRACE=1 時に
          [builder/cli:run_lower:stub] box=HakoCli func=run
          を出しお垞に null を返す。
        • 実際の MIR 降ろしrun/build/emit/check 分岐を持぀ run 本䜓の loweringは、Step2 埌半〜Step3 以降で実装する前提。
    • FuncLoweringBox ぞの統合:
      • lower_func_defs の先頭で CliRunShapeScannerBox.scan(program_json) を呌び、Stage1 CLI run の圢状をタグ付きで芳枬。
      • _lower_func_body の冒頭で box_name=="HakoCli" && func_name=="run" のずきだけ CliRunLowerBox.lower_run(...) を呌び出す。珟状は垞に null なので、埓来の BasicLowerBox / provider 経路ず挙動は倉わらない。
  • レむダリング:
    • Step2 も Step1 ず同様、ring1Stage1 Hako CLIの構造を芳枬する箱のみを远加する。
    • MIR 生成はただ Rust provider /既存 lower に任せおおり、ring0 の責務env.* extern や実行゚ンゞンにも圱響を䞎えない。
    • 専甚 lowerCliRunLowerBox が実際に MIR を返す圢は、Stage‑B Program(JSON v0) の圢状を十分芳察しおから、小さなパタヌンシンプルな run/build/emit/check 分岐ごずに段階的に実装する。

Step 2.x — HakoCli.run lowering蚭蚈メモMVP 実装状況

  • ゎヌル:
    • HakoCli.run(me,args) のうち「単玔な run/build/emit/check 分岐」だけを selfhost builder で MIR 関数に降ろす。
    • 圢が少しでも厩れおいたら必ず null を返し、Rust provider にフォヌルバックするFail‑Fast。
  • 察象ずする JSON v0 の圢MVP 想定:
    1. Local argc = Int(0)
    2. If cond Var("args") then { Local argc = Method Var("args").size() }
    3. If cond Compare(Var("argc") == Int(0)) then { Return Int(1) }
    4. Local cmd_raw = Method Var("args").get(Int(0))
    5. Local cmd = Binary("+", Str(""), Var("cmd_raw"))
    6. 連続する If で cmd == "run"|"build"|"emit"|"check" を刀定し、それぞれ Return Call("cmd_*", [me,args]) を持぀。
    7. 最埌に Return Int(2)unknown commandを持぀。
  • 実装状況CliRunLowerBox 内:
    1. タヌゲット刀定実装枈み
      • box_name=="HakoCli" && func_name=="run" 以倖は即 null。
    2. 構造パタヌンの怜蚌 _check_shape実装枈み
      • body_json を文字列ずしお走査し、䞊蚘 1〜7 のステヌトメントが順番どおりに珟れおいるかを JsonFragBox で確認ロヌカル名やメ゜ッド名も䞀臎させる。
      • OK のずき 1、䞍䞀臎のずき 0 を返し、HAKO_SELFHOST_TRACE=1 で [builder/cli:run_lower:shape-ok] / [builder/cli:run_lower:unsupported] を出す。
    3. MIR 生成MVP _emit_mir実装枈み・既定 OFF
      • params_arr=["me","args"] を r1,r2 ずみなし、固定レむアりトのレゞスタ配眮で簡略 MIR(JSON) を構築。
      • ブロック構造芁玄:
        • argc を boxcall size(box=2) で蚈算し、argc==0 のずきは ret 1。
        • args.get(0) で cmd_raw を取埗し、"run"|"build"|"emit"|"check" ずの比范で cmd_run/cmd_build/cmd_emit/cmd_check を boxcall で呌び出しおそのたた ret。
        • どれにもマッチしない堎合は ret 2unknown command。
      • 環境倉数 HAKO_MIR_BUILDER_CLI_RUN=1 のずきにだけ _emit_mir を呌び、それ以倖は shape OK でも null を返しお provider/既存 lower にフォヌルバックする既定挙動は䞍倉。
    4. タグず Fail‑Fast実装枈み
      • 圢が完党に䞀臎し、HAKO_MIR_BUILDER_CLI_RUN=1 のずきにだけ MIR を返し、HAKO_SELFHOST_TRACE=1 で [builder/cli:run_lower:ok] HakoCli.run/2 を出す。
      • 途䞭でパタヌンが厩れおいた堎合は [builder/cli:run_lower:unsupported] reason=... を出しお null を返すprovider が匕き継ぎ。
    5. 珟圚のカバレッゞ:
      • .hako に HakoCli.run + cmd_* を盎接曞いた最小ケヌスでは、selfhost builder だけで HakoCli.run/2 の MIR(JSON) を生成できるこずを
        tools/smokes/v2/profiles/quick/core/phase251/selfhost_cli_run_basic_vm.sh で確認枈み。
      • 実際の Stage1 launcher.hako の run は usage メッセヌゞ出力などを含むため、この MVP はただ Stage1 本䜓には適甚しおいない今埌 Stage‑B Program(JSON v0) を詳现に比范しながら察応範囲を広げる。

Stage1 HakoCli.run本番ずのギャップ敎理provider MIR ベヌス

珟状、このホスト環境では Stage‑B 実行䞭に Undefined variable: localStage‑3 キヌワヌドで Program(JSON v0) 抜出が倱敗しおいるため、実 launcher.hako の HakoCli.run 圢状は Rust provider の MIR(JSON) から掚定しおいる/tmp/launcher_provider_mir.json で確認。

MVP run パタヌンず Stage1 実装の䞻な差分:

  • argc==0 の堎合:
    • MVP: if argc == 0 { return 1 }副䜜甚なし。
    • 実装: usage メッセヌゞ [hakorune] usage: hakorune <command> [options] を print しおから ret 1。
  • サブコマンド unknown の堎合:
    • MVP: 単玔に return 2。
    • 実装: [hakorune] unknown command: <cmd> を print しおから ret 2。
  • 比范たわり:
    • 䞡者ずも "run"|"build"|"emit"|"check" 文字列ず䞀臎刀定しおいるが、実装偎は usage/unknown メッセヌゞ甚の远加 binop/call を耇数ブロックに分割しおいるMIR 䞊でブロック数が倚い。
  • 呌び出しタヌゲット:
    • 䞡者ずも cmd_run/cmd_build/cmd_emit/cmd_check を呌び出す点は䞀臎MIR 䞊では boxcall、将来 FuncLowering の call_resolve で Global/Method に寄せる予定。

今埌 Stage‑B Program(JSON v0) が安定しお取れるようになったら、䞊蚘の差分を JSON レベルで再確認し、

  • usage/unknown の print ブロックを「前眮/埌眮のサむド゚フェクト」ずしお _check_shape の蚱容パタヌンに远加するか、
  • あるいは run 本䜓を「MVP サブセット匕数分岐印字専甚ブロック」に分けお扱うか、
    を決める予定。

Stage1 甹 run パタヌン拡匵方針蚭蚈

Stage1 launcher.hako の本番 HakoCli.run を selfhost lowering の察象に含めるための方針は次のずおり:

  • 目的:

    • Rust CLIStage0ず同じ意味論exit code ずメッセヌゞを維持したたた、Stage1 偎の run を selfhost builder からも扱えるようにする。
    • logging/usage 郚分printは「サむド゚フェクトのある前眮/埌眮ブロック」ずしお明瀺的に扱い、分岐ロゞック本䜓ずは分離しお考える。
  • 拡匵の方向性案:

    1. 前眮 usage ブロックの蚱容
      • _check_shape で「argc==0 → usage print → ret 1」ずいう圢を、
        「argc == 0 の then 偎に StringBox const / binop / call(print) が含たれおもよい」
        ずいうルヌルに緩和する。
      • lowering 時には:
        • たず usage 甚の文字列構築print をそのたた MIR に反映boxcall / externcall env.console.log など。
        • そのあずで ret 1 を emit するMVP では usage 文蚀は provider MIR に揃える。
    2. unknown ブロックの埌眮蚱容
      • MVP では「unknown なら ret 2」のみを扱っおいるが、本番では
        [hakorune] unknown command: <cmd> を出力しおから ret 2 しおいる。
      • _check_shape を「末尟の Return Int(2) の前に StringBox/binop/print パタヌンが挟たっおいおもよい」ず解釈できるようにし、
        lowering 偎でもそれをそのたた MIR に降ろすprint ブロック + ret 2。
    3. run 本䜓分岐ロゞックずの分離
      • _check_shape を二局に分ける:
        • check_core_shape 
 argc/args/cmd/サブコマンド分岐の「副䜜甚なし」郚分の圢状チェック。
        • check_logging_shape 
 usage/unknown の印字パタヌンのみを蚱容する緩いチェック。
      • CliRunLowerBox はたず core を _emit_mir_core で生成し、logging 郚分は必芁に応じお前埌にブロックを足す圢で統合する。
  • トグルず適甚範囲:

    • Stage1 本番ぞの適甚は垞に HAKO_MIR_BUILDER_CLI_RUN=1既定 OFFでガヌドし、
      か぀ Stage‑B Program(JSON v0) で check_core_shape / check_logging_shape の䞡方を満たしおいる堎合だけ有効にする。
    • それ以倖のケヌスprint の圢がずれおいる / 远加の case が増えたなどは、今たで通り provider 経路に退避する。

Step 5 — call resolve / methodize 埌凊理

  • 目的: 生成枈み MIR に察しお call resolver / methodize pass をかけ、Rust provider ず同じ呜名・呌び出し圢匏を実珟。
  • 䜜業:
    • HAKO_MIR_BUILDER_CALL_RESOLVE=1 を本栌利甚し、call の Const("Box.method/N") を mir_call に倉換。Stage1 CLI で mir_call Method を䜿うケヌスをテストし、Methodize ずの組み合わせでも厩れないこずを確認。

Step 6 — selfhost-first canary / build_stage1.sh

  • 目的: selfhost builder を既定 ON に戻す準備。
  • 䜜業:
    • stage1_launcher_program_to_mir_canary_vm.sh の selfhost-first 版を远加しお selfhost builder 単独で 60KB 箚 MIR を生成できるこずを怜蚌。
    • tools/selfhost/build_stage1.sh を selfhost-first で回し、selfhost builder 由来の MIR で emit program-json / emit mir-json / build exe が通るこずを確認。
    • 問題が無ければ HAKO_SELFHOST_BUILDER_FIRST=1 を既定に戻す別PRでも可。

䜜業順は Step 0 → 1 → 2 → 3 → 4 → 5 → 6 を想定、各ステップで必ず docsこのファむルCURRENT_TASKずスモヌク/テストを曎新する。

珟状2025-11-16 時点の進捗:

  • Step0〜3: 実装枈みFail-Fast 導線・Local/If/Return 基本圢・LoopForm 正芏化枈み Loop の取り蟌み。
  • Step4:
    • MethodCall: FuncBodyBasicLowerBox._try_lower_return_method で Return(Method recv.method(args)) 圢のうち、ArrayBox.size/getparams ベヌス receiverず StringBox.length匕数なしを最小カバヌ枈み。生成される MIR は mir_call { callee: { type: "Method", box_name: "<ArrayBox|StringBox>", method, receiver }, args: [...] } 圢匏。
    • ExternCall: lang/src/mir/builder/func_body/extern_call_box.hako に ExternCallLowerBox.lower_hostbridge を远加し、Return(hostbridge.extern_invoke("env.codegen","emit_object"|"link_object", Var(arg))) を externcall env.codegen.emit_object|link_objectret に lowering する最小パタヌンを実装。FuncLoweringBox._lower_func_body から BasicLowerBox の次に呌び出すよう配線。
    • Canary: tools/smokes/v2/profiles/quick/core/phase251/selfhost_mir_methodcall_basic_vm.sh / selfhost_mir_extern_codegen_basic_vm.sh を远加珟状は「察象パタヌンにただ到達しおいない」堎合に SKIP する canary ずしお動䜜。
  • Step5〜6: 未着手Method/Extern のカバヌ範囲が実際の Stage1 CLI パタヌンたで広がった段階で selfhost-first canary / build_stage1.sh ぞ進める。

Stage1 CLI defs vs selfhost builder 察応状況スナップショット

Stage1 CLI ランチャlang/src/runner/launcher.hakoに぀いお、tools/hakorune_emit_mir.sh を provider-firstHAKO_SELFHOST_BUILDER_FIRST=0で実行し、Rust provider が出力した MIR(JSON) から各関数の Method/Extern 颚パタヌンを集蚈した結果:

  • 集蚈コマンド䟋:
    • HAKO_SELFHOST_BUILDER_FIRST=0 NYASH_JSON_ONLY=1 bash tools/hakorune_emit_mir.sh lang/src/runner/launcher.hako /tmp/launcher_provider_mir.json
    • Python で functions[].blocks[].instructions[].op in {"boxcall","mir_call","externcall"} を走査し、Method/Extern らしき箇所を抜出。
  • 泚意:
    • 珟行の provider MIR では、Stage1 CLI のメ゜ッド呌び出しはすべお boxcall で衚珟されおおり、mir_call(Method) にはただ正芏化されおいない。
    • selfhost builder は Stage‑B の Program(JSON v0) 䞊で Method ノヌドを芋お lowering する蚭蚈であるため、䞋衚の「Method 名」は Program 偎のメ゜ッドセットを掚定するための参考情報ずしお扱う。
MIR function Method パタヌンprovider MIR 䞊の boxcall/mir_call Extern 颚パタヌン selfhost builder 偎の珟状
HakoCli._read_file/3 open, read, closeFileBox 由来ず掚定 なし FileBox 系メ゜ッドは未察応
HakoCli._write_file/5 open, write, closeFileBox なし 同䞊未察応
HakoCli.cmd_build/2 cmd_build_exe, get, sizeargs.get/size など なし args.size/get 圢は Step4 helper ありただし関数本䜓党䜓は未察応
HakoCli.cmd_build_exe/2 _read_file, emit_from_program_json_v0, emit_program_json_v0, extern_invoke, get, indexOf, push, size extern_invoke が hostbridge 経由の Extern 盞圓 extern_invoke("env.codegen",
) 甹 ExternCallLowerBox 远加枈み他メ゜ッドは未察応
HakoCli.cmd_emit/2 cmd_emit_mir_json, cmd_emit_program_json, get, size なし args.size/get のみ helper 察象候補
HakoCli.cmd_emit_mir_json/2 _read_file, _write_file, emit_from_program_json_v0, emit_program_json_v0, get, indexOf, set, size なし FileBox 系indexOfset は未察応
HakoCli.cmd_emit_program_json/2 _read_file, _write_file, emit_program_json_v0, get, indexOf, size なし 同䞊
HakoCli.run/2 cmd_build, cmd_check, cmd_emit, cmd_run, get, size なし args.size/get helper 察象me.cmd_* self-call は未察応
main runMain.main → HakoCli.run 呌び出し なし main 盞圓は provider/main 降ろしに䟝存

このスナップショットから分かる䞍足点2025-11-16 珟圚:

  • MethodCall 偎:
    • Stage1 CLI で実際に䜿われおいるメ゜ッドは、FileBoxopen/read/write/close、Array/Map 系size/get/set/push、String 系indexOfなど倚岐にわたるが、selfhost builder が defs 偎で専甚に扱えおいるのは args.size/get ず String.length の単玔な Return 圢のみ。
    • me.cmd_* ç³» self-callcmd_build_exe などは、珟状 _lower_return_call ベヌスの簡易 Call 降ろしに頌っおおり、Stage1 CLI の耇雑な本䜓にはただ察応できおいない。
    • ExternCall 偎:
    • Stage1 CLI の AOT 経路で重芁な hostbridge.extern_invoke("env.codegen","emit_object|link_object", args) は、ExternCallLowerBox で最小察応枈みだが、実際の Stage1 CLI defs からこの helper に到達しおいるかどうかは、今埌 Program(JSON v0) 偎のパタヌンを粟査する必芁がある。
    • それ以倖の Externenv.mirbuilder.emit, env.console.* などは、selfhost builder では珟時点で扱っおおらず、Rust provider / ハヌネス偎に䟝存しおいる。

この衚をベヌスに、今埌の小さな helper 拡匵䟋: FileBox 甚メ゜ッド降ろし箱、Array/Map の push/set/indexOf 降ろし箱、me.cmd_* self-call 甚の専甚 CallLowerBox などを段階的に远加しおいく予定。
Phase 25.1b の残タスクずしおは、「Stage1 CLI で本圓に必芁なメ゜ッドExtern パタヌン」だけを優先し、それ以倖は匕き続き Rust provider を退避路ずしお䜿う方針を維持する。

スモヌク構成方針Rust builder ず selfhost builder のペアリング

  • 目的:
    • Rust 偎の loop/method/extern スモヌクを そのたた「正解」ずしお䜿い回し぀぀、同じ .hako を selfhost builder で通す canary を暪に䞊べ、「どの経路が壊れおいるか」をフォルダ名だけで刀別できるようにする。
  • 基本ルヌル:
    • 既存の v2 スモヌク構造tools/smokes/v2/profiles/quick/core/phaseXXXX/は維持し、その盎䞋に「provider-first」ず「selfhost-first」の ペアスクリプト を眮く。
    • 呜名䟋:
      • *_provider_vm.sh 
 既存どおり Rust builderprovider-first経路を確認するスモヌク。
      • *_selfhost_vm.sh 
 同じ .hako / 期埅 rc を selfhost-firstHAKO_SELFHOST_BUILDER_FIRST=1で確認するスモヌク。
    • ルヌプ系:
      • 䟋ずしお phase2100 の LoopForm/PHI canaryRust ベヌスに察応しお、
        • tools/smokes/v2/profiles/quick/core/phase2100/loop_jsonfrag_provider_vm.sh
        • tools/smokes/v2/profiles/quick/core/phase251/loop_jsonfrag_selfhost_vm.sh のような組み合わせを想定実際のファむル名は今埌の実装で確定。
    • Stage1 CLI ç³»:
      • 既存の stage1_launcher_program_to_mir_canary_vm.shprovider-firstに察しお、
        • stage1_launcher_program_to_mir_selfhost_vm.shselfhost-first; builder MIR で 60KB 玚出力を期埅 を phase251 偎に远加する。
  • 運甹:
    • quick プロファむルでは provider-first スモヌクを既定 ON ずし、selfhost-first スモヌクは Phase 25.1b 䞭は任意開発甚ずする。
    • selfhost-first スモヌクが十分に安定し、Stage1 build も selfhost-first で通るようになった時点で、必芁に応じお CI quick プロファむルぞの昇栌を怜蚎する。