diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 53f186d8..11a39eb2 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -124,34 +124,35 @@ impl fmt::Debug for FnCallHashes { } } -impl From for FnCallHashes { +impl FnCallHashes { + /// Create a [`FnCallHashes`] from a single hash. #[inline] - fn from(hash: u64) -> Self { + #[must_use] + pub const fn from_hash(hash: u64) -> Self { Self { #[cfg(not(feature = "no_function"))] script: Some(hash), native: hash, } } -} - -impl FnCallHashes { /// Create a [`FnCallHashes`] with only the native Rust hash. #[inline] #[must_use] - pub fn from_native(hash: u64) -> Self { + pub const fn from_native_only(hash: u64) -> Self { Self { #[cfg(not(feature = "no_function"))] script: None, native: hash, } } - /// Create a [`FnCallHashes`] with both native Rust and script function hashes. + /// Create a [`FnCallHashes`] with both script function and native Rust hashes. + /// + /// Not available under `no_function`. + #[cfg(not(feature = "no_function"))] #[inline] #[must_use] - pub fn from_all(#[cfg(not(feature = "no_function"))] script: u64, native: u64) -> Self { + pub const fn from_script_and_native(script: u64, native: u64) -> Self { Self { - #[cfg(not(feature = "no_function"))] script: Some(script), native, } @@ -577,7 +578,7 @@ impl Expr { FnCallExpr { namespace: Namespace::NONE, name: KEYWORD_FN_PTR.into(), - hashes: calc_fn_hash(None, f.fn_name(), 1).into(), + hashes: FnCallHashes::from_hash(calc_fn_hash(None, f.fn_name(), 1)), args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(), capture_parent_scope: false, op_token: None, diff --git a/src/func/call.rs b/src/func/call.rs index 0741a409..bdcdf899 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -785,9 +785,9 @@ impl Engine { let fn_name = fn_ptr.fn_name(); // Recalculate hashes let new_hash = if !is_anon && !is_valid_function_name(fn_name) { - FnCallHashes::from_native(calc_fn_hash(None, fn_name, args.len())) + FnCallHashes::from_native_only(calc_fn_hash(None, fn_name, args.len())) } else { - calc_fn_hash(None, fn_name, args.len()).into() + FnCallHashes::from_hash(calc_fn_hash(None, fn_name, args.len())) }; // Map it to name(args) in function-call style @@ -867,14 +867,17 @@ impl Engine { args.insert(0, target.as_mut()); // Recalculate hash - let new_hash = if !is_anon && !is_valid_function_name(&fn_name) { - FnCallHashes::from_native(calc_fn_hash(None, &fn_name, args.len())) - } else { - FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] + let new_hash = match is_anon { + false if !is_valid_function_name(&fn_name) => { + FnCallHashes::from_native_only(calc_fn_hash(None, &fn_name, args.len())) + } + #[cfg(not(feature = "no_function"))] + _ => FnCallHashes::from_script_and_native( calc_fn_hash(None, &fn_name, args.len() - 1), calc_fn_hash(None, &fn_name, args.len()), - ) + ), + #[cfg(feature = "no_function")] + _ => FnCallHashes::from_native_only(calc_fn_hash(None, &fn_name, args.len())), }; // Map it to name(args) in function-call style @@ -943,18 +946,22 @@ impl Engine { call_args = &mut _arg_values; } // Recalculate the hash based on the new function name and new arguments - hash = if !is_anon && !is_valid_function_name(fn_name) { - FnCallHashes::from_native(calc_fn_hash( - None, - fn_name, - call_args.len() + 1, - )) - } else { - FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, fn_name, call_args.len()), - calc_fn_hash(None, fn_name, call_args.len() + 1), - ) + let args_len = call_args.len() + 1; + hash = match is_anon { + false if !is_valid_function_name(fn_name) => { + FnCallHashes::from_native_only(calc_fn_hash( + None, fn_name, args_len, + )) + } + #[cfg(not(feature = "no_function"))] + _ => FnCallHashes::from_script_and_native( + calc_fn_hash(None, fn_name, args_len - 1), + calc_fn_hash(None, fn_name, args_len), + ), + #[cfg(feature = "no_function")] + _ => FnCallHashes::from_native_only(calc_fn_hash( + None, fn_name, args_len, + )), }; } } @@ -1080,9 +1087,9 @@ impl Engine { let args_len = total_args + curry.len(); hashes = if !is_anon && !is_valid_function_name(name) { - FnCallHashes::from_native(calc_fn_hash(None, name, args_len)) + FnCallHashes::from_native_only(calc_fn_hash(None, name, args_len)) } else { - calc_fn_hash(None, name, args_len).into() + FnCallHashes::from_hash(calc_fn_hash(None, name, args_len)) }; } // Handle Fn() diff --git a/src/func/native.rs b/src/func/native.rs index e776c4b0..409e3948 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -457,14 +457,15 @@ impl<'a> NativeCallContext<'a> { // Native or script - let hash = if is_method_call { - FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] + let hash = match is_method_call { + #[cfg(not(feature = "no_function"))] + true => FnCallHashes::from_script_and_native( calc_fn_hash(None, fn_name, args_len - 1), calc_fn_hash(None, fn_name, args_len), - ) - } else { - calc_fn_hash(None, fn_name, args_len).into() + ), + #[cfg(feature = "no_function")] + true => FnCallHashes::from_native_only(calc_fn_hash(None, fn_name, args_len)), + _ => FnCallHashes::from_hash(calc_fn_hash(None, fn_name, args_len)), }; self.engine() diff --git a/src/parser.rs b/src/parser.rs index 465166ed..46c37a27 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -625,9 +625,9 @@ impl Engine { let hash = calc_fn_hash(None, &id, 0); let hashes = if is_valid_function_name(&id) { - hash.into() + FnCallHashes::from_hash(hash) } else { - FnCallHashes::from_native(hash) + FnCallHashes::from_native_only(hash) }; args.shrink_to_fit(); @@ -700,9 +700,9 @@ impl Engine { let hash = calc_fn_hash(None, &id, args.len()); let hashes = if is_valid_function_name(&id) { - hash.into() + FnCallHashes::from_hash(hash) } else { - FnCallHashes::from_native(hash) + FnCallHashes::from_native_only(hash) }; args.shrink_to_fit(); @@ -1952,7 +1952,7 @@ impl Engine { Ok(FnCallExpr { namespace: Namespace::NONE, name: state.get_interned_string("-"), - hashes: FnCallHashes::from_native(calc_fn_hash(None, "-", 1)), + hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "-", 1)), args, op_token: Some(token), capture_parent_scope: false, @@ -1980,7 +1980,7 @@ impl Engine { Ok(FnCallExpr { namespace: Namespace::NONE, name: state.get_interned_string("+"), - hashes: FnCallHashes::from_native(calc_fn_hash(None, "+", 1)), + hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "+", 1)), args, op_token: Some(token), capture_parent_scope: false, @@ -2001,7 +2001,7 @@ impl Engine { Ok(FnCallExpr { namespace: Namespace::NONE, name: state.get_interned_string("!"), - hashes: FnCallHashes::from_native(calc_fn_hash(None, "!", 1)), + hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "!", 1)), args, op_token: Some(token), capture_parent_scope: false, @@ -2180,14 +2180,21 @@ impl Engine { // lhs.func(...) (lhs, Expr::FnCall(mut f, func_pos)) => { // Recalculate hash + let args_len = f.args.len() + 1; f.hashes = if is_valid_function_name(&f.name) { - FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, &f.name, f.args.len()), - calc_fn_hash(None, &f.name, f.args.len() + 1), - ) + #[cfg(not(feature = "no_function"))] + { + FnCallHashes::from_script_and_native( + calc_fn_hash(None, &f.name, args_len - 1), + calc_fn_hash(None, &f.name, args_len), + ) + } + #[cfg(feature = "no_function")] + { + FnCallHashes::from_native_only(calc_fn_hash(None, &f.name, args_len)) + } } else { - FnCallHashes::from_native(calc_fn_hash(None, &f.name, f.args.len() + 1)) + FnCallHashes::from_native_only(calc_fn_hash(None, &f.name, args_len)) }; let rhs = Expr::MethodCall(f, func_pos); @@ -2228,14 +2235,23 @@ impl Engine { // lhs.func().dot_rhs or lhs.func()[idx_rhs] Expr::FnCall(mut f, func_pos) => { // Recalculate hash + let args_len = f.args.len() + 1; f.hashes = if is_valid_function_name(&f.name) { - FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, &f.name, f.args.len()), - calc_fn_hash(None, &f.name, f.args.len() + 1), - ) + #[cfg(not(feature = "no_function"))] + { + FnCallHashes::from_script_and_native( + calc_fn_hash(None, &f.name, args_len - 1), + calc_fn_hash(None, &f.name, args_len), + ) + } + #[cfg(feature = "no_function")] + { + FnCallHashes::from_native_only(calc_fn_hash( + None, &f.name, args_len, + )) + } } else { - FnCallHashes::from_native(calc_fn_hash(None, &f.name, f.args.len() + 1)) + FnCallHashes::from_native_only(calc_fn_hash(None, &f.name, args_len)) }; let new_lhs = BinaryExpr { @@ -2351,7 +2367,7 @@ impl Engine { let mut op_base = FnCallExpr { namespace: Namespace::NONE, name: state.get_interned_string(&op), - hashes: FnCallHashes::from_native(hash), + hashes: FnCallHashes::from_native_only(hash), args, op_token: operator_token, capture_parent_scope: false, @@ -2394,7 +2410,7 @@ impl Engine { op_base.args.shrink_to_fit(); // Convert into a call to `contains` - op_base.hashes = calc_fn_hash(None, OP_CONTAINS, 2).into(); + op_base.hashes = FnCallHashes::from_hash(calc_fn_hash(None, OP_CONTAINS, 2)); op_base.name = state.get_interned_string(OP_CONTAINS); let fn_call = op_base.into_fn_call_expr(pos); @@ -2409,7 +2425,7 @@ impl Engine { let not_base = FnCallExpr { namespace: Namespace::NONE, name: state.get_interned_string(op), - hashes: FnCallHashes::from_native(calc_fn_hash(None, op, 1)), + hashes: FnCallHashes::from_native_only(calc_fn_hash(None, op, 1)), args, op_token: Some(Token::Bang), capture_parent_scope: false, @@ -2427,9 +2443,9 @@ impl Engine { .map_or(false, Option::is_some) => { op_base.hashes = if is_valid_script_function { - calc_fn_hash(None, &s, 2).into() + FnCallHashes::from_hash(calc_fn_hash(None, &s, 2)) } else { - FnCallHashes::from_native(calc_fn_hash(None, &s, 2)) + FnCallHashes::from_native_only(calc_fn_hash(None, &s, 2)) }; op_base.into_fn_call_expr(pos) } @@ -3709,7 +3725,7 @@ impl Engine { let expr = FnCallExpr { namespace: Namespace::NONE, name: state.get_interned_string(crate::engine::KEYWORD_FN_PTR_CURRY), - hashes: FnCallHashes::from_native(calc_fn_hash( + hashes: FnCallHashes::from_native_only(calc_fn_hash( None, crate::engine::KEYWORD_FN_PTR_CURRY, num_externals + 1,