diff --git a/src/engine.rs b/src/engine.rs index 926e2e8f..4cf71e9a 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, NativeFunction, SharedNativeFunction}; +use crate::fn_native::{FnCallArgs, NativeFunction, NativeFunctionABI, SharedNativeFunction}; use crate::optimize::OptimizationLevel; use crate::packages::{ CorePackage, Package, PackageLibrary, PackageStore, PackagesCollection, StandardPackage, @@ -544,13 +544,14 @@ impl Engine { scope: Option<&mut Scope>, state: &State, fn_name: &str, + is_protected: bool, hash_fn_spec: u64, hash_fn_def: u64, args: &mut FnCallArgs, def_val: Option<&Dynamic>, pos: Position, level: usize, - ) -> Result> { + ) -> Result<(Dynamic, bool), Box> { // Check for stack overflow if level > self.max_call_stack_depth { return Err(Box::new(EvalAltResult::ErrorStackOverflow(pos))); @@ -559,7 +560,9 @@ impl Engine { // First search in script-defined functions (can override built-in) if hash_fn_def > 0 { if let Some(fn_def) = state.get_function(hash_fn_def) { - return self.call_script_fn(scope, state, fn_def, args, pos, level); + return self + .call_script_fn(scope, state, fn_def, args, pos, level) + .map(|v| (v, false)); } } @@ -569,32 +572,61 @@ impl Engine { .get_function(hash_fn_spec) .or_else(|| self.packages.get_function(hash_fn_spec)) { + let mut backup: Dynamic = ().into(); + let mut restore = false; + + let updated = match func.abi() { + // Calling pure function in method-call + NativeFunctionABI::Pure if is_protected && args.len() > 0 => { + backup = args[0].clone(); + restore = true; + false + } + NativeFunctionABI::Pure => false, + NativeFunctionABI::Method => true, + }; + // Run external function - let result = func.call(args, pos)?; + let result = match func.call(args, pos) { + Ok(r) => { + // Restore the backup value for the first argument since it has been consumed! + if restore { + *args[0] = backup; + } + r + } + Err(err) => return Err(err), + }; // See if the function match print/debug (which requires special processing) return Ok(match fn_name { - KEYWORD_PRINT => (self.print)(result.as_str().map_err(|type_name| { - Box::new(EvalAltResult::ErrorMismatchOutputType( - type_name.into(), - pos, - )) - })?) - .into(), - KEYWORD_DEBUG => (self.debug)(result.as_str().map_err(|type_name| { - Box::new(EvalAltResult::ErrorMismatchOutputType( - type_name.into(), - pos, - )) - })?) - .into(), - _ => result, + KEYWORD_PRINT => ( + (self.print)(result.as_str().map_err(|type_name| { + Box::new(EvalAltResult::ErrorMismatchOutputType( + type_name.into(), + pos, + )) + })?) + .into(), + false, + ), + KEYWORD_DEBUG => ( + (self.debug)(result.as_str().map_err(|type_name| { + Box::new(EvalAltResult::ErrorMismatchOutputType( + type_name.into(), + pos, + )) + })?) + .into(), + false, + ), + _ => (result, updated), }); } // Return default value (if any) if let Some(val) = def_val { - return Ok(val.clone()); + return Ok((val.clone(), false)); } // Getter function not found? @@ -730,12 +762,13 @@ impl Engine { &self, state: &State, fn_name: &str, + is_protected: bool, hash_fn_def: u64, args: &mut FnCallArgs, def_val: Option<&Dynamic>, pos: Position, level: usize, - ) -> Result> { + ) -> Result<(Dynamic, bool), Box> { // Qualifiers (none) + function name + argument `TypeId`'s. let hash_fn_spec = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id())); @@ -744,7 +777,10 @@ impl Engine { KEYWORD_TYPE_OF if args.len() == 1 && !self.has_override(state, hash_fn_spec, hash_fn_def) => { - Ok(self.map_type_name(args[0].type_name()).to_string().into()) + Ok(( + self.map_type_name(args[0].type_name()).to_string().into(), + false, + )) } // eval - reaching this point it must be a method-style call @@ -757,11 +793,12 @@ impl Engine { ))) } - // Normal method call + // Normal function call _ => self.call_fn_raw( None, state, fn_name, + is_protected, hash_fn_spec, hash_fn_def, args, @@ -820,10 +857,10 @@ impl Engine { mut new_val: Option, ) -> Result<(Dynamic, bool), Box> { // Get a reference to the mutation target Dynamic - let obj = match target { - Target::Ref(r) => r, - Target::Value(ref mut r) => r.as_mut(), - Target::StringChar(ref mut x) => &mut x.2, + let (obj, is_protected) = match target { + Target::Ref(r) => (r, true), + Target::Value(ref mut r) => (r.as_mut(), false), + Target::StringChar(ref mut x) => (&mut x.2, false), }; // Pop the last index value @@ -835,8 +872,15 @@ impl Engine { Expr::Dot(x) | Expr::Index(x) => { let is_index = matches!(rhs, Expr::Index(_)); - let indexed_val = - self.get_indexed_mut(state, obj, idx_val, x.0.position(), op_pos, false)?; + let indexed_val = self.get_indexed_mut( + state, + obj, + is_protected, + idx_val, + x.0.position(), + op_pos, + false, + )?; self.eval_dot_index_chain_helper( state, indexed_val, @@ -850,14 +894,29 @@ impl Engine { } // xxx[rhs] = new_val _ if new_val.is_some() => { - let mut indexed_val = - self.get_indexed_mut(state, obj, idx_val, rhs.position(), op_pos, true)?; + let mut indexed_val = self.get_indexed_mut( + state, + obj, + is_protected, + idx_val, + rhs.position(), + op_pos, + true, + )?; indexed_val.set_value(new_val.unwrap(), rhs.position())?; Ok((Default::default(), true)) } // xxx[rhs] _ => self - .get_indexed_mut(state, obj, idx_val, rhs.position(), op_pos, false) + .get_indexed_mut( + state, + obj, + is_protected, + idx_val, + rhs.position(), + op_pos, + false, + ) .map(|v| (v.clone_into_dynamic(), false)), } } else { @@ -865,8 +924,9 @@ impl Engine { // xxx.fn_name(arg_expr_list) Expr::FnCall(x) if x.1.is_none() => { let ((name, pos), _, hash, _, def_val) = x.as_ref(); + let def_val = def_val.as_ref(); - let mut args: StaticVec<_> = once(obj) + let mut arg_values: StaticVec<_> = once(obj) .chain( idx_val .downcast_mut::>() @@ -874,10 +934,9 @@ impl Engine { .iter_mut(), ) .collect(); - // A function call is assumed to have side effects, so the value is changed - // TODO - Remove assumption of side effects by checking whether the first parameter is &mut - self.exec_fn_call(state, name, *hash, args.as_mut(), def_val.as_ref(), *pos, 0) - .map(|v| (v, true)) + let args = arg_values.as_mut(); + + self.exec_fn_call(state, name, is_protected, *hash, args, def_val, *pos, 0) } // xxx.module::fn_name(...) - syntax error Expr::FnCall(_) => unreachable!(), @@ -886,7 +945,7 @@ impl Engine { Expr::Property(x) if obj.is::() && new_val.is_some() => { let index = x.0.clone().into(); let mut indexed_val = - self.get_indexed_mut(state, obj, index, x.1, op_pos, true)?; + self.get_indexed_mut(state, obj, is_protected, index, x.1, op_pos, true)?; indexed_val.set_value(new_val.unwrap(), rhs.position())?; Ok((Default::default(), true)) } @@ -895,22 +954,22 @@ impl Engine { Expr::Property(x) if obj.is::() => { let index = x.0.clone().into(); let indexed_val = - self.get_indexed_mut(state, obj, index, x.1, op_pos, false)?; + self.get_indexed_mut(state, obj, is_protected, index, x.1, op_pos, false)?; Ok((indexed_val.clone_into_dynamic(), false)) } // xxx.id = ??? a Expr::Property(x) if new_val.is_some() => { let fn_name = make_setter(&x.0); let mut args = [obj, new_val.as_mut().unwrap()]; - self.exec_fn_call(state, &fn_name, 0, &mut args, None, x.1, 0) - .map(|v| (v, true)) + self.exec_fn_call(state, &fn_name, is_protected, 0, &mut args, None, x.1, 0) + .map(|(v, _)| (v, true)) } // xxx.id Expr::Property(x) => { let fn_name = make_getter(&x.0); let mut args = [obj]; - self.exec_fn_call(state, &fn_name, 0, &mut args, None, x.1, 0) - .map(|v| (v, false)) + self.exec_fn_call(state, &fn_name, is_protected, 0, &mut args, None, x.1, 0) + .map(|(v, _)| (v, false)) } #[cfg(not(feature = "no_object"))] // {xxx:map}.idx_lhs[idx_expr] | {xxx:map}.dot_lhs.rhs @@ -919,7 +978,7 @@ impl Engine { let indexed_val = if let Expr::Property(p) = &x.0 { let index = p.0.clone().into(); - self.get_indexed_mut(state, obj, index, x.2, op_pos, false)? + self.get_indexed_mut(state, obj, is_protected, index, x.2, op_pos, false)? } else { // Syntax error return Err(Box::new(EvalAltResult::ErrorDotExpr( @@ -941,18 +1000,21 @@ impl Engine { // xxx.idx_lhs[idx_expr] | xxx.dot_lhs.rhs Expr::Index(x) | Expr::Dot(x) => { let is_index = matches!(rhs, Expr::Index(_)); - let mut args = [obj, &mut Default::default()]; + let mut arg_values = [obj, &mut Default::default()]; - let indexed_val = &mut (if let Expr::Property(p) = &x.0 { + let (mut indexed_val, updated) = if let Expr::Property(p) = &x.0 { let fn_name = make_getter(&p.0); - self.exec_fn_call(state, &fn_name, 0, &mut args[..1], None, x.2, 0)? + let args = &mut arg_values[..1]; + self.exec_fn_call(state, &fn_name, is_protected, 0, args, None, x.2, 0)? } else { // Syntax error return Err(Box::new(EvalAltResult::ErrorDotExpr( "".to_string(), rhs.position(), ))); - }); + }; + let indexed_val = &mut indexed_val; + let (result, may_be_changed) = self.eval_dot_index_chain_helper( state, indexed_val.into(), @@ -965,12 +1027,13 @@ impl Engine { )?; // Feed the value back via a setter just in case it has been updated - if may_be_changed { + if updated || may_be_changed { if let Expr::Property(p) = &x.0 { let fn_name = make_setter(&p.0); // Re-use args because the first &mut parameter will not be consumed - args[1] = indexed_val; - self.exec_fn_call(state, &fn_name, 0, &mut args, None, x.2, 0) + arg_values[1] = indexed_val; + let args = &mut arg_values; + self.exec_fn_call(state, &fn_name, is_protected, 0, args, None, x.2, 0) .or_else(|err| match *err { // If there is no setter, no need to feed it back because the property is read-only EvalAltResult::ErrorDotExpr(_, _) => Ok(Default::default()), @@ -1099,6 +1162,7 @@ impl Engine { &self, state: &State, val: &'a mut Dynamic, + is_protected: bool, mut idx: Dynamic, idx_pos: Position, op_pos: Position, @@ -1177,8 +1241,8 @@ impl Engine { _ => { let args = &mut [val, &mut idx]; - self.exec_fn_call(state, FUNC_INDEXER, 0, args, None, op_pos, 0) - .map(|v| v.into()) + self.exec_fn_call(state, FUNC_INDEXER, is_protected, 0, args, None, op_pos, 0) + .map(|(v, _)| v.into()) .map_err(|_| { Box::new(EvalAltResult::ErrorIndexingType( // Error - cannot be indexed @@ -1223,8 +1287,9 @@ impl Engine { if self .call_fn_raw( - None, state, op, fn_spec, fn_def, args, def_value, pos, level, + None, state, op, false, fn_spec, fn_def, args, def_value, pos, level, )? + .0 .as_bool() .unwrap_or(false) { @@ -1398,12 +1463,14 @@ impl Engine { self.exec_fn_call( state, name, + false, *hash_fn_def, args.as_mut(), def_val.as_ref(), *pos, level, ) + .map(|(v, _)| v) } } diff --git a/src/fn_native.rs b/src/fn_native.rs index dfabc1d3..4bb7fde1 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -17,30 +17,45 @@ pub type IteratorFn = dyn Fn(Dynamic) -> Box> + Sen #[cfg(not(feature = "sync"))] pub type IteratorFn = dyn Fn(Dynamic) -> Box>; +/// A type representing the type of ABI of a native Rust function. +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +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 trait implemented by all native Rust functions that are callable by Rhai. 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, pos: Position) -> Result>; } /// A type encapsulating a native Rust function callable by Rhai. -pub struct NativeFunction(Box); +pub struct NativeFunction(Box, NativeFunctionABI); impl NativeCallable for NativeFunction { + fn abi(&self) -> NativeFunctionABI { + self.1 + } fn call(&self, args: &mut FnCallArgs, pos: Position) -> Result> { (self.0)(args, pos) } } -impl From> for NativeFunction { - fn from(func: Box) -> Self { - Self::new(func) +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) -> Self { - Self(func) + pub fn new(func: Box, abi: NativeFunctionABI) -> Self { + Self(func, abi) } } diff --git a/src/fn_register.rs b/src/fn_register.rs index a4e7d214..28c15c7f 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -4,7 +4,7 @@ use crate::any::{Dynamic, Variant}; use crate::engine::Engine; -use crate::fn_native::{FnCallArgs, NativeFunction}; +use crate::fn_native::{FnCallArgs, NativeFunction, NativeFunctionABI::*}; use crate::result::EvalAltResult; use crate::token::Position; use crate::utils::calc_fn_spec; @@ -134,11 +134,12 @@ pub fn by_value(data: &mut Dynamic) -> T { /// This macro creates a closure wrapping a registered function. macro_rules! make_func { - ($fn:ident : $map:expr ; $($par:ident => $convert:expr),*) => { + ($fn:ident : $abi:expr ; $map:expr ; $($par:ident => $convert:expr),*) => { // ^ function pointer -// ^ result mapping function -// ^ function parameter generic type name (A, B, C etc.) -// ^ dereferencing function +// ^ function ABI type +// ^ result mapping function +// ^ function parameter generic type name (A, B, C etc.) +// ^ dereferencing function NativeFunction::new(Box::new(move |args: &mut FnCallArgs, pos: Position| { // The arguments are assumed to be of the correct number and types! @@ -156,7 +157,7 @@ macro_rules! make_func { // Map the result $map(r, pos) - })); + }), $abi); }; } @@ -187,13 +188,14 @@ pub fn map_result( macro_rules! def_register { () => { - def_register!(imp); + def_register!(imp Pure;); }; - (imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => { - // ^ function parameter generic type name (A, B, C etc.) - // ^ function parameter marker type (T, Ref or Mut) - // ^ function parameter actual type (T, &T or &mut T) - // ^ dereferencing function + (imp $abi:expr ; $($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) + // ^ function parameter actual type (T, &T or &mut T) + // ^ dereferencing function impl< $($par: Variant + Clone,)* @@ -207,7 +209,7 @@ macro_rules! def_register { > RegisterFn for Engine { fn register_fn(&mut self, name: &str, f: FN) { - let func = make_func!(f : map_dynamic ; $($par => $clone),*); + let func = make_func!(f : $abi ; map_dynamic ; $($par => $clone),*); let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned()); self.base_package.functions.insert(hash, Box::new(func)); } @@ -224,7 +226,7 @@ macro_rules! def_register { > RegisterDynamicFn for Engine { fn register_dynamic_fn(&mut self, name: &str, f: FN) { - let func = make_func!(f : map_identity ; $($par => $clone),*); + let func = make_func!(f : $abi ; map_identity ; $($par => $clone),*); let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned()); self.base_package.functions.insert(hash, Box::new(func)); } @@ -242,7 +244,7 @@ macro_rules! def_register { > RegisterResultFn for Engine { fn register_result_fn(&mut self, name: &str, f: FN) { - let func = make_func!(f : map_result ; $($par => $clone),*); + let func = make_func!(f : $abi ; map_result ; $($par => $clone),*); let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned()); self.base_package.functions.insert(hash, Box::new(func)); } @@ -251,10 +253,10 @@ macro_rules! def_register { //def_register!(imp_pop $($par => $mark => $param),*); }; ($p0:ident $(, $p:ident)*) => { - def_register!(imp $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => by_value)*); - def_register!(imp $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => by_value)*); - // handle the first parameter ^ first parameter passed through - // ^ others passed by value (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)*); + // handle the first parameter ^ first parameter passed through + // ^ others passed by value (by_value) // Currently does not support first argument which is a reference, as there will be // conflicting implementations since &T: Any and T: Any cannot be distinguished diff --git a/src/module.rs b/src/module.rs index 284d662b..2d7dc424 100644 --- a/src/module.rs +++ b/src/module.rs @@ -4,7 +4,10 @@ use crate::any::{Dynamic, Variant}; use crate::calc_fn_hash; use crate::engine::{Engine, FunctionsLib}; -use crate::fn_native::{FnAny, FnCallArgs, NativeCallable, NativeFunction, SharedNativeFunction}; +use crate::fn_native::{ + FnAny, FnCallArgs, NativeCallable, NativeFunction, NativeFunctionABI, NativeFunctionABI::*, + SharedNativeFunction, +}; use crate::parser::{FnAccess, FnDef, SharedFnDef, AST}; use crate::result::EvalAltResult; use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope}; @@ -39,6 +42,9 @@ pub trait ModuleResolver { ) -> Result>; } +/// Default function access mode. +const DEF_ACCESS: FnAccess = FnAccess::Public; + /// Return type of module-level Rust function. type FuncReturn = Result>; @@ -263,21 +269,22 @@ impl Module { /// If there is an existing Rust function of the same hash, it is replaced. pub fn set_fn( &mut self, - fn_name: String, + name: String, + abi: NativeFunctionABI, access: FnAccess, params: Vec, func: Box, ) -> u64 { - let hash = calc_fn_hash(empty(), &fn_name, params.iter().cloned()); + let hash = calc_fn_hash(empty(), &name, params.iter().cloned()); - let f = Box::new(NativeFunction::from(func)) as Box; + let f = Box::new(NativeFunction::from((func, abi))) as Box; #[cfg(not(feature = "sync"))] let func = Rc::new(f); #[cfg(feature = "sync")] let func = Arc::new(f); - self.functions.insert(hash, (fn_name, access, params, func)); + self.functions.insert(hash, (name, access, params, func)); hash } @@ -297,7 +304,7 @@ impl Module { /// ``` pub fn set_fn_0, T: Into>( &mut self, - fn_name: K, + name: K, #[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn + 'static, #[cfg(feature = "sync")] func: impl Fn() -> FuncReturn + Send + Sync + 'static, ) -> u64 { @@ -307,7 +314,7 @@ impl Module { .map_err(|err| EvalAltResult::set_position(err, pos)) }; let arg_types = vec![]; - self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f)) + self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f)) } /// Set a Rust function taking one parameter into the module, returning a hash key. @@ -325,7 +332,7 @@ impl Module { /// ``` pub fn set_fn_1, A: Variant + Clone, T: Into>( &mut self, - fn_name: K, + name: K, #[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn + 'static, #[cfg(feature = "sync")] func: impl Fn(A) -> FuncReturn + Send + Sync + 'static, ) -> u64 { @@ -335,7 +342,7 @@ impl Module { .map_err(|err| EvalAltResult::set_position(err, pos)) }; let arg_types = vec![TypeId::of::()]; - self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f)) + self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f)) } /// Set a Rust function taking one mutable parameter into the module, returning a hash key. @@ -353,7 +360,7 @@ impl Module { /// ``` pub fn set_fn_1_mut, A: Variant + Clone, T: Into>( &mut self, - fn_name: K, + name: K, #[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn + 'static, #[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn + Send + Sync + 'static, ) -> u64 { @@ -363,7 +370,7 @@ impl Module { .map_err(|err| EvalAltResult::set_position(err, pos)) }; let arg_types = vec![TypeId::of::()]; - self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f)) + self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f)) } /// Set a Rust function taking two parameters into the module, returning a hash key. @@ -383,7 +390,7 @@ impl Module { /// ``` pub fn set_fn_2, A: Variant + Clone, B: Variant + Clone, T: Into>( &mut self, - fn_name: K, + name: K, #[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> FuncReturn + 'static, #[cfg(feature = "sync")] func: impl Fn(A, B) -> FuncReturn + Send + Sync + 'static, ) -> u64 { @@ -396,7 +403,7 @@ impl Module { .map_err(|err| EvalAltResult::set_position(err, pos)) }; let arg_types = vec![TypeId::of::(), TypeId::of::()]; - self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f)) + self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f)) } /// Set a Rust function taking two parameters (the first one mutable) into the module, @@ -420,7 +427,7 @@ impl Module { T: Into, >( &mut self, - fn_name: K, + name: K, #[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn + 'static, #[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn + Send + Sync + 'static, ) -> u64 { @@ -433,7 +440,7 @@ impl Module { .map_err(|err| EvalAltResult::set_position(err, pos)) }; let arg_types = vec![TypeId::of::(), TypeId::of::()]; - self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f)) + self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f)) } /// Set a Rust function taking three parameters into the module, returning a hash key. @@ -459,7 +466,7 @@ impl Module { T: Into, >( &mut self, - fn_name: K, + name: K, #[cfg(not(feature = "sync"))] func: impl Fn(A, B, C) -> FuncReturn + 'static, #[cfg(feature = "sync")] func: impl Fn(A, B, C) -> FuncReturn + Send + Sync + 'static, ) -> u64 { @@ -473,7 +480,7 @@ impl Module { .map_err(|err| EvalAltResult::set_position(err, pos)) }; let arg_types = vec![TypeId::of::(), TypeId::of::(), TypeId::of::()]; - self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f)) + self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f)) } /// Set a Rust function taking three parameters (the first one mutable) into the module, @@ -500,7 +507,7 @@ impl Module { T: Into, >( &mut self, - fn_name: K, + name: K, #[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C) -> FuncReturn + 'static, #[cfg(feature = "sync")] func: impl Fn(&mut A, B, C) -> FuncReturn + Send + Sync + 'static, ) -> u64 { @@ -514,7 +521,7 @@ impl Module { .map_err(|err| EvalAltResult::set_position(err, pos)) }; let arg_types = vec![TypeId::of::(), TypeId::of::(), TypeId::of::()]; - self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f)) + self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f)) } /// Get a Rust function. @@ -646,7 +653,7 @@ impl Module { variables.push((hash, value.clone())); } // Index all Rust functions - for (fn_name, access, params, func) in module.functions.values() { + for (name, access, params, func) in module.functions.values() { match access { // Private functions are not exported FnAccess::Private => continue, @@ -657,7 +664,7 @@ impl Module { // i.e. qualifiers + function name + dummy parameter types (one for each parameter). let hash_fn_def = calc_fn_hash( qualifiers.iter().map(|&v| v), - fn_name, + name, repeat(EMPTY_TYPE_ID()).take(params.len()), ); // 2) Calculate a second hash with no qualifiers, empty function name, and @@ -673,7 +680,7 @@ impl Module { match fn_def.access { // Private functions are not exported FnAccess::Private => continue, - FnAccess::Public => (), + DEF_ACCESS => (), } // Qualifiers + function name + placeholders (one for each parameter) let hash = calc_fn_hash( diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index dfb80422..c7938e74 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -118,9 +118,8 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { // Register array iterator lib.type_iterators.insert( TypeId::of::(), - Box::new(|a: Dynamic| { - Box::new(a.cast::().into_iter()) - as Box> - }), + Box::new(|arr| Box::new( + arr.cast::().into_iter()) as Box> + ), ); }); diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 031ac095..d50ad72a 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -18,7 +18,7 @@ where { lib.type_iterators.insert( TypeId::of::>(), - Box::new(|source: Dynamic| { + Box::new(|source| { Box::new(source.cast::>().map(|x| x.into_dynamic())) as Box> }), @@ -58,7 +58,7 @@ where { lib.type_iterators.insert( TypeId::of::>(), - Box::new(|source: Dynamic| { + Box::new(|source| { Box::new(source.cast::>().map(|x| x.into_dynamic())) as Box> }), diff --git a/src/packages/utils.rs b/src/packages/utils.rs index d4783811..3c082a6a 100644 --- a/src/packages/utils.rs +++ b/src/packages/utils.rs @@ -2,7 +2,7 @@ use super::PackageStore; use crate::any::{Dynamic, Variant}; use crate::calc_fn_hash; -use crate::fn_native::{FnCallArgs, NativeFunction}; +use crate::fn_native::{FnCallArgs, NativeFunction, NativeFunctionABI::*}; use crate::result::EvalAltResult; use crate::token::Position; @@ -106,7 +106,8 @@ pub fn reg_none( map_result(r, pos) }); - lib.functions.insert(hash, Box::new(NativeFunction::new(f))); + lib.functions + .insert(hash, Box::new(NativeFunction::new(f, Pure))); } /// Add a function with one parameter to the package. @@ -157,7 +158,8 @@ pub fn reg_unary( map_result(r, pos) }); - lib.functions.insert(hash, Box::new(NativeFunction::new(f))); + lib.functions + .insert(hash, Box::new(NativeFunction::new(f, Pure))); } /// Add a function with one mutable reference parameter to the package. @@ -215,7 +217,8 @@ pub fn reg_unary_mut( map_result(r, pos) }); - lib.functions.insert(hash, Box::new(NativeFunction::new(f))); + lib.functions + .insert(hash, Box::new(NativeFunction::new(f, Method))); } /// Add a function with two parameters to the package. @@ -271,7 +274,8 @@ pub fn reg_binary( map_result(r, pos) }); - lib.functions.insert(hash, Box::new(NativeFunction::new(f))); + lib.functions + .insert(hash, Box::new(NativeFunction::new(f, Pure))); } /// Add a function with two parameters (the first one being a mutable reference) to the package. @@ -334,7 +338,8 @@ pub fn reg_binary_mut( map_result(r, pos) }); - lib.functions.insert(hash, Box::new(NativeFunction::new(f))); + lib.functions + .insert(hash, Box::new(NativeFunction::new(f, Method))); } /// Add a function with three parameters to the package. @@ -374,7 +379,8 @@ pub fn reg_trinary Result<(), Box> { Ok(()) } + +#[test] +fn test_method_call_style() -> Result<(), Box> { + let mut engine = Engine::new(); + + assert_eq!(engine.eval::("let x = -123; x.abs(); x")?, -123); + + Ok(()) +}