18 KiB
Current Task — Phase 15 Self‑Hosting (2025‑09‑16)
TL;DR
- 目標は「自己ホスティング達成」= Nyash製パーサで Ny → JSON v0 → Bridge → MIR 実行を安定化すること。
- PyVM は意味論の参照実行器(開発補助)。llvmlite は AOT/検証。配布やバンドル化は後回し(基礎固めが先)。
What Changed (today)
- Selfhost 経路の安定化(Python MVP 優先→PyVM 実行)。Selfhost Stage‑2(直/Bridge)スモークは緑化。
- Using/Resolver を Runner 前処理に集約し、BoxIndex(グローバル)+解決キャッシュを導入。
- nyash.toml の
[aliases]/envNYASH_ALIASES対応、候補提示、NYASH_RESOLVE_TRACE=1でトレース。 - strict プレフィクス:
NYASH_PLUGIN_REQUIRE_PREFIX=1または[plugins] require_prefix=true。 - per‑plugin meta(
prefix/require_prefix/expose_short_names)の読取導線を実装(挙動は現状据え置き)。
- nyash.toml の
- CLI
--usingを追加(--using "ns as Alias"/--using '"apps/foo.nyash" as Foo')。 - フィールドは box 先頭のみルールのリンタを Runner に追加(
NYASH_FIELDS_TOP_STRICT=1でエラー)。 - Syntax Torture スイートの実行正規化(末行比較)。一部テスト本文を Nyash 仕様に合わせて修正。
- JSON v0 仕様に Stage‑3 ノード(Break/Continue/Throw/Try)を追記。Parser Stage‑3 設計メモの現状/残課題を更新。
- LLVM smoke に Stage‑3 loop サンプル(break/continue + throw/try/catch/finally 付き)を追加(
NYASH_LLVM_STAGE3_SMOKE=1)。 - Bridge (
json_v0) に Stage‑3 throw/try の実稼働ルートを追加(NYASH_BRIDGE_THROW_ENABLE=1/NYASH_BRIDGE_TRY_ENABLE=1で MIR Throw/Catch を生成)。
Decision (Phase‑15 wrap‑up)
- MIR13 移行(PHI 非生成): Phase‑15 の締めとして、MIR 生成層(Bridge/Builder)は PHI を生成しない方針に切替。PHI 合成は LLVM 層(llvmlite/Resolver)に集約。
- LoopForm は次フェーズ(MIR18)で導入: まずは MIR14 を維持し、次フェーズで
LoopHeader/Enter/Latch等の占位命令を追加。現行 Phase‑15 は CFG パターン検知でループ搬送値を合成。 - 例外は段階導入: Throw/Catch は現行維持(Bridge ゲートで出力可)。Try/Finally の構造化は将来の TryRegion で検討。
Next Focus (Throw/Try — LLVM first)
- ブリッジ設計:
emit_degraded_throwの差し替え方針を策定し、JSON v0Tryノード → MIR 変換の仕様を決める(Stage-3 例外モデル)。 - MIR Builder/Runtime 調査: Rust VM/PyVM の
ControlFlow::Throw経路と既存 TryCatch 降格の挙動を整理。必要に応じて docs と CURRENT_TASK に反映。 - PyVM 設計: 例外モデルをどこまで Python 側に実装するか決め、最小テスト計画を用意。
- LLVM 実装方針: Throw/Try の MIR 命令を LLVM 側がどう扱うか(panic扱い or fallback)を設計し、smoke 更新案を作る。
- テスト計画: JSON フィクスチャと
tools/llvm_smoke.shを中心に Stage-3 例外用のスモーク/単体テストを整備。
※ Cranelift/JIT 系は当面対象外。ビルド時も LLVM のみを有効化(JIT 関連 feature/CI は無視)。
- llvmlite/AOT(本戦)強化 — コアコレクション配線とエントリ統一
- Array/Map の BoxCall を NyRT ハンドルAPIに直結:
- Array:
push→nyash.array.push_h、length/len→nyash.any.length_h - Map:
set→nyash.map.set_hh、get→nyash.map.get_hh、has→nyash.map.has_hh、size→nyash.any.length_h
- Array:
ny_mainを i64 戻りに統一し、Main.main/1を優先(既定 args はnew ArrayBox())。- Core Box 生成の安定化:
nyash.array.birth_h/nyash.map.birth_hを追加し、llvmlitenewは birth_h を優先。 - AOT 実行確認:
[1,2,3].length()→Result: 3{"name":"Alice","age":25}.size()→Result: 2m.has("name") ? m.get("name").length() : 0→Result: 5
- Array/Map の BoxCall を NyRT ハンドルAPIに直結:
Quick Next (today)
- いよいよ「Nyash で書く」段階へ(Self‑Hosting 実装の着手):
- ParserBox 拡張(Stage‑2 の堅牢化・回帰修正)✅ Done 2025‑09‑16
- bool/null リテラルと空 RHS(代入/return/local)を Int(0) フォールバックで正規化。
- simple assignment → Local 正常化を
==判定と共に調整。 - 三項演算子
cond ? a : bをTernaryノードに正規化し、自走スモーク追加。
- EmitterBox 拡張(JSON v0 の安定化)✅ Done 2025‑09‑16
meta.usingsを常時出力(空は[])。
- Resolver/BoxIndex の prefix メタ反映 ✅ Done 2025‑09‑16
plugin_meta_by_boxを構築し、require_prefix/expose_short_namesをresolve_using_targetへ適用。NYASH_PLUGIN_REQUIRE_PREFIXが無効でも per-plugin meta で短名禁止を検知。
- Parser Stage‑3 下地 ✅ Done 2025‑09‑16
ParserBox.stage3_enable()を追加し、Break/Continue/Throw/Try を JSON v0 に出力できるゲートを実装。--stage3CLI フラグから ParserBox へ渡す導線を追加。docs/reference/architecture/parser_mvp_stage3.mdに Stage‑3 設計を記録。
- 自己ホスト経路で Ny 実装切替のゲート準備(現状は Python MVP 優先を維持)。
- ParserBox 拡張(Stage‑2 の堅牢化・回帰修正)✅ Done 2025‑09‑16
- テスト:
source tools/dev_env.sh pyvmNYASH_VM_USE_PY=1 ./tools/selfhost_stage2_smoke.shNYASH_VM_USE_PY=1 ./tools/selfhost_stage2_bridge_smoke.sh- Torture(VM中心):
(cd tests/nyash_syntax_torture_20250916 && BACKENDS="vm" NYASH_BIN=../../target/release/nyash bash run_spec_smoke.sh) - LLVM Stage‑3 smoke (手動):
NYASH_LLVM_STAGE3_SMOKE=1 ./tools/llvm_smoke.sh release
- Runner/Bridge 実行系
--ny-parser-pipeはNYASH_PIPE_USE_PYVM=1で PyVM に委譲(exit code 判定に統一)。- 自己ホスト JSON 生成は Python MVP を優先、LLVM EXE/インラインVMを段階フォールバック。
- Runner 分割(第1弾〜第2弾):
dispatch.rsへ backend 分岐を集約、tasks.rs/build.rs/demos.rsへ職責分離。mod.rsを薄型化。
- LLVM Codegen リファクタ(第1弾〜第2弾)
codegen/utils.rsを新設しsanitize_symbol/build_const_str_mapを抽出。codegen/function.rsを追加しlower_one_functionを完全移管(呼び出しはfunction::lower_one_function)。- 旧レガシー断片コメントを除去して軽量化。機能・出力は不変。
- MIR Builder 整理(小分割)
builder/vars.rsを追加し、Lambda の自由変数収集ロジックを外出し。- 既存の
LoopBuilder/phi分割方針は維持(今後 small utils をloops.rsに抽出予定)。
Current Status
- Stage‑2: 自己ホスト → JSON v0 → PyVM の代表スモークは緑(配列/文字列/論理/if/loop)。
- Stage‑3: 構文受理のみ完了(break/continue/throw/try/catch/finally)。現時点では JSON 降格(no‑op/Expr)で安全受理。
- Runner: Using/Resolver を前処理に統合(BoxIndex/キャッシュ/strict)。
--ny-parser-pipeは PyVM 委譲(exit code 判定)。 - llvmlite/AOT: Array/Map の基本操作(push/get/set/has/size, length)が NyRT ハンドルAPIで動作。
ny_mainは i64 戻り・Main.main/1優先で起動。
Open
-
Bridge/PHI の正規化: 短絡(入れ子)における merge/PHI incoming を固定化(rhs_end/fall_bb の順序)。
-
JSON v0 の拡張方針: break/continue/try/catch/finally の表現(受け皿設計 or 受理時の事前降下)。➡
docs/reference/architecture/parser_mvp_stage3.md -
per‑plugin meta の反映:
require_prefix/expose_short_names/prefixを Resolver 挙動へ段階適用(導線は実装済み)。✅ 2025‑09‑16 prefix enforcement とテスト追加済み。 -
meの扱い: MVP はNYASH_BRIDGE_ME_DUMMY=1の仮注入を継続(将来撤去)。 -
LLVM 直結(任意): JSON v0 → LLVM の導線追加は後回し。
-
NyRT 整頓:
- FFI ヘルパー化(handles/boxing 正規化)/birth_h→new_i64x 統合/Core Box のプラグイン事前登録/FFI エクスポートのマクロ化。
-
llvmlite 整頓:
- boxcall のテーブル駆動化、追加 API(delete/keys/values など)の段階配線。
Plan (to Self‑Hosting)
- Phase‑1: Stage‑2 完了+堅牢化(今ここ)
- 正常系スモークを自己ホスト直/Bridge(PyVM)で常緑化(追加分を反映済み)。
- 進捗ガードの継続検証(不完全入力セット)。
- Phase‑2: Bridge 短絡/PHI 固定+パリティ収束
- 入れ子短絡の merge/PHI incoming を固定し、stdout 判定でスモークを緑化。
- PyVM/llvmlite パリティを常時緑(代表ケースを exit code 判定へ統一)。
- Phase‑3: 構文受理の拡張(完了)→ Bootstrap c0→c1→c1’
- 受理のみ: break/continue/throw/try-catch-finally(実行意味論は降格)。
- emit‑only で c1 を生成→既存経路にフォールバック実行、正規化 JSON 差分で等価を確認。
How to Run (dev)
- 推奨環境:
source tools/dev_env.sh pyvm(PyVM を既定。Bridge→PyVM 直送) - 自己ホスト(子経路 ON):
NYASH_USE_NY_COMPILER=1 - 安全弁:
NYASH_NY_COMPILER_TIMEOUT_MS=2000、emit‑only 既定:NYASH_NY_COMPILER_EMIT_ONLY=1
Smokes
- 無限ループ防止:
./tools/selfhost_progress_guard_smoke.sh - 自己ホスト → Interpreter(BoxCallなし集合):
./tools/selfhost_stage2_smoke.sh - 自己ホスト → JSON → PyVM(Array/String/Console 含む):
./tools/selfhost_stage2_bridge_smoke.sh
Notes / Policies
- PyVM は意味論の参照実行器として運用(exit code 判定を基本)。
- Bridge は JSON v0 → MIR 降下で PHI を生成(Phase‑15 中は現行方式を維持)。
- 配布/バンドル/EXE 化は任意の実験導線として維持(Phase‑15 の主目的外)。
Smoke Snapshot (2025‑09‑15)
- 修正:
runner/dispatch.rsにvm分岐が欠落しており--backend vmが interpreter にフォールバックしていたため、PyVM スモークが作動せず。分岐を追加して復旧済み。 - PyVM Stage‑2 部分結果:
- PASS: string ops basic, me method call
- FAIL: loop/if/phi → 出力
sum=4(期待sum=9)- 原因分析: ループ内 if の merge で
sumの Phi 正規化が入らず、latch 側スナップショットが else 系の一時値を優先(16)しうる構造。LoopBuilder::build_statement(If)がnormalize_if_else_phi相当を呼ばず、変数マップが φ 統合されていない。 - 対応方針(最小修正):
- LoopBuilder の If 降下で merge 到達時に「両枝が同一変数に代入」の場合は
phi(dst=[then,else])を emit→その φ を対象変数に bind。 - latch スナップショットはこの φ 後の変数マップで採取する。
- 代替(短期): Builder 側の
normalize_if_else_phiを呼ぶ薄いフックを設けて流用。
- LoopBuilder の If 降下で merge 到達時に「両枝が同一変数に代入」の場合は
- 原因分析: ループ内 if の merge で
Fixes Applied (2025‑09‑15)
- LoopBuilder If 降下に φ 正規化を追加(両枝代入の変数を merge 時に φ で束ねて再束縛)。
- PyVM φ 解決ロジックを安定化(incoming を [value, pred] 形に限定し、[pred, value] の曖昧推測を削除)。偶然一致による誤選択を排除。
- これにより
tools/pyvm_stage2_smoke.shは全 PASS を確認済み。
Refactor Candidates (early plan)
- runner/mod.rs(~70K chars): “runner pipeline” を用途別に分割(TODO #15)
- runner/pipeline.rs(入力正規化/using解決/環境注入)
- runner/pipe_io.rs(stdin/file の JSON v0 受理・整形)
- runner/selfhost.rs(自己ホスト EXE/VM/Python フォールバック、timeout/ログ含む)
- runner/dispatch.rs(backend 選択と実行、PyVM 委譲)
- 既存 json_v0_bridge/mir_json_emit は流用、mod.rs から薄いファサードに縮退。
- backend/llvm/compiler/codegen(責務分割の継続)
- 済: utils 抽出、
lower_one_functionをfunction.rsへ移管。 - 次: 終端系・選択系の薄層切り出し。
instructions/terminators.rs: return/jump/branch の分岐ドライバ(emit_* 呼び出し集約)。instructions/select.rs: 条件・短絡・PHI 前処理(sealed-SSA 前提の前段正規化)。
- 目標:
function.rsの見通し改善(1関数=制御フロー骨格)、テスト容易化。
- 済: utils 抽出、
- mir/builder.rs(ヘッダ
80行、全体1K行)- 既に多くを modules に分割済み。残る “variable/phi 合流”“loop ヘッダ/出口管理” を builder/loops.rs / builder/phi.rs に抽出。
- 目標: 依存関係(utils/exprs/stmts)を維持したまま、1ファイル1責務を徹底。
Recommended Next (short list)
- LLVM Codegen(B 継続)
instructions/terminators.rsを新設し、function.rsから終端分岐(return/jump/branch)を移譲。instructions/select.rsを新設し、条件/短絡/PHI 前処理(sealed-SSA 前提の軽い正規化)を集約。function.rsは「BB 周回+各 lowering 呼び出し」の骨格のみへ縮退。
- MIR Builder(C 継続)
builder/loops.rsを新設し、ループのヘッダ/出口の小物ユーティリティを抽出(LoopBuilderの補助レイヤ)。builder/vars.rsに SSA 変数正規化の小物を段階追加(変数名再束縛/スコープ終端の型ヒント伝搬など)。
- Runner(仕上げ)
mod.rsの残置ヘルパ(usingの候補提示・環境注入ログ)をpipeline/dispatchへ集約し、mod.rsを最小のオーケストレーションに。- Namespaces Phase‑1(実装着手): BoxIndex 構築・3段階解決・toml aliases・曖昧エラー改善・トレース
Smoke Policy (Phase‑15)
- PyVM: 一部チェックのみ(async/nowait/await/GC/sync は対象外)
- LLVM: フル対応(llvmlite harness)。
tools/smokes/curated_llvm.sh [--phi-off]を利用 - JIT: 未整備(JIT向けスモークは
tools/smokes/archive/に移管)
MIR13 Plan(Phase‑15 終盤)
- Bridge/Builder: PHI を生成しない(受理は維持)。If/Loop の合流は LLVM Resolver に任せる。
- llvmlite: Resolver を使い、BB 先頭で PHI 合成。ループは preheader/cond/body の CFG から搬送値を復元(break は exit 側でマージ)。
- Smoke: LLVM はまず loop‑only(break/continue)を常時緑化。例外系(throw/try)は IR 降ろし込み整備後に復帰。
- 詳細設計:
docs/private/papers/paper-e-loop-signal-ir/mir-evolution-plan.mdに MIR14→MIR13→MIR17 の段階的移行計画を記載。
Array/Map Literals Plan(Syntax Sugar)
- Stage‑1: Array literal
[e1, e2, ...]を実装(ゲート:NYASH_SYNTAX_SUGAR_LEVEL=basic|fullまたはNYASH_ENABLE_ARRAY_LITERAL=1)。- Lowering:
new ArrayBox()→ 各要素を評価 →.push(elem)を左から右に順に発行 → 最後に配列値を返す。 - 末尾カンマ許可。
- スモーク:
apps/tests/array_literal_basic.nyash(size/順序/副作用1回性)。
- Lowering:
- Stage‑2: Map literal
{ "k": v, ... }(文字列キー限定)を実装(ゲート:NYASH_SYNTAX_SUGAR_LEVEL=basic|fullorNYASH_ENABLE_MAP_LITERAL=1)。- Lowering:
new MapBox()→ 各ペアを評価 →.set("k", v)を左から右に順に発行 → 最後に map 値を返す。 - 末尾カンマ許可。識別子キー糖
{name: v}は次フェーズ。 - スモーク:
apps/tests/map_literal_basic.nyash(size/get/順序検証)。
- Lowering:
- Stage‑3: 識別子キー糖
{name: v}と末尾カンマを強化(任意)。
Gates / Semantics
- 左から右で評価(一度だけ)。push/set 失敗は即時伝播(既存 BoxCall 規約に追従)。
- IR 変更なし(BoxCall/MethodCall のみ)。将来
with_capacity(n)最適化は任意で追加。
Decision Log (2025‑09‑15)
- Q: 警告削減(
ops_ext.rs/selfhost.rs)を先にやる?それとも挙動スモークを先に回す? - A: スモークを先に実施。理由は以下。
- リファクタ直後は回帰検出を最優先(PyVM/自己ホスト/Bridge の3レーンで即座に検証)。
- 警告削減は挙動非変化を原則とするが、微妙なスコープや保存スロットの触りが混入し得るため、先に“緑”を固める。 Namespaces / Using(現状)
- 解決順(決定性): 1) ローカル/コア → 2) エイリアス(nyash.toml/env)→ 3) 相対/using.paths → 4) プラグイン(短名/qualified)
- 曖昧時はエラー+候補提示(qualified または alias を要求)。
- モード切替: Relaxed(既定)/Strict(
NYASH_PLUGIN_REQUIRE_PREFIX=1または toml[plugins] require_prefix=true) - needs 糖衣は using の同義(Runner で alias 登録)。
- Plugins は統合名前空間。qualified
network.HttpClient常時許可。 - nyash.toml(MVP):
[aliases]/[plugins](グローバルrequire_prefixのみ反映。per‑plugin は導線のみ) - Index とキャッシュ(Runner):
-
BoxIndex(グローバル):
plugin_boxes,aliasesを保持。plugins init 後に構築。 -
Resolve Cache(グローバル):
tgt|base|strict|pathsキーで再解決回避。 -
NYASH_RESOLVE_TRACE=1: 解決手順/キャッシュヒット/未解決候補をログ出力。 -
スモークが緑=基礎健全性確認後に、静的ノイズの除去を安全に一気通貫で行う。
-
AOT Quick
- Array literal:
NYASH_SYNTAX_SUGAR_LEVEL=basic ./tools/build_llvm.sh tmp/aot_array_literal_main.nyash -o app && ./app - Map literal:
NYASH_SYNTAX_SUGAR_LEVEL=basic NYASH_ENABLE_MAP_LITERAL=1 ./tools/build_llvm.sh tmp/aot_map_literal_main.nyash -o app && ./app