Unify all functions into CallableFunction type, remove FunctionsLib.

This commit is contained in:
Stephen Chung
2020-06-05 15:14:42 +08:00
parent e21d25a0c5
commit 56eb659d5a
6 changed files with 316 additions and 253 deletions

View File

@@ -2,12 +2,12 @@
use crate::any::{Dynamic, Variant};
use crate::calc_fn_hash;
use crate::engine::{make_getter, make_setter, Engine, FunctionsLib, FUNC_INDEXER};
use crate::engine::{make_getter, make_setter, Engine, FUNC_INDEXER};
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, SendSync};
use crate::parser::{
FnAccess,
FnAccess::{Private, Public},
AST,
ScriptFnDef, AST,
};
use crate::result::EvalAltResult;
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
@@ -53,9 +53,6 @@ pub struct Module {
StraightHasherBuilder,
>,
/// Script-defined functions.
lib: FunctionsLib,
/// Iterator functions, keyed by the type producing the iterator.
type_iterators: HashMap<TypeId, IteratorFn>,
@@ -68,10 +65,9 @@ impl fmt::Debug for Module {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"<module {:?}, functions={}, lib={}>",
"<module {:?}, functions={}>",
self.variables,
self.functions.len(),
self.lib.len()
)
}
}
@@ -186,6 +182,23 @@ impl Module {
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.to_string(), pos)))
}
/// Set a script-defined function into the module.
///
/// If there is an existing function of the same name and number of arguments, it is replaced.
pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) {
// None + function name + number of arguments.
let hash_fn_def = calc_fn_hash(empty(), &fn_def.name, fn_def.params.len(), empty());
self.functions.insert(
hash_fn_def,
(
fn_def.name.to_string(),
fn_def.access,
Default::default(),
fn_def.into(),
),
);
}
/// Does a sub-module exist in the module?
///
/// # Examples
@@ -750,6 +763,41 @@ impl Module {
})
}
/// Merge another module into this module.
pub fn merge(&mut self, other: &Self) {
self.variables
.extend(other.variables.iter().map(|(k, v)| (k.clone(), v.clone())));
self.functions
.extend(other.functions.iter().map(|(&k, v)| (k, v.clone())));
self.type_iterators
.extend(other.type_iterators.iter().map(|(&k, v)| (k, v.clone())));
}
/// Get the number of variables in the module.
pub fn num_var(&self) -> usize {
self.variables.len()
}
/// Get the number of functions in the module.
pub fn num_fn(&self) -> usize {
self.variables.len()
}
/// Get the number of type iterators in the module.
pub fn num_iter(&self) -> usize {
self.variables.len()
}
/// Get an iterator to the variables in the module.
pub fn iter_var(&self) -> impl Iterator<Item = (&String, &Dynamic)> {
self.variables.iter()
}
/// Get an iterator to the functions in the module.
pub(crate) fn iter_fn(
&self,
) -> impl Iterator<Item = &(String, FnAccess, StaticVec<TypeId>, CallableFunction)> {
self.functions.values()
}
/// Create a new `Module` by evaluating an `AST`.
///
/// # Examples
@@ -795,12 +843,12 @@ impl Module {
},
);
module.lib = module.lib.merge(ast.lib());
module.merge(ast.lib());
Ok(module)
}
/// Scan through all the sub-modules in the `Module` build an index of all
/// Scan through all the sub-modules in the module build an index of all
/// variables and external Rust functions via hashing.
pub(crate) fn index_all_sub_modules(&mut self) {
// Collect a particular module.
@@ -830,34 +878,31 @@ impl Module {
Private => continue,
Public => (),
}
// Rust functions are indexed in two steps:
// 1) Calculate a hash in a similar manner to script-defined functions,
// i.e. qualifiers + function name + number of arguments.
let hash_fn_def =
calc_fn_hash(qualifiers.iter().map(|&v| v), name, params.len(), empty());
// 2) Calculate a second hash with no qualifiers, empty function name,
// zero number of arguments, and the actual list of argument `TypeId`'.s
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
// 3) The final hash is the XOR of the two hashes.
let hash_fn_native = hash_fn_def ^ hash_fn_args;
functions.push((hash_fn_native, func.clone()));
}
// Index all script-defined functions
for fn_def in module.lib.values() {
match fn_def.access {
// Private functions are not exported
Private => continue,
Public => (),
if func.is_script() {
let fn_def = func.get_shared_fn_def();
// Qualifiers + function name + number of arguments.
let hash_fn_def = calc_fn_hash(
qualifiers.iter().map(|&v| v),
&fn_def.name,
fn_def.params.len(),
empty(),
);
functions.push((hash_fn_def, fn_def.into()));
} else {
// Rust functions are indexed in two steps:
// 1) Calculate a hash in a similar manner to script-defined functions,
// i.e. qualifiers + function name + number of arguments.
let hash_fn_def =
calc_fn_hash(qualifiers.iter().map(|&v| v), name, params.len(), empty());
// 2) Calculate a second hash with no qualifiers, empty function name,
// zero number of arguments, and the actual list of argument `TypeId`'.s
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
// 3) The final hash is the XOR of the two hashes.
let hash_fn_native = hash_fn_def ^ hash_fn_args;
functions.push((hash_fn_native, func.clone()));
}
// Qualifiers + function name + number of arguments.
let hash_fn_def = calc_fn_hash(
qualifiers.iter().map(|&v| v),
&fn_def.name,
fn_def.params.len(),
empty(),
);
functions.push((hash_fn_def, CallableFunction::Script(fn_def.clone()).into()));
}
}