Step2実装内容: - FuncBodyBasicLowerBox導入(defs専用下請けモジュール) - _try_lower_local_if_return実装(Local+単純if) - _inline_local_ints実装(軽い正規化) - minimal lowers統合(Return/BinOp/IfCompare/MethodArray系) Fail-Fast体制確立: - MirBuilderBox: defs_onlyでも必ずタグ出力 - [builder/selfhost-first:unsupported:defs_only] - [builder/selfhost-first:unsupported:no_match] Phase構造整備: - Phase 25.1b README新設(Step0-3計画) - Phase 25.2b README新設(次期計画) - UsingResolverBox追加(using system対応準備) スモークテスト: - stage1_launcher_program_to_mir_canary_vm.sh追加 Next: Step3 LoopForm対応 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
16 KiB
16 KiB
Phase 25.1a — Stage1 Build Pipeline Hotfix (Program→MIR)
Status: hotfix-in-progress(緊急タスク/配線修正フェーズ)
ゴール
- Phase 25.1 で導入した Stage1 ランチャー(
lang/src/runner/launcher.hako)と selfhost AOT パイプライン(build_stage1.sh経由)を「実際に動く状態」に戻す。 .hako → Program(JSON v0) → MIR(JSON) → EXEのうち、Program(JSON v0) → MIR(JSON) の導線を再構成し、tools/hakorune_emit_mir.sh/tools/selfhost_exe_stageb.sh/tools/selfhost/build_stage1.shが代表ケースで成功するようにする。- selfhost builder / provider / legacy CLI の 3 経路が混在した現状を見直し、信頼できる1本の Program→MIR 経路を中心に据える。
進捗状況(2025-11-16 時点)
- Stage-B と provider 経路で
.hako → Program(JSON) → MIR(JSON)は安定。hakorune_emit_mir.sh lang/src/runner/launcher.hako …も[OK] MIR JSON written (delegate:provider)。 - selfhost builder (
HAKO_SELFHOST_BUILDER_FIRST=1) では、Stage1 CLI の Program(JSON) を完全に lowering できず 171 bytes の stub MIR を返すため、現状 selfhost-first を既定ONにできない。 - Stage1 EXE(
/tmp/hakorune-dev)は provider 経由の MIR を使えばリンク成功。ただし CLI I/O は JSON を出さずResult: 0のみ。JSON 出力契約に揃える作業は selfhost builder の修復後に実施予定。
現状の問題点(2025-11-15 時点)
-
tools/selfhost/build_stage1.sh:- 現在の entry:
lang/src/runner/launcher.hako(Stage1 CLI ランチャー)。 - provider 経由 (
env.mirbuilder.emit) では.hako → Program(JSON) → MIR(JSON)を安定して通せるが、selfhost builder (MirBuilderBoxon VM) はまだ Stage1 CLI の Program(JSON) をフルで扱えず、最小パターンの stub MIR(171 bytes)を出力してしまう。 - このため selfhost builder を既定ONにすると EXE が空挙動になるため、Phase 25.1a では暫定的に provider-first (
HAKO_SELFHOST_BUILDER_FIRST=0) を維持しつつ、selfhost builder 側の機能範囲拡張を翌フェーズへ送っている。
- 現在の entry:
-
tools/hakorune_emit_mir.sh— Program→MIR 部分:- Stage‑B(
compiler_stageb.hako):Stage-B: SUCCESS - Generated Program(JSON)まで成功("version":0,"kind":"Program"を含む JSON が得られている)。
- selfhost builder 経路(
try_selfhost_builder):builder_box=hako.mir.builderで Runner を生成し、VM 経由で実行。- 当初は tmp ハコファイルに対して
Parse error: Unexpected token FNやUnexpected token ASSIGNが発生し rc=1 で失敗していたが、lang/src/mir/builder/func_lowering.hakoのlocal fn = func_jsons.length()をlocal func_len = ...にリネームすることでUnexpected token FN自体は解消済み。 - その後、
lang/src/shared/mir/loop_form_box.hakoとlang/src/mir/builder/internal/lower_loop_count_param_box.hakoにおけるinit予約語衝突(local init = .../ 引数名init)をstart_value系にリネームし、LoopFormBox まわりのInvalid expressionも解消済み。 - 現在は selfhost builder Runner の実行フェーズで
VM error: Invalid instruction: global function: Unknown: self._is_on/1が発生しており、MirBuilder 内部のトグルヘルパーBuilderConfigBox._is_onの呼び出し(norm_ifラムダ経由)が VM 側にまだ実装されていないために落ちている状態(構文ではなく実行時エラー)。
- provider 経路(
try_provider_emit→env.mirbuilder.emit):- 当初は
env.mirbuilder.emit実行時に[mirbuilder/parse/error] undefined variable: argsにより失敗していたが、Rust 側の Program→MIR ルート修正によりこのエラーは解消済み。現在は provider 経路経由でlauncher.hakoから MIR(JSON) を安定して生成できている。
- 当初は
- legacy CLI 経路(
--program-json-to-mir):- Program(JSON) を一時ファイルに書いて
nyash --program-json-to-mirを叩くフォールバックも rc!=0 で終了していたが、Phase 25.1a では provider 経路の安定化を優先するため、現在は原則退避路とし、日常の導線では利用しない。
- Program(JSON) を一時ファイルに書いて
- Stage‑B(
-
Stage1 CLI (
launcher.hako) の VM 実行:nyash --backend vm lang/src/runner/launcher.hako -- emit ...で、usingの解決(lang.compiler.build.build_box)は nyash.toml に追加済みだが、- まだパーサが Stage‑3 構文/関数宣言の一部を受理できていない箇所があり、
Unexpected token ...系のエラーが残っている。
Update (2025-11-16 — Stage‑B using resolverを module alias 化)
lang/src/compiler/entry/compiler_stageb.hakoで使用していたファイルパス形式のusing "..." as ...を、nyash.toml[modules]に登録済みの module alias(hako.compiler.entry.bundle_resolver/lang.compiler.entry.using_resolver)へ置き換えた。tools/hakorune_emit_mir.shが export するHAKO_STAGEB_MODULES_LIST/HAKO_STAGEB_APPLY_USINGSを Stage‑B が参照できるようになり、Stage‑3 パーサがusing行で失敗しなくなった(HAKO_SELFHOST_TRACE=1 ./tools/hakorune_emit_mir.sh basic_test.hako /tmp/out.jsonが[emit:trace] Stage-B: SUCCESS ...で止まらずdelegate:providerまで進むことを確認)。- これにより Phase 25.1a の Program→MIR ホットフィックスでは「Stage‑B→provider delegate」が安定経路になり、selfhost builder の修復に専念できる状態になった(Stage1 CLI 側の
usingも module alias 化を継続)。 - 追加で、
tools/hakorune_emit_mir.sh側のHAKO_MIRBUILDER_IMPORTS生成ロジックを拡張し、using ns.path.Type(alias なし)の形式からも末尾セグメント(例:MirBuilderBox)を alias として抽出するようにした。これにより、using lang.mir.builder.MirBuilderBoxを含む Stage1 CLI/Builder コードでもenv.mirbuilder.emitがundefined variable: MirBuilderBoxを出さずに Program(JSON v0) を lowering できるようになった。 - Stage1 CLI(
lang/src/runner/launcher.hako)の emit/build コマンドを helper (_read_file/_write_file) で整理し、Stage‑3 friendly なlocal宣言・ログメッセージに統一。hakorune_emit_mir.sh lang/src/runner/launcher.hako …を provider delegate で再度通し、62KB 超の MIR(JSON) が得られることを quick smoke(phase251/stage1_launcher_program_to_mir_canary_vm.sh)でカバー済み。 - Rust 側の JSON v0 ブリッジ(
src/runner/json_v0_bridge/lowering/expr.rs)にはhostbridgeを well-known グローバルとして扱う最小の分岐を追加し、hostbridge.extern_invoke(...)を含む Program(JSON v0) でもundefined variable: hostbridgeエラーで止まらないようにした(値はConst(String("hostbridge"))を発行する placeholder とし、実際の extern dispatch は VM/ランタイム側に委譲する)。
フェーズ内タスク(25.1a TODO)
A. Stage1 CLI ソースの VM 実行復旧
lang/src/runner/launcher.hakoを Stage‑3 パーサが素直に通る形に調整する。- 関数/ブロック構造・ローカル宣言のスタイルを既存の selfhost コードに合わせる(
function定義やlocalの位置など)。 using lang.compiler.build.build_box as BuildBox経路を nyash.toml / hako_module.toml に統一し、「ファイルパス using」を完全に排除する。
- 関数/ブロック構造・ローカル宣言のスタイルを既存の selfhost コードに合わせる(
- VM 実行スモーク:
NYASH_ALLOW_NYASH=1 ./target/release/nyash --backend vm lang/src/runner/launcher.hako -- emit program-json apps/selfhost-minimal/main.hakoが parse error なく通ること。- 同様に
emit mir-json/build exeも、少なくともエラーメッセージ付きで Fail-Fast するところまで確認する(VM 側での構文エラーがないこと)。
B. Program→MIR selfhost builder 経路の安定化
try_selfhost_builder内で生成される tmp ハコファイル(__BUILDER_BOX__版)を最小ケースで切り出し、単体で parse/実行できるように修正。args未定義エラーやInvalid expressionの原因となっている記述を特定し、Runner 側のMain.main(args)などを正しく宣言する。- Stage‑3 構文の使用を必要最小限に抑え、selfhost builder 用 Runner のコードをシンプルに保つ。
- Stage‑3 パーサで予約語となった
fnをローカル変数名として使っている箇所(例:lang/src/mir/builder/func_lowering.hakoのlocal fn = func_jsons.length())をリネームし、Unexpected token FN, expected identifierを根本的に解消する。- selfhost builder/min で使っていた
fn(norm_ifクロージャ)を helper メソッドに置き換え、lambda 構文を排除。Stage‑3 VM がNewClosureを扱わなくても builder が進むようにした。 - VM 側で prelude/text-merge 後の Hako コードを落とすデバッグ用トグルを追加(
NYASH_VM_DUMP_MERGED_HAKO=1/NYASH_VM_DUMP_MERGED_HAKO_PATH=<path>)。selfhost builder 実行時はHAKO_SELFHOST_DUMP_MERGED_HAKO=1/HAKO_SELFHOST_DUMP_MERGED_HAKO_PATH=/tmp/hako_builder_merged.hakoを通じて/tmp/hako_builder_merged.hakoにマージ後の一時ハコを保存し、Invalid expression at line <N>の行を直接観察できるようにする。
- selfhost builder/min で使っていた
- 進捗メモ(2025-11-15):
HAKO_SELFHOST_BUILDER_FIRST=1 HAKO_SELFHOST_DUMP_MERGED_HAKO_PATH=/tmp/hako_builder_merged.hako tools/hakorune_emit_mir.sh lang/src/runner/launcher.hako …で 275KB の merged Hako が採取済み。BuilderConfigBox内_is_onなど Stage‑3 で落ちやすい箇所を直接確認できる。- 同条件で
apps/selfhost-runtime/runner.hakoも[OK] MIR JSON written (selfhost-first)まで到達。stage3 parse 落ちは再現していないため、次回失敗したケースが出たら/tmp/hako_builder_merged.hakoを差し替えて行番号を追跡する。
try_selfhost_builderを 第一候補 とし、代表ケース(launcher.hako 等)で常にここが成功することを確認。HAKO_SELFHOST_BUILDER_FIRST=1でtools/hakorune_emit_mir.shを叩いたときに[OK] MIR JSON written (selfhost-first)まで到達することをスモークで確認。
C. Provider / legacy delegate の整理
- provider 経路(
env.mirbuilder.emit)でのundefined variable: args原因を修正し、Stage‑B が出力する Program(JSON v0) を正しく受理できるようにする。HAKO_V1_EXTERN_PROVIDER/HAKO_V1_EXTERN_PROVIDER_C_ABIトグルのデフォルトを見直し、「selfhost builder が成功するなら provider には落ちない」構造に寄せる。
- legacy CLI 経路(
--program-json-to-mir)は、「selfhost builder が失敗したときだけ最後に試す」退避路として残しつつ、代表ケースでは通さない方針にする。 - 必要であれば Phase 25.1a 中は
HAKO_SELFHOST_NO_DELEGATE=1を既定 ON に近い扱いにし、「selfhost builder が通る範囲」に問題を絞る。
D. build_stage1.sh / selfhost_exe_stageb.sh 復旧
NYASH_LLVM_SKIP_BUILD=1 tools/selfhost/build_stage1.sh --out /tmp/hakorune-devが 0 exit すること(現状は selfhost builder を既定OFFにし、provider ルートで MIR を生成)。- 生成された
/tmp/hakorune-devについて:Stage1 CLI emit系は現在 Result:0 のみで JSON を出さない(MIR が stub のため)ので、selfhost builder が機能するまで provider MIR を直接使う(tools/selfhost/run_stage1_cli.shに JSON を書かせるタスクは後続)。./hakorune-dev build exe -o /tmp/hako_min apps/selfhost-minimal/main.hakoで簡単な EXE が生成され、実行して 0 exit を返すこと。
- Stage1 CLI を実行する補助スクリプト
tools/selfhost/run_stage1_cli.shを追加し、NYASH_NYRT_SILENT_RESULT=1/NYASH_DISABLE_PLUGINS=1/NYASH_FILEBOX_MODE=core-roを既定ONにした状態で CLI を呼び出せるようにした(llvmlite ハーネスと同じ JSON stdout 契約を満たすため)。 tools/selfhost_exe_stageb.shについても同様に.hako → EXEのスモークを通しておく(少なくとも launcher.hako / apps/selfhost-minimal/main.hako の2ケース)。- 進捗メモ(2025-11-15):
FuncScannerBoxを拡張し、static boxメソッドをdefsに追加(暗黙meもパラメータに補完)。- Rust 側 JSON v0 ブリッジに
ExprV0::Nullvariant を追加して Stage‑B からの Null リテラルを受理。 launcher.hakoのwhileをloop構文へ置換し、Stage‑B パーサ互換に揃えた。- 依然として using 依存(例:
lang.mir.builder.MirBuilderBox)を Stage‑B emit が解決できず、env.mirbuilder.emitがundefined variable: MirBuilderBoxで停止。BundleResolver / using resolver を Stage‑B 経路に統合し、依存 Box を Program(JSON) に連結するのが次タスク。
E. 次フェーズ(25.1b)に送る selfhost builder 強化項目
Program.defsを MirBuilder 側でも処理し、HakoCli.run/cmd_emit_*/cmd_build_*などのメソッドを MIR 関数として生成する(現状は main 1 本のみ)。func_lowering/call_resolve相当の処理を Hako 側に移植し、Call("cmd_emit_mir_json")がGlobalresolved call になるようにする。- Loop / branch / compare / Array・Map 操作など Stage1 CLI で出現するステートメントを包括的に lowering するため、
lang/src/mir/builder/internal/*の helper を本番経路に組み込む。 - JSON 出力を
jsonfragベースで構造的に生成し、functions 配列に複数関数を格納できるようにする(文字列連結のみの暫定実装を置き換える)。 - 上記を満たした段階で
HAKO_SELFHOST_BUILDER_FIRST=1を既定に戻し、Stage1 CLI バイナリの I/O(stdout JSON + exit code)を Rust/llvmlite と同じ契約に揃える。
25.1 / 25.1a / 25.2 の関係
- Phase 25.1:
- Stage0/Stage1 の責務とバイナリレイアウトを設計し、Stage1 CLI(launcher.hako)の顔と構文を固めるフェーズ。
- Phase 25.1a(本ファイル):
- 「設計した Stage1 CLI / selfhost パイプラインが実際に動くようにする」緊急ホットフィックスフェーズ。
- Scope はあくまで Program→MIR と selfhost AOT の復旧 に限定し、numeric_core などの最適化には踏み込まない。
- Phase 25.2:
- numeric_core AOT / microbench 統合・性能チューニングにフォーカス(
matmul_coreなど)。 - 25.1a で安定化した selfhost パイプラインの上に乗せる形で進める。
- numeric_core AOT / microbench 統合・性能チューニングにフォーカス(
Related docs
docs/development/roadmap/phases/phase-25.1/README.md… Stage0/Stage1 Bootstrap & Binary Layout(設計+初期実装)。docs/development/roadmap/phases/phase-25/README.md… Ring0/Ring1 再編と numeric_core BoxCall→Call パス。docs/development/runtime/cli-hakorune-stage1.md… Stage1 hakorune CLI のサブコマンド設計と実装範囲。tools/hakorune_emit_mir.sh… Stage‑B → Program(JSON v0) → MIR(JSON) の selfhost+delegate パイプライン。tools/selfhost_exe_stageb.sh/tools/selfhost/build_stage1.sh….hako → MIR(JSON) → EXEselfhost AOT パス。***- Notes:
- selfhost builder (
HAKO_SELFHOST_BUILDER_FIRST=1) は依然として parse error で落ちるため、Phase 25.1a では 既定を 0(無効) に切り替え、provider ルートを安定化させた。 - builder-first 経路の再有効化は Phase 25.1a 中の後続タスクとして扱う。
- selfhost builder (