From fefa5a7dc725a27702fef4e77ae794c0ec2eaeba Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 8 Mar 2021 18:40:23 +0800 Subject: [PATCH] Split has_script_fn and has_native_fn. --- src/fn_call.rs | 64 +++++++++++++------------------------------------ src/optimize.rs | 28 ++++++++++++++++------ 2 files changed, 38 insertions(+), 54 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index b0d43420..63fe6079 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -577,67 +577,37 @@ impl Engine { result } - // Has a system function a Rust-native override? + // Does a scripted function exist? #[inline(always)] - pub(crate) fn has_native_override( + pub(crate) fn has_script_fn( &self, mods: Option<&Imports>, state: &mut State, lib: &[&Module], - fn_name: &str, - arg_types: &[TypeId], - ) -> bool { - let hash_script = calc_fn_hash(empty(), fn_name, arg_types.len()); - let hash_params = calc_fn_params_hash(arg_types.iter().cloned()); - let hash_fn = combine_hashes(hash_script, hash_params); - - self.has_override(mods, state, lib, Some(hash_fn), None) - } - - // Has a system function an override? - #[inline(always)] - pub(crate) fn has_override( - &self, - mods: Option<&Imports>, - state: &mut State, - lib: &[&Module], - hash_fn: Option, - hash_script: Option, + hash_script: u64, ) -> bool { let cache = state.fn_resolution_cache_mut(); - if hash_script.map_or(false, |hash| cache.contains_key(&hash)) - || hash_fn.map_or(false, |hash| cache.contains_key(&hash)) - { - return true; + if let Some(result) = cache.get(&hash_script).map(|v| v.is_some()) { + return result; } // First check script-defined functions - if hash_script.map_or(false, |hash| lib.iter().any(|&m| m.contains_fn(hash, false))) - //|| hash_fn.map_or(false, |hash| lib.iter().any(|&m| m.contains_fn(hash, false))) + let result = lib.iter().any(|&m| m.contains_fn(hash_script, false)) // Then check registered functions - || hash_script.map_or(false, |hash| self.global_namespace.contains_fn(hash, false)) - || hash_fn.map_or(false, |hash| self.global_namespace.contains_fn(hash, false)) + || self.global_namespace.contains_fn(hash_script, false) // Then check packages - || hash_script.map_or(false, |hash| self.global_modules.iter().any(|m| m.contains_fn(hash, false))) - || hash_fn.map_or(false, |hash| self.global_modules.iter().any(|m| m.contains_fn(hash, false))) + || self.global_modules.iter().any(|m| m.contains_fn(hash_script, false)) // Then check imported modules - || hash_script.map_or(false, |hash| mods.map_or(false, |m| m.contains_fn(hash))) - || hash_fn.map_or(false, |hash| mods.map_or(false, |m| m.contains_fn(hash))) + || mods.map_or(false, |m| m.contains_fn(hash_script)) // Then check sub-modules - || hash_script.map_or(false, |hash| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash))) - || hash_fn.map_or(false, |hash| self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash))) - { - true - } else { - if let Some(hash_fn) = hash_fn { - cache.insert(hash_fn, None); - } - if let Some(hash_script) = hash_script { - cache.insert(hash_script, None); - } - false + || self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash_script)); + + if !result { + cache.insert(hash_script, None); } + + result } /// Perform an actual function call, native Rust or scripted, taking care of special functions. @@ -689,7 +659,7 @@ impl Engine { Dynamic::FALSE } else { let hash_script = calc_fn_hash(empty(), &fn_name, num_params as usize); - self.has_override(Some(mods), state, lib, None, Some(hash_script)) + self.has_script_fn(Some(mods), state, lib, hash_script) .into() }, false, @@ -1165,7 +1135,7 @@ impl Engine { Dynamic::FALSE } else { let hash_script = calc_fn_hash(empty(), &fn_name, num_params as usize); - self.has_override(Some(mods), state, lib, None, Some(hash_script)) + self.has_script_fn(Some(mods), state, lib, hash_script) .into() }); } diff --git a/src/optimize.rs b/src/optimize.rs index 653c05f0..20456ad2 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -6,6 +6,7 @@ use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF} use crate::fn_builtin::get_builtin_binary_op_fn; use crate::parser::map_dynamic_to_expr; use crate::stdlib::{ + any::TypeId, boxed::Box, hash::{Hash, Hasher}, iter::empty, @@ -15,8 +16,11 @@ use crate::stdlib::{ vec::Vec, }; use crate::token::is_valid_identifier; -use crate::utils::{calc_fn_hash, get_hasher}; -use crate::{Dynamic, Engine, Module, Position, Scope, StaticVec, AST}; +use crate::utils::get_hasher; +use crate::{ + calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, Module, Position, Scope, + StaticVec, AST, +}; /// Level of optimization performed. #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] @@ -126,15 +130,25 @@ impl<'a> State<'a> { } } +// Has a system function a Rust-native override? +fn has_native_fn(state: &State, hash_script: u64, arg_types: &[TypeId]) -> bool { + let hash_params = calc_fn_params_hash(arg_types.iter().cloned()); + let hash = combine_hashes(hash_script, hash_params); + + // First check registered functions + state.engine.global_namespace.contains_fn(hash, false) + // Then check packages + || state.engine.global_modules.iter().any(|m| m.contains_fn(hash, false)) + // Then check sub-modules + || state.engine.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash)) +} + /// Call a registered function fn call_fn_with_constant_arguments( state: &State, fn_name: &str, arg_values: &mut [Dynamic], ) -> Option { - // Search built-in's and external functions - let hash_native = calc_fn_hash(empty(), fn_name, arg_values.len()); - state .engine .call_native_fn( @@ -142,7 +156,7 @@ fn call_fn_with_constant_arguments( &mut Default::default(), state.lib, fn_name, - hash_native, + calc_fn_hash(empty(), fn_name, arg_values.len()), arg_values.iter_mut().collect::>().as_mut(), false, false, @@ -676,7 +690,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect(); // Search for overloaded operators (can override built-in). - if !state.engine.has_native_override(Some(&Default::default()), &mut Default::default(), state.lib, x.name.as_ref(), arg_types.as_ref()) { + if !has_native_fn(state, x.hash.native_hash(), arg_types.as_ref()) { if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1]) .and_then(|f| { let ctx = (state.engine, x.name.as_ref(), state.lib).into();