Move Engine functions and iterators lib to Packages API.

This commit is contained in:
Stephen Chung 2020-05-07 15:25:50 +08:00
parent f3c0609377
commit c607c7c428
5 changed files with 106 additions and 57 deletions

View File

@ -168,7 +168,9 @@ 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) {
self.type_iterators.insert(TypeId::of::<T>(), Box::new(f)); self.base_package
.type_iterators
.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

@ -4,7 +4,9 @@ use crate::any::{Dynamic, Union};
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::error::ParseErrorType; use crate::error::ParseErrorType;
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::packages::{CorePackage, Package, PackageLibrary, StandardPackage}; use crate::packages::{
CorePackage, Package, PackageLibrary, PackageStore, PackagesCollection, StandardPackage,
};
use crate::parser::{Expr, FnDef, ModuleRef, ReturnType, Stmt, AST}; use crate::parser::{Expr, FnDef, ModuleRef, ReturnType, Stmt, AST};
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope}; use crate::scope::{EntryType as ScopeEntryType, Scope};
@ -60,13 +62,6 @@ pub const MAX_CALL_STACK_DEPTH: usize = 28;
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
pub const MAX_CALL_STACK_DEPTH: usize = 256; pub const MAX_CALL_STACK_DEPTH: usize = 256;
#[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;
pub const KEYWORD_PRINT: &str = "print"; pub const KEYWORD_PRINT: &str = "print";
pub const KEYWORD_DEBUG: &str = "debug"; pub const KEYWORD_DEBUG: &str = "debug";
pub const KEYWORD_TYPE_OF: &str = "type_of"; pub const KEYWORD_TYPE_OF: &str = "type_of";
@ -185,10 +180,6 @@ pub struct FunctionsLib(
); );
impl FunctionsLib { impl FunctionsLib {
/// Create a new `FunctionsLib`.
pub fn new() -> Self {
Default::default()
}
/// Create a new `FunctionsLib` from a collection of `FnDef`. /// Create a new `FunctionsLib` from a collection of `FnDef`.
pub fn from_vec(vec: Vec<FnDef>) -> Self { pub fn from_vec(vec: Vec<FnDef>) -> Self {
FunctionsLib( FunctionsLib(
@ -270,14 +261,9 @@ 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 collection of all library packages loaded into the engine. /// A collection of all library packages loaded into the engine.
pub(crate) packages: Vec<PackageLibrary>, pub(crate) packages: PackagesCollection,
/// A `HashMap` containing all compiled functions known to the engine. /// A collection of all library packages loaded into the engine.
/// pub(crate) base_package: PackageStore,
/// The key of the `HashMap` is a `u64` hash calculated by the function `crate::calc_fn_hash`.
pub(crate) functions: HashMap<u64, Box<FnAny>>,
/// A hashmap containing all iterators known to the engine.
pub(crate) type_iterators: HashMap<TypeId, Box<IteratorFn>>,
/// A module resolution service. /// A module resolution service.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -314,8 +300,7 @@ impl Default for Engine {
// Create the new scripting Engine // Create the new scripting Engine
let mut engine = Self { let mut engine = Self {
packages: Default::default(), packages: Default::default(),
functions: HashMap::with_capacity(FUNCTIONS_COUNT), base_package: Default::default(),
type_iterators: Default::default(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
@ -459,8 +444,7 @@ impl Engine {
pub fn new_raw() -> Self { pub fn new_raw() -> Self {
Self { Self {
packages: Default::default(), packages: Default::default(),
functions: HashMap::with_capacity(FUNCTIONS_COUNT / 2), base_package: Default::default(),
type_iterators: Default::default(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
module_resolver: None, module_resolver: None,
@ -490,7 +474,7 @@ impl Engine {
/// In other words, loaded packages are searched in reverse order. /// In other words, loaded packages are searched in reverse order.
pub fn load_package(&mut self, package: PackageLibrary) { pub fn load_package(&mut self, package: PackageLibrary) {
// Push the package to the top - packages are searched in reverse order // Push the package to the top - packages are searched in reverse order
self.packages.insert(0, package); self.packages.push(package);
} }
/// Control whether and how the `Engine` will optimize an AST after compilation. /// Control whether and how the `Engine` will optimize an AST after compilation.
@ -545,12 +529,11 @@ impl Engine {
// Search built-in's and external functions // Search built-in's and external functions
let fn_spec = calc_fn_hash(fn_name, args.iter().map(|a| a.type_id())); let fn_spec = calc_fn_hash(fn_name, args.iter().map(|a| a.type_id()));
if let Some(func) = self.functions.get(&fn_spec).or_else(|| { if let Some(func) = self
self.packages .base_package
.iter() .get_function(fn_spec)
.find(|pkg| pkg.functions.contains_key(&fn_spec)) .or_else(|| self.packages.get_function(fn_spec))
.and_then(|pkg| pkg.functions.get(&fn_spec)) {
}) {
// Run external function // Run external function
let result = func(args, pos)?; let result = func(args, pos)?;
@ -696,9 +679,9 @@ impl Engine {
let hash = calc_fn_hash(name, once(TypeId::of::<String>())); let hash = calc_fn_hash(name, once(TypeId::of::<String>()));
// First check registered functions // First check registered functions
self.functions.contains_key(&hash) self.base_package.contains_function(hash)
// Then check packages // Then check packages
|| self.packages.iter().any(|p| p.functions.contains_key(&hash)) || self.packages.contains_function(hash)
// Then check script-defined functions // Then check script-defined functions
|| state.has_function(name, 1) || state.has_function(name, 1)
} }
@ -1211,7 +1194,7 @@ impl Engine {
let index = if state.always_search { None } else { *index }; let index = if state.always_search { None } else { *index };
match search_scope(scope, name, modules, index, *pos)? { match search_scope(scope, name, modules, index, *pos)? {
(_, ScopeEntryType::Constant) => Err(Box::new( (_, ScopeEntryType::Constant) => Err(Box::new(
EvalAltResult::ErrorAssignmentToConstant(name.to_string(), *op_pos), EvalAltResult::ErrorAssignmentToConstant(name.to_string(), *pos),
)), )),
(value_ptr, ScopeEntryType::Normal) => { (value_ptr, ScopeEntryType::Normal) => {
*value_ptr = rhs_val; *value_ptr = rhs_val;
@ -1482,12 +1465,11 @@ impl Engine {
let arr = self.eval_expr(scope, state, expr, level)?; let arr = self.eval_expr(scope, state, expr, level)?;
let tid = arr.type_id(); let tid = arr.type_id();
if let Some(iter_fn) = self.type_iterators.get(&tid).or_else(|| { if let Some(iter_fn) = self
self.packages .base_package
.iter() .get_iterator(tid)
.find(|pkg| pkg.type_iterators.contains_key(&tid)) .or_else(|| self.packages.get_iterator(tid))
.and_then(|pkg| pkg.type_iterators.get(&tid)) {
}) {
// Add the loop variable // Add the loop variable
let var_name = name.as_ref().clone(); let var_name = name.as_ref().clone();
scope.push(var_name, ()); scope.push(var_name, ());

View File

@ -221,7 +221,7 @@ macro_rules! def_register {
let fn_name = name.to_string(); let fn_name = name.to_string();
let func = make_func!(fn_name : f : map_dynamic ; $($par => $clone),*); let func = make_func!(fn_name : f : map_dynamic ; $($par => $clone),*);
let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned()); let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned());
self.functions.insert(hash, Box::new(func)); self.base_package.functions.insert(hash, Box::new(func));
} }
} }
@ -239,7 +239,7 @@ macro_rules! def_register {
let fn_name = name.to_string(); let fn_name = name.to_string();
let func = make_func!(fn_name : f : map_identity ; $($par => $clone),*); let func = make_func!(fn_name : f : map_identity ; $($par => $clone),*);
let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned()); let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned());
self.functions.insert(hash, Box::new(func)); self.base_package.functions.insert(hash, Box::new(func));
} }
} }
@ -258,7 +258,7 @@ macro_rules! def_register {
let fn_name = name.to_string(); let fn_name = name.to_string();
let func = make_func!(fn_name : f : map_result ; $($par => $clone),*); let func = make_func!(fn_name : f : map_result ; $($par => $clone),*);
let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned()); let hash = calc_fn_spec(name, [$(TypeId::of::<$par>()),*].iter().cloned());
self.functions.insert(hash, Box::new(func)); self.base_package.functions.insert(hash, Box::new(func));
} }
} }

View File

@ -4,7 +4,7 @@ use crate::engine::{
Engine, FnAny, FnCallArgs, FunctionsLib, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, Engine, FnAny, FnCallArgs, FunctionsLib, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT,
KEYWORD_TYPE_OF, KEYWORD_TYPE_OF,
}; };
use crate::packages::PackageLibrary; use crate::packages::{PackageStore, PackagesCollection};
use crate::parser::{map_dynamic_to_expr, Expr, FnDef, ReturnType, Stmt, AST}; use crate::parser::{map_dynamic_to_expr, Expr, FnDef, ReturnType, Stmt, AST};
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope}; use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
@ -110,8 +110,8 @@ impl<'a> State<'a> {
/// Call a registered function /// Call a registered function
fn call_fn( fn call_fn(
packages: &Vec<PackageLibrary>, packages: &PackagesCollection,
functions: &HashMap<u64, Box<FnAny>>, base_package: &PackageStore,
fn_name: &str, fn_name: &str,
args: &mut FnCallArgs, args: &mut FnCallArgs,
pos: Position, pos: Position,
@ -119,14 +119,9 @@ fn call_fn(
// Search built-in's and external functions // Search built-in's and external functions
let hash = calc_fn_hash(fn_name, args.iter().map(|a| a.type_id())); let hash = calc_fn_hash(fn_name, args.iter().map(|a| a.type_id()));
functions base_package
.get(&hash) .get_function(hash)
.or_else(|| { .or_else(|| packages.get_function(hash))
packages
.iter()
.find(|p| p.functions.contains_key(&hash))
.and_then(|p| p.functions.get(&hash))
})
.map(|func| func(args, pos)) .map(|func| func(args, pos))
.transpose() .transpose()
} }
@ -577,7 +572,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
"" ""
}; };
call_fn(&state.engine.packages, &state.engine.functions, &id, &mut call_args, pos).ok() call_fn(&state.engine.packages, &state.engine.base_package, &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() {

View File

@ -2,7 +2,7 @@
use crate::engine::{FnAny, IteratorFn}; use crate::engine::{FnAny, IteratorFn};
use crate::stdlib::{any::TypeId, boxed::Box, collections::HashMap, rc::Rc, sync::Arc}; use crate::stdlib::{any::TypeId, boxed::Box, collections::HashMap, rc::Rc, sync::Arc, vec::Vec};
mod arithmetic; mod arithmetic;
mod array_basic; mod array_basic;
@ -61,6 +61,30 @@ impl PackageStore {
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Default::default()
} }
/// Get an iterator over the keys of the functions in the `PackageStore`.
pub fn function_keys(&self) -> impl Iterator<Item = &u64> {
self.functions.keys()
}
/// Get an iterator over the `TypeId` of the type iterators in the `PackageStore`.
pub fn type_iterator_keys(&self) -> impl Iterator<Item = &TypeId> {
self.type_iterators.keys()
}
/// Does the specified function hash key exist in the `PackageStore`?
pub fn contains_function(&self, hash: u64) -> bool {
self.functions.contains_key(&hash)
}
/// Get specified function via its hash key.
pub fn get_function(&self, hash: u64) -> Option<&Box<FnAny>> {
self.functions.get(&hash)
}
/// Does the specified TypeId iterator exist in the `PackageStore`?
pub fn contains_iterator(&self, id: TypeId) -> bool {
self.type_iterators.contains_key(&id)
}
/// Get the specified TypeId iterator.
pub fn get_iterator(&self, id: TypeId) -> Option<&Box<IteratorFn>> {
self.type_iterators.get(&id)
}
} }
/// Type which `Rc`-wraps a `PackageStore` to facilitate sharing library instances. /// Type which `Rc`-wraps a `PackageStore` to facilitate sharing library instances.
@ -70,3 +94,49 @@ pub type PackageLibrary = Rc<PackageStore>;
/// Type which `Arc`-wraps a `PackageStore` to facilitate sharing library instances. /// Type which `Arc`-wraps a `PackageStore` to facilitate sharing library instances.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
pub type PackageLibrary = Arc<PackageStore>; pub type PackageLibrary = Arc<PackageStore>;
#[derive(Default)]
/// Type containing a collection of `PackageLibrary` instances.
/// All function and type iterator keys in the loaded packages are indexed for fast access.
pub(crate) struct PackagesCollection {
/// Collection of `PackageLibrary` instances.
packages: Vec<PackageLibrary>,
/// Index of all function keys, pointing to the offset in `packages`.
function_keys: HashMap<u64, usize>,
/// Index of all type iterator `TypeId`'s, pointing to the offset in `packages`.
iterator_types: HashMap<TypeId, usize>,
}
impl PackagesCollection {
/// Add a `PackageLibrary` into the `PackagesCollection`.
pub fn push(&mut self, package: PackageLibrary) {
let index = self.packages.len();
package.function_keys().for_each(|&hash| {
self.function_keys.insert(hash, index);
});
package.type_iterator_keys().for_each(|&id| {
self.iterator_types.insert(id, index);
});
self.packages.push(package);
}
/// Does the specified function hash key exist in the `PackagesCollection`?
pub fn contains_function(&self, hash: u64) -> bool {
self.function_keys.contains_key(&hash)
}
/// Get specified function via its hash key.
pub fn get_function(&self, hash: u64) -> Option<&Box<FnAny>> {
self.function_keys
.get(&hash)
.and_then(|&index| self.packages[index].functions.get(&hash))
}
/// Does the specified TypeId iterator exist in the `PackagesCollection`?
pub fn contains_iterator(&self, id: TypeId) -> bool {
self.iterator_types.contains_key(&id)
}
/// Get the specified TypeId iterator.
pub fn get_iterator(&self, id: TypeId) -> Option<&Box<IteratorFn>> {
self.iterator_types
.get(&id)
.and_then(|&index| self.packages[index].type_iterators.get(&id))
}
}