feat(phase-9.75g-0): Complete BID-FFI Day 5 - Plugin method calling system

## 🎉 Major Achievement
- BID-FFI FileBox plugin fully functional with Nyash integration
- Complete plugin-backed file I/O operations working
- Successful write/read operations via FFI interface

##  What Works
- Plugin loading from nyash.toml configuration
- FileBox plugin instantiation: `new FileBox(path)`
- Method calls: `f.write("text")`, `f.read()`
- Complete round-trip: Nyash → Plugin → File → Plugin → Nyash

## 🔧 Implementation Details
- Added PluginFileBox method dispatch in execute_method_call()
- Implemented execute_plugin_file_method() for read/write/exists/close
- Fixed "Cannot call method on non-instance type" error
- Plugin methods work via TLV encoding/FFI/decoding

## 🚨 Known Issue (Next Phase)
Current implementation uses hardcoded method names (read/write/exists/close).
This violates BID-FFI dynamic principles - methods should be discovered
from plugin metadata, not hardcoded in Nyash interpreter.

## 📊 Test Results
```
local f
f = new FileBox("test.txt")
f.write("Hello from Nyash via plugin\!")
print("READ=" + f.read())
# Output: READ=Hello from Nyash via plugin\!
```

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-18 11:44:59 +09:00
parent f5ab4910e4
commit 58f92c178d
2 changed files with 75 additions and 0 deletions

View File

@ -255,6 +255,11 @@ impl NyashInterpreter {
return self.execute_file_method(file_box, method, arguments); return self.execute_file_method(file_box, method, arguments);
} }
// PluginFileBox method calls (BID-FFI system)
if let Some(plugin_file_box) = obj_value.as_any().downcast_ref::<crate::bid::plugin_box::PluginFileBox>() {
return self.execute_plugin_file_method(plugin_file_box, method, arguments);
}
// ResultBox method calls // ResultBox method calls
if let Some(result_box) = obj_value.as_any().downcast_ref::<crate::box_trait::ResultBox>() { if let Some(result_box) = obj_value.as_any().downcast_ref::<crate::box_trait::ResultBox>() {
return self.execute_result_method(result_box, method, arguments); return self.execute_result_method(result_box, method, arguments);

View File

@ -10,6 +10,7 @@
use super::super::*; use super::super::*;
use crate::box_trait::{ResultBox, StringBox, NyashBox}; use crate::box_trait::{ResultBox, StringBox, NyashBox};
use crate::boxes::FileBox; use crate::boxes::FileBox;
use crate::bid::plugin_box::PluginFileBox;
impl NyashInterpreter { impl NyashInterpreter {
/// FileBoxのメソッド呼び出しを実行 /// FileBoxのメソッド呼び出しを実行
@ -105,4 +106,73 @@ impl NyashInterpreter {
}) })
} }
} }
/// PluginFileBoxのメソッド呼び出しを実行 (BID-FFI system)
/// Handles plugin-backed file I/O operations via FFI interface
pub(in crate::interpreter) fn execute_plugin_file_method(&mut self, plugin_file_box: &PluginFileBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
match method {
"read" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("read() expects 0 arguments, got {}", arguments.len()),
});
}
// Read the entire file content
match plugin_file_box.read_bytes(8192) { // Read up to 8KB
Ok(bytes) => {
let content = String::from_utf8_lossy(&bytes).to_string();
Ok(Box::new(StringBox::new(content)))
}
Err(e) => Err(RuntimeError::InvalidOperation {
message: format!("Plugin read failed: {:?}", e),
})
}
}
"write" => {
if arguments.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("write() expects 1 argument, got {}", arguments.len()),
});
}
let content = self.execute_expression(&arguments[0])?;
let text = content.to_string_box().value;
match plugin_file_box.write_bytes(text.as_bytes()) {
Ok(bytes_written) => Ok(Box::new(StringBox::new("OK".to_string()))),
Err(e) => Err(RuntimeError::InvalidOperation {
message: format!("Plugin write failed: {:?}", e),
})
}
}
"exists" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("exists() expects 0 arguments, got {}", arguments.len()),
});
}
// Plugin FileBox doesn't have exists() method in current implementation
// Return true if we can read (approximate)
match plugin_file_box.read_bytes(1) {
Ok(_) => Ok(Box::new(crate::box_trait::BoolBox::new(true))),
Err(_) => Ok(Box::new(crate::box_trait::BoolBox::new(false))),
}
}
"close" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("close() expects 0 arguments, got {}", arguments.len()),
});
}
match plugin_file_box.close() {
Ok(()) => Ok(Box::new(StringBox::new("OK".to_string()))),
Err(e) => Err(RuntimeError::InvalidOperation {
message: format!("Plugin close failed: {:?}", e),
})
}
}
_ => Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for PluginFileBox", method),
})
}
}
} }