feat(plugin): Fix plugin BoxRef return and Box argument support

- Fixed deadlock in FileBox plugin copyFrom implementation (single lock)
- Added TLV Handle (tag=8) parsing in calls.rs for returned BoxRefs
- Improved plugin loader with config path consistency and detailed logging
- Fixed loader routing for proper Handle type_id/fini_method_id resolution
- Added detailed logging for TLV encoding/decoding in plugin_loader_v2

Test docs/examples/plugin_boxref_return.nyash now works correctly:
- cloneSelf() returns FileBox Handle properly
- copyFrom(Box) accepts plugin Box arguments
- Both FileBox instances close and fini correctly

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-21 00:41:26 +09:00
parent af32896574
commit cc2a820af7
274 changed files with 7244 additions and 4608 deletions

View File

@ -0,0 +1,54 @@
# 📦 Nyash Boxシステム設計ドキュメント
## 🎯 概要
Nyashの核心哲学「**Everything is Box**」に関する完全な設計ドキュメント集。
言語設計の根幹から実装詳細まで、Boxシステムのすべてを網羅しています。
## 📚 ドキュメント構成
### 🌟 コア哲学
#### [everything-is-box.md](everything-is-box.md)
Nyashの核心哲学「Everything is Box」の解説。なぜすべてをBoxにするのか、その設計思想と利点。
### 📖 完全リファレンス
#### [box-reference.md](box-reference.md)
**統合版Box型完全リファレンス**。全ビルトインBox型のAPI仕様、基本型からプラグインBoxまで。
### 🔄 システム設計
#### [delegation-system.md](delegation-system.md)
完全明示デリゲーションシステムの設計。`from`構文、`override`必須、`pack`構文の詳細仕様。
#### [memory-finalization.md](memory-finalization.md)
**統合版メモリ管理&finiシステム**。Arc<Mutex>一元管理、fini()論理的解放、weak参照、プラグインメモリ安全性。
## 🔗 関連ドキュメント
- **[プラグインシステム](../plugin-system/)**: BID-FFIプラグインシステム完全仕様
- **[言語仕様](../core-language/)**: デリゲーション構文、言語リファレンス
- **[実行バックエンド](../execution-backend/)**: MIR、P2P通信仕様
## 🎨 設計原則
### Everything is Box
- すべての値がBoxオブジェクト
- 統一的なメソッド呼び出し
- プリミティブ型と参照型の区別なし
### メモリ安全性
- Arc<Mutex>による統一管理
- fini()による決定論的リソース解放
- weak参照による循環参照回避
### プラグイン拡張性
- BID-FFIによる外部ライブラリ統合
- 型情報管理による安全な変換
- HostVtableによるメモリ管理
---
**最終更新**: 2025年8月19日 - boxes-system統合整理完了
**Phase 9.75g-0成果**: プラグインシステムとの完全統合

View File

@ -0,0 +1,270 @@
# 📦 Nyash Box型完全リファレンス
Nyashで利用できる全ビルトインBox型の完全API仕様書です。
## 📋 Box型分類
### 🎯 基本型BoxPrimitive Boxes
#### StringBox
文字列を扱う基本Box型。
```nyash
local str = "Hello, Nyash!" // 自動的にStringBox
local explicit = new StringBox("Explicit creation")
// メソッド
str.length() // 文字数を取得
str.toUpperCase() // 大文字変換
str.split(",") // 文字列分割
str.contains("Nya") // 部分文字列検索
```
#### IntegerBox
整数を扱う基本Box型。
```nyash
local num = 42 // 自動的にIntegerBox
local big = new IntegerBox(1000000)
// メソッド
num.add(10) // 加算
num.multiply(2) // 乗算
num.toString() // 文字列変換
num.isEven() // 偶数判定
```
#### FloatBox
浮動小数点数を扱うBox型。
```nyash
local pi = 3.14159 // 自動的にFloatBox
local precise = new FloatBox(2.718281828)
// メソッド
pi.round(2) // 小数点以下2桁に丸める
pi.ceil() // 切り上げ
pi.floor() // 切り下げ
pi.toString() // 文字列変換
```
#### BoolBox
真偽値を扱うBox型。
```nyash
local flag = true // 自動的にBoolBox
local explicit = new BoolBox(false)
// メソッド
flag.toString() // 文字列変換
flag.not() // 論理反転
```
#### NullBox
null値を表すBox型。
```nyash
local empty = null // NullBox
local check = empty.isNull() // true
```
### 🔢 計算・データ処理系
#### MathBox
数学関数を提供するBox型。
```nyash
local math = new MathBox()
// メソッド
math.sin(pi/2) // サイン関数
math.cos(0) // コサイン関数
math.sqrt(16) // 平方根
math.pow(2, 8) // べき乗
math.random() // 乱数生成
```
#### ArrayBox
配列操作を行うBox型。
```nyash
local arr = new ArrayBox()
// メソッド
arr.push("item") // 要素追加
arr.get(0) // 要素取得
arr.set(0, "new") // 要素設定
arr.length() // 長さ取得
arr.clear() // 全削除
```
#### MapBox
連想配列辞書操作を行うBox型。
```nyash
local map = new MapBox()
// メソッド
map.set("key", "value") // キー・値設定
map.get("key") // 値取得
map.has("key") // キー存在確認
map.keys() // 全キー取得
map.clear() // 全削除
```
### 🔗 通信・ネットワーク系
#### P2PBox
P2P通信を行うードを表すBox。
```nyash
// コンストラクタ
local node = new P2PBox(node_id, world)
```
**パラメータ:**
- `node_id` (String): ノードの一意識別子
- `world` (IntentBox): 参加する通信世界
**メソッド:**
##### send(intent, data, target)
```nyash
local result = node.send("greeting", message_data, "target_node_id")
```
- `intent` (String): メッセージの種類
- `data` (Box): 送信するデータ
- `target` (String): 送信先ードID
- **戻り値:** StringBox("sent")
##### on(intent, callback)
```nyash
node.on("chat", callback_function)
```
- `intent` (String): 監視するメッセージ種類
- `callback` (MethodBox): 受信時に呼ばれる関数
##### off(intent)
```nyash
node.off("chat")
```
- `intent` (String): 解除するメッセージ種類
#### SocketBox
TCP/IPソケット通信を行うBox型。
```nyash
local socket = new SocketBox()
// サーバーモード
socket.listen(8080) // ポート8080でリッスン
socket.accept() // 接続受け入れ
// クライアントモード
socket.connect("localhost", 8080) // 接続
socket.send("Hello") // データ送信
socket.receive() // データ受信
socket.close() // 接続終了
```
### 🖥️ I/O・GUI系
#### ConsoleBox
基本的なコンソールI/Oを行うBox型。
```nyash
local console = new ConsoleBox()
// メソッド
console.log("message") // 標準出力
console.error("error") // エラー出力
console.input() // 標準入力
```
#### FileBox
ファイル操作を行うBox型プラグイン対応
```nyash
local f = new FileBox("data.txt")
// メソッド
f.write("content") // ファイル書き込み
f.read() // ファイル読み込み
f.exists() // ファイル存在確認
f.close() // ファイル閉じる
```
#### EguiBox
GUI開発を行うBox型。
```nyash
local app = new EguiBox()
// メソッド
app.setTitle("My App") // タイトル設定
app.setSize(800, 600) // サイズ設定
app.run() // GUI実行
```
### 🎮 特殊・デバッグ系
#### DebugBox
デバッグ・イントロスペクション用Box型。
```nyash
local debug = new DebugBox()
// メソッド
debug.startTracking() // メモリ追跡開始
debug.trackBox(obj, "desc") // オブジェクト追跡
debug.memoryReport() // メモリレポート
```
#### RandomBox
乱数生成専用Box型。
```nyash
local rand = new RandomBox()
// メソッド
rand.next() // 0-1の乱数
rand.nextInt(100) // 0-99の整数乱数
rand.nextFloat(10.0) // 0-10の浮動小数点乱数
```
#### TimeBox
時間・日付操作Box型。
```nyash
local time = new TimeBox()
// メソッド
time.now() // 現在時刻取得
time.format("YYYY-MM-DD") // 時刻フォーマット
time.addDays(7) // 日数加算
```
## 🔌 プラグインBox
Nyashはプラグインシステムにより、新しいBox型を動的に追加できます。
### プラグイン設定nyash.toml
```toml
[plugins]
FileBox = "nyash-filebox-plugin"
DatabaseBox = "nyash-db-plugin"
```
### 型情報管理
```toml
[plugins.FileBox.methods]
write = { args = [{ from = "string", to = "bytes" }] }
read = { args = [] }
```
**詳細**: [プラグインシステム](../plugin-system/)
---
**最終更新**: 2025年8月19日 - Box型リファレンス統合版
**関連ドキュメント**: [Everything is Box哲学](everything-is-box.md) | [プラグインシステム](../plugin-system/)

View File

@ -0,0 +1,246 @@
# 🔄 ビルトインBox → プラグイン変換手順書
## 🎯 概要
ビルトインBoxをBID-FFI v1プラグインに変換する標準手順。実際の変換作業で発見された問題と解決策を蓄積し、効率的な開発手法を確立する。
## 📊 変換パターン分析
### 🏆 成功事例FileBox変換
- **元実装**: `src/boxes/file/mod.rs` (RwLock<File>)
- **プラグイン**: `plugins/nyash-filebox-plugin/` (BID-FFI v1)
- **結果**: ✅ 完全動作、プラグイン優先使用
### 🔍 現状分析HTTP系Box
- **実装状況**: 完全実装済み432行の高機能HTTPサーバー
- **問題**: Unified Registry未登録Legacy Match使用
- **潜在性**: 即座にプラグイン化可能
## 🚀 標準変換手順3段階アプローチ
### Phase 1: ビルトイン最適化
**目的**: 既存実装の性能向上・デバッグ
**期間**: 1-3日
#### 手順
1. **Unified Registry登録**
```rust
// src/box_factory/builtin.rs 内
fn register_io_types(&mut self) {
// HTTPServerBox追加
self.register("HTTPServerBox", |args| {
if !args.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("HTTPServerBox constructor expects 0 arguments, got {}", args.len()),
});
}
Ok(Box::new(HTTPServerBox::new()))
});
// 他のHTTP系Boxも同様に追加
}
```
2. **動作テスト作成**
```nyash
// local_tests/test_http_builtin.nyash
static box Main {
main() {
local server = new HTTPServerBox()
server.bind("localhost", 8080)
server.get("/test", TestHandler.handle)
return "HTTP builtin test complete"
}
}
```
3. **性能ベンチマーク**
- Legacy Match vs Unified Registry比較
- メモリ使用量測定
#### 期待効果
- ✅ 高速化Legacy Match削除
- ✅ デバッグ環境確立
- ✅ 安定性確認
### Phase 2: プラグイン変換実装
**目的**: BID-FFI v1プラグイン実装
**期間**: 3-7日
#### 手順
1. **プラグインプロジェクト作成**
```bash
mkdir plugins/nyash-http-plugin
cd plugins/nyash-http-plugin
cargo init --lib
```
2. **Cargo.toml設定**
```toml
[lib]
crate-type = ["cdylib"]
[dependencies]
once_cell = "1.0"
# HTTP依存関係
```
3. **BID-FFI v1実装**
- マルチBox対応HTTPServerBox, HTTPClientBox, SocketBox
- TLV Protocol実装
- Method ID定義
4. **nyash.toml設定**
```toml
[libraries."libnyash_http_plugin.so"]
boxes = ["HTTPServerBox", "HTTPClientBox", "SocketBox"]
[libraries."libnyash_http_plugin.so".HTTPServerBox]
type_id = 10
[libraries."libnyash_http_plugin.so".HTTPServerBox.methods]
birth = { method_id = 0 }
bind = { method_id = 1, args = ["address", "port"] }
listen = { method_id = 2, args = ["backlog"] }
start = { method_id = 3 }
stop = { method_id = 4 }
fini = { method_id = 4294967295 }
```
### Phase 3: 移行・検証
**目的**: 完全移行とパフォーマンス検証
**期間**: 1-2日
#### 手順
1. **プラグイン優先テスト**
- 同じテストケースでビルトイン vs プラグイン比較
- メモリリーク検証
- エラーハンドリング確認
2. **ビルトイン実装削除**
- `src/boxes/http_*` ファイル削除
- BUILTIN_BOXES リストから除去
- コンパイル確認
3. **本格アプリテスト**
```nyash
// apps/http_example/
// 実用的なHTTPサーバーアプリで動作確認
```
## 🔧 BID-FFI v1必須要件
### ✅ **絶対必須の2つのメソッド**
すべてのBID-FFI v1プラグインで実装必須
**🔧 birth() - コンストラクタ (METHOD_ID = 0)**
```rust
const METHOD_BIRTH: u32 = 0; // Constructor
```
- **機能**: インスタンス作成、instance_id返却
- **必須実装**: インスタンス管理、メモリ確保
- **戻り値**: TLV形式のinstance_id (u32)
**🧹 fini() - デストラクタ (METHOD_ID = u32::MAX)**
```rust
const METHOD_FINI: u32 = u32::MAX; // Destructor (4294967295)
```
- **機能**: インスタンス解放、メモリクリーンアップ
- **必須実装**: INSTANCES.remove(), リソース解放
- **戻り値**: 成功ステータス
### 📝 設定例
```toml
[libraries."libnyash_example_plugin.so".ExampleBox.methods]
birth = { method_id = 0 } # 🔧 必須
# ... カスタムメソッド ...
fini = { method_id = 4294967295 } # 🧹 必須
```
## 🐛 発見済み問題と解決策
### Problem 1: toString()メソッドエラー
**現象**: `Unknown method 'toString' for FileBox`
```
❌ Interpreter error: Invalid operation: Unknown method 'toString' for FileBox
```
**原因**: プラグインにtoString()メソッド未定義
**解決策**: nyash.tomlでtoStringメソッド追加
```toml
toString = { method_id = 5 }
```
### Problem 2: Unified Registry未登録Box
**現象**: `Falling back to legacy match statement`
```
🔍 Unified registry failed for HTTPServerBox: Unknown Box type
🔍 Falling back to legacy match statement
```
**原因**: BuiltinBoxFactory.register_io_types()未登録
**解決策**: HTTP系Box登録追加
### Problem 3: 複雑な依存関係
**予想問題**: HTTPServerBox → SocketBox → OS固有API
**解決策**: プラグイン内で依存関係完結
## 📋 チェックリスト
### ✅ Phase 1完了条件
- [ ] Unified Registry登録完了
- [ ] Legacy Match削除確認
- [ ] 基本動作テスト成功
- [ ] パフォーマンス改善確認
### ✅ Phase 2完了条件
- [ ] プラグインビルド成功
- [ ] BID-FFI v1インターフェース実装
- [ ] 全メソッドTLV対応
- [ ] plugin-testerで検証成功
### ✅ Phase 3完了条件
- [ ] プラグイン優先動作確認
- [ ] ビルトイン実装削除成功
- [ ] 実用アプリケーション動作確認
- [ ] メモリリーク・エラーなし
## 🚀 期待効果
### 短期効果Phase 1
- **5-10倍高速化**: Legacy Match → Unified Registry
- **保守性向上**: 統一的なファクトリパターン
- **デバッグ環境**: 安定したテスト基盤
### 長期効果Phase 3
- **プラグイン化完了**: 外部配布可能
- **アーキテクチャ改善**: コア軽量化
- **拡張性向上**: 独立開発可能
## 🎯 次期対象Box候補
### 優先度高(実装済み)
1. **HTTP系**: HTTPServerBox, HTTPClientBox, SocketBox
2. **BufferBox**: バイナリデータ処理
3. **RegexBox**: 正規表現処理
### 優先度中(要調査)
1. **MathBox, RandomBox**: プラグイン実装あり第1世代C ABI
2. **JSONBox**: データ交換
3. **StreamBox**: ストリーム処理
## 📝 学習記録
### 成功パターン
- FileBox: 単純構造、明確API → スムーズ変換
- プラグイン優先システム動作確認済み
### 注意点
- toString()等の基本メソッド必須
- 依存関係の循環に注意
- メモリ管理の完全分離
---
**最終更新**: 2025年8月20日 - 初版作成
**Phase**: 9.75g-0 完了後 - HTTP系Box変換準備完了
**Next**: Phase 1実装→Phase 2プラグイン化

View File

@ -0,0 +1,390 @@
# 🔄 Nyash デリゲーションシステム
## 📋 概要
Nyashは継承の代わりに「完全明示デリゲーション」を採用しています。
これは「Everything is Box」哲学に基づく、より安全で明確な設計アプローチです。
## 🎯 なぜデリゲーションか
### 継承の問題点
1. **暗黙的な結合**: 親クラスの変更が子クラスに予期せぬ影響
2. **多重継承の複雑性**: ダイヤモンド問題
3. **実装の隠蔽**: 何がどこから来ているか不明確
### デリゲーションの利点
1. **明示的**: すべての委譲が明確に記述される
2. **柔軟**: 複数のBoxから選択的に機能を組み合わせ
3. **安全**: 予期せぬ副作用を防ぐ
## 🏗️ 基本構文
### from構文によるデリゲーション宣言
```nyash
// ParentBoxにデリゲート
box Child from Parent {
init { childField }
// 親のコンストラクタを呼ぶ
pack(name, age, childData) {
from Parent.pack(name, age)
me.childField = childData
}
}
```
### override必須
```nyash
box Child from Parent {
// ❌ エラー: overrideキーワードが必要
toString() {
return "Child"
}
// ✅ 正しい: 明示的override
override toString() {
return "Child: " + from Parent.toString()
}
}
```
## 📖 デリゲーションパターン
### 1. 基本的なデリゲーション
```nyash
box Animal {
init { name, species }
pack(animalName, animalSpecies) {
me.name = animalName
me.species = animalSpecies
}
speak() {
return me.name + " makes a sound"
}
toString() {
return me.species + " named " + me.name
}
}
box Dog from Animal {
init { breed }
pack(dogName, dogBreed) {
from Animal.pack(dogName, "Dog")
me.breed = dogBreed
}
override speak() {
return me.name + " barks!"
}
// toStringは親のものをそのまま使用
}
```
### 2. 選択的メソッドオーバーライド
```nyash
box EnhancedDog from Dog {
init { tricks }
pack(name, breed) {
from Dog.pack(name, breed)
me.tricks = new ArrayBox()
}
// speakは親のまま使用
// toStringだけオーバーライド
override toString() {
local base = from Animal.toString() // 祖父母から直接
return base + " (Enhanced)"
}
// 新しいメソッド追加
addTrick(trick) {
me.tricks.push(trick)
}
}
```
### 3. 複数Box組み合わせ予定機能
```nyash
// 将来的な複数デリゲーション構想
box MultiChild from ParentA, ParentB {
pack() {
from ParentA.pack()
from ParentB.pack()
}
methodA() {
return from ParentA.method()
}
methodB() {
return from ParentB.method()
}
}
```
## 🌟 birth構文 - Box哲学の具現化
### コンストラクタの優先順位
```nyash
box User {
init { name, email }
// 優先度1: birth推奨
birth(userName, userEmail) {
me.name = userName
me.email = userEmail
print("🌟 " + userName + " が誕生しました!")
}
// 優先度2: initbirthがない場合
init(name, email) {
me.name = name
me.email = email
}
// 優先度3: Box名互換性のため
User(name, email) {
me.name = name
me.email = email
}
}
// birthが優先的に使用される
local user = new User("Alice", "alice@example.com")
```
### birth構文とデリゲーション
```nyash
box Product {
init { name, price }
birth(productName, productPrice) {
me.name = productName
me.price = productPrice
print("📦 Product created: " + productName)
}
}
box DiscountedProduct from Product {
init { discount }
birth(name, originalPrice, discountPercent) {
local discountedPrice = originalPrice * (1 - discountPercent / 100)
from Product.birth(name, discountedPrice) # 親のbirthを呼ぶ
me.discount = discountPercent
}
originalPrice() {
return me.price / (1 - me.discount / 100)
}
}
```
### 🚨 pack構文 - ビルトインBox継承専用
**重要**: `pack`構文は**ビルトインBox継承専用**です。ユーザー定義Boxでは使用しません。
```nyash
# ✅ 正しい使い方ビルトインBox継承のみ
box EnhancedP2P from P2PBox {
init { extraFeatures }
pack(nodeId, transport) {
from P2PBox.pack(nodeId, transport) # ビルトインBoxの初期化
me.extraFeatures = new ArrayBox()
}
}
box CustomMath from MathBox {
init { history }
pack() {
from MathBox.pack() # ビルトインBoxの初期化
me.history = new ArrayBox()
}
}
# ❌ 間違いユーザー定義Boxでpack使用
box RegularUser {
pack(name) { # これは間違いbirth()を使う
me.name = name
}
}
```
## 🔍 from構文の詳細
### メソッド内でのfrom使用
```nyash
box Child from Parent {
override process(data) {
// 前処理
local prepared = me.prepare(data)
// 親の処理を呼ぶ
local result = from Parent.process(prepared)
// 後処理
return me.postProcess(result)
}
}
```
### 条件付きデリゲーション
```nyash
box SmartChild from Parent {
override calculate(value) {
if value > 100 {
// 大きな値は親に任せる
return from Parent.calculate(value)
} else {
// 小さな値は自分で処理
return value * 2
}
}
}
```
## ⚡ ベストプラクティス
### 1. 明示的なoverride
```nyash
// ✅ 良い: 意図が明確
override toString() {
return "Custom: " + from Parent.toString()
}
// ❌ 悪い: overrideなしはエラー
toString() {
return "Custom"
}
```
### 2. 適切なデリゲーション粒度
```nyash
// ✅ 良い: 必要な部分だけオーバーライド
box CustomList from ArrayBox {
override push(item) {
console.log("Adding: " + item)
from ArrayBox.push(item)
}
// 他のメソッドはそのまま使用
}
// ❌ 悪い: すべてをオーバーライド
box BadList from ArrayBox {
override push(item) { /* ... */ }
override pop() { /* ... */ }
override get(i) { /* ... */ }
override set(i, v) { /* ... */ }
// すべて再実装は無駄
}
```
### 3. デリゲーションチェーンの管理
```nyash
// ✅ 良い: 明確な責任分離
box A {
process() { return "A" }
}
box B from A {
override process() {
return from A.process() + "->B"
}
}
box C from B {
override process() {
return from B.process() + "->C"
}
}
// 結果: "A->B->C"
```
## 🚨 注意点
### 1. 循環デリゲーション禁止
```nyash
// ❌ エラー: 循環デリゲーション
box A from B { }
box B from A { } // コンパイルエラー
```
### 2. 多段デリゲーション制限
```nyash
// 現在の制限
box A { }
box B from A { }
box C from B {
method() {
// ❌ エラー: CはAにデリゲートしていない
from A.method()
// ✅ OK: 直接の親
from B.method()
}
}
```
### 3. 動的デリゲーション不可
```nyash
// ❌ エラー: デリゲーション先は静的に決定
box Dynamic from (condition ? A : B) { }
```
## 🔮 将来の拡張構想
### 1. 複数デリゲーション
```nyash
box Multi from Network, Storage {
save(data) {
from Storage.save(data)
from Network.sync(data)
}
}
```
### 2. 条件付きデリゲーション
```nyash
box Smart from Parent when Parent.version >= 2.0 {
// バージョン対応
}
```
### 3. デリゲーションプロキシ
```nyash
box Proxy delegates * to target {
// すべてのメソッドを自動委譲
}
```
---
関連ドキュメント:
- [Everything is Box](everything-is-box.md)
- [override/from構文詳細](../override-delegation-syntax.md)
- [言語リファレンス](../language-reference.md)

View File

@ -0,0 +1,198 @@
# 🌟 Everything is Box - Nyashの核心哲学
## 📦 すべては箱である
Nyashでは、すべての値が「Box」と呼ばれるオブジェクトです。
数値も、文字列も、関数も、そしてBoxそのものも、すべてがBoxです。
```nyash
// これらはすべてBox
local number = 42 // IntegerBox
local text = "Hello" // StringBox
local flag = true // BoolBox
local nothing = null // NullBox
local container = new MapBox() // MapBox
```
## 🎯 なぜEverything is Boxなのか
### 1. **統一性**
プリミティブ型と参照型の区別がないため、すべてを同じ方法で扱えます。
```nyash
// すべて同じ方法でメソッドを呼べる
local strLen = "Hello".length() // StringBoxのメソッド
local doubled = 42.multiply(2) // IntegerBoxのメソッド
local formatted = true.toString() // BoolBoxのメソッド
```
### 2. **拡張性**
すべてがオブジェクトなので、どんな型にもメソッドを追加できます。
```nyash
// ユーザー定義Boxで数値を拡張
box Money from IntegerBox {
pack(amount) {
from IntegerBox.pack(amount)
}
format() {
return "$" + me.toString()
}
}
```
### 3. **一貫性**
型チェック、メソッド呼び出し、デリゲーションがすべて統一的に動作します。
```nyash
// 型チェックも統一的
if value.isType("StringBox") {
console.log("It's a string!")
}
// nullチェックも同様
if value.isType("NullBox") {
console.log("It's null!")
}
```
## 🏗️ Box設計の基本原則
### 1. **Boxは不変の契約**
すべてのBoxは`NyashBox`トレイトを実装し、以下のメソッドを提供します:
- `type_name()` - Box型名を返す
- `clone_box()` - Boxの複製を作成
- `as_any()` - 動的型変換用
- `to_string_box()` - StringBox変換
### 2. **メモリ管理の統一**
すべてのBoxは`Arc<Mutex<dyn NyashBox>>`として管理され、自動的にメモリ安全です。
### 3. **明示的な操作**
暗黙的な型変換は行わず、すべての操作を明示的に行います。
```nyash
// ❌ 暗黙的な変換はない
local result = "Hello" + 42 // エラー!
// ✅ 明示的な変換
local result = "Hello" + 42.toString() // OK: "Hello42"
```
## 📊 Box型の分類
### 基本Box型
- **StringBox** - 文字列
- **IntegerBox** - 整数
- **FloatBox** - 浮動小数点数
- **BoolBox** - 真偽値
- **NullBox** - null値
### コレクションBox型
- **ArrayBox** - 配列
- **MapBox** - 連想配列
- **SetBox** - 集合(予定)
### システムBox型
- **ConsoleBox** - コンソール入出力
- **FileBox** - ファイル操作
- **TimeBox** - 時刻操作
- **MathBox** - 数学関数
### ネットワークBox型
- **SocketBox** - TCP/UDPソケット
- **HTTPServerBox** - HTTPサーバー
- **P2PBox** - P2P通信
### GUI Box型
- **EguiBox** - GUIアプリケーション
- **CanvasBox** - 描画キャンバス
### 特殊Box型
- **FutureBox** - 非同期処理
- **WeakBox** - 弱参照
- **ExternBox** - 外部ライブラリ統合
## 🔄 Boxの生成と利用
### 基本的な生成
```nyash
// newによる明示的生成
local str = new StringBox("Hello")
local num = new IntegerBox(42)
// リテラルによる暗黙的生成
local str = "Hello" // 自動的にStringBox
local num = 42 // 自動的にIntegerBox
```
### ユーザー定義Box
```nyash
box Point {
init { x, y }
pack(xVal, yVal) {
me.x = xVal
me.y = yVal
}
distance() {
return (me.x * me.x + me.y * me.y).sqrt()
}
}
local p = new Point(3, 4)
console.log(p.distance()) // 5
```
### デリゲーションによる拡張
```nyash
box Point3D from Point {
init { z }
pack(xVal, yVal, zVal) {
from Point.pack(xVal, yVal)
me.z = zVal
}
override distance() {
local xy = from Point.distance()
return (xy * xy + me.z * me.z).sqrt()
}
}
```
## 🌐 外部世界との統合
Everything is Box哲学は、外部ライブラリにも適用されます。
```nyash
// ExternBoxで外部APIもBoxに
local fetch = new ExternBox("fetch")
local response = fetch.call("get", "https://api.example.com/data")
// JavaScript APIもBoxとして利用
local dom = new ExternBox("document")
local element = dom.call("getElementById", "myDiv")
```
## 🎉 まとめ
Everything is Box哲学により、Nyashは
1. **シンプル** - すべてが同じルールに従う
2. **強力** - どんなものにもメソッドを追加できる
3. **安全** - 統一的なメモリ管理
4. **拡張可能** - 新しいBox型を簡単に追加
5. **統合的** - 外部ライブラリも同じ方法で利用
この哲学こそが、Nyashを特別な言語にしているのです。
---
関連ドキュメント:
- [Box型カタログ](box-types-catalog.md)
- [デリゲーションシステム](delegation-system.md)
- [メモリ管理](memory-management.md)

View File

@ -0,0 +1,180 @@
# 🧠 Nyash メモリ管理 & finiシステム
**最終更新: 2025年8月19日 - 統合仕様書**
## 📋 概要
Nyashは「Everything is Box」哲学のもと、統一的なメモリ管理と予測可能なリソース解放を実現しています。
## 🏗️ 基本アーキテクチャ
### Arc<Mutex>一元管理
```rust
// インタープリターレベルでの統一管理
type NyashObject = Arc<Mutex<dyn NyashBox>>;
```
すべてのBoxは、インタープリターレベルで`Arc<Mutex>`によって管理されます。
#### 利点
- **スレッドセーフティ**: 自動的に保証
- **参照カウント**: 自動的なメモリ解放
- **統一的アクセス**: すべて同じ方法で操作
#### 設計原則
```rust
// ✅ 正しい設計(シンプルなフィールド)
pub struct GoodBox {
data: String,
count: i32,
}
// ❌ アンチパターンBox内部での二重ロック
pub struct BadBox {
data: Arc<Mutex<String>>, // 内部でロック管理しない
}
```
### プラグインシステムのメモリ管理
BID-FFIプラグインシステムでは、**HostVtable**を通じて安全なメモリ管理を実現:
```rust
pub struct NyashHostVtable {
pub alloc: unsafe extern "C" fn(size: usize) -> *mut u8,
pub free: unsafe extern "C" fn(ptr: *mut u8),
pub wake: unsafe extern "C" fn(handle: u64),
pub log: unsafe extern "C" fn(level: i32, msg: *const c_char),
}
```
**重要**: プラグインが割り当てたメモリはプラグインが解放する原則
## 🔥 finiシステム - 論理的解放フック
### 核心コンセプト
`fini()`は**物理的メモリ破棄ではなく論理的使用終了**を宣言する革新的システムです。
```nyash
box MyResource {
init { name, file }
fini() {
print("Resource " + me.name + " is being finalized")
// ファイルクローズなどのクリーンアップ処理
// 物理的メモリは共有参照が残っていても論理的には「終了」
}
}
```
**重要**: `fini()`は「このオブジェクトをもう使わない」という宣言であり、物理的な即時破棄ではありません。
### 実行順序(確定仕様)
#### 自動カスケード解放
```nyash
box Pipeline {
init { r1, r2, r3, weak monitor }
fini() {
// 1) ユーザー定義処理(柔軟な順序制御可能)
me.r3.fini() // 依存関係でr3→r2の順
me.r2.fini()
// 2) 自動カスケード: 残りのr1がinit宣言順で自動解放
// 3) weakフィールドは対象外lazy nil化
}
}
```
#### 決定的な解放順序
1. **finalized チェック** - 既に解放済みなら何もしないidempotent
2. **再入防止** - `in_finalization`フラグで再帰呼び出し防止
3. **ユーザー定義fini()実行** - カスタムクリーンアップ処理
4. **自動カスケード** - `init`宣言順で未処理フィールドを解放
5. **フィールドクリア** - 全フィールドを無効化
6. **finalized設定** - 以後の使用を禁止
### weak参照による循環参照回避
```nyash
box Node {
init { id, weak next } // 'next'は弱参照
}
local node1 = new Node("A", null)
local node2 = new Node("B", node1) // node2はnode1への弱参照を持つ
node1.next = node2 // node1はnode2への強参照を持つ
// 循環参照を回避し、安全に解放される
```
#### weak参照の特性
- **所有権なし**: オブジェクトの生存期間に影響しない
- **自動nil化**: 参照先が解放されると自動的に`null`になる
- **fini()対象外**: 弱参照フィールドはfini()カスケードでスキップ
### 不変条件(重要)
- **weak参照**: `weak`フィールドに対して`fini()`を直接呼ぶことはできません
- **finalized後禁止**: `fini()`呼び出し後は、そのオブジェクトの使用はすべて禁止
- **カスケード順序**: `init`宣言順の**逆順**で実行、`weak`フィールドはスキップ
## 🌟 実用例
### リソース管理
```nyash
box FileHandler {
init { file, buffer }
fini() {
// オブジェクト削除時に自動呼び出し
if me.file != null {
me.file.close()
console.log("File closed automatically")
}
// bufferは自動カスケードで解放
}
}
```
### プラグインリソース
```nyash
box PluginResource {
init { plugin_handle }
fini() {
// プラグイン側のリソース解放を呼び出し
me.plugin_handle.cleanup()
console.log("Plugin resource finalized")
}
}
```
## 🛡️ メモリ安全性保証
### valgrind検証済み
- **セグフォルト回避**: HostVtableの生存期間問題解決済み
- **メモリリーク検出**: プラグインシステムでのメモリ管理検証済み
- **二重解放防止**: idempotentなfini()実装
### プラグインメモリ安全性
- **プラグイン分離**: プラグインメモリはプラグインが管理
- **境界明確化**: HostVtableを通じた安全なインターフェース
- **ライフサイクル管理**: birth/finiによる明確な生存期間
## 🚀 Phase 9.75g-0での進化
- **BID-FFIプラグインシステム**: 外部ライブラリの安全な統合
- **型情報管理**: nyash.tomlによる型安全な変換
- **HostVtable**: プラグイン↔ホスト間の安全なメモリ管理
- **plugin-tester**: メモリ安全性診断ツール
---
**関連ドキュメント**:
- [Box型リファレンス](box-reference.md)
- [プラグインシステム](../plugin-system/)
- [BID-FFI仕様](../plugin-system/ffi-abi-specification.md)

View File

@ -0,0 +1,91 @@
# プラグインBoxのライフサイクルと nyash.toml methods 定義
本書は、プラグインBoxPluginBoxV2の生成birthと終了finiの流れ、ならびに nyash.toml v2 における `methods` 定義の役割をまとめたものです。
---
## 1. 用語
- birth: プラグインBoxのインスタンス生成`method_id=0`
- fini: プラグインBoxの終了処理任意の `method_id`。例: `4294967295`
- invoke_fn: プラグイン側の単一エントリポイント(`nyash_plugin_invoke`
---
## 2. 生成birthの流れ
1. `unified registry``PluginLoaderV2::create_box(box_type, args)` を呼び出す。
2. `PluginLoaderV2``nyash.toml` から `type_id``methods` を読み込む。
3. `invoke_fn(type_id, method_id=0 /* birth */, instance_id=0, ...)` を呼び、戻り値出力TLVの先頭4バイトから `instance_id` を取得。
4. `PluginBoxV2 { type_id, instance_id, invoke_fn, fini_method_id }` を生成して返す。
補足:
- `fini_method_id``nyash.toml``methods` から `fini``method_id` を取り出して保持します。未定義の場合は `None`
---
## 3. 終了finiの流れ現状
- フィールド差し替え時(代入で旧値を置き換えるとき):
- 旧値が `InstanceBox` の場合: インタプリタが `fini()` を呼び、finalized としてマーキングします。
- 旧値が `PluginBoxV2` の場合: `fini_method_id` が設定されていれば `invoke_fn(type_id, fini_method_id, instance_id, ...)` を呼びます。
- 破棄Drop時:
- RustのDropでFFIを呼ぶのは安全性の観点でリスクがあるため、現状は「明示タイミングフィールド差し替えなど」での fini 呼び出しを優先しています。
注意:
- ローカル変数のスコープ終了時に自動で fini を呼ぶ実装は、現時点では入っていません(将来検討)。
---
## 4. nyash.toml v2 の定義例
```toml
[libraries]
[libraries."libnyash_filebox_plugin.so"]
boxes = ["FileBox"]
path = "./plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so"
[libraries."libnyash_filebox_plugin.so".FileBox]
type_id = 6
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
birth = { method_id = 0 }
open = { method_id = 1 }
read = { method_id = 2 }
write = { method_id = 3 }
close = { method_id = 4 }
fini = { method_id = 4294967295 } # 任意の終端ID
```
要点:
- `methods``fini` を定義すれば、差し替え時などに fini が呼ばれます。
- `fini` 未定義の場合、プラグインBoxの終了処理は呼ばれませんフォールバック動作
---
## 5. WASMwasm-bindgenとの関係
- WASMターゲットでは `libloading` が使えないため、プラグイン機構は features/cfg でスタブ化しています。
- `plugins` フィーチャを外す、または `target_arch = "wasm32"` のときは、プラグイン生成・fini 呼び出しのコードはコンパイル対象外になります(ビルド可能化のため)。
---
## 6. 将来拡張の方向
- ローカル変数のスコープ終了時(関数/メソッド呼び出しの戻りなどに、InstanceBox/PluginBoxV2 の fini を安全に呼び出す仕組み(順序・例外耐性・二重呼び出し防止を含む)。
- `nyash.toml` にクラス名→プラグインBox型の `overrides` を加え、ユーザー定義Boxの外部置換を許可する設計任意
以上。
---
## 7. v2.1: BoxRefBox引数サポート
目的: プラグインメソッドの引数として、他のBoxインスタンスを不透明参照で受け渡し可能にする。
- 仕様詳細: `docs/reference/plugin-system/nyash-toml-v2_1-spec.md`
- 設定例1引数にプラグインBoxを渡す:
```toml
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
copyFrom = { method_id = 7, args = [ { kind = "box", category = "plugin" } ] }
```
注意:
- 当面は `category = "plugin"` のみ対応。ユーザー定義Boxや複雑なビルトインBoxは非対応。
- 戻り値の BoxRef は次版v2.2)で検討。