Encapsulate register_fn_raw parameters into NativeCallContext.

This commit is contained in:
Stephen Chung 2020-10-18 17:02:17 +08:00
parent 58c820785b
commit 82e6dd446a
20 changed files with 368 additions and 265 deletions

View File

@ -10,6 +10,7 @@ Breaking changes
* `EvalAltResult::ErrorReadingScriptFile` is removed in favor of the new `EvalAltResult::ErrorSystem`. * `EvalAltResult::ErrorReadingScriptFile` is removed in favor of the new `EvalAltResult::ErrorSystem`.
* `EvalAltResult::ErrorLoopBreak` is renamed to `EvalAltResult::LoopBreak`. * `EvalAltResult::ErrorLoopBreak` is renamed to `EvalAltResult::LoopBreak`.
* `Engine::register_raw_fn` function signature has changed.
Enhancements Enhancements

View File

@ -17,10 +17,11 @@ Built-in methods
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
using a [raw `Engine`]) operate on function pointers: using a [raw `Engine`]) operate on function pointers:
| Function | Parameter(s) | Description | | Function | Parameter(s) | Description |
| -------------------------- | ------------ | ---------------------------------------------------------------------------- | | ---------------------------------- | ------------ | ---------------------------------------------------------------------------- |
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer | | `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ | | `is_anonymous` method and property | _none_ | does the function pointer refer to an [anonymous function]? |
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ |
Examples Examples
@ -186,16 +187,15 @@ must be used to register the function.
Essentially, use the low-level `Engine::register_raw_fn` method to register the function. Essentially, use the low-level `Engine::register_raw_fn` method to register the function.
`FnPtr::call_dynamic` is used to actually call the function pointer, passing to it the `FnPtr::call_dynamic` is used to actually call the function pointer, passing to it the
current scripting [`Engine`], collection of script-defined functions, the `this` pointer, current _native call context_, the `this` pointer, and other necessary arguments.
and other necessary arguments.
```rust ```rust
use rhai::{Engine, Module, Dynamic, FnPtr}; use rhai::{Engine, Module, Dynamic, FnPtr, NativeCallContext};
let mut engine = Engine::new(); let mut engine = Engine::new();
// Define Rust function in required low-level API signature // Define Rust function in required low-level API signature
fn call_fn_ptr_with_value(engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]) fn call_fn_ptr_with_value(context: NativeCallContext, args: &mut [&mut Dynamic])
-> Result<Dynamic, Box<EvalAltResult>> -> Result<Dynamic, Box<EvalAltResult>>
{ {
// 'args' is guaranteed to contain enough arguments of the correct types // 'args' is guaranteed to contain enough arguments of the correct types
@ -205,7 +205,7 @@ fn call_fn_ptr_with_value(engine: &Engine, lib: &Module, args: &mut [&mut Dynami
// Use 'FnPtr::call_dynamic' to call the function pointer. // Use 'FnPtr::call_dynamic' to call the function pointer.
// Beware, private script-defined functions will not be found. // Beware, private script-defined functions will not be found.
fp.call_dynamic(engine, lib, Some(this_ptr), [value]) fp.call_dynamic(context, Some(this_ptr), [value])
} }
// Register a Rust function using the low-level API // Register a Rust function using the low-level API
@ -218,3 +218,43 @@ engine.register_raw_fn("super_call",
call_fn_ptr_with_value call_fn_ptr_with_value
); );
``` ```
`NativeCallContext`
------------------
`FnPtr::call_dynamic` takes a parameter of type `NativeCallContext` which holds the _native call context_
of the particular call to a registered Rust function.
This type is normally provided by the [`Engine`] (e.g. when using `Engine::register_fn_raw`(../rust/register-raw.md)).
However, it may also be manually constructed from a tuple:
```rust
use rhai::{Engine, FnPtr};
let engine = Engine::new();
// Compile script to AST
let mut ast = engine.compile(
r#"
let test = "hello";
|x| test + x // this creates an closure
"#,
)?;
// Save the closure together with captured variables
let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
// Get rid of the script, retaining only functions
ast.retain_functions(|_, _, _| true);
// Create native call context via a tuple containing the Engine and the
// set of script-defined functions (within the AST)
let context = (&engine, ast.as_ref()).into();
// 'f' captures: the engine, the AST, and the closure
let f = move |x: i64| fn_ptr.call_dynamic(context, None, [x.into()]);
// 'f' can be called like a normal function
let result = f(42)?;
```

View File

@ -18,8 +18,9 @@ The `Engine::register_raw_fn` method is marked _volatile_, meaning that it may b
If this is acceptable, then using this method to register a Rust function opens up more opportunities. If this is acceptable, then using this method to register a Rust function opens up more opportunities.
In particular, a reference to the current `Engine` instance is passed as an argument so the Rust function In particular, a the current _native call context_ (in form of the `NativeCallContext` type) is passed as an argument.
can also use `Engine` facilities (like evaluating a script). `NativeCallContext` exposes the current [`Engine`], among others, so the Rust function can also use [`Engine`] facilities
(such as evaluating a script).
```rust ```rust
engine.register_raw_fn( engine.register_raw_fn(
@ -28,7 +29,7 @@ engine.register_raw_fn(
std::any::TypeId::of::<i64>(), // type of first parameter std::any::TypeId::of::<i64>(), // type of first parameter
std::any::TypeId::of::<i64>() // type of second parameter std::any::TypeId::of::<i64>() // type of second parameter
], ],
|engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| { // fixed function signature |context, args| { // fixed function signature
// Arguments are guaranteed to be correct in number and of the correct types. // Arguments are guaranteed to be correct in number and of the correct types.
// But remember this is Rust, so you can keep only one mutable reference at any one time! // But remember this is Rust, so you can keep only one mutable reference at any one time!
@ -59,17 +60,19 @@ Function Signature
The function signature passed to `Engine::register_raw_fn` takes the following form: The function signature passed to `Engine::register_raw_fn` takes the following form:
> `Fn(engine: &Engine, lib: &Module, args: &mut [&mut Dynamic])` > `Fn(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>> + 'static`
> `-> Result<T, Box<EvalAltResult>> + 'static`
where: where:
* `T: Variant + Clone` - return type of the function. * `T: Variant + Clone` - return type of the function.
* `engine: &Engine` - the current [`Engine`], with all configurations and settings. * `context: NativeCallContext` - the current _native call context_, which exposes the following:
* `lib: &Module` - the current global library of script-defined functions, as a [`Module`]. * `context.engine(): &Engine` - the current [`Engine`], with all configurations and settings.
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`]. This is sometimes useful for calling a script-defined function within the same evaluation context
using [`Engine::call_fn`][`call_fn`].
* `context.namespace(): &Module` - the global namespace of script-defined functions, as a [`Module`].
* `args: &mut [&mut Dynamic]` - a slice containing `&mut` references to [`Dynamic`] values. * `args: &mut [&mut Dynamic]` - a slice containing `&mut` references to [`Dynamic`] values.
The slice is guaranteed to contain enough arguments _of the correct types_. The slice is guaranteed to contain enough arguments _of the correct types_.
@ -106,7 +109,7 @@ then calls it within the same [`Engine`]. This way, a _callback_ function can b
to a native Rust function. to a native Rust function.
```rust ```rust
use rhai::{Engine, Module, Dynamic, FnPtr}; use rhai::{Engine, FnPtr};
let mut engine = Engine::new(); let mut engine = Engine::new();
@ -118,7 +121,7 @@ engine.register_raw_fn(
std::any::TypeId::of::<FnPtr>(), std::any::TypeId::of::<FnPtr>(),
std::any::TypeId::of::<i64>(), std::any::TypeId::of::<i64>(),
], ],
|engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| { |context, args| {
// 'args' is guaranteed to contain enough arguments of the correct types // 'args' is guaranteed to contain enough arguments of the correct types
let fp = std::mem::take(args[1]).cast::<FnPtr>(); // 2nd argument - function pointer let fp = std::mem::take(args[1]).cast::<FnPtr>(); // 2nd argument - function pointer
@ -127,7 +130,7 @@ engine.register_raw_fn(
// Use 'FnPtr::call_dynamic' to call the function pointer. // Use 'FnPtr::call_dynamic' to call the function pointer.
// Beware, private script-defined functions will not be found. // Beware, private script-defined functions will not be found.
fp.call_dynamic(engine, lib, Some(this_ptr), [value]) fp.call_dynamic(context, Some(this_ptr), [value])
}, },
); );

View File

@ -3,8 +3,7 @@
use crate::any::{Dynamic, Variant}; use crate::any::{Dynamic, Variant};
use crate::engine::{Engine, EvalContext, Imports, State}; use crate::engine::{Engine, EvalContext, Imports, State};
use crate::error::ParseError; use crate::error::ParseError;
use crate::fn_native::SendSync; use crate::fn_native::{NativeCallContext, SendSync};
use crate::module::{FuncReturn, Module};
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::parser::AST; use crate::parser::AST;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
@ -28,7 +27,7 @@ use crate::{
use crate::fn_register::{RegisterFn, RegisterResultFn}; use crate::fn_register::{RegisterFn, RegisterResultFn};
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
use crate::{fn_args::FuncArgs, fn_call::ensure_no_data_race, StaticVec}; use crate::{fn_args::FuncArgs, fn_call::ensure_no_data_race, module::Module, StaticVec};
#[cfg(not(feature = "no_optimize"))] #[cfg(not(feature = "no_optimize"))]
use crate::optimize::optimize_into_ast; use crate::optimize::optimize_into_ast;
@ -69,7 +68,9 @@ impl Engine {
&mut self, &mut self,
name: &str, name: &str,
arg_types: &[TypeId], arg_types: &[TypeId],
func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(NativeCallContext, &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>>
+ SendSync
+ 'static,
) -> &mut Self { ) -> &mut Self {
self.global_module.set_raw_fn(name, arg_types, func); self.global_module.set_raw_fn(name, arg_types, func);
self self
@ -1622,7 +1623,7 @@ impl Engine {
name: &str, name: &str,
mut this_ptr: Option<&mut Dynamic>, mut this_ptr: Option<&mut Dynamic>,
mut arg_values: impl AsMut<[Dynamic]>, mut arg_values: impl AsMut<[Dynamic]>,
) -> FuncReturn<Dynamic> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let mut args: StaticVec<_> = arg_values.as_mut().iter_mut().collect(); let mut args: StaticVec<_> = arg_values.as_mut().iter_mut().collect();
self.call_fn_dynamic_raw(scope, lib.as_ref(), name, &mut this_ptr, args.as_mut()) self.call_fn_dynamic_raw(scope, lib.as_ref(), name, &mut this_ptr, args.as_mut())
@ -1645,7 +1646,7 @@ impl Engine {
name: &str, name: &str,
this_ptr: &mut Option<&mut Dynamic>, this_ptr: &mut Option<&mut Dynamic>,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> FuncReturn<Dynamic> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let fn_def = lib let fn_def = lib
.get_script_fn(name, args.len(), true) .get_script_fn(name, args.len(), true)
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?; .ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;

View File

@ -1,12 +1,12 @@
//! Main module defining the script evaluation `Engine`. //! Main module defining the script evaluation `Engine`.
use crate::any::{map_std_type_name, Dynamic, Union}; use crate::any::{map_std_type_name, Dynamic, Union, Variant};
use crate::fn_call::run_builtin_op_assignment; use crate::fn_call::run_builtin_op_assignment;
use crate::fn_native::{Callback, FnPtr, OnVarCallback}; use crate::fn_native::{Callback, FnPtr, OnVarCallback};
use crate::module::{Module, ModuleRef}; use crate::module::{Module, ModuleRef};
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::packages::{Package, PackagesCollection, StandardPackage}; use crate::packages::{Package, PackagesCollection, StandardPackage};
use crate::parser::{Expr, ReturnType, Stmt, INT}; use crate::parser::{Expr, ReturnType, Stmt};
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime; use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope}; use crate::scope::{EntryType as ScopeEntryType, Scope};
@ -14,8 +14,8 @@ use crate::syntax::CustomSyntax;
use crate::token::Position; use crate::token::Position;
use crate::{calc_fn_hash, StaticVec}; use crate::{calc_fn_hash, StaticVec};
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(not(feature = "no_index"))]
use crate::any::Variant; use crate::parser::INT;
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
use crate::module::ModuleResolver; use crate::module::ModuleResolver;
@ -80,6 +80,7 @@ pub const MAX_CALL_STACK_DEPTH: usize = 12;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub const MAX_EXPR_DEPTH: usize = 32; pub const MAX_EXPR_DEPTH: usize = 32;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16; pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16;
@ -90,6 +91,7 @@ pub const MAX_CALL_STACK_DEPTH: usize = 128;
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
pub const MAX_EXPR_DEPTH: usize = 128; pub const MAX_EXPR_DEPTH: usize = 128;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32; pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
@ -144,6 +146,7 @@ impl IndexChainValue {
/// # Panics /// # Panics
/// ///
/// Panics if not `IndexChainValue::Value`. /// Panics if not `IndexChainValue::Value`.
#[cfg(not(feature = "no_index"))]
pub fn as_value(self) -> Dynamic { pub fn as_value(self) -> Dynamic {
match self { match self {
Self::None | Self::FnCallArgs(_) => panic!("expecting IndexChainValue::Value"), Self::None | Self::FnCallArgs(_) => panic!("expecting IndexChainValue::Value"),
@ -155,6 +158,7 @@ impl IndexChainValue {
/// # Panics /// # Panics
/// ///
/// Panics if not `IndexChainValue::FnCallArgs`. /// Panics if not `IndexChainValue::FnCallArgs`.
#[cfg(not(feature = "no_object"))]
pub fn as_fn_call_args(self) -> StaticVec<Dynamic> { pub fn as_fn_call_args(self) -> StaticVec<Dynamic> {
match self { match self {
Self::None | Self::Value(_) => panic!("expecting IndexChainValue::FnCallArgs"), Self::None | Self::Value(_) => panic!("expecting IndexChainValue::FnCallArgs"),
@ -178,7 +182,6 @@ impl From<Dynamic> for IndexChainValue {
} }
/// A type that encapsulates a mutation target for an expression with side effects. /// A type that encapsulates a mutation target for an expression with side effects.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[derive(Debug)] #[derive(Debug)]
pub enum Target<'a> { pub enum Target<'a> {
/// The target is a mutable reference to a `Dynamic` value somewhere. /// The target is a mutable reference to a `Dynamic` value somewhere.
@ -196,7 +199,6 @@ pub enum Target<'a> {
StringChar(&'a mut Dynamic, usize, Dynamic), StringChar(&'a mut Dynamic, usize, Dynamic),
} }
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl<'a> Target<'a> { impl<'a> Target<'a> {
/// Is the `Target` a reference pointing to other data? /// Is the `Target` a reference pointing to other data?
#[allow(dead_code)] #[allow(dead_code)]
@ -306,6 +308,7 @@ impl<'a> Target<'a> {
} }
} }
/// Update the value of the `Target`. /// Update the value of the `Target`.
#[cfg(any(not(feature = "no_object"), not(feature = "no_index")))]
pub fn set_value( pub fn set_value(
&mut self, &mut self,
new_val: (Dynamic, Position), new_val: (Dynamic, Position),
@ -348,7 +351,6 @@ impl<'a> Target<'a> {
} }
} }
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl<'a> From<&'a mut Dynamic> for Target<'a> { impl<'a> From<&'a mut Dynamic> for Target<'a> {
#[inline(always)] #[inline(always)]
fn from(value: &'a mut Dynamic) -> Self { fn from(value: &'a mut Dynamic) -> Self {
@ -364,7 +366,6 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> {
} }
} }
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl<T: Into<Dynamic>> From<T> for Target<'_> { impl<T: Into<Dynamic>> From<T> for Target<'_> {
#[inline(always)] #[inline(always)]
fn from(value: T) -> Self { fn from(value: T) -> Self {
@ -414,35 +415,44 @@ pub struct Limits {
/// ///
/// Defaults to 16 for debug builds and 128 for non-debug builds. /// Defaults to 16 for debug builds and 128 for non-debug builds.
pub max_call_stack_depth: usize, pub max_call_stack_depth: usize,
/// Maximum depth of statements/expressions at global level. /// Maximum depth of statements/expressions at global level (0 = unlimited).
pub max_expr_depth: usize, pub max_expr_depth: usize,
/// Maximum depth of statements/expressions in functions. /// Maximum depth of statements/expressions in functions (0 = unlimited).
/// Not available under `no_function`.
#[cfg(not(feature = "no_function"))]
pub max_function_expr_depth: usize, pub max_function_expr_depth: usize,
/// Maximum number of operations allowed to run. /// Maximum number of operations allowed to run (0 = unlimited).
pub max_operations: u64, pub max_operations: u64,
/// Maximum number of modules allowed to load. /// Maximum number of modules allowed to load.
/// Not available under `no_module`.
#[cfg(not(feature = "no_modules"))]
pub max_modules: usize, pub max_modules: usize,
/// Maximum length of a string. /// Maximum length of a string (0 = unlimited).
pub max_string_size: usize, pub max_string_size: usize,
/// Maximum length of an array. /// Maximum length of an array (0 = unlimited).
/// Not available under `no_index`.
#[cfg(not(feature = "no_index"))]
pub max_array_size: usize, pub max_array_size: usize,
/// Maximum number of properties in a map. /// Maximum number of properties in a map (0 = unlimited).
/// Not available under `no_object`.
#[cfg(not(feature = "no_object"))]
pub max_map_size: usize, pub max_map_size: usize,
} }
/// Context of a script evaluation process. /// Context of a script evaluation process.
#[derive(Debug)] #[derive(Debug)]
pub struct EvalContext<'e, 'a, 's, 'm, 't, 'd: 't> { pub struct EvalContext<'e, 'a, 's, 'm, 't, 'd: 't> {
pub(crate) engine: &'e Engine, engine: &'e Engine,
pub(crate) mods: &'a mut Imports, pub(crate) mods: &'a mut Imports,
pub(crate) state: &'s mut State, pub(crate) state: &'s mut State,
pub(crate) lib: &'m Module, lib: &'m Module,
pub(crate) this_ptr: &'t mut Option<&'d mut Dynamic>, pub(crate) this_ptr: &'t mut Option<&'d mut Dynamic>,
pub(crate) level: usize, level: usize,
} }
impl<'e, 'a, 's, 'm, 't, 'd> EvalContext<'e, 'a, 's, 'm, 't, 'd> { impl<'e, 'a, 's, 'm, 't, 'd> EvalContext<'e, 'a, 's, 'm, 't, 'd> {
/// The current `Engine`. /// The current `Engine`.
#[inline(always)]
pub fn engine(&self) -> &'e Engine { pub fn engine(&self) -> &'e Engine {
self.engine self.engine
} }
@ -450,14 +460,17 @@ impl<'e, 'a, 's, 'm, 't, 'd> EvalContext<'e, 'a, 's, 'm, 't, 'd> {
/// Available under the `internals` feature only. /// Available under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[cfg(not(feature = "no_modules"))] #[cfg(not(feature = "no_modules"))]
#[inline(always)]
pub fn imports(&self) -> &'a Imports { pub fn imports(&self) -> &'a Imports {
self.mods self.mods
} }
/// The global namespace containing definition of all script-defined functions. /// The global namespace containing definition of all script-defined functions.
#[inline(always)]
pub fn namespace(&self) -> &'m Module { pub fn namespace(&self) -> &'m Module {
self.lib self.lib
} }
/// The current nesting level of function calls. /// The current nesting level of function calls.
#[inline(always)]
pub fn call_level(&self) -> usize { pub fn call_level(&self) -> usize {
self.level self.level
} }
@ -516,7 +529,7 @@ pub struct Engine {
/// Max limits. /// Max limits.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub(crate) limits: Limits, pub(crate) limits_set: Limits,
} }
impl fmt::Debug for Engine { impl fmt::Debug for Engine {
@ -662,14 +675,18 @@ impl Engine {
}, },
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
limits: Limits { limits_set: Limits {
max_call_stack_depth: MAX_CALL_STACK_DEPTH, max_call_stack_depth: MAX_CALL_STACK_DEPTH,
max_expr_depth: MAX_EXPR_DEPTH, max_expr_depth: MAX_EXPR_DEPTH,
#[cfg(not(feature = "no_function"))]
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH, max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
max_operations: 0, max_operations: 0,
#[cfg(not(feature = "no_module"))]
max_modules: usize::MAX, max_modules: usize::MAX,
max_string_size: 0, max_string_size: 0,
#[cfg(not(feature = "no_index"))]
max_array_size: 0, max_array_size: 0,
#[cfg(not(feature = "no_object"))]
max_map_size: 0, max_map_size: 0,
}, },
}; };
@ -710,14 +727,18 @@ impl Engine {
}, },
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
limits: Limits { limits_set: Limits {
max_call_stack_depth: MAX_CALL_STACK_DEPTH, max_call_stack_depth: MAX_CALL_STACK_DEPTH,
max_expr_depth: MAX_EXPR_DEPTH, max_expr_depth: MAX_EXPR_DEPTH,
#[cfg(not(feature = "no_function"))]
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH, max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
max_operations: 0, max_operations: 0,
#[cfg(not(feature = "no_module"))]
max_modules: usize::MAX, max_modules: usize::MAX,
max_string_size: 0, max_string_size: 0,
#[cfg(not(feature = "no_index"))]
max_array_size: 0, max_array_size: 0,
#[cfg(not(feature = "no_object"))]
max_map_size: 0, max_map_size: 0,
}, },
} }
@ -1285,7 +1306,7 @@ impl Engine {
) -> Result<Target<'a>, Box<EvalAltResult>> { ) -> Result<Target<'a>, Box<EvalAltResult>> {
self.inc_operations(state)?; self.inc_operations(state)?;
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(not(feature = "no_index"))]
let is_ref = target.is_ref(); let is_ref = target.is_ref();
let val = target.as_mut(); let val = target.as_mut();
@ -1542,7 +1563,7 @@ impl Engine {
if func.is_plugin_fn() { if func.is_plugin_fn() {
func.get_plugin_fn().call(args)?; func.get_plugin_fn().call(args)?;
} else { } else {
func.get_native_fn()(self, lib, args)?; func.get_native_fn()((self, lib).into(), args)?;
} }
} }
// Built-in op-assignment function // Built-in op-assignment function
@ -1954,7 +1975,7 @@ impl Engine {
// Guard against too many modules // Guard against too many modules
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if state.modules >= self.limits.max_modules { if state.modules >= self.max_modules() {
return EvalAltResult::ErrorTooManyModules(*_pos).into(); return EvalAltResult::ErrorTooManyModules(*_pos).into();
} }
@ -2042,8 +2063,19 @@ impl Engine {
result: Result<Dynamic, Box<EvalAltResult>>, result: Result<Dynamic, Box<EvalAltResult>>,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
// If no data size limits, just return // If no data size limits, just return
if self.limits.max_string_size + self.limits.max_array_size + self.limits.max_map_size == 0 let mut total = 0;
total += self.max_string_size();
#[cfg(not(feature = "no_index"))]
{ {
total += self.max_array_size();
}
#[cfg(not(feature = "no_object"))]
{
total += self.max_map_size();
}
if total == 0 {
return result; return result;
} }
@ -2103,46 +2135,52 @@ impl Engine {
// Simply return all errors // Simply return all errors
Err(_) => return result, Err(_) => return result,
// String with limit // String with limit
Ok(Dynamic(Union::Str(_))) if self.limits.max_string_size > 0 => (), Ok(Dynamic(Union::Str(_))) if self.max_string_size() > 0 => (),
// Array with limit // Array with limit
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Ok(Dynamic(Union::Array(_))) if self.limits.max_array_size > 0 => (), Ok(Dynamic(Union::Array(_))) if self.max_array_size() > 0 => (),
// Map with limit // Map with limit
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Ok(Dynamic(Union::Map(_))) if self.limits.max_map_size > 0 => (), Ok(Dynamic(Union::Map(_))) if self.max_map_size() > 0 => (),
// Everything else is simply returned // Everything else is simply returned
Ok(_) => return result, Ok(_) => return result,
}; };
let (arr, map, s) = calc_size(result.as_ref().unwrap()); let (_arr, _map, s) = calc_size(result.as_ref().unwrap());
if s > self.limits.max_string_size { if s > self.max_string_size() {
EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
self.limits.max_string_size, self.max_string_size(),
s, s,
Position::none(), Position::none(),
) )
.into() .into();
} else if arr > self.limits.max_array_size {
EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(),
self.limits.max_array_size,
arr,
Position::none(),
)
.into()
} else if map > self.limits.max_map_size {
EvalAltResult::ErrorDataTooLarge(
"Number of properties in object map".to_string(),
self.limits.max_map_size,
map,
Position::none(),
)
.into()
} else {
result
} }
#[cfg(not(feature = "no_index"))]
if _arr > self.max_array_size() {
return EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(),
self.max_array_size(),
_arr,
Position::none(),
)
.into();
}
#[cfg(not(feature = "no_object"))]
if _map > self.max_map_size() {
return EvalAltResult::ErrorDataTooLarge(
"Number of properties in object map".to_string(),
self.max_map_size(),
_map,
Position::none(),
)
.into();
}
result
} }
/// Check if the number of operations stay within limit. /// Check if the number of operations stay within limit.
@ -2152,7 +2190,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
// Guard against too many operations // Guard against too many operations
if self.limits.max_operations > 0 && state.operations > self.limits.max_operations { if self.max_operations() > 0 && state.operations > self.max_operations() {
return EvalAltResult::ErrorTooManyOperations(Position::none()).into(); return EvalAltResult::ErrorTooManyOperations(Position::none()).into();
} }

View File

@ -208,7 +208,7 @@ impl Engine {
let result = if func.is_plugin_fn() { let result = if func.is_plugin_fn() {
func.get_plugin_fn().call(args) func.get_plugin_fn().call(args)
} else { } else {
func.get_native_fn()(self, lib, args) func.get_native_fn()((self, lib).into(), args)
}; };
// Restore the original reference // Restore the original reference
@ -356,7 +356,7 @@ impl Engine {
// Check for stack overflow // Check for stack overflow
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if level > self.limits.max_call_stack_depth { if level > self.max_call_levels() {
return Err(Box::new( return Err(Box::new(
EvalAltResult::ErrorStackOverflow(Position::none()), EvalAltResult::ErrorStackOverflow(Position::none()),
)); ));
@ -648,7 +648,7 @@ impl Engine {
// Check for stack overflow // Check for stack overflow
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _level > self.limits.max_call_stack_depth { if _level > self.max_call_levels() {
return Err(Box::new( return Err(Box::new(
EvalAltResult::ErrorStackOverflow(Position::none()), EvalAltResult::ErrorStackOverflow(Position::none()),
)); ));
@ -1196,7 +1196,7 @@ impl Engine {
} }
} }
f.get_native_fn()(self, lib, args.as_mut()) f.get_native_fn()((self, lib).into(), args.as_mut())
} }
Some(_) => unreachable!(), Some(_) => unreachable!(),
None if def_val.is_some() => Ok(def_val.unwrap().into()), None if def_val.is_some() => Ok(def_val.unwrap().into()),

View File

@ -1,7 +1,7 @@
//! Module defining interfaces to native-Rust functions. //! Module defining interfaces to native-Rust functions.
use crate::any::Dynamic; use crate::any::Dynamic;
use crate::engine::{Engine, EvalContext}; use crate::engine::{Engine, EvalContext, FN_ANONYMOUS};
use crate::module::Module; use crate::module::Module;
use crate::parser::{FnAccess, ScriptFnDef}; use crate::parser::{FnAccess, ScriptFnDef};
use crate::plugin::PluginFunction; use crate::plugin::PluginFunction;
@ -46,6 +46,35 @@ pub type Locked<T> = RefCell<T>;
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
pub type Locked<T> = RwLock<T>; pub type Locked<T> = RwLock<T>;
/// Context of a script evaluation process.
#[derive(Debug, Copy, Clone)]
pub struct NativeCallContext<'e, 'm> {
engine: &'e Engine,
lib: &'m Module,
}
impl<'e, 'm> From<(&'e Engine, &'m Module)> for NativeCallContext<'e, 'm> {
fn from(value: (&'e Engine, &'m Module)) -> Self {
Self {
engine: value.0,
lib: value.1,
}
}
}
impl<'e, 'm> NativeCallContext<'e, 'm> {
/// The current `Engine`.
#[inline(always)]
pub fn engine(&self) -> &'e Engine {
self.engine
}
/// The global namespace containing definition of all script-defined functions.
#[inline(always)]
pub fn namespace(&self) -> &'m Module {
self.lib
}
}
/// Consume a `Shared` resource and return a mutable reference to the wrapped value. /// Consume a `Shared` resource and return a mutable reference to the wrapped value.
/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used. /// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T { pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
@ -108,6 +137,11 @@ impl FnPtr {
pub fn curry(&self) -> &[Dynamic] { pub fn curry(&self) -> &[Dynamic] {
self.1.as_ref() self.1.as_ref()
} }
/// Does this function pointer refer to an anonymous function?
#[inline(always)]
pub fn is_anonymous(&self) -> bool {
self.0.starts_with(FN_ANONYMOUS)
}
/// Call the function pointer with curried arguments (if any). /// Call the function pointer with curried arguments (if any).
/// ///
@ -121,8 +155,7 @@ impl FnPtr {
/// clone them _before_ calling this function. /// clone them _before_ calling this function.
pub fn call_dynamic( pub fn call_dynamic(
&self, &self,
engine: &Engine, context: NativeCallContext,
lib: impl AsRef<Module>,
this_ptr: Option<&mut Dynamic>, this_ptr: Option<&mut Dynamic>,
mut arg_values: impl AsMut<[Dynamic]>, mut arg_values: impl AsMut<[Dynamic]>,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
@ -144,10 +177,11 @@ impl FnPtr {
args.insert(0, obj); args.insert(0, obj);
} }
engine context
.engine()
.exec_fn_call( .exec_fn_call(
&mut Default::default(), &mut Default::default(),
lib.as_ref(), context.namespace(),
fn_name, fn_name,
hash_script, hash_script,
args.as_mut(), args.as_mut(),
@ -204,11 +238,11 @@ impl TryFrom<&str> for FnPtr {
/// A general function trail object. /// A general function trail object.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
pub type FnAny = dyn Fn(&Engine, &Module, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>; pub type FnAny = dyn Fn(NativeCallContext, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
/// A general function trail object. /// A general function trail object.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
pub type FnAny = pub type FnAny =
dyn Fn(&Engine, &Module, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync; dyn Fn(NativeCallContext, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync;
/// A standard function that gets an iterator from a type. /// A standard function that gets an iterator from a type.
pub type IteratorFn = fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>; pub type IteratorFn = fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;

View File

@ -4,8 +4,7 @@
use crate::any::{Dynamic, DynamicWriteLock, Variant}; use crate::any::{Dynamic, DynamicWriteLock, Variant};
use crate::engine::Engine; use crate::engine::Engine;
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync}; use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, NativeCallContext, SendSync};
use crate::module::Module;
use crate::parser::FnAccess; use crate::parser::FnAccess;
use crate::r#unsafe::unsafe_cast_box; use crate::r#unsafe::unsafe_cast_box;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
@ -127,7 +126,7 @@ macro_rules! make_func {
// ^ dereferencing function // ^ dereferencing function
// ^ argument reference expression(like A, *B, &mut C etc) // ^ argument reference expression(like A, *B, &mut C etc)
Box::new(move |_: &Engine, _: &Module, args: &mut FnCallArgs| { Box::new(move |_: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut(); let mut _drain = args.iter_mut();

View File

@ -85,7 +85,7 @@ mod utils;
pub use any::Dynamic; pub use any::Dynamic;
pub use engine::{Engine, EvalContext}; pub use engine::{Engine, EvalContext};
pub use error::{ParseError, ParseErrorType}; pub use error::{ParseError, ParseErrorType};
pub use fn_native::FnPtr; pub use fn_native::{FnPtr, NativeCallContext};
pub use fn_register::{RegisterFn, RegisterResultFn}; pub use fn_register::{RegisterFn, RegisterResultFn};
pub use module::Module; pub use module::Module;
pub use parser::{ImmutableString, AST, INT}; pub use parser::{ImmutableString, AST, INT};

View File

@ -2,7 +2,7 @@
use crate::any::{Dynamic, Variant}; use crate::any::{Dynamic, Variant};
use crate::engine::Engine; use crate::engine::Engine;
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, SendSync}; use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync};
use crate::fn_register::by_value as cast_arg; use crate::fn_register::by_value as cast_arg;
use crate::parser::FnAccess; use crate::parser::FnAccess;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
@ -24,7 +24,11 @@ use crate::{
use crate::engine::{Array, FN_IDX_GET, FN_IDX_SET}; use crate::engine::{Array, FN_IDX_GET, FN_IDX_SET};
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::engine::{make_getter, make_setter, Map}; use crate::engine::{make_getter, make_setter};
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
use crate::engine::Map;
use crate::stdlib::{ use crate::stdlib::{
any::TypeId, any::TypeId,
@ -38,9 +42,6 @@ use crate::stdlib::{
vec::Vec, vec::Vec,
}; };
/// Return type of module-level Rust function.
pub type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
pub type FuncInfo = ( pub type FuncInfo = (
String, String,
FnAccess, FnAccess,
@ -536,10 +537,12 @@ impl Module {
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
arg_types: &[TypeId], arg_types: &[TypeId],
func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(NativeCallContext, &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>>
+ SendSync
+ 'static,
) -> u64 { ) -> u64 {
let f = move |engine: &Engine, lib: &Module, args: &mut FnCallArgs| { let f = move |context: NativeCallContext, args: &mut [&mut Dynamic]| {
func(engine, lib, args).map(Dynamic::from) func(context, args).map(Dynamic::from)
}; };
self.set_fn( self.set_fn(
name, name,
@ -566,9 +569,9 @@ impl Module {
pub fn set_fn_0<T: Variant + Clone>( pub fn set_fn_0<T: Variant + Clone>(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn() -> FuncReturn<T> + SendSync + 'static, func: impl Fn() -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, _: &mut FnCallArgs| func().map(Dynamic::from); let f = move |_: NativeCallContext, _: &mut FnCallArgs| func().map(Dynamic::from);
let arg_types = []; let arg_types = [];
self.set_fn( self.set_fn(
name, name,
@ -595,9 +598,9 @@ impl Module {
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>( pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(A) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
func(cast_arg::<A>(&mut args[0])).map(Dynamic::from) func(cast_arg::<A>(&mut args[0])).map(Dynamic::from)
}; };
let arg_types = [TypeId::of::<A>()]; let arg_types = [TypeId::of::<A>()];
@ -626,9 +629,9 @@ impl Module {
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>( pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from) func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from)
}; };
let arg_types = [TypeId::of::<A>()]; let arg_types = [TypeId::of::<A>()];
@ -658,7 +661,7 @@ impl Module {
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>( pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
self.set_fn_1_mut(make_getter(&name.into()), func) self.set_fn_1_mut(make_getter(&name.into()), func)
} }
@ -682,9 +685,9 @@ impl Module {
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>( pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(A, B) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let a = cast_arg::<A>(&mut args[0]); let a = cast_arg::<A>(&mut args[0]);
let b = cast_arg::<B>(&mut args[1]); let b = cast_arg::<B>(&mut args[1]);
@ -719,9 +722,9 @@ impl Module {
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>( pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let b = cast_arg::<B>(&mut args[1]); let b = cast_arg::<B>(&mut args[1]);
let a = &mut args[0].write_lock::<A>().unwrap(); let a = &mut args[0].write_lock::<A>().unwrap();
@ -758,7 +761,7 @@ impl Module {
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>( pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(&mut A, B) -> FuncReturn<()> + SendSync + 'static, func: impl Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
self.set_fn_2_mut(make_setter(&name.into()), func) self.set_fn_2_mut(make_setter(&name.into()), func)
} }
@ -788,7 +791,7 @@ impl Module {
#[inline] #[inline]
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>( pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self, &mut self,
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
if TypeId::of::<A>() == TypeId::of::<Array>() { if TypeId::of::<A>() == TypeId::of::<Array>() {
panic!("Cannot register indexer for arrays."); panic!("Cannot register indexer for arrays.");
@ -831,9 +834,9 @@ impl Module {
>( >(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(A, B, C) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let a = cast_arg::<A>(&mut args[0]); let a = cast_arg::<A>(&mut args[0]);
let b = cast_arg::<B>(&mut args[1]); let b = cast_arg::<B>(&mut args[1]);
let c = cast_arg::<C>(&mut args[2]); let c = cast_arg::<C>(&mut args[2]);
@ -874,9 +877,9 @@ impl Module {
>( >(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(&mut A, B, C) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(&mut A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let b = cast_arg::<B>(&mut args[2]); let b = cast_arg::<B>(&mut args[2]);
let c = cast_arg::<C>(&mut args[3]); let c = cast_arg::<C>(&mut args[3]);
let a = &mut args[0].write_lock::<A>().unwrap(); let a = &mut args[0].write_lock::<A>().unwrap();
@ -918,7 +921,7 @@ impl Module {
#[inline] #[inline]
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>( pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
&mut self, &mut self,
func: impl Fn(&mut A, B, C) -> FuncReturn<()> + SendSync + 'static, func: impl Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
if TypeId::of::<A>() == TypeId::of::<Array>() { if TypeId::of::<A>() == TypeId::of::<Array>() {
panic!("Cannot register indexer for arrays."); panic!("Cannot register indexer for arrays.");
@ -934,7 +937,7 @@ impl Module {
panic!("Cannot register indexer for strings."); panic!("Cannot register indexer for strings.");
} }
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let b = cast_arg::<B>(&mut args[1]); let b = cast_arg::<B>(&mut args[1]);
let c = cast_arg::<C>(&mut args[2]); let c = cast_arg::<C>(&mut args[2]);
let a = &mut args[0].write_lock::<A>().unwrap(); let a = &mut args[0].write_lock::<A>().unwrap();
@ -982,8 +985,8 @@ impl Module {
#[inline] #[inline]
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>( pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self, &mut self,
getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static, getter: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
setter: impl Fn(&mut A, B, T) -> FuncReturn<()> + SendSync + 'static, setter: impl Fn(&mut A, B, T) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
) -> (u64, u64) { ) -> (u64, u64) {
( (
self.set_indexer_get_fn(getter), self.set_indexer_get_fn(getter),
@ -1016,9 +1019,9 @@ impl Module {
>( >(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(A, B, C, D) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let a = cast_arg::<A>(&mut args[0]); let a = cast_arg::<A>(&mut args[0]);
let b = cast_arg::<B>(&mut args[1]); let b = cast_arg::<B>(&mut args[1]);
let c = cast_arg::<C>(&mut args[2]); let c = cast_arg::<C>(&mut args[2]);
@ -1066,9 +1069,9 @@ impl Module {
>( >(
&mut self, &mut self,
name: impl Into<String>, name: impl Into<String>,
func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + SendSync + 'static, func: impl Fn(&mut A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 { ) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let b = cast_arg::<B>(&mut args[1]); let b = cast_arg::<B>(&mut args[1]);
let c = cast_arg::<C>(&mut args[2]); let c = cast_arg::<C>(&mut args[2]);
let d = cast_arg::<D>(&mut args[3]); let d = cast_arg::<D>(&mut args[3]);
@ -1340,7 +1343,11 @@ impl Module {
/// # } /// # }
/// ``` /// ```
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
pub fn eval_ast_as_new(mut scope: Scope, ast: &AST, engine: &Engine) -> FuncReturn<Self> { pub fn eval_ast_as_new(
mut scope: Scope,
ast: &AST,
engine: &Engine,
) -> Result<Self, Box<EvalAltResult>> {
let mut mods = Imports::new(); let mut mods = Imports::new();
// Run the script // Run the script

View File

@ -3,8 +3,8 @@
use crate::any::{Dynamic, Variant}; use crate::any::{Dynamic, Variant};
use crate::def_package; use crate::def_package;
use crate::engine::{Array, Engine}; use crate::engine::Array;
use crate::fn_native::FnPtr; use crate::fn_native::{FnPtr, NativeCallContext};
use crate::parser::{ImmutableString, INT}; use crate::parser::{ImmutableString, INT};
use crate::plugin::*; use crate::plugin::*;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
@ -239,21 +239,20 @@ mod array_functions {
} }
fn pad<T: Variant + Clone>( fn pad<T: Variant + Clone>(
_engine: &Engine, _context: NativeCallContext,
_: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
let len = *args[1].read_lock::<INT>().unwrap(); let len = *args[1].read_lock::<INT>().unwrap();
// Check if array will be over max size limit // Check if array will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _engine.limits.max_array_size > 0 if _context.engine().max_array_size() > 0
&& len > 0 && len > 0
&& (len as usize) > _engine.limits.max_array_size && (len as usize) > _context.engine().max_array_size()
{ {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(), "Size of array".to_string(),
_engine.limits.max_array_size, _context.engine().max_array_size(),
len as usize, len as usize,
Position::none(), Position::none(),
) )
@ -271,11 +270,7 @@ fn pad<T: Variant + Clone>(
Ok(()) Ok(())
} }
fn map( fn map(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Array, Box<EvalAltResult>> {
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<Array, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap(); let list = args[0].read_lock::<Array>().unwrap();
let mapper = args[1].read_lock::<FnPtr>().unwrap(); let mapper = args[1].read_lock::<FnPtr>().unwrap();
@ -284,10 +279,10 @@ fn map(
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
array.push( array.push(
mapper mapper
.call_dynamic(engine, lib, None, [item.clone()]) .call_dynamic(context, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => { EvalAltResult::ErrorFunctionNotFound(_, _) => {
mapper.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()]) mapper.call_dynamic(context, None, [item.clone(), (i as INT).into()])
} }
_ => Err(err), _ => Err(err),
}) })
@ -305,8 +300,7 @@ fn map(
} }
fn filter( fn filter(
engine: &Engine, context: NativeCallContext,
lib: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap(); let list = args[0].read_lock::<Array>().unwrap();
@ -316,10 +310,10 @@ fn filter(
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
if filter if filter
.call_dynamic(engine, lib, None, [item.clone()]) .call_dynamic(context, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => { EvalAltResult::ErrorFunctionNotFound(_, _) => {
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()]) filter.call_dynamic(context, None, [item.clone(), (i as INT).into()])
} }
_ => Err(err), _ => Err(err),
}) })
@ -340,20 +334,16 @@ fn filter(
Ok(array) Ok(array)
} }
fn some( fn some(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<bool, Box<EvalAltResult>> {
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<bool, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap(); let list = args[0].read_lock::<Array>().unwrap();
let filter = args[1].read_lock::<FnPtr>().unwrap(); let filter = args[1].read_lock::<FnPtr>().unwrap();
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
if filter if filter
.call_dynamic(engine, lib, None, [item.clone()]) .call_dynamic(context, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => { EvalAltResult::ErrorFunctionNotFound(_, _) => {
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()]) filter.call_dynamic(context, None, [item.clone(), (i as INT).into()])
} }
_ => Err(err), _ => Err(err),
}) })
@ -374,20 +364,16 @@ fn some(
Ok(false.into()) Ok(false.into())
} }
fn all( fn all(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<bool, Box<EvalAltResult>> {
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<bool, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap(); let list = args[0].read_lock::<Array>().unwrap();
let filter = args[1].read_lock::<FnPtr>().unwrap(); let filter = args[1].read_lock::<FnPtr>().unwrap();
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
if !filter if !filter
.call_dynamic(engine, lib, None, [item.clone()]) .call_dynamic(context, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => { EvalAltResult::ErrorFunctionNotFound(_, _) => {
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()]) filter.call_dynamic(context, None, [item.clone(), (i as INT).into()])
} }
_ => Err(err), _ => Err(err),
}) })
@ -409,8 +395,7 @@ fn all(
} }
fn reduce( fn reduce(
engine: &Engine, context: NativeCallContext,
lib: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap(); let list = args[0].read_lock::<Array>().unwrap();
@ -420,14 +405,11 @@ fn reduce(
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
result = reducer result = reducer
.call_dynamic(engine, lib, None, [result.clone(), item.clone()]) .call_dynamic(context, None, [result.clone(), item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic( EvalAltResult::ErrorFunctionNotFound(_, _) => {
engine, reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
lib, }
None,
[result, item.clone(), (i as INT).into()],
),
_ => Err(err), _ => Err(err),
}) })
.map_err(|err| { .map_err(|err| {
@ -443,15 +425,14 @@ fn reduce(
} }
fn reduce_with_initial( fn reduce_with_initial(
engine: &Engine, context: NativeCallContext,
lib: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap(); let list = args[0].read_lock::<Array>().unwrap();
let reducer = args[1].read_lock::<FnPtr>().unwrap(); let reducer = args[1].read_lock::<FnPtr>().unwrap();
let initial = args[2].read_lock::<FnPtr>().unwrap(); let initial = args[2].read_lock::<FnPtr>().unwrap();
let mut result = initial.call_dynamic(engine, lib, None, []).map_err(|err| { let mut result = initial.call_dynamic(context, None, []).map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(), "reduce".to_string(),
err, err,
@ -461,14 +442,11 @@ fn reduce_with_initial(
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
result = reducer result = reducer
.call_dynamic(engine, lib, None, [result.clone(), item.clone()]) .call_dynamic(context, None, [result.clone(), item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic( EvalAltResult::ErrorFunctionNotFound(_, _) => {
engine, reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
lib, }
None,
[result, item.clone(), (i as INT).into()],
),
_ => Err(err), _ => Err(err),
}) })
.map_err(|err| { .map_err(|err| {
@ -484,8 +462,7 @@ fn reduce_with_initial(
} }
fn reduce_rev( fn reduce_rev(
engine: &Engine, context: NativeCallContext,
lib: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap(); let list = args[0].read_lock::<Array>().unwrap();
@ -495,14 +472,11 @@ fn reduce_rev(
for (i, item) in list.iter().enumerate().rev() { for (i, item) in list.iter().enumerate().rev() {
result = reducer result = reducer
.call_dynamic(engine, lib, None, [result.clone(), item.clone()]) .call_dynamic(context, None, [result.clone(), item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic( EvalAltResult::ErrorFunctionNotFound(_, _) => {
engine, reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
lib, }
None,
[result, item.clone(), (i as INT).into()],
),
_ => Err(err), _ => Err(err),
}) })
.map_err(|err| { .map_err(|err| {
@ -518,15 +492,14 @@ fn reduce_rev(
} }
fn reduce_rev_with_initial( fn reduce_rev_with_initial(
engine: &Engine, context: NativeCallContext,
lib: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap(); let list = args[0].read_lock::<Array>().unwrap();
let reducer = args[1].read_lock::<FnPtr>().unwrap(); let reducer = args[1].read_lock::<FnPtr>().unwrap();
let initial = args[2].read_lock::<FnPtr>().unwrap(); let initial = args[2].read_lock::<FnPtr>().unwrap();
let mut result = initial.call_dynamic(engine, lib, None, []).map_err(|err| { let mut result = initial.call_dynamic(context, None, []).map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(), "reduce".to_string(),
err, err,
@ -536,14 +509,11 @@ fn reduce_rev_with_initial(
for (i, item) in list.iter().enumerate().rev() { for (i, item) in list.iter().enumerate().rev() {
result = reducer result = reducer
.call_dynamic(engine, lib, None, [result.clone(), item.clone()]) .call_dynamic(context, None, [result.clone(), item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic( EvalAltResult::ErrorFunctionNotFound(_, _) => {
engine, reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
lib, }
None,
[result, item.clone(), (i as INT).into()],
),
_ => Err(err), _ => Err(err),
}) })
.map_err(|err| { .map_err(|err| {
@ -559,8 +529,7 @@ fn reduce_rev_with_initial(
} }
fn sort( fn sort(
engine: &Engine, context: NativeCallContext,
lib: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let comparer = args[1].read_lock::<FnPtr>().unwrap().clone(); let comparer = args[1].read_lock::<FnPtr>().unwrap().clone();
@ -568,7 +537,7 @@ fn sort(
list.sort_by(|x, y| { list.sort_by(|x, y| {
comparer comparer
.call_dynamic(engine, lib, None, [x.clone(), y.clone()]) .call_dynamic(context, None, [x.clone(), y.clone()])
.ok() .ok()
.and_then(|v| v.as_int().ok()) .and_then(|v| v.as_int().ok())
.map(|v| { .map(|v| {
@ -598,8 +567,7 @@ fn sort(
} }
fn drain( fn drain(
engine: &Engine, context: NativeCallContext,
lib: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
let filter = args[1].read_lock::<FnPtr>().unwrap().clone(); let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
@ -613,10 +581,10 @@ fn drain(
i -= 1; i -= 1;
if filter if filter
.call_dynamic(engine, lib, None, [list[i].clone()]) .call_dynamic(context, None, [list[i].clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => { EvalAltResult::ErrorFunctionNotFound(_, _) => {
filter.call_dynamic(engine, lib, None, [list[i].clone(), (i as INT).into()]) filter.call_dynamic(context, None, [list[i].clone(), (i as INT).into()])
} }
_ => Err(err), _ => Err(err),
}) })
@ -638,8 +606,7 @@ fn drain(
} }
fn retain( fn retain(
engine: &Engine, context: NativeCallContext,
lib: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
let filter = args[1].read_lock::<FnPtr>().unwrap().clone(); let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
@ -653,10 +620,10 @@ fn retain(
i -= 1; i -= 1;
if !filter if !filter
.call_dynamic(engine, lib, None, [list[i].clone()]) .call_dynamic(context, None, [list[i].clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => { EvalAltResult::ErrorFunctionNotFound(_, _) => {
filter.call_dynamic(engine, lib, None, [list[i].clone(), (i as INT).into()]) filter.call_dynamic(context, None, [list[i].clone(), (i as INT).into()])
} }
_ => Err(err), _ => Err(err),
}) })

View File

@ -12,4 +12,8 @@ mod fn_ptr_functions {
pub fn name(f: &mut FnPtr) -> ImmutableString { pub fn name(f: &mut FnPtr) -> ImmutableString {
f.get_fn_name().clone() f.get_fn_name().clone()
} }
#[rhai_fn(name = "is_anonymous", get = "is_anonymous")]
pub fn is_anonymous(f: &mut FnPtr) -> bool {
f.is_anonymous()
}
} }

View File

@ -1,11 +1,11 @@
use crate::any::Variant; use crate::any::Variant;
use crate::def_package; use crate::def_package;
use crate::module::FuncReturn;
use crate::parser::INT; use crate::parser::INT;
use crate::result::EvalAltResult;
use crate::stdlib::ops::{Add, Range}; use crate::stdlib::ops::{Add, Range};
fn get_range<T: Variant + Clone>(from: T, to: T) -> FuncReturn<Range<T>> { fn get_range<T: Variant + Clone>(from: T, to: T) -> Result<Range<T>, Box<EvalAltResult>> {
Ok(from..to) Ok(from..to)
} }
@ -34,7 +34,7 @@ where
} }
} }
fn get_step_range<T>(from: T, to: T, step: T) -> FuncReturn<StepRange<T>> fn get_step_range<T>(from: T, to: T, step: T) -> Result<StepRange<T>, Box<EvalAltResult>>
where where
for<'a> &'a T: Add<&'a T, Output = T>, for<'a> &'a T: Add<&'a T, Output = T>,
T: Variant + Clone + PartialOrd, T: Variant + Clone + PartialOrd,

View File

@ -2,7 +2,6 @@
use crate::any::Dynamic; use crate::any::Dynamic;
use crate::def_package; use crate::def_package;
use crate::engine::Engine;
use crate::fn_native::FnPtr; use crate::fn_native::FnPtr;
use crate::parser::{ImmutableString, INT}; use crate::parser::{ImmutableString, INT};
use crate::plugin::*; use crate::plugin::*;
@ -62,15 +61,17 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
lib.set_raw_fn( lib.set_raw_fn(
"pad", "pad",
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()], &[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()],
|_engine: &Engine, _: &Module, args: &mut [&mut Dynamic]| { |_context, args| {
let len = *args[1].read_lock::<INT>().unwrap(); let len = *args[1].read_lock::<INT>().unwrap();
// Check if string will be over max size limit // Check if string will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _engine.limits.max_string_size > 0 && len > 0 && (len as usize) > _engine.limits.max_string_size { if _context.engine().max_string_size() > 0 && len > 0
&& (len as usize) > _context.engine().max_string_size()
{
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
_engine.limits.max_string_size, _context.engine().max_string_size(),
len as usize, len as usize,
Position::none(), Position::none(),
).into(); ).into();
@ -90,10 +91,10 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
} }
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _engine.limits.max_string_size > 0 && s.len() > _engine.limits.max_string_size { if _context.engine().max_string_size() > 0 && s.len() > _context.engine().max_string_size() {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
_engine.limits.max_string_size, _context.engine().max_string_size(),
s.len(), s.len(),
Position::none(), Position::none(),
).into(); ).into();

View File

@ -1,9 +1,7 @@
//! Main module defining the lexer and parser. //! Main module defining the lexer and parser.
use crate::any::{Dynamic, Union}; use crate::any::{Dynamic, Union};
use crate::engine::{ use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
Engine, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT,
};
use crate::error::{LexError, ParseError, ParseErrorType}; use crate::error::{LexError, ParseError, ParseErrorType};
use crate::fn_native::{FnPtr, Shared}; use crate::fn_native::{FnPtr, Shared};
use crate::module::{Module, ModuleRef}; use crate::module::{Module, ModuleRef};
@ -18,7 +16,7 @@ use crate::{calc_fn_hash, StaticVec};
use crate::engine::Array; use crate::engine::Array;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::engine::{make_getter, make_setter, Map}; use crate::engine::{make_getter, make_setter, Map, KEYWORD_EVAL, KEYWORD_FN_PTR};
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY}; use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY};
@ -603,13 +601,15 @@ struct ParseState<'e> {
/// All consequent calls to `access_var` will not be affected /// All consequent calls to `access_var` will not be affected
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
allow_capture: bool, allow_capture: bool,
/// Encapsulates a local stack with variable names to simulate an actual runtime scope. /// Encapsulates a local stack with imported module names.
#[cfg(not(feature = "no_module"))]
modules: Vec<String>, modules: Vec<String>,
/// Maximum levels of expression nesting. /// Maximum levels of expression nesting.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
max_expr_depth: usize, max_expr_depth: usize,
/// Maximum levels of expression nesting in functions. /// Maximum levels of expression nesting in functions.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
max_function_expr_depth: usize, max_function_expr_depth: usize,
} }
@ -619,19 +619,23 @@ impl<'e> ParseState<'e> {
pub fn new( pub fn new(
engine: &'e Engine, engine: &'e Engine,
#[cfg(not(feature = "unchecked"))] max_expr_depth: usize, #[cfg(not(feature = "unchecked"))] max_expr_depth: usize,
#[cfg(not(feature = "unchecked"))] max_function_expr_depth: usize, #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
max_function_expr_depth: usize,
) -> Self { ) -> Self {
Self { Self {
engine, engine,
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
max_expr_depth, max_expr_depth,
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
max_function_expr_depth, max_function_expr_depth,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
externals: Default::default(), externals: Default::default(),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
allow_capture: true, allow_capture: true,
stack: Default::default(), stack: Default::default(),
#[cfg(not(feature = "no_module"))]
modules: Default::default(), modules: Default::default(),
} }
} }
@ -1696,11 +1700,10 @@ fn parse_array_literal(
while !input.peek().unwrap().0.is_eof() { while !input.peek().unwrap().0.is_eof() {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if state.engine.limits.max_array_size > 0 && arr.len() >= state.engine.limits.max_array_size if state.engine.max_array_size() > 0 && arr.len() >= state.engine.max_array_size() {
{
return Err(PERR::LiteralTooLarge( return Err(PERR::LiteralTooLarge(
"Size of array literal".to_string(), "Size of array literal".to_string(),
state.engine.limits.max_array_size, state.engine.max_array_size(),
) )
.into_err(input.peek().unwrap().1)); .into_err(input.peek().unwrap().1));
} }
@ -1804,10 +1807,10 @@ fn parse_map_literal(
}; };
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if state.engine.limits.max_map_size > 0 && map.len() >= state.engine.limits.max_map_size { if state.engine.max_map_size() > 0 && map.len() >= state.engine.max_map_size() {
return Err(PERR::LiteralTooLarge( return Err(PERR::LiteralTooLarge(
"Number of properties in object map literal".to_string(), "Number of properties in object map literal".to_string(),
state.engine.limits.max_map_size, state.engine.max_map_size(),
) )
.into_err(input.peek().unwrap().1)); .into_err(input.peek().unwrap().1));
} }
@ -3599,9 +3602,10 @@ impl Engine {
let mut state = ParseState::new( let mut state = ParseState::new(
self, self,
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.limits.max_expr_depth, self.max_expr_depth(),
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.limits.max_function_expr_depth, #[cfg(not(feature = "no_function"))]
self.max_function_expr_depth(),
); );
let settings = ParseSettings { let settings = ParseSettings {
@ -3646,9 +3650,10 @@ impl Engine {
let mut state = ParseState::new( let mut state = ParseState::new(
self, self,
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.limits.max_expr_depth, self.max_expr_depth(),
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.limits.max_function_expr_depth, #[cfg(not(feature = "no_function"))]
self.max_function_expr_depth(),
); );
while !input.peek().unwrap().0.is_eof() { while !input.peek().unwrap().0.is_eof() {

View File

@ -53,7 +53,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self { pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self {
self.limits.max_call_stack_depth = levels; self.limits_set.max_call_stack_depth = levels;
self self
} }
@ -61,7 +61,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn max_call_levels(&self) -> usize { pub fn max_call_levels(&self) -> usize {
self.limits.max_call_stack_depth self.limits_set.max_call_stack_depth
} }
/// Set the maximum number of operations allowed for a script to run to avoid /// Set the maximum number of operations allowed for a script to run to avoid
@ -69,7 +69,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self { pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
self.limits.max_operations = if operations == u64::MAX { self.limits_set.max_operations = if operations == u64::MAX {
0 0
} else { } else {
operations operations
@ -81,14 +81,14 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn max_operations(&self) -> u64 { pub fn max_operations(&self) -> u64 {
self.limits.max_operations self.limits_set.max_operations
} }
/// Set the maximum number of imported modules allowed for a script. /// Set the maximum number of imported modules allowed for a script.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn set_max_modules(&mut self, modules: usize) -> &mut Self { pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
self.limits.max_modules = modules; self.limits_set.max_modules = modules;
self self
} }
@ -96,7 +96,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn max_modules(&self) -> usize { pub fn max_modules(&self) -> usize {
self.limits.max_modules self.limits_set.max_modules
} }
/// Set the depth limits for expressions (0 for unlimited). /// Set the depth limits for expressions (0 for unlimited).
@ -105,18 +105,21 @@ impl Engine {
pub fn set_max_expr_depths( pub fn set_max_expr_depths(
&mut self, &mut self,
max_expr_depth: usize, max_expr_depth: usize,
max_function_expr_depth: usize, #[cfg(not(feature = "no_function"))] max_function_expr_depth: usize,
) -> &mut Self { ) -> &mut Self {
self.limits.max_expr_depth = if max_expr_depth == usize::MAX { self.limits_set.max_expr_depth = if max_expr_depth == usize::MAX {
0 0
} else { } else {
max_expr_depth max_expr_depth
}; };
self.limits.max_function_expr_depth = if max_function_expr_depth == usize::MAX { #[cfg(not(feature = "no_function"))]
0 {
} else { self.limits_set.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
max_function_expr_depth 0
}; } else {
max_function_expr_depth
};
}
self self
} }
@ -124,21 +127,22 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn max_expr_depth(&self) -> usize { pub fn max_expr_depth(&self) -> usize {
self.limits.max_expr_depth self.limits_set.max_expr_depth
} }
/// The depth limit for expressions in functions (0 for unlimited). /// The depth limit for expressions in functions (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
pub fn max_function_expr_depth(&self) -> usize { pub fn max_function_expr_depth(&self) -> usize {
self.limits.max_function_expr_depth self.limits_set.max_function_expr_depth
} }
/// Set the maximum length of strings (0 for unlimited). /// Set the maximum length of strings (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self { pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
self.limits.max_string_size = if max_size == usize::MAX { 0 } else { max_size }; self.limits_set.max_string_size = if max_size == usize::MAX { 0 } else { max_size };
self self
} }
@ -146,7 +150,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
pub fn max_string_size(&self) -> usize { pub fn max_string_size(&self) -> usize {
self.limits.max_string_size self.limits_set.max_string_size
} }
/// Set the maximum length of arrays (0 for unlimited). /// Set the maximum length of arrays (0 for unlimited).
@ -154,7 +158,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
#[inline(always)] #[inline(always)]
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self { pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
self.limits.max_array_size = if max_size == usize::MAX { 0 } else { max_size }; self.limits_set.max_array_size = if max_size == usize::MAX { 0 } else { max_size };
self self
} }
@ -163,7 +167,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
#[inline(always)] #[inline(always)]
pub fn max_array_size(&self) -> usize { pub fn max_array_size(&self) -> usize {
self.limits.max_array_size self.limits_set.max_array_size
} }
/// Set the maximum length of object maps (0 for unlimited). /// Set the maximum length of object maps (0 for unlimited).
@ -171,7 +175,7 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self { pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
self.limits.max_map_size = if max_size == usize::MAX { 0 } else { max_size }; self.limits_set.max_map_size = if max_size == usize::MAX { 0 } else { max_size };
self self
} }
@ -180,7 +184,7 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn max_map_size(&self) -> usize { pub fn max_map_size(&self) -> usize {
self.limits.max_map_size self.limits_set.max_map_size
} }
/// Set the module resolution service used by the `Engine`. /// Set the module resolution service used by the `Engine`.

View File

@ -67,14 +67,14 @@ impl EvalContext<'_, '_, '_, '_, '_, '_> {
scope: &mut Scope, scope: &mut Scope,
expr: &Expression, expr: &Expression,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
self.engine.eval_expr( self.engine().eval_expr(
scope, scope,
self.mods, self.mods,
self.state, self.state,
self.lib, self.namespace(),
self.this_ptr, self.this_ptr,
expr.expr(), expr.expr(),
self.level, self.call_level(),
) )
} }
} }

View File

@ -1747,7 +1747,7 @@ pub fn lex<'a, 'e>(
engine, engine,
state: TokenizeState { state: TokenizeState {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
max_string_size: engine.limits.max_string_size, max_string_size: engine.limits_set.max_string_size,
#[cfg(feature = "unchecked")] #[cfg(feature = "unchecked")]
max_string_size: 0, max_string_size: 0,
non_unary: false, non_unary: false,

View File

@ -98,12 +98,12 @@ fn test_fn_ptr_raw() -> Result<(), Box<EvalAltResult>> {
TypeId::of::<FnPtr>(), TypeId::of::<FnPtr>(),
TypeId::of::<INT>(), TypeId::of::<INT>(),
], ],
move |engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| { move |context, args| {
let fp = std::mem::take(args[1]).cast::<FnPtr>(); let fp = std::mem::take(args[1]).cast::<FnPtr>();
let value = args[2].clone(); let value = args[2].clone();
let this_ptr = args.get_mut(0).unwrap(); let this_ptr = args.get_mut(0).unwrap();
fp.call_dynamic(engine, lib, Some(this_ptr), [value]) fp.call_dynamic(context, Some(this_ptr), [value])
}, },
); );

View File

@ -1,5 +1,5 @@
#![cfg(not(feature = "no_function"))] #![cfg(not(feature = "no_function"))]
use rhai::{Dynamic, Engine, EvalAltResult, FnPtr, Module, ParseErrorType, RegisterFn, Scope, INT}; use rhai::{Engine, EvalAltResult, FnPtr, ParseErrorType, RegisterFn, Scope, INT};
use std::any::TypeId; use std::any::TypeId;
use std::cell::RefCell; use std::cell::RefCell;
use std::mem::take; use std::mem::take;
@ -16,9 +16,9 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
engine.register_raw_fn( engine.register_raw_fn(
"call_with_arg", "call_with_arg",
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()], &[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| { |context, args| {
let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>(); let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>();
fn_ptr.call_dynamic(engine, lib, None, [std::mem::take(args[1])]) fn_ptr.call_dynamic(context, None, [std::mem::take(args[1])])
}, },
); );
@ -135,10 +135,10 @@ fn test_closures() -> Result<(), Box<EvalAltResult>> {
engine.register_raw_fn( engine.register_raw_fn(
"custom_call", "custom_call",
&[TypeId::of::<INT>(), TypeId::of::<FnPtr>()], &[TypeId::of::<INT>(), TypeId::of::<FnPtr>()],
|engine: &Engine, module: &Module, args: &mut [&mut Dynamic]| { |context, args| {
let func = take(args[1]).cast::<FnPtr>(); let func = take(args[1]).cast::<FnPtr>();
func.call_dynamic(engine, module, None, []) func.call_dynamic(context, None, [])
}, },
); );
@ -259,7 +259,6 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
let mut ast = engine.compile( let mut ast = engine.compile(
r#" r#"
let test = "hello"; let test = "hello";
|x| test + x |x| test + x
"#, "#,
)?; )?;
@ -271,7 +270,7 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
ast.retain_functions(|_, _, _| true); ast.retain_functions(|_, _, _| true);
// Closure 'f' captures: the engine, the AST, and the curried function pointer // Closure 'f' captures: the engine, the AST, and the curried function pointer
let f = move |x: INT| fn_ptr.call_dynamic(&engine, ast, None, [x.into()]); let f = move |x: INT| fn_ptr.call_dynamic((&engine, ast.as_ref()).into(), None, [x.into()]);
assert_eq!(f(42)?.as_str(), Ok("hello42")); assert_eq!(f(42)?.as_str(), Ok("hello42"));