From 3295060dba35440239732ef87b8aa05df9bce63c Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 19 May 2020 19:03:06 +0800 Subject: [PATCH] Unify all functions under CallableFunction type. --- src/engine.rs | 113 +++++++++++++++----------------- src/fn_native.rs | 155 ++++++++++++++++++++++++++------------------ src/fn_register.rs | 26 ++++---- src/lib.rs | 1 - src/module.rs | 86 +++++++++--------------- src/optimize.rs | 8 +-- src/packages/mod.rs | 6 +- src/result.rs | 24 ------- 8 files changed, 199 insertions(+), 220 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index bd28ccf1..85c0c9f4 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -3,7 +3,7 @@ use crate::any::{Dynamic, Union}; use crate::calc_fn_hash; use crate::error::ParseErrorType; -use crate::fn_native::{FnCallArgs, NativeFunctionABI, PrintCallback, ProgressCallback}; +use crate::fn_native::{FnCallArgs, PrintCallback, ProgressCallback}; use crate::module::Module; use crate::optimize::OptimizationLevel; use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage}; @@ -229,15 +229,7 @@ impl FunctionsLib { // Qualifiers (none) + function name + placeholders (one for each parameter). let args_iter = repeat(EMPTY_TYPE_ID()).take(fn_def.params.len()); let hash = calc_fn_hash(empty(), &fn_def.name, args_iter); - - #[cfg(feature = "sync")] - { - (hash, Arc::new(fn_def)) - } - #[cfg(not(feature = "sync"))] - { - (hash, Rc::new(fn_def)) - } + (hash, fn_def.into()) }) .collect(), ) @@ -268,8 +260,7 @@ impl FunctionsLib { match fn_def.as_ref().map(|f| f.access) { None => None, Some(FnAccess::Private) if public_only => None, - Some(FnAccess::Private) => fn_def, - Some(FnAccess::Public) => fn_def, + Some(FnAccess::Private) | Some(FnAccess::Public) => fn_def, } } /// Merge another `FunctionsLib` into this `FunctionsLib`. @@ -659,25 +650,20 @@ impl Engine { .get_fn(hashes.0) .or_else(|| self.packages.get_fn(hashes.0)) { - let mut backup: Dynamic = Default::default(); - - let (updated, restore) = match func.abi() { - // Calling pure function in method-call - NativeFunctionABI::Pure if is_ref && args.len() > 0 => { - // Backup the original value. It'll be consumed because the function - // is pure and doesn't know that the first value is a reference (i.e. `is_ref`) - backup = args[0].clone(); - (false, true) - } - NativeFunctionABI::Pure => (false, false), - NativeFunctionABI::Method => (true, false), + // Calling pure function in method-call? + let backup: Option = if func.is_pure() && is_ref && args.len() > 0 { + // Backup the original value. It'll be consumed because the function + // is pure and doesn't know that the first value is a reference (i.e. `is_ref`) + Some(args[0].clone()) + } else { + None }; // Run external function - let result = match func.call(args) { + let result = match func.get_native_fn()(args) { Ok(r) => { // Restore the backup value for the first argument since it has been consumed! - if restore { + if let Some(backup) = backup { *args[0] = backup; } r @@ -709,7 +695,7 @@ impl Engine { .into(), false, ), - _ => (result, updated), + _ => (result, func.is_method()), }); } @@ -780,14 +766,12 @@ impl Engine { let scope_len = scope.len(); // Put arguments into scope as variables + // Actually consume the arguments instead of cloning them scope.extend( fn_def .params .iter() - .zip( - // Actually consume the arguments instead of cloning them - args.into_iter().map(|v| mem::take(*v)), - ) + .zip(args.iter_mut().map(|v| mem::take(*v))) .map(|(name, value)| { let var_name = unsafe_cast_var_name_to_lifetime(name.as_str(), &mut state); @@ -826,14 +810,12 @@ impl Engine { let mut scope = Scope::new(); // Put arguments into scope as variables + // Actually consume the arguments instead of cloning them scope.extend( fn_def .params .iter() - .zip( - // Actually consume the arguments instead of cloning them - args.into_iter().map(|v| mem::take(*v)), - ) + .zip(args.iter_mut().map(|v| mem::take(*v))) .map(|(name, value)| (name, ScopeEntryType::Normal, value)), ); @@ -1558,32 +1540,43 @@ impl Engine { }; // First search in script-defined functions (can override built-in) - if let Some(fn_def) = module.get_qualified_scripted_fn(*hash_fn_def) { - let args = args.as_mut(); - let (result, state2) = - self.call_script_fn(None, *state, name, fn_def, args, *pos, level)?; - *state = state2; - Ok(result) - } else { - // Then search in Rust functions - self.inc_operations(state, *pos)?; + let func = match module.get_qualified_fn(name, *hash_fn_def) { + Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => { + // Then search in Rust functions + self.inc_operations(state, *pos)?; - // Rust functions are indexed in two steps: - // 1) Calculate a hash in a similar manner to script-defined functions, - // i.e. qualifiers + function name + dummy parameter types (one for each parameter). - // 2) Calculate a second hash with no qualifiers, empty function name, and - // the actual list of parameter `TypeId`'.s - let hash_fn_args = calc_fn_hash(empty(), "", args.iter().map(|a| a.type_id())); - // 3) The final hash is the XOR of the two hashes. - let hash_fn_native = *hash_fn_def ^ hash_fn_args; + // Rust functions are indexed in two steps: + // 1) Calculate a hash in a similar manner to script-defined functions, + // i.e. qualifiers + function name + dummy parameter types (one for each parameter). + // 2) Calculate a second hash with no qualifiers, empty function name, and + // the actual list of parameter `TypeId`'.s + let hash_fn_args = + calc_fn_hash(empty(), "", args.iter().map(|a| a.type_id())); + // 3) The final hash is the XOR of the two hashes. + let hash_fn_native = *hash_fn_def ^ hash_fn_args; - match module.get_qualified_fn(name, hash_fn_native) { - Ok(func) => func - .call(args.as_mut()) - .map_err(|err| err.new_position(*pos)), - Err(_) if def_val.is_some() => Ok(def_val.clone().unwrap()), - Err(err) => Err(err), + module.get_qualified_fn(name, hash_fn_native) } + r => r, + }; + + match func { + Ok(x) if x.is_script() => { + let args = args.as_mut(); + let fn_def = x.get_fn_def(); + let (result, state2) = + self.call_script_fn(None, *state, name, fn_def, args, *pos, level)?; + *state = state2; + Ok(result) + } + Ok(x) => x.get_native_fn()(args.as_mut()).map_err(|err| err.new_position(*pos)), + Err(err) + if def_val.is_some() + && matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => + { + Ok(def_val.clone().unwrap()) + } + Err(err) => Err(err), } } @@ -1733,7 +1726,7 @@ impl Engine { let iter_type = self.eval_expr(scope, state, expr, level)?; let tid = iter_type.type_id(); - if let Some(iter_fn) = self + if let Some(func) = self .global_module .get_iter(tid) .or_else(|| self.packages.get_iter(tid)) @@ -1744,7 +1737,7 @@ impl Engine { let index = scope.len() - 1; state.scope_level += 1; - for loop_var in iter_fn(iter_type) { + for loop_var in func.get_iter_fn()(iter_type) { *scope.get_mut(index).0 = loop_var; self.inc_operations(state, stmt.position())?; diff --git a/src/fn_native.rs b/src/fn_native.rs index ccc458d3..328372b9 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -1,4 +1,5 @@ use crate::any::Dynamic; +use crate::parser::{FnDef, SharedFnDef}; use crate::result::EvalAltResult; use crate::stdlib::{boxed::Box, rc::Rc, sync::Arc}; @@ -72,70 +73,98 @@ pub trait IteratorCallback: Fn(Dynamic) -> Box> + ' #[cfg(not(feature = "sync"))] impl Box> + 'static> IteratorCallback for F {} -/// A type representing the type of ABI of a native Rust function. -#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)] -pub enum NativeFunctionABI { - /// A pure function where all arguments are passed by value. - Pure, - /// An object method where the first argument is the object passed by mutable reference. - /// All other arguments are passed by value. - Method, +/// A type encapsulating a function callable by Rhai. +pub enum CallableFunction { + /// A pure native Rust function with all arguments passed by value. + Pure(Box), + /// A native Rust object method with the first argument passed by reference, + /// and the rest passed by value. + Method(Box), + /// An iterator function. + Iterator(Box), + /// A script-defined function. + Script(SharedFnDef), } -/* -/// Trait implemented by all native Rust functions that are callable by Rhai. +impl CallableFunction { + /// Is this a pure native Rust function? + pub fn is_pure(&self) -> bool { + match self { + CallableFunction::Pure(_) => true, + CallableFunction::Method(_) + | CallableFunction::Iterator(_) + | CallableFunction::Script(_) => false, + } + } + /// Is this a pure native Rust method-call? + pub fn is_method(&self) -> bool { + match self { + CallableFunction::Method(_) => true, + CallableFunction::Pure(_) + | CallableFunction::Iterator(_) + | CallableFunction::Script(_) => false, + } + } + /// Is this an iterator function? + pub fn is_iter(&self) -> bool { + match self { + CallableFunction::Iterator(_) => true, + CallableFunction::Pure(_) + | CallableFunction::Method(_) + | CallableFunction::Script(_) => false, + } + } + /// Is this a Rhai-scripted function? + pub fn is_script(&self) -> bool { + match self { + CallableFunction::Script(_) => true, + CallableFunction::Pure(_) + | CallableFunction::Method(_) + | CallableFunction::Iterator(_) => false, + } + } + /// Get a reference to a native Rust function. + /// + /// # Panics + /// + /// Panics if the `CallableFunction` is not `Pure` or `Method`. + pub fn get_native_fn(&self) -> &Box { + match self { + CallableFunction::Pure(f) | CallableFunction::Method(f) => f, + CallableFunction::Iterator(_) | CallableFunction::Script(_) => panic!(), + } + } + /// Get a reference to a script-defined function definition. + /// + /// # Panics + /// + /// Panics if the `CallableFunction` is not `Script`. + pub fn get_fn_def(&self) -> &FnDef { + match self { + CallableFunction::Pure(_) + | CallableFunction::Method(_) + | CallableFunction::Iterator(_) => panic!(), + CallableFunction::Script(f) => f, + } + } + /// Get a reference to an iterator function. + /// + /// # Panics + /// + /// Panics if the `CallableFunction` is not `Iterator`. + pub fn get_iter_fn(&self) -> &Box { + match self { + CallableFunction::Pure(_) + | CallableFunction::Method(_) + | CallableFunction::Script(_) => panic!(), + CallableFunction::Iterator(f) => f, + } + } +} + +/// A callable function. #[cfg(not(feature = "sync"))] -pub trait NativeCallable { - /// Get the ABI type of a native Rust function. - fn abi(&self) -> NativeFunctionABI; - /// Call a native Rust function. - fn call(&self, args: &mut FnCallArgs) -> Result>; -} - -/// Trait implemented by all native Rust functions that are callable by Rhai. +pub type SharedFunction = Rc; +/// A callable function. #[cfg(feature = "sync")] -pub trait NativeCallable: Send + Sync { - /// Get the ABI type of a native Rust function. - fn abi(&self) -> NativeFunctionABI; - /// Call a native Rust function. - fn call(&self, args: &mut FnCallArgs) -> Result>; -} -*/ - -/// A type encapsulating a native Rust function callable by Rhai. -pub struct NativeFunction(Box, NativeFunctionABI); - -impl NativeFunction { - pub fn abi(&self) -> NativeFunctionABI { - self.1 - } - pub fn call(&self, args: &mut FnCallArgs) -> Result> { - (self.0)(args) - } -} - -impl From<(Box, NativeFunctionABI)> for NativeFunction { - fn from(func: (Box, NativeFunctionABI)) -> Self { - Self::new(func.0, func.1) - } -} -impl NativeFunction { - /// Create a new `NativeFunction`. - pub fn new(func: Box, abi: NativeFunctionABI) -> Self { - Self(func, abi) - } -} - -/// An external native Rust function. -#[cfg(not(feature = "sync"))] -pub type SharedNativeFunction = Rc; -/// An external native Rust function. -#[cfg(feature = "sync")] -pub type SharedNativeFunction = Arc; - -/// A type iterator function. -#[cfg(not(feature = "sync"))] -pub type SharedIteratorFunction = Rc>; -/// An external native Rust function. -#[cfg(feature = "sync")] -pub type SharedIteratorFunction = Arc>; +pub type SharedFunction = Arc; diff --git a/src/fn_register.rs b/src/fn_register.rs index 42e81c9b..9636e557 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -4,7 +4,10 @@ use crate::any::{Dynamic, Variant}; use crate::engine::Engine; -use crate::fn_native::{FnCallArgs, NativeFunctionABI::*}; +use crate::fn_native::{ + CallableFunction::{Method, Pure}, + FnCallArgs, +}; use crate::parser::FnAccess; use crate::result::EvalAltResult; @@ -181,9 +184,9 @@ pub fn map_result( macro_rules! def_register { () => { - def_register!(imp Pure;); + def_register!(imp Pure :); }; - (imp $abi:expr ; $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => { + (imp $abi:ident : $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => { // ^ function ABI type // ^ function parameter generic type name (A, B, C etc.) // ^ function parameter marker type (T, Ref or Mut) @@ -202,9 +205,9 @@ macro_rules! def_register { > RegisterFn for Engine { fn register_fn(&mut self, name: &str, f: FN) { - self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public, + self.global_module.set_fn(name.to_string(), FnAccess::Public, &[$(TypeId::of::<$par>()),*], - make_func!(f : map_dynamic ; $($par => $clone),*) + $abi(make_func!(f : map_dynamic ; $($par => $clone),*)) ); } } @@ -220,9 +223,9 @@ macro_rules! def_register { > RegisterDynamicFn for Engine { fn register_dynamic_fn(&mut self, name: &str, f: FN) { - self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public, + self.global_module.set_fn(name.to_string(), FnAccess::Public, &[$(TypeId::of::<$par>()),*], - make_func!(f : map_identity ; $($par => $clone),*) + $abi(make_func!(f : map_identity ; $($par => $clone),*)) ); } } @@ -239,9 +242,9 @@ macro_rules! def_register { > RegisterResultFn for Engine { fn register_result_fn(&mut self, name: &str, f: FN) { - self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public, + self.global_module.set_fn(name.to_string(), FnAccess::Public, &[$(TypeId::of::<$par>()),*], - make_func!(f : map_result ; $($par => $clone),*) + $abi(make_func!(f : map_result ; $($par => $clone),*)) ); } } @@ -249,8 +252,9 @@ macro_rules! def_register { //def_register!(imp_pop $($par => $mark => $param),*); }; ($p0:ident $(, $p:ident)*) => { - def_register!(imp Pure ; $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => by_value)*); - def_register!(imp Method ; $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => by_value)*); + def_register!(imp Pure : $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => by_value)*); + def_register!(imp Method : $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => by_value)*); + // ^ CallableFunction // handle the first parameter ^ first parameter passed through // ^ others passed by value (by_value) diff --git a/src/lib.rs b/src/lib.rs index 2494d71f..b4e71a83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,7 +91,6 @@ mod utils; pub use any::Dynamic; pub use engine::Engine; pub use error::{ParseError, ParseErrorType}; -//pub use fn_native::NativeCallable; pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn}; pub use module::Module; pub use parser::{AST, INT}; diff --git a/src/module.rs b/src/module.rs index f28c87fe..06d0cbbd 100644 --- a/src/module.rs +++ b/src/module.rs @@ -4,10 +4,11 @@ use crate::any::{Dynamic, Variant}; use crate::calc_fn_hash; use crate::engine::{Engine, FunctionsLib}; use crate::fn_native::{ - FnAny, FnCallArgs, IteratorFn, NativeFunction, NativeFunctionABI, NativeFunctionABI::*, - SharedIteratorFunction, SharedNativeFunction, + CallableFunction, + CallableFunction::{Method, Pure}, + FnCallArgs, IteratorFn, SharedFunction, }; -use crate::parser::{FnAccess, FnDef, SharedFnDef, AST}; +use crate::parser::{FnAccess, AST}; use crate::result::EvalAltResult; use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope}; use crate::token::{Position, Token}; @@ -51,19 +52,17 @@ pub struct Module { all_variables: HashMap, /// External Rust functions. - functions: HashMap, SharedNativeFunction)>, - - /// Flattened collection of all external Rust functions, including those in sub-modules. - all_functions: HashMap, + functions: HashMap, SharedFunction)>, /// Script-defined functions. fn_lib: FunctionsLib, - /// Flattened collection of all script-defined functions, including those in sub-modules. - all_fn_lib: FunctionsLib, - /// Iterator functions, keyed by the type producing the iterator. - type_iterators: HashMap, + type_iterators: HashMap, + + /// Flattened collection of all external Rust functions, native or scripted, + /// including those in sub-modules. + all_functions: HashMap, } impl fmt::Debug for Module { @@ -278,23 +277,16 @@ impl Module { pub fn set_fn( &mut self, name: String, - abi: NativeFunctionABI, access: FnAccess, params: &[TypeId], - func: Box, + func: CallableFunction, ) -> u64 { let hash_fn = calc_fn_hash(empty(), &name, params.iter().cloned()); - let f = NativeFunction::from((func, abi)); - - #[cfg(not(feature = "sync"))] - let func = Rc::new(f); - #[cfg(feature = "sync")] - let func = Arc::new(f); - let params = params.into_iter().cloned().collect(); - self.functions.insert(hash_fn, (name, access, params, func)); + self.functions + .insert(hash_fn, (name, access, params, func.into())); hash_fn } @@ -320,7 +312,7 @@ impl Module { ) -> u64 { let f = move |_: &mut FnCallArgs| func().map(Dynamic::from); let arg_types = []; - self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f)) + self.set_fn(name.into(), DEF_ACCESS, &arg_types, Pure(Box::new(f))) } /// Set a Rust function taking one parameter into the module, returning a hash key. @@ -345,7 +337,7 @@ impl Module { let f = move |args: &mut FnCallArgs| func(mem::take(args[0]).cast::()).map(Dynamic::from); let arg_types = [TypeId::of::()]; - self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f)) + self.set_fn(name.into(), DEF_ACCESS, &arg_types, Pure(Box::new(f))) } /// Set a Rust function taking one mutable parameter into the module, returning a hash key. @@ -371,7 +363,7 @@ impl Module { func(args[0].downcast_mut::().unwrap()).map(Dynamic::from) }; let arg_types = [TypeId::of::()]; - self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f)) + self.set_fn(name.into(), DEF_ACCESS, &arg_types, Method(Box::new(f))) } /// Set a Rust function taking two parameters into the module, returning a hash key. @@ -402,7 +394,7 @@ impl Module { func(a, b).map(Dynamic::from) }; let arg_types = [TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f)) + self.set_fn(name.into(), DEF_ACCESS, &arg_types, Pure(Box::new(f))) } /// Set a Rust function taking two parameters (the first one mutable) into the module, @@ -437,7 +429,7 @@ impl Module { func(a, b).map(Dynamic::from) }; let arg_types = [TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f)) + self.set_fn(name.into(), DEF_ACCESS, &arg_types, Method(Box::new(f))) } /// Set a Rust function taking three parameters into the module, returning a hash key. @@ -475,7 +467,7 @@ impl Module { func(a, b, c).map(Dynamic::from) }; let arg_types = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f)) + self.set_fn(name.into(), DEF_ACCESS, &arg_types, Pure(Box::new(f))) } /// Set a Rust function taking three parameters (the first one mutable) into the module, @@ -514,7 +506,7 @@ impl Module { func(a, b, c).map(Dynamic::from) }; let arg_types = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f)) + self.set_fn(name.into(), DEF_ACCESS, &arg_types, Method(Box::new(f))) } /// Get a Rust function. @@ -531,7 +523,7 @@ impl Module { /// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1)); /// assert!(module.get_fn(hash).is_some()); /// ``` - pub fn get_fn(&self, hash_fn: u64) -> Option<&NativeFunction> { + pub fn get_fn(&self, hash_fn: u64) -> Option<&CallableFunction> { self.functions.get(&hash_fn).map(|(_, _, _, v)| v.as_ref()) } @@ -543,7 +535,7 @@ impl Module { &mut self, name: &str, hash_fn_native: u64, - ) -> Result<&NativeFunction, Box> { + ) -> Result<&CallableFunction, Box> { self.all_functions .get(&hash_fn_native) .map(|f| f.as_ref()) @@ -555,13 +547,6 @@ impl Module { }) } - /// Get a modules-qualified script-defined functions. - /// - /// The `u64` hash is calculated by the function `crate::calc_fn_hash`. - pub(crate) fn get_qualified_scripted_fn(&mut self, hash_fn_def: u64) -> Option<&FnDef> { - self.all_fn_lib.get_function(hash_fn_def) - } - /// Create a new `Module` by evaluating an `AST`. /// /// # Examples @@ -620,13 +605,12 @@ impl Module { module: &'a Module, qualifiers: &mut Vec<&'a str>, variables: &mut Vec<(u64, Dynamic)>, - functions: &mut Vec<(u64, SharedNativeFunction)>, - fn_lib: &mut Vec<(u64, SharedFnDef)>, + functions: &mut Vec<(u64, SharedFunction)>, ) { for (name, m) in &module.modules { // Index all the sub-modules first. qualifiers.push(name); - index_module(m, qualifiers, variables, functions, fn_lib); + index_module(m, qualifiers, variables, functions); qualifiers.pop(); } @@ -672,25 +656,17 @@ impl Module { &fn_def.name, repeat(EMPTY_TYPE_ID()).take(fn_def.params.len()), ); - fn_lib.push((hash_fn_def, fn_def.clone())); + functions.push((hash_fn_def, CallableFunction::Script(fn_def.clone()).into())); } } let mut variables = Vec::new(); let mut functions = Vec::new(); - let mut fn_lib = Vec::new(); - index_module( - self, - &mut vec!["root"], - &mut variables, - &mut functions, - &mut fn_lib, - ); + index_module(self, &mut vec!["root"], &mut variables, &mut functions); self.all_variables = variables.into_iter().collect(); self.all_functions = functions.into_iter().collect(); - self.all_fn_lib = fn_lib.into(); } /// Does a type iterator exist in the module? @@ -701,14 +677,16 @@ impl Module { /// Set a type iterator into the module. pub fn set_iter(&mut self, typ: TypeId, func: Box) { #[cfg(not(feature = "sync"))] - self.type_iterators.insert(typ, Rc::new(func)); + self.type_iterators + .insert(typ, Rc::new(CallableFunction::Iterator(func))); #[cfg(feature = "sync")] - self.type_iterators.insert(typ, Arc::new(func)); + self.type_iterators + .insert(typ, Arc::new(CallableFunction::Iterator(func))); } /// Get the specified type iterator. - pub fn get_iter(&self, id: TypeId) -> Option<&SharedIteratorFunction> { - self.type_iterators.get(&id) + pub fn get_iter(&self, id: TypeId) -> Option<&CallableFunction> { + self.type_iterators.get(&id).map(|v| v.as_ref()) } } diff --git a/src/optimize.rs b/src/optimize.rs index 5fc6d608..d320d4bf 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -119,12 +119,12 @@ fn call_fn( pos: Position, ) -> Result, Box> { // Search built-in's and external functions - let hash = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id())); + let hash_fn = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id())); global_module - .get_fn(hash) - .or_else(|| packages.get_fn(hash)) - .map(|func| func.call(args)) + .get_fn(hash_fn) + .or_else(|| packages.get_fn(hash_fn)) + .map(|func| func.get_native_fn()(args)) .transpose() .map_err(|err| err.new_position(pos)) } diff --git a/src/packages/mod.rs b/src/packages/mod.rs index ad61ae19..39ce601c 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -1,6 +1,6 @@ //! Module containing all built-in _packages_ available to Rhai, plus facilities to define custom packages. -use crate::fn_native::{NativeFunction, SharedIteratorFunction}; +use crate::fn_native::CallableFunction; use crate::module::Module; use crate::utils::StaticVec; @@ -69,7 +69,7 @@ impl PackagesCollection { self.packages.iter().any(|p| p.contains_fn(hash)) } /// Get specified function via its hash key. - pub fn get_fn(&self, hash: u64) -> Option<&NativeFunction> { + pub fn get_fn(&self, hash: u64) -> Option<&CallableFunction> { self.packages .iter() .map(|p| p.get_fn(hash)) @@ -81,7 +81,7 @@ impl PackagesCollection { self.packages.iter().any(|p| p.contains_iter(id)) } /// Get the specified TypeId iterator. - pub fn get_iter(&self, id: TypeId) -> Option<&SharedIteratorFunction> { + pub fn get_iter(&self, id: TypeId) -> Option<&CallableFunction> { self.packages .iter() .map(|p| p.get_iter(id)) diff --git a/src/result.rs b/src/result.rs index 4ae0d9e5..af55535a 100644 --- a/src/result.rs +++ b/src/result.rs @@ -36,10 +36,6 @@ pub enum EvalAltResult { /// An error has occurred inside a called function. /// Wrapped values re the name of the function and the interior error. ErrorInFunctionCall(String, Box, Position), - /// Function call has incorrect number of arguments. - /// Wrapped values are the name of the function, the number of parameters required - /// and the actual number of arguments passed. - ErrorFunctionArgsMismatch(String, usize, usize, Position), /// Non-boolean operand encountered for boolean operator. Wrapped value is the operator. ErrorBooleanArgMismatch(String, Position), /// Non-character value encountered where a character is required. @@ -108,9 +104,6 @@ impl EvalAltResult { Self::ErrorParsing(p) => p.desc(), Self::ErrorInFunctionCall(_, _, _) => "Error in called function", Self::ErrorFunctionNotFound(_, _) => "Function not found", - Self::ErrorFunctionArgsMismatch(_, _, _, _) => { - "Function call with wrong number of arguments" - } Self::ErrorBooleanArgMismatch(_, _) => "Boolean operator expects boolean operands", Self::ErrorCharMismatch(_) => "Character expected", Self::ErrorNumericIndexExpr(_) => { @@ -208,21 +201,6 @@ impl fmt::Display for EvalAltResult { Self::ErrorLoopBreak(_, pos) => write!(f, "{} ({})", desc, pos), Self::Return(_, pos) => write!(f, "{} ({})", desc, pos), - Self::ErrorFunctionArgsMismatch(fn_name, 0, n, pos) => write!( - f, - "Function '{}' expects no argument but {} found ({})", - fn_name, n, pos - ), - Self::ErrorFunctionArgsMismatch(fn_name, 1, n, pos) => write!( - f, - "Function '{}' expects one argument but {} found ({})", - fn_name, n, pos - ), - Self::ErrorFunctionArgsMismatch(fn_name, need, n, pos) => write!( - f, - "Function '{}' expects {} argument(s) but {} found ({})", - fn_name, need, n, pos - ), Self::ErrorBooleanArgMismatch(op, pos) => { write!(f, "{} operator expects boolean operands ({})", op, pos) } @@ -292,7 +270,6 @@ impl EvalAltResult { Self::ErrorFunctionNotFound(_, pos) | Self::ErrorInFunctionCall(_, _, pos) - | Self::ErrorFunctionArgsMismatch(_, _, _, pos) | Self::ErrorBooleanArgMismatch(_, pos) | Self::ErrorCharMismatch(pos) | Self::ErrorArrayBounds(_, _, pos) @@ -331,7 +308,6 @@ impl EvalAltResult { Self::ErrorFunctionNotFound(_, pos) | Self::ErrorInFunctionCall(_, _, pos) - | Self::ErrorFunctionArgsMismatch(_, _, _, pos) | Self::ErrorBooleanArgMismatch(_, pos) | Self::ErrorCharMismatch(pos) | Self::ErrorArrayBounds(_, _, pos)