Phase 25.1a: selfhost builder hotfix (fn rename, docs)
This commit is contained in:
188
docs/development/roadmap/phases/phase-25.1/README.md
Normal file
188
docs/development/roadmap/phases/phase-25.1/README.md
Normal file
@ -0,0 +1,188 @@
|
||||
# Phase 25.1 — Stage0/Stage1 Bootstrap & Binary Layout
|
||||
|
||||
Status: design+partial implementation(Stage1 ビルド導線の初期版まで)
|
||||
|
||||
## ゴール
|
||||
|
||||
- Rust 製 `hakorune` を **Stage0 ブートストラップ**と位置付け、Hakorune コード(.hako)で構成された **Stage1 バイナリ**を明確に分離する。
|
||||
- Rust 側の責務を「プロセス起動+最小 FFI+VM/LLVM コア」に縮退し、それ以外の機能(パーサ高レイヤ、Stage‑B、MirBuilder、AotPrep、numeric core 等)は Stage1 に寄せる。
|
||||
- 将来的に「Stage1 hakorune(Hakorune 実装の EXE)」を日常利用の標準とし、Rust Stage0 は非常用ランチャ/ブートシードとして保持する。
|
||||
|
||||
## レイヤ構成(Stage0 / Stage1 / Runtime)
|
||||
|
||||
### Stage0 — Rust Bootstrap Binary
|
||||
|
||||
**想定バイナリ:**
|
||||
- 将来: `target/release/hakorune-bootstrap`
|
||||
- 現在: `target/release/nyash`(Rust 製 CLI。Stage0 ブートストラップとして扱う)
|
||||
|
||||
**責務:**
|
||||
- OS エントリポイント(`main()`)とプロセス起動。
|
||||
- 標準入出力・環境変数・argv の取得と最低限の整形。
|
||||
- LLVM / OS FFI への極小ラッパ(`rt_mem_*` などの intrinsic の土台)。
|
||||
- Rust VM/LLVM のコア(MIR インタプリタ/コード生成)の提供。
|
||||
- Stage1 で AOT されたコア関数(後述)を呼び出すランチャ。
|
||||
|
||||
**禁止/抑制:**
|
||||
- パーサ高レイヤ/Stage‑B/MirBuilder/AotPrep/numeric core のロジックを Rust 側に新規追加しない。
|
||||
- 新しい Box 実装やランタイム機能を Rust に持ち込まない(Phase 25 Rust Freeze を継続)。
|
||||
|
||||
### Stage1 — Hakorune Selfhost Binary
|
||||
|
||||
**想定バイナリ:**
|
||||
- `target/selfhost/hakorune`(Stage0 が AOT して生成する EXE; ファイル名で Stage1 を表し、配置ディレクトリで Stage0 と分離)
|
||||
|
||||
**構成要素(.hako 側で実装/AOT):**
|
||||
- Stage‑B コンパイラ(`lang/src/compiler/entry/compiler_stageb.hako` など)。
|
||||
- MirBuilder / MIR v1→v0 アダプタ。
|
||||
- AotPrep(`selfhost.llvm.ir.aot_prep.*`、numeric core パスを含む)。
|
||||
- Ring1 VM/runtime の一部(System Hakorune subset で書かれたコアロジック)。
|
||||
|
||||
**責務:**
|
||||
- Source(.hako) → Program(JSON) → MIR → 実行/LLVM AOT の全パイプラインを Hakorune コードで担う。
|
||||
- Stage1 自身を再ビルドできる最小セット(自己ホストコア)を提供する。
|
||||
|
||||
**起動イメージ:**
|
||||
- Stage0 `main()`:
|
||||
- 環境・argv を集約。
|
||||
- AOT 済み `hakorune_main(argc, argv_ptr)`(Stage1 側関数)を呼び出すだけの薄い導線。
|
||||
|
||||
### Runtime Lines(共通)
|
||||
|
||||
- VM 実行エンジンと LLVM バックエンドは Stage0/Rust に残す(Ring0)。
|
||||
- Ny 側からは `env.mirbuilder.emit` / `env.codegen.emit_object` / `env.codegen.link_object` といった extern 経由で利用する。
|
||||
- Stage1 は Rust CLI(`nyash`)を「バックエンド CLI」として前提にせず、C-ABI/extern 経由で Ring0 機能にアクセスする。
|
||||
- その上で Stage1/Hakorune コードを AOT したものをリンクして「言語本体」を構成する。
|
||||
- 長期的には、Stage1 からさらに Stage1' を再ビルドして差分が収束する自己ホストサイクルを目指す。
|
||||
- 具体的には「Stage0→Stage1(本バイナリ)」に加えて「Stage1→Stage1'」を実行し、両者の挙動/インターフェース一致を確認するチェックを設ける。
|
||||
|
||||
## ディレクトリ/バイナリ配置案
|
||||
|
||||
### Rust Stage0(Bootstrap)
|
||||
|
||||
- ソース配置案:
|
||||
- `src/bootstrap/` … Stage0 専用のエントリポイント/FFI/VM/LLVM コアの窓口。
|
||||
- 既存の Rust コードは徐々にここへ整理(広域リファクタは別フェーズで慎重に)。
|
||||
- バイナリ:
|
||||
- 現在: `target/release/nyash` … Stage0 実行ファイル(Rust 製 hakorune 相当)。
|
||||
- 将来: `target/release/hakorune-bootstrap` … Stage0 専用バイナリ(名称を分離予定)。
|
||||
|
||||
### Hakorune Stage1(Selfhost)
|
||||
|
||||
- ソース:
|
||||
- 既存どおり `lang/src/**` に配置(Stage‑B / MirBuilder / AotPrep / VM など)。
|
||||
- Stage1 としてビルドすべきモジュールセットを `tools/selfhost/` 以下のスクリプトで管理する。
|
||||
- バイナリ:
|
||||
- 現在(Phase 25.1 初期実装):
|
||||
- Dev line:
|
||||
- `tools/selfhost/build_stage1.sh` → `apps/selfhost-runtime/runner.hako` を AOT し、`target/selfhost/hakorune` を生成する。
|
||||
- 「Ny Executor(MIR v0 ランタイム)+CLI 実験」の開発用 EXE(最新版)。
|
||||
- Stable line:
|
||||
- `lang/build/build_runner.sh` → `lang/bin/hakorune` を生成(pure-lang launcher / legacy bring-up)。
|
||||
- 安定した `target/selfhost/hakorune` を `lang/bin/hakorune` に昇格させて配布基準とする運用を想定。
|
||||
- 将来:
|
||||
- `lang/bin/hakorune` を「標準 hakorune」として日常利用のメインバイナリに昇格させる(dev line は常に先行する実験用バイナリ)。
|
||||
- Stage0 は `hakorune-bootstrap` として非常用ランチャ/自己ホストの起点として残す。
|
||||
|
||||
## ビルド導線(Phase 25.1 初期版)
|
||||
|
||||
このフェーズでは「Rust Stage0 バイナリ」と「Hakorune Stage1 バイナリ」を、ビルド導線レベルで分離するところまでを行う。
|
||||
|
||||
### Makefile ターゲット(開発用)
|
||||
|
||||
- `make stage0-release`
|
||||
- 役割: Rust Stage0(`target/release/nyash`)をビルドする。
|
||||
- 実体: `cargo build --release`(既定機能のみ、Rust CLI のみを対象)。
|
||||
- `make stage1-selfhost`
|
||||
- 役割: Stage0 を利用して Stage1 selfhost バイナリをビルドする。
|
||||
- 実体:
|
||||
- `make stage0-release`(Stage0 準備)
|
||||
- `tools/selfhost/build_stage1.sh`
|
||||
- 出力: `target/selfhost/hakorune-selfhost`(Ny Executor 最小 EXE)。
|
||||
|
||||
### Stage1 ビルドスクリプト
|
||||
|
||||
- `tools/selfhost/build_stage1.sh`
|
||||
- 入力: `apps/selfhost-runtime/runner.hako`(Ny Executor エントリ)。
|
||||
- 経路:
|
||||
1. `tools/hakorune_emit_mir.sh` で Stage‑B+MirBuilder を通し、MIR(JSON v1) を生成。
|
||||
2. `tools/ny_mir_builder.sh --emit exe` で ny-llvmc 経由の EXE を生成。
|
||||
- 出力: `target/selfhost/hakorune-selfhost`。
|
||||
- 備考:
|
||||
- EXE のインターフェースは開発用(MIR v0 ファイルを引数に取る Ny Executor)。フル CLI 化は後続フェーズで行う。
|
||||
- `NYASH_LLVM_SKIP_BUILD=1` を指定すると、既存の ny-llvmc / nyash_kernel ビルド成果物を再利用して高速化できる。
|
||||
|
||||
## フェーズ内タスク(25.1 設計 TODO)
|
||||
|
||||
### A. Stage0/Stage1 境界のドキュメント固定
|
||||
|
||||
- [x] 本ファイル(phase-25.1/README.md)に Stage0/Stage1 の責務と禁止事項を明文化する。
|
||||
- [x] Phase 25 README に Stage0/Stage1 の関係をリンク(Ring0/Ring1 の上位概念として扱う)。
|
||||
- [x] CURRENT_TASK.md に「Stage0=Rust bootstrap / Stage1=Hakorune selfhost」の方針を追記。
|
||||
|
||||
### B. Stage1 コアセットの定義
|
||||
|
||||
- [ ] Stage1 で AOT すべきモジュール一覧をドラフトする(例: Stage‑B / MirBuilder / AotPrep / numeric core)。
|
||||
- [ ] それらのエントリポイント関数(例: `hakorune_main/argc,argv` 相当)を .hako 側で定義する設計メモを追加。
|
||||
|
||||
### C. ビルド/配置戦略(設計のみ)
|
||||
### C. ビルド/配置戦略(設計 → 初期実装)
|
||||
|
||||
- [x] `tools/selfhost/` 以下に Stage1 ビルド用スクリプト名と役割を決める(`build_stage1.sh`)。
|
||||
- [x] `target/selfhost/` ディレクトリに Stage1 バイナリを配置する方針を Cargo/Makefile コメントに記載。
|
||||
- [x] Makefile に `stage0-release` / `stage1-selfhost` ターゲットを追加し、Stage0/Stage1 のビルド導線を分離。
|
||||
|
||||
### D. 将来の自己ホストサイクルの入口を定義
|
||||
|
||||
- [ ] Stage0→Stage1→Stage1' のビルドシーケンスを文章で定義(どの組み合わせで自己一致チェックを行うか)。
|
||||
- [ ] 「普段使うのは Stage1」「問題発生時に Stage0 から再生成」という運用パターンを docs に記載。
|
||||
|
||||
## 実装チェックリスト(25.1 実行順案)
|
||||
|
||||
### 1. バイナリ命名と役割の明確化
|
||||
|
||||
- [x] Cargo.toml に Stage0/Stage1 の bin ターゲット方針を書き出す(ドキュメントコメントレベル)。
|
||||
- 現状: `[[bin]] name = "nyash"` を Stage0(Rust bootstrap)として扱い、Stage1 は `tools/selfhost/build_stage1.sh` で生成される `target/selfhost/hakorune` として外部管理。
|
||||
- [ ] CURRENT_TASK.md に「ユーザーが使うのは `hakorune` / Stage0 は `hakorune-rust`」という運用ポリシーを追記。
|
||||
|
||||
### 2. Stage1 ランチャー(Hako側 Main)の骨組み
|
||||
|
||||
- [ ] `lang/src/runner/launcher.hako` を Stage1 の論理エントリポイントとして固定し、コメントに責務(モード切り替え)を書く。
|
||||
- [ ] ランチャーから呼ぶパイプラインインターフェースを設計する:
|
||||
- [ ] `.hako → Program(JSON)` を呼ぶ関数(Stage‑B)。
|
||||
- [ ] `Program(JSON) → MIR(JSON)` を呼ぶ関数(MirBuilder)。
|
||||
- [ ] `MIR(JSON) → PREP(MIR)` を呼ぶ関数(AotPrep + numeric_core)。
|
||||
- [ ] `MIR(JSON) → 実行/EXE` を呼ぶ関数(VM/LLVM)。
|
||||
- [ ] `launcher.hako` の `Main.main(args)` から、上記インターフェースを呼び分ける最小のモード分岐を定義する設計メモを追加(実装は後続フェーズでもよい)。
|
||||
|
||||
### 3. selfhost 用ビルドスクリプトの足場
|
||||
|
||||
- [ ] `tools/selfhost/` ディレクトリを作成(存在しない場合)。
|
||||
- [ ] `tools/selfhost/build_stage1.sh`(仮称)の skeleton を追加:
|
||||
- [ ] 必要な Hako モジュールセット(Stage‑B / MirBuilder / AotPrep / runtime)をコメントで列挙。
|
||||
- [ ] 現時点では no-op または「未実装」のメッセージだけにして、呼び出し位置を固定。
|
||||
- [ ] README(本ファイル)に build_stage1.sh の役割と将来の AOT 手順(.hako→MIR→ny-llvmc→EXE)を文章で書いておく。
|
||||
|
||||
### 4. Stage0 ↔ Stage1 の切り替えポリシー
|
||||
|
||||
- [ ] docs に「普段は Stage1 の `hakorune` を使い、壊れたときだけ Stage0 の `hakorune-rust` を直接叩く」という運用例を追記。
|
||||
- [ ] `tools/selfhost/` に便利ラッパの案をメモしておく:
|
||||
- 例: `hako-vm.sh`(Stage1 + `--backend vm`)、`hako-exe.sh`(Stage1 + `--backend llvm --exe`)。
|
||||
|
||||
### 5. 将来の自己ホストルートへの接続
|
||||
|
||||
- [ ] Stage1 の `Main.main(args)` から「自分自身を再ビルドする」エントリポイント名だけ決めておく(例: `selfhost_build_main`)。
|
||||
- [ ] Phase 26 以降で、このエントリポイントを `tools/selfhost/build_stage1.sh` から呼ぶ形にする想定を書き残す。
|
||||
|
||||
このチェックリストは「コードを書く前に何を決めておくか」と「どこから小さく実装を始めるか」の順序を示すだけで、実装自体は後続フェーズで少しずつ進める前提だよ。
|
||||
|
||||
## このフェーズでやらないこと
|
||||
|
||||
- Rust コードの削除や広域リファクタ(責務の再ラベリングとロードマップ策定に留める)。
|
||||
- Stage1 バイナリを CI で標準に昇格させる変更(ローカル開発用の設計段階に留める)。
|
||||
- Stage1 ランチャー(フル CLI モード切り替え)の実装本体(このフェーズでは Ny Executor 最小 EXE まで)。
|
||||
|
||||
Related docs:
|
||||
- `docs/development/roadmap/phases/phase-25/README.md` … Stage0/Ring0-Ring1 再編と numeric_core BoxCall→Call パスのまとめ。
|
||||
- `docs/development/runtime/cli-hakorune-stage1.md` … Stage1 hakorune CLI のサブコマンド設計と Stage0 との役割分離。
|
||||
- `docs/development/roadmap/phases/phase-25.1a/README.md` … Stage1 build パイプライン(Program→MIR/selfhost AOT)のホットフィックス計画。***
|
||||
91
docs/development/roadmap/phases/phase-25.1a/README.md
Normal file
91
docs/development/roadmap/phases/phase-25.1a/README.md
Normal file
@ -0,0 +1,91 @@
|
||||
# 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-15 時点)
|
||||
|
||||
- `tools/selfhost/build_stage1.sh`:
|
||||
- 現在の entry: `lang/src/runner/launcher.hako`(Stage1 CLI ランチャー)。
|
||||
- 内部で `tools/selfhost_exe_stageb.sh` → `tools/hakorune_emit_mir.sh` を呼び出しているが、MIR 生成フェーズで失敗。
|
||||
- ログ: `[FAIL] Program→MIR delegate failed (provider+legacy)`。
|
||||
|
||||
- `tools/hakorune_emit_mir.sh` — Program→MIR 部分:
|
||||
1. Stage‑B(`compiler_stageb.hako`):
|
||||
- `Stage-B: SUCCESS - Generated Program(JSON)` まで成功(`"version":0,"kind":"Program"` を含む JSON が得られている)。
|
||||
2. 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` 自体は解消済み。
|
||||
- 現在は text-merge 後の巨大一時ファイルに対して `Parse error: Invalid expression at line <N>` が出ており、prelude 連結のどこかで Stage‑3 構文と合わない断片が残っている状態(selfhost builder は引き続き要調査)。
|
||||
3. provider 経路(`try_provider_emit` → `env.mirbuilder.emit`):
|
||||
- 当初は `env.mirbuilder.emit` 実行時に `[mirbuilder/parse/error] undefined variable: args` により失敗していたが、Rust 側の Program→MIR ルート修正によりこのエラーは解消済み。現在は provider 経路経由で `launcher.hako` から MIR(JSON) を安定して生成できている。
|
||||
4. legacy CLI 経路(`--program-json-to-mir`):
|
||||
- Program(JSON) を一時ファイルに書いて `nyash --program-json-to-mir` を叩くフォールバックも rc!=0 で終了していたが、Phase 25.1a では provider 経路の安定化を優先するため、現在は原則退避路とし、日常の導線では利用しない。
|
||||
|
||||
- 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 ...` 系のエラーが残っている。
|
||||
|
||||
## フェーズ内タスク(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」を完全に排除する。
|
||||
- [ ] 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 のコードをシンプルに保つ。
|
||||
- [x] Stage‑3 パーサで予約語となった `fn` をローカル変数名として使っている箇所(例: `lang/src/mir/builder/func_lowering.hako` の `local fn = func_jsons.length()`)をリネームし、`Unexpected token FN, expected identifier` を根本的に解消する。
|
||||
- [ ] `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 の整理
|
||||
|
||||
- [x] 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 復旧
|
||||
|
||||
- [x] `NYASH_LLVM_SKIP_BUILD=1 tools/selfhost/build_stage1.sh --out /tmp/hakorune-dev` が 0 exit すること(現状は selfhost builder を既定OFFにし、provider ルートで MIR を生成)。
|
||||
- [ ] 生成された `/tmp/hakorune-dev` について:
|
||||
- [ ] `./hakorune-dev emit program-json apps/selfhost-minimal/main.hako` が Program(JSON v0) を出力すること。
|
||||
- [ ] `./hakorune-dev emit mir-json apps/selfhost-minimal/main.hako` が MIR(JSON) を出力すること。
|
||||
- [ ] `./hakorune-dev build exe -o /tmp/hako_min apps/selfhost-minimal/main.hako` で簡単な EXE が生成され、実行して 0 exit を返すこと。
|
||||
- [ ] `tools/selfhost_exe_stageb.sh` についても同様に `.hako → EXE` のスモークを通しておく(少なくとも launcher.hako / apps/selfhost-minimal/main.hako の2ケース)。
|
||||
|
||||
## 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 パイプラインの上に乗せる形で進める。
|
||||
|
||||
## 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) → EXE` selfhost AOT パス。***
|
||||
- Notes:
|
||||
- selfhost builder (`HAKO_SELFHOST_BUILDER_FIRST=1`) は依然として parse error で落ちるため、Phase 25.1a では **既定を 0(無効)** に切り替え、provider ルートを安定化させた。
|
||||
- builder-first 経路の再有効化は Phase 25.1a 中の後続タスクとして扱う。
|
||||
47
docs/development/roadmap/phases/phase-25.2/README.md
Normal file
47
docs/development/roadmap/phases/phase-25.2/README.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Phase 25.2 — Numeric Microbench & EXE Tuning
|
||||
|
||||
Status: proposal(Phase 25 / 25.1 の後続フェーズ)
|
||||
|
||||
## ゴール
|
||||
|
||||
- Phase 25 で整備した numeric core / AotPrep / `NYASH_AOT_NUMERIC_CORE` の仕組みを前提に、
|
||||
- `matmul_core` を含む numeric 系 microbench(LLVM/EXE)を安定して実行できる状態にする。
|
||||
- EXE/LLVM ラインでの性能を観測しやすくし、「VM 側の自己ホスト部分の重さ」と「生成された EXE の速さ」を分離して評価できるようにする。
|
||||
- Phase 25.1 の Stage0/Stage1 設計に沿って、将来的に Stage1(EXE) から microbench を叩く土台を作る。
|
||||
|
||||
## スコープ(Phase 25.2)
|
||||
|
||||
### 1) matmul_core microbench EXE ラインの安定化
|
||||
|
||||
- 対象:
|
||||
- `tools/perf/microbench.sh --case matmul_core --backend llvm --exe ...`
|
||||
- 目標:
|
||||
- `NYASH_AOT_NUMERIC_CORE=1` ON の状態で、`matmul_core` microbench が LLVM/EXE 経路で安定して実行できること。
|
||||
- STRICT(`NYASH_AOT_NUMERIC_CORE_STRICT=1`)は AotPrep 後の MIR(JSON) に対してのみ適用し、pre-AotPrep の MIR emit/VM 起動を阻害しないこと。
|
||||
- タスク(例):
|
||||
- provider 経路(`env.mirbuilder.emit`)の安定化と診断強化(VM ハングや長時間化の原因切り分け)。
|
||||
- `NYASH_LLVM_DUMP_MIR_IN` を使った実際の `matmul_core` MIR 形状の観察と numeric_core パスの適用確認。
|
||||
|
||||
### 2) コンパイル経路とベンチ経路の分離
|
||||
|
||||
- 問題意識:
|
||||
- 現状 microbench は「`.hako → Program(JSON) → MIR(JSON) → AotPrep → ny-llvmc → EXE → 実行」を 1 コマンドで行うため、selfhost VM 部分の重さと EXE 実行の重さが混ざりやすい。
|
||||
- 方針:
|
||||
- `matmul_core` 用に:
|
||||
- 一度だけ MIR(JSON) を生成し、その JSON を複数回再利用するモードを用意する(例: `tools/dev_numeric_core_prep.sh` + `ny-llvmc` 直呼び)。
|
||||
- microbench は「既に生成済みの EXE を何度も実行する」モードと、「.hako からフルコンパイルする」モードを分ける。
|
||||
|
||||
### 3) numeric_core STRICT モードの本番運用ルール
|
||||
|
||||
- Phase 25 では:
|
||||
- STRICT は AotPrep 後の MIR(JSON) に対してのみチェックするように整理済み。
|
||||
- pre-AotPrep 生 MIR へのチェックは Rust 側から削除済み。
|
||||
- Phase 25.2 での追加整理:
|
||||
- microbench / CI で `NYASH_AOT_NUMERIC_CORE_STRICT=1` を使う場合のガイドラインを docs に追記。
|
||||
- STRICT 違反時の代表的な原因(numeric_core がマッチできないパターン)を例示し、デバッグ手順を `DEBUG_NUMERIC_CORE.md` に統合。
|
||||
|
||||
## スコープ外
|
||||
|
||||
- Stage0/Stage1 の設計・導線整理自体は Phase 25.1 の責務(本フェーズでは利用側の調整に留める)。
|
||||
- 新しい numeric ABI の機能追加や IntArrayCore/MatI64 の API 拡張(根幹設計は Phase 25 側で担当)。
|
||||
|
||||
118
docs/development/roadmap/phases/phase-25/DEBUG_NUMERIC_CORE.md
Normal file
118
docs/development/roadmap/phases/phase-25/DEBUG_NUMERIC_CORE.md
Normal file
@ -0,0 +1,118 @@
|
||||
# Phase 25 — numeric_core / AotPrep デバッグ指針
|
||||
|
||||
Status: memo(Claude Code / Codex 向け運用ガイド)
|
||||
|
||||
Phase 25 で導入した `numeric_core.hako`(BoxCall→Call 変換パス)が動かない・怪しいときに辿るルートをまとめる。
|
||||
Rust 側の修正に入る前に、ここに沿って Hako 側の構造・設定を確認する。
|
||||
|
||||
## 1. まず「パスが本当に動いているか」を確認する
|
||||
|
||||
### 1-1. using / nyash.toml マッピング
|
||||
|
||||
- `nyash.toml` に次のマッピングが存在するか確認する:
|
||||
- `selfhost.llvm.ir.aot_prep.passes.numeric_core = "lang/src/llvm_ir/boxes/aot_prep/passes/numeric_core.hako"`
|
||||
- `numeric_core` が見つからない場合でも致命的エラーにならず、単にパスがロードされないだけ、という挙動になりがちなので注意する。
|
||||
|
||||
### 1-2. AotPrep.run_json 経由での実行確認
|
||||
|
||||
- `tools/hakorune_emit_mir.sh` を使って、AotPrep が numeric_core を呼んでいるかを確認する:
|
||||
- `HAKO_APPLY_AOT_PREP=1`
|
||||
- `NYASH_AOT_NUMERIC_CORE=1`
|
||||
- `NYASH_AOT_NUMERIC_CORE_TRACE=1`
|
||||
- 期待するログ:
|
||||
- `[aot/numeric_core] PASS RUNNING`
|
||||
- MatI64 検出や変換結果に関するメッセージ。
|
||||
- これらが 1 行も出ない場合:
|
||||
- `using selfhost.llvm.ir.aot_prep.passes.numeric_core as AotPrepNumericCoreBox` が解決できていない
|
||||
- もしくは `NYASH_AOT_NUMERIC_CORE` が子プロセスに渡っていない
|
||||
可能性が高い。
|
||||
|
||||
## 2. standalone で numeric_core を動かしてみる
|
||||
|
||||
### 2-1. 最小 MIR(JSON) 入力を用意する
|
||||
|
||||
- `MatI64.mul_naive` を 1 回だけ呼ぶような小さな .hako を用意し、MIR(JSON v0) を吐き出す:
|
||||
- 例: `tmp/matmul_core_mir2.json`
|
||||
- 重要なのは、JSON 内に次の 2 種類の命令が含まれていること:
|
||||
- `"op":"const_string", "value":"MatI64"` 相当の文字列定数。
|
||||
- `"op":"boxcall", "box":..., "method":"mul_naive", ...` の BoxCall。
|
||||
|
||||
### 2-2. numeric_core.hako を直接呼ぶ
|
||||
|
||||
- selfhost 側で `AotPrepNumericCoreBox.run(json_text)` を直接呼び出す小さなハーネスを作るか、既存のテストスクリプト(例: `/tmp/run_numeric_core_test.sh`)を流用する。
|
||||
- 期待する振る舞い:
|
||||
- 型テーブルに MatI64 関連のエントリが 2〜3 件登録される。
|
||||
- BoxCall が `Call("NyNumericMatI64.mul_naive", args=[receiver, ...])` に 1 件だけ変換される。
|
||||
- 元の BoxCall 行は JSON から削除されている。
|
||||
|
||||
## 3. JSON スキャンの典型的な落とし穴
|
||||
|
||||
### 3-1. JSON 全体を 1 オブジェクトとして扱ってしまうバグ
|
||||
|
||||
- 過去のバグ:
|
||||
- `text.indexOf("{", pos)` でオブジェクト開始を探した結果、JSON 全体のルート `{` を拾ってしまい、
|
||||
- `instructions` 配列の全要素を 1 つの巨大な「inst」として扱ってしまった。
|
||||
- 結果:
|
||||
- 最初の命令の `dst:0` と、どこかにある `"MatI64"` 文字列が同じオブジェクトに含まれてしまい、型推論が完全に壊れる。
|
||||
|
||||
### 3-2. 修正パターン(op-marker-first)
|
||||
|
||||
- オブジェクト境界は次の手順で決める:
|
||||
1. `pos` 以降で `"op":"` を検索する。
|
||||
2. 見つかった位置から後方へ `lastIndexOf("{", op_pos)` して、その命令オブジェクトの開始位置を求める。
|
||||
3. その開始位置から `_seek_object_end(text, obj_start)` を呼んで終了位置を決める。
|
||||
- ポイント:
|
||||
- `_seek_object_end` 自体は「開始位置を与えればそのオブジェクトの終端を返す」役割に限定し、
|
||||
- 「どの `{` を開始とみなすか」という責務は外側のスキャンロジックに持たせる。
|
||||
|
||||
## 4. BoxCall→Call 変換結果の確認ポイント
|
||||
|
||||
### 4-1. 変換前後の JSON 断片
|
||||
|
||||
- 変換前(例):
|
||||
- `{"args":[3],"box":2,"dst":4,"method":"mul_naive","op":"boxcall"}`
|
||||
- 変換後(期待):
|
||||
- `{"dst":4,"op":"call","name":"NyNumericMatI64.mul_naive","args":[2,3]}`
|
||||
|
||||
チェックリスト:
|
||||
- [ ] `op:"boxcall"` が `"op":"call"` に変わっている。
|
||||
- [ ] `name` フィールドに `NyNumericMatI64.mul_naive` が入っている。
|
||||
- [ ] `args` の先頭が receiver(元の `box` のレジスタ)になっている。
|
||||
- [ ] 元の BoxCall 行が JSON から消えている。
|
||||
|
||||
### 4-2. MatI64 型検出ログ
|
||||
|
||||
- TRACE=1 のとき、次のようなログが出ているか確認する:
|
||||
- `[aot/numeric_core] MatI64.new() result at r2`
|
||||
- `[aot/numeric_core] MatI64.new() result at r3`
|
||||
- `[aot/numeric_core] type table size: 3`
|
||||
- これらが出ていない場合:
|
||||
- `"MatI64"` 文字列定数の検出に失敗しているか、
|
||||
- `MatI64.new` のパターンが期待とずれている(関数名・引数数など)のどちらか。
|
||||
|
||||
## 5. VM/LLVM ラインでの最終確認
|
||||
|
||||
### 5-1. VM ライン
|
||||
|
||||
- `NYASH_AOT_NUMERIC_CORE=0`:
|
||||
- 既存挙動が変わっていないか確認する(BoxCall のままでも OK)。
|
||||
- `NYASH_AOT_NUMERIC_CORE=1`:
|
||||
- VM 実行結果が OFF のときと一致することを確認する。
|
||||
- 可能であれば、AotPrep 適用後の MIR(JSON) を一度ダンプし、`boxcall` が消えて `call` になっていることを目視確認する。
|
||||
|
||||
### 5-2. LLVM ライン
|
||||
|
||||
- `NYASH_AOT_NUMERIC_CORE=1 NYASH_SKIP_TOML_ENV=1 NYASH_DISABLE_PLUGINS=1` など、最小構成で `--backend llvm --exe` による実行を行う。
|
||||
- 期待すること:
|
||||
- LLVM コンパイルがエラーなく通る。
|
||||
- VM ラインと同じ数値結果が得られる。
|
||||
- IR ダンプを取った場合、`NyNumericMatI64.mul_naive` が通常の `call` として現れ、BoxCall 特有のノードは存在しない。
|
||||
|
||||
## 6. それでも原因が分からないとき
|
||||
|
||||
- ここまでの手順を踏んでも原因が特定できない場合は、次の情報を CURRENT_TASK.md に貼ってから LLM にバトンタッチする:
|
||||
- AotPrep 適用前後の MIR(JSON) の短い抜粋(変換対象の関数のみ)。
|
||||
- `NYASH_AOT_NUMERIC_CORE_TRACE=1` 時点の `[aot/numeric_core]` ログ。
|
||||
- 使用した .hako ファイル名とベンチ名(例: `matmul_core`)。
|
||||
- そのうえで、「numeric_core のどこまで動いていて、どの段階で期待と違うか」を一言で書いておくと、後続の LLM(Claude Code など)がすぐに再現・解析しやすくなる。
|
||||
|
||||
@ -1,6 +1,66 @@
|
||||
# Phase 25 — 脱Rustランタイム / Ring0-Ring1 再編
|
||||
|
||||
Status: proposal(設計フェーズ・実装は後続ホスト想定)
|
||||
**Status: ✅ MVP COMPLETED** (2025-11-15)
|
||||
|
||||
## 🎉 Phase 25 MVP 完全成功!
|
||||
|
||||
**numeric_core BoxCall→Call 変換** が完全動作確認済み!
|
||||
|
||||
### 主要成果 (2025-11-14 → 2025-11-15)
|
||||
|
||||
1. **✅ 型伝播システム完全動作**:
|
||||
- 4回反復型伝播で copy → phi → copy チェーン完全対応
|
||||
- MatI64 型を15レジスタまで正しく追跡
|
||||
- PHI 検出バグ修正(8d9bbc40): `indexOf("{")` → `indexOf("\"op\":\"")`
|
||||
|
||||
2. **✅ 両SSAパターン対応確認**:
|
||||
- 冗長版(13 PHI nodes): test_direct.json, test_matmul_debug.json
|
||||
- 最適化版(1 PHI node): test_matmul_with_wrapper.json, microbench_matmul_core.json
|
||||
- すべてのパターンで BoxCall → Call 変換成功 ✅
|
||||
|
||||
3. **✅ 環境変数伝播修正** (3d082ca1):
|
||||
- microbench.sh に `NYASH_AOT_NUMERIC_CORE` と `NYASH_AOT_NUMERIC_CORE_TRACE` 伝播追加
|
||||
- `tools/perf/microbench.sh --case matmul_core --backend llvm --exe` で完全動作
|
||||
|
||||
4. **✅ ログ転送問題根治**:
|
||||
- hakorune_emit_mir.sh の provider 経路にログ転送追加(ユーザー実装)
|
||||
- `[aot/numeric_core]` ログが NYASH_AOT_NUMERIC_CORE_TRACE=1 で正しく表示
|
||||
|
||||
5. **✅ 開発ワークフロー確立**:
|
||||
- `tools/dev_numeric_core_prep.sh` で環境変数自動設定
|
||||
- 推奨開発フロー確立・ドキュメント化完了
|
||||
|
||||
### 変換例
|
||||
|
||||
**Before** (BoxCall):
|
||||
```json
|
||||
{"args":[15],"box":7,"dst":53,"method":"mul_naive","op":"boxcall"}
|
||||
```
|
||||
|
||||
**After** (Call):
|
||||
```json
|
||||
{"dst":53,"op":"call","name":"NyNumericMatI64.mul_naive","args":[7,15]}
|
||||
```
|
||||
|
||||
### 既知の制限・次フェーズ
|
||||
|
||||
- `NYASH_AOT_NUMERIC_CORE_STRICT=1`: 検証関数実装済みだが未使用(タイミング問題)
|
||||
- microbench 性能チューニング: **Phase 25.2** に移管
|
||||
- 他の numeric メソッド(add, sub, etc.): 将来対応
|
||||
|
||||
---
|
||||
|
||||
## Phase status (2025-11-14 - 初期バージョン):
|
||||
- このフェーズでは「Ring0/Ring1 の設計」と「numeric_core (MatI64.mul_naive) の BoxCall→Call 降ろし用 AotPrep パス」の MVP 実装までをカバーする。
|
||||
- `NYASH_AOT_NUMERIC_CORE=1` + AotPrep.run_json による MatI64.mul_naive 降ろしは、代表的な MIR パターン(13 PHI / 1 PHI 両方)で動作確認済み。
|
||||
- `NYASH_AOT_NUMERIC_CORE_STRICT=1` は AotPrep 後の MIR(JSON) に対してのみ BoxCall(mul_naive) 残存をチェックするように整理済み(pre-AotPrep の MirBuilder には干渉しない)。
|
||||
- microbench(`tools/perf/microbench.sh --case matmul_core --backend llvm --exe`)による EXE/LLVM ベンチ統合と性能チューニングは **Phase 25.2** に移管する。
|
||||
|
||||
Related docs:
|
||||
- `docs/development/roadmap/phases/phase-25.1/README.md` … Stage0(Rust bootstrap)/Stage1(Hakorune selfhost)によるバイナリ二段構えの設計。
|
||||
- `docs/development/runtime/NUMERIC_ABI.md` … IntArrayCore/MatI64 など numeric ABI の関数契約。
|
||||
- `docs/development/runtime/system-hakorune-subset.md` … Ring1/System Hakorune サブセットの範囲と責務。
|
||||
- `docs/development/runtime/ENV_VARS.md` … `NYASH_AOT_NUMERIC_CORE` など Phase 25 関連の環境変数。
|
||||
|
||||
## ゴール
|
||||
|
||||
|
||||
241
docs/development/runtime/cli-hakorune-stage1.md
Normal file
241
docs/development/runtime/cli-hakorune-stage1.md
Normal file
@ -0,0 +1,241 @@
|
||||
# Stage1 Hakorune CLI Design(Proposal)
|
||||
|
||||
Status: design-only(Phase 25.1 時点では仕様策定と導線の整理まで)
|
||||
|
||||
## ゴール
|
||||
|
||||
- 「ユーザー/開発者が日常叩く CLI」としての `hakorune`(Stage1 selfhost バイナリ)のインターフェースを定義する。
|
||||
- 既存の Rust CLI(Stage0: `nyash`)が提供している機能を、「パイプライン志向」の小さなサブコマンドに整理し直す。
|
||||
- Stage1 は **パイプラインのオーケストレーションのみ** 担当し、MIR 実行・LLVM コード生成などの実行コアは Stage0/Rust に委譲する。
|
||||
|
||||
## バイナリとプロセスモデル
|
||||
|
||||
- Stage0(Rust CLI / ランタイムサービス)
|
||||
- 実体: `target/release/nyash`(将来: `hakorune-bootstrap`)
|
||||
- 役割: プロセス起動・VM/LLVM コア・ny-llvmc 呼び出しなどの「Ring0」。
|
||||
- Ny 側からは `env.mirbuilder.emit` / `env.codegen.emit_object` / `env.codegen.link_object` などの extern 名で見える。
|
||||
- Stage1 実行時は「CLI として」ではなく、これらのランタイムサービス層(C-ABI/extern)として利用することを前提とする。
|
||||
- Stage1(Hakorune selfhost CLI)
|
||||
- 実体: `target/selfhost/hakorune`(Phase 25.1 では Ny Executor プロトタイプ)。
|
||||
- 役割: `.hako → Program(JSON) → MIR(JSON) → 実行/EXE` というパイプラインの制御。
|
||||
- 将来的には、ユーザーが直接叩く標準 CLI として昇格(`PATH` に入れる対象)。
|
||||
|
||||
プロセスモデルの原則:
|
||||
- Stage1 は **自分で VM/LLVM を実装しない**。常に Ring0 のサービス(env.codegen/env.mirbuilder, NyRT/ny-llvmc 等)を経由して実行・AOT する。
|
||||
- Stage1 CLI は「どのステージまで進めるか」と「どのバックエンドで実行/ビルドするか」を宣言的に指定するだけに留める。
|
||||
- Stage1 バイナリ自体は Stage0 の CLI からは独立しており、Stage0 はあくまで「ブートストラップおよびランタイムサービス提供者」として扱う。
|
||||
|
||||
## トップレベル構文
|
||||
|
||||
```text
|
||||
hakorune <command> [<subcommand>] [options] [-- script_args...]
|
||||
```
|
||||
|
||||
- `command`/`subcommand` は **パイプラインの到達点** を表す。
|
||||
- `options` は主に:
|
||||
- 入出力ファイル
|
||||
- backend 選択(vm/llvm/pyvm)
|
||||
- profile(dev/ci/lite 等のプリセット)
|
||||
を指定する。
|
||||
- `--` 以降はユーザープログラムに渡す引数(既存の `NYASH_SCRIPT_ARGS_JSON` 経路と整合させる)。
|
||||
|
||||
## コマンド一覧(MVP 案)
|
||||
|
||||
| コマンド | 役割 |
|
||||
|-----------------------------------|-------------------------------------------|
|
||||
| `run` | .hako をコンパイルして実行(既定 VM) |
|
||||
| `build exe` | .hako からネイティブ EXE を AOT ビルド |
|
||||
| `emit program-json` | Stage‑B で Program(JSON v0) を出力 |
|
||||
| `emit mir-json` | Program(JSON) → MIR(JSON) を出力 |
|
||||
| `check` | 将来の構文/型/using チェック(予約) |
|
||||
|
||||
Phase 25.1 では、既存スクリプト置き換えに近い **`emit mir-json` / `build exe` を中心** に進め、`run`/`check` は設計レベルに留める。
|
||||
|
||||
## `run` コマンド
|
||||
|
||||
```text
|
||||
hakorune run [options] <entry.hako> [-- script_args...]
|
||||
```
|
||||
|
||||
### 意味論
|
||||
|
||||
- `.hako` ソースを Stage‑B → MirBuilder → AotPrep まで通し、選択された backend で実行する。
|
||||
- 実行経路:
|
||||
- backend=`vm` : Stage0 Rust VM(現行 `--backend vm` 相当)
|
||||
- backend=`llvm` : ny-llvmc+NyRT を通した EXE 実行(実装は後続フェーズ)
|
||||
- backend=`pyvm` : PyVM 経路(Phase‑15 の方針に従い、開発/検証専用)
|
||||
- プログラムの戻り値をプロセスの exit code にマッピング(現行 Rust CLI と同じ)。
|
||||
|
||||
### 主なオプション案
|
||||
|
||||
- `--backend {vm|llvm|pyvm}`(既定: `vm`)
|
||||
- `--profile {dev|ci|lite|strict}`
|
||||
- `dev` : 詳細ログ・トレースを有効(Phase 15/25 の既存 ENV を束ねる)
|
||||
- `ci` : 安定志向・プラグイン無効化など(現行 quick profile 相当)
|
||||
- `lite` : macro/using など重い機能をオフ
|
||||
- `strict`: 各種 STRICT トグルを有効(AotPrep/Verifier 等)
|
||||
- `--using-path <paths>`: `tools/dev_selfhost_loop.sh` の `--using-path` と一致させる。
|
||||
- `--json-only`(将来): Stage‑B までで止め、Program(JSON v0) を stdout に出力。
|
||||
|
||||
### Stage0 との関係
|
||||
|
||||
- Stage1 `run` は **直接 MIR を実行しない**。
|
||||
- 代わりに:
|
||||
1. Stage1 内で Program(JSON)/MIR(JSON) を構築。
|
||||
2. `NYASH_VERIFY_JSON` / `NYASH_JSON_ONLY` / `NYASH_SCRIPT_ARGS_JSON` など既存の ENV プロトコルを用いて Stage0 プロセスを呼び出す。
|
||||
- これにより「Rust 側の VM/LLVM コアはそのまま」「CLI 表面だけ selfhost 化」という段階移行が可能になる。
|
||||
|
||||
## `build exe` コマンド
|
||||
|
||||
```text
|
||||
hakorune build exe [options] <entry.hako>
|
||||
```
|
||||
|
||||
### 意味論
|
||||
|
||||
- `.hako` からネイティブ EXE を生成する高レベル API。
|
||||
- Phase 25.1 実装では、`.hako → Program(JSON v0) → MIR(JSON) → env.codegen.emit_object/link_object → EXE` までを 1 コマンドで行う。
|
||||
- 具体的な呼び出し:
|
||||
|
||||
```text
|
||||
hakorune build exe [-o <out>] [--quiet] <source.hako>
|
||||
```
|
||||
|
||||
### 意味論(Phase 25.1 実装範囲)
|
||||
|
||||
- `.hako` から EXE までのパイプライン:
|
||||
1. `.hako` → Program(JSON v0):
|
||||
- `BuildBox.emit_program_json_v0(src, null)` を呼び出し。
|
||||
- `"version":0` / `"kind":"Program"` を検査。
|
||||
2. Program(JSON v0) → MIR(JSON):
|
||||
- `MirBuilderBox.emit_from_program_json_v0(program_json, null)` を呼び出し。
|
||||
3. MIR(JSON) → object:
|
||||
- `hostbridge.extern_invoke("env.codegen", "emit_object", [mir_json])` を呼び出し、`.o` パスを取得。
|
||||
4. object → EXE:
|
||||
- `hostbridge.extern_invoke("env.codegen", "link_object", [obj_path, out?])` を呼び出し、EXE パスを取得。
|
||||
- 実行には C-API ルートの有効化が前提:
|
||||
- 例: `NYASH_LLVM_USE_CAPI=1`, `HAKO_V1_EXTERN_PROVIDER_C_ABI=1`, `NYASH_EMIT_EXE_NYRT` など。
|
||||
|
||||
### オプション(Phase 25.1 実装済み)
|
||||
|
||||
- `-o, --out <path>`:
|
||||
- 生成する EXE のパスを指定(省略時は env.codegen 側の既定パスを使用)。
|
||||
- `--quiet`:
|
||||
- 成功時のステータス出力(`[hakorune] build exe: <exe_path>`)を抑制。
|
||||
|
||||
※ `--target` / `--nyrt` / `--skip-build` などは、現時点では未実装の設計(将来の AOT プロファイル用)。***
|
||||
|
||||
## `emit program-json` コマンド
|
||||
|
||||
```text
|
||||
hakorune emit program-json [options] <entry.hako>
|
||||
```
|
||||
|
||||
### 意味論(Phase 25.1 実装範囲)
|
||||
|
||||
- `.hako` ソースファイル(`<entry.hako>`)を読み込み、`BuildBox.emit_program_json_v0(src, null)` を呼び出して Program(JSON v0) を生成する。
|
||||
- Phase 25.1 の実装では:
|
||||
- 入力: `<entry.hako>` パスのみ(標準入力や複数ファイルは未対応)。
|
||||
- 出力:
|
||||
- 既定: Program(JSON v0) を stdout にそのまま出力。
|
||||
- `-o/--out` 指定時: JSON はファイルに書き込み、stdout には短いステータス行のみを出力。
|
||||
- バリデーション: `"version":0` と `"kind":"Program"` を含まない場合はエラー終了(exit code 92)。
|
||||
|
||||
### オプション(Phase 25.1 実装済み)
|
||||
|
||||
- `-o, --out <file>`:
|
||||
- Program(JSON v0) を `<file>` に書き出す。
|
||||
- スクリプト互換性のため、stdout には短いメッセージ(タグ)だけを出す(JSON 本文は出さない)。
|
||||
- `--quiet`:
|
||||
- `-o/--out` と組み合わせた場合に、ステータス行も抑制し「完全に無音」のファイル出力にする。
|
||||
- `--quiet` 単独では意味を持たず、現状は無視される(将来のログ制御用に予約)。
|
||||
|
||||
## `emit mir-json` コマンド
|
||||
|
||||
```text
|
||||
hakorune emit mir-json [options] <entry.hako>
|
||||
```
|
||||
|
||||
### 意味論(Phase 25.1 実装範囲)
|
||||
|
||||
- Program(JSON v0) から MIR(JSON) を出す経路に加えて、`.hako` から Program(JSON v0)→MIR(JSON) まで進める経路も実装済み。
|
||||
- 実際の CLI 呼び出しは主に次の2通り:
|
||||
|
||||
```text
|
||||
# 1) Program(JSON v0) から MIR(JSON)
|
||||
hakorune emit mir-json --from-program-json <program.json>
|
||||
|
||||
# 2) .hako から直接 MIR(JSON) まで
|
||||
hakorune emit mir-json [-o <out>] [--quiet] <source.hako>
|
||||
```
|
||||
|
||||
- 処理内容:
|
||||
- `--from-program-json` 指定時:
|
||||
- FileBox で `<program.json>` を読み込み、文字列として取得。
|
||||
- `MirBuilderBox.emit_from_program_json_v0(program_json, null)` を呼び出して MIR(JSON) を生成。
|
||||
- `.hako` 直接指定時:
|
||||
- FileBox で `<source.hako>` を読み込み、`BuildBox.emit_program_json_v0(src, null)` で Program(JSON v0) を生成。
|
||||
- `"version":0` / `"kind":"Program"` を検査した上で、その Program(JSON v0) を `MirBuilderBox.emit_from_program_json_v0` に渡す。
|
||||
- 成功時は MIR(JSON) を stdout に出力(`-o/--out` 指定時はファイル出力)し、exit code 0。
|
||||
- 失敗時(ファイルエラー / builder null など)はエラーメッセージ+exit code 92。
|
||||
|
||||
### オプション(Phase 25.1 実装済み)
|
||||
|
||||
- `--from-program-json <file>`:
|
||||
- Program(JSON v0) を含むファイルパスを指定。
|
||||
- `.hako` との併用は禁止(両方指定した場合はエラー)。
|
||||
- `-o, --out <file>`:
|
||||
- MIR(JSON) を `<file>` に書き出す。
|
||||
- stdout に MIR(JSON) を直接出さなくなる(短いステータス行のみ)。
|
||||
- `--quiet`:
|
||||
- `-o/--out` と併用時にステータス行も抑制し、MIR(JSON) をファイルにだけ書き込む。
|
||||
|
||||
※ `--force-jsonfrag` / `--normalize-provider` などは、引き続き設計のみで未実装。
|
||||
|
||||
## `check` コマンド(予約)
|
||||
|
||||
```text
|
||||
hakorune check [options] <entry.hako>
|
||||
```
|
||||
|
||||
### 意味論(将来)
|
||||
|
||||
- Stage‑B / MirBuilder / AotPrep を **実行せずに**:
|
||||
- 構文
|
||||
- using 解決
|
||||
- System Hakorune subset 制約
|
||||
などを検証するためのエントリポイント。
|
||||
|
||||
- 実装は `.hako` 側で `tools/hako-check` 相当のロジックを呼び出す想定。
|
||||
- Phase 25.1 では「名前予約」と「インターフェース定義」のみを行い、実装は Phase 26 以降。
|
||||
|
||||
## Stage0 / Stage1 の責務分離(CLI 視点)
|
||||
|
||||
- Stage1(hakorune)
|
||||
- ユーザー向け CLI surface。
|
||||
- パイプライン選択とオプション解釈。
|
||||
- JSON v0/v1 の配線・一時ファイル管理。
|
||||
- Stage0(nyash / hakorune-bootstrap)
|
||||
- VM 実行(vm/backend=vm)。
|
||||
- LLVM ハーネス/ny-llvmc 経由の AOT(backend=llvm)。
|
||||
- env.codegen / env.mirbuilder などのホストブリッジ提供。
|
||||
|
||||
原則:
|
||||
- Stage1 は **新しい意味論・最適化ロジックを持たない**。
|
||||
- Stage1 CLI は「どの Stage0/ny-llvmc サービスをどう呼ぶか」を決める **構造レイヤ**。
|
||||
|
||||
## フェーズ別導入計画(CLI 観点)
|
||||
|
||||
- Phase 25.1
|
||||
- `build_stage1.sh` による Ny Executor EXE(`target/selfhost/hakorune`)を用意。
|
||||
- 本ドキュメントで CLI サブコマンドと引数の仕様を固定。
|
||||
- `hakorune emit mir-json` / `hakorune build exe` に対応する内部 API を `.hako` 側で設計(実装は最小限 or 後続)。
|
||||
- Phase 26 以降
|
||||
- `run` サブコマンドを実装し、日常的な `hakorune run apps/APP/main.hako` 導線を整備。
|
||||
- 既存の selfhost スクリプト(`selfhost_build.sh` / `hakorune_emit_mir.sh` / `selfhost_exe_stageb.sh`)を段階的に CLI 経由に移行。
|
||||
- `check` を `.hako` 側の hako-check ライブラリに接続。
|
||||
- Stage1 → Stage1' の自己ホストサイクルを検証する:
|
||||
- Stage1 が自分自身(launcher/runner/CLI を含む)を AOT して Stage1' を生成できること。
|
||||
- Stage1 / Stage1' の CLI インターフェース・代表挙動が一致することをゴールデン/スモークで確認する。
|
||||
|
||||
このファイルは「Stage1 CLI の仕様 SSOT」として扱い、実装時は本仕様を先に更新→テスト→コードの順で進める。***
|
||||
Reference in New Issue
Block a user