Unify all functions under CallableFunction type.

This commit is contained in:
Stephen Chung 2020-05-19 19:03:06 +08:00
parent a22f338b03
commit 3295060dba
8 changed files with 199 additions and 220 deletions

View File

@ -3,7 +3,7 @@
use crate::any::{Dynamic, Union}; use crate::any::{Dynamic, Union};
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::error::ParseErrorType; 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::module::Module;
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage}; use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage};
@ -229,15 +229,7 @@ impl FunctionsLib {
// Qualifiers (none) + function name + placeholders (one for each parameter). // Qualifiers (none) + function name + placeholders (one for each parameter).
let args_iter = repeat(EMPTY_TYPE_ID()).take(fn_def.params.len()); let args_iter = repeat(EMPTY_TYPE_ID()).take(fn_def.params.len());
let hash = calc_fn_hash(empty(), &fn_def.name, args_iter); let hash = calc_fn_hash(empty(), &fn_def.name, args_iter);
(hash, fn_def.into())
#[cfg(feature = "sync")]
{
(hash, Arc::new(fn_def))
}
#[cfg(not(feature = "sync"))]
{
(hash, Rc::new(fn_def))
}
}) })
.collect(), .collect(),
) )
@ -268,8 +260,7 @@ impl FunctionsLib {
match fn_def.as_ref().map(|f| f.access) { match fn_def.as_ref().map(|f| f.access) {
None => None, None => None,
Some(FnAccess::Private) if public_only => None, Some(FnAccess::Private) if public_only => None,
Some(FnAccess::Private) => fn_def, Some(FnAccess::Private) | Some(FnAccess::Public) => fn_def,
Some(FnAccess::Public) => fn_def,
} }
} }
/// Merge another `FunctionsLib` into this `FunctionsLib`. /// Merge another `FunctionsLib` into this `FunctionsLib`.
@ -659,25 +650,20 @@ impl Engine {
.get_fn(hashes.0) .get_fn(hashes.0)
.or_else(|| self.packages.get_fn(hashes.0)) .or_else(|| self.packages.get_fn(hashes.0))
{ {
let mut backup: Dynamic = Default::default(); // Calling pure function in method-call?
let backup: Option<Dynamic> = if func.is_pure() && is_ref && args.len() > 0 {
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 // 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`) // is pure and doesn't know that the first value is a reference (i.e. `is_ref`)
backup = args[0].clone(); Some(args[0].clone())
(false, true) } else {
} None
NativeFunctionABI::Pure => (false, false),
NativeFunctionABI::Method => (true, false),
}; };
// Run external function // Run external function
let result = match func.call(args) { let result = match func.get_native_fn()(args) {
Ok(r) => { Ok(r) => {
// Restore the backup value for the first argument since it has been consumed! // Restore the backup value for the first argument since it has been consumed!
if restore { if let Some(backup) = backup {
*args[0] = backup; *args[0] = backup;
} }
r r
@ -709,7 +695,7 @@ impl Engine {
.into(), .into(),
false, false,
), ),
_ => (result, updated), _ => (result, func.is_method()),
}); });
} }
@ -780,14 +766,12 @@ impl Engine {
let scope_len = scope.len(); let scope_len = scope.len();
// Put arguments into scope as variables // Put arguments into scope as variables
// Actually consume the arguments instead of cloning them
scope.extend( scope.extend(
fn_def fn_def
.params .params
.iter() .iter()
.zip( .zip(args.iter_mut().map(|v| mem::take(*v)))
// Actually consume the arguments instead of cloning them
args.into_iter().map(|v| mem::take(*v)),
)
.map(|(name, value)| { .map(|(name, value)| {
let var_name = let var_name =
unsafe_cast_var_name_to_lifetime(name.as_str(), &mut state); unsafe_cast_var_name_to_lifetime(name.as_str(), &mut state);
@ -826,14 +810,12 @@ impl Engine {
let mut scope = Scope::new(); let mut scope = Scope::new();
// Put arguments into scope as variables // Put arguments into scope as variables
// Actually consume the arguments instead of cloning them
scope.extend( scope.extend(
fn_def fn_def
.params .params
.iter() .iter()
.zip( .zip(args.iter_mut().map(|v| mem::take(*v)))
// Actually consume the arguments instead of cloning them
args.into_iter().map(|v| mem::take(*v)),
)
.map(|(name, value)| (name, ScopeEntryType::Normal, value)), .map(|(name, value)| (name, ScopeEntryType::Normal, value)),
); );
@ -1558,13 +1540,8 @@ impl Engine {
}; };
// First search in script-defined functions (can override built-in) // First search in script-defined functions (can override built-in)
if let Some(fn_def) = module.get_qualified_scripted_fn(*hash_fn_def) { let func = match module.get_qualified_fn(name, *hash_fn_def) {
let args = args.as_mut(); Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => {
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 // Then search in Rust functions
self.inc_operations(state, *pos)?; self.inc_operations(state, *pos)?;
@ -1573,17 +1550,33 @@ impl Engine {
// i.e. qualifiers + function name + dummy parameter types (one for each parameter). // i.e. qualifiers + function name + dummy parameter types (one for each parameter).
// 2) Calculate a second hash with no qualifiers, empty function name, and // 2) Calculate a second hash with no qualifiers, empty function name, and
// the actual list of parameter `TypeId`'.s // the actual list of parameter `TypeId`'.s
let hash_fn_args = calc_fn_hash(empty(), "", args.iter().map(|a| a.type_id())); 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. // 3) The final hash is the XOR of the two hashes.
let hash_fn_native = *hash_fn_def ^ hash_fn_args; let hash_fn_native = *hash_fn_def ^ hash_fn_args;
match module.get_qualified_fn(name, hash_fn_native) { 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),
} }
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 iter_type = self.eval_expr(scope, state, expr, level)?;
let tid = iter_type.type_id(); let tid = iter_type.type_id();
if let Some(iter_fn) = self if let Some(func) = self
.global_module .global_module
.get_iter(tid) .get_iter(tid)
.or_else(|| self.packages.get_iter(tid)) .or_else(|| self.packages.get_iter(tid))
@ -1744,7 +1737,7 @@ impl Engine {
let index = scope.len() - 1; let index = scope.len() - 1;
state.scope_level += 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; *scope.get_mut(index).0 = loop_var;
self.inc_operations(state, stmt.position())?; self.inc_operations(state, stmt.position())?;

View File

@ -1,4 +1,5 @@
use crate::any::Dynamic; use crate::any::Dynamic;
use crate::parser::{FnDef, SharedFnDef};
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::stdlib::{boxed::Box, rc::Rc, sync::Arc}; use crate::stdlib::{boxed::Box, rc::Rc, sync::Arc};
@ -72,70 +73,98 @@ pub trait IteratorCallback: Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + '
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
impl<F: Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static> IteratorCallback for F {} impl<F: Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static> IteratorCallback for F {}
/// A type representing the type of ABI of a native Rust function. /// A type encapsulating a function callable by Rhai.
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)] pub enum CallableFunction {
pub enum NativeFunctionABI { /// A pure native Rust function with all arguments passed by value.
/// A pure function where all arguments are passed by value. Pure(Box<FnAny>),
Pure, /// A native Rust object method with the first argument passed by reference,
/// An object method where the first argument is the object passed by mutable reference. /// and the rest passed by value.
/// All other arguments are passed by value. Method(Box<FnAny>),
Method, /// An iterator function.
Iterator(Box<IteratorFn>),
/// A script-defined function.
Script(SharedFnDef),
} }
/* impl CallableFunction {
/// Trait implemented by all native Rust functions that are callable by Rhai. /// 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<FnAny> {
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<IteratorFn> {
match self {
CallableFunction::Pure(_)
| CallableFunction::Method(_)
| CallableFunction::Script(_) => panic!(),
CallableFunction::Iterator(f) => f,
}
}
}
/// A callable function.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
pub trait NativeCallable { pub type SharedFunction = Rc<CallableFunction>;
/// Get the ABI type of a native Rust function. /// A callable function.
fn abi(&self) -> NativeFunctionABI;
/// Call a native Rust function.
fn call(&self, args: &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
}
/// Trait implemented by all native Rust functions that are callable by Rhai.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
pub trait NativeCallable: Send + Sync { pub type SharedFunction = Arc<CallableFunction>;
/// 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<Dynamic, Box<EvalAltResult>>;
}
*/
/// A type encapsulating a native Rust function callable by Rhai.
pub struct NativeFunction(Box<FnAny>, NativeFunctionABI);
impl NativeFunction {
pub fn abi(&self) -> NativeFunctionABI {
self.1
}
pub fn call(&self, args: &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> {
(self.0)(args)
}
}
impl From<(Box<FnAny>, NativeFunctionABI)> for NativeFunction {
fn from(func: (Box<FnAny>, NativeFunctionABI)) -> Self {
Self::new(func.0, func.1)
}
}
impl NativeFunction {
/// Create a new `NativeFunction`.
pub fn new(func: Box<FnAny>, abi: NativeFunctionABI) -> Self {
Self(func, abi)
}
}
/// An external native Rust function.
#[cfg(not(feature = "sync"))]
pub type SharedNativeFunction = Rc<NativeFunction>;
/// An external native Rust function.
#[cfg(feature = "sync")]
pub type SharedNativeFunction = Arc<NativeFunction>;
/// A type iterator function.
#[cfg(not(feature = "sync"))]
pub type SharedIteratorFunction = Rc<Box<IteratorFn>>;
/// An external native Rust function.
#[cfg(feature = "sync")]
pub type SharedIteratorFunction = Arc<Box<IteratorFn>>;

View File

@ -4,7 +4,10 @@
use crate::any::{Dynamic, Variant}; use crate::any::{Dynamic, Variant};
use crate::engine::Engine; use crate::engine::Engine;
use crate::fn_native::{FnCallArgs, NativeFunctionABI::*}; use crate::fn_native::{
CallableFunction::{Method, Pure},
FnCallArgs,
};
use crate::parser::FnAccess; use crate::parser::FnAccess;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
@ -181,9 +184,9 @@ pub fn map_result<T: Variant + Clone>(
macro_rules! def_register { 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 ABI type
// ^ function parameter generic type name (A, B, C etc.) // ^ function parameter generic type name (A, B, C etc.)
// ^ function parameter marker type (T, Ref<T> or Mut<T>) // ^ function parameter marker type (T, Ref<T> or Mut<T>)
@ -202,9 +205,9 @@ macro_rules! def_register {
> RegisterFn<FN, ($($mark,)*), RET> for Engine > RegisterFn<FN, ($($mark,)*), RET> for Engine
{ {
fn register_fn(&mut self, name: &str, f: FN) { 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>()),*], &[$(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<FN, ($($mark,)*)> for Engine > RegisterDynamicFn<FN, ($($mark,)*)> for Engine
{ {
fn register_dynamic_fn(&mut self, name: &str, f: FN) { 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>()),*], &[$(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<FN, ($($mark,)*), RET> for Engine > RegisterResultFn<FN, ($($mark,)*), RET> for Engine
{ {
fn register_result_fn(&mut self, name: &str, f: FN) { 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>()),*], &[$(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),*); //def_register!(imp_pop $($par => $mark => $param),*);
}; };
($p0:ident $(, $p:ident)*) => { ($p0:ident $(, $p:ident)*) => {
def_register!(imp Pure ; $p0 => $p0 => $p0 => by_value $(, $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)*); 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 // handle the first parameter ^ first parameter passed through
// ^ others passed by value (by_value) // ^ others passed by value (by_value)

View File

@ -91,7 +91,6 @@ mod utils;
pub use any::Dynamic; pub use any::Dynamic;
pub use engine::Engine; pub use engine::Engine;
pub use error::{ParseError, ParseErrorType}; pub use error::{ParseError, ParseErrorType};
//pub use fn_native::NativeCallable;
pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn}; pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn};
pub use module::Module; pub use module::Module;
pub use parser::{AST, INT}; pub use parser::{AST, INT};

View File

@ -4,10 +4,11 @@ use crate::any::{Dynamic, Variant};
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::engine::{Engine, FunctionsLib}; use crate::engine::{Engine, FunctionsLib};
use crate::fn_native::{ use crate::fn_native::{
FnAny, FnCallArgs, IteratorFn, NativeFunction, NativeFunctionABI, NativeFunctionABI::*, CallableFunction,
SharedIteratorFunction, SharedNativeFunction, CallableFunction::{Method, Pure},
FnCallArgs, IteratorFn, SharedFunction,
}; };
use crate::parser::{FnAccess, FnDef, SharedFnDef, AST}; use crate::parser::{FnAccess, AST};
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope}; use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
use crate::token::{Position, Token}; use crate::token::{Position, Token};
@ -51,19 +52,17 @@ pub struct Module {
all_variables: HashMap<u64, Dynamic>, all_variables: HashMap<u64, Dynamic>,
/// External Rust functions. /// External Rust functions.
functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, SharedNativeFunction)>, functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, SharedFunction)>,
/// Flattened collection of all external Rust functions, including those in sub-modules.
all_functions: HashMap<u64, SharedNativeFunction>,
/// Script-defined functions. /// Script-defined functions.
fn_lib: FunctionsLib, 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. /// Iterator functions, keyed by the type producing the iterator.
type_iterators: HashMap<TypeId, SharedIteratorFunction>, type_iterators: HashMap<TypeId, SharedFunction>,
/// Flattened collection of all external Rust functions, native or scripted,
/// including those in sub-modules.
all_functions: HashMap<u64, SharedFunction>,
} }
impl fmt::Debug for Module { impl fmt::Debug for Module {
@ -278,23 +277,16 @@ impl Module {
pub fn set_fn( pub fn set_fn(
&mut self, &mut self,
name: String, name: String,
abi: NativeFunctionABI,
access: FnAccess, access: FnAccess,
params: &[TypeId], params: &[TypeId],
func: Box<FnAny>, func: CallableFunction,
) -> u64 { ) -> u64 {
let hash_fn = calc_fn_hash(empty(), &name, params.iter().cloned()); 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(); 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 hash_fn
} }
@ -320,7 +312,7 @@ impl Module {
) -> u64 { ) -> u64 {
let f = move |_: &mut FnCallArgs| func().map(Dynamic::from); let f = move |_: &mut FnCallArgs| func().map(Dynamic::from);
let arg_types = []; 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. /// Set a Rust function taking one parameter into the module, returning a hash key.
@ -345,7 +337,7 @@ impl Module {
let f = let f =
move |args: &mut FnCallArgs| func(mem::take(args[0]).cast::<A>()).map(Dynamic::from); move |args: &mut FnCallArgs| func(mem::take(args[0]).cast::<A>()).map(Dynamic::from);
let arg_types = [TypeId::of::<A>()]; let arg_types = [TypeId::of::<A>()];
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. /// 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::<A>().unwrap()).map(Dynamic::from) func(args[0].downcast_mut::<A>().unwrap()).map(Dynamic::from)
}; };
let arg_types = [TypeId::of::<A>()]; let arg_types = [TypeId::of::<A>()];
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. /// 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) func(a, b).map(Dynamic::from)
}; };
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()]; let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
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, /// 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) func(a, b).map(Dynamic::from)
}; };
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()]; let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
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. /// 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) func(a, b, c).map(Dynamic::from)
}; };
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()]; let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
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, /// 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) func(a, b, c).map(Dynamic::from)
}; };
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()]; let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
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. /// Get a Rust function.
@ -531,7 +523,7 @@ impl Module {
/// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1)); /// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1));
/// assert!(module.get_fn(hash).is_some()); /// 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()) self.functions.get(&hash_fn).map(|(_, _, _, v)| v.as_ref())
} }
@ -543,7 +535,7 @@ impl Module {
&mut self, &mut self,
name: &str, name: &str,
hash_fn_native: u64, hash_fn_native: u64,
) -> Result<&NativeFunction, Box<EvalAltResult>> { ) -> Result<&CallableFunction, Box<EvalAltResult>> {
self.all_functions self.all_functions
.get(&hash_fn_native) .get(&hash_fn_native)
.map(|f| f.as_ref()) .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`. /// Create a new `Module` by evaluating an `AST`.
/// ///
/// # Examples /// # Examples
@ -620,13 +605,12 @@ impl Module {
module: &'a Module, module: &'a Module,
qualifiers: &mut Vec<&'a str>, qualifiers: &mut Vec<&'a str>,
variables: &mut Vec<(u64, Dynamic)>, variables: &mut Vec<(u64, Dynamic)>,
functions: &mut Vec<(u64, SharedNativeFunction)>, functions: &mut Vec<(u64, SharedFunction)>,
fn_lib: &mut Vec<(u64, SharedFnDef)>,
) { ) {
for (name, m) in &module.modules { for (name, m) in &module.modules {
// Index all the sub-modules first. // Index all the sub-modules first.
qualifiers.push(name); qualifiers.push(name);
index_module(m, qualifiers, variables, functions, fn_lib); index_module(m, qualifiers, variables, functions);
qualifiers.pop(); qualifiers.pop();
} }
@ -672,25 +656,17 @@ impl Module {
&fn_def.name, &fn_def.name,
repeat(EMPTY_TYPE_ID()).take(fn_def.params.len()), 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 variables = Vec::new();
let mut functions = Vec::new(); let mut functions = Vec::new();
let mut fn_lib = Vec::new();
index_module( index_module(self, &mut vec!["root"], &mut variables, &mut functions);
self,
&mut vec!["root"],
&mut variables,
&mut functions,
&mut fn_lib,
);
self.all_variables = variables.into_iter().collect(); self.all_variables = variables.into_iter().collect();
self.all_functions = functions.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? /// Does a type iterator exist in the module?
@ -701,14 +677,16 @@ impl Module {
/// Set a type iterator into the module. /// Set a type iterator into the module.
pub fn set_iter(&mut self, typ: TypeId, func: Box<IteratorFn>) { pub fn set_iter(&mut self, typ: TypeId, func: Box<IteratorFn>) {
#[cfg(not(feature = "sync"))] #[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")] #[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. /// Get the specified type iterator.
pub fn get_iter(&self, id: TypeId) -> Option<&SharedIteratorFunction> { pub fn get_iter(&self, id: TypeId) -> Option<&CallableFunction> {
self.type_iterators.get(&id) self.type_iterators.get(&id).map(|v| v.as_ref())
} }
} }

View File

@ -119,12 +119,12 @@ fn call_fn(
pos: Position, pos: Position,
) -> Result<Option<Dynamic>, Box<EvalAltResult>> { ) -> Result<Option<Dynamic>, Box<EvalAltResult>> {
// Search built-in's and external functions // 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 global_module
.get_fn(hash) .get_fn(hash_fn)
.or_else(|| packages.get_fn(hash)) .or_else(|| packages.get_fn(hash_fn))
.map(|func| func.call(args)) .map(|func| func.get_native_fn()(args))
.transpose() .transpose()
.map_err(|err| err.new_position(pos)) .map_err(|err| err.new_position(pos))
} }

View File

@ -1,6 +1,6 @@
//! Module containing all built-in _packages_ available to Rhai, plus facilities to define custom packages. //! 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::module::Module;
use crate::utils::StaticVec; use crate::utils::StaticVec;
@ -69,7 +69,7 @@ impl PackagesCollection {
self.packages.iter().any(|p| p.contains_fn(hash)) self.packages.iter().any(|p| p.contains_fn(hash))
} }
/// Get specified function via its hash key. /// 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 self.packages
.iter() .iter()
.map(|p| p.get_fn(hash)) .map(|p| p.get_fn(hash))
@ -81,7 +81,7 @@ impl PackagesCollection {
self.packages.iter().any(|p| p.contains_iter(id)) self.packages.iter().any(|p| p.contains_iter(id))
} }
/// Get the specified TypeId iterator. /// 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 self.packages
.iter() .iter()
.map(|p| p.get_iter(id)) .map(|p| p.get_iter(id))

View File

@ -36,10 +36,6 @@ pub enum EvalAltResult {
/// An error has occurred inside a called function. /// An error has occurred inside a called function.
/// Wrapped values re the name of the function and the interior error. /// Wrapped values re the name of the function and the interior error.
ErrorInFunctionCall(String, Box<EvalAltResult>, Position), ErrorInFunctionCall(String, Box<EvalAltResult>, 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. /// Non-boolean operand encountered for boolean operator. Wrapped value is the operator.
ErrorBooleanArgMismatch(String, Position), ErrorBooleanArgMismatch(String, Position),
/// Non-character value encountered where a character is required. /// Non-character value encountered where a character is required.
@ -108,9 +104,6 @@ impl EvalAltResult {
Self::ErrorParsing(p) => p.desc(), Self::ErrorParsing(p) => p.desc(),
Self::ErrorInFunctionCall(_, _, _) => "Error in called function", Self::ErrorInFunctionCall(_, _, _) => "Error in called function",
Self::ErrorFunctionNotFound(_, _) => "Function not found", Self::ErrorFunctionNotFound(_, _) => "Function not found",
Self::ErrorFunctionArgsMismatch(_, _, _, _) => {
"Function call with wrong number of arguments"
}
Self::ErrorBooleanArgMismatch(_, _) => "Boolean operator expects boolean operands", Self::ErrorBooleanArgMismatch(_, _) => "Boolean operator expects boolean operands",
Self::ErrorCharMismatch(_) => "Character expected", Self::ErrorCharMismatch(_) => "Character expected",
Self::ErrorNumericIndexExpr(_) => { Self::ErrorNumericIndexExpr(_) => {
@ -208,21 +201,6 @@ impl fmt::Display for EvalAltResult {
Self::ErrorLoopBreak(_, pos) => write!(f, "{} ({})", desc, pos), Self::ErrorLoopBreak(_, pos) => write!(f, "{} ({})", desc, pos),
Self::Return(_, 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) => { Self::ErrorBooleanArgMismatch(op, pos) => {
write!(f, "{} operator expects boolean operands ({})", op, pos) write!(f, "{} operator expects boolean operands ({})", op, pos)
} }
@ -292,7 +270,6 @@ impl EvalAltResult {
Self::ErrorFunctionNotFound(_, pos) Self::ErrorFunctionNotFound(_, pos)
| Self::ErrorInFunctionCall(_, _, pos) | Self::ErrorInFunctionCall(_, _, pos)
| Self::ErrorFunctionArgsMismatch(_, _, _, pos)
| Self::ErrorBooleanArgMismatch(_, pos) | Self::ErrorBooleanArgMismatch(_, pos)
| Self::ErrorCharMismatch(pos) | Self::ErrorCharMismatch(pos)
| Self::ErrorArrayBounds(_, _, pos) | Self::ErrorArrayBounds(_, _, pos)
@ -331,7 +308,6 @@ impl EvalAltResult {
Self::ErrorFunctionNotFound(_, pos) Self::ErrorFunctionNotFound(_, pos)
| Self::ErrorInFunctionCall(_, _, pos) | Self::ErrorInFunctionCall(_, _, pos)
| Self::ErrorFunctionArgsMismatch(_, _, _, pos)
| Self::ErrorBooleanArgMismatch(_, pos) | Self::ErrorBooleanArgMismatch(_, pos)
| Self::ErrorCharMismatch(pos) | Self::ErrorCharMismatch(pos)
| Self::ErrorArrayBounds(_, _, pos) | Self::ErrorArrayBounds(_, _, pos)