Add checks for is_empty.

This commit is contained in:
Stephen Chung 2022-03-03 13:02:57 +08:00
parent 83755bf936
commit 0e9a16e437
18 changed files with 202 additions and 110 deletions

View File

@ -101,7 +101,8 @@ impl Engine {
// Collect all `import` statements with a string constant path // Collect all `import` statements with a string constant path
ASTNode::Stmt(Stmt::Import(x, ..)) => match x.0 { ASTNode::Stmt(Stmt::Import(x, ..)) => match x.0 {
Expr::StringConstant(ref s, ..) Expr::StringConstant(ref s, ..)
if !resolver.contains_path(s) && !imports.contains(s.as_str()) => if !resolver.contains_path(s)
&& (imports.is_empty() || !imports.contains(s.as_str())) =>
{ {
imports.insert(s.clone().into()); imports.insert(s.clone().into());
true true

View File

@ -227,9 +227,10 @@ impl Engine {
// Standard or reserved keyword/symbol not in first position // Standard or reserved keyword/symbol not in first position
_ if !segments.is_empty() && token.is_some() => { _ if !segments.is_empty() && token.is_some() => {
// Make it a custom keyword/symbol if it is disabled or reserved // Make it a custom keyword/symbol if it is disabled or reserved
if (self.disabled_symbols.contains(s) if ((!self.disabled_symbols.is_empty() && self.disabled_symbols.contains(s))
|| token.map_or(false, |v| v.is_reserved())) || token.map_or(false, |v| v.is_reserved()))
&& !self.custom_keywords.contains_key(s) && (self.custom_keywords.is_empty()
|| !self.custom_keywords.contains_key(s))
{ {
self.custom_keywords.insert(s.into(), None); self.custom_keywords.insert(s.into(), None);
} }
@ -238,7 +239,7 @@ impl Engine {
// Standard keyword in first position but not disabled // Standard keyword in first position but not disabled
_ if segments.is_empty() _ if segments.is_empty()
&& token.as_ref().map_or(false, |v| v.is_standard_keyword()) && token.as_ref().map_or(false, |v| v.is_standard_keyword())
&& !self.disabled_symbols.contains(s) => && (self.disabled_symbols.is_empty() || !self.disabled_symbols.contains(s)) =>
{ {
return Err(LexError::ImproperSymbol( return Err(LexError::ImproperSymbol(
s.to_string(), s.to_string(),
@ -253,9 +254,11 @@ impl Engine {
// Identifier in first position // Identifier in first position
_ if segments.is_empty() && is_valid_identifier(s.chars()) => { _ if segments.is_empty() && is_valid_identifier(s.chars()) => {
// Make it a custom keyword/symbol if it is disabled or reserved // Make it a custom keyword/symbol if it is disabled or reserved
if self.disabled_symbols.contains(s) || token.map_or(false, |v| v.is_reserved()) if (!self.disabled_symbols.is_empty() && self.disabled_symbols.contains(s))
|| token.map_or(false, |v| v.is_reserved())
{ {
if !self.custom_keywords.contains_key(s) { if self.custom_keywords.is_empty() || !self.custom_keywords.contains_key(s)
{
self.custom_keywords.insert(s.into(), None); self.custom_keywords.insert(s.into(), None);
} }
} }

View File

@ -162,18 +162,25 @@ impl Engine {
// Active standard keywords cannot be made custom // Active standard keywords cannot be made custom
// Disabled keywords are OK // Disabled keywords are OK
Some(token) if token.is_standard_keyword() => { Some(token) if token.is_standard_keyword() => {
if !self.disabled_symbols.contains(&*token.syntax()) { if self.disabled_symbols.is_empty()
|| !self.disabled_symbols.contains(&*token.syntax())
{
return Err(format!("'{}' is a reserved keyword", keyword.as_ref())); return Err(format!("'{}' is a reserved keyword", keyword.as_ref()));
} }
} }
// Active standard symbols cannot be made custom // Active standard symbols cannot be made custom
Some(token) if token.is_standard_symbol() => { Some(token) if token.is_standard_symbol() => {
if !self.disabled_symbols.contains(&*token.syntax()) { if self.disabled_symbols.is_empty()
|| !self.disabled_symbols.contains(&*token.syntax())
{
return Err(format!("'{}' is a reserved operator", keyword.as_ref())); return Err(format!("'{}' is a reserved operator", keyword.as_ref()));
} }
} }
// Active standard symbols cannot be made custom // Active standard symbols cannot be made custom
Some(token) if !self.disabled_symbols.contains(&*token.syntax()) => { Some(token)
if self.disabled_symbols.is_empty()
|| !self.disabled_symbols.contains(&*token.syntax()) =>
{
return Err(format!("'{}' is a reserved symbol", keyword.as_ref())) return Err(format!("'{}' is a reserved symbol", keyword.as_ref()))
} }
// Disabled symbols are OK // Disabled symbols are OK

View File

@ -1003,7 +1003,7 @@ impl Engine {
let sub_module = iter.next().expect("contains separator").trim(); let sub_module = iter.next().expect("contains separator").trim();
let remainder = iter.next().expect("contains separator").trim(); let remainder = iter.next().expect("contains separator").trim();
if !root.contains_key(sub_module) { if root.is_empty() || !root.contains_key(sub_module) {
let mut m = Module::new(); let mut m = Module::new();
register_static_module_raw(m.sub_modules_mut(), remainder, module); register_static_module_raw(m.sub_modules_mut(), remainder, module);
m.build_index(); m.build_index();

View File

@ -907,7 +907,7 @@ impl Engine {
self.make_type_mismatch_err::<crate::ImmutableString>(idx.type_name(), idx_pos) self.make_type_mismatch_err::<crate::ImmutableString>(idx.type_name(), idx_pos)
})?; })?;
if _add_if_not_found && !map.contains_key(index.as_str()) { if _add_if_not_found && (map.is_empty() || !map.contains_key(index.as_str())) {
map.insert(index.clone().into(), Dynamic::UNIT); map.insert(index.clone().into(), Dynamic::UNIT);
} }

View File

@ -20,7 +20,7 @@ impl Engine {
state: &mut EvalState, state: &mut EvalState,
namespace: &crate::module::Namespace, namespace: &crate::module::Namespace,
) -> Option<crate::Shared<Module>> { ) -> Option<crate::Shared<Module>> {
let root = &namespace[0].name; let root = namespace.root();
// Qualified - check if the root module is directly indexed // Qualified - check if the root module is directly indexed
let index = if state.always_search_scope { let index = if state.always_search_scope {
@ -72,32 +72,24 @@ impl Engine {
(_, Some((namespace, hash_var)), var_name) => { (_, Some((namespace, hash_var)), var_name) => {
// foo:bar::baz::VARIABLE // foo:bar::baz::VARIABLE
if let Some(module) = self.search_imports(global, state, namespace) { if let Some(module) = self.search_imports(global, state, namespace) {
return match module.get_qualified_var(*hash_var) { return if let Some(mut target) = module.get_qualified_var(*hash_var) {
Ok(target) => { // Module variables are constant
let mut target = target.clone(); target.set_access_mode(AccessMode::ReadOnly);
// Module variables are constant Ok((target.into(), *_var_pos))
target.set_access_mode(AccessMode::ReadOnly); } else {
Ok((target.into(), *_var_pos)) let sep = crate::tokenizer::Token::DoubleColon.literal_syntax();
}
Err(err) => Err(match *err { Err(ERR::ErrorVariableNotFound(
ERR::ErrorVariableNotFound(..) => ERR::ErrorVariableNotFound( format!("{}{}{}", namespace, sep, var_name),
format!( namespace.position(),
"{}{}{}", )
namespace, .into())
crate::tokenizer::Token::DoubleColon.literal_syntax(),
var_name
),
namespace[0].pos,
)
.into(),
_ => err.fill_position(*_var_pos),
}),
}; };
} }
// global::VARIABLE // global::VARIABLE
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
if namespace.len() == 1 && namespace[0].name == crate::engine::KEYWORD_GLOBAL { if namespace.len() == 1 && namespace.root() == crate::engine::KEYWORD_GLOBAL {
if let Some(ref constants) = global.constants { if let Some(ref constants) = global.constants {
if let Some(value) = if let Some(value) =
crate::func::locked_write(constants).get_mut(var_name) crate::func::locked_write(constants).get_mut(var_name)
@ -109,19 +101,19 @@ impl Engine {
} }
} }
let sep = crate::tokenizer::Token::DoubleColon.literal_syntax();
return Err(ERR::ErrorVariableNotFound( return Err(ERR::ErrorVariableNotFound(
format!( format!("{}{}{}", namespace, sep, var_name),
"{}{}{}", namespace.position(),
namespace,
crate::tokenizer::Token::DoubleColon.literal_syntax(),
var_name
),
namespace[0].pos,
) )
.into()); .into());
} }
Err(ERR::ErrorModuleNotFound(namespace.to_string(), namespace[0].pos).into()) Err(
ERR::ErrorModuleNotFound(namespace.to_string(), namespace.position())
.into(),
)
} }
}, },
_ => unreachable!("Expr::Variable expected but gets {:?}", expr), _ => unreachable!("Expr::Variable expected but gets {:?}", expr),

View File

@ -288,7 +288,7 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
OP_CONTAINS => Some(|_, args| { OP_CONTAINS => Some(|_, args| {
let blob = &*args[0].read_lock::<Blob>().expect(BUILTIN); let blob = &*args[0].read_lock::<Blob>().expect(BUILTIN);
let x = (args[1].as_int().expect("`INT`") & 0x000000ff) as u8; let x = (args[1].as_int().expect("`INT`") & 0x000000ff) as u8;
Ok(blob.contains(&x).into()) Ok((!blob.is_empty() && blob.contains(&x)).into())
}), }),
_ => None, _ => None,
}; };

View File

@ -1353,7 +1353,7 @@ impl Engine {
let module = self let module = self
.search_imports(global, state, namespace) .search_imports(global, state, namespace)
.ok_or_else(|| ERR::ErrorModuleNotFound(namespace.to_string(), namespace[0].pos))?; .ok_or_else(|| ERR::ErrorModuleNotFound(namespace.to_string(), namespace.position()))?;
// First search in script-defined functions (can override built-in) // First search in script-defined functions (can override built-in)
let func = match module.get_qualified_fn(hash) { let func = match module.get_qualified_fn(hash) {

View File

@ -41,20 +41,30 @@ pub use std::sync::Arc as Shared;
#[allow(dead_code)] #[allow(dead_code)]
pub use std::cell::RefCell as Locked; pub use std::cell::RefCell as Locked;
/// Lock guard for synchronized shared object. /// Read-only lock guard for synchronized shared object.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
#[allow(dead_code)] #[allow(dead_code)]
pub type LockGuard<'a, T> = std::cell::RefMut<'a, T>; pub type LockGuard<'a, T> = std::cell::Ref<'a, T>;
/// Mutable lock guard for synchronized shared object.
#[cfg(not(feature = "sync"))]
#[allow(dead_code)]
pub type LockGuardMut<'a, T> = std::cell::RefMut<'a, T>;
/// Synchronized shared object. /// Synchronized shared object.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
#[allow(dead_code)] #[allow(dead_code)]
pub use std::sync::RwLock as Locked; pub use std::sync::RwLock as Locked;
/// Lock guard for synchronized shared object. /// Read-only lock guard for synchronized shared object.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
#[allow(dead_code)] #[allow(dead_code)]
pub type LockGuard<'a, T> = std::sync::RwLockWriteGuard<'a, T>; pub type LockGuard<'a, T> = std::sync::RwLockReadGuard<'a, T>;
/// Mutable lock guard for synchronized shared object.
#[cfg(feature = "sync")]
#[allow(dead_code)]
pub type LockGuardMut<'a, T> = std::sync::RwLockWriteGuard<'a, T>;
/// Context of a native Rust function call. /// Context of a native Rust function call.
#[derive(Debug)] #[derive(Debug)]
@ -374,11 +384,23 @@ pub fn shared_take<T>(value: Shared<T>) -> T {
shared_try_take(value).ok().expect("not shared") shared_try_take(value).ok().expect("not shared")
} }
/// Lock a [`Locked`] resource. /// Lock a [`Locked`] resource for mutable access.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
#[allow(dead_code)] #[allow(dead_code)]
pub fn locked_write<'a, T>(value: &'a Locked<T>) -> LockGuard<'a, T> { pub fn locked_read<'a, T>(value: &'a Locked<T>) -> LockGuard<'a, T> {
#[cfg(not(feature = "sync"))]
return value.borrow();
#[cfg(feature = "sync")]
return value.read().unwrap();
}
/// Lock a [`Locked`] resource for mutable access.
#[inline(always)]
#[must_use]
#[allow(dead_code)]
pub fn locked_write<'a, T>(value: &'a Locked<T>) -> LockGuardMut<'a, T> {
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
return value.borrow_mut(); return value.borrow_mut();

View File

@ -488,7 +488,11 @@ impl Module {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn contains_var(&self, name: &str) -> bool { pub fn contains_var(&self, name: &str) -> bool {
self.variables.contains_key(name) if !self.variables.is_empty() {
self.variables.contains_key(name)
} else {
false
}
} }
/// Get the value of a [`Module`] variable. /// Get the value of a [`Module`] variable.
@ -520,7 +524,11 @@ impl Module {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn get_var(&self, name: &str) -> Option<Dynamic> { pub fn get_var(&self, name: &str) -> Option<Dynamic> {
self.variables.get(name).cloned() if !self.variables.is_empty() {
self.variables.get(name).cloned()
} else {
None
}
} }
/// Set a variable into the [`Module`]. /// Set a variable into the [`Module`].
@ -552,14 +560,15 @@ impl Module {
self self
} }
/// Get a reference to a namespace-qualified variable. /// Get a namespace-qualified [`Module`] variable as a [`Dynamic`].
/// Name and Position in [`EvalAltResult`] are [`None`] and [`NONE`][Position::NONE] and must be set afterwards.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline] #[inline]
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> RhaiResultOf<&Dynamic> { pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Option<Dynamic> {
self.all_variables.get(&hash_var).ok_or_else(|| { if !self.all_variables.is_empty() {
crate::ERR::ErrorVariableNotFound(String::new(), crate::Position::NONE).into() self.all_variables.get(&hash_var).cloned()
}) } else {
None
}
} }
/// Set a script-defined function into the [`Module`]. /// Set a script-defined function into the [`Module`].
@ -610,14 +619,14 @@ impl Module {
name: impl AsRef<str>, name: impl AsRef<str>,
num_params: usize, num_params: usize,
) -> Option<&Shared<crate::ast::ScriptFnDef>> { ) -> Option<&Shared<crate::ast::ScriptFnDef>> {
if self.functions.is_empty() { if !self.functions.is_empty() {
None
} else {
let name = name.as_ref(); let name = name.as_ref();
self.iter_fn() self.iter_fn()
.find(|f| f.metadata.params == num_params && f.metadata.name == name) .find(|f| f.metadata.params == num_params && f.metadata.name == name)
.and_then(|f| f.func.get_script_fn_def()) .and_then(|f| f.func.get_script_fn_def())
} else {
None
} }
} }
@ -656,7 +665,11 @@ impl Module {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn contains_sub_module(&self, name: &str) -> bool { pub fn contains_sub_module(&self, name: &str) -> bool {
self.modules.contains_key(name) if !self.modules.is_empty() {
self.modules.contains_key(name)
} else {
false
}
} }
/// Get a sub-module in the [`Module`]. /// Get a sub-module in the [`Module`].
@ -673,7 +686,11 @@ impl Module {
#[inline] #[inline]
#[must_use] #[must_use]
pub fn get_sub_module(&self, name: &str) -> Option<&Module> { pub fn get_sub_module(&self, name: &str) -> Option<&Module> {
self.modules.get(name).map(|m| m.as_ref()) if !self.modules.is_empty() {
self.modules.get(name).map(|m| m.as_ref())
} else {
None
}
} }
/// Set a sub-module into the [`Module`]. /// Set a sub-module into the [`Module`].
@ -716,7 +733,11 @@ impl Module {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn contains_fn(&self, hash_fn: u64) -> bool { pub fn contains_fn(&self, hash_fn: u64) -> bool {
self.functions.contains_key(&hash_fn) if !self.functions.is_empty() {
self.functions.contains_key(&hash_fn)
} else {
false
}
} }
/// _(metadata)_ Update the metadata (parameter names/types and return type) of a registered function. /// _(metadata)_ Update the metadata (parameter names/types and return type) of a registered function.
@ -1357,7 +1378,11 @@ impl Module {
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn get_fn(&self, hash_fn: u64) -> Option<&CallableFunction> { pub(crate) fn get_fn(&self, hash_fn: u64) -> Option<&CallableFunction> {
self.functions.get(&hash_fn).map(|f| f.func.as_ref()) if !self.functions.is_empty() {
self.functions.get(&hash_fn).map(|f| f.func.as_ref())
} else {
None
}
} }
/// Does the particular namespace-qualified function exist in the [`Module`]? /// Does the particular namespace-qualified function exist in the [`Module`]?
@ -1366,7 +1391,11 @@ impl Module {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn contains_qualified_fn(&self, hash_fn: u64) -> bool { pub fn contains_qualified_fn(&self, hash_fn: u64) -> bool {
self.all_functions.contains_key(&hash_fn) if !self.all_functions.is_empty() {
self.all_functions.contains_key(&hash_fn)
} else {
false
}
} }
/// Get a namespace-qualified function. /// Get a namespace-qualified function.
@ -1376,9 +1405,13 @@ impl Module {
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> { pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
self.all_functions if !self.all_functions.is_empty() {
.get(&hash_qualified_fn) self.all_functions
.map(|f| f.as_ref()) .get(&hash_qualified_fn)
.map(|f| f.as_ref())
} else {
None
}
} }
/// Combine another [`Module`] into this [`Module`]. /// Combine another [`Module`] into this [`Module`].
@ -1906,14 +1939,22 @@ impl Module {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn contains_qualified_iter(&self, id: TypeId) -> bool { pub fn contains_qualified_iter(&self, id: TypeId) -> bool {
self.all_type_iterators.contains_key(&id) if !self.all_type_iterators.is_empty() {
self.all_type_iterators.contains_key(&id)
} else {
false
}
} }
/// Does a type iterator exist in the module? /// Does a type iterator exist in the module?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn contains_iter(&self, id: TypeId) -> bool { pub fn contains_iter(&self, id: TypeId) -> bool {
self.type_iterators.contains_key(&id) if !self.type_iterators.is_empty() {
self.type_iterators.contains_key(&id)
} else {
false
}
} }
/// Set a type iterator into the [`Module`]. /// Set a type iterator into the [`Module`].
@ -1979,14 +2020,22 @@ impl Module {
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&IteratorFn> { pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&IteratorFn> {
self.all_type_iterators.get(&id).map(|f| f.as_ref()) if !self.all_type_iterators.is_empty() {
self.all_type_iterators.get(&id).map(|f| f.as_ref())
} else {
None
}
} }
/// Get the specified type iterator. /// Get the specified type iterator.
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> { pub(crate) fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> {
self.type_iterators.get(&id).map(|f| f.as_ref()) if !self.type_iterators.is_empty() {
self.type_iterators.get(&id).map(|f| f.as_ref())
} else {
None
}
} }
} }

View File

@ -24,8 +24,8 @@ use std::{
/// one level, and it is wasteful to always allocate a [`Vec`] with one element. /// one level, and it is wasteful to always allocate a [`Vec`] with one element.
#[derive(Clone, Eq, PartialEq, Default, Hash)] #[derive(Clone, Eq, PartialEq, Default, Hash)]
pub struct Namespace { pub struct Namespace {
index: Option<NonZeroUsize>,
path: StaticVec<Ident>, path: StaticVec<Ident>,
index: Option<NonZeroUsize>,
} }
impl fmt::Debug for Namespace { impl fmt::Debug for Namespace {
@ -119,7 +119,19 @@ impl Namespace {
/// # Panics /// # Panics
/// ///
/// Panics if the path is empty. /// Panics if the path is empty.
#[inline(always)]
#[must_use]
pub fn position(&self) -> Position { pub fn position(&self) -> Position {
self.path[0].pos self.path[0].pos
} }
/// Get the first path segment of this [`Namespace`].
///
/// # Panics
///
/// Panics if the path is empty.
#[inline(always)]
#[must_use]
pub fn root(&self) -> &str {
&self.path[0].name
}
} }

View File

@ -2,7 +2,7 @@
#![cfg(not(target_family = "wasm"))] #![cfg(not(target_family = "wasm"))]
use crate::eval::GlobalRuntimeState; use crate::eval::GlobalRuntimeState;
use crate::func::native::locked_write; use crate::func::native::{locked_read, locked_write};
use crate::{ use crate::{
Engine, Identifier, Module, ModuleResolver, Position, RhaiResultOf, Scope, Shared, ERR, Engine, Identifier, Module, ModuleResolver, Position, RhaiResultOf, Scope, Shared, ERR,
}; };
@ -208,7 +208,13 @@ impl FileModuleResolver {
let file_path = self.get_file_path(path.as_ref(), source_path); let file_path = self.get_file_path(path.as_ref(), source_path);
locked_write(&self.cache).contains_key(&file_path) let cache = locked_read(&self.cache);
if !cache.is_empty() {
cache.contains_key(&file_path)
} else {
false
}
} }
/// Empty the internal cache. /// Empty the internal cache.
#[inline] #[inline]

View File

@ -62,7 +62,11 @@ impl StaticModuleResolver {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn contains_path(&self, path: &str) -> bool { pub fn contains_path(&self, path: &str) -> bool {
self.0.contains_key(path) if !self.0.is_empty() {
self.0.contains_key(path)
} else {
false
}
} }
/// Get an iterator of all the [modules][Module]. /// Get an iterator of all the [modules][Module].
#[inline] #[inline]

View File

@ -484,8 +484,8 @@ impl Engine {
eat_token(input, Token::RightParen); eat_token(input, Token::RightParen);
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
let hash = if let Some(modules) = namespace.as_mut() { let hash = if let Some(namespace) = namespace.as_mut() {
let index = state.find_module(&modules[0].name); let index = state.find_module(namespace.root());
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let relax = settings.is_function_scope; let relax = settings.is_function_scope;
@ -493,13 +493,13 @@ impl Engine {
let relax = false; let relax = false;
if !relax && settings.options.strict_var && index.is_none() { if !relax && settings.options.strict_var && index.is_none() {
return Err(PERR::ModuleUndefined(modules[0].name.to_string()) return Err(PERR::ModuleUndefined(namespace.root().to_string())
.into_err(modules[0].pos)); .into_err(namespace.position()));
} }
modules.set_index(index); namespace.set_index(index);
crate::calc_qualified_fn_hash(modules.iter().map(|m| m.name.as_str()), &id, 0) crate::calc_qualified_fn_hash(namespace.iter().map(|m| m.name.as_str()), &id, 0)
} else { } else {
calc_fn_hash(&id, 0) calc_fn_hash(&id, 0)
}; };
@ -545,8 +545,8 @@ impl Engine {
eat_token(input, Token::RightParen); eat_token(input, Token::RightParen);
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
let hash = if let Some(modules) = namespace.as_mut() { let hash = if let Some(namespace) = namespace.as_mut() {
let index = state.find_module(&modules[0].name); let index = state.find_module(namespace.root());
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let relax = settings.is_function_scope; let relax = settings.is_function_scope;
@ -554,14 +554,14 @@ impl Engine {
let relax = false; let relax = false;
if !relax && settings.options.strict_var && index.is_none() { if !relax && settings.options.strict_var && index.is_none() {
return Err(PERR::ModuleUndefined(modules[0].name.to_string()) return Err(PERR::ModuleUndefined(namespace.root().to_string())
.into_err(modules[0].pos)); .into_err(namespace.position()));
} }
modules.set_index(index); namespace.set_index(index);
crate::calc_qualified_fn_hash( crate::calc_qualified_fn_hash(
modules.iter().map(|m| m.name.as_str()), namespace.iter().map(|m| m.name.as_str()),
&id, &id,
args.len(), args.len(),
) )
@ -1084,7 +1084,7 @@ impl Engine {
value.hash(hasher); value.hash(hasher);
let hash = hasher.finish(); let hash = hasher.finish();
if cases.contains_key(&hash) { if !cases.is_empty() && cases.contains_key(&hash) {
return Err(PERR::DuplicatedSwitchCase.into_err(expr.start_position())); return Err(PERR::DuplicatedSwitchCase.into_err(expr.start_position()));
} }
(Some(hash), None) (Some(hash), None)
@ -1378,7 +1378,7 @@ impl Engine {
// Custom syntax. // Custom syntax.
Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key) Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key)
if self.custom_syntax.contains_key(&**key) => if !self.custom_syntax.is_empty() && self.custom_syntax.contains_key(&**key) =>
{ {
let (key, syntax) = self.custom_syntax.get_key_value(&**key).unwrap(); let (key, syntax) = self.custom_syntax.get_key_value(&**key).unwrap();
let (.., pos) = input.next().expect(NEVER_ENDS); let (.., pos) = input.next().expect(NEVER_ENDS);
@ -1657,7 +1657,7 @@ impl Engine {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
{ {
let index = state.find_module(&namespace[0].name); let index = state.find_module(namespace.root());
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let relax = settings.is_function_scope; let relax = settings.is_function_scope;
@ -1665,8 +1665,8 @@ impl Engine {
let relax = false; let relax = false;
if !relax && settings.options.strict_var && index.is_none() { if !relax && settings.options.strict_var && index.is_none() {
return Err(PERR::ModuleUndefined(namespace[0].name.to_string()) return Err(PERR::ModuleUndefined(namespace.root().to_string())
.into_err(namespace[0].pos)); .into_err(namespace.position()));
} }
namespace.set_index(index); namespace.set_index(index);
@ -3092,7 +3092,7 @@ impl Engine {
let hash = calc_fn_hash(&func.name, func.params.len()); let hash = calc_fn_hash(&func.name, func.params.len());
if lib.contains_key(&hash) { if !lib.is_empty() && lib.contains_key(&hash) {
return Err(PERR::FnDuplicatedDefinition( return Err(PERR::FnDuplicatedDefinition(
func.name.to_string(), func.name.to_string(),
func.params.len(), func.params.len(),

View File

@ -2251,7 +2251,7 @@ impl<'a> Iterator for TokenIterator<'a> {
} }
// Reserved keyword/symbol // Reserved keyword/symbol
Some((Token::Reserved(s), pos)) => (match Some((Token::Reserved(s), pos)) => (match
(&*s, self.engine.custom_keywords.contains_key(&*s)) (&*s, !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s))
{ {
("===", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(), ("===", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
"'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(), "'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(),
@ -2282,7 +2282,7 @@ impl<'a> Iterator for TokenIterator<'a> {
// Reserved keyword/operator that is custom. // Reserved keyword/operator that is custom.
(.., true) => Token::Custom(s), (.., true) => Token::Custom(s),
// Reserved keyword that is not custom and disabled. // Reserved keyword that is not custom and disabled.
(token, false) if self.engine.disabled_symbols.contains(token) => { (token, false) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token) => {
let msg = format!("reserved {} '{}' is disabled", if is_valid_identifier(token.chars()) { "keyword"} else {"symbol"}, token); let msg = format!("reserved {} '{}' is disabled", if is_valid_identifier(token.chars()) { "keyword"} else {"symbol"}, token);
Token::LexError(LERR::ImproperSymbol(s.to_string(), msg).into()) Token::LexError(LERR::ImproperSymbol(s.to_string(), msg).into())
}, },
@ -2290,12 +2290,12 @@ impl<'a> Iterator for TokenIterator<'a> {
(.., false) => Token::Reserved(s), (.., false) => Token::Reserved(s),
}, pos), }, pos),
// Custom keyword // Custom keyword
Some((Token::Identifier(s), pos)) if self.engine.custom_keywords.contains_key(&*s) => { Some((Token::Identifier(s), pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s) => {
(Token::Custom(s), pos) (Token::Custom(s), pos)
} }
// Custom keyword/symbol - must be disabled // Custom keyword/symbol - must be disabled
Some((token, pos)) if self.engine.custom_keywords.contains_key(token.literal_syntax()) => { Some((token, pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(token.literal_syntax()) => {
if self.engine.disabled_symbols.contains(token.literal_syntax()) { if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) {
// Disabled standard keyword/symbol // Disabled standard keyword/symbol
(Token::Custom(token.literal_syntax().into()), pos) (Token::Custom(token.literal_syntax().into()), pos)
} else { } else {
@ -2304,7 +2304,7 @@ impl<'a> Iterator for TokenIterator<'a> {
} }
} }
// Disabled symbol // Disabled symbol
Some((token, pos)) if self.engine.disabled_symbols.contains(token.literal_syntax()) => { Some((token, pos)) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) => {
(Token::Reserved(token.literal_syntax().into()), pos) (Token::Reserved(token.literal_syntax().into()), pos)
} }
// Normal symbol // Normal symbol

View File

@ -206,14 +206,10 @@ enum DynamicReadLockInner<'d, T: Clone> {
/// A simple reference to a non-shared value. /// A simple reference to a non-shared value.
Reference(&'d T), Reference(&'d T),
/// A read guard to a shared [`RefCell`][std::cell::RefCell]. /// A read guard to a shared value.
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
Guard(std::cell::Ref<'d, Dynamic>), Guard(crate::func::native::LockGuard<'d, Dynamic>),
/// A read guard to a shared [`RwLock`][std::sync::RwLock].
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Guard(std::sync::RwLockReadGuard<'d, Dynamic>),
} }
impl<'d, T: Any + Clone> Deref for DynamicReadLock<'d, T> { impl<'d, T: Any + Clone> Deref for DynamicReadLock<'d, T> {
@ -245,7 +241,7 @@ enum DynamicWriteLockInner<'d, T: Clone> {
/// A write guard to a shared value. /// A write guard to a shared value.
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Guard(crate::func::native::LockGuard<'d, Dynamic>), Guard(crate::func::native::LockGuardMut<'d, Dynamic>),
} }
impl<'d, T: Any + Clone> Deref for DynamicWriteLock<'d, T> { impl<'d, T: Any + Clone> Deref for DynamicWriteLock<'d, T> {

View File

@ -59,7 +59,7 @@ impl StringsInterner {
_ => unreachable!("unsupported prefix {}", prefix.as_ref()), _ => unreachable!("unsupported prefix {}", prefix.as_ref()),
}; };
if dict.contains_key(text.as_ref()) { if !dict.is_empty() && dict.contains_key(text.as_ref()) {
dict.get(text.as_ref()).unwrap().clone() dict.get(text.as_ref()).unwrap().clone()
} else { } else {
let value: ImmutableString = mapper(text.as_ref()).into(); let value: ImmutableString = mapper(text.as_ref()).into();

View File

@ -516,7 +516,7 @@ impl Scope<'_> {
#[inline] #[inline]
pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self { pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self {
let aliases = self.aliases.get_mut(index).unwrap(); let aliases = self.aliases.get_mut(index).unwrap();
if !aliases.contains(&alias) { if aliases.is_empty() || !aliases.contains(&alias) {
aliases.push(alias); aliases.push(alias);
} }
self self
@ -533,7 +533,7 @@ impl Scope<'_> {
.rev() .rev()
.enumerate() .enumerate()
.fold(Self::new(), |mut entries, (index, name)| { .fold(Self::new(), |mut entries, (index, name)| {
if !entries.names.contains(name) { if entries.names.is_empty() || !entries.names.contains(name) {
let orig_value = &self.values[len - 1 - index]; let orig_value = &self.values[len - 1 - index];
let alias = &self.aliases[len - 1 - index]; let alias = &self.aliases[len - 1 - index];
let mut value = orig_value.clone(); let mut value = orig_value.clone();