2021-11-13 15:36:23 +01:00
|
|
|
//! Module defining the public API of the Rhai engine.
|
|
|
|
|
2022-02-03 16:54:53 +01:00
|
|
|
pub mod type_names;
|
|
|
|
|
2021-11-20 07:57:21 +01:00
|
|
|
pub mod eval;
|
2021-11-20 14:29:36 +01:00
|
|
|
|
|
|
|
pub mod run;
|
|
|
|
|
|
|
|
pub mod compile;
|
|
|
|
|
2022-04-21 06:15:21 +02:00
|
|
|
pub mod json;
|
|
|
|
|
2021-11-20 07:57:21 +01:00
|
|
|
pub mod files;
|
2021-11-20 14:29:36 +01:00
|
|
|
|
|
|
|
pub mod register;
|
|
|
|
|
|
|
|
pub mod call_fn;
|
|
|
|
|
2021-12-03 04:16:35 +01:00
|
|
|
pub mod options;
|
|
|
|
|
2022-03-01 08:34:15 +01:00
|
|
|
pub mod optimize;
|
|
|
|
|
2021-11-20 07:57:21 +01:00
|
|
|
pub mod limits;
|
2021-11-20 14:29:36 +01:00
|
|
|
|
|
|
|
pub mod events;
|
|
|
|
|
2021-12-27 15:02:34 +01:00
|
|
|
pub mod custom_syntax;
|
|
|
|
|
2021-11-20 14:29:36 +01:00
|
|
|
pub mod deprecated;
|
2021-11-20 07:57:21 +01:00
|
|
|
|
2022-08-09 10:31:25 +02:00
|
|
|
pub mod build_type;
|
|
|
|
|
2022-07-26 13:55:10 +02:00
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
pub mod definitions;
|
|
|
|
|
2022-05-21 15:44:12 +02:00
|
|
|
use crate::{Dynamic, Engine, Identifier};
|
2021-11-20 07:57:21 +01:00
|
|
|
|
|
|
|
#[cfg(feature = "no_std")]
|
|
|
|
use std::prelude::v1::*;
|
|
|
|
|
2021-12-17 09:55:07 +01:00
|
|
|
pub mod default_limits {
|
|
|
|
#[cfg(not(feature = "unchecked"))]
|
2022-10-05 09:07:54 +02:00
|
|
|
pub use super::limits::default_limits::*;
|
2021-12-17 09:55:07 +01:00
|
|
|
|
|
|
|
pub const MAX_DYNAMIC_PARAMETERS: usize = 16;
|
|
|
|
}
|
|
|
|
|
2021-11-20 07:57:21 +01:00
|
|
|
impl Engine {
|
2022-08-25 16:25:41 +02:00
|
|
|
/// The module resolution service used by the [`Engine`].
|
|
|
|
///
|
|
|
|
/// Not available under `no_module`.
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
#[inline(always)]
|
2022-09-25 06:24:03 +02:00
|
|
|
#[must_use]
|
2022-08-25 16:25:41 +02:00
|
|
|
pub fn module_resolver(&self) -> &dyn crate::ModuleResolver {
|
|
|
|
&*self.module_resolver
|
|
|
|
}
|
|
|
|
|
2021-11-20 07:57:21 +01:00
|
|
|
/// Set the module resolution service used by the [`Engine`].
|
|
|
|
///
|
|
|
|
/// Not available under `no_module`.
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn set_module_resolver(
|
|
|
|
&mut self,
|
|
|
|
resolver: impl crate::ModuleResolver + 'static,
|
|
|
|
) -> &mut Self {
|
2022-03-20 14:58:43 +01:00
|
|
|
self.module_resolver = Box::new(resolver);
|
2021-11-20 07:57:21 +01:00
|
|
|
self
|
|
|
|
}
|
2022-03-01 08:34:15 +01:00
|
|
|
|
2021-11-20 07:57:21 +01:00
|
|
|
/// Disable a particular keyword or operator in the language.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
2022-02-24 03:36:20 +01:00
|
|
|
/// The following will raise an error during parsing because the `if` keyword is disabled and is
|
|
|
|
/// recognized as a reserved symbol!
|
2021-11-20 07:57:21 +01:00
|
|
|
///
|
|
|
|
/// ```rust,should_panic
|
|
|
|
/// # fn main() -> Result<(), rhai::ParseError> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// engine.disable_symbol("if"); // disable the 'if' keyword
|
|
|
|
///
|
|
|
|
/// engine.compile("let x = if true { 42 } else { 0 };")?;
|
|
|
|
/// // ^ 'if' is rejected as a reserved symbol
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// The following will raise an error during parsing because the `+=` operator is disabled.
|
|
|
|
///
|
|
|
|
/// ```rust,should_panic
|
|
|
|
/// # fn main() -> Result<(), rhai::ParseError> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// engine.disable_symbol("+="); // disable the '+=' operator
|
|
|
|
///
|
|
|
|
/// engine.compile("let x = 42; x += 1;")?;
|
|
|
|
/// // ^ unknown operator
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn disable_symbol(&mut self, symbol: impl Into<Identifier>) -> &mut Self {
|
|
|
|
self.disabled_symbols.insert(symbol.into());
|
|
|
|
self
|
|
|
|
}
|
2022-03-01 08:34:15 +01:00
|
|
|
|
2021-11-20 07:57:21 +01:00
|
|
|
/// Register a custom operator with a precedence into the language.
|
|
|
|
///
|
2022-07-05 16:59:03 +02:00
|
|
|
/// Not available under `no_custom_syntax`.
|
|
|
|
///
|
2021-12-09 15:54:10 +01:00
|
|
|
/// The operator can be a valid identifier, a reserved symbol, a disabled operator or a disabled keyword.
|
2021-11-20 07:57:21 +01:00
|
|
|
///
|
|
|
|
/// The precedence cannot be zero.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
2021-12-09 15:54:10 +01:00
|
|
|
/// // Register a custom operator called '#' and give it
|
2021-11-20 07:57:21 +01:00
|
|
|
/// // a precedence of 160 (i.e. between +|- and *|/).
|
2021-12-09 15:54:10 +01:00
|
|
|
/// engine.register_custom_operator("#", 160).expect("should succeed");
|
2021-11-20 07:57:21 +01:00
|
|
|
///
|
2021-12-09 15:54:10 +01:00
|
|
|
/// // Register a binary function named '#'
|
|
|
|
/// engine.register_fn("#", |x: i64, y: i64| (x * y) - (x + y));
|
2021-11-20 07:57:21 +01:00
|
|
|
///
|
|
|
|
/// assert_eq!(
|
2021-12-09 15:54:10 +01:00
|
|
|
/// engine.eval_expression::<i64>("1 + 2 * 3 # 4 - 5 / 6")?,
|
2021-11-20 07:57:21 +01:00
|
|
|
/// 15
|
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2022-07-05 16:59:03 +02:00
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
2021-11-20 07:57:21 +01:00
|
|
|
pub fn register_custom_operator(
|
|
|
|
&mut self,
|
2022-01-04 08:22:48 +01:00
|
|
|
keyword: impl AsRef<str>,
|
2021-11-20 07:57:21 +01:00
|
|
|
precedence: u8,
|
|
|
|
) -> Result<&mut Self, String> {
|
2022-10-16 05:35:21 +02:00
|
|
|
use crate::tokenizer::Token;
|
|
|
|
|
|
|
|
let precedence = crate::engine::Precedence::new(precedence)
|
|
|
|
.ok_or_else(|| "precedence cannot be zero".to_string())?;
|
2021-11-20 07:57:21 +01:00
|
|
|
|
2022-07-05 10:26:38 +02:00
|
|
|
let keyword = keyword.as_ref();
|
|
|
|
|
2022-10-30 15:16:09 +01:00
|
|
|
match Token::lookup_symbol_from_syntax(keyword) {
|
2022-07-05 16:59:03 +02:00
|
|
|
// Standard identifiers and reserved keywords are OK
|
|
|
|
None | Some(Token::Reserved(..)) => (),
|
|
|
|
// custom keywords are OK
|
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
|
|
|
Some(Token::Custom(..)) => (),
|
2021-11-20 07:57:21 +01:00
|
|
|
// Active standard keywords cannot be made custom
|
|
|
|
// Disabled keywords are OK
|
|
|
|
Some(token) if token.is_standard_keyword() => {
|
2022-03-03 06:02:57 +01:00
|
|
|
if self.disabled_symbols.is_empty()
|
|
|
|
|| !self.disabled_symbols.contains(&*token.syntax())
|
|
|
|
{
|
2022-08-11 13:01:23 +02:00
|
|
|
return Err(format!("'{keyword}' is a reserved keyword"));
|
2021-11-20 07:57:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Active standard symbols cannot be made custom
|
|
|
|
Some(token) if token.is_standard_symbol() => {
|
2022-03-03 06:02:57 +01:00
|
|
|
if self.disabled_symbols.is_empty()
|
|
|
|
|| !self.disabled_symbols.contains(&*token.syntax())
|
|
|
|
{
|
2022-08-11 13:01:23 +02:00
|
|
|
return Err(format!("'{keyword}' is a reserved operator"));
|
2021-11-20 07:57:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Active standard symbols cannot be made custom
|
2022-03-03 06:02:57 +01:00
|
|
|
Some(token)
|
|
|
|
if self.disabled_symbols.is_empty()
|
|
|
|
|| !self.disabled_symbols.contains(&*token.syntax()) =>
|
|
|
|
{
|
2022-08-11 13:01:23 +02:00
|
|
|
return Err(format!("'{keyword}' is a reserved symbol"))
|
2021-11-20 07:57:21 +01:00
|
|
|
}
|
|
|
|
// Disabled symbols are OK
|
|
|
|
Some(_) => (),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add to custom keywords
|
2022-09-13 16:54:13 +02:00
|
|
|
self.custom_keywords
|
|
|
|
.insert(keyword.into(), Some(precedence));
|
2021-11-20 07:57:21 +01:00
|
|
|
|
|
|
|
Ok(self)
|
|
|
|
}
|
2022-05-21 15:44:12 +02:00
|
|
|
|
|
|
|
/// Get the default value of the custom state for each evaluation run.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub fn default_tag(&self) -> &Dynamic {
|
|
|
|
&self.def_tag
|
|
|
|
}
|
|
|
|
/// Get a mutable reference to the default value of the custom state for each evaluation run.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub fn default_tag_mut(&mut self) -> &mut Dynamic {
|
|
|
|
&mut self.def_tag
|
|
|
|
}
|
|
|
|
/// Set the default value of the custom state for each evaluation run.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn set_default_tag(&mut self, value: impl Into<Dynamic>) -> &mut Self {
|
|
|
|
self.def_tag = value.into();
|
|
|
|
self
|
|
|
|
}
|
2021-11-20 07:57:21 +01:00
|
|
|
}
|
2022-10-16 05:35:21 +02:00
|
|
|
|
|
|
|
#[cfg(feature = "unchecked")]
|
|
|
|
impl Engine {
|
|
|
|
/// The maximum levels of function calls allowed for a script.
|
|
|
|
///
|
|
|
|
/// Always returns [`usize::MAX`] under `unchecked`.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn max_call_levels(&self) -> usize {
|
|
|
|
usize::MAX
|
|
|
|
}
|
|
|
|
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
|
|
|
///
|
|
|
|
/// Always returns zero under `unchecked`.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn max_operations(&self) -> u64 {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
/// The maximum number of imported [modules][crate::Module] allowed for a script.
|
|
|
|
///
|
|
|
|
/// Always returns [`usize::MAX`] under `unchecked`.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn max_modules(&self) -> usize {
|
|
|
|
usize::MAX
|
|
|
|
}
|
|
|
|
/// The depth limit for expressions (0 for unlimited).
|
|
|
|
///
|
|
|
|
/// Always returns zero under `unchecked`.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn max_expr_depth(&self) -> usize {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
/// The depth limit for expressions in functions (0 for unlimited).
|
|
|
|
///
|
|
|
|
/// Always returns zero under `unchecked`.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn max_function_expr_depth(&self) -> usize {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
|
|
|
///
|
|
|
|
/// Always returns zero under `unchecked`.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn max_string_size(&self) -> usize {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
|
|
|
|
///
|
|
|
|
/// Always returns zero under `unchecked`.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn max_array_size(&self) -> usize {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
/// The maximum size of [object maps][crate::Map] (0 for unlimited).
|
|
|
|
///
|
|
|
|
/// Always returns zero under `unchecked`.
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn max_map_size(&self) -> usize {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
}
|