Files
hakorune/docs/development/proposals/nyash.link/bid-using-integration.md
Moe Charm cc2a820af7 feat(plugin): Fix plugin BoxRef return and Box argument support
- Fixed deadlock in FileBox plugin copyFrom implementation (single lock)
- Added TLV Handle (tag=8) parsing in calls.rs for returned BoxRefs
- Improved plugin loader with config path consistency and detailed logging
- Fixed loader routing for proper Handle type_id/fini_method_id resolution
- Added detailed logging for TLV encoding/decoding in plugin_loader_v2

Test docs/examples/plugin_boxref_return.nyash now works correctly:
- cloneSelf() returns FileBox Handle properly
- copyFrom(Box) accepts plugin Box arguments
- Both FileBox instances close and fini correctly

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 00:41:26 +09:00

654 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# BID×usingシステム統合技術実装詳細
## 🎯 統合設計の核心
### 📊 既存システムとの整合性
-**MIR ExternCall**: 既にFFI-ABI対応実装済み
-**WASM RuntimeImports**: BID→WASM自動生成基盤あり
-**VM ExternStub**: スタブ実行環境実装済み
- 🔧 **統合課題**: usingシステムとBIDの橋渡し実装
### 🚀 統合アーキテクチャ概要
```
User Code (using statements)
UniversalNamespaceRegistry
CallTarget Resolution
↓ ↓ ↓
Builtin FFI-ABI NyashModule
↓ ↓ ↓
MIR Generation (BuiltinCall/ExternCall/ModuleCall)
Backend Execution (VM/WASM/AOT)
```
## 🏗️ 詳細技術実装
### 1. BID定義システム
#### **BIDファイル構造拡張**
```yaml
# apis/enhanced_canvas.yaml
version: 1
metadata:
name: "Enhanced Canvas API"
description: "Extended Canvas API with batch operations"
target_environments: ["browser", "node-canvas", "skia"]
nyash_namespace: "canvas_api" # usingで使用する名前空間
interfaces:
- name: canvas_api.canvas
box: Canvas
methods:
# 基本描画
- name: fillRect
params:
- {string: canvas_id, description: "Canvas element ID"}
- {i32: x, description: "X coordinate"}
- {i32: y, description: "Y coordinate"}
- {i32: width, description: "Rectangle width"}
- {i32: height, description: "Rectangle height"}
- {string: color, description: "Fill color (CSS format)"}
returns: void
effect: io
optimization_hints:
batch_compatible: true # バッチ処理可能
gpu_accelerated: true # GPU加速対応
# バッチ描画(最適化版)
- name: fillRectBatch
params:
- {string: canvas_id}
- {array_of_rect: rects, element_type: "CanvasRect"}
returns: void
effect: io
optimization_hints:
prefer_over: ["fillRect"] # 複数fillRectの代替
min_batch_size: 3
# テキスト描画
- name: fillText
params:
- {string: canvas_id}
- {string: text}
- {i32: x}
- {i32: y}
- {string: font}
- {string: color}
returns: void
effect: io
# カスタム型定義
custom_types:
- name: CanvasRect
fields:
- {i32: x}
- {i32: y}
- {i32: width}
- {i32: height}
- {string: color}
```
#### **BID読み込み・検証システム**
```rust
// 新ファイル: src/bid/mod.rs
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BidDefinition {
pub version: u32,
pub metadata: BidMetadata,
pub interfaces: Vec<BidInterface>,
pub custom_types: Option<Vec<BidCustomType>>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BidMetadata {
pub name: String,
pub description: String,
pub target_environments: Vec<String>,
pub nyash_namespace: String, // using文で使用する名前空間名
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BidInterface {
pub name: String, // "canvas_api.canvas"
pub box_name: String, // "Canvas"
pub methods: Vec<BidMethod>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BidMethod {
pub name: String,
pub params: Vec<BidParam>,
pub returns: BidType,
pub effect: BidEffect,
pub optimization_hints: Option<BidOptimizationHints>,
pub description: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BidOptimizationHints {
pub batch_compatible: Option<bool>,
pub gpu_accelerated: Option<bool>,
pub prefer_over: Option<Vec<String>>,
pub min_batch_size: Option<usize>,
}
impl BidDefinition {
pub fn load_from_file(path: &Path) -> Result<Self, BidError> {
let content = std::fs::read_to_string(path)?;
let bid: BidDefinition = serde_yaml::from_str(&content)?;
// バリデーション
bid.validate()?;
Ok(bid)
}
pub fn validate(&self) -> Result<(), BidError> {
// バージョン確認
if self.version > 1 {
return Err(BidError::UnsupportedVersion(self.version));
}
// 名前空間重複チェック
let mut interface_names = HashSet::new();
for interface in &self.interfaces {
if interface_names.contains(&interface.name) {
return Err(BidError::DuplicateInterface(interface.name.clone()));
}
interface_names.insert(interface.name.clone());
}
// パラメータ型確認
for interface in &self.interfaces {
for method in &interface.methods {
for param in &method.params {
self.validate_type(&param.param_type)?;
}
self.validate_type(&method.returns)?;
}
}
Ok(())
}
pub fn resolve_method(&self, box_name: &str, method_name: &str)
-> Option<&BidMethod> {
for interface in &self.interfaces {
// インターフェース名から最後の部分を取得
// "canvas_api.canvas" → "canvas"
let interface_box_name = interface.name.split('.').last().unwrap_or(&interface.name);
if interface_box_name == box_name {
for method in &interface.methods {
if method.name == method_name {
return Some(method);
}
}
}
}
None
}
}
```
### 2. 統合名前空間レジストリ詳細
#### **UniversalNamespaceRegistry実装**
```rust
// src/registry/universal.rs
use crate::stdlib::BuiltinStdlib;
use crate::bid::BidDefinition;
use crate::module::ExternalModule;
use crate::mir::Effect;
pub struct UniversalNamespaceRegistry {
/// 組み込み標準ライブラリ
builtin_stdlib: Arc<BuiltinStdlib>,
/// FFI-ABI定義BID
bid_definitions: HashMap<String, Arc<BidDefinition>>,
/// Nyashモジュール従来
nyash_modules: HashMap<String, Arc<ExternalModule>>,
/// ファイル別usingコンテキスト
using_contexts: Arc<RwLock<HashMap<String, UsingContext>>>,
/// 最適化情報キャッシュ
optimization_cache: Arc<RwLock<OptimizationCache>>,
}
#[derive(Debug, Clone)]
pub struct UsingContext {
pub file_id: String,
pub builtin_namespaces: Vec<String>, // ["nyashstd"]
pub bid_namespaces: Vec<String>, // ["canvas_api", "console_api"]
pub module_namespaces: Vec<String>, // ["mylib", "utils"]
}
impl UniversalNamespaceRegistry {
pub fn new() -> Self {
UniversalNamespaceRegistry {
builtin_stdlib: Arc::new(BuiltinStdlib::new()),
bid_definitions: HashMap::new(),
nyash_modules: HashMap::new(),
using_contexts: Arc::new(RwLock::new(HashMap::new())),
optimization_cache: Arc::new(RwLock::new(OptimizationCache::new())),
}
}
pub fn load_from_nyash_link(&mut self, nyash_link: &NyashLink)
-> Result<(), RegistryError> {
// BID依存関係読み込み
for (namespace_name, dependency) in &nyash_link.dependencies {
match dependency {
Dependency::Bid { bid_path, .. } => {
let bid = BidDefinition::load_from_file(Path::new(bid_path))?;
self.bid_definitions.insert(namespace_name.clone(), Arc::new(bid));
},
Dependency::Path { path } => {
let module = ExternalModule::load_from_file(Path::new(path))?;
self.nyash_modules.insert(namespace_name.clone(), Arc::new(module));
},
Dependency::Builtin { .. } => {
// 組み込みライブラリは既に初期化済み
},
}
}
Ok(())
}
/// 統合using処理
pub fn process_using(&mut self, namespace_name: &str, file_id: &str)
-> Result<(), RuntimeError> {
let mut contexts = self.using_contexts.write().unwrap();
let context = contexts.entry(file_id.to_string()).or_insert_with(|| {
UsingContext {
file_id: file_id.to_string(),
builtin_namespaces: Vec::new(),
bid_namespaces: Vec::new(),
module_namespaces: Vec::new(),
}
});
// 組み込み標準ライブラリチェック
if self.builtin_stdlib.has_namespace(namespace_name) {
if !context.builtin_namespaces.contains(&namespace_name.to_string()) {
context.builtin_namespaces.push(namespace_name.to_string());
}
return Ok(());
}
// BID定義チェック
if let Some(bid) = self.bid_definitions.get(namespace_name) {
if !context.bid_namespaces.contains(&namespace_name.to_string()) {
context.bid_namespaces.push(namespace_name.to_string());
}
return Ok(());
}
// Nyashモジュールチェック
if let Some(_module) = self.nyash_modules.get(namespace_name) {
if !context.module_namespaces.contains(&namespace_name.to_string()) {
context.module_namespaces.push(namespace_name.to_string());
}
return Ok(());
}
Err(RuntimeError::UndefinedNamespace(namespace_name.to_string()))
}
/// 統合関数解決
pub fn resolve_call(&self, file_id: &str, call_path: &[String])
-> Result<ResolvedCall, RuntimeError> {
if call_path.len() != 2 {
return Err(RuntimeError::InvalidCallPath(call_path.join(".")));
}
let box_name = &call_path[0];
let method_name = &call_path[1];
let contexts = self.using_contexts.read().unwrap();
if let Some(context) = contexts.get(file_id) {
// 1. 組み込み標準ライブラリ解決
for namespace in &context.builtin_namespaces {
if let Some(method) = self.builtin_stdlib.resolve_method(namespace, box_name, method_name) {
return Ok(ResolvedCall::Builtin {
namespace: namespace.clone(),
box_name: box_name.clone(),
method_name: method_name.clone(),
method_info: method,
});
}
}
// 2. BID定義解決
for namespace in &context.bid_namespaces {
if let Some(bid) = self.bid_definitions.get(namespace) {
if let Some(method) = bid.resolve_method(box_name, method_name) {
return Ok(ResolvedCall::BidCall {
namespace: namespace.clone(),
interface_name: format!("{}.{}", namespace, box_name),
method_name: method_name.clone(),
method_info: method.clone(),
bid_definition: bid.clone(),
});
}
}
}
// 3. Nyashモジュール解決
for namespace in &context.module_namespaces {
if let Some(module) = self.nyash_modules.get(namespace) {
if let Some(function) = module.resolve_function(box_name, method_name) {
return Ok(ResolvedCall::ModuleCall {
namespace: namespace.clone(),
module_name: namespace.clone(),
function_name: format!("{}.{}", box_name, method_name),
function_info: function,
});
}
}
}
}
Err(RuntimeError::UndefinedMethod(format!("{}.{}", box_name, method_name)))
}
}
#[derive(Debug, Clone)]
pub enum ResolvedCall {
Builtin {
namespace: String,
box_name: String,
method_name: String,
method_info: BuiltinMethodInfo,
},
BidCall {
namespace: String,
interface_name: String,
method_name: String,
method_info: BidMethod,
bid_definition: Arc<BidDefinition>,
},
ModuleCall {
namespace: String,
module_name: String,
function_name: String,
function_info: ModuleFunctionInfo,
},
}
```
### 3. MIR生成統合
#### **統合MIR Builder**
```rust
// src/mir/builder.rs拡張
impl MirBuilder {
pub fn build_unified_method_call(&mut self, resolved_call: ResolvedCall, args: Vec<ValueId>)
-> Result<Option<ValueId>, MirError> {
match resolved_call {
ResolvedCall::Builtin { method_info, .. } => {
let result = self.new_value_id();
self.emit(MirInstruction::BuiltinCall {
qualified_name: method_info.qualified_name(),
args,
result,
effect: method_info.effect(),
});
Ok(Some(result))
},
ResolvedCall::BidCall { interface_name, method_name, method_info, .. } => {
let result = if method_info.returns == BidType::Void {
None
} else {
Some(self.new_value_id())
};
self.emit(MirInstruction::ExternCall {
interface: interface_name,
method: method_name,
args,
result,
effect: self.bid_effect_to_mir_effect(&method_info.effect),
bid_signature: BidSignature::from_method(&method_info),
});
Ok(result)
},
ResolvedCall::ModuleCall { module_name, function_name, function_info, .. } => {
let result = self.new_value_id();
self.emit(MirInstruction::ModuleCall {
module: module_name,
function: function_name,
args,
result,
effect: Effect::Io, // Nyashモジュールはデフォルトでio
});
Ok(Some(result))
},
}
}
fn bid_effect_to_mir_effect(&self, bid_effect: &BidEffect) -> Effect {
match bid_effect {
BidEffect::Pure => Effect::Pure,
BidEffect::Mut => Effect::Mut,
BidEffect::Io => Effect::Io,
BidEffect::Control => Effect::Control,
}
}
}
```
### 4. バックエンド統合
#### **WASM生成統合**
```rust
// src/backend/wasm/codegen.rs拡張
impl WasmCodegen {
pub fn generate_unified_call(&mut self, instruction: &MirInstruction)
-> Result<(), WasmError> {
match instruction {
MirInstruction::ExternCall { interface, method, args, bid_signature, .. } => {
// BIDから自動生成されたWASM import名
let wasm_import_name = self.bid_to_wasm_import_name(interface, method);
// 引数の型変換・マーシャリング
let marshalled_args = self.marshal_args_for_wasm(args, &bid_signature.params)?;
// WASM関数呼び出し生成
self.emit_call(&wasm_import_name, &marshalled_args)?;
// 戻り値のアンマーシャリング
if bid_signature.returns != BidType::Void {
self.unmarshal_return_value(&bid_signature.returns)?;
}
Ok(())
},
// 他の命令は既存実装
_ => self.generate_instruction_legacy(instruction),
}
}
fn bid_to_wasm_import_name(&self, interface: &str, method: &str) -> String {
// "canvas_api.canvas" + "fillRect" → "canvas_api_canvas_fillRect"
format!("{}_{}", interface.replace(".", "_"), method)
}
fn marshal_args_for_wasm(&mut self, args: &[ValueId], params: &[BidParam])
-> Result<Vec<WasmValue>, WasmError> {
let mut marshalled = Vec::new();
for (i, param) in params.iter().enumerate() {
let arg_value = self.get_value(args[i])?;
match &param.param_type {
BidType::String => {
// 文字列を (ptr, len) にマーシャル
let (ptr, len) = self.string_to_wasm_memory(&arg_value)?;
marshalled.push(WasmValue::I32(ptr));
marshalled.push(WasmValue::I32(len));
},
BidType::I32 => {
marshalled.push(WasmValue::I32(arg_value.to_i32()?));
},
BidType::F64 => {
marshalled.push(WasmValue::F64(arg_value.to_f64()?));
},
// その他の型...
}
}
Ok(marshalled)
}
}
```
#### **VM実行統合**
```rust
// src/backend/vm.rs拡張
impl VmBackend {
pub fn execute_unified_instruction(&mut self, instruction: &MirInstruction)
-> Result<(), VmError> {
match instruction {
MirInstruction::ExternCall { interface, method, args, bid_signature, .. } => {
// VM環境ではスタブまたはネイティブ呼び出し
let evaluated_args = self.evaluate_args(args)?;
if let Some(native_impl) = self.find_native_implementation(interface, method) {
// ネイティブ実装がある場合ファイルI/O
let result = native_impl.call(evaluated_args, bid_signature)?;
if let Some(result_id) = &instruction.result {
self.set_value(*result_id, result);
}
} else {
// スタブ実装(ログ出力等)
self.execute_stub_call(interface, method, evaluated_args, bid_signature)?;
}
Ok(())
},
// 他の命令は既存実装
_ => self.execute_instruction_legacy(instruction),
}
}
fn find_native_implementation(&self, interface: &str, method: &str)
-> Option<&dyn NativeImplementation> {
// VM環境で利用可能なネイティブ実装を検索
match (interface, method) {
("env.console", "log") => Some(&self.console_impl),
("env.filesystem", "read") => Some(&self.filesystem_impl),
("env.filesystem", "write") => Some(&self.filesystem_impl),
_ => None,
}
}
}
```
## 🧪 統合テスト戦略
### Phase別テスト実装
#### **Phase 0: 基本統合テスト**
```nyash
# test_basic_integration.nyash
using nyashstd
# 組み込み標準ライブラリのみ
assert(string.upper("test") == "TEST")
assert(math.sin(0) == 0)
```
#### **Phase 1: BID統合テスト**
```nyash
# test_bid_integration.nyash
using nyashstd
using console_api
# 組み込み + FFI-ABI
string.upper("hello") # 組み込み
console.log("Testing") # FFI-ABI
```
#### **Phase 2: 完全統合テスト**
```nyash
# test_full_integration.nyash
using nyashstd
using console_api
using mylib
# 3種類すべて
string.upper("test") # 組み込み
console.log("Integration") # FFI-ABI
mylib.process("data") # Nyashモジュール
```
### エラーハンドリングテスト
```nyash
# test_error_handling.nyash
try {
using nonexistent_api
} catch error {
assert(error.type == "UndefinedNamespace")
}
try {
console.nonexistent_method("test")
} catch error {
assert(error.type == "UndefinedMethod")
assert(error.message.contains("Available methods:"))
}
```
## 📊 実装マイルストーン
### ✅ Phase 0完了条件
- [ ] UniversalNamespaceRegistry基盤実装
- [ ] 組み込み標準ライブラリ統合
- [ ] 基本using文処理
- [ ] MIR BuiltinCall生成
### ✅ Phase 1完了条件
- [ ] BID定義読み込み・検証
- [ ] BID→MIR ExternCall統合
- [ ] WASM RuntimeImports自動生成
- [ ] VM スタブ実行
### ✅ Phase 2完了条件
- [ ] Nyashモジュール統合
- [ ] 統合エラーハンドリング
- [ ] 最適化キャッシュ
- [ ] 全バックエンド対応
---
**🎯 この詳細実装により、BIDとusingシステムの完全統合が実現でき、「なんでもAPI計画」の技術基盤が完成するにゃ🚀🐱**