Encapsulate register_fn_raw parameters into NativeCallContext.
This commit is contained in:
parent
58c820785b
commit
82e6dd446a
@ -10,6 +10,7 @@ Breaking changes
|
||||
|
||||
* `EvalAltResult::ErrorReadingScriptFile` is removed in favor of the new `EvalAltResult::ErrorSystem`.
|
||||
* `EvalAltResult::ErrorLoopBreak` is renamed to `EvalAltResult::LoopBreak`.
|
||||
* `Engine::register_raw_fn` function signature has changed.
|
||||
|
||||
Enhancements
|
||||
|
||||
|
@ -17,10 +17,11 @@ Built-in methods
|
||||
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
|
||||
using a [raw `Engine`]) operate on function pointers:
|
||||
|
||||
| Function | Parameter(s) | Description |
|
||||
| -------------------------- | ------------ | ---------------------------------------------------------------------------- |
|
||||
| `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_ |
|
||||
| Function | Parameter(s) | Description |
|
||||
| ---------------------------------- | ------------ | ---------------------------------------------------------------------------- |
|
||||
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
|
||||
| `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
|
||||
@ -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.
|
||||
`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,
|
||||
and other necessary arguments.
|
||||
current _native call context_, the `this` pointer, and other necessary arguments.
|
||||
|
||||
```rust
|
||||
use rhai::{Engine, Module, Dynamic, FnPtr};
|
||||
use rhai::{Engine, Module, Dynamic, FnPtr, NativeCallContext};
|
||||
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// 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>>
|
||||
{
|
||||
// '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.
|
||||
// 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
|
||||
@ -218,3 +218,43 @@ engine.register_raw_fn("super_call",
|
||||
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)?;
|
||||
```
|
||||
|
@ -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.
|
||||
|
||||
In particular, a reference to the current `Engine` instance is passed as an argument so the Rust function
|
||||
can also use `Engine` facilities (like evaluating a script).
|
||||
In particular, a the current _native call context_ (in form of the `NativeCallContext` type) is passed as an argument.
|
||||
`NativeCallContext` exposes the current [`Engine`], among others, so the Rust function can also use [`Engine`] facilities
|
||||
(such as evaluating a script).
|
||||
|
||||
```rust
|
||||
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 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.
|
||||
|
||||
// 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:
|
||||
|
||||
> `Fn(engine: &Engine, lib: &Module, args: &mut [&mut Dynamic])`
|
||||
> `-> Result<T, Box<EvalAltResult>> + 'static`
|
||||
> `Fn(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>> + 'static`
|
||||
|
||||
where:
|
||||
|
||||
* `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`].
|
||||
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`].
|
||||
* `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`].
|
||||
|
||||
* `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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
use rhai::{Engine, Module, Dynamic, FnPtr};
|
||||
use rhai::{Engine, FnPtr};
|
||||
|
||||
let mut engine = Engine::new();
|
||||
|
||||
@ -118,7 +121,7 @@ engine.register_raw_fn(
|
||||
std::any::TypeId::of::<FnPtr>(),
|
||||
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
|
||||
|
||||
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.
|
||||
// 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])
|
||||
},
|
||||
);
|
||||
|
||||
|
13
src/api.rs
13
src/api.rs
@ -3,8 +3,7 @@
|
||||
use crate::any::{Dynamic, Variant};
|
||||
use crate::engine::{Engine, EvalContext, Imports, State};
|
||||
use crate::error::ParseError;
|
||||
use crate::fn_native::SendSync;
|
||||
use crate::module::{FuncReturn, Module};
|
||||
use crate::fn_native::{NativeCallContext, SendSync};
|
||||
use crate::optimize::OptimizationLevel;
|
||||
use crate::parser::AST;
|
||||
use crate::result::EvalAltResult;
|
||||
@ -28,7 +27,7 @@ use crate::{
|
||||
use crate::fn_register::{RegisterFn, RegisterResultFn};
|
||||
|
||||
#[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"))]
|
||||
use crate::optimize::optimize_into_ast;
|
||||
@ -69,7 +68,9 @@ impl Engine {
|
||||
&mut self,
|
||||
name: &str,
|
||||
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 {
|
||||
self.global_module.set_raw_fn(name, arg_types, func);
|
||||
self
|
||||
@ -1622,7 +1623,7 @@ impl Engine {
|
||||
name: &str,
|
||||
mut this_ptr: Option<&mut Dynamic>,
|
||||
mut arg_values: impl AsMut<[Dynamic]>,
|
||||
) -> FuncReturn<Dynamic> {
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
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())
|
||||
@ -1645,7 +1646,7 @@ impl Engine {
|
||||
name: &str,
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> FuncReturn<Dynamic> {
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let fn_def = lib
|
||||
.get_script_fn(name, args.len(), true)
|
||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
||||
|
140
src/engine.rs
140
src/engine.rs
@ -1,12 +1,12 @@
|
||||
//! 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_native::{Callback, FnPtr, OnVarCallback};
|
||||
use crate::module::{Module, ModuleRef};
|
||||
use crate::optimize::OptimizationLevel;
|
||||
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::result::EvalAltResult;
|
||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||
@ -14,8 +14,8 @@ use crate::syntax::CustomSyntax;
|
||||
use crate::token::Position;
|
||||
use crate::{calc_fn_hash, StaticVec};
|
||||
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
use crate::any::Variant;
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::parser::INT;
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
use crate::module::ModuleResolver;
|
||||
@ -80,6 +80,7 @@ pub const MAX_CALL_STACK_DEPTH: usize = 12;
|
||||
#[cfg(debug_assertions)]
|
||||
pub const MAX_EXPR_DEPTH: usize = 32;
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(debug_assertions)]
|
||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16;
|
||||
|
||||
@ -90,6 +91,7 @@ pub const MAX_CALL_STACK_DEPTH: usize = 128;
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub const MAX_EXPR_DEPTH: usize = 128;
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
|
||||
|
||||
@ -144,6 +146,7 @@ impl IndexChainValue {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if not `IndexChainValue::Value`.
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
pub fn as_value(self) -> Dynamic {
|
||||
match self {
|
||||
Self::None | Self::FnCallArgs(_) => panic!("expecting IndexChainValue::Value"),
|
||||
@ -155,6 +158,7 @@ impl IndexChainValue {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if not `IndexChainValue::FnCallArgs`.
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
pub fn as_fn_call_args(self) -> StaticVec<Dynamic> {
|
||||
match self {
|
||||
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.
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
#[derive(Debug)]
|
||||
pub enum Target<'a> {
|
||||
/// 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),
|
||||
}
|
||||
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
impl<'a> Target<'a> {
|
||||
/// Is the `Target` a reference pointing to other data?
|
||||
#[allow(dead_code)]
|
||||
@ -306,6 +308,7 @@ impl<'a> Target<'a> {
|
||||
}
|
||||
}
|
||||
/// Update the value of the `Target`.
|
||||
#[cfg(any(not(feature = "no_object"), not(feature = "no_index")))]
|
||||
pub fn set_value(
|
||||
&mut self,
|
||||
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> {
|
||||
#[inline(always)]
|
||||
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<'_> {
|
||||
#[inline(always)]
|
||||
fn from(value: T) -> Self {
|
||||
@ -414,35 +415,44 @@ pub struct Limits {
|
||||
///
|
||||
/// Defaults to 16 for debug builds and 128 for non-debug builds.
|
||||
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,
|
||||
/// 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,
|
||||
/// Maximum number of operations allowed to run.
|
||||
/// Maximum number of operations allowed to run (0 = unlimited).
|
||||
pub max_operations: u64,
|
||||
/// Maximum number of modules allowed to load.
|
||||
/// Not available under `no_module`.
|
||||
#[cfg(not(feature = "no_modules"))]
|
||||
pub max_modules: usize,
|
||||
/// Maximum length of a string.
|
||||
/// Maximum length of a string (0 = unlimited).
|
||||
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,
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// Context of a script evaluation process.
|
||||
#[derive(Debug)]
|
||||
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) state: &'s mut State,
|
||||
pub(crate) lib: &'m Module,
|
||||
lib: &'m Module,
|
||||
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> {
|
||||
/// The current `Engine`.
|
||||
#[inline(always)]
|
||||
pub fn engine(&self) -> &'e 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.
|
||||
#[cfg(feature = "internals")]
|
||||
#[cfg(not(feature = "no_modules"))]
|
||||
#[inline(always)]
|
||||
pub fn imports(&self) -> &'a Imports {
|
||||
self.mods
|
||||
}
|
||||
/// The global namespace containing definition of all script-defined functions.
|
||||
#[inline(always)]
|
||||
pub fn namespace(&self) -> &'m Module {
|
||||
self.lib
|
||||
}
|
||||
/// The current nesting level of function calls.
|
||||
#[inline(always)]
|
||||
pub fn call_level(&self) -> usize {
|
||||
self.level
|
||||
}
|
||||
@ -516,7 +529,7 @@ pub struct Engine {
|
||||
|
||||
/// Max limits.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
pub(crate) limits: Limits,
|
||||
pub(crate) limits_set: Limits,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Engine {
|
||||
@ -662,14 +675,18 @@ impl Engine {
|
||||
},
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
limits: Limits {
|
||||
limits_set: Limits {
|
||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||
max_expr_depth: MAX_EXPR_DEPTH,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||
max_operations: 0,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
max_modules: usize::MAX,
|
||||
max_string_size: 0,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
max_array_size: 0,
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
max_map_size: 0,
|
||||
},
|
||||
};
|
||||
@ -710,14 +727,18 @@ impl Engine {
|
||||
},
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
limits: Limits {
|
||||
limits_set: Limits {
|
||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||
max_expr_depth: MAX_EXPR_DEPTH,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||
max_operations: 0,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
max_modules: usize::MAX,
|
||||
max_string_size: 0,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
max_array_size: 0,
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
max_map_size: 0,
|
||||
},
|
||||
}
|
||||
@ -1285,7 +1306,7 @@ impl Engine {
|
||||
) -> Result<Target<'a>, Box<EvalAltResult>> {
|
||||
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 val = target.as_mut();
|
||||
@ -1542,7 +1563,7 @@ impl Engine {
|
||||
if func.is_plugin_fn() {
|
||||
func.get_plugin_fn().call(args)?;
|
||||
} else {
|
||||
func.get_native_fn()(self, lib, args)?;
|
||||
func.get_native_fn()((self, lib).into(), args)?;
|
||||
}
|
||||
}
|
||||
// Built-in op-assignment function
|
||||
@ -1954,7 +1975,7 @@ impl Engine {
|
||||
|
||||
// Guard against too many modules
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if state.modules >= self.limits.max_modules {
|
||||
if state.modules >= self.max_modules() {
|
||||
return EvalAltResult::ErrorTooManyModules(*_pos).into();
|
||||
}
|
||||
|
||||
@ -2042,8 +2063,19 @@ impl Engine {
|
||||
result: Result<Dynamic, Box<EvalAltResult>>,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -2103,46 +2135,52 @@ impl Engine {
|
||||
// Simply return all errors
|
||||
Err(_) => return result,
|
||||
// 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
|
||||
#[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
|
||||
#[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
|
||||
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 {
|
||||
EvalAltResult::ErrorDataTooLarge(
|
||||
if s > self.max_string_size() {
|
||||
return EvalAltResult::ErrorDataTooLarge(
|
||||
"Length of string".to_string(),
|
||||
self.limits.max_string_size,
|
||||
self.max_string_size(),
|
||||
s,
|
||||
Position::none(),
|
||||
)
|
||||
.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
|
||||
.into();
|
||||
}
|
||||
|
||||
#[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.
|
||||
@ -2152,7 +2190,7 @@ impl Engine {
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ impl Engine {
|
||||
let result = if func.is_plugin_fn() {
|
||||
func.get_plugin_fn().call(args)
|
||||
} else {
|
||||
func.get_native_fn()(self, lib, args)
|
||||
func.get_native_fn()((self, lib).into(), args)
|
||||
};
|
||||
|
||||
// Restore the original reference
|
||||
@ -356,7 +356,7 @@ impl Engine {
|
||||
// Check for stack overflow
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if level > self.limits.max_call_stack_depth {
|
||||
if level > self.max_call_levels() {
|
||||
return Err(Box::new(
|
||||
EvalAltResult::ErrorStackOverflow(Position::none()),
|
||||
));
|
||||
@ -648,7 +648,7 @@ impl Engine {
|
||||
// Check for stack overflow
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if _level > self.limits.max_call_stack_depth {
|
||||
if _level > self.max_call_levels() {
|
||||
return Err(Box::new(
|
||||
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!(),
|
||||
None if def_val.is_some() => Ok(def_val.unwrap().into()),
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Module defining interfaces to native-Rust functions.
|
||||
|
||||
use crate::any::Dynamic;
|
||||
use crate::engine::{Engine, EvalContext};
|
||||
use crate::engine::{Engine, EvalContext, FN_ANONYMOUS};
|
||||
use crate::module::Module;
|
||||
use crate::parser::{FnAccess, ScriptFnDef};
|
||||
use crate::plugin::PluginFunction;
|
||||
@ -46,6 +46,35 @@ pub type Locked<T> = RefCell<T>;
|
||||
#[cfg(feature = "sync")]
|
||||
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.
|
||||
/// 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 {
|
||||
@ -108,6 +137,11 @@ impl FnPtr {
|
||||
pub fn curry(&self) -> &[Dynamic] {
|
||||
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).
|
||||
///
|
||||
@ -121,8 +155,7 @@ impl FnPtr {
|
||||
/// clone them _before_ calling this function.
|
||||
pub fn call_dynamic(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
lib: impl AsRef<Module>,
|
||||
context: NativeCallContext,
|
||||
this_ptr: Option<&mut Dynamic>,
|
||||
mut arg_values: impl AsMut<[Dynamic]>,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
@ -144,10 +177,11 @@ impl FnPtr {
|
||||
args.insert(0, obj);
|
||||
}
|
||||
|
||||
engine
|
||||
context
|
||||
.engine()
|
||||
.exec_fn_call(
|
||||
&mut Default::default(),
|
||||
lib.as_ref(),
|
||||
context.namespace(),
|
||||
fn_name,
|
||||
hash_script,
|
||||
args.as_mut(),
|
||||
@ -204,11 +238,11 @@ impl TryFrom<&str> for FnPtr {
|
||||
|
||||
/// A general function trail object.
|
||||
#[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.
|
||||
#[cfg(feature = "sync")]
|
||||
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.
|
||||
pub type IteratorFn = fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
|
||||
|
@ -4,8 +4,7 @@
|
||||
|
||||
use crate::any::{Dynamic, DynamicWriteLock, Variant};
|
||||
use crate::engine::Engine;
|
||||
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync};
|
||||
use crate::module::Module;
|
||||
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, NativeCallContext, SendSync};
|
||||
use crate::parser::FnAccess;
|
||||
use crate::r#unsafe::unsafe_cast_box;
|
||||
use crate::result::EvalAltResult;
|
||||
@ -127,7 +126,7 @@ macro_rules! make_func {
|
||||
// ^ dereferencing function
|
||||
// ^ 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!
|
||||
|
||||
let mut _drain = args.iter_mut();
|
||||
|
@ -85,7 +85,7 @@ mod utils;
|
||||
pub use any::Dynamic;
|
||||
pub use engine::{Engine, EvalContext};
|
||||
pub use error::{ParseError, ParseErrorType};
|
||||
pub use fn_native::FnPtr;
|
||||
pub use fn_native::{FnPtr, NativeCallContext};
|
||||
pub use fn_register::{RegisterFn, RegisterResultFn};
|
||||
pub use module::Module;
|
||||
pub use parser::{ImmutableString, AST, INT};
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::any::{Dynamic, Variant};
|
||||
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::parser::FnAccess;
|
||||
use crate::result::EvalAltResult;
|
||||
@ -24,7 +24,11 @@ use crate::{
|
||||
use crate::engine::{Array, FN_IDX_GET, FN_IDX_SET};
|
||||
|
||||
#[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::{
|
||||
any::TypeId,
|
||||
@ -38,9 +42,6 @@ use crate::stdlib::{
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
/// Return type of module-level Rust function.
|
||||
pub type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
|
||||
|
||||
pub type FuncInfo = (
|
||||
String,
|
||||
FnAccess,
|
||||
@ -536,10 +537,12 @@ impl Module {
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
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 {
|
||||
let f = move |engine: &Engine, lib: &Module, args: &mut FnCallArgs| {
|
||||
func(engine, lib, args).map(Dynamic::from)
|
||||
let f = move |context: NativeCallContext, args: &mut [&mut Dynamic]| {
|
||||
func(context, args).map(Dynamic::from)
|
||||
};
|
||||
self.set_fn(
|
||||
name,
|
||||
@ -566,9 +569,9 @@ impl Module {
|
||||
pub fn set_fn_0<T: Variant + Clone>(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
func: impl Fn() -> FuncReturn<T> + SendSync + 'static,
|
||||
func: impl Fn() -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> 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 = [];
|
||||
self.set_fn(
|
||||
name,
|
||||
@ -595,9 +598,9 @@ impl Module {
|
||||
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
func: impl Fn(A) -> FuncReturn<T> + SendSync + 'static,
|
||||
func: impl Fn(A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> 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)
|
||||
};
|
||||
let arg_types = [TypeId::of::<A>()];
|
||||
@ -626,9 +629,9 @@ impl Module {
|
||||
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
|
||||
&mut self,
|
||||
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 {
|
||||
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)
|
||||
};
|
||||
let arg_types = [TypeId::of::<A>()];
|
||||
@ -658,7 +661,7 @@ impl Module {
|
||||
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
|
||||
&mut self,
|
||||
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 {
|
||||
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>(
|
||||
&mut self,
|
||||
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 {
|
||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||
let a = cast_arg::<A>(&mut args[0]);
|
||||
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>(
|
||||
&mut self,
|
||||
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 {
|
||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||
let b = cast_arg::<B>(&mut args[1]);
|
||||
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>(
|
||||
&mut self,
|
||||
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 {
|
||||
self.set_fn_2_mut(make_setter(&name.into()), func)
|
||||
}
|
||||
@ -788,7 +791,7 @@ impl Module {
|
||||
#[inline]
|
||||
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||
&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 {
|
||||
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
@ -831,9 +834,9 @@ impl Module {
|
||||
>(
|
||||
&mut self,
|
||||
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 {
|
||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||
let a = cast_arg::<A>(&mut args[0]);
|
||||
let b = cast_arg::<B>(&mut args[1]);
|
||||
let c = cast_arg::<C>(&mut args[2]);
|
||||
@ -874,9 +877,9 @@ impl Module {
|
||||
>(
|
||||
&mut self,
|
||||
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 {
|
||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||
let b = cast_arg::<B>(&mut args[2]);
|
||||
let c = cast_arg::<C>(&mut args[3]);
|
||||
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||
@ -918,7 +921,7 @@ impl Module {
|
||||
#[inline]
|
||||
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
||||
&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 {
|
||||
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
@ -934,7 +937,7 @@ impl Module {
|
||||
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 c = cast_arg::<C>(&mut args[2]);
|
||||
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||
@ -982,8 +985,8 @@ impl Module {
|
||||
#[inline]
|
||||
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||
&mut self,
|
||||
getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
|
||||
setter: impl Fn(&mut A, B, T) -> FuncReturn<()> + SendSync + 'static,
|
||||
getter: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||
setter: impl Fn(&mut A, B, T) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> (u64, u64) {
|
||||
(
|
||||
self.set_indexer_get_fn(getter),
|
||||
@ -1016,9 +1019,9 @@ impl Module {
|
||||
>(
|
||||
&mut self,
|
||||
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 {
|
||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||
let a = cast_arg::<A>(&mut args[0]);
|
||||
let b = cast_arg::<B>(&mut args[1]);
|
||||
let c = cast_arg::<C>(&mut args[2]);
|
||||
@ -1066,9 +1069,9 @@ impl Module {
|
||||
>(
|
||||
&mut self,
|
||||
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 {
|
||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||
let b = cast_arg::<B>(&mut args[1]);
|
||||
let c = cast_arg::<C>(&mut args[2]);
|
||||
let d = cast_arg::<D>(&mut args[3]);
|
||||
@ -1340,7 +1343,11 @@ impl 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();
|
||||
|
||||
// Run the script
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
use crate::any::{Dynamic, Variant};
|
||||
use crate::def_package;
|
||||
use crate::engine::{Array, Engine};
|
||||
use crate::fn_native::FnPtr;
|
||||
use crate::engine::Array;
|
||||
use crate::fn_native::{FnPtr, NativeCallContext};
|
||||
use crate::parser::{ImmutableString, INT};
|
||||
use crate::plugin::*;
|
||||
use crate::result::EvalAltResult;
|
||||
@ -239,21 +239,20 @@ mod array_functions {
|
||||
}
|
||||
|
||||
fn pad<T: Variant + Clone>(
|
||||
_engine: &Engine,
|
||||
_: &Module,
|
||||
_context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
let len = *args[1].read_lock::<INT>().unwrap();
|
||||
|
||||
// Check if array will be over max size limit
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if _engine.limits.max_array_size > 0
|
||||
if _context.engine().max_array_size() > 0
|
||||
&& len > 0
|
||||
&& (len as usize) > _engine.limits.max_array_size
|
||||
&& (len as usize) > _context.engine().max_array_size()
|
||||
{
|
||||
return EvalAltResult::ErrorDataTooLarge(
|
||||
"Size of array".to_string(),
|
||||
_engine.limits.max_array_size,
|
||||
_context.engine().max_array_size(),
|
||||
len as usize,
|
||||
Position::none(),
|
||||
)
|
||||
@ -271,11 +270,7 @@ fn pad<T: Variant + Clone>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Array, Box<EvalAltResult>> {
|
||||
fn map(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Array, Box<EvalAltResult>> {
|
||||
let list = args[0].read_lock::<Array>().unwrap();
|
||||
let mapper = args[1].read_lock::<FnPtr>().unwrap();
|
||||
|
||||
@ -284,10 +279,10 @@ fn map(
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
array.push(
|
||||
mapper
|
||||
.call_dynamic(engine, lib, None, [item.clone()])
|
||||
.call_dynamic(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
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),
|
||||
})
|
||||
@ -305,8 +300,7 @@ fn map(
|
||||
}
|
||||
|
||||
fn filter(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Array, Box<EvalAltResult>> {
|
||||
let list = args[0].read_lock::<Array>().unwrap();
|
||||
@ -316,10 +310,10 @@ fn filter(
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
if filter
|
||||
.call_dynamic(engine, lib, None, [item.clone()])
|
||||
.call_dynamic(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
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),
|
||||
})
|
||||
@ -340,20 +334,16 @@ fn filter(
|
||||
Ok(array)
|
||||
}
|
||||
|
||||
fn some(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<bool, Box<EvalAltResult>> {
|
||||
fn some(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<bool, Box<EvalAltResult>> {
|
||||
let list = args[0].read_lock::<Array>().unwrap();
|
||||
let filter = args[1].read_lock::<FnPtr>().unwrap();
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
if filter
|
||||
.call_dynamic(engine, lib, None, [item.clone()])
|
||||
.call_dynamic(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
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),
|
||||
})
|
||||
@ -374,20 +364,16 @@ fn some(
|
||||
Ok(false.into())
|
||||
}
|
||||
|
||||
fn all(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<bool, Box<EvalAltResult>> {
|
||||
fn all(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<bool, Box<EvalAltResult>> {
|
||||
let list = args[0].read_lock::<Array>().unwrap();
|
||||
let filter = args[1].read_lock::<FnPtr>().unwrap();
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
if !filter
|
||||
.call_dynamic(engine, lib, None, [item.clone()])
|
||||
.call_dynamic(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
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),
|
||||
})
|
||||
@ -409,8 +395,7 @@ fn all(
|
||||
}
|
||||
|
||||
fn reduce(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let list = args[0].read_lock::<Array>().unwrap();
|
||||
@ -420,14 +405,11 @@ fn reduce(
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
result = reducer
|
||||
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
|
||||
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
|
||||
engine,
|
||||
lib,
|
||||
None,
|
||||
[result, item.clone(), (i as INT).into()],
|
||||
),
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
|
||||
}
|
||||
_ => Err(err),
|
||||
})
|
||||
.map_err(|err| {
|
||||
@ -443,15 +425,14 @@ fn reduce(
|
||||
}
|
||||
|
||||
fn reduce_with_initial(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let list = args[0].read_lock::<Array>().unwrap();
|
||||
let reducer = args[1].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(
|
||||
"reduce".to_string(),
|
||||
err,
|
||||
@ -461,14 +442,11 @@ fn reduce_with_initial(
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
result = reducer
|
||||
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
|
||||
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
|
||||
engine,
|
||||
lib,
|
||||
None,
|
||||
[result, item.clone(), (i as INT).into()],
|
||||
),
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
|
||||
}
|
||||
_ => Err(err),
|
||||
})
|
||||
.map_err(|err| {
|
||||
@ -484,8 +462,7 @@ fn reduce_with_initial(
|
||||
}
|
||||
|
||||
fn reduce_rev(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let list = args[0].read_lock::<Array>().unwrap();
|
||||
@ -495,14 +472,11 @@ fn reduce_rev(
|
||||
|
||||
for (i, item) in list.iter().enumerate().rev() {
|
||||
result = reducer
|
||||
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
|
||||
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
|
||||
engine,
|
||||
lib,
|
||||
None,
|
||||
[result, item.clone(), (i as INT).into()],
|
||||
),
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
|
||||
}
|
||||
_ => Err(err),
|
||||
})
|
||||
.map_err(|err| {
|
||||
@ -518,15 +492,14 @@ fn reduce_rev(
|
||||
}
|
||||
|
||||
fn reduce_rev_with_initial(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let list = args[0].read_lock::<Array>().unwrap();
|
||||
let reducer = args[1].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(
|
||||
"reduce".to_string(),
|
||||
err,
|
||||
@ -536,14 +509,11 @@ fn reduce_rev_with_initial(
|
||||
|
||||
for (i, item) in list.iter().enumerate().rev() {
|
||||
result = reducer
|
||||
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
|
||||
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
|
||||
engine,
|
||||
lib,
|
||||
None,
|
||||
[result, item.clone(), (i as INT).into()],
|
||||
),
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
|
||||
}
|
||||
_ => Err(err),
|
||||
})
|
||||
.map_err(|err| {
|
||||
@ -559,8 +529,7 @@ fn reduce_rev_with_initial(
|
||||
}
|
||||
|
||||
fn sort(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let comparer = args[1].read_lock::<FnPtr>().unwrap().clone();
|
||||
@ -568,7 +537,7 @@ fn sort(
|
||||
|
||||
list.sort_by(|x, y| {
|
||||
comparer
|
||||
.call_dynamic(engine, lib, None, [x.clone(), y.clone()])
|
||||
.call_dynamic(context, None, [x.clone(), y.clone()])
|
||||
.ok()
|
||||
.and_then(|v| v.as_int().ok())
|
||||
.map(|v| {
|
||||
@ -598,8 +567,7 @@ fn sort(
|
||||
}
|
||||
|
||||
fn drain(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Array, Box<EvalAltResult>> {
|
||||
let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
|
||||
@ -613,10 +581,10 @@ fn drain(
|
||||
i -= 1;
|
||||
|
||||
if filter
|
||||
.call_dynamic(engine, lib, None, [list[i].clone()])
|
||||
.call_dynamic(context, None, [list[i].clone()])
|
||||
.or_else(|err| match *err {
|
||||
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),
|
||||
})
|
||||
@ -638,8 +606,7 @@ fn drain(
|
||||
}
|
||||
|
||||
fn retain(
|
||||
engine: &Engine,
|
||||
lib: &Module,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Array, Box<EvalAltResult>> {
|
||||
let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
|
||||
@ -653,10 +620,10 @@ fn retain(
|
||||
i -= 1;
|
||||
|
||||
if !filter
|
||||
.call_dynamic(engine, lib, None, [list[i].clone()])
|
||||
.call_dynamic(context, None, [list[i].clone()])
|
||||
.or_else(|err| match *err {
|
||||
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),
|
||||
})
|
||||
|
@ -12,4 +12,8 @@ mod fn_ptr_functions {
|
||||
pub fn name(f: &mut FnPtr) -> ImmutableString {
|
||||
f.get_fn_name().clone()
|
||||
}
|
||||
#[rhai_fn(name = "is_anonymous", get = "is_anonymous")]
|
||||
pub fn is_anonymous(f: &mut FnPtr) -> bool {
|
||||
f.is_anonymous()
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::any::Variant;
|
||||
use crate::def_package;
|
||||
use crate::module::FuncReturn;
|
||||
use crate::parser::INT;
|
||||
use crate::result::EvalAltResult;
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
for<'a> &'a T: Add<&'a T, Output = T>,
|
||||
T: Variant + Clone + PartialOrd,
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
use crate::any::Dynamic;
|
||||
use crate::def_package;
|
||||
use crate::engine::Engine;
|
||||
use crate::fn_native::FnPtr;
|
||||
use crate::parser::{ImmutableString, INT};
|
||||
use crate::plugin::*;
|
||||
@ -62,15 +61,17 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
||||
lib.set_raw_fn(
|
||||
"pad",
|
||||
&[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();
|
||||
|
||||
// Check if string will be over max size limit
|
||||
#[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(
|
||||
"Length of string".to_string(),
|
||||
_engine.limits.max_string_size,
|
||||
_context.engine().max_string_size(),
|
||||
len as usize,
|
||||
Position::none(),
|
||||
).into();
|
||||
@ -90,10 +91,10 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
||||
}
|
||||
|
||||
#[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(
|
||||
"Length of string".to_string(),
|
||||
_engine.limits.max_string_size,
|
||||
_context.engine().max_string_size(),
|
||||
s.len(),
|
||||
Position::none(),
|
||||
).into();
|
||||
|
@ -1,9 +1,7 @@
|
||||
//! Main module defining the lexer and parser.
|
||||
|
||||
use crate::any::{Dynamic, Union};
|
||||
use crate::engine::{
|
||||
Engine, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT,
|
||||
};
|
||||
use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
||||
use crate::fn_native::{FnPtr, Shared};
|
||||
use crate::module::{Module, ModuleRef};
|
||||
@ -18,7 +16,7 @@ use crate::{calc_fn_hash, StaticVec};
|
||||
use crate::engine::Array;
|
||||
|
||||
#[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"))]
|
||||
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
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
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>,
|
||||
/// Maximum levels of expression nesting.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
max_expr_depth: usize,
|
||||
/// Maximum levels of expression nesting in functions.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
max_function_expr_depth: usize,
|
||||
}
|
||||
|
||||
@ -619,19 +619,23 @@ impl<'e> ParseState<'e> {
|
||||
pub fn new(
|
||||
engine: &'e Engine,
|
||||
#[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 {
|
||||
engine,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
max_expr_depth,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
max_function_expr_depth,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
externals: Default::default(),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
allow_capture: true,
|
||||
stack: Default::default(),
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
modules: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -1696,11 +1700,10 @@ fn parse_array_literal(
|
||||
|
||||
while !input.peek().unwrap().0.is_eof() {
|
||||
#[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(
|
||||
"Size of array literal".to_string(),
|
||||
state.engine.limits.max_array_size,
|
||||
state.engine.max_array_size(),
|
||||
)
|
||||
.into_err(input.peek().unwrap().1));
|
||||
}
|
||||
@ -1804,10 +1807,10 @@ fn parse_map_literal(
|
||||
};
|
||||
|
||||
#[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(
|
||||
"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));
|
||||
}
|
||||
@ -3599,9 +3602,10 @@ impl Engine {
|
||||
let mut state = ParseState::new(
|
||||
self,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.limits.max_expr_depth,
|
||||
self.max_expr_depth(),
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.limits.max_function_expr_depth,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
self.max_function_expr_depth(),
|
||||
);
|
||||
|
||||
let settings = ParseSettings {
|
||||
@ -3646,9 +3650,10 @@ impl Engine {
|
||||
let mut state = ParseState::new(
|
||||
self,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.limits.max_expr_depth,
|
||||
self.max_expr_depth(),
|
||||
#[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() {
|
||||
|
@ -53,7 +53,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
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
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
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
|
||||
@ -69,7 +69,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
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
|
||||
} else {
|
||||
operations
|
||||
@ -81,14 +81,14 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
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.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
|
||||
self.limits.max_modules = modules;
|
||||
self.limits_set.max_modules = modules;
|
||||
self
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
pub fn max_modules(&self) -> usize {
|
||||
self.limits.max_modules
|
||||
self.limits_set.max_modules
|
||||
}
|
||||
|
||||
/// Set the depth limits for expressions (0 for unlimited).
|
||||
@ -105,18 +105,21 @@ impl Engine {
|
||||
pub fn set_max_expr_depths(
|
||||
&mut self,
|
||||
max_expr_depth: usize,
|
||||
max_function_expr_depth: usize,
|
||||
#[cfg(not(feature = "no_function"))] max_function_expr_depth: usize,
|
||||
) -> &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
|
||||
} else {
|
||||
max_expr_depth
|
||||
};
|
||||
self.limits.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
|
||||
0
|
||||
} else {
|
||||
max_function_expr_depth
|
||||
};
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
{
|
||||
self.limits_set.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
|
||||
0
|
||||
} else {
|
||||
max_function_expr_depth
|
||||
};
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
@ -124,21 +127,22 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
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).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
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).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
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
|
||||
}
|
||||
|
||||
@ -146,7 +150,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
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).
|
||||
@ -154,7 +158,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
#[inline(always)]
|
||||
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
|
||||
}
|
||||
|
||||
@ -163,7 +167,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
#[inline(always)]
|
||||
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).
|
||||
@ -171,7 +175,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[inline(always)]
|
||||
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
|
||||
}
|
||||
|
||||
@ -180,7 +184,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[inline(always)]
|
||||
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`.
|
||||
|
@ -67,14 +67,14 @@ impl EvalContext<'_, '_, '_, '_, '_, '_> {
|
||||
scope: &mut Scope,
|
||||
expr: &Expression,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
self.engine.eval_expr(
|
||||
self.engine().eval_expr(
|
||||
scope,
|
||||
self.mods,
|
||||
self.state,
|
||||
self.lib,
|
||||
self.namespace(),
|
||||
self.this_ptr,
|
||||
expr.expr(),
|
||||
self.level,
|
||||
self.call_level(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1747,7 +1747,7 @@ pub fn lex<'a, 'e>(
|
||||
engine,
|
||||
state: TokenizeState {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
max_string_size: engine.limits.max_string_size,
|
||||
max_string_size: engine.limits_set.max_string_size,
|
||||
#[cfg(feature = "unchecked")]
|
||||
max_string_size: 0,
|
||||
non_unary: false,
|
||||
|
@ -98,12 +98,12 @@ fn test_fn_ptr_raw() -> Result<(), Box<EvalAltResult>> {
|
||||
TypeId::of::<FnPtr>(),
|
||||
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 value = args[2].clone();
|
||||
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])
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![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::cell::RefCell;
|
||||
use std::mem::take;
|
||||
@ -16,9 +16,9 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.register_raw_fn(
|
||||
"call_with_arg",
|
||||
&[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>();
|
||||
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(
|
||||
"custom_call",
|
||||
&[TypeId::of::<INT>(), TypeId::of::<FnPtr>()],
|
||||
|engine: &Engine, module: &Module, args: &mut [&mut Dynamic]| {
|
||||
|context, args| {
|
||||
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(
|
||||
r#"
|
||||
let test = "hello";
|
||||
|
||||
|x| test + x
|
||||
"#,
|
||||
)?;
|
||||
@ -271,7 +270,7 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
||||
ast.retain_functions(|_, _, _| true);
|
||||
|
||||
// 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"));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user