From 0e9a16e437b0cbe7504a58593241a991d3e60f0a Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 3 Mar 2022 13:02:57 +0800 Subject: [PATCH] Add checks for is_empty. --- src/api/compile.rs | 3 +- src/api/custom_syntax.rs | 13 +++-- src/api/mod.rs | 13 +++-- src/api/register.rs | 2 +- src/eval/chaining.rs | 2 +- src/eval/expr.rs | 52 +++++++++----------- src/func/builtin.rs | 2 +- src/func/call.rs | 2 +- src/func/native.rs | 34 ++++++++++--- src/module/mod.rs | 95 +++++++++++++++++++++++++++--------- src/module/namespace.rs | 14 +++++- src/module/resolvers/file.rs | 10 +++- src/module/resolvers/stat.rs | 6 ++- src/parser.rs | 36 +++++++------- src/tokenizer.rs | 12 ++--- src/types/dynamic.rs | 10 ++-- src/types/interner.rs | 2 +- src/types/scope.rs | 4 +- 18 files changed, 202 insertions(+), 110 deletions(-) diff --git a/src/api/compile.rs b/src/api/compile.rs index 6d491da6..39a6ed79 100644 --- a/src/api/compile.rs +++ b/src/api/compile.rs @@ -101,7 +101,8 @@ impl Engine { // Collect all `import` statements with a string constant path ASTNode::Stmt(Stmt::Import(x, ..)) => match x.0 { 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()); true diff --git a/src/api/custom_syntax.rs b/src/api/custom_syntax.rs index cf5713a7..1fcb0455 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -227,9 +227,10 @@ impl Engine { // Standard or reserved keyword/symbol not in first position _ if !segments.is_empty() && token.is_some() => { // 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())) - && !self.custom_keywords.contains_key(s) + && (self.custom_keywords.is_empty() + || !self.custom_keywords.contains_key(s)) { self.custom_keywords.insert(s.into(), None); } @@ -238,7 +239,7 @@ impl Engine { // Standard keyword in first position but not disabled _ if segments.is_empty() && 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( s.to_string(), @@ -253,9 +254,11 @@ impl Engine { // Identifier in first position _ if segments.is_empty() && is_valid_identifier(s.chars()) => { // 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); } } diff --git a/src/api/mod.rs b/src/api/mod.rs index 85e2d0f0..2b94013a 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -162,18 +162,25 @@ impl Engine { // Active standard keywords cannot be made custom // Disabled keywords are OK 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())); } } // Active standard symbols cannot be made custom 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())); } } // 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())) } // Disabled symbols are OK diff --git a/src/api/register.rs b/src/api/register.rs index 8dc9ce0c..acd35914 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -1003,7 +1003,7 @@ impl Engine { let sub_module = 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(); register_static_module_raw(m.sub_modules_mut(), remainder, module); m.build_index(); diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index 36ba8436..d3b05744 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -907,7 +907,7 @@ impl Engine { self.make_type_mismatch_err::(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); } diff --git a/src/eval/expr.rs b/src/eval/expr.rs index d6ea6025..b2a155b3 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -20,7 +20,7 @@ impl Engine { state: &mut EvalState, namespace: &crate::module::Namespace, ) -> Option> { - let root = &namespace[0].name; + let root = namespace.root(); // Qualified - check if the root module is directly indexed let index = if state.always_search_scope { @@ -72,32 +72,24 @@ impl Engine { (_, Some((namespace, hash_var)), var_name) => { // foo:bar::baz::VARIABLE if let Some(module) = self.search_imports(global, state, namespace) { - return match module.get_qualified_var(*hash_var) { - Ok(target) => { - let mut target = target.clone(); - // Module variables are constant - target.set_access_mode(AccessMode::ReadOnly); - Ok((target.into(), *_var_pos)) - } - Err(err) => Err(match *err { - ERR::ErrorVariableNotFound(..) => ERR::ErrorVariableNotFound( - format!( - "{}{}{}", - namespace, - crate::tokenizer::Token::DoubleColon.literal_syntax(), - var_name - ), - namespace[0].pos, - ) - .into(), - _ => err.fill_position(*_var_pos), - }), + return if let Some(mut target) = module.get_qualified_var(*hash_var) { + // Module variables are constant + target.set_access_mode(AccessMode::ReadOnly); + Ok((target.into(), *_var_pos)) + } else { + let sep = crate::tokenizer::Token::DoubleColon.literal_syntax(); + + Err(ERR::ErrorVariableNotFound( + format!("{}{}{}", namespace, sep, var_name), + namespace.position(), + ) + .into()) }; } // global::VARIABLE #[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(value) = 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( - format!( - "{}{}{}", - namespace, - crate::tokenizer::Token::DoubleColon.literal_syntax(), - var_name - ), - namespace[0].pos, + format!("{}{}{}", namespace, sep, var_name), + namespace.position(), ) .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), diff --git a/src/func/builtin.rs b/src/func/builtin.rs index 1da1d250..5477893c 100644 --- a/src/func/builtin.rs +++ b/src/func/builtin.rs @@ -288,7 +288,7 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option Some(|_, args| { let blob = &*args[0].read_lock::().expect(BUILTIN); 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, }; diff --git a/src/func/call.rs b/src/func/call.rs index da327258..dc3090af 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -1353,7 +1353,7 @@ impl Engine { let module = self .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) let func = match module.get_qualified_fn(hash) { diff --git a/src/func/native.rs b/src/func/native.rs index 66e793a3..c3932824 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -41,20 +41,30 @@ pub use std::sync::Arc as Shared; #[allow(dead_code)] 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"))] #[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. #[cfg(feature = "sync")] #[allow(dead_code)] pub use std::sync::RwLock as Locked; -/// Lock guard for synchronized shared object. +/// Read-only lock guard for synchronized shared object. #[cfg(feature = "sync")] #[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. #[derive(Debug)] @@ -374,11 +384,23 @@ pub fn shared_take(value: Shared) -> T { shared_try_take(value).ok().expect("not shared") } -/// Lock a [`Locked`] resource. +/// Lock a [`Locked`] resource for mutable access. #[inline(always)] #[must_use] #[allow(dead_code)] -pub fn locked_write<'a, T>(value: &'a Locked) -> LockGuard<'a, T> { +pub fn locked_read<'a, T>(value: &'a Locked) -> 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) -> LockGuardMut<'a, T> { #[cfg(not(feature = "sync"))] return value.borrow_mut(); diff --git a/src/module/mod.rs b/src/module/mod.rs index 8da2ca55..4c04142e 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -488,7 +488,11 @@ impl Module { #[inline(always)] #[must_use] 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. @@ -520,7 +524,11 @@ impl Module { #[inline(always)] #[must_use] pub fn get_var(&self, name: &str) -> Option { - self.variables.get(name).cloned() + if !self.variables.is_empty() { + self.variables.get(name).cloned() + } else { + None + } } /// Set a variable into the [`Module`]. @@ -552,14 +560,15 @@ impl Module { self } - /// Get a reference to a namespace-qualified variable. - /// Name and Position in [`EvalAltResult`] are [`None`] and [`NONE`][Position::NONE] and must be set afterwards. + /// Get a namespace-qualified [`Module`] variable as a [`Dynamic`]. #[cfg(not(feature = "no_module"))] #[inline] - pub(crate) fn get_qualified_var(&self, hash_var: u64) -> RhaiResultOf<&Dynamic> { - self.all_variables.get(&hash_var).ok_or_else(|| { - crate::ERR::ErrorVariableNotFound(String::new(), crate::Position::NONE).into() - }) + pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Option { + if !self.all_variables.is_empty() { + self.all_variables.get(&hash_var).cloned() + } else { + None + } } /// Set a script-defined function into the [`Module`]. @@ -610,14 +619,14 @@ impl Module { name: impl AsRef, num_params: usize, ) -> Option<&Shared> { - if self.functions.is_empty() { - None - } else { + if !self.functions.is_empty() { let name = name.as_ref(); self.iter_fn() .find(|f| f.metadata.params == num_params && f.metadata.name == name) .and_then(|f| f.func.get_script_fn_def()) + } else { + None } } @@ -656,7 +665,11 @@ impl Module { #[inline(always)] #[must_use] 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`]. @@ -673,7 +686,11 @@ impl Module { #[inline] #[must_use] 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`]. @@ -716,7 +733,11 @@ impl Module { #[inline(always)] #[must_use] 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. @@ -1357,7 +1378,11 @@ impl Module { #[inline] #[must_use] 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`]? @@ -1366,7 +1391,11 @@ impl Module { #[inline(always)] #[must_use] 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. @@ -1376,9 +1405,13 @@ impl Module { #[inline] #[must_use] pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> { - self.all_functions - .get(&hash_qualified_fn) - .map(|f| f.as_ref()) + if !self.all_functions.is_empty() { + self.all_functions + .get(&hash_qualified_fn) + .map(|f| f.as_ref()) + } else { + None + } } /// Combine another [`Module`] into this [`Module`]. @@ -1906,14 +1939,22 @@ impl Module { #[inline(always)] #[must_use] 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? #[inline(always)] #[must_use] 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`]. @@ -1979,14 +2020,22 @@ impl Module { #[inline] #[must_use] 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. #[inline] #[must_use] 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 + } } } diff --git a/src/module/namespace.rs b/src/module/namespace.rs index 8ac09985..63595c29 100644 --- a/src/module/namespace.rs +++ b/src/module/namespace.rs @@ -24,8 +24,8 @@ use std::{ /// one level, and it is wasteful to always allocate a [`Vec`] with one element. #[derive(Clone, Eq, PartialEq, Default, Hash)] pub struct Namespace { - index: Option, path: StaticVec, + index: Option, } impl fmt::Debug for Namespace { @@ -119,7 +119,19 @@ impl Namespace { /// # Panics /// /// Panics if the path is empty. + #[inline(always)] + #[must_use] pub fn position(&self) -> Position { 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 + } } diff --git a/src/module/resolvers/file.rs b/src/module/resolvers/file.rs index 8ed6c7e7..5de00416 100644 --- a/src/module/resolvers/file.rs +++ b/src/module/resolvers/file.rs @@ -2,7 +2,7 @@ #![cfg(not(target_family = "wasm"))] use crate::eval::GlobalRuntimeState; -use crate::func::native::locked_write; +use crate::func::native::{locked_read, locked_write}; use crate::{ 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); - 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. #[inline] diff --git a/src/module/resolvers/stat.rs b/src/module/resolvers/stat.rs index dc25c563..5648b5ef 100644 --- a/src/module/resolvers/stat.rs +++ b/src/module/resolvers/stat.rs @@ -62,7 +62,11 @@ impl StaticModuleResolver { #[inline(always)] #[must_use] 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]. #[inline] diff --git a/src/parser.rs b/src/parser.rs index 2efce43b..d51ea346 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -484,8 +484,8 @@ impl Engine { eat_token(input, Token::RightParen); #[cfg(not(feature = "no_module"))] - let hash = if let Some(modules) = namespace.as_mut() { - let index = state.find_module(&modules[0].name); + let hash = if let Some(namespace) = namespace.as_mut() { + let index = state.find_module(namespace.root()); #[cfg(not(feature = "no_function"))] let relax = settings.is_function_scope; @@ -493,13 +493,13 @@ impl Engine { let relax = false; if !relax && settings.options.strict_var && index.is_none() { - return Err(PERR::ModuleUndefined(modules[0].name.to_string()) - .into_err(modules[0].pos)); + return Err(PERR::ModuleUndefined(namespace.root().to_string()) + .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 { calc_fn_hash(&id, 0) }; @@ -545,8 +545,8 @@ impl Engine { eat_token(input, Token::RightParen); #[cfg(not(feature = "no_module"))] - let hash = if let Some(modules) = namespace.as_mut() { - let index = state.find_module(&modules[0].name); + let hash = if let Some(namespace) = namespace.as_mut() { + let index = state.find_module(namespace.root()); #[cfg(not(feature = "no_function"))] let relax = settings.is_function_scope; @@ -554,14 +554,14 @@ impl Engine { let relax = false; if !relax && settings.options.strict_var && index.is_none() { - return Err(PERR::ModuleUndefined(modules[0].name.to_string()) - .into_err(modules[0].pos)); + return Err(PERR::ModuleUndefined(namespace.root().to_string()) + .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()), + namespace.iter().map(|m| m.name.as_str()), &id, args.len(), ) @@ -1084,7 +1084,7 @@ impl Engine { value.hash(hasher); 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())); } (Some(hash), None) @@ -1378,7 +1378,7 @@ impl Engine { // Custom syntax. 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 (.., pos) = input.next().expect(NEVER_ENDS); @@ -1657,7 +1657,7 @@ impl Engine { #[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"))] let relax = settings.is_function_scope; @@ -1665,8 +1665,8 @@ impl Engine { let relax = false; if !relax && settings.options.strict_var && index.is_none() { - return Err(PERR::ModuleUndefined(namespace[0].name.to_string()) - .into_err(namespace[0].pos)); + return Err(PERR::ModuleUndefined(namespace.root().to_string()) + .into_err(namespace.position())); } namespace.set_index(index); @@ -3092,7 +3092,7 @@ impl Engine { 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( func.name.to_string(), func.params.len(), diff --git a/src/tokenizer.rs b/src/tokenizer.rs index f0ebf8d4..5e8cd23a 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -2251,7 +2251,7 @@ impl<'a> Iterator for TokenIterator<'a> { } // Reserved keyword/symbol 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(), "'===' 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. (.., true) => Token::Custom(s), // 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); Token::LexError(LERR::ImproperSymbol(s.to_string(), msg).into()) }, @@ -2290,12 +2290,12 @@ impl<'a> Iterator for TokenIterator<'a> { (.., false) => Token::Reserved(s), }, pos), // 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) } // Custom keyword/symbol - must be disabled - Some((token, pos)) if self.engine.custom_keywords.contains_key(token.literal_syntax()) => { - if self.engine.disabled_symbols.contains(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.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) { // Disabled standard keyword/symbol (Token::Custom(token.literal_syntax().into()), pos) } else { @@ -2304,7 +2304,7 @@ impl<'a> Iterator for TokenIterator<'a> { } } // 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) } // Normal symbol diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index d50d530e..f5b991eb 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -206,14 +206,10 @@ enum DynamicReadLockInner<'d, T: Clone> { /// A simple reference to a non-shared value. 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 = "sync"))] - Guard(std::cell::Ref<'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>), + Guard(crate::func::native::LockGuard<'d, Dynamic>), } 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. #[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> { diff --git a/src/types/interner.rs b/src/types/interner.rs index 05e19fc5..e82152be 100644 --- a/src/types/interner.rs +++ b/src/types/interner.rs @@ -59,7 +59,7 @@ impl StringsInterner { _ => 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() } else { let value: ImmutableString = mapper(text.as_ref()).into(); diff --git a/src/types/scope.rs b/src/types/scope.rs index 812bedca..199940e9 100644 --- a/src/types/scope.rs +++ b/src/types/scope.rs @@ -516,7 +516,7 @@ impl Scope<'_> { #[inline] pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self { let aliases = self.aliases.get_mut(index).unwrap(); - if !aliases.contains(&alias) { + if aliases.is_empty() || !aliases.contains(&alias) { aliases.push(alias); } self @@ -533,7 +533,7 @@ impl Scope<'_> { .rev() .enumerate() .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 alias = &self.aliases[len - 1 - index]; let mut value = orig_value.clone();