Unify all functions under CallableFunction type.
This commit is contained in:
parent
a22f338b03
commit
3295060dba
113
src/engine.rs
113
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<Dynamic> = 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())?;
|
||||
|
||||
|
155
src/fn_native.rs
155
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<dyn Iterator<Item = Dynamic>> + '
|
||||
#[cfg(not(feature = "sync"))]
|
||||
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.
|
||||
#[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<FnAny>),
|
||||
/// A native Rust object method with the first argument passed by reference,
|
||||
/// and the rest passed by value.
|
||||
Method(Box<FnAny>),
|
||||
/// An iterator function.
|
||||
Iterator(Box<IteratorFn>),
|
||||
/// 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<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"))]
|
||||
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<Dynamic, Box<EvalAltResult>>;
|
||||
}
|
||||
|
||||
/// Trait implemented by all native Rust functions that are callable by Rhai.
|
||||
pub type SharedFunction = Rc<CallableFunction>;
|
||||
/// 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<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>>;
|
||||
pub type SharedFunction = Arc<CallableFunction>;
|
||||
|
@ -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<T: Variant + Clone>(
|
||||
|
||||
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<T> or Mut<T>)
|
||||
@ -202,9 +205,9 @@ macro_rules! def_register {
|
||||
> RegisterFn<FN, ($($mark,)*), RET> 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<FN, ($($mark,)*)> 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<FN, ($($mark,)*), RET> 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)
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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<u64, Dynamic>,
|
||||
|
||||
/// External Rust functions.
|
||||
functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, SharedNativeFunction)>,
|
||||
|
||||
/// Flattened collection of all external Rust functions, including those in sub-modules.
|
||||
all_functions: HashMap<u64, SharedNativeFunction>,
|
||||
functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, 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<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 {
|
||||
@ -278,23 +277,16 @@ impl Module {
|
||||
pub fn set_fn(
|
||||
&mut self,
|
||||
name: String,
|
||||
abi: NativeFunctionABI,
|
||||
access: FnAccess,
|
||||
params: &[TypeId],
|
||||
func: Box<FnAny>,
|
||||
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::<A>()).map(Dynamic::from);
|
||||
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.
|
||||
@ -371,7 +363,7 @@ impl Module {
|
||||
func(args[0].downcast_mut::<A>().unwrap()).map(Dynamic::from)
|
||||
};
|
||||
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.
|
||||
@ -402,7 +394,7 @@ impl Module {
|
||||
func(a, b).map(Dynamic::from)
|
||||
};
|
||||
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,
|
||||
@ -437,7 +429,7 @@ impl Module {
|
||||
func(a, b).map(Dynamic::from)
|
||||
};
|
||||
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.
|
||||
@ -475,7 +467,7 @@ impl Module {
|
||||
func(a, b, c).map(Dynamic::from)
|
||||
};
|
||||
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,
|
||||
@ -514,7 +506,7 @@ impl Module {
|
||||
func(a, b, c).map(Dynamic::from)
|
||||
};
|
||||
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.
|
||||
@ -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<EvalAltResult>> {
|
||||
) -> Result<&CallableFunction, Box<EvalAltResult>> {
|
||||
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<IteratorFn>) {
|
||||
#[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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,12 +119,12 @@ fn call_fn(
|
||||
pos: Position,
|
||||
) -> Result<Option<Dynamic>, Box<EvalAltResult>> {
|
||||
// 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))
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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<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.
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user