Anticipate number of functions to be registered.

This commit is contained in:
Stephen Chung 2020-04-19 13:40:11 +08:00
parent 53f7edf306
commit d3d62c7dd9
3 changed files with 104 additions and 118 deletions

View File

@ -62,12 +62,7 @@ impl<F: Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static> IteratorCal
impl Engine { impl Engine {
/// Register a custom function. /// Register a custom function.
pub(crate) fn register_fn_raw(&mut self, fn_name: &str, args: Vec<TypeId>, f: Box<FnAny>) { pub(crate) fn register_fn_raw(&mut self, fn_name: &str, args: Vec<TypeId>, f: Box<FnAny>) {
if self.functions.is_none() {
self.functions = Some(HashMap::new());
}
self.functions self.functions
.as_mut()
.unwrap()
.insert(calc_fn_spec(fn_name, args.into_iter()), f); .insert(calc_fn_spec(fn_name, args.into_iter()), f);
} }
@ -171,14 +166,7 @@ impl Engine {
/// Register an iterator adapter for a type with the `Engine`. /// Register an iterator adapter for a type with the `Engine`.
/// This is an advanced feature. /// This is an advanced feature.
pub fn register_iterator<T: Variant + Clone, F: IteratorCallback>(&mut self, f: F) { pub fn register_iterator<T: Variant + Clone, F: IteratorCallback>(&mut self, f: F) {
if self.type_iterators.is_none() { self.type_iterators.insert(TypeId::of::<T>(), Box::new(f));
self.type_iterators = Some(HashMap::new());
}
self.type_iterators
.as_mut()
.unwrap()
.insert(TypeId::of::<T>(), Box::new(f));
} }
/// Register a getter function for a member of a registered type with the `Engine`. /// Register a getter function for a member of a registered type with the `Engine`.

View File

@ -59,6 +59,13 @@ pub const FUNC_TO_STRING: &str = "to_string";
pub const FUNC_GETTER: &str = "get$"; pub const FUNC_GETTER: &str = "get$";
pub const FUNC_SETTER: &str = "set$"; pub const FUNC_SETTER: &str = "set$";
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
const FUNCTIONS_COUNT: usize = 512;
#[cfg(any(feature = "only_i32", feature = "only_i64"))]
const FUNCTIONS_COUNT: usize = 256;
#[derive(Debug, Eq, PartialEq, Hash, Clone)] #[derive(Debug, Eq, PartialEq, Hash, Clone)]
enum IndexValue { enum IndexValue {
Num(usize), Num(usize),
@ -169,11 +176,7 @@ impl FunctionsLib {
self.clone() self.clone()
} else { } else {
let mut functions = self.clone(); let mut functions = self.clone();
functions.extend(other.iter().map(|(hash, fn_def)| (*hash, fn_def.clone())));
other.iter().for_each(|(hash, fn_def)| {
functions.insert(*hash, fn_def.clone());
});
functions functions
} }
} }
@ -219,10 +222,10 @@ impl DerefMut for FunctionsLib {
/// Currently, `Engine` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`. /// Currently, `Engine` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
pub struct Engine { pub struct Engine {
/// A hashmap containing all compiled functions known to the engine. /// A hashmap containing all compiled functions known to the engine.
pub(crate) functions: Option<HashMap<u64, Box<FnAny>>>, pub(crate) functions: HashMap<u64, Box<FnAny>>,
/// A hashmap containing all iterators known to the engine. /// A hashmap containing all iterators known to the engine.
pub(crate) type_iterators: Option<HashMap<TypeId, Box<IteratorFn>>>, pub(crate) type_iterators: HashMap<TypeId, Box<IteratorFn>>,
/// A hashmap mapping type names to pretty-print names. /// A hashmap mapping type names to pretty-print names.
pub(crate) type_names: Option<HashMap<String, String>>, pub(crate) type_names: Option<HashMap<String, String>>,
@ -253,8 +256,8 @@ impl Default for Engine {
fn default() -> Self { fn default() -> Self {
// Create the new scripting Engine // Create the new scripting Engine
let mut engine = Engine { let mut engine = Engine {
functions: None, functions: HashMap::with_capacity(FUNCTIONS_COUNT),
type_iterators: None, type_iterators: HashMap::new(),
type_names: None, type_names: None,
// default print/debug implementations // default print/debug implementations
@ -350,8 +353,8 @@ impl Engine {
/// Create a new `Engine` with minimal configurations without the standard library etc. /// Create a new `Engine` with minimal configurations without the standard library etc.
pub fn new_raw() -> Self { pub fn new_raw() -> Self {
let mut engine = Engine { let mut engine = Engine {
functions: None, functions: HashMap::with_capacity(FUNCTIONS_COUNT / 2),
type_iterators: None, type_iterators: HashMap::new(),
type_names: None, type_names: None,
on_print: None, on_print: None,
on_debug: None, on_debug: None,
@ -476,7 +479,7 @@ impl Engine {
// Search built-in's and external functions // Search built-in's and external functions
let fn_spec = calc_fn_spec(fn_name, args.iter().map(|a| a.type_id())); let fn_spec = calc_fn_spec(fn_name, args.iter().map(|a| a.type_id()));
if let Some(func) = self.functions.as_ref().and_then(|f| f.get(&fn_spec)) { if let Some(func) = self.functions.get(&fn_spec) {
// Run external function // Run external function
let result = func(args, pos)?; let result = func(args, pos)?;
@ -548,7 +551,7 @@ impl Engine {
} }
/// Chain-evaluate a dot setter. /// Chain-evaluate a dot setter.
fn get_dot_val_helper( fn dot_get_helper(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
fn_lib: Option<&FunctionsLib>, fn_lib: Option<&FunctionsLib>,
@ -563,13 +566,10 @@ impl Engine {
.iter() .iter()
.map(|arg_expr| self.eval_expr(scope, fn_lib, arg_expr, level)) .map(|arg_expr| self.eval_expr(scope, fn_lib, arg_expr, level))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let mut args: Vec<_> = once(target.get_mut(scope))
let this_ptr = target.get_mut(scope); .chain(values.iter_mut())
.collect();
let mut args: Vec<_> = once(this_ptr).chain(values.iter_mut()).collect();
let def_val = def_val.as_ref(); let def_val = def_val.as_ref();
self.call_fn_raw(None, fn_lib, fn_name, &mut args, def_val, *pos, 0) self.call_fn_raw(None, fn_lib, fn_name, &mut args, def_val, *pos, 0)
} }
@ -590,7 +590,7 @@ impl Engine {
// xxx.???[???][idx_expr] // xxx.???[???][idx_expr]
Expr::Index(_, _, _) => { Expr::Index(_, _, _) => {
// Chain the indexing // Chain the indexing
self.get_dot_val_helper(scope, fn_lib, target, idx_lhs, level)? self.dot_get_helper(scope, fn_lib, target, idx_lhs, level)?
} }
// Syntax error // Syntax error
_ => { _ => {
@ -601,7 +601,7 @@ impl Engine {
} }
}; };
self.get_indexed_value(scope, fn_lib, &lhs_value, idx_expr, *op_pos, level, false) self.get_indexed_val(scope, fn_lib, &lhs_value, idx_expr, *op_pos, level, false)
.map(|(val, _)| val) .map(|(val, _)| val)
} }
@ -612,7 +612,7 @@ impl Engine {
let mut args = [target.get_mut(scope)]; let mut args = [target.get_mut(scope)];
self.call_fn_raw(None, fn_lib, &make_getter(id), &mut args, None, *pos, 0) self.call_fn_raw(None, fn_lib, &make_getter(id), &mut args, None, *pos, 0)
.and_then(|mut val| { .and_then(|mut val| {
self.get_dot_val_helper(scope, fn_lib, (&mut val).into(), rhs, level) self.dot_get_helper(scope, fn_lib, (&mut val).into(), rhs, level)
}) })
} }
// xxx.idx_lhs[idx_expr].rhs // xxx.idx_lhs[idx_expr].rhs
@ -626,7 +626,7 @@ impl Engine {
} }
// xxx.???[???][idx_expr].rhs // xxx.???[???][idx_expr].rhs
Expr::Index(_, _, _) => { Expr::Index(_, _, _) => {
self.get_dot_val_helper(scope, fn_lib, target, idx_lhs, level)? self.dot_get_helper(scope, fn_lib, target, idx_lhs, level)?
} }
// Syntax error // Syntax error
_ => { _ => {
@ -637,9 +637,9 @@ impl Engine {
} }
}; };
self.get_indexed_value(scope, fn_lib, &val, idx_expr, *op_pos, level, false) self.get_indexed_val(scope, fn_lib, &val, idx_expr, *op_pos, level, false)
.and_then(|(mut val, _)| { .and_then(|(mut val, _)| {
self.get_dot_val_helper(scope, fn_lib, (&mut val).into(), rhs, level) self.dot_get_helper(scope, fn_lib, (&mut val).into(), rhs, level)
}) })
} }
// Syntax error // Syntax error
@ -658,7 +658,7 @@ impl Engine {
} }
/// Evaluate a dot chain getter /// Evaluate a dot chain getter
fn get_dot_val( fn dot_get(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
fn_lib: Option<&FunctionsLib>, fn_lib: Option<&FunctionsLib>,
@ -676,15 +676,14 @@ impl Engine {
// This is a variable property access (potential function call). // This is a variable property access (potential function call).
// Use a direct index into `scope` to directly mutate the variable value. // Use a direct index into `scope` to directly mutate the variable value.
self.get_dot_val_helper(scope, fn_lib, entry.into(), dot_rhs, level) self.dot_get_helper(scope, fn_lib, entry.into(), dot_rhs, level)
} }
// idx_lhs[idx_expr].??? // idx_lhs[idx_expr].???
Expr::Index(idx_lhs, idx_expr, op_pos) => { Expr::Index(idx_lhs, idx_expr, op_pos) => {
let (src, index, mut val) = let (src, index, mut val) =
self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?; self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?;
let value = let value = self.dot_get_helper(scope, fn_lib, (&mut val).into(), dot_rhs, level);
self.get_dot_val_helper(scope, fn_lib, (&mut val).into(), dot_rhs, level);
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned. // In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
if let Some(src) = src { if let Some(src) = src {
@ -697,12 +696,8 @@ impl Engine {
} }
ScopeEntryType::Normal => { ScopeEntryType::Normal => {
Self::update_indexed_var_in_scope( let pos = dot_rhs.position();
scope, Self::update_indexed_scope_var(scope, src, index, val, pos)?;
src,
index,
(val, dot_rhs.position()),
)?;
} }
} }
} }
@ -713,7 +708,7 @@ impl Engine {
// {expr}.??? // {expr}.???
expr => { expr => {
let mut val = self.eval_expr(scope, fn_lib, expr, level)?; let mut val = self.eval_expr(scope, fn_lib, expr, level)?;
self.get_dot_val_helper(scope, fn_lib, (&mut val).into(), dot_rhs, level) self.dot_get_helper(scope, fn_lib, (&mut val).into(), dot_rhs, level)
} }
} }
} }
@ -730,7 +725,7 @@ impl Engine {
} }
/// Get the value at the indexed position of a base type /// Get the value at the indexed position of a base type
fn get_indexed_value( fn get_indexed_val(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
fn_lib: Option<&FunctionsLib>, fn_lib: Option<&FunctionsLib>,
@ -843,7 +838,7 @@ impl Engine {
let (ScopeSource { typ, index, .. }, val) = let (ScopeSource { typ, index, .. }, val) =
Self::search_scope(scope, &id, lhs.position())?; Self::search_scope(scope, &id, lhs.position())?;
let (val, idx) = let (val, idx) =
self.get_indexed_value(scope, fn_lib, &val, idx_expr, op_pos, level, false)?; self.get_indexed_val(scope, fn_lib, &val, idx_expr, op_pos, level, false)?;
Ok(( Ok((
Some(ScopeSource { Some(ScopeSource {
@ -859,7 +854,7 @@ impl Engine {
// (expr)[idx_expr] // (expr)[idx_expr]
expr => { expr => {
let val = self.eval_expr(scope, fn_lib, expr, level)?; let val = self.eval_expr(scope, fn_lib, expr, level)?;
self.get_indexed_value(scope, fn_lib, &val, idx_expr, op_pos, level, false) self.get_indexed_val(scope, fn_lib, &val, idx_expr, op_pos, level, false)
.map(|(val, index)| (None, index, val)) .map(|(val, index)| (None, index, val))
} }
} }
@ -879,29 +874,28 @@ impl Engine {
} }
/// Update the value at an index position in a variable inside the scope /// Update the value at an index position in a variable inside the scope
fn update_indexed_var_in_scope( fn update_indexed_scope_var(
scope: &mut Scope, scope: &mut Scope,
src: ScopeSource, src: ScopeSource,
idx: IndexValue, idx: IndexValue,
new_val: (Dynamic, Position), new_val: Dynamic,
pos: Position,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let target = scope.get_mut(src); let target = scope.get_mut(src);
match target.get_mut() { match target.get_mut() {
// array_id[idx] = val // array_id[idx] = val
Union::Array(arr) => { Union::Array(arr) => {
arr[idx.as_num()] = new_val.0; arr[idx.as_num()] = new_val;
} }
// map_id[idx] = val // map_id[idx] = val
Union::Map(map) => { Union::Map(map) => {
map.insert(idx.as_str(), new_val.0); map.insert(idx.as_str(), new_val);
} }
// string_id[idx] = val // string_id[idx] = val
Union::Str(s) => { Union::Str(s) => {
let pos = new_val.1;
// Value must be a character // Value must be a character
let ch = new_val let ch = new_val
.0
.as_char() .as_char()
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?; .map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
Self::str_replace_char(s, idx.as_num(), ch); Self::str_replace_char(s, idx.as_num(), ch);
@ -914,7 +908,7 @@ impl Engine {
} }
/// Update the value at an index position /// Update the value at an index position
fn update_indexed_value( fn update_indexed_val(
mut target: Dynamic, mut target: Dynamic,
idx: IndexValue, idx: IndexValue,
new_val: Dynamic, new_val: Dynamic,
@ -932,7 +926,6 @@ impl Engine {
let ch = new_val let ch = new_val
.as_char() .as_char()
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?; .map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
Self::str_replace_char(s, idx.as_num(), ch); Self::str_replace_char(s, idx.as_num(), ch);
} }
// All other variable types should be an error // All other variable types should be an error
@ -943,19 +936,20 @@ impl Engine {
} }
/// Chain-evaluate a dot setter /// Chain-evaluate a dot setter
fn set_dot_val_helper( fn dot_set_helper(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
fn_lib: Option<&FunctionsLib>, fn_lib: Option<&FunctionsLib>,
this_ptr: &mut Dynamic, this_ptr: &mut Dynamic,
dot_rhs: &Expr, dot_rhs: &Expr,
new_val: (&mut Dynamic, Position), new_val: &mut Dynamic,
val_pos: Position,
level: usize, level: usize,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
match dot_rhs { match dot_rhs {
// xxx.id // xxx.id
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let mut args = [this_ptr, new_val.0]; let mut args = [this_ptr, new_val];
self.call_fn_raw(None, fn_lib, &make_setter(id), &mut args, None, *pos, 0) self.call_fn_raw(None, fn_lib, &make_setter(id), &mut args, None, *pos, 0)
} }
@ -967,11 +961,11 @@ impl Engine {
let fn_name = make_getter(id); let fn_name = make_getter(id);
self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0) self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0)
.and_then(|val| { .and_then(|val| {
let (_, index) = self.get_indexed_value( let (_, index) = self.get_indexed_val(
scope, fn_lib, &val, idx_expr, *op_pos, level, true, scope, fn_lib, &val, idx_expr, *op_pos, level, true,
)?; )?;
Self::update_indexed_value(val, index, new_val.0.clone(), new_val.1) Self::update_indexed_val(val, index, new_val.clone(), val_pos)
}) })
.and_then(|mut val| { .and_then(|mut val| {
let fn_name = make_setter(id); let fn_name = make_setter(id);
@ -994,7 +988,9 @@ impl Engine {
let fn_name = make_getter(id); let fn_name = make_getter(id);
self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0) self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0)
.and_then(|mut val| { .and_then(|mut val| {
self.set_dot_val_helper(scope, fn_lib, &mut val, rhs, new_val, level) self.dot_set_helper(
scope, fn_lib, &mut val, rhs, new_val, val_pos, level,
)
.map(|_| val) // Discard Ok return value .map(|_| val) // Discard Ok return value
}) })
.and_then(|mut val| { .and_then(|mut val| {
@ -1012,18 +1008,16 @@ impl Engine {
let fn_name = make_getter(id); let fn_name = make_getter(id);
self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0) self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0)
.and_then(|v| { .and_then(|v| {
let (mut value, index) = self.get_indexed_value( let (mut value, index) = self.get_indexed_val(
scope, fn_lib, &v, idx_expr, *op_pos, level, false, scope, fn_lib, &v, idx_expr, *op_pos, level, false,
)?; )?;
let val_pos = new_val.1; self.dot_set_helper(
let this_ptr = &mut value; scope, fn_lib, &mut value, rhs, new_val, val_pos, level,
self.set_dot_val_helper(
scope, fn_lib, this_ptr, rhs, new_val, level,
)?; )?;
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned. // In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
Self::update_indexed_value(v, index, value, val_pos) Self::update_indexed_val(v, index, value, val_pos)
}) })
.and_then(|mut v| { .and_then(|mut v| {
let fn_name = make_setter(id); let fn_name = make_setter(id);
@ -1055,13 +1049,14 @@ impl Engine {
} }
// Evaluate a dot chain setter // Evaluate a dot chain setter
fn set_dot_val( fn dot_set(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
fn_lib: Option<&FunctionsLib>, fn_lib: Option<&FunctionsLib>,
dot_lhs: &Expr, dot_lhs: &Expr,
dot_rhs: &Expr, dot_rhs: &Expr,
new_val: (&mut Dynamic, Position), new_val: &mut Dynamic,
val_pos: Position,
op_pos: Position, op_pos: Position,
level: usize, level: usize,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
@ -1077,9 +1072,15 @@ impl Engine {
_ => { _ => {
// Avoid referencing scope which is used below as mut // Avoid referencing scope which is used below as mut
let entry = ScopeSource { name: id, ..src }; let entry = ScopeSource { name: id, ..src };
let this_ptr = &mut target; let value = self.dot_set_helper(
let value = self scope,
.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level); fn_lib,
&mut target,
dot_rhs,
new_val,
val_pos,
level,
);
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned. // In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
*scope.get_mut(entry) = target; *scope.get_mut(entry) = target;
@ -1094,10 +1095,9 @@ impl Engine {
Expr::Index(lhs, idx_expr, op_pos) => { Expr::Index(lhs, idx_expr, op_pos) => {
let (src, index, mut target) = let (src, index, mut target) =
self.eval_index_expr(scope, fn_lib, lhs, idx_expr, *op_pos, level)?; self.eval_index_expr(scope, fn_lib, lhs, idx_expr, *op_pos, level)?;
let val_pos = new_val.1;
let this_ptr = &mut target; let this_ptr = &mut target;
let value = let value =
self.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level); self.dot_set_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, val_pos, level);
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned. // In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
if let Some(src) = src { if let Some(src) = src {
@ -1108,14 +1108,8 @@ impl Engine {
lhs.position(), lhs.position(),
))); )));
} }
ScopeEntryType::Normal => { ScopeEntryType::Normal => {
Self::update_indexed_var_in_scope( Self::update_indexed_scope_var(scope, src, index, target, val_pos)?;
scope,
src,
index,
(target, val_pos),
)?;
} }
} }
} }
@ -1257,32 +1251,36 @@ impl Engine {
let (src, index, _) = let (src, index, _) =
self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?; self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?;
match src.map(|x| x.typ) { if let Some(src) = src {
None => Err(Box::new(EvalAltResult::ErrorAssignmentToUnknownLHS( match src.typ {
idx_lhs.position(), ScopeEntryType::Constant => {
))),
Some(ScopeEntryType::Constant) => {
Err(Box::new(EvalAltResult::ErrorAssignmentToConstant( Err(Box::new(EvalAltResult::ErrorAssignmentToConstant(
src.unwrap().name.to_string(), src.name.to_string(),
idx_lhs.position(), idx_lhs.position(),
))) )))
} }
ScopeEntryType::Normal => {
Some(ScopeEntryType::Normal) => Ok(Self::update_indexed_var_in_scope( let pos = rhs.position();
scope, Ok(Self::update_indexed_scope_var(
src.unwrap(), scope, src, index, rhs_val, pos,
index, )?)
(rhs_val, rhs.position()), }
)?), }
} else {
Err(Box::new(EvalAltResult::ErrorAssignmentToUnknownLHS(
idx_lhs.position(),
)))
} }
} }
// dot_lhs.dot_rhs = rhs // dot_lhs.dot_rhs = rhs
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Dot(dot_lhs, dot_rhs, _) => { Expr::Dot(dot_lhs, dot_rhs, _) => {
let new_val = (&mut rhs_val, rhs.position()); let new_val = &mut rhs_val;
self.set_dot_val(scope, fn_lib, dot_lhs, dot_rhs, new_val, *op_pos, level) let val_pos = rhs.position();
self.dot_set(
scope, fn_lib, dot_lhs, dot_rhs, new_val, val_pos, *op_pos, level,
)
} }
// Error assignment to constant // Error assignment to constant
@ -1307,7 +1305,7 @@ impl Engine {
.map(|(_, _, x)| x), .map(|(_, _, x)| x),
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Dot(lhs, rhs, _) => self.get_dot_val(scope, fn_lib, lhs, rhs, level), Expr::Dot(lhs, rhs, _) => self.dot_get(scope, fn_lib, lhs, rhs, level),
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Expr::Array(contents, _) => { Expr::Array(contents, _) => {
@ -1325,9 +1323,9 @@ impl Engine {
Expr::Map(contents, _) => { Expr::Map(contents, _) => {
let mut map = Map::new(); let mut map = Map::new();
contents.into_iter().try_for_each(|item| { contents.into_iter().try_for_each(|(key, expr, _)| {
self.eval_expr(scope, fn_lib, &item.1, level).map(|val| { self.eval_expr(scope, fn_lib, &expr, level).map(|val| {
map.insert(item.0.clone(), val); map.insert(key.clone(), val);
}) })
})?; })?;
@ -1341,10 +1339,10 @@ impl Engine {
fn_lib: Option<&FunctionsLib>, fn_lib: Option<&FunctionsLib>,
name: &str, name: &str,
) -> bool { ) -> bool {
engine.functions.as_ref().map_or(false, |lib| { engine
let fn_spec = calc_fn_spec(name, [TypeId::of::<String>()].iter().cloned()); .functions
lib.contains_key(&fn_spec) .contains_key(&calc_fn_spec(name, once(TypeId::of::<String>())))
}) || fn_lib.map_or(false, |lib| lib.has_function(name, 1)) || fn_lib.map_or(false, |lib| lib.has_function(name, 1))
} }
match fn_name.as_ref() { match fn_name.as_ref() {
@ -1552,7 +1550,7 @@ impl Engine {
let arr = self.eval_expr(scope, fn_lib, expr, level)?; let arr = self.eval_expr(scope, fn_lib, expr, level)?;
let tid = arr.type_id(); let tid = arr.type_id();
if let Some(iter_fn) = self.type_iterators.as_ref().and_then(|t| t.get(&tid)) { if let Some(iter_fn) = self.type_iterators.get(&tid) {
// Add the loop variable - variable name is copied // Add the loop variable - variable name is copied
// TODO - avoid copying variable name // TODO - avoid copying variable name
scope.push(name.clone(), ()); scope.push(name.clone(), ());

View File

@ -110,14 +110,14 @@ impl<'a> State<'a> {
/// Call a registered function /// Call a registered function
fn call_fn( fn call_fn(
functions: Option<&HashMap<u64, Box<FnAny>>>, functions: &HashMap<u64, Box<FnAny>>,
fn_name: &str, fn_name: &str,
args: &mut FnCallArgs, args: &mut FnCallArgs,
pos: Position, pos: Position,
) -> Result<Option<Dynamic>, Box<EvalAltResult>> { ) -> Result<Option<Dynamic>, Box<EvalAltResult>> {
// Search built-in's and external functions // Search built-in's and external functions
functions functions
.and_then(|f| f.get(&calc_fn_spec(fn_name, args.iter().map(|a| a.type_id())))) .get(&calc_fn_spec(fn_name, args.iter().map(|a| a.type_id())))
.map(|func| func(args, pos)) .map(|func| func(args, pos))
.transpose() .transpose()
} }
@ -576,7 +576,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
"" ""
}; };
call_fn(state.engine.functions.as_ref(), &id, &mut call_args, pos).ok() call_fn(&state.engine.functions, &id, &mut call_args, pos).ok()
.and_then(|result| .and_then(|result|
result.or_else(|| { result.or_else(|| {
if !arg_for_type_of.is_empty() { if !arg_for_type_of.is_empty() {