Avoid warnings.

This commit is contained in:
Stephen Chung 2020-07-26 15:53:22 +08:00
parent 5e48478496
commit 6b600704a3
27 changed files with 624 additions and 321 deletions

View File

@ -16,12 +16,16 @@ use crate::engine::Map;
use crate::stdlib::{ use crate::stdlib::{
any::{type_name, Any, TypeId}, any::{type_name, Any, TypeId},
boxed::Box, boxed::Box,
collections::HashMap,
fmt, fmt,
string::String, string::String,
vec::Vec,
}; };
#[cfg(not(feature = "no_object"))]
use crate::stdlib::collections::HashMap;
#[cfg(not(feature = "no_index"))]
use crate::stdlib::vec::Vec;
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use crate::stdlib::time::Instant; use crate::stdlib::time::Instant;

View File

@ -1,30 +1,33 @@
//! Module that defines the extern API of `Engine`. //! Module that defines the extern API of `Engine`.
use crate::any::{Dynamic, Variant}; use crate::any::{Dynamic, Variant};
use crate::engine::{make_getter, make_setter, Engine, Imports, State, FN_IDX_GET, FN_IDX_SET}; use crate::engine::{Engine, Imports, State};
use crate::error::ParseError; use crate::error::ParseError;
use crate::fn_args::FuncArgs;
use crate::fn_native::{IteratorFn, SendSync}; use crate::fn_native::{IteratorFn, SendSync};
use crate::fn_register::RegisterFn;
use crate::module::{FuncReturn, Module}; use crate::module::{FuncReturn, Module};
use crate::optimize::{optimize_into_ast, OptimizationLevel}; use crate::optimize::{optimize_into_ast, OptimizationLevel};
use crate::parser::AST; use crate::parser::AST;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::Scope; use crate::scope::Scope;
use crate::token::{lex, Position}; use crate::token::{lex, Position};
use crate::utils::StaticVec;
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::engine::Map; use crate::{
engine::{make_getter, make_setter, Map},
fn_register::RegisterFn,
};
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
use crate::engine::get_script_function_by_signature; use crate::{engine::get_script_function_by_signature, fn_args::FuncArgs, utils::StaticVec};
use crate::stdlib::{ use crate::stdlib::{
any::{type_name, TypeId}, any::{type_name, TypeId},
boxed::Box, boxed::Box,
mem, mem,
string::{String, ToString},
}; };
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
@ -293,7 +296,7 @@ impl Engine {
self.type_names self.type_names
.as_mut() .as_mut()
.unwrap() .unwrap()
.insert(type_name::<T>().to_string(), name.to_string()); .insert(type_name::<T>().into(), name.into());
self self
} }

View File

@ -1,13 +1,13 @@
//! Main module defining the script evaluation `Engine`. //! Main module defining the script evaluation `Engine`.
use crate::any::{map_std_type_name, Dynamic, Union, Variant}; use crate::any::{map_std_type_name, Dynamic, Union};
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::fn_call::run_builtin_op_assignment; use crate::fn_call::run_builtin_op_assignment;
use crate::fn_native::{CallableFunction, Callback, FnPtr}; use crate::fn_native::{CallableFunction, Callback, FnPtr};
use crate::module::{resolvers, Module, ModuleRef, ModuleResolver}; use crate::module::{Module, ModuleRef};
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::packages::{Package, PackagesCollection, StandardPackage}; use crate::packages::{Package, PackagesCollection, StandardPackage};
use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, Stmt}; use crate::parser::{Expr, ReturnType, Stmt};
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime; use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope}; use crate::scope::{EntryType as ScopeEntryType, Scope};
@ -15,8 +15,23 @@ use crate::syntax::{CustomSyntax, EvalContext};
use crate::token::Position; use crate::token::Position;
use crate::utils::StaticVec; use crate::utils::StaticVec;
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
use crate::any::Variant;
#[cfg(not(feature = "no_function"))]
use crate::parser::{FnAccess, ScriptFnDef};
#[cfg(not(feature = "no_module"))]
use crate::module::ModuleResolver;
#[cfg(not(feature = "no_std"))]
#[cfg(not(feature = "no_module"))]
use crate::module::resolvers;
#[cfg(any(not(feature = "no_object"), not(feature = "no_module")))]
use crate::utils::ImmutableString;
use crate::stdlib::{ use crate::stdlib::{
any::TypeId,
borrow::Cow, borrow::Cow,
boxed::Box, boxed::Box,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -26,6 +41,9 @@ use crate::stdlib::{
vec::Vec, vec::Vec,
}; };
#[cfg(not(feature = "no_index"))]
use crate::stdlib::any::TypeId;
/// Variable-sized array of `Dynamic` values. /// Variable-sized array of `Dynamic` values.
/// ///
/// Not available under the `no_index` feature. /// Not available under the `no_index` feature.
@ -66,13 +84,6 @@ pub const MAX_EXPR_DEPTH: usize = 128;
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32; pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
#[cfg(feature = "unchecked")]
pub const MAX_CALL_STACK_DEPTH: usize = usize::MAX;
#[cfg(feature = "unchecked")]
pub const MAX_EXPR_DEPTH: usize = 0;
#[cfg(feature = "unchecked")]
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 0;
pub const KEYWORD_PRINT: &str = "print"; pub const KEYWORD_PRINT: &str = "print";
pub const KEYWORD_DEBUG: &str = "debug"; pub const KEYWORD_DEBUG: &str = "debug";
pub const KEYWORD_TYPE_OF: &str = "type_of"; pub const KEYWORD_TYPE_OF: &str = "type_of";
@ -82,16 +93,22 @@ pub const KEYWORD_FN_PTR_CALL: &str = "call";
pub const KEYWORD_FN_PTR_CURRY: &str = "curry"; pub const KEYWORD_FN_PTR_CURRY: &str = "curry";
pub const KEYWORD_THIS: &str = "this"; pub const KEYWORD_THIS: &str = "this";
pub const FN_TO_STRING: &str = "to_string"; pub const FN_TO_STRING: &str = "to_string";
#[cfg(not(feature = "no_object"))]
pub const FN_GET: &str = "get$"; pub const FN_GET: &str = "get$";
#[cfg(not(feature = "no_object"))]
pub const FN_SET: &str = "set$"; pub const FN_SET: &str = "set$";
#[cfg(not(feature = "no_index"))]
pub const FN_IDX_GET: &str = "index$get$"; pub const FN_IDX_GET: &str = "index$get$";
#[cfg(not(feature = "no_index"))]
pub const FN_IDX_SET: &str = "index$set$"; pub const FN_IDX_SET: &str = "index$set$";
#[cfg(not(feature = "no_function"))]
pub const FN_ANONYMOUS: &str = "anon$"; pub const FN_ANONYMOUS: &str = "anon$";
pub const MARKER_EXPR: &str = "$expr$"; pub const MARKER_EXPR: &str = "$expr$";
pub const MARKER_BLOCK: &str = "$block$"; pub const MARKER_BLOCK: &str = "$block$";
pub const MARKER_IDENT: &str = "$ident$"; pub const MARKER_IDENT: &str = "$ident$";
/// A type specifying the method of chaining. /// A type specifying the method of chaining.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ChainType { pub enum ChainType {
None, None,
@ -100,6 +117,7 @@ pub enum ChainType {
} }
/// A type that encapsulates a mutation target for an expression with side effects. /// A type that encapsulates a mutation target for an expression with side effects.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[derive(Debug)] #[derive(Debug)]
pub enum Target<'a> { pub enum Target<'a> {
/// The target is a mutable reference to a `Dynamic` value somewhere. /// The target is a mutable reference to a `Dynamic` value somewhere.
@ -108,15 +126,19 @@ pub enum Target<'a> {
Value(Dynamic), Value(Dynamic),
/// The target is a character inside a String. /// The target is a character inside a String.
/// This is necessary because directly pointing to a char inside a String is impossible. /// This is necessary because directly pointing to a char inside a String is impossible.
#[cfg(not(feature = "no_index"))]
StringChar(&'a mut Dynamic, usize, Dynamic), StringChar(&'a mut Dynamic, usize, Dynamic),
} }
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl Target<'_> { impl Target<'_> {
/// Is the `Target` a reference pointing to other data? /// Is the `Target` a reference pointing to other data?
pub fn is_ref(&self) -> bool { pub fn is_ref(&self) -> bool {
match self { match self {
Self::Ref(_) => true, Self::Ref(_) => true,
Self::Value(_) | Self::StringChar(_, _, _) => false, Self::Value(_) => false,
#[cfg(not(feature = "no_index"))]
Self::StringChar(_, _, _) => false,
} }
} }
/// Is the `Target` an owned value? /// Is the `Target` an owned value?
@ -124,14 +146,17 @@ impl Target<'_> {
match self { match self {
Self::Ref(_) => false, Self::Ref(_) => false,
Self::Value(_) => true, Self::Value(_) => true,
#[cfg(not(feature = "no_index"))]
Self::StringChar(_, _, _) => false, Self::StringChar(_, _, _) => false,
} }
} }
/// Is the `Target` a specific type? /// Is the `Target` a specific type?
#[allow(dead_code)]
pub fn is<T: Variant + Clone>(&self) -> bool { pub fn is<T: Variant + Clone>(&self) -> bool {
match self { match self {
Target::Ref(r) => r.is::<T>(), Target::Ref(r) => r.is::<T>(),
Target::Value(r) => r.is::<T>(), Target::Value(r) => r.is::<T>(),
#[cfg(not(feature = "no_index"))]
Target::StringChar(_, _, _) => TypeId::of::<T>() == TypeId::of::<char>(), Target::StringChar(_, _, _) => TypeId::of::<T>() == TypeId::of::<char>(),
} }
} }
@ -140,6 +165,7 @@ impl Target<'_> {
match self { match self {
Self::Ref(r) => r.clone(), // Referenced value is cloned Self::Ref(r) => r.clone(), // Referenced value is cloned
Self::Value(v) => v, // Owned value is simply taken Self::Value(v) => v, // Owned value is simply taken
#[cfg(not(feature = "no_index"))]
Self::StringChar(_, _, ch) => ch, // Character is taken Self::StringChar(_, _, ch) => ch, // Character is taken
} }
} }
@ -148,6 +174,7 @@ impl Target<'_> {
match self { match self {
Self::Ref(r) => *r, Self::Ref(r) => *r,
Self::Value(ref mut r) => r, Self::Value(ref mut r) => r,
#[cfg(not(feature = "no_index"))]
Self::StringChar(_, _, ref mut r) => r, Self::StringChar(_, _, ref mut r) => r,
} }
} }
@ -161,6 +188,7 @@ impl Target<'_> {
Position::none(), Position::none(),
))) )))
} }
#[cfg(not(feature = "no_index"))]
Self::StringChar(Dynamic(Union::Str(ref mut s)), index, _) => { Self::StringChar(Dynamic(Union::Str(ref mut s)), index, _) => {
// Replace the character at the specified index position // Replace the character at the specified index position
let new_ch = new_val let new_ch = new_val
@ -176,18 +204,21 @@ impl Target<'_> {
*s = chars.iter().collect::<String>().into(); *s = chars.iter().collect::<String>().into();
} }
} }
_ => unreachable!(), #[cfg(not(feature = "no_index"))]
Self::StringChar(_, _, _) => unreachable!(),
} }
Ok(()) Ok(())
} }
} }
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl<'a> From<&'a mut Dynamic> for Target<'a> { impl<'a> From<&'a mut Dynamic> for Target<'a> {
fn from(value: &'a mut Dynamic) -> Self { fn from(value: &'a mut Dynamic) -> Self {
Self::Ref(value) Self::Ref(value)
} }
} }
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl<T: Into<Dynamic>> From<T> for Target<'_> { impl<T: Into<Dynamic>> From<T> for Target<'_> {
fn from(value: T) -> Self { fn from(value: T) -> Self {
Self::Value(value.into()) Self::Value(value.into())
@ -249,6 +280,34 @@ pub fn get_script_function_by_signature<'a>(
} }
} }
/// [INTERNALS] A type containing all the limits imposed by the `Engine`.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[cfg(not(feature = "unchecked"))]
pub struct Limits {
/// Maximum levels of call-stack to prevent infinite recursion.
///
/// Defaults to 16 for debug builds and 128 for non-debug builds.
pub max_call_stack_depth: usize,
/// Maximum depth of statements/expressions at global level.
pub max_expr_depth: usize,
/// Maximum depth of statements/expressions in functions.
pub max_function_expr_depth: usize,
/// Maximum number of operations allowed to run.
pub max_operations: u64,
/// Maximum number of modules allowed to load.
pub max_modules: usize,
/// Maximum length of a string.
pub max_string_size: usize,
/// Maximum length of an array.
pub max_array_size: usize,
/// Maximum number of properties in a map.
pub max_map_size: usize,
}
/// Rhai main scripting engine. /// Rhai main scripting engine.
/// ///
/// ``` /// ```
@ -275,6 +334,7 @@ pub struct Engine {
pub(crate) packages: PackagesCollection, pub(crate) packages: PackagesCollection,
/// A module resolution service. /// A module resolution service.
#[cfg(not(feature = "no_module"))]
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>, pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
/// A hashmap mapping type names to pretty-print names. /// A hashmap mapping type names to pretty-print names.
@ -296,24 +356,10 @@ pub struct Engine {
/// Optimize the AST after compilation. /// Optimize the AST after compilation.
pub(crate) optimization_level: OptimizationLevel, pub(crate) optimization_level: OptimizationLevel,
/// Maximum levels of call-stack to prevent infinite recursion.
/// /// Max limits.
/// Defaults to 16 for debug builds and 128 for non-debug builds. #[cfg(not(feature = "unchecked"))]
pub(crate) max_call_stack_depth: usize, pub(crate) limits: Limits,
/// Maximum depth of statements/expressions at global level.
pub(crate) max_expr_depth: usize,
/// Maximum depth of statements/expressions in functions.
pub(crate) max_function_expr_depth: usize,
/// Maximum number of operations allowed to run.
pub(crate) max_operations: u64,
/// Maximum number of modules allowed to load.
pub(crate) max_modules: usize,
/// Maximum length of a string.
pub(crate) max_string_size: usize,
/// Maximum length of an array.
pub(crate) max_array_size: usize,
/// Maximum number of properties in a map.
pub(crate) max_map_size: usize,
} }
impl fmt::Debug for Engine { impl fmt::Debug for Engine {
@ -338,7 +384,8 @@ impl Default for Engine {
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())), module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
#[cfg(any(feature = "no_module", feature = "no_std", target_arch = "wasm32",))] #[cfg(not(feature = "no_module"))]
#[cfg(any(feature = "no_std", target_arch = "wasm32",))]
module_resolver: None, module_resolver: None,
type_names: None, type_names: None,
@ -360,6 +407,8 @@ impl Default for Engine {
#[cfg(not(feature = "no_optimize"))] #[cfg(not(feature = "no_optimize"))]
optimization_level: OptimizationLevel::Simple, optimization_level: OptimizationLevel::Simple,
#[cfg(not(feature = "unchecked"))]
limits: Limits {
max_call_stack_depth: MAX_CALL_STACK_DEPTH, max_call_stack_depth: MAX_CALL_STACK_DEPTH,
max_expr_depth: MAX_EXPR_DEPTH, max_expr_depth: MAX_EXPR_DEPTH,
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH, max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
@ -368,6 +417,7 @@ impl Default for Engine {
max_string_size: 0, max_string_size: 0,
max_array_size: 0, max_array_size: 0,
max_map_size: 0, max_map_size: 0,
},
}; };
engine.load_package(StandardPackage::new().get()); engine.load_package(StandardPackage::new().get());
@ -377,20 +427,24 @@ impl Default for Engine {
} }
/// Make getter function /// Make getter function
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn make_getter(id: &str) -> String { pub fn make_getter(id: &str) -> String {
format!("{}{}", FN_GET, id) format!("{}{}", FN_GET, id)
} }
/// Make setter function /// Make setter function
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn make_setter(id: &str) -> String { pub fn make_setter(id: &str) -> String {
format!("{}{}", FN_SET, id) format!("{}{}", FN_SET, id)
} }
/// Print/debug to stdout /// Print/debug to stdout
fn default_print(s: &str) { fn default_print(_s: &str) {
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
println!("{}", s); println!("{}", _s);
} }
/// Search for a module within an imports stack. /// Search for a module within an imports stack.
@ -546,6 +600,8 @@ impl Engine {
packages: Default::default(), packages: Default::default(),
global_module: Default::default(), global_module: Default::default(),
#[cfg(not(feature = "no_module"))]
module_resolver: None, module_resolver: None,
type_names: None, type_names: None,
@ -563,6 +619,8 @@ impl Engine {
#[cfg(not(feature = "no_optimize"))] #[cfg(not(feature = "no_optimize"))]
optimization_level: OptimizationLevel::Simple, optimization_level: OptimizationLevel::Simple,
#[cfg(not(feature = "unchecked"))]
limits: Limits {
max_call_stack_depth: MAX_CALL_STACK_DEPTH, max_call_stack_depth: MAX_CALL_STACK_DEPTH,
max_expr_depth: MAX_EXPR_DEPTH, max_expr_depth: MAX_EXPR_DEPTH,
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH, max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
@ -571,11 +629,13 @@ impl Engine {
max_string_size: 0, max_string_size: 0,
max_array_size: 0, max_array_size: 0,
max_map_size: 0, max_map_size: 0,
},
} }
} }
/// Chain-evaluate a dot/index chain. /// Chain-evaluate a dot/index chain.
/// Position in `EvalAltResult` is `None` and must be set afterwards. /// Position in `EvalAltResult` is `None` and must be set afterwards.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn eval_dot_index_chain_helper( fn eval_dot_index_chain_helper(
&self, &self,
state: &mut State, state: &mut State,
@ -586,7 +646,7 @@ impl Engine {
idx_values: &mut StaticVec<Dynamic>, idx_values: &mut StaticVec<Dynamic>,
chain_type: ChainType, chain_type: ChainType,
level: usize, level: usize,
mut new_val: Option<Dynamic>, mut _new_val: Option<Dynamic>,
) -> Result<(Dynamic, bool), Box<EvalAltResult>> { ) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
if chain_type == ChainType::None { if chain_type == ChainType::None {
panic!(); panic!();
@ -618,18 +678,19 @@ impl Engine {
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level, state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
new_val, _new_val,
) )
.map_err(|err| err.new_position(*pos)) .map_err(|err| err.new_position(*pos))
} }
// xxx[rhs] = new_val // xxx[rhs] = new_val
_ if new_val.is_some() => { _ if _new_val.is_some() => {
let mut new_val = new_val.unwrap(); let mut new_val = _new_val.unwrap();
let mut idx_val2 = idx_val.clone(); let mut idx_val2 = idx_val.clone();
match self.get_indexed_mut(state, lib, target, idx_val, pos, true, level) { match self.get_indexed_mut(state, lib, target, idx_val, pos, true, level) {
// Indexed value is an owned value - the only possibility is an indexer // Indexed value is an owned value - the only possibility is an indexer
// Try to call an index setter // Try to call an index setter
#[cfg(not(feature = "no_index"))]
Ok(obj_ptr) if obj_ptr.is_value() => { Ok(obj_ptr) if obj_ptr.is_value() => {
let args = &mut [target.as_mut(), &mut idx_val2, &mut new_val]; let args = &mut [target.as_mut(), &mut idx_val2, &mut new_val];
@ -653,6 +714,7 @@ impl Engine {
} }
Err(err) => match *err { Err(err) => match *err {
// No index getter - try to call an index setter // No index getter - try to call an index setter
#[cfg(not(feature = "no_index"))]
EvalAltResult::ErrorIndexingType(_, _) => { EvalAltResult::ErrorIndexingType(_, _) => {
let args = &mut [target.as_mut(), &mut idx_val2, &mut new_val]; let args = &mut [target.as_mut(), &mut idx_val2, &mut new_val];
@ -684,13 +746,13 @@ impl Engine {
// xxx.module::fn_name(...) - syntax error // xxx.module::fn_name(...) - syntax error
Expr::FnCall(_) => unreachable!(), Expr::FnCall(_) => unreachable!(),
// {xxx:map}.id = ??? // {xxx:map}.id = ???
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => { Expr::Property(x) if target.is::<Map>() && _new_val.is_some() => {
let ((prop, _, _), pos) = x.as_ref(); let ((prop, _, _), pos) = x.as_ref();
let index = prop.clone().into(); let index = prop.clone().into();
let mut val = let mut val =
self.get_indexed_mut(state, lib, target, index, *pos, true, level)?; self.get_indexed_mut(state, lib, target, index, *pos, true, level)?;
val.set_value(new_val.unwrap()) val.set_value(_new_val.unwrap())
.map_err(|err| err.new_position(rhs.position()))?; .map_err(|err| err.new_position(rhs.position()))?;
Ok((Default::default(), true)) Ok((Default::default(), true))
} }
@ -704,9 +766,9 @@ impl Engine {
Ok((val.clone_into_dynamic(), false)) Ok((val.clone_into_dynamic(), false))
} }
// xxx.id = ??? // xxx.id = ???
Expr::Property(x) if new_val.is_some() => { Expr::Property(x) if _new_val.is_some() => {
let ((_, _, setter), pos) = x.as_ref(); let ((_, _, setter), pos) = x.as_ref();
let mut args = [target.as_mut(), new_val.as_mut().unwrap()]; let mut args = [target.as_mut(), _new_val.as_mut().unwrap()];
self.exec_fn_call( self.exec_fn_call(
state, lib, setter, true, 0, &mut args, is_ref, true, None, level, state, lib, setter, true, 0, &mut args, is_ref, true, None, level,
) )
@ -748,7 +810,7 @@ impl Engine {
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level, state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level,
new_val, _new_val,
) )
.map_err(|err| err.new_position(*pos)) .map_err(|err| err.new_position(*pos))
} }
@ -775,7 +837,7 @@ impl Engine {
let (result, may_be_changed) = self let (result, may_be_changed) = self
.eval_dot_index_chain_helper( .eval_dot_index_chain_helper(
state, lib, this_ptr, target, expr, idx_values, next_chain, state, lib, this_ptr, target, expr, idx_values, next_chain,
level, new_val, level, _new_val,
) )
.map_err(|err| err.new_position(*pos))?; .map_err(|err| err.new_position(*pos))?;
@ -810,7 +872,7 @@ impl Engine {
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
state, lib, this_ptr, target, expr, idx_values, next_chain, state, lib, this_ptr, target, expr, idx_values, next_chain,
level, new_val, level, _new_val,
) )
.map_err(|err| err.new_position(*pos)) .map_err(|err| err.new_position(*pos))
} }
@ -833,6 +895,7 @@ impl Engine {
} }
/// Evaluate a dot/index chain. /// Evaluate a dot/index chain.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn eval_dot_index_chain( fn eval_dot_index_chain(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
@ -909,6 +972,7 @@ impl Engine {
/// Any spill-overs are stored in `more`, which is dynamic. /// Any spill-overs are stored in `more`, which is dynamic.
/// The fixed length array is used to avoid an allocation in the overwhelming cases of just a few levels of indexing. /// The fixed length array is used to avoid an allocation in the overwhelming cases of just a few levels of indexing.
/// The total number of values is returned. /// The total number of values is returned.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn eval_indexed_chain( fn eval_indexed_chain(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
@ -979,26 +1043,30 @@ impl Engine {
/// Get the value at the indexed position of a base type /// Get the value at the indexed position of a base type
/// Position in `EvalAltResult` may be None and should be set afterwards. /// Position in `EvalAltResult` may be None and should be set afterwards.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn get_indexed_mut<'a>( fn get_indexed_mut<'a>(
&self, &self,
state: &mut State, state: &mut State,
lib: &Module, _lib: &Module,
target: &'a mut Target, target: &'a mut Target,
mut idx: Dynamic, mut _idx: Dynamic,
idx_pos: Position, idx_pos: Position,
create: bool, _create: bool,
level: usize, _level: usize,
) -> Result<Target<'a>, Box<EvalAltResult>> { ) -> Result<Target<'a>, Box<EvalAltResult>> {
self.inc_operations(state)?; self.inc_operations(state)?;
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
let is_ref = target.is_ref(); let is_ref = target.is_ref();
let val = target.as_mut(); let val = target.as_mut();
match val { match val {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Dynamic(Union::Array(arr)) => { Dynamic(Union::Array(arr)) => {
// val_array[idx] // val_array[idx]
let index = idx let index = _idx
.as_int() .as_int()
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?; .map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
@ -1020,14 +1088,14 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Dynamic(Union::Map(map)) => { Dynamic(Union::Map(map)) => {
// val_map[idx] // val_map[idx]
Ok(if create { Ok(if _create {
let index = idx let index = _idx
.take_immutable_string() .take_immutable_string()
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_pos))?; .map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
map.entry(index).or_insert(Default::default()).into() map.entry(index).or_insert(Default::default()).into()
} else { } else {
let index = idx let index = _idx
.downcast_ref::<ImmutableString>() .downcast_ref::<ImmutableString>()
.ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?; .ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
@ -1041,7 +1109,7 @@ impl Engine {
Dynamic(Union::Str(s)) => { Dynamic(Union::Str(s)) => {
// val_string[idx] // val_string[idx]
let chars_len = s.chars().count(); let chars_len = s.chars().count();
let index = idx let index = _idx
.as_int() .as_int()
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?; .map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
@ -1062,9 +1130,9 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
_ => { _ => {
let type_name = val.type_name(); let type_name = val.type_name();
let args = &mut [val, &mut idx]; let args = &mut [val, &mut _idx];
self.exec_fn_call( self.exec_fn_call(
state, lib, FN_IDX_GET, true, 0, args, is_ref, true, None, level, state, _lib, FN_IDX_GET, true, 0, args, is_ref, true, None, _level,
) )
.map(|(v, _)| v.into()) .map(|(v, _)| v.into())
.map_err(|err| match *err { .map_err(|err| match *err {
@ -1075,7 +1143,7 @@ impl Engine {
}) })
} }
#[cfg(feature = "no_index")] #[cfg(any(feature = "no_index", feature = "no_object"))]
_ => Err(Box::new(EvalAltResult::ErrorIndexingType( _ => Err(Box::new(EvalAltResult::ErrorIndexingType(
self.map_type_name(val.type_name()).into(), self.map_type_name(val.type_name()).into(),
Position::none(), Position::none(),
@ -1252,7 +1320,7 @@ impl Engine {
let mut rhs_val = let mut rhs_val =
self.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?; self.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?;
let new_val = Some(if op.is_empty() { let _new_val = Some(if op.is_empty() {
// Normal assignment // Normal assignment
rhs_val rhs_val
} else { } else {
@ -1275,7 +1343,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Expr::Index(_) => { Expr::Index(_) => {
self.eval_dot_index_chain( self.eval_dot_index_chain(
scope, mods, state, lib, this_ptr, lhs_expr, level, new_val, scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
)?; )?;
Ok(Default::default()) Ok(Default::default())
} }
@ -1283,7 +1351,7 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Dot(_) => { Expr::Dot(_) => {
self.eval_dot_index_chain( self.eval_dot_index_chain(
scope, mods, state, lib, this_ptr, lhs_expr, level, new_val, scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
)?; )?;
Ok(Default::default()) Ok(Default::default())
} }
@ -1639,19 +1707,20 @@ impl Engine {
Stmt::Const(_) => unreachable!(), Stmt::Const(_) => unreachable!(),
// Import statement // Import statement
#[cfg(not(feature = "no_module"))]
Stmt::Import(x) => { Stmt::Import(x) => {
let (expr, (name, pos)) = x.as_ref(); let (expr, (name, _pos)) = x.as_ref();
// Guard against too many modules // Guard against too many modules
if state.modules >= self.max_modules { #[cfg(not(feature = "unchecked"))]
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*pos))); if state.modules >= self.limits.max_modules {
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*_pos)));
} }
if let Some(path) = self if let Some(path) = self
.eval_expr(scope, mods, state, lib, this_ptr, &expr, level)? .eval_expr(scope, mods, state, lib, this_ptr, &expr, level)?
.try_cast::<ImmutableString>() .try_cast::<ImmutableString>()
{ {
#[cfg(not(feature = "no_module"))]
if let Some(resolver) = &self.module_resolver { if let Some(resolver) = &self.module_resolver {
let mut module = resolver.resolve(self, &path, expr.position())?; let mut module = resolver.resolve(self, &path, expr.position())?;
module.index_all_sub_modules(); module.index_all_sub_modules();
@ -1666,15 +1735,13 @@ impl Engine {
expr.position(), expr.position(),
))) )))
} }
#[cfg(feature = "no_module")]
Ok(Default::default())
} else { } else {
Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position()))) Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position())))
} }
} }
// Export statement // Export statement
#[cfg(not(feature = "no_module"))]
Stmt::Export(list) => { Stmt::Export(list) => {
for ((id, id_pos), rename) in list.iter() { for ((id, id_pos), rename) in list.iter() {
// Mark scope variables as public // Mark scope variables as public
@ -1696,8 +1763,18 @@ impl Engine {
.map_err(|err| err.new_position(stmt.position())) .map_err(|err| err.new_position(stmt.position()))
} }
#[cfg(feature = "unchecked")]
#[inline(always)]
fn check_data_size(
&self,
result: Result<Dynamic, Box<EvalAltResult>>,
) -> Result<Dynamic, Box<EvalAltResult>> {
return result;
}
/// Check a result to ensure that the data size is within allowable limit. /// Check a result to ensure that the data size is within allowable limit.
/// Position in `EvalAltResult` may be None and should be set afterwards. /// Position in `EvalAltResult` may be None and should be set afterwards.
#[cfg(not(feature = "unchecked"))]
fn check_data_size( fn check_data_size(
&self, &self,
result: Result<Dynamic, Box<EvalAltResult>>, result: Result<Dynamic, Box<EvalAltResult>>,
@ -1706,7 +1783,8 @@ impl Engine {
return result; return result;
// If no data size limits, just return // If no data size limits, just return
if self.max_string_size + self.max_array_size + self.max_map_size == 0 { if self.limits.max_string_size + self.limits.max_array_size + self.limits.max_map_size == 0
{
return result; return result;
} }
@ -1766,37 +1844,37 @@ impl Engine {
// Simply return all errors // Simply return all errors
Err(_) => return result, Err(_) => return result,
// String with limit // String with limit
Ok(Dynamic(Union::Str(_))) if self.max_string_size > 0 => (), Ok(Dynamic(Union::Str(_))) if self.limits.max_string_size > 0 => (),
// Array with limit // Array with limit
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Ok(Dynamic(Union::Array(_))) if self.max_array_size > 0 => (), Ok(Dynamic(Union::Array(_))) if self.limits.max_array_size > 0 => (),
// Map with limit // Map with limit
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Ok(Dynamic(Union::Map(_))) if self.max_map_size > 0 => (), Ok(Dynamic(Union::Map(_))) if self.limits.max_map_size > 0 => (),
// Everything else is simply returned // Everything else is simply returned
Ok(_) => return result, Ok(_) => return result,
}; };
let (arr, map, s) = calc_size(result.as_ref().unwrap()); let (arr, map, s) = calc_size(result.as_ref().unwrap());
if s > self.max_string_size { if s > self.limits.max_string_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge( Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
self.max_string_size, self.limits.max_string_size,
s, s,
Position::none(), Position::none(),
))) )))
} else if arr > self.max_array_size { } else if arr > self.limits.max_array_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge( Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(), "Size of array".to_string(),
self.max_array_size, self.limits.max_array_size,
arr, arr,
Position::none(), Position::none(),
))) )))
} else if map > self.max_map_size { } else if map > self.limits.max_map_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge( Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Number of properties in object map".to_string(), "Number of properties in object map".to_string(),
self.max_map_size, self.limits.max_map_size,
map, map,
Position::none(), Position::none(),
))) )))
@ -1812,7 +1890,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
// Guard against too many operations // Guard against too many operations
if self.max_operations > 0 && state.operations > self.max_operations { if self.limits.max_operations > 0 && state.operations > self.limits.max_operations {
return Err(Box::new(EvalAltResult::ErrorTooManyOperations( return Err(Box::new(EvalAltResult::ErrorTooManyOperations(
Position::none(), Position::none(),
))); )));

View File

@ -22,11 +22,10 @@ macro_rules! impl_args {
fn into_vec(self) -> StaticVec<Dynamic> { fn into_vec(self) -> StaticVec<Dynamic> {
let ($($p,)*) = self; let ($($p,)*) = self;
#[allow(unused_mut)] let mut _v = StaticVec::new();
let mut v = StaticVec::new(); $(_v.push($p.into_dynamic());)*
$(v.push($p.into_dynamic());)*
v _v
} }
} }

View File

@ -3,26 +3,34 @@
use crate::any::Dynamic; use crate::any::Dynamic;
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::engine::{ use crate::engine::{
search_imports, search_namespace, search_scope_only, Engine, Imports, State, Target, FN_GET, search_imports, search_namespace, search_scope_only, Engine, Imports, State, KEYWORD_DEBUG,
FN_IDX_GET, FN_IDX_SET, FN_SET, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_PRINT,
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_PRINT, KEYWORD_TYPE_OF, KEYWORD_TYPE_OF,
}; };
use crate::error::ParseErrorType; use crate::error::ParseErrorType;
use crate::fn_native::{FnCallArgs, FnPtr}; use crate::fn_native::{FnCallArgs, FnPtr};
use crate::module::{Module, ModuleRef}; use crate::module::{Module, ModuleRef};
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::parser::{Expr, ImmutableString, ScriptFnDef, AST, INT}; use crate::parser::{Expr, ImmutableString, AST, INT};
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope}; use crate::scope::Scope;
use crate::token::Position; use crate::token::Position;
use crate::utils::StaticVec; use crate::utils::StaticVec;
#[cfg(not(feature = "no_function"))]
use crate::{
parser::ScriptFnDef, r#unsafe::unsafe_cast_var_name_to_lifetime,
scope::EntryType as ScopeEntryType,
};
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::parser::FLOAT;
#[cfg(not(feature = "no_index"))]
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::engine::Map; use crate::engine::{Map, Target, FN_GET, FN_SET};
use crate::stdlib::{ use crate::stdlib::{
any::{type_name, TypeId}, any::{type_name, TypeId},
@ -36,20 +44,22 @@ use crate::stdlib::{
}; };
/// Extract the property name from a getter function name. /// Extract the property name from a getter function name.
fn extract_prop_from_getter(fn_name: &str) -> Option<&str> { #[inline(always)]
fn extract_prop_from_getter(_fn_name: &str) -> Option<&str> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
if fn_name.starts_with(FN_GET) { if _fn_name.starts_with(FN_GET) {
return Some(&fn_name[FN_GET.len()..]); return Some(&_fn_name[FN_GET.len()..]);
} }
None None
} }
/// Extract the property name from a setter function name. /// Extract the property name from a setter function name.
fn extract_prop_from_setter(fn_name: &str) -> Option<&str> { #[inline(always)]
fn extract_prop_from_setter(_fn_name: &str) -> Option<&str> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
if fn_name.starts_with(FN_SET) { if _fn_name.starts_with(FN_SET) {
return Some(&fn_name[FN_SET.len()..]); return Some(&_fn_name[FN_SET.len()..]);
} }
None None
@ -106,17 +116,17 @@ impl Engine {
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`! /// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
pub(crate) fn call_fn_raw( pub(crate) fn call_fn_raw(
&self, &self,
scope: &mut Scope, _scope: &mut Scope,
mods: &mut Imports, _mods: &mut Imports,
state: &mut State, state: &mut State,
lib: &Module, lib: &Module,
fn_name: &str, fn_name: &str,
(hash_fn, hash_script): (u64, u64), (hash_fn, hash_script): (u64, u64),
args: &mut FnCallArgs, args: &mut FnCallArgs,
is_ref: bool, is_ref: bool,
is_method: bool, _is_method: bool,
def_val: Option<bool>, def_val: Option<bool>,
level: usize, _level: usize,
) -> Result<(Dynamic, bool), Box<EvalAltResult>> { ) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
self.inc_operations(state)?; self.inc_operations(state)?;
@ -125,7 +135,7 @@ impl Engine {
// Check for stack overflow // Check for stack overflow
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if level > self.max_call_stack_depth { if _level > self.limits.max_call_stack_depth {
return Err(Box::new( return Err(Box::new(
EvalAltResult::ErrorStackOverflow(Position::none()), EvalAltResult::ErrorStackOverflow(Position::none()),
)); ));
@ -151,7 +161,7 @@ impl Engine {
if let Some(func) = func { if let Some(func) = func {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let need_normalize = is_ref && (func.is_pure() || (func.is_script() && !is_method)); let need_normalize = is_ref && (func.is_pure() || (func.is_script() && !_is_method));
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]
let need_normalize = is_ref && func.is_pure(); let need_normalize = is_ref && func.is_pure();
@ -164,25 +174,25 @@ impl Engine {
let fn_def = func.get_fn_def(); let fn_def = func.get_fn_def();
// Method call of script function - map first argument to `this` // Method call of script function - map first argument to `this`
return if is_method { return if _is_method {
let (first, rest) = args.split_at_mut(1); let (first, rest) = args.split_at_mut(1);
Ok(( Ok((
self.call_script_fn( self.call_script_fn(
scope, _scope,
mods, _mods,
state, state,
lib, lib,
&mut Some(first[0]), &mut Some(first[0]),
fn_name, fn_name,
fn_def, fn_def,
rest, rest,
level, _level,
)?, )?,
false, false,
)) ))
} else { } else {
let result = self.call_script_fn( let result = self.call_script_fn(
scope, mods, state, lib, &mut None, fn_name, fn_def, args, level, _scope, _mods, state, lib, &mut None, fn_name, fn_def, args, _level,
)?; )?;
// Restore the original reference // Restore the original reference
@ -256,6 +266,7 @@ impl Engine {
} }
// index getter function not found? // index getter function not found?
#[cfg(not(feature = "no_index"))]
if fn_name == FN_IDX_GET && args.len() == 2 { if fn_name == FN_IDX_GET && args.len() == 2 {
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound( return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
format!( format!(
@ -268,6 +279,7 @@ impl Engine {
} }
// index setter function not found? // index setter function not found?
#[cfg(not(feature = "no_index"))]
if fn_name == FN_IDX_SET { if fn_name == FN_IDX_SET {
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound( return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
format!( format!(
@ -305,6 +317,7 @@ impl Engine {
/// Function call arguments may be _consumed_ when the function requires them to be passed by value. /// Function call arguments may be _consumed_ when the function requires them to be passed by value.
/// All function arguments not in the first position are always passed by value and thus consumed. /// All function arguments not in the first position are always passed by value and thus consumed.
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`! /// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
#[cfg(not(feature = "no_function"))]
pub(crate) fn call_script_fn( pub(crate) fn call_script_fn(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
@ -486,6 +499,7 @@ impl Engine {
} }
/// Call a dot method. /// Call a dot method.
#[cfg(not(feature = "no_object"))]
pub(crate) fn make_method_call( pub(crate) fn make_method_call(
&self, &self,
state: &mut State, state: &mut State,
@ -506,9 +520,9 @@ impl Engine {
// Get a reference to the mutation target Dynamic // Get a reference to the mutation target Dynamic
let obj = target.as_mut(); let obj = target.as_mut();
let mut idx = idx_val.cast::<StaticVec<Dynamic>>(); let mut idx = idx_val.cast::<StaticVec<Dynamic>>();
let mut fn_name = name.as_ref(); let mut _fn_name = name.as_ref();
let (result, updated) = if fn_name == KEYWORD_FN_PTR_CALL && obj.is::<FnPtr>() { let (result, updated) = if _fn_name == KEYWORD_FN_PTR_CALL && obj.is::<FnPtr>() {
// FnPtr call // FnPtr call
let fn_ptr = obj.downcast_ref::<FnPtr>().unwrap(); let fn_ptr = obj.downcast_ref::<FnPtr>().unwrap();
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>(); let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
@ -527,7 +541,7 @@ impl Engine {
self.exec_fn_call( self.exec_fn_call(
state, lib, fn_name, *native, hash, args, false, false, *def_val, level, state, lib, fn_name, *native, hash, args, false, false, *def_val, level,
) )
} else if fn_name == KEYWORD_FN_PTR_CALL && idx.len() > 0 && idx[0].is::<FnPtr>() { } else if _fn_name == KEYWORD_FN_PTR_CALL && idx.len() > 0 && idx[0].is::<FnPtr>() {
// FnPtr call on object // FnPtr call on object
let fn_ptr = idx.remove(0).cast::<FnPtr>(); let fn_ptr = idx.remove(0).cast::<FnPtr>();
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>(); let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
@ -546,7 +560,7 @@ impl Engine {
self.exec_fn_call( self.exec_fn_call(
state, lib, &fn_name, *native, hash, args, is_ref, true, *def_val, level, state, lib, &fn_name, *native, hash, args, is_ref, true, *def_val, level,
) )
} else if fn_name == KEYWORD_FN_PTR_CURRY && obj.is::<FnPtr>() { } else if _fn_name == KEYWORD_FN_PTR_CURRY && obj.is::<FnPtr>() {
// Curry call // Curry call
let fn_ptr = obj.downcast_ref::<FnPtr>().unwrap(); let fn_ptr = obj.downcast_ref::<FnPtr>().unwrap();
Ok(( Ok((
@ -563,19 +577,20 @@ impl Engine {
false, false,
)) ))
} else { } else {
#[cfg(not(feature = "no_object"))]
let redirected; let redirected;
let mut hash = *hash; let mut _hash = *hash;
// Check if it is a map method call in OOP style // Check if it is a map method call in OOP style
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
if let Some(map) = obj.downcast_ref::<Map>() { if let Some(map) = obj.downcast_ref::<Map>() {
if let Some(val) = map.get(fn_name) { if let Some(val) = map.get(_fn_name) {
if let Some(f) = val.downcast_ref::<FnPtr>() { if let Some(f) = val.downcast_ref::<FnPtr>() {
// Remap the function name // Remap the function name
redirected = f.get_fn_name().clone(); redirected = f.get_fn_name().clone();
fn_name = &redirected; _fn_name = &redirected;
// Recalculate the hash based on the new function name // Recalculate the hash based on the new function name
hash = calc_fn_hash(empty(), fn_name, idx.len(), empty()); _hash = calc_fn_hash(empty(), _fn_name, idx.len(), empty());
} }
} }
}; };
@ -585,7 +600,7 @@ impl Engine {
let args = arg_values.as_mut(); let args = arg_values.as_mut();
self.exec_fn_call( self.exec_fn_call(
state, lib, fn_name, *native, hash, args, is_ref, true, *def_val, level, state, lib, _fn_name, *native, _hash, args, is_ref, true, *def_val, level,
) )
} }
.map_err(|err| err.new_position(*pos))?; .map_err(|err| err.new_position(*pos))?;

View File

@ -2,14 +2,18 @@
use crate::any::Dynamic; use crate::any::Dynamic;
use crate::engine::Engine; use crate::engine::Engine;
use crate::module::{FuncReturn, Module}; use crate::module::Module;
use crate::parser::ScriptFnDef;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::{is_valid_identifier, Position}; use crate::token::{is_valid_identifier, Position};
use crate::utils::{ImmutableString, StaticVec}; use crate::utils::ImmutableString;
use crate::Scope;
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, mem, string::String, vec::Vec}; #[cfg(not(feature = "no_function"))]
use crate::{module::FuncReturn, parser::ScriptFnDef, scope::Scope, utils::StaticVec};
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, string::String, vec::Vec};
#[cfg(not(feature = "no_function"))]
use crate::stdlib::mem;
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
use crate::stdlib::rc::Rc; use crate::stdlib::rc::Rc;
@ -85,12 +89,17 @@ impl FnPtr {
/// Call the function pointer with curried arguments (if any). /// Call the function pointer with curried arguments (if any).
/// ///
/// The function must be a script-defined function. It cannot be a Rust function.
///
/// To call a Rust function, just call it directly in Rust!
///
/// ## WARNING /// ## WARNING
/// ///
/// All the arguments are _consumed_, meaning that they're replaced by `()`. /// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments. /// This is to avoid unnecessarily cloning the arguments.
/// Do not use the arguments after this call. If they are needed afterwards, /// Do not use the arguments after this call. If they are needed afterwards,
/// clone them _before_ calling this function. /// clone them _before_ calling this function.
#[cfg(not(feature = "no_function"))]
pub fn call_dynamic( pub fn call_dynamic(
&self, &self,
engine: &Engine, engine: &Engine,

View File

@ -133,12 +133,11 @@ macro_rules! make_func {
Box::new(move |_: &Engine, _: &Module, args: &mut FnCallArgs| { Box::new(move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
#[allow(unused_variables, unused_mut)] let mut _drain = args.iter_mut();
let mut drain = args.iter_mut();
$( $(
// Downcast every element, panic in case of a type mismatch (which shouldn't happen). // Downcast every element, panic in case of a type mismatch (which shouldn't happen).
// Call the user-supplied function using ($convert) to access it either by value or by reference. // Call the user-supplied function using ($convert) to access it either by value or by reference.
let $par = ($convert)(drain.next().unwrap()); let $par = ($convert)(_drain.next().unwrap());
)* )*
// Call the function with each parameter value // Call the function with each parameter value

View File

@ -170,7 +170,7 @@ pub use parser::{CustomExpr, Expr, FloatWrapper, ReturnType, ScriptFnDef, Stmt};
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")] #[deprecated(note = "this type is volatile and may change")]
pub use engine::{Imports, State as EvalState}; pub use engine::{Imports, Limits, State as EvalState};
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")] #[deprecated(note = "this type is volatile and may change")]

View File

@ -2,22 +2,33 @@
use crate::any::{Dynamic, Variant}; use crate::any::{Dynamic, Variant};
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::engine::{make_getter, make_setter, Engine, Imports, FN_IDX_GET, FN_IDX_SET}; use crate::engine::Engine;
use crate::fn_native::{CallableFunction as Func, FnCallArgs, IteratorFn, SendSync, Shared}; use crate::fn_native::{CallableFunction as Func, FnCallArgs, IteratorFn, SendSync};
use crate::parser::{ use crate::parser::{FnAccess, FnAccess::Public};
FnAccess,
FnAccess::{Private, Public},
ScriptFnDef, AST,
};
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{Entry as ScopeEntry, Scope};
use crate::token::{Position, Token}; use crate::token::{Position, Token};
use crate::utils::{StaticVec, StraightHasherBuilder}; use crate::utils::{StaticVec, StraightHasherBuilder};
#[cfg(not(feature = "no_function"))]
use crate::{fn_native::Shared, parser::ScriptFnDef};
#[cfg(not(feature = "no_module"))]
use crate::{
engine::Imports,
parser::AST,
scope::{Entry as ScopeEntry, Scope},
};
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
#[cfg(not(feature = "no_object"))]
use crate::engine::{make_getter, make_setter};
use crate::stdlib::{ use crate::stdlib::{
any::TypeId, any::TypeId,
boxed::Box, boxed::Box,
cell::RefCell,
collections::HashMap, collections::HashMap,
fmt, format, fmt, format,
iter::empty, iter::empty,
@ -25,11 +36,16 @@ use crate::stdlib::{
num::NonZeroUsize, num::NonZeroUsize,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
string::{String, ToString}, string::{String, ToString},
vec,
vec::Vec, vec::Vec,
}; };
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "sync"))]
use crate::stdlib::cell::RefCell;
#[cfg(not(feature = "no_std"))]
#[cfg(not(feature = "no_module"))]
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
use crate::stdlib::sync::RwLock; use crate::stdlib::sync::RwLock;
@ -738,6 +754,8 @@ impl Module {
/// }); /// });
/// assert!(module.contains_fn(hash)); /// assert!(module.contains_fn(hash));
/// ``` /// ```
#[cfg(not(feature = "no_object"))]
#[cfg(not(feature = "no_index"))]
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>( pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
&mut self, &mut self,
func: impl Fn(&mut A, B, C) -> FuncReturn<()> + SendSync + 'static, func: impl Fn(&mut A, B, C) -> FuncReturn<()> + SendSync + 'static,
@ -781,6 +799,8 @@ impl Module {
/// assert!(module.contains_fn(hash_get)); /// assert!(module.contains_fn(hash_get));
/// assert!(module.contains_fn(hash_set)); /// assert!(module.contains_fn(hash_set));
/// ``` /// ```
#[cfg(not(feature = "no_object"))]
#[cfg(not(feature = "no_index"))]
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>( pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self, &mut self,
getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static, getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
@ -909,11 +929,11 @@ impl Module {
self.merge_filtered(other, |_, _, _| true) self.merge_filtered(other, |_, _, _| true)
} }
/// Merge another module into this module, with only selected functions based on a filter predicate. /// Merge another module into this module, with only selected script-defined functions based on a filter predicate.
pub(crate) fn merge_filtered( pub(crate) fn merge_filtered(
&mut self, &mut self,
other: &Self, other: &Self,
filter: impl Fn(FnAccess, &str, usize) -> bool, _filter: impl Fn(FnAccess, &str, usize) -> bool,
) -> &mut Self { ) -> &mut Self {
self.variables self.variables
.extend(other.variables.iter().map(|(k, v)| (k.clone(), v.clone()))); .extend(other.variables.iter().map(|(k, v)| (k.clone(), v.clone())));
@ -924,7 +944,7 @@ impl Module {
.iter() .iter()
.filter(|(_, (_, _, _, v))| match v { .filter(|(_, (_, _, _, v))| match v {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Func::Script(ref f) => filter(f.access, f.name.as_str(), f.params.len()), Func::Script(ref f) => _filter(f.access, f.name.as_str(), f.params.len()),
_ => true, _ => true,
}) })
.map(|(&k, v)| (k, v.clone())), .map(|(&k, v)| (k, v.clone())),
@ -975,6 +995,7 @@ impl Module {
} }
/// Get an iterator to the functions in the module. /// Get an iterator to the functions in the module.
#[cfg(not(feature = "no_function"))]
pub(crate) fn iter_fn( pub(crate) fn iter_fn(
&self, &self,
) -> impl Iterator<Item = &(String, FnAccess, StaticVec<TypeId>, Func)> { ) -> impl Iterator<Item = &(String, FnAccess, StaticVec<TypeId>, Func)> {
@ -1038,6 +1059,7 @@ impl Module {
/// Scan through all the sub-modules in the module build an index of all /// Scan through all the sub-modules in the module build an index of all
/// variables and external Rust functions via hashing. /// variables and external Rust functions via hashing.
#[cfg(not(feature = "no_module"))]
pub(crate) fn index_all_sub_modules(&mut self) { pub(crate) fn index_all_sub_modules(&mut self) {
// Collect a particular module. // Collect a particular module.
fn index_module<'a>( fn index_module<'a>(
@ -1063,8 +1085,8 @@ impl Module {
for (name, access, params, func) in module.functions.values() { for (name, access, params, func) in module.functions.values() {
match access { match access {
// Private functions are not exported // Private functions are not exported
Private => continue, FnAccess::Private => continue,
Public => (), FnAccess::Public => (),
} }
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
@ -1100,10 +1122,13 @@ impl Module {
return; return;
} }
let mut variables = Vec::new(); let mut qualifiers: Vec<_> = Default::default();
let mut functions = Vec::new(); let mut variables: Vec<_> = Default::default();
let mut functions: Vec<_> = Default::default();
index_module(self, &mut vec!["root"], &mut variables, &mut functions); qualifiers.push("root");
index_module(self, &mut qualifiers, &mut variables, &mut functions);
self.all_variables = variables.into_iter().collect(); self.all_variables = variables.into_iter().collect();
self.all_functions = functions.into_iter().collect(); self.all_functions = functions.into_iter().collect();

View File

@ -6,11 +6,14 @@ use crate::engine::{
Engine, Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF, Engine, Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
}; };
use crate::module::Module; use crate::module::Module;
use crate::parser::{map_dynamic_to_expr, Expr, ReturnType, ScriptFnDef, Stmt, AST}; use crate::parser::{map_dynamic_to_expr, Expr, ScriptFnDef, Stmt, AST};
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope}; use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
use crate::token::is_valid_identifier; use crate::token::is_valid_identifier;
use crate::utils::StaticVec; use crate::utils::StaticVec;
#[cfg(not(feature = "no_function"))]
use crate::parser::ReturnType;
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
use crate::parser::CustomExpr; use crate::parser::CustomExpr;
@ -249,6 +252,7 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
// let id; // let id;
stmt @ Stmt::Let(_) => stmt, stmt @ Stmt::Let(_) => stmt,
// import expr as id; // import expr as id;
#[cfg(not(feature = "no_module"))]
Stmt::Import(x) => Stmt::Import(Box::new((optimize_expr(x.0, state), x.1))), Stmt::Import(x) => Stmt::Import(Box::new((optimize_expr(x.0, state), x.1))),
// { block } // { block }
Stmt::Block(x) => { Stmt::Block(x) => {
@ -290,6 +294,7 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
match expr { match expr {
Stmt::Let(x) if x.1.is_none() => removed = true, Stmt::Let(x) if x.1.is_none() => removed = true,
Stmt::Let(x) if x.1.is_some() => removed = x.1.unwrap().is_pure(), Stmt::Let(x) if x.1.is_some() => removed = x.1.unwrap().is_pure(),
#[cfg(not(feature = "no_module"))]
Stmt::Import(x) => removed = x.0.is_pure(), Stmt::Import(x) => removed = x.0.is_pure(),
_ => { _ => {
result.push(expr); result.push(expr);
@ -345,8 +350,11 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
state.set_dirty(); state.set_dirty();
Stmt::Noop(pos) Stmt::Noop(pos)
} }
// Only one let/import statement - leave it alone // Only one let statement - leave it alone
[Stmt::Let(_)] | [Stmt::Import(_)] => Stmt::Block(Box::new((result.into(), pos))), [Stmt::Let(_)] => Stmt::Block(Box::new((result.into(), pos))),
// Only one import statement - leave it alone
#[cfg(not(feature = "no_module"))]
[Stmt::Import(_)] => Stmt::Block(Box::new((result.into(), pos))),
// Only one statement - promote // Only one statement - promote
[_] => { [_] => {
state.set_dirty(); state.set_dirty();
@ -557,16 +565,16 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// First search in functions lib (can override built-in) // First search in functions lib (can override built-in)
// Cater for both normal function call style and method call style (one additional arguments) // Cater for both normal function call style and method call style (one additional arguments)
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let has_script_fn = state.lib.iter_fn().find(|(_, _, _, f)| { let _has_script_fn = state.lib.iter_fn().find(|(_, _, _, f)| {
if !f.is_script() { return false; } if !f.is_script() { return false; }
let fn_def = f.get_fn_def(); let fn_def = f.get_fn_def();
fn_def.name.as_str() == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len()) fn_def.name.as_str() == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len())
}).is_some(); }).is_some();
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]
const has_script_fn: bool = false; let _has_script_fn: bool = false;
if has_script_fn { if _has_script_fn {
// A script-defined function overrides the built-in function - do not make the call // A script-defined function overrides the built-in function - do not make the call
x.3 = x.3.into_iter().map(|a| optimize_expr(a, state)).collect(); x.3 = x.3.into_iter().map(|a| optimize_expr(a, state)).collect();
return Expr::FnCall(x); return Expr::FnCall(x);
@ -686,7 +694,9 @@ fn optimize(
// Keep all variable declarations at this level // Keep all variable declarations at this level
// and always keep the last return value // and always keep the last return value
let keep = match stmt { let keep = match stmt {
Stmt::Let(_) | Stmt::Import(_) => true, Stmt::Let(_) => true,
#[cfg(not(feature = "no_module"))]
Stmt::Import(_) => true,
_ => i == num_statements - 1, _ => i == num_statements - 1,
}; };
optimize_stmt(stmt, &mut state, keep) optimize_stmt(stmt, &mut state, keep)
@ -721,7 +731,7 @@ pub fn optimize_into_ast(
engine: &Engine, engine: &Engine,
scope: &Scope, scope: &Scope,
statements: Vec<Stmt>, statements: Vec<Stmt>,
functions: Vec<ScriptFnDef>, _functions: Vec<ScriptFnDef>,
level: OptimizationLevel, level: OptimizationLevel,
) -> AST { ) -> AST {
#[cfg(feature = "no_optimize")] #[cfg(feature = "no_optimize")]
@ -735,7 +745,7 @@ pub fn optimize_into_ast(
// We only need the script library's signatures for optimization purposes // We only need the script library's signatures for optimization purposes
let mut lib2 = Module::new(); let mut lib2 = Module::new();
functions _functions
.iter() .iter()
.map(|fn_def| { .map(|fn_def| {
ScriptFnDef { ScriptFnDef {
@ -751,7 +761,7 @@ pub fn optimize_into_ast(
lib2.set_script_fn(fn_def); lib2.set_script_fn(fn_def);
}); });
functions _functions
.into_iter() .into_iter()
.map(|mut fn_def| { .map(|mut fn_def| {
let pos = fn_def.body.position(); let pos = fn_def.body.position();
@ -782,7 +792,7 @@ pub fn optimize_into_ast(
module.set_script_fn(fn_def); module.set_script_fn(fn_def);
}); });
} else { } else {
functions.into_iter().for_each(|fn_def| { _functions.into_iter().for_each(|fn_def| {
module.set_script_fn(fn_def); module.set_script_fn(fn_def);
}); });
} }

View File

@ -1,8 +1,9 @@
use crate::def_package; use crate::def_package;
use crate::module::FuncReturn; use crate::module::FuncReturn;
use crate::parser::INT; use crate::parser::INT;
use crate::result::EvalAltResult;
use crate::token::Position; #[cfg(not(feature = "unchecked"))]
use crate::{result::EvalAltResult, token::Position};
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::parser::FLOAT;
@ -11,22 +12,25 @@ use crate::parser::FLOAT;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use num_traits::*; use num_traits::*;
#[cfg(not(feature = "unchecked"))]
use num_traits::{ use num_traits::{
identities::Zero, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, identities::Zero, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl,
CheckedShr, CheckedSub, CheckedShr, CheckedSub,
}; };
use crate::stdlib::{ use crate::stdlib::ops::{BitAnd, BitOr, BitXor};
boxed::Box,
fmt::Display, #[cfg(any(feature = "unchecked", not(feature = "no_float")))]
format, use crate::stdlib::ops::{Add, Div, Mul, Neg, Rem, Sub};
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Sub},
};
#[cfg(feature = "unchecked")] #[cfg(feature = "unchecked")]
use crate::stdlib::ops::{Shl, Shr}; use crate::stdlib::ops::{Shl, Shr};
#[cfg(not(feature = "unchecked"))]
use crate::stdlib::{boxed::Box, fmt::Display, format};
// Checked add // Checked add
#[cfg(not(feature = "unchecked"))]
pub(crate) fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> { pub(crate) fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
x.checked_add(&y).ok_or_else(|| { x.checked_add(&y).ok_or_else(|| {
Box::new(EvalAltResult::ErrorArithmetic( Box::new(EvalAltResult::ErrorArithmetic(
@ -36,6 +40,7 @@ pub(crate) fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
}) })
} }
// Checked subtract // Checked subtract
#[cfg(not(feature = "unchecked"))]
pub(crate) fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> { pub(crate) fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> {
x.checked_sub(&y).ok_or_else(|| { x.checked_sub(&y).ok_or_else(|| {
Box::new(EvalAltResult::ErrorArithmetic( Box::new(EvalAltResult::ErrorArithmetic(
@ -45,6 +50,7 @@ pub(crate) fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> {
}) })
} }
// Checked multiply // Checked multiply
#[cfg(not(feature = "unchecked"))]
pub(crate) fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> { pub(crate) fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> {
x.checked_mul(&y).ok_or_else(|| { x.checked_mul(&y).ok_or_else(|| {
Box::new(EvalAltResult::ErrorArithmetic( Box::new(EvalAltResult::ErrorArithmetic(
@ -54,6 +60,7 @@ pub(crate) fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> {
}) })
} }
// Checked divide // Checked divide
#[cfg(not(feature = "unchecked"))]
pub(crate) fn div<T>(x: T, y: T) -> FuncReturn<T> pub(crate) fn div<T>(x: T, y: T) -> FuncReturn<T>
where where
T: Display + CheckedDiv + PartialEq + Zero, T: Display + CheckedDiv + PartialEq + Zero,
@ -74,6 +81,7 @@ where
}) })
} }
// Checked negative - e.g. -(i32::MIN) will overflow i32::MAX // Checked negative - e.g. -(i32::MIN) will overflow i32::MAX
#[cfg(not(feature = "unchecked"))]
pub(crate) fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> { pub(crate) fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> {
x.checked_neg().ok_or_else(|| { x.checked_neg().ok_or_else(|| {
Box::new(EvalAltResult::ErrorArithmetic( Box::new(EvalAltResult::ErrorArithmetic(
@ -83,6 +91,7 @@ pub(crate) fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> {
}) })
} }
// Checked absolute // Checked absolute
#[cfg(not(feature = "unchecked"))]
pub(crate) fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> FuncReturn<T> { pub(crate) fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> FuncReturn<T> {
// FIX - We don't use Signed::abs() here because, contrary to documentation, it panics // FIX - We don't use Signed::abs() here because, contrary to documentation, it panics
// when the number is ::MIN instead of returning ::MIN itself. // when the number is ::MIN instead of returning ::MIN itself.
@ -98,26 +107,32 @@ pub(crate) fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> FuncRetu
} }
} }
// Unchecked add - may panic on overflow // Unchecked add - may panic on overflow
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
fn add_u<T: Add>(x: T, y: T) -> FuncReturn<<T as Add>::Output> { fn add_u<T: Add>(x: T, y: T) -> FuncReturn<<T as Add>::Output> {
Ok(x + y) Ok(x + y)
} }
// Unchecked subtract - may panic on underflow // Unchecked subtract - may panic on underflow
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
fn sub_u<T: Sub>(x: T, y: T) -> FuncReturn<<T as Sub>::Output> { fn sub_u<T: Sub>(x: T, y: T) -> FuncReturn<<T as Sub>::Output> {
Ok(x - y) Ok(x - y)
} }
// Unchecked multiply - may panic on overflow // Unchecked multiply - may panic on overflow
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
fn mul_u<T: Mul>(x: T, y: T) -> FuncReturn<<T as Mul>::Output> { fn mul_u<T: Mul>(x: T, y: T) -> FuncReturn<<T as Mul>::Output> {
Ok(x * y) Ok(x * y)
} }
// Unchecked divide - may panic when dividing by zero // Unchecked divide - may panic when dividing by zero
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
fn div_u<T: Div>(x: T, y: T) -> FuncReturn<<T as Div>::Output> { fn div_u<T: Div>(x: T, y: T) -> FuncReturn<<T as Div>::Output> {
Ok(x / y) Ok(x / y)
} }
// Unchecked negative - may panic on overflow // Unchecked negative - may panic on overflow
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
fn neg_u<T: Neg>(x: T) -> FuncReturn<<T as Neg>::Output> { fn neg_u<T: Neg>(x: T) -> FuncReturn<<T as Neg>::Output> {
Ok(-x) Ok(-x)
} }
// Unchecked absolute - may panic on overflow // Unchecked absolute - may panic on overflow
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
fn abs_u<T>(x: T) -> FuncReturn<<T as Neg>::Output> fn abs_u<T>(x: T) -> FuncReturn<<T as Neg>::Output>
where where
T: Neg + PartialOrd + Default + Into<<T as Neg>::Output>, T: Neg + PartialOrd + Default + Into<<T as Neg>::Output>,
@ -140,6 +155,7 @@ fn binary_xor<T: BitXor>(x: T, y: T) -> FuncReturn<<T as BitXor>::Output> {
Ok(x ^ y) Ok(x ^ y)
} }
// Checked left-shift // Checked left-shift
#[cfg(not(feature = "unchecked"))]
pub(crate) fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> { pub(crate) fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> {
// Cannot shift by a negative number of bits // Cannot shift by a negative number of bits
if y < 0 { if y < 0 {
@ -157,6 +173,7 @@ pub(crate) fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> {
}) })
} }
// Checked right-shift // Checked right-shift
#[cfg(not(feature = "unchecked"))]
pub(crate) fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> { pub(crate) fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> {
// Cannot shift by a negative number of bits // Cannot shift by a negative number of bits
if y < 0 { if y < 0 {
@ -184,6 +201,7 @@ pub(crate) fn shr_u<T: Shr<T>>(x: T, y: T) -> FuncReturn<<T as Shr<T>>::Output>
Ok(x.shr(y)) Ok(x.shr(y))
} }
// Checked modulo // Checked modulo
#[cfg(not(feature = "unchecked"))]
pub(crate) fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> { pub(crate) fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> {
x.checked_rem(&y).ok_or_else(|| { x.checked_rem(&y).ok_or_else(|| {
Box::new(EvalAltResult::ErrorArithmetic( Box::new(EvalAltResult::ErrorArithmetic(
@ -193,10 +211,12 @@ pub(crate) fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> {
}) })
} }
// Unchecked modulo - may panic if dividing by zero // Unchecked modulo - may panic if dividing by zero
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
fn modulo_u<T: Rem>(x: T, y: T) -> FuncReturn<<T as Rem>::Output> { fn modulo_u<T: Rem>(x: T, y: T) -> FuncReturn<<T as Rem>::Output> {
Ok(x % y) Ok(x % y)
} }
// Checked power // Checked power
#[cfg(not(feature = "unchecked"))]
pub(crate) fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> { pub(crate) fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
if y > (u32::MAX as INT) { if y > (u32::MAX as INT) {
@ -245,6 +265,7 @@ pub(crate) fn pow_f_f(x: FLOAT, y: FLOAT) -> FuncReturn<FLOAT> {
} }
// Checked power // Checked power
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
#[cfg(not(feature = "unchecked"))]
pub(crate) fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn<FLOAT> { pub(crate) fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn<FLOAT> {
// Raise to power that is larger than an i32 // Raise to power that is larger than an i32
if y > (i32::MAX as INT) { if y > (i32::MAX as INT) {

View File

@ -5,10 +5,14 @@ use crate::def_package;
use crate::engine::{Array, Engine}; use crate::engine::{Array, Engine};
use crate::module::{FuncReturn, Module}; use crate::module::{FuncReturn, Module};
use crate::parser::{ImmutableString, INT}; use crate::parser::{ImmutableString, INT};
use crate::result::EvalAltResult;
use crate::token::Position;
use crate::stdlib::{any::TypeId, boxed::Box, string::ToString}; #[cfg(not(feature = "unchecked"))]
use crate::{result::EvalAltResult, token::Position};
use crate::stdlib::{any::TypeId, boxed::Box};
#[cfg(not(feature = "unchecked"))]
use crate::stdlib::string::ToString;
// Register array utility functions // Register array utility functions
fn push<T: Variant + Clone>(list: &mut Array, item: T) -> FuncReturn<()> { fn push<T: Variant + Clone>(list: &mut Array, item: T) -> FuncReturn<()> {
@ -26,7 +30,7 @@ fn ins<T: Variant + Clone>(list: &mut Array, position: INT, item: T) -> FuncRetu
Ok(()) Ok(())
} }
fn pad<T: Variant + Clone>( fn pad<T: Variant + Clone>(
engine: &Engine, _engine: &Engine,
_: &Module, _: &Module,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> FuncReturn<()> { ) -> FuncReturn<()> {
@ -34,10 +38,13 @@ fn pad<T: Variant + Clone>(
// Check if array will be over max size limit // Check if array will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if engine.max_array_size > 0 && len > 0 && (len as usize) > engine.max_array_size { if _engine.limits.max_array_size > 0
&& len > 0
&& (len as usize) > _engine.limits.max_array_size
{
return Err(Box::new(EvalAltResult::ErrorDataTooLarge( return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(), "Size of array".to_string(),
engine.max_array_size, _engine.limits.max_array_size,
len as usize, len as usize,
Position::none(), Position::none(),
))); )));

View File

@ -1,16 +1,20 @@
#![cfg(not(feature = "no_object"))] #![cfg(not(feature = "no_object"))]
use crate::any::Dynamic;
use crate::def_package; use crate::def_package;
use crate::engine::Map; use crate::engine::Map;
use crate::module::FuncReturn;
use crate::parser::{ImmutableString, INT}; use crate::parser::{ImmutableString, INT};
#[cfg(not(feature = "no_index"))]
use crate::{any::Dynamic, module::FuncReturn};
#[cfg(not(feature = "no_index"))]
use crate::stdlib::vec::Vec; use crate::stdlib::vec::Vec;
#[cfg(not(feature = "no_index"))]
fn map_get_keys(map: &mut Map) -> FuncReturn<Vec<Dynamic>> { fn map_get_keys(map: &mut Map) -> FuncReturn<Vec<Dynamic>> {
Ok(map.iter().map(|(k, _)| k.clone().into()).collect()) Ok(map.iter().map(|(k, _)| k.clone().into()).collect())
} }
#[cfg(not(feature = "no_index"))]
fn map_get_values(map: &mut Map) -> FuncReturn<Vec<Dynamic>> { fn map_get_values(map: &mut Map) -> FuncReturn<Vec<Dynamic>> {
Ok(map.iter().map(|(_, v)| v.clone()).collect()) Ok(map.iter().map(|(_, v)| v.clone()).collect())
} }

View File

@ -1,20 +1,26 @@
use crate::def_package; use crate::def_package;
use crate::parser::INT; use crate::parser::INT;
use crate::result::EvalAltResult;
use crate::token::Position;
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::parser::FLOAT;
#[cfg(not(feature = "no_float"))]
#[cfg(not(feature = "unchecked"))]
use crate::{result::EvalAltResult, token::Position};
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use num_traits::*; use num_traits::*;
use crate::stdlib::{boxed::Box, format, i32, i64}; #[cfg(not(feature = "no_float"))]
#[cfg(not(feature = "unchecked"))]
use crate::stdlib::{boxed::Box, format};
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
#[cfg(not(feature = "unchecked"))]
pub const MAX_INT: INT = i32::MAX; pub const MAX_INT: INT = i32::MAX;
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "unchecked"))]
pub const MAX_INT: INT = i64::MAX; pub const MAX_INT: INT = i64::MAX;
def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {

View File

@ -24,7 +24,6 @@ pub use arithmetic::ArithmeticPackage;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
pub use array_basic::BasicArrayPackage; pub use array_basic::BasicArrayPackage;
pub use eval::EvalPackage; pub use eval::EvalPackage;
#[cfg(not(feature = "no_function"))]
pub use fn_basic::BasicFnPackage; pub use fn_basic::BasicFnPackage;
pub use iter_basic::BasicIteratorPackage; pub use iter_basic::BasicIteratorPackage;
pub use logic::LogicPackage; pub use logic::LogicPackage;

View File

@ -3,10 +3,11 @@ use crate::def_package;
use crate::engine::Engine; use crate::engine::Engine;
use crate::module::{FuncReturn, Module}; use crate::module::{FuncReturn, Module};
use crate::parser::{ImmutableString, INT}; use crate::parser::{ImmutableString, INT};
use crate::result::EvalAltResult;
use crate::token::Position;
use crate::utils::StaticVec; use crate::utils::StaticVec;
#[cfg(not(feature = "unchecked"))]
use crate::{result::EvalAltResult, token::Position};
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::Array; use crate::engine::Array;
@ -226,15 +227,15 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
lib.set_raw_fn( lib.set_raw_fn(
"pad", "pad",
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()], &[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()],
|engine: &Engine, _: &Module, args: &mut [&mut Dynamic]| { |_engine: &Engine, _: &Module, args: &mut [&mut Dynamic]| {
let len = *args[1].downcast_ref::< INT>().unwrap(); let len = *args[1].downcast_ref::< INT>().unwrap();
// Check if string will be over max size limit // Check if string will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if engine.max_string_size > 0 && len > 0 && (len as usize) > engine.max_string_size { if _engine.limits.max_string_size > 0 && len > 0 && (len as usize) > _engine.limits.max_string_size {
return Err(Box::new(EvalAltResult::ErrorDataTooLarge( return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
engine.max_string_size, _engine.limits.max_string_size,
len as usize, len as usize,
Position::none(), Position::none(),
))); )));
@ -253,10 +254,11 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
p.push(ch); p.push(ch);
} }
if engine.max_string_size > 0 && s.len() > engine.max_string_size { #[cfg(not(feature = "unchecked"))]
if _engine.limits.max_string_size > 0 && s.len() > _engine.limits.max_string_size {
return Err(Box::new(EvalAltResult::ErrorDataTooLarge( return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
engine.max_string_size, _engine.limits.max_string_size,
s.len(), s.len(),
Position::none(), Position::none(),
))); )));

View File

@ -2,6 +2,7 @@
use super::logic::{eq, gt, gte, lt, lte, ne}; use super::logic::{eq, gt, gte, lt, lte, ne};
#[cfg(feature = "no_float")] #[cfg(feature = "no_float")]
#[cfg(not(feature = "unchecked"))]
use super::math_basic::MAX_INT; use super::math_basic::MAX_INT;
use crate::def_package; use crate::def_package;
@ -11,7 +12,11 @@ use crate::result::EvalAltResult;
use crate::parser::FLOAT; use crate::parser::FLOAT;
#[cfg(feature = "no_float")] #[cfg(feature = "no_float")]
use crate::{module::FuncReturn, parser::INT, token::Position}; use crate::parser::INT;
#[cfg(feature = "no_float")]
#[cfg(not(feature = "unchecked"))]
use crate::token::Position;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use crate::stdlib::time::Instant; use crate::stdlib::time::Instant;

View File

@ -2,10 +2,7 @@
use crate::any::{Dynamic, Union}; use crate::any::{Dynamic, Union};
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::engine::{ use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
make_getter, make_setter, Engine, FN_ANONYMOUS, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR,
MARKER_IDENT,
};
use crate::error::{LexError, ParseError, ParseErrorType}; use crate::error::{LexError, ParseError, ParseErrorType};
use crate::fn_native::Shared; use crate::fn_native::Shared;
use crate::module::{Module, ModuleRef}; use crate::module::{Module, ModuleRef};
@ -15,6 +12,12 @@ use crate::syntax::FnCustomSyntaxEval;
use crate::token::{is_valid_identifier, Position, Token, TokenStream}; use crate::token::{is_valid_identifier, Position, Token, TokenStream};
use crate::utils::{StaticVec, StraightHasherBuilder}; use crate::utils::{StaticVec, StraightHasherBuilder};
#[cfg(not(feature = "no_function"))]
use crate::engine::FN_ANONYMOUS;
#[cfg(not(feature = "no_object"))]
use crate::engine::{make_getter, make_setter};
use crate::stdlib::{ use crate::stdlib::{
borrow::Cow, borrow::Cow,
boxed::Box, boxed::Box,
@ -32,9 +35,11 @@ use crate::stdlib::{
}; };
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(feature = "no_function"))]
use crate::stdlib::collections::hash_map::DefaultHasher; use crate::stdlib::collections::hash_map::DefaultHasher;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
#[cfg(not(feature = "no_function"))]
use ahash::AHasher; use ahash::AHasher;
/// The system integer type. /// The system integer type.
@ -84,7 +89,7 @@ impl AST {
&self.0 &self.0
} }
/// Get the statements. /// [INTERNALS] Get the statements.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[deprecated(note = "this method is volatile and may change")] #[deprecated(note = "this method is volatile and may change")]
pub fn statements(&self) -> &[Stmt] { pub fn statements(&self) -> &[Stmt] {
@ -102,7 +107,7 @@ impl AST {
&self.1 &self.1
} }
/// Get the internal `Module` containing all script-defined functions. /// [INTERNALS] Get the internal `Module` containing all script-defined functions.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[deprecated(note = "this method is volatile and may change")] #[deprecated(note = "this method is volatile and may change")]
pub fn lib(&self) -> &Module { pub fn lib(&self) -> &Module {
@ -404,20 +409,28 @@ struct ParseState<'e> {
/// Encapsulates a local stack with variable names to simulate an actual runtime scope. /// Encapsulates a local stack with variable names to simulate an actual runtime scope.
modules: Vec<String>, modules: Vec<String>,
/// Maximum levels of expression nesting. /// Maximum levels of expression nesting.
#[cfg(not(feature = "unchecked"))]
max_expr_depth: usize, max_expr_depth: usize,
/// Maximum levels of expression nesting in functions. /// Maximum levels of expression nesting in functions.
#[cfg(not(feature = "unchecked"))]
max_function_expr_depth: usize, max_function_expr_depth: usize,
} }
impl<'e> ParseState<'e> { impl<'e> ParseState<'e> {
/// Create a new `ParseState`. /// Create a new `ParseState`.
pub fn new(engine: &'e Engine, max_expr_depth: usize, max_function_expr_depth: usize) -> Self { pub fn new(
engine: &'e Engine,
#[cfg(not(feature = "unchecked"))] max_expr_depth: usize,
#[cfg(not(feature = "unchecked"))] max_function_expr_depth: usize,
) -> Self {
Self { Self {
engine, engine,
max_expr_depth,
max_function_expr_depth,
stack: Default::default(), stack: Default::default(),
modules: Default::default(), modules: Default::default(),
#[cfg(not(feature = "unchecked"))]
max_expr_depth,
#[cfg(not(feature = "unchecked"))]
max_function_expr_depth,
} }
} }
/// Find a variable by name in the `ParseState`, searching in reverse. /// Find a variable by name in the `ParseState`, searching in reverse.
@ -476,6 +489,7 @@ impl ParseSettings {
} }
} }
/// Make sure that the current level of expression nesting is within the maximum limit. /// Make sure that the current level of expression nesting is within the maximum limit.
#[cfg(not(feature = "unchecked"))]
pub fn ensure_level_within_max_limit(&self, limit: usize) -> Result<(), ParseError> { pub fn ensure_level_within_max_limit(&self, limit: usize) -> Result<(), ParseError> {
if limit == 0 { if limit == 0 {
Ok(()) Ok(())
@ -519,8 +533,10 @@ pub enum Stmt {
/// return/throw /// return/throw
ReturnWithVal(Box<((ReturnType, Position), Option<Expr>)>), ReturnWithVal(Box<((ReturnType, Position), Option<Expr>)>),
/// import expr as module /// import expr as module
#[cfg(not(feature = "no_module"))]
Import(Box<(Expr, (String, Position))>), Import(Box<(Expr, (String, Position))>),
/// expr id as name, ... /// expr id as name, ...
#[cfg(not(feature = "no_module"))]
Export(Box<StaticVec<((String, Position), Option<(String, Position)>)>>), Export(Box<StaticVec<((String, Position), Option<(String, Position)>)>>),
} }
@ -544,7 +560,10 @@ impl Stmt {
Stmt::While(x) => x.1.position(), Stmt::While(x) => x.1.position(),
Stmt::Loop(x) => x.position(), Stmt::Loop(x) => x.position(),
Stmt::For(x) => x.2.position(), Stmt::For(x) => x.2.position(),
#[cfg(not(feature = "no_module"))]
Stmt::Import(x) => (x.1).1, Stmt::Import(x) => (x.1).1,
#[cfg(not(feature = "no_module"))]
Stmt::Export(x) => (x.get(0).0).1, Stmt::Export(x) => (x.get(0).0).1,
} }
} }
@ -563,12 +582,13 @@ impl Stmt {
Stmt::Let(_) Stmt::Let(_)
| Stmt::Const(_) | Stmt::Const(_)
| Stmt::Import(_)
| Stmt::Export(_)
| Stmt::Expr(_) | Stmt::Expr(_)
| Stmt::Continue(_) | Stmt::Continue(_)
| Stmt::Break(_) | Stmt::Break(_)
| Stmt::ReturnWithVal(_) => false, | Stmt::ReturnWithVal(_) => false,
#[cfg(not(feature = "no_module"))]
Stmt::Import(_) | Stmt::Export(_) => false,
} }
} }
@ -587,7 +607,10 @@ impl Stmt {
Stmt::Let(_) | Stmt::Const(_) => false, Stmt::Let(_) | Stmt::Const(_) => false,
Stmt::Block(x) => x.0.iter().all(Stmt::is_pure), Stmt::Block(x) => x.0.iter().all(Stmt::is_pure),
Stmt::Continue(_) | Stmt::Break(_) | Stmt::ReturnWithVal(_) => false, Stmt::Continue(_) | Stmt::Break(_) | Stmt::ReturnWithVal(_) => false,
#[cfg(not(feature = "no_module"))]
Stmt::Import(_) => false, Stmt::Import(_) => false,
#[cfg(not(feature = "no_module"))]
Stmt::Export(_) => false, Stmt::Export(_) => false,
} }
} }
@ -950,6 +973,7 @@ impl Expr {
} }
/// Convert a `Variable` into a `Property`. All other variants are untouched. /// Convert a `Variable` into a `Property`. All other variants are untouched.
#[cfg(not(feature = "no_object"))]
pub(crate) fn into_property(self) -> Self { pub(crate) fn into_property(self) -> Self {
match self { match self {
Self::Variable(x) if x.1.is_none() => { Self::Variable(x) if x.1.is_none() => {
@ -996,6 +1020,7 @@ fn parse_paren_expr(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
if match_token(input, Token::RightParen)? { if match_token(input, Token::RightParen)? {
@ -1028,6 +1053,8 @@ fn parse_call_expr(
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let (token, token_pos) = input.peek().unwrap(); let (token, token_pos) = input.peek().unwrap();
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut args = StaticVec::new(); let mut args = StaticVec::new();
@ -1141,6 +1168,7 @@ fn parse_call_expr(
/// Parse an indexing chain. /// Parse an indexing chain.
/// Indexing binds to the right, so this call parses all possible levels of indexing following in the input. /// Indexing binds to the right, so this call parses all possible levels of indexing following in the input.
#[cfg(not(feature = "no_index"))]
fn parse_index_chain( fn parse_index_chain(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,
@ -1148,6 +1176,7 @@ fn parse_index_chain(
lhs: Expr, lhs: Expr,
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let idx_expr = parse_expr(input, state, lib, settings.level_up())?; let idx_expr = parse_expr(input, state, lib, settings.level_up())?;
@ -1321,21 +1350,25 @@ fn parse_index_chain(
} }
/// Parse an array literal. /// Parse an array literal.
#[cfg(not(feature = "no_index"))]
fn parse_array_literal( fn parse_array_literal(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut arr = StaticVec::new(); let mut arr = StaticVec::new();
while !input.peek().unwrap().0.is_eof() { while !input.peek().unwrap().0.is_eof() {
if state.engine.max_array_size > 0 && arr.len() >= state.engine.max_array_size { #[cfg(not(feature = "unchecked"))]
if state.engine.limits.max_array_size > 0 && arr.len() >= state.engine.limits.max_array_size
{
return Err(PERR::LiteralTooLarge( return Err(PERR::LiteralTooLarge(
"Size of array literal".to_string(), "Size of array literal".to_string(),
state.engine.max_array_size, state.engine.limits.max_array_size,
) )
.into_err(input.peek().unwrap().1)); .into_err(input.peek().unwrap().1));
} }
@ -1378,12 +1411,14 @@ fn parse_array_literal(
} }
/// Parse a map literal. /// Parse a map literal.
#[cfg(not(feature = "no_object"))]
fn parse_map_literal( fn parse_map_literal(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut map = StaticVec::new(); let mut map = StaticVec::new();
@ -1436,10 +1471,11 @@ fn parse_map_literal(
} }
}; };
if state.engine.max_map_size > 0 && map.len() >= state.engine.max_map_size { #[cfg(not(feature = "unchecked"))]
if state.engine.limits.max_map_size > 0 && map.len() >= state.engine.limits.max_map_size {
return Err(PERR::LiteralTooLarge( return Err(PERR::LiteralTooLarge(
"Number of properties in object map literal".to_string(), "Number of properties in object map literal".to_string(),
state.engine.max_map_size, state.engine.limits.max_map_size,
) )
.into_err(input.peek().unwrap().1)); .into_err(input.peek().unwrap().1));
} }
@ -1492,6 +1528,8 @@ fn parse_primary(
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let (token, token_pos) = input.peek().unwrap(); let (token, token_pos) = input.peek().unwrap();
settings.pos = *token_pos; settings.pos = *token_pos;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let (token, _) = match token { let (token, _) = match token {
@ -1626,6 +1664,8 @@ fn parse_unary(
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let (token, token_pos) = input.peek().unwrap(); let (token, token_pos) = input.peek().unwrap();
settings.pos = *token_pos; settings.pos = *token_pos;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
match token { match token {
@ -1708,7 +1748,9 @@ fn parse_unary(
Token::Pipe | Token::Or => { Token::Pipe | Token::Or => {
let mut state = ParseState::new( let mut state = ParseState::new(
state.engine, state.engine,
#[cfg(not(feature = "unchecked"))]
state.max_function_expr_depth, state.max_function_expr_depth,
#[cfg(not(feature = "unchecked"))]
state.max_function_expr_depth, state.max_function_expr_depth,
); );
@ -1809,6 +1851,8 @@ fn parse_op_assignment_stmt(
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let (token, token_pos) = input.peek().unwrap(); let (token, token_pos) = input.peek().unwrap();
settings.pos = *token_pos; settings.pos = *token_pos;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let op = match token { let op = match token {
@ -1835,6 +1879,7 @@ fn parse_op_assignment_stmt(
} }
/// Make a dot expression. /// Make a dot expression.
#[cfg(not(feature = "no_object"))]
fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseError> { fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseError> {
Ok(match (lhs, rhs) { Ok(match (lhs, rhs) {
// idx_lhs[idx_expr].rhs // idx_lhs[idx_expr].rhs
@ -2048,6 +2093,8 @@ fn parse_binary_op(
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
settings.pos = lhs.position(); settings.pos = lhs.position();
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut root = lhs; let mut root = lhs;
@ -2081,6 +2128,8 @@ fn parse_binary_op(
settings = settings.level_up(); settings = settings.level_up();
settings.pos = pos; settings.pos = pos;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let cmp_def = Some(false); let cmp_def = Some(false);
@ -2164,6 +2213,8 @@ fn parse_expr(
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
settings.pos = input.peek().unwrap().1; settings.pos = input.peek().unwrap().1;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// Check if it is a custom syntax. // Check if it is a custom syntax.
@ -2291,6 +2342,8 @@ fn parse_if(
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
// if ... // if ...
settings.pos = eat_token(input, Token::If); settings.pos = eat_token(input, Token::If);
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// if guard { if_body } // if guard { if_body }
@ -2324,6 +2377,8 @@ fn parse_while(
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
// while ... // while ...
settings.pos = eat_token(input, Token::While); settings.pos = eat_token(input, Token::While);
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// while guard { body } // while guard { body }
@ -2346,6 +2401,8 @@ fn parse_loop(
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
// loop ... // loop ...
settings.pos = eat_token(input, Token::Loop); settings.pos = eat_token(input, Token::Loop);
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// loop { body } // loop { body }
@ -2364,6 +2421,8 @@ fn parse_for(
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
// for ... // for ...
settings.pos = eat_token(input, Token::For); settings.pos = eat_token(input, Token::For);
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// for name ... // for name ...
@ -2417,6 +2476,8 @@ fn parse_let(
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
// let/const... (specified in `var_type`) // let/const... (specified in `var_type`)
settings.pos = input.next().unwrap().1; settings.pos = input.next().unwrap().1;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// let name ... // let name ...
@ -2475,6 +2536,8 @@ fn parse_import(
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
// import ... // import ...
settings.pos = eat_token(input, Token::Import); settings.pos = eat_token(input, Token::Import);
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// import expr ... // import expr ...
@ -2509,12 +2572,14 @@ fn parse_import(
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
fn parse_export( fn parse_export(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, _state: &mut ParseState,
_lib: &mut FunctionsLib, _lib: &mut FunctionsLib,
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
settings.pos = eat_token(input, Token::Export); settings.pos = eat_token(input, Token::Export);
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(_state.max_expr_depth)?;
let mut exports = StaticVec::new(); let mut exports = StaticVec::new();
@ -2594,6 +2659,7 @@ fn parse_block(
} }
}; };
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut statements = StaticVec::new(); let mut statements = StaticVec::new();
@ -2657,6 +2723,8 @@ fn parse_expr_stmt(
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
settings.pos = input.peek().unwrap().1; settings.pos = input.peek().unwrap().1;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let expr = parse_expr(input, state, lib, settings.level_up())?; let expr = parse_expr(input, state, lib, settings.level_up())?;
@ -2678,6 +2746,8 @@ fn parse_stmt(
x => x, x => x,
}; };
settings.pos = *token_pos; settings.pos = *token_pos;
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
match token { match token {
@ -2703,7 +2773,9 @@ fn parse_stmt(
(Token::Fn, pos) => { (Token::Fn, pos) => {
let mut state = ParseState::new( let mut state = ParseState::new(
state.engine, state.engine,
#[cfg(not(feature = "unchecked"))]
state.max_function_expr_depth, state.max_function_expr_depth,
#[cfg(not(feature = "unchecked"))]
state.max_function_expr_depth, state.max_function_expr_depth,
); );
@ -2807,6 +2879,7 @@ fn parse_fn(
access: FnAccess, access: FnAccess,
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<ScriptFnDef, ParseError> { ) -> Result<ScriptFnDef, ParseError> {
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let name = match input.next().unwrap() { let name = match input.next().unwrap() {
@ -2899,6 +2972,7 @@ fn parse_anon_fn(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<(Expr, ScriptFnDef), ParseError> { ) -> Result<(Expr, ScriptFnDef), ParseError> {
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut params = Vec::new(); let mut params = Vec::new();
@ -2994,7 +3068,15 @@ impl Engine {
optimization_level: OptimizationLevel, optimization_level: OptimizationLevel,
) -> Result<AST, ParseError> { ) -> Result<AST, ParseError> {
let mut functions = Default::default(); let mut functions = Default::default();
let mut state = ParseState::new(self, self.max_expr_depth, self.max_function_expr_depth);
let mut state = ParseState::new(
self,
#[cfg(not(feature = "unchecked"))]
self.limits.max_expr_depth,
#[cfg(not(feature = "unchecked"))]
self.limits.max_function_expr_depth,
);
let settings = ParseSettings { let settings = ParseSettings {
allow_if_expr: false, allow_if_expr: false,
allow_stmt_expr: false, allow_stmt_expr: false,
@ -3032,7 +3114,14 @@ impl Engine {
) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> { ) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> {
let mut statements: Vec<Stmt> = Default::default(); let mut statements: Vec<Stmt> = Default::default();
let mut functions = Default::default(); let mut functions = Default::default();
let mut state = ParseState::new(self, self.max_expr_depth, self.max_function_expr_depth);
let mut state = ParseState::new(
self,
#[cfg(not(feature = "unchecked"))]
self.limits.max_expr_depth,
#[cfg(not(feature = "unchecked"))]
self.limits.max_function_expr_depth,
);
while !input.peek().unwrap().0.is_eof() { while !input.peek().unwrap().0.is_eof() {
let settings = ParseSettings { let settings = ParseSettings {

View File

@ -34,10 +34,10 @@ pub enum EvalAltResult {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
ErrorReadingScriptFile(PathBuf, Position, std::io::Error), ErrorReadingScriptFile(PathBuf, Position, std::io::Error),
/// Call to an unknown function. Wrapped value is the name of the function. /// Call to an unknown function. Wrapped value is the signature of the function.
ErrorFunctionNotFound(String, Position), ErrorFunctionNotFound(String, Position),
/// An error has occurred inside a called function. /// An error has occurred inside a called function.
/// Wrapped values re the name of the function and the interior error. /// Wrapped values are the name of the function and the interior error.
ErrorInFunctionCall(String, Box<EvalAltResult>, Position), ErrorInFunctionCall(String, Box<EvalAltResult>, Position),
/// Access to `this` that is not bounded. /// Access to `this` that is not bounded.
ErrorUnboundedThis(Position), ErrorUnboundedThis(Position),

View File

@ -377,6 +377,7 @@ impl<'a> Scope<'a> {
} }
/// Update the access type of an entry in the Scope. /// Update the access type of an entry in the Scope.
#[cfg(not(feature = "no_module"))]
pub(crate) fn set_entry_alias(&mut self, index: usize, alias: String) -> &mut Self { pub(crate) fn set_entry_alias(&mut self, index: usize, alias: String) -> &mut Self {
let entry = self.0.get_mut(index).expect("invalid index in Scope"); let entry = self.0.get_mut(index).expect("invalid index in Scope");
entry.alias = Some(Box::new(alias)); entry.alias = Some(Box::new(alias));
@ -384,6 +385,7 @@ impl<'a> Scope<'a> {
} }
/// Get an iterator to entries in the Scope. /// Get an iterator to entries in the Scope.
#[cfg(not(feature = "no_module"))]
pub(crate) fn into_iter(self) -> impl Iterator<Item = Entry<'a>> { pub(crate) fn into_iter(self) -> impl Iterator<Item = Entry<'a>> {
self.0.into_iter() self.0.into_iter()
} }

View File

@ -8,17 +8,20 @@ use crate::token::Position;
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use serde::de::{ use serde::de::{
DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, MapAccess, SeqAccess, DeserializeSeed, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor,
VariantAccess, Visitor,
}; };
use serde::Deserialize; use serde::Deserialize;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::Array; use crate::engine::Array;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::engine::Map; use crate::engine::Map;
use crate::stdlib::{any::type_name, fmt}; #[cfg(not(feature = "no_object"))]
use serde::de::{EnumAccess, VariantAccess};
use crate::stdlib::{any::type_name, boxed::Box, fmt, string::ToString};
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -46,8 +49,12 @@ impl<'de> DynamicDeserializer<'de> {
} }
/// Shortcut for a type conversion error. /// Shortcut for a type conversion error.
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> { fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
self.type_error_str(type_name::<T>())
}
/// Shortcut for a type conversion error.
fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> {
Err(Box::new(EvalAltResult::ErrorMismatchOutputType( Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
type_name::<T>().into(), error.into(),
self.value.type_name().into(), self.value.type_name().into(),
Position::none(), Position::none(),
))) )))
@ -283,23 +290,23 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
} }
} }
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> { fn deserialize_f32<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
return self return self
.value .value
.downcast_ref::<f32>() .downcast_ref::<f32>()
.map_or_else(|| self.type_error(), |&x| visitor.visit_f32(x)); .map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
#[cfg(feature = "no_float")] #[cfg(feature = "no_float")]
return self.type_error_str("f32"); return self.type_error_str("f32");
} }
fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> { fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
return self return self
.value .value
.downcast_ref::<f64>() .downcast_ref::<f64>()
.map_or_else(|| self.type_error(), |&x| visitor.visit_f64(x)); .map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
#[cfg(feature = "no_float")] #[cfg(feature = "no_float")]
return self.type_error_str("f64"); return self.type_error_str("f64");
@ -359,11 +366,11 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
visitor.visit_newtype_struct(self) visitor.visit_newtype_struct(self)
} }
fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> { fn deserialize_seq<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
return self.value.downcast_ref::<Array>().map_or_else( return self.value.downcast_ref::<Array>().map_or_else(
|| self.type_error(), || self.type_error(),
|arr| visitor.visit_seq(IterateArray::new(arr.iter())), |arr| _visitor.visit_seq(IterateArray::new(arr.iter())),
); );
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
@ -387,11 +394,11 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
self.deserialize_seq(visitor) self.deserialize_seq(visitor)
} }
fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> { fn deserialize_map<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
return self.value.downcast_ref::<Map>().map_or_else( return self.value.downcast_ref::<Map>().map_or_else(
|| self.type_error(), || self.type_error(),
|map| visitor.visit_map(IterateMap::new(map.keys(), map.values())), |map| _visitor.visit_map(IterateMap::new(map.keys(), map.values())),
); );
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
@ -461,6 +468,7 @@ where
iter: ITER, iter: ITER,
} }
#[cfg(not(feature = "no_index"))]
impl<'a, ITER> IterateArray<'a, ITER> impl<'a, ITER> IterateArray<'a, ITER>
where where
ITER: Iterator<Item = &'a Dynamic>, ITER: Iterator<Item = &'a Dynamic>,
@ -502,6 +510,7 @@ where
values: VALUES, values: VALUES,
} }
#[cfg(not(feature = "no_object"))]
impl<'a, KEYS, VALUES> IterateMap<'a, KEYS, VALUES> impl<'a, KEYS, VALUES> IterateMap<'a, KEYS, VALUES>
where where
KEYS: Iterator<Item = &'a ImmutableString>, KEYS: Iterator<Item = &'a ImmutableString>,

View File

@ -10,27 +10,36 @@ use crate::engine::Array;
use crate::engine::Map; use crate::engine::Map;
use serde::ser::{ use serde::ser::{
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, SerializeTupleStruct,
SerializeTupleStruct, SerializeTupleVariant, Serializer, Serializer,
}; };
use serde::Serialize; use serde::Serialize;
use crate::stdlib::{any::type_name, fmt, mem}; #[cfg(not(any(feature = "no_object", feature = "no_index")))]
use serde::ser::SerializeTupleVariant;
#[cfg(not(feature = "no_object"))]
use serde::ser::SerializeStructVariant;
use crate::stdlib::{boxed::Box, fmt, string::ToString};
#[cfg(not(feature = "no_object"))]
use crate::stdlib::mem;
/// Serializer for `Dynamic` which is kept as a reference. /// Serializer for `Dynamic` which is kept as a reference.
pub struct DynamicSerializer { pub struct DynamicSerializer {
/// Buffer to hold a temporary key. /// Buffer to hold a temporary key.
key: Dynamic, _key: Dynamic,
/// Buffer to hold a temporary value. /// Buffer to hold a temporary value.
value: Dynamic, _value: Dynamic,
} }
impl DynamicSerializer { impl DynamicSerializer {
/// Create a `DynamicSerializer` from a `Dynamic` value. /// Create a `DynamicSerializer` from a `Dynamic` value.
pub fn new(value: Dynamic) -> Self { pub fn new(_value: Dynamic) -> Self {
Self { Self {
key: Default::default(), _key: Default::default(),
value, _value,
} }
} }
} }
@ -280,13 +289,13 @@ impl Serializer for &mut DynamicSerializer {
self, self,
_name: &'static str, _name: &'static str,
_variant_index: u32, _variant_index: u32,
variant: &'static str, _variant: &'static str,
value: &T, _value: &T,
) -> Result<Self::Ok, Box<EvalAltResult>> { ) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
{ {
let content = to_dynamic(value)?; let content = to_dynamic(_value)?;
make_variant(variant, content) make_variant(_variant, content)
} }
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
@ -323,13 +332,13 @@ impl Serializer for &mut DynamicSerializer {
self, self,
_name: &'static str, _name: &'static str,
_variant_index: u32, _variant_index: u32,
variant: &'static str, _variant: &'static str,
len: usize, _len: usize,
) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> { ) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> {
#[cfg(not(any(feature = "no_object", feature = "no_index")))] #[cfg(not(any(feature = "no_object", feature = "no_index")))]
return Ok(TupleVariantSerializer { return Ok(TupleVariantSerializer {
variant, variant: _variant,
array: Array::with_capacity(len), array: Array::with_capacity(_len),
}); });
#[cfg(any(feature = "no_object", feature = "no_index"))] #[cfg(any(feature = "no_object", feature = "no_index"))]
{ {
@ -368,13 +377,13 @@ impl Serializer for &mut DynamicSerializer {
self, self,
_name: &'static str, _name: &'static str,
_variant_index: u32, _variant_index: u32,
variant: &'static str, _variant: &'static str,
len: usize, _len: usize,
) -> Result<Self::SerializeStructVariant, Box<EvalAltResult>> { ) -> Result<Self::SerializeStructVariant, Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
return Ok(StructVariantSerializer { return Ok(StructVariantSerializer {
variant, variant: _variant,
map: Map::with_capacity(len), map: Map::with_capacity(_len),
}); });
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
@ -391,13 +400,13 @@ impl SerializeSeq for DynamicSerializer {
fn serialize_element<T: ?Sized + Serialize>( fn serialize_element<T: ?Sized + Serialize>(
&mut self, &mut self,
value: &T, _value: &T,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
{ {
let value = value.serialize(&mut *self)?; let _value = _value.serialize(&mut *self)?;
let arr = self.value.downcast_mut::<Array>().unwrap(); let arr = self._value.downcast_mut::<Array>().unwrap();
arr.push(value); arr.push(_value);
Ok(()) Ok(())
} }
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
@ -407,7 +416,7 @@ impl SerializeSeq for DynamicSerializer {
// Close the sequence. // Close the sequence.
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> { fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
return Ok(self.value); return Ok(self._value);
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
unreachable!() unreachable!()
} }
@ -419,13 +428,13 @@ impl SerializeTuple for DynamicSerializer {
fn serialize_element<T: ?Sized + Serialize>( fn serialize_element<T: ?Sized + Serialize>(
&mut self, &mut self,
value: &T, _value: &T,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
{ {
let value = value.serialize(&mut *self)?; let _value = _value.serialize(&mut *self)?;
let arr = self.value.downcast_mut::<Array>().unwrap(); let arr = self._value.downcast_mut::<Array>().unwrap();
arr.push(value); arr.push(_value);
Ok(()) Ok(())
} }
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
@ -434,7 +443,7 @@ impl SerializeTuple for DynamicSerializer {
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> { fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
return Ok(self.value); return Ok(self._value);
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
unreachable!() unreachable!()
} }
@ -446,13 +455,13 @@ impl SerializeTupleStruct for DynamicSerializer {
fn serialize_field<T: ?Sized + Serialize>( fn serialize_field<T: ?Sized + Serialize>(
&mut self, &mut self,
value: &T, _value: &T,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
{ {
let value = value.serialize(&mut *self)?; let _value = _value.serialize(&mut *self)?;
let arr = self.value.downcast_mut::<Array>().unwrap(); let arr = self._value.downcast_mut::<Array>().unwrap();
arr.push(value); arr.push(_value);
Ok(()) Ok(())
} }
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
@ -461,7 +470,7 @@ impl SerializeTupleStruct for DynamicSerializer {
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> { fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
return Ok(self.value); return Ok(self._value);
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
unreachable!() unreachable!()
} }
@ -471,10 +480,10 @@ impl SerializeMap for DynamicSerializer {
type Ok = Dynamic; type Ok = Dynamic;
type Error = Box<EvalAltResult>; type Error = Box<EvalAltResult>;
fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<(), Box<EvalAltResult>> { fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
{ {
self.key = key.serialize(&mut *self)?; self._key = _key.serialize(&mut *self)?;
Ok(()) Ok(())
} }
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
@ -483,11 +492,11 @@ impl SerializeMap for DynamicSerializer {
fn serialize_value<T: ?Sized + Serialize>( fn serialize_value<T: ?Sized + Serialize>(
&mut self, &mut self,
value: &T, _value: &T,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
{ {
let key = mem::take(&mut self.key) let key = mem::take(&mut self._key)
.take_immutable_string() .take_immutable_string()
.map_err(|typ| { .map_err(|typ| {
Box::new(EvalAltResult::ErrorMismatchOutputType( Box::new(EvalAltResult::ErrorMismatchOutputType(
@ -496,9 +505,9 @@ impl SerializeMap for DynamicSerializer {
Position::none(), Position::none(),
)) ))
})?; })?;
let value = value.serialize(&mut *self)?; let _value = _value.serialize(&mut *self)?;
let map = self.value.downcast_mut::<Map>().unwrap(); let map = self._value.downcast_mut::<Map>().unwrap();
map.insert(key, value); map.insert(key, _value);
Ok(()) Ok(())
} }
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
@ -507,22 +516,22 @@ impl SerializeMap for DynamicSerializer {
fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>( fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>(
&mut self, &mut self,
key: &K, _key: &K,
value: &T, _value: &T,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
{ {
let key: Dynamic = key.serialize(&mut *self)?; let _key: Dynamic = _key.serialize(&mut *self)?;
let key = key.take_immutable_string().map_err(|typ| { let _key = _key.take_immutable_string().map_err(|typ| {
Box::new(EvalAltResult::ErrorMismatchOutputType( Box::new(EvalAltResult::ErrorMismatchOutputType(
"string".into(), "string".into(),
typ.into(), typ.into(),
Position::none(), Position::none(),
)) ))
})?; })?;
let value = value.serialize(&mut *self)?; let _value = _value.serialize(&mut *self)?;
let map = self.value.downcast_mut::<Map>().unwrap(); let map = self._value.downcast_mut::<Map>().unwrap();
map.insert(key, value); map.insert(_key, _value);
Ok(()) Ok(())
} }
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
@ -531,7 +540,7 @@ impl SerializeMap for DynamicSerializer {
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> { fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
return Ok(self.value); return Ok(self._value);
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
unreachable!() unreachable!()
} }
@ -543,14 +552,14 @@ impl SerializeStruct for DynamicSerializer {
fn serialize_field<T: ?Sized + Serialize>( fn serialize_field<T: ?Sized + Serialize>(
&mut self, &mut self,
key: &'static str, _key: &'static str,
value: &T, _value: &T,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
{ {
let value = value.serialize(&mut *self)?; let _value = _value.serialize(&mut *self)?;
let map = self.value.downcast_mut::<Map>().unwrap(); let map = self._value.downcast_mut::<Map>().unwrap();
map.insert(key.into(), value); map.insert(_key.into(), _value);
Ok(()) Ok(())
} }
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
@ -559,7 +568,7 @@ impl SerializeStruct for DynamicSerializer {
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> { fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
return Ok(self.value); return Ok(self._value);
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
unreachable!() unreachable!()
} }

View File

@ -6,7 +6,7 @@ use crate::utils::ImmutableString;
use serde::de::{Deserializer, Visitor}; use serde::de::{Deserializer, Visitor};
use crate::stdlib::any::type_name; use crate::stdlib::{any::type_name, boxed::Box};
/// Deserializer for `ImmutableString`. /// Deserializer for `ImmutableString`.
pub struct ImmutableStringDeserializer<'a> { pub struct ImmutableStringDeserializer<'a> {

View File

@ -1,12 +1,17 @@
//! Configuration settings for `Engine`. //! Configuration settings for `Engine`.
use crate::engine::Engine; use crate::engine::Engine;
use crate::module::ModuleResolver;
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::packages::PackageLibrary; use crate::packages::PackageLibrary;
use crate::token::{is_valid_identifier, Token}; use crate::token::{is_valid_identifier, Token};
use crate::stdlib::{boxed::Box, format, string::String}; #[cfg(not(feature = "no_module"))]
use crate::module::ModuleResolver;
use crate::stdlib::{format, string::String};
#[cfg(not(feature = "no_module"))]
use crate::stdlib::boxed::Box;
impl Engine { impl Engine {
/// Load a new package into the `Engine`. /// Load a new package into the `Engine`.
@ -41,21 +46,21 @@ impl Engine {
/// infinite recursion and stack overflows. /// infinite recursion and stack overflows.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self { pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self {
self.max_call_stack_depth = levels; self.limits.max_call_stack_depth = levels;
self self
} }
/// The maximum levels of function calls allowed for a script. /// The maximum levels of function calls allowed for a script.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn max_call_levels(&self) -> usize { pub fn max_call_levels(&self) -> usize {
self.max_call_stack_depth self.limits.max_call_stack_depth
} }
/// Set the maximum number of operations allowed for a script to run to avoid /// Set the maximum number of operations allowed for a script to run to avoid
/// consuming too much resources (0 for unlimited). /// consuming too much resources (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self { pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
self.max_operations = if operations == u64::MAX { self.limits.max_operations = if operations == u64::MAX {
0 0
} else { } else {
operations operations
@ -66,20 +71,20 @@ impl Engine {
/// The maximum number of operations allowed for a script to run (0 for unlimited). /// The maximum number of operations allowed for a script to run (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn max_operations(&self) -> u64 { pub fn max_operations(&self) -> u64 {
self.max_operations self.limits.max_operations
} }
/// Set the maximum number of imported modules allowed for a script. /// Set the maximum number of imported modules allowed for a script.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn set_max_modules(&mut self, modules: usize) -> &mut Self { pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
self.max_modules = modules; self.limits.max_modules = modules;
self self
} }
/// The maximum number of imported modules allowed for a script. /// The maximum number of imported modules allowed for a script.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn max_modules(&self) -> usize { pub fn max_modules(&self) -> usize {
self.max_modules self.limits.max_modules
} }
/// Set the depth limits for expressions (0 for unlimited). /// Set the depth limits for expressions (0 for unlimited).
@ -89,12 +94,12 @@ impl Engine {
max_expr_depth: usize, max_expr_depth: usize,
max_function_expr_depth: usize, max_function_expr_depth: usize,
) -> &mut Self { ) -> &mut Self {
self.max_expr_depth = if max_expr_depth == usize::MAX { self.limits.max_expr_depth = if max_expr_depth == usize::MAX {
0 0
} else { } else {
max_expr_depth max_expr_depth
}; };
self.max_function_expr_depth = if max_function_expr_depth == usize::MAX { self.limits.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
0 0
} else { } else {
max_function_expr_depth max_function_expr_depth
@ -105,33 +110,33 @@ impl Engine {
/// The depth limit for expressions (0 for unlimited). /// The depth limit for expressions (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn max_expr_depth(&self) -> usize { pub fn max_expr_depth(&self) -> usize {
self.max_expr_depth self.limits.max_expr_depth
} }
/// The depth limit for expressions in functions (0 for unlimited). /// The depth limit for expressions in functions (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn max_function_expr_depth(&self) -> usize { pub fn max_function_expr_depth(&self) -> usize {
self.max_function_expr_depth self.limits.max_function_expr_depth
} }
/// Set the maximum length of strings (0 for unlimited). /// Set the maximum length of strings (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self { pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
self.max_string_size = if max_size == usize::MAX { 0 } else { max_size }; self.limits.max_string_size = if max_size == usize::MAX { 0 } else { max_size };
self self
} }
/// The maximum length of strings (0 for unlimited). /// The maximum length of strings (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub fn max_string_size(&self) -> usize { pub fn max_string_size(&self) -> usize {
self.max_string_size self.limits.max_string_size
} }
/// Set the maximum length of arrays (0 for unlimited). /// Set the maximum length of arrays (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self { pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
self.max_array_size = if max_size == usize::MAX { 0 } else { max_size }; self.limits.max_array_size = if max_size == usize::MAX { 0 } else { max_size };
self self
} }
@ -139,14 +144,14 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
pub fn max_array_size(&self) -> usize { pub fn max_array_size(&self) -> usize {
self.max_array_size self.limits.max_array_size
} }
/// Set the maximum length of object maps (0 for unlimited). /// Set the maximum length of object maps (0 for unlimited).
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self { pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
self.max_map_size = if max_size == usize::MAX { 0 } else { max_size }; self.limits.max_map_size = if max_size == usize::MAX { 0 } else { max_size };
self self
} }
@ -154,7 +159,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub fn max_map_size(&self) -> usize { pub fn max_map_size(&self) -> usize {
self.max_map_size self.limits.max_map_size
} }
/// Set the module resolution service used by the `Engine`. /// Set the module resolution service used by the `Engine`.

View File

@ -1549,7 +1549,10 @@ pub fn lex<'a, 'e>(input: &'a [&'a str], engine: &'e Engine) -> TokenIterator<'a
TokenIterator { TokenIterator {
engine, engine,
state: TokenizeState { state: TokenizeState {
max_string_size: engine.max_string_size, #[cfg(not(feature = "unchecked"))]
max_string_size: engine.limits.max_string_size,
#[cfg(feature = "unchecked")]
max_string_size: 0,
non_unary: false, non_unary: false,
comment_level: 0, comment_level: 0,
end_with_none: false, end_with_none: false,

View File

@ -166,9 +166,9 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
module.set_raw_fn( module.set_raw_fn(
"call_with_arg", "call_with_arg",
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()], &[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|engine: &Engine, module: &Module, args: &mut [&mut Dynamic]| { |engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| {
let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>(); let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>();
fn_ptr.call_dynamic(engine, module, None, [std::mem::take(args[1])]) fn_ptr.call_dynamic(engine, lib, None, [std::mem::take(args[1])])
}, },
); );

View File

@ -245,7 +245,7 @@ fn test_module_from_ast() -> Result<(), Box<EvalAltResult>> {
*engine *engine
.consume(r#"import "testing" as ttt; ttt::hidden()"#) .consume(r#"import "testing" as ttt; ttt::hidden()"#)
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorFunctionNotFound(fn_name, _) if fn_name == "ttt::hidden" EvalAltResult::ErrorFunctionNotFound(fn_name, _) if fn_name == "ttt::hidden ()"
)); ));
Ok(()) Ok(())