diff --git a/docs/CURRENT_TASK.md b/docs/CURRENT_TASK.md index b4bed54c..28e5db7f 100644 --- a/docs/CURRENT_TASK.md +++ b/docs/CURRENT_TASK.md @@ -1,57 +1,94 @@ # 🎯 現在のタスク (2025-08-19 更新) -## ✅ 完了: Phase 9.78e instance_v2移行成功! +## 🚧 進行中: Phase 9.78e instance_v2移行(最終段階) -### 🎉 **Phase 9.78e: instance_v2への完全移行** -**達成**: インタープリター全体でinstance_v2を使用、instance.rsは参照されず +### 🎉 **Phase 9.78e: 重要マイルストーン達成済み** +- ✅ instance.rs完全削除成功! +- ✅ 統一レジストリによるユーザー定義Box生成成功 +- ✅ コンストラクタ実行成功 +- ✅ インポート問題完全解決 -#### ✅ **完了事項** -- ✅ instance_v2にレガシー互換レイヤー追加 - - fields、weak_fields_union等のレガシーフィールド - - get_fields()、set_field_legacy()等の互換メソッド -- ✅ インタープリター全箇所でinstance_v2使用 - - すべての`crate::instance::`を`crate::instance_v2::`に変更 - - fields直接アクセスをget_fields()経由に変更 -- ✅ 型エラー解決(強引だが動作) - - set_weak_field_from_legacy実装 - - 一時的な型変換回避策 +### 🔥 **現在の課題: InstanceBoxラップ演算子問題** -#### 🚧 **残課題(非ブロッカー)** -- **TODO**: 型変換の適切な実装(instance_v2.rs:218, 238) - - **現在の型変換フロー**: - - SharedNyashBox = `Arc` - - NyashValue::Box = `Arc>` - - 変換1: `SharedNyashBox` → `NyashValue::Box` (Mutexで包む必要) - - 変換2: `Box` → `SharedNyashBox` (Arc::from) - - 変換3: `NyashValue` → `SharedNyashBox` (取り出してArcに) - - **スコープ問題**: - - get_field()が2つ存在(レガシー版とNyashValue版) - - set_field()も同様に2つ存在 - - 呼び出し元によって期待される型が異なる - - **一時的回避策**: - - set_field_legacy()では変換を諦めてNullを設定 - - set_weak_field_from_legacy()ではレガシーfieldsに直接保存 -- バイナリビルドのimportパス修正 -- テストの完全実行 +#### 💥 **具体的なエラー** +```bash +❌ Runtime error: +⚠️ Invalid operation: Addition not supported between StringBox and StringBox +``` -## 🚀 次のステップ: instance.rs削除 +#### 🔍 **根本原因** +1. **BuiltinBoxFactory**がStringBoxを`InstanceBox::from_any_box()`でラップして返す +2. **演算子処理**(try_add_operation)が直接StringBoxを期待 +3. **実際の構造**: `InstanceBox` vs 期待: `StringBox` -### 🎯 **instance v1完全削除で勝利宣言!** -**現状**: instance.rsは誰も使っていない(lib.rsでinstance_v2がエクスポート) +#### 🎯 **解決方針: シンプル実装アプローチ** +**ChatGPT5/Gemini先生への相談結果**: 段階的実装を推奨 -1. **削除対象**: - - src/instance.rs(本体) - - lib.rs:20の`pub mod instance;` - - main.rs:21の`pub mod instance;` +**選択した戦略**: +```rust +// unwrap_instanceヘルパー関数(30分で実装可能) +fn unwrap_instance(boxed: &dyn NyashBox) -> &dyn NyashBox { + if let Some(instance) = boxed.as_any().downcast_ref::() { + if let Some(ref inner) = instance.inner_content { + return inner.as_ref(); + } + } + boxed +} +``` -2. **動作確認**: - - 基本的なBox定義・インスタンス作成 - - フィールドアクセス・デリゲーション +**修正対象**: 4つの演算子関数のみ +- try_add_operation +- try_sub_operation +- try_mul_operation +- try_div_operation -3. **将来のクリーンアップ**(段階的に): - - レガシーfields → fields_ngに統一 - - 互換メソッド削除 - - 型変換の適切な実装 +#### 🏆 **完了事項** +- ✅ インポート問題解決(バイナリビルド) +- ✅ 完全パス使用箇所をuse文で修正 +- ✅ ユーザー定義Boxの統一レジストリ登録問題 +- ✅ コンストラクタ実行成功 +- ✅ Person("Alice", 25) → init実行確認 + +#### ⚡ **次の実装ステップ(30分で完了予定)** +1. **unwrap_instanceヘルパー関数実装** ← 進行中 + - 場所: `src/interpreter/expressions/operators.rs` + - 役割: InstanceBoxでラップされた場合、内部のBoxを取得 + +2. **4つの演算子関数を修正** + - try_add_operation: 文字列結合とIntegerBox加算 + - try_sub_operation: IntegerBox減算 + - try_mul_operation: IntegerBox乗算、StringBox繰り返し + - try_div_operation: IntegerBox除算、ゼロ除算エラー処理 + +3. **テスト実行** + - `./target/debug/nyash local_tests/test_instance_v2_migration.nyash` + - 期待結果: Person created, Hello I'm Alice, フィールドアクセス成功 + +#### 🎯 **成功の指標** +```nyash +local alice = new Person("Alice", 25) +alice.greet() // ← これが成功すれば完了! +print("Name: " + alice.name) // ← StringBox演算子が動けば完了! +``` + +## 🚀 次のステップ: レガシー互換層のクリーンアップ + +### 🎯 **instance_v2の純粋化** +**現状**: instance_v2にレガシー互換層が残存(段階的削除予定) + +1. **クリーンアップ対象**: + - レガシーfields → fields_ngに完全統一 + - get_field_legacy/set_field_legacy等の互換メソッド削除 + - SharedNyashBox ↔ NyashValue型変換の適切な実装 + +2. **バイナリビルド修正**: + - importパスエラー修正(crate::instance_v2) + - テスト実行環境の整備 + +3. **性能最適化**: + - 不要なMutex削除検討 + - 型変換オーバーヘッド削減 --- @@ -102,4 +139,4 @@ cargo build --release -j32 --features wasm-backend - レジスタ割り当て最適化 - インライン展開 -最終更新: 2025-08-19 - Phase 9.78e instance_v2主体の移行戦略に変更、型変換TODO追加 \ No newline at end of file +最終更新: 2025-08-19 - Phase 9.78e完全勝利!instance.rs削除成功、instance_v2が唯一の実装に \ No newline at end of file diff --git a/local_tests/gemini_consultation_instancebox.txt b/local_tests/gemini_consultation_instancebox.txt new file mode 100644 index 00000000..2cd8724f --- /dev/null +++ b/local_tests/gemini_consultation_instancebox.txt @@ -0,0 +1,86 @@ +Nyashプログラミング言語のInstanceBoxアーキテクチャについて深い技術相談です。 + +【現在の状況】 +Phase 9.78eでinstance_v2統一実装を進めています。統一レジストリ(UnifiedBoxRegistry)によりビルトインBox、ユーザー定義Box、プラグインBoxをすべて同じインターフェースで生成する仕組みを実装しました。 + +【発生している問題】 +BuiltinBoxFactoryがStringBoxを作る際、InstanceBoxでラップして返しています: +```rust +// StringBox作成時 +let inner = StringBox::new(value); +let instance = InstanceBox::from_any_box("StringBox".to_string(), Box::new(inner)); +Ok(Box::new(instance) as Box) +``` + +しかし、演算子処理(try_add_operation)が直接StringBoxを期待しているため: +``` +❌ Runtime error: +⚠️ Invalid operation: Addition not supported between StringBox and StringBox +``` + +【2つの選択肢】 + +Option 1: すべてのBoxをInstanceBoxでラップする統一アーキテクチャ +- StringBox → InstanceBox +- IntegerBox → InstanceBox +- UserBox → InstanceBox +- 演算子処理をInstanceBox対応に修正 + +Option 2: ビルトインは直接返す混在アーキテクチャ +- StringBox → StringBox(直接) +- UserBox → InstanceBox +- ビルトインと他で扱いが異なる + +【Option 1を推奨する理由】 + +1. Everything is Box哲学の完全実現 + - すべてのBoxが同じ形で統一される美しさ + - ビルトイン、ユーザー定義、プラグインの区別なし + +2. 将来の拡張性 + - プラグインBoxも同じように扱える + - 新しいBox型追加時も同じパターン + +3. デバッグ・保守性 + - 統一構造によりデバッグツールが書きやすい + - メモリ管理、ライフサイクル管理が統一的 + +4. ユーザー体験の一貫性 + - ユーザーから見て全Box型が同じ挙動 + - 継承・デリゲーションも統一的 + +【技術的な懸念事項】 + +1. パフォーマンス + - 二重構造によるオーバーヘッド + - 演算子呼び出し時の追加のダウンキャスト + +2. 実装の複雑さ + - すべての演算子処理を修正する必要 + - 既存コードとの互換性 + +3. 型安全性 + - inner_contentがOption>なので、実行時チェックが必要 + +【質問】 +1. このアーキテクチャ選択についてどう思われますか? +2. パフォーマンスへの影響は許容範囲でしょうか?(最適化は後回しで良い前提) +3. Everything is Box哲学の観点から、統一アーキテクチャは正しい方向性でしょうか? +4. 他の言語(Ruby、Python、JavaScript)の類似事例はありますか? + +【実装方針案】 +```rust +// 演算子処理の修正例 +fn try_add_operation(left: &dyn NyashBox, right: &dyn NyashBox) -> Option> { + // InstanceBoxの場合、内包されたBoxを取り出す + let left_inner = if let Some(instance) = left.as_any().downcast_ref::() { + instance.inner_content.as_ref()?.as_ref() + } else { + left + }; + + // 以下、従来の処理... +} +``` + +Nyashの設計哲学と実装の現実性のバランスについて、専門的な視点からアドバイスをお願いします。 \ No newline at end of file diff --git a/src/box_factory/mod.rs b/src/box_factory/mod.rs index 9d832205..5a7a1975 100644 --- a/src/box_factory/mod.rs +++ b/src/box_factory/mod.rs @@ -90,10 +90,22 @@ impl UnifiedBoxRegistry { } drop(cache); - // Fallback: linear search through all factories + // Linear search through all factories for factory in &self.factories { - if factory.box_types().contains(&name) && factory.is_available() { - return factory.create_box(name, args); + if !factory.is_available() { + continue; + } + + // For factories that advertise types, check if they support this type + let box_types = factory.box_types(); + if !box_types.is_empty() && !box_types.contains(&name) { + continue; + } + + // Try to create the box (factories with empty box_types() will always be tried) + match factory.create_box(name, args) { + Ok(boxed) => return Ok(boxed), + Err(_) => continue, // Try next factory } } diff --git a/src/box_factory/user_defined.rs b/src/box_factory/user_defined.rs index 46f483af..160d42c9 100644 --- a/src/box_factory/user_defined.rs +++ b/src/box_factory/user_defined.rs @@ -7,19 +7,18 @@ use super::BoxFactory; use crate::box_trait::NyashBox; -use crate::interpreter::RuntimeError; +use crate::interpreter::{RuntimeError, SharedState}; +use crate::instance_v2::InstanceBox; /// Factory for user-defined Box types pub struct UserDefinedBoxFactory { - // TODO: This will need access to the interpreter context - // to look up box declarations and execute constructors - // For now, this is a placeholder + shared_state: SharedState, } impl UserDefinedBoxFactory { - pub fn new() -> Self { + pub fn new(shared_state: SharedState) -> Self { Self { - // TODO: Initialize with interpreter reference + shared_state, } } } @@ -27,28 +26,39 @@ impl UserDefinedBoxFactory { impl BoxFactory for UserDefinedBoxFactory { fn create_box( &self, - _name: &str, + name: &str, _args: &[Box], ) -> Result, RuntimeError> { - // TODO: Implementation will be moved from objects.rs - // This will: - // 1. Look up box declaration - // 2. Create InstanceBox with fields and methods - // 3. Execute birth constructor if present - // 4. Return the instance + // Look up box declaration + let box_decl = { + let box_decls = self.shared_state.box_declarations.read().unwrap(); + box_decls.get(name).cloned() + }; - Err(RuntimeError::InvalidOperation { - message: "User-defined Box factory not yet implemented".to_string(), - }) + let box_decl = box_decl.ok_or_else(|| RuntimeError::InvalidOperation { + message: format!("Unknown Box type: {}", name), + })?; + + // Create InstanceBox with fields and methods + let instance = InstanceBox::from_declaration( + name.to_string(), + box_decl.fields.clone(), + box_decl.methods.clone(), + ); + + // TODO: Execute birth/init constructor with args + // For now, just return the instance + Ok(Box::new(instance)) } fn box_types(&self) -> Vec<&str> { - // TODO: Return list of registered user-defined Box types + // Can't return borrowed strings from temporary RwLock guard + // For now, return empty - this method isn't critical vec![] } fn is_available(&self) -> bool { - // TODO: Check if interpreter context is available - false + // Always available when SharedState is present + true } } \ No newline at end of file diff --git a/src/finalization.rs b/src/finalization.rs index 2f77be8f..69ea5e5d 100644 --- a/src/finalization.rs +++ b/src/finalization.rs @@ -11,6 +11,7 @@ use std::collections::HashSet; use std::sync::{Arc, Mutex}; use std::fmt; use crate::box_trait::NyashBox; +use crate::instance_v2::InstanceBox; use lazy_static::lazy_static; lazy_static! { @@ -67,7 +68,7 @@ impl BoxFinalizer { if !is_finalized(*box_id) { // fini()メソッドを呼び出す(存在する場合) - if let Some(instance) = nyash_box.as_any().downcast_ref::() { + if let Some(instance) = nyash_box.as_any().downcast_ref::() { let _ = instance.fini(); } mark_as_finalized(*box_id); diff --git a/src/interpreter/core.rs b/src/interpreter/core.rs index 6dd0add6..f285e650 100644 --- a/src/interpreter/core.rs +++ b/src/interpreter/core.rs @@ -220,6 +220,13 @@ impl NyashInterpreter { pub fn new() -> Self { let shared = SharedState::new(); + // Register user-defined box factory with unified registry + use crate::box_factory::user_defined::UserDefinedBoxFactory; + use crate::runtime::register_user_defined_factory; + + let factory = UserDefinedBoxFactory::new(shared.clone()); + register_user_defined_factory(Arc::new(factory)); + Self { shared, local_vars: HashMap::new(), @@ -387,7 +394,7 @@ impl NyashInterpreter { } else { eprintln!("🔍 DEBUG: '{}' not found in statics MapBox", name); } - } else if let Some(instance) = statics_namespace.as_any().downcast_ref::() { + } else if let Some(instance) = statics_namespace.as_any().downcast_ref::() { eprintln!("🔍 DEBUG: statics is an InstanceBox, looking for '{}'", name); if let Some(static_box) = instance.get_field(name) { eprintln!("🔍 DEBUG: Found '{}' in statics namespace", name); diff --git a/src/interpreter/expressions/operators.rs b/src/interpreter/expressions/operators.rs index 1f5434b9..b2fa038b 100644 --- a/src/interpreter/expressions/operators.rs +++ b/src/interpreter/expressions/operators.rs @@ -8,8 +8,20 @@ use crate::box_trait::{NyashBox, IntegerBox, BoolBox, CompareBox}; use crate::boxes::StringBox; // 🔧 統一レジストリと一致させる use crate::boxes::FloatBox; use crate::interpreter::core::{NyashInterpreter, RuntimeError}; +use crate::instance_v2::InstanceBox; // Local helper functions to bypass import issues + +/// InstanceBoxでラップされている場合、内部のBoxを取得する +/// シンプルなヘルパー関数で型地獄を回避 +fn unwrap_instance(boxed: &dyn NyashBox) -> &dyn NyashBox { + if let Some(instance) = boxed.as_any().downcast_ref::() { + if let Some(ref inner) = instance.inner_content { + return inner.as_ref(); + } + } + boxed +} pub(super) fn try_add_operation(left: &dyn NyashBox, right: &dyn NyashBox) -> Option> { // 🔍 デバッグ出力追加 eprintln!("🔍 try_add_operation: left={}, right={}", left.type_name(), right.type_name()); diff --git a/src/interpreter/objects.rs b/src/interpreter/objects.rs index 2c74000c..2177f8ef 100644 --- a/src/interpreter/objects.rs +++ b/src/interpreter/objects.rs @@ -36,6 +36,44 @@ impl NyashInterpreter { match registry_lock.create_box(class, &args) { Ok(box_instance) => { eprintln!("🏭 Unified registry created: {}", class); + + // Check if this is a user-defined box that needs constructor execution + if let Some(_instance_box) = box_instance.as_any().downcast_ref::() { + // This is a user-defined box, we need to execute its constructor + eprintln!("🔍 User-defined box detected, executing constructor"); + + // Check if we have a box declaration for this class + let (box_decl_opt, constructor_opt) = { + let box_decls = self.shared.box_declarations.read().unwrap(); + if let Some(box_decl) = box_decls.get(class) { + // Find the appropriate constructor + let constructor_name = format!("init/{}", arguments.len()); + let constructor = box_decl.constructors.get(&constructor_name).cloned(); + (Some(box_decl.clone()), constructor) + } else { + (None, None) + } + }; + + if let Some(box_decl) = box_decl_opt { + if let Some(constructor) = constructor_opt { + // Execute the constructor + let instance_arc: SharedNyashBox = Arc::from(box_instance); + drop(registry_lock); // Release lock before executing constructor + self.execute_constructor(&instance_arc, &constructor, arguments, &box_decl)?; + return Ok((*instance_arc).clone_box()); + } else if arguments.is_empty() { + // No constructor needed for zero arguments + return Ok(box_instance); + } else { + return Err(RuntimeError::InvalidOperation { + message: format!("No constructor found for {} with {} arguments", class, arguments.len()), + }); + } + } + } + + // Not a user-defined box or no constructor needed return Ok(box_instance); }, Err(e) => { diff --git a/src/interpreter/special_methods.rs b/src/interpreter/special_methods.rs index 4d28a9ef..15508509 100644 --- a/src/interpreter/special_methods.rs +++ b/src/interpreter/special_methods.rs @@ -15,6 +15,7 @@ use super::*; use crate::boxes::SoundBox; use crate::method_box::MethodBox; +use crate::instance_v2::InstanceBox; impl NyashInterpreter { /// SoundBoxのメソッド呼び出しを実行 @@ -159,7 +160,7 @@ impl NyashInterpreter { let instance = instance_arc.lock().unwrap(); // InstanceBoxにダウンキャスト - if let Some(instance_box) = instance.as_any().downcast_ref::() { + if let Some(instance_box) = instance.as_any().downcast_ref::() { // メソッドを取得 let method_ast = instance_box.get_method(&method_box.method_name) .ok_or(RuntimeError::InvalidOperation {