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:
54
docs/reference/boxes-system/README.md
Normal file
54
docs/reference/boxes-system/README.md
Normal 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成果**: プラグインシステムとの完全統合
|
||||
270
docs/reference/boxes-system/box-reference.md
Normal file
270
docs/reference/boxes-system/box-reference.md
Normal file
@ -0,0 +1,270 @@
|
||||
# 📦 Nyash Box型完全リファレンス
|
||||
|
||||
Nyashで利用できる全ビルトインBox型の完全API仕様書です。
|
||||
|
||||
## 📋 Box型分類
|
||||
|
||||
### 🎯 基本型Box(Primitive 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/)
|
||||
246
docs/reference/boxes-system/builtin-to-plugin-conversion.md
Normal file
246
docs/reference/boxes-system/builtin-to-plugin-conversion.md
Normal 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プラグイン化
|
||||
390
docs/reference/boxes-system/delegation-system.md
Normal file
390
docs/reference/boxes-system/delegation-system.md
Normal 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: init(birthがない場合)
|
||||
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)
|
||||
198
docs/reference/boxes-system/everything-is-box.md
Normal file
198
docs/reference/boxes-system/everything-is-box.md
Normal 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)
|
||||
180
docs/reference/boxes-system/memory-finalization.md
Normal file
180
docs/reference/boxes-system/memory-finalization.md
Normal 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)
|
||||
91
docs/reference/boxes-system/plugin_lifecycle.md
Normal file
91
docs/reference/boxes-system/plugin_lifecycle.md
Normal file
@ -0,0 +1,91 @@
|
||||
# プラグインBoxのライフサイクルと nyash.toml methods 定義
|
||||
|
||||
本書は、プラグインBox(PluginBoxV2)の生成(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. WASM(wasm-bindgen)との関係
|
||||
- WASMターゲットでは `libloading` が使えないため、プラグイン機構は features/cfg でスタブ化しています。
|
||||
- `plugins` フィーチャを外す、または `target_arch = "wasm32"` のときは、プラグイン生成・fini 呼び出しのコードはコンパイル対象外になります(ビルド可能化のため)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 将来拡張の方向
|
||||
- ローカル変数のスコープ終了時(関数/メソッド呼び出しの戻りなど)に、InstanceBox/PluginBoxV2 の fini を安全に呼び出す仕組み(順序・例外耐性・二重呼び出し防止を含む)。
|
||||
- `nyash.toml` にクラス名→プラグインBox型の `overrides` を加え、ユーザー定義Boxの外部置換を許可する設計(任意)。
|
||||
|
||||
以上。
|
||||
|
||||
---
|
||||
|
||||
## 7. v2.1: BoxRef(Box引数)サポート
|
||||
|
||||
目的: プラグインメソッドの引数として、他の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)で検討。
|
||||
Reference in New Issue
Block a user