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:
27
docs/reference/README.md
Normal file
27
docs/reference/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Nyash Reference Documentation 📖
|
||||
|
||||
このディレクトリには、Nyashプログラミング言語の正式な技術仕様が含まれています。
|
||||
|
||||
## 📚 サブディレクトリ
|
||||
|
||||
### language/
|
||||
- 言語仕様(構文、型システム、Box仕様、デリゲーション)
|
||||
- 正式な言語リファレンス
|
||||
|
||||
### architecture/
|
||||
- システムアーキテクチャ(MIR、VM、インタープリター)
|
||||
- 実行バックエンド仕様
|
||||
- 内部設計ドキュメント
|
||||
|
||||
### api/
|
||||
- ビルトインBoxのAPI仕様
|
||||
- 標準ライブラリリファレンス
|
||||
- 各Boxのメソッド詳細
|
||||
|
||||
### plugin-system/
|
||||
- プラグインシステム仕様
|
||||
- BID-FFI(Box Interface Definition - Foreign Function Interface)
|
||||
- プラグイン開発ガイド
|
||||
|
||||
## 📝 注意事項
|
||||
このディレクトリのドキュメントは安定版です。開発中の仕様は`development/`を参照してください。
|
||||
103
docs/reference/architecture/README.md
Normal file
103
docs/reference/architecture/README.md
Normal file
@ -0,0 +1,103 @@
|
||||
# Nyash VM 実行基盤ガイド
|
||||
|
||||
最終更新: 2025-08-21(Phase 9.78 系対応)
|
||||
|
||||
本書は Nyash の VM バックエンド(MIR 実行機構)と、その周辺の実装・拡張ポイントをまとめた開発者向けドキュメントです。
|
||||
|
||||
## 全体像
|
||||
- 入力: `MirModule`(`mir::MirCompiler` が AST から生成)
|
||||
- 実行: `backend::vm::VM`
|
||||
- `execute_module` → `execute_function` → 命令列を逐次 `execute_instruction`
|
||||
- ランタイム DI: `NyashRuntime`
|
||||
- `box_registry`(統一 BoxFactory 経由の生成)
|
||||
- `box_declarations`(ユーザー定義 Box の宣言)
|
||||
- ライフサイクル: `ScopeTracker` により関数入退出で `fini()` を呼ぶ
|
||||
|
||||
## 主要ファイル
|
||||
- `src/backend/vm.rs` … VM 本体(命令ディスパッチ、Call/BoxCall、NewBox ほか)
|
||||
- `src/mir/*` … MIR 命令定義・Builder・Function/Module 管理
|
||||
- `src/runtime/nyash_runtime.rs` … ランタイムコンテナ(DI 受け皿)
|
||||
- `src/box_factory/*` … Builtin/User/Plugin の各 Factory 実装
|
||||
- `src/runtime/plugin_loader_v2.rs` … BID-FFI v2 ローダ(ExternCall/Plugin 呼び出し)
|
||||
|
||||
## 実行フロー(概略)
|
||||
1) Nyash コード → Parser → AST → `MirCompiler` で `MirModule` を生成
|
||||
2) `VM::with_runtime(runtime)` で実行(`execute_module`)
|
||||
3) 命令ごとに処理:
|
||||
- `Const/Load/Store/BinOp/...` など基本命令
|
||||
- `NewBox`: 統一レジストリ経由で Box 生成
|
||||
- `Call`: `"{Box}.{method}/{N}"` の関数名で MIR 関数呼び出し
|
||||
- `BoxCall`: Box の種類で分岐(ユーザー定義/ビルトイン/プラグイン)
|
||||
- `ExternCall`: `env.console`/`env.canvas` 等をローダへ委譲
|
||||
|
||||
## Box 生成と種別
|
||||
- 生成パス(`NewBox`)は `NyashRuntime::box_registry` が担当
|
||||
- Builtin: `BuiltinBoxFactory` が直接生成
|
||||
- User-defined: `UserDefinedBoxFactory` → `InstanceBox`
|
||||
- Plugin: プラグイン設定(`nyash.toml`)に従い BID-FFI で `PluginBoxV2`
|
||||
|
||||
## birth/メソッドの関数化(MIR)
|
||||
- Lowering ポリシー: AST の `new` は `NewBox` に続けて `BoxCall("birth")` を自動挿入
|
||||
- Box 宣言の `birth/N` と通常メソッド `method/N` は `"{Box}.{name}/{N}"` の MIR 関数に関数化
|
||||
- 命名例: `Person.birth/1`, `Person.greet/0`
|
||||
- 引数: `me` が `%0`、ユーザー引数が `%1..N`(`me` は `MirType::Box(BoxName)`)
|
||||
- 戻り値型: 明示の `return <expr>` があれば `Unknown`、なければ `Void`(軽量推定)
|
||||
- `VM` の呼び出し
|
||||
- `Call` 命令: 関数名(`Const(String)`)を解決 → `call_function_by_name`
|
||||
- `BoxCall` 命令: 下記の種類分岐に委譲
|
||||
|
||||
## BoxCall の種類分岐
|
||||
- ユーザー定義 Box(`InstanceBox`)
|
||||
- `BoxCall("birth")`: `"{Box}.birth/{argc}"` を `Call` 等価で実行
|
||||
- 通常メソッド: `"{Box}.{method}/{argc}"` を `Call` 等価で実行
|
||||
- プラグイン Box(`PluginBoxV2`)
|
||||
- `PluginLoaderV2::invoke_instance_method(box_type, method, instance_id, args)` を呼び出し
|
||||
- 引数/戻り値は最小 TLV でやり取り(タグ: 1=Int64, 2=String, 3=Bool)
|
||||
- 戻り値なしは `void` 扱い
|
||||
- ビルトイン Box
|
||||
- 現状は VM 内の簡易ディスパッチ(`String/Integer/Array/Math` を中心にサポート)
|
||||
- 将来はビルトインも MIR 関数へ寄せる計画
|
||||
|
||||
## ExternCall(ホスト機能)
|
||||
- `env.console.log`, `env.canvas.*` などを `PluginLoaderV2::extern_call` に委譲
|
||||
- いまは最小実装(ログ出力・スタブ)。将来は BID-FFI 由来の外部機能にも接続予定
|
||||
|
||||
## ライフサイクル管理(ScopeTracker)
|
||||
- `VM` は関数入退出で `push_scope()/pop_scope()` を実行
|
||||
- 退出時に登録 Box を `fini()`(`InstanceBox`/`PluginBoxV2`)
|
||||
- Interpreter でも同思想で `restore_local_vars()` にて `fini()` 呼び出し
|
||||
|
||||
## ランタイム DI(依存注入)
|
||||
- `NyashRuntime`
|
||||
- `box_declarations`: AST から収集(Box 宣言)
|
||||
- `box_registry`: Builtin/User/Plugin の順で探索・生成
|
||||
- Runner(CLI 実行)
|
||||
- AST パース後、Box 宣言を `runtime.box_declarations` へ登録
|
||||
- `UserDefinedBoxFactory` をレジストリに注入 → VM を `with_runtime(runtime)` で起動
|
||||
|
||||
## 最適化
|
||||
- 置換: `new X(...).m(...)` → 直接 `Call("X.m/N", me+args)` に最適化
|
||||
- 拡張余地: 変数へ束縛してからの `.m()` も静的に決まる範囲で `Call` 化可能
|
||||
- 戻り値型: 軽量推定。将来は `MirType` 推論/注釈の強化
|
||||
|
||||
## 制約と今後
|
||||
- ビルトインのメソッドはまだ簡易ディスパッチ(MIR 関数化は未)
|
||||
- プラグインの TLV は最小型(Int/String/Bool)のみ。拡張予定
|
||||
- 例外(throw/catch)は簡易扱い(将来の unwind/handler 連携は別設計)
|
||||
|
||||
## テスト
|
||||
- 単体/E2E(抜粋): `src/backend/vm.rs` の `#[cfg(test)]`
|
||||
- `test_vm_user_box_birth_and_method` … `new Person("Alice").greet()` → "Hello, Alice"
|
||||
- `test_vm_user_box_var_then_method` … 変数に束縛→メソッド→戻り値(11)
|
||||
- `test_vm_extern_console_log` … ExternCall の void 確認
|
||||
- 実行例
|
||||
- `cargo test -j32`(plugins 機能や環境依存に注意)
|
||||
|
||||
## 実行(参考)
|
||||
- VMルート実行(Runner 経由)
|
||||
- `nyash --backend vm your_file.nyash`
|
||||
- WASM(ブラウザ)
|
||||
- plugins は無効。ExternCall はスタブ。MIR 関数はそのまま再利用される設計
|
||||
|
||||
---
|
||||
開発ポリシー: 小さく安全に最適化 → MIR/VM の共有ロジックを増やす → Extern/Plugin を段階統合 → WASM/LLVM/JIT へ横展開。
|
||||
393
docs/reference/architecture/TECHNICAL_ARCHITECTURE_2025.md
Normal file
393
docs/reference/architecture/TECHNICAL_ARCHITECTURE_2025.md
Normal file
@ -0,0 +1,393 @@
|
||||
# 🔧 Nyash Technical Architecture & Implementation Guide
|
||||
|
||||
**最終更新: 2025年8月8日**
|
||||
|
||||
## 📐 アーキテクチャ概要
|
||||
|
||||
Nyashインタープリターは以下の主要コンポーネントから構成されています:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Nyash Runtime │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ Parser │ AST │ Interpreter │
|
||||
│ ├─Tokenizer │ ├─ASTNode │ ├─SharedState │
|
||||
│ ├─ParseError │ ├─Span │ ├─NyashBox │
|
||||
│ └─NyashParser │ └─BoxDecl │ └─RuntimeError │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ Box System │
|
||||
│ ├─StringBox ├─IntegerBox ├─BoolBox ├─ArrayBox │
|
||||
│ ├─MapBox ├─DebugBox ├─MathBox ├─TimeBox │
|
||||
│ ├─RandomBox ├─SoundBox ├─MethodBox└─TypeBox │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ Memory Management │
|
||||
│ ├─InstanceBox ├─GlobalBox ├─finalization │
|
||||
│ └─reference counting + explicit destructors │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 🎯 核心設計原則
|
||||
|
||||
### 1. **Everything is Box**
|
||||
すべてのデータがNyashBoxトレイトを実装:
|
||||
```rust
|
||||
pub trait NyashBox: Any + Send + Sync {
|
||||
fn to_string_box(&self) -> Box<StringBox>;
|
||||
fn clone_box(&self) -> Box<dyn NyashBox>;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn box_id(&self) -> usize;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **Unified Memory Model**
|
||||
- **GlobalBox**: 全グローバル変数・関数の統一管理
|
||||
- **Local Variables**: 一時的なローカルスコープ
|
||||
- **SharedState**: 並行処理でのスレッド間共有
|
||||
|
||||
### 3. **Zero-Copy Philosophy**
|
||||
- Arc/Rc による効率的な参照共有
|
||||
- Clone-on-Write パターンの活用
|
||||
- 最小限のメモリコピー
|
||||
|
||||
## 🏗️ 主要コンポーネント
|
||||
|
||||
### **Tokenizer (src/tokenizer.rs)**
|
||||
```rust
|
||||
pub enum TokenType {
|
||||
// 基本トークン
|
||||
IDENTIFIER(String), STRING(String), INTEGER(i64), FLOAT(f64),
|
||||
|
||||
// 演算子
|
||||
PLUS, MINUS, MULTIPLY, DIVIDE,
|
||||
EQ, NE, LT, GT, LE, GE,
|
||||
NOT, AND, OR,
|
||||
|
||||
// キーワード
|
||||
LOCAL, OUTBOX, STATIC, FUNCTION, BOX,
|
||||
IF, ELSE, LOOP, BREAK, RETURN,
|
||||
NOWAIT, AWAIT,
|
||||
|
||||
// 区切り文字
|
||||
LPAREN, RPAREN, LBRACE, RBRACE,
|
||||
COMMA, DOT, ASSIGN,
|
||||
}
|
||||
```
|
||||
|
||||
### **AST構造 (src/ast.rs)**
|
||||
```rust
|
||||
pub enum ASTNode {
|
||||
// 変数宣言(初期化対応)
|
||||
Local {
|
||||
variables: Vec<String>,
|
||||
initial_values: Vec<Option<Box<ASTNode>>>, // 🚀 2025-08-08実装
|
||||
span: Span,
|
||||
},
|
||||
|
||||
// Box宣言(static対応)
|
||||
BoxDeclaration {
|
||||
name: String,
|
||||
fields: Vec<String>,
|
||||
methods: HashMap<String, ASTNode>,
|
||||
constructors: HashMap<String, ASTNode>,
|
||||
init_fields: Vec<String>,
|
||||
is_interface: bool,
|
||||
extends: Option<String>,
|
||||
implements: Vec<String>,
|
||||
type_parameters: Vec<String>, // ジェネリクス
|
||||
is_static: bool, // 🚀 Static Box
|
||||
static_init: Option<Vec<ASTNode>>,
|
||||
},
|
||||
|
||||
// 非同期
|
||||
Nowait { variable: String, expression: Box<ASTNode> },
|
||||
|
||||
// その他の全ASTノード...
|
||||
}
|
||||
```
|
||||
|
||||
### **Interpreter Core (src/interpreter/mod.rs)**
|
||||
|
||||
#### SharedState - 並行処理アーキテクチャ
|
||||
```rust
|
||||
#[derive(Clone)]
|
||||
pub struct SharedState {
|
||||
/// 🌍 グローバルBox:すべてのグローバル変数・関数を管理
|
||||
pub global_box: Arc<Mutex<InstanceBox>>,
|
||||
|
||||
/// 📦 Box宣言:クラス定義情報を管理
|
||||
pub box_declarations: Arc<RwLock<HashMap<String, BoxDeclaration>>>,
|
||||
|
||||
/// ⚡ Static関数:static box関数を管理
|
||||
pub static_functions: Arc<RwLock<HashMap<String, HashMap<String, ASTNode>>>>,
|
||||
|
||||
/// 📁 インクルード済みファイル:重複読み込み防止
|
||||
pub included_files: Arc<Mutex<HashSet<String>>>,
|
||||
}
|
||||
```
|
||||
|
||||
#### NyashInterpreter - 実行エンジン
|
||||
```rust
|
||||
pub struct NyashInterpreter {
|
||||
/// 🤝 共有状態:マルチスレッド対応
|
||||
pub shared: SharedState,
|
||||
|
||||
/// 📍 ローカル変数:スレッドローカル
|
||||
pub local_vars: HashMap<String, Box<dyn NyashBox>>,
|
||||
|
||||
/// 📤 outbox変数:所有権移転用
|
||||
pub outbox_vars: HashMap<String, Box<dyn NyashBox>>,
|
||||
|
||||
/// 🔄 制御フロー:return/break/throw管理
|
||||
pub control_flow: ControlFlow,
|
||||
}
|
||||
```
|
||||
|
||||
## ⚡ 革新的実装詳細
|
||||
|
||||
### 1. **GlobalBox革命**
|
||||
従来のEnvironmentスコープチェーンを廃止:
|
||||
|
||||
```rust
|
||||
// ❌ 従来のスコープチェーン(複雑・低効率)
|
||||
Environment -> ParentEnvironment -> GlobalEnvironment
|
||||
|
||||
// ✅ GlobalBox統一管理(シンプル・高効率)
|
||||
local_vars -> GlobalBox (直接2段階解決)
|
||||
```
|
||||
|
||||
**効果:**
|
||||
- メモリ使用量30%削減
|
||||
- 変数解決速度向上
|
||||
- コード複雑性大幅削減
|
||||
|
||||
### 2. **Static Box Lazy Initialization**
|
||||
```rust
|
||||
impl NyashInterpreter {
|
||||
pub fn ensure_static_box_initialized(&mut self, name: &str) -> Result<(), RuntimeError> {
|
||||
// 1. 初期化済みチェック
|
||||
if self.is_static_box_initialized(name) { return Ok(()); }
|
||||
|
||||
// 2. 循環参照検出
|
||||
if self.is_static_box_initializing(name) {
|
||||
return Err(RuntimeError::CircularDependency(name.to_string()));
|
||||
}
|
||||
|
||||
// 3. 初期化実行
|
||||
self.initialize_static_box(name)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**遅延初期化の利点:**
|
||||
- 効率的なリソース利用
|
||||
- 循環参照の安全な検出
|
||||
- JavaScript ES Modules準拠の実績あるパターン
|
||||
|
||||
### 3. **並行処理アーキテクチャ**
|
||||
```rust
|
||||
pub fn execute_nowait(&mut self, variable: &str, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
let shared_state = self.shared.clone(); // SharedState複製
|
||||
let expr = expression.clone(); // AST複製
|
||||
|
||||
// 🚀 別スレッドで非同期実行
|
||||
let handle = std::thread::spawn(move || {
|
||||
let mut interpreter = NyashInterpreter::new_with_shared(shared_state);
|
||||
interpreter.execute_expression(&expr)
|
||||
});
|
||||
|
||||
// FutureBoxとして結果を返す
|
||||
let future_box = FutureBox::new(handle);
|
||||
self.set_variable(variable, Box::new(future_box))?;
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
```
|
||||
|
||||
### 4. **初期化付きlocal宣言実装**
|
||||
```rust
|
||||
// AST: 各変数の初期化状態を個別管理
|
||||
Local {
|
||||
variables: vec!["a", "b", "c"],
|
||||
initial_values: vec![
|
||||
Some(Box::new(/* 10 + 20 */)), // a = 30
|
||||
None, // b(初期化なし)
|
||||
Some(Box::new(/* "hello" */)), // c = "hello"
|
||||
],
|
||||
}
|
||||
|
||||
// Interpreter: 効率的な初期化処理
|
||||
for (i, var_name) in variables.iter().enumerate() {
|
||||
if let Some(Some(init_expr)) = initial_values.get(i) {
|
||||
let init_value = self.execute_expression(init_expr)?;
|
||||
self.declare_local_variable(var_name, init_value);
|
||||
} else {
|
||||
self.declare_local_variable(var_name, Box::new(VoidBox::new()));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 Box System詳細
|
||||
|
||||
### **Core Boxes**
|
||||
```rust
|
||||
// StringBox: 文字列データ
|
||||
pub struct StringBox { pub value: String }
|
||||
|
||||
// IntegerBox: 整数データ
|
||||
pub struct IntegerBox { pub value: i64 }
|
||||
|
||||
// BoolBox: 論理値データ
|
||||
pub struct BoolBox { pub value: bool }
|
||||
|
||||
// ArrayBox: 動的配列
|
||||
pub struct ArrayBox {
|
||||
elements: RefCell<Vec<Box<dyn NyashBox>>>,
|
||||
box_id: usize
|
||||
}
|
||||
```
|
||||
|
||||
### **Advanced Boxes**
|
||||
```rust
|
||||
// InstanceBox: ユーザー定義Box
|
||||
pub struct InstanceBox {
|
||||
class_name: String,
|
||||
fields: RefCell<HashMap<String, Box<dyn NyashBox>>>,
|
||||
box_id: usize,
|
||||
}
|
||||
|
||||
// DebugBox: デバッグ・プロファイリング
|
||||
pub struct DebugBox {
|
||||
tracked_boxes: RefCell<HashMap<String, WeakBox>>,
|
||||
call_stack: RefCell<Vec<String>>,
|
||||
start_time: Instant,
|
||||
}
|
||||
|
||||
// FutureBox: 非同期結果
|
||||
pub struct FutureBox {
|
||||
handle: Option<JoinHandle<Result<Box<dyn NyashBox>, RuntimeError>>>,
|
||||
result: RefCell<Option<Result<Box<dyn NyashBox>, RuntimeError>>>,
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 パフォーマンス特性
|
||||
|
||||
### **メモリ使用量**
|
||||
| コンポーネント | メモリ効率化手法 |
|
||||
|---------------|------------------|
|
||||
| GlobalBox | 単一インスタンス管理 |
|
||||
| SharedState | Arc/Mutex最小限使用 |
|
||||
| Local Variables | スコープ終了で自動解放 |
|
||||
| Static Boxes | 遅延初期化・シングルトン |
|
||||
|
||||
### **実行速度**
|
||||
```
|
||||
ベンチマーク結果(目安):
|
||||
- 変数解決: ~100ns (GlobalBox直接アクセス)
|
||||
- メソッド呼び出し: ~500ns (ハッシュマップ検索)
|
||||
- 並行処理: ~10μs (スレッド作成コスト)
|
||||
- Box作成: ~200ns (RefCell + allocation)
|
||||
```
|
||||
|
||||
### **スケーラビリティ**
|
||||
- **CPU**: 並行処理によりマルチコア活用
|
||||
- **メモリ**: 参照カウントによる効率的管理
|
||||
- **I/O**: 非同期処理による非ブロッキング実行
|
||||
|
||||
## 🔧 開発ツール
|
||||
|
||||
### **デバッグ機能**
|
||||
```nyash
|
||||
DEBUG = new DebugBox()
|
||||
DEBUG.startTracking() # トラッキング開始
|
||||
DEBUG.trackBox(obj, "label") # オブジェクト監視
|
||||
DEBUG.traceCall("funcName") # 関数呼び出しトレース
|
||||
print(DEBUG.memoryReport()) # メモリレポート
|
||||
DEBUG.saveToFile("debug.txt") # ファイル出力
|
||||
```
|
||||
|
||||
### **エラーハンドリング**
|
||||
```rust
|
||||
pub enum RuntimeError {
|
||||
UndefinedVariable { name: String },
|
||||
TypeError { message: String },
|
||||
DivisionByZero,
|
||||
CircularDependency(String),
|
||||
InvalidOperation { message: String },
|
||||
FileNotFound { path: String },
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 最適化戦略
|
||||
|
||||
### **コンパイル時最適化**
|
||||
- 静的解析による未使用コードの検出
|
||||
- 定数畳み込み最適化
|
||||
- インライン化可能な小関数の特定
|
||||
|
||||
### **実行時最適化**
|
||||
- ホット関数の動的最適化
|
||||
- JIT コンパイルの準備
|
||||
- プロファイル誘導最適化
|
||||
|
||||
### **メモリ最適化**
|
||||
- Boxプールによる割り当て最適化
|
||||
- 世代別ガベージコレクションの検討
|
||||
- Copy-on-Write の積極的活用
|
||||
|
||||
## 🚀 拡張性設計
|
||||
|
||||
### **FFI (Foreign Function Interface)**
|
||||
```rust
|
||||
// extern boxシステム準備完了
|
||||
pub struct ExternBoxDeclaration {
|
||||
name: String,
|
||||
native_functions: HashMap<String, fn(&[Box<dyn NyashBox>]) -> Box<dyn NyashBox>>,
|
||||
}
|
||||
```
|
||||
|
||||
### **プラグインシステム**
|
||||
- Dynamic loading対応準備
|
||||
- Box定義の動的追加
|
||||
- ランタイム機能拡張
|
||||
|
||||
### **WebAssembly出力**
|
||||
```bash
|
||||
# 🌐 準備完了
|
||||
cargo build --target wasm32-unknown-unknown
|
||||
wasm-bindgen --out-dir web --target web target/wasm32-unknown-unknown/release/nyash.wasm
|
||||
```
|
||||
|
||||
## 📈 今後の技術課題
|
||||
|
||||
### **Short-term (1-2 weeks)**
|
||||
1. ジェネリクス実行時特殊化完成
|
||||
2. スレッドプール実装
|
||||
3. WebAssembly バインディング
|
||||
|
||||
### **Mid-term (1-2 months)**
|
||||
1. JIT コンパイル導入
|
||||
2. GUI フレームワーク統合
|
||||
3. パッケージマネージャー
|
||||
|
||||
### **Long-term (3-6 months)**
|
||||
1. Language Server Protocol対応
|
||||
2. LLVM バックエンド
|
||||
3. 分散処理フレームワーク
|
||||
|
||||
## 🎉 技術的達成
|
||||
|
||||
**2025年8月6日-8日のわずか3日間で達成:**
|
||||
|
||||
- ✅ **30,000+ lines** の実装コード
|
||||
- ✅ **15+ Box types** の完全実装
|
||||
- ✅ **並行処理・非同期** システム完成
|
||||
- ✅ **Static Box・名前空間** システム実装
|
||||
- ✅ **現代的構文** (初期化付き変数等) 実装
|
||||
- ✅ **4つの実用アプリケーション** 完成
|
||||
- ✅ **包括的デバッグシステム** 実装
|
||||
|
||||
**結論: Nyashは実験的プロトタイプから production-ready プログラミング言語へと飛躍的進化を遂げました。**
|
||||
|
||||
---
|
||||
*技術仕様書 v1.0*
|
||||
*Everything is Box - Simple yet Powerful*
|
||||
108
docs/reference/architecture/design-overview.md
Normal file
108
docs/reference/architecture/design-overview.md
Normal file
@ -0,0 +1,108 @@
|
||||
# Nyash 設計図(アーキテクチャ概要)
|
||||
|
||||
最終更新: 2025-08-21(Phase 9.78b〜3 反映)
|
||||
|
||||
本書はNyashの実装設計を、バックエンド共通で理解できる単一ドキュメントとしてまとめたもの。言語コア、MIR、インタープリター/VM統合、ランタイム/プラグイン、ビルドと配布の観点を俯瞰する。
|
||||
|
||||
## レイヤー構成
|
||||
|
||||
- 構文/AST: `tokenizer`, `parser`, `ast`
|
||||
- モデル層: `core::model`(BoxDeclaration等の純粋データ)
|
||||
- ランタイム層: `runtime`(UnifiedBoxRegistry, PluginLoader, NyashRuntime)
|
||||
- 実行戦略層: `interpreter`(AST実行)/ `mir`+`backend::vm`(MIR実行)/ 将来 `wasm`/`llvm`
|
||||
- 付帯基盤: `box_factory`, `instance_v2`, `scope_tracker`, `boxes/*`, `stdlib`
|
||||
|
||||
## コア概念
|
||||
|
||||
- Everything is Box: すべての値はBox(ビルトイン、ユーザー定義、プラグイン)
|
||||
- 統一コンストラクタ: `birth(args)`(packはビルトイン継承内部用に透過化)
|
||||
- 明示デリゲーション: `box Child from Parent` と `from Parent.method()`
|
||||
- 厳密変数宣言/スコープ安全: `local`, `outbox`、スコープ退出時の`fini`一元化
|
||||
|
||||
## モデル層(core::model)
|
||||
|
||||
- `BoxDeclaration` を `interpreter` から分離し `core::model` に移動
|
||||
- name, fields, methods, constructors(birth/N), extends, implements, type_parameters
|
||||
- 実行戦略非依存の純粋データ
|
||||
|
||||
## ランタイム層(runtime)
|
||||
|
||||
- `NyashRuntime`
|
||||
- `box_registry: UnifiedBoxRegistry`(ビルトイン/ユーザー定義/プラグインを順序付き検索)
|
||||
- `box_declarations: RwLock<HashMap<String, BoxDeclaration>>`
|
||||
- BuilderでDI(`with_factory`)可能。Interpreter/VMから共有・注入できる
|
||||
- `UnifiedBoxRegistry`
|
||||
- `Arc<dyn BoxFactory>` の列で優先解決(builtin > user > plugin)
|
||||
- `create_box(name, args)` の統一エントリ
|
||||
- `BoxFactory`
|
||||
- builtin: 全ビルトインBoxの生成
|
||||
- user_defined: `BoxDeclaration`に基づき`InstanceBox`生成(birthは実行戦略側で)
|
||||
- plugin: BID-FFI準拠のプラグインBox(将来のExternCall/MIR接続)
|
||||
|
||||
## 実行戦略(Interpreter / VM)
|
||||
|
||||
- Interpreter(AST実行)
|
||||
- `SharedState` は段階的に分解し、宣言等を `NyashRuntime` に寄せ替え
|
||||
- 生成は統一レジストリへ委譲、コンストラクタ実行は`birth/N`のASTを実行
|
||||
|
||||
- VM (MIR実行)
|
||||
- `VM::with_runtime(runtime)` でDI、`NewBox`は`runtime.box_registry.create_box`へ
|
||||
- `ScopeTracker`でスコープ退出時に`fini`(InstanceBox/PluginBox)
|
||||
- birth/メソッドのMIR関数化(Phase 2/3):
|
||||
- Builderが `new` を `NewBox` + `BoxCall("birth")` に展開
|
||||
- Box宣言の `birth/N` と通常メソッド(`method/N`)を `"{Box}.{name}/{N}"` のMIR関数へ関数化
|
||||
- VMの`BoxCall`は `InstanceBox` なら該当MIR関数へディスパッチ(me + 引数)
|
||||
|
||||
## MIR(中間表現)
|
||||
|
||||
- 目的: バックエンド共通の最適化/実行基盤(VM/LLVM/WASM/JIT)
|
||||
- Builder
|
||||
- AST→MIR lowering。`ASTNode::New`→`NewBox`(+ `BoxCall("birth")`)
|
||||
- `ASTNode::BoxDeclaration` の `constructors` / `methods` をMIR関数化
|
||||
- if/loop/try-catch/phi等の基本構造を提供
|
||||
- VM
|
||||
- Stackベースの簡易実装→順次強化中
|
||||
- `call_function_by_name` による関数呼び出しフレームの最小実装
|
||||
|
||||
## インスタンス表現(InstanceBox)
|
||||
|
||||
- 統一フィールド`fields_ng: HashMap<String, NyashValue>`
|
||||
- メソッドASTを保持(ユーザー定義時)
|
||||
- `fini()`による簡易解放(将来、リソースBoxは明示やRAII連携)
|
||||
|
||||
## ライフサイクル統一(fini)
|
||||
|
||||
- Interpreter: スコープ復帰時に`InstanceBox.fini()`等を呼ぶ
|
||||
- VM: `ScopeTracker`で関数入退出時に登録Boxを`fini`
|
||||
|
||||
## プラグイン(BID-FFI)
|
||||
|
||||
- v2ローダ(`runtime::plugin_loader_v2`)とテスター完備
|
||||
- 目標: MIRの`ExternCall`→ローダに接続し、VM/LLVM/WASMで共通パス
|
||||
|
||||
## Runner/ビルド
|
||||
|
||||
- VMモード:
|
||||
1) ASTパース
|
||||
2) ランタイムにBox宣言収集 + UserDefinedBoxFactory登録
|
||||
3) MIRコンパイル
|
||||
4) VMを`with_runtime`で起動し実行
|
||||
|
||||
## 進行中フェーズと方針
|
||||
|
||||
- Phase 9.78b: Interpreter/VMのモデル・ランタイム共有(完了)
|
||||
- Phase 2/3(実質): birth/メソッドのMIR関数化とVMディスパッチ(実装済・基本動作)
|
||||
- 次:
|
||||
- BoxCall→Callへの段階的置換(型決定済みのとき)
|
||||
- ExternCallの実装(VM→プラグイン)
|
||||
- WASM/LLVMバックエンドへMIR関数の共有
|
||||
|
||||
## 参考ファイル
|
||||
|
||||
- `src/core/model.rs`(BoxDeclaration)
|
||||
- `src/runtime/nyash_runtime.rs`(NyashRuntime)
|
||||
- `src/box_factory/*`(builtin/user_defined/plugin)
|
||||
- `src/mir/*`(builder/instruction/function/etc.)
|
||||
- `src/backend/vm.rs`(VM実行)
|
||||
- `src/interpreter/*`(AST実行)
|
||||
|
||||
339
docs/reference/architecture/execution-backends.md
Normal file
339
docs/reference/architecture/execution-backends.md
Normal file
@ -0,0 +1,339 @@
|
||||
# Nyash実行バックエンド完全ガイド
|
||||
|
||||
Nyashプログラミング言語は、**Everything is Box**哲学を維持しながら、3つの異なる実行方式をサポートしています。用途に応じて最適な実行方式を選択できます。
|
||||
|
||||
## 🚀 実行方式一覧
|
||||
|
||||
| 実行方式 | 用途 | 特徴 | パフォーマンス |
|
||||
|---------|------|------|---------------|
|
||||
| **インタープリター** | 開発・デバッグ | 直接AST実行、詳細ログ | 低速・高機能 |
|
||||
| **VM** | 本番・高速実行 | MIR→VM実行 | 中速・最適化 |
|
||||
| **WASM** | Web・サンドボックス | MIR→WASM変換 | 高速・移植性 |
|
||||
|
||||
## 📋 CLIオプション
|
||||
|
||||
### 基本実行(インタープリター)
|
||||
```bash
|
||||
# デフォルト:インタープリター実行
|
||||
nyash program.nyash
|
||||
|
||||
# デバッグ燃料制限付き
|
||||
nyash --debug-fuel 50000 program.nyash
|
||||
|
||||
# 無制限デバッグ燃料
|
||||
nyash --debug-fuel unlimited program.nyash
|
||||
```
|
||||
|
||||
### VM実行
|
||||
```bash
|
||||
# VM実行(高速)
|
||||
nyash --backend vm program.nyash
|
||||
```
|
||||
|
||||
### MIR操作
|
||||
```bash
|
||||
# MIR表示(中間表現確認)
|
||||
nyash --dump-mir program.nyash
|
||||
|
||||
# MIR検証
|
||||
nyash --verify program.nyash
|
||||
|
||||
# 詳細MIR情報
|
||||
nyash --mir-verbose --dump-mir program.nyash
|
||||
```
|
||||
|
||||
### WASM生成・実行
|
||||
```bash
|
||||
# WASMコンパイル(WAT出力)
|
||||
nyash --compile-wasm program.nyash
|
||||
|
||||
# ファイル出力
|
||||
nyash --compile-wasm program.nyash -o output.wat
|
||||
|
||||
# ブラウザで実行可能なWASMを生成
|
||||
nyash --compile-wasm program.nyash -o public/app.wat
|
||||
```
|
||||
|
||||
### ⚡ ベンチマーク(パフォーマンス測定)
|
||||
```bash
|
||||
# 全バックエンド性能比較(デフォルト5回実行)
|
||||
nyash --benchmark
|
||||
|
||||
# 実行回数指定(統計精度向上)
|
||||
nyash --benchmark --iterations 100
|
||||
|
||||
# 結果をファイル保存
|
||||
nyash --benchmark --iterations 50 > benchmark_results.txt
|
||||
```
|
||||
|
||||
## 🎯 インタープリター(デフォルト)
|
||||
|
||||
### 特徴
|
||||
- **用途**: 開発・デバッグ・学習
|
||||
- **実行**: AST直接実行
|
||||
- **速度**: 最も低速
|
||||
- **機能**: 最も詳細なデバッグ情報
|
||||
|
||||
### 利点
|
||||
- 詳細な実行ログ
|
||||
- エラー位置の正確な特定
|
||||
- リアルタイム変数監視
|
||||
- メモリ使用量詳細表示
|
||||
|
||||
### デバッグ燃料システム
|
||||
```bash
|
||||
# パーサー無限ループ対策
|
||||
nyash --debug-fuel 10000 problem.nyash
|
||||
|
||||
# エラー例:
|
||||
🚨 PARSER INFINITE LOOP DETECTED at method call argument parsing
|
||||
🔍 Current token: IDENTIFIER("from") at line 17
|
||||
```
|
||||
|
||||
## 🏎️ VM実行(高速)
|
||||
|
||||
### 特徴
|
||||
- **用途**: 本番実行・性能重視
|
||||
- **実行**: AST→MIR→VM実行
|
||||
- **速度**: 中〜高速
|
||||
- **機能**: 最適化済み
|
||||
|
||||
### 実行パイプライン
|
||||
```
|
||||
Nyashソース → AST → MIR → VM → 結果
|
||||
```
|
||||
|
||||
### MIR(中間表現)
|
||||
```bash
|
||||
# MIR確認
|
||||
nyash --dump-mir simple.nyash
|
||||
|
||||
# 出力例:
|
||||
; MIR Module: main
|
||||
define void @main() {
|
||||
bb0:
|
||||
0: safepoint
|
||||
1: %0 = const 42
|
||||
2: %1 = const 8
|
||||
3: %2 = %0 Add %1
|
||||
4: print %2
|
||||
5: ret %2
|
||||
}
|
||||
```
|
||||
|
||||
### VMの特徴
|
||||
- **SSA形式**: 静的単一代入
|
||||
- **基本ブロック**: 制御フロー最適化
|
||||
- **効果追跡**: 副作用の管理
|
||||
- **型安全**: 実行時型チェック
|
||||
|
||||
## 🌐 WASM実行(Web対応)
|
||||
|
||||
### 特徴
|
||||
- **用途**: Webブラウザ・サンドボックス実行
|
||||
- **実行**: AST→MIR→WASM→ブラウザ
|
||||
- **速度**: 最高速(ネイティブ並み)
|
||||
- **移植性**: 全プラットフォーム対応
|
||||
|
||||
### 実行パイプライン
|
||||
```
|
||||
Nyashソース → AST → MIR → WAT → WASM → ブラウザ
|
||||
```
|
||||
|
||||
### 生成例
|
||||
```nyash
|
||||
// Nyashコード
|
||||
static box Main {
|
||||
main() {
|
||||
return 42
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```wat
|
||||
; 生成されるWAT
|
||||
(module
|
||||
(import "env" "print" (func $print (param i32) ))
|
||||
(memory (export "memory") 1)
|
||||
(global $heap_ptr (mut i32) (i32.const 2048))
|
||||
(func $main (local $0 i32)
|
||||
nop ; safepoint
|
||||
i32.const 42 ; const 42
|
||||
local.set $0 ; store to local
|
||||
local.get $0 ; load from local
|
||||
return ; return 42
|
||||
)
|
||||
(export "main" (func $main))
|
||||
)
|
||||
```
|
||||
|
||||
### Web実行
|
||||
```html
|
||||
<!-- HTMLで読み込み -->
|
||||
<script>
|
||||
async function loadNyashWasm() {
|
||||
const response = await fetch('output.wat');
|
||||
const watText = await response.text();
|
||||
|
||||
const wabt = await WabtModule();
|
||||
const module = wabt.parseWat('output.wat', watText);
|
||||
const binary = module.toBinary({});
|
||||
|
||||
const importObject = {
|
||||
env: { print: console.log }
|
||||
};
|
||||
|
||||
const wasmModule = await WebAssembly.instantiate(binary.buffer, importObject);
|
||||
const result = wasmModule.instance.exports.main(); // 42
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 📊 パフォーマンス比較
|
||||
|
||||
### 🚀 実際のベンチマーク結果(2025-08-14測定・修正)
|
||||
|
||||
#### ⚠️ **重要**: 性能測定の正確な説明
|
||||
|
||||
**真の実行性能比較**(wasmtime統合・100回実行平均):
|
||||
| Backend | 実行時間 | 速度比 | 測定内容 | 最適用途 |
|
||||
|---------|---------|---------|----------|----------|
|
||||
| **🌐 WASM** | **8.12ms** | **13.5x faster** | 真の実行性能 | Web配布・高速実行 |
|
||||
| **📝 Interpreter** | **110.10ms** | **1x (baseline)** | AST直接実行 | 開発・デバッグ |
|
||||
| **🏎️ VM** | **119.80ms** | **0.9x slower** | MIR→VM実行 | 🚨要改善 |
|
||||
|
||||
**コンパイル性能参考**(従来のベンチマーク):
|
||||
| Backend | コンパイル時間 | 速度比 | 測定内容 |
|
||||
|---------|-------------|---------|----------|
|
||||
| **🌐 WASM** | **0.17ms** | **280x faster** | MIR→WASM変換 |
|
||||
| **🏎️ VM** | **16.97ms** | **2.9x faster** | MIR→VM変換 |
|
||||
| **📝 Interpreter** | **48.59ms** | **1x (baseline)** | AST→実行 |
|
||||
|
||||
### 📈 ベンチマーク詳細
|
||||
|
||||
#### 🚨 **VM性能問題の発見**
|
||||
**異常事象**: VMがインタープリターより遅い結果が判明
|
||||
- **推定原因**: MIR変換オーバーヘッド、VM実行エンジン未最適化
|
||||
- **対策**: Phase 9でのJIT化、VM最適化が急務
|
||||
|
||||
#### 実行性能詳細(wasmtime統合測定)
|
||||
```
|
||||
🌐 WASM (wasmtime): 8.12 ms (13.5x faster - 真の実行性能)
|
||||
📝 Interpreter: 110.10 ms (1x baseline)
|
||||
🏎️ VM: 119.80 ms (0.9x slower - 要改善)
|
||||
```
|
||||
|
||||
#### コンパイル性能詳細(従来測定)
|
||||
```
|
||||
🌐 WASM変換: 0.15-0.21 ms (280x faster - コンパイル速度)
|
||||
🏎️ VM変換: 4.44-25.08 ms (3-120x faster - コンパイル速度)
|
||||
📝 実行のみ: 14.85-84.88 ms (1x baseline)
|
||||
```
|
||||
|
||||
### 💡 ベンチマーク実行方法
|
||||
```bash
|
||||
# 現在のマシンで性能測定
|
||||
nyash --benchmark --iterations 100
|
||||
|
||||
# 軽量テスト(開発中)
|
||||
nyash --benchmark --iterations 10
|
||||
```
|
||||
|
||||
### メモリ使用量
|
||||
```
|
||||
インタープリター ████████████████████ 高い(AST+実行情報)
|
||||
VM ████████████ 中程度(MIR+実行時)
|
||||
WASM ████ 低い(最適化済み)
|
||||
```
|
||||
|
||||
## 🎁 Everything is Box の維持
|
||||
|
||||
全ての実行方式で、Nyashの核心哲学「Everything is Box」が維持されます:
|
||||
|
||||
### インタープリター
|
||||
```rust
|
||||
// RustのArc<Mutex<dyn NyashBox>>として実装
|
||||
StringBox::new("Hello") → Arc<Mutex<StringBox>>
|
||||
```
|
||||
|
||||
### VM
|
||||
```
|
||||
// MIRのValueIdとして管理
|
||||
%0 = const "Hello" ; StringBox相当
|
||||
%1 = %0.length() ; メソッド呼び出し
|
||||
```
|
||||
|
||||
### WASM
|
||||
```wat
|
||||
;; WASMの線形メモリでBox表現
|
||||
;; [type_id:4][field_count:4][field0:4][field1:4]...
|
||||
i32.const 1001 ;; StringBox type ID
|
||||
i32.store offset=0 ;; メモリにBox情報格納
|
||||
```
|
||||
|
||||
## 🚀 用途別推奨
|
||||
|
||||
### 開発・デバッグ時
|
||||
```bash
|
||||
# 詳細ログでエラー特定
|
||||
nyash --debug-fuel unlimited debug_me.nyash
|
||||
```
|
||||
|
||||
### 本番実行時
|
||||
```bash
|
||||
# 高速・安定実行
|
||||
nyash --backend vm production.nyash
|
||||
```
|
||||
|
||||
### Web配布時
|
||||
```bash
|
||||
# ブラウザ対応WASM生成
|
||||
nyash --compile-wasm app.nyash -o public/app.wat
|
||||
```
|
||||
|
||||
## 🔧 トラブルシューティング
|
||||
|
||||
### パーサーエラー
|
||||
```bash
|
||||
# 無限ループ検出時
|
||||
🚨 PARSER INFINITE LOOP DETECTED
|
||||
→ nyash --debug-fuel 1000 problem.nyash
|
||||
```
|
||||
|
||||
### MIRエラー
|
||||
```bash
|
||||
# 未対応AST構文
|
||||
❌ MIR compilation error: Unsupported AST node type: BoxDeclaration
|
||||
→ 現在はstatic box Mainのみ対応
|
||||
```
|
||||
|
||||
### WASMエラー
|
||||
```bash
|
||||
# 未対応MIR命令
|
||||
❌ WASM compilation error: Instruction not yet supported: ComplexInstruction
|
||||
→ Phase 8.3で順次対応予定
|
||||
```
|
||||
|
||||
## 📈 今後の拡張予定
|
||||
|
||||
### Phase 8.3: Box操作のWASM対応
|
||||
- RefNew/RefGet/RefSet
|
||||
- オブジェクト指向プログラミング
|
||||
- メモリ管理の高度化
|
||||
|
||||
### Phase 8.4: 非同期処理のWASM対応
|
||||
- nowait/await構文
|
||||
- Future操作
|
||||
- 並列処理
|
||||
|
||||
### Phase 8.5: 最適化
|
||||
- デッドコード除去
|
||||
- インライン展開
|
||||
- ループ最適化
|
||||
|
||||
---
|
||||
|
||||
**💡 Tip**: 開発中は**インタープリター**、テスト時は**VM**、配布時は**WASM**という使い分けが効果的です!
|
||||
|
||||
最終更新: 2025-08-14
|
||||
作成者: Nyash Development Team
|
||||
235
docs/reference/architecture/mir-unified-reference.md
Normal file
235
docs/reference/architecture/mir-unified-reference.md
Normal file
@ -0,0 +1,235 @@
|
||||
# 🤖 Nyash MIR (Mid-level Intermediate Representation) - 統合リファレンス
|
||||
|
||||
*26命令削減実装中・ChatGPT5仕様準拠 - 2025年8月17日版*
|
||||
|
||||
## 🚨 **重要: MIR命令削減プロジェクト進行中**
|
||||
|
||||
**現状**: 35命令実装(175%膨張)→ **目標**: 26命令(ChatGPT5仕様)
|
||||
**Gemini評価**: 削減戦略「極めて健全」「断行推奨」
|
||||
|
||||
## 🎯 **MIR概要**
|
||||
|
||||
Nyash MIRは、Everything is Box哲学を基盤とした中間表現です。現在35命令が実装され、インタープリター・VM・WASM・AOTの全バックエンドで統一された実行を実現します。
|
||||
|
||||
### **🌟 主要特徴**
|
||||
- **Everything is Box**: 全データがBoxオブジェクトとして統一表現
|
||||
- **Effect System**: pure/mut/io/control効果による最適化基盤
|
||||
- **所有権管理**: 強参照森(ownership forest)+ weak参照システム
|
||||
- **非同期対応**: Future/Bus操作の言語レベル統合
|
||||
- **FFI/ABI統合**: ExternCall命令による外部API統一呼び出し
|
||||
|
||||
## 🏗️ **命令分類 - 35命令全体系**
|
||||
|
||||
### **Tier-0: コア演算 (8命令)**
|
||||
基本的な計算・制御フロー命令
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Const` | `%dst = const value` | pure | 定数値生成 |
|
||||
| `BinOp` | `%dst = %lhs op %rhs` | pure | 二項演算(+,-,*,/等) |
|
||||
| `UnaryOp` | `%dst = op %operand` | pure | 単項演算(not, neg等) |
|
||||
| `Compare` | `%dst = %lhs cmp %rhs` | pure | 比較演算(==, !=, <等) |
|
||||
| `Branch` | `br %cond -> %then, %else` | control | 条件分岐 |
|
||||
| `Jump` | `jmp %target` | control | 無条件ジャンプ |
|
||||
| `Return` | `ret %value?` | control | 関数戻り |
|
||||
| `Phi` | `%dst = phi [%val1:%bb1, %val2:%bb2]` | pure | SSA φ関数 |
|
||||
|
||||
### **Tier-1: メモリ・関数操作 (8命令)**
|
||||
メモリアクセス・関数呼び出し・型操作
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Load` | `%dst = load %ptr` | pure | メモリ読み取り |
|
||||
| `Store` | `store %value -> %ptr` | mut | メモリ書き込み |
|
||||
| `Call` | `%dst = call %func(%args...)` | context | 関数呼び出し |
|
||||
| `BoxCall` | `%dst = %box.method(%args...)` | context | Boxメソッド呼び出し |
|
||||
| `NewBox` | `%dst = new_box "Type"(%args...)` | mut | Box生成 |
|
||||
| `TypeCheck` | `%dst = type_check %box "Type"` | pure | 型チェック |
|
||||
| `Cast` | `%dst = cast %value as Type` | pure | 型変換 |
|
||||
| `Copy` | `%dst = copy %src` | pure | 値コピー |
|
||||
|
||||
### **Tier-2: 配列・デバッグ・制御 (7命令)**
|
||||
配列操作・デバッグ・例外処理
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `ArrayGet` | `%dst = %array[%index]` | pure | 配列要素取得 |
|
||||
| `ArraySet` | `%array[%index] = %value` | mut | 配列要素設定 |
|
||||
| `Debug` | `debug %value "message"` | io | デバッグ出力 |
|
||||
| `Print` | `print %value` | io | コンソール出力 |
|
||||
| `Nop` | `nop` | pure | 無操作 |
|
||||
| `Throw` | `throw %exception` | control | 例外発生 |
|
||||
| `Catch` | `catch %type -> %handler` | control | 例外捕捉 |
|
||||
|
||||
### **Tier-3: 参照・非同期・外部API (12命令)**
|
||||
所有権管理・非同期処理・外部連携
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Safepoint` | `safepoint` | io | セーフポイント |
|
||||
| `RefNew` | `%dst = ref_new %box` | pure | 参照生成 |
|
||||
| `RefGet` | `%dst = ref_get %ref.field` | pure | 参照経由読み取り |
|
||||
| `RefSet` | `ref_set %ref.field = %value` | mut | 参照経由書き込み |
|
||||
| `WeakNew` | `%dst = weak_new %box` | pure | weak参照生成 |
|
||||
| `WeakLoad` | `%dst = weak_load %weak_ref` | pure | weak参照読み取り |
|
||||
| `BarrierRead` | `barrier_read %ptr` | io | メモリバリア読み |
|
||||
| `BarrierWrite` | `barrier_write %ptr` | io | メモリバリア書き |
|
||||
| `FutureNew` | `%dst = future_new %value` | mut | Future生成 |
|
||||
| `FutureSet` | `future_set %future = %value` | mut | Future値設定 |
|
||||
| `Await` | `%dst = await %future` | io | Future待機 |
|
||||
| `ExternCall` | `%dst = extern_call iface.method(%args...)` | context | 外部API呼び出し |
|
||||
|
||||
## 🎭 **Effect System - 4種類の効果**
|
||||
|
||||
### **効果分類と最適化ルール**
|
||||
|
||||
```rust
|
||||
pub enum Effect {
|
||||
Pure, // 再順序化可能、共通部分式除去可能
|
||||
Mut, // 同一リソースで順序保持必要
|
||||
Io, // 全順序保持必要(副作用あり)
|
||||
Control, // 制御フロー変更
|
||||
}
|
||||
```
|
||||
|
||||
### **効果別命令分類**
|
||||
|
||||
#### **Pure命令 (15命令)**
|
||||
```
|
||||
Const, BinOp, UnaryOp, Compare, Phi, Load, TypeCheck, Cast, Copy,
|
||||
ArrayGet, Nop, RefNew, RefGet, WeakNew, WeakLoad
|
||||
```
|
||||
|
||||
#### **Mut命令 (7命令)**
|
||||
```
|
||||
Store, NewBox, ArraySet, RefSet, FutureNew, FutureSet
|
||||
```
|
||||
|
||||
#### **Io命令 (6命令)**
|
||||
```
|
||||
Debug, Print, Safepoint, BarrierRead, BarrierWrite, Await
|
||||
```
|
||||
|
||||
#### **Control命令 (4命令)**
|
||||
```
|
||||
Branch, Jump, Return, Throw, Catch
|
||||
```
|
||||
|
||||
#### **Context依存命令 (3命令)**
|
||||
```
|
||||
Call, BoxCall, ExternCall
|
||||
```
|
||||
*効果は呼び出し先に依存*
|
||||
|
||||
## 🔧 **重要なMIR実装詳細**
|
||||
|
||||
### **ExternCall命令 - FFI/ABI統合**
|
||||
|
||||
```rust
|
||||
ExternCall {
|
||||
dst: Option<ValueId>,
|
||||
iface_name: String, // "env.console", "nyash.math"等
|
||||
method_name: String, // "log", "sqrt"等
|
||||
args: Vec<ValueId>,
|
||||
effects: EffectMask, // BID仕様から決定
|
||||
}
|
||||
```
|
||||
|
||||
**用途**: ブラウザーAPI・ネイティブライブラリ・プラグインの統一呼び出し
|
||||
|
||||
### **所有権管理システム**
|
||||
|
||||
#### **強参照森(Ownership Forest)**
|
||||
- 各Boxは最大1つの強参照を持つ(in-degree ≤ 1)
|
||||
- 強参照による循環は禁止(DAG構造保証)
|
||||
- `NewBox`, `RefSet`で所有権移転
|
||||
|
||||
#### **weak参照システム**
|
||||
- 所有権を持たない軽量参照
|
||||
- `WeakNew`で生成、`WeakLoad`で安全アクセス
|
||||
- 参照先削除時は自動的にnull化
|
||||
|
||||
### **非同期処理 - Future操作**
|
||||
|
||||
```mir
|
||||
%future = FutureNew %initial_value // Future生成
|
||||
FutureSet %future = %result // 結果設定
|
||||
%value = Await %future // 結果取得(ブロッキング)
|
||||
```
|
||||
|
||||
## 🚀 **バックエンド別対応状況**
|
||||
|
||||
### **実装済みバックエンド**
|
||||
|
||||
| バックエンド | 対応命令数 | 主要用途 | 特徴 |
|
||||
|-------------|-----------|----------|------|
|
||||
| **Interpreter** | 35/35 | デバッグ・開発 | 全命令完全対応 |
|
||||
| **VM** | 35/35 | 高速実行 | レジスタベース |
|
||||
| **WASM** | 30/35 | Web配布 | ExternCall→import対応 |
|
||||
| **AOT準備** | 計画中 | ネイティブ | LLVM IR生成予定 |
|
||||
|
||||
### **バックエンド固有の最適化**
|
||||
|
||||
#### **VM バックエンド**
|
||||
- レジスタベース実行
|
||||
- 局所最適化(ローカルBus elision)
|
||||
- 直接スレッド化
|
||||
|
||||
#### **WASM バックエンド**
|
||||
- メモリ線形化(文字列は (ptr,len))
|
||||
- ExternCall → import宣言自動生成
|
||||
- ホスト側JavaScript連携
|
||||
|
||||
## 📊 **MIR最適化パス**
|
||||
|
||||
### **Pure命令最適化**
|
||||
- **共通部分式除去 (CSE)**: 同一pure計算の除去
|
||||
- **不変コード移動 (LICM)**: ループ外移動
|
||||
- **定数畳み込み**: コンパイル時計算
|
||||
|
||||
### **Effect-aware最適化**
|
||||
- **Mut順序保持**: 同一リソースアクセス順序維持
|
||||
- **Io順序保持**: 全Io命令の順序保証
|
||||
- **Bus elision**: ローカル通信の直接アクセス化
|
||||
|
||||
## 🧪 **テスト・検証**
|
||||
|
||||
### **MIR検証項目**
|
||||
- [ ] **所有権森検証**: strong in-degree ≤ 1
|
||||
- [ ] **強循環禁止**: 強参照のDAG構造保証
|
||||
- [ ] **weak参照安全性**: 失効時null化
|
||||
- [ ] **効果注釈正確性**: 各命令の効果分類
|
||||
- [ ] **型安全性**: Box型システム整合性
|
||||
|
||||
### **バックエンド互換性テスト**
|
||||
```bash
|
||||
# 全バックエンドMIR一致テスト
|
||||
./target/release/nyash --dump-mir program.nyash > interpreter.mir
|
||||
./target/release/nyash --backend vm --dump-mir program.nyash > vm.mir
|
||||
./target/release/nyash --backend wasm --dump-mir program.nyash > wasm.mir
|
||||
diff interpreter.mir vm.mir && diff vm.mir wasm.mir
|
||||
```
|
||||
|
||||
## 🔮 **将来計画**
|
||||
|
||||
### **Phase 10: AOT/JIT対応**
|
||||
- LLVM IR生成バックエンド
|
||||
- ExternCall → ネイティブ関数呼び出し
|
||||
- 高度な最適化パス統合
|
||||
|
||||
### **Phase 11: MIR v2設計**
|
||||
- 命令数最適化(35 → 25命令目標)
|
||||
- BID統合(Box Interface Definition)
|
||||
- リソース所有権拡張(own<T>, borrow<T>)
|
||||
|
||||
## 📚 **関連ドキュメント**
|
||||
|
||||
- **FFI/ABI仕様**: `docs/説明書/reference/box-design/ffi-abi-specification.md`
|
||||
- **実装詳細**: `src/mir/instruction.rs`
|
||||
- **Phase計画**: `docs/予定/native-plan/copilot_issues.txt`
|
||||
|
||||
---
|
||||
|
||||
**最終更新**: 2025年8月17日
|
||||
**実装ベース**: 35命令完全対応
|
||||
**次期計画**: BID統合プラグインシステム(Phase 9.75f-BID)
|
||||
654
docs/reference/architecture/nyash_core_concepts.md
Normal file
654
docs/reference/architecture/nyash_core_concepts.md
Normal file
@ -0,0 +1,654 @@
|
||||
# 🚀 Nyash言語 - 一目でわかる速習ガイド
|
||||
|
||||
**Nyash**は「Everything is Box」哲学に基づく革新的プログラミング言語です。このドキュメントで、Nyashのコアコンセプトを素早く理解できます。
|
||||
|
||||
## 🎯 **5分で動かす!クイックスタート**
|
||||
|
||||
```bash
|
||||
# ビルド & 実行
|
||||
cargo build --release -j32
|
||||
./target/release/nyash program.nyash
|
||||
|
||||
# プラグイン対応FileBox実行例
|
||||
./target/release/nyash local_tests/test_plugin_filebox.nyash
|
||||
```
|
||||
|
||||
### 🌟 **実際に動く!Nyashコード例**
|
||||
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
static box Main {
|
||||
init { console }
|
||||
|
||||
main() {
|
||||
// 🎉 自動リテラル変換 - 超簡単!
|
||||
local name = "Nyash" // → StringBox
|
||||
local year = 2025 // → IntegerBox
|
||||
local pi = 3.14159 // → FloatBox
|
||||
|
||||
// 🚀 プラグインシステム
|
||||
local f = new FileBox("data.txt") // プラグイン実装
|
||||
f.write("Hello from plugin!")
|
||||
print("読み取り: " + f.read())
|
||||
|
||||
// 📚 標準ライブラリ
|
||||
local upper = string.upper(name)
|
||||
console.log("🎉 " + upper + " " + year + " Ready!")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**実行結果:**
|
||||
```
|
||||
読み取り: Hello from plugin!
|
||||
🎉 NYASH 2025 Ready!
|
||||
```
|
||||
|
||||
## 🔌 **BID-FFIプラグインシステム** - Phase 9.75g-0の革命!
|
||||
|
||||
Nyashの最新の革命的機能:**プラグインによるBox拡張システム**
|
||||
|
||||
### 🎯 **プラグインの威力**
|
||||
|
||||
```nyash
|
||||
// プラグイン設定(nyash.toml)
|
||||
[plugins]
|
||||
FileBox = "nyash-filebox-plugin"
|
||||
|
||||
// Nyashコード - 透過的にプラグイン使用
|
||||
local f = new FileBox("important.txt") // プラグイン実装を自動選択
|
||||
f.write("機密データ") // プラグインのwrite()
|
||||
local data = f.read() // プラグインのread()
|
||||
```
|
||||
|
||||
### ✨ **型情報管理システム**
|
||||
|
||||
```toml
|
||||
# nyash.toml - 型情報で自動変換
|
||||
[plugins.FileBox.methods]
|
||||
write = { args = [{ from = "string", to = "bytes" }] } # 自動変換
|
||||
read = { args = [] } # 引数なし
|
||||
```
|
||||
|
||||
### 🛡️ **メモリ安全性**
|
||||
|
||||
- **HostVtable**: プラグイン↔ホスト間の安全なインターフェース
|
||||
- **生存期間管理**: birth/finiライフサイクル完全実装
|
||||
- **valgrind検証済み**: セグフォルト完全解消
|
||||
|
||||
### 📋 **プラグイン診断ツール**
|
||||
|
||||
```bash
|
||||
# プラグインの健全性チェック
|
||||
./tools/plugin-tester/target/release/plugin-tester check plugin.so
|
||||
./tools/plugin-tester/target/release/plugin-tester io plugin.so
|
||||
```
|
||||
|
||||
**詳細**: [BID-FFI仕様書](説明書/reference/box-design/ffi-abi-specification.md)
|
||||
|
||||
## ⚡ **実行バックエンド選択** - 開発から本番まで
|
||||
|
||||
Nyashは用途に応じて最適な実行方式を選択可能:
|
||||
|
||||
```bash
|
||||
# 開発・デバッグ(即時実行)
|
||||
./target/release/nyash program.nyash
|
||||
|
||||
# 高速実行(本番用)
|
||||
./target/release/nyash --backend vm program.nyash
|
||||
|
||||
# Web配布用
|
||||
./target/release/nyash --compile-wasm program.nyash
|
||||
|
||||
# 性能比較
|
||||
./target/release/nyash --benchmark --iterations 100
|
||||
```
|
||||
|
||||
### 🚀 **性能実績**
|
||||
- **VM**: 20.4倍高速化
|
||||
- **WASM**: 13.5倍高速化
|
||||
- **LLVM AOT**: 100-1000倍高速化(Phase 10計画中)
|
||||
- **インタープリター**: 開発に最適、本番でも実用的
|
||||
|
||||
**詳細**: [実行バックエンド完全ガイド](execution-backends.md)
|
||||
|
||||
## 1. 基本哲学: Everything is a Box (すべてはBoxである)
|
||||
|
||||
- Nyashの基本原則は「すべてがBoxである」ということです。
|
||||
- 単純な整数から複雑な構造体まで、すべてのデータ型は「Box」オブジェクトの一種です。これにより、純粋で一貫性のあるオブジェクトベースのシステムが実現されています。
|
||||
|
||||
### 🌟 **革命的改善: 自動リテラル変換(Phase 9.75h完了)**
|
||||
|
||||
Nyashでは、Everything is Box哲学を維持しながら、使いやすさを大幅に向上させる自動リテラル変換機能を提供します:
|
||||
|
||||
```nyash
|
||||
// 🎉 新しい書き方 - 自動変換で超使いやすい!
|
||||
local text = "Hello" // "Hello" → StringBox::new("Hello") に自動変換
|
||||
local name = "Alice" // "Alice" → StringBox::new("Alice") に自動変換
|
||||
local age = 30 // 30 → IntegerBox::new(30) に自動変換
|
||||
local active = true // true → BoolBox::new(true) に自動変換
|
||||
local pi = 3.14159 // 3.14159 → FloatBox::new(3.14159) に自動変換
|
||||
|
||||
// ❌ 古い書き方(まだサポート)
|
||||
local oldText = new StringBox("Hello")
|
||||
local oldAge = new IntegerBox(30)
|
||||
|
||||
// ✅ Everything is Box哲学 + 書きやすさ革命達成!
|
||||
```
|
||||
|
||||
**重要**: この自動変換はパーサーレベルで行われるため、実行時オーバーヘッドはありません。すべてが内部的にBoxとして処理されます。
|
||||
|
||||
## 2. オブジェクトモデルとデリゲーション (Nyash独自の方式)
|
||||
|
||||
Nyashは古典的な継承ではなく、デリゲーション(委譲)モデルを使用します。これは非常に重要な違いです。
|
||||
|
||||
- **Boxの定義:**
|
||||
```nyash
|
||||
box MyBox {
|
||||
// フィールドはinitやpackのようなコンストラクタ内で宣言される
|
||||
// メソッドはこの場所に定義される
|
||||
}
|
||||
```
|
||||
|
||||
- **コンストラクタ** (優先順位: birth > pack > init > Box名形式)
|
||||
- **`birth` (推奨・統一):** 「Boxに生命を与える」直感的コンストラクタ。Everything is Box哲学を体現する最新の統一構文。
|
||||
```nyash
|
||||
box Life {
|
||||
init { name, energy } // フィールド宣言
|
||||
|
||||
birth(lifeName) { // ← 「生命を与える」哲学的コンストラクタ
|
||||
me.name = lifeName
|
||||
me.energy = 100
|
||||
print("🌟 " + lifeName + " が誕生しました!")
|
||||
}
|
||||
}
|
||||
local alice = new Life("Alice") // birthが呼び出される
|
||||
```
|
||||
- **`init` (基本):** 従来のユーザー定義Boxのコンストラクタ。フィールド宣言と基本的な初期化。
|
||||
```nyash
|
||||
box User {
|
||||
init { name, email } // フィールド宣言のみ
|
||||
// new時に直接フィールドに値が設定される
|
||||
}
|
||||
local user = new User("Alice", "alice@example.com") // initが呼び出される
|
||||
```
|
||||
- **`pack` (ビルトインBox継承専用):** ビルトインBox(P2PBox、MathBox等)を継承する際の特別なコンストラクタ。ユーザー定義Boxでは使用禁止。
|
||||
```nyash
|
||||
box ChatNode from P2PBox {
|
||||
init { chatHistory } // 追加フィールド宣言
|
||||
|
||||
pack(nodeId, world) {
|
||||
from P2PBox.pack(nodeId, world) // ビルトインBoxの初期化
|
||||
me.chatHistory = new ArrayBox() // 自分の追加フィールド初期化
|
||||
}
|
||||
}
|
||||
local node = new ChatNode("node1", "tcp") // packが呼び出される
|
||||
```
|
||||
|
||||
- **デリゲーション (`from`キーワード):** あるオブジェクトが、メソッド呼び出しやフィールドアクセスを別のオブジェクトに委譲できます。
|
||||
```nyash
|
||||
// AdminがUserにデリゲートする
|
||||
box Admin from User {
|
||||
init { permissions } // Adminの追加フィールド
|
||||
}
|
||||
```
|
||||
|
||||
- **明示的なオーバーライド (`override`キーワード):** 子Boxが親Boxのメソッドを再実装する場合、必ず`override`でマークしなければなりません。
|
||||
```nyash
|
||||
box AdminUser from User {
|
||||
init { permissions } // 追加フィールド
|
||||
|
||||
birth(name, email, permissions) { // birth構文使用
|
||||
from User.birth(name, email) // 親のbirthを呼び出し
|
||||
me.permissions = permissions // 追加フィールド初期化
|
||||
print("🎉 管理者 " + name + " が誕生しました")
|
||||
}
|
||||
|
||||
override greet() {
|
||||
from User.greet() // 親の処理を実行
|
||||
print("(Administrator)") // 追加の処理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **デリゲートされたメソッドの呼び出し (`from`キーワード):** オーバーライドしたメソッド内から親の実装を呼び出すには、`from Parent.method()`を使用します。
|
||||
```nyash
|
||||
box ScientificCalc from MathBox {
|
||||
init { history }
|
||||
|
||||
pack() {
|
||||
from MathBox.pack() // ビルトインBoxの初期化
|
||||
me.history = new ArrayBox() // 自分の追加フィールド
|
||||
}
|
||||
|
||||
override sin(x) {
|
||||
local result = from MathBox.sin(x) // 親のメソッド呼び出し
|
||||
me.history.push("sin(" + x + ") = " + result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **ファイナライズ (`fini`キーワード):**
|
||||
- `fini()`は「リソース解放フック」として機能する特別なメソッドです。
|
||||
- **Nyashの明示的哲学**: 自動的な解放は最小限に留め、プログラマーが制御します。
|
||||
|
||||
**🎯 finiが呼ばれる3つのタイミング:**
|
||||
|
||||
1. **スコープ離脱時(自動)**
|
||||
- ローカル変数がスコープを抜ける時に自動的に呼ばれます
|
||||
- ただし`me`(インスタンス自身)は除外されます
|
||||
```nyash
|
||||
function test() {
|
||||
local resource = new FileBox("data.txt")
|
||||
// 関数終了時、resourceのfini()が自動的に呼ばれる
|
||||
}
|
||||
```
|
||||
|
||||
2. **明示的呼び出し(推奨)**
|
||||
- プログラマーが必要に応じて明示的に呼び出します
|
||||
```nyash
|
||||
local file = new FileBox("temp.txt")
|
||||
file.write("data")
|
||||
file.fini() // 明示的にリソースを解放
|
||||
```
|
||||
|
||||
3. **インスタンスのfini時(カスケード)**
|
||||
- インスタンスがfiniされる時、そのフィールドもfiniされます
|
||||
- ただしweakフィールドは除外されます
|
||||
|
||||
**⚠️ 重要な注意点:**
|
||||
- **フィールド差し替え時にはfiniは呼ばれません**(GC的な「おせっかい」を避ける設計)
|
||||
- ファイナライズ後のオブジェクト使用は実行時エラーになります
|
||||
- `fini()`の重複呼び出しは安全(何もしない)
|
||||
- **すべてのBox型(ビルトイン含む)にfini実装が必要**(設計統一性)
|
||||
|
||||
```nyash
|
||||
box ManagedResource {
|
||||
init { handle, weak observer } // observerはweakなのでfiniされない
|
||||
|
||||
fini() {
|
||||
// リソースのクリーンアップ
|
||||
me.console.log("リソースをファイナライズしました。")
|
||||
// handleは自動的にfiniされる(weakでない限り)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用例
|
||||
local res = new ManagedResource()
|
||||
res.handle = new FileBox("data.txt")
|
||||
|
||||
// ❌ これではfiniは呼ばれない(明示的管理)
|
||||
res.handle = new FileBox("other.txt") // 古いhandleは解放されない!
|
||||
|
||||
// ✅ 正しい方法
|
||||
res.handle.fini() // 明示的に古いリソースを解放
|
||||
res.handle = new FileBox("other.txt")
|
||||
```
|
||||
|
||||
## 3. 標準ライブラリアクセス (using & namespace) 🎉 **Phase 9.75e完了**
|
||||
|
||||
Nyashは組み込み標準ライブラリ`nyashstd`と、using文による名前空間インポートをサポートします。
|
||||
|
||||
### **🌟 using nyashstd - 完全実装済み**
|
||||
|
||||
**基本構文:**
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
// ✅ 実際に動作確認済みの標準ライブラリ機能
|
||||
local result = string.create("Hello World") // → "Hello World"
|
||||
local upper = string.upper(result) // → "HELLO WORLD"
|
||||
local number = integer.create(42) // → 42
|
||||
local flag = bool.create(true) // → true
|
||||
local arr = array.create() // → []
|
||||
console.log("✅ using nyashstd test completed!") // ✅ 出力成功
|
||||
```
|
||||
|
||||
### **🎯 実装済み名前空間モジュール:**
|
||||
|
||||
- **string.*** - 文字列操作
|
||||
```nyash
|
||||
string.create("text") // 文字列Box作成
|
||||
string.upper("hello") // "HELLO" - 大文字変換
|
||||
string.lower("WORLD") // "world" - 小文字変換
|
||||
```
|
||||
|
||||
- **integer.*** - 整数操作
|
||||
```nyash
|
||||
integer.create(42) // 整数Box作成
|
||||
// 将来: integer.add(), integer.multiply() 等
|
||||
```
|
||||
|
||||
- **bool.*** - 真偽値操作
|
||||
```nyash
|
||||
bool.create(true) // 真偽値Box作成
|
||||
// 将来: bool.and(), bool.or(), bool.not() 等
|
||||
```
|
||||
|
||||
- **array.*** - 配列操作
|
||||
```nyash
|
||||
array.create() // 空配列Box作成
|
||||
// 将来: array.push(), array.length() 等
|
||||
```
|
||||
|
||||
- **console.*** - コンソール出力
|
||||
```nyash
|
||||
console.log("message") // コンソール出力
|
||||
// 将来: console.error(), console.debug() 等
|
||||
```
|
||||
|
||||
### **⚡ 自動リテラル変換との連携**
|
||||
|
||||
using nyashstdと自動リテラル変換を組み合わせると、極めてシンプルなコードが書けます:
|
||||
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
// 🌟 革命的シンプルさ!
|
||||
local name = "Nyash" // 自動StringBox変換
|
||||
local year = 2025 // 自動IntegerBox変換
|
||||
local upper = string.upper(name) // nyashstd + 自動変換連携
|
||||
console.log("🚀 " + upper + " " + year.toString() + " Ready!")
|
||||
// 出力: "🚀 NYASH 2025 Ready!" ✅
|
||||
```
|
||||
|
||||
### **📋 名前空間の特徴:**
|
||||
- **✅ Phase 9.75e完了**: `nyashstd`完全実装・動作確認済み
|
||||
- **IDE補完対応**: `string.`で標準機能の補完が可能(将来)
|
||||
- **明示的インポート**: プレリュード(自動インポート)よりIDE補完に適した設計
|
||||
- **拡張可能**: 将来的にユーザー定義名前空間もサポート予定
|
||||
|
||||
## 4. 構文クイックリファレンス
|
||||
|
||||
### **🎯 現代的Nyash構文(Phase 9.75h対応)**
|
||||
|
||||
- **厳格な変数宣言:** すべての変数は使用前に宣言が必要です。
|
||||
```nyash
|
||||
// 🌟 自動リテラル変換 + 宣言
|
||||
local text = "Hello" // 自動StringBox変換 + ローカル宣言
|
||||
local count = 42 // 自動IntegerBox変換 + ローカル宣言
|
||||
local flag = true // 自動BoolBox変換 + ローカル宣言
|
||||
|
||||
// Box内フィールドアクセス
|
||||
me.field = "value" // 現在のBoxインスタンスのフィールド
|
||||
|
||||
// 静的関数内での所有権移転
|
||||
outbox product = new Item() // 所有権が呼び出し元に移転
|
||||
```
|
||||
|
||||
- **統一されたループ:** ループ構文は一種類のみです。
|
||||
```nyash
|
||||
loop(condition) {
|
||||
// 条件がtrueの間ループ
|
||||
}
|
||||
```
|
||||
|
||||
- **プログラムのエントリーポイント:** 実行は`static box Main`の`main`メソッドから開始されます。
|
||||
```nyash
|
||||
using nyashstd // 標準ライブラリインポート
|
||||
|
||||
static box Main {
|
||||
init { console } // フィールド宣言
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
// 🌟 現代的Nyash書法
|
||||
local message = "Hello Nyash 2025!" // 自動変換
|
||||
console.log(message) // 標準ライブラリ使用
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **🎉 実用的なコード例(最新機能活用)**
|
||||
|
||||
```nyash
|
||||
using nyashstd
|
||||
|
||||
static box Main {
|
||||
init { console }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
// 🌟 すべて自動変換 + 標準ライブラリ
|
||||
local name = "Nyash" // 自動StringBox
|
||||
local version = 2025 // 自動IntegerBox
|
||||
local isStable = true // 自動BoolBox
|
||||
local pi = 3.14159 // 自動FloatBox
|
||||
|
||||
// string標準ライブラリ活用
|
||||
local upper = string.upper(name)
|
||||
|
||||
// コンソール出力
|
||||
console.log("🚀 " + upper + " " + version.toString() + " Ready!")
|
||||
console.log("円周率: " + pi.toString())
|
||||
console.log("安定版: " + isStable.toString())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 演算子
|
||||
|
||||
- **論理演算子:** `and`, `or`, `not`
|
||||
- **算術演算子:** `+`, `-`, `*`, `/` (ゼロ除算をハンドルします)
|
||||
- **比較演算子:** `==`, `!=`, `<`, `>`, `<=`, `>=`
|
||||
|
||||
## 5. 主要なビルトインBox(実装済み)
|
||||
|
||||
- **基本型**
|
||||
- **`StringBox`**: 文字列操作
|
||||
- **`IntegerBox`**: 整数値
|
||||
- **`FloatBox`**: 浮動小数点数(Phase 9.75h追加)
|
||||
- **`BoolBox`**: 真偽値
|
||||
- **`NullBox`**: null値
|
||||
|
||||
- **計算・データ処理系**
|
||||
- **`MathBox`**: 数学関数(sin, cos, sqrt等)
|
||||
- **`RandomBox`**: 乱数生成
|
||||
- **`TimeBox`**: 時間・日付操作
|
||||
- **`ArrayBox`**: 配列操作
|
||||
- **`MapBox`**: 連想配列(辞書)操作
|
||||
|
||||
- **I/O・デバッグ系**
|
||||
- **`ConsoleBox`**: 基本的なI/O (例: `log()`)
|
||||
- **`DebugBox`**: イントロスペクション/デバッグ (例: `memoryReport()`)
|
||||
- **`SoundBox`**: 音声出力
|
||||
|
||||
- **GUI・Web系(環境依存)**
|
||||
- **`EguiBox`**: GUI(メインスレッド制約など)
|
||||
- **`WebDisplayBox`**: Web表示
|
||||
- **`WebConsoleBox`**: Webコンソール
|
||||
- **`WebCanvasBox`**: Web Canvas操作
|
||||
|
||||
- **通信・ネットワーク系**
|
||||
- **`P2PBox`**: P2P通信
|
||||
- **`SimpleIntentBox`**: 簡単なインテント通信
|
||||
- **`SocketBox`**: TCP/IPソケット通信(Phase 9.75i追加)
|
||||
- **`BufferBox`**: バイナリバッファ操作(Phase 9.75i追加)
|
||||
|
||||
**注意**: using nyashstdで標準ライブラリ経由でのアクセスも可能です。
|
||||
|
||||
## 6. データ構造 (Data Structures)
|
||||
|
||||
現行バージョンでは配列/マップのリテラル構文(`[]`, `{}`)は未実装です(将来計画)。
|
||||
利用時はビルトインBoxを用います。
|
||||
|
||||
- **配列 (ArrayBox):**
|
||||
```nyash
|
||||
local a = new ArrayBox()
|
||||
a.push(1)
|
||||
a.push(2)
|
||||
a.push(3)
|
||||
// 取得
|
||||
local first = a.get(0)
|
||||
// サイズ(実装に依存)
|
||||
// 例: a.length() または length はAPIに従って利用
|
||||
```
|
||||
|
||||
- **マップ (MapBox):**
|
||||
```nyash
|
||||
local m = new MapBox()
|
||||
m.set("name", "Alice")
|
||||
m.set("age", 30)
|
||||
local name = m.get("name")
|
||||
```
|
||||
|
||||
## 7. エラーハンドリング (Error Handling)
|
||||
|
||||
実行時エラーによってプログラムがクラッシュするのを防ぐために、`try...catch`ブロックを使用します。
|
||||
|
||||
- **構文:**
|
||||
```nyash
|
||||
try {
|
||||
// エラーが発生する可能性のあるコード
|
||||
local result = 10 / 0
|
||||
} catch {
|
||||
// エラーが発生した場合に実行されるコード
|
||||
print("エラーが発生しましたが、プログラムは続行します。")
|
||||
}
|
||||
```
|
||||
|
||||
- **finally/throw の補足:**
|
||||
```nyash
|
||||
try {
|
||||
if (x < 0) { throw "negative" }
|
||||
} catch {
|
||||
print("error")
|
||||
} finally {
|
||||
print("always")
|
||||
}
|
||||
```
|
||||
|
||||
## 8. メモリ管理と弱参照 (Memory Management & Weak References)
|
||||
|
||||
- **`weak` キーワード:** `init`ブロック内でフィールドを`weak`として宣言することで、弱参照を作成します。これは主に循環参照を防ぐために使用されます。
|
||||
- 弱参照はオブジェクトの所有権を持ちません。
|
||||
- 参照先のオブジェクトが解放されると、弱参照フィールドは自動的に`null`になります。
|
||||
```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への強参照を持つ
|
||||
// この場合、node1とnode2が互いを所有しないため、安全に解放される
|
||||
```
|
||||
|
||||
不変条件(重要)
|
||||
- weak フィールドに対して `fini()` を直接呼ぶことはできません(エラーになります)。
|
||||
- インスタンスで `fini()` 呼び出し後は、そのオブジェクトの使用はすべて禁止です(アクセス時にエラー)。
|
||||
- `fini()` のカスケードは init 宣言順の「逆順」で実行され、weak フィールドはスキップされます。
|
||||
|
||||
## 9. 非同期処理 (Asynchronous Processing)
|
||||
|
||||
- **`nowait` 文:** 式を別スレッドで非同期実行し、その結果を表す `FutureBox` を変数に格納します。
|
||||
- 構文: `nowait future = expression`
|
||||
- 挙動: 内部でスレッドを生成し、完了時に `future.set_result(...)` が呼ばれます。
|
||||
|
||||
- **`await` 式:** `FutureBox` の完了を待機し、結果を取り出します。
|
||||
- 構文: `result = await future`
|
||||
- 実装: `FutureBox.wait_and_get()` を通じて結果を返します。
|
||||
|
||||
使用例:
|
||||
```nyash
|
||||
// 非同期に3つの処理を開始
|
||||
nowait f1 = heavyComputation(5000)
|
||||
nowait f2 = heavyComputation(3000)
|
||||
nowait f3 = heavyComputation(4000)
|
||||
|
||||
// 結果を待機
|
||||
r1 = await f1
|
||||
r2 = await f2
|
||||
r3 = await f3
|
||||
```
|
||||
|
||||
備考(現実装の特性)
|
||||
- 実装はスレッドベースの簡易非同期(イベントループ無し)。
|
||||
- FutureBox は簡易 busy-wait を用います(将来 condvar 等で改善予定)。
|
||||
- 例外は `ErrorBox` として `FutureBox` に格納されます(`await` 側で結果を取り出す設計)。
|
||||
|
||||
## 10. 静的Box/関数と所有権移転(outbox)
|
||||
|
||||
- **静的エントリーポイント:**
|
||||
```nyash
|
||||
static box Main {
|
||||
main() {
|
||||
print("Hello Nyash")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **静的boxメソッド呼び出し(Phase 9.75i実装):**
|
||||
```nyash
|
||||
static box ProxyServer {
|
||||
static port = 8080 // 静的フィールド
|
||||
|
||||
static main() {
|
||||
print("Starting proxy on port " + ProxyServer.port.toString())
|
||||
}
|
||||
}
|
||||
|
||||
// 呼び出し
|
||||
ProxyServer.main() // ✅ 静的メソッド直接呼び出し可能
|
||||
```
|
||||
|
||||
- **静的関数の定義/呼び出し:**
|
||||
```nyash
|
||||
static function Math.min(a, b) {
|
||||
if (a < b) { return a } else { return b }
|
||||
}
|
||||
local m = Math.min(1, 2)
|
||||
```
|
||||
|
||||
- **所有権移転(outbox, static関数内のみ):**
|
||||
```nyash
|
||||
static function Factory.create() {
|
||||
outbox product
|
||||
product = new Item()
|
||||
return product
|
||||
}
|
||||
```
|
||||
|
||||
## 11. クイック実行コマンド
|
||||
|
||||
```bash
|
||||
# ビルド & 基本実行
|
||||
cargo build --release -j32
|
||||
./target/release/nyash program.nyash
|
||||
|
||||
# プラグイン診断
|
||||
./tools/plugin-tester/target/release/plugin-tester check plugin.so
|
||||
|
||||
# 性能比較
|
||||
./target/release/nyash --benchmark --iterations 100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**最終更新: 2025年8月19日** - **🚀 Phase 9.75g-0 BID-FFI完全実装!**
|
||||
|
||||
### 🎉 **最新の革命的成果**
|
||||
- 🔌 **BID-FFIプラグインシステム**: プラグインによるBox拡張完全実装
|
||||
- ✨ **型情報管理システム**: nyash.tomlベースの自動型変換
|
||||
- 🛡️ **メモリ安全性確保**: HostVtable生存期間問題解決、valgrind検証済み
|
||||
- 🧪 **plugin-tester**: 汎用プラグイン診断ツール完成
|
||||
|
||||
### 🌟 **過去の革命的改善**
|
||||
- **Phase 9.75h**: 自動リテラル変換、using nyashstd、birth構文
|
||||
- **Phase 9.75i**: 静的boxメソッド、SocketBox、BufferBox
|
||||
- **Phase 9.75j**: 警告削減(106個→0個)
|
||||
|
||||
### 🚀 **Nyashの実用的価値**
|
||||
**Everything is Box哲学 + プラグイン拡張 + 実用的性能** の革新的言語!
|
||||
|
||||
- **🔌 拡張性**: プラグインで無限にBox機能拡張
|
||||
- **🛡️ 安全性**: メモリ安全性とvalgrind検証済み
|
||||
- **⚡ 性能**: VM 20倍、WASM 13倍、将来AOT 1000倍高速化
|
||||
- **📚 使いやすさ**: 自動変換、標準ライブラリ、直感的構文
|
||||
|
||||
**詳しいdocs**: [完全リファレンス](説明書/reference/) | [開発ガイド](../CLAUDE.md) | [Phase計画](予定/native-plan/copilot_issues.txt)
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
# Plugin Migration Guide v2 Enhancement Summary
|
||||
|
||||
## What was accomplished
|
||||
|
||||
This task involved enhancing the existing `docs/plugin-migration-request.md` with comprehensive implementation guidance based on the issue requirements.
|
||||
|
||||
## Key improvements made:
|
||||
|
||||
### 1. **Comprehensive nyash.toml explanation**
|
||||
- Added detailed explanation of the `from`/`to` type conversion system
|
||||
- Explained TLV (Type-Length-Value) encoding with specific tag mappings
|
||||
- Provided clear examples using FileBox as reference
|
||||
|
||||
### 2. **Detailed implementation examples**
|
||||
- Added complete Rust code examples for TLV parsing
|
||||
- Showed real HttpClientBox plugin implementation patterns
|
||||
- Included proper error handling and memory management examples
|
||||
|
||||
### 3. **Structured migration priorities**
|
||||
- **Phase 1**: Network boxes (HttpClientBox, SocketBox) - highest priority
|
||||
- **Phase 2**: GUI boxes (EguiBox, Canvas) - platform dependent
|
||||
- **Phase 3**: Special purpose boxes (TimerBox, QRBox) - independent
|
||||
|
||||
### 4. **Testing and validation guidelines**
|
||||
- Complete testing workflow with plugin-tester
|
||||
- Real Nyash code examples for validation
|
||||
- Troubleshooting guidance for common mistakes
|
||||
|
||||
### 5. **Reference implementation guidance**
|
||||
- FileBox plugin as the gold standard example
|
||||
- Specific file paths for all reference materials
|
||||
- Success tips and common pitfalls
|
||||
|
||||
## Document statistics:
|
||||
- **Length**: 368 lines (vs ~200 lines originally)
|
||||
- **Code examples**: 16 code blocks with real implementation patterns
|
||||
- **Comprehensive coverage**: TLV, nyash.toml, FFI, testing, and reference materials
|
||||
|
||||
## Validation:
|
||||
- All key sections verified to be present
|
||||
- Code examples cover the full implementation pipeline
|
||||
- References to FileBox plugin success story maintained
|
||||
- HttpClientBox positioned as Phase 1 priority target
|
||||
|
||||
The guide now serves as a complete reference for migrating any builtin Box to a plugin, with FileBox as the proven template and HttpClientBox as the next target.
|
||||
249
docs/reference/architecture/plugin-migration-guide-v2.md
Normal file
249
docs/reference/architecture/plugin-migration-guide-v2.md
Normal file
@ -0,0 +1,249 @@
|
||||
# 📦 Nyash ビルトインBox → プラグイン化移行ガイド v2
|
||||
|
||||
## 🎯 概要
|
||||
NyashのビルトインBoxをプラグイン化し、コアを軽量化します。
|
||||
FileBoxプラグインの成功例を詳しく解説しながら、移行方法を説明します。
|
||||
|
||||
## 🔑 重要な概念:nyash.tomlの型定義システム
|
||||
|
||||
### 型変換の仕組み
|
||||
nyash.tomlでは、Nyash側とプラグイン側の型変換を明示的に定義します:
|
||||
|
||||
```toml
|
||||
# FileBoxの例
|
||||
[plugins.FileBox.methods]
|
||||
# writeメソッド:Nyashのstringをプラグインではbytesとして扱う
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# openメソッド:2つのstring引数(型変換なし)
|
||||
open = { args = [
|
||||
{ name = "path", from = "string", to = "string" },
|
||||
{ name = "mode", from = "string", to = "string" }
|
||||
] }
|
||||
```
|
||||
|
||||
### from/toの意味
|
||||
- **from**: Nyash側の型(ユーザーが渡す型)
|
||||
- **to**: プラグイン側で受け取る型(TLVエンコーディング)
|
||||
|
||||
### TLVタグとの対応
|
||||
プラグインはTLV(Type-Length-Value)形式でデータを受け取ります:
|
||||
- `to = "i32"` → TLV tag=2(32ビット整数)
|
||||
- `to = "string"` → TLV tag=6(UTF-8文字列)
|
||||
- `to = "bytes"` → TLV tag=7(バイト配列)
|
||||
|
||||
## 📋 移行対象Box一覧(優先順位順)
|
||||
|
||||
### 🌐 Phase 1: ネットワーク系(最優先・最も簡単)
|
||||
既にスタブ実装があり、reqwest依存を追加するだけで完成します。
|
||||
|
||||
#### HttpClientBox
|
||||
```toml
|
||||
[plugins.HttpClientBox.methods]
|
||||
# シンプルなGETリクエスト
|
||||
get = {
|
||||
args = [{ from = "string", to = "string" }], # URL
|
||||
returns = "string" # レスポンスボディ
|
||||
}
|
||||
|
||||
# POSTリクエスト(ボディ付き)
|
||||
post = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "string", to = "bytes" } # ボディ(バイナリ対応)
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# 詳細なリクエスト(ヘッダー等を含む)
|
||||
request = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # メソッド(GET/POST等)
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "map", to = "map" } # オプション(headers, timeout等)
|
||||
],
|
||||
returns = "map" # { status: i32, body: string, headers: map }
|
||||
}
|
||||
```
|
||||
|
||||
### 🖼️ Phase 2: GUI系(プラットフォーム依存)
|
||||
EguiBoxは既にfeature分離されているので参考になります。
|
||||
|
||||
### 🎵 Phase 3: 特殊用途系(独立性高い)
|
||||
TimerBox、QRBox等は単機能で実装しやすいです。
|
||||
|
||||
## 🔧 実装ガイド:FileBoxを例に
|
||||
|
||||
### 1. プラグイン側での型受け取り例
|
||||
|
||||
```rust
|
||||
// nyash.toml: write = { args = [{ from = "string", to = "bytes" }] }
|
||||
METHOD_WRITE => {
|
||||
// TLVでbytesとして受け取る
|
||||
let data = tlv_parse_bytes(args)?; // Vec<u8>として取得
|
||||
|
||||
// ファイルに書き込み
|
||||
match file.write(&data) {
|
||||
Ok(n) => {
|
||||
file.flush()?; // 重要:フラッシュを忘れずに!
|
||||
// 書き込んだバイト数を返す(TLV i32)
|
||||
write_tlv_i32(n as i32, result, result_len)
|
||||
}
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 複数引数の解析例
|
||||
|
||||
```rust
|
||||
// nyash.toml: open = { args = [{ from = "string", to = "string" }, { from = "string", to = "string" }] }
|
||||
METHOD_OPEN => {
|
||||
// 2つのstring引数を解析
|
||||
let (path, mode) = tlv_parse_two_strings(args)?;
|
||||
|
||||
// ファイルを開く
|
||||
let file = match mode.as_str() {
|
||||
"r" => File::open(&path)?,
|
||||
"w" => File::create(&path)?,
|
||||
"a" => OpenOptions::new().append(true).open(&path)?,
|
||||
_ => return NYB_E_INVALID_ARGS
|
||||
};
|
||||
|
||||
// 成功時はVoid(空)を返す
|
||||
write_tlv_void(result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 引数なしメソッドの例
|
||||
|
||||
```rust
|
||||
// nyash.toml: read = { args = [] }
|
||||
METHOD_READ => {
|
||||
// 引数なし - ファイル全体を読む
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
let mut buf = Vec::new();
|
||||
file.read_to_end(&mut buf)?;
|
||||
|
||||
// bytesとして返す
|
||||
write_tlv_bytes(&buf, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 HttpClientBox実装の具体例
|
||||
|
||||
```rust
|
||||
// HttpClientBoxプラグインの実装イメージ
|
||||
use reqwest::blocking::Client;
|
||||
|
||||
METHOD_GET => {
|
||||
// URLを解析
|
||||
let url = tlv_parse_string(args)?;
|
||||
|
||||
// HTTPリクエスト実行
|
||||
let client = Client::new();
|
||||
let response = client.get(&url).send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
// 文字列として返す
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
|
||||
METHOD_POST => {
|
||||
// URL と ボディを解析
|
||||
let (url, body_bytes) = tlv_parse_string_and_bytes(args)?;
|
||||
|
||||
// POSTリクエスト
|
||||
let client = Client::new();
|
||||
let response = client.post(&url)
|
||||
.body(body_bytes)
|
||||
.send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 実装のコツとよくある間違い
|
||||
|
||||
### ✅ 正しいnyash.toml
|
||||
```toml
|
||||
# 引数の型変換を明示
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# 戻り値の型も指定可能
|
||||
exists = { args = [], returns = "bool" }
|
||||
```
|
||||
|
||||
### ❌ よくある間違い
|
||||
```toml
|
||||
# 間違い:型情報がない
|
||||
write = { args = ["string"] } # ❌ from/toが必要
|
||||
|
||||
# 間違い:不要なフィールド
|
||||
get = { args = [{ type = "string" }] } # ❌ typeではなくfrom/to
|
||||
```
|
||||
|
||||
### メモリ管理の注意点
|
||||
1. 文字列は必ずCString/CStr経由で変換
|
||||
2. プラグイン側でallocしたメモリはプラグイン側でfree
|
||||
3. ホスト側のVtableを使ってログ出力
|
||||
|
||||
### エラーハンドリング
|
||||
```rust
|
||||
// パニックをFFI境界で止める
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
// 実際の処理
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(val) => val,
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 テスト方法
|
||||
|
||||
### 1. プラグインビルド
|
||||
```bash
|
||||
cd plugins/nyash-http-plugin
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### 2. plugin-testerで診断
|
||||
```bash
|
||||
cd ../../tools/plugin-tester
|
||||
./target/release/plugin-tester ../../plugins/nyash-http-plugin/target/release/libnyash_http_plugin.so
|
||||
|
||||
# 期待される出力:
|
||||
# Plugin Information:
|
||||
# Box Type: HttpClientBox (ID: 20)
|
||||
# Methods: 5
|
||||
# - birth [ID: 0] (constructor)
|
||||
# - get, post, put, delete
|
||||
# - fini [ID: 4294967295] (destructor)
|
||||
```
|
||||
|
||||
### 3. Nyashで実行
|
||||
```nyash
|
||||
// test_http.nyash
|
||||
local http = new HttpClientBox()
|
||||
local response = http.get("https://api.example.com/data")
|
||||
print(response)
|
||||
```
|
||||
|
||||
## 📚 参考資料
|
||||
- **FileBoxプラグイン完全実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
|
||||
- **TLVエンコーディング仕様**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
|
||||
- **nyash.toml設定例**: プロジェクトルートの`nyash.toml`
|
||||
|
||||
## 🎯 成功の秘訣
|
||||
1. **FileBoxを完全に理解してから始める** - コピペベースで改造
|
||||
2. **nyash.tomlの型定義を正確に** - from/toを明示
|
||||
3. **TLVの理解** - tag=6(string), tag=7(bytes)の違い
|
||||
4. **plugin-testerで早期検証** - 問題を早期発見
|
||||
|
||||
---
|
||||
|
||||
質問があれば、FileBoxの実装を参考にしてください。
|
||||
すべての答えがそこにあります!
|
||||
369
docs/reference/architecture/plugin-migration-request.md
Normal file
369
docs/reference/architecture/plugin-migration-request.md
Normal file
@ -0,0 +1,369 @@
|
||||
# 📦 Nyash ビルトインBox → プラグイン化移行ガイド v2
|
||||
|
||||
## 🎯 概要
|
||||
NyashのビルトインBoxをプラグイン化し、コアを軽量化します。
|
||||
FileBoxプラグインの成功例を詳しく解説しながら、移行方法を説明します。
|
||||
|
||||
## 🔑 重要な概念:nyash.tomlの型定義システム
|
||||
|
||||
### 型変換の仕組み
|
||||
nyash.tomlでは、Nyash側とプラグイン側の型変換を明示的に定義します:
|
||||
|
||||
```toml
|
||||
# FileBoxの例
|
||||
[plugins.FileBox.methods]
|
||||
# writeメソッド:Nyashのstringをプラグインではbytesとして扱う
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# openメソッド:2つのstring引数(型変換なし)
|
||||
open = { args = [
|
||||
{ name = "path", from = "string", to = "string" },
|
||||
{ name = "mode", from = "string", to = "string" }
|
||||
] }
|
||||
```
|
||||
|
||||
### from/toの意味
|
||||
- **from**: Nyash側の型(ユーザーが渡す型)
|
||||
- **to**: プラグイン側で受け取る型(TLVエンコーディング)
|
||||
|
||||
### TLVタグとの対応
|
||||
プラグインはTLV(Type-Length-Value)形式でデータを受け取ります:
|
||||
- `to = "i32"` → TLV tag=2(32ビット整数)
|
||||
- `to = "string"` → TLV tag=6(UTF-8文字列)
|
||||
- `to = "bytes"` → TLV tag=7(バイト配列)
|
||||
|
||||
## 📋 移行対象Box一覧(優先順位順)
|
||||
|
||||
### 🌐 Phase 1: ネットワーク系(最優先・最も簡単)
|
||||
既にスタブ実装があり、reqwest依存を追加するだけで完成します。
|
||||
|
||||
#### HttpClientBox
|
||||
```toml
|
||||
[plugins.HttpClientBox.methods]
|
||||
# シンプルなGETリクエスト
|
||||
get = {
|
||||
args = [{ from = "string", to = "string" }], # URL
|
||||
returns = "string" # レスポンスボディ
|
||||
}
|
||||
|
||||
# POSTリクエスト(ボディ付き)
|
||||
post = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "string", to = "bytes" } # ボディ(バイナリ対応)
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# 詳細なリクエスト(ヘッダー等を含む)
|
||||
request = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # メソッド(GET/POST等)
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "map", to = "map" } # オプション(headers, timeout等)
|
||||
],
|
||||
returns = "map" # { status: i32, body: string, headers: map }
|
||||
}
|
||||
```
|
||||
|
||||
### 🖼️ Phase 2: GUI系(プラットフォーム依存)
|
||||
EguiBoxは既にfeature分離されているので参考になります。
|
||||
|
||||
### 🎵 Phase 3: 特殊用途系(独立性高い)
|
||||
TimerBox、QRBox等は単機能で実装しやすいです。
|
||||
|
||||
## 🔧 実装ガイドライン
|
||||
|
||||
### 1. 参考にするファイル
|
||||
- **成功例**: `plugins/nyash-filebox-plugin/` - 動作確認済みのFileBoxプラグイン
|
||||
- **設定例**: `nyash.toml` - 型情報定義の書き方
|
||||
- **テスト**: `tools/plugin-tester/` - プラグイン診断ツール
|
||||
|
||||
### 2. 各プラグインの構成
|
||||
```
|
||||
plugins/nyash-xxx-plugin/
|
||||
├── Cargo.toml # 依存関係(例: reqwest for HTTP)
|
||||
├── src/
|
||||
│ └── lib.rs # FFI実装
|
||||
├── nyash.toml # 型情報定義
|
||||
└── README.md # 使用方法
|
||||
```
|
||||
|
||||
### 3. nyash.toml記述例(HttpClientBoxの場合)
|
||||
```toml
|
||||
[plugins.HttpClientBox.methods]
|
||||
# GETリクエスト
|
||||
get = {
|
||||
args = [{ name = "url", from = "string", to = "string" }],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# POSTリクエスト
|
||||
post = {
|
||||
args = [
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "body", from = "string", to = "string" }
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# ヘッダー付きリクエスト
|
||||
request = {
|
||||
args = [
|
||||
{ name = "method", from = "string", to = "string" },
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "options", from = "map", to = "map" }
|
||||
],
|
||||
returns = "map" # { status, body, headers }
|
||||
}
|
||||
|
||||
# DELETE リクエスト
|
||||
delete = {
|
||||
args = [{ name = "url", from = "string", to = "string" }],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# PUT リクエスト
|
||||
put = {
|
||||
args = [
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "body", from = "string", to = "string" }
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. テスト方法
|
||||
```bash
|
||||
# ビルド
|
||||
cd plugins/nyash-xxx-plugin
|
||||
cargo build --release
|
||||
|
||||
# plugin-testerで診断
|
||||
cd ../../tools/plugin-tester
|
||||
./target/release/plugin-tester ../../plugins/nyash-xxx-plugin/target/release/libnyash_xxx_plugin.so
|
||||
|
||||
# Nyashで実行テスト
|
||||
./target/release/nyash test_xxx.nyash
|
||||
```
|
||||
|
||||
## 📝 特記事項
|
||||
|
||||
### HttpBox系
|
||||
- 現在スタブ実装なので移行しやすい
|
||||
- reqwest依存を復活させる
|
||||
- 非同期処理の考慮が必要
|
||||
|
||||
### EguiBox
|
||||
- 既にfeature分離されているので参考になる
|
||||
- メインスレッド制約に注意
|
||||
|
||||
### AudioBox/SoundBox
|
||||
- プラットフォーム依存性が高い
|
||||
- Web/Desktop両対応を検討
|
||||
|
||||
### 依存関係の管理
|
||||
- 各プラグインは独立したCargo.tomlを持つ
|
||||
- ビルド時間短縮のため最小限の依存にする
|
||||
|
||||
## 💡 実装の重要ポイント
|
||||
|
||||
### FFI境界での注意事項
|
||||
1. **メモリ管理**:
|
||||
- Rustの所有権とCのメモリ管理の違いに注意
|
||||
- 文字列は必ずCString/CStr経由で変換
|
||||
|
||||
2. **エラーハンドリング**:
|
||||
- パニックをFFI境界で止める(catch_unwind使用)
|
||||
- エラーコードで通信(0=成功, 負値=エラー)
|
||||
|
||||
3. **型変換パターン** (FileBoxプラグインより):
|
||||
```rust
|
||||
// Nyash文字列 → Rust文字列
|
||||
let path = get_string_arg(&args[0], 0)?;
|
||||
|
||||
// Rust文字列 → Nyash文字列
|
||||
encode_string_result(&contents, result, result_len)
|
||||
```
|
||||
|
||||
### 参考ファイルの具体的パス
|
||||
- **FileBoxプラグイン実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
|
||||
- **FFI仕様書**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
|
||||
- **プラグインシステム説明**: `docs/説明書/reference/plugin-system/plugin-system.md`
|
||||
- **BID-FFI型変換** (参考): `src/bid-converter-copilot/tlv.rs`
|
||||
|
||||
## 🔧 実装ガイド:FileBoxを例に
|
||||
|
||||
### 1. プラグイン側での型受け取り例
|
||||
|
||||
```rust
|
||||
// nyash.toml: write = { args = [{ from = "string", to = "bytes" }] }
|
||||
METHOD_WRITE => {
|
||||
// TLVでbytesとして受け取る
|
||||
let data = tlv_parse_bytes(args)?; // Vec<u8>として取得
|
||||
|
||||
// ファイルに書き込み
|
||||
match file.write(&data) {
|
||||
Ok(n) => {
|
||||
file.flush()?; // 重要:フラッシュを忘れずに!
|
||||
// 書き込んだバイト数を返す(TLV i32)
|
||||
write_tlv_i32(n as i32, result, result_len)
|
||||
}
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 複数引数の解析例
|
||||
|
||||
```rust
|
||||
// nyash.toml: open = { args = [{ from = "string", to = "string" }, { from = "string", to = "string" }] }
|
||||
METHOD_OPEN => {
|
||||
// 2つのstring引数を解析
|
||||
let (path, mode) = tlv_parse_two_strings(args)?;
|
||||
|
||||
// ファイルを開く
|
||||
let file = match mode.as_str() {
|
||||
"r" => File::open(&path)?,
|
||||
"w" => File::create(&path)?,
|
||||
"a" => OpenOptions::new().append(true).open(&path)?,
|
||||
_ => return NYB_E_INVALID_ARGS
|
||||
};
|
||||
|
||||
// 成功時はVoid(空)を返す
|
||||
write_tlv_void(result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 引数なしメソッドの例
|
||||
|
||||
```rust
|
||||
// nyash.toml: read = { args = [] }
|
||||
METHOD_READ => {
|
||||
// 引数なし - ファイル全体を読む
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
let mut buf = Vec::new();
|
||||
file.read_to_end(&mut buf)?;
|
||||
|
||||
// bytesとして返す
|
||||
write_tlv_bytes(&buf, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 HttpClientBox実装の具体例
|
||||
|
||||
```rust
|
||||
// HttpClientBoxプラグインの実装イメージ
|
||||
use reqwest::blocking::Client;
|
||||
|
||||
METHOD_GET => {
|
||||
// URLを解析
|
||||
let url = tlv_parse_string(args)?;
|
||||
|
||||
// HTTPリクエスト実行
|
||||
let client = Client::new();
|
||||
let response = client.get(&url).send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
// 文字列として返す
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
|
||||
METHOD_POST => {
|
||||
// URL と ボディを解析
|
||||
let (url, body_bytes) = tlv_parse_string_and_bytes(args)?;
|
||||
|
||||
// POSTリクエスト
|
||||
let client = Client::new();
|
||||
let response = client.post(&url)
|
||||
.body(body_bytes)
|
||||
.send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 実装のコツとよくある間違い
|
||||
|
||||
### ✅ 正しいnyash.toml
|
||||
```toml
|
||||
# 引数の型変換を明示
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# 戻り値の型も指定可能
|
||||
exists = { args = [], returns = "bool" }
|
||||
```
|
||||
|
||||
### ❌ よくある間違い
|
||||
```toml
|
||||
# 間違い:型情報がない
|
||||
write = { args = ["string"] } # ❌ from/toが必要
|
||||
|
||||
# 間違い:不要なフィールド
|
||||
get = { args = [{ type = "string" }] } # ❌ typeではなくfrom/to
|
||||
```
|
||||
|
||||
### メモリ管理の注意点
|
||||
1. 文字列は必ずCString/CStr経由で変換
|
||||
2. プラグイン側でallocしたメモリはプラグイン側でfree
|
||||
3. ホスト側のVtableを使ってログ出力
|
||||
|
||||
### エラーハンドリング
|
||||
```rust
|
||||
// パニックをFFI境界で止める
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
// 実際の処理
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(val) => val,
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 テスト方法
|
||||
|
||||
### 1. プラグインビルド
|
||||
```bash
|
||||
cd plugins/nyash-http-plugin
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### 2. plugin-testerで診断
|
||||
```bash
|
||||
cd ../../tools/plugin-tester
|
||||
./target/release/plugin-tester ../../plugins/nyash-http-plugin/target/release/libnyash_http_plugin.so
|
||||
|
||||
# 期待される出力:
|
||||
# Plugin Information:
|
||||
# Box Type: HttpClientBox (ID: 20)
|
||||
# Methods: 5
|
||||
# - birth [ID: 0] (constructor)
|
||||
# - get, post, put, delete
|
||||
# - fini [ID: 4294967295] (destructor)
|
||||
```
|
||||
|
||||
### 3. Nyashで実行
|
||||
```nyash
|
||||
// test_http.nyash
|
||||
local http = new HttpClientBox()
|
||||
local response = http.get("https://api.example.com/data")
|
||||
print(response)
|
||||
```
|
||||
|
||||
## 📚 参考資料
|
||||
- **FileBoxプラグイン完全実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
|
||||
- **TLVエンコーディング仕様**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
|
||||
- **nyash.toml設定例**: プロジェクトルートの`nyash.toml`
|
||||
|
||||
## 🎯 成功の秘訣
|
||||
1. **FileBoxを完全に理解してから始める** - コピペベースで改造
|
||||
2. **nyash.tomlの型定義を正確に** - from/toを明示
|
||||
3. **TLVの理解** - tag=6(string), tag=7(bytes)の違い
|
||||
4. **plugin-testerで早期検証** - 問題を早期発見
|
||||
|
||||
---
|
||||
|
||||
質問があれば、FileBoxの実装を参考にしてください。
|
||||
すべての答えがそこにあります!
|
||||
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)で検討。
|
||||
337
docs/reference/core-language/design-philosophy.md
Normal file
337
docs/reference/core-language/design-philosophy.md
Normal file
@ -0,0 +1,337 @@
|
||||
# 🌟 明示的デリゲーション革命:なぜNyashは世界初の完全明示デリゲーション言語になったのか
|
||||
|
||||
作成日: 2025年8月11日
|
||||
著者: Nyashプロジェクトチーム
|
||||
ステータス: 設計思想決定版
|
||||
|
||||
## 📜 はじめに:革命の始まり
|
||||
|
||||
2025年8月11日、Nyashプログラミング言語の開発において、言語設計史上最大級の発見がありました。それは、**暗黙のオーバーライド問題**の発見と、それを解決する**完全明示デリゲーション構文**の誕生です。
|
||||
|
||||
この文書は、なぜこの革命が必要だったのか、どのような思想の元に設計されたのかを詳しく解説します。
|
||||
|
||||
## 🚨 問題の発見:暗黙の悪魔
|
||||
|
||||
### HashMap::insert による意図しない上書き
|
||||
|
||||
Nyashの実装を詳しく調査した結果、恐ろしい問題が発見されました:
|
||||
|
||||
```rust
|
||||
// instance.rs - add_method関数
|
||||
pub fn add_method(&mut self, method_name: String, method_ast: ASTNode) {
|
||||
let mut new_methods = (*self.methods).clone();
|
||||
new_methods.insert(method_name, method_ast); // ← 暗黙の上書き!
|
||||
self.methods = Arc::new(new_methods);
|
||||
}
|
||||
```
|
||||
|
||||
この実装により、以下のような**暗黙のオーバーライド**が発生していました:
|
||||
|
||||
```nyash
|
||||
box Node {
|
||||
send(msg) { // 最初の定義
|
||||
print("Version 1")
|
||||
}
|
||||
|
||||
send(msg) { // 暗黙に上書きされる
|
||||
print("Version 2") // ← こちらだけが残る
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Nyash哲学との根本的矛盾
|
||||
|
||||
この問題は、Nyashの3つの核心哲学と完全に矛盾していました:
|
||||
|
||||
1. **明示性重視**: 「何が起きているかを隠さない」
|
||||
2. **Everything is Box**: 「統一された世界観」
|
||||
3. **初学者フレンドリー**: 「複雑な概念を分かりやすく表現」
|
||||
|
||||
暗黙のオーバーライドは、これらすべてを破壊する**言語設計上の致命的欠陥**だったのです。
|
||||
|
||||
## 💡 解決への道:3AI大会議
|
||||
|
||||
### AI専門家による徹底分析
|
||||
|
||||
この問題の解決策を求めて、言語設計の専門家であるGeminiとChatGPTに相談を行いました。結果は予想を上回る**圧倒的な支持**でした。
|
||||
|
||||
#### Gemini先生の評価
|
||||
> **「全面的に賛成します」**
|
||||
> **「極めて重要な一歩」**
|
||||
> **「Nyashのアイデンティティを確立する」**
|
||||
|
||||
#### ChatGPT先生の評価
|
||||
> **「強く整合する」**
|
||||
> **「安全性と読みやすさを大幅に向上」**
|
||||
> **「実装工数3-5日程度」**
|
||||
|
||||
### 専門的視点からの裏付け
|
||||
|
||||
両専門家から以下の重要な指摘がありました:
|
||||
|
||||
1. **哲学的整合性**: Nyashの明示性哲学と完全に合致
|
||||
2. **技術的優位性**: 他言語の問題(Python MRO、Java super等)を根本解決
|
||||
3. **学習効果**: 初学者にとってより理解しやすい設計
|
||||
4. **実装可能性**: 技術的に十分実現可能
|
||||
|
||||
## 🌟 革命的解決策:Override + From 統一構文
|
||||
|
||||
### 4つの統一原則
|
||||
|
||||
この問題を解決するため、以下の4つの統一原則を確立しました:
|
||||
|
||||
#### 1. 宣言の統一
|
||||
```nyash
|
||||
box Child from Parent // デリゲーション関係の明示
|
||||
```
|
||||
|
||||
#### 2. 置換の統一
|
||||
```nyash
|
||||
override methodName() // オーバーライドの明示宣言
|
||||
```
|
||||
|
||||
#### 3. 呼び出しの統一
|
||||
```nyash
|
||||
from Parent.methodName() // 親実装の明示呼び出し
|
||||
```
|
||||
|
||||
#### 4. 構築の統一
|
||||
```nyash
|
||||
from Parent.init() // コンストラクタも同じ構文
|
||||
```
|
||||
|
||||
### 完全な例
|
||||
|
||||
```nyash
|
||||
box MeshNode : P2PBox {
|
||||
init routing = RoutingTable()
|
||||
|
||||
constructor(nodeId, world) {
|
||||
from P2PBox.constructor(nodeId, world) // 統一構文
|
||||
me.routing = RoutingTable()
|
||||
}
|
||||
|
||||
override send(intent, data, target) { // 明示的置換
|
||||
me.routing.log(target)
|
||||
from P2PBox.send(intent, data, target) // 明示的呼び出し
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔥 革命的特徴
|
||||
|
||||
### 1. 完全な明示性
|
||||
|
||||
**従来の問題**:
|
||||
- 何がオーバーライドされているかわからない
|
||||
- 親のどのメソッドを呼んでいるかわからない
|
||||
- 実行順序が不明確
|
||||
|
||||
**Nyashの解決**:
|
||||
- `override` で置換を明示宣言
|
||||
- `from Parent.method()` で呼び出し先を完全明示
|
||||
- 上から下への直感的な実行順序
|
||||
|
||||
### 2. 曖昧性の完全排除
|
||||
|
||||
**多重デリゲーション時の曖昧性解消**:
|
||||
```nyash
|
||||
box SmartNode : P2PBox, Logger {
|
||||
override send(intent, data, target) {
|
||||
from Logger.debug("Sending: " + intent) // どのLoggerか明確
|
||||
from P2PBox.send(intent, data, target) // どのP2PBoxか明確
|
||||
}
|
||||
}
|
||||
|
||||
// 競合時は更に明示的に
|
||||
box ConflictNode from ParentA, ParentB {
|
||||
override ParentA.process(data) { // ParentAのprocessを置換
|
||||
from ParentA.process(data)
|
||||
}
|
||||
|
||||
override ParentB.process(data) { // ParentBのprocessを置換
|
||||
from ParentB.process(data)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 学習コストの最小化
|
||||
|
||||
**覚えるべきルール**:
|
||||
1. 親のメソッドを置換したい → `override`
|
||||
2. 親のメソッドを呼びたい → `from Parent.method()`
|
||||
3. 親のコンストラクタを呼びたい → `from Parent.init()`
|
||||
|
||||
たった3つのルールで、すべてのデリゲーション操作が表現できます。
|
||||
|
||||
## 🌍 他言語との比較:なぜNyashが優れているのか
|
||||
|
||||
### Python の問題
|
||||
```python
|
||||
# MRO(Method Resolution Order)地獄
|
||||
class C(A, B):
|
||||
def method(self):
|
||||
super().method() # どっちのmethod?
|
||||
```
|
||||
|
||||
**Nyash の解決**:
|
||||
```nyash
|
||||
box C : A, B {
|
||||
override method() {
|
||||
from A.method() // Aのmethodと明示
|
||||
from B.method() // Bのmethodと明示
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Java/C# の問題
|
||||
```java
|
||||
// どの親のmethodを呼んでいるかコードから不明
|
||||
@Override
|
||||
public void method() {
|
||||
super.method(); // 単一継承でも曖昧
|
||||
}
|
||||
```
|
||||
|
||||
**Nyash の解決**:
|
||||
```nyash
|
||||
override method() {
|
||||
from Parent.method() // どのParentか完全に明確
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript の問題
|
||||
```typescript
|
||||
// 暗黙のオーバーライドによる事故
|
||||
class Child extends Parent {
|
||||
method() { // うっかり同名メソッド → 意図しない上書き
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Nyash の解決**:
|
||||
```nyash
|
||||
// overrideなしで同名メソッド → コンパイルエラー
|
||||
// 意図しない上書きは100%防止
|
||||
```
|
||||
|
||||
## 🎯 設計思想の深層
|
||||
|
||||
### Everything is Box との統合
|
||||
|
||||
この革命は、Nyashの根本思想「Everything is Box」と完全に統合されています:
|
||||
|
||||
- **Box同士のデリゲーション**: 階層ではなく、協力関係
|
||||
- **Boxメソッドの明示的管理**: どのBoxのどのメソッドかが常に明確
|
||||
- **Box構築の明示的制御**: コンストラクタも普通のメソッド
|
||||
|
||||
### 明示性の哲学
|
||||
|
||||
Nyashが目指すのは、**「魔法のない言語」**です:
|
||||
|
||||
- 隠れた処理は一切なし
|
||||
- すべての動作がコードに現れる
|
||||
- 初学者でも上級者でも同じように理解できる
|
||||
|
||||
### 初学者への配慮
|
||||
|
||||
複雑な概念を、シンプルな文法で表現:
|
||||
|
||||
- `override` = 「置き換えます」
|
||||
- `from Parent.method()` = 「親の方法を使います」
|
||||
- コンパイルエラー = 「間違いを素早く教える」
|
||||
|
||||
## 🚀 実装戦略
|
||||
|
||||
### 段階的導入
|
||||
|
||||
ChatGPT先生の提案による実装ロードマップ:
|
||||
|
||||
**Phase 1(0.5-1日)**:
|
||||
- `override` キーワード追加
|
||||
- 基本パーサー拡張
|
||||
|
||||
**Phase 2(1-2日)**:
|
||||
- 暗黙オーバーライド検出
|
||||
- コンストラクタ重複禁止
|
||||
|
||||
**Phase 3(1日)**:
|
||||
- `from Parent.init()` 実装
|
||||
- エラーメッセージ改善
|
||||
|
||||
### 移行支援
|
||||
|
||||
既存コードの安全な移行:
|
||||
- 段階的警告システム
|
||||
- 自動修正支援ツール
|
||||
- 詳細な移行ガイド
|
||||
|
||||
## 🌟 期待される効果
|
||||
|
||||
### 1. 開発者体験の革命的向上
|
||||
|
||||
**Before(暗黙オーバーライド)**:
|
||||
- バグの発見が困難
|
||||
- 意図しない動作
|
||||
- デバッグに多大な時間
|
||||
|
||||
**After(明示的オーバーライド)**:
|
||||
- コンパイル時に間違いを検出
|
||||
- 意図が明確に表現される
|
||||
- デバッグ時間の劇的短縮
|
||||
|
||||
### 2. コードの可読性向上
|
||||
|
||||
**Before**:
|
||||
```nyash
|
||||
// これは何をオーバーライドしている?
|
||||
send(msg) {
|
||||
// 親を呼んでる?呼んでない?
|
||||
processMessage(msg)
|
||||
}
|
||||
```
|
||||
|
||||
**After**:
|
||||
```nyash
|
||||
// P2PBoxのsendを明示的にオーバーライド
|
||||
override send(msg) {
|
||||
processMessage(msg)
|
||||
from P2PBox.send(msg) // P2PBoxの実装も使用
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 保守性の向上
|
||||
|
||||
- 変更の影響範囲が明確
|
||||
- リファクタリングが安全
|
||||
- チーム開発での誤解を防止
|
||||
|
||||
## 🏆 結論:言語設計史に残る革命
|
||||
|
||||
この明示的デリゲーション革命により、Nyashは以下を達成しました:
|
||||
|
||||
### 世界初の完全明示デリゲーション言語
|
||||
|
||||
1. **完全な明示性**: すべての動作を明示
|
||||
2. **曖昧性の完全排除**: どんな複雑なケースも明確
|
||||
3. **統一構文**: デリゲーションとオーバーライドの完全統合
|
||||
4. **初学者フレンドリー**: 学習しやすく、間違いにくい
|
||||
|
||||
### プログラミング言語設計への貢献
|
||||
|
||||
- **暗黙の悪魔**からの完全な解放
|
||||
- **多重デリゲーション**の安全で明確な実現
|
||||
- **コード可読性**の新しい基準の確立
|
||||
|
||||
### 未来への影響
|
||||
|
||||
Nyashのこの革命は、今後のプログラミング言語設計に大きな影響を与えるでしょう。「暗黙より明示」という哲学が、ついに技術的に完全実現されたのです。
|
||||
|
||||
---
|
||||
|
||||
**2025年8月11日は、プログラミング言語史において「明示的デリゲーション革命の日」として記憶されることでしょう。** 🎊
|
||||
|
||||
この革命により、Nyashは単なるプログラミング言語を超えて、**新しいプログラミングパラダイムの先駆者**となりました。
|
||||
|
||||
Everything is Box. Everything is Explicit. Everything is Beautiful. 🌟
|
||||
525
docs/reference/core-language/language-reference.md
Normal file
525
docs/reference/core-language/language-reference.md
Normal file
@ -0,0 +1,525 @@
|
||||
# 🚀 Nyash Language Reference 2025
|
||||
|
||||
**最終更新: 2025年8月11日 - デリゲーション革命完了!`from`統一構文+`init`構文決定!**
|
||||
|
||||
## 📖 概要
|
||||
|
||||
Nyashは「Everything is Box」哲学に基づく革新的プログラミング言語です。
|
||||
Rust製インタープリターによる高性能実行と、直感的な構文により、学習しやすく実用的な言語として完成しました。
|
||||
|
||||
---
|
||||
|
||||
## 🔤 **1. 予約語・キーワード完全リスト**
|
||||
|
||||
### **コア言語**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `box` | クラス定義 | `box MyClass { }` |
|
||||
| `static` | 静的Box・関数定義 | `static box Main { }` |
|
||||
| `interface` | インターフェース定義 | `interface Comparable { }` |
|
||||
| `from` | デリゲーション指定 | `box Child from Parent { }` |
|
||||
| `new` | オブジェクト生成 | `new ConsoleBox()` |
|
||||
| `me`/`this` | 自己参照 | `me.field = value` |
|
||||
|
||||
### **変数・スコープ**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `local` | ローカル変数宣言 | `local x, y = 10` |
|
||||
| `outbox` | 所有権移転変数 | `outbox result = compute()` |
|
||||
| `global` | グローバル変数 | `global CONFIG = "dev"` |
|
||||
| `init` | フィールド初期化ブロック | `init { name, age }` |
|
||||
|
||||
### **制御構文**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `if` | 条件分岐 | `if condition { }` |
|
||||
| `else` | else節 | `else { }` |
|
||||
| `loop` | ループ(唯一の形式) | `loop(condition) { }` |
|
||||
| `break` | ループ脱出 | `break` |
|
||||
| `return` | 関数リターン | `return value` |
|
||||
|
||||
### **論理・演算**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `not` | 論理否定 | `not condition` |
|
||||
| `and` | 論理積 | `a and b` |
|
||||
| `or` | 論理和 | `a or b` |
|
||||
| `true`/`false` | 真偽値 | `flag = true` |
|
||||
|
||||
### **非同期・並行**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `nowait` | 非同期実行 | `nowait future = task()` |
|
||||
| `await` | 待機・結果取得 | `result = await future` |
|
||||
|
||||
### **例外処理**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `try` | 例外捕獲開始 | `try { }` |
|
||||
| `catch` | 例外処理 | `catch (e) { }` |
|
||||
| `finally` | 最終処理 | `finally { }` |
|
||||
| `throw` | 例外発生 | `throw error` |
|
||||
|
||||
### **その他**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `function` | 関数定義 | `function add(a,b) { }` |
|
||||
| `print` | 出力 | `print("Hello")` |
|
||||
| `include` | ファイル取り込み | `include "math.nyash"` |
|
||||
|
||||
---
|
||||
|
||||
## 📝 **2. 文法・構文仕様**
|
||||
|
||||
### **2.1 Box定義文法**
|
||||
|
||||
#### **基本Box**
|
||||
```nyash
|
||||
box ClassName {
|
||||
init { field1, field2, field3 } # カンマ必須!CPU暴走防止
|
||||
|
||||
# コンストラクタ
|
||||
init(param1, param2) { # init構文に統一
|
||||
me.field1 = param1
|
||||
me.field2 = param2
|
||||
me.field3 = defaultValue()
|
||||
}
|
||||
|
||||
# メソッド
|
||||
methodName(arg1, arg2) {
|
||||
return me.field1 + arg1
|
||||
}
|
||||
|
||||
# デストラクタ
|
||||
fini() {
|
||||
print("Cleanup: " + me.field1)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **デリゲーションBox**
|
||||
```nyash
|
||||
box Child from Parent interface Comparable {
|
||||
init { childField }
|
||||
|
||||
init(parentParam, childParam) { # init構文に統一
|
||||
from Parent.init(parentParam) # 親コンストラクタ明示呼び出し
|
||||
me.childField = childParam
|
||||
}
|
||||
|
||||
# メソッドオーバーライド
|
||||
override process(data) { # override必須
|
||||
local result = from Parent.process(data) # 親メソッド呼び出し
|
||||
return result + " (Child processed)"
|
||||
}
|
||||
|
||||
# インターフェース実装
|
||||
compareTo(other) {
|
||||
return me.value - other.value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **Static Box(推奨エントリーポイント)**
|
||||
```nyash
|
||||
static box Main {
|
||||
init { console, result }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🎉 Everything is Box!")
|
||||
return "Success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **ジェネリックBox**
|
||||
```nyash
|
||||
box Container<T> {
|
||||
init { value }
|
||||
|
||||
Container(item) {
|
||||
me.value = item
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return me.value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **2.2 変数宣言**
|
||||
|
||||
#### **基本パターン**
|
||||
```nyash
|
||||
# 単一宣言
|
||||
local x
|
||||
local name = "初期値"
|
||||
|
||||
# 複数宣言
|
||||
local a, b, c
|
||||
local x = 10, y = 20, z # 混合初期化
|
||||
|
||||
# 所有権移転(static関数内)
|
||||
static function Factory.create() {
|
||||
outbox product # 呼び出し側に所有権移転
|
||||
product = new Item()
|
||||
return product
|
||||
}
|
||||
```
|
||||
|
||||
#### **変数宣言厳密化システム(2025-08-09実装)**
|
||||
```nyash
|
||||
# ✅ 正しい - 明示宣言必須
|
||||
local temp
|
||||
temp = 42
|
||||
|
||||
# ❌ エラー - 未宣言変数への代入
|
||||
x = 42 # RuntimeError: 未宣言変数 + 修正提案表示
|
||||
```
|
||||
|
||||
### **2.3 制御構文**
|
||||
|
||||
#### **条件分岐**
|
||||
```nyash
|
||||
if condition {
|
||||
# 処理
|
||||
} else if condition2 {
|
||||
# 処理2
|
||||
} else {
|
||||
# else処理
|
||||
}
|
||||
```
|
||||
|
||||
#### **ループ(統一構文)**
|
||||
```nyash
|
||||
# ✅ 唯一の正しい形式
|
||||
loop(condition) {
|
||||
# ループ本体
|
||||
if exitCondition {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# ❌ 削除済み - 使用不可
|
||||
while condition { } # パーサーエラー
|
||||
loop() { } # パーサーエラー
|
||||
```
|
||||
|
||||
### **2.4 演算子・式**
|
||||
|
||||
#### **🚀 新実装: 関数オーバーロードシステム**
|
||||
```nyash
|
||||
# Rust風トレイトベース演算子(2025-08-10実装完了)
|
||||
sum = 10 + 20 # IntegerBox + IntegerBox = IntegerBox
|
||||
concat = "Hi" + " !" # StringBox + StringBox = StringBox
|
||||
repeat = "Ha" * 3 # StringBox * IntegerBox = "HaHaHa"
|
||||
mixed = 42 + " answer" # 混合型 → 自動文字列結合フォールバック
|
||||
```
|
||||
|
||||
#### **演算子優先順位**
|
||||
```nyash
|
||||
result = a + b * c / d - e # 算術演算子は標準的優先順位
|
||||
logic = not a and b or c # not > and > or
|
||||
compare = (x > y) and (z <= w) # 比較は括弧推奨
|
||||
```
|
||||
|
||||
#### **論理演算子**
|
||||
```nyash
|
||||
# キーワード版(推奨)
|
||||
canAccess = level >= 5 and hasKey
|
||||
isValid = not (isEmpty or hasError)
|
||||
|
||||
# シンボル版(互換)
|
||||
result = condition && other || fallback # 利用可能だが非推奨
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ **3. Box構文詳細ガイド**
|
||||
|
||||
### **3.1 Everything is Box 原則**
|
||||
|
||||
```nyash
|
||||
# すべての値がBox
|
||||
number = 42 # IntegerBox
|
||||
text = "hello" # StringBox
|
||||
flag = true # BoolBox
|
||||
array = new ArrayBox() # ArrayBox
|
||||
console = new ConsoleBox() # ConsoleBox
|
||||
|
||||
# 統一的なメソッド呼び出し
|
||||
print(number.to_string_box().value) # "42"
|
||||
print(array.length()) # 配列長
|
||||
console.log("Everything is Box!") # コンソール出力
|
||||
```
|
||||
|
||||
### **3.2 コンストラクタパターン**
|
||||
|
||||
#### **パラメータ付きコンストラクタ**
|
||||
```nyash
|
||||
box Person {
|
||||
init { name, age, email }
|
||||
|
||||
init(personName, personAge) { # init構文に統一
|
||||
me.name = personName
|
||||
me.age = personAge
|
||||
me.email = me.name + "@example.com" # 計算フィールド
|
||||
}
|
||||
|
||||
# ファクトリーメソッド
|
||||
static createGuest() {
|
||||
outbox guest
|
||||
guest = new Person("Guest", 0)
|
||||
return guest
|
||||
}
|
||||
}
|
||||
|
||||
# 使用例
|
||||
person = new Person("Alice", 25)
|
||||
guest = Person.createGuest()
|
||||
```
|
||||
|
||||
### **3.3 継承とインターフェース**
|
||||
|
||||
#### **デリゲーションチェーン**
|
||||
```nyash
|
||||
# 基底Box
|
||||
box Animal {
|
||||
init { name, species }
|
||||
|
||||
init(animalName, animalSpecies) {
|
||||
me.name = animalName
|
||||
me.species = animalSpecies
|
||||
}
|
||||
|
||||
speak() {
|
||||
return me.name + " makes a sound"
|
||||
}
|
||||
}
|
||||
|
||||
# デリゲーション
|
||||
box Dog from Animal {
|
||||
init { breed } # 追加フィールド
|
||||
|
||||
init(dogName, dogBreed) {
|
||||
from Animal.init(dogName, "Canine") # 親コンストラクタ呼び出し
|
||||
me.breed = dogBreed
|
||||
}
|
||||
|
||||
override speak() { # 明示的オーバーライド
|
||||
return me.name + " barks: Woof!"
|
||||
}
|
||||
}
|
||||
|
||||
# インターフェース実装
|
||||
box Cat from Animal interface Playful {
|
||||
# Playfulインターフェースの実装必須
|
||||
}
|
||||
```
|
||||
|
||||
### **3.4 Static Boxパターン**
|
||||
|
||||
#### **名前空間・ユーティリティ**
|
||||
```nyash
|
||||
static box MathUtils {
|
||||
init { PI, E }
|
||||
|
||||
static {
|
||||
me.PI = 3.14159265
|
||||
me.E = 2.71828182
|
||||
}
|
||||
|
||||
add(a, b) {
|
||||
return a + b
|
||||
}
|
||||
|
||||
circleArea(radius) {
|
||||
return me.PI * radius * radius
|
||||
}
|
||||
}
|
||||
|
||||
# 使用法
|
||||
area = MathUtils.circleArea(5)
|
||||
sum = MathUtils.add(10, 20)
|
||||
pi = MathUtils.PI
|
||||
```
|
||||
|
||||
#### **アプリケーションエントリーポイント**
|
||||
```nyash
|
||||
# 🎯 推奨: Static Box Main パターン
|
||||
static box Main {
|
||||
init { console, result }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🚀 Starting application...")
|
||||
|
||||
# アプリケーションロジック
|
||||
me.result = processData()
|
||||
|
||||
return "Application completed successfully"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **4. 最新機能・革新技術**
|
||||
|
||||
### **4.1 Arc<Mutex> Revolution(2025-08-10)**
|
||||
```nyash
|
||||
# 全16種類のBox型が統一Arc<Mutex>パターンで実装
|
||||
# 完全なスレッドセーフティと高性能を両立
|
||||
|
||||
array = new ArrayBox()
|
||||
array.push(10) # スレッドセーフな追加
|
||||
array.push(20)
|
||||
item = array.get(0) # スレッドセーフな取得
|
||||
|
||||
json = new JSONBox()
|
||||
json.set("name", "Alice") # 並行安全な操作
|
||||
data = json.stringify() # JSON文字列化
|
||||
```
|
||||
|
||||
### **4.2 Rust風トレイトベース演算子(2025-08-10)**
|
||||
```nyash
|
||||
# AI大相談会で決定された最適設計
|
||||
# 静的・動的ハイブリッドディスパッチによる高性能実現
|
||||
|
||||
# 整数演算
|
||||
result = 100 - 25 # IntegerBox間演算 → IntegerBox
|
||||
product = 6 * 7 # 高速静的ディスパッチ
|
||||
|
||||
# 文字列操作
|
||||
greeting = "Hello" + " World" # 文字列結合
|
||||
repeated = "Echo" * 3 # "EchoEchoEcho"
|
||||
|
||||
# 混合型フォールバック
|
||||
message = "Answer: " + 42 # "Answer: 42"
|
||||
|
||||
# Boolean演算
|
||||
boolSum = true + false # 1 (IntegerBox)
|
||||
```
|
||||
|
||||
### **4.3 変数宣言厳密化(2025-08-09)**
|
||||
```nyash
|
||||
# メモリ安全性・非同期安全性保証システム
|
||||
|
||||
static box Calculator {
|
||||
init { memory } # 必須フィールド宣言
|
||||
|
||||
calculate() {
|
||||
local temp # 必須ローカル変数宣言
|
||||
temp = me.memory * 2
|
||||
return temp
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ **5. 実装済みBox型ライブラリ**
|
||||
|
||||
### **5.1 基本型**
|
||||
- `StringBox` - 文字列(split, find, replace, trim等)
|
||||
- `IntegerBox` - 64bit整数
|
||||
- `BoolBox` - 真偽値
|
||||
- `VoidBox` - null/void値
|
||||
|
||||
### **5.2 コレクション**
|
||||
- `ArrayBox` - 動的配列(push, pop, get, set, join等)
|
||||
- `MapBox` - 連想配列・辞書
|
||||
|
||||
### **5.3 システム・I/O**
|
||||
- `ConsoleBox` - コンソール入出力
|
||||
- `DebugBox` - デバッグ支援・メモリ追跡
|
||||
- `FileBox` - ファイルシステム操作
|
||||
|
||||
### **5.4 数学・時間**
|
||||
- `MathBox` - 数学関数(sin, cos, log, sqrt等)
|
||||
- `TimeBox` - 時刻操作・タイマー
|
||||
- `RandomBox` - 乱数生成・選択・シャッフル
|
||||
|
||||
### **5.5 データ処理**
|
||||
- `JSONBox` - JSON解析・生成(parse, stringify, get, set)
|
||||
- `RegexBox` - 正規表現(test, find, replace, split)
|
||||
- `BufferBox` - バイナリデータ処理
|
||||
- `StreamBox` - ストリーム処理
|
||||
|
||||
### **5.6 ネットワーク・Web**
|
||||
- `HttpClientBox` - HTTP通信
|
||||
- `WebDisplayBox` - HTML表示(WASM)
|
||||
- `WebConsoleBox` - ブラウザコンソール(WASM)
|
||||
- `WebCanvasBox` - Canvas描画(WASM)
|
||||
|
||||
### **5.7 GUI・マルチメディア**
|
||||
- `EguiBox` - デスクトップGUI(Windows/Linux)
|
||||
- `SoundBox` - 音声再生
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **6. パフォーマンス・デザイン原則**
|
||||
|
||||
### **6.1 メモリ安全性**
|
||||
- Rust所有権システムによる完全なメモリ安全性
|
||||
- Arc<Mutex>によるスレッドセーフな共有状態管理
|
||||
- 自動参照カウント + 明示的デストラクタ(fini)
|
||||
|
||||
### **6.2 実行効率**
|
||||
- 統一されたBox型システムによる最適化
|
||||
- 静的・動的ハイブリッドディスパッチで高速演算
|
||||
- パーサー無限ループ対策(--debug-fuel)
|
||||
|
||||
### **6.3 開発効率**
|
||||
- 変数宣言厳密化による早期エラー検出
|
||||
- 包括的デバッグ機能(DebugBox)
|
||||
- 直感的な"Everything is Box"概念
|
||||
|
||||
---
|
||||
|
||||
## 📚 **7. 学習パス・ベストプラクティス**
|
||||
|
||||
### **7.1 初心者向け学習順序**
|
||||
1. **基本概念**: Everything is Box哲学理解
|
||||
2. **基本構文**: 変数宣言・制御構文・演算子
|
||||
3. **Box定義**: 基本的なクラス作成
|
||||
4. **Static Box Main**: アプリケーションエントリーポイント
|
||||
5. **継承・インターフェース**: オブジェクト指向機能
|
||||
|
||||
### **7.2 推奨コーディングスタイル**
|
||||
```nyash
|
||||
# ✅ 推奨スタイル
|
||||
static box Main {
|
||||
init { console, result } # フィールド明示
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
local data # 変数事前宣言
|
||||
data = processInput()
|
||||
|
||||
me.result = data # 明確な代入
|
||||
return "Success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **7.3 よくある間違いと対策**
|
||||
```nyash
|
||||
# ❌ よくある間違い
|
||||
init { field1 field2 } # カンマなし → CPU暴走
|
||||
x = 42 # 変数未宣言 → ランタイムエラー
|
||||
while condition { } # 非対応構文 → パーサーエラー
|
||||
|
||||
# ✅ 正しい書き方
|
||||
init { field1, field2 } # カンマ必須
|
||||
local x = 42 # 事前宣言
|
||||
loop(condition) { } # 統一ループ構文
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**🎉 Nyash 2025は、AI協働設計による最先端言語システムとして、シンプルさと強力さを完全に両立しました。**
|
||||
|
||||
*最終更新: 2025年8月10日 - Arc<Mutex> Revolution + AI大相談会成功記念*
|
||||
525
docs/reference/core-language/language_spec.md
Normal file
525
docs/reference/core-language/language_spec.md
Normal file
@ -0,0 +1,525 @@
|
||||
# 🚀 Nyash Language Reference 2025
|
||||
|
||||
**最終更新: 2025年8月11日 - デリゲーション革命完了!`from`統一構文+`init`構文決定!**
|
||||
|
||||
## 📖 概要
|
||||
|
||||
Nyashは「Everything is Box」哲学に基づく革新的プログラミング言語です。
|
||||
Rust製インタープリターによる高性能実行と、直感的な構文により、学習しやすく実用的な言語として完成しました。
|
||||
|
||||
---
|
||||
|
||||
## 🔤 **1. 予約語・キーワード完全リスト**
|
||||
|
||||
### **コア言語**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `box` | クラス定義 | `box MyClass { }` |
|
||||
| `static` | 静的Box・関数定義 | `static box Main { }` |
|
||||
| `interface` | インターフェース定義 | `interface Comparable { }` |
|
||||
| `from` | デリゲーション指定 | `box Child from Parent { }` |
|
||||
| `new` | オブジェクト生成 | `new ConsoleBox()` |
|
||||
| `me`/`this` | 自己参照 | `me.field = value` |
|
||||
|
||||
### **変数・スコープ**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `local` | ローカル変数宣言 | `local x, y = 10` |
|
||||
| `outbox` | 所有権移転変数 | `outbox result = compute()` |
|
||||
| `global` | グローバル変数 | `global CONFIG = "dev"` |
|
||||
| `init` | フィールド初期化ブロック | `init { name, age }` |
|
||||
|
||||
### **制御構文**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `if` | 条件分岐 | `if condition { }` |
|
||||
| `else` | else節 | `else { }` |
|
||||
| `loop` | ループ(唯一の形式) | `loop(condition) { }` |
|
||||
| `break` | ループ脱出 | `break` |
|
||||
| `return` | 関数リターン | `return value` |
|
||||
|
||||
### **論理・演算**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `not` | 論理否定 | `not condition` |
|
||||
| `and` | 論理積 | `a and b` |
|
||||
| `or` | 論理和 | `a or b` |
|
||||
| `true`/`false` | 真偽値 | `flag = true` |
|
||||
|
||||
### **非同期・並行**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `nowait` | 非同期実行 | `nowait future = task()` |
|
||||
| `await` | 待機・結果取得 | `result = await future` |
|
||||
|
||||
### **例外処理**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `try` | 例外捕獲開始 | `try { }` |
|
||||
| `catch` | 例外処理 | `catch (e) { }` |
|
||||
| `finally` | 最終処理 | `finally { }` |
|
||||
| `throw` | 例外発生 | `throw error` |
|
||||
|
||||
### **その他**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `function` | 関数定義 | `function add(a,b) { }` |
|
||||
| `print` | 出力 | `print("Hello")` |
|
||||
| `include` | ファイル取り込み | `include "math.nyash"` |
|
||||
|
||||
---
|
||||
|
||||
## 📝 **2. 文法・構文仕様**
|
||||
|
||||
### **2.1 Box定義文法**
|
||||
|
||||
#### **基本Box**
|
||||
```nyash
|
||||
box ClassName {
|
||||
init { field1, field2, field3 } # カンマ必須!CPU暴走防止
|
||||
|
||||
# コンストラクタ
|
||||
init(param1, param2) { # init構文に統一
|
||||
me.field1 = param1
|
||||
me.field2 = param2
|
||||
me.field3 = defaultValue()
|
||||
}
|
||||
|
||||
# メソッド
|
||||
methodName(arg1, arg2) {
|
||||
return me.field1 + arg1
|
||||
}
|
||||
|
||||
# デストラクタ
|
||||
fini() {
|
||||
print("Cleanup: " + me.field1)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **デリゲーションBox**
|
||||
```nyash
|
||||
box Child from Parent interface Comparable {
|
||||
init { childField }
|
||||
|
||||
init(parentParam, childParam) { # init構文に統一
|
||||
from Parent.init(parentParam) # 親コンストラクタ明示呼び出し
|
||||
me.childField = childParam
|
||||
}
|
||||
|
||||
# メソッドオーバーライド
|
||||
override process(data) { # override必須
|
||||
local result = from Parent.process(data) # 親メソッド呼び出し
|
||||
return result + " (Child processed)"
|
||||
}
|
||||
|
||||
# インターフェース実装
|
||||
compareTo(other) {
|
||||
return me.value - other.value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **Static Box(推奨エントリーポイント)**
|
||||
```nyash
|
||||
static box Main {
|
||||
init { console, result }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🎉 Everything is Box!")
|
||||
return "Success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **ジェネリックBox**
|
||||
```nyash
|
||||
box Container<T> {
|
||||
init { value }
|
||||
|
||||
Container(item) {
|
||||
me.value = item
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return me.value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **2.2 変数宣言**
|
||||
|
||||
#### **基本パターン**
|
||||
```nyash
|
||||
# 単一宣言
|
||||
local x
|
||||
local name = "初期値"
|
||||
|
||||
# 複数宣言
|
||||
local a, b, c
|
||||
local x = 10, y = 20, z # 混合初期化
|
||||
|
||||
# 所有権移転(static関数内)
|
||||
static function Factory.create() {
|
||||
outbox product # 呼び出し側に所有権移転
|
||||
product = new Item()
|
||||
return product
|
||||
}
|
||||
```
|
||||
|
||||
#### **変数宣言厳密化システム(2025-08-09実装)**
|
||||
```nyash
|
||||
# ✅ 正しい - 明示宣言必須
|
||||
local temp
|
||||
temp = 42
|
||||
|
||||
# ❌ エラー - 未宣言変数への代入
|
||||
x = 42 # RuntimeError: 未宣言変数 + 修正提案表示
|
||||
```
|
||||
|
||||
### **2.3 制御構文**
|
||||
|
||||
#### **条件分岐**
|
||||
```nyash
|
||||
if condition {
|
||||
# 処理
|
||||
} else if condition2 {
|
||||
# 処理2
|
||||
} else {
|
||||
# else処理
|
||||
}
|
||||
```
|
||||
|
||||
#### **ループ(統一構文)**
|
||||
```nyash
|
||||
# ✅ 唯一の正しい形式
|
||||
loop(condition) {
|
||||
# ループ本体
|
||||
if exitCondition {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# ❌ 削除済み - 使用不可
|
||||
while condition { } # パーサーエラー
|
||||
loop() { } # パーサーエラー
|
||||
```
|
||||
|
||||
### **2.4 演算子・式**
|
||||
|
||||
#### **🚀 新実装: 関数オーバーロードシステム**
|
||||
```nyash
|
||||
# Rust風トレイトベース演算子(2025-08-10実装完了)
|
||||
sum = 10 + 20 # IntegerBox + IntegerBox = IntegerBox
|
||||
concat = "Hi" + " !" # StringBox + StringBox = StringBox
|
||||
repeat = "Ha" * 3 # StringBox * IntegerBox = "HaHaHa"
|
||||
mixed = 42 + " answer" # 混合型 → 自動文字列結合フォールバック
|
||||
```
|
||||
|
||||
#### **演算子優先順位**
|
||||
```nyash
|
||||
result = a + b * c / d - e # 算術演算子は標準的優先順位
|
||||
logic = not a and b or c # not > and > or
|
||||
compare = (x > y) and (z <= w) # 比較は括弧推奨
|
||||
```
|
||||
|
||||
#### **論理演算子**
|
||||
```nyash
|
||||
# キーワード版(推奨)
|
||||
canAccess = level >= 5 and hasKey
|
||||
isValid = not (isEmpty or hasError)
|
||||
|
||||
# シンボル版(互換)
|
||||
result = condition && other || fallback # 利用可能だが非推奨
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ **3. Box構文詳細ガイド**
|
||||
|
||||
### **3.1 Everything is Box 原則**
|
||||
|
||||
```nyash
|
||||
# すべての値がBox
|
||||
number = 42 # IntegerBox
|
||||
text = "hello" # StringBox
|
||||
flag = true # BoolBox
|
||||
array = new ArrayBox() # ArrayBox
|
||||
console = new ConsoleBox() # ConsoleBox
|
||||
|
||||
# 統一的なメソッド呼び出し
|
||||
print(number.to_string_box().value) # "42"
|
||||
print(array.length()) # 配列長
|
||||
console.log("Everything is Box!") # コンソール出力
|
||||
```
|
||||
|
||||
### **3.2 コンストラクタパターン**
|
||||
|
||||
#### **パラメータ付きコンストラクタ**
|
||||
```nyash
|
||||
box Person {
|
||||
init { name, age, email }
|
||||
|
||||
init(personName, personAge) { # init構文に統一
|
||||
me.name = personName
|
||||
me.age = personAge
|
||||
me.email = me.name + "@example.com" # 計算フィールド
|
||||
}
|
||||
|
||||
# ファクトリーメソッド
|
||||
static createGuest() {
|
||||
outbox guest
|
||||
guest = new Person("Guest", 0)
|
||||
return guest
|
||||
}
|
||||
}
|
||||
|
||||
# 使用例
|
||||
person = new Person("Alice", 25)
|
||||
guest = Person.createGuest()
|
||||
```
|
||||
|
||||
### **3.3 継承とインターフェース**
|
||||
|
||||
#### **デリゲーションチェーン**
|
||||
```nyash
|
||||
# 基底Box
|
||||
box Animal {
|
||||
init { name, species }
|
||||
|
||||
init(animalName, animalSpecies) {
|
||||
me.name = animalName
|
||||
me.species = animalSpecies
|
||||
}
|
||||
|
||||
speak() {
|
||||
return me.name + " makes a sound"
|
||||
}
|
||||
}
|
||||
|
||||
# デリゲーション
|
||||
box Dog from Animal {
|
||||
init { breed } # 追加フィールド
|
||||
|
||||
init(dogName, dogBreed) {
|
||||
from Animal.init(dogName, "Canine") # 親コンストラクタ呼び出し
|
||||
me.breed = dogBreed
|
||||
}
|
||||
|
||||
override speak() { # 明示的オーバーライド
|
||||
return me.name + " barks: Woof!"
|
||||
}
|
||||
}
|
||||
|
||||
# インターフェース実装
|
||||
box Cat from Animal interface Playful {
|
||||
# Playfulインターフェースの実装必須
|
||||
}
|
||||
```
|
||||
|
||||
### **3.4 Static Boxパターン**
|
||||
|
||||
#### **名前空間・ユーティリティ**
|
||||
```nyash
|
||||
static box MathUtils {
|
||||
init { PI, E }
|
||||
|
||||
static {
|
||||
me.PI = 3.14159265
|
||||
me.E = 2.71828182
|
||||
}
|
||||
|
||||
add(a, b) {
|
||||
return a + b
|
||||
}
|
||||
|
||||
circleArea(radius) {
|
||||
return me.PI * radius * radius
|
||||
}
|
||||
}
|
||||
|
||||
# 使用法
|
||||
area = MathUtils.circleArea(5)
|
||||
sum = MathUtils.add(10, 20)
|
||||
pi = MathUtils.PI
|
||||
```
|
||||
|
||||
#### **アプリケーションエントリーポイント**
|
||||
```nyash
|
||||
# 🎯 推奨: Static Box Main パターン
|
||||
static box Main {
|
||||
init { console, result }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🚀 Starting application...")
|
||||
|
||||
# アプリケーションロジック
|
||||
me.result = processData()
|
||||
|
||||
return "Application completed successfully"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **4. 最新機能・革新技術**
|
||||
|
||||
### **4.1 Arc<Mutex> Revolution(2025-08-10)**
|
||||
```nyash
|
||||
# 全16種類のBox型が統一Arc<Mutex>パターンで実装
|
||||
# 完全なスレッドセーフティと高性能を両立
|
||||
|
||||
array = new ArrayBox()
|
||||
array.push(10) # スレッドセーフな追加
|
||||
array.push(20)
|
||||
item = array.get(0) # スレッドセーフな取得
|
||||
|
||||
json = new JSONBox()
|
||||
json.set("name", "Alice") # 並行安全な操作
|
||||
data = json.stringify() # JSON文字列化
|
||||
```
|
||||
|
||||
### **4.2 Rust風トレイトベース演算子(2025-08-10)**
|
||||
```nyash
|
||||
# AI大相談会で決定された最適設計
|
||||
# 静的・動的ハイブリッドディスパッチによる高性能実現
|
||||
|
||||
# 整数演算
|
||||
result = 100 - 25 # IntegerBox間演算 → IntegerBox
|
||||
product = 6 * 7 # 高速静的ディスパッチ
|
||||
|
||||
# 文字列操作
|
||||
greeting = "Hello" + " World" # 文字列結合
|
||||
repeated = "Echo" * 3 # "EchoEchoEcho"
|
||||
|
||||
# 混合型フォールバック
|
||||
message = "Answer: " + 42 # "Answer: 42"
|
||||
|
||||
# Boolean演算
|
||||
boolSum = true + false # 1 (IntegerBox)
|
||||
```
|
||||
|
||||
### **4.3 変数宣言厳密化(2025-08-09)**
|
||||
```nyash
|
||||
# メモリ安全性・非同期安全性保証システム
|
||||
|
||||
static box Calculator {
|
||||
init { memory } # 必須フィールド宣言
|
||||
|
||||
calculate() {
|
||||
local temp # 必須ローカル変数宣言
|
||||
temp = me.memory * 2
|
||||
return temp
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ **5. 実装済みBox型ライブラリ**
|
||||
|
||||
### **5.1 基本型**
|
||||
- `StringBox` - 文字列(split, find, replace, trim等)
|
||||
- `IntegerBox` - 64bit整数
|
||||
- `BoolBox` - 真偽値
|
||||
- `VoidBox` - null/void値
|
||||
|
||||
### **5.2 コレクション**
|
||||
- `ArrayBox` - 動的配列(push, pop, get, set, join等)
|
||||
- `MapBox` - 連想配列・辞書
|
||||
|
||||
### **5.3 システム・I/O**
|
||||
- `ConsoleBox` - コンソール入出力
|
||||
- `DebugBox` - デバッグ支援・メモリ追跡
|
||||
- `FileBox` - ファイルシステム操作
|
||||
|
||||
### **5.4 数学・時間**
|
||||
- `MathBox` - 数学関数(sin, cos, log, sqrt等)
|
||||
- `TimeBox` - 時刻操作・タイマー
|
||||
- `RandomBox` - 乱数生成・選択・シャッフル
|
||||
|
||||
### **5.5 データ処理**
|
||||
- `JSONBox` - JSON解析・生成(parse, stringify, get, set)
|
||||
- `RegexBox` - 正規表現(test, find, replace, split)
|
||||
- `BufferBox` - バイナリデータ処理
|
||||
- `StreamBox` - ストリーム処理
|
||||
|
||||
### **5.6 ネットワーク・Web**
|
||||
- `HttpClientBox` - HTTP通信
|
||||
- `WebDisplayBox` - HTML表示(WASM)
|
||||
- `WebConsoleBox` - ブラウザコンソール(WASM)
|
||||
- `WebCanvasBox` - Canvas描画(WASM)
|
||||
|
||||
### **5.7 GUI・マルチメディア**
|
||||
- `EguiBox` - デスクトップGUI(Windows/Linux)
|
||||
- `SoundBox` - 音声再生
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **6. パフォーマンス・デザイン原則**
|
||||
|
||||
### **6.1 メモリ安全性**
|
||||
- Rust所有権システムによる完全なメモリ安全性
|
||||
- Arc<Mutex>によるスレッドセーフな共有状態管理
|
||||
- 自動参照カウント + 明示的デストラクタ(fini)
|
||||
|
||||
### **6.2 実行効率**
|
||||
- 統一されたBox型システムによる最適化
|
||||
- 静的・動的ハイブリッドディスパッチで高速演算
|
||||
- パーサー無限ループ対策(--debug-fuel)
|
||||
|
||||
### **6.3 開発効率**
|
||||
- 変数宣言厳密化による早期エラー検出
|
||||
- 包括的デバッグ機能(DebugBox)
|
||||
- 直感的な"Everything is Box"概念
|
||||
|
||||
---
|
||||
|
||||
## 📚 **7. 学習パス・ベストプラクティス**
|
||||
|
||||
### **7.1 初心者向け学習順序**
|
||||
1. **基本概念**: Everything is Box哲学理解
|
||||
2. **基本構文**: 変数宣言・制御構文・演算子
|
||||
3. **Box定義**: 基本的なクラス作成
|
||||
4. **Static Box Main**: アプリケーションエントリーポイント
|
||||
5. **継承・インターフェース**: オブジェクト指向機能
|
||||
|
||||
### **7.2 推奨コーディングスタイル**
|
||||
```nyash
|
||||
# ✅ 推奨スタイル
|
||||
static box Main {
|
||||
init { console, result } # フィールド明示
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
local data # 変数事前宣言
|
||||
data = processInput()
|
||||
|
||||
me.result = data # 明確な代入
|
||||
return "Success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **7.3 よくある間違いと対策**
|
||||
```nyash
|
||||
# ❌ よくある間違い
|
||||
init { field1 field2 } # カンマなし → CPU暴走
|
||||
x = 42 # 変数未宣言 → ランタイムエラー
|
||||
while condition { } # 非対応構文 → パーサーエラー
|
||||
|
||||
# ✅ 正しい書き方
|
||||
init { field1, field2 } # カンマ必須
|
||||
local x = 42 # 事前宣言
|
||||
loop(condition) { } # 統一ループ構文
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**🎉 Nyash 2025は、AI協働設計による最先端言語システムとして、シンプルさと強力さを完全に両立しました。**
|
||||
|
||||
*最終更新: 2025年8月10日 - Arc<Mutex> Revolution + AI大相談会成功記念*
|
||||
338
docs/reference/core-language/override-delegation-syntax.md
Normal file
338
docs/reference/core-language/override-delegation-syntax.md
Normal file
@ -0,0 +1,338 @@
|
||||
# 🌟 Nyash Override + Delegation 統一構文仕様
|
||||
|
||||
バージョン: 2.0
|
||||
作成日: 2025年8月11日
|
||||
ステータス: 正式決定
|
||||
|
||||
## 📋 概要
|
||||
|
||||
Nyashプログラミング言語における明示的オーバーライドとデリゲーション構文の完全仕様。世界初の**完全明示デリゲーション言語**としてのNyashの核心機能を定義する。
|
||||
|
||||
## 🎯 設計哲学
|
||||
|
||||
### 基本原則
|
||||
1. **完全明示性**: すべての動作を明示的に宣言
|
||||
2. **曖昧性の完全排除**: 暗黙の動作は一切許可しない
|
||||
3. **統一構文**: デリゲーションとオーバーライドの完全統合
|
||||
4. **初学者フレンドリー**: 直感的で理解しやすい構文
|
||||
|
||||
### Everything is Box との整合性
|
||||
- すべてのオブジェクトがBox
|
||||
- デリゲーション先もBox
|
||||
- オーバーライドもBoxメソッドの置換
|
||||
|
||||
## 🔥 基本構文
|
||||
|
||||
### デリゲーション宣言
|
||||
```nyash
|
||||
box Child from Parent {
|
||||
// 親Boxからの機能デリゲーション
|
||||
}
|
||||
|
||||
// 多重デリゲーション
|
||||
box Child from Parent1, Parent2 {
|
||||
// 複数のBoxからの機能デリゲーション
|
||||
}
|
||||
```
|
||||
|
||||
### メソッドオーバーライド
|
||||
```nyash
|
||||
box Child from Parent {
|
||||
// 必須: overrideキーワードによる明示的宣言
|
||||
override methodName(params) {
|
||||
// オーバーライド実装
|
||||
from Parent.methodName(params) // 親実装呼び出し(任意)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### コンストラクタデリゲーション
|
||||
```nyash
|
||||
box Child from Parent {
|
||||
init(params) { # init構文に統一
|
||||
from Parent.init(params) # 必須: 親コンストラクタ明示呼び出し
|
||||
me.childSpecificField = value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📚 詳細仕様
|
||||
|
||||
### 1. Override キーワード
|
||||
|
||||
#### 必須条件
|
||||
- 親Box(デリゲーション先)に同名メソッドが存在する場合のみ使用可能
|
||||
- 同名メソッドが存在しない場合は**コンパイルエラー**
|
||||
|
||||
#### 禁止事項
|
||||
- 同一Box内での同名メソッド重複定義は**すべてエラー**
|
||||
- 暗黙のオーバーライドは**完全禁止**
|
||||
|
||||
#### 構文例
|
||||
```nyash
|
||||
box MeshNode from P2PBox {
|
||||
// ✅ 正しい使用法
|
||||
override send(intent, data, target) {
|
||||
me.routing.log(target)
|
||||
from P2PBox.send(intent, data, target)
|
||||
}
|
||||
|
||||
// ❌ エラー: P2PBoxに存在しないメソッド
|
||||
override nonExistentMethod() {
|
||||
// Error: Method 'nonExistentMethod' does not exist in parent P2PBox
|
||||
}
|
||||
|
||||
// ❌ エラー: overrideなしで親メソッドと同名
|
||||
send(intent, data, target) {
|
||||
// Error: Method 'send' overrides parent method. Add 'override' keyword.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. From デリゲーション構文
|
||||
|
||||
#### 基本構文
|
||||
```nyash
|
||||
from ParentBox.methodName(args)
|
||||
from ParentBox.fieldName
|
||||
```
|
||||
|
||||
#### メソッド呼び出し
|
||||
```nyash
|
||||
// 親の特定メソッドを明示的に呼び出し
|
||||
from P2PBox.send(intent, data, target)
|
||||
|
||||
// 複数親からの呼び出し
|
||||
from Logger.log("Starting operation")
|
||||
from P2PBox.send(intent, data, target)
|
||||
from Cache.store(data)
|
||||
```
|
||||
|
||||
#### フィールドアクセス
|
||||
```nyash
|
||||
// 親のフィールドへのアクセス
|
||||
local status = from P2PBox.connectionStatus
|
||||
from Logger.logLevel = "DEBUG"
|
||||
```
|
||||
|
||||
#### コンストラクタ呼び出し
|
||||
```nyash
|
||||
init(nodeId, world) { # init構文に統一
|
||||
from P2PBox.init(nodeId, world) # 完全統一構文
|
||||
me.routing = RoutingTable()
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 多重デリゲーション
|
||||
|
||||
#### 基本形式
|
||||
```nyash
|
||||
box ComplexNode from P2PBox, Logger, Cache {
|
||||
override send(intent, data, target) {
|
||||
from Logger.debug("Sending: " + intent) // Logger親から
|
||||
from Cache.store(intent, data) // Cache親から
|
||||
from P2PBox.send(intent, data, target) // P2PBox親から
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 曖昧性の解消
|
||||
```nyash
|
||||
// 複数親に同名メソッドが存在する場合
|
||||
box ConflictNode from ParentA, ParentB {
|
||||
// ❌ エラー: どちらのprocessを置換するか不明
|
||||
override process(data) {
|
||||
// Error: Method 'process' exists in multiple parents. Use specific parent.
|
||||
}
|
||||
|
||||
// ✅ 正しい解決法: 親を明示指定
|
||||
override ParentA.process(data) {
|
||||
// ParentAのprocessをオーバーライド
|
||||
from ParentA.process(data)
|
||||
}
|
||||
|
||||
override ParentB.process(data) {
|
||||
// ParentBのprocessをオーバーライド
|
||||
from ParentB.process(data)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. エラーメッセージ仕様
|
||||
|
||||
#### 重複定義エラー
|
||||
```
|
||||
Error: Method 'send' is already defined in this box at line 15.
|
||||
--> box.nyash:20:5
|
||||
|
|
||||
20 | send(msg) {
|
||||
| ^^^^ duplicate method definition
|
||||
|
|
||||
Help: Remove duplicate definition or rename method.
|
||||
```
|
||||
|
||||
#### Missing Override エラー
|
||||
```
|
||||
Error: Method 'send' overrides a parent method. Add 'override' keyword.
|
||||
--> box.nyash:18:5
|
||||
|
|
||||
18 | send(intent, data, target) {
|
||||
| ^^^^ missing 'override' keyword
|
||||
|
|
||||
Help: Change to 'override send(intent, data, target) {'
|
||||
```
|
||||
|
||||
#### Wrong Override エラー
|
||||
```
|
||||
Error: Method 'newMethod' does not exist in any parent. Remove 'override' keyword.
|
||||
--> box.nyash:22:5
|
||||
|
|
||||
22 | override newMethod() {
|
||||
| ^^^^^^^^ unnecessary 'override'
|
||||
|
|
||||
Help: Remove 'override' or verify parent method name.
|
||||
```
|
||||
|
||||
#### 曖昧Override エラー
|
||||
```
|
||||
Error: Method 'process' exists in multiple parents. Specify which parent to override.
|
||||
--> box.nyash:25:5
|
||||
|
|
||||
25 | override process(data) {
|
||||
| ^^^^^^^^ ambiguous override
|
||||
|
|
||||
Help: Use 'override ParentA.process' or 'override ParentB.process'
|
||||
```
|
||||
|
||||
## 🚫 禁止事項
|
||||
|
||||
### 1. 暗黙のオーバーライド
|
||||
```nyash
|
||||
box Child from Parent {
|
||||
send(msg) { // ❌ エラー: overrideキーワードなし
|
||||
print("Child implementation")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. コンストラクタオーバーロード
|
||||
```nyash
|
||||
box Node {
|
||||
init(id) { // 最初の定義
|
||||
me.id = id
|
||||
}
|
||||
|
||||
init(id, name) { // ❌ エラー: 重複定義
|
||||
me.id = id
|
||||
me.name = name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 同名メソッド重複定義
|
||||
```nyash
|
||||
box Example {
|
||||
process(data) { // 最初の定義
|
||||
print("Version 1")
|
||||
}
|
||||
|
||||
process(data) { // ❌ エラー: 重複定義
|
||||
print("Version 2")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ ベストプラクティス
|
||||
|
||||
### 1. 明示的な親呼び出し
|
||||
```nyash
|
||||
box MeshNode from P2PBox {
|
||||
override send(intent, data, target) {
|
||||
// 前処理
|
||||
me.routing.logOutgoing(target)
|
||||
|
||||
// 親実装呼び出し(明示的)
|
||||
from P2PBox.send(intent, data, target)
|
||||
|
||||
// 後処理
|
||||
me.statistics.incrementSentCount()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 多重デリゲーションでの順序指定
|
||||
```nyash
|
||||
box SmartNode from P2PBox, Logger, Cache {
|
||||
override send(intent, data, target) {
|
||||
// 1. ログ記録
|
||||
from Logger.info("Sending to: " + target)
|
||||
|
||||
// 2. キャッシュ保存
|
||||
from Cache.store(intent + ":" + target, data)
|
||||
|
||||
// 3. 実際の送信
|
||||
from P2PBox.send(intent, data, target)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. コンストラクタチェーン
|
||||
```nyash
|
||||
box SecureNode from P2PBox {
|
||||
init security = SecurityManager()
|
||||
|
||||
init(nodeId, world, keyFile) { # init構文に統一
|
||||
// 1. 親初期化(必須)
|
||||
from P2PBox.init(nodeId, world)
|
||||
|
||||
// 2. 子固有の初期化
|
||||
me.security = SecurityManager()
|
||||
me.security.loadKeys(keyFile)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔮 将来の拡張
|
||||
|
||||
### 1. Final メソッド(検討中)
|
||||
```nyash
|
||||
box Parent {
|
||||
final criticalMethod() { // オーバーライド禁止
|
||||
// 重要な処理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Abstract メソッド(検討中)
|
||||
```nyash
|
||||
box AbstractParent {
|
||||
abstract process(data) // 子でのoverride必須
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Override チェック強化(検討中)
|
||||
```nyash
|
||||
override! send(data) { // 親呼び出し必須チェック
|
||||
// from Parent.send(data) がないとエラー
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 他言語との比較
|
||||
|
||||
| 言語 | 継承方式 | オーバーライド | 親呼び出し | 多重継承 |
|
||||
|------|----------|---------------|-----------|----------|
|
||||
| **Nyash** | デリゲーション | `override` 必須 | `from Parent.method()` | 明示的解消 |
|
||||
| Java | クラス継承 | `@Override` 注釈 | `super.method()` | 不可 |
|
||||
| Python | クラス継承 | 暗黙 | `super().method()` | MRO(複雑) |
|
||||
| C# | クラス継承 | `override` 必須 | `base.method()` | 不可 |
|
||||
| TypeScript | プロトタイプ | 暗黙 | `super.method()` | 不可 |
|
||||
|
||||
### Nyashの優位性
|
||||
1. **完全な明示性**: すべての動作が明確
|
||||
2. **曖昧性の完全排除**: 多重デリゲーションでも安全
|
||||
3. **統一構文**: デリゲーションとオーバーライドが統合
|
||||
4. **初学者フレンドリー**: 分かりやすいエラーメッセージ
|
||||
|
||||
---
|
||||
|
||||
**この仕様により、Nyashは世界初の「完全明示デリゲーション言語」として、プログラミング言語史に新たな1ページを刻むことになります。** 🌟
|
||||
295
docs/reference/core-language/portability-contract.md
Normal file
295
docs/reference/core-language/portability-contract.md
Normal file
@ -0,0 +1,295 @@
|
||||
# 🤝 Nyash Portability Contract v0
|
||||
|
||||
*ChatGPT5アドバイス・全バックエンド互換性保証仕様*
|
||||
|
||||
## 🎯 目的
|
||||
|
||||
**「nyash --target= interp / vm / wasm / aot-rust / jit-cranelift」で同一プログラムが同一結果を保証**
|
||||
|
||||
全バックエンドでNyashプログラムが確実に動作し、最適化レベルに関係なく**決定的で予測可能な実行**を実現。
|
||||
|
||||
## 🔧 **Contract v0 仕様**
|
||||
|
||||
### 1️⃣ **決定的破棄(Deterministic Finalization)**
|
||||
|
||||
#### **強参照のみ伝播保証**
|
||||
```rust
|
||||
// ✅ 保証される動作
|
||||
box Parent {
|
||||
child_strong: ChildBox // 強参照→破棄連鎖
|
||||
}
|
||||
|
||||
parent.fini() // 必ずchild_strong.fini()も呼ばれる
|
||||
```
|
||||
|
||||
#### **破棄順序の決定性**
|
||||
```nyash
|
||||
// 破棄順序: 最新→最古(スタック順序)
|
||||
box Child from Parent {
|
||||
init { data }
|
||||
pack() {
|
||||
from Parent.pack() // 1. Parent初期化
|
||||
me.data = "child" // 2. Child初期化
|
||||
}
|
||||
// fini順序: 2→1(逆順破棄)
|
||||
}
|
||||
```
|
||||
|
||||
#### **例外安全性**
|
||||
```rust
|
||||
pub enum FinalizationGuarantee {
|
||||
AlwaysExecuted, // fini()は例外時も必ず実行
|
||||
NoDoubleDestroy, // 同一オブジェクトの二重破棄禁止
|
||||
OrderPreserved, // 初期化と逆順での破棄保証
|
||||
}
|
||||
```
|
||||
|
||||
### 2️⃣ **weak参照の非伝播+生存チェック**
|
||||
|
||||
#### **非伝播保証**
|
||||
```nyash
|
||||
box Parent {
|
||||
init { child_weak }
|
||||
|
||||
pack() {
|
||||
local child = new Child()
|
||||
me.child_weak = weak(child) // weak参照生成
|
||||
// child がfini()されても Parent は影響なし
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **生存チェック必須**
|
||||
```mir
|
||||
// MIR レベルでの生存チェック
|
||||
%alive = weak_load %weak_ref
|
||||
br %alive -> %use_bb, %null_bb
|
||||
|
||||
%use_bb:
|
||||
// weak参照が有効な場合の処理
|
||||
%value = /* weak_refの値使用 */
|
||||
jmp %continue_bb
|
||||
|
||||
%null_bb:
|
||||
// weak参照が無効な場合の処理
|
||||
%value = const null
|
||||
jmp %continue_bb
|
||||
|
||||
%continue_bb:
|
||||
// 合流地点(Phi必須)
|
||||
%result = phi [%value from %use_bb, %value from %null_bb]
|
||||
```
|
||||
|
||||
#### **自動null化契約**
|
||||
```rust
|
||||
pub struct WeakContract {
|
||||
auto_nullification: true, // 参照先fini()時に自動null
|
||||
no_dangling_pointers: true, // ダングリングポインタ禁止
|
||||
thread_safe_access: true, // マルチスレッド安全アクセス
|
||||
}
|
||||
```
|
||||
|
||||
### 3️⃣ **Effect意味論(最適化可能性)**
|
||||
|
||||
#### **Effect分類契約**
|
||||
```rust
|
||||
pub enum EffectLevel {
|
||||
Pure, // 副作用なし→並び替え・除去・重複実行可能
|
||||
Mut, // メモリ変更→順序保証必要・並列化制限
|
||||
Io, // I/O操作→実行順序厳密保証・キャッシュ禁止
|
||||
Bus, // 分散通信→elision対象・ネットワーク最適化可能
|
||||
}
|
||||
```
|
||||
|
||||
#### **最適化契約**
|
||||
```mir
|
||||
// Pure関数→最適化可能
|
||||
%result1 = call @pure_function(%arg) effects=[PURE]
|
||||
%result2 = call @pure_function(%arg) effects=[PURE]
|
||||
// → 最適化: %result2 = copy %result1
|
||||
|
||||
// Mut操作→順序保証
|
||||
store %value1 -> %ptr effects=[MUT]
|
||||
store %value2 -> %ptr effects=[MUT]
|
||||
// → 順序維持必須
|
||||
|
||||
// Bus操作→elision対象
|
||||
send %bus, %message effects=[BUS]
|
||||
// → ネットワーク最適化・バッチ化可能
|
||||
```
|
||||
|
||||
### 4️⃣ **Bus-elision基盤契約**
|
||||
|
||||
#### **elision ON/OFF同一結果保証**
|
||||
```bash
|
||||
# 最適化ON→高速実行
|
||||
nyash --elide-bus --target wasm program.nyash
|
||||
|
||||
# 最適化OFF→完全分散実行
|
||||
nyash --no-elide-bus --target vm program.nyash
|
||||
|
||||
# 結果は必ず同一(契約保証)
|
||||
```
|
||||
|
||||
#### **Bus操作の意味保証**
|
||||
```mir
|
||||
// Bus送信の意味論
|
||||
send %bus, %message effects=[BUS] {
|
||||
// elision OFF: 実際のネットワーク送信
|
||||
// elision ON: ローカル最適化(結果同一)
|
||||
}
|
||||
|
||||
// Bus受信の意味論
|
||||
%msg = recv %bus effects=[BUS] {
|
||||
// elision OFF: ネットワーク受信待ち
|
||||
// elision ON: ローカル値返却(結果同一)
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 **Contract検証システム**
|
||||
|
||||
### **互換テストスイート**
|
||||
```rust
|
||||
// tests/portability_contract_tests.rs
|
||||
#[test]
|
||||
fn test_deterministic_finalization() {
|
||||
let program = "/* fini順序テスト */";
|
||||
|
||||
let interp_result = run_interpreter(program);
|
||||
let vm_result = run_vm(program);
|
||||
let wasm_result = run_wasm(program);
|
||||
|
||||
// 破棄順序・タイミングが全バックエンドで同一
|
||||
assert_eq!(interp_result.finalization_order, vm_result.finalization_order);
|
||||
assert_eq!(vm_result.finalization_order, wasm_result.finalization_order);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_reference_semantics() {
|
||||
let program = "/* weak参照テスト */";
|
||||
|
||||
// 生存チェック・null化が全バックエンドで同一動作
|
||||
let results = run_all_backends(program);
|
||||
assert_all_equal(results.map(|r| r.weak_behavior));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_effect_optimization_equivalence() {
|
||||
let program = "/* Effect最適化テスト */";
|
||||
|
||||
// PURE関数の最適化結果が同一
|
||||
let optimized = run_with_optimization(program);
|
||||
let reference = run_without_optimization(program);
|
||||
assert_eq!(optimized.output, reference.output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bus_elision_equivalence() {
|
||||
let program = "/* Bus通信テスト */";
|
||||
|
||||
let elision_on = run_with_flag(program, "--elide-bus");
|
||||
let elision_off = run_with_flag(program, "--no-elide-bus");
|
||||
|
||||
// Bus最適化ON/OFFで結果同一
|
||||
assert_eq!(elision_on.output, elision_off.output);
|
||||
}
|
||||
```
|
||||
|
||||
### **Golden Dump検証**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# scripts/verify_portability_contract.sh
|
||||
|
||||
echo "🧪 Portability Contract v0 検証中..."
|
||||
|
||||
# 1. MIR出力一致検証
|
||||
nyash --dump-mir test.nyash > golden.mir
|
||||
nyash --dump-mir test.nyash > current.mir
|
||||
if ! diff golden.mir current.mir; then
|
||||
echo "❌ MIR回帰エラー検出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. 全バックエンド同一出力
|
||||
declare -a backends=("interp" "vm" "wasm")
|
||||
for backend in "${backends[@]}"; do
|
||||
nyash --target $backend test.nyash > ${backend}.out
|
||||
done
|
||||
|
||||
# 出力一致確認
|
||||
if diff interp.out vm.out && diff vm.out wasm.out; then
|
||||
echo "✅ 全バックエンド出力一致"
|
||||
else
|
||||
echo "❌ バックエンド出力差異検出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. Bus-elision検証
|
||||
nyash --elide-bus test.nyash > elision_on.out
|
||||
nyash --no-elide-bus test.nyash > elision_off.out
|
||||
if diff elision_on.out elision_off.out; then
|
||||
echo "✅ Bus-elision同一結果"
|
||||
else
|
||||
echo "❌ Bus-elision結果差異"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🎉 Portability Contract v0 検証完了"
|
||||
```
|
||||
|
||||
## 📊 **Contract適合レベル**
|
||||
|
||||
### **Tier-0: 基本互換性**
|
||||
- [ ] **決定的破棄**: fini()順序がバックエンド間で同一
|
||||
- [ ] **weak非伝播**: weak参照が親破棄に影響しない
|
||||
- [ ] **基本Effect**: PURE/MUT/IO の意味論統一
|
||||
- [ ] **出力一致**: 同一プログラム→同一標準出力
|
||||
|
||||
### **Tier-1: 最適化互換性**
|
||||
- [ ] **PURE最適化**: 純粋関数の除去・移動がバックエンド間で同等
|
||||
- [ ] **weak生存チェック**: 全バックエンドで同一タイミング
|
||||
- [ ] **Bus-elision**: ON/OFF切り替えで結果同一
|
||||
- [ ] **性能予測**: 最適化レベル差が定量的
|
||||
|
||||
### **Tier-2: 高度互換性**
|
||||
- [ ] **メモリレイアウト**: Box構造がバックエンド間で互換
|
||||
- [ ] **エラー処理**: 例外・パニックが同一動作
|
||||
- [ ] **並行性**: Future/awaitが同一意味論
|
||||
- [ ] **デバッグ**: スタックトレース・診断情報が同等
|
||||
|
||||
## ⚡ **実装優先順位**
|
||||
|
||||
### **Phase 8.4(今すぐ)**
|
||||
1. **Tier-0契約実装**: 基本互換性確保
|
||||
2. **Golden dump自動化**: CI/CDで回帰検出
|
||||
3. **Bus命令設計**: elision基盤構築
|
||||
|
||||
### **Phase 8.5(短期)**
|
||||
1. **Tier-1契約実装**: 最適化互換性
|
||||
2. **性能ベンチマーク**: 契約準拠性測定
|
||||
3. **エラー契約**: 例外処理統一
|
||||
|
||||
### **Phase 9+(中長期)**
|
||||
1. **Tier-2契約実装**: 高度互換性
|
||||
2. **形式検証**: 契約の数学的証明
|
||||
3. **認証システム**: 契約適合認定
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **期待効果**
|
||||
|
||||
### **開発者体験**
|
||||
- **予測可能性**: どのバックエンドでも同一動作保証
|
||||
- **デバッグ容易性**: バックエンド切り替えで問題切り分け
|
||||
- **最適化信頼性**: 高速化しても結果不変保証
|
||||
|
||||
### **Nyash言語価値**
|
||||
- **差別化**: 「全バックエンド互換」言語として独自性
|
||||
- **信頼性**: エンタープライズ採用の技術的根拠
|
||||
- **拡張性**: 新バックエンド追加時の品質保証
|
||||
|
||||
---
|
||||
|
||||
*最終更新: 2025-08-14 - ChatGPT5アドバイス完全実装*
|
||||
|
||||
*「Everything is Box」×「全バックエンド互換」= Nyashの技術的優位性*
|
||||
285
docs/reference/execution-backend/mir-26-specification.md
Normal file
285
docs/reference/execution-backend/mir-26-specification.md
Normal file
@ -0,0 +1,285 @@
|
||||
# MIR 26-Instruction Specification
|
||||
|
||||
*Nyash Machine Intermediate Representation - ChatGPT5 Compliant Version*
|
||||
|
||||
## Overview
|
||||
|
||||
This document specifies the official 26-instruction set for Nyash MIR (Machine Intermediate Representation), following the ChatGPT5 specification and AI consensus from the grand meeting.
|
||||
|
||||
## Instruction Set (26 Instructions)
|
||||
|
||||
### Tier-0: Core Instructions (5)
|
||||
|
||||
1. **Const** - Load constant value
|
||||
```mir
|
||||
%dst = const <value>
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
2. **BinOp** - Binary operations (includes arithmetic, logical, comparison)
|
||||
```mir
|
||||
%dst = binop <op> %lhs, %rhs
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
3. **Compare** - Comparison operations
|
||||
```mir
|
||||
%dst = icmp <op> %lhs, %rhs
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
4. **Phi** - SSA phi node
|
||||
```mir
|
||||
%dst = phi [%bb1: %val1], [%bb2: %val2], ...
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
5. **Call** - Function and intrinsic calls
|
||||
```mir
|
||||
%dst = call <func>(%arg1, %arg2, ...)
|
||||
call <func>(%arg1, %arg2, ...)
|
||||
```
|
||||
Effect: context-dependent
|
||||
|
||||
### Tier-0: Control Flow (3)
|
||||
|
||||
6. **Branch** - Conditional branch
|
||||
```mir
|
||||
br %cond, label %then, label %else
|
||||
```
|
||||
Effect: control
|
||||
|
||||
7. **Jump** - Unconditional jump
|
||||
```mir
|
||||
br label %target
|
||||
```
|
||||
Effect: control
|
||||
|
||||
8. **Return** - Return from function
|
||||
```mir
|
||||
ret %value
|
||||
ret void
|
||||
```
|
||||
Effect: control
|
||||
|
||||
### Tier-1: Box Operations (5)
|
||||
|
||||
9. **NewBox** - Create new Box instance
|
||||
```mir
|
||||
%dst = new <BoxType>(%arg1, %arg2, ...)
|
||||
```
|
||||
Effect: mut
|
||||
|
||||
10. **BoxFieldLoad** - Load field from Box
|
||||
```mir
|
||||
%dst = %box.field
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
11. **BoxFieldStore** - Store field to Box
|
||||
```mir
|
||||
%box.field = %value
|
||||
```
|
||||
Effect: mut
|
||||
|
||||
12. **BoxCall** - Call Box method
|
||||
```mir
|
||||
%dst = call %box.method(%arg1, %arg2, ...)
|
||||
```
|
||||
Effect: context-dependent
|
||||
|
||||
13. **ExternCall** - Call external function
|
||||
```mir
|
||||
%dst = extern_call "interface.method"(%arg1, %arg2, ...)
|
||||
```
|
||||
Effect: context-dependent
|
||||
|
||||
### Tier-1: Reference Operations (6)
|
||||
|
||||
14. **RefGet** - Get reference target
|
||||
```mir
|
||||
%dst = ref_get %reference
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
15. **RefSet** - Set reference target
|
||||
```mir
|
||||
ref_set %reference -> %new_target
|
||||
```
|
||||
Effect: mut
|
||||
|
||||
16. **WeakNew** - Create weak reference
|
||||
```mir
|
||||
%dst = weak_new %box
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
17. **WeakLoad** - Load from weak reference
|
||||
```mir
|
||||
%dst = weak_load %weak_ref
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
18. **WeakCheck** - Check if weak reference is alive
|
||||
```mir
|
||||
%dst = weak_check %weak_ref
|
||||
```
|
||||
Effect: pure
|
||||
|
||||
19. **Safepoint** - GC safepoint
|
||||
```mir
|
||||
safepoint
|
||||
```
|
||||
Effect: io
|
||||
|
||||
### Tier-2: Advanced Operations (7)
|
||||
|
||||
20. **Send** - Send message via Bus
|
||||
```mir
|
||||
send %data -> %target
|
||||
```
|
||||
Effect: io
|
||||
|
||||
21. **Recv** - Receive message from Bus
|
||||
```mir
|
||||
%dst = recv %source
|
||||
```
|
||||
Effect: io
|
||||
|
||||
22. **TailCall** - Tail call optimization
|
||||
```mir
|
||||
tail_call %func(%arg1, %arg2, ...)
|
||||
```
|
||||
Effect: control
|
||||
|
||||
23. **Adopt** - Adopt ownership
|
||||
```mir
|
||||
adopt %parent <- %child
|
||||
```
|
||||
Effect: mut
|
||||
|
||||
24. **Release** - Release ownership
|
||||
```mir
|
||||
release %reference
|
||||
```
|
||||
Effect: mut
|
||||
|
||||
25. **MemCopy** - Optimized memory copy
|
||||
```mir
|
||||
memcpy %dst <- %src, %size
|
||||
```
|
||||
Effect: mut
|
||||
|
||||
26. **AtomicFence** - Memory barrier
|
||||
```mir
|
||||
atomic_fence <ordering>
|
||||
```
|
||||
Effect: io
|
||||
|
||||
## Deprecated Instructions (17)
|
||||
|
||||
The following instructions have been removed from the specification:
|
||||
|
||||
1. **UnaryOp** → Use `BinOp` (e.g., `not %x` → `%x xor true`)
|
||||
2. **Load** → Use `BoxFieldLoad`
|
||||
3. **Store** → Use `BoxFieldStore`
|
||||
4. **ArrayGet** → Use `BoxFieldLoad` or `Call @array_get`
|
||||
5. **ArraySet** → Use `BoxFieldStore` or `Call @array_set`
|
||||
6. **Print** → Use `Call @print`
|
||||
7. **Debug** → Use `Call @debug`
|
||||
8. **TypeCheck** → Use `Call @type_check`
|
||||
9. **Cast** → Use `Call @cast`
|
||||
10. **Throw** → Use `Call @throw`
|
||||
11. **Catch** → Use `Call @catch`
|
||||
12. **Copy** → Optimization pass only
|
||||
13. **Nop** → Not needed
|
||||
14. **RefNew** → References handled implicitly
|
||||
15. **BarrierRead** → Use `AtomicFence`
|
||||
16. **BarrierWrite** → Use `AtomicFence`
|
||||
17. **FutureNew/FutureSet/Await** → Use `NewBox` + `BoxCall`
|
||||
|
||||
## Intrinsic Functions
|
||||
|
||||
Standard intrinsic functions available via `Call` instruction:
|
||||
|
||||
- `@print(value)` - Print value to console
|
||||
- `@debug(value, message)` - Debug output
|
||||
- `@type_check(value, type)` - Runtime type check
|
||||
- `@cast(value, type)` - Type cast
|
||||
- `@throw(exception)` - Throw exception
|
||||
- `@catch(type, handler)` - Set exception handler
|
||||
- `@array_get(array, index)` - Array element access
|
||||
- `@array_set(array, index, value)` - Array element update
|
||||
- `@unary_neg(value)` - Unary negation
|
||||
- `@unary_not(value)` - Logical not
|
||||
|
||||
## Effect System
|
||||
|
||||
Each instruction has an associated effect mask:
|
||||
|
||||
- **pure** - No side effects, can be reordered/eliminated
|
||||
- **mut** - Mutates memory, order-dependent
|
||||
- **io** - I/O operations, cannot be eliminated
|
||||
- **control** - Control flow, affects program execution path
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### UnaryOp Migration
|
||||
```mir
|
||||
// Before
|
||||
%dst = neg %x
|
||||
%dst = not %x
|
||||
|
||||
// After
|
||||
%dst = binop sub 0, %x
|
||||
%dst = binop xor %x, true
|
||||
```
|
||||
|
||||
### Load/Store Migration
|
||||
```mir
|
||||
// Before
|
||||
%value = load %ptr
|
||||
store %value -> %ptr
|
||||
|
||||
// After
|
||||
%value = %box.field
|
||||
%box.field = %value
|
||||
```
|
||||
|
||||
### Print Migration
|
||||
```mir
|
||||
// Before
|
||||
print %value
|
||||
|
||||
// After
|
||||
call @print(%value)
|
||||
```
|
||||
|
||||
### Future Operations Migration
|
||||
```mir
|
||||
// Before
|
||||
%future = future_new %value
|
||||
future_set %future = %result
|
||||
%result = await %future
|
||||
|
||||
// After
|
||||
%future = new FutureBox(%value)
|
||||
call %future.set(%result)
|
||||
%result = call %future.await()
|
||||
```
|
||||
|
||||
## Implementation Status
|
||||
|
||||
- ✅ Phase 1: New instruction definitions
|
||||
- ✅ Phase 2: Frontend migration (AST→MIR generation)
|
||||
- ✅ Phase 3: Optimization pass migration
|
||||
- ✅ Phase 4: Backend implementation (VM/WASM)
|
||||
- ✅ Phase 5-1: Deprecated instruction marking
|
||||
- ✅ Phase 5-2: Backend rejection of deprecated instructions
|
||||
- ✅ Phase 5-3: Frontend stops generating deprecated instructions
|
||||
- 🔄 Phase 5-4: Test and documentation updates (in progress)
|
||||
- 📋 Phase 5-5: Final verification and cleanup
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2025-08-17*
|
||||
254
docs/reference/execution-backend/p2p_spec.md
Normal file
254
docs/reference/execution-backend/p2p_spec.md
Normal file
@ -0,0 +1,254 @@
|
||||
# 🌐 P2PBox完全実装 - AI大会議仕様準拠
|
||||
|
||||
## 📋 Issue概要
|
||||
|
||||
**目標**: NyaMeshP2Pライブラリ実現のためのP2P通信システムを、AI大会議で決定した最新仕様に従って完全実装する
|
||||
|
||||
**重要**: 既存の `src/boxes/intent_box.rs` と `src/boxes/p2p_box.rs` は**古い設計**のため、**完全に作り直し**が必要
|
||||
|
||||
## 🎯 AI大会議決定事項
|
||||
|
||||
### ✅ 採用仕様
|
||||
- **構造化IntentBox**: `name` + `payload` 形式のメッセージBox
|
||||
- **個別送信のみ**: `send(to, message)` 固定API
|
||||
- **明示的デリゲーション**: `from Parent.method()` 統一構文
|
||||
|
||||
### ❌ 除外仕様
|
||||
- **ブロードキャスト**: 安全性のため完全除外(無限ループリスク回避)
|
||||
- **関数オーバーロード**: `send(a)` vs `send(a,b)` 分岐不採用
|
||||
|
||||
## 🏗️ 新アーキテクチャ設計
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
||||
│ P2PBox │◄──►│ MessageBus │◄──►│ Transport │
|
||||
│ (ユーザーAPI) │ │ (ローカル配送) │ │ (送受信層) │
|
||||
└─────────────┘ └──────────────┘ └─────────────┘
|
||||
▲ ▲ ▲
|
||||
│ │ │
|
||||
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
||||
│ IntentBox │ │ ハンドラ管理 │ │ InProcess │
|
||||
│ (構造化MSG) │ │ ノード登録 │ │ WebSocket │
|
||||
└─────────────┘ └──────────────┘ │ WebRTC │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
## 📦 段階的実装計画
|
||||
|
||||
### 🎯 **Phase 1: 基盤実装**
|
||||
|
||||
#### **Step 1: IntentBox(構造化メッセージ)**
|
||||
**ファイル**: `src/boxes/intent_box.rs` (完全作り直し)
|
||||
|
||||
```rust
|
||||
// 新しいIntentBox設計
|
||||
pub struct IntentBoxData {
|
||||
pub name: String, // "chat.message", "file.share"等
|
||||
pub payload: serde_json::Value, // 任意のJSON data
|
||||
}
|
||||
pub type IntentBox = Arc<Mutex<IntentBoxData>>;
|
||||
```
|
||||
|
||||
**実装要件**:
|
||||
- Arc<Mutex>統一パターン準拠
|
||||
- BoxCore + NyashBox実装
|
||||
- serde_json::Value使用
|
||||
|
||||
**テストコード**:
|
||||
```nyash
|
||||
// tests/phase2/intent_box_test.nyash
|
||||
local msg = new IntentBox("chat.message", { text: "Hello P2P!" })
|
||||
local console = new ConsoleBox()
|
||||
console.log("Name: " + msg.name) // "chat.message"
|
||||
console.log("Text: " + msg.payload.text) // "Hello P2P!"
|
||||
```
|
||||
|
||||
#### **Step 2: MessageBus(プロセス内シングルトン)**
|
||||
**ファイル**: `src/messaging/message_bus.rs` (新規作成)
|
||||
|
||||
```rust
|
||||
pub struct MessageBusData {
|
||||
nodes: HashMap<String, BusEndpoint>, // ノード登録
|
||||
subscribers: HashMap<String, Vec<IntentHandler>>, // ハンドラー管理
|
||||
}
|
||||
pub type MessageBus = Arc<Mutex<MessageBusData>>;
|
||||
|
||||
impl MessageBusData {
|
||||
pub fn global() -> MessageBus // シングルトンアクセス
|
||||
pub fn register_node(&mut self, id: String, endpoint: BusEndpoint)
|
||||
pub fn route(&self, to: &str, intent: IntentBox) -> Result<(), SendError>
|
||||
}
|
||||
```
|
||||
|
||||
#### **Step 3: Transport trait(送受信抽象化)**
|
||||
**ファイル**: `src/transport/mod.rs` (新規作成)
|
||||
|
||||
```rust
|
||||
pub trait Transport: Send + Sync {
|
||||
fn node_id(&self) -> &str;
|
||||
fn send(&self, to: &str, intent: IntentBox, opts: SendOpts) -> Result<(), SendError>;
|
||||
fn on_receive(&mut self, callback: Box<dyn Fn(IntentEnvelope) + Send + Sync>);
|
||||
}
|
||||
```
|
||||
|
||||
### 🎯 **Phase 2: InProcess実装**
|
||||
|
||||
#### **Step 4: InProcessTransport**
|
||||
**ファイル**: `src/transport/inprocess.rs` (新規作成)
|
||||
|
||||
```rust
|
||||
pub struct InProcessTransport {
|
||||
node_id: String,
|
||||
bus: MessageBus, // MessageBus::global()を使用
|
||||
}
|
||||
|
||||
impl Transport for InProcessTransport {
|
||||
// Bus経由の高速ローカル配送実装
|
||||
}
|
||||
```
|
||||
|
||||
### 🎯 **Phase 3: P2PBox統合**
|
||||
|
||||
#### **Step 5: P2PBox基本実装**
|
||||
**ファイル**: `src/boxes/p2p_box.rs` (完全作り直し)
|
||||
|
||||
```rust
|
||||
pub struct P2PBoxData {
|
||||
node_id: String,
|
||||
transport: Arc<dyn Transport>,
|
||||
bus: MessageBus, // 全P2PBoxで共有
|
||||
}
|
||||
pub type P2PBox = Arc<Mutex<P2PBoxData>>;
|
||||
|
||||
impl P2PBoxData {
|
||||
pub fn new(node_id: String, kind: TransportKind) -> P2PBox
|
||||
pub fn on(&self, intent_name: &str, handler: IntentHandler) -> Result<(), P2PError>
|
||||
pub fn send(&self, to: &str, intent: IntentBox) -> Result<(), SendError>
|
||||
// ブロードキャストメソッドは実装しない
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 包括的テスト要件
|
||||
|
||||
### **基本動作テスト**
|
||||
**ファイル**: `test_p2p_basic_new.nyash`
|
||||
|
||||
```nyash
|
||||
// 2つのノード作成
|
||||
local node_a = new P2PBox("alice", transport: "inprocess")
|
||||
local node_b = new P2PBox("bob", transport: "inprocess")
|
||||
|
||||
// 受信ハンドラ設定
|
||||
node_b.on("chat.message", function(intent, from) {
|
||||
local console = new ConsoleBox()
|
||||
console.log("From " + from + ": " + intent.payload.text)
|
||||
})
|
||||
|
||||
// メッセージ送信
|
||||
local msg = new IntentBox("chat.message", { text: "Hello P2P!" })
|
||||
node_a.send("bob", msg) // → "From alice: Hello P2P!"
|
||||
```
|
||||
|
||||
### **エラーハンドリングテスト**
|
||||
```nyash
|
||||
// 存在しないノードへの送信
|
||||
local result = node_a.send("nonexistent", msg)
|
||||
// → SendError::NodeNotFound
|
||||
|
||||
// 不正なIntentBox
|
||||
local invalid_msg = "not an IntentBox"
|
||||
local result = node_a.send("bob", invalid_msg)
|
||||
// → 型エラー
|
||||
```
|
||||
|
||||
### **パフォーマンステスト**
|
||||
```nyash
|
||||
// 大量メッセージ送信テスト
|
||||
local start_time = new TimeBox()
|
||||
loop(i < 1000) {
|
||||
local msg = new IntentBox("test.performance", { id: i })
|
||||
node_a.send("bob", msg)
|
||||
i = i + 1
|
||||
}
|
||||
local end_time = new TimeBox()
|
||||
// 実行時間計測
|
||||
```
|
||||
|
||||
## 📁 必要なディレクトリ構成
|
||||
|
||||
```
|
||||
src/
|
||||
├── boxes/
|
||||
│ ├── intent_box.rs # 完全作り直し
|
||||
│ └── p2p_box.rs # 完全作り直し
|
||||
├── messaging/ # 新規作成
|
||||
│ └── message_bus.rs # MessageBus実装
|
||||
└── transport/ # 新規作成
|
||||
├── mod.rs # Transport trait
|
||||
└── inprocess.rs # InProcessTransport
|
||||
```
|
||||
|
||||
## 🔧 実装時の重要注意点
|
||||
|
||||
### **Arc<Mutex>統一パターン厳守**
|
||||
```rust
|
||||
// ✅ 正しい統一パターン
|
||||
pub type IntentBox = Arc<Mutex<IntentBoxData>>;
|
||||
pub type MessageBus = Arc<Mutex<MessageBusData>>;
|
||||
pub type P2PBox = Arc<Mutex<P2PBoxData>>;
|
||||
|
||||
// ❌ 避けるべき
|
||||
pub struct IntentBox { ... } // Arcなし
|
||||
```
|
||||
|
||||
### **BoxCore実装必須**
|
||||
```rust
|
||||
impl BoxCore for IntentBox {
|
||||
fn box_id(&self) -> u64 { self.lock().unwrap().base.id }
|
||||
fn parent_type_id(&self) -> Option<TypeId> { None }
|
||||
fn fmt_box(&self, f: &mut fmt::Formatter) -> fmt::Result { ... }
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||
}
|
||||
```
|
||||
|
||||
### **エラーハンドリング設計**
|
||||
```rust
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SendError {
|
||||
NodeNotFound(String), // 宛先ノードが見つからない
|
||||
NetworkError(String), // ネットワークエラー
|
||||
SerializationError(String), // JSON変換エラー
|
||||
BusError(String), // MessageBusエラー
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 成功の定義
|
||||
|
||||
以下のテストが全て通過すること:
|
||||
|
||||
1. **基本通信**: ノード間でIntentBoxメッセージ送受信
|
||||
2. **ハンドラ登録**: `on()` でイベントリスナー正常動作
|
||||
3. **エラーハンドリング**: 不正な送信先・データで適切エラー
|
||||
4. **パフォーマンス**: 1000メッセージ/秒以上の送信性能
|
||||
5. **メモリ安全性**: valgrind等でメモリリーク検出なし
|
||||
|
||||
## 📚 参考ドキュメント
|
||||
|
||||
- **[P2P_GUIDE.md](docs/P2P_GUIDE.md)** - 設計詳細・使用例
|
||||
- **[CURRENT_TASK.md](CURRENT_TASK.md)** - 実装状況・優先順位
|
||||
- **[ai_conference_overload_decision.md](ai_conference_overload_decision.md)** - AI大会議決定事項
|
||||
- **[docs/reference/override-delegation-syntax.md](docs/reference/override-delegation-syntax.md)** - デリゲーション構文仕様
|
||||
|
||||
## 🚀 実装開始
|
||||
|
||||
**Priority**: High
|
||||
**Assignee**: Copilot
|
||||
**Labels**: enhancement, p2p, breaking-change
|
||||
**Milestone**: P2P Phase 2 Complete
|
||||
|
||||
**最初に取り組むべき**: Step 1 IntentBox の完全作り直し
|
||||
|
||||
---
|
||||
|
||||
🎉 **この実装により、Nyashは本格的なP2P通信システムを持つ現代的プログラミング言語になります!**
|
||||
525
docs/reference/language/LANGUAGE_REFERENCE_2025.md
Normal file
525
docs/reference/language/LANGUAGE_REFERENCE_2025.md
Normal file
@ -0,0 +1,525 @@
|
||||
# 🚀 Nyash Language Reference 2025
|
||||
|
||||
**最終更新: 2025年8月11日 - デリゲーション革命完了!`from`統一構文+`init`構文決定!**
|
||||
|
||||
## 📖 概要
|
||||
|
||||
Nyashは「Everything is Box」哲学に基づく革新的プログラミング言語です。
|
||||
Rust製インタープリターによる高性能実行と、直感的な構文により、学習しやすく実用的な言語として完成しました。
|
||||
|
||||
---
|
||||
|
||||
## 🔤 **1. 予約語・キーワード完全リスト**
|
||||
|
||||
### **コア言語**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `box` | クラス定義 | `box MyClass { }` |
|
||||
| `static` | 静的Box・関数定義 | `static box Main { }` |
|
||||
| `interface` | インターフェース定義 | `interface Comparable { }` |
|
||||
| `from` | デリゲーション指定 | `box Child from Parent { }` |
|
||||
| `new` | オブジェクト生成 | `new ConsoleBox()` |
|
||||
| `me`/`this` | 自己参照 | `me.field = value` |
|
||||
|
||||
### **変数・スコープ**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `local` | ローカル変数宣言 | `local x, y = 10` |
|
||||
| `outbox` | 所有権移転変数 | `outbox result = compute()` |
|
||||
| `global` | グローバル変数 | `global CONFIG = "dev"` |
|
||||
| `init` | フィールド初期化ブロック | `init { name, age }` |
|
||||
|
||||
### **制御構文**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `if` | 条件分岐 | `if condition { }` |
|
||||
| `else` | else節 | `else { }` |
|
||||
| `loop` | ループ(唯一の形式) | `loop(condition) { }` |
|
||||
| `break` | ループ脱出 | `break` |
|
||||
| `return` | 関数リターン | `return value` |
|
||||
|
||||
### **論理・演算**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `not` | 論理否定 | `not condition` |
|
||||
| `and` | 論理積 | `a and b` |
|
||||
| `or` | 論理和 | `a or b` |
|
||||
| `true`/`false` | 真偽値 | `flag = true` |
|
||||
|
||||
### **非同期・並行**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `nowait` | 非同期実行 | `nowait future = task()` |
|
||||
| `await` | 待機・結果取得 | `result = await future` |
|
||||
|
||||
### **例外処理**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `try` | 例外捕獲開始 | `try { }` |
|
||||
| `catch` | 例外処理 | `catch (e) { }` |
|
||||
| `finally` | 最終処理 | `finally { }` |
|
||||
| `throw` | 例外発生 | `throw error` |
|
||||
|
||||
### **その他**
|
||||
| 予約語 | 用途 | 例 |
|
||||
|-------|------|---|
|
||||
| `function` | 関数定義 | `function add(a,b) { }` |
|
||||
| `print` | 出力 | `print("Hello")` |
|
||||
| `include` | ファイル取り込み | `include "math.nyash"` |
|
||||
|
||||
---
|
||||
|
||||
## 📝 **2. 文法・構文仕様**
|
||||
|
||||
### **2.1 Box定義文法**
|
||||
|
||||
#### **基本Box**
|
||||
```nyash
|
||||
box ClassName {
|
||||
init { field1, field2, field3 } # カンマ必須!CPU暴走防止
|
||||
|
||||
# コンストラクタ
|
||||
init(param1, param2) { # init構文に統一
|
||||
me.field1 = param1
|
||||
me.field2 = param2
|
||||
me.field3 = defaultValue()
|
||||
}
|
||||
|
||||
# メソッド
|
||||
methodName(arg1, arg2) {
|
||||
return me.field1 + arg1
|
||||
}
|
||||
|
||||
# デストラクタ
|
||||
fini() {
|
||||
print("Cleanup: " + me.field1)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **デリゲーションBox**
|
||||
```nyash
|
||||
box Child from Parent interface Comparable {
|
||||
init { childField }
|
||||
|
||||
init(parentParam, childParam) { # init構文に統一
|
||||
from Parent.init(parentParam) # 親コンストラクタ明示呼び出し
|
||||
me.childField = childParam
|
||||
}
|
||||
|
||||
# メソッドオーバーライド
|
||||
override process(data) { # override必須
|
||||
local result = from Parent.process(data) # 親メソッド呼び出し
|
||||
return result + " (Child processed)"
|
||||
}
|
||||
|
||||
# インターフェース実装
|
||||
compareTo(other) {
|
||||
return me.value - other.value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **Static Box(推奨エントリーポイント)**
|
||||
```nyash
|
||||
static box Main {
|
||||
init { console, result }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🎉 Everything is Box!")
|
||||
return "Success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **ジェネリックBox**
|
||||
```nyash
|
||||
box Container<T> {
|
||||
init { value }
|
||||
|
||||
Container(item) {
|
||||
me.value = item
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return me.value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **2.2 変数宣言**
|
||||
|
||||
#### **基本パターン**
|
||||
```nyash
|
||||
# 単一宣言
|
||||
local x
|
||||
local name = "初期値"
|
||||
|
||||
# 複数宣言
|
||||
local a, b, c
|
||||
local x = 10, y = 20, z # 混合初期化
|
||||
|
||||
# 所有権移転(static関数内)
|
||||
static function Factory.create() {
|
||||
outbox product # 呼び出し側に所有権移転
|
||||
product = new Item()
|
||||
return product
|
||||
}
|
||||
```
|
||||
|
||||
#### **変数宣言厳密化システム(2025-08-09実装)**
|
||||
```nyash
|
||||
# ✅ 正しい - 明示宣言必須
|
||||
local temp
|
||||
temp = 42
|
||||
|
||||
# ❌ エラー - 未宣言変数への代入
|
||||
x = 42 # RuntimeError: 未宣言変数 + 修正提案表示
|
||||
```
|
||||
|
||||
### **2.3 制御構文**
|
||||
|
||||
#### **条件分岐**
|
||||
```nyash
|
||||
if condition {
|
||||
# 処理
|
||||
} else if condition2 {
|
||||
# 処理2
|
||||
} else {
|
||||
# else処理
|
||||
}
|
||||
```
|
||||
|
||||
#### **ループ(統一構文)**
|
||||
```nyash
|
||||
# ✅ 唯一の正しい形式
|
||||
loop(condition) {
|
||||
# ループ本体
|
||||
if exitCondition {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# ❌ 削除済み - 使用不可
|
||||
while condition { } # パーサーエラー
|
||||
loop() { } # パーサーエラー
|
||||
```
|
||||
|
||||
### **2.4 演算子・式**
|
||||
|
||||
#### **🚀 新実装: 関数オーバーロードシステム**
|
||||
```nyash
|
||||
# Rust風トレイトベース演算子(2025-08-10実装完了)
|
||||
sum = 10 + 20 # IntegerBox + IntegerBox = IntegerBox
|
||||
concat = "Hi" + " !" # StringBox + StringBox = StringBox
|
||||
repeat = "Ha" * 3 # StringBox * IntegerBox = "HaHaHa"
|
||||
mixed = 42 + " answer" # 混合型 → 自動文字列結合フォールバック
|
||||
```
|
||||
|
||||
#### **演算子優先順位**
|
||||
```nyash
|
||||
result = a + b * c / d - e # 算術演算子は標準的優先順位
|
||||
logic = not a and b or c # not > and > or
|
||||
compare = (x > y) and (z <= w) # 比較は括弧推奨
|
||||
```
|
||||
|
||||
#### **論理演算子**
|
||||
```nyash
|
||||
# キーワード版(推奨)
|
||||
canAccess = level >= 5 and hasKey
|
||||
isValid = not (isEmpty or hasError)
|
||||
|
||||
# シンボル版(互換)
|
||||
result = condition && other || fallback # 利用可能だが非推奨
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ **3. Box構文詳細ガイド**
|
||||
|
||||
### **3.1 Everything is Box 原則**
|
||||
|
||||
```nyash
|
||||
# すべての値がBox
|
||||
number = 42 # IntegerBox
|
||||
text = "hello" # StringBox
|
||||
flag = true # BoolBox
|
||||
array = new ArrayBox() # ArrayBox
|
||||
console = new ConsoleBox() # ConsoleBox
|
||||
|
||||
# 統一的なメソッド呼び出し
|
||||
print(number.to_string_box().value) # "42"
|
||||
print(array.length()) # 配列長
|
||||
console.log("Everything is Box!") # コンソール出力
|
||||
```
|
||||
|
||||
### **3.2 コンストラクタパターン**
|
||||
|
||||
#### **パラメータ付きコンストラクタ**
|
||||
```nyash
|
||||
box Person {
|
||||
init { name, age, email }
|
||||
|
||||
init(personName, personAge) { # init構文に統一
|
||||
me.name = personName
|
||||
me.age = personAge
|
||||
me.email = me.name + "@example.com" # 計算フィールド
|
||||
}
|
||||
|
||||
# ファクトリーメソッド
|
||||
static createGuest() {
|
||||
outbox guest
|
||||
guest = new Person("Guest", 0)
|
||||
return guest
|
||||
}
|
||||
}
|
||||
|
||||
# 使用例
|
||||
person = new Person("Alice", 25)
|
||||
guest = Person.createGuest()
|
||||
```
|
||||
|
||||
### **3.3 継承とインターフェース**
|
||||
|
||||
#### **デリゲーションチェーン**
|
||||
```nyash
|
||||
# 基底Box
|
||||
box Animal {
|
||||
init { name, species }
|
||||
|
||||
init(animalName, animalSpecies) {
|
||||
me.name = animalName
|
||||
me.species = animalSpecies
|
||||
}
|
||||
|
||||
speak() {
|
||||
return me.name + " makes a sound"
|
||||
}
|
||||
}
|
||||
|
||||
# デリゲーション
|
||||
box Dog from Animal {
|
||||
init { breed } # 追加フィールド
|
||||
|
||||
init(dogName, dogBreed) {
|
||||
from Animal.init(dogName, "Canine") # 親コンストラクタ呼び出し
|
||||
me.breed = dogBreed
|
||||
}
|
||||
|
||||
override speak() { # 明示的オーバーライド
|
||||
return me.name + " barks: Woof!"
|
||||
}
|
||||
}
|
||||
|
||||
# インターフェース実装
|
||||
box Cat from Animal interface Playful {
|
||||
# Playfulインターフェースの実装必須
|
||||
}
|
||||
```
|
||||
|
||||
### **3.4 Static Boxパターン**
|
||||
|
||||
#### **名前空間・ユーティリティ**
|
||||
```nyash
|
||||
static box MathUtils {
|
||||
init { PI, E }
|
||||
|
||||
static {
|
||||
me.PI = 3.14159265
|
||||
me.E = 2.71828182
|
||||
}
|
||||
|
||||
add(a, b) {
|
||||
return a + b
|
||||
}
|
||||
|
||||
circleArea(radius) {
|
||||
return me.PI * radius * radius
|
||||
}
|
||||
}
|
||||
|
||||
# 使用法
|
||||
area = MathUtils.circleArea(5)
|
||||
sum = MathUtils.add(10, 20)
|
||||
pi = MathUtils.PI
|
||||
```
|
||||
|
||||
#### **アプリケーションエントリーポイント**
|
||||
```nyash
|
||||
# 🎯 推奨: Static Box Main パターン
|
||||
static box Main {
|
||||
init { console, result }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🚀 Starting application...")
|
||||
|
||||
# アプリケーションロジック
|
||||
me.result = processData()
|
||||
|
||||
return "Application completed successfully"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **4. 最新機能・革新技術**
|
||||
|
||||
### **4.1 Arc<Mutex> Revolution(2025-08-10)**
|
||||
```nyash
|
||||
# 全16種類のBox型が統一Arc<Mutex>パターンで実装
|
||||
# 完全なスレッドセーフティと高性能を両立
|
||||
|
||||
array = new ArrayBox()
|
||||
array.push(10) # スレッドセーフな追加
|
||||
array.push(20)
|
||||
item = array.get(0) # スレッドセーフな取得
|
||||
|
||||
json = new JSONBox()
|
||||
json.set("name", "Alice") # 並行安全な操作
|
||||
data = json.stringify() # JSON文字列化
|
||||
```
|
||||
|
||||
### **4.2 Rust風トレイトベース演算子(2025-08-10)**
|
||||
```nyash
|
||||
# AI大相談会で決定された最適設計
|
||||
# 静的・動的ハイブリッドディスパッチによる高性能実現
|
||||
|
||||
# 整数演算
|
||||
result = 100 - 25 # IntegerBox間演算 → IntegerBox
|
||||
product = 6 * 7 # 高速静的ディスパッチ
|
||||
|
||||
# 文字列操作
|
||||
greeting = "Hello" + " World" # 文字列結合
|
||||
repeated = "Echo" * 3 # "EchoEchoEcho"
|
||||
|
||||
# 混合型フォールバック
|
||||
message = "Answer: " + 42 # "Answer: 42"
|
||||
|
||||
# Boolean演算
|
||||
boolSum = true + false # 1 (IntegerBox)
|
||||
```
|
||||
|
||||
### **4.3 変数宣言厳密化(2025-08-09)**
|
||||
```nyash
|
||||
# メモリ安全性・非同期安全性保証システム
|
||||
|
||||
static box Calculator {
|
||||
init { memory } # 必須フィールド宣言
|
||||
|
||||
calculate() {
|
||||
local temp # 必須ローカル変数宣言
|
||||
temp = me.memory * 2
|
||||
return temp
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ **5. 実装済みBox型ライブラリ**
|
||||
|
||||
### **5.1 基本型**
|
||||
- `StringBox` - 文字列(split, find, replace, trim等)
|
||||
- `IntegerBox` - 64bit整数
|
||||
- `BoolBox` - 真偽値
|
||||
- `VoidBox` - null/void値
|
||||
|
||||
### **5.2 コレクション**
|
||||
- `ArrayBox` - 動的配列(push, pop, get, set, join等)
|
||||
- `MapBox` - 連想配列・辞書
|
||||
|
||||
### **5.3 システム・I/O**
|
||||
- `ConsoleBox` - コンソール入出力
|
||||
- `DebugBox` - デバッグ支援・メモリ追跡
|
||||
- `FileBox` - ファイルシステム操作
|
||||
|
||||
### **5.4 数学・時間**
|
||||
- `MathBox` - 数学関数(sin, cos, log, sqrt等)
|
||||
- `TimeBox` - 時刻操作・タイマー
|
||||
- `RandomBox` - 乱数生成・選択・シャッフル
|
||||
|
||||
### **5.5 データ処理**
|
||||
- `JSONBox` - JSON解析・生成(parse, stringify, get, set)
|
||||
- `RegexBox` - 正規表現(test, find, replace, split)
|
||||
- `BufferBox` - バイナリデータ処理
|
||||
- `StreamBox` - ストリーム処理
|
||||
|
||||
### **5.6 ネットワーク・Web**
|
||||
- `HttpClientBox` - HTTP通信
|
||||
- `WebDisplayBox` - HTML表示(WASM)
|
||||
- `WebConsoleBox` - ブラウザコンソール(WASM)
|
||||
- `WebCanvasBox` - Canvas描画(WASM)
|
||||
|
||||
### **5.7 GUI・マルチメディア**
|
||||
- `EguiBox` - デスクトップGUI(Windows/Linux)
|
||||
- `SoundBox` - 音声再生
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **6. パフォーマンス・デザイン原則**
|
||||
|
||||
### **6.1 メモリ安全性**
|
||||
- Rust所有権システムによる完全なメモリ安全性
|
||||
- Arc<Mutex>によるスレッドセーフな共有状態管理
|
||||
- 自動参照カウント + 明示的デストラクタ(fini)
|
||||
|
||||
### **6.2 実行効率**
|
||||
- 統一されたBox型システムによる最適化
|
||||
- 静的・動的ハイブリッドディスパッチで高速演算
|
||||
- パーサー無限ループ対策(--debug-fuel)
|
||||
|
||||
### **6.3 開発効率**
|
||||
- 変数宣言厳密化による早期エラー検出
|
||||
- 包括的デバッグ機能(DebugBox)
|
||||
- 直感的な"Everything is Box"概念
|
||||
|
||||
---
|
||||
|
||||
## 📚 **7. 学習パス・ベストプラクティス**
|
||||
|
||||
### **7.1 初心者向け学習順序**
|
||||
1. **基本概念**: Everything is Box哲学理解
|
||||
2. **基本構文**: 変数宣言・制御構文・演算子
|
||||
3. **Box定義**: 基本的なクラス作成
|
||||
4. **Static Box Main**: アプリケーションエントリーポイント
|
||||
5. **継承・インターフェース**: オブジェクト指向機能
|
||||
|
||||
### **7.2 推奨コーディングスタイル**
|
||||
```nyash
|
||||
# ✅ 推奨スタイル
|
||||
static box Main {
|
||||
init { console, result } # フィールド明示
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
local data # 変数事前宣言
|
||||
data = processInput()
|
||||
|
||||
me.result = data # 明確な代入
|
||||
return "Success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **7.3 よくある間違いと対策**
|
||||
```nyash
|
||||
# ❌ よくある間違い
|
||||
init { field1 field2 } # カンマなし → CPU暴走
|
||||
x = 42 # 変数未宣言 → ランタイムエラー
|
||||
while condition { } # 非対応構文 → パーサーエラー
|
||||
|
||||
# ✅ 正しい書き方
|
||||
init { field1, field2 } # カンマ必須
|
||||
local x = 42 # 事前宣言
|
||||
loop(condition) { } # 統一ループ構文
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**🎉 Nyash 2025は、AI協働設計による最先端言語システムとして、シンプルさと強力さを完全に両立しました。**
|
||||
|
||||
*最終更新: 2025年8月10日 - Arc<Mutex> Revolution + AI大相談会成功記念*
|
||||
87
docs/reference/plugin-system/README.md
Normal file
87
docs/reference/plugin-system/README.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Nyash Plugin System Documentation
|
||||
|
||||
## 🎯 Quick Start
|
||||
|
||||
**For new developers**: Start with [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md)
|
||||
|
||||
## 📚 Documentation Index
|
||||
|
||||
### 🟢 **Current & Accurate**
|
||||
- **[bid-ffi-v1-actual-specification.md](./bid-ffi-v1-actual-specification.md)** - **主要仕様書**
|
||||
- 実際に動作している実装をベースとした正確な仕様
|
||||
- FileBoxプラグインで実証済み
|
||||
- プラグイン開発者はここから始める
|
||||
|
||||
- **[vm-plugin-integration.md](./vm-plugin-integration.md)** - **VM統合仕様書** 🆕
|
||||
- VMバックエンドとプラグインシステムの統合
|
||||
- BoxRef型による統一アーキテクチャ
|
||||
- パフォーマンス最適化とエラーハンドリング
|
||||
|
||||
- **[plugin-tester.md](./plugin-tester.md)** - プラグイン診断ツール
|
||||
- プラグインの動作確認とデバッグに使用
|
||||
- `tools/plugin-tester`ツールの使用方法
|
||||
|
||||
- **[filebox-bid-mapping.md](./filebox-bid-mapping.md)** - 参考資料
|
||||
- FileBox APIとプラグイン実装の対応表
|
||||
- API設計の参考として有用
|
||||
|
||||
### 🔄 **Migration & Reference**
|
||||
- **[migration-guide.md](./migration-guide.md)** - 移行ガイド
|
||||
- 古いドキュメントから現在の実装への移行方法
|
||||
- ドキュメント状況の整理
|
||||
|
||||
### ⚠️ **Deprecated - 非推奨**
|
||||
- **[ffi-abi-specification.md](./ffi-abi-specification.md)** - ❌ 理想案、未実装
|
||||
- **[plugin-system.md](./plugin-system.md)** - ❌ 将来構想
|
||||
- **[nyash-toml-v2-spec.md](./nyash-toml-v2-spec.md)** - ⚠️ 部分的に古い
|
||||
|
||||
## 🚀 For Plugin Developers
|
||||
|
||||
### 1. **Read the Specification**
|
||||
```bash
|
||||
# 主要仕様書を読む
|
||||
cat docs/説明書/reference/plugin-system/bid-ffi-v1-actual-specification.md
|
||||
```
|
||||
|
||||
### 2. **Study Working Example**
|
||||
```bash
|
||||
# FileBoxプラグインを参考にする
|
||||
cd plugins/nyash-filebox-plugin
|
||||
cat src/lib.rs
|
||||
```
|
||||
|
||||
### 3. **Configure Your Plugin**
|
||||
```bash
|
||||
# nyash.tomlで設定
|
||||
cat nyash.toml # 実際の設定形式を確認
|
||||
```
|
||||
|
||||
### 4. **Test Your Plugin**
|
||||
```bash
|
||||
# プラグインテスターで確認
|
||||
cd tools/plugin-tester
|
||||
cargo build --release
|
||||
./target/release/plugin-tester check path/to/your/plugin.so
|
||||
```
|
||||
|
||||
## 🔧 For Nyash Core Developers
|
||||
|
||||
### Implementation Files
|
||||
- **[plugin_loader_v2.rs](../../../../src/runtime/plugin_loader_v2.rs)** - プラグインローダー実装
|
||||
- **[nyash_toml_v2.rs](../../../../src/config/nyash_toml_v2.rs)** - 設定パーサー
|
||||
- **[tlv.rs](../../../../src/bid/tlv.rs)** - TLVエンコーダー/デコーダー
|
||||
|
||||
### Next Steps
|
||||
- **Phase 3**: MIR ExternCall → plugin system 接続実装
|
||||
- **Future**: HTTP系ボックスのプラグイン化
|
||||
|
||||
## 📞 Support & Issues
|
||||
|
||||
- **Working Examples**: `plugins/nyash-filebox-plugin/`
|
||||
- **Issues**: Report at [GitHub Issues](https://github.com/moe-charm/nyash/issues)
|
||||
- **Configuration**: `nyash.toml` in project root
|
||||
|
||||
---
|
||||
|
||||
**Status**: Phase 2 Documentation Reorganization - Completed
|
||||
**Last Updated**: 2025-08-20
|
||||
194
docs/reference/plugin-system/bid-ffi-v1-actual-specification.md
Normal file
194
docs/reference/plugin-system/bid-ffi-v1-actual-specification.md
Normal file
@ -0,0 +1,194 @@
|
||||
# BID-FFI v1 実装仕様書 (実装ベース)
|
||||
|
||||
## 🎯 概要
|
||||
|
||||
**これは現在動作している実装をベースとした正確な仕様書です。**
|
||||
- FileBoxプラグインで実証済み
|
||||
- plugin_loader_v2.rsの実装に基づく
|
||||
- 理想案ではなく、実際に動く仕様
|
||||
|
||||
## 📋 プラグインAPI仕様
|
||||
|
||||
### 必須エクスポート関数
|
||||
|
||||
#### 1. ABI Version (オプション)
|
||||
```c
|
||||
extern "C" u32 nyash_plugin_abi(void) {
|
||||
return 1; // BID-FFI v1
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 初期化 (オプション)
|
||||
```c
|
||||
extern "C" i32 nyash_plugin_init(void) {
|
||||
// グローバルリソース初期化
|
||||
// 0=成功, 負数=エラー(プラグイン無効化)
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. メソッド呼び出し (必須)
|
||||
```c
|
||||
extern "C" i32 nyash_plugin_invoke(
|
||||
u32 type_id, // Box型ID (6=FileBox)
|
||||
u32 method_id, // メソッドID (0=birth, 4294967295=fini)
|
||||
u32 instance_id, // インスタンスID (0=static call)
|
||||
const u8* args, // TLV引数
|
||||
usize args_len, // 引数サイズ
|
||||
u8* result, // TLV結果バッファ
|
||||
usize* result_len // [IN/OUT]バッファサイズ
|
||||
) -> i32; // 0=成功, 負数=エラー
|
||||
```
|
||||
|
||||
#### 4. 終了処理 (オプション)
|
||||
```c
|
||||
extern "C" void nyash_plugin_shutdown(void) {
|
||||
// グローバルリソース解放
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 エラーコード
|
||||
|
||||
```c
|
||||
#define NYB_SUCCESS 0 // 成功
|
||||
#define NYB_E_SHORT_BUFFER -1 // バッファ不足
|
||||
#define NYB_E_INVALID_TYPE -2 // 無効な型ID
|
||||
#define NYB_E_INVALID_METHOD -3 // 無効なメソッドID
|
||||
#define NYB_E_INVALID_ARGS -4 // 無効な引数
|
||||
#define NYB_E_PLUGIN_ERROR -5 // プラグイン内部エラー
|
||||
#define NYB_E_INVALID_HANDLE -8 // 無効なハンドル
|
||||
```
|
||||
|
||||
## 🏗️ TLV (Type-Length-Value) 形式
|
||||
|
||||
### ヘッダー構造
|
||||
```c
|
||||
struct TlvHeader {
|
||||
u16 version; // 1 (BID-FFI v1)
|
||||
u16 argc; // 引数数
|
||||
};
|
||||
```
|
||||
|
||||
### エントリー構造
|
||||
```c
|
||||
struct TlvEntry {
|
||||
u8 tag; // 型タグ
|
||||
u8 reserved; // 0(将来拡張用)
|
||||
u16 size; // ペイロードサイズ
|
||||
// followed by payload data
|
||||
};
|
||||
```
|
||||
|
||||
### 型タグ定義
|
||||
```c
|
||||
#define BID_TAG_BOOL 1 // bool: 1 byte (0/1)
|
||||
#define BID_TAG_I32 2 // i32: 4 bytes (little-endian)
|
||||
#define BID_TAG_I64 3 // i64: 8 bytes (little-endian)
|
||||
#define BID_TAG_F32 4 // f32: 4 bytes (IEEE 754)
|
||||
#define BID_TAG_F64 5 // f64: 8 bytes (IEEE 754)
|
||||
#define BID_TAG_STRING 6 // string: UTF-8 bytes
|
||||
#define BID_TAG_BYTES 7 // bytes: binary data
|
||||
#define BID_TAG_HANDLE 8 // handle: 8 bytes (type_id + instance_id)
|
||||
#define BID_TAG_VOID 9 // void: 0 bytes
|
||||
```
|
||||
|
||||
## 🔧 nyash.toml設定仕様
|
||||
|
||||
### 基本構造
|
||||
```toml
|
||||
[libraries."<library_name>"]
|
||||
boxes = ["BoxType1", "BoxType2"] # 提供するBox型
|
||||
path = "./path/to/library.so" # ライブラリパス
|
||||
|
||||
[libraries."<library_name>".<BoxType>]
|
||||
type_id = <number> # Box型ID (必須)
|
||||
|
||||
[libraries."<library_name>".<BoxType>.methods]
|
||||
<method_name> = { method_id = <number> }
|
||||
```
|
||||
|
||||
### 実例 (FileBox)
|
||||
```toml
|
||||
[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 } # デストラクタ (u32::MAX)
|
||||
```
|
||||
|
||||
## 🔄 必須メソッド規約
|
||||
|
||||
### birth() - コンストラクタ
|
||||
- **method_id**: 必ず 0
|
||||
- **引数**: TLV形式(型依存)
|
||||
- **戻り値**: instance_id (u32, little-endian, 4bytes)
|
||||
- **呼び出し**: instance_id=0 (static call)
|
||||
|
||||
### fini() - デストラクタ
|
||||
- **method_id**: 必ず 4294967295 (u32::MAX)
|
||||
- **引数**: 空のTLV (version=1, argc=0)
|
||||
- **戻り値**: Void
|
||||
- **呼び出し**: 対象のinstance_id
|
||||
|
||||
## 📝 PluginBoxV2構造体
|
||||
|
||||
```rust
|
||||
pub struct PluginBoxV2 {
|
||||
pub box_type: String, // "FileBox"
|
||||
pub type_id: u32, // 6
|
||||
pub invoke_fn: InvokeFn, // 関数ポインタ
|
||||
pub instance_id: u32, // プラグイン生成ID
|
||||
pub fini_method_id: Option<u32>, // finiメソッドID
|
||||
}
|
||||
```
|
||||
|
||||
## 🚨 重要な制約
|
||||
|
||||
### メモリ管理
|
||||
- **プラグイン責任**: プラグインが確保したメモリはプラグインが解放
|
||||
- **2段階呼び出し**:
|
||||
1. result=NULL でサイズ取得
|
||||
2. ホストがバッファ確保後、実際のデータ取得
|
||||
|
||||
### 文字列エンコーディング
|
||||
- **UTF-8必須**: すべての文字列はUTF-8
|
||||
- **NUL終端不要**: lengthが正確性を保証
|
||||
|
||||
### インスタンス管理
|
||||
- **instance_id**: プラグイン内で一意
|
||||
- **birth順序**: birth() → 実際のメソッド → fini()
|
||||
- **共有・複製**: clone_box()は新birth()、share_box()は同一instance_id
|
||||
|
||||
## 🔗 実装ファイル
|
||||
|
||||
### Nyash側
|
||||
- `src/runtime/plugin_loader_v2.rs` - プラグインローダー
|
||||
- `src/config/nyash_toml_v2.rs` - 設定パーサー
|
||||
- `src/bid/tlv.rs` - TLVエンコーダー/デコーダー
|
||||
|
||||
### プラグイン例
|
||||
- `plugins/nyash-filebox-plugin/src/lib.rs` - FileBox実装
|
||||
- `plugins/nyash-test-multibox/src/lib.rs` - マルチBox実装
|
||||
|
||||
## ✅ 動作確認済み
|
||||
|
||||
- ✅ FileBoxプラグイン完全動作
|
||||
- ✅ birth/finiライフサイクル
|
||||
- ✅ TLVエンコーディング/デコーディング
|
||||
- ✅ clone_box/share_box メソッド
|
||||
- ✅ マルチインスタンス管理
|
||||
|
||||
---
|
||||
|
||||
**最終更新**: 2025年8月20日 - Phase 1現実調査完了
|
||||
**ベース**: plugin_loader_v2.rs実装 + FileBox実証
|
||||
**状態**: Production Ready (実際に動作中)
|
||||
626
docs/reference/plugin-system/ffi-abi-specification.md
Normal file
626
docs/reference/plugin-system/ffi-abi-specification.md
Normal file
@ -0,0 +1,626 @@
|
||||
# Box FFI/ABI v0 (BID-1 Enhanced Edition)
|
||||
|
||||
> ⚠️ **DEPRECATED - 理想案、未実装**
|
||||
>
|
||||
> この文書は将来の理想的なプラグインシステム設計案です。
|
||||
> **現在の実装とは異なります。**
|
||||
>
|
||||
> **実際に動作している仕様については、以下を参照してください:**
|
||||
> - [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md) - 現在動作中の仕様
|
||||
> - [nyash.toml設定例](../../../../nyash.toml) - 実際の設定形式
|
||||
> - [plugin_loader_v2.rs](../../../../src/runtime/plugin_loader_v2.rs) - 実装詳細
|
||||
|
||||
Purpose
|
||||
- Define a language-agnostic ABI to call external libraries as Boxes.
|
||||
- Serve as a single source of truth for MIR ExternCall, WASM RuntimeImports, VM stubs, and future language codegens (TS/Python/Rust/LLVM IR).
|
||||
- Support Everything is Box philosophy with efficient Handle design.
|
||||
|
||||
Design Goals
|
||||
- Simple first: UTF-8 strings as (ptr,len), i32 for small integers, 32-bit linear memory alignment friendly.
|
||||
- Deterministic and portable across WASM/VM/native backends.
|
||||
- Align with MIR effect system (pure/mut/io/control) to preserve optimization safety.
|
||||
- Efficient Handle design for Box instances (type_id + instance_id).
|
||||
|
||||
Core Types
|
||||
- i32, i64, f32, f64, bool (0|1)
|
||||
- string: UTF-8 in linear memory as (ptr: usize, len: usize)
|
||||
- bytes: Binary data as (ptr: usize, len: usize)
|
||||
- handle: Efficient Box handle as {type_id: u32, instance_id: u32} or packed u64
|
||||
- array(T): (ptr: usize, len: usize)
|
||||
- void (no return value)
|
||||
|
||||
Memory & Alignment
|
||||
- All pointers are platform-dependent (usize): 32-bit in WASM MVP, 64-bit on native x86-64.
|
||||
- Alignment: 8-byte boundary for all structures.
|
||||
- Strings/arrays must be contiguous in linear memory; no NUL terminator required (len is authoritative).
|
||||
- Box layout examples for built-ins (for backends that materialize Boxes in memory):
|
||||
- Header: [type_id:i32][ref_count:i32][field_count:i32]
|
||||
- StringBox: header + [data_ptr:usize][length:usize]
|
||||
|
||||
Handle Design (BID-1 Enhancement)
|
||||
- Handle represents a Box instance with two components:
|
||||
- type_id: u32 (1=StringBox, 6=FileBox, 7=FutureBox, 8=P2PBox, etc.)
|
||||
- instance_id: u32 (unique instance identifier)
|
||||
- Can be passed as single u64 (type_id << 32 | instance_id) or struct
|
||||
|
||||
Naming & Resolution
|
||||
- Interface namespace: `env.console`, `env.canvas`, `nyash.file`, etc.
|
||||
- Method: `log`, `fillRect`, `fillText`, `open`, `read`, `write`, `close`.
|
||||
- Fully-qualified name: `env.console.log`, `env.canvas.fillRect`, `nyash.file.open`.
|
||||
|
||||
Calling Convention (BID-1)
|
||||
- Single entry point: `nyash_plugin_invoke`
|
||||
- Arguments passed as BID-1 TLV format
|
||||
- Return values in BID-1 TLV format
|
||||
- Two-call pattern for dynamic results:
|
||||
1. First call with null result buffer to get size
|
||||
2. Second call with allocated buffer to get data
|
||||
|
||||
Error Model (BID-1)
|
||||
- Standardized error codes:
|
||||
- NYB_SUCCESS (0): Operation successful
|
||||
- NYB_E_SHORT_BUFFER (-1): Buffer too small
|
||||
- NYB_E_INVALID_TYPE (-2): Invalid type ID
|
||||
- NYB_E_INVALID_METHOD (-3): Invalid method ID
|
||||
- NYB_E_INVALID_ARGS (-4): Invalid arguments
|
||||
- NYB_E_PLUGIN_ERROR (-5): Plugin internal error
|
||||
|
||||
Effects
|
||||
- Each BID method declares one of: pure | mut | io | control.
|
||||
- Optimizer/verifier rules:
|
||||
- pure: reordering permitted, memoization possible
|
||||
- mut: preserve order w.r.t same resource
|
||||
- io: preserve program order strictly
|
||||
- control: affects CFG; handled as terminators or dedicated ops
|
||||
|
||||
BID-1 TLV Format
|
||||
```c
|
||||
// BID-1 TLV specification - unified format for arguments and results
|
||||
struct BidTLV {
|
||||
u16 version; // 1 (BID-1)
|
||||
u16 argc; // argument count
|
||||
// followed by TLVEntry array
|
||||
};
|
||||
|
||||
struct TLVEntry {
|
||||
u8 tag; // type tag
|
||||
u8 reserved; // future use (0)
|
||||
u16 size; // payload size
|
||||
// followed by payload data
|
||||
};
|
||||
|
||||
// Tag definitions (Phase 1)
|
||||
#define BID_TAG_BOOL 1 // payload: 1 byte (0/1)
|
||||
#define BID_TAG_I32 2 // payload: 4 bytes (little-endian)
|
||||
#define BID_TAG_I64 3 // payload: 8 bytes (little-endian)
|
||||
#define BID_TAG_F32 4 // payload: 4 bytes (IEEE 754)
|
||||
#define BID_TAG_F64 5 // payload: 8 bytes (IEEE 754)
|
||||
#define BID_TAG_STRING 6 // payload: UTF-8 bytes
|
||||
#define BID_TAG_BYTES 7 // payload: binary data
|
||||
#define BID_TAG_HANDLE 8 // payload: 8 bytes (type_id + instance_id)
|
||||
|
||||
// Phase 2 reserved
|
||||
#define BID_TAG_RESULT 20 // Result<T,E>
|
||||
#define BID_TAG_OPTION 21 // Option<T>
|
||||
#define BID_TAG_ARRAY 22 // Array<T>
|
||||
```
|
||||
|
||||
Plugin API (BID-1)
|
||||
```c
|
||||
// src/bid/plugin_api.h - Plugin API complete version
|
||||
|
||||
// Host function table
|
||||
typedef struct {
|
||||
void* (*alloc)(size_t size); // Memory allocation
|
||||
void (*free)(void* ptr); // Memory deallocation
|
||||
void (*wake)(u32 future_id); // FutureBox wake
|
||||
void (*log)(const char* msg); // Log output
|
||||
} NyashHostVtable;
|
||||
|
||||
// Plugin information
|
||||
typedef struct {
|
||||
u32 type_id; // Box type ID
|
||||
const char* type_name; // "FileBox" etc.
|
||||
u32 method_count; // Method count
|
||||
const NyashMethodInfo* methods; // Method table
|
||||
} NyashPluginInfo;
|
||||
|
||||
typedef struct {
|
||||
u32 method_id; // Method ID
|
||||
const char* method_name; // "open", "read" etc.
|
||||
u32 signature_hash; // Type signature hash
|
||||
} NyashMethodInfo;
|
||||
|
||||
// Plugin API (required implementation)
|
||||
extern "C" {
|
||||
// Get ABI version
|
||||
u32 nyash_plugin_abi(void);
|
||||
|
||||
// Initialize (host integration & metadata registration)
|
||||
i32 nyash_plugin_init(const NyashHostVtable* host, NyashPluginInfo* info);
|
||||
|
||||
// Unified method invocation
|
||||
i32 nyash_plugin_invoke(
|
||||
u32 type_id, // Box type ID
|
||||
u32 method_id, // Method ID
|
||||
u32 instance_id, // Instance ID
|
||||
const u8* args, // BID-1 TLV arguments
|
||||
size_t args_len, // Arguments size
|
||||
u8* result, // BID-1 TLV result
|
||||
size_t* result_len // Result size (in/out)
|
||||
);
|
||||
|
||||
// Shutdown
|
||||
void nyash_plugin_shutdown(void);
|
||||
}
|
||||
```
|
||||
|
||||
BID (Box Interface Definition) — YAML
|
||||
```yaml
|
||||
version: 1 # BID-1 format
|
||||
interfaces:
|
||||
- name: env.console
|
||||
box: Console
|
||||
methods:
|
||||
- name: log
|
||||
params: [ {string: msg} ]
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: env.canvas
|
||||
box: Canvas
|
||||
methods:
|
||||
- name: fillRect
|
||||
params:
|
||||
- {string: canvas_id}
|
||||
- {i32: x}
|
||||
- {i32: y}
|
||||
- {i32: w}
|
||||
- {i32: h}
|
||||
- {string: color}
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: fillText
|
||||
params:
|
||||
- {string: canvas_id}
|
||||
- {string: text}
|
||||
- {i32: x}
|
||||
- {i32: y}
|
||||
- {string: font}
|
||||
- {string: color}
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: nyash.file
|
||||
box: FileBox
|
||||
type_id: 6
|
||||
methods:
|
||||
- name: open
|
||||
method_id: 1
|
||||
params:
|
||||
- {string: path}
|
||||
- {string: mode}
|
||||
returns: {handle: FileBox}
|
||||
effect: io
|
||||
|
||||
- name: read
|
||||
method_id: 2
|
||||
params:
|
||||
- {handle: handle}
|
||||
- {i32: size}
|
||||
returns: {bytes: data}
|
||||
effect: io
|
||||
|
||||
- name: write
|
||||
method_id: 3
|
||||
params:
|
||||
- {handle: handle}
|
||||
- {bytes: data}
|
||||
returns: {i32: written}
|
||||
effect: io
|
||||
|
||||
- name: close
|
||||
method_id: 4
|
||||
params:
|
||||
- {handle: handle}
|
||||
returns: void
|
||||
effect: io
|
||||
```
|
||||
|
||||
FileBox Plugin Example (BID-1)
|
||||
```c
|
||||
// plugins/nyash-file/src/lib.c
|
||||
|
||||
#include "nyash_plugin_api.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const NyashHostVtable* g_host = NULL;
|
||||
|
||||
// ABI version
|
||||
u32 nyash_plugin_abi(void) {
|
||||
return 1; // BID-1 support
|
||||
}
|
||||
|
||||
// Method table
|
||||
static const NyashMethodInfo FILE_METHODS[] = {
|
||||
{0, "birth", 0xBEEFCAFE}, // birth(path: string, mode: string) - Constructor
|
||||
{1, "open", 0x12345678}, // open(path: string, mode: string) -> Handle
|
||||
{2, "read", 0x87654321}, // read(handle: Handle, size: i32) -> Bytes
|
||||
{3, "write", 0x11223344}, // write(handle: Handle, data: Bytes) -> i32
|
||||
{4, "close", 0xABCDEF00}, // close(handle: Handle) -> Void
|
||||
{5, "fini", 0xDEADBEEF}, // fini() - Destructor
|
||||
};
|
||||
|
||||
// Initialize
|
||||
i32 nyash_plugin_init(const NyashHostVtable* host, NyashPluginInfo* info) {
|
||||
info->type_id = 6; // FileBox
|
||||
info->type_name = "FileBox";
|
||||
info->method_count = 4;
|
||||
info->methods = FILE_METHODS;
|
||||
|
||||
// Save host functions
|
||||
g_host = host;
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// Method execution
|
||||
i32 nyash_plugin_invoke(u32 type_id, u32 method_id, u32 instance_id,
|
||||
const u8* args, size_t args_len,
|
||||
u8* result, size_t* result_len) {
|
||||
if (type_id != 6) return NYB_E_INVALID_TYPE;
|
||||
|
||||
switch (method_id) {
|
||||
case 1: return file_open(args, args_len, result, result_len);
|
||||
case 2: return file_read(instance_id, args, args_len, result, result_len);
|
||||
case 3: return file_write(instance_id, args, args_len, result, result_len);
|
||||
case 4: return file_close(instance_id, args, args_len, result, result_len);
|
||||
default: return NYB_E_INVALID_METHOD;
|
||||
}
|
||||
}
|
||||
|
||||
// File open implementation
|
||||
static i32 file_open(const u8* args, size_t args_len,
|
||||
u8* result, size_t* result_len) {
|
||||
// BID-1 TLV parsing
|
||||
BidTLV* tlv = (BidTLV*)args;
|
||||
if (tlv->version != 1 || tlv->argc != 2) {
|
||||
return NYB_E_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// Extract arguments: path, mode
|
||||
const char* path = extract_string_arg(tlv, 0);
|
||||
const char* mode = extract_string_arg(tlv, 1);
|
||||
|
||||
// Open file
|
||||
FILE* fp = fopen(path, mode);
|
||||
if (!fp) return NYB_E_PLUGIN_ERROR;
|
||||
|
||||
// Generate handle
|
||||
u32 handle_id = register_file_handle(fp);
|
||||
|
||||
// BID-1 result creation
|
||||
if (!result) {
|
||||
*result_len = sizeof(BidTLV) + sizeof(TLVEntry) + 8; // Handle
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// Return Handle{type_id: 6, instance_id: handle_id} in TLV
|
||||
encode_handle_result(result, 6, handle_id);
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// birth implementation - Box constructor
|
||||
static i32 file_birth(u32 instance_id, const u8* args, size_t args_len,
|
||||
u8* result, size_t* result_len) {
|
||||
// Parse constructor arguments
|
||||
BidTLV* tlv = (BidTLV*)args;
|
||||
const char* path = extract_string_arg(tlv, 0);
|
||||
const char* mode = extract_string_arg(tlv, 1);
|
||||
|
||||
// Create instance
|
||||
FileInstance* instance = malloc(sizeof(FileInstance));
|
||||
instance->fp = fopen(path, mode);
|
||||
instance->buffer = NULL;
|
||||
|
||||
// Register instance
|
||||
register_instance(instance_id, instance);
|
||||
|
||||
// No return value for birth
|
||||
*result_len = 0;
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// fini implementation - Box destructor
|
||||
static i32 file_fini(u32 instance_id) {
|
||||
FileInstance* instance = get_instance(instance_id);
|
||||
if (!instance) return NYB_E_INVALID_HANDLE;
|
||||
|
||||
// Free plugin-allocated memory
|
||||
if (instance->buffer) {
|
||||
free(instance->buffer);
|
||||
}
|
||||
|
||||
// Close file handle
|
||||
if (instance->fp) {
|
||||
fclose(instance->fp);
|
||||
}
|
||||
|
||||
// Free instance
|
||||
free(instance);
|
||||
unregister_instance(instance_id);
|
||||
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
void nyash_plugin_shutdown(void) {
|
||||
// Cleanup all remaining instances
|
||||
cleanup_all_instances();
|
||||
}
|
||||
```
|
||||
|
||||
WASM Mapping (RuntimeImports)
|
||||
- Import examples:
|
||||
- `(import "env" "console_log" (func $console_log (param i32 i32)))` // (ptr,len)
|
||||
- `(import "env" "canvas_fillRect" (func $canvas_fillRect (param i32 i32 i32 i32 i32 i32)))`
|
||||
- `(import "env" "canvas_fillText" (func $canvas_fillText (param i32 i32 i32 i32 i32 i32 i32 i32)))` // two strings as (ptr,len) each
|
||||
- Host responsibilities:
|
||||
- Resolve strings from memory via `(ptr,len)` using TextDecoder('utf-8')
|
||||
- Map to DOM/Canvas/Console as appropriate
|
||||
- For plugins: use dlopen/dlsym to load and invoke nyash_plugin_* functions
|
||||
|
||||
WASM Mapping Rules (v0)
|
||||
- String marshalling: UTF-8 `(ptr:i32, len:i32)`; memory exported as `memory`.
|
||||
- Alignment: `ptr` 4-byte aligned is推奨(必須ではないが実装簡素化のため)。
|
||||
- Import naming: `env.<iface>_<method>` or nested `env` modules(実装都合でどちらでも可)。
|
||||
- 推奨: `env.console_log`, `env.canvas_fillRect`, `env.canvas_fillText`。
|
||||
- Argument order: 文字列は `(ptr,len)` を1引数扱いで連続配置。複数文字列はその都度 `(ptr,len)`。
|
||||
- Return: v0では`void`または整数のみ(複合戻りはout-paramに委譲)。
|
||||
- Memory growth: ホストは`memory.buffer`の再割当を考慮(必要に応じて毎回ビューを取り直す)。
|
||||
|
||||
RuntimeImportsとBIDの関係
|
||||
- `RuntimeImports` は ABI/BID をWASM向けに具体化した実装レイヤー(WASM専用の橋渡し)。
|
||||
- 生成方針: 将来的にBID(YAML/JSON)から`importObject`と`(import ...)`宣言を自動生成する。
|
||||
- 例(BID→WASM):
|
||||
- `env.console.log(string msg)` → `console_log(ptr:i32, len:i32)`
|
||||
- `env.canvas.fillRect(string canvasId, i32 x, i32 y, i32 w, i32 h, string color)`
|
||||
→ `canvas_fillRect(id_ptr, id_len, x, y, w, h, color_ptr, color_len)`
|
||||
|
||||
============================================================
|
||||
ABIの確定事項(BID-1, 日本語)
|
||||
============================================================
|
||||
|
||||
基本方針(BID-1)
|
||||
- 文字列は UTF-8 の `(ptr:usize, len:usize)` で受け渡す(NUL終端不要、内部NUL禁止)。
|
||||
- 配列/バイト列は `(ptr:usize, len:usize)` とする。
|
||||
- 数値は WASM/LLVM と親和性の高い素のプリミティブ(i32/i64/f32/f64)。
|
||||
- 真偽値は `i32` で 0=false, 1=true。
|
||||
- ポインタは `usize`(WASM MVPは32bit、ネイティブx86-64は64bit)。
|
||||
- エンディアンはリトルエンディアン(WASM/一般的なネイティブと一致)。
|
||||
- 呼出規約は単一エントリーポイント `nyash_plugin_invoke` + BID-1 TLV形式。
|
||||
- 戻り値はBID-1 TLV形式(2回呼び出しパターンでサイズ取得)。
|
||||
- メモリは `memory` をエクスポート(WASM)。ホスト側で管理。
|
||||
- 効果(effect)は BID に必須。pure は再順序化可、mut/io は順序保持。
|
||||
- 同期のみ(非同期は将来拡張)。
|
||||
- スレッド前提:シングルスレッド(Phase 1)。
|
||||
|
||||
メモリ管理戦略
|
||||
- 2回呼び出しパターン:
|
||||
1. result=NULLでサイズ取得
|
||||
2. ホストがallocateして結果取得
|
||||
- 文字列エンコーディング:UTF-8必須、内部NUL禁止
|
||||
- ハンドル再利用対策:generation追加で ABA問題回避(将来)
|
||||
|
||||
Boxライフサイクル管理
|
||||
- **birth/fini原則**:
|
||||
- method_id=0 は必ず`birth()`(コンストラクタ)
|
||||
- method_id=最大値 は必ず`fini()`(デストラクタ)
|
||||
- birthで割り当てたリソースはfiniで解放
|
||||
- **メモリ所有権**:
|
||||
- プラグインがmalloc()したメモリ → プラグインがfree()
|
||||
- ホストが提供したバッファ → ホストが管理
|
||||
- 引数として渡されたメモリ → read-onlyとして扱う
|
||||
- **インスタンス管理**:
|
||||
- instance_idはホストが発行・管理
|
||||
- プラグインは内部マップでinstance_id → 実装構造体を管理
|
||||
- nyash_plugin_shutdown()で全インスタンスをクリーンアップ
|
||||
|
||||
型と表現(BID-1)
|
||||
- `i32`: 32bit 符号付き整数
|
||||
- `i64`: 64bit 符号付き整数(WASMではJSブリッジ注意。Host側はBigInt等)
|
||||
- `f32/f64`: IEEE 754
|
||||
- `bool`: i32(0/1)
|
||||
- `string`: UTF-8 `(ptr:usize, len:usize)`
|
||||
- `bytes`: バイナリデータ `(ptr:usize, len:usize)`
|
||||
- `array<T>`: `(ptr:usize, len:usize)`
|
||||
- `handle`: Box参照 `{type_id:u32, instance_id:u32}` または packed u64
|
||||
- `void`: 戻り値なし
|
||||
|
||||
BidType Rust実装
|
||||
```rust
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum BidType {
|
||||
// プリミティブ(FFI境界で値渡し)
|
||||
Bool, I32, I64, F32, F64,
|
||||
String, Bytes,
|
||||
|
||||
// Handle設計
|
||||
Handle { type_id: u32, instance_id: u32 },
|
||||
|
||||
// メタ型
|
||||
Void,
|
||||
|
||||
// Phase 2予約
|
||||
Option(Box<BidType>),
|
||||
Result(Box<BidType>, Box<BidType>),
|
||||
Array(Box<BidType>),
|
||||
}
|
||||
```
|
||||
|
||||
アラインメント/境界
|
||||
- `ptr` は 8byte アライン必須(構造体の効率的アクセス)。
|
||||
- 範囲外アクセスは未定義ではなく「Hostが防ぐ/検証する」方針(将来、Verifier/境界チェック生成)。
|
||||
- プラットフォーム依存:
|
||||
- Linux x86-64: 8バイト境界
|
||||
- WASM MVP: 4バイト境界(互換性のため)
|
||||
|
||||
命名規約
|
||||
- `env.console.log`, `env.canvas.fillRect` のように `<namespace>.<iface>.<method>`。
|
||||
- WASM import 名は `env.console_log` 等の平坦化でも可(生成側で一貫)。
|
||||
- プラグイン関数名: `nyash_plugin_*` プレフィックス必須。
|
||||
|
||||
エラー/例外
|
||||
- BID-1標準エラーコード使用(NYB_*)。
|
||||
- 失敗は整数ステータスで返却。
|
||||
- 例外/シグナルは範囲外。
|
||||
|
||||
セキュリティ/権限(将来)
|
||||
- BID に必要権限(console/canvas/storage/net…)を記述。HostはAllowlistで制御(Phase 9.9)。
|
||||
|
||||
実装上の注意点
|
||||
- ハンドル再利用/ABA: generation追加で回避
|
||||
- スレッド前提: シングルスレッド前提を明記
|
||||
- メソッドID衝突: ビルド時固定で回避
|
||||
- エラー伝播: トランスポート/ドメインエラー分離
|
||||
- 文字列エンコード: UTF-8必須、内部NUL禁止
|
||||
|
||||
============================================================
|
||||
BIDサンプル(YAML, 日本語)
|
||||
============================================================
|
||||
|
||||
```yaml
|
||||
version: 0
|
||||
interfaces:
|
||||
- name: env.console
|
||||
box: Console
|
||||
methods:
|
||||
- name: log
|
||||
params: [ { string: msg } ]
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: env.canvas
|
||||
box: Canvas
|
||||
methods:
|
||||
- name: fillRect
|
||||
params:
|
||||
- { string: canvas_id }
|
||||
- { i32: x }
|
||||
- { i32: y }
|
||||
- { i32: w }
|
||||
- { i32: h }
|
||||
- { string: color }
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: fillText
|
||||
params:
|
||||
- { string: canvas_id }
|
||||
- { string: text }
|
||||
- { i32: x }
|
||||
- { i32: y }
|
||||
- { string: font }
|
||||
- { string: color }
|
||||
returns: void
|
||||
effect: io
|
||||
```
|
||||
|
||||
ファイルとしてのサンプル(同等内容)
|
||||
- `docs/nyir/bid_samples/console.yaml`
|
||||
- `docs/nyir/bid_samples/canvas.yaml`
|
||||
|
||||
============================================================
|
||||
Host側 importObject サンプル(ブラウザ, 日本語)
|
||||
============================================================
|
||||
|
||||
```js
|
||||
// 文字列(ptr,len)の復元ヘルパ
|
||||
function utf8FromMemory(memory, ptr, len) {
|
||||
const u8 = new Uint8Array(memory.buffer, ptr, len);
|
||||
return new TextDecoder('utf-8').decode(u8);
|
||||
}
|
||||
|
||||
const importObject = {
|
||||
env: {
|
||||
print: (v) => console.log(v),
|
||||
print_str: (ptr, len) => {
|
||||
console.log(utf8FromMemory(wasmInstance.exports.memory, ptr, len));
|
||||
},
|
||||
console_log: (ptr, len) => {
|
||||
console.log(utf8FromMemory(wasmInstance.exports.memory, ptr, len));
|
||||
},
|
||||
canvas_fillRect: (idPtr, idLen, x, y, w, h, colorPtr, colorLen) => {
|
||||
const mem = wasmInstance.exports.memory;
|
||||
const id = utf8FromMemory(mem, idPtr, idLen);
|
||||
const color = utf8FromMemory(mem, colorPtr, colorLen);
|
||||
const cv = document.getElementById(id);
|
||||
if (!cv) return;
|
||||
const ctx = cv.getContext('2d');
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(x, y, w, h);
|
||||
},
|
||||
canvas_fillText: (idPtr, idLen, textPtr, textLen, x, y, fontPtr, fontLen, colorPtr, colorLen) => {
|
||||
const mem = wasmInstance.exports.memory;
|
||||
const id = utf8FromMemory(mem, idPtr, idLen);
|
||||
const text = utf8FromMemory(mem, textPtr, textLen);
|
||||
const font = utf8FromMemory(mem, fontPtr, fontLen);
|
||||
const color = utf8FromMemory(mem, colorPtr, colorLen);
|
||||
const cv = document.getElementById(id);
|
||||
if (!cv) return;
|
||||
const ctx = cv.getContext('2d');
|
||||
ctx.font = font;
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
============================================================
|
||||
ExternCall → WASM 呼び出しの例(日本語)
|
||||
============================================================
|
||||
|
||||
Nyash コード(概念):
|
||||
```
|
||||
console = new WebConsoleBox("output")
|
||||
console.log("Hello Nyash!")
|
||||
|
||||
canvas = new WebCanvasBox("game-canvas", 400, 300)
|
||||
canvas.fillRect(50, 50, 80, 60, "red")
|
||||
```
|
||||
|
||||
MIR(ExternCall化のイメージ):
|
||||
```
|
||||
ExternCall { iface: "env.console", method: "log", args: [ string("Hello Nyash!") ] }
|
||||
ExternCall { iface: "env.canvas", method: "fillRect", args: [ string("game-canvas"), 50, 50, 80, 60, string("red") ] }
|
||||
```
|
||||
|
||||
WASM import 呼び出し(概念):
|
||||
```
|
||||
call $console_log(msg_ptr, msg_len)
|
||||
call $canvas_fillRect(id_ptr, id_len, 50, 50, 80, 60, color_ptr, color_len)
|
||||
```
|
||||
|
||||
備考
|
||||
- 文字列定数は data segment に配置し、実行時に (ptr,len) を与える。
|
||||
- 動的文字列はランタイムでバッファ確保→(ptr,len) を渡す。
|
||||
|
||||
|
||||
VM Mapping (Stub v0)
|
||||
- Maintain a registry of externs by FQN (e.g., env.console.log) → function pointer.
|
||||
- Console: print to stdout; Canvas: log params or no-op.
|
||||
|
||||
LLVM IR Mapping (Preview)
|
||||
- Declare external functions with matching signatures (i32/i64/f32/f64/bool, i8* + i32 for strings).
|
||||
- Example: `declare void @env_console_log(i8* nocapture, i32)`
|
||||
- Strings allocated in data segment or heap; pass pointer + length.
|
||||
|
||||
Versioning
|
||||
- `version: 0` for the first public draft.
|
||||
- Backward-compatible extensions should add new methods/imports; breaking changes bump major.
|
||||
|
||||
Open Points (to validate post v0)
|
||||
- Boxref passing across FFI boundaries (opaque handles vs pointers).
|
||||
- Async externs and scheduling.
|
||||
- Error model harmonization (status vs result-box).
|
||||
68
docs/reference/plugin-system/filebox-bid-mapping.md
Normal file
68
docs/reference/plugin-system/filebox-bid-mapping.md
Normal file
@ -0,0 +1,68 @@
|
||||
FileBox × BID-FFI 対応表(Nyash API ↔ Plugin ABI)
|
||||
|
||||
概要
|
||||
- 目的: Nyash言語における `FileBox` のAPIを、BID-FFIプラグイン実装(C ABI)と正確に対応付ける。
|
||||
- 設置: C:\git\nyash-project\nyash\docs\説明書\reference\box-design\filebox-bid-mapping.md(Windowsパス例)
|
||||
|
||||
前提
|
||||
- BID-FFI v1(2段階応答/ShortBuffer=-1)
|
||||
- TLVヘッダ: `u16 version(=1)`, `u16 argc`
|
||||
- TLVエントリ: `u8 tag`, `u8 reserved(0)`, `u16 size`, payload
|
||||
- 主要タグ: 1=Bool, 2=I32, 3=I64, 4=F32, 5=F64, 6=String, 7=Bytes, 8=Handle(u64), 9=Void
|
||||
|
||||
メソッドID(プラグイン側)
|
||||
- 0: birth(instance生成) → 戻り値: u32 instance_id(暫定)
|
||||
- 1: open(String path, String mode) → Void
|
||||
- 2: read(I32 size) → Bytes
|
||||
- 3: write(Bytes data) → I32(書込バイト数)
|
||||
- 4: close() → Void
|
||||
- 0xFFFF_FFFF: fini(破棄)
|
||||
|
||||
Nyash API ↔ Plugin ABI 対応
|
||||
- 構築: `new FileBox(path: string)`
|
||||
- 既定動作: プラグイン設定が有効な場合、birth→open(path, "rw") を内部実行
|
||||
- フォールバック: プラグインが無効/未設定ならビルトインFileBoxを使用
|
||||
|
||||
- 書込: `FileBox.write(data: string)`
|
||||
- 変換: String → Bytes(UTF-8)
|
||||
- 呼出: method_id=3(write)
|
||||
- 戻り: I32 を受け取り、Nyash側は "ok" を返却(将来は書込サイズも返せる拡張余地)
|
||||
|
||||
- 読取: `FileBox.read([size: integer])`
|
||||
- 変換: 省略時デフォルト 1MB(1_048_576)を指定
|
||||
- 呼出: method_id=2(read)
|
||||
- 戻り: Bytes → String(UTF-8として解釈、失敗時はlossy)
|
||||
|
||||
- 閉じ: `FileBox.close()`
|
||||
- 呼出: method_id=4(close)
|
||||
- 戻り: Void → Nyash側は "ok"
|
||||
|
||||
エラーモデル(戻り値)
|
||||
- 0: 成功
|
||||
- -1: ShortBuffer(2段階応答。副作用なしで必要サイズを *result_len に返却)
|
||||
- -2: InvalidType
|
||||
- -3: InvalidMethod
|
||||
- -4: InvalidArgs
|
||||
- -5: PluginError
|
||||
- -8: InvalidHandle
|
||||
|
||||
例(Nyashコード)
|
||||
```
|
||||
// プラグイン優先で FileBox を生成
|
||||
local f
|
||||
f = new FileBox("/tmp/nyash_example.txt")
|
||||
f.write("Hello from Nyash via plugin!")
|
||||
print("READ=" + f.read())
|
||||
f.close()
|
||||
```
|
||||
|
||||
実装メモ(現在の挙動)
|
||||
- コンストラクタ: プラグイン有効時は birth→open("rw")。指定モードでの open は将来のAPI拡張候補(例: `FileBox.open(mode)`)。
|
||||
- read(size): Nyashからサイズを指定するAPIは次段で追加予定。現状は既定1MBで読み取り。
|
||||
- write: 書込サイズはプラグインからI32で返るが、Nyash側APIは簡便化のため "ok" を返却(将来拡張余地)。
|
||||
|
||||
関連ドキュメント
|
||||
- plugin-ABI: docs/説明書/reference/box-design/ffi-abi-specification.md
|
||||
- plugin system: docs/説明書/reference/box-design/plugin-system.md
|
||||
- plugin-tester: docs/説明書/reference/plugin-tester.md
|
||||
|
||||
104
docs/reference/plugin-system/migration-guide.md
Normal file
104
docs/reference/plugin-system/migration-guide.md
Normal file
@ -0,0 +1,104 @@
|
||||
# Plugin Documentation Migration Guide
|
||||
|
||||
## 🎯 概要
|
||||
|
||||
このガイドは、Nyashプラグインシステムの古いドキュメントから実際の実装に移行するためのものです。
|
||||
|
||||
## 📚 Documentation Status
|
||||
|
||||
### ✅ **Current Working Specification**
|
||||
- **[BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md)** - **RECOMMENDED**
|
||||
- 実際に動作している実装をベースとした正確な仕様
|
||||
- FileBoxプラグインで実証済み
|
||||
- `plugin_loader_v2.rs`の実装に基づく
|
||||
|
||||
### ⚠️ **Deprecated Documentation**
|
||||
- **[ffi-abi-specification.md](./ffi-abi-specification.md)** - ❌ DEPRECATED
|
||||
- 理想的な設計案だが未実装
|
||||
- MIR ExternCall設計が含まれているが、実際には使われていない
|
||||
|
||||
- **[plugin-system.md](./plugin-system.md)** - ❌ DEPRECATED
|
||||
- YAML DSLを使った将来構想
|
||||
- 現在の実装とは大きく異なる
|
||||
|
||||
- **[nyash-toml-v2-spec.md](./nyash-toml-v2-spec.md)** - ⚠️ PARTIALLY OUTDATED
|
||||
- 基本構造は正しいが、実際の形式と部分的に異なる
|
||||
|
||||
### ✅ **Still Accurate Documentation**
|
||||
- **[plugin-tester.md](./plugin-tester.md)** - ✅ CURRENT
|
||||
- プラグイン診断ツールの使用方法
|
||||
- 実際のツールと一致
|
||||
|
||||
- **[filebox-bid-mapping.md](./filebox-bid-mapping.md)** - ✅ USEFUL REFERENCE
|
||||
- FileBox APIとプラグイン実装の対応表
|
||||
- 開発時の参考資料として有効
|
||||
|
||||
## 🔄 Migration Steps
|
||||
|
||||
### For Plugin Developers
|
||||
|
||||
1. **Start with**: [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md)
|
||||
2. **Refer to**: [実際のnyash.toml](../../../../nyash.toml) for configuration format
|
||||
3. **Use**: [plugin-tester](../../../../tools/plugin-tester/) for testing
|
||||
4. **Study**: [FileBox plugin](../../../../plugins/nyash-filebox-plugin/) as reference implementation
|
||||
|
||||
### For Nyash Core Developers
|
||||
|
||||
1. **Phase 1**: ✅ COMPLETED - Documentation cleanup with deprecation notices
|
||||
2. **Phase 2**: ✅ COMPLETED - Accurate specification creation
|
||||
3. **Phase 3**: 🚧 TODO - MIR ExternCall implementation to connect with plugin system
|
||||
|
||||
## 🎯 Key Differences
|
||||
|
||||
### Old Documentation vs Reality
|
||||
|
||||
| Aspect | Old Docs | Reality |
|
||||
|--------|----------|---------|
|
||||
| Configuration | YAML DSL | TOML format |
|
||||
| API Design | Complex handle system | Simple TLV + method_id |
|
||||
| MIR Integration | Fully designed | Stub only |
|
||||
| ABI Version | Multiple versions | BID-FFI v1 only |
|
||||
|
||||
### Working Configuration Format
|
||||
|
||||
**Old (in deprecated docs)**:
|
||||
```yaml
|
||||
# filebox.plugin.yaml
|
||||
schema: 1
|
||||
apis:
|
||||
- sig: "FileBox::open(path: string) -> FileBox"
|
||||
```
|
||||
|
||||
**Current (actual)**:
|
||||
```toml
|
||||
[libraries."libnyash_filebox_plugin.so"]
|
||||
boxes = ["FileBox"]
|
||||
path = "./plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so"
|
||||
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
|
||||
birth = { method_id = 0 }
|
||||
open = { method_id = 1 }
|
||||
```
|
||||
|
||||
## 📞 FFI Interface
|
||||
|
||||
**Old (complex)**:
|
||||
- Multiple entry points
|
||||
- Complex handle management
|
||||
- Dynamic type discovery
|
||||
|
||||
**Current (simple)**:
|
||||
- Single entry point: `nyash_plugin_invoke`
|
||||
- Fixed TLV protocol
|
||||
- Static configuration in nyash.toml
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. ✅ **Documentation Cleanup**: Completed
|
||||
2. 🚧 **MIR Integration**: Implement ExternCall → plugin system connection
|
||||
3. 🔮 **Future**: Consider implementing some ideas from deprecated docs
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-08-20
|
||||
**Status**: Documentation reorganization Phase 2 completed
|
||||
163
docs/reference/plugin-system/nyash-toml-v2-spec.md
Normal file
163
docs/reference/plugin-system/nyash-toml-v2-spec.md
Normal file
@ -0,0 +1,163 @@
|
||||
# nyash.toml v2 仕様 - 究極のシンプル設計
|
||||
|
||||
> ⚠️ **PARTIALLY OUTDATED - 部分的に古い**
|
||||
>
|
||||
> この文書の基本構造は正しいですが、実際の形式と一部異なります。
|
||||
>
|
||||
> **最新の実際の設定形式については、以下を参照してください:**
|
||||
> - [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md) - 現在動作中の仕様
|
||||
> - [nyash.toml設定例](../../../../nyash.toml) - 実際の設定形式
|
||||
|
||||
## 🎯 概要
|
||||
**革命的シンプル設計**: nyash.toml中心アーキテクチャ + 最小限FFI
|
||||
|
||||
## 📝 nyash.toml v2形式
|
||||
|
||||
### マルチBox型プラグイン対応
|
||||
```toml
|
||||
[libraries]
|
||||
# ライブラリ定義(1つのプラグインで複数のBox型を提供可能)
|
||||
"libnyash_filebox_plugin.so" = {
|
||||
boxes = ["FileBox"],
|
||||
path = "./target/release/libnyash_filebox_plugin.so"
|
||||
}
|
||||
|
||||
# 将来の拡張例: 1つのプラグインで複数Box型
|
||||
"libnyash_network_plugin.so" = {
|
||||
boxes = ["SocketBox", "HTTPServerBox", "HTTPClientBox"],
|
||||
path = "./target/release/libnyash_network_plugin.so"
|
||||
}
|
||||
|
||||
# FileBoxの型情報定義
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox]
|
||||
type_id = 6
|
||||
abi_version = 1 # ABIバージョンもここに!
|
||||
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
|
||||
# method_id だけで十分(引数情報は実行時チェック)
|
||||
birth = { method_id = 0 }
|
||||
open = { method_id = 1 }
|
||||
read = { method_id = 2 }
|
||||
write = { method_id = 3 }
|
||||
close = { method_id = 4 }
|
||||
fini = { method_id = 4294967295 } # 0xFFFFFFFF
|
||||
```
|
||||
|
||||
## 🚀 究極のシンプルFFI
|
||||
|
||||
### プラグインが実装する関数
|
||||
|
||||
#### 必須: メソッド実行エントリーポイント
|
||||
```c
|
||||
// 唯一の必須関数 - すべてのメソッド呼び出しはここから
|
||||
extern "C" fn nyash_plugin_invoke(
|
||||
type_id: u32, // Box型ID(例: FileBox = 6)
|
||||
method_id: u32, // メソッドID(0=birth, 0xFFFFFFFF=fini)
|
||||
instance_id: u32, // インスタンスID(0=static/birth)
|
||||
args: *const u8, // TLVエンコード引数
|
||||
args_len: usize,
|
||||
result: *mut u8, // TLVエンコード結果バッファ
|
||||
result_len: *mut usize // [IN/OUT]バッファサイズ
|
||||
) -> i32 // 0=成功, 負=エラー
|
||||
```
|
||||
|
||||
#### オプション: グローバル初期化
|
||||
```c
|
||||
// プラグインロード時に1回だけ呼ばれる(実装は任意)
|
||||
extern "C" fn nyash_plugin_init() -> i32 {
|
||||
// グローバルリソースの初期化
|
||||
// 設定ファイルの読み込み
|
||||
// ログファイルのオープン
|
||||
// 0=成功, 負=エラー(プラグインは無効化される)
|
||||
}
|
||||
```
|
||||
|
||||
### 廃止されたAPI
|
||||
```c
|
||||
// ❌ これらは全部不要!
|
||||
nyash_plugin_abi_version() // → nyash.tomlのabi_version
|
||||
nyash_plugin_get_box_count() // → nyash.tomlのboxes配列
|
||||
nyash_plugin_get_box_info() // → nyash.tomlから取得
|
||||
NyashHostVtable // → 完全廃止!
|
||||
```
|
||||
|
||||
## 📊 設計原則
|
||||
|
||||
### 1. **Single Source of Truth**
|
||||
- すべてのメタ情報はnyash.tomlに集約
|
||||
- プラグインは純粋な実装のみ
|
||||
|
||||
### 2. **Zero Dependencies**
|
||||
- Host VTable廃止 = 依存関係ゼロ
|
||||
- プラグインは完全に独立
|
||||
|
||||
### 3. **シンプルなライフサイクル**
|
||||
- `init` (オプション): プラグインロード時の初期化
|
||||
- `birth` (method_id=0): インスタンス作成
|
||||
- 各種メソッド: インスタンス操作
|
||||
- `fini` (method_id=0xFFFFFFFF): 論理的終了
|
||||
|
||||
### 4. **ログ出力**
|
||||
```rust
|
||||
// プラグインは自己完結でログ出力
|
||||
eprintln!("[FileBox] Opened: {}", path); // 標準エラー
|
||||
|
||||
// または専用ログファイル
|
||||
let mut log = File::create("plugin_debug.log")?;
|
||||
writeln!(log, "{}: FileBox birth", chrono::Local::now())?;
|
||||
```
|
||||
|
||||
### 5. **init関数の活用例**
|
||||
```rust
|
||||
static mut LOG_FILE: Option<File> = None;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn nyash_plugin_init() -> i32 {
|
||||
// ログファイルを事前に開く
|
||||
match File::create("filebox.log") {
|
||||
Ok(f) => {
|
||||
unsafe { LOG_FILE = Some(f); }
|
||||
0 // 成功
|
||||
}
|
||||
Err(_) => -1 // エラー → プラグイン無効化
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 実装の流れ
|
||||
|
||||
### Phase 1: nyash.toml v2パーサー
|
||||
1. 新形式の読み込み
|
||||
2. Box型情報の抽出
|
||||
3. メソッドID管理
|
||||
|
||||
### Phase 2: プラグインローダー簡素化
|
||||
1. `nyash_plugin_init`(オプション)と`nyash_plugin_invoke`(必須)をロード
|
||||
2. nyash.tomlベースの型登録
|
||||
3. Host VTable関連コードを削除
|
||||
4. init関数が存在し失敗した場合はプラグインを無効化
|
||||
|
||||
### Phase 3: プラグイン側の対応
|
||||
1. abi/get_box_count/get_box_info関数を削除
|
||||
2. init関数は必要に応じて実装(グローバル初期化)
|
||||
3. invoke関数でメソッド処理
|
||||
4. ログ出力を自己完結に
|
||||
|
||||
## 🎉 メリット
|
||||
|
||||
1. **究極のシンプルさ** - 基本的にFFI関数1つ(initはオプション)
|
||||
2. **保守性向上** - 複雑な相互依存なし
|
||||
3. **テスト容易性** - モック不要
|
||||
4. **移植性** - どの言語でも実装可能
|
||||
5. **拡張性** - nyash.toml編集で機能追加
|
||||
6. **初期化保証** - init関数で早期エラー検出可能
|
||||
|
||||
## 🚨 注意事項
|
||||
|
||||
- プラグインのログは標準エラー出力かファイル出力で
|
||||
- メモリ管理はプラグイン内で完結
|
||||
- 非同期処理はNyash側でFutureBoxラップ
|
||||
|
||||
---
|
||||
|
||||
**革命完了**: これ以上シンプルにできない究極の設計!
|
||||
55
docs/reference/plugin-system/nyash-toml-v2_1-spec.md
Normal file
55
docs/reference/plugin-system/nyash-toml-v2_1-spec.md
Normal file
@ -0,0 +1,55 @@
|
||||
# nyash.toml v2.1 拡張仕様(最小)
|
||||
|
||||
目的: プラグインBoxのメソッド引数として、他のBoxを不透明参照(BoxRef)で安全に受け渡す。
|
||||
|
||||
## 変更点(v2 → v2.1)
|
||||
- メソッド引数型に `kind = "box"` を追加(当面は `category = "plugin"` のみ)
|
||||
- TLVに BoxRef(Handle)を追加(tag = 8)
|
||||
- payload: `type_id: u32 (LE)`, `instance_id: u32 (LE)`(合計8バイト)
|
||||
- 既存タグは不変:1=Int64, 2=String(UTF-8), 3=Bool
|
||||
|
||||
## 例: libraries セクション
|
||||
```toml
|
||||
[libraries]
|
||||
[libraries."libnyash_filebox_plugin.so"]
|
||||
boxes = ["FileBox"]
|
||||
path = "./target/release/libnyash_filebox_plugin.so"
|
||||
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox]
|
||||
type_id = 6
|
||||
abi_version = 1
|
||||
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
|
||||
# 既存
|
||||
birth = { method_id = 0 }
|
||||
open = { method_id = 1 }
|
||||
close = { method_id = 4 }
|
||||
|
||||
# 追加例: Box引数を1つ受け取る
|
||||
copyFrom = { method_id = 7, args = [ { kind = "box", category = "plugin" } ] }
|
||||
```
|
||||
|
||||
備考:
|
||||
- `args` を省略した場合は引数なし(ゼロ引数)とみなす(v2互換)
|
||||
- 複数引数は配列で列挙(例: 2引数なら2要素)
|
||||
- ユーザー定義Boxや複雑なビルトインBoxは当面対象外(将来のvtable/retain-release設計で拡張)
|
||||
|
||||
## 呼び出し時のTLVエンコード
|
||||
- 先頭ヘッダ `[ver:1, argc:1, rsv:2]` の後、各引数を `tag + payload` で列挙
|
||||
- `tag=8 (Handle/BoxRef)`: payload = `type_id(4) + instance_id(4)` (LE)
|
||||
- 未対応Box種別に対してはエラーを返す(開発時のみ toString フォールバックを許容可能)
|
||||
|
||||
## 戻り値(v2.1→v2.2)
|
||||
- v2.1: Int/String/Bool(1/6/3)とVoid(9)
|
||||
- v2.2: BoxRef(Handle, tag=8) の「返り値」対応を追加(同一/別Box型どちらも可)
|
||||
- payload: `type_id:u32` + `instance_id:u32`
|
||||
- Loaderは `type_id` から `lib_name/box_name` を逆引きし、`PluginBoxV2` を生成して返す
|
||||
|
||||
## 互換性
|
||||
- `args` 宣言がない既存v2設定はそのまま利用可
|
||||
- BoxRefを使わないメソッドは従来通り Int/String/Bool のみで動作
|
||||
|
||||
## 実装メモ(参考)
|
||||
- Loader: invoke時の引数エンコードに `tag=4` を追加(`category=plugin` のみ)
|
||||
- プラグイン側: 受領した `type_id` と期待型を照合し、不一致ならエラー
|
||||
- 所有権: 呼び出し中の一時借用(保持は将来の retain/release で対応)
|
||||
437
docs/reference/plugin-system/plugin-system.md
Normal file
437
docs/reference/plugin-system/plugin-system.md
Normal file
@ -0,0 +1,437 @@
|
||||
# Nyash Box プラグインシステム設計
|
||||
|
||||
> ⚠️ **DEPRECATED - 将来構想**
|
||||
>
|
||||
> この文書はYAML DSLを使った将来的なプラグインシステム構想です。
|
||||
> **現在の実装とは異なります。**
|
||||
>
|
||||
> **実際に動作している仕様については、以下を参照してください:**
|
||||
> - [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md) - 現在動作中の仕様
|
||||
> - [nyash.toml設定例](../../../../nyash.toml) - 実際の設定形式
|
||||
> - [plugin_loader_v2.rs](../../../../src/runtime/plugin_loader_v2.rs) - 実装詳細
|
||||
|
||||
## 概要
|
||||
|
||||
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` - 矢印記法
|
||||
|
||||
### 🔄 Boxライフサイクル管理
|
||||
|
||||
```yaml
|
||||
lifecycle:
|
||||
# コンストラクタ(生命を与える)
|
||||
- sig: "FileBox#birth(path: string, mode?: string)"
|
||||
doc: "Box creation - called after memory allocation"
|
||||
|
||||
# デストラクタ(生命を終える)
|
||||
- sig: "FileBox#fini()"
|
||||
doc: "Box destruction - called before memory deallocation"
|
||||
```
|
||||
|
||||
**重要な原則**:
|
||||
- `birth()` - Boxインスタンス作成時に呼ばれる(メモリ割り当て後)
|
||||
- `fini()` - Boxインスタンス破棄時に呼ばれる(メモリ解放前)
|
||||
- プラグインが割り当てたメモリはプラグインが解放する責任を持つ
|
||||
|
||||
## 🔧 設定ファイル(nyash.toml)
|
||||
|
||||
### 基本形式(v1) - 単一Box型プラグイン
|
||||
|
||||
```toml
|
||||
# プロジェクトルートのnyash.toml
|
||||
[plugins]
|
||||
FileBox = "nyash-filebox-plugin" # FileBoxはプラグイン版を使用
|
||||
# StringBox = "mystring" # コメントアウト = ビルトイン使用
|
||||
|
||||
# FileBoxの型情報定義
|
||||
[plugins.FileBox.methods]
|
||||
read = { args = [] }
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
open = { args = [
|
||||
{ name = "path", from = "string", to = "string" },
|
||||
{ name = "mode", from = "string", to = "string" }
|
||||
] }
|
||||
close = { args = [] }
|
||||
exists = { args = [], returns = "bool" }
|
||||
```
|
||||
|
||||
### 拡張形式(v2) - マルチBox型プラグイン
|
||||
|
||||
```toml
|
||||
# 1つのプラグインで複数のBox型を提供
|
||||
[plugins.libraries]
|
||||
"nyash-network" = {
|
||||
plugin_path = "libnyash_network.so",
|
||||
provides = ["SocketBox", "HTTPServerBox", "HTTPRequestBox", "HTTPResponseBox", "HttpClientBox"]
|
||||
}
|
||||
|
||||
"nyash-stdlib" = {
|
||||
plugin_path = "libnyash_stdlib.so",
|
||||
provides = ["MathBox", "TimeBox", "RandomBox"]
|
||||
}
|
||||
|
||||
# 各Box型の詳細定義
|
||||
[plugins.types.SocketBox]
|
||||
library = "nyash-network"
|
||||
type_id = 100
|
||||
methods = {
|
||||
bind = { args = [
|
||||
{ name = "address", from = "string", to = "string" },
|
||||
{ name = "port", from = "integer", to = "u16" }
|
||||
]},
|
||||
connect = { args = [
|
||||
{ name = "address", from = "string", to = "string" },
|
||||
{ name = "port", from = "integer", to = "u16" }
|
||||
]},
|
||||
read = { args = [], returns = "string" },
|
||||
write = { args = [{ from = "string", to = "bytes" }] },
|
||||
close = { args = [] }
|
||||
}
|
||||
|
||||
[plugins.types.HTTPServerBox]
|
||||
library = "nyash-network"
|
||||
type_id = 101
|
||||
methods = {
|
||||
bind = { args = [
|
||||
{ name = "address", from = "string", to = "string" },
|
||||
{ name = "port", from = "integer", to = "u16" }
|
||||
]},
|
||||
route = { args = [
|
||||
{ name = "path", from = "string", to = "string" },
|
||||
{ name = "method", from = "string", to = "string" }
|
||||
]},
|
||||
start = { args = [] }
|
||||
}
|
||||
|
||||
[plugins.types.HttpClientBox]
|
||||
library = "nyash-network"
|
||||
type_id = 102
|
||||
methods = {
|
||||
get = { args = [{ name = "url", from = "string", to = "string" }], returns = "string" },
|
||||
post = { args = [
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "body", from = "string", to = "string" }
|
||||
], returns = "string" }
|
||||
}
|
||||
```
|
||||
|
||||
### 型マッピング仕様
|
||||
|
||||
#### 基本型
|
||||
| Nyash型 | FFI型 | TLVタグ | 説明 |
|
||||
|---------|-------|---------|------|
|
||||
| `string` | `string` | 0x01 | UTF-8文字列 |
|
||||
| `integer` | `i64` | 0x02 | 64ビット整数 |
|
||||
| `float` | `f64` | 0x03 | 64ビット浮動小数点 |
|
||||
| `bool` | `bool` | 0x04 | 真偽値 |
|
||||
| `bytes` | `Vec<u8>` | 0x05 | バイト配列 |
|
||||
|
||||
|
||||
### プラグイン検索パス
|
||||
|
||||
```toml
|
||||
[plugin_paths]
|
||||
search_paths = [
|
||||
"./plugins/*/target/release", # 開発時リリースビルド
|
||||
"./plugins/*/target/debug", # 開発時デバッグビルド
|
||||
"/usr/local/lib/nyash/plugins", # システムインストール
|
||||
"~/.nyash/plugins" # ユーザーローカル
|
||||
]
|
||||
```
|
||||
|
||||
## 🏗️ アーキテクチャ
|
||||
|
||||
### 1. Boxレジストリ(v2対応版)
|
||||
|
||||
```rust
|
||||
// 起動時の動作
|
||||
let mut registry = HashMap::new();
|
||||
let mut loaded_plugins = 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_v2()?;
|
||||
|
||||
// 3a. v1形式:単一Box型プラグイン
|
||||
for (box_name, plugin_name) in config.plugins {
|
||||
registry.insert(box_name, BoxProvider::Plugin(plugin_name));
|
||||
}
|
||||
|
||||
// 3b. v2形式:マルチBox型プラグイン
|
||||
if let Some(libraries) = config.libraries {
|
||||
for (lib_name, lib_def) in libraries.libraries {
|
||||
// プラグインを一度だけロード
|
||||
let plugin = load_plugin(&lib_def.plugin_path)?;
|
||||
loaded_plugins.insert(lib_name.clone(), plugin);
|
||||
|
||||
// 提供する全Box型を登録
|
||||
for box_type in &lib_def.provides {
|
||||
registry.insert(box_type, BoxProvider::MultiPlugin(lib_name.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### マルチBox型プラグインFFI
|
||||
|
||||
```c
|
||||
// v2プラグインの追加エクスポート関数
|
||||
// 提供するBox型の数を返す
|
||||
extern "C" u32 nyash_plugin_get_box_count();
|
||||
|
||||
// 各Box型の情報を取得
|
||||
extern "C" NyashPluginInfo* nyash_plugin_get_box_info(u32 index);
|
||||
|
||||
// Box型名からtype_idを解決
|
||||
extern "C" u32 nyash_plugin_get_type_id(const char* box_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経由でプラグインに転送
|
||||
}
|
||||
```
|
||||
|
||||
## 📦 プラグイン実装例
|
||||
|
||||
```c
|
||||
// plugins/filebox/src/filebox.c
|
||||
#include "nyash_plugin_api.h"
|
||||
|
||||
// インスタンス管理
|
||||
typedef struct {
|
||||
FILE* fp;
|
||||
char* buffer; // プラグインが管理するバッファ
|
||||
} FileBoxInstance;
|
||||
|
||||
// birth - Boxに生命を与える
|
||||
i32 filebox_birth(u32 instance_id, const u8* args, size_t args_len) {
|
||||
// 引数からpath, modeを取得
|
||||
const char* path = extract_string_arg(args, 0);
|
||||
const char* mode = extract_string_arg(args, 1);
|
||||
|
||||
// インスタンス作成
|
||||
FileBoxInstance* instance = malloc(sizeof(FileBoxInstance));
|
||||
instance->fp = fopen(path, mode);
|
||||
instance->buffer = NULL;
|
||||
|
||||
// インスタンスを登録
|
||||
register_instance(instance_id, instance);
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// fini - Boxの生命を終える
|
||||
i32 filebox_fini(u32 instance_id) {
|
||||
FileBoxInstance* instance = get_instance(instance_id);
|
||||
if (!instance) return NYB_E_INVALID_HANDLE;
|
||||
|
||||
// プラグインが割り当てたメモリを解放
|
||||
if (instance->buffer) {
|
||||
free(instance->buffer);
|
||||
}
|
||||
|
||||
// ファイルハンドルをクローズ
|
||||
if (instance->fp) {
|
||||
fclose(instance->fp);
|
||||
}
|
||||
|
||||
// インスタンス自体を解放
|
||||
free(instance);
|
||||
unregister_instance(instance_id);
|
||||
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// read - バッファはプラグインが管理
|
||||
i32 filebox_read(u32 instance_id, i32 size, u8** result, size_t* result_len) {
|
||||
FileBoxInstance* instance = get_instance(instance_id);
|
||||
|
||||
// 既存バッファを解放して新規割り当て
|
||||
if (instance->buffer) free(instance->buffer);
|
||||
instance->buffer = malloc(size + 1);
|
||||
|
||||
// ファイル読み込み
|
||||
size_t read = fread(instance->buffer, 1, size, instance->fp);
|
||||
instance->buffer[read] = '\0';
|
||||
|
||||
// プラグインが所有するメモリを返す
|
||||
*result = instance->buffer;
|
||||
*result_len = read;
|
||||
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
## 🔐 メモリ管理の原則
|
||||
|
||||
### 所有権ルール
|
||||
1. **プラグインが割り当てたメモリ**
|
||||
- プラグインが`malloc()`したメモリはプラグインが`free()`する
|
||||
- `fini()`メソッドで確実に解放する
|
||||
- Nyash側は読み取りのみ(書き込み禁止)
|
||||
|
||||
2. **Nyashが割り当てたメモリ**
|
||||
- Nyashが提供したバッファはNyashが管理
|
||||
- プラグインは読み書き可能だが解放禁止
|
||||
- 引数として渡されたメモリはread-only
|
||||
|
||||
3. **ライフサイクル保証**
|
||||
- `birth()` → 各メソッド呼び出し → `fini()` の順序を保証
|
||||
- `fini()`は必ず呼ばれる(GC時またはプログラム終了時)
|
||||
- 循環参照による`fini()`遅延に注意
|
||||
|
||||
### Nyash側の実装
|
||||
```rust
|
||||
impl Drop for PluginBox {
|
||||
fn drop(&mut self) {
|
||||
// Boxが破棄される時、必ずfiniを呼ぶ
|
||||
let result = self.plugin.invoke(
|
||||
self.handle.type_id,
|
||||
FINI_METHOD_ID, // 最大値のmethod_id
|
||||
self.handle.instance_id,
|
||||
&[], // no arguments
|
||||
&mut []
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
eprintln!("Warning: fini failed for instance {}", self.handle.instance_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 段階的導入計画
|
||||
|
||||
### Phase 1: 基本実装(完了)
|
||||
- [x] BID-FFI基盤
|
||||
- [x] FileBoxプラグイン実装
|
||||
- [x] nyash.toml v1パーサー
|
||||
- [x] PluginBoxプロキシ
|
||||
- [x] プラグインロード機能
|
||||
|
||||
### Phase 2: マルチBox型対応(進行中)
|
||||
- [ ] nyash.toml v2パーサー実装
|
||||
- [ ] マルチBox型プラグインFFI拡張
|
||||
- [ ] plugin-testerの複数Box型対応
|
||||
- [ ] ネットワーク系プラグイン統合
|
||||
- HttpClientBox(新規実装)
|
||||
- SocketBox(既存移行)
|
||||
- HTTPServerBox(既存移行)
|
||||
- HTTPRequestBox(既存移行)
|
||||
- HTTPResponseBox(既存移行)
|
||||
|
||||
### Phase 3: 開発体験向上
|
||||
- [ ] YAMLからFFIコード自動生成
|
||||
- [ ] エラーメッセージ改善
|
||||
- [ ] プラグインテンプレート
|
||||
- [ ] ホットリロード対応
|
||||
|
||||
### Phase 4: エコシステム
|
||||
- [ ] プラグインレジストリ
|
||||
- [ ] バージョン管理
|
||||
- [ ] 依存関係解決
|
||||
- [ ] プラグイン間通信
|
||||
|
||||
## 🎉 利点
|
||||
|
||||
### v1形式の利点
|
||||
1. **ビルド時間短縮** - 使わないBoxはコンパイル不要
|
||||
2. **動的拡張** - 再コンパイルなしで新Box追加
|
||||
3. **Everything is Box維持** - 哲学は変わらない
|
||||
4. **段階的移行** - 1つずつBoxをプラグイン化
|
||||
|
||||
### v2形式の追加利点
|
||||
5. **依存関係の解決** - 関連Box群を1つのプラグインに
|
||||
6. **効率的な配布** - 複数Box型を1ライブラリで提供
|
||||
7. **メモリ効率** - 共有ライブラリは1度だけロード
|
||||
8. **内部連携** - 同一プラグイン内で直接通信可能
|
||||
|
||||
### 実例:HTTPServerBoxの依存問題解決
|
||||
|
||||
```toml
|
||||
# v1では困難だった構成
|
||||
# HTTPServerBoxはSocketBoxに依存するが...
|
||||
[plugins]
|
||||
SocketBox = "socket-plugin" # 別プラグイン
|
||||
HTTPServerBox = "http-plugin" # SocketBoxが使えない!
|
||||
|
||||
# v2なら簡単に解決
|
||||
[plugins.libraries]
|
||||
"nyash-network" = {
|
||||
plugin_path = "libnyash_network.so",
|
||||
provides = ["SocketBox", "HTTPServerBox", "HTTPRequestBox", "HTTPResponseBox"]
|
||||
}
|
||||
# HTTPServerBoxは同じプラグイン内でSocketBoxを直接使用可能
|
||||
```
|
||||
|
||||
## 📚 関連ドキュメント
|
||||
|
||||
- [BID-FFI仕様](./ffi-abi-specification.md)
|
||||
- [Everything is Box哲学](./everything-is-box.md)
|
||||
- [実装タスク](../../../予定/native-plan/issues/phase_9_75g_0_chatgpt_enhanced_final.md)
|
||||
66
docs/reference/plugin-system/plugin-tester.md
Normal file
66
docs/reference/plugin-system/plugin-tester.md
Normal file
@ -0,0 +1,66 @@
|
||||
Nyash Plugin Tester - 開発者向けツールガイド
|
||||
|
||||
概要
|
||||
- 目的: Nyash用プラグイン(BID-FFI準拠)の基本健全性を素早く診断するツール。
|
||||
- 実装場所: `tools/plugin-tester`
|
||||
- 想定対象: C ABIで `nyash_plugin_*` をエクスポートする動的ライブラリ(.so/.dll/.dylib)
|
||||
|
||||
ビルド
|
||||
- コマンド: `cd tools/plugin-tester && cargo build --release`
|
||||
- 実行ファイル: `tools/plugin-tester/target/release/plugin-tester`
|
||||
|
||||
サブコマンド
|
||||
- `check <plugin>`: プラグインのロード、ABI確認、init呼び出し、型名・メソッド一覧の表示
|
||||
- `lifecycle <plugin>`: birth→fini の往復テスト(インスタンスIDを返すことを確認)
|
||||
- `io <plugin>`: FileBox向けE2E(open→write→close→open→read)テスト
|
||||
|
||||
使用例
|
||||
- チェック:
|
||||
- `tools/plugin-tester/target/release/plugin-tester check plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so`
|
||||
- 期待出力例:
|
||||
- `ABI version: 1`
|
||||
- `Plugin initialized`
|
||||
- `Box Type: FileBox (ID: 6)` と 6メソッド(birth/open/read/write/close/fini)の列挙
|
||||
- ライフサイクル:
|
||||
- `tools/plugin-tester/target/release/plugin-tester lifecycle <path-to-plugin>`
|
||||
- 期待出力例: `birth → instance_id=1`, `fini → instance 1 cleaned`
|
||||
- ファイルI/O:
|
||||
- `tools/plugin-tester/target/release/plugin-tester io <path-to-plugin>`
|
||||
- 期待出力例: `open(w)`, `write 25 bytes`, `open(r)`, `read 25 bytes → 'Hello from plugin-tester!'`
|
||||
|
||||
BID-FFI 前提(v1)
|
||||
- 必須シンボル: `nyash_plugin_abi`, `nyash_plugin_init`, `nyash_plugin_invoke`, `nyash_plugin_shutdown`
|
||||
- 返却コード: 0=成功, -1=ShortBuffer(2段階応答), -2=InvalidType, -3=InvalidMethod, -4=InvalidArgs, -5=PluginError, -8=InvalidHandle
|
||||
- 2段階応答: `result`がNULLまたは小さい場合は `*result_len` に必要サイズを設定し -1 を返す(副作用なし)
|
||||
|
||||
TLV(Type-Length-Value)概要(簡易)
|
||||
- ヘッダ: `u16 version (=1)`, `u16 argc`
|
||||
- エントリ: `u8 tag`, `u8 reserved(0)`, `u16 size`, `payload...`
|
||||
- 主なタグ: 1=Bool, 2=I32, 3=I64, 4=F32, 5=F64, 6=String, 7=Bytes, 8=Handle(u64), 9=Void
|
||||
- plugin-testerの `io` は最小限のTLVエンコード/デコードを内蔵
|
||||
|
||||
プラグイン例(FileBox)
|
||||
- 実装場所: `plugins/nyash-filebox-plugin`
|
||||
- メソッドID: 0=birth, 1=open, 2=read, 3=write, 4=close, 0xFFFF_FFFF=fini
|
||||
- `open(path, mode)`: 引数は TLV(String, String)、返り値は TLV(Void)
|
||||
- `read(size)`: 引数 TLV(I32)、返 TLV(Bytes)
|
||||
- `write(bytes)`: 引数 TLV(Bytes)、返 TLV(I32: 書き込みバイト数)
|
||||
- `close()`: 返 TLV(Void)
|
||||
|
||||
パスの指定(例)
|
||||
- Linux: `plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so`
|
||||
- Windows: `plugins\nyash-filebox-plugin\target\release\nyash_filebox_plugin.dll`
|
||||
- macOS: `plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.dylib`
|
||||
|
||||
トラブルシュート
|
||||
- `nyash_plugin_abi not found`: ビルド設定(cdylib)やシンボル名を再確認
|
||||
- `ShortBuffer`が返るのにデータが取れない: 2回目の呼び出しで `result` と `*result_len` を適切に設定しているか確認
|
||||
- 読み出しサイズが0: 書き込み後に `close`→`open(r)` してから `read` を実行しているか確認
|
||||
|
||||
関連ドキュメント
|
||||
- `docs/CURRENT_TASK.md`(現在の進捗)
|
||||
- `docs/予定/native-plan/issues/phase_9_75g_bid_integration_architecture.md`(設計計画)
|
||||
|
||||
備考
|
||||
- 本説明書は `C:\git\nyash-project\nyash\docs\説明書\reference\plugin-tester.md` に配置されます(Windowsパス例)。
|
||||
|
||||
503
docs/reference/plugin-system/vm-plugin-integration.md
Normal file
503
docs/reference/plugin-system/vm-plugin-integration.md
Normal file
@ -0,0 +1,503 @@
|
||||
# VM Plugin Integration仕様書
|
||||
|
||||
## 🎯 概要
|
||||
|
||||
NyashのVMバックエンドとプラグインシステム(BID-FFI v1)の統合に関する技術仕様。Everything is Box哲学に基づき、**すべてのBox型(ビルトイン、ユーザー定義、プラグイン)**をVMで統一的に扱えるようにする。
|
||||
|
||||
## ⚠️ **現在のVM実装の重大な問題**
|
||||
|
||||
1. **ユーザー定義Box未対応** - NewBoxで文字列を返すだけ
|
||||
2. **birth/finiライフサイクル欠落** - コンストラクタ・デストラクタが呼ばれない
|
||||
3. **メソッド呼び出しハードコード** - 新メソッド追加が困難
|
||||
|
||||
これらを解決し、インタープリターと同等の統一処理を実現する。
|
||||
|
||||
## 🏗️ アーキテクチャ
|
||||
|
||||
### 統一Box管理モデル
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Nyash VM │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ VMValue │
|
||||
│ ├─ Integer(i64) ← 基本型は直接保持 │
|
||||
│ ├─ String(String) │
|
||||
│ ├─ Bool(bool) │
|
||||
│ └─ BoxRef(Arc<dyn NyashBox>) ← 複雑型全般 │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ 統一Box管理層 │
|
||||
│ ├─ BoxFactory : 統一Box作成 │
|
||||
│ ├─ ScopeTracker : ライフサイクル管理 │
|
||||
│ └─ MethodDispatcher : 統一メソッド呼び出し │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ 変換レイヤー │
|
||||
│ ├─ to_nyash_box() : VMValue → Box │
|
||||
│ └─ from_nyash_box() : Box → VMValue │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ プラグインローダー (PluginLoaderV2) │
|
||||
│ └─ BID-FFI v1プロトコルで通信 │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### VM構造体の完全形
|
||||
|
||||
```rust
|
||||
pub struct VM {
|
||||
// 既存フィールド
|
||||
registers: HashMap<RegisterId, VMValue>,
|
||||
memory: HashMap<MemoryLocation, VMValue>,
|
||||
|
||||
// 統一Box管理(新規)
|
||||
box_factory: Arc<BoxFactory>, // 統一Box作成
|
||||
plugin_loader: Option<Arc<PluginLoaderV2>>, // プラグイン
|
||||
scope_tracker: ScopeTracker, // finiライフサイクル
|
||||
box_declarations: Arc<RwLock<HashMap<String, BoxDeclaration>>>, // ユーザー定義Box
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 VMValue拡張仕様
|
||||
|
||||
### 型定義
|
||||
|
||||
```rust
|
||||
pub enum VMValue {
|
||||
// 基本型(既存)
|
||||
Integer(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
String(String),
|
||||
Future(FutureBox),
|
||||
Void,
|
||||
|
||||
// 拡張型(新規)
|
||||
BoxRef(Arc<dyn NyashBox>),
|
||||
}
|
||||
```
|
||||
|
||||
### 変換規則
|
||||
|
||||
#### NyashBox → VMValue
|
||||
|
||||
1. **基本型の最適化**
|
||||
- IntegerBox → VMValue::Integer(値を直接保持)
|
||||
- StringBox → VMValue::String(値を直接保持)
|
||||
- BoolBox → VMValue::Bool(値を直接保持)
|
||||
|
||||
2. **複雑型の参照保持**
|
||||
- PluginBoxV2 → VMValue::BoxRef
|
||||
- ユーザー定義Box → VMValue::BoxRef
|
||||
- その他のBox → VMValue::BoxRef
|
||||
|
||||
#### VMValue → NyashBox
|
||||
|
||||
1. **基本型の再Box化**
|
||||
- VMValue::Integer → IntegerBox::new()
|
||||
- VMValue::String → StringBox::new()
|
||||
- VMValue::Bool → BoolBox::new()
|
||||
|
||||
2. **参照型のクローン**
|
||||
- VMValue::BoxRef → Arc::clone_box()
|
||||
|
||||
## 🔄 MIR命令の処理
|
||||
|
||||
### NewBox命令の統一実装
|
||||
|
||||
```rust
|
||||
MirInstruction::NewBox { dst, box_type, args } => {
|
||||
// 🌟 統一Box作成プロセス
|
||||
|
||||
// Step 1: 引数を評価してNyashBoxに変換
|
||||
let nyash_args: Vec<Box<dyn NyashBox>> = args.iter()
|
||||
.map(|id| self.get_value(*id)?.to_nyash_box())
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// Step 2: BoxFactory経由で統一作成
|
||||
let new_box = self.box_factory.create_box(box_type, &nyash_args)?;
|
||||
|
||||
// Step 3: birth実行(ユーザー定義Boxの場合)
|
||||
if let Some(instance) = new_box.as_any().downcast_ref::<InstanceBox>() {
|
||||
// birthコンストラクタを検索
|
||||
let birth_key = format!("birth/{}", args.len());
|
||||
|
||||
if let Some(box_decl) = self.box_declarations.read().unwrap().get(&instance.class_name) {
|
||||
if let Some(constructor) = box_decl.constructors.get(&birth_key) {
|
||||
// birthメソッドを実行
|
||||
self.push_scope(); // 新しいスコープ
|
||||
self.set_variable("me", new_box.clone()); // me をバインド
|
||||
|
||||
// コンストラクタ本体を実行
|
||||
let result = self.execute_constructor(constructor, nyash_args)?;
|
||||
|
||||
self.pop_scope(); // スコープ終了
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: プラグインBoxのbirth実行
|
||||
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
||||
if new_box.as_any().downcast_ref::<PluginBoxV2>().is_some() {
|
||||
// プラグインのbirthは既にcreate_box内で実行済み
|
||||
}
|
||||
|
||||
// Step 5: スコープ追跡に登録(fini用)
|
||||
self.scope_tracker.register_box(new_box.clone());
|
||||
|
||||
// Step 6: VMValueに変換して格納
|
||||
let vm_value = VMValue::from_nyash_box(new_box);
|
||||
self.set_value(*dst, vm_value);
|
||||
}
|
||||
```
|
||||
|
||||
### BoxCall命令の統一処理
|
||||
|
||||
```rust
|
||||
MirInstruction::BoxCall { dst, box_val, method, args, effects } => {
|
||||
let box_vm_value = self.get_value(*box_val)?;
|
||||
|
||||
// 統一的なメソッド呼び出し
|
||||
let result = match &box_vm_value {
|
||||
// 基本型の最適化パス
|
||||
VMValue::String(s) => {
|
||||
self.call_string_method_optimized(s, method, args)?
|
||||
},
|
||||
VMValue::Integer(i) => {
|
||||
self.call_integer_method_optimized(i, method, args)?
|
||||
},
|
||||
|
||||
// BoxRef経由の汎用パス
|
||||
VMValue::BoxRef(arc_box) => {
|
||||
let nyash_args = convert_args_to_nyash(args);
|
||||
self.call_box_method_generic(arc_box.as_ref(), method, nyash_args)?
|
||||
},
|
||||
|
||||
_ => return Err(VMError::TypeError("Not a box type"))
|
||||
};
|
||||
|
||||
if let Some(dst_id) = dst {
|
||||
self.set_value(*dst_id, result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ExternCall命令の実装
|
||||
|
||||
```rust
|
||||
MirInstruction::ExternCall { dst, iface_name, method_name, args, effects } => {
|
||||
match (iface_name.as_str(), method_name.as_str()) {
|
||||
// プラグインBox作成
|
||||
("plugin", "new") => {
|
||||
let box_type = self.get_value(args[0])?.to_string();
|
||||
let ctor_args = self.convert_args_to_nyash(&args[1..])?;
|
||||
|
||||
if let Some(loader) = &self.plugin_loader {
|
||||
let plugin_box = loader.create_box(&box_type, ctor_args)?;
|
||||
let vm_value = VMValue::from_nyash_box(plugin_box);
|
||||
|
||||
if let Some(dst_id) = dst {
|
||||
self.set_value(*dst_id, vm_value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 既存のconsole.log等
|
||||
("env.console", "log") => {
|
||||
// 既存の処理
|
||||
},
|
||||
|
||||
_ => {
|
||||
println!("ExternCall stub: {}.{}", iface_name, method_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 メモリ管理
|
||||
|
||||
### 参照カウント管理
|
||||
|
||||
1. **BoxRefの作成時**
|
||||
- Arc::fromでBox<dyn NyashBox>をArc<dyn NyashBox>に変換
|
||||
- 参照カウント = 1
|
||||
|
||||
2. **BoxRefのクローン時**
|
||||
- Arc::cloneで参照カウント増加
|
||||
- 軽量なポインタコピー
|
||||
|
||||
3. **BoxRefの破棄時**
|
||||
- 参照カウント減少
|
||||
- 0になったら自動解放
|
||||
|
||||
### スコープとライフタイム
|
||||
|
||||
```rust
|
||||
// VMのスコープ管理
|
||||
impl VM {
|
||||
fn exit_scope(&mut self) {
|
||||
// BoxRefを含むレジスタがクリアされると
|
||||
// 参照カウントが自動的に減少
|
||||
self.registers.clear();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📈 パフォーマンス最適化
|
||||
|
||||
### 基本型の直接処理
|
||||
|
||||
```rust
|
||||
// 最適化されたStringメソッド呼び出し
|
||||
fn call_string_method_optimized(&self, s: &str, method: &str, args: &[ValueId])
|
||||
-> Result<VMValue, VMError> {
|
||||
match method {
|
||||
"length" => Ok(VMValue::Integer(s.len() as i64)),
|
||||
"substring" => {
|
||||
// 引数を直接整数として取得(Box化を回避)
|
||||
let start = self.get_value(args[0])?.to_i64()?;
|
||||
let end = self.get_value(args[1])?.to_i64()?;
|
||||
Ok(VMValue::String(s[start..end].to_string()))
|
||||
},
|
||||
_ => {
|
||||
// 未知のメソッドは汎用パスへ
|
||||
let string_box = Box::new(StringBox::new(s));
|
||||
self.call_box_method_generic(&*string_box, method, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### プラグイン呼び出しの最適化
|
||||
|
||||
1. **メソッドIDキャッシュ**
|
||||
- 頻繁に呼ばれるメソッドのIDをキャッシュ
|
||||
- 文字列比較を回避
|
||||
|
||||
2. **TLV変換の遅延評価**
|
||||
- 必要になるまでTLV変換を遅延
|
||||
- 基本型は直接渡す
|
||||
|
||||
## 🧪 テスト戦略
|
||||
|
||||
### 単体テスト
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_vm_plugin_box_creation() {
|
||||
let plugin_loader = create_test_plugin_loader();
|
||||
let mut vm = VM::new_with_plugins(plugin_loader);
|
||||
|
||||
// FileBoxの作成
|
||||
let result = vm.execute_extern_call(
|
||||
"plugin", "new",
|
||||
vec!["FileBox", "test.txt"]
|
||||
);
|
||||
|
||||
assert!(matches!(result, Ok(VMValue::BoxRef(_))));
|
||||
}
|
||||
```
|
||||
|
||||
### 統合テスト
|
||||
|
||||
```nyash
|
||||
// VMで実行されるNyashコード
|
||||
local file = new FileBox("output.txt")
|
||||
file.write("VM Plugin Test")
|
||||
local content = file.read()
|
||||
assert(content == "VM Plugin Test")
|
||||
```
|
||||
|
||||
### パフォーマンステスト
|
||||
|
||||
```rust
|
||||
#[bench]
|
||||
fn bench_plugin_method_call(b: &mut Bencher) {
|
||||
let vm = setup_vm_with_plugins();
|
||||
let file_box = create_file_box(&vm);
|
||||
|
||||
b.iter(|| {
|
||||
vm.call_box_method(&file_box, "write", &["test"])
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 🚨 エラーハンドリング
|
||||
|
||||
### プラグイン関連エラー
|
||||
|
||||
```rust
|
||||
pub enum VMError {
|
||||
// 既存のエラー
|
||||
TypeError(String),
|
||||
RuntimeError(String),
|
||||
|
||||
// プラグイン関連(新規)
|
||||
PluginNotFound(String),
|
||||
PluginMethodError {
|
||||
plugin: String,
|
||||
method: String,
|
||||
error: String
|
||||
},
|
||||
PluginInitError(String),
|
||||
}
|
||||
```
|
||||
|
||||
### エラー伝播
|
||||
|
||||
```rust
|
||||
// プラグインエラーをVMエラーに変換
|
||||
impl From<PluginError> for VMError {
|
||||
fn from(err: PluginError) -> Self {
|
||||
match err {
|
||||
PluginError::MethodNotFound(m) => {
|
||||
VMError::PluginMethodError {
|
||||
plugin: "unknown".to_string(),
|
||||
method: m,
|
||||
error: "Method not found".to_string()
|
||||
}
|
||||
},
|
||||
// ... 他のエラー変換
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 メトリクスとモニタリング
|
||||
|
||||
### パフォーマンスメトリクス
|
||||
|
||||
- プラグイン呼び出し回数
|
||||
- 平均呼び出し時間
|
||||
- TLV変換オーバーヘッド
|
||||
- メモリ使用量
|
||||
|
||||
### デバッグ情報
|
||||
|
||||
```rust
|
||||
// デバッグモードでの詳細ログ
|
||||
if cfg!(debug_assertions) {
|
||||
eprintln!("VM: Calling plugin method {}.{}", box_type, method);
|
||||
eprintln!("VM: Args: {:?}", args);
|
||||
eprintln!("VM: Result: {:?}", result);
|
||||
}
|
||||
```
|
||||
|
||||
## 🔄 ライフサイクル管理
|
||||
|
||||
### スコープ管理とfini呼び出し
|
||||
|
||||
```rust
|
||||
pub struct ScopeTracker {
|
||||
scopes: Vec<Scope>,
|
||||
}
|
||||
|
||||
pub struct Scope {
|
||||
boxes: Vec<(u64, Arc<dyn NyashBox>)>, // (id, box)
|
||||
variables: HashMap<String, VMValue>, // ローカル変数
|
||||
}
|
||||
|
||||
impl VM {
|
||||
/// スコープ開始
|
||||
fn push_scope(&mut self) {
|
||||
self.scope_tracker.scopes.push(Scope::new());
|
||||
}
|
||||
|
||||
/// スコープ終了時の自動fini呼び出し
|
||||
fn pop_scope(&mut self) -> Result<(), VMError> {
|
||||
if let Some(scope) = self.scope_tracker.scopes.pop() {
|
||||
// 逆順でfiniを呼ぶ(作成順と逆)
|
||||
for (_, box_ref) in scope.boxes.iter().rev() {
|
||||
self.call_fini_if_needed(box_ref)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 統一fini呼び出し
|
||||
fn call_fini_if_needed(&mut self, box_ref: &Arc<dyn NyashBox>) -> Result<(), VMError> {
|
||||
match box_ref.type_name() {
|
||||
// ユーザー定義Box
|
||||
name if self.box_declarations.read().unwrap().contains_key(name) => {
|
||||
if let Some(instance) = box_ref.as_any().downcast_ref::<InstanceBox>() {
|
||||
// finiメソッドが定義されているか確認
|
||||
if let Some(box_decl) = self.box_declarations.read().unwrap().get(name) {
|
||||
if let Some(fini_method) = box_decl.methods.get("fini") {
|
||||
// finiを実行
|
||||
self.set_variable("me", box_ref.clone_box());
|
||||
self.execute_method(fini_method.clone())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// プラグインBox
|
||||
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
||||
_ if box_ref.as_any().downcast_ref::<PluginBoxV2>().is_some() => {
|
||||
if let Some(plugin) = box_ref.as_any().downcast_ref::<PluginBoxV2>() {
|
||||
plugin.call_fini();
|
||||
}
|
||||
},
|
||||
|
||||
// ビルトインBox(将来finiサポート予定)
|
||||
_ => {
|
||||
// 現在ビルトインBoxはfiniなし
|
||||
// 将来的にはStringBox等もfini対応
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ライフサイクルの完全性
|
||||
|
||||
```nyash
|
||||
// 🌟 すべてのBoxが同じライフサイクル
|
||||
|
||||
{ // スコープ開始
|
||||
local str = new StringBox("hello") // birth(引数1つ)
|
||||
local user = new UserBox("Alice", 25) // birth(引数2つ)
|
||||
local file = new FileBox("test.txt") // birth(引数1つ)
|
||||
|
||||
// 使用
|
||||
str.length()
|
||||
user.greet()
|
||||
file.write("data")
|
||||
|
||||
} // スコープ終了 → 自動的にfini呼び出し
|
||||
// file.fini() → user.fini() → str.fini() の順
|
||||
```
|
||||
|
||||
## 🎯 統一の利点
|
||||
|
||||
### 1. **シンプルな実装**
|
||||
- すべてのBox型が同じコードパスを通る
|
||||
- 特殊ケースの削減
|
||||
- バグの温床排除
|
||||
|
||||
### 2. **拡張性**
|
||||
- 新しいBox型追加が容易
|
||||
- プラグインも同じ扱い
|
||||
- 将来の機能追加も簡単
|
||||
|
||||
### 3. **パフォーマンス**
|
||||
- 基本型は最適化パス維持
|
||||
- 必要時のみBoxRef使用
|
||||
- メソッドディスパッチの効率化
|
||||
|
||||
---
|
||||
|
||||
**最終更新**: 2025-08-21
|
||||
**関連文書**:
|
||||
- [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md)
|
||||
- [Phase 9.78a VM Plugin Integration](../../予定/native-plan/issues/phase_9_78a_vm_plugin_integration.md)
|
||||
- [Phase 9.78a 深層分析](../../予定/native-plan/issues/phase_9_78a_vm_plugin_integration_deep_analysis.md)
|
||||
- [nyash.toml v2.1: BoxRef仕様](../plugin-system/nyash-toml-v2_1-spec.md)
|
||||
|
||||
### 付録: 引数エンコード(v2.1 追加)
|
||||
- TLVタグ: 1=Bool, 2=I32, 3=I64, 4=F32, 5=F64, 6=String, 7=Bytes, 8=Handle(BoxRef)
|
||||
- BoxRef payload(tag=8): `type_id:u32` + `instance_id:u32`(LE, 8バイト)
|
||||
- `nyash.toml` の `args` で `{ kind="box", category="plugin" }` を指定したとき、Loaderは `tag=8` を使用
|
||||
|
||||
### 返り値(v2.2)
|
||||
- プラグインが `tag=8` を返した場合、Loaderは `type_id` からBox型名を逆引きし `PluginBoxV2` を構築
|
||||
- 同一ライブラリでなくてもOK(構成ファイル全体から探索)
|
||||
407
docs/reference/testing-quality/golden-dump-testing.md
Normal file
407
docs/reference/testing-quality/golden-dump-testing.md
Normal file
@ -0,0 +1,407 @@
|
||||
# 🏆 Nyash Golden Dump Testing System
|
||||
|
||||
*ChatGPT5推奨・MIR互換テスト(回帰検出)完全仕様*
|
||||
|
||||
## 🎯 目的
|
||||
|
||||
**「同じ入力→同じ出力」をinterp/vm/wasm/aot間で保証する自動検証システム**
|
||||
|
||||
MIR仕様の揺れ・バックエンド差異・最適化バグを**即座検出**し、Portability Contract v0を技術的に保証。
|
||||
|
||||
## 🔧 **Golden Dump方式**
|
||||
|
||||
### **基本原理**
|
||||
```bash
|
||||
# 1. MIR「黄金標準」生成
|
||||
nyash --dump-mir program.nyash > program.golden.mir
|
||||
|
||||
# 2. 実行時MIR比較(回帰検出)
|
||||
nyash --dump-mir program.nyash > program.current.mir
|
||||
diff program.golden.mir program.current.mir
|
||||
|
||||
# 3. 全バックエンド出力比較(互換検証)
|
||||
nyash --target interp program.nyash > interp.out
|
||||
nyash --target vm program.nyash > vm.out
|
||||
nyash --target wasm program.nyash > wasm.out
|
||||
diff interp.out vm.out && diff vm.out wasm.out
|
||||
```
|
||||
|
||||
### **階層化検証戦略**
|
||||
| レベル | 検証対象 | 目的 | 頻度 |
|
||||
|--------|----------|------|------|
|
||||
| **L1: MIR構造** | AST→MIR変換 | 回帰検出 | 毎commit |
|
||||
| **L2: 実行結果** | stdout/stderr | 互換性 | 毎PR |
|
||||
| **L3: 最適化効果** | 性能・メモリ | 最適化回帰 | 毎週 |
|
||||
| **L4: エラー処理** | 例外・エラー | 堅牢性 | 毎リリース |
|
||||
|
||||
## 🧪 **検証テストスイート**
|
||||
|
||||
### **1️⃣ MIR Structure Tests (L1)**
|
||||
|
||||
#### **基本構造検証**
|
||||
```rust
|
||||
// tests/golden_dump/mir_structure_tests.rs
|
||||
#[test]
|
||||
fn test_basic_arithmetic_mir_stability() {
|
||||
let source = r#"
|
||||
static box Main {
|
||||
main() {
|
||||
local a, b, result
|
||||
a = 42
|
||||
b = 8
|
||||
result = a + b
|
||||
print(result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let golden_mir = load_golden_mir("basic_arithmetic.mir");
|
||||
let current_mir = compile_to_mir(source);
|
||||
|
||||
assert_eq!(golden_mir, current_mir, "MIR回帰検出");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box_operations_mir_stability() {
|
||||
let source = r#"
|
||||
box DataBox {
|
||||
init { value }
|
||||
pack(val) { me.value = val }
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local obj = new DataBox(100)
|
||||
print(obj.value)
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let golden_mir = load_golden_mir("box_operations.mir");
|
||||
let current_mir = compile_to_mir(source);
|
||||
|
||||
assert_mir_equivalent(golden_mir, current_mir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_reference_mir_stability() {
|
||||
let source = r#"
|
||||
box Parent { init { child_weak } }
|
||||
box Child { init { data } }
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local parent = new Parent()
|
||||
local child = new Child(42)
|
||||
parent.child_weak = weak(child)
|
||||
|
||||
if parent.child_weak.isAlive() {
|
||||
print(parent.child_weak.get().data)
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
verify_mir_golden("weak_reference", source);
|
||||
}
|
||||
```
|
||||
|
||||
#### **MIR比較アルゴリズム**
|
||||
```rust
|
||||
// src/testing/mir_comparison.rs
|
||||
pub fn assert_mir_equivalent(golden: &MirModule, current: &MirModule) {
|
||||
// 1. 関数数・名前一致
|
||||
assert_eq!(golden.functions.len(), current.functions.len());
|
||||
|
||||
for (name, golden_func) in &golden.functions {
|
||||
let current_func = current.functions.get(name)
|
||||
.expect(&format!("関数{}が見つからない", name));
|
||||
|
||||
// 2. 基本ブロック構造一致
|
||||
assert_eq!(golden_func.blocks.len(), current_func.blocks.len());
|
||||
|
||||
// 3. 命令列意味的等価性(ValueId正規化)
|
||||
let golden_normalized = normalize_value_ids(golden_func);
|
||||
let current_normalized = normalize_value_ids(current_func);
|
||||
assert_eq!(golden_normalized, current_normalized);
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_value_ids(func: &MirFunction) -> MirFunction {
|
||||
// ValueIdを連番に正規化(%0, %1, %2...)
|
||||
// 意味的に同じ命令列を確実に比較可能にする
|
||||
}
|
||||
```
|
||||
|
||||
### **2️⃣ Cross-Backend Output Tests (L2)**
|
||||
|
||||
#### **標準出力一致検証**
|
||||
```rust
|
||||
// tests/golden_dump/output_compatibility_tests.rs
|
||||
#[test]
|
||||
fn test_cross_backend_arithmetic_output() {
|
||||
let program = "arithmetic_test.nyash";
|
||||
|
||||
let interp_output = run_backend("interp", program);
|
||||
let vm_output = run_backend("vm", program);
|
||||
let wasm_output = run_backend("wasm", program);
|
||||
|
||||
assert_eq!(interp_output.stdout, vm_output.stdout);
|
||||
assert_eq!(vm_output.stdout, wasm_output.stdout);
|
||||
assert_eq!(interp_output.exit_code, vm_output.exit_code);
|
||||
assert_eq!(vm_output.exit_code, wasm_output.exit_code);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cross_backend_object_lifecycle() {
|
||||
let program = "object_lifecycle_test.nyash";
|
||||
|
||||
let results = run_all_backends(program);
|
||||
|
||||
// fini()順序・タイミングが全バックエンドで同一
|
||||
let finalization_orders: Vec<_> = results.iter()
|
||||
.map(|r| &r.finalization_order)
|
||||
.collect();
|
||||
|
||||
assert!(finalization_orders.windows(2).all(|w| w[0] == w[1]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cross_backend_weak_reference_behavior() {
|
||||
let program = "weak_reference_test.nyash";
|
||||
|
||||
let results = run_all_backends(program);
|
||||
|
||||
// weak参照の生存チェック・null化が同一タイミング
|
||||
let weak_behaviors: Vec<_> = results.iter()
|
||||
.map(|r| &r.weak_reference_timeline)
|
||||
.collect();
|
||||
|
||||
assert_all_equivalent(weak_behaviors);
|
||||
}
|
||||
```
|
||||
|
||||
#### **エラー処理一致検証**
|
||||
```rust
|
||||
#[test]
|
||||
fn test_cross_backend_error_handling() {
|
||||
let error_programs = [
|
||||
"null_dereference.nyash",
|
||||
"division_by_zero.nyash",
|
||||
"weak_reference_after_fini.nyash",
|
||||
"infinite_recursion.nyash"
|
||||
];
|
||||
|
||||
for program in &error_programs {
|
||||
let results = run_all_backends(program);
|
||||
|
||||
// エラー種別・メッセージが全バックエンドで同一
|
||||
let error_types: Vec<_> = results.iter()
|
||||
.map(|r| &r.error_type)
|
||||
.collect();
|
||||
assert_all_equivalent(error_types);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **3️⃣ Optimization Effect Tests (L3)**
|
||||
|
||||
#### **Bus-elision検証**
|
||||
```rust
|
||||
// tests/golden_dump/optimization_tests.rs
|
||||
#[test]
|
||||
fn test_bus_elision_output_equivalence() {
|
||||
let program = "bus_communication_test.nyash";
|
||||
|
||||
let elision_on = run_with_flag(program, "--elide-bus");
|
||||
let elision_off = run_with_flag(program, "--no-elide-bus");
|
||||
|
||||
// 出力は同一・性能は差がある
|
||||
assert_eq!(elision_on.stdout, elision_off.stdout);
|
||||
assert!(elision_on.execution_time < elision_off.execution_time);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pure_function_optimization_equivalence() {
|
||||
let program = "pure_function_optimization.nyash";
|
||||
|
||||
let optimized = run_with_flag(program, "--optimize");
|
||||
let reference = run_with_flag(program, "--no-optimize");
|
||||
|
||||
// 最適化ON/OFFで結果同一
|
||||
assert_eq!(optimized.output, reference.output);
|
||||
|
||||
// PURE関数の呼び出し回数が最適化で削減
|
||||
assert!(optimized.pure_function_calls <= reference.pure_function_calls);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_memory_layout_compatibility() {
|
||||
let program = "memory_intensive_test.nyash";
|
||||
|
||||
let results = run_all_backends(program);
|
||||
|
||||
// Box構造・フィールドアクセスが全バックエンドで同一結果
|
||||
let memory_access_patterns: Vec<_> = results.iter()
|
||||
.map(|r| &r.memory_access_log)
|
||||
.collect();
|
||||
|
||||
assert_memory_semantics_equivalent(memory_access_patterns);
|
||||
}
|
||||
```
|
||||
|
||||
#### **性能回帰検証**
|
||||
```rust
|
||||
#[test]
|
||||
fn test_performance_regression() {
|
||||
let benchmarks = [
|
||||
"arithmetic_heavy.nyash",
|
||||
"object_creation_heavy.nyash",
|
||||
"weak_reference_heavy.nyash"
|
||||
];
|
||||
|
||||
for benchmark in &benchmarks {
|
||||
let golden_perf = load_golden_performance(benchmark);
|
||||
let current_perf = measure_current_performance(benchmark);
|
||||
|
||||
// 性能が大幅に劣化していないことを確認
|
||||
let regression_threshold = 1.2; // 20%まで許容
|
||||
assert!(current_perf.execution_time <= golden_perf.execution_time * regression_threshold);
|
||||
assert!(current_perf.memory_usage <= golden_perf.memory_usage * regression_threshold);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤖 **自動化CI/CD統合**
|
||||
|
||||
### **GitHub Actions設定**
|
||||
```yaml
|
||||
# .github/workflows/golden_dump_testing.yml
|
||||
name: Golden Dump Testing
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
mir-stability:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Run MIR Structure Tests (L1)
|
||||
run: |
|
||||
cargo test --test mir_structure_tests
|
||||
|
||||
- name: Verify MIR Golden Dumps
|
||||
run: |
|
||||
./scripts/verify_mir_golden_dumps.sh
|
||||
|
||||
cross-backend-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
needs: mir-stability
|
||||
steps:
|
||||
- name: Run Cross-Backend Tests (L2)
|
||||
run: |
|
||||
cargo test --test output_compatibility_tests
|
||||
|
||||
- name: Verify All Backend Output Equality
|
||||
run: |
|
||||
./scripts/verify_backend_compatibility.sh
|
||||
|
||||
optimization-regression:
|
||||
runs-on: ubuntu-latest
|
||||
needs: cross-backend-compatibility
|
||||
steps:
|
||||
- name: Run Optimization Tests (L3)
|
||||
run: |
|
||||
cargo test --test optimization_tests
|
||||
|
||||
- name: Performance Regression Check
|
||||
run: |
|
||||
./scripts/check_performance_regression.sh
|
||||
```
|
||||
|
||||
### **自動Golden Dump更新**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# scripts/update_golden_dumps.sh
|
||||
|
||||
echo "🏆 Golden Dump更新中..."
|
||||
|
||||
# 1. 現在のMIRを新しい黄金標準として設定
|
||||
for test_file in tests/golden_dump/programs/*.nyash; do
|
||||
program_name=$(basename "$test_file" .nyash)
|
||||
echo "更新中: $program_name"
|
||||
|
||||
# MIR golden dump更新
|
||||
./target/release/nyash --dump-mir "$test_file" > "tests/golden_dump/mir/${program_name}.golden.mir"
|
||||
|
||||
# 出力 golden dump更新
|
||||
./target/release/nyash --target interp "$test_file" > "tests/golden_dump/output/${program_name}.golden.out"
|
||||
done
|
||||
|
||||
echo "✅ Golden Dump更新完了"
|
||||
|
||||
# 2. 更新を確認するためのテスト実行
|
||||
cargo test --test golden_dump_tests
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "🎉 新しいGolden Dumpでテスト成功"
|
||||
else
|
||||
echo "❌ 新しいGolden Dumpでテスト失敗"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## 📊 **実装優先順位**
|
||||
|
||||
### **Phase 8.4(緊急)**
|
||||
- [ ] **L1実装**: MIR構造検証・基本golden dump
|
||||
- [ ] **基本自動化**: CI/CDでのMIR回帰検出
|
||||
- [ ] **Bus命令テスト**: elision ON/OFF検証基盤
|
||||
|
||||
### **Phase 8.5(短期)**
|
||||
- [ ] **L2実装**: 全バックエンド出力一致検証
|
||||
- [ ] **エラー処理**: 例外・エラーケース検証
|
||||
- [ ] **性能基準**: ベンチマーク回帰検出
|
||||
|
||||
### **Phase 9+(中長期)**
|
||||
- [ ] **L3-L4実装**: 最適化・堅牢性検証
|
||||
- [ ] **高度自動化**: 自動修復・性能トレンド分析
|
||||
- [ ] **形式検証**: 数学的正当性証明
|
||||
|
||||
## 🎯 **期待効果**
|
||||
|
||||
### **品質保証**
|
||||
- **回帰即座検出**: MIR仕様変更のバグを即座発見
|
||||
- **バックエンド信頼性**: 全実行環境で同一動作保証
|
||||
- **最適化安全性**: 高速化による動作変更防止
|
||||
|
||||
### **開発効率**
|
||||
- **自動品質確認**: 手動テスト不要・CI/CDで自動化
|
||||
- **リファクタリング安全性**: 大規模変更の影響範囲特定
|
||||
- **新機能信頼性**: 追加機能が既存動作に影響しない保証
|
||||
|
||||
### **Nyash言語価値**
|
||||
- **エンタープライズ品質**: 厳密な品質保証プロセス
|
||||
- **技術的差別化**: 「全バックエンド互換保証」の実証
|
||||
- **拡張性基盤**: 新バックエンド追加時の品質維持
|
||||
|
||||
---
|
||||
|
||||
## 📚 **関連ドキュメント**
|
||||
|
||||
- **MIRリファレンス**: [mir-reference.md](mir-reference.md)
|
||||
- **互換性契約**: [portability-contract.md](portability-contract.md)
|
||||
- **ベンチマークシステム**: [../../../benchmarks/README.md](../../../benchmarks/README.md)
|
||||
- **CI/CD設定**: [../../../.github/workflows/](../../../.github/workflows/)
|
||||
|
||||
---
|
||||
|
||||
*最終更新: 2025-08-14 - ChatGPT5推奨3点セット完成*
|
||||
|
||||
*Golden Dump Testing = Nyash品質保証の技術的基盤*
|
||||
Reference in New Issue
Block a user