diff --git a/src/ast.rs b/src/ast.rs index d90be201..0c8f5792 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -13,7 +13,6 @@ use std::{ collections::BTreeMap, fmt, hash::Hash, - iter::empty, mem, num::{NonZeroU8, NonZeroUsize}, ops::{Add, AddAssign, Deref, DerefMut}, @@ -1404,8 +1403,8 @@ impl OpAssignment { let op_assignment = op.keyword_syntax(); Self { - hash_op_assign: calc_fn_hash(empty(), op_assignment, 2), - hash_op: calc_fn_hash(empty(), op_raw, 2), + hash_op_assign: calc_fn_hash(op_assignment, 2), + hash_op: calc_fn_hash(op_raw, 2), op: op_assignment, } } diff --git a/src/engine.rs b/src/engine.rs index 37eb455f..e3e78934 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -29,7 +29,7 @@ use std::{ }; #[cfg(not(feature = "no_index"))] -use crate::{calc_fn_hash, Array}; +use crate::Array; #[cfg(not(feature = "no_object"))] use crate::Map; @@ -1166,61 +1166,40 @@ impl Engine { } // xxx[rhs] op= new_val _ if new_val.is_some() => { + let ((mut new_val, new_pos), (op_info, op_pos)) = new_val.unwrap(); let idx_val = idx_val.as_index_value(); #[cfg(not(feature = "no_index"))] - let mut idx_val2 = idx_val.clone(); + let mut idx_val_for_setter = idx_val.clone(); - // `call_setter` is introduced to bypass double mutable borrowing of target - let _call_setter = match self.get_indexed_mut( + match self.get_indexed_mut( mods, state, lib, target, idx_val, pos, true, false, level, ) { // Indexed value is a reference - update directly Ok(obj_ptr) => { - let ((new_val, new_pos), (op_info, op_pos)) = new_val.unwrap(); self.eval_op_assignment( mods, state, lib, op_info, op_pos, obj_ptr, root, new_val, new_pos, )?; - None + return Ok((Dynamic::UNIT, true)); } - Err(err) => match *err { - // No index getter - try to call an index setter - #[cfg(not(feature = "no_index"))] - EvalAltResult::ErrorIndexingType(_, _) => Some(new_val.unwrap()), - // Any other error - return - err => return err.into(), - }, - }; - - if let Some(mut new_val) = _call_setter { - let val_type_name = target.type_name(); - let ((_, val_pos), _) = new_val; - - let hash_set = FnCallHashes::from_native(calc_fn_hash( - std::iter::empty(), - FN_IDX_SET, - 3, - )); - let args = &mut [target, &mut idx_val2, &mut (new_val.0).0]; - - self.exec_fn_call( - mods, state, lib, FN_IDX_SET, hash_set, args, is_ref, true, - val_pos, None, level, - ) - .map_err(|err| match *err { - EvalAltResult::ErrorFunctionNotFound(fn_sig, _) - if fn_sig.ends_with("]=") => - { - EvalAltResult::ErrorIndexingType( - self.map_type_name(val_type_name).into(), - Position::NONE, - ) - } - err => err, - })?; + // Can't index - try to call an index setter + #[cfg(not(feature = "no_index"))] + Err(err) if matches!(*err, EvalAltResult::ErrorIndexingType(_, _)) => {} + // Any other error + Err(err) => return Err(err), } + // Try to call index setter + let hash_set = + FnCallHashes::from_native(crate::calc_fn_hash(FN_IDX_SET, 3)); + let args = &mut [target, &mut idx_val_for_setter, &mut new_val]; + + self.exec_fn_call( + mods, state, lib, FN_IDX_SET, hash_set, args, is_ref, true, new_pos, + None, level, + )?; + Ok((Dynamic::UNIT, true)) } // xxx[rhs] @@ -1325,11 +1304,8 @@ impl Engine { EvalAltResult::ErrorDotExpr(_, _) => { let mut prop = name.into(); let args = &mut [target, &mut prop, &mut new_val]; - let hash_set = FnCallHashes::from_native(crate::calc_fn_hash( - std::iter::empty(), - FN_IDX_SET, - 3, - )); + let hash_set = + FnCallHashes::from_native(crate::calc_fn_hash(FN_IDX_SET, 3)); self.exec_fn_call( mods, state, lib, FN_IDX_SET, hash_set, args, is_ref, true, *pos, None, level, @@ -1477,12 +1453,9 @@ impl Engine { EvalAltResult::ErrorDotExpr(_, _) => { let mut prop = name.into(); let args = &mut [target.as_mut(), &mut prop, val]; - let hash_set = - FnCallHashes::from_native(crate::calc_fn_hash( - std::iter::empty(), - FN_IDX_SET, - 3, - )); + let hash_set = FnCallHashes::from_native( + crate::calc_fn_hash(FN_IDX_SET, 3), + ); self.exec_fn_call( mods, state, lib, FN_IDX_SET, hash_set, args, is_ref, true, *pos, None, level, @@ -1842,11 +1815,7 @@ impl Engine { _ if indexers => { let args = &mut [target, &mut idx]; - let hash_get = FnCallHashes::from_native(crate::calc_fn_hash( - std::iter::empty(), - FN_IDX_GET, - 2, - )); + let hash_get = FnCallHashes::from_native(crate::calc_fn_hash(FN_IDX_GET, 2)); self.exec_fn_call( mods, state, lib, FN_IDX_GET, hash_get, args, true, true, idx_pos, None, level, diff --git a/src/fn_call.rs b/src/fn_call.rs index 8dbcf493..b47676be 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -24,7 +24,7 @@ use std::prelude::v1::*; use std::{ any::{type_name, TypeId}, convert::TryFrom, - iter::{empty, once}, + iter::once, mem, }; @@ -653,7 +653,7 @@ impl Engine { if num_params < 0 { Dynamic::FALSE } else { - let hash_script = calc_fn_hash(empty(), fn_name, num_params as usize); + let hash_script = calc_fn_hash(fn_name, num_params as usize); self.has_script_fn(Some(mods), state, lib, hash_script) .into() }, @@ -911,7 +911,7 @@ impl Engine { let fn_name = fn_ptr.fn_name(); let args_len = call_args.len() + fn_ptr.curry().len(); // Recalculate hashes - let new_hash = FnCallHashes::from_script(calc_fn_hash(empty(), fn_name, args_len)); + let new_hash = FnCallHashes::from_script(calc_fn_hash(fn_name, args_len)); // Arguments are passed as-is, adding the curried arguments let mut curry = fn_ptr.curry().iter().cloned().collect::>(); let mut args = curry @@ -947,8 +947,8 @@ impl Engine { let args_len = call_args.len() + fn_ptr.curry().len(); // Recalculate hash let new_hash = FnCallHashes::from_script_and_native( - calc_fn_hash(empty(), fn_name, args_len), - calc_fn_hash(empty(), fn_name, args_len + 1), + calc_fn_hash(fn_name, args_len), + calc_fn_hash(fn_name, args_len + 1), ); // Replace the first argument with the object pointer, adding the curried arguments let mut curry = fn_ptr.curry().iter().cloned().collect::>(); @@ -1021,8 +1021,8 @@ impl Engine { }); // Recalculate the hash based on the new function name and new arguments hash = FnCallHashes::from_script_and_native( - calc_fn_hash(empty(), fn_name, call_args.len()), - calc_fn_hash(empty(), fn_name, call_args.len() + 1), + calc_fn_hash(fn_name, call_args.len()), + calc_fn_hash(fn_name, call_args.len() + 1), ); } } @@ -1107,9 +1107,9 @@ impl Engine { // Recalculate hash let args_len = total_args + curry.len(); hashes = if !hashes.is_native_only() { - FnCallHashes::from_script(calc_fn_hash(empty(), name, args_len)) + FnCallHashes::from_script(calc_fn_hash(name, args_len)) } else { - FnCallHashes::from_native(calc_fn_hash(empty(), name, args_len)) + FnCallHashes::from_native(calc_fn_hash(name, args_len)) }; } // Handle Fn() @@ -1206,7 +1206,7 @@ impl Engine { return Ok(if num_params < 0 { Dynamic::FALSE } else { - let hash_script = calc_fn_hash(empty(), &fn_name, num_params as usize); + let hash_script = calc_fn_hash(&fn_name, num_params as usize); self.has_script_fn(Some(mods), state, lib, hash_script) .into() }); diff --git a/src/fn_native.rs b/src/fn_native.rs index 5996d6db..5d687735 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -13,7 +13,7 @@ use std::prelude::v1::*; use std::{ convert::{TryFrom, TryInto}, fmt, - iter::{empty, once}, + iter::once, mem, }; @@ -202,11 +202,11 @@ impl<'a> NativeCallContext<'a> { let hash = if is_method { FnCallHashes::from_script_and_native( - calc_fn_hash(empty(), fn_name, args.len() - 1), - calc_fn_hash(empty(), fn_name, args.len()), + calc_fn_hash(fn_name, args.len() - 1), + calc_fn_hash(fn_name, args.len()), ) } else { - FnCallHashes::from_script(calc_fn_hash(empty(), fn_name, args.len())) + FnCallHashes::from_script(calc_fn_hash(fn_name, args.len())) }; self.engine() diff --git a/src/lib.rs b/src/lib.rs index 30b9faa9..2db92c3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -169,7 +169,7 @@ pub use fn_native::Shared; #[cfg(not(feature = "no_closure"))] use fn_native::Locked; -pub(crate) use utils::{calc_fn_hash, calc_fn_params_hash, combine_hashes}; +pub(crate) use utils::{calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes}; pub use rhai_codegen::*; diff --git a/src/module/mod.rs b/src/module/mod.rs index 2b531e9e..b9320870 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -7,8 +7,8 @@ use crate::fn_register::RegisterNativeFunction; use crate::token::Token; use crate::utils::IdentifierBuilder; use crate::{ - calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, EvalAltResult, Identifier, - ImmutableString, NativeCallContext, Position, Shared, StaticVec, + calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, EvalAltResult, + Identifier, ImmutableString, NativeCallContext, Position, Shared, StaticVec, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -116,7 +116,7 @@ fn calc_native_fn_hash<'a>( fn_name: impl AsRef, params: &[TypeId], ) -> u64 { - let hash_script = calc_fn_hash(modules, fn_name, params.len()); + let hash_script = calc_qualified_fn_hash(modules, fn_name, params.len()); let hash_params = calc_fn_params_hash(params.iter().cloned()); combine_hashes(hash_script, hash_params) } @@ -440,7 +440,7 @@ impl Module { let value = Dynamic::from(value); if self.indexed { - let hash_var = crate::calc_fn_hash(once(""), &ident, 0); + let hash_var = crate::calc_qualified_fn_hash(once(""), &ident, 0); self.all_variables.insert(hash_var, value.clone()); } self.variables.insert(ident, value); @@ -466,7 +466,7 @@ impl Module { // None + function name + number of arguments. let num_params = fn_def.params.len(); - let hash_script = crate::calc_fn_hash(empty(), &fn_def.name, num_params); + let hash_script = crate::calc_fn_hash(&fn_def.name, num_params); let mut param_names = fn_def.params.clone(); param_names.push("Dynamic".into()); self.functions.insert( @@ -1491,7 +1491,7 @@ impl Module { // Index all variables module.variables.iter().for_each(|(var_name, value)| { - let hash_var = crate::calc_fn_hash(path.iter().map(|&v| v), var_name, 0); + let hash_var = crate::calc_qualified_fn_hash(path.iter().map(|&v| v), var_name, 0); variables.insert(hash_var, value.clone()); }); @@ -1521,8 +1521,11 @@ impl Module { calc_native_fn_hash(path.iter().cloned(), f.name.as_str(), &f.param_types); functions.insert(hash_qualified_fn, f.func.clone()); } else if cfg!(not(feature = "no_function")) { - let hash_qualified_script = - crate::calc_fn_hash(path.iter().cloned(), f.name.as_str(), f.params); + let hash_qualified_script = crate::calc_qualified_fn_hash( + path.iter().cloned(), + f.name.as_str(), + f.params, + ); functions.insert(hash_qualified_script, f.func.clone()); } }); diff --git a/src/optimize.rs b/src/optimize.rs index 20b1cc4a..de2c242a 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -15,7 +15,6 @@ use std::prelude::v1::*; use std::{ any::TypeId, hash::{Hash, Hasher}, - iter::empty, mem, }; @@ -147,7 +146,7 @@ fn call_fn_with_constant_arguments( &mut Default::default(), state.lib, fn_name, - calc_fn_hash(empty(), fn_name, arg_values.len()), + calc_fn_hash(fn_name, arg_values.len()), arg_values.iter_mut().collect::>().as_mut(), false, false, diff --git a/src/parser.rs b/src/parser.rs index 8539960c..3eec52e6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -15,15 +15,14 @@ use crate::token::{ }; use crate::utils::{get_hasher, IdentifierBuilder}; use crate::{ - calc_fn_hash, Dynamic, Engine, FnPtr, Identifier, LexError, ParseError, ParseErrorType, - Position, Scope, Shared, StaticVec, AST, + calc_fn_hash, calc_qualified_fn_hash, Dynamic, Engine, FnPtr, Identifier, LexError, ParseError, + ParseErrorType, Position, Scope, Shared, StaticVec, AST, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ collections::BTreeMap, hash::{Hash, Hasher}, - iter::empty, num::{NonZeroU8, NonZeroUsize}, }; @@ -225,9 +224,9 @@ impl Expr { Self::Variable(_, pos, x) if x.1.is_none() => { let ident = x.2; let getter = state.get_identifier(crate::engine::make_getter(&ident)); - let hash_get = calc_fn_hash(empty(), &getter, 1); + let hash_get = calc_fn_hash(&getter, 1); let setter = state.get_identifier(crate::engine::make_setter(&ident)); - let hash_set = calc_fn_hash(empty(), &setter, 2); + let hash_set = calc_fn_hash(&setter, 2); Self::Property(Box::new(( (getter, hash_get), @@ -334,9 +333,9 @@ fn parse_fn_call( #[cfg(not(feature = "no_module"))] modules.set_index(state.find_module(&modules[0].name)); - calc_fn_hash(modules.iter().map(|m| m.name.as_str()), &id, 0) + calc_qualified_fn_hash(modules.iter().map(|m| m.name.as_str()), &id, 0) } else { - calc_fn_hash(empty(), &id, 0) + calc_fn_hash(&id, 0) }; let hashes = if is_valid_identifier(id.chars()) { @@ -381,9 +380,9 @@ fn parse_fn_call( #[cfg(not(feature = "no_module"))] modules.set_index(state.find_module(&modules[0].name)); - calc_fn_hash(modules.iter().map(|m| m.name.as_str()), &id, args.len()) + calc_qualified_fn_hash(modules.iter().map(|m| m.name.as_str()), &id, args.len()) } else { - calc_fn_hash(empty(), &id, args.len()) + calc_fn_hash(&id, args.len()) }; let hashes = if is_valid_identifier(id.chars()) { @@ -1016,7 +1015,7 @@ fn parse_primary( state.access_var(closure, *pos); }); - let hash_script = calc_fn_hash(empty(), &func.name, func.params.len()); + let hash_script = calc_fn_hash(&func.name, func.params.len()); lib.insert(hash_script, func.into()); expr @@ -1295,7 +1294,7 @@ fn parse_primary( } .map(|x| match x.as_mut() { (_, Some((hash, namespace)), name) => { - *hash = calc_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0); + *hash = calc_qualified_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0); #[cfg(not(feature = "no_module"))] namespace.set_index(state.find_module(&namespace[0].name)); @@ -1351,7 +1350,7 @@ fn parse_unary( Ok(Expr::FnCall( Box::new(FnCallExpr { name: state.get_identifier("-"), - hashes: FnCallHashes::from_native(calc_fn_hash(empty(), "-", 1)), + hashes: FnCallHashes::from_native(calc_fn_hash("-", 1)), args, ..Default::default() }), @@ -1378,7 +1377,7 @@ fn parse_unary( Ok(Expr::FnCall( Box::new(FnCallExpr { name: state.get_identifier("+"), - hashes: FnCallHashes::from_native(calc_fn_hash(empty(), "+", 1)), + hashes: FnCallHashes::from_native(calc_fn_hash("+", 1)), args, ..Default::default() }), @@ -1397,7 +1396,7 @@ fn parse_unary( Ok(Expr::FnCall( Box::new(FnCallExpr { name: state.get_identifier("!"), - hashes: FnCallHashes::from_native(calc_fn_hash(empty(), "!", 1)), + hashes: FnCallHashes::from_native(calc_fn_hash("!", 1)), args, ..Default::default() }), @@ -1531,9 +1530,9 @@ fn make_dot_expr( (lhs, Expr::Variable(_, var_pos, x)) if x.1.is_none() => { let ident = x.2; let getter = state.get_identifier(crate::engine::make_getter(&ident)); - let hash_get = calc_fn_hash(empty(), &getter, 1); + let hash_get = calc_fn_hash(&getter, 1); let setter = state.get_identifier(crate::engine::make_setter(&ident)); - let hash_set = calc_fn_hash(empty(), &setter, 2); + let hash_set = calc_fn_hash(&setter, 2); let rhs = Expr::Property(Box::new(( (getter, hash_get), @@ -1566,8 +1565,8 @@ fn make_dot_expr( Expr::FnCall(mut func, func_pos) => { // Recalculate hash func.hashes = FnCallHashes::from_script_and_native( - calc_fn_hash(empty(), &func.name, func.args_count()), - calc_fn_hash(empty(), &func.name, func.args_count() + 1), + calc_fn_hash(&func.name, func.args_count()), + calc_fn_hash(&func.name, func.args_count() + 1), ); let rhs = Expr::Dot( @@ -1622,8 +1621,8 @@ fn make_dot_expr( (lhs, Expr::FnCall(mut func, func_pos)) => { // Recalculate hash func.hashes = FnCallHashes::from_script_and_native( - calc_fn_hash(empty(), &func.name, func.args_count()), - calc_fn_hash(empty(), &func.name, func.args_count() + 1), + calc_fn_hash(&func.name, func.args_count()), + calc_fn_hash(&func.name, func.args_count() + 1), ); let rhs = Expr::FnCall(func, func_pos); Expr::Dot(Box::new(BinaryExpr { lhs, rhs }), op_pos) @@ -1705,7 +1704,7 @@ fn parse_binary_op( settings.ensure_level_within_max_limit(state.max_expr_depth)?; let op = op_token.syntax(); - let hash = calc_fn_hash(empty(), &op, 2); + let hash = calc_fn_hash(&op, 2); let op_base = FnCallExpr { name: state.get_identifier(op.as_ref()), @@ -1773,7 +1772,7 @@ fn parse_binary_op( args.shrink_to_fit(); // Convert into a call to `contains` - let hash = calc_fn_hash(empty(), OP_CONTAINS, 2); + let hash = calc_fn_hash(OP_CONTAINS, 2); Expr::FnCall( Box::new(FnCallExpr { hashes: FnCallHashes::from_script(hash), @@ -1792,7 +1791,7 @@ fn parse_binary_op( .get(s.as_str()) .map_or(false, Option::is_some) => { - let hash = calc_fn_hash(empty(), &s, 2); + let hash = calc_fn_hash(&s, 2); Expr::FnCall( Box::new(FnCallExpr { @@ -2580,7 +2579,7 @@ fn parse_stmt( comments, )?; - let hash = calc_fn_hash(empty(), &func.name, func.params.len()); + let hash = calc_fn_hash(&func.name, func.params.len()); if lib.contains_key(&hash) { return Err(PERR::FnDuplicatedDefinition( @@ -2863,7 +2862,6 @@ fn make_curry_from_externals( Box::new(FnCallExpr { name: state.get_identifier(crate::engine::KEYWORD_FN_PTR_CURRY), hashes: FnCallHashes::from_native(calc_fn_hash( - empty(), crate::engine::KEYWORD_FN_PTR_CURRY, num_externals + 1, )), diff --git a/src/utils.rs b/src/utils.rs index ab998c5d..49012ea3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,7 +10,7 @@ use std::{ cmp::Ordering, fmt, hash::{BuildHasher, Hash, Hasher}, - iter::FromIterator, + iter::{empty, FromIterator}, ops::{Add, AddAssign, Deref, Sub, SubAssign}, str::FromStr, }; @@ -58,9 +58,8 @@ pub fn get_hasher() -> ahash::AHasher { Default::default() } -/// _(INTERNALS)_ Calculate a [`u64`] hash key from a namespace-qualified function name +/// Calculate a [`u64`] hash key from a namespace-qualified function name /// and the number of parameters, but no parameter types. -/// Exported under the `internals` feature only. /// /// Module names are passed in via `&str` references from an iterator. /// Parameter types are passed in via [`TypeId`] values from an iterator. @@ -68,8 +67,8 @@ pub fn get_hasher() -> ahash::AHasher { /// # Note /// /// The first module name is skipped. Hashing starts from the _second_ module in the chain. -#[inline(always)] -pub fn calc_fn_hash<'a>( +#[inline] +pub fn calc_qualified_fn_hash<'a>( modules: impl Iterator, fn_name: impl AsRef, num: usize, @@ -88,11 +87,19 @@ pub fn calc_fn_hash<'a>( s.finish() } -/// _(INTERNALS)_ Calculate a [`u64`] hash key from a list of parameter types. -/// Exported under the `internals` feature only. +/// Calculate a [`u64`] hash key from a non-namespace-qualified function name +/// and the number of parameters, but no parameter types. /// /// Parameter types are passed in via [`TypeId`] values from an iterator. #[inline(always)] +pub fn calc_fn_hash(fn_name: impl AsRef, num: usize) -> u64 { + calc_qualified_fn_hash(empty(), fn_name, num) +} + +/// Calculate a [`u64`] hash key from a list of parameter types. +/// +/// Parameter types are passed in via [`TypeId`] values from an iterator. +#[inline] pub fn calc_fn_params_hash(params: impl Iterator) -> u64 { let s = &mut get_hasher(); let mut len = 0;