Add new &Module parameter to native functions.

This commit is contained in:
Stephen Chung
2020-07-06 12:04:02 +08:00
parent 495d202af4
commit ea86888638
10 changed files with 107 additions and 99 deletions

View File

@@ -6,6 +6,7 @@ use crate::error::ParseError;
use crate::fn_call::FuncArgs;
use crate::fn_native::{IteratorFn, SendSync};
use crate::fn_register::RegisterFn;
use crate::module::Module;
use crate::optimize::{optimize_into_ast, OptimizationLevel};
use crate::parser::AST;
use crate::result::EvalAltResult;
@@ -53,10 +54,10 @@ impl Engine {
name: &str,
args: &[TypeId],
#[cfg(not(feature = "sync"))] func: impl Fn(&Engine, &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>>
#[cfg(not(feature = "sync"))] func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>>
+ 'static,
#[cfg(feature = "sync")] func: impl Fn(&Engine, &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>>
#[cfg(feature = "sync")] func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>>
+ Send
+ Sync
+ 'static,
@@ -459,7 +460,7 @@ impl Engine {
self.register_indexer_set(setter);
}
/// Compile a string into an [`AST`], which can be used later for evaluation.
/// Compile a string into an `AST`, which can be used later for evaluation.
///
/// # Example
///
@@ -482,7 +483,7 @@ impl Engine {
self.compile_with_scope(&Scope::new(), script)
}
/// Compile a string into an [`AST`] using own scope, which can be used later for evaluation.
/// Compile a string into an `AST` using own scope, which can be used later for evaluation.
///
/// The scope is useful for passing constants into the script for optimization
/// when using `OptimizationLevel::Full`.
@@ -525,7 +526,7 @@ impl Engine {
}
/// When passed a list of strings, first join the strings into one large script,
/// and then compile them into an [`AST`] using own scope, which can be used later for evaluation.
/// and then compile them into an `AST` using own scope, which can be used later for evaluation.
///
/// The scope is useful for passing constants into the script for optimization
/// when using `OptimizationLevel::Full`.
@@ -578,7 +579,7 @@ impl Engine {
self.compile_with_scope_and_optimization_level(scope, scripts, self.optimization_level)
}
/// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level.
/// Join a list of strings and compile into an `AST` using own scope at a specific optimization level.
pub(crate) fn compile_with_scope_and_optimization_level(
&self,
scope: &Scope,
@@ -614,7 +615,7 @@ impl Engine {
Ok(contents)
}
/// Compile a script file into an [`AST`], which can be used later for evaluation.
/// Compile a script file into an `AST`, which can be used later for evaluation.
///
/// # Example
///
@@ -640,7 +641,7 @@ impl Engine {
self.compile_file_with_scope(&Scope::new(), path)
}
/// Compile a script file into an [`AST`] using own scope, which can be used later for evaluation.
/// Compile a script file into an `AST` using own scope, which can be used later for evaluation.
///
/// The scope is useful for passing constants into the script for optimization
/// when using `OptimizationLevel::Full`.
@@ -722,7 +723,7 @@ impl Engine {
self.eval_ast_with_scope(&mut scope, &ast)
}
/// Compile a string containing an expression into an [`AST`],
/// Compile a string containing an expression into an `AST`,
/// which can be used later for evaluation.
///
/// # Example
@@ -746,7 +747,7 @@ impl Engine {
self.compile_expression_with_scope(&Scope::new(), script)
}
/// Compile a string containing an expression into an [`AST`] using own scope,
/// Compile a string containing an expression into an `AST` using own scope,
/// which can be used later for evaluation.
///
/// The scope is useful for passing constants into the script for optimization
@@ -954,7 +955,7 @@ impl Engine {
self.eval_ast_with_scope(scope, &ast)
}
/// Evaluate an [`AST`].
/// Evaluate an `AST`.
///
/// # Example
///
@@ -976,7 +977,7 @@ impl Engine {
self.eval_ast_with_scope(&mut Scope::new(), ast)
}
/// Evaluate an [`AST`] with own scope.
/// Evaluate an `AST` with own scope.
///
/// # Example
///
@@ -1024,7 +1025,7 @@ impl Engine {
});
}
/// Evaluate an [`AST`] with own scope.
/// Evaluate an `AST` with own scope.
pub(crate) fn eval_ast_with_scope_raw<'a>(
&self,
scope: &mut Scope,
@@ -1090,7 +1091,7 @@ impl Engine {
self.consume_ast_with_scope(&mut Scope::new(), ast)
}
/// Evaluate an [`AST`] with own scope, but throw away the result and only return error (if any).
/// Evaluate an `AST` with own scope, but throw away the result and only return error (if any).
/// Useful for when you don't need the result, but still need to keep track of possible errors.
pub fn consume_ast_with_scope(
&self,
@@ -1114,7 +1115,7 @@ impl Engine {
)
}
/// Call a script function defined in an [`AST`] with multiple arguments.
/// Call a script function defined in an `AST` with multiple arguments.
/// Arguments are passed as a tuple.
///
/// # Example
@@ -1159,7 +1160,8 @@ impl Engine {
args: A,
) -> Result<T, Box<EvalAltResult>> {
let mut arg_values = args.into_vec();
let result = self.call_fn_dynamic_raw(scope, ast, name, &mut None, arg_values.as_mut())?;
let result =
self.call_fn_dynamic_raw(scope, ast.lib(), name, &mut None, arg_values.as_mut())?;
let typ = self.map_type_name(result.type_name());
@@ -1172,7 +1174,7 @@ impl Engine {
});
}
/// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments
/// Call a script function defined in an `AST` with multiple `Dynamic` arguments
/// and optionally a value for binding to the 'this' pointer.
///
/// ## WARNING
@@ -1203,19 +1205,19 @@ impl Engine {
/// scope.push("foo", 42_i64);
///
/// // Call the script-defined function
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "add", None, [ String::from("abc").into(), 123_i64.into() ])?;
/// // ^^^^ no 'this' pointer
/// let result = engine.call_fn_dynamic(&mut scope, ast.into(), "add", None, [ String::from("abc").into(), 123_i64.into() ])?;
/// // ^^^^ no 'this' pointer
/// assert_eq!(result.cast::<i64>(), 168);
///
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "add1", None, [ String::from("abc").into() ])?;
/// let result = engine.call_fn_dynamic(&mut scope, ast.into(), "add1", None, [ String::from("abc").into() ])?;
/// assert_eq!(result.cast::<i64>(), 46);
///
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "bar", None, [])?;
/// let result = engine.call_fn_dynamic(&mut scope, ast.into(), "bar", None, [])?;
/// assert_eq!(result.cast::<i64>(), 21);
///
/// let mut value: Dynamic = 1_i64.into();
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "action", Some(&mut value), [ 41_i64.into() ])?;
/// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer
/// let result = engine.call_fn_dynamic(&mut scope, ast.into(), "action", Some(&mut value), [ 41_i64.into() ])?;
/// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer
/// assert_eq!(value.as_int().unwrap(), 42);
/// # }
/// # Ok(())
@@ -1225,15 +1227,15 @@ impl Engine {
pub fn call_fn_dynamic(
&self,
scope: &mut Scope,
ast: &AST,
lib: &Module,
name: &str,
mut this_ptr: Option<&mut Dynamic>,
mut arg_values: impl AsMut<[Dynamic]>,
) -> Result<Dynamic, Box<EvalAltResult>> {
self.call_fn_dynamic_raw(scope, ast, name, &mut this_ptr, arg_values.as_mut())
self.call_fn_dynamic_raw(scope, lib, name, &mut this_ptr, arg_values.as_mut())
}
/// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments.
/// Call a script function defined in an `AST` with multiple `Dynamic` arguments.
///
/// ## WARNING
///
@@ -1245,14 +1247,14 @@ impl Engine {
pub(crate) fn call_fn_dynamic_raw(
&self,
scope: &mut Scope,
ast: &AST,
lib: &Module,
name: &str,
this_ptr: &mut Option<&mut Dynamic>,
arg_values: &mut [Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> {
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
let fn_def = get_script_function_by_signature(ast.lib(), name, args.len(), true)
.ok_or_else(|| {
let fn_def =
get_script_function_by_signature(lib, name, args.len(), true).ok_or_else(|| {
Box::new(EvalAltResult::ErrorFunctionNotFound(
name.into(),
Position::none(),
@@ -1264,27 +1266,19 @@ impl Engine {
let args = args.as_mut();
self.call_script_fn(
scope,
&mut mods,
&mut state,
ast.lib(),
this_ptr,
name,
fn_def,
args,
0,
scope, &mut mods, &mut state, lib, this_ptr, name, fn_def, args, 0,
)
}
/// Optimize the [`AST`] with constants defined in an external Scope.
/// An optimized copy of the [`AST`] is returned while the original [`AST`] is consumed.
/// Optimize the `AST` with constants defined in an external Scope.
/// An optimized copy of the `AST` is returned while the original `AST` is consumed.
///
/// Although optimization is performed by default during compilation, sometimes it is necessary to
/// _re_-optimize an AST. For example, when working with constants that are passed in via an
/// external scope, it will be more efficient to optimize the [`AST`] once again to take advantage
/// external scope, it will be more efficient to optimize the `AST` once again to take advantage
/// of the new constants.
///
/// With this method, it is no longer necessary to recompile a large script. The script [`AST`] can be
/// With this method, it is no longer necessary to recompile a large script. The script `AST` can be
/// compiled just once. Before evaluation, constants are passed into the `Engine` via an external scope
/// (i.e. with `scope.push_constant(...)`). Then, the `AST is cloned and the copy re-optimized before running.
#[cfg(not(feature = "no_optimize"))]