rhai/src/engine_api.rs

1830 lines
62 KiB
Rust
Raw Normal View History

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;
use crate::engine::{EvalContext, Imports};
use crate::fn_native::{FnCallArgs, SendSync};
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,
2020-11-22 10:49:00 +01:00
format,
2020-11-13 11:32:18 +01:00
hash::{Hash, Hasher},
2020-09-22 12:06:36 +02:00
string::String,
2020-11-22 10:49:00 +01:00
vec::Vec,
2020-03-10 03:07:44 +01:00
};
2020-11-16 16:10:14 +01:00
use crate::utils::get_hasher;
use crate::{
2020-11-17 05:23:53 +01:00
scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, NativeCallContext,
2020-11-20 09:52:28 +01:00
ParseError, Position, 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-11-13 11:32:18 +01:00
/// Calculate a unique hash for a script.
fn calc_hash_for_scripts<'a>(scripts: impl IntoIterator<Item = &'a &'a str>) -> u64 {
let s = &mut get_hasher();
scripts.into_iter().for_each(|&script| script.hash(s));
s.finish()
}
2020-04-03 11:17:00 +02:00
/// Engine public API
2020-04-16 17:31:48 +02:00
impl Engine {
2020-11-20 09:52:28 +01:00
/// Register a function of the [`Engine`].
2020-07-05 17:08:44 +02:00
///
/// ## WARNING - Low Level API
///
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
///
2020-07-07 16:59:23 +02:00
/// To access a primary parameter value (i.e. cloning is cheap), use: `args[n].clone().cast::<T>()`
2020-07-05 17:08:44 +02:00
///
2020-07-07 16:59:23 +02:00
/// To access a parameter 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-07-05 17:08:44 +02:00
#[deprecated(note = "this function is volatile and may change")]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-07 16:59:23 +02:00
pub fn register_raw_fn<T: Variant + Clone>(
2020-07-05 17:08:44 +02:00
&mut self,
name: &str,
2020-07-06 06:06:57 +02:00
arg_types: &[TypeId],
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
+ SendSync
+ 'static,
2020-07-12 05:46:53 +02:00
) -> &mut Self {
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 } }
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
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
2020-03-22 03:18:16 +01:00
/// // Use `register_fn` to register methods on the type.
2020-03-19 06:52:10 +01:00
/// engine.register_fn("update", TestStruct::update);
///
/// 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(())
/// # }
/// ```
#[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
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// assert_eq!(
/// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
/// "rust_out::TestStruct"
/// );
///
/// // Register the custom type with a name.
/// engine.register_type_with_name::<TestStruct>("Hello");
///
/// // Register methods on the type.
/// engine.register_fn("new_ts", TestStruct::new);
///
/// assert_eq!(
/// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
/// "Hello"
/// );
/// # Ok(())
/// # }
/// ```
#[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 } }
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 }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register a getter on a property (notice it doesn't have to be the same name).
/// engine.register_get("xyz", TestStruct::get_field);
///
/// 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)]
2020-11-16 16:10:14 +01:00
pub fn register_get<T: Variant + Clone, U: Variant + Clone>(
2020-05-21 11:11:01 +02:00
&mut self,
name: &str,
callback: impl Fn(&mut T) -> U + SendSync + 'static,
2020-11-16 16:10:14 +01:00
) -> &mut Self {
2020-11-16 09:28:04 +01:00
crate::RegisterFn::register_fn(self, &crate::engine::make_getter(name), callback)
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
///
/// ```
/// use rhai::{Engine, Dynamic, EvalAltResult, RegisterFn};
///
/// #[derive(Clone)]
/// struct TestStruct {
/// field: i64
/// }
///
/// impl TestStruct {
2020-10-19 08:26:15 +02:00
/// fn new() -> Self { Self { field: 1 } }
2020-08-07 05:10:38 +02:00
/// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self) -> Result<Dynamic, Box<EvalAltResult>> {
/// Ok(self.field.into())
/// }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register a getter on a property (notice it doesn't have to be the same name).
/// engine.register_get_result("xyz", TestStruct::get_field);
///
/// 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)]
2020-08-07 05:10:38 +02:00
pub fn register_get_result<T: Variant + Clone>(
&mut self,
name: &str,
callback: impl Fn(&mut T) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
) -> &mut Self {
2020-11-16 09:28:04 +01:00
crate::RegisterResultFn::register_result_fn(
self,
&crate::engine::make_getter(name),
callback,
)
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 } }
2020-03-19 06:52:10 +01:00
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register a setter on a property (notice it doesn't have to be the same name)
/// engine.register_set("xyz", TestStruct::set_field);
///
/// // 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(())
/// # }
/// ```
#[cfg(not(feature = "no_object"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-11-16 16:10:14 +01:00
pub fn register_set<T: Variant + Clone, U: Variant + Clone>(
2020-05-21 11:11:01 +02:00
&mut self,
name: &str,
callback: impl Fn(&mut T, U) + SendSync + 'static,
2020-11-16 16:10:14 +01:00
) -> &mut Self {
2020-11-16 09:28:04 +01:00
crate::RegisterFn::register_fn(self, &crate::engine::make_setter(name), callback)
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
///
/// ```
/// use rhai::{Engine, Dynamic, EvalAltResult, RegisterFn};
///
/// #[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 } }
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();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register a setter on a property (notice it doesn't have to be the same name)
/// engine.register_set_result("xyz", TestStruct::set_field);
///
/// // 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)]
2020-11-16 16:10:14 +01:00
pub fn register_set_result<T: Variant + Clone, U: Variant + Clone>(
2020-08-07 05:10:38 +02:00
&mut self,
name: &str,
2020-09-22 06:14:26 +02:00
callback: impl Fn(&mut T, U) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
2020-11-16 16:10:14 +01:00
) -> &mut Self {
2020-11-16 09:28:04 +01:00
crate::RegisterResultFn::register_result_fn(
self,
&crate::engine::make_setter(name),
move |obj: &mut T, value: U| callback(obj, value).map(Into::into),
)
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 } }
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 }
2020-03-19 06:52:10 +01:00
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register a getter and a setter on a property
/// // (notice it doesn't have to be the same name)
/// engine.register_get_set("xyz", TestStruct::get_field, TestStruct::set_field);
///
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz = 42; a.xyz")?, 42);
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_object"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-11-16 16:10:14 +01:00
pub fn register_get_set<T: Variant + Clone, U: Variant + Clone>(
2020-05-21 11:11:01 +02:00
&mut self,
name: &str,
get_fn: impl Fn(&mut T) -> U + SendSync + 'static,
set_fn: impl Fn(&mut T, U) + 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`.
///
/// # Panics
///
2020-11-20 09:52:28 +01:00
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
/// 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] } }
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>> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register 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>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register an indexer.
2020-06-06 07:06:00 +02:00
/// engine.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)]
2020-11-16 16:10:14 +01:00
pub fn register_indexer_get<T: Variant + Clone, X: Variant + Clone, U: Variant + Clone>(
2020-05-21 11:11:01 +02:00
&mut self,
callback: impl Fn(&mut T, X) -> U + SendSync + 'static,
2020-11-16 16:10:14 +01:00
) -> &mut Self {
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>()
{
panic!("Cannot register indexer for strings.");
}
2020-11-16 09:28:04 +01:00
crate::RegisterFn::register_fn(self, crate::engine::FN_IDX_GET, callback)
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`.
///
/// # Panics
///
2020-11-20 09:52:28 +01:00
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
/// Indexers for arrays, object maps and strings cannot be registered.
///
2020-08-07 05:10:38 +02:00
/// # Example
///
/// ```
/// use rhai::{Engine, Dynamic, EvalAltResult, RegisterFn};
///
/// #[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] } }
2020-08-07 05:10:38 +02:00
/// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self, index: i64) -> Result<Dynamic, Box<EvalAltResult>> {
/// Ok(self.fields[index as usize].into())
/// }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// let mut engine = Engine::new();
///
/// // Register 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>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register an indexer.
/// engine.register_indexer_get_result(TestStruct::get_field);
///
/// 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)]
2020-11-16 16:10:14 +01:00
pub fn register_indexer_get_result<T: Variant + Clone, X: Variant + Clone>(
2020-08-07 05:10:38 +02:00
&mut self,
callback: impl Fn(&mut T, X) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
2020-11-16 16:10:14 +01:00
) -> &mut Self {
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>()
{
panic!("Cannot register indexer for strings.");
}
2020-11-16 09:28:04 +01:00
crate::RegisterResultFn::register_result_fn(self, crate::engine::FN_IDX_GET, callback)
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
///
/// # Panics
///
2020-11-20 09:52:28 +01:00
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
/// 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] } }
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>> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register 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>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register an indexer.
/// engine.register_indexer_set(TestStruct::set_field);
///
/// 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<T: Variant + Clone, X: Variant + Clone, U: Variant + Clone>(
2020-06-06 07:06:00 +02:00
&mut self,
2020-09-22 06:14:26 +02:00
callback: impl Fn(&mut T, X, U) + SendSync + 'static,
2020-11-16 16:10:14 +01:00
) -> &mut Self {
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>()
{
panic!("Cannot register indexer for strings.");
}
2020-11-16 09:28:04 +01:00
crate::RegisterFn::register_fn(self, crate::engine::FN_IDX_SET, callback)
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
///
/// # Panics
///
2020-11-20 09:52:28 +01:00
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
/// Indexers for arrays, object maps and strings cannot be registered.
///
2020-08-07 05:10:38 +02:00
/// # Example
///
/// ```
/// use rhai::{Engine, Dynamic, EvalAltResult, RegisterFn};
///
/// #[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] } }
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();
///
/// // Register 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>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register an indexer.
/// engine.register_indexer_set_result(TestStruct::set_field);
///
/// 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,
2020-11-16 16:10:14 +01:00
U: Variant + Clone,
>(
&mut self,
callback: impl Fn(&mut T, X, U) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
) -> &mut Self {
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>()
{
panic!("Cannot register indexer for strings.");
}
2020-11-16 09:28:04 +01:00
crate::RegisterResultFn::register_result_fn(
self,
crate::engine::FN_IDX_SET,
move |obj: &mut T, index: X, value: U| callback(obj, index, value).map(Into::into),
)
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
///
/// # Panics
///
2020-11-20 09:52:28 +01:00
/// Panics if the type is [`Array`], [`Map`], [`String`], [`ImmutableString`][crate::ImmutableString] or `&str`.
/// 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] } }
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] }
/// fn set_field(&mut self, index: i64, value: i64) { self.fields[index as usize] = value; }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register 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>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register an indexer.
/// engine.register_indexer_get_set(TestStruct::get_field, TestStruct::set_field);
///
/// 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)]
2020-11-16 16:10:14 +01:00
pub fn register_indexer_get_set<T: Variant + Clone, X: Variant + Clone, U: Variant + Clone>(
2020-06-06 07:06:00 +02:00
&mut self,
getter: impl Fn(&mut T, X) -> U + SendSync + 'static,
setter: impl Fn(&mut T, X, U) -> () + SendSync + 'static,
2020-11-16 16:10:14 +01:00
) -> &mut Self {
2020-07-12 05:46:53 +02:00
self.register_indexer_get(getter)
.register_indexer_set(setter)
2020-05-05 14:38:48 +02:00
}
2020-11-20 09:52:28 +01:00
/// Register a [`Module`][crate::Module] as a fixed module namespace with the [`Engine`].
2020-11-15 16:14:16 +01:00
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// use rhai::{Engine, Module};
///
/// let mut engine = Engine::new();
///
/// // Create the module
/// let mut module = Module::new();
/// module.set_fn_1("calc", |x: i64| Ok(x + 1));
///
/// // Register the module as a fixed sub-module
2020-11-15 16:14:16 +01:00
/// engine.register_module("CalcService", module);
///
/// assert_eq!(engine.eval::<i64>("CalcService::calc(41)")?, 42);
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_module"))]
pub fn register_module(
&mut self,
2020-11-16 09:28:04 +01:00
name: impl Into<crate::ImmutableString>,
module: impl Into<crate::Shared<crate::Module>>,
2020-11-15 16:14:16 +01:00
) -> &mut Self {
let module = module.into();
if !module.is_indexed() {
// Index the module (making a clone copy if necessary) if it is not indexed
2020-11-16 09:28:04 +01:00
let mut module = crate::fn_native::shared_take_or_clone(module);
2020-11-15 16:14:16 +01:00
module.build_index();
2020-11-17 05:23:53 +01:00
self.global_sub_modules.push(name, module);
2020-11-15 16:14:16 +01:00
} else {
2020-11-17 05:23:53 +01:00
self.global_sub_modules.push(name, module);
2020-11-15 16:14:16 +01:00
}
self
}
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
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::Engine;
///
/// 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)]
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-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
///
/// ```
/// # 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)]
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-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],
) -> 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)]
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,
) -> Result<AST, ParseError> {
2020-11-13 11:32:18 +01:00
let hash = calc_hash_for_scripts(scripts);
let stream = self.lex(scripts, None);
2020-11-13 11:32:18 +01:00
self.parse(hash, &mut stream.peekable(), scope, optimization_level)
}
2020-03-19 06:52:10 +01:00
/// Read the contents of a file into a string.
#[cfg(not(feature = "no_std"))]
2020-06-17 03:54:17 +02:00
#[cfg(not(target_arch = "wasm32"))]
2020-10-08 16:25:50 +02:00
#[inline]
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(
format!("Cannot open script file '{}'", path.to_string_lossy()),
err.into(),
)
2020-05-05 18:09:04 +02: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(
format!("Cannot read script file '{}'", path.to_string_lossy()),
err.into(),
)
2020-05-05 18:09:04 +02:00
})?;
2020-03-30 16:19:37 +02:00
Ok(contents)
}
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
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::Engine;
///
/// 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(())
/// # }
/// ```
#[cfg(not(feature = "no_std"))]
2020-06-17 03:54:17 +02:00
#[cfg(not(target_arch = "wasm32"))]
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-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
///
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
/// # 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(())
/// # }
/// ```
#[cfg(not(feature = "no_std"))]
2020-06-17 03:54:17 +02:00
#[cfg(not(target_arch = "wasm32"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
pub fn compile_file_with_scope(
&self,
scope: &Scope,
2020-11-16 16:10:14 +01:00
path: crate::stdlib::path::PathBuf,
) -> 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-04-10 11:14:07 +02:00
/// Parse a JSON string into a map.
///
/// The JSON string must be an object hash. It cannot be a simple JavaScript primitive.
///
2020-04-10 11:14:07 +02:00
/// Set `has_null` to `true` in order to map `null` values to `()`.
/// Setting it to `false` will cause a _variable not found_ error during parsing.
///
/// # 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,
/// then globally replace `{` with `#{` before calling this method.
///
2020-04-10 11:14:07 +02:00
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// use rhai::{Engine, Map};
2020-04-10 11:14:07 +02:00
///
/// let engine = Engine::new();
///
/// 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);
/// 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"))]
pub fn parse_json(&self, json: &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
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
let json_text = json.trim_start();
let scripts = if json_text.starts_with(Token::MapStart.syntax().as_ref()) {
[json_text, ""]
} else if json_text.starts_with(Token::LeftBrace.syntax().as_ref()) {
["#", 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(),
)
.into_err(Position::new(1, (json.len() - json_text.len() + 1) as u16))
.into());
};
2020-11-13 11:32:18 +01:00
let hash = calc_hash_for_scripts(&scripts);
let stream = self.lex(
2020-07-26 16:25:30 +02:00
&scripts,
if has_null {
Some(Box::new(|token| match token {
// If `null` is present, make sure `null` is treated as a variable
Token::Reserved(s) if s == "null" => Token::Identifier(s),
_ => token,
}))
} else {
None
},
);
2020-11-13 11:32:18 +01:00
let ast = self.parse_global_expr(
hash,
&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
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-22 14:03:58 +01:00
/// use rhai::Engine;
///
/// 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)]
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
///
/// ```
/// # 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(())
/// # }
/// ```
2020-10-08 16:25:50 +02:00
#[inline]
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,
) -> Result<AST, ParseError> {
2020-04-10 11:14:07 +02:00
let scripts = [script];
2020-11-13 11:32:18 +01:00
let hash = calc_hash_for_scripts(&scripts);
let stream = self.lex(&scripts, None);
2020-11-10 16:26:50 +01:00
let mut peekable = stream.peekable();
2020-11-13 11:32:18 +01:00
self.parse_global_expr(hash, &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.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::Engine;
///
/// 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(())
/// # }
/// ```
#[cfg(not(feature = "no_std"))]
2020-06-17 03:54:17 +02:00
#[cfg(not(target_arch = "wasm32"))]
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-19 06:52:10 +01:00
/// Evaluate a script file with own scope.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, Scope};
///
/// 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(())
/// # }
/// ```
#[cfg(not(feature = "no_std"))]
2020-06-17 03:54:17 +02:00
#[cfg(not(target_arch = "wasm32"))]
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>(
&self,
scope: &mut Scope,
2020-11-16 16:10:14 +01:00
path: crate::stdlib::path::PathBuf,
) -> Result<T, Box<EvalAltResult>> {
Self::read_file(path).and_then(|contents| self.eval_with_scope::<T>(scope, &contents))
}
/// Evaluate a string.
2020-03-19 06:52:10 +01:00
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::Engine;
///
/// 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)]
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)
}
/// Evaluate a string with own scope.
2020-03-19 06:52:10 +01:00
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, Scope};
///
/// 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(())
/// # }
/// ```
2020-10-08 16:25:50 +02:00
#[inline]
2020-04-12 17:00:06 +02:00
pub fn eval_with_scope<T: Variant + Clone>(
&self,
scope: &mut Scope,
2020-04-08 10:57:15 +02:00
script: &str,
) -> 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
)?;
self.eval_ast_with_scope(scope, &ast)
}
2020-03-22 14:03:58 +01:00
/// Evaluate a string containing an expression.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-22 14:03:58 +01:00
/// use rhai::Engine;
///
/// 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)]
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
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-22 14:03:58 +01:00
/// use rhai::{Engine, Scope};
///
/// 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(())
/// # }
/// ```
2020-10-08 16:25:50 +02:00
#[inline]
2020-04-12 17:00:06 +02:00
pub fn eval_expression_with_scope<T: Variant + Clone>(
&self,
2020-03-22 14:03:58 +01:00
scope: &mut Scope,
2020-04-08 10:57:15 +02:00
script: &str,
) -> Result<T, Box<EvalAltResult>> {
2020-04-10 15:02:38 +02:00
let scripts = [script];
2020-11-13 11:32:18 +01:00
let hash = calc_hash_for_scripts(&scripts);
let stream = self.lex(&scripts, None);
// No need to optimize a lone expression
2020-11-13 11:32:18 +01:00
let ast =
self.parse_global_expr(hash, &mut stream.peekable(), scope, OptimizationLevel::None)?;
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
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::Engine;
///
/// 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)]
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-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
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, Scope};
///
/// 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(())
/// # }
/// ```
2020-10-08 16:25:50 +02:00
#[inline]
2020-04-12 17:00:06 +02:00
pub fn eval_ast_with_scope<T: Variant + Clone>(
&self,
scope: &mut Scope,
ast: &AST,
) -> Result<T, Box<EvalAltResult>> {
2020-11-15 16:14:16 +01:00
let mut mods = self.global_sub_modules.clone();
let (result, _) = self.eval_ast_with_scope_raw(scope, &mut mods, ast)?;
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)]
pub(crate) fn eval_ast_with_scope_raw<'a>(
&self,
2020-03-19 12:53:42 +01:00
scope: &mut Scope,
mods: &mut Imports,
ast: &'a AST,
) -> Result<(Dynamic, u64), Box<EvalAltResult>> {
2020-11-04 04:49:02 +01:00
self.eval_statements_raw(scope, mods, ast.statements(), &[ast.lib()])
}
2020-03-04 15:00:01 +01:00
/// Evaluate a file, 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.
#[cfg(not(feature = "no_std"))]
2020-06-17 03:54:17 +02:00
#[cfg(not(target_arch = "wasm32"))]
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>> {
Self::read_file(path).and_then(|contents| self.consume(&contents))
}
/// 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.
#[cfg(not(feature = "no_std"))]
2020-06-17 03:54:17 +02:00
#[cfg(not(target_arch = "wasm32"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
pub fn consume_file_with_scope(
&self,
scope: &mut Scope,
2020-11-16 16:10:14 +01:00
path: crate::stdlib::path::PathBuf,
) -> Result<(), Box<EvalAltResult>> {
Self::read_file(path).and_then(|contents| self.consume_with_scope(scope, &contents))
}
2020-03-04 15:00:01 +01:00
/// Evaluate a string, 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)]
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)
}
/// Evaluate a string 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.
2020-10-08 16:25:50 +02:00
#[inline]
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];
2020-11-13 11:32:18 +01:00
let hash = calc_hash_for_scripts(&scripts);
let stream = self.lex(&scripts, None);
2020-11-13 11:32:18 +01:00
let ast = self.parse(hash, &mut stream.peekable(), scope, self.optimization_level)?;
self.consume_ast_with_scope(scope, &ast)
}
/// 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)]
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-11-20 09:52:28 +01:00
/// Evaluate an [`AST`] with own scope, but throw away the result and only return error (if any).
/// Useful for when you don't need the result, but still need to keep track of possible errors.
2020-10-20 04:54:32 +02:00
#[inline(always)]
pub fn consume_ast_with_scope(
&self,
scope: &mut Scope,
ast: &AST,
) -> Result<(), Box<EvalAltResult>> {
2020-11-15 16:14:16 +01:00
let mut mods = self.global_sub_modules.clone();
2020-11-04 04:49:02 +01:00
self.eval_statements_raw(scope, &mut mods, ast.statements(), &[ast.lib()])
2020-10-20 04:54:32 +02:00
.map(|_| ())
}
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
///
/// # Example
///
2020-03-19 06:52:10 +01:00
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// use rhai::{Engine, Scope};
2020-03-09 14:57:07 +01:00
///
/// let engine = Engine::new();
2020-03-04 15:00:01 +01: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 }
/// ")?;
///
/// 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
/// let result: i64 = engine.call_fn(&mut scope, &ast, "add", ( String::from("abc"), 123_i64 ) )?;
/// assert_eq!(result, 168);
///
/// let result: i64 = engine.call_fn(&mut scope, &ast, "add1", ( String::from("abc"), ) )?;
/// // ^^^^^^^^^^^^^^^^^^^^^^^^ tuple of one
/// assert_eq!(result, 46);
///
/// let result: i64 = engine.call_fn(&mut scope, &ast, "bar", () )?;
/// assert_eq!(result, 21);
/// # }
2020-03-04 15:00:01 +01:00
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_function"))]
2020-10-08 16:25:50 +02:00
#[inline]
2020-11-16 09:28:04 +01:00
pub fn call_fn<A: crate::fn_args::FuncArgs, T: Variant + Clone>(
&self,
scope: &mut Scope,
ast: &AST,
2020-03-04 15:00:01 +01:00
name: &str,
args: A,
) -> Result<T, Box<EvalAltResult>> {
let mut arg_values = args.into_vec();
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
2020-11-08 16:00:37 +01:00
let result =
self.call_fn_dynamic_raw(scope, &[ast.lib()], 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
///
/// ## WARNING
///
/// 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
2020-07-06 07:01:57 +02:00
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "add", None, [ String::from("abc").into(), 123_i64.into() ])?;
/// // ^^^^ no 'this' pointer
2020-05-31 06:37:19 +02:00
/// assert_eq!(result.cast::<i64>(), 168);
///
2020-07-06 07:01:57 +02:00
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "add1", None, [ String::from("abc").into() ])?;
2020-05-31 06:37:19 +02:00
/// assert_eq!(result.cast::<i64>(), 46);
///
2020-07-06 07:01:57 +02:00
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "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();
2020-07-06 07:01:57 +02:00
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "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(
&self,
scope: &mut Scope,
2020-11-16 09:28:04 +01:00
lib: impl AsRef<crate::Module>,
name: &str,
2020-07-05 17:08:44 +02:00
mut this_ptr: Option<&mut Dynamic>,
mut arg_values: impl AsMut<[Dynamic]>,
) -> Result<Dynamic, Box<EvalAltResult>> {
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
2020-11-08 16:00:37 +01:00
self.call_fn_dynamic_raw(scope, &[lib.as_ref()], name, &mut this_ptr, args.as_mut())
}
2020-11-22 10:21:34 +01:00
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
///
/// ## WARNING
///
/// 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"))]
2020-10-08 16:25:50 +02:00
#[inline]
pub(crate) fn call_fn_dynamic_raw(
2020-05-31 06:37:19 +02:00
&self,
scope: &mut Scope,
2020-11-16 09:28:04 +01:00
lib: &[&crate::Module],
2020-05-31 06:37:19 +02:00
name: &str,
2020-07-05 17:08:44 +02:00
this_ptr: &mut Option<&mut Dynamic>,
args: &mut FnCallArgs,
) -> Result<Dynamic, Box<EvalAltResult>> {
2020-10-02 17:14:33 +02:00
let fn_def = lib
2020-11-08 16:00:37 +01:00
.iter()
.find_map(|&m| m.get_script_fn(name, args.len(), true))
2020-11-20 09:52:28 +01:00
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?;
2020-04-24 06:39:24 +02:00
2020-10-29 04:37:51 +01:00
let mut state = Default::default();
2020-11-15 16:14:16 +01:00
let mut mods = self.global_sub_modules.clone();
2020-08-02 07:33:51 +02:00
// Check for data race.
2020-08-03 06:10:20 +02:00
if cfg!(not(feature = "no_closure")) {
2020-11-16 09:28:04 +01:00
crate::fn_call::ensure_no_data_race(name, args, false)?;
2020-08-02 07:33:51 +02:00
}
2020-12-12 04:15:09 +01:00
self.call_script_fn(
scope,
&mut mods,
&mut state,
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.
///
/// 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
/// 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
/// (i.e. with [`scope.push_constant(...)`][crate::Scope::push_constant]).
/// Then, the [`AST`] is cloned and the copy re-optimized before running.
#[cfg(not(feature = "no_optimize"))]
2020-10-08 16:25:50 +02:00
#[inline]
pub fn optimize_ast(
&self,
scope: &Scope,
2020-05-05 09:00:10 +02:00
mut ast: AST,
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());
crate::optimize::optimize_into_ast(self, scope, stmt, lib, optimization_level)
}
2020-11-22 10:21:34 +01:00
/// Generate a list of all registered functions.
///
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)
2020-11-22 10:21:34 +01:00
pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> {
let mut signatures: Vec<_> = Default::default();
signatures.extend(self.global_namespace.gen_fn_signatures());
self.global_sub_modules.iter().for_each(|(name, m)| {
signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f)))
});
if include_packages {
signatures.extend(self.packages.gen_fn_signatures());
}
signatures
}
2020-10-11 15:58:11 +02:00
/// Provide a callback that will be invoked before each variable access.
///
/// ## Return Value of Callback
///
/// Return `Ok(None)` to continue with normal variable access.
/// Return `Ok(Some(Dynamic))` as the variable's value.
///
/// ## Errors in Callback
///
/// 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.
/// 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,
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
}
/// 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| {
/// if ops > 10000 {
2020-11-02 04:04:45 +01:00
/// Some("Over 10,000 operations!".into())
/// } else if ops % 800 == 0 {
/// *logger.write().unwrap() = ops;
2020-11-02 04:04:45 +01:00
/// None
/// } else {
2020-11-02 04:04:45 +01:00
/// None
/// }
/// });
///
/// 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 {
self.progress = Some(Box::new(callback));
2020-07-12 05:46:53 +02:00
self
}
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
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # 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;
///
2020-04-16 17:31:48 +02:00
/// let result = Arc::new(RwLock::new(String::from("")));
///
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
///
/// 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-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>> {
/// # 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;
///
2020-04-16 17:31:48 +02:00
/// let result = Arc::new(RwLock::new(String::from("")));
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-12 04:47:18 +01:00
/// engine.on_debug(move |s, pos| logger.write().unwrap().push_str(
/// &format!("{:?} > {}", pos, s)
/// ));
2020-04-16 17:31:48 +02:00
///
2020-12-12 04:47:18 +01:00
/// engine.consume(r#"let x = "hello"; debug(x);"#)?;
///
2020-12-12 04:47:18 +01:00
/// assert_eq!(*result.read().unwrap(), r#"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,
callback: impl Fn(&str, Position) + SendSync + 'static,
) -> &mut Self {
2020-04-27 15:28:31 +02:00
self.debug = Box::new(callback);
2020-07-12 05:46:53 +02:00
self
}
}