Phase 12.7文法改革: ドキュメント文法統一 + VMリファクタリング準備
🌟 Phase 12.7文法改革に基づくドキュメント更新 - init {} → field: TypeBox 個別フィールド宣言形式 - init() → birth() コンストラクタ統一 - pack() → 廃止(birth()に統一) - public {}/private {} → 個別フィールド修飾子 - override → 廃止(メソッド定義はシンプルに) 📚 更新したドキュメント - CLAUDE.md: メイン開発ガイド - docs/quick-reference/syntax-cheatsheet.md: 構文早見表 - docs/reference/language/LANGUAGE_REFERENCE_2025.md: 言語リファレンス - docs/development/roadmap/phases/phase-15/README.md: Phase 15計画 🔧 VMリファクタリング準備 - vm_methods.rs: VMメソッド呼び出しの分離 - plugin_loader.rs → plugin_loader/: ディレクトリ構造化 - mir/builder/exprs.rs: 式ビルダー分離 📝 新規ドキュメント追加 - 論文戦略・ロードマップ - Phase 15セルフホスティング準備資料 - Codex Androidセットアップガイド ビルドは正常に通ることを確認済み!🎉 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
171
src/interpreter/plugin_loader/loader.rs
Normal file
171
src/interpreter/plugin_loader/loader.rs
Normal file
@ -0,0 +1,171 @@
|
||||
//! Loader entrypoints for dynamic plugins
|
||||
|
||||
use std::ffi::{CString, c_char, c_void};
|
||||
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
use libloading::{Library, Symbol};
|
||||
|
||||
use crate::box_trait::NyashBox;
|
||||
use crate::interpreter::RuntimeError;
|
||||
|
||||
use super::proxies::{FileBoxProxy, MathBoxProxy, RandomBoxProxy, TimeBoxProxy, DateTimeBoxProxy};
|
||||
use super::types::{PLUGIN_CACHE, LoadedPlugin, PluginInfo};
|
||||
|
||||
/// Public plugin loader API
|
||||
pub struct PluginLoader;
|
||||
|
||||
impl PluginLoader {
|
||||
/// Load File plugin
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn load_file_plugin() -> Result<(), RuntimeError> {
|
||||
let mut cache = PLUGIN_CACHE.write().unwrap();
|
||||
if cache.contains_key("file") { return Ok(()); }
|
||||
let lib_name = if cfg!(target_os = "windows") { "nyash_file.dll" } else if cfg!(target_os = "macos") { "libnyash_file.dylib" } else { "libnyash_file.so" };
|
||||
let possible_paths = vec![
|
||||
format!("./target/release/{}", lib_name),
|
||||
format!("./target/debug/{}", lib_name),
|
||||
format!("./plugins/{}", lib_name),
|
||||
format!("./{}", lib_name),
|
||||
];
|
||||
let lib_path = possible_paths.iter().find(|p| std::path::Path::new(p.as_str()).exists()).cloned()
|
||||
.ok_or_else(|| RuntimeError::InvalidOperation { message: format!("Failed to find file plugin library. Searched paths: {:?}", possible_paths) })?;
|
||||
unsafe {
|
||||
let library = Library::new(&lib_path).map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to load file plugin: {}", e) })?;
|
||||
let init_fn: Symbol<unsafe extern "C" fn() -> *const c_void> = library.get(b"nyash_plugin_init\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get plugin init: {}", e) })?;
|
||||
let plugin_info_ptr = init_fn();
|
||||
if plugin_info_ptr.is_null() { return Err(RuntimeError::InvalidOperation { message: "Plugin initialization failed".to_string() }); }
|
||||
let info = PluginInfo { name: "file".to_string(), version: 1, api_version: 1 };
|
||||
cache.insert("file".to_string(), LoadedPlugin { library, info });
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create FileBox
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn create_file_box(path: &str) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
Self::load_file_plugin()?;
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("file") {
|
||||
let c_path = CString::new(path).map_err(|_| RuntimeError::InvalidOperation { message: "Invalid path string".to_string() })?;
|
||||
unsafe {
|
||||
let open_fn: Symbol<unsafe extern "C" fn(*const c_char) -> *mut c_void> = plugin.library.get(b"nyash_file_open\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_file_open: {}", e) })?;
|
||||
let handle = open_fn(c_path.as_ptr());
|
||||
if handle.is_null() { return Err(RuntimeError::InvalidOperation { message: format!("Failed to open file: {}", path) }); }
|
||||
Ok(Box::new(FileBoxProxy::new(handle, path.to_string())))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "File plugin not loaded".to_string() }) }
|
||||
}
|
||||
|
||||
/// Check FileBox existence
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn file_exists(path: &str) -> Result<bool, RuntimeError> {
|
||||
Self::load_file_plugin()?;
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("file") {
|
||||
let c_path = CString::new(path).map_err(|_| RuntimeError::InvalidOperation { message: "Invalid path string".to_string() })?;
|
||||
unsafe {
|
||||
let exists_fn: Symbol<unsafe extern "C" fn(*const c_char) -> i32> = plugin.library.get(b"nyash_file_exists\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_file_exists: {}", e) })?;
|
||||
Ok(exists_fn(c_path.as_ptr()) != 0)
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "File plugin not loaded".to_string() }) }
|
||||
}
|
||||
|
||||
/// Load Math plugin
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn load_math_plugin() -> Result<(), RuntimeError> {
|
||||
let mut cache = PLUGIN_CACHE.write().unwrap();
|
||||
if cache.contains_key("math") { return Ok(()); }
|
||||
let lib_name = if cfg!(target_os = "windows") { "nyash_math.dll" } else if cfg!(target_os = "macos") { "libnyash_math.dylib" } else { "libnyash_math.so" };
|
||||
let possible_paths = vec![
|
||||
format!("./target/release/{}", lib_name),
|
||||
format!("./target/debug/{}", lib_name),
|
||||
format!("./plugins/{}", lib_name),
|
||||
format!("./{}", lib_name),
|
||||
];
|
||||
let lib_path = possible_paths.iter().find(|p| std::path::Path::new(p.as_str()).exists()).cloned()
|
||||
.ok_or_else(|| RuntimeError::InvalidOperation { message: format!("Failed to find math plugin library. Searched paths: {:?}", possible_paths) })?;
|
||||
unsafe {
|
||||
let library = Library::new(&lib_path).map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to load math plugin: {}", e) })?;
|
||||
let info = PluginInfo { name: "math".to_string(), version: 1, api_version: 1 };
|
||||
cache.insert("math".to_string(), LoadedPlugin { library, info });
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create MathBox
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn create_math_box() -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
Self::load_math_plugin()?;
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
let create_fn: Symbol<unsafe extern "C" fn() -> *mut c_void> = plugin.library.get(b"nyash_math_create\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_math_create: {}", e) })?;
|
||||
let handle = create_fn();
|
||||
if handle.is_null() { return Err(RuntimeError::InvalidOperation { message: "Failed to create MathBox".to_string() }); }
|
||||
Ok(Box::new(MathBoxProxy::new(handle)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "Math plugin not loaded".to_string() }) }
|
||||
}
|
||||
|
||||
/// Create RandomBox
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn create_random_box() -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
Self::load_math_plugin()?;
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
let create_fn: Symbol<unsafe extern "C" fn() -> *mut c_void> = plugin.library.get(b"nyash_random_create\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_random_create: {}", e) })?;
|
||||
let handle = create_fn();
|
||||
if handle.is_null() { return Err(RuntimeError::InvalidOperation { message: "Failed to create RandomBox".to_string() }); }
|
||||
Ok(Box::new(RandomBoxProxy::new(handle)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "Math plugin not loaded".to_string() }) }
|
||||
}
|
||||
|
||||
/// Create TimeBox
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn create_time_box() -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
Self::load_math_plugin()?;
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
let create_fn: Symbol<unsafe extern "C" fn() -> *mut c_void> = plugin.library.get(b"nyash_time_create\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_time_create: {}", e) })?;
|
||||
let handle = create_fn();
|
||||
if handle.is_null() { return Err(RuntimeError::InvalidOperation { message: "Failed to create TimeBox".to_string() }); }
|
||||
Ok(Box::new(TimeBoxProxy::new(handle)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "Math plugin not loaded".to_string() }) }
|
||||
}
|
||||
|
||||
/// Create DateTimeBox (now)
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn create_datetime_now() -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
Self::load_math_plugin()?;
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
let now_fn: Symbol<unsafe extern "C" fn() -> *mut c_void> = plugin.library.get(b"nyash_time_now\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_time_now: {}", e) })?;
|
||||
let handle = now_fn();
|
||||
if handle.is_null() { return Err(RuntimeError::InvalidOperation { message: "Failed to create DateTimeBox".to_string() }); }
|
||||
Ok(Box::new(DateTimeBoxProxy::new(handle)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "Math plugin not loaded".to_string() }) }
|
||||
}
|
||||
|
||||
/// Create DateTimeBox from string
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub fn create_datetime_from_string(time_str: &str) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
Self::load_math_plugin()?;
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
let c_str = CString::new(time_str).map_err(|_| RuntimeError::InvalidOperation { message: "Invalid time string".to_string() })?;
|
||||
unsafe {
|
||||
let parse_fn: Symbol<unsafe extern "C" fn(*const c_char) -> *mut c_void> = plugin.library.get(b"nyash_time_parse\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_time_parse: {}", e) })?;
|
||||
let handle = parse_fn(c_str.as_ptr());
|
||||
if handle.is_null() { return Err(RuntimeError::InvalidOperation { message: format!("Failed to parse time string: {}", time_str) }); }
|
||||
Ok(Box::new(DateTimeBoxProxy::new(handle)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "Math plugin not loaded".to_string() }) }
|
||||
}
|
||||
}
|
||||
|
||||
23
src/interpreter/plugin_loader/mod.rs
Normal file
23
src/interpreter/plugin_loader/mod.rs
Normal file
@ -0,0 +1,23 @@
|
||||
//! Dynamic Plugin Loader for Nyash (split module)
|
||||
//!
|
||||
//! Refactored into smaller files to improve readability while preserving
|
||||
//! the original public API surface used across the interpreter:
|
||||
//! - types.rs: globals and native handles
|
||||
//! - proxies.rs: Box proxy implementations
|
||||
//! - loader.rs: public loader entrypoints
|
||||
|
||||
mod types;
|
||||
mod proxies;
|
||||
mod loader;
|
||||
|
||||
// Re-export to preserve original paths like
|
||||
// crate::interpreter::plugin_loader::{PluginLoader, FileBoxProxy, ..., PLUGIN_CACHE}
|
||||
pub use loader::PluginLoader;
|
||||
pub use proxies::{
|
||||
FileBoxProxy, MathBoxProxy, RandomBoxProxy, TimeBoxProxy, DateTimeBoxProxy,
|
||||
};
|
||||
pub use types::{
|
||||
PLUGIN_CACHE, LoadedPlugin, PluginInfo, FileBoxHandle, MathBoxHandle,
|
||||
RandomBoxHandle, TimeBoxHandle, DateTimeBoxHandle,
|
||||
};
|
||||
|
||||
274
src/interpreter/plugin_loader/proxies.rs
Normal file
274
src/interpreter/plugin_loader/proxies.rs
Normal file
@ -0,0 +1,274 @@
|
||||
//! Proxies for dynamic plugins (File/Math/Random/Time/DateTime)
|
||||
|
||||
use std::ffi::{CStr, CString, c_char, c_void};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
use libloading::Symbol;
|
||||
|
||||
use crate::box_trait::{NyashBox, StringBox, BoolBox, BoxCore, BoxBase, IntegerBox};
|
||||
use crate::boxes::FloatBox;
|
||||
use crate::interpreter::RuntimeError;
|
||||
|
||||
use super::types::{PLUGIN_CACHE, FileBoxHandle, MathBoxHandle, RandomBoxHandle, TimeBoxHandle, DateTimeBoxHandle};
|
||||
use super::PluginLoader;
|
||||
|
||||
// ================== FileBoxProxy ==================
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileBoxProxy {
|
||||
pub(crate) handle: Arc<FileBoxHandle>,
|
||||
pub(crate) path: String,
|
||||
pub(crate) base: BoxBase,
|
||||
}
|
||||
|
||||
unsafe impl Send for FileBoxProxy {}
|
||||
unsafe impl Sync for FileBoxProxy {}
|
||||
|
||||
impl FileBoxProxy {
|
||||
pub fn new(handle: *mut c_void, path: String) -> Self {
|
||||
FileBoxProxy { handle: Arc::new(FileBoxHandle { ptr: handle }), path, base: BoxBase::new() }
|
||||
}
|
||||
|
||||
pub fn read(&self) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("file") {
|
||||
unsafe {
|
||||
let read_fn: Symbol<unsafe extern "C" fn(*mut c_void) -> *mut c_char> =
|
||||
plugin.library.get(b"nyash_file_read\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_file_read: {}", e) })?;
|
||||
let result_ptr = read_fn(self.handle.ptr);
|
||||
if result_ptr.is_null() { return Err(RuntimeError::InvalidOperation { message: "Failed to read file".to_string() }); }
|
||||
let content = CStr::from_ptr(result_ptr).to_string_lossy().into_owned();
|
||||
let free_fn: Symbol<unsafe extern "C" fn(*mut c_char)> =
|
||||
plugin.library.get(b"nyash_string_free\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_string_free: {}", e) })?;
|
||||
free_fn(result_ptr);
|
||||
Ok(Box::new(StringBox::new(content)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "File plugin not loaded".to_string() }) }
|
||||
}
|
||||
#[cfg(not(feature = "dynamic-file"))]
|
||||
{ Err(RuntimeError::InvalidOperation { message: "Dynamic file support not enabled".to_string() }) }
|
||||
}
|
||||
|
||||
pub fn write(&self, content: Box<dyn NyashBox>) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("file") {
|
||||
let content_str = content.to_string_box().value;
|
||||
let c_content = CString::new(content_str).map_err(|_| RuntimeError::InvalidOperation { message: "Invalid content string".to_string() })?;
|
||||
unsafe {
|
||||
let write_fn: Symbol<unsafe extern "C" fn(*mut c_void, *const c_char) -> i32> =
|
||||
plugin.library.get(b"nyash_file_write\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_file_write: {}", e) })?;
|
||||
let result = write_fn(self.handle.ptr, c_content.as_ptr());
|
||||
if result == 0 { return Err(RuntimeError::InvalidOperation { message: "Failed to write file".to_string() }); }
|
||||
Ok(Box::new(StringBox::new("ok")))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "File plugin not loaded".to_string() }) }
|
||||
}
|
||||
#[cfg(not(feature = "dynamic-file"))]
|
||||
{ Err(RuntimeError::InvalidOperation { message: "Dynamic file support not enabled".to_string() }) }
|
||||
}
|
||||
|
||||
pub fn exists(&self) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
Ok(Box::new(BoolBox::new(std::path::Path::new(&self.path).exists())))
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxCore for FileBoxProxy {
|
||||
fn box_id(&self) -> u64 { self.base.id }
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> { self.base.parent_type_id }
|
||||
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "FileBox({})", self.path) }
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
|
||||
}
|
||||
|
||||
impl NyashBox for FileBoxProxy {
|
||||
fn type_name(&self) -> &'static str { "FileBox" }
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> { match PluginLoader::create_file_box(&self.path) { Ok(b) => b, Err(_) => Box::new(FileBoxProxy::new(self.handle.ptr, self.path.clone())) } }
|
||||
fn share_box(&self) -> Box<dyn NyashBox> { self.clone_box() }
|
||||
fn to_string_box(&self) -> StringBox { StringBox::new(format!("FileBox({})", self.path)) }
|
||||
fn equals(&self, other: &dyn NyashBox) -> BoolBox { other.as_any().downcast_ref::<FileBoxProxy>().is_some().into() }
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FileBoxProxy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } }
|
||||
|
||||
// ================== MathBoxProxy ==================
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MathBoxProxy { pub(crate) handle: Arc<MathBoxHandle>, pub(crate) base: BoxBase }
|
||||
|
||||
unsafe impl Send for MathBoxProxy {}
|
||||
unsafe impl Sync for MathBoxProxy {}
|
||||
|
||||
impl MathBoxProxy { pub fn new(handle: *mut c_void) -> Self { MathBoxProxy { handle: Arc::new(MathBoxHandle { ptr: handle }), base: BoxBase::new() } } }
|
||||
|
||||
impl BoxCore for MathBoxProxy {
|
||||
fn box_id(&self) -> u64 { self.base.id }
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> { None }
|
||||
fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "MathBox") }
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
|
||||
}
|
||||
|
||||
impl NyashBox for MathBoxProxy {
|
||||
fn type_name(&self) -> &'static str { "MathBox" }
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> { match PluginLoader::create_math_box() { Ok(new_box) => new_box, Err(_) => Box::new(MathBoxProxy { handle: Arc::clone(&self.handle), base: BoxBase::new() }) } }
|
||||
fn share_box(&self) -> Box<dyn NyashBox> { self.clone_box() }
|
||||
fn to_string_box(&self) -> StringBox { StringBox::new("MathBox") }
|
||||
fn equals(&self, other: &dyn NyashBox) -> BoolBox { other.as_any().downcast_ref::<MathBoxProxy>().is_some().into() }
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MathBoxProxy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } }
|
||||
|
||||
// ================== RandomBoxProxy ==================
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RandomBoxProxy { pub(crate) handle: Arc<RandomBoxHandle>, pub(crate) base: BoxBase }
|
||||
|
||||
unsafe impl Send for RandomBoxProxy {}
|
||||
unsafe impl Sync for RandomBoxProxy {}
|
||||
|
||||
impl RandomBoxProxy { pub fn new(handle: *mut c_void) -> Self { RandomBoxProxy { handle: Arc::new(RandomBoxHandle { ptr: handle }), base: BoxBase::new() } } }
|
||||
|
||||
impl RandomBoxProxy {
|
||||
pub fn next(&self) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
let next_fn: Symbol<unsafe extern "C" fn(*mut c_void) -> f64> = plugin.library.get(b"nyash_random_next\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_random_next: {}", e) })?;
|
||||
let value = next_fn(self.handle.ptr);
|
||||
Ok(Box::new(FloatBox::new(value)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "Math plugin not loaded".to_string() }) }
|
||||
}
|
||||
#[cfg(not(feature = "dynamic-file"))]
|
||||
{ Err(RuntimeError::InvalidOperation { message: "Dynamic loading not enabled".to_string() }) }
|
||||
}
|
||||
pub fn range(&self, min: f64, max: f64) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
let range_fn: Symbol<unsafe extern "C" fn(*mut c_void, f64, f64) -> f64> = plugin.library.get(b"nyash_random_range\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_random_range: {}", e) })?;
|
||||
let value = range_fn(self.handle.ptr, min, max);
|
||||
Ok(Box::new(FloatBox::new(value)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "Math plugin not loaded".to_string() }) }
|
||||
}
|
||||
#[cfg(not(feature = "dynamic-file"))]
|
||||
{ Err(RuntimeError::InvalidOperation { message: "Dynamic loading not enabled".to_string() }) }
|
||||
}
|
||||
pub fn int(&self, min: i64, max: i64) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
let int_fn: Symbol<unsafe extern "C" fn(*mut c_void, i64, i64) -> i64> = plugin.library.get(b"nyash_random_int\0").map_err(|e| RuntimeError::InvalidOperation { message: format!("Failed to get nyash_random_int: {}", e) })?;
|
||||
let value = int_fn(self.handle.ptr, min, max);
|
||||
Ok(Box::new(IntegerBox::new(value)))
|
||||
}
|
||||
} else { Err(RuntimeError::InvalidOperation { message: "Math plugin not loaded".to_string() }) }
|
||||
}
|
||||
#[cfg(not(feature = "dynamic-file"))]
|
||||
{ Err(RuntimeError::InvalidOperation { message: "Dynamic loading not enabled".to_string() }) }
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxCore for RandomBoxProxy {
|
||||
fn box_id(&self) -> u64 { self.base.id }
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> { None }
|
||||
fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "RandomBox") }
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
|
||||
}
|
||||
|
||||
impl NyashBox for RandomBoxProxy {
|
||||
fn type_name(&self) -> &'static str { "RandomBox" }
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> { match PluginLoader::create_random_box() { Ok(new_box) => new_box, Err(_) => Box::new(RandomBoxProxy { handle: Arc::clone(&self.handle), base: BoxBase::new() }) } }
|
||||
fn share_box(&self) -> Box<dyn NyashBox> { self.clone_box() }
|
||||
fn to_string_box(&self) -> StringBox { StringBox::new("RandomBox") }
|
||||
fn equals(&self, other: &dyn NyashBox) -> BoolBox { other.as_any().downcast_ref::<RandomBoxProxy>().is_some().into() }
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RandomBoxProxy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } }
|
||||
|
||||
// ================== TimeBoxProxy ==================
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TimeBoxProxy { pub(crate) handle: Arc<TimeBoxHandle>, pub(crate) base: BoxBase }
|
||||
|
||||
unsafe impl Send for TimeBoxProxy {}
|
||||
unsafe impl Sync for TimeBoxProxy {}
|
||||
|
||||
impl TimeBoxProxy { pub fn new(handle: *mut c_void) -> Self { TimeBoxProxy { handle: Arc::new(TimeBoxHandle { ptr: handle }), base: BoxBase::new() } } }
|
||||
|
||||
impl BoxCore for TimeBoxProxy {
|
||||
fn box_id(&self) -> u64 { self.base.id }
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> { None }
|
||||
fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "TimeBox") }
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
|
||||
}
|
||||
|
||||
impl NyashBox for TimeBoxProxy {
|
||||
fn type_name(&self) -> &'static str { "TimeBox" }
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> { match PluginLoader::create_time_box() { Ok(new_box) => new_box, Err(_) => Box::new(TimeBoxProxy { handle: Arc::clone(&self.handle), base: BoxBase::new() }) } }
|
||||
fn share_box(&self) -> Box<dyn NyashBox> { self.clone_box() }
|
||||
fn to_string_box(&self) -> StringBox { StringBox::new("TimeBox") }
|
||||
fn equals(&self, other: &dyn NyashBox) -> BoolBox { other.as_any().downcast_ref::<TimeBoxProxy>().is_some().into() }
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TimeBoxProxy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } }
|
||||
|
||||
// ================== DateTimeBoxProxy ==================
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DateTimeBoxProxy { pub(crate) handle: Arc<DateTimeBoxHandle>, pub(crate) base: BoxBase }
|
||||
|
||||
unsafe impl Send for DateTimeBoxProxy {}
|
||||
unsafe impl Sync for DateTimeBoxProxy {}
|
||||
|
||||
impl DateTimeBoxProxy { pub fn new(handle: *mut c_void) -> Self { DateTimeBoxProxy { handle: Arc::new(DateTimeBoxHandle { ptr: handle }), base: BoxBase::new() } } }
|
||||
|
||||
impl BoxCore for DateTimeBoxProxy {
|
||||
fn box_id(&self) -> u64 { self.base.id }
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> { None }
|
||||
fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "DateTimeBox") }
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
|
||||
}
|
||||
|
||||
impl NyashBox for DateTimeBoxProxy {
|
||||
fn type_name(&self) -> &'static str { "DateTimeBox" }
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> { match PluginLoader::create_datetime_now() { Ok(new_box) => new_box, Err(_) => Box::new(DateTimeBoxProxy { handle: Arc::clone(&self.handle), base: BoxBase::new() }) } }
|
||||
fn share_box(&self) -> Box<dyn NyashBox> { self.clone_box() }
|
||||
fn to_string_box(&self) -> StringBox { StringBox::new("DateTimeBox") }
|
||||
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
|
||||
if let Some(other_datetime) = other.as_any().downcast_ref::<DateTimeBoxProxy>() {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
if let Ok(timestamp_fn) = plugin.library.get::<Symbol<unsafe extern "C" fn(*mut c_void) -> i64>>(b"nyash_datetime_timestamp\0") {
|
||||
let this_ts = timestamp_fn(self.handle.ptr);
|
||||
let other_ts = timestamp_fn(other_datetime.handle.ptr);
|
||||
return BoolBox::new(this_ts == other_ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BoolBox::new(false)
|
||||
} else { BoolBox::new(false) }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DateTimeBoxProxy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } }
|
||||
|
||||
159
src/interpreter/plugin_loader/types.rs
Normal file
159
src/interpreter/plugin_loader/types.rs
Normal file
@ -0,0 +1,159 @@
|
||||
//! Types and globals for interpreter plugin loader
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::ffi::c_void;
|
||||
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
use libloading::Library;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
/// Global cache for loaded plugins (keyed by simple name like "file" or "math")
|
||||
pub(crate) static ref PLUGIN_CACHE: RwLock<HashMap<String, LoadedPlugin>> = RwLock::new(HashMap::new());
|
||||
}
|
||||
|
||||
/// Loaded plugin handle + basic info
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
pub(crate) struct LoadedPlugin {
|
||||
pub(crate) library: Library,
|
||||
pub(crate) info: PluginInfo,
|
||||
}
|
||||
|
||||
/// Minimal plugin info (simplified)
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct PluginInfo {
|
||||
pub(crate) name: String,
|
||||
pub(crate) version: u32,
|
||||
pub(crate) api_version: u32,
|
||||
}
|
||||
|
||||
/// FileBox native handle wrapper
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FileBoxHandle { pub(crate) ptr: *mut c_void }
|
||||
|
||||
impl Drop for FileBoxHandle {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
if !self.ptr.is_null() {
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("file") {
|
||||
unsafe {
|
||||
use libloading::Symbol;
|
||||
if let Ok(free_fn) = plugin.library.get::<Symbol<unsafe extern "C" fn(*mut c_void)>>(b"nyash_file_free\0") {
|
||||
free_fn(self.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for FileBoxHandle {}
|
||||
unsafe impl Sync for FileBoxHandle {}
|
||||
|
||||
/// MathBox native handle wrapper
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MathBoxHandle { pub(crate) ptr: *mut c_void }
|
||||
|
||||
impl Drop for MathBoxHandle {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
if !self.ptr.is_null() {
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
use libloading::Symbol;
|
||||
if let Ok(free_fn) = plugin.library.get::<Symbol<unsafe extern "C" fn(*mut c_void)>>(b"nyash_math_free\0") {
|
||||
free_fn(self.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for MathBoxHandle {}
|
||||
unsafe impl Sync for MathBoxHandle {}
|
||||
|
||||
/// RandomBox native handle wrapper
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct RandomBoxHandle { pub(crate) ptr: *mut c_void }
|
||||
|
||||
impl Drop for RandomBoxHandle {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
if !self.ptr.is_null() {
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
use libloading::Symbol;
|
||||
if let Ok(free_fn) = plugin.library.get::<Symbol<unsafe extern "C" fn(*mut c_void)>>(b"nyash_random_free\0") {
|
||||
free_fn(self.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for RandomBoxHandle {}
|
||||
unsafe impl Sync for RandomBoxHandle {}
|
||||
|
||||
/// TimeBox native handle wrapper
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TimeBoxHandle { pub(crate) ptr: *mut c_void }
|
||||
|
||||
impl Drop for TimeBoxHandle {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
if !self.ptr.is_null() {
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
use libloading::Symbol;
|
||||
if let Ok(free_fn) = plugin.library.get::<Symbol<unsafe extern "C" fn(*mut c_void)>>(b"nyash_time_free\0") {
|
||||
free_fn(self.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for TimeBoxHandle {}
|
||||
unsafe impl Sync for TimeBoxHandle {}
|
||||
|
||||
/// DateTimeBox native handle wrapper
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DateTimeBoxHandle { pub(crate) ptr: *mut c_void }
|
||||
|
||||
impl Drop for DateTimeBoxHandle {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "dynamic-file")]
|
||||
{
|
||||
if !self.ptr.is_null() {
|
||||
let cache = PLUGIN_CACHE.read().unwrap();
|
||||
if let Some(plugin) = cache.get("math") {
|
||||
unsafe {
|
||||
use libloading::Symbol;
|
||||
if let Ok(free_fn) = plugin.library.get::<Symbol<unsafe extern "C" fn(*mut c_void)>>(b"nyash_datetime_free\0") {
|
||||
free_fn(self.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for DateTimeBoxHandle {}
|
||||
unsafe impl Sync for DateTimeBoxHandle {}
|
||||
|
||||
Reference in New Issue
Block a user