rhai/src/api/call_fn.rs

307 lines
10 KiB
Rust
Raw Normal View History

2021-11-20 07:57:21 +01:00
//! Module that defines the `call_fn` API of [`Engine`].
2021-11-27 16:20:05 +01:00
#![cfg(not(feature = "no_function"))]
2021-11-20 07:57:21 +01:00
2022-04-16 10:36:53 +02:00
use crate::eval::{Caches, GlobalRuntimeState};
2021-11-20 07:57:21 +01:00
use crate::types::dynamic::Variant;
2021-11-27 16:20:05 +01:00
use crate::{
reify, Dynamic, Engine, FuncArgs, Position, RhaiResult, RhaiResultOf, Scope, StaticVec, AST,
ERR,
2021-11-27 16:20:05 +01:00
};
use std::any::{type_name, TypeId};
2021-11-20 07:57:21 +01:00
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
impl Engine {
/// Call a script function defined in an [`AST`] with multiple arguments.
///
/// Not available under `no_function`.
///
/// The [`AST`] is evaluated before calling the function.
/// This allows a script to load the necessary modules.
/// This is usually desired. If not, a specialized [`AST`] can be prepared that contains only
/// function definitions without any body script via [`AST::clear_statements`].
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// use rhai::{Engine, Scope};
///
/// let engine = Engine::new();
///
/// let ast = engine.compile("
/// fn add(x, y) { len(x) + y + foo }
/// fn add1(x) { len(x) + 1 + foo }
/// fn bar() { foo/2 }
/// ")?;
///
/// let mut scope = Scope::new();
/// scope.push("foo", 42_i64);
///
/// // Call the script-defined function
2022-08-12 16:48:15 +02:00
/// let result = engine.call_fn::<i64>(&mut scope, &ast, "add", ( "abc", 123_i64 ) )?;
2021-11-20 07:57:21 +01:00
/// assert_eq!(result, 168);
///
2022-08-12 16:48:15 +02:00
/// let result = engine.call_fn::<i64>(&mut scope, &ast, "add1", ( "abc", ) )?;
/// // ^^^^^^^^^^ tuple of one
2021-11-20 07:57:21 +01:00
/// assert_eq!(result, 46);
///
2022-08-12 16:48:15 +02:00
/// let result = engine.call_fn::<i64>(&mut scope, &ast, "bar", () )?;
2021-11-20 07:57:21 +01:00
/// assert_eq!(result, 21);
/// # }
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn call_fn<T: Variant + Clone>(
&self,
scope: &mut Scope,
ast: &AST,
name: impl AsRef<str>,
2021-11-27 16:20:05 +01:00
args: impl FuncArgs,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<T> {
2021-11-27 16:20:05 +01:00
let mut arg_values = StaticVec::new_const();
2021-11-20 07:57:21 +01:00
args.parse(&mut arg_values);
let result = self.call_fn_raw(scope, ast, true, true, name, None, arg_values)?;
// Bail out early if the return type needs no cast
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return Ok(reify!(result => T));
}
if TypeId::of::<T>() == TypeId::of::<()>() {
return Ok(reify!(() => T));
}
// Cast return type
2021-11-20 07:57:21 +01:00
let typ = self.map_type_name(result.type_name());
result.try_cast().ok_or_else(|| {
2022-03-14 01:50:17 +01:00
let t = self.map_type_name(type_name::<T>()).into();
ERR::ErrorMismatchOutputType(t, typ.into(), Position::NONE).into()
2021-11-20 07:57:21 +01:00
})
}
2022-04-23 07:15:27 +02:00
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
///
/// The following options are available:
2021-11-20 07:57:21 +01:00
///
/// * whether to evaluate the [`AST`] to load necessary modules before calling the function
/// * whether to rewind the [`Scope`] after the function call
/// * a value for binding to the `this` pointer (if any)
///
/// Not available under `no_function`.
///
2021-11-29 06:12:47 +01:00
/// # WARNING - Low Level API
///
/// This function is very low level.
///
2021-12-27 04:43:11 +01:00
/// # Arguments
2021-11-20 07:57:21 +01:00
///
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments.
2021-12-27 04:43:11 +01:00
///
2022-02-24 03:36:20 +01:00
/// Do not use the arguments after this call. If they are needed afterwards, clone them _before_
/// calling this function.
2021-11-20 07:57:21 +01:00
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// use rhai::{Engine, Scope, Dynamic};
///
/// let engine = Engine::new();
///
/// let ast = engine.compile("
/// fn add(x, y) { len(x) + y + foo }
/// fn add1(x) { len(x) + 1 + foo }
/// fn bar() { foo/2 }
/// fn action(x) { this += x; } // function using 'this' pointer
/// fn decl(x) { let hello = x; } // declaring variables
/// ")?;
///
/// let mut scope = Scope::new();
/// scope.push("foo", 42_i64);
///
/// // Call the script-defined function
/// let result = engine.call_fn_raw(&mut scope, &ast, true, true, "add", None, [ "abc".into(), 123_i64.into() ])?;
/// // ^^^^ no 'this' pointer
/// assert_eq!(result.cast::<i64>(), 168);
///
/// let result = engine.call_fn_raw(&mut scope, &ast, true, true, "add1", None, [ "abc".into() ])?;
/// assert_eq!(result.cast::<i64>(), 46);
///
/// let result = engine.call_fn_raw(&mut scope, &ast, true, true, "bar", None, [])?;
/// assert_eq!(result.cast::<i64>(), 21);
///
2021-12-27 04:43:11 +01:00
/// let mut value = 1_i64.into();
2021-11-20 07:57:21 +01:00
/// let result = engine.call_fn_raw(&mut scope, &ast, true, true, "action", Some(&mut value), [ 41_i64.into() ])?;
/// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer
2021-12-27 04:43:11 +01:00
/// assert_eq!(value.as_int().unwrap(), 42);
2021-11-20 07:57:21 +01:00
///
/// engine.call_fn_raw(&mut scope, &ast, true, false, "decl", None, [ 42_i64.into() ])?;
/// // ^^^^^ do not rewind scope
/// assert_eq!(scope.get_value::<i64>("hello").unwrap(), 42);
/// # }
/// # Ok(())
/// # }
/// ```
2022-04-23 07:15:27 +02:00
#[inline(always)]
2021-11-20 07:57:21 +01:00
pub fn call_fn_raw(
&self,
scope: &mut Scope,
ast: &AST,
eval_ast: bool,
rewind_scope: bool,
name: impl AsRef<str>,
this_ptr: Option<&mut Dynamic>,
arg_values: impl AsMut<[Dynamic]>,
2022-04-23 07:15:27 +02:00
) -> RhaiResult {
2022-04-23 09:25:00 +02:00
let mut arg_values = arg_values;
2022-06-09 02:41:51 +02:00
self._call_fn(
2022-04-23 07:15:27 +02:00
scope,
&mut GlobalRuntimeState::new(self),
2022-04-23 07:28:26 +02:00
&mut Caches::new(),
2022-04-23 07:15:27 +02:00
ast,
eval_ast,
rewind_scope,
2022-04-23 09:25:00 +02:00
name.as_ref(),
2022-04-23 07:15:27 +02:00
this_ptr,
2022-04-23 09:25:00 +02:00
arg_values.as_mut(),
2022-04-23 07:15:27 +02:00
)
}
/// _(internals)_ Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
/// Exported under the `internals` feature only.
///
/// The following options are available:
///
/// * whether to evaluate the [`AST`] to load necessary modules before calling the function
/// * whether to rewind the [`Scope`] after the function call
/// * a value for binding to the `this` pointer (if any)
///
/// Not available under `no_function`.
///
2022-07-06 06:56:15 +02:00
/// # WARNING - Unstable API
///
/// This API is volatile and may change in the future.
///
2022-04-23 07:15:27 +02:00
/// # WARNING - Low Level API
///
2022-05-19 08:41:48 +02:00
/// This function is _extremely_ low level.
2022-04-23 07:15:27 +02:00
///
2022-04-23 07:28:26 +02:00
/// A [`GlobalRuntimeState`] and [`Caches`] need to be passed into the function, which can be
/// created via [`GlobalRuntimeState::new`] and [`Caches::new`].
/// This makes repeatedly calling particular functions more efficient as the functions resolution cache
2022-04-23 07:15:27 +02:00
/// is kept intact.
///
/// # Arguments
///
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments.
///
/// Do not use the arguments after this call. If they are needed afterwards, clone them _before_
/// calling this function.
#[cfg(feature = "internals")]
2022-07-06 06:56:15 +02:00
#[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
2022-04-23 07:15:27 +02:00
#[inline(always)]
2022-04-23 07:28:26 +02:00
pub fn call_fn_raw_raw(
2022-04-23 07:15:27 +02:00
&self,
scope: &mut Scope,
global: &mut GlobalRuntimeState,
2022-04-23 07:28:26 +02:00
caches: &mut Caches,
2022-04-23 07:15:27 +02:00
ast: &AST,
eval_ast: bool,
rewind_scope: bool,
2022-04-23 09:25:00 +02:00
name: &str,
2022-04-23 07:15:27 +02:00
this_ptr: Option<&mut Dynamic>,
2022-04-23 09:25:00 +02:00
arg_values: &mut [Dynamic],
2022-04-23 07:15:27 +02:00
) -> RhaiResult {
2022-06-09 02:41:51 +02:00
self._call_fn(
2022-04-23 07:15:27 +02:00
scope,
global,
2022-04-23 07:28:26 +02:00
caches,
2022-04-23 07:15:27 +02:00
ast,
eval_ast,
rewind_scope,
name,
this_ptr,
arg_values,
)
}
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
2022-06-09 02:41:51 +02:00
fn _call_fn(
2022-04-23 07:15:27 +02:00
&self,
scope: &mut Scope,
global: &mut GlobalRuntimeState,
2022-04-23 07:28:26 +02:00
caches: &mut Caches,
2022-04-23 07:15:27 +02:00
ast: &AST,
eval_ast: bool,
rewind_scope: bool,
2022-04-23 09:25:00 +02:00
name: &str,
2022-04-23 07:15:27 +02:00
this_ptr: Option<&mut Dynamic>,
2022-04-23 09:25:00 +02:00
arg_values: &mut [Dynamic],
2021-11-20 07:57:21 +01:00
) -> RhaiResult {
let statements = ast.statements();
let orig_scope_len = scope.len();
#[cfg(not(feature = "no_module"))]
let orig_embedded_module_resolver = std::mem::replace(
&mut global.embedded_module_resolver,
ast.resolver().cloned(),
);
2021-11-20 07:57:21 +01:00
if eval_ast && !statements.is_empty() {
2022-04-16 10:36:53 +02:00
self.eval_global_statements(scope, global, caches, statements, &[ast.as_ref()], 0)?;
2021-11-20 07:57:21 +01:00
if rewind_scope {
scope.rewind(orig_scope_len);
}
}
let mut this_ptr = this_ptr;
2022-07-05 10:26:38 +02:00
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
2021-11-20 07:57:21 +01:00
2022-04-26 10:36:24 +02:00
// Check for data race.
#[cfg(not(feature = "no_closure"))]
crate::func::call::ensure_no_data_race(name, &args, false)?;
2022-04-26 10:36:24 +02:00
let lib = &[ast.as_ref()];
2021-11-20 07:57:21 +01:00
let fn_def = ast
2021-11-28 15:57:28 +01:00
.shared_lib()
2021-11-20 07:57:21 +01:00
.get_script_fn(name, args.len())
2021-12-27 05:27:31 +01:00
.ok_or_else(|| ERR::ErrorFunctionNotFound(name.into(), Position::NONE))?;
2021-11-20 07:57:21 +01:00
2022-04-26 10:36:24 +02:00
let result = self.call_script_fn(
2021-11-20 07:57:21 +01:00
scope,
2021-12-27 16:03:30 +01:00
global,
2022-04-16 10:36:53 +02:00
caches,
2022-04-26 10:36:24 +02:00
lib,
2021-11-20 07:57:21 +01:00
&mut this_ptr,
fn_def,
&mut args,
rewind_scope,
Position::NONE,
2021-11-20 07:57:21 +01:00
0,
2022-04-26 10:36:24 +02:00
)?;
#[cfg(not(feature = "no_module"))]
{
global.embedded_module_resolver = orig_embedded_module_resolver;
}
2022-04-26 10:36:24 +02:00
#[cfg(feature = "debugging")]
if self.debugger.is_some() {
global.debugger.status = crate::eval::DebuggerStatus::Terminate;
let node = &crate::ast::Stmt::Noop(Position::NONE);
self.run_debugger(scope, global, lib, &mut this_ptr, node, 0)?;
}
Ok(result)
2021-11-20 07:57:21 +01:00
}
}