Phase 25.1a: selfhost builder hotfix (fn rename, docs)

This commit is contained in:
nyash-codex
2025-11-15 05:42:32 +09:00
parent 8d9bbc40bd
commit 6856922374
40 changed files with 2013 additions and 72 deletions

View File

@ -0,0 +1,241 @@
# Stage1 Hakorune CLI DesignProposal
Status: design-onlyPhase 25.1 時点では仕様策定と導線の整理まで)
## ゴール
- 「ユーザー/開発者が日常叩く CLI」としての `hakorune`Stage1 selfhost バイナリ)のインターフェースを定義する。
- 既存の Rust CLIStage0: `nyash`)が提供している機能を、「パイプライン志向」の小さなサブコマンドに整理し直す。
- Stage1 は **パイプラインのオーケストレーションのみ** 担当し、MIR 実行・LLVM コード生成などの実行コアは Stage0/Rust に委譲する。
## バイナリとプロセスモデル
- Stage0Rust 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として利用することを前提とする。
- Stage1Hakorune 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
- profiledev/ci/lite 等のプリセット)
を指定する。
- `--` 以降はユーザープログラムに渡す引数(既存の `NYASH_SCRIPT_ARGS_JSON` 経路と整合させる)。
## コマンド一覧MVP 案)
| コマンド | 役割 |
|-----------------------------------|-------------------------------------------|
| `run` | .hako をコンパイルして実行(既定 VM |
| `build exe` | .hako からネイティブ EXE を AOT ビルド |
| `emit program-json` | StageB で 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` ソースを StageB → MirBuilder → AotPrep まで通し、選択された backend で実行する。
- 実行経路:
- backend=`vm` : Stage0 Rust VM現行 `--backend vm` 相当)
- backend=`llvm` : ny-llvmcNyRT を通した EXE 実行(実装は後続フェーズ)
- backend=`pyvm` : PyVM 経路Phase15 の方針に従い、開発/検証専用)
- プログラムの戻り値をプロセスの 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`(将来): StageB までで止め、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>
```
### 意味論(将来)
- StageB / MirBuilder / AotPrep を **実行せずに**:
- 構文
- using 解決
- System Hakorune subset 制約
などを検証するためのエントリポイント。
- 実装は `.hako` 側で `tools/hako-check` 相当のロジックを呼び出す想定。
- Phase 25.1 では「名前予約」と「インターフェース定義」のみを行い、実装は Phase 26 以降。
## Stage0 / Stage1 の責務分離CLI 視点)
- Stage1hakorune
- ユーザー向け CLI surface。
- パイプライン選択とオプション解釈。
- JSON v0/v1 の配線・一時ファイル管理。
- Stage0nyash / hakorune-bootstrap
- VM 実行vm/backend=vm
- LLVM ハーネスny-llvmc 経由の AOTbackend=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」として扱い、実装時は本仕様を先に更新→テスト→コードの順で進める。***