diff --git a/src/ast.rs b/src/ast.rs index 9ce4c8bf..1e42993c 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -658,7 +658,7 @@ impl AST { pub(crate) fn iter_fn_def(&self) -> impl Iterator { self.functions .iter_script_fn() - .map(|(_, _, _, _, fn_def)| fn_def) + .map(|(_, _, _, _, fn_def)| fn_def.as_ref()) } /// Iterate through all function definitions. /// @@ -668,7 +668,7 @@ impl AST { pub fn iter_functions<'a>(&'a self) -> impl Iterator + 'a { self.functions .iter_script_fn() - .map(|(_, _, _, _, fn_def)| fn_def.into()) + .map(|(_, _, _, _, fn_def)| fn_def.as_ref().into()) } /// Clear all function definitions in the [`AST`]. /// diff --git a/src/fn_native.rs b/src/fn_native.rs index ace60b56..fdb4ba9b 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -570,9 +570,9 @@ impl CallableFunction { /// Panics if the [`CallableFunction`] is not [`Pure`][CallableFunction::Pure] or /// [`Method`][CallableFunction::Method]. #[inline(always)] - pub fn get_native_fn(&self) -> &FnAny { + pub fn get_native_fn(&self) -> &Shared { match self { - Self::Pure(f) | Self::Method(f) => f.as_ref(), + Self::Pure(f) | Self::Method(f) => f, Self::Iterator(_) | Self::Plugin(_) => panic!("function should be native"), #[cfg(not(feature = "no_function"))] @@ -586,12 +586,12 @@ impl CallableFunction { /// Panics if the [`CallableFunction`] is not [`Script`][CallableFunction::Script]. #[cfg(not(feature = "no_function"))] #[inline(always)] - pub fn get_fn_def(&self) -> &crate::ast::ScriptFnDef { + pub fn get_fn_def(&self) -> &Shared { match self { Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => { panic!("function should be scripted") } - Self::Script(f) => f.as_ref(), + Self::Script(f) => f, } } /// Get a reference to an iterator function. @@ -617,9 +617,9 @@ impl CallableFunction { /// /// Panics if the [`CallableFunction`] is not [`Plugin`][CallableFunction::Plugin]. #[inline(always)] - pub fn get_plugin_fn<'s>(&'s self) -> &FnPlugin { + pub fn get_plugin_fn<'s>(&'s self) -> &Shared { match self { - Self::Plugin(f) => f.as_ref(), + Self::Plugin(f) => f, Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => { panic!("function should a plugin") } diff --git a/src/module/mod.rs b/src/module/mod.rs index 2a0c2edc..d9dbd69b 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -136,7 +136,7 @@ pub struct Module { /// Flattened collection of all [`Module`] variables, including those in sub-modules. all_variables: HashMap, /// External Rust functions. - functions: HashMap, + functions: HashMap, StraightHasherBuilder>, /// Flattened collection of all external Rust functions, native or scripted. /// including those in sub-modules. all_functions: HashMap, @@ -207,7 +207,7 @@ impl fmt::Debug for Module { " functions: {}\n", self.functions .values() - .map(|FuncInfo { func, .. }| func.to_string()) + .map(|f| f.func.to_string()) .collect::>() .join(", ") ) @@ -384,11 +384,11 @@ impl Module { pub fn gen_fn_signatures(&self) -> impl Iterator + '_ { self.functions .values() - .filter(|FuncInfo { access, .. }| match access { + .filter(|f| match f.access { FnAccess::Public => true, FnAccess::Private => false, }) - .map(FuncInfo::gen_signature) + .map(|f| f.gen_signature()) } /// Does a variable exist in the [`Module`]? @@ -490,7 +490,7 @@ impl Module { param_names.push("Dynamic".into()); self.functions.insert( hash_script, - FuncInfo { + Box::new(FuncInfo { name: fn_def.name.to_string(), namespace: FnNamespace::Internal, access: fn_def.access, @@ -498,14 +498,15 @@ impl Module { param_types: Default::default(), param_names, func: fn_def.into(), - }, + }), ); self.indexed = false; self.contains_indexed_global_functions = false; hash_script } - /// Get a script-defined function in the [`Module`] based on name and number of parameters. + /// Get a shared reference to the script-defined function in the [`Module`] based on name + /// and number of parameters. #[cfg(not(feature = "no_function"))] #[inline(always)] pub fn get_script_fn( @@ -513,22 +514,15 @@ impl Module { name: &str, num_params: usize, public_only: bool, - ) -> Option<&crate::ast::ScriptFnDef> { + ) -> Option<&Shared> { self.functions .values() - .find( - |FuncInfo { - name: fn_name, - access, - params, - .. - }| { - (!public_only || *access == FnAccess::Public) - && *params == num_params - && fn_name == name - }, - ) - .map(|FuncInfo { func, .. }| func.get_fn_def()) + .find(|f| { + (!public_only || f.access == FnAccess::Public) + && f.params == num_params + && f.name == name + }) + .map(|f| f.func.get_fn_def()) } /// Get a mutable reference to the underlying [`HashMap`] of sub-modules. @@ -629,7 +623,7 @@ impl Module { if public_only { self.functions .get(&hash_fn) - .map_or(false, |FuncInfo { access, .. }| match access { + .map_or(false, |f| match f.access { FnAccess::Public => true, FnAccess::Private => false, }) @@ -717,7 +711,7 @@ impl Module { self.functions.insert( hash_fn, - FuncInfo { + Box::new(FuncInfo { name, namespace, access, @@ -729,7 +723,7 @@ impl Module { Default::default() }, func: func.into(), - }, + }), ); self.indexed = false; @@ -1478,13 +1472,11 @@ impl Module { /// The [`u64`] hash is returned by the `set_fn_XXX` calls. #[inline(always)] pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> { - self.functions - .get(&hash_fn) - .and_then(|FuncInfo { access, func, .. }| match access { - _ if !public_only => Some(func), - FnAccess::Public => Some(func), - FnAccess::Private => None, - }) + self.functions.get(&hash_fn).and_then(|f| match f.access { + _ if !public_only => Some(&f.func), + FnAccess::Public => Some(&f.func), + FnAccess::Private => None, + }) } /// Does the particular namespace-qualified function exist in the [`Module`]? @@ -1594,27 +1586,15 @@ impl Module { other .functions .iter() - .filter( - |( - _, - FuncInfo { - namespace, - access, - name, - params, - func, - .. - }, - )| { - _filter( - *namespace, - *access, - func.is_script(), - name.as_str(), - *params, - ) - }, - ) + .filter(|(_, f)| { + _filter( + f.namespace, + f.access, + f.func.is_script(), + f.name.as_str(), + f.params, + ) + }) .map(|(&k, v)| (k, v.clone())), ); @@ -1634,23 +1614,13 @@ impl Module { &mut self, filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool, ) -> &mut Self { - self.functions.retain( - |_, - FuncInfo { - namespace, - access, - name, - params, - func, - .. - }| { - if func.is_script() { - filter(*namespace, *access, name.as_str(), *params) - } else { - false - } - }, - ); + self.functions.retain(|_, f| { + if f.func.is_script() { + filter(f.namespace, f.access, f.name.as_str(), f.params) + } else { + false + } + }); self.all_functions.clear(); self.all_variables.clear(); @@ -1686,7 +1656,7 @@ impl Module { #[inline(always)] #[allow(dead_code)] pub(crate) fn iter_fn(&self) -> impl Iterator { - self.functions.values() + self.functions.values().map(Box::as_ref) } /// Get an iterator over all script-defined functions in the [`Module`]. @@ -1701,26 +1671,27 @@ impl Module { #[inline(always)] pub(crate) fn iter_script_fn( &self, - ) -> impl Iterator + '_ - { - self.functions.values().filter(|f| f.func.is_script()).map( - |FuncInfo { - namespace, - access, - name, - params, - func, - .. - }| { + ) -> impl Iterator< + Item = ( + FnNamespace, + FnAccess, + &str, + usize, + &Shared, + ), + > + '_ { + self.functions + .values() + .filter(|f| f.func.is_script()) + .map(|f| { ( - *namespace, - *access, - name.as_str(), - *params, - func.get_fn_def(), + f.namespace, + f.access, + f.name.as_str(), + f.params, + f.func.get_fn_def(), ) - }, - ) + }) } /// Get an iterator over all script-defined functions in the [`Module`]. @@ -1736,15 +1707,10 @@ impl Module { pub fn iter_script_fn_info( &self, ) -> impl Iterator { - self.functions.values().filter(|f| f.func.is_script()).map( - |FuncInfo { - name, - namespace, - access, - params, - .. - }| (*namespace, *access, name.as_str(), *params), - ) + self.functions + .values() + .filter(|f| f.func.is_script()) + .map(|f| (f.namespace, f.access, f.name.as_str(), f.params)) } /// _(INTERNALS)_ Get an iterator over all script-defined functions in the [`Module`]. @@ -1825,14 +1791,14 @@ impl Module { ast.lib() .functions .values() - .filter(|FuncInfo { access, .. }| match access { + .filter(|f| match f.access { FnAccess::Public => true, FnAccess::Private => false, }) - .filter(|FuncInfo { func, .. }| func.is_script()) - .for_each(|FuncInfo { func, .. }| { + .filter(|f| f.func.is_script()) + .for_each(|f| { // Encapsulate AST environment - let mut func = func.get_fn_def().clone(); + let mut func = crate::fn_native::shared_take_or_clone(f.func.get_fn_def().clone()); func.lib = Some(ast.shared_lib()); func.mods = func_mods.clone(); module.set_script_fn(func); @@ -1891,43 +1857,33 @@ impl Module { }); // Index all Rust functions - module.functions.iter().for_each( - |( - &hash, - FuncInfo { - name, - namespace, - access, - params, - param_types, - func, - .. - }, - )| { - match namespace { - FnNamespace::Global => { - // Flatten all functions with global namespace - functions.insert(hash, func.clone()); - contains_indexed_global_functions = true; - } - FnNamespace::Internal => (), - } - match access { - FnAccess::Public => (), - FnAccess::Private => return, // Do not index private functions + module.functions.iter().for_each(|(&hash, f)| { + match f.namespace { + FnNamespace::Global => { + // Flatten all functions with global namespace + functions.insert(hash, f.func.clone()); + contains_indexed_global_functions = true; } + FnNamespace::Internal => (), + } + match f.access { + FnAccess::Public => (), + FnAccess::Private => return, // Do not index private functions + } - if !func.is_script() { - let hash_qualified_fn = - calc_native_fn_hash(qualifiers.iter().cloned(), name, param_types); - functions.insert(hash_qualified_fn, func.clone()); - } else if cfg!(not(feature = "no_function")) { - let hash_qualified_script = - crate::calc_fn_hash(qualifiers.iter().cloned(), name, *params); - functions.insert(hash_qualified_script, func.clone()); - } - }, - ); + if !f.func.is_script() { + let hash_qualified_fn = calc_native_fn_hash( + qualifiers.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(qualifiers.iter().cloned(), f.name.as_str(), f.params); + functions.insert(hash_qualified_script, f.func.clone()); + } + }); contains_indexed_global_functions } diff --git a/src/optimize.rs b/src/optimize.rs index 06a06eaf..d087f584 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -849,7 +849,7 @@ pub fn optimize_into_ast( engine: &Engine, scope: &Scope, mut statements: Vec, - _functions: Vec, + _functions: Vec>, optimization_level: OptimizationLevel, ) -> AST { let level = if cfg!(feature = "no_optimize") { @@ -888,7 +888,9 @@ pub fn optimize_into_ast( _functions .into_iter() - .map(|mut fn_def| { + .map(|fn_def| { + let mut fn_def = crate::fn_native::shared_take_or_clone(fn_def); + let pos = fn_def.body.pos; let mut body = fn_def.body.statements.into_vec(); diff --git a/src/parser.rs b/src/parser.rs index db15c06a..171976e3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -26,7 +26,7 @@ use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream} use crate::utils::{get_hasher, StraightHasherBuilder}; use crate::{ calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position, - Scope, StaticVec, AST, + Scope, Shared, StaticVec, AST, }; #[cfg(not(feature = "no_float"))] @@ -37,7 +37,7 @@ use crate::FnAccess; type PERR = ParseErrorType; -type FunctionsLib = HashMap; +type FunctionsLib = HashMap, StraightHasherBuilder>; /// A type that encapsulates the current state of the parser. #[derive(Debug)] @@ -1008,7 +1008,7 @@ fn parse_primary( }); let hash_script = calc_fn_hash(empty(), &func.name, func.params.len()); - lib.insert(hash_script, func); + lib.insert(hash_script, func.into()); expr } @@ -2530,7 +2530,7 @@ fn parse_stmt( .into_err(pos)); } - lib.insert(hash, func); + lib.insert(hash, func.into()); Ok(Stmt::Noop(pos)) } @@ -2969,7 +2969,7 @@ impl Engine { fn parse_global_level( &self, input: &mut TokenStream, - ) -> Result<(Vec, Vec), ParseError> { + ) -> Result<(Vec, Vec>), ParseError> { let mut statements = Vec::with_capacity(16); let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder); let mut state = ParseState::new(