feat: Implement Phase 9.78e instance_v2 migration with unified registry

Major achievements:
-  UserDefinedBoxFactory implementation with unified registry integration
-  Constructor execution for user-defined boxes (Person init working)
-  Import path fixes across interpreter modules
-  unwrap_instance helper function for InstanceBox operator support

Technical details:
- Modified UnifiedBoxRegistry to handle empty box_types() factories
- Implemented constructor execution in execute_new for InstanceBox
- Added unwrap_instance helper to handle InstanceBox wrapping in operators
- Updated CURRENT_TASK.md with detailed progress tracking

Next: Fix 4 operator functions to complete InstanceBox operator support

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-20 00:21:20 +09:00
parent 5a50cf6415
commit e5e381aa83
9 changed files with 274 additions and 70 deletions

View File

@ -1,57 +1,94 @@
# 🎯 現在のタスク (2025-08-19 更新) # 🎯 現在のタスク (2025-08-19 更新)
## ✅ 完了: Phase 9.78e instance_v2移行成功! ## 🚧 進行中: Phase 9.78e instance_v2移行(最終段階)
### 🎉 **Phase 9.78e: instance_v2への完全移行** ### 🎉 **Phase 9.78e: 重要マイルストーン達成済み**
**達成**: インタープリター全体でinstance_v2を使用、instance.rsは参照されず -instance.rs完全削除成功!
- ✅ 統一レジストリによるユーザー定義Box生成成功
- ✅ コンストラクタ実行成功
- ✅ インポート問題完全解決
#### ✅ **完了事項** ### 🔥 **現在の課題: InstanceBoxラップ演算子問題**
- ✅ 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実装
- 一時的な型変換回避策
#### 🚧 **残課題(非ブロッカー)** #### 💥 **具体的なエラー**
- **TODO**: 型変換の適切な実装instance_v2.rs:218, 238 ```bash
- **現在の型変換フロー**: ❌ Runtime error:
- SharedNyashBox = `Arc<dyn NyashBox>` ⚠️ Invalid operation: Addition not supported between StringBox and StringBox
- NyashValue::Box = `Arc<Mutex<dyn NyashBox>>` ```
- 変換1: `SharedNyashBox``NyashValue::Box` (Mutexで包む必要)
- 変換2: `Box<dyn NyashBox>``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パス修正
- テストの完全実行
## 🚀 次のステップ: instance.rs削除 #### 🔍 **根本原因**
1. **BuiltinBoxFactory**がStringBoxを`InstanceBox::from_any_box()`でラップして返す
2. **演算子処理**try_add_operationが直接StringBoxを期待
3. **実際の構造**: `InstanceBox<StringBox>` vs 期待: `StringBox`
### 🎯 **instance v1完全削除で勝利宣言** #### 🎯 **解決方針: シンプル実装アプローチ**
**現状**: instance.rsは誰も使っていないlib.rsでinstance_v2がエクスポート **ChatGPT5/Gemini先生への相談結果**: 段階的実装を推奨
1. **削除対象**: **選択した戦略**:
- src/instance.rs本体 ```rust
- lib.rs:20の`pub mod instance;` // unwrap_instanceヘルパー関数30分で実装可能
- main.rs:21の`pub mod instance;` fn unwrap_instance(boxed: &dyn NyashBox) -> &dyn NyashBox {
if let Some(instance) = boxed.as_any().downcast_ref::<InstanceBox>() {
if let Some(ref inner) = instance.inner_content {
return inner.as_ref();
}
}
boxed
}
```
2. **動作確認**: **修正対象**: 4つの演算子関数のみ
- 基本的なBox定義・インスタンス作成 - 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追加 最終更新: 2025-08-19 - Phase 9.78e完全勝利instance.rs削除成功、instance_v2が唯一の実装に

View File

@ -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<dyn NyashBox>)
```
しかし、演算子処理try_add_operationが直接StringBoxを期待しているため
```
❌ Runtime error:
⚠️ Invalid operation: Addition not supported between StringBox and StringBox
```
【2つの選択肢】
Option 1: すべてのBoxをInstanceBoxでラップする統一アーキテクチャ
- StringBox → InstanceBox<StringBox>
- IntegerBox → InstanceBox<IntegerBox>
- UserBox → InstanceBox<UserBox>
- 演算子処理をInstanceBox対応に修正
Option 2: ビルトインは直接返す混在アーキテクチャ
- StringBox → StringBox直接
- UserBox → InstanceBox<UserBox>
- ビルトインと他で扱いが異なる
【Option 1を推奨する理由】
1. Everything is Box哲学の完全実現
- すべてのBoxが同じ形で統一される美しさ
- ビルトイン、ユーザー定義、プラグインの区別なし
2. 将来の拡張性
- プラグインBoxも同じように扱える
- 新しいBox型追加時も同じパターン
3. デバッグ・保守性
- 統一構造によりデバッグツールが書きやすい
- メモリ管理、ライフサイクル管理が統一的
4. ユーザー体験の一貫性
- ユーザーから見て全Box型が同じ挙動
- 継承・デリゲーションも統一的
【技術的な懸念事項】
1. パフォーマンス
- 二重構造によるオーバーヘッド
- 演算子呼び出し時の追加のダウンキャスト
2. 実装の複雑さ
- すべての演算子処理を修正する必要
- 既存コードとの互換性
3. 型安全性
- inner_contentがOption<Box<dyn NyashBox>>なので、実行時チェックが必要
【質問】
1. このアーキテクチャ選択についてどう思われますか?
2. パフォーマンスへの影響は許容範囲でしょうか?(最適化は後回しで良い前提)
3. Everything is Box哲学の観点から、統一アーキテクチャは正しい方向性でしょうか
4. 他の言語Ruby、Python、JavaScriptの類似事例はありますか
【実装方針案】
```rust
// 演算子処理の修正例
fn try_add_operation(left: &dyn NyashBox, right: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
// InstanceBoxの場合、内包されたBoxを取り出す
let left_inner = if let Some(instance) = left.as_any().downcast_ref::<InstanceBox>() {
instance.inner_content.as_ref()?.as_ref()
} else {
left
};
// 以下、従来の処理...
}
```
Nyashの設計哲学と実装の現実性のバランスについて、専門的な視点からアドバイスをお願いします。

View File

@ -90,10 +90,22 @@ impl UnifiedBoxRegistry {
} }
drop(cache); drop(cache);
// Fallback: linear search through all factories // Linear search through all factories
for factory in &self.factories { for factory in &self.factories {
if factory.box_types().contains(&name) && factory.is_available() { if !factory.is_available() {
return factory.create_box(name, args); 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
} }
} }

View File

@ -7,19 +7,18 @@
use super::BoxFactory; use super::BoxFactory;
use crate::box_trait::NyashBox; 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 /// Factory for user-defined Box types
pub struct UserDefinedBoxFactory { pub struct UserDefinedBoxFactory {
// TODO: This will need access to the interpreter context shared_state: SharedState,
// to look up box declarations and execute constructors
// For now, this is a placeholder
} }
impl UserDefinedBoxFactory { impl UserDefinedBoxFactory {
pub fn new() -> Self { pub fn new(shared_state: SharedState) -> Self {
Self { Self {
// TODO: Initialize with interpreter reference shared_state,
} }
} }
} }
@ -27,28 +26,39 @@ impl UserDefinedBoxFactory {
impl BoxFactory for UserDefinedBoxFactory { impl BoxFactory for UserDefinedBoxFactory {
fn create_box( fn create_box(
&self, &self,
_name: &str, name: &str,
_args: &[Box<dyn NyashBox>], _args: &[Box<dyn NyashBox>],
) -> Result<Box<dyn NyashBox>, RuntimeError> { ) -> Result<Box<dyn NyashBox>, RuntimeError> {
// TODO: Implementation will be moved from objects.rs // Look up box declaration
// This will: let box_decl = {
// 1. Look up box declaration let box_decls = self.shared_state.box_declarations.read().unwrap();
// 2. Create InstanceBox with fields and methods box_decls.get(name).cloned()
// 3. Execute birth constructor if present };
// 4. Return the instance
Err(RuntimeError::InvalidOperation { let box_decl = box_decl.ok_or_else(|| RuntimeError::InvalidOperation {
message: "User-defined Box factory not yet implemented".to_string(), 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> { 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![] vec![]
} }
fn is_available(&self) -> bool { fn is_available(&self) -> bool {
// TODO: Check if interpreter context is available // Always available when SharedState is present
false true
} }
} }

View File

@ -11,6 +11,7 @@ use std::collections::HashSet;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::fmt; use std::fmt;
use crate::box_trait::NyashBox; use crate::box_trait::NyashBox;
use crate::instance_v2::InstanceBox;
use lazy_static::lazy_static; use lazy_static::lazy_static;
lazy_static! { lazy_static! {
@ -67,7 +68,7 @@ impl BoxFinalizer {
if !is_finalized(*box_id) { if !is_finalized(*box_id) {
// fini()メソッドを呼び出す(存在する場合) // fini()メソッドを呼び出す(存在する場合)
if let Some(instance) = nyash_box.as_any().downcast_ref::<crate::instance_v2::InstanceBox>() { if let Some(instance) = nyash_box.as_any().downcast_ref::<InstanceBox>() {
let _ = instance.fini(); let _ = instance.fini();
} }
mark_as_finalized(*box_id); mark_as_finalized(*box_id);

View File

@ -220,6 +220,13 @@ impl NyashInterpreter {
pub fn new() -> Self { pub fn new() -> Self {
let shared = SharedState::new(); 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 { Self {
shared, shared,
local_vars: HashMap::new(), local_vars: HashMap::new(),
@ -387,7 +394,7 @@ impl NyashInterpreter {
} else { } else {
eprintln!("🔍 DEBUG: '{}' not found in statics MapBox", name); eprintln!("🔍 DEBUG: '{}' not found in statics MapBox", name);
} }
} else if let Some(instance) = statics_namespace.as_any().downcast_ref::<crate::instance_v2::InstanceBox>() { } else if let Some(instance) = statics_namespace.as_any().downcast_ref::<InstanceBox>() {
eprintln!("🔍 DEBUG: statics is an InstanceBox, looking for '{}'", name); eprintln!("🔍 DEBUG: statics is an InstanceBox, looking for '{}'", name);
if let Some(static_box) = instance.get_field(name) { if let Some(static_box) = instance.get_field(name) {
eprintln!("🔍 DEBUG: Found '{}' in statics namespace", name); eprintln!("🔍 DEBUG: Found '{}' in statics namespace", name);

View File

@ -8,8 +8,20 @@ use crate::box_trait::{NyashBox, IntegerBox, BoolBox, CompareBox};
use crate::boxes::StringBox; // 🔧 統一レジストリと一致させる use crate::boxes::StringBox; // 🔧 統一レジストリと一致させる
use crate::boxes::FloatBox; use crate::boxes::FloatBox;
use crate::interpreter::core::{NyashInterpreter, RuntimeError}; use crate::interpreter::core::{NyashInterpreter, RuntimeError};
use crate::instance_v2::InstanceBox;
// Local helper functions to bypass import issues // 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::<InstanceBox>() {
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<Box<dyn NyashBox>> { pub(super) fn try_add_operation(left: &dyn NyashBox, right: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
// 🔍 デバッグ出力追加 // 🔍 デバッグ出力追加
eprintln!("🔍 try_add_operation: left={}, right={}", left.type_name(), right.type_name()); eprintln!("🔍 try_add_operation: left={}, right={}", left.type_name(), right.type_name());

View File

@ -36,6 +36,44 @@ impl NyashInterpreter {
match registry_lock.create_box(class, &args) { match registry_lock.create_box(class, &args) {
Ok(box_instance) => { Ok(box_instance) => {
eprintln!("🏭 Unified registry created: {}", class); 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::<crate::instance_v2::InstanceBox>() {
// 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); return Ok(box_instance);
}, },
Err(e) => { Err(e) => {

View File

@ -15,6 +15,7 @@
use super::*; use super::*;
use crate::boxes::SoundBox; use crate::boxes::SoundBox;
use crate::method_box::MethodBox; use crate::method_box::MethodBox;
use crate::instance_v2::InstanceBox;
impl NyashInterpreter { impl NyashInterpreter {
/// SoundBoxのメソッド呼び出しを実行 /// SoundBoxのメソッド呼び出しを実行
@ -159,7 +160,7 @@ impl NyashInterpreter {
let instance = instance_arc.lock().unwrap(); let instance = instance_arc.lock().unwrap();
// InstanceBoxにダウンキャスト // InstanceBoxにダウンキャスト
if let Some(instance_box) = instance.as_any().downcast_ref::<crate::instance_v2::InstanceBox>() { if let Some(instance_box) = instance.as_any().downcast_ref::<InstanceBox>() {
// メソッドを取得 // メソッドを取得
let method_ast = instance_box.get_method(&method_box.method_name) let method_ast = instance_box.get_method(&method_box.method_name)
.ok_or(RuntimeError::InvalidOperation { .ok_or(RuntimeError::InvalidOperation {