2020-11-20 09:52:28 +01:00
|
|
|
//! Module that defines the extern API of [`Engine`].
|
2020-03-08 12:54:02 +01:00
|
|
|
|
2020-11-16 16:10:14 +01:00
|
|
|
use crate::dynamic::Variant;
|
2020-12-21 15:04:46 +01:00
|
|
|
use crate::engine::{EvalContext, Imports, State};
|
2020-11-16 16:10:14 +01:00
|
|
|
use crate::fn_native::{FnCallArgs, SendSync};
|
2021-03-15 04:36:30 +01:00
|
|
|
use crate::fn_register::RegisterNativeFunction;
|
2020-11-16 16:32:44 +01:00
|
|
|
use crate::optimize::OptimizationLevel;
|
2020-03-17 19:26:11 +01:00
|
|
|
use crate::stdlib::{
|
2020-03-10 03:07:44 +01:00
|
|
|
any::{type_name, TypeId},
|
2020-03-17 19:26:11 +01:00
|
|
|
boxed::Box,
|
2021-03-24 12:27:38 +01:00
|
|
|
string::String,
|
2020-03-10 03:07:44 +01:00
|
|
|
};
|
2020-11-16 16:10:14 +01:00
|
|
|
use crate::{
|
2021-03-29 05:36:02 +02:00
|
|
|
scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, Identifier, Module,
|
2021-03-24 12:27:38 +01:00
|
|
|
NativeCallContext, ParseError, Position, RhaiResult, Shared, AST,
|
2020-11-16 16:10:14 +01:00
|
|
|
};
|
2020-05-12 10:32:22 +02:00
|
|
|
|
2020-11-16 16:10:14 +01:00
|
|
|
#[cfg(not(feature = "no_index"))]
|
|
|
|
use crate::Array;
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
use crate::Map;
|
2020-03-02 07:28:42 +01:00
|
|
|
|
2020-04-03 11:17:00 +02:00
|
|
|
/// Engine public API
|
2020-04-16 17:31:48 +02:00
|
|
|
impl Engine {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// Register a custom function with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// // Normal function
|
|
|
|
/// fn add(x: i64, y: i64) -> i64 {
|
|
|
|
/// x + y
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// engine.register_fn("add", add);
|
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("add(40, 2)")?, 42);
|
|
|
|
///
|
|
|
|
/// // You can also register a closure.
|
|
|
|
/// engine.register_fn("sub", |x: i64, y: i64| x - y );
|
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("sub(44, 2)")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-03-15 15:19:21 +01:00
|
|
|
#[inline]
|
2021-03-24 12:27:38 +01:00
|
|
|
pub fn register_fn<N, A, F>(&mut self, name: N, func: F) -> &mut Self
|
2021-03-15 05:39:06 +01:00
|
|
|
where
|
2021-03-29 05:36:02 +02:00
|
|
|
N: AsRef<str> + Into<Identifier>,
|
2021-03-15 05:39:06 +01:00
|
|
|
F: RegisterNativeFunction<A, ()>,
|
|
|
|
{
|
2021-03-15 15:19:21 +01:00
|
|
|
let param_types = F::param_types();
|
2021-03-24 12:27:38 +01:00
|
|
|
|
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
let mut param_type_names: crate::StaticVec<_> = F::param_names()
|
2021-03-15 15:19:21 +01:00
|
|
|
.iter()
|
2021-03-29 07:40:33 +02:00
|
|
|
.map(|ty| crate::stdlib::format!("_: {}", self.map_type_name(ty)))
|
2021-03-15 15:19:21 +01:00
|
|
|
.collect();
|
2021-03-24 12:27:38 +01:00
|
|
|
|
|
|
|
#[cfg(feature = "metadata")]
|
2021-03-15 15:19:21 +01:00
|
|
|
if F::return_type() != TypeId::of::<()>() {
|
2021-03-24 12:27:38 +01:00
|
|
|
param_type_names.push(self.map_type_name(F::return_type_name()).into());
|
2021-03-15 15:19:21 +01:00
|
|
|
}
|
2021-03-24 12:27:38 +01:00
|
|
|
|
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
let param_type_names: Option<crate::StaticVec<_>> =
|
|
|
|
Some(param_type_names.iter().map(|ty| ty.as_str()).collect());
|
|
|
|
|
|
|
|
#[cfg(not(feature = "metadata"))]
|
|
|
|
let param_type_names: Option<[&str; 0]> = None;
|
2021-03-15 15:19:21 +01:00
|
|
|
|
2021-03-15 05:39:06 +01:00
|
|
|
self.global_namespace.set_fn(
|
|
|
|
name,
|
|
|
|
FnNamespace::Global,
|
|
|
|
FnAccess::Public,
|
2021-03-24 12:27:38 +01:00
|
|
|
param_type_names.as_ref().map(|v| v.as_ref()),
|
2021-03-15 15:19:21 +01:00
|
|
|
¶m_types,
|
2021-03-15 05:39:06 +01:00
|
|
|
func.into_callable_function(),
|
|
|
|
);
|
2021-03-15 04:36:30 +01:00
|
|
|
self
|
|
|
|
}
|
|
|
|
/// Register a custom fallible function with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2021-03-15 15:37:50 +01:00
|
|
|
/// use rhai::{Engine, EvalAltResult};
|
2021-03-15 04:36:30 +01:00
|
|
|
///
|
|
|
|
/// // Normal function
|
2021-03-15 15:37:50 +01:00
|
|
|
/// fn div(x: i64, y: i64) -> Result<i64, Box<EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// if y == 0 {
|
|
|
|
/// // '.into()' automatically converts to 'Box<EvalAltResult::ErrorRuntime>'
|
|
|
|
/// Err("division by zero!".into())
|
|
|
|
/// } else {
|
2021-03-15 15:37:50 +01:00
|
|
|
/// Ok(x / y)
|
2021-03-15 04:36:30 +01:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// engine.register_result_fn("div", div);
|
|
|
|
///
|
|
|
|
/// engine.eval::<i64>("div(42, 0)")
|
|
|
|
/// .expect_err("expecting division by zero error!");
|
|
|
|
/// ```
|
2021-03-15 15:19:21 +01:00
|
|
|
#[inline]
|
2021-03-24 12:27:38 +01:00
|
|
|
pub fn register_result_fn<N, A, F, R>(&mut self, name: N, func: F) -> &mut Self
|
2021-03-15 05:39:06 +01:00
|
|
|
where
|
2021-03-29 05:36:02 +02:00
|
|
|
N: AsRef<str> + Into<Identifier>,
|
2021-03-15 15:37:50 +01:00
|
|
|
F: RegisterNativeFunction<A, Result<R, Box<EvalAltResult>>>,
|
2021-03-15 05:39:06 +01:00
|
|
|
{
|
2021-03-15 15:19:21 +01:00
|
|
|
let param_types = F::param_types();
|
2021-03-24 12:27:38 +01:00
|
|
|
|
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
let param_type_names: crate::StaticVec<_> = F::param_names()
|
2021-03-15 15:19:21 +01:00
|
|
|
.iter()
|
2021-03-29 07:40:33 +02:00
|
|
|
.map(|ty| crate::stdlib::format!("_: {}", self.map_type_name(ty)))
|
2021-03-24 12:27:38 +01:00
|
|
|
.chain(crate::stdlib::iter::once(
|
|
|
|
self.map_type_name(F::return_type_name()).into(),
|
|
|
|
))
|
2021-03-15 15:19:21 +01:00
|
|
|
.collect();
|
2021-03-24 12:27:38 +01:00
|
|
|
|
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
let param_type_names: Option<crate::StaticVec<_>> =
|
|
|
|
Some(param_type_names.iter().map(|ty| ty.as_str()).collect());
|
|
|
|
|
|
|
|
#[cfg(not(feature = "metadata"))]
|
|
|
|
let param_type_names: Option<[&str; 0]> = None;
|
2021-03-15 15:19:21 +01:00
|
|
|
|
2021-03-15 05:39:06 +01:00
|
|
|
self.global_namespace.set_fn(
|
|
|
|
name,
|
|
|
|
FnNamespace::Global,
|
|
|
|
FnAccess::Public,
|
2021-03-24 12:27:38 +01:00
|
|
|
param_type_names.as_ref().map(|v| v.as_ref()),
|
2021-03-15 15:19:21 +01:00
|
|
|
¶m_types,
|
2021-03-15 05:39:06 +01:00
|
|
|
func.into_callable_function(),
|
|
|
|
);
|
2021-03-15 04:36:30 +01:00
|
|
|
self
|
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register a function of the [`Engine`].
|
2020-07-05 17:08:44 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # WARNING - Low Level API
|
2020-07-05 17:08:44 +02:00
|
|
|
///
|
2020-11-25 02:36:06 +01:00
|
|
|
/// This function is very low level. It takes a list of [`TypeId`][std::any::TypeId]'s indicating the actual types of the parameters.
|
2020-07-05 17:08:44 +02:00
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][Dynamic],
|
2020-11-25 02:36:06 +01:00
|
|
|
/// The arguments are guaranteed to be of the correct types matching the [`TypeId`][std::any::TypeId]'s.
|
2020-07-05 17:08:44 +02:00
|
|
|
///
|
2021-03-03 11:13:41 +01:00
|
|
|
/// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()`
|
2020-07-05 17:08:44 +02:00
|
|
|
///
|
2021-03-03 04:40:27 +01:00
|
|
|
/// To access an argument value and avoid cloning, use `std::mem::take(args[n]).cast::<T>()`.
|
2020-07-05 17:08:44 +02:00
|
|
|
/// Notice that this will _consume_ the argument, replacing it with `()`.
|
|
|
|
///
|
2020-07-07 16:59:23 +02:00
|
|
|
/// To access the first mutable parameter, use `args.get_mut(0).unwrap()`
|
2020-12-23 08:30:35 +01:00
|
|
|
#[deprecated = "this function is volatile and may change"]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-03-24 12:27:38 +01:00
|
|
|
pub fn register_raw_fn<N, T>(
|
2020-07-05 17:08:44 +02:00
|
|
|
&mut self,
|
2021-03-24 12:27:38 +01:00
|
|
|
name: N,
|
2020-07-06 06:06:57 +02:00
|
|
|
arg_types: &[TypeId],
|
2020-10-19 13:11:55 +02:00
|
|
|
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
|
2020-10-18 11:02:17 +02:00
|
|
|
+ SendSync
|
|
|
|
+ 'static,
|
2021-03-24 12:27:38 +01:00
|
|
|
) -> &mut Self
|
|
|
|
where
|
2021-03-29 05:36:02 +02:00
|
|
|
N: AsRef<str> + Into<Identifier>,
|
2021-03-24 12:27:38 +01:00
|
|
|
T: Variant + Clone,
|
|
|
|
{
|
2020-11-19 06:56:03 +01:00
|
|
|
self.global_namespace.set_raw_fn(
|
|
|
|
name,
|
|
|
|
FnNamespace::Global,
|
|
|
|
FnAccess::Public,
|
|
|
|
arg_types,
|
|
|
|
func,
|
|
|
|
);
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-07-06 06:06:57 +02:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register a custom type for use with the [`Engine`].
|
|
|
|
/// The type must implement [`Clone`].
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-03-30 10:10:50 +02:00
|
|
|
/// #[derive(Debug, Clone, Eq, PartialEq)]
|
2020-03-19 06:52:10 +01:00
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { field: 1 } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-03-22 03:18:16 +01:00
|
|
|
/// fn update(&mut self, offset: i64) { self.field += offset; }
|
2020-03-19 06:52:10 +01:00
|
|
|
/// }
|
|
|
|
///
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::Engine;
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Use `register_fn` to register methods on the type.
|
|
|
|
/// .register_fn("update", TestStruct::update);
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// assert_eq!(
|
2020-03-30 10:10:50 +02:00
|
|
|
/// engine.eval::<TestStruct>("let x = new_ts(); x.update(41); x")?,
|
|
|
|
/// TestStruct { field: 42 }
|
2020-03-19 06:52:10 +01:00
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-29 11:15:12 +02:00
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-07-12 05:46:53 +02:00
|
|
|
pub fn register_type<T: Variant + Clone>(&mut self) -> &mut Self {
|
|
|
|
self.register_type_with_name::<T>(type_name::<T>())
|
2020-03-04 15:00:01 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register a custom type for use with the [`Engine`], with a pretty-print name
|
|
|
|
/// for the `type_of` function. The type must implement [`Clone`].
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
2020-03-30 10:10:50 +02:00
|
|
|
/// struct TestStruct {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { field: 1 } }
|
2020-03-19 06:52:10 +01:00
|
|
|
/// }
|
|
|
|
///
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::Engine;
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new);
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
|
|
|
|
/// "rust_out::TestStruct"
|
|
|
|
/// );
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Re-register the custom type with a name.
|
2020-03-19 06:52:10 +01:00
|
|
|
/// engine.register_type_with_name::<TestStruct>("Hello");
|
|
|
|
///
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
|
|
|
|
/// "Hello"
|
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-29 11:15:12 +02:00
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-07-12 05:46:53 +02:00
|
|
|
pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self {
|
2020-03-04 15:00:01 +01:00
|
|
|
// Add the pretty-print type name into the map
|
2020-10-25 14:57:18 +01:00
|
|
|
self.type_names.insert(type_name::<T>().into(), name.into());
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-03-04 15:00:01 +01:00
|
|
|
}
|
2020-12-14 08:15:05 +01:00
|
|
|
/// Register an type iterator for an iterable type with the [`Engine`].
|
2020-03-19 06:52:10 +01:00
|
|
|
/// This is an advanced feature.
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-10-15 16:11:18 +02:00
|
|
|
pub fn register_iterator<T>(&mut self) -> &mut Self
|
|
|
|
where
|
2020-12-14 08:15:05 +01:00
|
|
|
T: Variant + Clone + IntoIterator,
|
|
|
|
<T as IntoIterator>::Item: Variant + Clone,
|
2020-10-15 16:11:18 +02:00
|
|
|
{
|
2020-11-19 06:56:03 +01:00
|
|
|
self.global_namespace.set_iterable::<T>();
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-03-04 15:00:01 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register a getter function for a member of a registered type with the [`Engine`].
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
2020-03-22 03:18:16 +01:00
|
|
|
/// The function signature must start with `&mut self` and not `&self`.
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
2020-03-30 10:10:50 +02:00
|
|
|
/// struct TestStruct {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { field: 1 } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-03-22 03:18:16 +01:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2020-03-19 06:52:10 +01:00
|
|
|
/// fn get_field(&mut self) -> i64 { self.field }
|
|
|
|
/// }
|
|
|
|
///
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::Engine;
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register a getter on a property (notice it doesn't have to be the same name).
|
|
|
|
/// .register_get("xyz", TestStruct::get_field);
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz")?, 1);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-29 11:15:12 +02:00
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-04-02 06:34:39 +02:00
|
|
|
pub fn register_get<T: Variant + Clone, V: Variant + Clone>(
|
2020-05-21 11:11:01 +02:00
|
|
|
&mut self,
|
|
|
|
name: &str,
|
2021-04-02 06:34:39 +02:00
|
|
|
get_fn: impl Fn(&mut T) -> V + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2021-03-15 04:36:30 +01:00
|
|
|
use crate::engine::make_getter;
|
2020-12-26 06:05:57 +01:00
|
|
|
self.register_fn(&make_getter(name), get_fn)
|
2020-03-04 15:00:01 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register a getter function for a member of a registered type with the [`Engine`].
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// The function signature must start with `&mut self` and not `&self`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::{Engine, Dynamic, EvalAltResult};
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { field: 1 } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-08-07 05:10:38 +02:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2021-03-15 15:37:50 +01:00
|
|
|
/// fn get_field(&mut self) -> Result<i64, Box<EvalAltResult>> {
|
|
|
|
/// Ok(self.field)
|
2020-08-07 05:10:38 +02:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register a getter on a property (notice it doesn't have to be the same name).
|
|
|
|
/// .register_get_result("xyz", TestStruct::get_field);
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz")?, 1);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-04-02 06:34:39 +02:00
|
|
|
pub fn register_get_result<T: Variant + Clone, V: Variant + Clone>(
|
2020-08-07 05:10:38 +02:00
|
|
|
&mut self,
|
|
|
|
name: &str,
|
2021-04-02 06:34:39 +02:00
|
|
|
get_fn: impl Fn(&mut T) -> Result<V, Box<EvalAltResult>> + SendSync + 'static,
|
2020-08-07 05:10:38 +02:00
|
|
|
) -> &mut Self {
|
2021-03-15 04:36:30 +01:00
|
|
|
use crate::engine::make_getter;
|
2020-12-26 06:05:57 +01:00
|
|
|
self.register_result_fn(&make_getter(name), get_fn)
|
2020-08-07 05:10:38 +02:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register a setter function for a member of a registered type with the [`Engine`].
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-03-30 10:10:50 +02:00
|
|
|
/// #[derive(Debug, Clone, Eq, PartialEq)]
|
2020-03-19 06:52:10 +01:00
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { field: 1 } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
|
|
|
|
/// }
|
|
|
|
///
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::Engine;
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register a setter on a property (notice it doesn't have to be the same name)
|
|
|
|
/// .register_set("xyz", TestStruct::set_field);
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// // Notice that, with a getter, there is no way to get the property value
|
2020-03-30 10:10:50 +02:00
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<TestStruct>("let a = new_ts(); a.xyz = 42; a")?,
|
|
|
|
/// TestStruct { field: 42 }
|
|
|
|
/// );
|
2020-03-19 06:52:10 +01:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-29 11:15:12 +02:00
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-04-02 06:34:39 +02:00
|
|
|
pub fn register_set<T: Variant + Clone, V: Variant + Clone>(
|
2020-05-21 11:11:01 +02:00
|
|
|
&mut self,
|
|
|
|
name: &str,
|
2021-04-02 06:34:39 +02:00
|
|
|
set_fn: impl Fn(&mut T, V) + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2021-03-15 04:36:30 +01:00
|
|
|
use crate::engine::make_setter;
|
2020-12-26 06:05:57 +01:00
|
|
|
self.register_fn(&make_setter(name), set_fn)
|
2020-03-04 15:00:01 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register a setter function for a member of a registered type with the [`Engine`].
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::{Engine, Dynamic, EvalAltResult};
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// #[derive(Debug, Clone, Eq, PartialEq)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { field: 1 } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-09-22 06:14:26 +02:00
|
|
|
/// fn set_field(&mut self, new_val: i64) -> Result<(), Box<EvalAltResult>> {
|
2020-08-07 05:10:38 +02:00
|
|
|
/// self.field = new_val;
|
2020-09-22 06:14:26 +02:00
|
|
|
/// Ok(())
|
2020-08-07 05:10:38 +02:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register a setter on a property (notice it doesn't have to be the same name)
|
|
|
|
/// .register_set_result("xyz", TestStruct::set_field);
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// // Notice that, with a getter, there is no way to get the property value
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<TestStruct>("let a = new_ts(); a.xyz = 42; a")?,
|
|
|
|
/// TestStruct { field: 42 }
|
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-04-02 06:34:39 +02:00
|
|
|
pub fn register_set_result<T: Variant + Clone, V: Variant + Clone>(
|
2020-08-07 05:10:38 +02:00
|
|
|
&mut self,
|
|
|
|
name: &str,
|
2021-04-02 06:34:39 +02:00
|
|
|
set_fn: impl Fn(&mut T, V) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2021-03-15 04:36:30 +01:00
|
|
|
use crate::engine::make_setter;
|
2021-04-02 06:34:39 +02:00
|
|
|
self.register_result_fn(&make_setter(name), move |obj: &mut T, value: V| {
|
2021-03-15 15:37:50 +01:00
|
|
|
set_fn(obj, value)
|
2020-12-26 06:05:57 +01:00
|
|
|
})
|
2020-08-07 05:10:38 +02:00
|
|
|
}
|
2020-09-20 08:52:38 +02:00
|
|
|
/// Short-hand for registering both getter and setter functions
|
2020-11-20 09:52:28 +01:00
|
|
|
/// of a registered type with the [`Engine`].
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
2020-03-22 03:18:16 +01:00
|
|
|
/// All function signatures must start with `&mut self` and not `&self`.
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { field: 1 } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-03-22 03:18:16 +01:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2020-09-22 06:14:26 +02:00
|
|
|
/// fn get_field(&mut self) -> i64 { self.field }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
|
|
|
|
/// }
|
|
|
|
///
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::Engine;
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register both a getter and a setter on a property
|
|
|
|
/// // (notice it doesn't have to be the same name)
|
|
|
|
/// .register_get_set("xyz", TestStruct::get_field, TestStruct::set_field);
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz = 42; a.xyz")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-29 11:15:12 +02:00
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-04-02 06:34:39 +02:00
|
|
|
pub fn register_get_set<T: Variant + Clone, V: Variant + Clone>(
|
2020-05-21 11:11:01 +02:00
|
|
|
&mut self,
|
|
|
|
name: &str,
|
2021-04-02 06:34:39 +02:00
|
|
|
get_fn: impl Fn(&mut T) -> V + SendSync + 'static,
|
|
|
|
set_fn: impl Fn(&mut T, V) + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2020-07-12 05:46:53 +02:00
|
|
|
self.register_get(name, get_fn).register_set(name, set_fn)
|
2020-03-04 15:00:01 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register an index getter for a custom type with the [`Engine`].
|
2020-05-05 14:38:48 +02:00
|
|
|
///
|
|
|
|
/// The function signature must start with `&mut self` and not `&self`.
|
|
|
|
///
|
2020-09-22 11:57:56 +02:00
|
|
|
/// # Panics
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
|
2020-09-22 11:57:56 +02:00
|
|
|
/// Indexers for arrays, object maps and strings cannot be registered.
|
|
|
|
///
|
2020-05-05 14:38:48 +02:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// fields: Vec<i64>
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-05-05 14:38:48 +02:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
|
|
|
/// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::Engine;
|
2020-05-05 14:38:48 +02:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
2020-09-20 09:55:11 +02:00
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
2020-05-05 14:38:48 +02:00
|
|
|
/// engine.register_type::<TestStruct>();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// engine
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register an indexer.
|
|
|
|
/// .register_indexer_get(TestStruct::get_field);
|
2020-05-05 14:38:48 +02:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2]")?, 3);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-04-02 06:34:39 +02:00
|
|
|
pub fn register_indexer_get<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>(
|
2020-05-21 11:11:01 +02:00
|
|
|
&mut self,
|
2021-04-02 06:34:39 +02:00
|
|
|
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2020-09-22 11:57:56 +02:00
|
|
|
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
|
|
|
panic!("Cannot register indexer for arrays.");
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
|
|
|
panic!("Cannot register indexer for object maps.");
|
|
|
|
}
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<String>()
|
|
|
|
|| TypeId::of::<T>() == TypeId::of::<&str>()
|
2020-11-16 09:28:04 +01:00
|
|
|
|| TypeId::of::<T>() == TypeId::of::<crate::ImmutableString>()
|
2020-09-22 11:57:56 +02:00
|
|
|
{
|
|
|
|
panic!("Cannot register indexer for strings.");
|
|
|
|
}
|
|
|
|
|
2021-03-15 04:36:30 +01:00
|
|
|
self.register_fn(crate::engine::FN_IDX_GET, get_fn)
|
2020-06-06 07:06:00 +02:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register an index getter for a custom type with the [`Engine`].
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// The function signature must start with `&mut self` and not `&self`.
|
|
|
|
///
|
2020-09-22 11:57:56 +02:00
|
|
|
/// # Panics
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
|
2020-09-22 11:57:56 +02:00
|
|
|
/// Indexers for arrays, object maps and strings cannot be registered.
|
|
|
|
///
|
2020-08-07 05:10:38 +02:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::{Engine, Dynamic, EvalAltResult};
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// fields: Vec<i64>
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-08-07 05:10:38 +02:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2021-03-15 15:37:50 +01:00
|
|
|
/// fn get_field(&mut self, index: i64) -> Result<i64, Box<EvalAltResult>> {
|
|
|
|
/// Ok(self.fields[index as usize])
|
2020-08-07 05:10:38 +02:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
2020-09-20 09:55:11 +02:00
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
2020-08-07 05:10:38 +02:00
|
|
|
/// engine.register_type::<TestStruct>();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// engine
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register an indexer.
|
|
|
|
/// .register_indexer_get_result(TestStruct::get_field);
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2]")?, 3);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-03-15 15:37:50 +01:00
|
|
|
pub fn register_indexer_get_result<
|
|
|
|
T: Variant + Clone,
|
|
|
|
X: Variant + Clone,
|
2021-04-02 06:34:39 +02:00
|
|
|
V: Variant + Clone,
|
2021-03-15 15:37:50 +01:00
|
|
|
>(
|
2020-08-07 05:10:38 +02:00
|
|
|
&mut self,
|
2021-04-02 06:34:39 +02:00
|
|
|
get_fn: impl Fn(&mut T, X) -> Result<V, Box<EvalAltResult>> + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2020-09-22 11:57:56 +02:00
|
|
|
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
|
|
|
panic!("Cannot register indexer for arrays.");
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
|
|
|
panic!("Cannot register indexer for object maps.");
|
|
|
|
}
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<String>()
|
|
|
|
|| TypeId::of::<T>() == TypeId::of::<&str>()
|
2020-11-16 09:28:04 +01:00
|
|
|
|| TypeId::of::<T>() == TypeId::of::<crate::ImmutableString>()
|
2020-09-22 11:57:56 +02:00
|
|
|
{
|
|
|
|
panic!("Cannot register indexer for strings.");
|
|
|
|
}
|
|
|
|
|
2021-03-15 04:36:30 +01:00
|
|
|
self.register_result_fn(crate::engine::FN_IDX_GET, get_fn)
|
2020-08-07 05:10:38 +02:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register an index setter for a custom type with the [`Engine`].
|
2020-06-06 07:06:00 +02:00
|
|
|
///
|
2020-09-22 11:57:56 +02:00
|
|
|
/// # Panics
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
|
2020-09-22 11:57:56 +02:00
|
|
|
/// Indexers for arrays, object maps and strings cannot be registered.
|
|
|
|
///
|
2020-06-06 07:06:00 +02:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// fields: Vec<i64>
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-06-06 07:06:00 +02:00
|
|
|
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::Engine;
|
2020-06-06 07:06:00 +02:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
2020-09-20 09:55:11 +02:00
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
2020-06-06 07:06:00 +02:00
|
|
|
/// engine.register_type::<TestStruct>();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// engine
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register an indexer.
|
|
|
|
/// .register_indexer_set(TestStruct::set_field);
|
2020-06-06 07:06:00 +02:00
|
|
|
///
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<TestStruct>("let a = new_ts(); a[2] = 42; a")?.fields[2],
|
|
|
|
/// 42
|
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-04-02 06:34:39 +02:00
|
|
|
pub fn register_indexer_set<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>(
|
2020-06-06 07:06:00 +02:00
|
|
|
&mut self,
|
2021-04-02 06:34:39 +02:00
|
|
|
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2020-09-22 11:57:56 +02:00
|
|
|
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
|
|
|
panic!("Cannot register indexer for arrays.");
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
|
|
|
panic!("Cannot register indexer for object maps.");
|
|
|
|
}
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<String>()
|
|
|
|
|| TypeId::of::<T>() == TypeId::of::<&str>()
|
2020-11-16 09:28:04 +01:00
|
|
|
|| TypeId::of::<T>() == TypeId::of::<crate::ImmutableString>()
|
2020-09-22 11:57:56 +02:00
|
|
|
{
|
|
|
|
panic!("Cannot register indexer for strings.");
|
|
|
|
}
|
|
|
|
|
2021-03-15 04:36:30 +01:00
|
|
|
self.register_fn(crate::engine::FN_IDX_SET, set_fn)
|
2020-06-06 07:06:00 +02:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Register an index setter for a custom type with the [`Engine`].
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
2020-09-22 11:57:56 +02:00
|
|
|
/// # Panics
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
|
2020-09-22 11:57:56 +02:00
|
|
|
/// Indexers for arrays, object maps and strings cannot be registered.
|
|
|
|
///
|
2020-08-07 05:10:38 +02:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::{Engine, Dynamic, EvalAltResult};
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// fields: Vec<i64>
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-09-22 06:14:26 +02:00
|
|
|
/// fn set_field(&mut self, index: i64, value: i64) -> Result<(), Box<EvalAltResult>> {
|
2020-08-07 05:10:38 +02:00
|
|
|
/// self.fields[index as usize] = value;
|
2020-09-22 06:14:26 +02:00
|
|
|
/// Ok(())
|
2020-08-07 05:10:38 +02:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
2020-09-20 09:55:11 +02:00
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
2020-08-07 05:10:38 +02:00
|
|
|
/// engine.register_type::<TestStruct>();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// engine
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register an indexer.
|
|
|
|
/// .register_indexer_set_result(TestStruct::set_field);
|
2020-08-07 05:10:38 +02:00
|
|
|
///
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<TestStruct>("let a = new_ts(); a[2] = 42; a")?.fields[2],
|
|
|
|
/// 42
|
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-11-16 16:10:14 +01:00
|
|
|
pub fn register_indexer_set_result<
|
2020-08-07 05:10:38 +02:00
|
|
|
T: Variant + Clone,
|
|
|
|
X: Variant + Clone,
|
2021-04-02 06:34:39 +02:00
|
|
|
V: Variant + Clone,
|
2020-11-16 16:10:14 +01:00
|
|
|
>(
|
|
|
|
&mut self,
|
2021-04-02 06:34:39 +02:00
|
|
|
set_fn: impl Fn(&mut T, X, V) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2020-09-22 11:57:56 +02:00
|
|
|
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
|
|
|
panic!("Cannot register indexer for arrays.");
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
|
|
|
panic!("Cannot register indexer for object maps.");
|
|
|
|
}
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<String>()
|
|
|
|
|| TypeId::of::<T>() == TypeId::of::<&str>()
|
2020-11-16 09:28:04 +01:00
|
|
|
|| TypeId::of::<T>() == TypeId::of::<crate::ImmutableString>()
|
2020-09-22 11:57:56 +02:00
|
|
|
{
|
|
|
|
panic!("Cannot register indexer for strings.");
|
|
|
|
}
|
|
|
|
|
2021-03-15 04:36:30 +01:00
|
|
|
self.register_result_fn(
|
|
|
|
crate::engine::FN_IDX_SET,
|
2021-04-02 06:34:39 +02:00
|
|
|
move |obj: &mut T, index: X, value: V| set_fn(obj, index, value),
|
2021-03-15 04:36:30 +01:00
|
|
|
)
|
2020-08-07 05:10:38 +02:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Short-hand for register both index getter and setter functions for a custom type with the [`Engine`].
|
2020-06-06 07:06:00 +02:00
|
|
|
///
|
2020-09-22 11:57:56 +02:00
|
|
|
/// # Panics
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
|
2020-09-22 11:57:56 +02:00
|
|
|
/// Indexers for arrays, object maps and strings cannot be registered.
|
|
|
|
///
|
2020-06-06 07:06:00 +02:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// fields: Vec<i64>
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2020-10-19 08:26:15 +02:00
|
|
|
/// fn new() -> Self { Self { fields: vec![1, 2, 3, 4, 5] } }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-09-22 06:14:26 +02:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2020-06-06 07:06:00 +02:00
|
|
|
/// fn get_field(&mut self, index: i64) -> i64 { self.fields[index as usize] }
|
2021-03-02 16:08:54 +01:00
|
|
|
///
|
2020-06-06 07:06:00 +02:00
|
|
|
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2021-03-15 04:36:30 +01:00
|
|
|
/// use rhai::Engine;
|
2020-06-06 07:06:00 +02:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// // Register API for the custom type.
|
2020-09-20 09:55:11 +02:00
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
2020-06-06 07:06:00 +02:00
|
|
|
/// engine.register_type::<TestStruct>();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// engine
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register an indexer.
|
|
|
|
/// .register_indexer_get_set(TestStruct::get_field, TestStruct::set_field);
|
2020-06-06 07:06:00 +02:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2] = 42; a[2]")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-04-02 06:34:39 +02:00
|
|
|
pub fn register_indexer_get_set<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>(
|
2020-06-06 07:06:00 +02:00
|
|
|
&mut self,
|
2021-04-02 06:34:39 +02:00
|
|
|
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static,
|
|
|
|
set_fn: impl Fn(&mut T, X, V) -> () + SendSync + 'static,
|
2020-11-16 16:10:14 +01:00
|
|
|
) -> &mut Self {
|
2021-02-13 03:56:09 +01:00
|
|
|
self.register_indexer_get(get_fn)
|
|
|
|
.register_indexer_set(set_fn)
|
2020-05-05 14:38:48 +02:00
|
|
|
}
|
2020-12-26 16:21:16 +01:00
|
|
|
/// Register a shared [`Module`] into the global namespace of [`Engine`].
|
2020-12-22 16:45:14 +01:00
|
|
|
///
|
2020-12-26 16:21:16 +01:00
|
|
|
/// All functions and type iterators are automatically available to scripts without namespace
|
|
|
|
/// qualifications.
|
2020-12-22 16:45:14 +01:00
|
|
|
///
|
|
|
|
/// Sub-modules and variables are **ignored**.
|
|
|
|
///
|
2020-12-26 16:21:16 +01:00
|
|
|
/// When searching for functions, modules loaded later are preferred. In other words, loaded
|
|
|
|
/// modules are searched in reverse order.
|
2020-12-22 16:45:14 +01:00
|
|
|
#[inline(always)]
|
2020-12-23 03:08:43 +01:00
|
|
|
pub fn register_global_module(&mut self, module: Shared<Module>) -> &mut Self {
|
2020-12-22 16:45:14 +01:00
|
|
|
// Insert the module into the front
|
2020-12-23 03:08:43 +01:00
|
|
|
self.global_modules.insert(0, module);
|
2020-12-22 16:45:14 +01:00
|
|
|
self
|
|
|
|
}
|
2020-12-26 16:21:16 +01:00
|
|
|
/// Register a shared [`Module`] into the global namespace of [`Engine`].
|
2021-03-28 11:04:16 +02:00
|
|
|
/// This function is deprecated and will be removed in the future.
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Use [`register_global_module`][Engine::register_global_module] instead.
|
2020-12-23 08:30:35 +01:00
|
|
|
#[inline(always)]
|
2021-03-28 11:04:16 +02:00
|
|
|
#[deprecated(since = "0.19.9", note = "use `register_global_module` instead")]
|
2020-12-23 08:30:35 +01:00
|
|
|
pub fn load_package(&mut self, module: impl Into<Shared<Module>>) -> &mut Self {
|
|
|
|
self.register_global_module(module.into())
|
|
|
|
}
|
2021-03-15 05:39:06 +01:00
|
|
|
/// Register a shared [`Module`] as a static module namespace with the [`Engine`].
|
2020-12-22 16:45:14 +01:00
|
|
|
///
|
2020-12-26 16:21:16 +01:00
|
|
|
/// Functions marked [`FnNamespace::Global`] and type iterators are exposed to scripts without
|
|
|
|
/// namespace qualifications.
|
2020-11-15 16:14:16 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-12-26 06:05:57 +01:00
|
|
|
/// use rhai::{Engine, Shared, Module};
|
2020-11-15 16:14:16 +01:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Create the module
|
|
|
|
/// let mut module = Module::new();
|
2021-03-15 05:39:06 +01:00
|
|
|
/// module.set_native_fn("calc", |x: i64| Ok(x + 1));
|
2020-11-15 16:14:16 +01:00
|
|
|
///
|
2020-12-26 06:05:57 +01:00
|
|
|
/// let module: Shared<Module> = module.into();
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// engine
|
|
|
|
/// // Register the module as a fixed sub-module
|
|
|
|
/// .register_static_module("foo::bar::baz", module.clone())
|
|
|
|
/// // Multiple registrations to the same partial path is also OK!
|
|
|
|
/// .register_static_module("foo::bar::hello", module.clone())
|
|
|
|
/// .register_static_module("CalcService", module);
|
2020-12-26 06:05:57 +01:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("foo::bar::baz::calc(41)")?, 42);
|
|
|
|
/// assert_eq!(engine.eval::<i64>("foo::bar::hello::calc(41)")?, 42);
|
2020-11-15 16:14:16 +01:00
|
|
|
/// assert_eq!(engine.eval::<i64>("CalcService::calc(41)")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
2021-03-24 06:17:52 +01:00
|
|
|
pub fn register_static_module(
|
|
|
|
&mut self,
|
2021-03-29 05:36:02 +02:00
|
|
|
name: impl AsRef<str> + Into<Identifier>,
|
2021-03-24 06:17:52 +01:00
|
|
|
module: Shared<Module>,
|
|
|
|
) -> &mut Self {
|
2020-12-26 06:05:57 +01:00
|
|
|
fn register_static_module_raw(
|
2021-03-29 05:36:02 +02:00
|
|
|
root: &mut crate::stdlib::collections::BTreeMap<Identifier, Shared<Module>>,
|
|
|
|
name: impl AsRef<str> + Into<Identifier>,
|
2020-12-26 06:05:57 +01:00
|
|
|
module: Shared<Module>,
|
|
|
|
) {
|
|
|
|
let separator = crate::token::Token::DoubleColon.syntax();
|
|
|
|
|
2021-03-24 06:17:52 +01:00
|
|
|
if !name.as_ref().contains(separator.as_ref()) {
|
2020-12-26 06:05:57 +01:00
|
|
|
if !module.is_indexed() {
|
|
|
|
// Index the module (making a clone copy if necessary) if it is not indexed
|
|
|
|
let mut module = crate::fn_native::shared_take_or_clone(module);
|
|
|
|
module.build_index();
|
2021-03-24 06:17:52 +01:00
|
|
|
root.insert(name.into(), module.into());
|
2020-12-26 06:05:57 +01:00
|
|
|
} else {
|
2021-03-24 06:17:52 +01:00
|
|
|
root.insert(name.into(), module);
|
2020-12-26 06:05:57 +01:00
|
|
|
}
|
|
|
|
} else {
|
2021-03-24 06:17:52 +01:00
|
|
|
let mut iter = name.as_ref().splitn(2, separator.as_ref());
|
2020-12-26 06:05:57 +01:00
|
|
|
let sub_module = iter.next().unwrap().trim();
|
|
|
|
let remainder = iter.next().unwrap().trim();
|
|
|
|
|
|
|
|
if !root.contains_key(sub_module) {
|
|
|
|
let mut m: Module = Default::default();
|
|
|
|
register_static_module_raw(m.sub_modules_mut(), remainder, module);
|
|
|
|
m.build_index();
|
|
|
|
root.insert(sub_module.into(), m.into());
|
|
|
|
} else {
|
|
|
|
let m = root.remove(sub_module).unwrap();
|
|
|
|
let mut m = crate::fn_native::shared_take_or_clone(m);
|
|
|
|
register_static_module_raw(m.sub_modules_mut(), remainder, module);
|
|
|
|
m.build_index();
|
|
|
|
root.insert(sub_module.into(), m.into());
|
|
|
|
}
|
|
|
|
}
|
2020-11-15 16:14:16 +01:00
|
|
|
}
|
2020-12-26 06:05:57 +01:00
|
|
|
|
2021-03-24 06:17:52 +01:00
|
|
|
register_static_module_raw(&mut self.global_sub_modules, name, module);
|
2020-11-15 16:14:16 +01:00
|
|
|
self
|
|
|
|
}
|
2020-12-26 06:05:57 +01:00
|
|
|
|
2020-12-26 16:21:16 +01:00
|
|
|
/// Register a shared [`Module`] as a static module namespace with the [`Engine`].
|
2021-03-28 11:04:16 +02:00
|
|
|
/// This function is deprecated and will be removed in the future.
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Use [`register_static_module`][Engine::register_static_module] instead.
|
2020-12-23 08:30:35 +01:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
#[inline(always)]
|
2021-03-28 11:04:16 +02:00
|
|
|
#[deprecated(since = "0.19.9", note = "use `register_static_module` instead")]
|
2021-03-24 06:17:52 +01:00
|
|
|
pub fn register_module(
|
|
|
|
&mut self,
|
2021-03-29 05:36:02 +02:00
|
|
|
name: impl AsRef<str> + Into<Identifier>,
|
2021-03-24 06:17:52 +01:00
|
|
|
module: impl Into<Shared<Module>>,
|
|
|
|
) -> &mut Self {
|
2020-12-23 08:30:35 +01:00
|
|
|
self.register_static_module(name, module.into())
|
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Compile a string into an [`AST`], which can be used later for evaluation.
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Compile a script to an AST and store it for later evaluation
|
2020-03-19 06:52:10 +01:00
|
|
|
/// let ast = engine.compile("40 + 2")?;
|
|
|
|
///
|
|
|
|
/// for _ in 0..42 {
|
|
|
|
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
|
|
|
|
/// }
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-22 12:28:13 +02:00
|
|
|
pub fn compile(&self, script: &str) -> Result<AST, ParseError> {
|
2020-10-20 04:54:32 +02:00
|
|
|
self.compile_with_scope(&Default::default(), script)
|
2020-03-14 07:30:44 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Compile a string into an [`AST`] using own scope, which can be used later for evaluation.
|
2020-05-13 05:57:07 +02:00
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// The scope is useful for passing constants into the script for optimization
|
2020-11-20 09:52:28 +01:00
|
|
|
/// when using [`OptimizationLevel::Full`].
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 12:53:42 +01:00
|
|
|
/// # #[cfg(not(feature = "no_optimize"))]
|
|
|
|
/// # {
|
|
|
|
/// use rhai::{Engine, Scope, OptimizationLevel};
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Set optimization level to 'Full' so the Engine can fold constants
|
|
|
|
/// // into function calls and operators.
|
|
|
|
/// engine.set_optimization_level(OptimizationLevel::Full);
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// // Create initialized scope
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push_constant("x", 42_i64); // 'x' is a constant
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Compile a script to an AST and store it for later evaluation.
|
|
|
|
/// // Notice that `Full` optimization is on, so constants are folded
|
|
|
|
/// // into function calls and operators.
|
2020-03-19 06:52:10 +01:00
|
|
|
/// let ast = engine.compile_with_scope(&mut scope,
|
2020-03-19 12:53:42 +01:00
|
|
|
/// "if x > 40 { x } else { 0 }" // all 'x' are replaced with 42
|
2020-03-19 06:52:10 +01:00
|
|
|
/// )?;
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Normally this would have failed because no scope is passed into the 'eval_ast'
|
|
|
|
/// // call and so the variable 'x' does not exist. Here, it passes because the script
|
|
|
|
/// // has been optimized and all references to 'x' are already gone.
|
2020-03-19 06:52:10 +01:00
|
|
|
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
|
2020-03-19 12:53:42 +01:00
|
|
|
/// # }
|
2020-03-19 06:52:10 +01:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-22 12:28:13 +02:00
|
|
|
pub fn compile_with_scope(&self, scope: &Scope, script: &str) -> Result<AST, ParseError> {
|
2020-05-13 05:57:07 +02:00
|
|
|
self.compile_scripts_with_scope(scope, &[script])
|
2020-04-08 04:19:03 +02:00
|
|
|
}
|
2021-01-08 17:24:55 +01:00
|
|
|
/// Compile a string into an [`AST`] using own scope, which can be used later for evaluation,
|
|
|
|
/// embedding all imported modules.
|
|
|
|
///
|
|
|
|
/// Modules referred by `import` statements containing literal string paths are eagerly resolved
|
|
|
|
/// via the current [module resolver][crate::ModuleResolver] and embedded into the resultant
|
|
|
|
/// [`AST`]. When it is evaluated later, `import` statement directly recall pre-resolved
|
|
|
|
/// [modules][Module] and the resolution process is not performed again.
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
pub fn compile_into_self_contained(
|
|
|
|
&self,
|
|
|
|
scope: &Scope,
|
|
|
|
script: &str,
|
|
|
|
) -> Result<AST, Box<EvalAltResult>> {
|
|
|
|
use crate::{
|
2021-01-09 09:52:22 +01:00
|
|
|
ast::{ASTNode, Expr, Stmt},
|
2021-01-08 17:24:55 +01:00
|
|
|
fn_native::shared_take_or_clone,
|
|
|
|
module::resolvers::StaticModuleResolver,
|
2021-03-23 05:13:53 +01:00
|
|
|
stdlib::collections::BTreeSet,
|
2021-01-08 17:24:55 +01:00
|
|
|
};
|
|
|
|
|
2021-01-09 09:52:22 +01:00
|
|
|
fn collect_imports(
|
|
|
|
ast: &AST,
|
|
|
|
resolver: &StaticModuleResolver,
|
2021-03-29 05:36:02 +02:00
|
|
|
imports: &mut BTreeSet<Identifier>,
|
2021-01-09 09:52:22 +01:00
|
|
|
) {
|
|
|
|
ast.walk(&mut |path| match path.last().unwrap() {
|
|
|
|
// Collect all `import` statements with a string constant path
|
|
|
|
ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, _), _, _))
|
2021-03-29 05:36:02 +02:00
|
|
|
if !resolver.contains_path(s) && !imports.contains(s.as_str()) =>
|
2021-01-08 17:40:44 +01:00
|
|
|
{
|
2021-03-29 05:36:02 +02:00
|
|
|
imports.insert(s.clone().into());
|
2021-03-11 14:55:55 +01:00
|
|
|
true
|
2021-01-08 17:40:44 +01:00
|
|
|
}
|
2021-03-11 14:55:55 +01:00
|
|
|
_ => true,
|
2021-01-08 17:24:55 +01:00
|
|
|
});
|
2021-01-09 09:52:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut resolver = StaticModuleResolver::new();
|
|
|
|
let mut ast = self.compile_scripts_with_scope(scope, &[script])?;
|
2021-03-23 05:13:53 +01:00
|
|
|
let mut imports = Default::default();
|
2021-01-09 09:52:22 +01:00
|
|
|
|
|
|
|
collect_imports(&ast, &mut resolver, &mut imports);
|
2021-01-08 17:24:55 +01:00
|
|
|
|
|
|
|
if !imports.is_empty() {
|
2021-01-09 09:52:22 +01:00
|
|
|
while let Some(path) = imports.iter().next() {
|
|
|
|
let path = path.clone();
|
|
|
|
|
2021-01-09 16:26:50 +01:00
|
|
|
match self
|
|
|
|
.module_resolver
|
2021-04-02 06:34:39 +02:00
|
|
|
.resolve_ast(self, None, &path, Position::NONE)
|
2021-01-09 09:52:22 +01:00
|
|
|
{
|
2021-01-09 16:26:50 +01:00
|
|
|
Some(Ok(module_ast)) => {
|
|
|
|
collect_imports(&module_ast, &mut resolver, &mut imports)
|
|
|
|
}
|
|
|
|
Some(err @ Err(_)) => return err,
|
|
|
|
None => (),
|
2021-01-09 09:52:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let module = shared_take_or_clone(self.module_resolver.resolve(
|
|
|
|
self,
|
2021-04-02 06:34:39 +02:00
|
|
|
None,
|
2021-01-09 09:52:22 +01:00
|
|
|
&path,
|
|
|
|
Position::NONE,
|
|
|
|
)?);
|
|
|
|
|
|
|
|
imports.remove(&path);
|
2021-01-08 17:24:55 +01:00
|
|
|
resolver.insert(path, module);
|
|
|
|
}
|
|
|
|
ast.set_resolver(resolver);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(ast)
|
|
|
|
}
|
2020-05-13 05:57:07 +02:00
|
|
|
/// When passed a list of strings, first join the strings into one large script,
|
2020-11-20 09:52:28 +01:00
|
|
|
/// and then compile them into an [`AST`] using own scope, which can be used later for evaluation.
|
2020-05-13 05:57:07 +02:00
|
|
|
///
|
|
|
|
/// The scope is useful for passing constants into the script for optimization
|
2020-11-20 09:52:28 +01:00
|
|
|
/// when using [`OptimizationLevel::Full`].
|
2020-05-13 05:57:07 +02:00
|
|
|
///
|
|
|
|
/// ## Note
|
|
|
|
///
|
|
|
|
/// All strings are simply parsed one after another with nothing inserted in between, not even
|
|
|
|
/// a newline or space.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// # #[cfg(not(feature = "no_optimize"))]
|
|
|
|
/// # {
|
|
|
|
/// use rhai::{Engine, Scope, OptimizationLevel};
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Set optimization level to 'Full' so the Engine can fold constants
|
|
|
|
/// // into function calls and operators.
|
|
|
|
/// engine.set_optimization_level(OptimizationLevel::Full);
|
|
|
|
///
|
|
|
|
/// // Create initialized scope
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push_constant("x", 42_i64); // 'x' is a constant
|
|
|
|
///
|
|
|
|
/// // Compile a script made up of script segments to an AST and store it for later evaluation.
|
|
|
|
/// // Notice that `Full` optimization is on, so constants are folded
|
|
|
|
/// // into function calls and operators.
|
|
|
|
/// let ast = engine.compile_scripts_with_scope(&mut scope, &[
|
|
|
|
/// "if x > 40", // all 'x' are replaced with 42
|
2020-05-13 13:21:42 +02:00
|
|
|
/// "{ x } el",
|
2020-05-13 05:57:07 +02:00
|
|
|
/// "se { 0 }" // segments do not need to be valid scripts!
|
|
|
|
/// ])?;
|
|
|
|
///
|
|
|
|
/// // Normally this would have failed because no scope is passed into the 'eval_ast'
|
|
|
|
/// // call and so the variable 'x' does not exist. Here, it passes because the script
|
|
|
|
/// // has been optimized and all references to 'x' are already gone.
|
|
|
|
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
|
|
|
|
/// # }
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-13 05:57:07 +02:00
|
|
|
pub fn compile_scripts_with_scope(
|
|
|
|
&self,
|
|
|
|
scope: &Scope,
|
|
|
|
scripts: &[&str],
|
2020-05-22 12:28:13 +02:00
|
|
|
) -> Result<AST, ParseError> {
|
2020-05-13 05:57:07 +02:00
|
|
|
self.compile_with_scope_and_optimization_level(scope, scripts, self.optimization_level)
|
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level.
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-04-08 04:19:03 +02:00
|
|
|
pub(crate) fn compile_with_scope_and_optimization_level(
|
|
|
|
&self,
|
|
|
|
scope: &Scope,
|
2020-05-13 05:57:07 +02:00
|
|
|
scripts: &[&str],
|
2020-04-10 06:16:39 +02:00
|
|
|
optimization_level: OptimizationLevel,
|
2020-05-22 12:28:13 +02:00
|
|
|
) -> Result<AST, ParseError> {
|
2021-03-03 15:49:57 +01:00
|
|
|
let stream = self.lex_raw(scripts, None);
|
2021-01-04 04:58:24 +01:00
|
|
|
self.parse(&mut stream.peekable(), scope, optimization_level)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-03-19 06:52:10 +01:00
|
|
|
/// Read the contents of a file into a string.
|
2020-03-18 05:04:26 +01:00
|
|
|
#[cfg(not(feature = "no_std"))]
|
2021-02-19 08:50:48 +01:00
|
|
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
2020-11-16 16:10:14 +01:00
|
|
|
fn read_file(path: crate::stdlib::path::PathBuf) -> Result<String, Box<EvalAltResult>> {
|
|
|
|
use crate::stdlib::io::Read;
|
|
|
|
|
|
|
|
let mut f = crate::stdlib::fs::File::open(path.clone()).map_err(|err| {
|
2020-10-17 10:34:07 +02:00
|
|
|
EvalAltResult::ErrorSystem(
|
2021-03-29 07:40:33 +02:00
|
|
|
crate::stdlib::format!("Cannot open script file '{}'", path.to_string_lossy()),
|
2020-10-17 10:34:07 +02:00
|
|
|
err.into(),
|
|
|
|
)
|
2020-05-05 18:09:04 +02:00
|
|
|
})?;
|
2020-03-02 07:28:42 +01:00
|
|
|
|
|
|
|
let mut contents = String::new();
|
|
|
|
|
2020-05-05 18:09:04 +02:00
|
|
|
f.read_to_string(&mut contents).map_err(|err| {
|
2020-10-17 10:34:07 +02:00
|
|
|
EvalAltResult::ErrorSystem(
|
2021-03-29 07:40:33 +02:00
|
|
|
crate::stdlib::format!("Cannot read script file '{}'", path.to_string_lossy()),
|
2020-10-17 10:34:07 +02:00
|
|
|
err.into(),
|
|
|
|
)
|
2020-05-05 18:09:04 +02:00
|
|
|
})?;
|
2020-03-30 16:19:37 +02:00
|
|
|
|
2021-03-28 10:36:56 +02:00
|
|
|
if contents.starts_with("#!") {
|
|
|
|
// Remove shebang
|
|
|
|
if let Some(n) = contents.find('\n') {
|
|
|
|
contents.drain(0..n).count();
|
|
|
|
} else {
|
|
|
|
contents.clear();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-03-30 16:19:37 +02:00
|
|
|
Ok(contents)
|
2020-03-10 10:10:33 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Compile a script file into an [`AST`], which can be used later for evaluation.
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Not available under `no_std` or `WASM`.
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Compile a script file to an AST and store it for later evaluation.
|
2020-03-19 06:52:10 +01:00
|
|
|
/// // Notice that a PathBuf is required which can easily be constructed from a string.
|
|
|
|
/// let ast = engine.compile_file("script.rhai".into())?;
|
|
|
|
///
|
|
|
|
/// for _ in 0..42 {
|
|
|
|
/// engine.eval_ast::<i64>(&ast)?;
|
|
|
|
/// }
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-18 05:04:26 +01:00
|
|
|
#[cfg(not(feature = "no_std"))]
|
2021-02-19 08:50:48 +01:00
|
|
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-11-16 16:10:14 +01:00
|
|
|
pub fn compile_file(
|
|
|
|
&self,
|
|
|
|
path: crate::stdlib::path::PathBuf,
|
|
|
|
) -> Result<AST, Box<EvalAltResult>> {
|
2020-10-20 04:54:32 +02:00
|
|
|
self.compile_file_with_scope(&Default::default(), path)
|
2020-03-14 07:30:44 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Compile a script file into an [`AST`] using own scope, which can be used later for evaluation.
|
2020-05-13 05:57:07 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Not available under `no_std` or `WASM`.
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// The scope is useful for passing constants into the script for optimization
|
2020-11-20 09:52:28 +01:00
|
|
|
/// when using [`OptimizationLevel::Full`].
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 12:53:42 +01:00
|
|
|
/// # #[cfg(not(feature = "no_optimize"))]
|
|
|
|
/// # {
|
|
|
|
/// use rhai::{Engine, Scope, OptimizationLevel};
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Set optimization level to 'Full' so the Engine can fold constants.
|
|
|
|
/// engine.set_optimization_level(OptimizationLevel::Full);
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// // Create initialized scope
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push_constant("x", 42_i64); // 'x' is a constant
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Compile a script to an AST and store it for later evaluation.
|
2020-03-19 06:52:10 +01:00
|
|
|
/// // Notice that a PathBuf is required which can easily be constructed from a string.
|
|
|
|
/// let ast = engine.compile_file_with_scope(&mut scope, "script.rhai".into())?;
|
|
|
|
///
|
|
|
|
/// let result = engine.eval_ast::<i64>(&ast)?;
|
2020-03-19 12:53:42 +01:00
|
|
|
/// # }
|
2020-03-19 06:52:10 +01:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-18 05:04:26 +01:00
|
|
|
#[cfg(not(feature = "no_std"))]
|
2021-02-19 08:50:48 +01:00
|
|
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-03-14 07:30:44 +01:00
|
|
|
pub fn compile_file_with_scope(
|
|
|
|
&self,
|
|
|
|
scope: &Scope,
|
2020-11-16 16:10:14 +01:00
|
|
|
path: crate::stdlib::path::PathBuf,
|
2020-04-21 17:25:12 +02:00
|
|
|
) -> Result<AST, Box<EvalAltResult>> {
|
2020-04-08 10:57:15 +02:00
|
|
|
Self::read_file(path).and_then(|contents| Ok(self.compile_with_scope(scope, &contents)?))
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Parse a JSON string into an [object map][`Map`].
|
2021-03-24 03:02:50 +01:00
|
|
|
/// This is a light-weight alternative to using, say, [`serde_json`] to deserialize the JSON.
|
2020-04-10 11:14:07 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// The JSON string must be an object hash. It cannot be a simple scalar value.
|
2020-08-18 17:07:17 +02:00
|
|
|
///
|
2020-04-10 11:14:07 +02:00
|
|
|
/// Set `has_null` to `true` in order to map `null` values to `()`.
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Setting it to `false` will cause an [`ErrorVariableNotFound`][EvalAltResult::ErrorVariableNotFound] error during parsing.
|
2020-04-10 11:14:07 +02:00
|
|
|
///
|
2020-08-18 17:07:17 +02:00
|
|
|
/// # JSON With Sub-Objects
|
|
|
|
///
|
|
|
|
/// This method assumes no sub-objects in the JSON string. That is because the syntax
|
|
|
|
/// of a JSON sub-object (or object hash), `{ .. }`, is different from Rhai's syntax, `#{ .. }`.
|
|
|
|
/// Parsing a JSON string with sub-objects will cause a syntax error.
|
|
|
|
///
|
|
|
|
/// If it is certain that the character `{` never appears in any text string within the JSON object,
|
2021-01-02 16:30:10 +01:00
|
|
|
/// which is a valid assumption for many use cases, then globally replace `{` with `#{` before calling this method.
|
2020-08-18 17:07:17 +02:00
|
|
|
///
|
2020-04-10 11:14:07 +02:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-08-18 17:07:17 +02:00
|
|
|
/// use rhai::{Engine, Map};
|
2020-04-10 11:14:07 +02:00
|
|
|
///
|
|
|
|
/// let engine = Engine::new();
|
|
|
|
///
|
2020-08-18 17:07:17 +02:00
|
|
|
/// let map = engine.parse_json(
|
|
|
|
/// r#"{"a":123, "b":42, "c":{"x":false, "y":true}, "d":null}"#
|
|
|
|
/// .replace("{", "#{").as_str(), true)?;
|
2020-04-10 11:14:07 +02:00
|
|
|
///
|
|
|
|
/// assert_eq!(map.len(), 4);
|
2020-08-18 17:07:17 +02:00
|
|
|
/// assert_eq!(map["a"].as_int().unwrap(), 123);
|
|
|
|
/// assert_eq!(map["b"].as_int().unwrap(), 42);
|
|
|
|
/// assert!(map["d"].is::<()>());
|
|
|
|
///
|
|
|
|
/// let c = map["c"].read_lock::<Map>().unwrap();
|
|
|
|
/// assert_eq!(c["x"].as_bool().unwrap(), false);
|
2020-04-10 11:14:07 +02:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2021-03-24 06:17:52 +01:00
|
|
|
pub fn parse_json(
|
|
|
|
&self,
|
|
|
|
json: impl AsRef<str>,
|
|
|
|
has_null: bool,
|
|
|
|
) -> Result<Map, Box<EvalAltResult>> {
|
2020-11-20 09:52:28 +01:00
|
|
|
use crate::token::Token;
|
2020-11-16 09:28:04 +01:00
|
|
|
|
2021-03-24 06:17:52 +01:00
|
|
|
let json = json.as_ref();
|
2020-10-20 04:54:32 +02:00
|
|
|
let mut scope = Default::default();
|
2020-04-10 11:14:07 +02:00
|
|
|
|
|
|
|
// Trims the JSON string and add a '#' in front
|
2020-08-18 17:07:17 +02:00
|
|
|
let json_text = json.trim_start();
|
2021-03-23 13:04:54 +01:00
|
|
|
let scripts = if json_text.starts_with(Token::MapStart.keyword_syntax()) {
|
2020-08-18 17:07:17 +02:00
|
|
|
[json_text, ""]
|
2021-03-23 13:04:54 +01:00
|
|
|
} else if json_text.starts_with(Token::LeftBrace.keyword_syntax()) {
|
2020-08-18 17:07:17 +02:00
|
|
|
["#", json_text]
|
|
|
|
} else {
|
2020-11-16 09:28:04 +01:00
|
|
|
return Err(crate::ParseErrorType::MissingToken(
|
2020-08-22 17:01:25 +02:00
|
|
|
Token::LeftBrace.syntax().into(),
|
|
|
|
"to start a JSON object hash".into(),
|
2020-08-18 17:07:17 +02:00
|
|
|
)
|
|
|
|
.into_err(Position::new(1, (json.len() - json_text.len() + 1) as u16))
|
|
|
|
.into());
|
|
|
|
};
|
|
|
|
|
2021-03-03 15:49:57 +01:00
|
|
|
let stream = self.lex_raw(
|
2020-07-26 16:25:30 +02:00
|
|
|
&scripts,
|
2021-03-03 15:49:57 +01:00
|
|
|
Some(if has_null {
|
2020-12-29 03:41:20 +01:00
|
|
|
|token| match token {
|
2020-07-26 16:25:30 +02:00
|
|
|
// If `null` is present, make sure `null` is treated as a variable
|
|
|
|
Token::Reserved(s) if s == "null" => Token::Identifier(s),
|
|
|
|
_ => token,
|
2020-12-29 03:41:20 +01:00
|
|
|
}
|
2020-07-26 16:25:30 +02:00
|
|
|
} else {
|
2020-12-29 03:41:20 +01:00
|
|
|
|t| t
|
2021-03-03 15:49:57 +01:00
|
|
|
}),
|
2020-07-26 16:25:30 +02:00
|
|
|
);
|
2020-12-29 03:41:20 +01:00
|
|
|
|
2021-01-04 04:58:24 +01:00
|
|
|
let ast =
|
|
|
|
self.parse_global_expr(&mut stream.peekable(), &scope, OptimizationLevel::None)?;
|
2020-04-10 11:14:07 +02:00
|
|
|
|
|
|
|
// Handle null - map to ()
|
|
|
|
if has_null {
|
|
|
|
scope.push_constant("null", ());
|
|
|
|
}
|
|
|
|
|
|
|
|
self.eval_ast_with_scope(&mut scope, &ast)
|
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Compile a string containing an expression into an [`AST`],
|
2020-03-22 14:03:58 +01:00
|
|
|
/// which can be used later for evaluation.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-22 14:03:58 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-22 14:03:58 +01:00
|
|
|
///
|
|
|
|
/// // Compile a script to an AST and store it for later evaluation
|
|
|
|
/// let ast = engine.compile_expression("40 + 2")?;
|
|
|
|
///
|
|
|
|
/// for _ in 0..42 {
|
|
|
|
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
|
|
|
|
/// }
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-22 12:28:13 +02:00
|
|
|
pub fn compile_expression(&self, script: &str) -> Result<AST, ParseError> {
|
2020-10-20 04:54:32 +02:00
|
|
|
self.compile_expression_with_scope(&Default::default(), script)
|
2020-03-22 14:03:58 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Compile a string containing an expression into an [`AST`] using own scope,
|
2020-03-22 14:03:58 +01:00
|
|
|
/// which can be used later for evaluation.
|
|
|
|
///
|
|
|
|
/// The scope is useful for passing constants into the script for optimization
|
2020-11-20 09:52:28 +01:00
|
|
|
/// when using [`OptimizationLevel::Full`].
|
2020-03-22 14:03:58 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-22 14:03:58 +01:00
|
|
|
/// # #[cfg(not(feature = "no_optimize"))]
|
|
|
|
/// # {
|
|
|
|
/// use rhai::{Engine, Scope, OptimizationLevel};
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Set optimization level to 'Full' so the Engine can fold constants
|
|
|
|
/// // into function calls and operators.
|
|
|
|
/// engine.set_optimization_level(OptimizationLevel::Full);
|
|
|
|
///
|
|
|
|
/// // Create initialized scope
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push_constant("x", 10_i64); // 'x' is a constant
|
|
|
|
///
|
|
|
|
/// // Compile a script to an AST and store it for later evaluation.
|
|
|
|
/// // Notice that `Full` optimization is on, so constants are folded
|
|
|
|
/// // into function calls and operators.
|
|
|
|
/// let ast = engine.compile_expression_with_scope(&mut scope,
|
|
|
|
/// "2 + (x + x) * 2" // all 'x' are replaced with 10
|
|
|
|
/// )?;
|
|
|
|
///
|
|
|
|
/// // Normally this would have failed because no scope is passed into the 'eval_ast'
|
|
|
|
/// // call and so the variable 'x' does not exist. Here, it passes because the script
|
|
|
|
/// // has been optimized and all references to 'x' are already gone.
|
|
|
|
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
|
|
|
|
/// # }
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-03-04 11:13:47 +01:00
|
|
|
#[inline(always)]
|
2020-03-22 14:03:58 +01:00
|
|
|
pub fn compile_expression_with_scope(
|
|
|
|
&self,
|
|
|
|
scope: &Scope,
|
2020-04-08 10:57:15 +02:00
|
|
|
script: &str,
|
2020-05-22 12:28:13 +02:00
|
|
|
) -> Result<AST, ParseError> {
|
2020-04-10 11:14:07 +02:00
|
|
|
let scripts = [script];
|
2021-03-03 15:49:57 +01:00
|
|
|
let stream = self.lex_raw(&scripts, None);
|
2020-11-10 16:26:50 +01:00
|
|
|
|
|
|
|
let mut peekable = stream.peekable();
|
2021-01-04 04:58:24 +01:00
|
|
|
self.parse_global_expr(&mut peekable, scope, self.optimization_level)
|
2020-03-22 14:03:58 +01:00
|
|
|
}
|
2020-03-19 06:52:10 +01:00
|
|
|
/// Evaluate a script file.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Not available under `no_std` or `WASM`.
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// // Notice that a PathBuf is required which can easily be constructed from a string.
|
|
|
|
/// let result = engine.eval_file::<i64>("script.rhai".into())?;
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-18 05:04:26 +01:00
|
|
|
#[cfg(not(feature = "no_std"))]
|
2021-02-19 08:50:48 +01:00
|
|
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-11-16 16:10:14 +01:00
|
|
|
pub fn eval_file<T: Variant + Clone>(
|
|
|
|
&self,
|
|
|
|
path: crate::stdlib::path::PathBuf,
|
|
|
|
) -> Result<T, Box<EvalAltResult>> {
|
2020-03-13 11:27:53 +01:00
|
|
|
Self::read_file(path).and_then(|contents| self.eval::<T>(&contents))
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-03-19 06:52:10 +01:00
|
|
|
/// Evaluate a script file with own scope.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Not available under `no_std` or `WASM`.
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// use rhai::{Engine, Scope};
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// // Create initialized scope
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push("x", 42_i64);
|
|
|
|
///
|
|
|
|
/// // Notice that a PathBuf is required which can easily be constructed from a string.
|
|
|
|
/// let result = engine.eval_file_with_scope::<i64>(&mut scope, "script.rhai".into())?;
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-18 05:04:26 +01:00
|
|
|
#[cfg(not(feature = "no_std"))]
|
2021-02-19 08:50:48 +01:00
|
|
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-04-12 17:00:06 +02:00
|
|
|
pub fn eval_file_with_scope<T: Variant + Clone>(
|
2020-04-07 07:23:06 +02:00
|
|
|
&self,
|
2020-03-15 15:39:58 +01:00
|
|
|
scope: &mut Scope,
|
2020-11-16 16:10:14 +01:00
|
|
|
path: crate::stdlib::path::PathBuf,
|
2020-04-21 17:25:12 +02:00
|
|
|
) -> Result<T, Box<EvalAltResult>> {
|
2020-03-15 15:39:58 +01:00
|
|
|
Self::read_file(path).and_then(|contents| self.eval_with_scope::<T>(scope, &contents))
|
|
|
|
}
|
2020-03-10 02:30:12 +01:00
|
|
|
/// Evaluate a string.
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("40 + 2")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-04-21 17:25:12 +02:00
|
|
|
pub fn eval<T: Variant + Clone>(&self, script: &str) -> Result<T, Box<EvalAltResult>> {
|
2020-10-20 04:54:32 +02:00
|
|
|
self.eval_with_scope(&mut Default::default(), script)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-03-10 02:30:12 +01:00
|
|
|
/// Evaluate a string with own scope.
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// use rhai::{Engine, Scope};
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// // Create initialized scope
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push("x", 40_i64);
|
|
|
|
///
|
2020-07-06 10:20:03 +02:00
|
|
|
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x += 2; x")?, 42);
|
|
|
|
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x += 2; x")?, 44);
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// // The variable in the scope is modified
|
|
|
|
/// assert_eq!(scope.get_value::<i64>("x").expect("variable x should exist"), 44);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-03-04 11:13:47 +01:00
|
|
|
#[inline(always)]
|
2020-04-12 17:00:06 +02:00
|
|
|
pub fn eval_with_scope<T: Variant + Clone>(
|
2020-04-07 07:23:06 +02:00
|
|
|
&self,
|
2020-03-02 07:28:42 +01:00
|
|
|
scope: &mut Scope,
|
2020-04-08 10:57:15 +02:00
|
|
|
script: &str,
|
2020-04-21 17:25:12 +02:00
|
|
|
) -> Result<T, Box<EvalAltResult>> {
|
2020-05-13 05:57:07 +02:00
|
|
|
let ast = self.compile_with_scope_and_optimization_level(
|
|
|
|
scope,
|
|
|
|
&[script],
|
2020-05-17 16:19:49 +02:00
|
|
|
self.optimization_level,
|
2020-05-13 05:57:07 +02:00
|
|
|
)?;
|
2020-03-12 07:54:14 +01:00
|
|
|
self.eval_ast_with_scope(scope, &ast)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-03-22 14:03:58 +01:00
|
|
|
/// Evaluate a string containing an expression.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-22 14:03:58 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-22 14:03:58 +01:00
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval_expression::<i64>("40 + 2")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-04-21 17:25:12 +02:00
|
|
|
pub fn eval_expression<T: Variant + Clone>(
|
|
|
|
&self,
|
|
|
|
script: &str,
|
|
|
|
) -> Result<T, Box<EvalAltResult>> {
|
2020-10-20 04:54:32 +02:00
|
|
|
self.eval_expression_with_scope(&mut Default::default(), script)
|
2020-03-22 14:03:58 +01:00
|
|
|
}
|
|
|
|
/// Evaluate a string containing an expression with own scope.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-22 14:03:58 +01:00
|
|
|
/// use rhai::{Engine, Scope};
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-22 14:03:58 +01:00
|
|
|
///
|
|
|
|
/// // Create initialized scope
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push("x", 40_i64);
|
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval_expression_with_scope::<i64>(&mut scope, "x + 2")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-03-04 11:13:47 +01:00
|
|
|
#[inline(always)]
|
2020-04-12 17:00:06 +02:00
|
|
|
pub fn eval_expression_with_scope<T: Variant + Clone>(
|
2020-04-07 07:23:06 +02:00
|
|
|
&self,
|
2020-03-22 14:03:58 +01:00
|
|
|
scope: &mut Scope,
|
2020-04-08 10:57:15 +02:00
|
|
|
script: &str,
|
2020-04-21 17:25:12 +02:00
|
|
|
) -> Result<T, Box<EvalAltResult>> {
|
2020-04-10 15:02:38 +02:00
|
|
|
let scripts = [script];
|
2021-03-03 15:49:57 +01:00
|
|
|
let stream = self.lex_raw(&scripts, None);
|
2020-05-18 13:32:22 +02:00
|
|
|
|
2020-06-15 15:49:02 +02:00
|
|
|
// No need to optimize a lone expression
|
2021-01-04 04:58:24 +01:00
|
|
|
let ast = self.parse_global_expr(&mut stream.peekable(), scope, OptimizationLevel::None)?;
|
2020-05-19 18:06:19 +02:00
|
|
|
|
2020-03-22 14:03:58 +01:00
|
|
|
self.eval_ast_with_scope(scope, &ast)
|
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Evaluate an [`AST`].
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Compile a script to an AST and store it for later evaluation
|
2020-03-19 06:52:10 +01:00
|
|
|
/// let ast = engine.compile("40 + 2")?;
|
|
|
|
///
|
|
|
|
/// // Evaluate it
|
|
|
|
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-04-21 17:25:12 +02:00
|
|
|
pub fn eval_ast<T: Variant + Clone>(&self, ast: &AST) -> Result<T, Box<EvalAltResult>> {
|
2020-10-20 04:54:32 +02:00
|
|
|
self.eval_ast_with_scope(&mut Default::default(), ast)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Evaluate an [`AST`] with own scope.
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-19 06:52:10 +01:00
|
|
|
/// use rhai::{Engine, Scope};
|
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Compile a script to an AST and store it for later evaluation
|
2020-03-19 06:52:10 +01:00
|
|
|
/// let ast = engine.compile("x + 2")?;
|
|
|
|
///
|
|
|
|
/// // Create initialized scope
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push("x", 40_i64);
|
|
|
|
///
|
2020-03-19 12:53:42 +01:00
|
|
|
/// // Compile a script to an AST and store it for later evaluation
|
2020-07-06 10:20:03 +02:00
|
|
|
/// let ast = engine.compile("x += 2; x")?;
|
2020-03-19 12:53:42 +01:00
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// // Evaluate it
|
2020-03-19 12:53:42 +01:00
|
|
|
/// assert_eq!(engine.eval_ast_with_scope::<i64>(&mut scope, &ast)?, 42);
|
|
|
|
/// assert_eq!(engine.eval_ast_with_scope::<i64>(&mut scope, &ast)?, 44);
|
2020-03-19 06:52:10 +01:00
|
|
|
///
|
|
|
|
/// // The variable in the scope is modified
|
|
|
|
/// assert_eq!(scope.get_value::<i64>("x").expect("variable x should exist"), 44);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-03-04 11:13:47 +01:00
|
|
|
#[inline(always)]
|
2020-04-12 17:00:06 +02:00
|
|
|
pub fn eval_ast_with_scope<T: Variant + Clone>(
|
2020-04-07 07:23:06 +02:00
|
|
|
&self,
|
2020-03-02 07:28:42 +01:00
|
|
|
scope: &mut Scope,
|
|
|
|
ast: &AST,
|
2020-04-21 17:25:12 +02:00
|
|
|
) -> Result<T, Box<EvalAltResult>> {
|
2021-03-01 07:54:20 +01:00
|
|
|
let mods = &mut Default::default();
|
2020-11-15 16:14:16 +01:00
|
|
|
|
2020-12-29 05:29:45 +01:00
|
|
|
let result = self.eval_ast_with_scope_raw(scope, mods, ast, 0)?;
|
2020-04-17 18:14:33 +02:00
|
|
|
|
2020-07-03 04:45:01 +02:00
|
|
|
let typ = self.map_type_name(result.type_name());
|
2020-04-13 04:27:08 +02:00
|
|
|
|
|
|
|
return result.try_cast::<T>().ok_or_else(|| {
|
2020-08-06 04:17:32 +02:00
|
|
|
EvalAltResult::ErrorMismatchOutputType(
|
2020-07-03 04:45:01 +02:00
|
|
|
self.map_type_name(type_name::<T>()).into(),
|
|
|
|
typ.into(),
|
2020-11-20 09:52:28 +01:00
|
|
|
Position::NONE,
|
2020-08-06 04:17:32 +02:00
|
|
|
)
|
|
|
|
.into()
|
2020-04-13 04:27:08 +02:00
|
|
|
});
|
2020-03-19 12:53:42 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Evaluate an [`AST`] with own scope.
|
2020-10-20 04:54:32 +02:00
|
|
|
#[inline(always)]
|
2020-06-27 17:56:24 +02:00
|
|
|
pub(crate) fn eval_ast_with_scope_raw<'a>(
|
2020-04-07 07:23:06 +02:00
|
|
|
&self,
|
2020-03-19 12:53:42 +01:00
|
|
|
scope: &mut Scope,
|
2020-06-27 17:56:24 +02:00
|
|
|
mods: &mut Imports,
|
|
|
|
ast: &'a AST,
|
2020-12-29 05:29:45 +01:00
|
|
|
level: usize,
|
2021-03-02 08:02:28 +01:00
|
|
|
) -> RhaiResult {
|
2021-02-07 10:56:29 +01:00
|
|
|
let mut state: State = Default::default();
|
|
|
|
state.source = ast.clone_source();
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
{
|
|
|
|
state.resolver = ast.resolver();
|
|
|
|
}
|
|
|
|
|
2021-02-07 10:06:33 +01:00
|
|
|
let statements = ast.statements();
|
|
|
|
let lib = &[ast.lib()];
|
2021-02-07 10:56:29 +01:00
|
|
|
self.eval_global_statements(scope, mods, &mut state, statements, lib, level)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-03-04 15:00:01 +01:00
|
|
|
/// Evaluate a file, but throw away the result and only return error (if any).
|
2020-03-10 02:30:12 +01:00
|
|
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
2021-01-02 16:30:10 +01:00
|
|
|
///
|
|
|
|
/// Not available under `no_std` or `WASM`.
|
2020-03-18 05:04:26 +01:00
|
|
|
#[cfg(not(feature = "no_std"))]
|
2021-02-19 08:50:48 +01:00
|
|
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-11-16 16:10:14 +01:00
|
|
|
pub fn consume_file(
|
|
|
|
&self,
|
|
|
|
path: crate::stdlib::path::PathBuf,
|
|
|
|
) -> Result<(), Box<EvalAltResult>> {
|
2020-04-04 16:00:44 +02:00
|
|
|
Self::read_file(path).and_then(|contents| self.consume(&contents))
|
2020-03-15 15:39:58 +01:00
|
|
|
}
|
|
|
|
/// Evaluate a file 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.
|
2021-01-02 16:30:10 +01:00
|
|
|
///
|
|
|
|
/// Not available under `no_std` or `WASM`.
|
2020-03-18 05:04:26 +01:00
|
|
|
#[cfg(not(feature = "no_std"))]
|
2021-02-19 08:50:48 +01:00
|
|
|
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-03-15 15:39:58 +01:00
|
|
|
pub fn consume_file_with_scope(
|
2020-04-07 07:23:06 +02:00
|
|
|
&self,
|
2020-03-15 15:39:58 +01:00
|
|
|
scope: &mut Scope,
|
2020-11-16 16:10:14 +01:00
|
|
|
path: crate::stdlib::path::PathBuf,
|
2020-04-21 17:25:12 +02:00
|
|
|
) -> Result<(), Box<EvalAltResult>> {
|
2020-04-04 16:00:44 +02:00
|
|
|
Self::read_file(path).and_then(|contents| self.consume_with_scope(scope, &contents))
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-03-04 15:00:01 +01:00
|
|
|
/// Evaluate a string, but throw away the result and only return error (if any).
|
2020-03-10 02:30:12 +01:00
|
|
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-04-21 17:25:12 +02:00
|
|
|
pub fn consume(&self, script: &str) -> Result<(), Box<EvalAltResult>> {
|
2020-10-20 04:54:32 +02:00
|
|
|
self.consume_with_scope(&mut Default::default(), script)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-03-15 15:39:58 +01:00
|
|
|
/// Evaluate a string with own scope, but throw away the result and only return error (if any).
|
2020-03-10 02:30:12 +01:00
|
|
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
2021-03-04 11:13:47 +01:00
|
|
|
#[inline(always)]
|
2020-04-21 17:25:12 +02:00
|
|
|
pub fn consume_with_scope(
|
|
|
|
&self,
|
|
|
|
scope: &mut Scope,
|
|
|
|
script: &str,
|
|
|
|
) -> Result<(), Box<EvalAltResult>> {
|
2020-04-10 11:14:07 +02:00
|
|
|
let scripts = [script];
|
2021-03-03 15:49:57 +01:00
|
|
|
let stream = self.lex_raw(&scripts, None);
|
2021-01-04 04:58:24 +01:00
|
|
|
let ast = self.parse(&mut stream.peekable(), scope, self.optimization_level)?;
|
2020-04-04 16:00:44 +02:00
|
|
|
self.consume_ast_with_scope(scope, &ast)
|
2020-03-12 08:30:42 +01:00
|
|
|
}
|
|
|
|
/// Evaluate an AST, 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.
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-04-21 17:25:12 +02:00
|
|
|
pub fn consume_ast(&self, ast: &AST) -> Result<(), Box<EvalAltResult>> {
|
2020-10-20 04:54:32 +02:00
|
|
|
self.consume_ast_with_scope(&mut Default::default(), ast)
|
2020-03-15 15:39:58 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Evaluate an [`AST`] with own scope, but throw away the result and only return error (if any).
|
2020-03-15 15:39:58 +01:00
|
|
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
2020-10-20 04:54:32 +02:00
|
|
|
#[inline(always)]
|
2020-03-12 08:30:42 +01:00
|
|
|
pub fn consume_ast_with_scope(
|
2020-04-07 07:23:06 +02:00
|
|
|
&self,
|
2020-03-12 08:30:42 +01:00
|
|
|
scope: &mut Scope,
|
|
|
|
ast: &AST,
|
2020-04-21 17:25:12 +02:00
|
|
|
) -> Result<(), Box<EvalAltResult>> {
|
2021-03-01 07:54:20 +01:00
|
|
|
let mods = &mut Default::default();
|
2021-02-07 10:56:29 +01:00
|
|
|
let mut state: State = Default::default();
|
|
|
|
state.source = ast.clone_source();
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
{
|
|
|
|
state.resolver = ast.resolver();
|
|
|
|
}
|
2021-02-07 10:06:33 +01:00
|
|
|
let statements = ast.statements();
|
|
|
|
let lib = &[ast.lib()];
|
2021-02-07 10:56:29 +01:00
|
|
|
self.eval_global_statements(scope, mods, &mut state, statements, lib, 0)?;
|
2020-12-20 16:25:11 +01:00
|
|
|
Ok(())
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Call a script function defined in an [`AST`] with multiple arguments.
|
2020-05-31 06:37:19 +02:00
|
|
|
/// Arguments are passed as a tuple.
|
2020-03-04 15:00:01 +01:00
|
|
|
///
|
2021-02-26 04:21:23 +01:00
|
|
|
/// ## Warning
|
|
|
|
///
|
|
|
|
/// The [`AST`] is _not_ evaluated before calling the function. The function is called as-is.
|
|
|
|
///
|
|
|
|
/// If the [`AST`] needs to be evaluated before calling the function (usually to load external modules),
|
|
|
|
/// use [`call_fn_dynamic`][Engine::call_fn_dynamic].
|
|
|
|
///
|
2020-03-04 15:00:01 +01:00
|
|
|
/// # Example
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-03-11 06:28:12 +01:00
|
|
|
/// # #[cfg(not(feature = "no_function"))]
|
2020-03-10 12:48:47 +01:00
|
|
|
/// # {
|
2020-04-05 06:17:31 +02:00
|
|
|
/// use rhai::{Engine, Scope};
|
2020-03-09 14:57:07 +01:00
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// let engine = Engine::new();
|
2020-03-04 15:00:01 +01:00
|
|
|
///
|
2020-04-07 15:50:33 +02:00
|
|
|
/// let ast = engine.compile(r"
|
|
|
|
/// fn add(x, y) { len(x) + y + foo }
|
|
|
|
/// fn add1(x) { len(x) + 1 + foo }
|
|
|
|
/// fn bar() { foo/2 }
|
|
|
|
/// ")?;
|
2020-04-05 06:17:31 +02:00
|
|
|
///
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push("foo", 42_i64);
|
2020-03-04 15:00:01 +01:00
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// // Call the script-defined function
|
2021-02-26 04:21:23 +01:00
|
|
|
/// let result: i64 = engine.call_fn(&mut scope, &ast, "add", ( "abc", 123_i64 ) )?;
|
2020-04-05 06:17:31 +02:00
|
|
|
/// assert_eq!(result, 168);
|
2020-04-07 15:50:33 +02:00
|
|
|
///
|
2021-02-26 04:21:23 +01:00
|
|
|
/// let result: i64 = engine.call_fn(&mut scope, &ast, "add1", ( "abc", ) )?;
|
|
|
|
/// // ^^^^^^^^^^ tuple of one
|
2020-04-07 15:50:33 +02:00
|
|
|
/// assert_eq!(result, 46);
|
|
|
|
///
|
|
|
|
/// let result: i64 = engine.call_fn(&mut scope, &ast, "bar", () )?;
|
|
|
|
/// assert_eq!(result, 21);
|
2020-03-10 12:48:47 +01:00
|
|
|
/// # }
|
2020-03-04 15:00:01 +01:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-03-11 06:28:12 +01:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2021-03-04 11:13:47 +01:00
|
|
|
#[inline(always)]
|
2020-12-26 06:05:57 +01:00
|
|
|
pub fn call_fn<T: Variant + Clone>(
|
2020-04-07 07:23:06 +02:00
|
|
|
&self,
|
2020-04-05 06:17:31 +02:00
|
|
|
scope: &mut Scope,
|
2020-04-04 16:00:44 +02:00
|
|
|
ast: &AST,
|
2021-03-24 06:17:52 +01:00
|
|
|
name: impl AsRef<str>,
|
2020-12-26 06:05:57 +01:00
|
|
|
args: impl crate::fn_args::FuncArgs,
|
2020-04-21 17:25:12 +02:00
|
|
|
) -> Result<T, Box<EvalAltResult>> {
|
2021-01-28 08:29:55 +01:00
|
|
|
let mut arg_values: crate::StaticVec<_> = Default::default();
|
|
|
|
args.parse(&mut arg_values);
|
2020-11-16 09:28:04 +01:00
|
|
|
let mut args: crate::StaticVec<_> = arg_values.as_mut().iter_mut().collect();
|
2020-09-24 16:50:28 +02:00
|
|
|
|
2021-02-26 04:21:23 +01:00
|
|
|
let result = self.call_fn_dynamic_raw(scope, ast, false, name, &mut None, args.as_mut())?;
|
2020-05-31 06:37:19 +02:00
|
|
|
|
2020-07-03 04:45:01 +02:00
|
|
|
let typ = self.map_type_name(result.type_name());
|
2020-05-31 06:37:19 +02:00
|
|
|
|
|
|
|
return result.try_cast().ok_or_else(|| {
|
2020-08-06 04:17:32 +02:00
|
|
|
EvalAltResult::ErrorMismatchOutputType(
|
2020-07-03 04:45:01 +02:00
|
|
|
self.map_type_name(type_name::<T>()).into(),
|
|
|
|
typ.into(),
|
2020-11-20 09:52:28 +01:00
|
|
|
Position::NONE,
|
2020-08-06 04:17:32 +02:00
|
|
|
)
|
|
|
|
.into()
|
2020-05-31 06:37:19 +02:00
|
|
|
});
|
|
|
|
}
|
2020-11-22 10:21:34 +01:00
|
|
|
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments
|
2020-11-20 09:52:28 +01:00
|
|
|
/// and optionally a value for binding to the `this` pointer.
|
2020-07-05 17:08:44 +02:00
|
|
|
///
|
2021-02-26 04:21:23 +01:00
|
|
|
/// There is also an option to evaluate the [`AST`] (e.g. to configuration the environment)
|
|
|
|
/// before calling the function.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # WARNING
|
2020-07-05 17:08:44 +02:00
|
|
|
///
|
|
|
|
/// 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.
|
2020-05-31 06:37:19 +02:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// # #[cfg(not(feature = "no_function"))]
|
|
|
|
/// # {
|
2020-07-05 17:08:44 +02:00
|
|
|
/// use rhai::{Engine, Scope, Dynamic};
|
2020-05-31 06:37:19 +02:00
|
|
|
///
|
|
|
|
/// let engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// let ast = engine.compile(r"
|
|
|
|
/// fn add(x, y) { len(x) + y + foo }
|
|
|
|
/// fn add1(x) { len(x) + 1 + foo }
|
|
|
|
/// fn bar() { foo/2 }
|
2020-07-05 17:08:44 +02:00
|
|
|
/// fn action(x) { this += x; } // function using 'this' pointer
|
2020-05-31 06:37:19 +02:00
|
|
|
/// ")?;
|
|
|
|
///
|
|
|
|
/// let mut scope = Scope::new();
|
|
|
|
/// scope.push("foo", 42_i64);
|
|
|
|
///
|
|
|
|
/// // Call the script-defined function
|
2021-02-26 04:21:23 +01:00
|
|
|
/// let result = engine.call_fn_dynamic(&mut scope, &ast, false, "add", None, [ "abc".into(), 123_i64.into() ])?;
|
|
|
|
/// // ^^^^ no 'this' pointer
|
2020-05-31 06:37:19 +02:00
|
|
|
/// assert_eq!(result.cast::<i64>(), 168);
|
|
|
|
///
|
2021-02-26 04:21:23 +01:00
|
|
|
/// let result = engine.call_fn_dynamic(&mut scope, &ast, false, "add1", None, [ "abc".into() ])?;
|
2020-05-31 06:37:19 +02:00
|
|
|
/// assert_eq!(result.cast::<i64>(), 46);
|
|
|
|
///
|
2021-02-26 04:21:23 +01:00
|
|
|
/// let result = engine.call_fn_dynamic(&mut scope, &ast, false, "bar", None, [])?;
|
2020-05-31 06:37:19 +02:00
|
|
|
/// assert_eq!(result.cast::<i64>(), 21);
|
2020-07-05 17:08:44 +02:00
|
|
|
///
|
|
|
|
/// let mut value: Dynamic = 1_i64.into();
|
2021-02-26 04:21:23 +01:00
|
|
|
/// let result = engine.call_fn_dynamic(&mut scope, &ast, false, "action", Some(&mut value), [ 41_i64.into() ])?;
|
|
|
|
/// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer
|
2020-07-05 17:08:44 +02:00
|
|
|
/// assert_eq!(value.as_int().unwrap(), 42);
|
2020-05-31 06:37:19 +02:00
|
|
|
/// # }
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-31 06:37:19 +02:00
|
|
|
pub fn call_fn_dynamic(
|
2020-06-12 13:54:55 +02:00
|
|
|
&self,
|
|
|
|
scope: &mut Scope,
|
2021-02-26 04:21:23 +01:00
|
|
|
ast: &AST,
|
|
|
|
eval_ast: bool,
|
2021-03-24 06:17:52 +01:00
|
|
|
name: impl AsRef<str>,
|
2020-07-05 17:08:44 +02:00
|
|
|
mut this_ptr: Option<&mut Dynamic>,
|
|
|
|
mut arg_values: impl AsMut<[Dynamic]>,
|
2021-03-02 08:02:28 +01:00
|
|
|
) -> RhaiResult {
|
2020-11-16 09:28:04 +01:00
|
|
|
let mut args: crate::StaticVec<_> = arg_values.as_mut().iter_mut().collect();
|
2020-09-24 16:50:28 +02:00
|
|
|
|
2021-02-26 04:21:23 +01:00
|
|
|
self.call_fn_dynamic_raw(scope, ast, eval_ast, name, &mut this_ptr, args.as_mut())
|
2020-06-12 13:54:55 +02:00
|
|
|
}
|
2020-11-22 10:21:34 +01:00
|
|
|
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
|
2020-06-12 13:54:55 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # WARNING
|
2020-06-12 13:54:55 +02:00
|
|
|
///
|
|
|
|
/// 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.
|
2020-07-04 10:21:15 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2021-03-04 11:13:47 +01:00
|
|
|
#[inline(always)]
|
2020-06-12 13:54:55 +02:00
|
|
|
pub(crate) fn call_fn_dynamic_raw(
|
2020-05-31 06:37:19 +02:00
|
|
|
&self,
|
|
|
|
scope: &mut Scope,
|
2021-02-26 04:21:23 +01:00
|
|
|
ast: &AST,
|
|
|
|
eval_ast: bool,
|
2021-03-24 06:17:52 +01:00
|
|
|
name: impl AsRef<str>,
|
2020-07-05 17:08:44 +02:00
|
|
|
this_ptr: &mut Option<&mut Dynamic>,
|
2020-10-19 13:11:55 +02:00
|
|
|
args: &mut FnCallArgs,
|
2021-03-02 08:02:28 +01:00
|
|
|
) -> RhaiResult {
|
2021-02-26 04:21:23 +01:00
|
|
|
let state = &mut Default::default();
|
2021-03-01 07:54:20 +01:00
|
|
|
let mods = &mut Default::default();
|
2021-02-26 04:21:23 +01:00
|
|
|
let lib = &[ast.lib()];
|
|
|
|
|
|
|
|
if eval_ast {
|
|
|
|
self.eval_global_statements(scope, mods, state, ast.statements(), lib, 0)?;
|
|
|
|
}
|
2020-04-24 06:39:24 +02:00
|
|
|
|
2021-02-26 04:21:23 +01:00
|
|
|
let fn_def = ast
|
|
|
|
.lib()
|
2021-03-24 06:17:52 +01:00
|
|
|
.get_script_fn(name.as_ref(), args.len())
|
|
|
|
.ok_or_else(|| {
|
|
|
|
EvalAltResult::ErrorFunctionNotFound(name.as_ref().into(), Position::NONE)
|
|
|
|
})?;
|
2020-05-07 04:00:10 +02:00
|
|
|
|
2020-08-02 07:33:51 +02:00
|
|
|
// Check for data race.
|
2021-03-22 04:18:09 +01:00
|
|
|
#[cfg(not(feature = "no_closure"))]
|
2021-03-24 06:17:52 +01:00
|
|
|
crate::fn_call::ensure_no_data_race(name.as_ref(), args, false)?;
|
2020-08-02 07:33:51 +02:00
|
|
|
|
2020-12-12 04:15:09 +01:00
|
|
|
self.call_script_fn(
|
|
|
|
scope,
|
2021-02-26 04:21:23 +01:00
|
|
|
mods,
|
|
|
|
state,
|
2020-12-12 04:15:09 +01:00
|
|
|
lib,
|
|
|
|
this_ptr,
|
|
|
|
fn_def,
|
|
|
|
args,
|
|
|
|
Position::NONE,
|
|
|
|
0,
|
|
|
|
)
|
2020-03-04 15:00:01 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Optimize the [`AST`] with constants defined in an external Scope.
|
|
|
|
/// An optimized copy of the [`AST`] is returned while the original [`AST`] is consumed.
|
2020-03-15 15:39:58 +01:00
|
|
|
///
|
|
|
|
/// Although optimization is performed by default during compilation, sometimes it is necessary to
|
2020-11-20 09:52:28 +01:00
|
|
|
/// _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
|
2020-03-15 15:39:58 +01:00
|
|
|
/// of the new constants.
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// 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
|
2020-12-26 16:21:16 +01:00
|
|
|
/// (i.e. with [`Scope::push_constant`]).
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Then, the [`AST`] is cloned and the copy re-optimized before running.
|
2020-03-15 15:39:58 +01:00
|
|
|
#[cfg(not(feature = "no_optimize"))]
|
2021-03-04 11:13:47 +01:00
|
|
|
#[inline(always)]
|
2020-04-08 03:30:50 +02:00
|
|
|
pub fn optimize_ast(
|
|
|
|
&self,
|
|
|
|
scope: &Scope,
|
2020-05-05 09:00:10 +02:00
|
|
|
mut ast: AST,
|
2020-04-08 03:30:50 +02:00
|
|
|
optimization_level: OptimizationLevel,
|
|
|
|
) -> AST {
|
2020-11-08 03:56:33 +01:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
|
|
|
let lib = ast
|
|
|
|
.lib()
|
|
|
|
.iter_fn()
|
|
|
|
.filter(|f| f.func.is_script())
|
2020-11-25 02:36:06 +01:00
|
|
|
.map(|f| f.func.get_fn_def().clone())
|
2020-11-08 03:56:33 +01:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
#[cfg(feature = "no_function")]
|
|
|
|
let lib = Default::default();
|
2020-07-04 10:21:15 +02:00
|
|
|
|
2020-11-16 09:28:04 +01:00
|
|
|
let stmt = crate::stdlib::mem::take(ast.statements_mut());
|
2021-03-10 06:32:09 +01:00
|
|
|
crate::optimize::optimize_into_ast(self, scope, stmt.into_vec(), lib, optimization_level)
|
2020-03-15 15:39:58 +01:00
|
|
|
}
|
2020-11-22 10:21:34 +01:00
|
|
|
/// Generate a list of all registered functions.
|
2021-04-02 06:34:39 +02:00
|
|
|
/// Exported under the `metadata` feature only.
|
2020-11-22 10:21:34 +01:00
|
|
|
///
|
2020-11-23 13:27:20 +01:00
|
|
|
/// Functions from the following sources are included, in order:
|
2020-11-22 10:21:34 +01:00
|
|
|
/// 1) Functions registered into the global namespace
|
|
|
|
/// 2) Functions in registered sub-modules
|
2020-11-23 13:27:20 +01:00
|
|
|
/// 3) Functions in packages (optional)
|
2021-03-24 12:27:38 +01:00
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
pub fn gen_fn_signatures(&self, include_packages: bool) -> crate::stdlib::vec::Vec<String> {
|
|
|
|
let mut signatures: crate::stdlib::vec::Vec<_> = Default::default();
|
2020-11-22 10:21:34 +01:00
|
|
|
|
|
|
|
signatures.extend(self.global_namespace.gen_fn_signatures());
|
|
|
|
|
|
|
|
self.global_sub_modules.iter().for_each(|(name, m)| {
|
2021-03-29 07:40:33 +02:00
|
|
|
signatures.extend(
|
|
|
|
m.gen_fn_signatures()
|
|
|
|
.map(|f| crate::stdlib::format!("{}::{}", name, f)),
|
|
|
|
)
|
2020-11-22 10:21:34 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
if include_packages {
|
2020-12-22 16:45:14 +01:00
|
|
|
signatures.extend(
|
|
|
|
self.global_modules
|
|
|
|
.iter()
|
|
|
|
.flat_map(|m| m.gen_fn_signatures()),
|
|
|
|
);
|
2020-11-22 10:21:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
signatures
|
|
|
|
}
|
2020-10-11 15:58:11 +02:00
|
|
|
/// Provide a callback that will be invoked before each variable access.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # Return Value of Callback
|
2020-10-11 15:58:11 +02:00
|
|
|
///
|
|
|
|
/// Return `Ok(None)` to continue with normal variable access.
|
|
|
|
/// Return `Ok(Some(Dynamic))` as the variable's value.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # Errors in Callback
|
2020-10-11 15:58:11 +02:00
|
|
|
///
|
|
|
|
/// Return `Err(...)` if there is an error.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register a variable resolver.
|
2020-10-19 13:11:55 +02:00
|
|
|
/// engine.on_var(|name, _, _| {
|
2020-10-11 15:58:11 +02:00
|
|
|
/// match name {
|
|
|
|
/// "MYSTIC_NUMBER" => Ok(Some(42_i64.into())),
|
|
|
|
/// _ => Ok(None)
|
|
|
|
/// }
|
|
|
|
/// });
|
|
|
|
///
|
|
|
|
/// engine.eval::<i64>("MYSTIC_NUMBER")?;
|
|
|
|
///
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn on_var(
|
|
|
|
&mut self,
|
2020-10-19 13:11:55 +02:00
|
|
|
callback: impl Fn(&str, usize, &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
2020-10-11 15:58:11 +02:00
|
|
|
+ SendSync
|
|
|
|
+ 'static,
|
|
|
|
) -> &mut Self {
|
|
|
|
self.resolve_var = Some(Box::new(callback));
|
|
|
|
self
|
|
|
|
}
|
2020-05-15 05:43:32 +02:00
|
|
|
/// Register a callback for script evaluation progress.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// # use std::sync::RwLock;
|
|
|
|
/// # use std::sync::Arc;
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let result = Arc::new(RwLock::new(0_u64));
|
|
|
|
/// let logger = result.clone();
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2020-12-12 03:10:27 +01:00
|
|
|
/// engine.on_progress(move |ops| {
|
2020-05-15 05:43:32 +02:00
|
|
|
/// if ops > 10000 {
|
2020-11-02 04:04:45 +01:00
|
|
|
/// Some("Over 10,000 operations!".into())
|
2020-05-15 05:43:32 +02:00
|
|
|
/// } else if ops % 800 == 0 {
|
|
|
|
/// *logger.write().unwrap() = ops;
|
2020-11-02 04:04:45 +01:00
|
|
|
/// None
|
2020-05-15 05:43:32 +02:00
|
|
|
/// } else {
|
2020-11-02 04:04:45 +01:00
|
|
|
/// None
|
2020-05-15 05:43:32 +02:00
|
|
|
/// }
|
|
|
|
/// });
|
|
|
|
///
|
|
|
|
/// engine.consume("for x in range(0, 50000) {}")
|
|
|
|
/// .expect_err("should error");
|
|
|
|
///
|
|
|
|
/// assert_eq!(*result.read().unwrap(), 9600);
|
|
|
|
///
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-07-12 05:46:53 +02:00
|
|
|
pub fn on_progress(
|
|
|
|
&mut self,
|
2020-12-12 03:10:27 +01:00
|
|
|
callback: impl Fn(u64) -> Option<Dynamic> + SendSync + 'static,
|
2020-07-12 05:46:53 +02:00
|
|
|
) -> &mut Self {
|
2020-05-15 05:43:32 +02:00
|
|
|
self.progress = Some(Box::new(callback));
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-05-15 05:43:32 +02:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Override default action of `print` (print to stdout using [`println!`])
|
2020-03-04 15:00:01 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// ```
|
2020-04-21 17:25:12 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-04-07 07:23:06 +02:00
|
|
|
/// # use std::sync::RwLock;
|
2020-04-16 17:31:48 +02:00
|
|
|
/// # use std::sync::Arc;
|
2020-03-09 14:57:07 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2021-02-26 04:21:23 +01:00
|
|
|
/// let result = Arc::new(RwLock::new(String::new()));
|
2020-04-07 07:23:06 +02:00
|
|
|
///
|
2020-04-16 17:31:48 +02:00
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Override action of 'print' function
|
|
|
|
/// let logger = result.clone();
|
|
|
|
/// engine.on_print(move |s| logger.write().unwrap().push_str(s));
|
|
|
|
///
|
|
|
|
/// engine.consume("print(40 + 2);")?;
|
2020-03-04 15:00:01 +01:00
|
|
|
///
|
2020-04-07 07:23:06 +02:00
|
|
|
/// assert_eq!(*result.read().unwrap(), "42");
|
2020-03-09 14:57:07 +01:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
2020-03-04 15:00:01 +01:00
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-07-12 05:46:53 +02:00
|
|
|
pub fn on_print(&mut self, callback: impl Fn(&str) + SendSync + 'static) -> &mut Self {
|
2020-04-27 15:28:31 +02:00
|
|
|
self.print = Box::new(callback);
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Override default action of `debug` (print to stdout using [`println!`])
|
2020-03-04 15:00:01 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2020-03-19 06:52:10 +01:00
|
|
|
/// ```
|
2020-04-23 07:22:53 +02:00
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-04-07 07:23:06 +02:00
|
|
|
/// # use std::sync::RwLock;
|
2020-04-16 17:31:48 +02:00
|
|
|
/// # use std::sync::Arc;
|
2020-03-09 14:57:07 +01:00
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
2021-02-26 04:21:23 +01:00
|
|
|
/// let result = Arc::new(RwLock::new(String::new()));
|
2020-03-04 15:00:01 +01:00
|
|
|
///
|
2020-04-16 17:31:48 +02:00
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Override action of 'print' function
|
|
|
|
/// let logger = result.clone();
|
2020-12-21 15:04:46 +01:00
|
|
|
/// engine.on_debug(move |s, src, pos| logger.write().unwrap().push_str(
|
|
|
|
/// &format!("{} @ {:?} > {}", src.unwrap_or("unknown"), pos, s)
|
|
|
|
/// ));
|
2020-04-16 17:31:48 +02:00
|
|
|
///
|
2020-12-21 15:04:46 +01:00
|
|
|
/// let mut ast = engine.compile(r#"let x = "hello"; debug(x);"#)?;
|
2021-01-09 10:06:01 +01:00
|
|
|
/// ast.set_source("world");
|
2020-12-21 15:04:46 +01:00
|
|
|
/// engine.consume_ast(&ast)?;
|
2020-04-07 07:23:06 +02:00
|
|
|
///
|
2020-12-21 15:04:46 +01:00
|
|
|
/// assert_eq!(*result.read().unwrap(), r#"world @ 1:18 > "hello""#);
|
2020-03-09 14:57:07 +01:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
2020-03-04 15:00:01 +01:00
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-12-12 04:47:18 +01:00
|
|
|
pub fn on_debug(
|
|
|
|
&mut self,
|
2020-12-21 15:04:46 +01:00
|
|
|
callback: impl Fn(&str, Option<&str>, Position) + SendSync + 'static,
|
2020-12-12 04:47:18 +01:00
|
|
|
) -> &mut Self {
|
2020-04-27 15:28:31 +02:00
|
|
|
self.debug = Box::new(callback);
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
|
|
|
}
|