Minor code and docs refactor.
This commit is contained in:
parent
dca47d5233
commit
9fa4d60336
@ -7,7 +7,7 @@ Version 1.3.0
|
||||
Compiler requirement
|
||||
--------------------
|
||||
|
||||
* Minimum compiler version is 1.51.
|
||||
* Minimum compiler version is bumped to 1.51.
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
@ -20,6 +20,7 @@ Deprecated API's
|
||||
|
||||
* The internal `no_smartstring` feature is removed since `SmartString` now supports `no-std`.
|
||||
* `NativeCallContext::new` is deprecated because it is simpler to call a function pointer via `FnPtr::call`.
|
||||
* `AST::shared_lib` is changed to return `&Shared<Module>` while `AST::lib` is deprecated.
|
||||
|
||||
|
||||
Version 1.2.1
|
||||
|
@ -156,7 +156,7 @@ impl Engine {
|
||||
|
||||
if eval_ast && !statements.is_empty() {
|
||||
// Make sure new variables introduced at global level do not _spill_ into the function call
|
||||
self.eval_global_statements(scope, mods, state, statements, &[ast.lib()], 0)?;
|
||||
self.eval_global_statements(scope, mods, state, statements, &[ast.as_ref()], 0)?;
|
||||
|
||||
if rewind_scope {
|
||||
scope.rewind(orig_scope_len);
|
||||
@ -169,7 +169,7 @@ impl Engine {
|
||||
let mut args: StaticVec<_> = arg_values.as_mut().iter_mut().collect();
|
||||
|
||||
let fn_def = ast
|
||||
.lib()
|
||||
.shared_lib()
|
||||
.get_script_fn(name, args.len())
|
||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?;
|
||||
|
||||
@ -181,7 +181,7 @@ impl Engine {
|
||||
scope,
|
||||
mods,
|
||||
state,
|
||||
&[ast.lib()],
|
||||
&[ast.as_ref()],
|
||||
&mut this_ptr,
|
||||
fn_def,
|
||||
&mut args,
|
||||
|
@ -230,6 +230,12 @@ impl NativeCallContext<'_> {
|
||||
///
|
||||
/// If `is_method` is [`true`], the first argument is assumed to be passed
|
||||
/// by reference and is not consumed.
|
||||
///
|
||||
/// # Deprecated
|
||||
///
|
||||
/// This method is deprecated. Use [`call_fn_raw`][NativeCallContext::call_fn_raw] instead.
|
||||
///
|
||||
/// This method will be removed in the next major version.
|
||||
#[deprecated(since = "1.2.0", note = "use `call_fn_raw` instead")]
|
||||
#[inline(always)]
|
||||
pub fn call_fn_dynamic_raw(
|
||||
@ -250,3 +256,23 @@ impl<T> From<EvalAltResult> for Result<T, Box<EvalAltResult>> {
|
||||
Err(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl AST {
|
||||
/// _(internals)_ Get the internal [`Module`] containing all script-defined functions.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
///
|
||||
/// # Deprecated
|
||||
///
|
||||
/// This method is deprecated. Use [`shared_lib`][AST::shared_lib] instead.
|
||||
///
|
||||
/// This method will be removed in the next major version.
|
||||
#[deprecated(since = "1.3.0", note = "use `shared_lib` instead")]
|
||||
#[cfg(feature = "internals")]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn lib(&self) -> &Module {
|
||||
&self.functions
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ impl Engine {
|
||||
return Ok(Dynamic::UNIT);
|
||||
}
|
||||
|
||||
let lib = &[ast.lib()];
|
||||
let lib = &[ast.as_ref()];
|
||||
self.eval_global_statements(scope, mods, &mut state, statements, lib, level)
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,80 @@ use std::prelude::v1::*;
|
||||
|
||||
use std::num::{NonZeroU64, NonZeroUsize};
|
||||
|
||||
/// _(internals)_ A type containing all the limits imposed by the [`Engine`].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Not available under `unchecked`.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Limits {
|
||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||
///
|
||||
/// Set to zero to effectively disable function calls.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub max_call_stack_depth: usize,
|
||||
/// Maximum depth of statements/expressions at global level.
|
||||
pub max_expr_depth: Option<NonZeroUsize>,
|
||||
/// Maximum depth of statements/expressions in functions.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub max_function_expr_depth: Option<NonZeroUsize>,
|
||||
/// Maximum number of operations allowed to run.
|
||||
pub max_operations: Option<std::num::NonZeroU64>,
|
||||
/// Maximum number of [modules][Module] allowed to load.
|
||||
///
|
||||
/// Set to zero to effectively disable loading any [module][Module].
|
||||
///
|
||||
/// Not available under `no_module`.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub max_modules: usize,
|
||||
/// Maximum length of a [string][ImmutableString].
|
||||
pub max_string_size: Option<NonZeroUsize>,
|
||||
/// Maximum length of an [array][Array].
|
||||
///
|
||||
/// Not available under `no_index`.
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
pub max_array_size: Option<NonZeroUsize>,
|
||||
/// Maximum number of properties in an [object map][Map].
|
||||
///
|
||||
/// Not available under `no_object`.
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
pub max_map_size: Option<NonZeroUsize>,
|
||||
}
|
||||
|
||||
impl Limits {
|
||||
/// Create a new [`Limits`] with default values.
|
||||
///
|
||||
/// Not available under `unchecked`.
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
max_call_stack_depth: crate::engine::MAX_CALL_STACK_DEPTH,
|
||||
max_expr_depth: NonZeroUsize::new(crate::engine::MAX_EXPR_DEPTH),
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
max_function_expr_depth: NonZeroUsize::new(crate::engine::MAX_FUNCTION_EXPR_DEPTH),
|
||||
max_operations: None,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
max_modules: usize::MAX,
|
||||
max_string_size: None,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
max_array_size: None,
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
max_map_size: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Limits {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
/// Set the maximum levels of function calls allowed for a script in order to avoid
|
||||
/// infinite recursion and stack overflows.
|
||||
|
@ -75,7 +75,7 @@ impl Engine {
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let lib = ast
|
||||
.lib()
|
||||
.shared_lib()
|
||||
.iter_fn()
|
||||
.filter(|f| f.func.is_script())
|
||||
.map(|f| {
|
||||
|
@ -64,7 +64,7 @@ impl Engine {
|
||||
|
||||
let statements = ast.statements();
|
||||
if !statements.is_empty() {
|
||||
let lib = &[ast.lib()];
|
||||
let lib = &[ast.as_ref()];
|
||||
self.eval_global_statements(scope, mods, &mut state, statements, lib, 0)?;
|
||||
}
|
||||
Ok(())
|
||||
|
32
src/ast.rs
32
src/ast.rs
@ -302,8 +302,8 @@ impl AST {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub(crate) fn shared_lib(&self) -> Shared<Module> {
|
||||
self.functions.clone()
|
||||
pub(crate) fn shared_lib(&self) -> &Shared<Module> {
|
||||
&self.functions
|
||||
}
|
||||
/// _(internals)_ Get the internal shared [`Module`] containing all script-defined functions.
|
||||
/// Exported under the `internals` feature only.
|
||||
@ -314,24 +314,7 @@ impl AST {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn shared_lib(&self) -> Shared<Module> {
|
||||
self.functions.clone()
|
||||
}
|
||||
/// Get the internal [`Module`] containing all script-defined functions.
|
||||
#[cfg(not(feature = "internals"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub(crate) fn lib(&self) -> &Module {
|
||||
&self.functions
|
||||
}
|
||||
/// _(internals)_ Get the internal [`Module`] containing all script-defined functions.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
#[cfg(feature = "internals")]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn lib(&self) -> &Module {
|
||||
pub fn shared_lib(&self) -> &Shared<Module> {
|
||||
&self.functions
|
||||
}
|
||||
/// Get the embedded [module resolver][`ModuleResolver`].
|
||||
@ -895,7 +878,14 @@ impl AsRef<[Stmt]> for AST {
|
||||
impl AsRef<Module> for AST {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &Module {
|
||||
self.lib()
|
||||
self.shared_lib().as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Shared<Module>> for AST {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &Shared<Module> {
|
||||
self.shared_lib()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,9 @@ pub struct Imports {
|
||||
pub num_operations: u64,
|
||||
/// Number of modules loaded.
|
||||
pub num_modules: usize,
|
||||
/// Function call hashes to FN_IDX_GET and FN_IDX_SET.
|
||||
/// Function call hashes to index getters and setters.
|
||||
///
|
||||
/// Not available under `no_index` and `no_object`.
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
fn_hash_indexing: (u64, u64),
|
||||
/// Embedded module resolver.
|
||||
@ -74,11 +76,20 @@ pub struct Imports {
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub embedded_module_resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
||||
/// Cache of globally-defined constants.
|
||||
///
|
||||
/// Not available under `no_module` and `no_function`.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
global_constants: Option<Shared<crate::Locked<BTreeMap<Identifier, Dynamic>>>>,
|
||||
}
|
||||
|
||||
impl Default for Imports {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Imports {
|
||||
/// Create a new stack of imported [modules][Module].
|
||||
#[inline(always)]
|
||||
@ -129,12 +140,15 @@ impl Imports {
|
||||
#[must_use]
|
||||
pub fn find(&self, name: impl AsRef<str>) -> Option<usize> {
|
||||
let name = name.as_ref();
|
||||
let len = self.keys.len();
|
||||
|
||||
self.keys
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find_map(|(i, key)| if key == name { Some(i) } else { None })
|
||||
self.keys.iter().rev().enumerate().find_map(|(i, key)| {
|
||||
if key == name {
|
||||
Some(len - 1 - i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
/// Push an imported [module][Module] onto the stack.
|
||||
#[inline(always)]
|
||||
@ -154,8 +168,8 @@ impl Imports {
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&str, &Module)> {
|
||||
self.keys
|
||||
.iter()
|
||||
.zip(self.modules.iter())
|
||||
.rev()
|
||||
.zip(self.modules.iter().rev())
|
||||
.map(|(name, module)| (name.as_str(), module.as_ref()))
|
||||
}
|
||||
/// Get an iterator to this stack of imported [modules][Module] in reverse order.
|
||||
@ -812,69 +826,6 @@ impl EvalState {
|
||||
}
|
||||
}
|
||||
|
||||
/// _(internals)_ A type containing all the limits imposed by the [`Engine`].
|
||||
/// Exported under the `internals` feature only.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Limits {
|
||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||
///
|
||||
/// Set to zero to effectively disable function calls.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub max_call_stack_depth: usize,
|
||||
/// Maximum depth of statements/expressions at global level.
|
||||
pub max_expr_depth: Option<NonZeroUsize>,
|
||||
/// Maximum depth of statements/expressions in functions.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub max_function_expr_depth: Option<NonZeroUsize>,
|
||||
/// Maximum number of operations allowed to run.
|
||||
pub max_operations: Option<std::num::NonZeroU64>,
|
||||
/// Maximum number of [modules][Module] allowed to load.
|
||||
///
|
||||
/// Set to zero to effectively disable loading any [module][Module].
|
||||
///
|
||||
/// Not available under `no_module`.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub max_modules: usize,
|
||||
/// Maximum length of a [string][ImmutableString].
|
||||
pub max_string_size: Option<NonZeroUsize>,
|
||||
/// Maximum length of an [array][Array].
|
||||
///
|
||||
/// Not available under `no_index`.
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
pub max_array_size: Option<NonZeroUsize>,
|
||||
/// Maximum number of properties in an [object map][Map].
|
||||
///
|
||||
/// Not available under `no_object`.
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
pub max_map_size: Option<NonZeroUsize>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
impl Limits {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||
max_expr_depth: NonZeroUsize::new(MAX_EXPR_DEPTH),
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
max_function_expr_depth: NonZeroUsize::new(MAX_FUNCTION_EXPR_DEPTH),
|
||||
max_operations: None,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
max_modules: usize::MAX,
|
||||
max_string_size: None,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
max_array_size: None,
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
max_map_size: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Context of a script evaluation process.
|
||||
#[derive(Debug)]
|
||||
pub struct EvalContext<'a, 'x, 'px, 'm, 's, 'b, 't, 'pt> {
|
||||
@ -1024,7 +975,7 @@ pub struct Engine {
|
||||
|
||||
/// Max limits.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
pub(crate) limits: Limits,
|
||||
pub(crate) limits: crate::api::limits::Limits,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Engine {
|
||||
@ -1146,7 +1097,7 @@ impl Engine {
|
||||
optimization_level: crate::OptimizationLevel::default(),
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
limits: Limits::new(),
|
||||
limits: crate::api::limits::Limits::new(),
|
||||
};
|
||||
|
||||
// Add the global namespace module
|
||||
|
@ -886,7 +886,7 @@ impl Engine {
|
||||
)?;
|
||||
|
||||
// If new functions are defined within the eval string, it is an error
|
||||
if !ast.lib().is_empty() {
|
||||
if !ast.shared_lib().is_empty() {
|
||||
return Err(ParseErrorType::WrongFnDefinition.into());
|
||||
}
|
||||
|
||||
|
@ -190,13 +190,6 @@ impl fmt::Debug for Module {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Module> for Module {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &Module {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: AsRef<Module>> Add<M> for &Module {
|
||||
type Output = Module;
|
||||
|
||||
@ -1467,8 +1460,8 @@ impl Module {
|
||||
|
||||
// Non-private functions defined become module functions
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if !ast.lib().functions.is_empty() {
|
||||
ast.lib()
|
||||
if !ast.shared_lib().functions.is_empty() {
|
||||
ast.shared_lib()
|
||||
.functions
|
||||
.values()
|
||||
.filter(|f| match f.access {
|
||||
@ -1484,7 +1477,7 @@ impl Module {
|
||||
.expect("scripted function")
|
||||
.as_ref()
|
||||
.clone();
|
||||
func.lib = Some(ast.shared_lib());
|
||||
func.lib = Some(ast.shared_lib().clone());
|
||||
func.mods = func_mods.clone();
|
||||
module.set_script_fn(func);
|
||||
});
|
||||
@ -1728,6 +1721,17 @@ impl DerefMut for NamespaceRef {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Ident>> for NamespaceRef {
|
||||
#[inline(always)]
|
||||
fn from(mut path: Vec<Ident>) -> Self {
|
||||
path.shrink_to_fit();
|
||||
Self {
|
||||
index: None,
|
||||
path: path.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StaticVec<Ident>> for NamespaceRef {
|
||||
#[inline(always)]
|
||||
fn from(mut path: StaticVec<Ident>) -> Self {
|
||||
|
@ -728,8 +728,9 @@ mod array_functions {
|
||||
}
|
||||
|
||||
let mut result = initial;
|
||||
let len = array.len();
|
||||
|
||||
for (i, item) in array.iter().enumerate().rev() {
|
||||
for (i, item) in array.iter().rev().enumerate() {
|
||||
let item = item.clone();
|
||||
|
||||
result = reducer
|
||||
@ -738,7 +739,11 @@ mod array_functions {
|
||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
||||
if fn_sig.starts_with(reducer.fn_name()) =>
|
||||
{
|
||||
reducer.call_dynamic(&ctx, None, [result, item, (i as INT).into()])
|
||||
reducer.call_dynamic(
|
||||
&ctx,
|
||||
None,
|
||||
[result, item, ((len - 1 - i) as INT).into()],
|
||||
)
|
||||
}
|
||||
_ => Err(err),
|
||||
})
|
||||
|
@ -301,22 +301,21 @@ impl<'a> Scope<'a> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn contains(&self, name: &str) -> bool {
|
||||
self.names
|
||||
.iter()
|
||||
.rev() // Always search a Scope in reverse order
|
||||
.any(|(key, _)| name == key.as_ref())
|
||||
self.names.iter().any(|(key, _)| name == key.as_ref())
|
||||
}
|
||||
/// Find an entry in the [`Scope`], starting from the last.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, AccessMode)> {
|
||||
let len = self.len();
|
||||
|
||||
self.names
|
||||
.iter()
|
||||
.rev() // Always search a Scope in reverse order
|
||||
.enumerate()
|
||||
.find_map(|(index, (key, _))| {
|
||||
.find_map(|(i, (key, _))| {
|
||||
if name == key.as_ref() {
|
||||
let index = self.len() - 1 - index;
|
||||
let index = len - 1 - i;
|
||||
Some((index, self.values[index].access_mode()))
|
||||
} else {
|
||||
None
|
||||
@ -338,16 +337,14 @@ impl<'a> Scope<'a> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
||||
let len = self.len();
|
||||
|
||||
self.names
|
||||
.iter()
|
||||
.rev()
|
||||
.enumerate()
|
||||
.find(|(_, (key, _))| name == key.as_ref())
|
||||
.and_then(|(index, _)| {
|
||||
self.values[self.len() - 1 - index]
|
||||
.flatten_clone()
|
||||
.try_cast()
|
||||
})
|
||||
.and_then(|(index, _)| self.values[len - 1 - index].flatten_clone().try_cast())
|
||||
}
|
||||
/// Check if the named entry in the [`Scope`] is constant.
|
||||
///
|
||||
@ -522,14 +519,14 @@ impl<'a> Scope<'a> {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn clone_visible(&self) -> Self {
|
||||
let len = self.len();
|
||||
|
||||
self.names.iter().rev().enumerate().fold(
|
||||
Self::new(),
|
||||
|mut entries, (index, (name, alias))| {
|
||||
if !entries.names.iter().any(|(key, _)| key == name) {
|
||||
entries.names.push((name.clone(), alias.clone()));
|
||||
entries
|
||||
.values
|
||||
.push(self.values[self.len() - 1 - index].clone());
|
||||
entries.values.push(self.values[len - 1 - index].clone());
|
||||
}
|
||||
entries
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user