feat(phase-9.75g-0): Add simple nyash.toml parser for plugin configuration
- ✅ Simple TOML parser for [plugins] section - ✅ Maps Box names to plugin names (e.g., FileBox => filebox) - ✅ Handles comments and empty lines - ✅ Complete test coverage - 🎯 Minimal implementation for transparent Box replacement! Part of Day 4 FileBox plugin implementation (60% → 70%) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -48,22 +48,27 @@
|
||||
### 🎯 **Day 4 進行中!** (2025-08-17)
|
||||
**目標**: FileBoxプラグイン実装(open/read/write/close)
|
||||
|
||||
**実装完了** (50%達成!):
|
||||
**実装完了** (60%達成!):
|
||||
- ✅ FileBoxプラグイン設計: open/read/write/close API設計
|
||||
- ✅ FileBoxプラグイン実装: ハンドル管理・ファイル操作実装
|
||||
- ✅ FileBoxテスト作成: ファイル操作テスト(1/1合格!)
|
||||
- ✅ **プラグインシステム設計統合**: gemini先生とcodex先生の提案を統合
|
||||
- [Box プラグインシステム設計](../説明書/reference/box-design/plugin-system.md) 作成
|
||||
- YAML署名DSL仕様確定
|
||||
- nyash.tomlによる透過的置き換え設計
|
||||
|
||||
**残タスク**:
|
||||
- ⏳ FileBoxホスト統合: Nyash側からの呼び出し
|
||||
- ⏳ プラグインロード機構: 動的ロード実装
|
||||
- ⏳ nyash.tomlパーサー実装(シンプル版)
|
||||
- ⏳ PluginBoxプロキシ実装(最小版)
|
||||
- ⏳ libloadingでプラグイン動的ロード
|
||||
|
||||
### 🎯 今週の実装計画(ChatGPT最終案準拠)
|
||||
### 🎯 今週の実装計画(シンプル設計版に更新)
|
||||
- **Day 1**: ✅ BID-1基盤実装(TLV仕様、Handle構造体、エンコード/デコード)
|
||||
- **Day 2**: ✅ メタデータAPI実装(init/abi/shutdown、HostVtable、レジストリ)
|
||||
- **Day 3**: ✅ 既存Box統合(StringBox/IntegerBox/FutureBoxブリッジ)**100%完了!**
|
||||
- **Day 4**: ⏳ FileBoxプラグイン実装(open/read/write/close)**50%進行中!**
|
||||
- **Day 5**: 統合テスト・最適化(メモリリーク検証、性能測定)
|
||||
- **Day 6-7**: ドキュメント・CI・仕上げ
|
||||
- **Day 4**: ⏳ FileBoxプラグイン実装(open/read/write/close)**60%進行中!**
|
||||
- **Day 5**: プラグインロードと統合(libloading、Boxレジストリ、透過的置き換え)
|
||||
- **Day 6-7**: 仕上げとドキュメント(使用例、開発ガイド、拡張計画)
|
||||
|
||||
### 🔑 技術的決定事項
|
||||
- ポインタ: `usize`(プラットフォーム依存)
|
||||
@ -130,5 +135,5 @@ cargo build --release -j32
|
||||
```
|
||||
|
||||
---
|
||||
**最終更新**: 2025-08-17 22:00
|
||||
**最終更新**: 2025-08-17 23:30
|
||||
**次回レビュー**: 2025-08-18(Day 4継続時)
|
||||
@ -0,0 +1,69 @@
|
||||
# Gemini先生によるNyashプログラミング言語の総合分析 (2025-08-17)
|
||||
|
||||
## 総合評価
|
||||
|
||||
Nyashは、「Everything is a Box」という強力な統一哲学を掲げ、WebAssembly (WASM) ファースト、クリエイティブコーディング、教育用途を明確なターゲットとして設計された、意欲的でモダンなプログラミング言語です。Rustによる実装は、メモリ安全性とパフォーマンスという現代的な要求に応えるための堅実な選択と言えます。
|
||||
|
||||
特に、AI支援を積極的に活用し、短期間で豊富な機能セットと複数の実行バックエンド(インタープリター、VM、WASM)を実装した開発プロセスは注目に値します。
|
||||
|
||||
## 1. 設計哲学と一貫性: 「Everything is a Box」
|
||||
|
||||
### 長所:
|
||||
- **統一された概念モデル:** すべての値を「Box」として扱うことで、データ型間の不整合をなくし、非常にシンプルで一貫性のあるオブジェクトモデルを提供
|
||||
- **メタプログラミングの可能性:** すべてが統一されたインターフェース(`NyashBox`トレイト)を持つため、リフレクションや動的な操作が容易
|
||||
- **自動リテラル変換:** `local text = "Hello"` のように書ける機能は、哲学の一貫性を保ちつつ、冗長な `new StringBox("Hello")` を不要にする優れた実用的判断
|
||||
|
||||
### 課題とトレードオフ:
|
||||
- **パフォーマンスオーバーヘッド:** すべてをヒープ上のオブジェクト(Box)として扱うことは、単純な値(整数など)に対しても参照カウントや動的ディスパッチのコストを伴う
|
||||
- **プリミティブ型の不在:** 他の多くの言語が持つスタック上の軽量なプリミティブ型が存在しないため、低レベルな最適化が難しくなる
|
||||
|
||||
## 2. 構文と表現力
|
||||
|
||||
### 長所:
|
||||
- **直感的で読みやすい:** `if`, `loop`, `and`, `or`, `not` といったキーワードは、PythonやRubyのように自然言語に近く、初学者にも親しみやすい
|
||||
- **`static box Main` パターン:** プログラムのエントリーポイントを明確に定義する優れた方法
|
||||
- **`init { ... }` フィールド宣言:** フィールドをまとめて宣言する構文は、クラスの構造を一目で把握しやすくする良い設計
|
||||
|
||||
### 改善の可能性:
|
||||
- **ループ構文:** `loop(condition)` のみが存在するのはシンプルですが、`for-each` のようなコレクションを反復処理するための専用構文がない
|
||||
- **コンストラクタの多様性:** `birth`, `init`, `pack` と複数のコンストラクタ概念が存在するのは、言語のシンプルさを少し損なっている
|
||||
|
||||
## 3. 型システムとメモリ管理
|
||||
|
||||
### 長所:
|
||||
- **メモリ安全性:** Rustの所有権モデルを基盤に、`Arc<Mutex>` を活用することで、スレッドセーフなメモリ管理を実現
|
||||
- **明示的な変数宣言:** `local` キーワードによる変数宣言を強制する設計は、タイプミスによるバグを防ぐ
|
||||
- **デリゲーションモデル:** 古典的な継承の代わりにデリゲーション(`from`)を採用しているのは、柔軟性が高くモダンな設計
|
||||
|
||||
### 課題:
|
||||
- **型推論:** `local x = 10` のように型を明記しないスタイルは動的言語のようですが、内部的には静的なBox型に変換されている
|
||||
- **Nullの扱い:** `VoidBox` や `NullBox` が存在しますが、言語レベルでNull安全性を強制する仕組みについての言及が少ない
|
||||
|
||||
## 4. 非同期処理
|
||||
|
||||
### 長所:
|
||||
- **シンプルな構文:** `nowait` と `await` は、C#やJavaScriptで成功を収めたモデルであり、非常に直感的
|
||||
- **スレッドベースの実装:** Rustのネイティブスレッドを利用することで、真の並列処理を実現
|
||||
|
||||
### 課題:
|
||||
- **構造化並行性:** より高度なエラーハンドリングやキャンセルの伝播を実現するためには、構造化並行性の概念を導入することが望ましい
|
||||
- **イベントループの不在:** GUIアプリケーションや大量のI/Oを扱うサーバーサイドアプリケーションでは、効率的なタスクスケジューリングのためにイベントループモデルが一般的
|
||||
|
||||
## 5. エコシステムとツールチェイン
|
||||
|
||||
### 長所:
|
||||
- **WASMファースト:** ブラウザで直接実行できることを最優先に設計されており、インストール不要のPlaygroundは非常に強力
|
||||
- **組み込みのデバッグ機能:** `DebugBox` のようなデバッグ支援機能が言語仕様に組み込まれているのはユニーク
|
||||
- **複数の実行バックエンド:** インタープリター、VM、WASM、そして将来的にはAOTコンパイラと、ユースケースに応じて実行方式を選べる柔軟性
|
||||
|
||||
### 課題:
|
||||
- **パッケージ管理:** `include` によるファイル取り込みは小規模なプロジェクトでは機能しますが、エコシステムが成長するためには公式なパッケージマネージャが不可欠
|
||||
- **LSPとIDEサポート:** Language Server Protocol (LSP) への対応は、現代的な開発体験を提供するために極めて重要
|
||||
|
||||
## 結論と将来性
|
||||
|
||||
Nyashは、明確な哲学とターゲットユーザーを持ち、多くのモダンな言語の良い点を取り入れた、非常によく考えられた言語です。特に「Everything is a Box」というコアコンセプトは、シンプルさと強力さを両立させる可能性を秘めています。
|
||||
|
||||
**成功への鍵は、今後のエコシステムの発展と、パフォーマンス・クリティカルな領域への対応にかかっているでしょう。** 計画されているLLVMバックエンドが実現すれば、現在の使いやすさを維持したまま、システムプログラミングに近い領域にも挑戦できる言語になる可能性があります。
|
||||
|
||||
総じて、Nyashは単なる実験的なプロジェクトではなく、プログラミング言語設計の新たな可能性を示す、将来が非常に楽しみな言語であると言えます。
|
||||
@ -0,0 +1,141 @@
|
||||
# Gemini先生によるNyashプラグインシステム深層分析 (2025-08-17)
|
||||
|
||||
## 概要
|
||||
Nyashプログラミング言語のプラグインシステム設計について、時間無制限で深い分析を実施。「Everything is a Box」哲学を維持しながら、透過的な置き換えと高いメンテナンス性を実現する具体的な実装提案。
|
||||
|
||||
## 1. 透過的な置き換えの最良実装方法
|
||||
|
||||
### 提案:Boxファクトリレジストリ + 設定ファイルによるオーバーライド
|
||||
|
||||
**アーキテクチャ:**
|
||||
```rust
|
||||
// src/runtime/box_registry.rs
|
||||
enum BoxFactory {
|
||||
Builtin(fn(&[Box<dyn NyashBox>]) -> Result<Box<dyn NyashBox>, RuntimeError>),
|
||||
Plugin(PluginFactory),
|
||||
}
|
||||
|
||||
struct PluginFactory {
|
||||
plugin_id: PluginId,
|
||||
function_name: String, // 例: "filebox_open"
|
||||
}
|
||||
```
|
||||
|
||||
**設定ファイル(nyash.toml):**
|
||||
```toml
|
||||
[plugins]
|
||||
enable = ["nyash-file-plugin"]
|
||||
|
||||
[overrides]
|
||||
"FileBox" = "nyash-file-plugin" # FileBoxをプラグイン版で置き換え
|
||||
```
|
||||
|
||||
**実行時フロー:**
|
||||
1. ランタイム起動時、全ビルトインBoxをレジストリに登録
|
||||
2. nyash.tomlを読み込み、overridesに従ってレジストリを更新
|
||||
3. `new FileBox()` 実行時、レジストリから適切なファクトリを検索・実行
|
||||
|
||||
**パフォーマンス:** HashMap検索1回のみ、その後は通常のdyn NyashBoxディスパッチ
|
||||
|
||||
## 2. 署名DSLの設計の妥当性
|
||||
|
||||
### 分析:`::` (静的) と `#` (インスタンス) の記法は優秀
|
||||
|
||||
**拡張提案:**
|
||||
```yaml
|
||||
apis:
|
||||
# オーバーロード対応
|
||||
- sig: "FileBox::open(path: string) -> FileBox"
|
||||
- sig: "FileBox::open(path: string, mode: string) -> FileBox"
|
||||
|
||||
# Result型対応
|
||||
- sig: "FileBox::open(path: string) -> Result<FileBox, FileError>"
|
||||
|
||||
# 複数の戻り値型
|
||||
- sig: "FileBox#read() -> string"
|
||||
- sig: "FileBox#read(size: int) -> bytes"
|
||||
```
|
||||
|
||||
**将来性:**
|
||||
- 現時点:具象型で固定
|
||||
- 将来:`Array<T>` のようなジェネリクス構文を後方互換性を保ちつつ追加
|
||||
|
||||
## 3. Everything is a Box哲学との整合性
|
||||
|
||||
### 提案:FFI境界の標準化されたBoxプロキシ
|
||||
|
||||
```rust
|
||||
// src/runtime/plugin_box.rs
|
||||
pub struct PluginBox {
|
||||
base: BoxBase,
|
||||
plugin_id: PluginId,
|
||||
instance_handle: u64, // プラグイン内のインスタンスハンドル
|
||||
}
|
||||
|
||||
impl NyashBox for PluginBox {
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> {
|
||||
// FFI呼び出しでプラグインにcloneを依頼
|
||||
let new_handle = ffi_call(self.plugin_id, "clone", self.instance_handle);
|
||||
Box::new(PluginBox { ..., instance_handle: new_handle })
|
||||
}
|
||||
|
||||
// 全てのNyashBoxメソッドをFFI経由で実装
|
||||
}
|
||||
```
|
||||
|
||||
**保証される点:**
|
||||
- 統一インターフェース:dyn NyashBoxのみを扱う
|
||||
- メモリ管理:Drop時にプラグイン側に破棄を通知
|
||||
- 哲学の維持:内部実装(ネイティブ/FFI)は完全に隠蔽
|
||||
|
||||
## 4. 実装の複雑さとメンテナンス性のバランス
|
||||
|
||||
### 提案:多層抽象化とツールによる自動化
|
||||
|
||||
**3層アーキテクチャ:**
|
||||
1. **低レベルFFI (C-ABI)**
|
||||
- `#[repr(C)]` 構造体と `extern "C"` 関数
|
||||
- libloadingクレートで動的ライブラリロード
|
||||
|
||||
2. **中レベルAPI (安全なラッパー)**
|
||||
- nullチェック、文字列変換、エラー処理
|
||||
- unsafeコードを隔離
|
||||
|
||||
3. **高レベルAPI (署名DSLとコード生成)**
|
||||
- plugin.yaml → FFIコード自動生成
|
||||
- cargo-nyash-pluginサブコマンド
|
||||
|
||||
**ロードマップ:**
|
||||
- フェーズ1:FileBoxで手動実装、アーキテクチャ確立
|
||||
- フェーズ2:コード生成ツール開発、プラグイン開発の自動化
|
||||
|
||||
## 5. 他言語の成功例との比較
|
||||
|
||||
**Node.js (N-API):**
|
||||
- 安定したABI → Nyashも同様にC-ABIベースで実装
|
||||
- バージョン管理と前方互換性を重視
|
||||
|
||||
**Python (C拡張):**
|
||||
- 課題:手作業多い、参照カウント管理が煩雑
|
||||
- Nyashの解決:コード生成とRAIIによる自動メモリ管理
|
||||
|
||||
**WebAssembly Component Model:**
|
||||
- 言語非依存インターフェースの未来形
|
||||
- 将来的にNyashプラグインをWASMで記述する可能性
|
||||
|
||||
## 実装計画(具体的ステップ)
|
||||
|
||||
1. **nyash.toml仕様策定とパーサー実装**
|
||||
2. **Boxファクトリレジストリ実装**
|
||||
3. **FileBoxプラグイン手動実装**
|
||||
- nyash_plugin_init
|
||||
- filebox_open
|
||||
- filebox_read/write/close
|
||||
- filebox_drop
|
||||
4. **PluginBoxプロキシ実装**
|
||||
5. **libloadingで動的ロード実装**
|
||||
6. **プラグイン版FileBoxテスト追加**
|
||||
|
||||
## 結論
|
||||
|
||||
この設計は、Nyashの核心哲学を尊重しつつ、スケーラビリティ、安全性、開発者体験の向上を実現する。FileBoxの置き換えから始め、エコシステム全体へ展開していくのが最良の道筋。
|
||||
@ -0,0 +1,110 @@
|
||||
# プラグインインターフェース設計討論 (2025-08-17)
|
||||
|
||||
## 🎯 議題:BID-FFIプラグインシステムの設計
|
||||
|
||||
### 背景
|
||||
- ビルトインFileBoxが既に存在
|
||||
- BID-FFIプラグイン版FileBoxで置き換えたい
|
||||
- ビルド時間短縮とプラグインアーキテクチャの実証が目的
|
||||
|
||||
### 主な論点
|
||||
1. ビルトインBox → プラグインBoxの透過的な置き換え
|
||||
2. `FileBox.open()` のような静的メソッドの結びつけ方
|
||||
3. プラグインインターフェース定義の外部化方式
|
||||
|
||||
## 💡 検討した案
|
||||
|
||||
### 案1: 汎用ラッパー
|
||||
```nyash
|
||||
// 呼び出しが汚い
|
||||
local file = Plugin.call("FileBox", "open", ["test.txt", "r"])
|
||||
```
|
||||
|
||||
### 案2: 専用ラッパー
|
||||
```nyash
|
||||
// きれい!でも各Boxごとに手書きが必要
|
||||
local file = FileBox.open("test.txt")
|
||||
```
|
||||
|
||||
### 案3: BoxDispatcher(透過的ディスパッチ)
|
||||
```rust
|
||||
pub enum BoxImpl {
|
||||
Builtin(Box<dyn NyashBox>), // ビルトイン実装
|
||||
Plugin(BidHandle, PluginRef), // プラグイン実装
|
||||
}
|
||||
```
|
||||
|
||||
### 案4: Unified Box Factory
|
||||
```rust
|
||||
pub struct BoxFactory {
|
||||
providers: HashMap<String, Box<dyn BoxProvider>>,
|
||||
}
|
||||
```
|
||||
|
||||
## 🎉 最終解:YAML/JSON + 署名DSL
|
||||
|
||||
### Codex先生の推奨設計
|
||||
```yaml
|
||||
# filebox.plugin.yaml
|
||||
schema: 1
|
||||
plugin:
|
||||
name: filebox
|
||||
version: 1
|
||||
|
||||
apis:
|
||||
# 静的メソッド(::)
|
||||
- sig: "FileBox::open(path: string, mode?: string) -> FileBox"
|
||||
doc: "Open a file"
|
||||
|
||||
# インスタンスメソッド(#)
|
||||
- sig: "FileBox#read(size?: int) -> string"
|
||||
doc: "Read file content"
|
||||
```
|
||||
|
||||
### 利点
|
||||
1. **記号で静的/インスタンスを区別**
|
||||
- `::` = 静的メソッド(C++風)
|
||||
- `#` = インスタンスメソッド(Ruby風)
|
||||
|
||||
2. **フラット構造**
|
||||
- `apis` 配列にすべて並べる
|
||||
- 階層が深くならない
|
||||
|
||||
3. **署名DSL**
|
||||
- 型情報を1行で表現
|
||||
- パーサーも簡単
|
||||
|
||||
4. **YAML → JSON変換**
|
||||
- 開発時:YAML(人間に優しい)
|
||||
- 実行時:JSON(マシンに優しい)
|
||||
|
||||
## 🤔 Gemini先生への質問事項
|
||||
|
||||
1. **透過的な置き換え**
|
||||
- 既存のNyashコードを一切変更せずに、ビルトインBoxをプラグインBoxに置き換える最良の方法は?
|
||||
- パフォーマンスインパクトをどう最小化するか?
|
||||
|
||||
2. **署名DSLの設計**
|
||||
- `Type::method()` vs `Type.method()` の選択理由
|
||||
- オーバーロードの表現方法
|
||||
- ジェネリクスの将来的な拡張性
|
||||
|
||||
3. **実装戦略**
|
||||
- インタープリター実行時のディスパッチ最適化
|
||||
- プラグインの遅延ロード実装
|
||||
- エラーハンドリングのベストプラクティス
|
||||
|
||||
4. **Everything is Box哲学との整合性**
|
||||
- プラグインBoxもビルトインBoxも「同じBox」として扱う方法
|
||||
- Box型の統一インターフェースの維持
|
||||
|
||||
5. **実用性**
|
||||
- 他の言語(Python、Ruby、JavaScript)の成功例から学べること
|
||||
- プラグイン作者にとっての開発体験
|
||||
- デバッグ・プロファイリングの考慮事項
|
||||
|
||||
## 📚 参考情報
|
||||
- 現在のFileBox実装: `src/boxes/file/mod.rs`
|
||||
- BID-FFIプラグインFileBox: `src/bid/plugins/filebox/mod.rs`
|
||||
- Everything is Box哲学: すべての値がBoxオブジェクト
|
||||
- Nyashの目標: シンプル、分かりやすい、階層が深くならない
|
||||
@ -5,6 +5,17 @@
|
||||
> **方向性は正しい**: primitives-by-value + box-by-handle は適切で、Everything is Box哲学を維持している。
|
||||
> **1週間Phase 1は現実的**(スコープを限定すれば)
|
||||
|
||||
## 📋 更新:シンプルなプラグインシステム設計
|
||||
|
||||
gemini先生とcodex先生の提案を統合し、よりシンプルで実装しやすい設計に更新しました。
|
||||
|
||||
**→ 詳細設計: [Box プラグインシステム設計](../../説明書/reference/box-design/plugin-system.md)**
|
||||
|
||||
主な変更点:
|
||||
- YAML署名DSLによる簡潔なインターフェース定義
|
||||
- nyash.tomlによる透過的な置き換え
|
||||
- 段階的実装(まず手動、後で自動化)
|
||||
|
||||
## 🌟 修正された型システム設計
|
||||
|
||||
### 1. Handle設計の改善(ChatGPT提案)
|
||||
@ -164,42 +175,42 @@ i32 call_plugin_method(...) {
|
||||
|
||||
## 📋 修正された実装計画
|
||||
|
||||
### Phase 1実装チェックリスト(ChatGPT提案)
|
||||
### Phase 1実装チェックリスト(シンプル設計版)
|
||||
|
||||
#### Day 1: BID-1基盤実装
|
||||
- [ ] **BID-1 TLV仕様**とエラーコード定義
|
||||
- [ ] **Handle{type_id,instance_id}**構造体実装
|
||||
- [ ] **基本TLVエンコード/デコード**機能
|
||||
- [ ] テスト: プリミティブ型のTLV変換
|
||||
#### ✅ Day 1: BID-1基盤実装(完了!)
|
||||
- [x] **BID-1 TLV仕様**とエラーコード定義
|
||||
- [x] **Handle{type_id,instance_id}**構造体実装
|
||||
- [x] **基本TLVエンコード/デコード**機能
|
||||
- [x] テスト: プリミティブ型のTLV変換
|
||||
|
||||
#### Day 2: メタデータAPI実装
|
||||
- [ ] **プラグインinit/abi/shutdown**実装
|
||||
- [ ] **NyashHostVtable**とホスト機能提供
|
||||
- [ ] **型・メソッドレジストリ**管理
|
||||
- [ ] テスト: プラグイン初期化・メタデータ取得
|
||||
#### ✅ Day 2: メタデータAPI実装(完了!)
|
||||
- [x] **プラグインinit/abi/shutdown**実装
|
||||
- [x] **NyashHostVtable**とホスト機能提供
|
||||
- [x] **型・メソッドレジストリ**管理
|
||||
- [x] テスト: プラグイン初期化・メタデータ取得
|
||||
|
||||
#### Day 3: 既存Box統合
|
||||
- [ ] **既存StringBox/IntegerBox/FutureBoxブリッジ**
|
||||
- [ ] **NyashBoxRegistry**でハンドル管理
|
||||
- [ ] **FutureBox用wake経路**実装
|
||||
- [ ] テスト: 既存Boxとプラグインの統一操作
|
||||
#### ✅ Day 3: 既存Box統合(完了!)
|
||||
- [x] **既存StringBox/IntegerBox/FutureBoxブリッジ**
|
||||
- [x] **NyashBoxRegistry**でハンドル管理
|
||||
- [x] **FutureBox用wake経路**実装
|
||||
- [x] テスト: 既存Boxとプラグインの統一操作
|
||||
|
||||
#### Day 4: FileBoxプラグイン実装
|
||||
- [ ] **FileBoxプラグイン**(open/read/close)
|
||||
- [ ] **BID-1フォーマット**での引数・結果処理
|
||||
- [ ] **エラー処理**完全実装
|
||||
- [ ] テスト: ファイル操作e2e動作
|
||||
#### ⏳ Day 4: FileBoxプラグイン実装(50%完了)
|
||||
- [x] **FileBoxプラグイン**(open/read/close)
|
||||
- [x] テスト: ファイル操作基本動作
|
||||
- [ ] **nyash.tomlパーサー**(シンプル版)
|
||||
- [ ] **PluginBoxプロキシ**(最小実装)
|
||||
|
||||
#### Day 5: 統合テスト・最適化
|
||||
- [ ] **適合性テスト**(プリミティブ、ハンドル、エラー)
|
||||
- [ ] **メモリリーク検証**
|
||||
- [ ] **性能測定**(FFI呼び出しオーバーヘッド)
|
||||
- [ ] テスト: 全機能統合動作
|
||||
#### Day 5: プラグインロードと統合
|
||||
- [ ] **libloadingで動的ロード**
|
||||
- [ ] **Boxファクトリレジストリ**
|
||||
- [ ] **透過的な置き換え**テスト
|
||||
- [ ] 統合テスト: 既存コードで動作確認
|
||||
|
||||
#### Day 6-7: ドキュメント・CI
|
||||
- [ ] **使用例とドキュメント**
|
||||
- [ ] **Linux x86-64 CI設定**
|
||||
- [ ] **プラグイン開発ガイド**
|
||||
#### Day 6-7: 仕上げとドキュメント
|
||||
- [ ] **使用例作成**
|
||||
- [ ] **プラグイン開発ガイド**(YAML署名DSL説明)
|
||||
- [ ] **今後の拡張計画**(自動化ツール等)
|
||||
- [ ] 予備日(問題対応)
|
||||
|
||||
## 🛠️ 具体的な実装例
|
||||
|
||||
158
docs/説明書/reference/box-design/plugin-system.md
Normal file
158
docs/説明書/reference/box-design/plugin-system.md
Normal file
@ -0,0 +1,158 @@
|
||||
# Nyash Box プラグインシステム設計
|
||||
|
||||
## 概要
|
||||
|
||||
Nyashの「Everything is Box」哲学を維持しながら、Boxの実装をプラグイン化できるシステム。ビルトインBoxとプラグインBoxを透過的に切り替え可能。
|
||||
|
||||
## 🎯 設計原則
|
||||
|
||||
1. **シンプル** - 設定ファイル1つで切り替え
|
||||
2. **透過的** - Nyashコードの変更不要
|
||||
3. **統一的** - ビルトインもプラグインも同じBox
|
||||
|
||||
## 📋 プラグイン定義(YAML署名DSL)
|
||||
|
||||
```yaml
|
||||
# filebox.plugin.yaml
|
||||
schema: 1
|
||||
plugin:
|
||||
name: filebox
|
||||
version: 1
|
||||
|
||||
apis:
|
||||
# 静的メソッド(::)
|
||||
- sig: "FileBox::open(path: string, mode?: string) -> FileBox"
|
||||
doc: "Open a file with optional mode"
|
||||
|
||||
- sig: "FileBox::exists(path: string) -> bool"
|
||||
doc: "Check if file exists"
|
||||
|
||||
# インスタンスメソッド(#)
|
||||
- sig: "FileBox#read(size?: int) -> string"
|
||||
doc: "Read file content"
|
||||
|
||||
- sig: "FileBox#write(content: string) -> int"
|
||||
doc: "Write to file"
|
||||
|
||||
- sig: "FileBox#close() -> void"
|
||||
doc: "Close file handle"
|
||||
```
|
||||
|
||||
### 署名DSL仕様
|
||||
|
||||
- **静的メソッド**: `Type::method()` - C++風の`::`記法
|
||||
- **インスタンスメソッド**: `Type#method()` - Ruby風の`#`記法
|
||||
- **オプショナル引数**: `arg?: type` - `?`サフィックス
|
||||
- **戻り値**: `-> type` - 矢印記法
|
||||
|
||||
## 🔧 設定ファイル(nyash.toml)
|
||||
|
||||
```toml
|
||||
# プロジェクトルートのnyash.toml
|
||||
[plugins]
|
||||
FileBox = "filebox" # FileBoxはプラグイン版を使用
|
||||
# StringBox = "mystring" # コメントアウト = ビルトイン使用
|
||||
```
|
||||
|
||||
## 🏗️ アーキテクチャ
|
||||
|
||||
### 1. Boxレジストリ
|
||||
|
||||
```rust
|
||||
// 起動時の動作
|
||||
let mut registry = HashMap::new();
|
||||
|
||||
// 1. ビルトインBoxを登録
|
||||
registry.insert("FileBox", BoxProvider::Builtin(native_filebox));
|
||||
registry.insert("StringBox", BoxProvider::Builtin(native_stringbox));
|
||||
|
||||
// 2. nyash.toml読み込み
|
||||
let config = parse_nyash_toml()?;
|
||||
|
||||
// 3. プラグイン設定で上書き
|
||||
for (box_name, plugin_name) in config.plugins {
|
||||
registry.insert(box_name, BoxProvider::Plugin(plugin_name));
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 透過的なディスパッチ
|
||||
|
||||
```nyash
|
||||
# Nyashコード(変更不要!)
|
||||
local file = new FileBox("test.txt")
|
||||
file.write("Hello, plugin!")
|
||||
local content = file.read()
|
||||
```
|
||||
|
||||
内部動作:
|
||||
1. `new FileBox` → レジストリ検索
|
||||
2. `BoxProvider::Plugin("filebox")` → プラグインロード
|
||||
3. BID-FFI経由で実行
|
||||
|
||||
### 3. PluginBoxプロキシ
|
||||
|
||||
```rust
|
||||
// すべてのプラグインBoxの統一インターフェース
|
||||
pub struct PluginBox {
|
||||
plugin_name: String,
|
||||
handle: BidHandle, // プラグイン内のインスタンス
|
||||
}
|
||||
|
||||
impl NyashBox for PluginBox {
|
||||
// NyashBoxトレイトの全メソッドを
|
||||
// FFI経由でプラグインに転送
|
||||
}
|
||||
```
|
||||
|
||||
## 📦 プラグイン実装例
|
||||
|
||||
```rust
|
||||
// plugins/filebox/src/lib.rs
|
||||
#[no_mangle]
|
||||
pub extern "C" fn filebox_open(
|
||||
path: *const c_char,
|
||||
mode: *const c_char
|
||||
) -> BidHandle {
|
||||
// ファイルを開いてハンドルを返す
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn filebox_read(
|
||||
handle: BidHandle,
|
||||
size: i32
|
||||
) -> *const u8 {
|
||||
// ファイルを読む
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 段階的導入計画
|
||||
|
||||
### Phase 1: 基本実装(現在)
|
||||
- [x] BID-FFI基盤
|
||||
- [x] FileBoxプラグイン実装
|
||||
- [ ] nyash.tomlパーサー
|
||||
- [ ] PluginBoxプロキシ
|
||||
- [ ] 手動プラグインロード
|
||||
|
||||
### Phase 2: 開発体験向上
|
||||
- [ ] YAMLからFFIコード自動生成
|
||||
- [ ] エラーメッセージ改善
|
||||
- [ ] プラグインテンプレート
|
||||
|
||||
### Phase 3: エコシステム
|
||||
- [ ] プラグインレジストリ
|
||||
- [ ] バージョン管理
|
||||
- [ ] 依存関係解決
|
||||
|
||||
## 🎉 利点
|
||||
|
||||
1. **ビルド時間短縮** - 使わないBoxはコンパイル不要
|
||||
2. **動的拡張** - 再コンパイルなしで新Box追加
|
||||
3. **Everything is Box維持** - 哲学は変わらない
|
||||
4. **段階的移行** - 1つずつBoxをプラグイン化
|
||||
|
||||
## 📚 関連ドキュメント
|
||||
|
||||
- [BID-FFI仕様](./ffi-abi-specification.md)
|
||||
- [Everything is Box哲学](./everything-is-box.md)
|
||||
- [実装タスク](../../../予定/native-plan/issues/phase_9_75g_0_chatgpt_enhanced_final.md)
|
||||
94
local_tests/plugin_design_consultation.txt
Normal file
94
local_tests/plugin_design_consultation.txt
Normal file
@ -0,0 +1,94 @@
|
||||
Nyashプログラミング言語のプラグインシステムについて相談です。
|
||||
|
||||
プラグインのインターフェース定義をYAML/JSONで外部化する設計を検討しています。
|
||||
|
||||
【要件】
|
||||
- 簡単で分かりやすい
|
||||
- 階層が深くならない
|
||||
- 必要な機能は入れる
|
||||
- FileBox.open() のような静的メソッドも定義できる
|
||||
- Everything is Box哲学を維持
|
||||
|
||||
【案1: YAML設計図方式】
|
||||
```yaml
|
||||
plugin:
|
||||
name: FileBox
|
||||
type_id: 6
|
||||
version: "1.0.0"
|
||||
|
||||
static_methods:
|
||||
open:
|
||||
args: [path: string, mode?: string]
|
||||
returns: FileBox
|
||||
default_args: {mode: "r"}
|
||||
|
||||
exists:
|
||||
args: [path: string]
|
||||
returns: bool
|
||||
|
||||
methods:
|
||||
read:
|
||||
args: [size?: number]
|
||||
returns: string
|
||||
|
||||
write:
|
||||
args: [content: string]
|
||||
returns: number
|
||||
|
||||
close:
|
||||
args: []
|
||||
returns: void
|
||||
```
|
||||
|
||||
【案2: より簡潔なJSON】
|
||||
```json
|
||||
{
|
||||
"FileBox": {
|
||||
"static": {
|
||||
"open(path, mode='r')": "FileBox",
|
||||
"exists(path)": "bool"
|
||||
},
|
||||
"methods": {
|
||||
"read(size?)": "string",
|
||||
"write(content)": "number",
|
||||
"close()": "void"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
【案3: 最小限のTOML】
|
||||
```toml
|
||||
[FileBox]
|
||||
type_id = 6
|
||||
|
||||
[FileBox.static]
|
||||
open = "path:string, mode:string? -> FileBox"
|
||||
exists = "path:string -> bool"
|
||||
|
||||
[FileBox.methods]
|
||||
read = "size:number? -> string"
|
||||
write = "content:string -> number"
|
||||
close = "-> void"
|
||||
```
|
||||
|
||||
【案4: プラグイン実装に埋め込む】
|
||||
Rustコードに属性マクロで定義を埋め込む:
|
||||
```rust
|
||||
#[plugin_box(type_id = 6)]
|
||||
impl FileBoxPlugin {
|
||||
#[static_method]
|
||||
fn open(path: String, mode: Option<String>) -> BidHandle { ... }
|
||||
|
||||
#[method]
|
||||
fn read(&self, handle: BidHandle, size: Option<usize>) -> Vec<u8> { ... }
|
||||
}
|
||||
```
|
||||
|
||||
【質問】
|
||||
1. どの方式が最も実用的でしょうか?
|
||||
2. 静的メソッドとインスタンスメソッドの区別をどう表現するのが良いでしょうか?
|
||||
3. メンテナンス性と実装の簡単さのバランスはどう取るべきでしょうか?
|
||||
4. 他により良い設計パターンはありますか?
|
||||
|
||||
プログラミング言語設計の観点から、シンプルさと拡張性のバランスを重視してアドバイスをお願いします。
|
||||
112
src/runtime/plugin_config.rs
Normal file
112
src/runtime/plugin_config.rs
Normal file
@ -0,0 +1,112 @@
|
||||
//! プラグイン設定(nyash.toml)の読み込み
|
||||
//!
|
||||
//! シンプルな実装から始める - 必要最小限の機能のみ
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
/// プラグイン設定
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PluginConfig {
|
||||
/// Box名 → プラグイン名のマッピング
|
||||
/// 例: "FileBox" => "filebox"
|
||||
pub plugins: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl PluginConfig {
|
||||
/// nyash.tomlを読み込む
|
||||
pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self, String> {
|
||||
let content = fs::read_to_string(path)
|
||||
.map_err(|e| format!("Failed to read nyash.toml: {}", e))?;
|
||||
|
||||
Self::parse(&content)
|
||||
}
|
||||
|
||||
/// 設定文字列をパース(シンプル版)
|
||||
///
|
||||
/// 対応フォーマット:
|
||||
/// ```toml
|
||||
/// [plugins]
|
||||
/// FileBox = "filebox"
|
||||
/// StringBox = "mystring"
|
||||
/// ```
|
||||
pub fn parse(content: &str) -> Result<Self, String> {
|
||||
let mut config = PluginConfig::default();
|
||||
let mut in_plugins_section = false;
|
||||
|
||||
for line in content.lines() {
|
||||
let line = line.trim();
|
||||
|
||||
// 空行やコメントはスキップ
|
||||
if line.is_empty() || line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// セクション検出
|
||||
if line == "[plugins]" {
|
||||
in_plugins_section = true;
|
||||
continue;
|
||||
} else if line.starts_with('[') {
|
||||
in_plugins_section = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// plugins セクション内の設定を読む
|
||||
if in_plugins_section {
|
||||
if let Some((key, value)) = line.split_once('=') {
|
||||
let box_name = key.trim().to_string();
|
||||
let plugin_name = value.trim().trim_matches('"').to_string();
|
||||
config.plugins.insert(box_name, plugin_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_simple_config() {
|
||||
let toml = r#"
|
||||
[plugins]
|
||||
FileBox = "filebox"
|
||||
StringBox = "mystring"
|
||||
|
||||
[other]
|
||||
something = "else"
|
||||
"#;
|
||||
|
||||
let config = PluginConfig::parse(toml).unwrap();
|
||||
assert_eq!(config.plugins.get("FileBox"), Some(&"filebox".to_string()));
|
||||
assert_eq!(config.plugins.get("StringBox"), Some(&"mystring".to_string()));
|
||||
assert_eq!(config.plugins.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_empty_config() {
|
||||
let toml = "";
|
||||
let config = PluginConfig::parse(toml).unwrap();
|
||||
assert!(config.plugins.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_with_comments() {
|
||||
let toml = r#"
|
||||
# This is a comment
|
||||
[plugins]
|
||||
# FileBox uses the plugin version
|
||||
FileBox = "filebox"
|
||||
# StringBox = "disabled" # This is commented out
|
||||
"#;
|
||||
|
||||
let config = PluginConfig::parse(toml).unwrap();
|
||||
assert_eq!(config.plugins.get("FileBox"), Some(&"filebox".to_string()));
|
||||
assert_eq!(config.plugins.get("StringBox"), None);
|
||||
assert_eq!(config.plugins.len(), 1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user