rhai/src/engine_settings.rs

312 lines
11 KiB
Rust
Raw Normal View History

2020-11-20 09:52:28 +01:00
//! Configuration settings for [`Engine`].
2021-01-06 06:46:53 +01:00
use crate::stdlib::{
format,
num::{NonZeroU64, NonZeroU8, NonZeroUsize},
string::String,
};
2020-12-26 16:21:09 +01:00
use crate::token::Token;
2020-12-22 16:45:14 +01:00
use crate::Engine;
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "no_module"))]
use crate::stdlib::boxed::Box;
2020-07-13 13:38:50 +02:00
2020-07-05 09:23:51 +02:00
impl Engine {
2020-11-20 09:52:28 +01:00
/// Control whether and how the [`Engine`] will optimize an [`AST`][crate::AST] after compilation.
2020-07-05 09:23:51 +02:00
///
2021-01-02 16:30:10 +01:00
/// Not available under `no_optimize`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "no_optimize"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-11-16 09:28:04 +01:00
pub fn set_optimization_level(
&mut self,
optimization_level: crate::OptimizationLevel,
) -> &mut Self {
2020-07-12 05:46:53 +02:00
self.optimization_level = optimization_level;
self
2020-07-05 09:23:51 +02:00
}
/// The current optimization level.
2020-11-20 09:52:28 +01:00
/// It controls whether and how the [`Engine`] will optimize an [`AST`][crate::AST] after compilation.
2020-07-05 09:23:51 +02:00
///
2021-01-02 16:30:10 +01:00
/// Not available under `no_optimize`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "no_optimize"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-11-16 09:28:04 +01:00
pub fn optimization_level(&self) -> crate::OptimizationLevel {
2020-07-05 09:23:51 +02:00
self.optimization_level
}
/// Enable/disable doc-comments.
#[inline(always)]
pub fn set_doc_comments(&mut self, enable: bool) -> &mut Self {
self.disable_doc_comments = !enable;
self
}
2020-07-05 09:23:51 +02:00
/// Set the maximum levels of function calls allowed for a script in order to avoid
/// infinite recursion and stack overflows.
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked` or `no_function`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-12-29 05:29:45 +01:00
#[cfg(not(feature = "no_function"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-12 05:46:53 +02:00
pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self {
2020-11-10 16:26:50 +01:00
self.limits.max_call_stack_depth = levels;
2020-07-12 05:46:53 +02:00
self
2020-07-05 09:23:51 +02:00
}
/// The maximum levels of function calls allowed for a script.
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked` or `no_function`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-12-29 05:29:45 +01:00
#[cfg(not(feature = "no_function"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-05 09:23:51 +02:00
pub fn max_call_levels(&self) -> usize {
2020-11-10 16:26:50 +01:00
self.limits.max_call_stack_depth
2020-07-05 09:23:51 +02:00
}
/// Set the maximum number of operations allowed for a script to run to avoid
/// consuming too much resources (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-12 05:46:53 +02:00
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
2021-01-06 06:46:53 +01:00
self.limits.max_operations = NonZeroU64::new(operations);
2020-07-12 05:46:53 +02:00
self
2020-07-05 09:23:51 +02:00
}
/// The maximum number of operations allowed for a script to run (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-05 09:23:51 +02:00
pub fn max_operations(&self) -> u64 {
2021-01-06 06:46:53 +01:00
self.limits.max_operations.map_or(0, NonZeroU64::get)
2020-07-05 09:23:51 +02:00
}
2020-11-25 02:36:06 +01:00
/// Set the maximum number of imported [modules][crate::Module] allowed for a script.
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked` or `no_module`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-10-18 16:10:08 +02:00
#[cfg(not(feature = "no_module"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-12 05:46:53 +02:00
pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
2020-11-10 16:26:50 +01:00
self.limits.max_modules = modules;
2020-07-12 05:46:53 +02:00
self
2020-07-05 09:23:51 +02:00
}
2020-11-25 02:36:06 +01:00
/// The maximum number of imported [modules][crate::Module] allowed for a script.
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked` or `no_module`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-10-18 16:10:08 +02:00
#[cfg(not(feature = "no_module"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-05 09:23:51 +02:00
pub fn max_modules(&self) -> usize {
2020-11-10 16:26:50 +01:00
self.limits.max_modules
2020-07-05 09:23:51 +02:00
}
/// Set the depth limits for expressions (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-12 05:46:53 +02:00
pub fn set_max_expr_depths(
&mut self,
max_expr_depth: usize,
#[cfg(not(feature = "no_function"))] max_function_expr_depth: usize,
2020-07-12 05:46:53 +02:00
) -> &mut Self {
2021-01-06 06:46:53 +01:00
self.limits.max_expr_depth = NonZeroUsize::new(max_expr_depth);
#[cfg(not(feature = "no_function"))]
{
2021-01-06 06:46:53 +01:00
self.limits.max_function_expr_depth = NonZeroUsize::new(max_function_expr_depth);
}
2020-07-12 05:46:53 +02:00
self
2020-07-05 09:23:51 +02:00
}
/// The depth limit for expressions (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-05 09:23:51 +02:00
pub fn max_expr_depth(&self) -> usize {
2021-01-06 06:46:53 +01:00
self.limits.max_expr_depth.map_or(0, NonZeroUsize::get)
2020-07-05 09:23:51 +02:00
}
/// The depth limit for expressions in functions (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked` or `no_function`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-05 09:23:51 +02:00
pub fn max_function_expr_depth(&self) -> usize {
2021-01-06 06:46:53 +01:00
self.limits
.max_function_expr_depth
.map_or(0, NonZeroUsize::get)
2020-07-05 09:23:51 +02:00
}
2020-11-25 02:36:06 +01:00
/// Set the maximum length of [strings][crate::ImmutableString] (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-12 05:46:53 +02:00
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
2021-01-06 06:46:53 +01:00
self.limits.max_string_size = NonZeroUsize::new(max_size);
2020-07-12 05:46:53 +02:00
self
2020-07-05 09:23:51 +02:00
}
2020-11-25 02:36:06 +01:00
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-05 09:23:51 +02:00
pub fn max_string_size(&self) -> usize {
2021-01-06 06:46:53 +01:00
self.limits.max_string_size.map_or(0, NonZeroUsize::get)
2020-07-05 09:23:51 +02:00
}
2020-11-25 02:36:06 +01:00
/// Set the maximum length of [arrays][crate::Array] (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked` or `no_index`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_index"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-12 05:46:53 +02:00
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
2021-01-06 06:46:53 +01:00
self.limits.max_array_size = NonZeroUsize::new(max_size);
2020-07-12 05:46:53 +02:00
self
2020-07-05 09:23:51 +02:00
}
2020-11-25 02:36:06 +01:00
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
2021-01-02 16:30:10 +01:00
///
/// Not available under `unchecked` or `no_index`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_index"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-05 09:23:51 +02:00
pub fn max_array_size(&self) -> usize {
2021-01-06 06:46:53 +01:00
self.limits.max_array_size.map_or(0, NonZeroUsize::get)
2020-07-05 09:23:51 +02:00
}
2021-01-02 16:30:10 +01:00
/// Set the maximum size of [object maps][crate::Map] (0 for unlimited).
///
/// Not available under `unchecked` or `no_object`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
#[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 set_max_map_size(&mut self, max_size: usize) -> &mut Self {
2021-01-06 06:46:53 +01:00
self.limits.max_map_size = NonZeroUsize::new(max_size);
2020-07-12 05:46:53 +02:00
self
2020-07-05 09:23:51 +02:00
}
2021-01-02 16:30:10 +01:00
/// The maximum size of [object maps][crate::Map] (0 for unlimited).
///
/// Not available under `unchecked` or `no_object`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_object"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-05 09:23:51 +02:00
pub fn max_map_size(&self) -> usize {
2021-01-06 06:46:53 +01:00
self.limits.max_map_size.map_or(0, NonZeroUsize::get)
2020-07-05 09:23:51 +02:00
}
2020-11-20 09:52:28 +01:00
/// Set the module resolution service used by the [`Engine`].
2020-07-05 09:23:51 +02:00
///
2021-01-02 16:30:10 +01:00
/// Not available under `no_module`.
2020-07-05 09:23:51 +02:00
#[cfg(not(feature = "no_module"))]
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-12 05:46:53 +02:00
pub fn set_module_resolver(
&mut self,
2020-12-26 06:05:57 +01:00
resolver: impl crate::ModuleResolver + 'static,
2020-07-12 05:46:53 +02:00
) -> &mut Self {
2020-12-26 06:05:57 +01:00
self.module_resolver = Box::new(resolver);
2020-07-12 05:46:53 +02:00
self
2020-07-05 09:23:51 +02:00
}
/// Disable a particular keyword or operator in the language.
///
/// # Examples
///
/// The following will raise an error during parsing because the `if` keyword is disabled
/// and is recognized as a variable name!
///
/// ```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 keyword
2020-07-05 09:23:51 +02:00
/// # 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(())
/// # }
/// ```
2020-10-08 16:25:50 +02:00
#[inline(always)]
2020-07-12 05:46:53 +02:00
pub fn disable_symbol(&mut self, symbol: &str) -> &mut Self {
2020-10-25 14:57:18 +01:00
self.disabled_symbols.insert(symbol.into());
2020-07-12 05:46:53 +02:00
self
2020-07-05 11:41:45 +02:00
}
/// Register a custom operator with a precedence into the language.
2020-07-05 11:41:45 +02:00
///
/// The operator must be a valid identifier (i.e. it cannot be a symbol).
///
/// The precedence cannot be zero.
///
2020-10-27 04:30:38 +01:00
/// # Example
2020-07-05 11:41:45 +02:00
///
/// ```rust
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register a custom operator called 'foo' and give it
2020-07-06 07:01:57 +02:00
/// // a precedence of 160 (i.e. between +|- and *|/).
/// engine.register_custom_operator("foo", 160).unwrap();
2020-07-05 11:41:45 +02:00
///
/// // Register a binary function named 'foo'
/// engine.register_fn("foo", |x: i64, y: i64| (x * y) - (x + y));
///
/// assert_eq!(
/// engine.eval_expression::<i64>("1 + 2 * 3 foo 4 - 5 / 6")?,
/// 15
/// );
/// # Ok(())
/// # }
/// ```
pub fn register_custom_operator(
&mut self,
keyword: &str,
precedence: u8,
2020-07-12 05:46:53 +02:00
) -> Result<&mut Self, String> {
let precedence = NonZeroU8::new(precedence);
if precedence.is_none() {
return Err("precedence cannot be zero".into());
}
2020-07-05 11:41:45 +02:00
match Token::lookup_from_syntax(keyword) {
// Standard identifiers, reserved keywords and custom keywords are OK
None | Some(Token::Reserved(_)) | Some(Token::Custom(_)) => (),
// Active standard keywords cannot be made custom
2020-12-26 16:21:09 +01:00
// Disabled keywords are OK
Some(token) if token.is_keyword() => {
if !self.disabled_symbols.contains(token.syntax().as_ref()) {
return Err(format!("'{}' is a reserved keyword", keyword).into());
}
}
// Active standard operators cannot be made custom
Some(token) if token.is_operator() => {
if !self.disabled_symbols.contains(token.syntax().as_ref()) {
return Err(format!("'{}' is a reserved operator", keyword).into());
}
}
// Active standard symbols cannot be made custom
Some(token) if !self.disabled_symbols.contains(token.syntax().as_ref()) => {
return Err(format!("'{}' is a reserved symbol", keyword).into())
}
// Disabled symbols are OK
Some(_) => (),
}
// Add to custom keywords
self.custom_keywords.insert(keyword.into(), precedence);
2020-07-05 11:41:45 +02:00
2020-07-12 05:46:53 +02:00
Ok(self)
2020-07-05 09:23:51 +02:00
}
}