diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index bbc251e1..b8738122 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -11,7 +11,7 @@ --- -## 今の状態(Phase 74–89 まで到達) +## 今の状態(Phase 74–90 まで到達) - Scope/BindingId の段階移行(dev-only)は Pattern2/3/4 まで配線済み(dual-path 維持)。 - Pattern2 の promoted carriers(DigitPos/Trim)について ExitLine 契約(ConditionOnly を exit PHI から除外)を E2E で固定済み。 @@ -19,10 +19,12 @@ - **LLVM exe line SSOT 確立**: `tools/build_llvm.sh` を使用した .hako → executable パイプライン標準化完了。 - **Phase 88 完了**: continue + 可変ステップ(i=i+const 差分)を dev-only fixture で固定、StepCalculator Box 抽出。 - **Phase 89 完了**: P0(ContinueReturn detector)+ P1(lowering 実装)完了。 +- **Phase 90 完了**: ParseStringComposite + `Null` literal + ContinueReturn(同一値の複数 return-if)を dev-only fixture で固定。 - `cargo test --release --lib` は PASS を維持(993 passed、退行なし)。 参照: - `docs/development/current/main/10-Now.md` +- `docs/development/current/main/phase86-90-loop-frontends-summary.md` - `docs/development/current/main/phase73-scope-manager-design.md` - `docs/development/current/main/phase80-bindingid-p3p4-plan.md` - `docs/development/current/main/phase81-pattern2-exitline-contract.md` @@ -33,30 +35,30 @@ ## 次の指示書(優先順位) -### P0: Phase 90 - _parse_string 合成 fixture +### P0: Docs 整備(数の増殖を止める) -**目的**: continue(escape) + return(close quote) の合成パターンを dev-only fixture で固定 +**目的**: SSOT への集約と導線整備(Phase 86–90 の情報が散らばらない状態にする) -**実装順序**(最短・事故減): -1. 合成 fixture 設計(制御構造のみ、文字列処理なし) - - continue(escape) + return(close quote) + str += ... + p += 1/2 - - 期待値が一意(例: n=10 で return 前に acc=4) -2. ShapeGuard 追加(誤爆防止) - - PatternParseStringCompositeMinimal (dev shape) - - P4/ContinueReturn と区別する条件 -3. lowering 実装(新しい箱) - - parse_string_composite_pattern.rs(例) - - Fail-Fast: 対応形以外は即エラー -4. normalized_dev テスト(2本) - - structured vs canonical 一致 - - 期待値一致 +やること: +1. Phase 86–90 の要約を 1 ファイルに集約(SSOT) + - `docs/development/current/main/phase86-90-loop-frontends-summary.md` +2. INDEX から要約へ導線を追加(迷子対策) + - `docs/development/current/main/01-JoinIR-Selfhost-INDEX.md` +3. `10-Now.md` / `CURRENT_TASK.md` の断定・重複を “要約へのリンク” に寄せる **受け入れ基準**: -- `NYASH_JOINIR_NORMALIZED_DEV_RUN=1 cargo test --features normalized_dev --test normalized_joinir_min` PASS -- `cargo test --release --lib` PASS(退行なし) -- dev-only のみ(canonical には入れない) +- 読み始め導線が `01-JoinIR-Selfhost-INDEX.md` から辿れる +- `10-Now.md` と `CURRENT_TASK.md` は “最新の入口” として機能する(詳細は要約へ) -### P1: JoinIR / Selfhost depth-2 の前進(Phase 91 候補) +### P1: Loop Canonicalizer の設計(docs-only、外部検討待ち) + +**目的**: ループ形状の組み合わせ爆発を抑えるための “前処理パス” を設計し、SSOT を定める + +注意: +- 実装は急がず、設計(SSOT)を先に固める +- 既定挙動は変えない(dev-only で段階投入する) + +### P2: JoinIR / Selfhost depth-2 の前進(Phase 91 候補) 目的: - JsonParserBox の残り複合ループを JoinIR 対応する。 @@ -70,7 +72,7 @@ 受け入れ基準: - 代表ケースが 1 コマンドで再現可能(CI は増やさない、quick を重くしない)。 -### P2: Ownership/Relay runtime 対応の再開(Phase 92 候補) +### P3: Ownership/Relay runtime 対応の再開(Phase 92 候補) 目的: - multihop/merge relay を “runtime でも” 受理できるところまで契約を伸ばす(Fail-Fast の段階解除)。 @@ -78,23 +80,9 @@ 受け入れ基準: - dev-only 既定OFF のまま、既存ラインを壊さない。 -### Done: Phase 88-89 完了 +### Done: Phase 86–90(Loop frontends) -**Phase 88**: -- continue + 可変ステップ(i=i+const 差分)を dev-only fixture で固定 -- StepCalculator Box 抽出(+6 unit tests、再利用可能) -- エラーメッセージ詳細化、Fail-Fast 仕様固定 - -**Phase 89 P0**: -- Pattern4 detector 締め(Select 必須 + conditional Jump exactly 1) -- LoopPattern::ContinueReturn enum + shape 追加 -- canonical には入れない(dev-only、誤爆防止) - -**Phase 89 P1**: -- continue_return_pattern.rs 実装(457行、StepCalculator 再利用) -- normalized_dev tests +2(vm_bridge + 期待値) - -**Impact**: 993 lib tests + 61 normalized_dev tests 全パス、箱化スコア 10/10 +- まとめ(SSOT): `docs/development/current/main/phase86-90-loop-frontends-summary.md` --- diff --git a/docs/development/current/main/01-JoinIR-Selfhost-INDEX.md b/docs/development/current/main/01-JoinIR-Selfhost-INDEX.md index 1dcbc18b..85648870 100644 --- a/docs/development/current/main/01-JoinIR-Selfhost-INDEX.md +++ b/docs/development/current/main/01-JoinIR-Selfhost-INDEX.md @@ -19,6 +19,8 @@ Scope: JoinIR と Selfhost(Stage‑B/Stage‑1/Stage‑3)に関する「最 - `docs/development/current/main/10-Now.md` - 「JoinIR / Loop / If ライン」 - 「JsonParser / Selfhost depth‑2 ライン」 +- Phase 86–90(Loop frontends)の要約(1枚) + - `docs/development/current/main/phase86-90-loop-frontends-summary.md` --- @@ -62,6 +64,8 @@ JoinIR の箱構造と責務、ループ/if の lowering パターンを把握 - `docs/development/current/main/phase33-16-INDEX.md` - `docs/development/current/main/phase33-17-joinir-modularization-analysis.md` - `docs/development/current/main/phase183-selfhost-depth2-joinir-status.md` +9. Phase 86–90(Loop frontends)の要約(1枚) + - `docs/development/current/main/phase86-90-loop-frontends-summary.md` Phase 文書は歴史や検証ログも含むので、「JoinIR の現役設計を確認した上で、必要なときだけ掘る」という前提で読んでね。 @@ -92,6 +96,9 @@ Phase 文書は歴史や検証ログも含むので、「JoinIR の現役設計 - → 2章の 1〜3 をこの順番で読む。 - Selfhost のビルド / 実行フローで迷っているとき - → 3章の 1〜3 をこの順番で読む。 +- VM backend の Box 解決(ConsoleBox / plugin / builtin)で迷っているとき + - → `docs/development/current/main/phase131-2-box-resolution-map.md`(経路図) + - → `docs/development/current/main/phase131-2-summary.md`(要点) - 「この Phase 文書は現役か?」で迷ったとき - → まず `docs/development/current/main/10-Now.md` と `docs/development/current/main/30-Backlog.md` を確認し、そこで名前が挙がっている Phase 文書を優先して読んでね。 diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index 7330692d..37194fee 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -1,6 +1,6 @@ # Self Current Task — Now (main) -## 2025‑12‑06:現状サマリ +## 2025‑12‑14:現状サマリ ### JoinIR / Loop / If ライン @@ -17,103 +17,13 @@ - 残課題(JoinIR ライン): - JoinIR→MIR merge の一般化(複雑な Select/PHI パターンの統合) - JsonParserBox など実アプリ側での長期運用テスト +- Phase 86–90(Loop frontends)まとめ(1枚): + - `docs/development/current/main/phase86-90-loop-frontends-summary.md` -### Phase 86: Carrier Init Builder + Error Tags (2025-12-13) ✅ +### Phase 86–90: Loop frontends(要約) -**Status**: COMPLETE - SSOT 確立完了 - -**Achievements**: -- Carrier Initialization Builder: CarrierInit → ValueId 生成を単一関数化 (carrier_init_builder.rs, +8 tests) -- Error Message Centralization: JoinIR エラータグを SSOT 化 (error_tags.rs, +5 tests) -- DebugOutputBox Migration: 全 JOINIR_DEBUG 使用箇所を DebugOutputBox に統一 - -**Impact**: -- Tests: 987/987 PASS (+13 unit tests from Phase 86) -- SSOT modules: carrier_init_builder, error_tags (一貫性向上) -- Code quality: Single Responsibility, Testability First principles validated - -**Reference**: phase78-85-boxification-feedback.md, carrier_init_builder.rs, error_tags.rs - -### Phase 87: LLVM Exe Line SSOT (2025-12-13) ✅ - -**Status**: COMPLETE - Pipeline 確立完了 - -**Achievements**: -- SSOT established: `tools/build_llvm.sh` - Single pipeline for .hako → executable -- Integration smoke: phase87_llvm_exe_min.sh (exit code 42 verification) -- Minimal fixture: apps/tests/phase87_llvm_exe_min.hako (5 lines, return 42) -- Full documentation: phase87-selfhost-llvm-exe-line.md (troubleshooting + advanced usage) - -**Policy**: -- ✅ Use build_llvm.sh SSOT (no duplication/fragmentation) -- ✅ Integration smoke only (not in quick profile) -- ✅ SKIP if LLVM unavailable (graceful degradation) -- ✅ Exit code verification (stdout-independent testing) - -**Impact**: -- Standard procedure: `tools/build_llvm.sh input.hako -o output_exe` -- Prerequisites documented: llvm-config-18, llvmlite, LLVM features -- Integration test: PASS (or SKIP if no LLVM) - -**Reference**: phase87-selfhost-llvm-exe-line.md - -### Phase 88: Continue + 可変ステップ (2025-12-14) ✅ - -**Status**: COMPLETE - dev-only fixture 固定完了 - -**Achievements**: -- continue + 可変ステップ(i=i+const 差分加算)を dev-only fixture で固定 -- continue 分岐側での acc 更新を許可 -- Fail-Fast 仕様固定(非 const の i 更新を拒否) -- StepCalculator Box 抽出(+6 unit tests、再利用可能な純関数設計) -- エラーメッセージ詳細化(Expected/Found/Hint 形式) - -**Impact**: -- Tests: 993 lib tests PASS, 60 normalized_dev tests PASS -- 箱化スコア: 9/10(Phase 33 Box 理論の模範実装) -- コード削減: 5%(321→305行、重複ロジック削除) - -**Reference**: -- continue_pattern.rs, step_calculator.rs -- jsonparser_unescape_string_step2_min.program.json - -### Phase 89 P0: Continue + Early Return Pattern Detector (2025-12-14) ✅ - -**Status**: COMPLETE - Dev-only detector 確立完了 - -**Achievements**: -- Pattern4 detector 締め(Select 必須 + conditional Jump exactly 1) -- LoopPattern::ContinueReturn enum 追加 -- NormalizedDevShape::PatternContinueReturnMinimal 追加(detector: Select + conditional Jumps >= 2) -- Fail-Fast: UnimplementedPattern error(フォールバックなし) -- canonical には入れない(dev-only、誤爆防止) - -**Impact**: -- Pattern4 誤爆防止(continue+return を正しく区別) -- Tests: 987 lib tests PASS - -**Reference**: -- shape_guard.rs, loop_patterns/mod.rs, analysis.rs -- pattern_continue_return_min.program.json (fixture) - -### Phase 89 P1: ContinueReturn Lowering Implementation (2025-12-14) ✅ - -**Status**: COMPLETE - 独立箱実装完了 - -**Achievements**: -- continue_return_pattern.rs 実装(457行、StepCalculator 再利用) -- Continue + Early Return の JoinIR lowering(loop 内 return 対応) -- Fail-Fast 原則徹底(5箇所検証) -- fixtures.rs に build_pattern_continue_return_min 追加 -- normalized_dev tests +2(vm_bridge + 期待値 n=10→acc=4) - -**Impact**: -- Tests: 993 lib tests PASS, 61 normalized_dev tests PASS (+2) -- 箱化原則:単一責任・境界明確・再利用性高 - -**Reference**: -- continue_return_pattern.rs, fixtures.rs -- tests/normalized_joinir_min/shapes.rs +- Phase 86–90 は “dev-only fixtures + shape guard + fail-fast” で段階的に固定済み。 +- 具体の fixture / shape / 未検証は `docs/development/current/main/phase86-90-loop-frontends-summary.md` を SSOT とする。 ### Scope / BindingId(dev-only の段階移行ライン) @@ -161,6 +71,8 @@ - Ring0.log(internal/dev) - println!(test 専用) の 3 層が `logging_policy.md` で整理済み。JoinIR/Loop trace も同ドキュメントに集約。 +- VM backend の Box 解決(UnifiedBoxRegistry / BoxFactoryRegistry)の経路図: + - `docs/development/current/main/phase131-2-box-resolution-map.md` --- diff --git a/docs/development/current/main/30-Backlog.md b/docs/development/current/main/30-Backlog.md index a965baaa..37ee2584 100644 --- a/docs/development/current/main/30-Backlog.md +++ b/docs/development/current/main/30-Backlog.md @@ -1,5 +1,12 @@ # Self Current Task — Backlog (main) +直近のループ前線(Phase 86–90, dev-only fixtures)は完了し、状況は `docs/development/current/main/10-Now.md` と +`docs/development/current/main/phase86-90-loop-frontends-summary.md` に集約したよ。 + +設計検討(docs-only, まだ未決定): +- Loop Canonicalizer / LoopSkeleton(組み合わせ爆発を抑える前処理パス) +- Loop Corpus Extractor(実コード抽出→差分検知で fixture 化を支援) + 短期(JoinIR/selfhost ライン 第3章 - LLVM統合) - ✅ Phase 130: JoinIR → LLVM ベースライン確立(完了 2025-12-04) - 🎯 **Phase 131: JoinIR→LLVM 個別修正ライン**(次の最優先タスク) diff --git a/docs/development/current/main/phase131-2-box-resolution-map.md b/docs/development/current/main/phase131-2-box-resolution-map.md new file mode 100644 index 00000000..c66def35 --- /dev/null +++ b/docs/development/current/main/phase131-2-box-resolution-map.md @@ -0,0 +1,298 @@ +# Phase 131-2: Box Resolution Mapping - 現状 vs 理想 + +## 🗺️ 現状マップ(VM Backend) + +``` +MIR NewBox ConsoleBox + ↓ +MirInterpreter::handle_new_box() (src/backend/mir_interpreter/handlers/boxes.rs) + ↓ + [分岐点 1: Fast path?] + ├─ Yes (NYASH_VM_FAST=1 + StringBox) → Direct creation(bench/profile-only) + └─ No → Continue + ↓ + [分岐点 2: Provider Lock] + ├─ guard_before_new_box() → OK/NG + └─ Continue + ↓ + get_global_unified_registry() (src/runtime/unified_registry.rs) + ↓ + UnifiedBoxRegistry::create_box("ConsoleBox", args) (src/box_factory/mod.rs) + ↓ + [分岐点 3: FactoryPolicy による優先順位] + ├─ BuiltinBoxFactory → builtin_impls(src/box_factory/builtin_impls/*) + └─ PluginBoxFactory → BoxFactoryRegistry → PluginHost + (src/box_factory/plugin.rs) (src/runtime/box_registry.rs) + ※ plugin_loader_unified が BoxFactoryRegistry を populate する + (src/runtime/plugin_loader_unified.rs) +``` + +**問題点**: +- ❌ 「Box 解決 SSOT」が 1 箇所に見えない(UnifiedBoxRegistry と BoxFactoryRegistry に分散) +- ❌ 優先順位が “FactoryPolicy + provider mapping” の合成で、全体像が追いにくい +- ❌ `NYASH_VM_FAST` の特例が入口にあり、観測なしだと混乱しやすい + +## 🎯 理想マップ(SSOT 化後) + +``` +MIR NewBox ConsoleBox + ↓ +handle_new_box() + ↓ +CoreBoxRegistry::create("ConsoleBox", args) + ↓ + [SSOT: 登録情報検索] + CoreBoxId::Console in registry? + ├─ Yes → Continue + └─ No → Error: "ConsoleBox not registered" (Fail-Fast!) + ↓ + [優先順位: Plugin > Builtin] + registered_provider? + ├─ Plugin → PluginHost.create_box() + │ ↓ + │ TypeBox v2 FFI + │ ↓ + │ console_invoke_id() + │ ↓ + │ ConsoleInstance::new() + │ + └─ Builtin → builtin::ConsoleBox::new() + ↓ + VMValue::BoxRef(ConsoleBox) +``` + +**改善点**: +- ✅ 単一の Box 解決ルート(SSOT) +- ✅ CoreBoxId による型安全性 +- ✅ 明確な優先順位(Plugin > Builtin) +- ✅ Fail-Fast(見つからない = エラー) + +## 📊 VM vs LLVM 比較表 + +| 項目 | VM Backend(現状) | LLVM Backend(Phase 133) | 理想(SSOT化後) | +|------|-------------------|--------------------------|-----------------| +| **Box 登録** | ⚠️ UnifiedBoxRegistry + BoxFactoryRegistry | ✅ TypeRegistry + Plugin FFI | ✅ CoreBoxRegistry | +| **メソッド解決** | ❌ 複数経路(boxes.rs 分岐) | ✅ ConsoleLlvmBridge 箱化 | ✅ 箱化モジュール | +| **ABI** | NyashBox trait | i8* + i64 (llvmlite) | ✅ 統一(TypeRegistry SSOT) | +| **優先順位** | ❓ 不明確 | ✅ Plugin > Builtin | ✅ 明示的優先順位 | +| **Fail-Fast** | ❌ フォールバック多数 | ✅ エラー即座に報告 | ✅ Fail-Fast 原則 | +| **型安全性** | ❌ 文字列ベース | ✅ TypeBox v2 | ✅ CoreBoxId enum | +| **SSOT 化** | ❌ 分散 | ✅ 完了(Phase 133) | ✅ 完了(目標) | + +## 🔍 登録システム詳細比較 + +### 現状(VM Backend) + +```rust +// System 1: BoxFactoryRegistry(plugin provider mapping) +impl BoxFactoryRegistry { + pub fn create_box(&self, name: &str, args: &[Box]) + -> Result, String> + { + let provider = self.get_provider(name)?; + match provider { + BoxProvider::Builtin(constructor) => constructor(args), + BoxProvider::Plugin(plugin_name) => + self.create_plugin_box(&plugin_name, name, args), + } + } +} + +// System 2: UnifiedBoxRegistry(VM NewBox の入口) +// src/backend/mir_interpreter/handlers/boxes.rs::handle_new_box +let reg = crate::runtime::unified_registry::get_global_unified_registry(); +let created = reg.lock().unwrap().create_box(box_type, &converted)?; + +// Builtins は UnifiedBoxRegistry 内で BuiltinBoxFactory が担当し、 +// builtin_impls/* の実装へ委譲される(外部フォールバックではない)。 +``` + +**問題**: +- 3つのシステムの関係が不明 +- どれが優先されるのか不明確 +- エラーハンドリングが統一されていない + +### Phase 133(LLVM Backend)- 成功モデル + +```python +# ConsoleLlvmBridge: 単一の箱化モジュール +def emit_console_call(builder, module, method_name, args, ...): + if method_name not in CONSOLE_METHODS: + return False # Fail-Fast: 即座に不明通知 + + runtime_fn_name = CONSOLE_METHODS[method_name] + callee = _declare(module, runtime_fn_name, i64, [i8p]) + builder.call(callee, [arg0_ptr]) + return True # 成功 +``` + +**成功要因**: +- ✅ CONSOLE_METHODS が SSOT(唯一の真実) +- ✅ 箱化モジュール(1箇所に集約) +- ✅ Fail-Fast(不明メソッド = False 即座) +- ✅ TypeRegistry との ABI 一致 + +### 理想(SSOT化後の VM Backend) + +```rust +// CoreBoxRegistry: 単一の SSOT +pub struct CoreBoxRegistry { + core_boxes: RwLock>, + user_boxes: RwLock>, +} + +impl CoreBoxRegistry { + pub fn create(&self, box_name: &str, args: &[Box]) + -> Result, RuntimeError> + { + // 1. CoreBoxId 変換 + let box_id = CoreBoxId::from_name(box_name) + .ok_or_else(|| RuntimeError::InvalidOperation { + message: format!("Unknown Box type: {}", box_name) + })?; + + // 2. 登録情報取得(SSOT) + let entry = self.core_boxes.read().unwrap() + .get(&box_id) + .ok_or_else(|| RuntimeError::InvalidOperation { + message: format!("Box not registered: {:?}", box_id) + })? + .clone(); + + // 3. 優先順位に従って生成 + match entry.provider { + CoreBoxProvider::Plugin { plugin_name, type_id } => { + self.plugin_host.create_box(&plugin_name, type_id, args) + } + CoreBoxProvider::Builtin { constructor } => { + constructor(args) + } + } + } +} +``` + +**改善点**: +- ✅ CoreBoxId による型安全性 +- ✅ 単一の登録マップ(SSOT) +- ✅ 明示的な優先順位(Plugin > Builtin) +- ✅ Fail-Fast(登録なし = エラー) + +## 🎯 Phase 133 の教訓 + +### 成功パターン: 箱化モジュール化 + +``` +Before (Phase 132): 40 行の分岐が boxcall.py に埋め込み +After (Phase 133): 1 行の箱化呼び出し + +# Before +if method_name in ("print", "println", "log"): + # ... 40 行のロジック ... + +# After +if emit_console_call(builder, module, method_name, args, ...): + return +``` + +**成果**: +- 分岐を 1 箇所に集約 +- テスト容易性向上 +- レガシー削除が簡単 + +### VM Backend への適用 + +```rust +// Before(現状): 複数経路の分岐 +let reg = unified_registry::get_global_unified_registry(); +let created = reg.lock().unwrap().create_box(box_type, &converted)?; + +// After(Phase 131-3): 箱化モジュール化 +let created = CoreBoxRegistry::global() + .create(box_type, &converted)?; +``` + +## 📋 Phase 131-3 実装ガイド + +### Step 1: 現状SSOTの所在を固定(入口と接続) + +```bash +# VM NewBox の入口(ここから追う) +rg "fn handle_new_box\\(" src/backend/mir_interpreter/handlers/boxes.rs + +# global accessor と registry 本体 +rg "get_global_unified_registry\\(" src/runtime/unified_registry.rs +rg "struct UnifiedBoxRegistry" src/box_factory/mod.rs + +# plugin 側の provider mapping +rg "struct BoxFactoryRegistry" src/runtime/box_registry.rs +``` + +**前提**: +- UnifiedBoxRegistry は既に存在する(NewBox の入口)。 +- BoxFactoryRegistry は PluginBoxFactory の provider mapping として間接利用される。 + +### Step 2: CoreBoxId 統合 + +```rust +// CoreBoxId に基づく検証ロジック追加 +impl CoreBoxRegistry { + pub fn validate_on_startup(&self, profile: &RuntimeProfile) + -> Result<(), String> + { + for box_id in CoreBoxId::iter() { + if box_id.is_required_in(&profile) && !self.has(box_id) { + return Err(format!("Missing core_required box: {:?}", box_id)); + } + } + Ok(()) + } +} +``` + +### Step 3: プラグイン優先順位の明確化 + +```rust +// 登録時に優先順位を決定 +impl CoreBoxRegistry { + /// プラグイン設定適用(既存ビルトインを上書き) + pub fn apply_plugin_config(&mut self, config: &PluginConfig) { + for (box_name, plugin_name) in &config.plugins { + if let Some(box_id) = CoreBoxId::from_name(box_name) { + self.register_plugin(box_id, plugin_name); // 上書き + } + } + } +} +``` + +### Step 4: Fail-Fast の徹底 + +```rust +// ❌ 削除対象: フォールバックロジック +if let Err(_) = create_plugin_box() { + create_builtin_box() // 隠蔽! +} + +// ✅ 追加: 即座にエラー +create_plugin_box() + .map_err(|e| VMError::InvalidInstruction( + format!("ConsoleBox plugin failed: {:?}. Check nyash.toml", e) + ))? +``` + +## ✅ チェックリスト(Phase 131-3) + +- [ ] UnifiedBoxRegistry / BoxFactoryRegistry の責務境界を SSOT として固定 +- [ ] CoreBoxRegistry を新設するなら “入口SSOT” を 1 箇所にする(NewBox から見える形) +- [ ] CoreBoxId 統合(型安全性) +- [ ] プラグイン優先順位の明確化(Plugin > Builtin) +- [ ] Fail-Fast 原則の徹底(フォールバック削除) +- [ ] 起動時検証テスト追加 +- [ ] VM/LLVM 両方で ConsoleBox 生成確認 + +--- + +**Status**: Ready for Implementation +**Next Phase**: 131-3 (SSOT Implementation) +**Estimated Time**: 4-6 hours diff --git a/docs/development/current/main/phase131-2-consolebox-investigation.md b/docs/development/current/main/phase131-2-consolebox-investigation.md new file mode 100644 index 00000000..0fdabcdf --- /dev/null +++ b/docs/development/current/main/phase131-2-consolebox-investigation.md @@ -0,0 +1,570 @@ +# Phase 131-2: ConsoleBox 問題根治調査レポート + +## 🎯 調査目的 + +実アプリの E2E で最初に詰まる「Box 登録/認識」問題を特定し、VM/LLVM 共通の土台を確立する。 + +## 📊 調査結果サマリ + +### 問題の本質 + +**ConsoleBox は既に両 backend で完全実装済み** - 問題は **登録メカニズムの分岐** にある: + +1. **VM backend**: Box 解決が「UnifiedBoxRegistry(入口) + BoxFactoryRegistry(plugin provider mapping) + VM fast path」の合成に見え、全体像が追いにくい +2. **LLVM backend**: 別の経路(TypeRegistry/FFI)を使用(Phase 133 の事例あり) +3. **両者の規約不一致**: “どれをSSOTとして読むべきか” が docs/コードで分散している + +### 重要な発見 + +#### ✅ LLVM 側は統合事例がある(Phase 133 / archive) + +LLVM backend の ConsoleBox 問題は **Phase 133 で完全解決済み**: +- ConsoleLlvmBridge 箱化モジュール実装済み +- TypeRegistry との ABI 完全一致 +- 7/7 テスト全て PASS + +**結論**: LLVM 側は “参考モデル” として参照し、当面の焦点は VM 側の経路可視化と SSOT 明文化。 + +#### ⚠️ VM backend の Box 解決が「2層 + 特例」に見える(問題の根源) + +VM backend では “入口” と “plugin provider mapping” が分かれており、加えて入口に特例がある: + +``` +1. BoxFactoryRegistry (src/runtime/box_registry.rs) + - Plugin-First アーキテクチャ + - プラグイン設定で上書き可能 + - グローバルレジストリ + +2. UnifiedBoxRegistry + global accessor + - global accessor: `src/runtime/unified_registry.rs` + - registry 本体: `src/box_factory/mod.rs` + - handle_new_box()(VM NewBox)が使用 + +3. VM fast path(特例) + - `NYASH_VM_FAST=1` のとき `StringBox` をレジストリ経由せず生成(bench/profile-only) +``` + +## 🔍 詳細分析 + +### 1. VM Backend の Box 解決フロー + +#### NewBox 命令処理(src/backend/mir_interpreter/handlers/boxes.rs) + +```rust +pub(super) fn handle_new_box( + &mut self, + dst: ValueId, + box_type: &str, + args: &[ValueId], +) -> Result<(), VMError> { + // ① Provider Lock guard(既定は挙動不変) + provider_lock::guard_before_new_box(box_type)?; + + // ② Fast path (StringBox のみ、NYASH_VM_FAST=1 時) + if box_type == "StringBox" { /* ... */ } + + // ③ 統一レジストリ経由で生成 ← ここが主経路 + let reg = unified_registry::get_global_unified_registry(); + let created = reg.lock().unwrap().create_box(box_type, &converted)?; + + // ④ 生成結果を VMValue に変換して格納 + self.regs.insert(dst, VMValue::from_nyash_box(created)); + + Ok(()) +} +``` + +**問題点**: +- `unified_registry` は `src/runtime/unified_registry.rs` にあり、`UnifiedBoxRegistry` は `src/box_factory/mod.rs` +- `UnifiedBoxRegistry` は `PluginBoxFactory`(`src/box_factory/plugin.rs`)を通じて `BoxFactoryRegistry` を参照するため、間接的に両者が接続されている +- Provider Lock の役割が曖昧(「既定は挙動不変」) + +#### BoxFactoryRegistry の設計(src/runtime/box_registry.rs) + +```rust +pub struct BoxFactoryRegistry { + providers: RwLock>, +} + +pub enum BoxProvider { + Builtin(BoxConstructor), // 互換用(テスト専用) + Plugin(String), // プラグイン実装 +} +``` + +**特徴**: +- Plugin-First 設計(プラグインがビルトインを上書き可能) +- `apply_plugin_config()` で nyash.toml から動的登録 +- `create_plugin_box()` → PluginHost 経由で実際の生成 + +**疑問**: +- このレジストリは `PluginBoxFactory` の provider mapping として使用される(VM NewBox → UnifiedBoxRegistry → PluginBoxFactory → BoxFactoryRegistry) +- provider の populate は `src/runtime/plugin_loader_unified.rs` が行う(`apply_plugin_config`) + +#### Builtin Fallback(src/box_factory/builtin_impls/console_box.rs) + +```rust +/// Create builtin ConsoleBox instance +/// +/// Primary: nyash-console-plugin +/// Fallback: This builtin implementation (selfhost support) +pub fn create(_args: &[Box]) -> Result, RuntimeError> { + // Phase 151: Quiet fallback (no deprecation warning) + Ok(Box::new(ConsoleBox::new())) +} +``` + +**用途**: +- セルフホスト Stage-3 パイプライン用 +- プラグイン初期化失敗時のバックアップ +- Phase 151 で追加(Phase 150 のエラー対処) + +### 2. LLVM Backend の Box 解決フロー(Phase 133 完了済み) + +#### ConsoleLlvmBridge(src/llvm_py/console_bridge.py) + +```python +CONSOLE_METHODS = { + "log": "nyash.console.log", + "println": "nyash.console.log", # Phase 122: log のエイリアス + "warn": "nyash.console.warn", + "error": "nyash.console.error", + "clear": "nyash.console.clear", +} + +def emit_console_call(builder, module, method_name, args, ...): + """ConsoleBox method call to LLVM IR""" + if method_name not in CONSOLE_METHODS: + return False + + runtime_fn_name = CONSOLE_METHODS[method_name] + # LLVM IR generation... + return True +``` + +**特徴**: +- Phase 133 で箱化モジュール化済み +- TypeRegistry の slot 400-403 と完全一致 +- Phase 122 の println/log エイリアス統一を継承 + +#### TypeRegistry との連携(src/runtime/type_registry.rs) + +```rust +// ConsoleBox 用 slot 定義 +const CONSOLE_METHODS: &[MethodEntry] = &[ + MethodEntry { name: "log", arity: 1, slot: 400 }, + MethodEntry { name: "println", arity: 1, slot: 400 }, // エイリアス + MethodEntry { name: "warn", arity: 1, slot: 401 }, + MethodEntry { name: "error", arity: 1, slot: 402 }, + MethodEntry { name: "clear", arity: 0, slot: 403 }, +]; +``` + +**SSOT 化の成果**: +- ✅ メソッド名 → slot 番号のマッピングが一元管理 +- ✅ VM/LLVM 両方で共通の型情報を参照 +- ✅ Phase 122 のエイリアス統一が完全適用 + +### 3. Plugin System との連携 + +#### TypeBox v2 FFI(plugins/nyash-console-plugin/src/lib.rs) + +```rust +#[no_mangle] +pub static nyash_typebox_ConsoleBox: NyashTypeBoxFfi = NyashTypeBoxFfi { + abi_tag: 0x54594258, // 'TYBX' + version: 1, + name: b"ConsoleBox\0".as_ptr() as *const c_char, + resolve: Some(console_resolve), + invoke_id: Some(console_invoke_id), + capabilities: 0, +}; +``` + +**特徴**: +- TypeBox v2 FFI を実装 +- `resolve()` でメソッド名 → ID 変換 +- `invoke_id()` で実際のメソッド呼び出し + +**問題点**: +- VM backend の `unified_registry` がこの FFI を使っているか不明 +- プラグインローダーとの接続点が見えない + +### 4. CoreBoxId システム(Phase 87) + +#### CoreBoxId 定義(src/runtime/core_box_ids.rs) + +```rust +pub enum CoreBoxId { + String, Integer, Bool, Array, Map, Console, // core_required + Float, Null, File, Path, Regex, Math, Time, Json, Toml, // core_optional + Function, Result, Method, Missing, // 特殊型 +} + +impl CoreBoxId { + pub fn is_core_required(&self) -> bool { + matches!(self, String | Integer | Bool | Array | Map | Console | File) + } + + pub fn is_required_in(&self, profile: &RuntimeProfile) -> bool { + match profile { + RuntimeProfile::Default => self.is_core_required(), + RuntimeProfile::NoFs => self.is_core_required() && *self != Self::File, + } + } +} +``` + +**設計思想**: +- Core Box を型安全な enum で管理 +- Phase 85 の core_required/core_optional 分類を実装 +- Runtime profile による動的要件変更 + +**問題点**: +- この enum が **Box 登録の強制力** を持っているか不明 +- `is_core_required()` の結果が実際の登録処理に反映されているか要確認 + +### 5. CoreServices(Phase 91) + +#### CoreServices 定義(src/runtime/core_services.rs) + +```rust +pub trait ConsoleService: Send + Sync { + fn println(&self, msg: &str); + fn print(&self, msg: &str); +} + +pub struct CoreServices { + pub string: Option>, + pub integer: Option>, + pub bool: Option>, + pub array: Option>, + pub map: Option>, + pub console: Option>, +} +``` + +**特徴**: +- Ring1-Core の Service trait 群 +- Phase 87 CoreBoxId の core_required をカバー +- Optional 化により Graceful Degradation 対応 + +**疑問**: +- この Service trait は **誰が実装しているのか?** +- VM の Box 呼び出しがこの trait を経由するのか? + +## 🚨 発見した問題点 + +### 1. **SSOT の欠如(最重要)** + +Box 登録規約が複数箇所に分散: + +``` +┌─ BoxFactoryRegistry (グローバル) +├─ UnifiedBoxRegistry (NewBox の入口) +├─ BuiltinBoxFactory (UnifiedBoxRegistry 内の factory) +├─ CoreBoxId enum (型定義) +├─ CoreServices (Service trait) +└─ TypeRegistry (メソッド情報) +``` + +**問題**: +- どのレジストリが「正」なのか不明 +- 登録順序・優先度の規約がない +- 初期化タイミングが散在 + +### 2. **VM と LLVM の分岐** + +| 項目 | VM Backend | LLVM Backend | +|------|-----------|--------------| +| Box 登録 | UnifiedBoxRegistry + BoxFactoryRegistry | TypeRegistry + Plugin FFI | +| メソッド解決 | BoxCall handler | ConsoleLlvmBridge | +| ABI | NyashBox trait | i8* + i64 | +| SSOT 化 | ❌ 不明 | ✅ Phase 133 完了 | + +### 3. **失敗パターンの特定** + +Phase 150/151 で報告されたエラー: + +``` +[ERROR] ❌ [rust-vm] VM error: Invalid instruction: NewBox ConsoleBox: + invalid operation: Unknown Box type: ConsoleBox. Available: Main +``` + +**原因推測**: +1. セルフホスト経由時にプラグイン初期化が失敗 +2. plugin provider mapping(BoxFactoryRegistry)が未設定で PluginBoxFactory が失敗 +3. BuiltinBoxFactory が無効(`plugins-only`)または該当 Box が builtin factory に登録されていない + +**Phase 151 の対処**: +- `builtin_impls/console_box.rs` を builtin 実装として追加/整備(UnifiedBoxRegistry 内の BuiltinBoxFactory 経由) +- "Available: Main" → ConsoleBox が登録されるようになった + +## 💡 SSOT 化提案 + +### 設計原則 + +1. **Single Source of Truth**: Box 登録規約を一箇所に集約 +2. **Explicit Dependencies**: 依存関係を明示化 +3. **Fail-Fast**: エラーは早期に明示的に失敗 +4. **Box-First**: Phase 33 の箱理論に基づく設計 + +### 提案 A: UnifiedBoxRegistry を入口SSOTとして強化(保守的アプローチ) + +```rust +// src/runtime/unified_registry.rs / src/box_factory/mod.rs を “入口SSOT” として扱い、 +// provider mapping や core_required 検証の責務をどこまで寄せるかを整理する。 + +pub struct UnifiedBoxRegistry { + // SSOT: すべての Box 登録情報 + factories: RwLock>, + + // CoreBoxId による必須 Box 検証 + core_validator: CoreBoxValidator, + + // プラグインローダーとの接続 + plugin_loader: Arc, +} + +impl UnifiedBoxRegistry { + /// 初期化時に core_required Box を強制登録 + pub fn new(profile: RuntimeProfile) -> Self { + let mut reg = Self { /* ... */ }; + + // CoreBoxId に基づく必須 Box 登録 + for box_id in CoreBoxId::iter() { + if box_id.is_required_in(&profile) { + reg.register_core_box(box_id)?; + } + } + + reg + } + + /// Box 生成(優先順位: Plugin > Builtin > Error) + pub fn create_box(&self, name: &str, args: &[Box]) + -> Result, RuntimeError> + { + // 1. プラグイン検索 + if let Some(provider) = self.factories.read().unwrap().get(name) { + match provider { + BoxProvider::Plugin(plugin_name) => { + return self.plugin_loader.create_box(name, args); + } + BoxProvider::Builtin(constructor) => { + return constructor(args); + } + } + } + + // 2. エラー(SSOT なので見つからない = 存在しない) + Err(RuntimeError::InvalidOperation { + message: format!("Unknown Box type: {}", name) + }) + } + + /// プラグイン設定の適用(nyash.toml から) + pub fn apply_plugin_config(&mut self, config: &PluginConfig) { + for (box_name, plugin_name) in &config.plugins { + self.factories.write().unwrap() + .insert(box_name.clone(), BoxProvider::Plugin(plugin_name.clone())); + } + } +} +``` + +**利点**: +- 既存コードへの影響最小 +- CoreBoxId による型安全性 +- プラグイン優先順位の明確化 + +### 提案 B: CoreBoxRegistry 新設(理想的アプローチ) + +```rust +// src/runtime/core_box_registry.rs (新規) + +/// Phase 131-2: Core Box 登録の SSOT +pub struct CoreBoxRegistry { + // CoreBoxId → 登録情報のマッピング + core_boxes: RwLock>, + + // ユーザー定義 Box(CoreBoxId 以外) + user_boxes: RwLock>, +} + +struct CoreBoxEntry { + box_id: CoreBoxId, + provider: CoreBoxProvider, + metadata: CoreBoxMetadata, +} + +enum CoreBoxProvider { + Plugin { plugin_name: String, type_id: u32 }, + Builtin { constructor: fn(&[Box]) -> Result, RuntimeError> }, +} + +impl CoreBoxRegistry { + /// 初期化時の必須 Box 検証 + pub fn validate_core_boxes(&self, profile: &RuntimeProfile) -> Result<(), String> { + let missing: Vec<_> = CoreBoxId::iter() + .filter(|id| id.is_required_in(profile)) + .filter(|id| !self.has_core_box(*id)) + .collect(); + + if !missing.is_empty() { + return Err(format!("Missing core_required boxes: {:?}", missing)); + } + + Ok(()) + } + + /// Box 生成(型安全) + pub fn create_core_box(&self, box_id: CoreBoxId, args: &[Box]) + -> Result, RuntimeError> + { + let entry = self.core_boxes.read().unwrap() + .get(&box_id) + .ok_or_else(|| RuntimeError::InvalidOperation { + message: format!("Core box not registered: {:?}", box_id) + })? + .clone(); + + match entry.provider { + CoreBoxProvider::Plugin { plugin_name, type_id } => { + self.create_plugin_box(&plugin_name, type_id, args) + } + CoreBoxProvider::Builtin { constructor } => { + constructor(args) + } + } + } +} +``` + +**利点**: +- CoreBoxId による完全な型安全性 +- 必須 Box の起動時検証 +- プラグイン vs ビルトインの明確な分離 + +## 🎯 次のステップ + +### Phase 131-3: SSOT 実装(推奨) + +1. **入口SSOTの確定(VM NewBox)** + - 入口は `src/backend/mir_interpreter/handlers/boxes.rs::handle_new_box` と + `src/runtime/unified_registry.rs` / `src/box_factory/mod.rs`(UnifiedBoxRegistry)で固定する + - BoxFactoryRegistry は “plugin provider mapping” として位置付け、関係図を SSOT 化する + +2. **CoreBoxId との統合** + - `CoreBoxValidator` 実装 + - 起動時の必須 Box 検証 + +3. **プラグインローダーとの接続明確化** + - plugin_loader_unified が BoxFactoryRegistry を populate し、 + PluginBoxFactory(UnifiedBoxRegistry 内)が BoxFactoryRegistry を参照する流れを明文化 + - TypeBox v2 FFI との整合(method/type id の参照箇所)を整理 + +4. **既存 BoxFactoryRegistry の整理** + - provider mapping を BoxFactoryRegistry に閉じるか、UnifiedBoxRegistry に吸収するかを決める + - 移行ガイドの作成 + +### Phase 131-4: テストケース追加 + +```rust +#[test] +fn test_core_box_registration() { + let reg = UnifiedBoxRegistry::new(RuntimeProfile::Default); + + // core_required が全て登録されていること + for box_id in CoreBoxId::iter() { + if box_id.is_core_required() { + assert!(reg.has_box(box_id.name())); + } + } + + // ConsoleBox が生成できること + let console = reg.create_box("ConsoleBox", &[]).unwrap(); + assert_eq!(console.type_name(), "ConsoleBox"); +} + +#[test] +fn test_plugin_priority() { + let mut reg = UnifiedBoxRegistry::new(RuntimeProfile::Default); + + // ビルトイン ConsoleBox 登録済み + assert!(reg.has_box("ConsoleBox")); + + // プラグイン設定で上書き + let mut config = PluginConfig::default(); + config.plugins.insert("ConsoleBox".to_string(), "nyash-console".to_string()); + reg.apply_plugin_config(&config); + + // プラグイン版が優先されること + let console = reg.create_box("ConsoleBox", &[]).unwrap(); + // プラグイン判定ロジック(実装依存) +} +``` + +## 📋 関連ファイル一覧 + +### VM Backend +- `src/runtime/box_registry.rs` - BoxFactoryRegistry +- `src/runtime/unified_registry.rs` - global UnifiedBoxRegistry accessor +- `src/box_factory/mod.rs` - UnifiedBoxRegistry(FactoryPolicy / create_box) +- `src/box_factory/plugin.rs` - PluginBoxFactory(BoxFactoryRegistry を参照) +- `src/runtime/core_box_ids.rs` - CoreBoxId enum +- `src/runtime/core_services.rs` - CoreServices trait +- `src/runtime/type_registry.rs` - TypeRegistry (メソッド情報) +- `src/backend/mir_interpreter/handlers/boxes.rs` - handle_new_box() +- `src/box_factory/builtin_impls/console_box.rs` - Builtin 実装(BuiltinBoxFactory 経由) + +### LLVM Backend +- `src/llvm_py/console_bridge.py` - ConsoleLlvmBridge(Phase 133) +- `src/llvm_py/instructions/boxcall.py` - BoxCall lowering + +### Plugin System +- `plugins/nyash-console-plugin/src/lib.rs` - TypeBox v2 FFI +- `src/runtime/plugin_host.rs` - PluginHost + +### Core Infrastructure +- `src/boxes/console_box.rs` - ConsoleBox 実装 +- `crates/nyash_kernel/src/lib.rs` - NyRT ランタイム + +## 🔍 未解決の疑問 + +1. **UnifiedBoxRegistry ↔ BoxFactoryRegistry の責務境界** + - provider mapping の SSOT をどこに置くか(BoxFactoryRegistry を残す/吸収する) + - `UnifiedBoxRegistry::FactoryPolicy` と plugin_config の関係をどう可視化するか + +2. **Provider Lock の役割** + - `provider_lock::guard_before_new_box()` の実装と目的 + - 「既定は挙動不変」の意味 + +3. **CoreServices の実装者** + - ConsoleService trait を実装しているのは誰か + - VM の Box 呼び出しがこの trait を経由するのか + +4. **初期化順序** + - プラグインローダー、レジストリ、サービスの初期化タイミング + - 循環依存の有無 + +## ✅ 成果 + +### 明確になった事実 + +1. **LLVM backend は問題なし** - Phase 133 で完全解決済み +2. **VM backend の Box 解決が分散して見える** - UnifiedBoxRegistry(入口)と BoxFactoryRegistry(provider mapping)の関係を SSOT 化する必要がある +3. **ConsoleBox 自体は完全実装** - 登録メカニズムの問題 +4. **CoreBoxId システム存在** - 型安全性の基盤あり + +### 提案した解決策 + +1. **UnifiedBoxRegistry 強化** - 保守的アプローチ +2. **CoreBoxRegistry 新設** - 理想的アプローチ +3. **起動時検証** - Fail-Fast 原則の実現 + +--- + +**Status**: Investigation Complete - Ready for Implementation +**Next Phase**: 131-3 (SSOT Implementation) +**Estimated Time**: 4-6 hours diff --git a/docs/development/current/main/phase131-2-summary.md b/docs/development/current/main/phase131-2-summary.md new file mode 100644 index 00000000..60cdba68 --- /dev/null +++ b/docs/development/current/main/phase131-2-summary.md @@ -0,0 +1,135 @@ +# Phase 131-2: ConsoleBox 問題根治調査 - エグゼクティブサマリ + +## 🎯 調査結論(3行サマリ) + +1. **LLVM 側は既存の統合事例がある** - Phase 133(archive)を参考にできる +2. **VM backend の Box 解決が分散して見える** - UnifiedBoxRegistry(入口)と BoxFactoryRegistry(plugin provider mapping)の関係が追いにくい +3. **ConsoleBox 自体は問題なし** - 迷子の原因は “どこを見ればよいか” の SSOT 不在 + +## 📊 問題の本質 + +### VM Backend の Box 解決が「2層 + 特例」に見える(問題の根源) + +``` +┌─ BoxFactoryRegistry (src/runtime/box_registry.rs) +│ └─ Plugin-First 設計、グローバルレジストリ +│ +├─ UnifiedBoxRegistry (src/box_factory/mod.rs) + global accessor (src/runtime/unified_registry.rs) +│ └─ MIR `NewBox`(VM)の入口 +│ +└─ VM fast path (NYASH_VM_FAST=1 + StringBox) + └─ ベンチ/プロファイル用の最適化(入口で分岐するため観測なしだと混乱しやすい) +``` + +**問題**: +- どのレジストリが「正」なのか不明 +- 登録順序・優先度の規約がない +- VM と LLVM で Box 解決方法が異なる + +## ✅ LLVM Backend の成功事例(参考モデル) + +Phase 133 で既に **完全な SSOT 化** を達成: + +```python +# ConsoleLlvmBridge (src/llvm_py/console_bridge.py) +CONSOLE_METHODS = { + "log": "nyash.console.log", + "println": "nyash.console.log", # Phase 122: エイリアス統一 + "warn": "nyash.console.warn", + "error": "nyash.console.error", + "clear": "nyash.console.clear", +} +``` + +**成果**: +- ✅ TypeRegistry との ABI 完全一致(slot 400-403) +- ✅ Phase 122 のエイリアス統一を継承 +- ✅ 7/7 テスト全て PASS + +## 💡 推奨アクション + +### 優先度 1: 入口SSOTの所在確認(VM NewBox) + +```bash +# 主要入口の所在(この3箇所を見る) +rg "get_global_unified_registry\\(|struct UnifiedBoxRegistry|struct BoxFactoryRegistry" src/ --type rust +``` + +**次の判断**: +- UnifiedBoxRegistry を “入口SSOT” として明文化し、BoxFactoryRegistry は plugin provider mapping として位置付ける +- その上で CoreBoxId / CoreServices との接続(Fail-Fast の境界)を設計する + +### 優先度 2: CoreBoxId との統合 + +```rust +// CoreBoxId に基づく必須 Box 検証 +pub fn validate_core_boxes(&self, profile: &RuntimeProfile) -> Result<(), String> { + let missing: Vec<_> = CoreBoxId::iter() + .filter(|id| id.is_required_in(profile)) + .filter(|id| !self.has_core_box(*id)) + .collect(); + + if !missing.is_empty() { + return Err(format!("Missing core_required boxes: {:?}", missing)); + } + Ok(()) +} +``` + +### 優先度 3: Fail-Fast 原則の徹底 + +```rust +// ❌ 悪い例:フォールバック +if let Err(_) = create_plugin_box() { + create_builtin_box() // 隠蔽される! +} + +// ✅ 良い例:即座に失敗 +create_plugin_box() + .map_err(|e| format!("ConsoleBox plugin failed: {:?}", e))? +``` + +## 🔍 未解決の疑問(Phase 131-3 で調査) + +1. **UnifiedBoxRegistry ↔ BoxFactoryRegistry の責務境界** + - “plugin provider mapping” を BoxFactoryRegistry に閉じ込めるなら、どこまで公開するか(例: box_types 一覧) + - `NYASH_BOX_FACTORY_POLICY` と plugin_config の関係を SSOT 化する場所 + +2. **Provider Lock の役割** + - `provider_lock::guard_before_new_box()` の目的 + - 「既定は挙動不変」の意味 + +3. **CoreServices の実装者** + - ConsoleService trait を誰が実装しているか + - Box 呼び出しが trait を経由するか + +## 📋 関連ドキュメント + +- **詳細レポート**: [phase131-2-consolebox-investigation.md](./phase131-2-consolebox-investigation.md) +- **Phase 133 成果**: [docs/archive/phases/phase-106-156/phase133_consolebox_llvm_integration.md](../../../archive/phases/phase-106-156/phase133_consolebox_llvm_integration.md) +- **CoreBoxId 設計**: `src/runtime/core_box_ids.rs` +- **TypeRegistry**: `src/runtime/type_registry.rs` + +## ⏱️ 次のステップ(Phase 131-3) + +### タスク概要 + +1. SSOT 設計決定(1時間) +2. 実装(2-3時間) +3. テスト追加(1時間) + +**合計見積もり**: 4-6時間 + +### 完成条件 + +- [ ] UnifiedBoxRegistry / BoxFactoryRegistry の責務境界を SSOT として固定 +- [ ] CoreBoxId に基づく必須 Box 検証実装 +- [ ] プラグイン vs ビルトイン優先順位の明確化 +- [ ] 起動時の core_required Box 検証テスト追加 +- [ ] VM/LLVM 両方で ConsoleBox 生成成功確認 + +--- + +**Status**: Investigation Complete ✅ +**Next Phase**: 131-3 (SSOT Implementation) +**Owner**: ChatGPT + Claude 協働 diff --git a/docs/development/current/main/phase86-90-loop-frontends-summary.md b/docs/development/current/main/phase86-90-loop-frontends-summary.md new file mode 100644 index 00000000..0bf83491 --- /dev/null +++ b/docs/development/current/main/phase86-90-loop-frontends-summary.md @@ -0,0 +1,66 @@ +# Phase 86–90 Summary — Loop Frontends (dev-only fixtures) + +目的: 実アプリ由来のループ形を「fixture + shape guard + fail-fast」で段階的に JoinIR frontend に取り込み、 +Normalized-dev の回帰テストで固定する。 + +このファイルは Phase 86–90 の“ループ前線”だけを 1 枚に集約するサマリ。 +詳細ログや設計の背景は各 Phase 文書に委譲し、このサマリでは **到達点 / SSOT / fixture / 未検証**だけを書く。 + +## SSOT(参照の優先順位) + +- JoinIR 全体SSOT: `docs/development/current/main/joinir-architecture-overview.md` +- いまの状態: `docs/development/current/main/10-Now.md` +- タスク優先度: `CURRENT_TASK.md` + +## Phase 86 — Carrier Init Builder + Error Tags ✅ + +- 目的: ValueId 生成とエラー語彙を SSOT 化し、段階移行ラインの土台を固める +- SSOT modules: + - `src/mir/builder/control_flow/joinir/merge/carrier_init_builder.rs` + - `src/mir/join_ir/lowering/error_tags.rs` + +## Phase 87 — LLVM exe line SSOT ✅ + +- 目的: `.hako → executable` の手順を `tools/build_llvm.sh` に統一し、Smoke を 1 本に固定する +- SSOT: + - `tools/build_llvm.sh` + - `docs/development/current/main/phase87-selfhost-llvm-exe-line.md` + +## Phase 88 — continue + 可変ステップ(dev-only fixture)✅ + +- 目的: `continue` 分岐で `i` が可変ステップ更新される形(`i = i + const`)を段階拡張し、回帰を固定する +- 追加: continue 分岐側での carrier 更新(例: `acc`)を許可 +- Fail-Fast: const 以外の step 更新は拒否 +- Fixture: + - `docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_unescape_string_step2_min.program.json` + +## Phase 89 — ContinueReturn(detector + lowering)✅ + +- 目的: `continue + early return`(loop 内 return)を Pattern4 と誤認しないように shape を分離し、frontend lowering を追加する +- Shape guard: + - Pattern4 detector を厳格化(誤爆防止) + - ContinueReturn 用 detector を追加(dev-only) +- Fixtures: + - `docs/private/roadmap2/phases/normalized_dev/fixtures/pattern_continue_return_min.program.json` + - `docs/private/roadmap2/phases/normalized_dev/fixtures/continue_return_multi_min.program.json`(同一値の複数 return-if) + +## Phase 90 — ParseStringComposite(dev-only fixture)✅ + +- 目的: `_parse_string` の制御骨格(escape continue + close-quote return)を “制御だけ抽出” した合成 fixture として固定する +- Fixture: + - `docs/private/roadmap2/phases/normalized_dev/fixtures/parse_string_composite_min.program.json` +- 追加(実ループ寄せの土台、制御抽出): + - `docs/private/roadmap2/phases/normalized_dev/fixtures/parse_array_min.program.json` + - `docs/private/roadmap2/phases/normalized_dev/fixtures/parse_object_min.program.json` + +## Refactor(Phase 89–90 の維持性向上) + +- Fixture 名・パス・ルーティングの SSOT: + - `src/mir/join_ir/normalized/dev_fixtures.rs` +- Shape detector の共通化(Inspector 等)は `shape_guard.rs` を参照 + +## 未検証(SSOT にしない) + +- 実コード(`tools/hako_shared/json_parser.hako`)の `_parse_string/_parse_array/_parse_object` を、 + JoinIR frontend で “そのまま” E2E 実行するライン(dev-only での段階投入) +- 文字列・配列・マップなど Box の意味論を含む大域 E2E(fixture は制御抽出が主目的) diff --git a/docs/development/current/main/phase87-selfhost-llvm-exe-line.md b/docs/development/current/main/phase87-selfhost-llvm-exe-line.md index 43c9b11e..7680069a 100644 --- a/docs/development/current/main/phase87-selfhost-llvm-exe-line.md +++ b/docs/development/current/main/phase87-selfhost-llvm-exe-line.md @@ -27,6 +27,130 @@ Establish single source of truth for `.hako → .o → executable → execution` # Expected: 0.40.0 or newer ``` +## Compiler Modes + +`tools/build_llvm.sh` supports two compiler modes for LLVM object generation: + +### Harness (Default) - Production Ready + +**Python llvmlite-based LLVM IR generation** + +- **Stability**: ✅ Proven stable, battle-tested +- **Build Time**: Fast (~1-3s for minimal programs) +- **Dependencies**: Python 3, llvmlite, LLVM 18 +- **Use Case**: Default for all production builds + +**Enable** (default behavior): +```bash +# Explicit mode selection (optional): +NYASH_LLVM_COMPILER=harness tools/build_llvm.sh program.hako -o output + +# Default (no env var needed): +tools/build_llvm.sh program.hako -o output +``` + +**How it works**: +1. `hakorune --backend llvm` invokes Python harness +2. `src/llvm_py/llvm_builder.py` generates LLVM IR via llvmlite +3. `llc-18` compiles IR to object file + +### Crate (Experimental) - Rust-native Compiler + +**Pure Rust LLVM IR generation via crates/nyash-llvm-compiler** + +- **Stability**: ⚠️ Experimental, under active development +- **Build Time**: Slower (~5-10s, requires crate compilation) +- **Dependencies**: LLVM 18 dev libraries, Rust toolchain +- **Use Case**: Advanced users, development/testing + +**Enable**: +```bash +NYASH_LLVM_COMPILER=crate tools/build_llvm.sh program.hako -o output +``` + +**How it works**: +1. `hakorune --emit-mir-json` generates MIR JSON +2. `ny-llvmc` (Rust crate) reads JSON and emits LLVM IR +3. `llc-18` compiles IR to object file + +**Advanced: Direct exe emission** (experimental): +```bash +NYASH_LLVM_COMPILER=crate NYASH_LLVM_EMIT=exe \ + tools/build_llvm.sh program.hako -o output +# Skips separate linking step, emits executable directly +``` + +### Mode Comparison Table + +| Feature | Harness (Default) | Crate (Experimental) | +|---------|------------------|----------------------| +| **Stability** | ✅ Production ready | ⚠️ Experimental | +| **Build Time** | Fast (1-3s) | Moderate (5-10s) | +| **Dependencies** | Python + llvmlite | LLVM dev + Rust | +| **MIR JSON** | Internal | Explicit generation | +| **Direct exe** | ❌ Not supported | ✅ Experimental | +| **Recommended For** | All users | Advanced/dev only | + +**Default recommendation**: Use harness mode (no env vars needed). + +## Environment Variables Reference + +### Control Variables + +These environment variables control the build pipeline behavior: + +| Variable | Default | Purpose | Example | +|----------|---------|---------|---------| +| `NYASH_BIN` | `./target/release/hakorune` | Path to hakorune binary | `NYASH_BIN=/custom/path/hakorune` | +| `NYASH_LLVM_COMPILER` | `harness` | Compiler mode: `harness` or `crate` | `NYASH_LLVM_COMPILER=crate` | +| `NYASH_LLVM_FEATURE` | `llvm` | LLVM feature flag for cargo build | `NYASH_LLVM_FEATURE=llvm-inkwell-legacy` | +| `NYASH_LLVM_OBJ_OUT` | `target/aot_objects/.o` | Object file output path | `NYASH_LLVM_OBJ_OUT=/tmp/custom.o` | +| `NYASH_CLI_VERBOSE` | `0` | Enable verbose build output | `NYASH_CLI_VERBOSE=1` | + +### Advanced Control Variables + +For specialized use cases and debugging: + +| Variable | Default | Purpose | Example | +|----------|---------|---------|---------| +| `NYASH_LLVM_SKIP_EMIT` | `0` | Skip object generation (use pre-generated .o) | `NYASH_LLVM_SKIP_EMIT=1` | +| `NYASH_LLVM_ONLY_OBJ` | `0` | Stop after object generation (skip linking) | `NYASH_LLVM_ONLY_OBJ=1` | +| `NYASH_LLVM_SKIP_NYRT_BUILD` | `0` | Skip Nyash Kernel runtime build | `NYASH_LLVM_SKIP_NYRT_BUILD=1` | +| `NYASH_LLVM_MIR_JSON` | (auto-generated) | Pre-generated MIR JSON path (crate mode) | `NYASH_LLVM_MIR_JSON=/tmp/mir.json` | +| `NYASH_LLVM_VALIDATE_JSON` | `0` | Validate MIR JSON schema (crate mode) | `NYASH_LLVM_VALIDATE_JSON=1` | +| `NYASH_LLVM_EMIT` | `obj` | Emission mode: `obj` or `exe` (crate only) | `NYASH_LLVM_EMIT=exe` | +| `NYASH_LLVM_NYRT` | `crates/nyash_kernel/target/release` | Nyash Kernel runtime path | `NYASH_LLVM_NYRT=/custom/nyrt` | +| `NYASH_LLVM_LIBS` | (empty) | Additional link libraries | `NYASH_LLVM_LIBS="-lcustom"` | +| `NYASH_LLVM_USE_HARNESS` | (auto-set) | Force Python harness usage | `NYASH_LLVM_USE_HARNESS=1` | + +### Typical Usage Examples + +**Basic build** (all defaults): +```bash +tools/build_llvm.sh program.hako -o output +``` + +**Verbose debugging**: +```bash +NYASH_CLI_VERBOSE=1 tools/build_llvm.sh program.hako -o output +``` + +**Use pre-generated object file**: +```bash +# Step 1: Generate object via smoke test +./tools/smokes/v2/run.sh --profile quick --filter 'smoke_obj_*' + +# Step 2: Link using existing object +NYASH_LLVM_SKIP_EMIT=1 NYASH_LLVM_OBJ_OUT=target/aot_objects/existing.o \ + tools/build_llvm.sh program.hako -o output +``` + +**Crate mode with validation**: +```bash +NYASH_LLVM_COMPILER=crate NYASH_LLVM_VALIDATE_JSON=1 \ + tools/build_llvm.sh program.hako -o output +``` + ## Standard Procedure **Build and execute** a .hako program to native executable: @@ -107,6 +231,150 @@ clang-18 tmp/program.o -o tmp/program **Output**: Native executable +## Success/Failure Criteria + +### Success Indicators + +A successful build via `tools/build_llvm.sh` exhibits: + +**1. Exit Code**: `0` +```bash +tools/build_llvm.sh program.hako -o output +echo $? # Should output: 0 +``` + +**2. All 4 Steps Complete**: +``` +[1/4] Building hakorune (feature selectable) ... +[2/4] Emitting object (.o) via LLVM backend ... +[3/4] Building Nyash Kernel static runtime ... +[4/4] Linking output ... +✅ Done: output +``` + +**3. Executable Generated**: +```bash +ls -lh output +# Should exist and be executable +file output +# Output: ELF 64-bit LSB executable, x86-64, dynamically linked +``` + +**4. Executable Runs**: +```bash +./output +echo $? +# Should match expected exit code (e.g., 42 for phase87_llvm_exe_min.hako) +``` + +### Failure Modes + +`build_llvm.sh` uses distinct exit codes for different failure types: + +| Exit Code | Meaning | Common Cause | +|-----------|---------|--------------| +| **0** | ✅ Success | Build completed normally | +| **1** | Usage error | Missing input file or invalid arguments | +| **2** | Missing dependency | `llvm-config-18` not found | +| **3** | Compilation failure | Object file not generated (MIR/LLVM IR error) | +| **Other** | System/linking error | Linking failure, missing libraries | + +**Exit Code 1** - Usage Error: +```bash +tools/build_llvm.sh +# Output: Usage: tools/build_llvm.sh [-o ] +# Exit: 1 +``` + +**Exit Code 2** - Missing LLVM: +```bash +# When llvm-config-18 not installed +tools/build_llvm.sh program.hako -o output +# Output: error: llvm-config-18 not found (install LLVM 18 dev). +# Exit: 2 +``` + +**Exit Code 3** - Object Generation Failed: +```bash +# When MIR/LLVM IR compilation fails +tools/build_llvm.sh bad_program.hako -o output +# Output: error: object not generated: target/aot_objects/bad_program.o +# Exit: 3 +``` + +### Validation Commands + +**Verify object file validity**: +```bash +# Check object file exists and has correct format +file target/aot_objects/program.o +# Expected: ELF 64-bit relocatable, x86-64 + +# Check object file symbols +nm target/aot_objects/program.o | grep -E '(main|nyash_)' +# Should show exported symbols +``` + +**Verify LLVM IR validity** (when using crate mode with JSON): +```bash +# Step 1: Generate LLVM IR (manual) +NYASH_LLVM_COMPILER=crate NYASH_LLVM_MIR_JSON=tmp/test.json \ + tools/build_llvm.sh program.hako -o output + +# Step 2: Validate LLVM IR +llvm-as-18 tmp/test.ll -o /dev/null +# Should complete without errors + +# Step 3: Disassemble and inspect +llvm-dis-18 target/aot_objects/program.o -o - | less +# Should show valid LLVM IR +``` + +**Verify MIR JSON validity** (crate mode): +```bash +# Ensure MIR JSON is well-formed +jq . tmp/test.json > /dev/null +echo $? # Should output: 0 + +# Optional: Schema validation +NYASH_LLVM_VALIDATE_JSON=1 NYASH_LLVM_COMPILER=crate \ + tools/build_llvm.sh program.hako -o output +``` + +### Build Time Expectations + +Typical build times for `phase87_llvm_exe_min.hako` (minimal program): + +| Step | Expected Time | Notes | +|------|---------------|-------| +| **[1/4] Build hakorune** | ~0.5-2s | Incremental build (release) | +| **[2/4] Emit object** | ~1-2s | Harness mode (llvmlite) | +| | ~5-10s | Crate mode (ny-llvmc) | +| **[3/4] Build Nyash Kernel** | ~1-3s | Incremental build (release) | +| **[4/4] Linking** | ~0.2-0.5s | Native linker (cc/clang) | +| **Total** | ~3-8s | Harness mode | +| | ~7-15s | Crate mode | + +**First build**: Add ~30-60s for initial `cargo build --release` compilation. + +**Performance factors**: +- **Parallel builds**: `-j 24` used by default (see `build_llvm.sh`) +- **Incremental builds**: `CARGO_INCREMENTAL=1` enabled +- **Cache hits**: Subsequent builds much faster (~1-3s total) + +**Troubleshooting slow builds**: +```bash +# Check cargo cache status +cargo clean --release -p nyash-rust +cargo clean --release -p nyash-llvm-compiler + +# Rebuild with timing information +time tools/build_llvm.sh program.hako -o output + +# Verbose output for bottleneck analysis +NYASH_CLI_VERBOSE=1 time tools/build_llvm.sh program.hako -o output +``` + ## Troubleshooting ### Issue: llvm-config-18 not found @@ -181,6 +449,206 @@ llvm-as-18 test.ll -o /dev/null # Should complete without errors ``` +### Debugging Build Pipeline + +When `build_llvm.sh` fails, use these techniques to isolate the problem: + +#### Enable Verbose Mode + +**Global verbose output**: +```bash +NYASH_CLI_VERBOSE=1 tools/build_llvm.sh program.hako -o output +# Shows detailed command execution via set -x +``` + +**Step-by-step verbosity**: +```bash +# Verbose hakorune compilation +NYASH_CLI_VERBOSE=1 ./target/release/hakorune --emit-mir-json tmp/debug.json program.hako + +# Verbose Python LLVM builder +python3 -v src/llvm_py/llvm_builder.py tmp/debug.json -o tmp/debug.ll + +# Verbose LLVM compilation +llc-18 -debug tmp/debug.ll -o tmp/debug.o -filetype=obj + +# Verbose linking +cc -v tmp/debug.o -L crates/nyash_kernel/target/release -lnyash_kernel -o output +``` + +#### Manual Step Tracing + +**Isolate each step** to find exact failure point: + +**Step 1: Test MIR emission**: +```bash +./target/release/hakorune --emit-mir-json tmp/test.json program.hako +echo $? # Should be 0 +jq . tmp/test.json # Validate JSON +``` + +**Step 2: Test LLVM IR generation**: +```bash +# Harness mode (default) +NYASH_LLVM_USE_HARNESS=1 ./target/release/hakorune --backend llvm program.hako +# Check exit code + +# Crate mode +cargo build --release -p nyash-llvm-compiler +./target/release/ny-llvmc --in tmp/test.json --out tmp/test.o +file tmp/test.o # Should be ELF object +``` + +**Step 3: Test object compilation**: +```bash +# If .ll file available (crate mode intermediate) +llc-18 -filetype=obj tmp/test.ll -o tmp/test.o +file tmp/test.o # Verify ELF format +nm tmp/test.o # Check symbols +``` + +**Step 4: Test linking**: +```bash +# Ensure Nyash Kernel built +cd crates/nyash_kernel && cargo build --release +cd ../.. + +# Manual link +cc tmp/test.o \ + -L crates/nyash_kernel/target/release \ + -Wl,--whole-archive -lnyash_kernel -Wl,--no-whole-archive \ + -lpthread -ldl -lm -o tmp/manual_output + +# Test execution +./tmp/manual_output +echo $? +``` + +#### Save Intermediate Files + +**Preserve all build artifacts** for inspection: + +```bash +# Create debug directory +mkdir -p debug_build + +# Step 1: Emit MIR JSON +./target/release/hakorune --emit-mir-json debug_build/program.json program.hako + +# Step 2: Generate LLVM IR (harness mode, manual Python call) +python3 src/llvm_py/llvm_builder.py debug_build/program.json -o debug_build/program.ll + +# Step 3: Compile to object +llc-18 debug_build/program.ll -o debug_build/program.o -filetype=obj + +# Step 4: Link +cc debug_build/program.o \ + -L crates/nyash_kernel/target/release \ + -Wl,--whole-archive -lnyash_kernel -Wl,--no-whole-archive \ + -lpthread -ldl -lm -o debug_build/program + +# Inspect all intermediate files +ls -lh debug_build/ +file debug_build/* +``` + +**Inspect saved artifacts**: +```bash +# View MIR JSON structure +jq '.functions[] | {name: .name, blocks: .blocks | length}' debug_build/program.json + +# View LLVM IR +less debug_build/program.ll + +# Disassemble object file +objdump -d debug_build/program.o | less + +# Check symbols +nm debug_build/program.o +nm debug_build/program +``` + +#### Common LLVM IR Issues + +**Problem 1: Invalid function signature** +``` +error: expected type '...' but found '...' +``` +**Diagnosis**: MIR → LLVM IR type mismatch +**Fix**: Check MIR JSON `functions[].signature`, ensure correct types + +**Problem 2: Undefined symbol** +``` +error: undefined reference to 'nyash_...' +``` +**Diagnosis**: Missing Nyash Kernel runtime symbols +**Fix**: +```bash +# Rebuild Nyash Kernel +cd crates/nyash_kernel && cargo clean && cargo build --release + +# Verify symbols available +nm crates/nyash_kernel/target/release/libnyash_kernel.a | grep nyash_ +``` + +**Problem 3: Invalid IR instruction** +``` +error: invalid IR instruction '...' +``` +**Diagnosis**: Python llvm_builder.py bug or unsupported MIR instruction +**Fix**: +```bash +# Check LLVM IR syntax +llvm-as-18 -o /dev/null debug_build/program.ll +# Error message shows exact line number + +# Inspect problematic instruction +sed -n 'p' debug_build/program.ll +``` + +**Problem 4: Linking failure** +``` +ld: symbol(s) not found for architecture x86_64 +``` +**Diagnosis**: Missing system libraries or incorrect link order +**Fix**: +```bash +# Check what symbols are needed +nm -u debug_build/program.o + +# Verify Nyash Kernel provides them +nm crates/nyash_kernel/target/release/libnyash_kernel.a | grep + +# If system library missing, add to NYASH_LLVM_LIBS +NYASH_LLVM_LIBS="-lmissing_lib" tools/build_llvm.sh program.hako -o output +``` + +#### Environment Variables for Debugging + +Combine multiple debugging flags: + +```bash +# Maximum verbosity + preserve artifacts +NYASH_CLI_VERBOSE=1 \ +NYASH_LLVM_COMPILER=crate \ +NYASH_LLVM_MIR_JSON=/tmp/debug.json \ +NYASH_LLVM_VALIDATE_JSON=1 \ + tools/build_llvm.sh program.hako -o /tmp/debug_output + +# Then inspect intermediate files +ls -lh /tmp/debug* +jq . /tmp/debug.json +cat /tmp/debug.ll +``` + +**Recommended debugging workflow**: +1. Enable `NYASH_CLI_VERBOSE=1` for initial diagnosis +2. Use manual step tracing to isolate failure +3. Save intermediate files for inspection +4. Check LLVM IR validity with `llvm-as-18` +5. Verify object symbols with `nm` +6. Test linking manually with verbose `cc -v` + ## What NOT to Do ❌ **DO NOT** create custom link procedures: