Reduce Module size.
This commit is contained in:
parent
bda8c2b636
commit
cefe3f1715
@ -3,8 +3,8 @@
|
||||
use crate::func::RegisterNativeFunction;
|
||||
use crate::types::dynamic::Variant;
|
||||
use crate::{
|
||||
Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, NativeCallContext,
|
||||
Position, RhaiResult, RhaiResultOf, Scope, SharedModule, AST,
|
||||
Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, Module, NativeCallContext,
|
||||
Position, RhaiResult, RhaiResultOf, Scope, SharedModule, TypeBuilder, AST,
|
||||
};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
@ -534,7 +534,7 @@ impl Position {
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<'a, T: Variant + Clone> crate::TypeBuilder<'a, T> {
|
||||
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
||||
/// Register a custom fallible function.
|
||||
///
|
||||
/// # Deprecated
|
||||
@ -642,3 +642,19 @@ impl<'a, T: Variant + Clone> crate::TypeBuilder<'a, T> {
|
||||
self.with_indexer_set(set_fn)
|
||||
}
|
||||
}
|
||||
|
||||
impl Module {
|
||||
/// Create a new [`Module`] with a pre-sized capacity for functions.
|
||||
///
|
||||
/// # Deprecated
|
||||
///
|
||||
/// This method is deprecated. Use `new` instead.
|
||||
///
|
||||
/// This method will be removed in the next major version.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
#[deprecated(since = "1.12.0", note = "use `new` instead")]
|
||||
pub fn with_capacity(_capacity: usize) -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ impl Engine {
|
||||
};
|
||||
|
||||
// Add the global namespace module
|
||||
let mut global_namespace = Module::with_capacity(0);
|
||||
let mut global_namespace = Module::new();
|
||||
global_namespace.flags |= ModuleFlags::INTERNAL;
|
||||
engine.global_modules.push(global_namespace.into());
|
||||
|
||||
|
@ -173,12 +173,13 @@ impl GlobalRuntimeState {
|
||||
name: impl Into<ImmutableString>,
|
||||
module: impl Into<crate::SharedModule>,
|
||||
) {
|
||||
if self.imports.is_none() {
|
||||
self.imports = Some(crate::StaticVec::new_const().into());
|
||||
self.modules = Some(crate::StaticVec::new_const().into());
|
||||
}
|
||||
self.imports.as_mut().unwrap().push(name.into());
|
||||
self.modules.as_mut().unwrap().push(module.into());
|
||||
self.imports
|
||||
.get_or_insert_with(|| crate::StaticVec::new_const().into())
|
||||
.push(name.into());
|
||||
|
||||
self.modules
|
||||
.get_or_insert_with(|| crate::StaticVec::new_const().into())
|
||||
.push(module.into());
|
||||
}
|
||||
/// Truncate the stack of globally-imported [modules][crate::Module] to a particular length.
|
||||
///
|
||||
@ -352,13 +353,12 @@ impl GlobalRuntimeState {
|
||||
impl<K: Into<ImmutableString>, M: Into<crate::SharedModule>> Extend<(K, M)> for GlobalRuntimeState {
|
||||
#[inline]
|
||||
fn extend<T: IntoIterator<Item = (K, M)>>(&mut self, iter: T) {
|
||||
if self.imports.is_none() {
|
||||
self.imports = Some(crate::StaticVec::new_const().into());
|
||||
self.modules = Some(crate::StaticVec::new_const().into());
|
||||
}
|
||||
|
||||
let imports = self.imports.as_mut().unwrap();
|
||||
let modules = self.modules.as_mut().unwrap();
|
||||
let imports = self
|
||||
.imports
|
||||
.get_or_insert_with(|| crate::StaticVec::new_const().into());
|
||||
let modules = self
|
||||
.modules
|
||||
.get_or_insert_with(|| crate::StaticVec::new_const().into());
|
||||
|
||||
for (k, m) in iter {
|
||||
imports.push(k.into());
|
||||
|
@ -177,26 +177,26 @@ pub struct Module {
|
||||
id: Option<ImmutableString>,
|
||||
/// Module documentation.
|
||||
#[cfg(feature = "metadata")]
|
||||
doc: crate::SmartString,
|
||||
doc: Option<crate::SmartString>,
|
||||
/// Custom types.
|
||||
custom_types: Option<CustomTypesCollection>,
|
||||
custom_types: Option<Box<CustomTypesCollection>>,
|
||||
/// Sub-modules.
|
||||
modules: Option<BTreeMap<Identifier, SharedModule>>,
|
||||
modules: Option<Box<BTreeMap<Identifier, SharedModule>>>,
|
||||
/// [`Module`] variables.
|
||||
variables: Option<BTreeMap<Identifier, Dynamic>>,
|
||||
variables: Option<Box<BTreeMap<Identifier, Dynamic>>>,
|
||||
/// Flattened collection of all [`Module`] variables, including those in sub-modules.
|
||||
all_variables: Option<StraightHashMap<Dynamic>>,
|
||||
all_variables: Option<Box<StraightHashMap<Dynamic>>>,
|
||||
/// Functions (both native Rust and scripted).
|
||||
functions: StraightHashMap<FuncInfo>,
|
||||
functions: Option<Box<StraightHashMap<FuncInfo>>>,
|
||||
/// Flattened collection of all functions, native Rust and scripted.
|
||||
/// including those in sub-modules.
|
||||
all_functions: Option<StraightHashMap<CallableFunction>>,
|
||||
all_functions: Option<Box<StraightHashMap<CallableFunction>>>,
|
||||
/// Bloom filter on native Rust functions (in scripted hash format) that contain [`Dynamic`] parameters.
|
||||
dynamic_functions_filter: BloomFilterU64,
|
||||
/// Iterator functions, keyed by the type producing the iterator.
|
||||
type_iterators: Option<BTreeMap<TypeId, Shared<IteratorFn>>>,
|
||||
type_iterators: Option<Box<BTreeMap<TypeId, Shared<IteratorFn>>>>,
|
||||
/// Flattened collection of iterator functions, including those in sub-modules.
|
||||
all_type_iterators: Option<BTreeMap<TypeId, Shared<IteratorFn>>>,
|
||||
all_type_iterators: Option<Box<BTreeMap<TypeId, Shared<IteratorFn>>>>,
|
||||
/// Flags.
|
||||
pub(crate) flags: ModuleFlags,
|
||||
}
|
||||
@ -282,31 +282,16 @@ impl Module {
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::with_capacity(16)
|
||||
}
|
||||
/// Create a new [`Module`] with a pre-sized capacity for functions.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use rhai::Module;
|
||||
/// let mut module = Module::with_capacity(10);
|
||||
/// module.set_var("answer", 42_i64);
|
||||
/// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
id: None,
|
||||
#[cfg(feature = "metadata")]
|
||||
doc: crate::SmartString::new_const(),
|
||||
doc: None,
|
||||
custom_types: None,
|
||||
modules: None,
|
||||
variables: None,
|
||||
all_variables: None,
|
||||
functions: StraightHashMap::with_capacity_and_hasher(capacity, Default::default()),
|
||||
functions: None,
|
||||
all_functions: None,
|
||||
dynamic_functions_filter: BloomFilterU64::new(),
|
||||
type_iterators: None,
|
||||
@ -396,7 +381,7 @@ impl Module {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn doc(&self) -> &str {
|
||||
&self.doc
|
||||
self.doc.as_ref().map_or("", |s| s.as_str())
|
||||
}
|
||||
|
||||
/// Set the documentation of the [`Module`].
|
||||
@ -415,7 +400,7 @@ impl Module {
|
||||
#[cfg(feature = "metadata")]
|
||||
#[inline(always)]
|
||||
pub fn set_doc(&mut self, doc: impl Into<crate::SmartString>) -> &mut Self {
|
||||
self.doc = doc.into();
|
||||
self.doc = Some(doc.into());
|
||||
self
|
||||
}
|
||||
|
||||
@ -434,7 +419,7 @@ impl Module {
|
||||
#[cfg(feature = "metadata")]
|
||||
#[inline(always)]
|
||||
pub fn clear_doc(&mut self) -> &mut Self {
|
||||
self.doc.clear();
|
||||
self.doc = None;
|
||||
self
|
||||
}
|
||||
|
||||
@ -442,12 +427,14 @@ impl Module {
|
||||
#[inline(always)]
|
||||
pub fn clear(&mut self) {
|
||||
#[cfg(feature = "metadata")]
|
||||
self.doc.clear();
|
||||
{
|
||||
self.doc = None;
|
||||
}
|
||||
self.custom_types = None;
|
||||
self.modules = None;
|
||||
self.variables = None;
|
||||
self.all_variables = None;
|
||||
self.functions.clear();
|
||||
self.functions = None;
|
||||
self.all_functions = None;
|
||||
self.dynamic_functions_filter.clear();
|
||||
self.type_iterators = None;
|
||||
@ -475,7 +462,7 @@ impl Module {
|
||||
#[inline(always)]
|
||||
pub fn set_custom_type<T>(&mut self, name: &str) -> &mut Self {
|
||||
self.custom_types
|
||||
.get_or_insert_with(CustomTypesCollection::new)
|
||||
.get_or_insert_with(|| CustomTypesCollection::new().into())
|
||||
.add_type::<T>(name);
|
||||
self
|
||||
}
|
||||
@ -501,7 +488,7 @@ impl Module {
|
||||
name: impl Into<Identifier>,
|
||||
) -> &mut Self {
|
||||
self.custom_types
|
||||
.get_or_insert_with(CustomTypesCollection::new)
|
||||
.get_or_insert_with(|| CustomTypesCollection::new().into())
|
||||
.add(type_path, name);
|
||||
self
|
||||
}
|
||||
@ -544,7 +531,7 @@ impl Module {
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
!self.flags.contains(ModuleFlags::INDEXED_GLOBAL_FUNCTIONS)
|
||||
&& self.functions.is_empty()
|
||||
&& self.functions.as_ref().map_or(true, |m| m.is_empty())
|
||||
&& self.variables.as_ref().map_or(true, |m| m.is_empty())
|
||||
&& self.modules.as_ref().map_or(true, |m| m.is_empty())
|
||||
&& self.type_iterators.as_ref().map_or(true, |t| t.is_empty())
|
||||
@ -700,23 +687,25 @@ impl Module {
|
||||
let hash_script = crate::calc_fn_hash(None, &fn_def.name, num_params);
|
||||
#[cfg(feature = "metadata")]
|
||||
let params_info = fn_def.params.iter().map(Into::into).collect();
|
||||
self.functions.insert(
|
||||
hash_script,
|
||||
FuncInfo {
|
||||
name: fn_def.name.as_str().into(),
|
||||
namespace: FnNamespace::Internal,
|
||||
access: fn_def.access,
|
||||
num_params,
|
||||
param_types: StaticVec::new_const(),
|
||||
#[cfg(feature = "metadata")]
|
||||
params_info,
|
||||
#[cfg(feature = "metadata")]
|
||||
return_type: "".into(),
|
||||
#[cfg(feature = "metadata")]
|
||||
comments: Box::default(),
|
||||
func: fn_def.into(),
|
||||
},
|
||||
);
|
||||
self.functions
|
||||
.get_or_insert_with(|| StraightHashMap::default().into())
|
||||
.insert(
|
||||
hash_script,
|
||||
FuncInfo {
|
||||
name: fn_def.name.as_str().into(),
|
||||
namespace: FnNamespace::Internal,
|
||||
access: fn_def.access,
|
||||
num_params,
|
||||
param_types: StaticVec::new_const(),
|
||||
#[cfg(feature = "metadata")]
|
||||
params_info,
|
||||
#[cfg(feature = "metadata")]
|
||||
return_type: "".into(),
|
||||
#[cfg(feature = "metadata")]
|
||||
comments: Box::default(),
|
||||
func: fn_def.into(),
|
||||
},
|
||||
);
|
||||
self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS;
|
||||
hash_script
|
||||
}
|
||||
@ -731,15 +720,13 @@ impl Module {
|
||||
name: impl AsRef<str>,
|
||||
num_params: usize,
|
||||
) -> Option<&Shared<crate::ast::ScriptFnDef>> {
|
||||
if self.functions.is_empty() {
|
||||
None
|
||||
} else {
|
||||
self.functions.as_ref().and_then(|lib| {
|
||||
let name = name.as_ref();
|
||||
|
||||
self.iter_fn()
|
||||
.find(|f| f.num_params == num_params && f.name == name)
|
||||
lib.values()
|
||||
.find(|&f| f.num_params == num_params && f.name == name)
|
||||
.and_then(|f| f.func.get_script_fn_def())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the underlying [`BTreeMap`] of sub-modules,
|
||||
@ -840,14 +827,12 @@ impl Module {
|
||||
/// let hash = module.set_native_fn("calc", || Ok(42_i64));
|
||||
/// assert!(module.contains_fn(hash));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn contains_fn(&self, hash_fn: u64) -> bool {
|
||||
if self.functions.is_empty() {
|
||||
false
|
||||
} else {
|
||||
self.functions.contains_key(&hash_fn)
|
||||
}
|
||||
self.functions
|
||||
.as_ref()
|
||||
.map_or(false, |m| m.contains_key(&hash_fn))
|
||||
}
|
||||
|
||||
/// _(metadata)_ Update the metadata (parameter names/types and return type) of a registered function.
|
||||
@ -876,7 +861,7 @@ impl Module {
|
||||
.map(|s| s.as_ref().into())
|
||||
.collect();
|
||||
|
||||
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
||||
if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) {
|
||||
let (param_names, return_type_name) = if param_names.len() > f.num_params {
|
||||
let return_type = param_names.pop().unwrap();
|
||||
(param_names, return_type)
|
||||
@ -925,7 +910,11 @@ impl Module {
|
||||
let comments = comments.as_ref();
|
||||
|
||||
if !comments.is_empty() {
|
||||
let f = self.functions.get_mut(&hash_fn).unwrap();
|
||||
let f = self
|
||||
.functions
|
||||
.as_mut()
|
||||
.and_then(|m| m.get_mut(&hash_fn))
|
||||
.unwrap();
|
||||
f.comments = comments.iter().map(|s| s.as_ref().into()).collect();
|
||||
}
|
||||
|
||||
@ -937,7 +926,7 @@ impl Module {
|
||||
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
|
||||
#[inline]
|
||||
pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self {
|
||||
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
||||
if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) {
|
||||
f.namespace = namespace;
|
||||
self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS;
|
||||
}
|
||||
@ -1029,23 +1018,27 @@ impl Module {
|
||||
self.dynamic_functions_filter.mark(hash_script);
|
||||
}
|
||||
|
||||
self.functions.insert(
|
||||
hash_fn,
|
||||
FuncInfo {
|
||||
func,
|
||||
name: name.into(),
|
||||
namespace,
|
||||
access,
|
||||
num_params: param_types.len(),
|
||||
param_types,
|
||||
#[cfg(feature = "metadata")]
|
||||
params_info: param_names,
|
||||
#[cfg(feature = "metadata")]
|
||||
return_type: return_type_name,
|
||||
#[cfg(feature = "metadata")]
|
||||
comments: Box::default(),
|
||||
},
|
||||
);
|
||||
self.functions
|
||||
.get_or_insert_with(|| {
|
||||
StraightHashMap::with_capacity_and_hasher(16, Default::default()).into()
|
||||
})
|
||||
.insert(
|
||||
hash_fn,
|
||||
FuncInfo {
|
||||
func,
|
||||
name: name.into(),
|
||||
namespace,
|
||||
access,
|
||||
num_params: param_types.len(),
|
||||
param_types,
|
||||
#[cfg(feature = "metadata")]
|
||||
params_info: param_names,
|
||||
#[cfg(feature = "metadata")]
|
||||
return_type: return_type_name,
|
||||
#[cfg(feature = "metadata")]
|
||||
comments: Box::default(),
|
||||
},
|
||||
);
|
||||
|
||||
self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS;
|
||||
|
||||
@ -1095,7 +1088,7 @@ impl Module {
|
||||
let comments = comments.as_ref();
|
||||
|
||||
if !comments.is_empty() {
|
||||
let f = self.functions.get_mut(&hash).unwrap();
|
||||
let f = self.functions.as_mut().unwrap().get_mut(&hash).unwrap();
|
||||
f.comments = comments.iter().map(|s| s.as_ref().into()).collect();
|
||||
}
|
||||
|
||||
@ -1533,11 +1526,10 @@ impl Module {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&CallableFunction> {
|
||||
if self.functions.is_empty() {
|
||||
None
|
||||
} else {
|
||||
self.functions.get(&hash_native).map(|f| &f.func)
|
||||
}
|
||||
self.functions
|
||||
.as_ref()
|
||||
.and_then(|m| m.get(&hash_native))
|
||||
.map(|f| &f.func)
|
||||
}
|
||||
|
||||
/// Can the particular function with [`Dynamic`] parameter(s) exist in the [`Module`]?
|
||||
@ -1590,7 +1582,13 @@ impl Module {
|
||||
Some(_) => (),
|
||||
None => self.variables = other.variables,
|
||||
}
|
||||
self.functions.extend(other.functions.into_iter());
|
||||
match self.functions {
|
||||
Some(ref mut m) if other.functions.is_some() => {
|
||||
m.extend(other.functions.unwrap().into_iter())
|
||||
}
|
||||
Some(_) => (),
|
||||
None => self.functions = other.functions,
|
||||
}
|
||||
self.dynamic_functions_filter += &other.dynamic_functions_filter;
|
||||
match self.type_iterators {
|
||||
Some(ref mut m) if other.type_iterators.is_some() => {
|
||||
@ -1605,11 +1603,15 @@ impl Module {
|
||||
self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS;
|
||||
|
||||
#[cfg(feature = "metadata")]
|
||||
if !other.doc.is_empty() {
|
||||
if !self.doc.is_empty() {
|
||||
self.doc.push('\n');
|
||||
if !other.doc.as_ref().map_or(true, |s| s.is_empty()) {
|
||||
if !self.doc.as_ref().map_or(true, |s| s.is_empty()) {
|
||||
self.doc
|
||||
.get_or_insert_with(|| SmartString::new_const())
|
||||
.push('\n');
|
||||
}
|
||||
self.doc.push_str(&other.doc);
|
||||
self.doc
|
||||
.get_or_insert_with(|| SmartString::new_const())
|
||||
.push_str(other.doc.as_ref().unwrap());
|
||||
}
|
||||
|
||||
self
|
||||
@ -1632,7 +1634,13 @@ impl Module {
|
||||
Some(_) => (),
|
||||
None => self.variables = other.variables,
|
||||
}
|
||||
self.functions.extend(other.functions.into_iter());
|
||||
match self.functions {
|
||||
Some(ref mut m) if other.functions.is_some() => {
|
||||
m.extend(other.functions.unwrap().into_iter())
|
||||
}
|
||||
Some(_) => (),
|
||||
None => self.functions = other.functions,
|
||||
}
|
||||
self.dynamic_functions_filter += &other.dynamic_functions_filter;
|
||||
match self.type_iterators {
|
||||
Some(ref mut m) if other.type_iterators.is_some() => {
|
||||
@ -1647,11 +1655,15 @@ impl Module {
|
||||
self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS;
|
||||
|
||||
#[cfg(feature = "metadata")]
|
||||
if !other.doc.is_empty() {
|
||||
if !self.doc.is_empty() {
|
||||
self.doc.push('\n');
|
||||
if !other.doc.as_ref().map_or(true, |s| s.is_empty()) {
|
||||
if !self.doc.as_ref().map_or(true, |s| s.is_empty()) {
|
||||
self.doc
|
||||
.get_or_insert_with(|| SmartString::new_const())
|
||||
.push('\n');
|
||||
}
|
||||
self.doc.push_str(&other.doc);
|
||||
self.doc
|
||||
.get_or_insert_with(|| SmartString::new_const())
|
||||
.push_str(other.doc.as_ref().unwrap());
|
||||
}
|
||||
|
||||
self
|
||||
@ -1664,23 +1676,29 @@ impl Module {
|
||||
if let Some(ref modules) = other.modules {
|
||||
let m = self.modules.get_or_insert_with(|| Default::default());
|
||||
|
||||
for (k, v) in modules {
|
||||
for (k, v) in modules.iter() {
|
||||
if !m.contains_key(k) {
|
||||
m.insert(k.clone(), v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref variables) = other.variables {
|
||||
for (k, v) in variables {
|
||||
let m = self.variables.get_or_insert_with(|| Default::default());
|
||||
for (k, v) in variables.iter() {
|
||||
let map = self.variables.get_or_insert_with(|| Default::default());
|
||||
|
||||
if !m.contains_key(k) {
|
||||
m.insert(k.clone(), v.clone());
|
||||
if !map.contains_key(k) {
|
||||
map.insert(k.clone(), v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (&k, v) in &other.functions {
|
||||
self.functions.entry(k).or_insert_with(|| v.clone());
|
||||
if let Some(ref functions) = other.functions {
|
||||
for (k, f) in functions.iter() {
|
||||
let map = self.functions.get_or_insert_with(|| Default::default());
|
||||
|
||||
if !map.contains_key(k) {
|
||||
map.insert(*k, f.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
self.dynamic_functions_filter += &other.dynamic_functions_filter;
|
||||
if let Some(ref type_iterators) = other.type_iterators {
|
||||
@ -1688,7 +1706,7 @@ impl Module {
|
||||
.type_iterators
|
||||
.get_or_insert_with(|| Default::default());
|
||||
|
||||
for (&k, v) in type_iterators {
|
||||
for (&k, v) in type_iterators.iter() {
|
||||
t.entry(k).or_insert_with(|| v.clone());
|
||||
}
|
||||
}
|
||||
@ -1698,11 +1716,15 @@ impl Module {
|
||||
self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS;
|
||||
|
||||
#[cfg(feature = "metadata")]
|
||||
if !other.doc.is_empty() {
|
||||
if !self.doc.is_empty() {
|
||||
self.doc.push('\n');
|
||||
if !other.doc.as_ref().map_or(true, |s| s.is_empty()) {
|
||||
if !self.doc.as_ref().map_or(true, |s| s.is_empty()) {
|
||||
self.doc
|
||||
.get_or_insert_with(|| SmartString::new_const())
|
||||
.push('\n');
|
||||
}
|
||||
self.doc.push_str(&other.doc);
|
||||
self.doc
|
||||
.get_or_insert_with(|| SmartString::new_const())
|
||||
.push_str(other.doc.as_ref().unwrap());
|
||||
}
|
||||
|
||||
self
|
||||
@ -1721,7 +1743,7 @@ impl Module {
|
||||
_filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool + Copy,
|
||||
) -> &mut Self {
|
||||
if let Some(ref modules) = other.modules {
|
||||
for (k, v) in modules {
|
||||
for (k, v) in modules.iter() {
|
||||
let mut m = Self::new();
|
||||
m.merge_filtered(v, _filter);
|
||||
self.set_sub_module(k.clone(), m);
|
||||
@ -1740,22 +1762,25 @@ impl Module {
|
||||
None => self.variables = other.variables.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
self.functions.extend(
|
||||
other
|
||||
.functions
|
||||
.iter()
|
||||
.filter(|&(.., f)| {
|
||||
_filter(
|
||||
f.namespace,
|
||||
f.access,
|
||||
f.func.is_script(),
|
||||
f.name.as_str(),
|
||||
f.num_params,
|
||||
)
|
||||
})
|
||||
.map(|(&k, v)| (k, v.clone())),
|
||||
);
|
||||
if let Some(ref functions) = other.functions {
|
||||
match self.functions {
|
||||
Some(ref mut m) => m.extend(
|
||||
functions
|
||||
.iter()
|
||||
.filter(|&(.., f)| {
|
||||
_filter(
|
||||
f.namespace,
|
||||
f.access,
|
||||
f.func.is_script(),
|
||||
f.name.as_str(),
|
||||
f.num_params,
|
||||
)
|
||||
})
|
||||
.map(|(&k, f)| (k, f.clone())),
|
||||
),
|
||||
None => self.functions = other.functions.clone(),
|
||||
}
|
||||
}
|
||||
self.dynamic_functions_filter += &other.dynamic_functions_filter;
|
||||
|
||||
if let Some(ref type_iterators) = other.type_iterators {
|
||||
@ -1770,11 +1795,15 @@ impl Module {
|
||||
self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS;
|
||||
|
||||
#[cfg(feature = "metadata")]
|
||||
if !other.doc.is_empty() {
|
||||
if !self.doc.is_empty() {
|
||||
self.doc.push('\n');
|
||||
if !other.doc.as_ref().map_or(true, |s| s.is_empty()) {
|
||||
if !self.doc.as_ref().map_or(true, |s| s.is_empty()) {
|
||||
self.doc
|
||||
.get_or_insert_with(|| SmartString::new_const())
|
||||
.push('\n');
|
||||
}
|
||||
self.doc.push_str(&other.doc);
|
||||
self.doc
|
||||
.get_or_insert_with(|| SmartString::new_const())
|
||||
.push_str(other.doc.as_ref().unwrap());
|
||||
}
|
||||
|
||||
self
|
||||
@ -1787,16 +1816,19 @@ impl Module {
|
||||
&mut self,
|
||||
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
|
||||
) -> &mut Self {
|
||||
self.functions = std::mem::take(&mut self.functions)
|
||||
.into_iter()
|
||||
.filter(|(.., f)| {
|
||||
if f.func.is_script() {
|
||||
filter(f.namespace, f.access, f.name.as_str(), f.num_params)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
self.functions = std::mem::take(&mut self.functions).map(|m| {
|
||||
Box::new(
|
||||
m.into_iter()
|
||||
.filter(|(.., f)| {
|
||||
if f.func.is_script() {
|
||||
filter(f.namespace, f.access, f.name.as_str(), f.num_params)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
});
|
||||
|
||||
self.dynamic_functions_filter.clear();
|
||||
self.all_functions = None;
|
||||
@ -1812,7 +1844,7 @@ impl Module {
|
||||
pub fn count(&self) -> (usize, usize, usize) {
|
||||
(
|
||||
self.variables.as_ref().map_or(0, |m| m.len()),
|
||||
self.functions.len(),
|
||||
self.functions.as_ref().map_or(0, |m| m.len()),
|
||||
self.type_iterators.as_ref().map_or(0, |t| t.len()),
|
||||
)
|
||||
}
|
||||
@ -1837,7 +1869,7 @@ impl Module {
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn iter_fn(&self) -> impl Iterator<Item = &FuncInfo> {
|
||||
self.functions.values()
|
||||
self.functions.iter().flat_map(|m| m.values())
|
||||
}
|
||||
|
||||
/// Get an iterator over all script-defined functions in the [`Module`].
|
||||
@ -2117,7 +2149,7 @@ impl Module {
|
||||
let mut contains_indexed_global_functions = false;
|
||||
|
||||
if let Some(ref modules) = module.modules {
|
||||
for (name, m) in modules {
|
||||
for (name, m) in modules.iter() {
|
||||
// Index all the sub-modules first.
|
||||
path.push(name);
|
||||
if index_module(m, path, variables, functions, type_iterators) {
|
||||
@ -2129,7 +2161,7 @@ impl Module {
|
||||
|
||||
// Index all variables
|
||||
if let Some(ref v) = module.variables {
|
||||
for (var_name, value) in v {
|
||||
for (var_name, value) in v.iter() {
|
||||
let hash_var = crate::calc_var_hash(path.iter().copied(), var_name);
|
||||
variables.insert(hash_var, value.clone());
|
||||
}
|
||||
@ -2137,13 +2169,13 @@ impl Module {
|
||||
|
||||
// Index type iterators
|
||||
if let Some(ref t) = module.type_iterators {
|
||||
for (&type_id, func) in t {
|
||||
for (&type_id, func) in t.iter() {
|
||||
type_iterators.insert(type_id, func.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Index all Rust functions
|
||||
for (&hash, f) in &module.functions {
|
||||
for (&hash, f) in module.functions.iter().flat_map(|m| m.iter()) {
|
||||
match f.namespace {
|
||||
FnNamespace::Global => {
|
||||
// Flatten all functions with global namespace
|
||||
@ -2194,17 +2226,17 @@ impl Module {
|
||||
self.all_variables = if variables.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(variables)
|
||||
Some(variables.into())
|
||||
};
|
||||
self.all_functions = if functions.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(functions)
|
||||
Some(functions.into())
|
||||
};
|
||||
self.all_type_iterators = if type_iterators.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(type_iterators)
|
||||
Some(type_iterators.into())
|
||||
};
|
||||
|
||||
self.flags |= ModuleFlags::INDEXED;
|
||||
|
146
src/parser.rs
146
src/parser.rs
@ -200,13 +200,12 @@ impl<'e, 's> ParseState<'e, 's> {
|
||||
.flat_map(|v| v.iter())
|
||||
.any(|v| v.as_str() == name)
|
||||
{
|
||||
if self.external_vars.is_none() {
|
||||
self.external_vars = Some(FnArgsVec::new().into());
|
||||
}
|
||||
self.external_vars.as_mut().unwrap().push(Ident {
|
||||
name: name.into(),
|
||||
pos: _pos,
|
||||
});
|
||||
self.external_vars
|
||||
.get_or_insert_with(|| FnArgsVec::new().into())
|
||||
.push(Ident {
|
||||
name: name.into(),
|
||||
pos: _pos,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
self.allow_capture = true;
|
||||
@ -2040,7 +2039,7 @@ impl Engine {
|
||||
}
|
||||
// var (indexed) = rhs
|
||||
Expr::Variable(ref x, i, var_pos) => {
|
||||
let stack = state.stack.as_mut().unwrap();
|
||||
let stack = state.stack.get_or_insert_with(|| Scope::new().into());
|
||||
let (index, .., name) = &**x;
|
||||
let index = i.map_or_else(
|
||||
|| index.expect("either long or short index is `None`").get(),
|
||||
@ -2462,10 +2461,10 @@ impl Engine {
|
||||
// Add a barrier variable to the stack so earlier variables will not be matched.
|
||||
// Variable searches stop at the first barrier.
|
||||
let marker = state.get_interned_string(SCOPE_SEARCH_BARRIER_MARKER);
|
||||
if state.stack.is_none() {
|
||||
state.stack = Some(Scope::new().into());
|
||||
}
|
||||
state.stack.as_mut().unwrap().push(marker, ());
|
||||
state
|
||||
.stack
|
||||
.get_or_insert_with(|| Scope::new().into())
|
||||
.push(marker, ());
|
||||
}
|
||||
|
||||
let mut user_state = Dynamic::UNIT;
|
||||
@ -2817,26 +2816,29 @@ impl Engine {
|
||||
.parse_expr(input, state, lib, settings.level_up()?)?
|
||||
.ensure_iterable()?;
|
||||
|
||||
if state.stack.is_none() {
|
||||
state.stack = Some(Scope::new().into());
|
||||
}
|
||||
let prev_stack_len = state.stack.as_mut().unwrap().len();
|
||||
|
||||
if !counter_name.is_empty() {
|
||||
state.stack.as_mut().unwrap().push(name.clone(), ());
|
||||
}
|
||||
let counter_var = Ident {
|
||||
name: state.get_interned_string(counter_name),
|
||||
pos: counter_pos,
|
||||
};
|
||||
|
||||
let loop_var = state.get_interned_string(name);
|
||||
state.stack.as_mut().unwrap().push(loop_var.clone(), ());
|
||||
let loop_var = Ident {
|
||||
name: loop_var,
|
||||
name: state.get_interned_string(name),
|
||||
pos: name_pos,
|
||||
};
|
||||
|
||||
let prev_stack_len = {
|
||||
let stack = state.stack.get_or_insert_with(|| Scope::new().into());
|
||||
|
||||
let prev_stack_len = stack.len();
|
||||
|
||||
if !counter_var.name.is_empty() {
|
||||
stack.push(counter_var.name.clone(), ());
|
||||
}
|
||||
stack.push(&loop_var.name, ());
|
||||
|
||||
prev_stack_len
|
||||
};
|
||||
|
||||
settings.flags |= ParseSettingFlags::BREAKABLE;
|
||||
let body = self.parse_block(input, state, lib, settings.level_up()?)?;
|
||||
|
||||
@ -2865,49 +2867,41 @@ impl Engine {
|
||||
// let name ...
|
||||
let (name, pos) = parse_var_name(input)?;
|
||||
|
||||
if state.stack.is_none() {
|
||||
state.stack = Some(Scope::new().into());
|
||||
}
|
||||
if !self.allow_shadowing()
|
||||
&& state
|
||||
.stack
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|(v, ..)| v == name)
|
||||
{
|
||||
return Err(PERR::VariableExists(name.into()).into_err(pos));
|
||||
}
|
||||
let stack = state.stack.get_or_insert_with(|| Scope::new().into());
|
||||
|
||||
if let Some(ref filter) = self.def_var_filter {
|
||||
let stack = state.stack.as_mut().unwrap();
|
||||
let will_shadow = stack.iter().any(|(v, ..)| v == name);
|
||||
|
||||
if state.global.is_none() {
|
||||
state.global = Some(GlobalRuntimeState::new(self).into());
|
||||
if !self.allow_shadowing() && stack.iter().any(|(v, ..)| v == name) {
|
||||
return Err(PERR::VariableExists(name.into()).into_err(pos));
|
||||
}
|
||||
let global = state.global.as_mut().unwrap();
|
||||
|
||||
global.level = settings.level;
|
||||
let is_const = access == AccessMode::ReadOnly;
|
||||
let info = VarDefInfo {
|
||||
name: &name,
|
||||
is_const,
|
||||
nesting_level: settings.level,
|
||||
will_shadow,
|
||||
};
|
||||
let caches = &mut Caches::new();
|
||||
let mut this = Dynamic::NULL;
|
||||
if let Some(ref filter) = self.def_var_filter {
|
||||
let will_shadow = stack.iter().any(|(v, ..)| v == name);
|
||||
|
||||
let context = EvalContext::new(self, global, caches, stack, &mut this);
|
||||
let global = state
|
||||
.global
|
||||
.get_or_insert_with(|| GlobalRuntimeState::new(self).into());
|
||||
|
||||
match filter(false, info, context) {
|
||||
Ok(true) => (),
|
||||
Ok(false) => return Err(PERR::ForbiddenVariable(name.into()).into_err(pos)),
|
||||
Err(err) => match *err {
|
||||
EvalAltResult::ErrorParsing(e, pos) => return Err(e.into_err(pos)),
|
||||
_ => return Err(PERR::ForbiddenVariable(name.into()).into_err(pos)),
|
||||
},
|
||||
global.level = settings.level;
|
||||
let is_const = access == AccessMode::ReadOnly;
|
||||
let info = VarDefInfo {
|
||||
name: &name,
|
||||
is_const,
|
||||
nesting_level: settings.level,
|
||||
will_shadow,
|
||||
};
|
||||
let caches = &mut Caches::new();
|
||||
let mut this = Dynamic::NULL;
|
||||
|
||||
let context = EvalContext::new(self, global, caches, stack, &mut this);
|
||||
|
||||
match filter(false, info, context) {
|
||||
Ok(true) => (),
|
||||
Ok(false) => return Err(PERR::ForbiddenVariable(name.into()).into_err(pos)),
|
||||
Err(err) => match *err {
|
||||
EvalAltResult::ErrorParsing(e, pos) => return Err(e.into_err(pos)),
|
||||
_ => return Err(PERR::ForbiddenVariable(name.into()).into_err(pos)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2945,7 +2939,7 @@ impl Engine {
|
||||
|
||||
let idx = if let Some(n) = existing {
|
||||
stack.get_mut_by_index(n).set_access_mode(access);
|
||||
Some(NonZeroUsize::new(state.stack.as_mut().unwrap().len() - n).unwrap())
|
||||
Some(NonZeroUsize::new(stack.len() - n).unwrap())
|
||||
} else {
|
||||
stack.push_entry(name.as_str(), access, Dynamic::UNIT);
|
||||
None
|
||||
@ -3470,12 +3464,11 @@ impl Engine {
|
||||
.into_err(err_pos));
|
||||
}
|
||||
|
||||
if state.stack.is_none() {
|
||||
state.stack = Some(Scope::new().into());
|
||||
}
|
||||
|
||||
let name = state.get_interned_string(name);
|
||||
state.stack.as_mut().unwrap().push(name.clone(), ());
|
||||
state
|
||||
.stack
|
||||
.get_or_insert_with(|| Scope::new().into())
|
||||
.push(name.clone(), ());
|
||||
Ident { name, pos }
|
||||
} else {
|
||||
Ident {
|
||||
@ -3489,8 +3482,7 @@ impl Engine {
|
||||
|
||||
if !catch_var.is_empty() {
|
||||
// Remove the error variable from the stack
|
||||
let stack = state.stack.as_mut().unwrap();
|
||||
stack.rewind(stack.len() - 1);
|
||||
state.stack.as_mut().unwrap().pop();
|
||||
}
|
||||
|
||||
Ok(Stmt::TryCatch(
|
||||
@ -3554,12 +3546,11 @@ impl Engine {
|
||||
);
|
||||
}
|
||||
|
||||
if state.stack.is_none() {
|
||||
state.stack = Some(Scope::new().into());
|
||||
}
|
||||
|
||||
let s = state.get_interned_string(*s);
|
||||
state.stack.as_mut().unwrap().push(s.clone(), ());
|
||||
state
|
||||
.stack
|
||||
.get_or_insert_with(|| Scope::new().into())
|
||||
.push(s.clone(), ());
|
||||
params.push((s, pos));
|
||||
}
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
||||
@ -3700,12 +3691,11 @@ impl Engine {
|
||||
);
|
||||
}
|
||||
|
||||
if state.stack.is_none() {
|
||||
state.stack = Some(Scope::new().into());
|
||||
}
|
||||
|
||||
let s = state.get_interned_string(*s);
|
||||
state.stack.as_mut().unwrap().push(s.clone(), ());
|
||||
state
|
||||
.stack
|
||||
.get_or_insert_with(|| Scope::new().into())
|
||||
.push(s.clone(), ());
|
||||
params_list.push(s);
|
||||
}
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
||||
|
@ -353,6 +353,43 @@ impl Scope<'_> {
|
||||
self.values.push(value);
|
||||
self
|
||||
}
|
||||
/// Remove the last entry from the [`Scope`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics is the [`Scope`] is empty.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::Scope;
|
||||
///
|
||||
/// let mut my_scope = Scope::new();
|
||||
///
|
||||
/// my_scope.push("x", 42_i64);
|
||||
/// my_scope.push("y", 123_i64);
|
||||
/// assert!(my_scope.contains("x"));
|
||||
/// assert!(my_scope.contains("y"));
|
||||
/// assert_eq!(my_scope.len(), 2);
|
||||
///
|
||||
/// my_scope.pop();
|
||||
/// assert!(my_scope.contains("x"));
|
||||
/// assert!(!my_scope.contains("y"));
|
||||
/// assert_eq!(my_scope.len(), 1);
|
||||
///
|
||||
/// my_scope.pop();
|
||||
/// assert!(!my_scope.contains("x"));
|
||||
/// assert!(!my_scope.contains("y"));
|
||||
/// assert_eq!(my_scope.len(), 0);
|
||||
/// assert!(my_scope.is_empty());
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn pop(&mut self) -> &mut Self {
|
||||
self.names.pop().expect("`Scope` must not be empty");
|
||||
self.values.pop().expect("`Scope` must not be empty");
|
||||
self.aliases.pop().expect("`Scope` must not be empty");
|
||||
self
|
||||
}
|
||||
/// Truncate (rewind) the [`Scope`] to a previous size.
|
||||
///
|
||||
/// # Example
|
||||
|
Loading…
Reference in New Issue
Block a user