Core-13 pure: add CI workflows, VM e2e tests, LLVM parity bridge (minimal); do not touch private docs
This commit is contained in:
109
docs/private/reference/architecture/README.md
Normal file
109
docs/private/reference/architecture/README.md
Normal file
@ -0,0 +1,109 @@
|
||||
# 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 呼び出し)
|
||||
|
||||
関連ドキュメント
|
||||
- 動的プラグインの流れ: [dynamic-plugin-flow.md](./dynamic-plugin-flow.md)
|
||||
- 命令セットダイエット: [mir-26-instruction-diet.md](./mir-26-instruction-diet.md)
|
||||
- MIR→VMマッピング: [mir-to-vm-mapping.md](./mir-to-vm-mapping.md)
|
||||
|
||||
## 実行フロー(概略)
|
||||
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`
|
||||
- **動的解決の詳細**: [dynamic-plugin-flow.md](./dynamic-plugin-flow.md) を参照
|
||||
|
||||
## 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 へ横展開。
|
||||
@ -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/private/reference/architecture/design-overview.md
Normal file
108
docs/private/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実行)
|
||||
|
||||
118
docs/private/reference/architecture/dynamic-plugin-flow.md
Normal file
118
docs/private/reference/architecture/dynamic-plugin-flow.md
Normal file
@ -0,0 +1,118 @@
|
||||
# Dynamic Plugin Flow (VM × Registry × PluginLoader v2)
|
||||
|
||||
最終更新: 2025-08-23
|
||||
|
||||
目的
|
||||
- Nyash 実行時に、MIR→VM→Registry→Plugin の呼び出しがどう流れるかを図解・手順で把握する。
|
||||
- TLVエンコード、ResultBoxの扱い、Handleのライフサイクル、nyash.tomlとの連携を1枚で理解する。
|
||||
|
||||
## ハイレベル流れ(シーケンス)
|
||||
|
||||
```
|
||||
Nyash Source ──▶ MIR (Builder)
|
||||
│ (BoxCall/NewBox/…)
|
||||
▼
|
||||
VM Executor
|
||||
│ (BoxCall dispatch)
|
||||
├─ InstanceBox → Lowered MIR 関数呼び出し
|
||||
├─ BuiltinBox → VM内ディスパッチ
|
||||
└─ PluginBoxV2 → PluginLoader v2
|
||||
│ (nyash.toml を参照)
|
||||
▼
|
||||
Invoke (TLV)
|
||||
│
|
||||
▼
|
||||
Plugin (lib*.so)
|
||||
│ (戻り値をTLVで返却)
|
||||
▼
|
||||
Loader でデコード
|
||||
│ (returns_result/Handle/型)
|
||||
▼
|
||||
NyashBox (ResultBox/PluginBoxV2/基本型)
|
||||
│
|
||||
▼
|
||||
VM に復帰
|
||||
```
|
||||
|
||||
## 主要構成要素
|
||||
- MIR: `MirInstruction::{BoxCall, NewBox, …}` で外部呼び出し箇所を明示。
|
||||
- VM: `src/backend/vm.rs`
|
||||
- InstanceBoxは `{Class}.{method}/{argc}` のLowered関数へ呼び出し
|
||||
- BuiltinはVM内の簡易ディスパッチ
|
||||
- PluginBoxV2は Loader v2 へ委譲
|
||||
- Registry/Runtime: `NyashRuntime` + `box_registry` + `plugin_loader_v2`
|
||||
- `nyash.toml` の `libraries.*` を読み込み、Box名→ライブラリ名、type_id、method_id等を集約
|
||||
|
||||
## NewBox(生成)
|
||||
1) MIRの `NewBox { box_type, args }`
|
||||
2) VM: `runtime.box_registry` に `box_type` を問い合わせ
|
||||
3) PluginBoxの場合、Loader v2が `birth(method_id=0)` を TLV で呼び出し
|
||||
4) Pluginは `type_id` と新規 `instance_id` を返却 → Loader は `PluginBoxV2` を構築
|
||||
5) VMは `ScopeTracker` に登録(スコープ終了で `fini` を呼ぶ)
|
||||
|
||||
## BoxCall(メソッド呼び出し)
|
||||
- InstanceBox: Lowered関数 `{Class}.{method}/{argc}` を MIR/VM内で実行
|
||||
- Builtin: VM内の `call_box_method` で対応(StringBox.length 等)
|
||||
- PluginBoxV2: Loader v2 の `invoke_instance_method` で TLV を組み立てて呼び出し
|
||||
|
||||
## TLV(Type-Length-Value)
|
||||
- ヘッダ: `u16 ver=1`, `u16 argc`
|
||||
- 各引数: `u8 tag`, `u8 reserved`, `u16 size`, `payload`
|
||||
- 主な tag:
|
||||
- 2 = i32 (size=4)
|
||||
- 6 = string, 7 = bytes
|
||||
- 8 = Handle(BoxRef) → payload = `u32 type_id || u32 instance_id`
|
||||
- 9 = void (size=0)
|
||||
|
||||
## 戻り値のマッピング(重要)
|
||||
- `returns_result=false`
|
||||
- tag=8 → PluginBoxV2(Handle)
|
||||
- tag=2 → IntegerBox、tag=6/7 → StringBox、tag=9 → void
|
||||
- `returns_result=true`(ResultBoxで包む)
|
||||
- tag=8/2 → `Result.Ok(value)`
|
||||
- tag=6/7 → `Result.Err(ErrorBox(message))`(Netプラグインなどがエラー文字列を返却)
|
||||
- tag=9 → `Result.Ok(void)`
|
||||
|
||||
補足
|
||||
- VM内で ResultBox の `isOk/getValue/getError` をディスパッチ済み
|
||||
- `toString()` フォールバックにより任意の Box を安全に文字列化可能
|
||||
|
||||
## Handle(BoxRef)のライフサイクル
|
||||
- Loaderは `(type_id, instance_id)` を `PluginBoxV2` としてラップ
|
||||
- `share_box()` は同一インスタンス共有、`clone_box()` はプラグインの birth を呼ぶ(設計意図による)
|
||||
- `fini` は `ScopeTracker` または Drop で保証(プラグインの `fini_method_id` を参照)
|
||||
|
||||
## 具体例(HttpClientBox.get)
|
||||
1) Nyash: `r = cli.get(url)`
|
||||
2) MIR: `BoxCall`(returns_result=true)
|
||||
3) VM→Loader: TLV(url = tag=6)
|
||||
4) Loader→Plugin: `invoke(type_id=HttpClient, method_id=get)`
|
||||
5) Plugin:
|
||||
- 接続成功: `Handle(HttpResponse)` を返す → Loaderは `Result.Ok(PluginBoxV2)`
|
||||
- 接続失敗: `String("connect failed …")` を返す → Loaderは `Result.Err(ErrorBox)`
|
||||
6) Nyash: `if r.isOk() { resp = r.getValue() … } else { print(r.getError().toString()) }`
|
||||
|
||||
## nyash.toml 連携
|
||||
- 例: `libraries."libnyash_net_plugin.so".HttpClientBox.methods.get = { method_id = 1, args=["url"], returns_result = true }`
|
||||
- Loaderは `method_id` と `returns_result` を参照し、TLVと戻り値のラップ方針を決定
|
||||
- 型宣言(args/kind)により、引数のTLVタグ検証を実施(不一致は InvalidArgs)
|
||||
|
||||
## デバッグTips
|
||||
- `NYASH_DEBUG_PLUGIN=1`: VM→Plugin の TLV ヘッダと先頭64バイトをプレビュー
|
||||
- `NYASH_NET_LOG=1 NYASH_NET_LOG_FILE=net_plugin.log`: Netプラグイン内部ログ
|
||||
- `--dump-mir --mir-verbose`: if/phi/return などのMIRを確認
|
||||
- `--vm-stats --vm-stats-json`: 命令使用のJSONを取得(hot pathの裏取りに)
|
||||
|
||||
## 将来の整合・改善
|
||||
- nyash.toml に ok側の戻り型(例: `ok_returns = "HttpResponseBox"`)を追加 → Loader判定の厳密化
|
||||
- Verifier強化: use-before-def across merge の検出(phi誤用を早期に発見)
|
||||
- BoxCall fast-path の最適化(hot path最優先)
|
||||
|
||||
関連
|
||||
- `docs/reference/plugin-system/net-plugin.md`
|
||||
- `docs/reference/architecture/mir-to-vm-mapping.md`
|
||||
- `docs/reference/architecture/mir-26-instruction-diet.md`
|
||||
|
||||
See also
|
||||
- `docs/examples/http_result_patterns.md` - HTTPのResult挙動(unreachable/404/500)のE2E例
|
||||
- `docs/VM_README.md` - VM統計とプラグイン周りの既知制約
|
||||
519
docs/private/reference/architecture/execution-backends.md
Normal file
519
docs/private/reference/architecture/execution-backends.md
Normal file
@ -0,0 +1,519 @@
|
||||
# Nyash実行バックエンド完全ガイド
|
||||
|
||||
Nyashプログラミング言語は、**Everything is Box**哲学を維持しながら、4つの異なる実行方式をサポートしています。用途に応じて最適な実行方式を選択できます。
|
||||
|
||||
## 🚀 実行方式一覧
|
||||
|
||||
| 実行方式 | 用途 | 特徴 | パフォーマンス |
|
||||
|---------|------|------|---------------|
|
||||
| **インタープリター** | 開発・デバッグ | 直接AST実行、詳細ログ | 低速・高機能 |
|
||||
| **VM** | 本番・高速実行 | MIR→VM実行 | 中速・最適化 |
|
||||
| **WASM** | Web・サンドボックス | MIR→WASM変換 | 高速・移植性 |
|
||||
| **AOT** (実験的) | 高速起動 | MIR→WASM→ネイティブ | 最高速・要wasmtime |
|
||||
|
||||
## 📋 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
|
||||
```
|
||||
|
||||
### AOT/ネイティブコンパイル(実験的機能)
|
||||
```bash
|
||||
# ビルド時に wasm-backend feature が必要
|
||||
cargo build --release --features wasm-backend
|
||||
|
||||
# AOTコンパイル(.cwasm生成)
|
||||
nyash --compile-native program.nyash -o program
|
||||
# または
|
||||
nyash --aot program.nyash -o program
|
||||
|
||||
# 注意: 現在は完全なスタンドアロン実行ファイルではなく、
|
||||
# wasmtime用のプリコンパイル済みWASM(.cwasm)が生成されます
|
||||
```
|
||||
|
||||
### ⚡ ベンチマーク(パフォーマンス測定)
|
||||
```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形式**: 静的単一代入
|
||||
- **基本ブロック**: 制御フロー最適化
|
||||
- **効果追跡**: 副作用の管理
|
||||
- **型安全**: 実行時型チェック
|
||||
- **対応状況**: 命令ごとの実装は「MIR → VM Mapping」を参照(欠落・暫定箇所の把握に)
|
||||
- docs/reference/architecture/mir-to-vm-mapping.md
|
||||
|
||||
### 🧮 VM実行統計(命令カウント・時間計測)
|
||||
VMバックエンドは命令ごとの実行回数と総実行時間(ms)を出力できます。
|
||||
|
||||
有効化方法(CLI推奨):
|
||||
```bash
|
||||
# 人間向け表示
|
||||
nyash --backend vm --vm-stats program.nyash
|
||||
|
||||
# JSON出力(機械可読)
|
||||
nyash --backend vm --vm-stats --vm-stats-json program.nyash
|
||||
```
|
||||
|
||||
環境変数でも制御可能:
|
||||
```bash
|
||||
NYASH_VM_STATS=1 ./target/release/nyash --backend vm program.nyash
|
||||
NYASH_VM_STATS=1 NYASH_VM_STATS_JSON=1 ./target/release/nyash --backend vm program.nyash
|
||||
# もしくは NYASH_VM_STATS_FORMAT=json でも可
|
||||
```
|
||||
|
||||
JSON出力例:
|
||||
```json
|
||||
{
|
||||
"total": 1234,
|
||||
"elapsed_ms": 5.123,
|
||||
"counts": { "Const": 200, "BinOp": 300, "Return": 100 },
|
||||
"top20": [ { "op": "BinOp", "count": 300 } ],
|
||||
"timestamp_ms": 1724371200000
|
||||
}
|
||||
```
|
||||
|
||||
ベンチマークと併用して、ホット命令の抽出・命令セット最適化に活用できます。
|
||||
|
||||
### ⏱️ 協調スケジューラ(Phase 10.6b)
|
||||
- VMはMIRの`safepoint`命令到達時にランタイムのスケジューラ`poll()`を呼びます。
|
||||
- シングルスレ実装(既定)では、`spawn`/`spawn_after`で投入されたタスクを safepoint ごとに最大N件実行します。
|
||||
- 制御: `NYASH_SCHED_POLL_BUDGET`(既定: 1)でNを指定。
|
||||
|
||||
デモ実行:
|
||||
```bash
|
||||
cargo build --release -j32
|
||||
NYASH_SCHED_DEMO=1 NYASH_SCHED_POLL_BUDGET=2 \
|
||||
./target/release/nyash --backend vm examples/scheduler_demo.nyash
|
||||
```
|
||||
|
||||
### 🧹 GCトレーシング(Phase 10.4)
|
||||
- カウンタ有効化: `NYASH_GC_COUNTING=1`(CountingGcを注入)
|
||||
- 出力レベル: `NYASH_GC_TRACE=1/2/3`
|
||||
- 1: safepoint/barrierログ+カウンタ
|
||||
- 2: + ルート内訳
|
||||
- 3: + depth=2 リーチャビリティ概要
|
||||
- 厳格検証: `NYASH_GC_BARRIER_STRICT=1`(Write-Barrier未増分ならpanic)
|
||||
|
||||
```bash
|
||||
NYASH_GC_COUNTING=1 NYASH_GC_TRACE=2 \
|
||||
./target/release/nyash --backend vm examples/scheduler_demo.nyash
|
||||
```
|
||||
|
||||
#### Boxからの切替(GcConfigBox)
|
||||
環境変数ではなくNyashスクリプトから切り替える場合は `GcConfigBox` を使います。`apply()` で環境に反映され、その後の実行に適用されます。
|
||||
|
||||
```nyash
|
||||
// 最小例: CountingGc + trace をオン
|
||||
static box Main {
|
||||
main() {
|
||||
local G
|
||||
G = new GcConfigBox()
|
||||
G = G.setFlag("counting", true)
|
||||
G = G.setFlag("trace", true) // 1/2/3 は環境。Box では on/off を切替
|
||||
G.apply() // ← ここで反映
|
||||
return "ok"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
代表デモ(書き込みバリア/カウンタの可視化):
|
||||
```bash
|
||||
./target/release/nyash --backend vm examples/gc_counting_demo.nyash
|
||||
```
|
||||
|
||||
## 🌐 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>
|
||||
```
|
||||
|
||||
## 🚀 AOT/ネイティブコンパイル(実験的)
|
||||
|
||||
### 特徴
|
||||
- **用途**: 高速起動・配布用実行ファイル
|
||||
- **実行**: AST→MIR→WASM→プリコンパイル済みネイティブ
|
||||
- **速度**: 最高速(JIT起動オーバーヘッドなし)
|
||||
- **制約**: wasmtimeランタイムが必要
|
||||
|
||||
### コンパイルパイプライン
|
||||
```
|
||||
Nyashソース → AST → MIR → WASM → .cwasm(プリコンパイル済み)
|
||||
```
|
||||
|
||||
### ビルド方法
|
||||
```bash
|
||||
# 1. wasm-backend feature付きでNyashをビルド
|
||||
cargo build --release --features wasm-backend
|
||||
|
||||
# 2. AOTコンパイル実行
|
||||
./target/release/nyash --compile-native hello.nyash -o hello
|
||||
# または短縮形
|
||||
./target/release/nyash --aot hello.nyash -o hello
|
||||
|
||||
# 3. 生成されたファイル
|
||||
# hello.cwasm が生成される(wasmtimeプリコンパイル形式)
|
||||
```
|
||||
|
||||
### 現在の実装状況
|
||||
- ✅ MIR→WASM変換
|
||||
- ✅ WASM→.cwasm(wasmtimeプリコンパイル)
|
||||
- ❌ 完全なスタンドアロン実行ファイル生成(TODO)
|
||||
- ❌ ランタイム埋め込み(将来実装予定)
|
||||
|
||||
### 使用例
|
||||
```bash
|
||||
# コンパイル
|
||||
./target/release/nyash --aot examples/hello_world.nyash -o hello_aot
|
||||
|
||||
# 実行(将来的な目標)
|
||||
# ./hello_aot # 現在は未実装
|
||||
|
||||
# 現在は wasmtime で実行
|
||||
# wasmtime --precompiled hello_aot.cwasm
|
||||
```
|
||||
|
||||
### 技術的詳細
|
||||
AOTバックエンドは内部的に以下の処理を行います:
|
||||
1. **MirCompiler**: NyashコードをMIRに変換
|
||||
2. **WasmBackend**: MIRをWASMバイトコードに変換
|
||||
3. **wasmtime::Engine::precompile**: WASMをネイティブコードにプリコンパイル
|
||||
4. **出力**: .cwasm形式で保存(wasmtime独自形式)
|
||||
|
||||
## 📊 パフォーマンス比較
|
||||
|
||||
### 🚀 実際のベンチマーク結果(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
|
||||
### 🔥 JIT実行(Phase 10_c 最小経路)
|
||||
- 有効化: `NYASH_JIT_EXEC=1` とし、`NYASH_JIT_THRESHOLD=1` でホット判定しきい値を下げる
|
||||
- 追加情報: `NYASH_JIT_STATS=1` でJITコンパイル/実行時間、サイト集計を出力
|
||||
- ダンプ: `NYASH_JIT_DUMP=1` でLowerカバレッジ/emit統計を表示
|
||||
- HostCall(配列/Map最小): `NYASH_JIT_HOSTCALL=1`
|
||||
|
||||
例:
|
||||
```bash
|
||||
NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 NYASH_JIT_HOSTCALL=1 NYASH_JIT_STATS=1 \
|
||||
./target/release/nyash --backend vm examples/scheduler_demo.nyash
|
||||
```
|
||||
|
||||
現状のカバレッジ(Core-1)
|
||||
- Const(i64/bool), BinOp(Add/Sub/Mul/Div/Mod), Compare(Eq/Ne/Lt/Le/Gt/Ge), Return
|
||||
- Paramのi64経路(複数引数対応)
|
||||
- Array/Mapの最小HostCall(len/get/set/push/size)
|
||||
- Branch/JumpはPhase 10.7でCranelift配線を導入(feature: `cranelift-jit`)。
|
||||
- 分岐条件はb1化(i64の場合は !=0 で正規化)
|
||||
- 直線+if/elseでのreturnをJITで実行(副作用は未対応のためVMへ)
|
||||
- PHIは将来の`NYASH_JIT_PHI_MIN=1`で最小導入予定
|
||||
|
||||
#### 予約シンボル(Runtime/GC 橋渡し)
|
||||
- `nyash.rt.checkpoint`(セーフポイント)
|
||||
- JIT: no-op スタブを登録済み(将来のスケジューラ/GC連携用)
|
||||
- AOT: `nyrt` が同名シンボルをエクスポート(`#[export_name]`)。リンク済み
|
||||
- トレース: `NYASH_RUNTIME_CHECKPOINT_TRACE=1` でstderrに到達ログ
|
||||
- `nyash.gc.barrier_write`(書き込みバリア)
|
||||
- JIT: no-op スタブを登録済み(将来のインクリメンタルGC向けフック)
|
||||
- AOT: `nyrt` が同名シンボルをエクスポート(`#[export_name]`)
|
||||
- トレース: `NYASH_GC_BARRIER_TRACE=1` でstderrに到達ログ
|
||||
|
||||
メモ: 現時点では両シンボルとも副作用なし(no-op)。MIR側では `Safepoint` → `ExternCall(env.runtime.checkpoint)` へ段階移行中です。
|
||||
@ -0,0 +1,98 @@
|
||||
# MIR 26-Instruction Diet (Agreed Final Set)
|
||||
|
||||
Goal
|
||||
- Converge on a lean, proven instruction set guided by vm-stats and E2E.
|
||||
- Preserve hot paths, demote meta, fold type ops, reserve room for growth.
|
||||
|
||||
Agreed Final Set (26)
|
||||
1) Const
|
||||
2) Copy
|
||||
3) Load
|
||||
4) Store
|
||||
5) BinOp
|
||||
6) UnaryOp
|
||||
7) Compare
|
||||
8) Jump
|
||||
9) Branch
|
||||
10) Phi
|
||||
11) Return
|
||||
12) Call
|
||||
13) BoxCall
|
||||
14) NewBox
|
||||
15) ArrayGet
|
||||
16) ArraySet
|
||||
17) RefNew
|
||||
18) RefGet
|
||||
19) RefSet
|
||||
20) Await
|
||||
21) Print
|
||||
22) ExternCall (keep minimal; prefer BoxCall)
|
||||
23) TypeOp (unify TypeCheck/Cast)
|
||||
24) WeakRef (unify WeakNew/WeakLoad)
|
||||
25) Barrier (unify BarrierRead/BarrierWrite)
|
||||
26) Reserve (future async/error instr)
|
||||
|
||||
Hot/Core (keep)
|
||||
- Data: Const, Copy, Load, Store
|
||||
- ALU: BinOp, UnaryOp, Compare
|
||||
- Control: Jump, Branch, Phi, Return
|
||||
- Calls: Call, BoxCall
|
||||
- Objects: NewBox
|
||||
- Arrays: ArrayGet, ArraySet
|
||||
|
||||
Likely Keep (usage-dependent)
|
||||
- Refs: RefNew, RefGet, RefSet (seen in language features; keep unless stats prove cold)
|
||||
- Async: Await (FutureNew/Set can be Box/APIs)
|
||||
|
||||
Meta (demote to build-mode)
|
||||
- Debug, Nop, Safepoint
|
||||
|
||||
Type Ops (fold)
|
||||
- TypeCheck, Cast → fold/verify-time or unify as a single TypeOp (optional).
|
||||
|
||||
External (unify)
|
||||
- ExternCall → prefer BoxCall; keep ExternCall only where required.
|
||||
|
||||
Extended/Reserve
|
||||
- Weak*: WeakNew, WeakLoad
|
||||
- Barriers: BarrierRead, BarrierWrite
|
||||
- 2 Reserve IDs for future async/error instrumentation
|
||||
|
||||
Mapping Notes
|
||||
- HTTP E2E shows BoxCall/NewBox dominate (33–42%), then Const/NewBox, with Branch/Jump/Phi only in error flows.
|
||||
- FileBox path similarly heavy on BoxCall/NewBox/Const.
|
||||
- Implication: invest into BoxCall fast path and const/alloc optimization.
|
||||
|
||||
Migration Strategy
|
||||
1) Introduce an experimental feature gate that switches TypeCheck/Cast to TypeOp or folds them.
|
||||
2) Demote Debug/Nop/Safepoint under non-release builds.
|
||||
3) Keep ExternCall available, route new external APIs via BoxCall when possible.
|
||||
4) Track Weak*/Barrier usage; unify under WeakRef/Barrier. Graduate dedicated ops only if vm-stats shows recurring use.
|
||||
|
||||
Mapping from Current → Final
|
||||
- TypeCheck, Cast → TypeOp
|
||||
- WeakNew, WeakLoad → WeakRef
|
||||
- BarrierRead, BarrierWrite → Barrier
|
||||
- (Keep) ExternCall, but prefer BoxCall where possible(ExternCall は最小限に)
|
||||
- (Keep) Debug/Nop/Safepoint as meta under non-release builds(命令セット外のビルドモード制御に降格)
|
||||
|
||||
Verification
|
||||
- Add MIR verifier rule: use-before-def across merges is rejected (guards phi misuse).
|
||||
- Add snapshot tests for classic if-merge returning phi.
|
||||
|
||||
Appendix: Rationale
|
||||
- Smaller ISA simplifies VM fast paths and aids JIT/AOT later.
|
||||
- Data shows hot paths concentrated on calls, const, alloc; control sparse and localized.
|
||||
- Folding type ops reduces interpreter/VM dispatch; verification handles safety.
|
||||
---
|
||||
|
||||
Feature Flags (Cargo)
|
||||
- Deprecated flags (unified by default):
|
||||
- `mir_typeop_poc`: no-op now. Builder always emits `TypeOp(Check/Cast)` instead of legacy `TypeCheck/Cast`。
|
||||
- `mir_refbarrier_unify_poc`: no-op now. Builder always emits `WeakRef/Barrier` instead of legacy `WeakNew/WeakLoad/BarrierRead/Write`。
|
||||
- Optimizer has a Pass 0 that normalizes any残存の旧命令 → 統合命令(安全ネット)。
|
||||
|
||||
Status (2025-08-23)
|
||||
- Flags declared in `Cargo.toml` (off by default)
|
||||
- PoC design doc: `docs/development/proposals/mir-typeop-weakref-barrier-poc.md`
|
||||
- Next: land builder/VM mapping behind flags, add snapshot tests; no behavior change with flags off
|
||||
218
docs/private/reference/architecture/mir-to-vm-mapping.md
Normal file
218
docs/private/reference/architecture/mir-to-vm-mapping.md
Normal file
@ -0,0 +1,218 @@
|
||||
# MIR → VM Mapping (Draft)
|
||||
|
||||
最終更新: 2025-08-23
|
||||
|
||||
目的: 生成されたMIR命令がVMでどう実行されるかを1枚で把握し、欠落や暫定実装を洗い出す。26命令ダイエット検討の足場にする。
|
||||
|
||||
記法: 状態 = Implemented / Partial / No-op / TODO。
|
||||
|
||||
## コア命令
|
||||
- Const: Implemented
|
||||
- 定数を `VMValue` に格納。
|
||||
- BinOp: Partial
|
||||
- Integer: Add/Sub/Mul/Div 実装(Divは0割チェック)。他の算術/論理/ビット演算は TODO。
|
||||
- String: `+` 連結のみ対応。その他は TypeError。
|
||||
- UnaryOp: Partial
|
||||
- `Neg`(int), `Not`(bool) のみ。`BitNot` は TODO。
|
||||
- Compare: Partial
|
||||
- Integer/ String の Eq/Ne/Lt/Le/Gt/Ge 対応。Bool は Eq/Ne のみ。
|
||||
- Void は値を持たないため、比較は Eq/Ne のみ定義。
|
||||
- `Void == Void` は true、`Void != Void` は false
|
||||
- `Void == X` は false、`Void != X` は true(順序比較は TypeError)
|
||||
- Load / Store: Implemented
|
||||
- 現状はVM内の値スロット操作(簡易)。
|
||||
- Copy: Implemented
|
||||
- 値コピー+クラス名/内部参照印の伝播。
|
||||
|
||||
## 制御フロー
|
||||
- Branch / Jump / Return: Implemented
|
||||
- Branchの条件は `Bool` を期待。以下の動的変換を許容:
|
||||
- `Integer` → 非ゼロは true
|
||||
- `BoxRef(BoolBox)` → 中身のbool
|
||||
- `BoxRef(VoidBox)` → false(nullish false)
|
||||
- Phi: Implemented
|
||||
- `LoopExecutor` による選択実装(前BB情報を利用)。
|
||||
|
||||
## 呼び出し/Box関連
|
||||
- Call: Implemented
|
||||
- 関数名を `Const String` として解決しVM内ディスパッチ。
|
||||
- BoxCall: Partial
|
||||
- InstanceBox: `{Class}.{method}/{argc}` へ降格呼び出し(MIR関数)。
|
||||
- PluginBoxV2: cfg(feature="plugins")下でLoader経由invoke(引数: NyashBox配列)。
|
||||
- Builtinの簡易ディスパッチ: `StringBox.length/substr/concat`, `IntegerBox.toString/abs` 等の最小対応。
|
||||
- birth 特例: user-definedの `birth` はMIR関数へ直呼。
|
||||
- NewBox: Implemented
|
||||
- `runtime.box_registry` から生成。`scope_tracker` に登録。クラス名マップ更新。
|
||||
- TypeCheck: No-op (常にtrue)
|
||||
- TODO: 正式な型チェックに置換。
|
||||
- Cast: No-op (コピー)
|
||||
- TODO: 正式な型変換に置換。
|
||||
|
||||
## 配列
|
||||
- ArrayGet: ArrayBox.get(index) を呼び出し、戻り値を格納(VM対応済み)
|
||||
- ArraySet: ArrayBox.set(index, value) を呼び出し(VM対応済み)
|
||||
|
||||
## デバッグ/出力
|
||||
- Debug: No-op(性能優先)
|
||||
- Print: Implemented(`to_string()`して標準出力)
|
||||
- Nop: No-op
|
||||
|
||||
## 例外/安全ポイント
|
||||
- Throw: Partial
|
||||
- 例外値を表示してVMErrorで中断。ハンドラ探索なし。
|
||||
- Catch: No-op
|
||||
- 例外値スロットを `Void` セットのみ。制御遷移の実装は未対応。
|
||||
- Safepoint: No-op
|
||||
|
||||
## 参照/弱参照/バリア
|
||||
- RefNew / RefGet / RefSet: Partial
|
||||
- `object_fields` に簡易格納。`object_class` と `box_declarations` を用いた可視性(public/private)簡易検査あり。
|
||||
- WeakNew / WeakLoad: No-op相当(通常コピー/取得と同値)
|
||||
- TODO: 実際の弱参照生存判定を導入。
|
||||
- BarrierRead / BarrierWrite: No-op
|
||||
- 効果注釈のみ(将来の最適化/並行実行基盤に備えた形)。
|
||||
|
||||
## 非同期
|
||||
- FutureNew / FutureSet / Await: Implemented
|
||||
- `boxes::future::FutureBox` を利用し、同期ブロッキングで結果取得。
|
||||
|
||||
## 外部呼び出し
|
||||
- ExternCall: Implemented
|
||||
- `runtime::get_global_loader_v2().extern_call(iface, method, args)` にルーティング。Some/Noneで戻り値void扱いも考慮。
|
||||
|
||||
---
|
||||
|
||||
## Result / Err / Handle(BoxRef) 取り扱い(重要)
|
||||
|
||||
目的: プラグイン呼び出し(BoxCall→PluginLoaderV2)およびVM内の戻り値で、ResultとBoxRef(Handle)を正しく扱うための合意事項。
|
||||
|
||||
- HTTP系(Netプラグイン)の約束
|
||||
- unreachable(接続不可/タイムアウト等): `Result.Err(ErrorBox)` にマップする。
|
||||
- HTTP 404/500 等のステータス異常: `Result.Ok(Response)` として返す(アプリ層で扱う)。
|
||||
- FileBox等のVoid戻り
|
||||
- `close()` のような副作用のみのメソッドは `Ok(Void)` を返す。VMではVoidの実体は持たない。
|
||||
- Handle(BoxRef)戻り値
|
||||
- プラグインは TLV tag=8(Handle)で `type_id:u32, instance_id:u32` を返す。
|
||||
- Loader は返り値の `type_id` に対応する正しい `fini_method_id` を設定し、`PluginBoxV2` を生成してVMへ返す。
|
||||
- 注意: 生成元のBoxと返り値のBoxの型が異なるケースがあるため、「呼び出し元のfini値を流用しない」。必ず返り値 `type_id` を基に解決する。
|
||||
- Resultの整合
|
||||
- VMは `Result<T, ErrorBox>` をネイティブ表現し、`match` 等で分岐可能。
|
||||
- `Ok(Void)` は `match Ok(_)` と等価に扱える(Voidは値を持たない)。
|
||||
|
||||
参考: TLV/Loader仕様は `docs/reference/plugin-system/ffi-abi-specification.md` と `plugin-tester.md` を参照。
|
||||
|
||||
---
|
||||
|
||||
## 既知の課題(抜粋)
|
||||
- BinOp/UnaryOp/Compare の型拡張(浮動小数・Bool/Box等)。
|
||||
- ArrayGet/ArraySet の実装。
|
||||
- TypeCheck/Cast の正規化(型表現と整合)。
|
||||
- 例外ハンドリング(Throw/Catchの制御フロー接続)。
|
||||
- WeakRef/Barrier の実体化(必要性評価の上、命令ダイエット候補)。
|
||||
- PluginBoxV2 のVM側統合強化(引数/戻り値のTLV全型対応、Handle戻り値→BoxRef化)。
|
||||
|
||||
Verifier(検証)に関する追加事項(方針)
|
||||
- use-before-def across merge の強化: merge後にphiが未使用/未定義を選択するパスを禁止。
|
||||
- if-merge の戻り: retはphiのdstを返す(実装済み)。
|
||||
- TypeOp(TypeCheck/Cast)と命令の整合: Verifierで型注釈に基づく不一致を検出。
|
||||
|
||||
## VM統計(計測)
|
||||
- `--vm-stats` / `--vm-stats-json` で命令ごとの使用回数と時間(ms)を出力。
|
||||
- ホット命令抽出によりダイエット候補を定量化。
|
||||
|
||||
---
|
||||
|
||||
## 実測結果サマリー(初回プローブ)
|
||||
出所: `local_tests/vm_stats_hello.json`, `local_tests/vm_stats_loop.json`, `simple_math.nyash`
|
||||
|
||||
- ループ系(139命令 / 0.158ms)トップ:
|
||||
- Const: 25, BoxCall: 23, NewBox: 23, BinOp: 11, Branch: 11, Compare: 11, Jump: 11, Phi: 11, Safepoint: 11
|
||||
- 所見: ループloweringで Branch/Jump/Phi/Safepoint が並び、Box初期化とBoxCallが多い。
|
||||
- Hello系(6命令): 期待どおりの最小構成(Const/Print/Return中心)。
|
||||
- simple_math(18命令): BinOpの使用を確認(整数加減乗除)。
|
||||
|
||||
補足:
|
||||
- Safepoint はMIR上で挿入されるが、VMではNo-op(計測には現れる)。
|
||||
- NewBox/BoxCall が上位に入るため、命令セットから外すのは不可(コア扱い)。
|
||||
- Compare/Branch/Jump/Phi は制御フローのコア。26命令の中核として維持が妥当。
|
||||
|
||||
## 実測統計(2025-08-23)
|
||||
出所: vm-stats(正常系HTTP/異常系HTTP/FileBox)
|
||||
|
||||
- 正常系HTTP(40命令)
|
||||
- BoxCall: 17(42.5%)/ Const: 12(30%)/ NewBox: 9(22.5%)/ Return: 1 / Safepoint: 1
|
||||
- 異常系HTTP(21命令 = 正常の52.5%)
|
||||
- BoxCall: 7(33.3%)/ Const: 6(28.6%)/ NewBox: 3(14.3%)
|
||||
- Branch: 1 / Jump: 1 / Phi: 1(エラーハンドリング特有)/ Return: 1 / Safepoint: 1
|
||||
- FileBox(44命令)
|
||||
- BoxCall: 17(38.6%)/ Const: 13(29.5%)/ NewBox: 12(27.3%)/ Return: 1 / Safepoint: 1
|
||||
|
||||
設計含意:
|
||||
- BoxCallが常に最頻出(33〜42%)。呼び出しコスト最適化が最優先。
|
||||
- Const/NewBoxが次点。定数・生成の最適化(定数畳み込み/軽量生成・シェアリング)が効果的。
|
||||
- 異常系は早期収束で命令半減。if/phi修正は実戦で有効(Branch/Jump/Phiが顕在化)。
|
||||
|
||||
補足(HTTP 404/500の比較)
|
||||
- 404("Not Found")、500("Internal Server Error")ともに同一プロファイル(合計55命令)
|
||||
- 内訳例: BoxCall: 23 / Const: 16 / NewBox: 12 / BinOp: 2 / Return: 1 / Safepoint: 1
|
||||
- ステータス差はアプリ層で完結し、VM命令の分布には有意差なし(設計の意図どおり)
|
||||
|
||||
## 26命令ダイエット(検討のたたき台)
|
||||
方針: 「命令の意味は保ちつつ集約」。代表案:
|
||||
- 維持: Const / Copy / Load / Store / BinOp / UnaryOp / Compare / Jump / Branch / Phi / Return / Call / BoxCall / NewBox / ArrayGet / ArraySet
|
||||
- 参照: RefNew / RefGet / RefSet(Weak/Barrierは拡張枠へ)
|
||||
- 非同期: Await(FutureNew/SetはBox APIへ寄せる案も可)
|
||||
- I/O: Print は開発モード限定 or ExternCall統合(ExternCall自体はBoxCallへ統合方針)
|
||||
- 調整: TypeCheck/Cast はVerifier/型系に寄せる(命令から外す or 1命令に集約)
|
||||
- Debug/Nop/Safepoint: メタ扱い(命令数からは外す)
|
||||
|
||||
次ステップ:
|
||||
- サンプル/テストをVMで実行し、`vm-stats`結果から実使用命令セットを抽出。
|
||||
- 上記案に対し互換影響を洗い出し、段階移行(エイリアス→削除)を設計。
|
||||
|
||||
---
|
||||
|
||||
## 26命令ダイエットの指針(実測反映)
|
||||
- 維持(ホット・コア): BoxCall / NewBox / Const / BinOp / Compare / Branch / Jump / Phi / Return / Copy / Load / Store / Call
|
||||
- 実装方針: ExternCallは原則BoxCallへ集約(必要なら限定的に残す)。
|
||||
- メタ降格: Debug/Nop/Safepoint(ビルドモードで制御)。
|
||||
- 型系: TypeCheck/Castは折りたたみ or 検証時に処理(1命令に集約も可)。
|
||||
- 参照/弱参照/バリア: 需要ベースで拡張枠へ(vm-statsに登場しない限りコア外)。
|
||||
|
||||
提案(ドラフト):
|
||||
- コア候補(例): Const, Copy, Load, Store, BinOp, UnaryOp, Compare, Jump, Branch, Phi, Return, Call, BoxCall, NewBox, ArrayGet, ArraySet, RefNew, RefGet, RefSet, Await, Print, ExternCall(集約可), TypeOp(=TypeCheck/Cast), 予備2(将来枠)
|
||||
- 予備はWeak*/Barrierや将来の非同期拡張等に割当(実測で常用化したら昇格)。
|
||||
|
||||
---
|
||||
|
||||
## E2E更新(VM経由の実働確認)
|
||||
|
||||
成功ケース(VM):
|
||||
- FileBox.open/write/read: 引数2個のTLVエンコード(String, String)で成功(HELLO往復)
|
||||
- FileBox.copyFrom(handle): Handle引数(tag=8, size=8, type_id+instance_id)で成功
|
||||
- HttpClientBox.get + HttpServerBox: 基本GETの往復(ResultBox経由でResponse取得)
|
||||
- HttpClientBox.post + headers: Status/ヘッダー/ボディをVMで往復確認
|
||||
- HttpClientBox.get unreachable: 接続失敗時はResult.Err(ErrorBox)(ローダーがstring/bytesをErrにマップ)
|
||||
- HTTP 404/500: Result.Ok(Response)(ステータスはResponse上に保持)
|
||||
|
||||
デバッグ小技:
|
||||
- `NYASH_DEBUG_PLUGIN=1` で VM→Plugin 呼び出しTLVの ver/argc/先頭バイトをダンプ
|
||||
- Netプラグインの内部ログ: `NYASH_NET_LOG=1 NYASH_NET_LOG_FILE=net_plugin.log`
|
||||
## 型・Null/Void・比較の扱い(更新)
|
||||
|
||||
- NullはVM内部でVoidに折りたたみ(`Const Null → VMValue::Void`)。
|
||||
- VoidとNullは同一視されない(等価比較は `Void == Void` のみtrue)。
|
||||
- Compareの対応:
|
||||
- 整数/文字列: Eq/Ne/Lt/Le/Gt/Ge(実装済)
|
||||
- 真偽値: Eq/Ne のみ
|
||||
- Void: Eq/Ne のみ(Void==Voidはtrue、それ以外はfalse)
|
||||
- 浮動小数点: Eq/Ne/Lt/Le/Gt/Ge(新規)
|
||||
- 整数と浮動小数点の混在: 双方をf64比較で対応(新規)
|
||||
|
||||
## TypeOp(PoC)
|
||||
- 目的: TypeCheck/Castの統合。
|
||||
- Check: 最小意味論を実装(Integer/Float/Bool/String/Void/Box名に対し一致判定)。
|
||||
- Cast: 当面コピー等価(将来の変換方針に備える)。
|
||||
- me 参照
|
||||
- メソッド/コンストラクタlowering時は `%0` にマップ(パラメータ)。
|
||||
- それ以外の文脈ではフォールバックとして `Const "__me__"` を一度だけ発行して変数マップに保持し、以降の `me` は同一ValueIdを参照(RefGet/RefSetの整合性を保証)。
|
||||
235
docs/private/reference/architecture/mir-unified-reference.md
Normal file
235
docs/private/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)
|
||||
653
docs/private/reference/architecture/nyash_core_concepts.md
Normal file
653
docs/private/reference/architecture/nyash_core_concepts.md
Normal file
@ -0,0 +1,653 @@
|
||||
# 🚀 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仕様書](../plugin-system/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**: [完全リファレンス](../) | [開発ガイド](../../../CLAUDE.md) | [Phase計画](../../development/roadmap/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/private/reference/architecture/plugin-migration-guide-v2.md
Normal file
249
docs/private/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/private/reference/architecture/plugin-migration-request.md
Normal file
369
docs/private/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の実装を参考にしてください。
|
||||
すべての答えがそこにあります!
|
||||
Reference in New Issue
Block a user