From 1300ad86770d764dc1d02676cde1d975843607c3 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 1 Mar 2021 14:54:20 +0800 Subject: [PATCH] No need to copy sub-modules. --- src/engine.rs | 90 ++++++++++++++++++++++------------------------- src/engine_api.rs | 6 ++-- src/fn_call.rs | 21 ++++++++--- src/module/mod.rs | 2 +- src/optimize.rs | 2 +- 5 files changed, 65 insertions(+), 56 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 705ef918..febc1441 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -17,7 +17,7 @@ use crate::stdlib::{ collections::{HashMap, HashSet}, fmt, format, hash::{Hash, Hasher}, - iter::{empty, FromIterator}, + iter::empty, num::{NonZeroU64, NonZeroU8, NonZeroUsize}, ops::DerefMut, string::{String, ToString}, @@ -151,24 +151,6 @@ impl Imports { } } -impl<'a, T: IntoIterator)>> From for Imports { - #[inline(always)] - fn from(value: T) -> Self { - Self( - value - .into_iter() - .map(|(k, v)| (k.clone(), v.clone())) - .collect(), - ) - } -} -impl FromIterator<(ImmutableString, Shared)> for Imports { - #[inline(always)] - fn from_iter)>>(iter: T) -> Self { - Self(iter.into_iter().collect()) - } -} - #[cfg(not(feature = "unchecked"))] #[cfg(debug_assertions)] #[cfg(not(feature = "no_function"))] @@ -824,32 +806,6 @@ fn default_debug(_s: &str, _source: Option<&str>, _pos: Position) { } } -/// Search for a module within an imports stack. -/// [`Position`] in [`EvalAltResult`] is [`None`][Position::None] and must be set afterwards. -pub fn search_imports( - mods: &Imports, - state: &mut State, - namespace: &NamespaceRef, -) -> Result, Box> { - let Ident { name: root, pos } = &namespace[0]; - - // Qualified - check if the root module is directly indexed - let index = if state.always_search { - None - } else { - namespace.index() - }; - - Ok(if let Some(index) = index { - let offset = mods.len() - index.get(); - mods.get(offset).expect("invalid index in Imports") - } else { - mods.find(root) - .map(|n| mods.get(n).expect("invalid index in Imports")) - .ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *pos))? - }) -} - impl Engine { /// Create a new [`Engine`] #[inline] @@ -970,6 +926,34 @@ impl Engine { } } + /// Search for a module within an imports stack. + /// [`Position`] in [`EvalAltResult`] is [`None`][Position::None] and must be set afterwards. + pub fn search_imports( + &self, + mods: &Imports, + state: &mut State, + namespace: &NamespaceRef, + ) -> Result, Box> { + let Ident { name: root, pos } = &namespace[0]; + + // Qualified - check if the root module is directly indexed + let index = if state.always_search { + None + } else { + namespace.index() + }; + + Ok(if let Some(index) = index { + let offset = mods.len() - index.get(); + mods.get(offset).expect("invalid index in Imports") + } else { + mods.find(root) + .map(|n| mods.get(n).expect("invalid index in Imports")) + .or_else(|| self.global_sub_modules.get(root).cloned()) + .ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *pos))? + }) + } + /// Search for a variable within the scope or within imports, /// depending on whether the variable name is namespace-qualified. pub(crate) fn search_namespace<'s>( @@ -985,7 +969,7 @@ impl Engine { Expr::Variable(v) => match v.as_ref() { // Qualified variable (_, Some((hash_var, modules)), Ident { name, pos }) => { - let module = search_imports(mods, state, modules)?; + let module = self.search_imports(mods, state, modules)?; let target = module.get_qualified_var(*hash_var).map_err(|mut err| { match *err { EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => { @@ -2175,6 +2159,13 @@ impl Engine { let iter_obj = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; let iter_type = iter_obj.type_id(); + // lib should only contain scripts, so technically they cannot have iterators + + // Search order: + // 1) Global namespace - functions registered via Engine::register_XXX + // 2) Global modules - packages + // 3) Imported modules - functions marked with global namespace + // 4) Global sub-modules - functions marked with global namespace let func = self .global_namespace .get_iter(iter_type) @@ -2183,7 +2174,12 @@ impl Engine { .iter() .find_map(|m| m.get_iter(iter_type)) }) - .or_else(|| mods.get_iter(iter_type)); + .or_else(|| mods.get_iter(iter_type)) + .or_else(|| { + self.global_sub_modules + .values() + .find_map(|m| m.get_qualified_iter(iter_type)) + }); if let Some(func) = func { // Add the loop variable diff --git a/src/engine_api.rs b/src/engine_api.rs index e98ace88..f40b8bb3 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -1503,7 +1503,7 @@ impl Engine { scope: &mut Scope, ast: &AST, ) -> Result> { - let mods = &mut (&self.global_sub_modules).into(); + let mods = &mut Default::default(); let result = self.eval_ast_with_scope_raw(scope, mods, ast, 0)?; @@ -1598,7 +1598,7 @@ impl Engine { scope: &mut Scope, ast: &AST, ) -> Result<(), Box> { - let mods = &mut (&self.global_sub_modules).into(); + let mods = &mut Default::default(); let mut state: State = Default::default(); state.source = ast.clone_source(); #[cfg(not(feature = "no_module"))] @@ -1766,7 +1766,7 @@ impl Engine { args: &mut FnCallArgs, ) -> Result> { let state = &mut Default::default(); - let mods = &mut (&self.global_sub_modules).into(); + let mods = &mut Default::default(); let lib = &[ast.lib()]; if eval_ast { diff --git a/src/fn_call.rs b/src/fn_call.rs index 4f91dc94..1adc1db8 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -2,8 +2,8 @@ use crate::ast::{Expr, Stmt}; use crate::engine::{ - search_imports, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, - KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF, + Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, + KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF, MAX_DYNAMIC_PARAMETERS, }; use crate::fn_native::FnCallArgs; @@ -212,7 +212,14 @@ impl Engine { let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic` loop { - //lib.get_fn(hash, false).or_else(|| + // lib should only contain scripts, so technically speaking we don't have to check it + // lib.iter().find_map(|m| m.get_fn(hash, false).map(|f| (f.clone(), m.id_raw().cloned()))).or_else(|| { + + // Search order: + // 1) Global namespace - functions registered via Engine::register_XXX + // 2) Global modules - packages + // 3) Imported modules - functions marked with global namespace + // 4) Global sub-modules - functions marked with global namespace match self .global_namespace .get_fn(hash, false) @@ -227,6 +234,12 @@ impl Engine { .or_else(|| { mods.get_fn(hash) .map(|(f, source)| (f.clone(), source.cloned())) + }) + .or_else(|| { + self.global_sub_modules.values().find_map(|m| { + m.get_qualified_fn(hash) + .map(|f| (f.clone(), m.id_raw().cloned())) + }) }) { // Specific version found Some(f) => return Some(f), @@ -1297,7 +1310,7 @@ impl Engine { } } - let module = search_imports(mods, state, namespace)?; + let module = self.search_imports(mods, state, namespace)?; // First search in script-defined functions (can override built-in) let func = match module.get_qualified_fn(hash_script) { diff --git a/src/module/mod.rs b/src/module/mod.rs index 01a7ed25..5d61bb68 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -1783,7 +1783,7 @@ impl Module { ast: &crate::AST, engine: &crate::Engine, ) -> Result> { - let mut mods: crate::engine::Imports = (&engine.global_sub_modules).into(); + let mut mods: crate::engine::Imports = Default::default(); let orig_mods_len = mods.len(); // Run the script diff --git a/src/optimize.rs b/src/optimize.rs index 64609e60..dda80da1 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -79,7 +79,7 @@ impl<'a> State<'a> { variables: vec![], propagate_constants: true, engine, - mods: (&engine.global_sub_modules).into(), + mods: Default::default(), lib, optimization_level: level, }