diff --git a/src/api.rs b/src/api.rs index 40eef3c3..90a918c7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -956,7 +956,11 @@ impl Engine { ast: AST, optimization_level: OptimizationLevel, ) -> AST { - let fn_lib = ast.1.iter().map(|fn_def| fn_def.as_ref().clone()).collect(); + let fn_lib = ast + .1 + .iter() + .map(|(_, fn_def)| fn_def.as_ref().clone()) + .collect(); optimize_into_ast(self, scope, ast.0, fn_lib, optimization_level) } diff --git a/src/engine.rs b/src/engine.rs index 2e1462d9..b0b44a38 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -11,7 +11,6 @@ use crate::token::Position; use crate::stdlib::{ any::TypeId, boxed::Box, - cmp::Ordering, collections::{hash_map::DefaultHasher, HashMap}, format, hash::{Hash, Hasher}, @@ -125,48 +124,41 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> { /// So instead this is implemented as a sorted list and binary searched. #[derive(Debug, Clone)] pub struct FunctionsLib( - #[cfg(feature = "sync")] Vec>, - #[cfg(not(feature = "sync"))] Vec>, + #[cfg(feature = "sync")] HashMap>, + #[cfg(not(feature = "sync"))] HashMap>, ); -impl FnDef { - /// Function to order two FnDef records, for binary search. - pub fn compare(&self, name: &str, params_len: usize) -> Ordering { - // First order by name - match self.name.as_str().cmp(name) { - // Then by number of parameters - Ordering::Equal => self.params.len().cmp(¶ms_len), - order => order, - } - } -} - impl FunctionsLib { /// Create a new `FunctionsLib`. pub fn new() -> Self { - FunctionsLib(Vec::new()) + FunctionsLib(HashMap::new()) } /// Create a new `FunctionsLib` from a collection of `FnDef`. pub fn from_vec(vec: Vec) -> Self { - #[cfg(feature = "sync")] - { - FunctionsLib(vec.into_iter().map(Arc::new).collect()) - } - #[cfg(not(feature = "sync"))] - { - FunctionsLib(vec.into_iter().map(Rc::new).collect()) - } + FunctionsLib( + vec.into_iter() + .map(|f| { + let hash = calc_fn_def(&f.name, f.params.len()); + + #[cfg(feature = "sync")] + { + (hash, Arc::new(f)) + } + #[cfg(not(feature = "sync"))] + { + (hash, Rc::new(f)) + } + }) + .collect(), + ) } /// Does a certain function exist in the `FunctionsLib`? pub fn has_function(&self, name: &str, params: usize) -> bool { - self.0.binary_search_by(|f| f.compare(name, params)).is_ok() + self.contains_key(&calc_fn_def(name, params)) } /// Get a function definition from the `FunctionsLib`. pub fn get_function(&self, name: &str, params: usize) -> Option<&FnDef> { - self.0 - .binary_search_by(|f| f.compare(name, params)) - .ok() - .map(|n| self.0[n].as_ref()) + self.get(&calc_fn_def(name, params)).map(|f| f.as_ref()) } /// Merge another `FunctionsLib` into this `FunctionsLib`. pub fn merge(&self, other: &Self) -> Self { @@ -177,16 +169,8 @@ impl FunctionsLib { } else { let mut functions = self.clone(); - other.iter().cloned().for_each(|fn_def| { - if let Some((n, _)) = functions - .iter() - .enumerate() - .find(|(_, f)| f.name == fn_def.name && f.params.len() == fn_def.params.len()) - { - functions[n] = fn_def; - } else { - functions.push(fn_def); - } + other.iter().for_each(|(hash, fn_def)| { + functions.insert(*hash, fn_def.clone()); }); functions @@ -196,9 +180,9 @@ impl FunctionsLib { impl Deref for FunctionsLib { #[cfg(feature = "sync")] - type Target = Vec>; + type Target = HashMap>; #[cfg(not(feature = "sync"))] - type Target = Vec>; + type Target = HashMap>; fn deref(&self) -> &Self::Target { &self.0 @@ -207,11 +191,11 @@ impl Deref for FunctionsLib { impl DerefMut for FunctionsLib { #[cfg(feature = "sync")] - fn deref_mut(&mut self) -> &mut Vec> { + fn deref_mut(&mut self) -> &mut HashMap> { &mut self.0 } #[cfg(not(feature = "sync"))] - fn deref_mut(&mut self) -> &mut Vec> { + fn deref_mut(&mut self) -> &mut HashMap> { &mut self.0 } } @@ -349,6 +333,13 @@ pub(crate) fn calc_fn_spec(fn_name: &str, params: impl Iterator) s.finish() } +pub(crate) fn calc_fn_def(fn_name: &str, params: usize) -> u64 { + let mut s = DefaultHasher::new(); + fn_name.hash(&mut s); + params.hash(&mut s); + s.finish() +} + impl Engine { /// Create a new `Engine` pub fn new() -> Self { diff --git a/src/parser.rs b/src/parser.rs index c8331d35..fe7b3191 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ //! Main module defining the lexer and parser. use crate::any::{Dynamic, Union}; -use crate::engine::{Engine, FunctionsLib}; +use crate::engine::{calc_fn_def, Engine, FunctionsLib}; use crate::error::{LexError, ParseError, ParseErrorType}; use crate::optimize::{optimize_into_ast, OptimizationLevel}; use crate::scope::{EntryType as ScopeEntryType, Scope}; @@ -1787,9 +1787,9 @@ pub fn parse_global_expr<'a>( /// Parse the global level statements. fn parse_global_level<'a>( input: &mut Peekable>, -) -> Result<(Vec, Vec), ParseError> { +) -> Result<(Vec, HashMap), ParseError> { let mut statements = Vec::::new(); - let mut functions = Vec::::new(); + let mut functions = HashMap::::new(); while input.peek().is_some() { // Collect all the function definitions @@ -1797,13 +1797,7 @@ fn parse_global_level<'a>( { if matches!(input.peek().expect("should not be None"), (Token::Fn, _)) { let f = parse_fn(input, true)?; - - // Ensure list is sorted - match functions.binary_search_by(|fn_def| fn_def.compare(&f.name, f.params.len())) { - Ok(n) => functions[n] = f, // Override previous definition - Err(n) => functions.insert(n, f), // New function definition - } - + functions.insert(calc_fn_def(&f.name, f.params.len()), f); continue; } } @@ -1849,9 +1843,10 @@ pub fn parse<'a>( ) -> Result { let (statements, functions) = parse_global_level(input)?; + let fn_lib = functions.into_iter().map(|(_, v)| v).collect(); Ok( // Optimize AST - optimize_into_ast(engine, scope, statements, functions, optimization_level), + optimize_into_ast(engine, scope, statements, fn_lib, optimization_level), ) } diff --git a/src/scope.rs b/src/scope.rs index 3da54404..a9fd579c 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -397,13 +397,6 @@ impl<'a> Scope<'a> { &mut entry.value } - /// Get a mutable reference to an entry in the Scope and downcast it to a specific type - pub(crate) fn get_mut_by_type(&mut self, key: EntryRef) -> &mut T { - self.get_mut(key) - .downcast_mut::() - .expect("wrong type cast") - } - /// Get an iterator to entries in the Scope. pub fn iter(&self) -> impl Iterator { self.0.iter().rev() // Always search a Scope in reverse order