diff --git a/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md b/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md index 28b01bad..118856b5 100644 --- a/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md +++ b/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md @@ -437,4 +437,94 @@ struct BoxVTable { - [ ] 全Box型でtoString/type/equals/cloneが動作 - [ ] プラグインBoxの透過的な動作 - [ ] パフォーマンス改善の確認 -- [ ] メモリ使用量の変化なし \ No newline at end of file +- [ ] メモリ使用量の変化なし + +## 🚀 究極の統一:ビルトインBox完全プラグイン化構想 + +### 現状の二重実装問題 +- **plugin_loader.rs** (1217行) - ビルトインBoxの動的ライブラリ化 +- **plugin_loader_v2.rs** (906行) - プラグインBoxシステム +- 合計2000行以上の重複! + +### 完全プラグイン化の提案 + +#### すべてをプラグインに統一 +```rust +// 現在 +ビルトインFileBox → 静的リンク +プラグインFileBox → 動的ロード(.so) + +// 統一後 +すべてのBox → プラグイン(.so)として実装 +``` + +#### コアBoxの自動ロード戦略 +```rust +const CORE_BOXES: &[&str] = &[ + "libnyash_string_box.so", // StringBox(必須) + "libnyash_integer_box.so", // IntegerBox(必須) + "libnyash_bool_box.so", // BoolBox(必須) + "libnyash_console_box.so", // ConsoleBox(print用) +]; + +// 起動時に自動ロード +fn init_core_boxes() { + for plugin in CORE_BOXES { + plugin_loader.load_required(plugin) + .expect("Core box loading failed"); + } +} +``` + +### メリット +1. **コード削減**: plugin_loader.rs (1217行) を完全削除 +2. **統一性**: Everything is Boxの究極の実現 +3. **柔軟性**: StringBoxすら置き換え可能 +4. **ビルド高速化**: 本体が軽量に +5. **配布の柔軟性**: 必要なBoxだけ選択可能 + +### 考慮事項 + +#### パフォーマンス +- FFI境界のオーバーヘッドは**ナノ秒レベル** +- 実用上の影響なし + +#### デバッグの課題と対策 +```rust +// 課題:エラー時のスタックトレース +thread 'main' panicked at 'FFI boundary: 0x7f8b2c001234' + +// 対策1:プラグイン側でのロギング +#[no_mangle] +pub extern "C" fn box_method_toString() { + eprintln!("[StringBox::toString] called from {:?}", std::thread::current().id()); +} + +// 対策2:デバッグシンボル保持 +cargo build --features debug-symbols + +// 対策3:プラグイン単体テストの充実 +#[test] +fn test_string_box_methods() { /* ... */ } +``` + +### 実装ロードマップ +1. **Phase A**: コアBoxのプラグイン化 + - StringBox, IntegerBox, BoolBox, ConsoleBox +2. **Phase B**: 起動時自動ロード機構 +3. **Phase C**: plugin_loader.rs削除 +4. **Phase D**: ドキュメント・テスト整備 + +### 設定ファイル案 +```toml +# ~/.nyash/config.toml +[plugins] +core_path = "./plugins/core/" +search_paths = ["./plugins", "/usr/lib/nyash/plugins"] + +[core_boxes] +required = ["string", "integer", "bool", "console"] +optional = ["file", "math", "time"] +``` + +これにより、「Everything is Box」哲学が実装レベルでも完全に実現される! \ No newline at end of file diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index e24d6fbe..5ebb3b92 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -162,6 +162,8 @@ impl<'a> LoopBuilder<'a> { // 完成したPhi nodeを発行 self.emit_phi_at_block_start(block_id, phi.phi_id, phi.known_inputs)?; + // 重要: ループ外から参照される変数はPhi結果に束縛し直す + self.update_variable(phi.var_name.clone(), phi.phi_id); } } diff --git a/src/mir/verification.rs b/src/mir/verification.rs index a3d8385d..0eca97d3 100644 --- a/src/mir/verification.rs +++ b/src/mir/verification.rs @@ -753,4 +753,95 @@ mod tests { assert!(errs.iter().any(|e| matches!(e, VerificationError::MergeUsesPredecessorValue{..} | VerificationError::DominatorViolation{..})), "Expected merge/dominator error, got: {:?}", errs); } + + #[test] + fn test_loop_phi_normalization() { + // Program: + // local i = 0 + // loop(false) { i = 1 } + // i + let ast = ASTNode::Program { + statements: vec![ + ASTNode::Local { + variables: vec!["i".to_string()], + initial_values: vec![Some(Box::new(ASTNode::Literal { value: LiteralValue::Integer(0), span: Span::unknown() }))], + span: Span::unknown(), + }, + ASTNode::Loop { + condition: Box::new(ASTNode::Literal { value: LiteralValue::Bool(false), span: Span::unknown() }), + body: vec![ ASTNode::Assignment { + target: Box::new(ASTNode::Variable { name: "i".to_string(), span: Span::unknown() }), + value: Box::new(ASTNode::Literal { value: LiteralValue::Integer(1), span: Span::unknown() }), + span: Span::unknown(), + }], + span: Span::unknown(), + }, + ASTNode::Variable { name: "i".to_string(), span: Span::unknown() }, + ], + span: Span::unknown(), + }; + + let mut builder = MirBuilder::new(); + let module = builder.build_module(ast).expect("build mir"); + + // Verify SSA/dominance: should pass + let mut verifier = MirVerifier::new(); + let res = verifier.verify_module(&module); + if let Err(errs) = &res { eprintln!("Verifier errors: {:?}", errs); } + assert!(res.is_ok(), "MIR loop with phi normalization should pass verification"); + + // Ensure phi is printed (header phi for variable i) + let printer = MirPrinter::verbose(); + let mir_text = printer.print_module(&module); + assert!(mir_text.contains("phi"), "Printed MIR should contain a phi for loop header\n{}", mir_text); + } + + #[test] + fn test_loop_nested_if_phi() { + // Program: + // local x = 0 + // loop(false) { if true { x = 1 } else { x = 2 } } + // x + let ast = ASTNode::Program { + statements: vec![ + ASTNode::Local { + variables: vec!["x".to_string()], + initial_values: vec![Some(Box::new(ASTNode::Literal { value: LiteralValue::Integer(0), span: Span::unknown() }))], + span: Span::unknown(), + }, + ASTNode::Loop { + condition: Box::new(ASTNode::Literal { value: LiteralValue::Bool(false), span: Span::unknown() }), + body: vec![ ASTNode::If { + condition: Box::new(ASTNode::Literal { value: LiteralValue::Bool(true), span: Span::unknown() }), + then_body: vec![ ASTNode::Assignment { + target: Box::new(ASTNode::Variable { name: "x".to_string(), span: Span::unknown() }), + value: Box::new(ASTNode::Literal { value: LiteralValue::Integer(1), span: Span::unknown() }), + span: Span::unknown(), + }], + else_body: Some(vec![ ASTNode::Assignment { + target: Box::new(ASTNode::Variable { name: "x".to_string(), span: Span::unknown() }), + value: Box::new(ASTNode::Literal { value: LiteralValue::Integer(2), span: Span::unknown() }), + span: Span::unknown(), + }]), + span: Span::unknown(), + }], + span: Span::unknown(), + }, + ASTNode::Variable { name: "x".to_string(), span: Span::unknown() }, + ], + span: Span::unknown(), + }; + + let mut builder = MirBuilder::new(); + let module = builder.build_module(ast).expect("build mir"); + + let mut verifier = MirVerifier::new(); + let res = verifier.verify_module(&module); + if let Err(errs) = &res { eprintln!("Verifier errors: {:?}", errs); } + assert!(res.is_ok(), "Nested if in loop should pass verification with proper phis"); + + let printer = MirPrinter::verbose(); + let mir_text = printer.print_module(&module); + assert!(mir_text.contains("phi"), "Printed MIR should contain phi nodes for nested if/loop\n{}", mir_text); + } }