Make FunctionsLib a HashMap.
This commit is contained in:
parent
f8e9d66a0b
commit
3a93ab8240
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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<Arc<FnDef>>,
|
||||
#[cfg(not(feature = "sync"))] Vec<Rc<FnDef>>,
|
||||
#[cfg(feature = "sync")] HashMap<u64, Arc<FnDef>>,
|
||||
#[cfg(not(feature = "sync"))] HashMap<u64, Rc<FnDef>>,
|
||||
);
|
||||
|
||||
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<FnDef>) -> Self {
|
||||
FunctionsLib(
|
||||
vec.into_iter()
|
||||
.map(|f| {
|
||||
let hash = calc_fn_def(&f.name, f.params.len());
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
{
|
||||
FunctionsLib(vec.into_iter().map(Arc::new).collect())
|
||||
(hash, Arc::new(f))
|
||||
}
|
||||
#[cfg(not(feature = "sync"))]
|
||||
{
|
||||
FunctionsLib(vec.into_iter().map(Rc::new).collect())
|
||||
(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<Arc<FnDef>>;
|
||||
type Target = HashMap<u64, Arc<FnDef>>;
|
||||
#[cfg(not(feature = "sync"))]
|
||||
type Target = Vec<Rc<FnDef>>;
|
||||
type Target = HashMap<u64, Rc<FnDef>>;
|
||||
|
||||
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<Arc<FnDef>> {
|
||||
fn deref_mut(&mut self) -> &mut HashMap<u64, Arc<FnDef>> {
|
||||
&mut self.0
|
||||
}
|
||||
#[cfg(not(feature = "sync"))]
|
||||
fn deref_mut(&mut self) -> &mut Vec<Rc<FnDef>> {
|
||||
fn deref_mut(&mut self) -> &mut HashMap<u64, Rc<FnDef>> {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
@ -349,6 +333,13 @@ pub(crate) fn calc_fn_spec(fn_name: &str, params: impl Iterator<Item = TypeId>)
|
||||
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 {
|
||||
|
@ -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<TokenIterator<'a>>,
|
||||
) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
|
||||
) -> Result<(Vec<Stmt>, HashMap<u64, FnDef>), ParseError> {
|
||||
let mut statements = Vec::<Stmt>::new();
|
||||
let mut functions = Vec::<FnDef>::new();
|
||||
let mut functions = HashMap::<u64, FnDef>::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<AST, ParseError> {
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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<T: Variant + Clone>(&mut self, key: EntryRef) -> &mut T {
|
||||
self.get_mut(key)
|
||||
.downcast_mut::<T>()
|
||||
.expect("wrong type cast")
|
||||
}
|
||||
|
||||
/// Get an iterator to entries in the Scope.
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Entry> {
|
||||
self.0.iter().rev() // Always search a Scope in reverse order
|
||||
|
Loading…
Reference in New Issue
Block a user