freeze: macro platform complete; default ON with profiles; env consolidation; docs + smokes\n\n- Profiles: --profile {lite|dev|ci|strict} (dev-like default for macros)\n- Macro paths: prefer NYASH_MACRO_PATHS (legacy envs deprecated with warnings)\n- Selfhost pre-expand: auto mode, PyVM-only, add smokes (array/map)\n- Docs: user-macros updated; new macro-profiles guide; AGENTS freeze note; CURRENT_TASK freeze\n- Compat: non-breaking; legacy envs print deprecation notices\n
This commit is contained in:
108
docs/reference/architecture/design-overview.md
Normal file
108
docs/reference/architecture/design-overview.md
Normal file
@ -0,0 +1,108 @@
|
||||
# Nyash 設計図(アーキテクチャ概要)
|
||||
|
||||
最終更新: 2025-08-21(Phase 9.78b〜3 反映)
|
||||
|
||||
本書はNyashの実装設計を、バックエンド共通で理解できる単一ドキュメントとしてまとめたもの。言語コア、MIR、インタープリター/VM統合、ランタイム/プラグイン、ビルドと配布の観点を俯瞰する。
|
||||
|
||||
## レイヤー構成
|
||||
|
||||
- 構文/AST: `tokenizer`, `parser`, `ast`
|
||||
- モデル層: `core::model`(BoxDeclaration等の純粋データ)
|
||||
- ランタイム層: `runtime`(UnifiedBoxRegistry, PluginLoader, NyashRuntime)
|
||||
- 実行戦略層: `interpreter`(AST実行)/ `mir`+`backend::vm`(MIR実行)/ 将来 `wasm`/`llvm`
|
||||
- 付帯基盤: `box_factory`, `instance_v2`, `scope_tracker`, `boxes/*`, `stdlib`
|
||||
|
||||
## コア概念
|
||||
|
||||
- Everything is Box: すべての値はBox(ビルトイン、ユーザー定義、プラグイン)
|
||||
- 統一コンストラクタ: `birth(args)`(packはビルトイン継承内部用に透過化)
|
||||
- 明示デリゲーション: `box Child from Parent` と `from Parent.method()`
|
||||
- 厳密変数宣言/スコープ安全: `local`, `outbox`、スコープ退出時の`fini`一元化
|
||||
|
||||
## モデル層(core::model)
|
||||
|
||||
- `BoxDeclaration` を `interpreter` から分離し `core::model` に移動
|
||||
- name, fields, methods, constructors(birth/N), extends, implements, type_parameters
|
||||
- 実行戦略非依存の純粋データ
|
||||
|
||||
## ランタイム層(runtime)
|
||||
|
||||
- `NyashRuntime`
|
||||
- `box_registry: UnifiedBoxRegistry`(ビルトイン/ユーザー定義/プラグインを順序付き検索)
|
||||
- `box_declarations: RwLock<HashMap<String, BoxDeclaration>>`
|
||||
- BuilderでDI(`with_factory`)可能。Interpreter/VMから共有・注入できる
|
||||
- `UnifiedBoxRegistry`
|
||||
- `Arc<dyn BoxFactory>` の列で優先解決(builtin > user > plugin)
|
||||
- `create_box(name, args)` の統一エントリ
|
||||
- `BoxFactory`
|
||||
- builtin: 全ビルトインBoxの生成
|
||||
- user_defined: `BoxDeclaration`に基づき`InstanceBox`生成(birthは実行戦略側で)
|
||||
- plugin: BID-FFI準拠のプラグインBox(将来のExternCall/MIR接続)
|
||||
|
||||
## 実行戦略(Interpreter / VM)
|
||||
|
||||
- Interpreter(AST実行)
|
||||
- `SharedState` は段階的に分解し、宣言等を `NyashRuntime` に寄せ替え
|
||||
- 生成は統一レジストリへ委譲、コンストラクタ実行は`birth/N`のASTを実行
|
||||
|
||||
- VM (MIR実行)
|
||||
- `VM::with_runtime(runtime)` でDI、`NewBox`は`runtime.box_registry.create_box`へ
|
||||
- `ScopeTracker`でスコープ退出時に`fini`(InstanceBox/PluginBox)
|
||||
- birth/メソッドのMIR関数化(Phase 2/3):
|
||||
- Builderが `new` を `NewBox` + `BoxCall("birth")` に展開
|
||||
- Box宣言の `birth/N` と通常メソッド(`method/N`)を `"{Box}.{name}/{N}"` のMIR関数へ関数化
|
||||
- VMの`BoxCall`は `InstanceBox` なら該当MIR関数へディスパッチ(me + 引数)
|
||||
|
||||
## MIR(中間表現)
|
||||
|
||||
- 目的: バックエンド共通の最適化/実行基盤(VM/LLVM/WASM/JIT)
|
||||
- Builder
|
||||
- AST→MIR lowering。`ASTNode::New`→`NewBox`(+ `BoxCall("birth")`)
|
||||
- `ASTNode::BoxDeclaration` の `constructors` / `methods` をMIR関数化
|
||||
- if/loop/try-catch/phi等の基本構造を提供
|
||||
- VM
|
||||
- Stackベースの簡易実装→順次強化中
|
||||
- `call_function_by_name` による関数呼び出しフレームの最小実装
|
||||
|
||||
## インスタンス表現(InstanceBox)
|
||||
|
||||
- 統一フィールド`fields_ng: HashMap<String, NyashValue>`
|
||||
- メソッドASTを保持(ユーザー定義時)
|
||||
- `fini()`による簡易解放(将来、リソースBoxは明示やRAII連携)
|
||||
|
||||
## ライフサイクル統一(fini)
|
||||
|
||||
- Interpreter: スコープ復帰時に`InstanceBox.fini()`等を呼ぶ
|
||||
- VM: `ScopeTracker`で関数入退出時に登録Boxを`fini`
|
||||
|
||||
## プラグイン(BID-FFI)
|
||||
|
||||
- v2ローダ(`runtime::plugin_loader_v2`)とテスター完備
|
||||
- 目標: MIRの`ExternCall`→ローダに接続し、VM/LLVM/WASMで共通パス
|
||||
|
||||
## Runner/ビルド
|
||||
|
||||
- VMモード:
|
||||
1) ASTパース
|
||||
2) ランタイムにBox宣言収集 + UserDefinedBoxFactory登録
|
||||
3) MIRコンパイル
|
||||
4) VMを`with_runtime`で起動し実行
|
||||
|
||||
## 進行中フェーズと方針
|
||||
|
||||
- Phase 9.78b: Interpreter/VMのモデル・ランタイム共有(完了)
|
||||
- Phase 2/3(実質): birth/メソッドのMIR関数化とVMディスパッチ(実装済・基本動作)
|
||||
- 次:
|
||||
- BoxCall→Callへの段階的置換(型決定済みのとき)
|
||||
- ExternCallの実装(VM→プラグイン)
|
||||
- WASM/LLVMバックエンドへMIR関数の共有
|
||||
|
||||
## 参考ファイル
|
||||
|
||||
- `src/core/model.rs`(BoxDeclaration)
|
||||
- `src/runtime/nyash_runtime.rs`(NyashRuntime)
|
||||
- `src/box_factory/*`(builtin/user_defined/plugin)
|
||||
- `src/mir/*`(builder/instruction/function/etc.)
|
||||
- `src/backend/vm.rs`(VM実行)
|
||||
- `src/interpreter/*`(AST実行)
|
||||
|
||||
118
docs/reference/architecture/dynamic-plugin-flow.md
Normal file
118
docs/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統計とプラグイン周りの既知制約
|
||||
98
docs/reference/architecture/mir-26-instruction-diet.md
Normal file
98
docs/reference/architecture/mir-26-instruction-diet.md
Normal file
@ -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/reference/architecture/mir-to-vm-mapping.md
Normal file
218
docs/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/reference/architecture/mir-unified-reference.md
Normal file
235
docs/reference/architecture/mir-unified-reference.md
Normal file
@ -0,0 +1,235 @@
|
||||
# 🤖 Nyash MIR (Mid-level Intermediate Representation) - 統合リファレンス
|
||||
|
||||
*26命令削減実装中・ChatGPT5仕様準拠 - 2025年8月17日版*
|
||||
|
||||
## 🚨 **重要: MIR命令削減プロジェクト進行中**
|
||||
|
||||
**現状**: 35命令実装(175%膨張)→ **目標**: 26命令(ChatGPT5仕様)
|
||||
**Gemini評価**: 削減戦略「極めて健全」「断行推奨」
|
||||
|
||||
## 🎯 **MIR概要**
|
||||
|
||||
Nyash MIRは、Everything is Box哲学を基盤とした中間表現です。現在35命令が実装され、インタープリター・VM・WASM・AOTの全バックエンドで統一された実行を実現します。
|
||||
|
||||
### **🌟 主要特徴**
|
||||
- **Everything is Box**: 全データがBoxオブジェクトとして統一表現
|
||||
- **Effect System**: pure/mut/io/control効果による最適化基盤
|
||||
- **所有権管理**: 強参照森(ownership forest)+ weak参照システム
|
||||
- **非同期対応**: Future/Bus操作の言語レベル統合
|
||||
- **FFI/ABI統合**: ExternCall命令による外部API統一呼び出し
|
||||
|
||||
## 🏗️ **命令分類 - 35命令全体系**
|
||||
|
||||
### **Tier-0: コア演算 (8命令)**
|
||||
基本的な計算・制御フロー命令
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Const` | `%dst = const value` | pure | 定数値生成 |
|
||||
| `BinOp` | `%dst = %lhs op %rhs` | pure | 二項演算(+,-,*,/等) |
|
||||
| `UnaryOp` | `%dst = op %operand` | pure | 単項演算(not, neg等) |
|
||||
| `Compare` | `%dst = %lhs cmp %rhs` | pure | 比較演算(==, !=, <等) |
|
||||
| `Branch` | `br %cond -> %then, %else` | control | 条件分岐 |
|
||||
| `Jump` | `jmp %target` | control | 無条件ジャンプ |
|
||||
| `Return` | `ret %value?` | control | 関数戻り |
|
||||
| `Phi` | `%dst = phi [%val1:%bb1, %val2:%bb2]` | pure | SSA φ関数 |
|
||||
|
||||
### **Tier-1: メモリ・関数操作 (8命令)**
|
||||
メモリアクセス・関数呼び出し・型操作
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Load` | `%dst = load %ptr` | pure | メモリ読み取り |
|
||||
| `Store` | `store %value -> %ptr` | mut | メモリ書き込み |
|
||||
| `Call` | `%dst = call %func(%args...)` | context | 関数呼び出し |
|
||||
| `BoxCall` | `%dst = %box.method(%args...)` | context | Boxメソッド呼び出し |
|
||||
| `NewBox` | `%dst = new_box "Type"(%args...)` | mut | Box生成 |
|
||||
| `TypeCheck` | `%dst = type_check %box "Type"` | pure | 型チェック |
|
||||
| `Cast` | `%dst = cast %value as Type` | pure | 型変換 |
|
||||
| `Copy` | `%dst = copy %src` | pure | 値コピー |
|
||||
|
||||
### **Tier-2: 配列・デバッグ・制御 (7命令)**
|
||||
配列操作・デバッグ・例外処理
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `ArrayGet` | `%dst = %array[%index]` | pure | 配列要素取得 |
|
||||
| `ArraySet` | `%array[%index] = %value` | mut | 配列要素設定 |
|
||||
| `Debug` | `debug %value "message"` | io | デバッグ出力 |
|
||||
| `Print` | `print %value` | io | コンソール出力 |
|
||||
| `Nop` | `nop` | pure | 無操作 |
|
||||
| `Throw` | `throw %exception` | control | 例外発生 |
|
||||
| `Catch` | `catch %type -> %handler` | control | 例外捕捉 |
|
||||
|
||||
### **Tier-3: 参照・非同期・外部API (12命令)**
|
||||
所有権管理・非同期処理・外部連携
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Safepoint` | `safepoint` | io | セーフポイント |
|
||||
| `RefNew` | `%dst = ref_new %box` | pure | 参照生成 |
|
||||
| `RefGet` | `%dst = ref_get %ref.field` | pure | 参照経由読み取り |
|
||||
| `RefSet` | `ref_set %ref.field = %value` | mut | 参照経由書き込み |
|
||||
| `WeakNew` | `%dst = weak_new %box` | pure | weak参照生成 |
|
||||
| `WeakLoad` | `%dst = weak_load %weak_ref` | pure | weak参照読み取り |
|
||||
| `BarrierRead` | `barrier_read %ptr` | io | メモリバリア読み |
|
||||
| `BarrierWrite` | `barrier_write %ptr` | io | メモリバリア書き |
|
||||
| `FutureNew` | `%dst = future_new %value` | mut | Future生成 |
|
||||
| `FutureSet` | `future_set %future = %value` | mut | Future値設定 |
|
||||
| `Await` | `%dst = await %future` | io | Future待機 |
|
||||
| `ExternCall` | `%dst = extern_call iface.method(%args...)` | context | 外部API呼び出し |
|
||||
|
||||
## 🎭 **Effect System - 4種類の効果**
|
||||
|
||||
### **効果分類と最適化ルール**
|
||||
|
||||
```rust
|
||||
pub enum Effect {
|
||||
Pure, // 再順序化可能、共通部分式除去可能
|
||||
Mut, // 同一リソースで順序保持必要
|
||||
Io, // 全順序保持必要(副作用あり)
|
||||
Control, // 制御フロー変更
|
||||
}
|
||||
```
|
||||
|
||||
### **効果別命令分類**
|
||||
|
||||
#### **Pure命令 (15命令)**
|
||||
```
|
||||
Const, BinOp, UnaryOp, Compare, Phi, Load, TypeCheck, Cast, Copy,
|
||||
ArrayGet, Nop, RefNew, RefGet, WeakNew, WeakLoad
|
||||
```
|
||||
|
||||
#### **Mut命令 (7命令)**
|
||||
```
|
||||
Store, NewBox, ArraySet, RefSet, FutureNew, FutureSet
|
||||
```
|
||||
|
||||
#### **Io命令 (6命令)**
|
||||
```
|
||||
Debug, Print, Safepoint, BarrierRead, BarrierWrite, Await
|
||||
```
|
||||
|
||||
#### **Control命令 (4命令)**
|
||||
```
|
||||
Branch, Jump, Return, Throw, Catch
|
||||
```
|
||||
|
||||
#### **Context依存命令 (3命令)**
|
||||
```
|
||||
Call, BoxCall, ExternCall
|
||||
```
|
||||
*効果は呼び出し先に依存*
|
||||
|
||||
## 🔧 **重要なMIR実装詳細**
|
||||
|
||||
### **ExternCall命令 - FFI/ABI統合**
|
||||
|
||||
```rust
|
||||
ExternCall {
|
||||
dst: Option<ValueId>,
|
||||
iface_name: String, // "env.console", "nyash.math"等
|
||||
method_name: String, // "log", "sqrt"等
|
||||
args: Vec<ValueId>,
|
||||
effects: EffectMask, // BID仕様から決定
|
||||
}
|
||||
```
|
||||
|
||||
**用途**: ブラウザーAPI・ネイティブライブラリ・プラグインの統一呼び出し
|
||||
|
||||
### **所有権管理システム**
|
||||
|
||||
#### **強参照森(Ownership Forest)**
|
||||
- 各Boxは最大1つの強参照を持つ(in-degree ≤ 1)
|
||||
- 強参照による循環は禁止(DAG構造保証)
|
||||
- `NewBox`, `RefSet`で所有権移転
|
||||
|
||||
#### **weak参照システム**
|
||||
- 所有権を持たない軽量参照
|
||||
- `WeakNew`で生成、`WeakLoad`で安全アクセス
|
||||
- 参照先削除時は自動的にnull化
|
||||
|
||||
### **非同期処理 - Future操作**
|
||||
|
||||
```mir
|
||||
%future = FutureNew %initial_value // Future生成
|
||||
FutureSet %future = %result // 結果設定
|
||||
%value = Await %future // 結果取得(ブロッキング)
|
||||
```
|
||||
|
||||
## 🚀 **バックエンド別対応状況**
|
||||
|
||||
### **実装済みバックエンド**
|
||||
|
||||
| バックエンド | 対応命令数 | 主要用途 | 特徴 |
|
||||
|-------------|-----------|----------|------|
|
||||
| **Interpreter** | 35/35 | デバッグ・開発 | 全命令完全対応 |
|
||||
| **VM** | 35/35 | 高速実行 | レジスタベース |
|
||||
| **WASM** | 30/35 | Web配布 | ExternCall→import対応 |
|
||||
| **AOT準備** | 計画中 | ネイティブ | LLVM IR生成予定 |
|
||||
|
||||
### **バックエンド固有の最適化**
|
||||
|
||||
#### **VM バックエンド**
|
||||
- レジスタベース実行
|
||||
- 局所最適化(ローカルBus elision)
|
||||
- 直接スレッド化
|
||||
|
||||
#### **WASM バックエンド**
|
||||
- メモリ線形化(文字列は (ptr,len))
|
||||
- ExternCall → import宣言自動生成
|
||||
- ホスト側JavaScript連携
|
||||
|
||||
## 📊 **MIR最適化パス**
|
||||
|
||||
### **Pure命令最適化**
|
||||
- **共通部分式除去 (CSE)**: 同一pure計算の除去
|
||||
- **不変コード移動 (LICM)**: ループ外移動
|
||||
- **定数畳み込み**: コンパイル時計算
|
||||
|
||||
### **Effect-aware最適化**
|
||||
- **Mut順序保持**: 同一リソースアクセス順序維持
|
||||
- **Io順序保持**: 全Io命令の順序保証
|
||||
- **Bus elision**: ローカル通信の直接アクセス化
|
||||
|
||||
## 🧪 **テスト・検証**
|
||||
|
||||
### **MIR検証項目**
|
||||
- [ ] **所有権森検証**: strong in-degree ≤ 1
|
||||
- [ ] **強循環禁止**: 強参照のDAG構造保証
|
||||
- [ ] **weak参照安全性**: 失効時null化
|
||||
- [ ] **効果注釈正確性**: 各命令の効果分類
|
||||
- [ ] **型安全性**: Box型システム整合性
|
||||
|
||||
### **バックエンド互換性テスト**
|
||||
```bash
|
||||
# 全バックエンドMIR一致テスト
|
||||
./target/release/nyash --dump-mir program.nyash > interpreter.mir
|
||||
./target/release/nyash --backend vm --dump-mir program.nyash > vm.mir
|
||||
./target/release/nyash --backend wasm --dump-mir program.nyash > wasm.mir
|
||||
diff interpreter.mir vm.mir && diff vm.mir wasm.mir
|
||||
```
|
||||
|
||||
## 🔮 **将来計画**
|
||||
|
||||
### **Phase 10: AOT/JIT対応**
|
||||
- LLVM IR生成バックエンド
|
||||
- ExternCall → ネイティブ関数呼び出し
|
||||
- 高度な最適化パス統合
|
||||
|
||||
### **Phase 11: MIR v2設計**
|
||||
- 命令数最適化(35 → 25命令目標)
|
||||
- BID統合(Box Interface Definition)
|
||||
- リソース所有権拡張(own<T>, borrow<T>)
|
||||
|
||||
## 📚 **関連ドキュメント**
|
||||
|
||||
- **FFI/ABI仕様**: `docs/説明書/reference/box-design/ffi-abi-specification.md`
|
||||
- **実装詳細**: `src/mir/instruction.rs`
|
||||
- **Phase計画**: `docs/予定/native-plan/copilot_issues.txt`
|
||||
|
||||
---
|
||||
|
||||
**最終更新**: 2025年8月17日
|
||||
**実装ベース**: 35命令完全対応
|
||||
**次期計画**: BID統合プラグインシステム(Phase 9.75f-BID)
|
||||
@ -0,0 +1,45 @@
|
||||
# Plugin Migration Guide v2 Enhancement Summary
|
||||
|
||||
## What was accomplished
|
||||
|
||||
This task involved enhancing the existing `docs/plugin-migration-request.md` with comprehensive implementation guidance based on the issue requirements.
|
||||
|
||||
## Key improvements made:
|
||||
|
||||
### 1. **Comprehensive nyash.toml explanation**
|
||||
- Added detailed explanation of the `from`/`to` type conversion system
|
||||
- Explained TLV (Type-Length-Value) encoding with specific tag mappings
|
||||
- Provided clear examples using FileBox as reference
|
||||
|
||||
### 2. **Detailed implementation examples**
|
||||
- Added complete Rust code examples for TLV parsing
|
||||
- Showed real HttpClientBox plugin implementation patterns
|
||||
- Included proper error handling and memory management examples
|
||||
|
||||
### 3. **Structured migration priorities**
|
||||
- **Phase 1**: Network boxes (HttpClientBox, SocketBox) - highest priority
|
||||
- **Phase 2**: GUI boxes (EguiBox, Canvas) - platform dependent
|
||||
- **Phase 3**: Special purpose boxes (TimerBox, QRBox) - independent
|
||||
|
||||
### 4. **Testing and validation guidelines**
|
||||
- Complete testing workflow with plugin-tester
|
||||
- Real Nyash code examples for validation
|
||||
- Troubleshooting guidance for common mistakes
|
||||
|
||||
### 5. **Reference implementation guidance**
|
||||
- FileBox plugin as the gold standard example
|
||||
- Specific file paths for all reference materials
|
||||
- Success tips and common pitfalls
|
||||
|
||||
## Document statistics:
|
||||
- **Length**: 368 lines (vs ~200 lines originally)
|
||||
- **Code examples**: 16 code blocks with real implementation patterns
|
||||
- **Comprehensive coverage**: TLV, nyash.toml, FFI, testing, and reference materials
|
||||
|
||||
## Validation:
|
||||
- All key sections verified to be present
|
||||
- Code examples cover the full implementation pipeline
|
||||
- References to FileBox plugin success story maintained
|
||||
- HttpClientBox positioned as Phase 1 priority target
|
||||
|
||||
The guide now serves as a complete reference for migrating any builtin Box to a plugin, with FileBox as the proven template and HttpClientBox as the next target.
|
||||
249
docs/reference/architecture/plugin-migration-guide-v2.md
Normal file
249
docs/reference/architecture/plugin-migration-guide-v2.md
Normal file
@ -0,0 +1,249 @@
|
||||
# 📦 Nyash ビルトインBox → プラグイン化移行ガイド v2
|
||||
|
||||
## 🎯 概要
|
||||
NyashのビルトインBoxをプラグイン化し、コアを軽量化します。
|
||||
FileBoxプラグインの成功例を詳しく解説しながら、移行方法を説明します。
|
||||
|
||||
## 🔑 重要な概念:nyash.tomlの型定義システム
|
||||
|
||||
### 型変換の仕組み
|
||||
nyash.tomlでは、Nyash側とプラグイン側の型変換を明示的に定義します:
|
||||
|
||||
```toml
|
||||
# FileBoxの例
|
||||
[plugins.FileBox.methods]
|
||||
# writeメソッド:Nyashのstringをプラグインではbytesとして扱う
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# openメソッド:2つのstring引数(型変換なし)
|
||||
open = { args = [
|
||||
{ name = "path", from = "string", to = "string" },
|
||||
{ name = "mode", from = "string", to = "string" }
|
||||
] }
|
||||
```
|
||||
|
||||
### from/toの意味
|
||||
- **from**: Nyash側の型(ユーザーが渡す型)
|
||||
- **to**: プラグイン側で受け取る型(TLVエンコーディング)
|
||||
|
||||
### TLVタグとの対応
|
||||
プラグインはTLV(Type-Length-Value)形式でデータを受け取ります:
|
||||
- `to = "i32"` → TLV tag=2(32ビット整数)
|
||||
- `to = "string"` → TLV tag=6(UTF-8文字列)
|
||||
- `to = "bytes"` → TLV tag=7(バイト配列)
|
||||
|
||||
## 📋 移行対象Box一覧(優先順位順)
|
||||
|
||||
### 🌐 Phase 1: ネットワーク系(最優先・最も簡単)
|
||||
既にスタブ実装があり、reqwest依存を追加するだけで完成します。
|
||||
|
||||
#### HttpClientBox
|
||||
```toml
|
||||
[plugins.HttpClientBox.methods]
|
||||
# シンプルなGETリクエスト
|
||||
get = {
|
||||
args = [{ from = "string", to = "string" }], # URL
|
||||
returns = "string" # レスポンスボディ
|
||||
}
|
||||
|
||||
# POSTリクエスト(ボディ付き)
|
||||
post = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "string", to = "bytes" } # ボディ(バイナリ対応)
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# 詳細なリクエスト(ヘッダー等を含む)
|
||||
request = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # メソッド(GET/POST等)
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "map", to = "map" } # オプション(headers, timeout等)
|
||||
],
|
||||
returns = "map" # { status: i32, body: string, headers: map }
|
||||
}
|
||||
```
|
||||
|
||||
### 🖼️ Phase 2: GUI系(プラットフォーム依存)
|
||||
EguiBoxは既にfeature分離されているので参考になります。
|
||||
|
||||
### 🎵 Phase 3: 特殊用途系(独立性高い)
|
||||
TimerBox、QRBox等は単機能で実装しやすいです。
|
||||
|
||||
## 🔧 実装ガイド:FileBoxを例に
|
||||
|
||||
### 1. プラグイン側での型受け取り例
|
||||
|
||||
```rust
|
||||
// nyash.toml: write = { args = [{ from = "string", to = "bytes" }] }
|
||||
METHOD_WRITE => {
|
||||
// TLVでbytesとして受け取る
|
||||
let data = tlv_parse_bytes(args)?; // Vec<u8>として取得
|
||||
|
||||
// ファイルに書き込み
|
||||
match file.write(&data) {
|
||||
Ok(n) => {
|
||||
file.flush()?; // 重要:フラッシュを忘れずに!
|
||||
// 書き込んだバイト数を返す(TLV i32)
|
||||
write_tlv_i32(n as i32, result, result_len)
|
||||
}
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 複数引数の解析例
|
||||
|
||||
```rust
|
||||
// nyash.toml: open = { args = [{ from = "string", to = "string" }, { from = "string", to = "string" }] }
|
||||
METHOD_OPEN => {
|
||||
// 2つのstring引数を解析
|
||||
let (path, mode) = tlv_parse_two_strings(args)?;
|
||||
|
||||
// ファイルを開く
|
||||
let file = match mode.as_str() {
|
||||
"r" => File::open(&path)?,
|
||||
"w" => File::create(&path)?,
|
||||
"a" => OpenOptions::new().append(true).open(&path)?,
|
||||
_ => return NYB_E_INVALID_ARGS
|
||||
};
|
||||
|
||||
// 成功時はVoid(空)を返す
|
||||
write_tlv_void(result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 引数なしメソッドの例
|
||||
|
||||
```rust
|
||||
// nyash.toml: read = { args = [] }
|
||||
METHOD_READ => {
|
||||
// 引数なし - ファイル全体を読む
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
let mut buf = Vec::new();
|
||||
file.read_to_end(&mut buf)?;
|
||||
|
||||
// bytesとして返す
|
||||
write_tlv_bytes(&buf, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 HttpClientBox実装の具体例
|
||||
|
||||
```rust
|
||||
// HttpClientBoxプラグインの実装イメージ
|
||||
use reqwest::blocking::Client;
|
||||
|
||||
METHOD_GET => {
|
||||
// URLを解析
|
||||
let url = tlv_parse_string(args)?;
|
||||
|
||||
// HTTPリクエスト実行
|
||||
let client = Client::new();
|
||||
let response = client.get(&url).send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
// 文字列として返す
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
|
||||
METHOD_POST => {
|
||||
// URL と ボディを解析
|
||||
let (url, body_bytes) = tlv_parse_string_and_bytes(args)?;
|
||||
|
||||
// POSTリクエスト
|
||||
let client = Client::new();
|
||||
let response = client.post(&url)
|
||||
.body(body_bytes)
|
||||
.send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 実装のコツとよくある間違い
|
||||
|
||||
### ✅ 正しいnyash.toml
|
||||
```toml
|
||||
# 引数の型変換を明示
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# 戻り値の型も指定可能
|
||||
exists = { args = [], returns = "bool" }
|
||||
```
|
||||
|
||||
### ❌ よくある間違い
|
||||
```toml
|
||||
# 間違い:型情報がない
|
||||
write = { args = ["string"] } # ❌ from/toが必要
|
||||
|
||||
# 間違い:不要なフィールド
|
||||
get = { args = [{ type = "string" }] } # ❌ typeではなくfrom/to
|
||||
```
|
||||
|
||||
### メモリ管理の注意点
|
||||
1. 文字列は必ずCString/CStr経由で変換
|
||||
2. プラグイン側でallocしたメモリはプラグイン側でfree
|
||||
3. ホスト側のVtableを使ってログ出力
|
||||
|
||||
### エラーハンドリング
|
||||
```rust
|
||||
// パニックをFFI境界で止める
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
// 実際の処理
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(val) => val,
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 テスト方法
|
||||
|
||||
### 1. プラグインビルド
|
||||
```bash
|
||||
cd plugins/nyash-http-plugin
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### 2. plugin-testerで診断
|
||||
```bash
|
||||
cd ../../tools/plugin-tester
|
||||
./target/release/plugin-tester ../../plugins/nyash-http-plugin/target/release/libnyash_http_plugin.so
|
||||
|
||||
# 期待される出力:
|
||||
# Plugin Information:
|
||||
# Box Type: HttpClientBox (ID: 20)
|
||||
# Methods: 5
|
||||
# - birth [ID: 0] (constructor)
|
||||
# - get, post, put, delete
|
||||
# - fini [ID: 4294967295] (destructor)
|
||||
```
|
||||
|
||||
### 3. Nyashで実行
|
||||
```nyash
|
||||
// test_http.nyash
|
||||
local http = new HttpClientBox()
|
||||
local response = http.get("https://api.example.com/data")
|
||||
print(response)
|
||||
```
|
||||
|
||||
## 📚 参考資料
|
||||
- **FileBoxプラグイン完全実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
|
||||
- **TLVエンコーディング仕様**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
|
||||
- **nyash.toml設定例**: プロジェクトルートの`nyash.toml`
|
||||
|
||||
## 🎯 成功の秘訣
|
||||
1. **FileBoxを完全に理解してから始める** - コピペベースで改造
|
||||
2. **nyash.tomlの型定義を正確に** - from/toを明示
|
||||
3. **TLVの理解** - tag=6(string), tag=7(bytes)の違い
|
||||
4. **plugin-testerで早期検証** - 問題を早期発見
|
||||
|
||||
---
|
||||
|
||||
質問があれば、FileBoxの実装を参考にしてください。
|
||||
すべての答えがそこにあります!
|
||||
369
docs/reference/architecture/plugin-migration-request.md
Normal file
369
docs/reference/architecture/plugin-migration-request.md
Normal file
@ -0,0 +1,369 @@
|
||||
# 📦 Nyash ビルトインBox → プラグイン化移行ガイド v2
|
||||
|
||||
## 🎯 概要
|
||||
NyashのビルトインBoxをプラグイン化し、コアを軽量化します。
|
||||
FileBoxプラグインの成功例を詳しく解説しながら、移行方法を説明します。
|
||||
|
||||
## 🔑 重要な概念:nyash.tomlの型定義システム
|
||||
|
||||
### 型変換の仕組み
|
||||
nyash.tomlでは、Nyash側とプラグイン側の型変換を明示的に定義します:
|
||||
|
||||
```toml
|
||||
# FileBoxの例
|
||||
[plugins.FileBox.methods]
|
||||
# writeメソッド:Nyashのstringをプラグインではbytesとして扱う
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# openメソッド:2つのstring引数(型変換なし)
|
||||
open = { args = [
|
||||
{ name = "path", from = "string", to = "string" },
|
||||
{ name = "mode", from = "string", to = "string" }
|
||||
] }
|
||||
```
|
||||
|
||||
### from/toの意味
|
||||
- **from**: Nyash側の型(ユーザーが渡す型)
|
||||
- **to**: プラグイン側で受け取る型(TLVエンコーディング)
|
||||
|
||||
### TLVタグとの対応
|
||||
プラグインはTLV(Type-Length-Value)形式でデータを受け取ります:
|
||||
- `to = "i32"` → TLV tag=2(32ビット整数)
|
||||
- `to = "string"` → TLV tag=6(UTF-8文字列)
|
||||
- `to = "bytes"` → TLV tag=7(バイト配列)
|
||||
|
||||
## 📋 移行対象Box一覧(優先順位順)
|
||||
|
||||
### 🌐 Phase 1: ネットワーク系(最優先・最も簡単)
|
||||
既にスタブ実装があり、reqwest依存を追加するだけで完成します。
|
||||
|
||||
#### HttpClientBox
|
||||
```toml
|
||||
[plugins.HttpClientBox.methods]
|
||||
# シンプルなGETリクエスト
|
||||
get = {
|
||||
args = [{ from = "string", to = "string" }], # URL
|
||||
returns = "string" # レスポンスボディ
|
||||
}
|
||||
|
||||
# POSTリクエスト(ボディ付き)
|
||||
post = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "string", to = "bytes" } # ボディ(バイナリ対応)
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# 詳細なリクエスト(ヘッダー等を含む)
|
||||
request = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # メソッド(GET/POST等)
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "map", to = "map" } # オプション(headers, timeout等)
|
||||
],
|
||||
returns = "map" # { status: i32, body: string, headers: map }
|
||||
}
|
||||
```
|
||||
|
||||
### 🖼️ Phase 2: GUI系(プラットフォーム依存)
|
||||
EguiBoxは既にfeature分離されているので参考になります。
|
||||
|
||||
### 🎵 Phase 3: 特殊用途系(独立性高い)
|
||||
TimerBox、QRBox等は単機能で実装しやすいです。
|
||||
|
||||
## 🔧 実装ガイドライン
|
||||
|
||||
### 1. 参考にするファイル
|
||||
- **成功例**: `plugins/nyash-filebox-plugin/` - 動作確認済みのFileBoxプラグイン
|
||||
- **設定例**: `nyash.toml` - 型情報定義の書き方
|
||||
- **テスト**: `tools/plugin-tester/` - プラグイン診断ツール
|
||||
|
||||
### 2. 各プラグインの構成
|
||||
```
|
||||
plugins/nyash-xxx-plugin/
|
||||
├── Cargo.toml # 依存関係(例: reqwest for HTTP)
|
||||
├── src/
|
||||
│ └── lib.rs # FFI実装
|
||||
├── nyash.toml # 型情報定義
|
||||
└── README.md # 使用方法
|
||||
```
|
||||
|
||||
### 3. nyash.toml記述例(HttpClientBoxの場合)
|
||||
```toml
|
||||
[plugins.HttpClientBox.methods]
|
||||
# GETリクエスト
|
||||
get = {
|
||||
args = [{ name = "url", from = "string", to = "string" }],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# POSTリクエスト
|
||||
post = {
|
||||
args = [
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "body", from = "string", to = "string" }
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# ヘッダー付きリクエスト
|
||||
request = {
|
||||
args = [
|
||||
{ name = "method", from = "string", to = "string" },
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "options", from = "map", to = "map" }
|
||||
],
|
||||
returns = "map" # { status, body, headers }
|
||||
}
|
||||
|
||||
# DELETE リクエスト
|
||||
delete = {
|
||||
args = [{ name = "url", from = "string", to = "string" }],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# PUT リクエスト
|
||||
put = {
|
||||
args = [
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "body", from = "string", to = "string" }
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. テスト方法
|
||||
```bash
|
||||
# ビルド
|
||||
cd plugins/nyash-xxx-plugin
|
||||
cargo build --release
|
||||
|
||||
# plugin-testerで診断
|
||||
cd ../../tools/plugin-tester
|
||||
./target/release/plugin-tester ../../plugins/nyash-xxx-plugin/target/release/libnyash_xxx_plugin.so
|
||||
|
||||
# Nyashで実行テスト
|
||||
./target/release/nyash test_xxx.nyash
|
||||
```
|
||||
|
||||
## 📝 特記事項
|
||||
|
||||
### HttpBox系
|
||||
- 現在スタブ実装なので移行しやすい
|
||||
- reqwest依存を復活させる
|
||||
- 非同期処理の考慮が必要
|
||||
|
||||
### EguiBox
|
||||
- 既にfeature分離されているので参考になる
|
||||
- メインスレッド制約に注意
|
||||
|
||||
### AudioBox/SoundBox
|
||||
- プラットフォーム依存性が高い
|
||||
- Web/Desktop両対応を検討
|
||||
|
||||
### 依存関係の管理
|
||||
- 各プラグインは独立したCargo.tomlを持つ
|
||||
- ビルド時間短縮のため最小限の依存にする
|
||||
|
||||
## 💡 実装の重要ポイント
|
||||
|
||||
### FFI境界での注意事項
|
||||
1. **メモリ管理**:
|
||||
- Rustの所有権とCのメモリ管理の違いに注意
|
||||
- 文字列は必ずCString/CStr経由で変換
|
||||
|
||||
2. **エラーハンドリング**:
|
||||
- パニックをFFI境界で止める(catch_unwind使用)
|
||||
- エラーコードで通信(0=成功, 負値=エラー)
|
||||
|
||||
3. **型変換パターン** (FileBoxプラグインより):
|
||||
```rust
|
||||
// Nyash文字列 → Rust文字列
|
||||
let path = get_string_arg(&args[0], 0)?;
|
||||
|
||||
// Rust文字列 → Nyash文字列
|
||||
encode_string_result(&contents, result, result_len)
|
||||
```
|
||||
|
||||
### 参考ファイルの具体的パス
|
||||
- **FileBoxプラグイン実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
|
||||
- **FFI仕様書**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
|
||||
- **プラグインシステム説明**: `docs/説明書/reference/plugin-system/plugin-system.md`
|
||||
- **BID-FFI型変換** (参考): `src/bid-converter-copilot/tlv.rs`
|
||||
|
||||
## 🔧 実装ガイド:FileBoxを例に
|
||||
|
||||
### 1. プラグイン側での型受け取り例
|
||||
|
||||
```rust
|
||||
// nyash.toml: write = { args = [{ from = "string", to = "bytes" }] }
|
||||
METHOD_WRITE => {
|
||||
// TLVでbytesとして受け取る
|
||||
let data = tlv_parse_bytes(args)?; // Vec<u8>として取得
|
||||
|
||||
// ファイルに書き込み
|
||||
match file.write(&data) {
|
||||
Ok(n) => {
|
||||
file.flush()?; // 重要:フラッシュを忘れずに!
|
||||
// 書き込んだバイト数を返す(TLV i32)
|
||||
write_tlv_i32(n as i32, result, result_len)
|
||||
}
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 複数引数の解析例
|
||||
|
||||
```rust
|
||||
// nyash.toml: open = { args = [{ from = "string", to = "string" }, { from = "string", to = "string" }] }
|
||||
METHOD_OPEN => {
|
||||
// 2つのstring引数を解析
|
||||
let (path, mode) = tlv_parse_two_strings(args)?;
|
||||
|
||||
// ファイルを開く
|
||||
let file = match mode.as_str() {
|
||||
"r" => File::open(&path)?,
|
||||
"w" => File::create(&path)?,
|
||||
"a" => OpenOptions::new().append(true).open(&path)?,
|
||||
_ => return NYB_E_INVALID_ARGS
|
||||
};
|
||||
|
||||
// 成功時はVoid(空)を返す
|
||||
write_tlv_void(result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 引数なしメソッドの例
|
||||
|
||||
```rust
|
||||
// nyash.toml: read = { args = [] }
|
||||
METHOD_READ => {
|
||||
// 引数なし - ファイル全体を読む
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
let mut buf = Vec::new();
|
||||
file.read_to_end(&mut buf)?;
|
||||
|
||||
// bytesとして返す
|
||||
write_tlv_bytes(&buf, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 HttpClientBox実装の具体例
|
||||
|
||||
```rust
|
||||
// HttpClientBoxプラグインの実装イメージ
|
||||
use reqwest::blocking::Client;
|
||||
|
||||
METHOD_GET => {
|
||||
// URLを解析
|
||||
let url = tlv_parse_string(args)?;
|
||||
|
||||
// HTTPリクエスト実行
|
||||
let client = Client::new();
|
||||
let response = client.get(&url).send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
// 文字列として返す
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
|
||||
METHOD_POST => {
|
||||
// URL と ボディを解析
|
||||
let (url, body_bytes) = tlv_parse_string_and_bytes(args)?;
|
||||
|
||||
// POSTリクエスト
|
||||
let client = Client::new();
|
||||
let response = client.post(&url)
|
||||
.body(body_bytes)
|
||||
.send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 実装のコツとよくある間違い
|
||||
|
||||
### ✅ 正しいnyash.toml
|
||||
```toml
|
||||
# 引数の型変換を明示
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# 戻り値の型も指定可能
|
||||
exists = { args = [], returns = "bool" }
|
||||
```
|
||||
|
||||
### ❌ よくある間違い
|
||||
```toml
|
||||
# 間違い:型情報がない
|
||||
write = { args = ["string"] } # ❌ from/toが必要
|
||||
|
||||
# 間違い:不要なフィールド
|
||||
get = { args = [{ type = "string" }] } # ❌ typeではなくfrom/to
|
||||
```
|
||||
|
||||
### メモリ管理の注意点
|
||||
1. 文字列は必ずCString/CStr経由で変換
|
||||
2. プラグイン側でallocしたメモリはプラグイン側でfree
|
||||
3. ホスト側のVtableを使ってログ出力
|
||||
|
||||
### エラーハンドリング
|
||||
```rust
|
||||
// パニックをFFI境界で止める
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
// 実際の処理
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(val) => val,
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 テスト方法
|
||||
|
||||
### 1. プラグインビルド
|
||||
```bash
|
||||
cd plugins/nyash-http-plugin
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### 2. plugin-testerで診断
|
||||
```bash
|
||||
cd ../../tools/plugin-tester
|
||||
./target/release/plugin-tester ../../plugins/nyash-http-plugin/target/release/libnyash_http_plugin.so
|
||||
|
||||
# 期待される出力:
|
||||
# Plugin Information:
|
||||
# Box Type: HttpClientBox (ID: 20)
|
||||
# Methods: 5
|
||||
# - birth [ID: 0] (constructor)
|
||||
# - get, post, put, delete
|
||||
# - fini [ID: 4294967295] (destructor)
|
||||
```
|
||||
|
||||
### 3. Nyashで実行
|
||||
```nyash
|
||||
// test_http.nyash
|
||||
local http = new HttpClientBox()
|
||||
local response = http.get("https://api.example.com/data")
|
||||
print(response)
|
||||
```
|
||||
|
||||
## 📚 参考資料
|
||||
- **FileBoxプラグイン完全実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
|
||||
- **TLVエンコーディング仕様**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
|
||||
- **nyash.toml設定例**: プロジェクトルートの`nyash.toml`
|
||||
|
||||
## 🎯 成功の秘訣
|
||||
1. **FileBoxを完全に理解してから始める** - コピペベースで改造
|
||||
2. **nyash.tomlの型定義を正確に** - from/toを明示
|
||||
3. **TLVの理解** - tag=6(string), tag=7(bytes)の違い
|
||||
4. **plugin-testerで早期検証** - 問題を早期発見
|
||||
|
||||
---
|
||||
|
||||
質問があれば、FileBoxの実装を参考にしてください。
|
||||
すべての答えがそこにあります!
|
||||
Reference in New Issue
Block a user