Move Engine functions and iterators lib to Packages API.
This commit is contained in:
parent
f3c0609377
commit
c607c7c428
@ -168,7 +168,9 @@ impl Engine {
|
||||
/// Register an iterator adapter for a type with the `Engine`.
|
||||
/// This is an advanced feature.
|
||||
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`.
|
||||
|
@ -4,7 +4,9 @@ use crate::any::{Dynamic, Union};
|
||||
use crate::calc_fn_hash;
|
||||
use crate::error::ParseErrorType;
|
||||
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::result::EvalAltResult;
|
||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||
@ -60,13 +62,6 @@ pub const MAX_CALL_STACK_DEPTH: usize = 28;
|
||||
#[cfg(not(debug_assertions))]
|
||||
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_DEBUG: &str = "debug";
|
||||
pub const KEYWORD_TYPE_OF: &str = "type_of";
|
||||
@ -185,10 +180,6 @@ pub struct FunctionsLib(
|
||||
);
|
||||
|
||||
impl FunctionsLib {
|
||||
/// Create a new `FunctionsLib`.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
/// Create a new `FunctionsLib` from a collection of `FnDef`.
|
||||
pub fn from_vec(vec: Vec<FnDef>) -> Self {
|
||||
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`.
|
||||
pub struct Engine {
|
||||
/// A collection of all library packages loaded into the engine.
|
||||
pub(crate) packages: Vec<PackageLibrary>,
|
||||
/// A `HashMap` containing all compiled functions known to the engine.
|
||||
///
|
||||
/// 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>>,
|
||||
pub(crate) packages: PackagesCollection,
|
||||
/// A collection of all library packages loaded into the engine.
|
||||
pub(crate) base_package: PackageStore,
|
||||
|
||||
/// A module resolution service.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
@ -314,8 +300,7 @@ impl Default for Engine {
|
||||
// Create the new scripting Engine
|
||||
let mut engine = Self {
|
||||
packages: Default::default(),
|
||||
functions: HashMap::with_capacity(FUNCTIONS_COUNT),
|
||||
type_iterators: Default::default(),
|
||||
base_package: Default::default(),
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
@ -459,8 +444,7 @@ impl Engine {
|
||||
pub fn new_raw() -> Self {
|
||||
Self {
|
||||
packages: Default::default(),
|
||||
functions: HashMap::with_capacity(FUNCTIONS_COUNT / 2),
|
||||
type_iterators: Default::default(),
|
||||
base_package: Default::default(),
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
module_resolver: None,
|
||||
@ -490,7 +474,7 @@ impl Engine {
|
||||
/// In other words, loaded packages are searched in reverse order.
|
||||
pub fn load_package(&mut self, package: PackageLibrary) {
|
||||
// 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.
|
||||
@ -545,12 +529,11 @@ impl Engine {
|
||||
// Search built-in's and external functions
|
||||
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(|| {
|
||||
self.packages
|
||||
.iter()
|
||||
.find(|pkg| pkg.functions.contains_key(&fn_spec))
|
||||
.and_then(|pkg| pkg.functions.get(&fn_spec))
|
||||
}) {
|
||||
if let Some(func) = self
|
||||
.base_package
|
||||
.get_function(fn_spec)
|
||||
.or_else(|| self.packages.get_function(fn_spec))
|
||||
{
|
||||
// Run external function
|
||||
let result = func(args, pos)?;
|
||||
|
||||
@ -696,9 +679,9 @@ impl Engine {
|
||||
let hash = calc_fn_hash(name, once(TypeId::of::<String>()));
|
||||
|
||||
// First check registered functions
|
||||
self.functions.contains_key(&hash)
|
||||
self.base_package.contains_function(hash)
|
||||
// Then check packages
|
||||
|| self.packages.iter().any(|p| p.functions.contains_key(&hash))
|
||||
|| self.packages.contains_function(hash)
|
||||
// Then check script-defined functions
|
||||
|| state.has_function(name, 1)
|
||||
}
|
||||
@ -1211,7 +1194,7 @@ impl Engine {
|
||||
let index = if state.always_search { None } else { *index };
|
||||
match search_scope(scope, name, modules, index, *pos)? {
|
||||
(_, ScopeEntryType::Constant) => Err(Box::new(
|
||||
EvalAltResult::ErrorAssignmentToConstant(name.to_string(), *op_pos),
|
||||
EvalAltResult::ErrorAssignmentToConstant(name.to_string(), *pos),
|
||||
)),
|
||||
(value_ptr, ScopeEntryType::Normal) => {
|
||||
*value_ptr = rhs_val;
|
||||
@ -1482,12 +1465,11 @@ impl Engine {
|
||||
let arr = self.eval_expr(scope, state, expr, level)?;
|
||||
let tid = arr.type_id();
|
||||
|
||||
if let Some(iter_fn) = self.type_iterators.get(&tid).or_else(|| {
|
||||
self.packages
|
||||
.iter()
|
||||
.find(|pkg| pkg.type_iterators.contains_key(&tid))
|
||||
.and_then(|pkg| pkg.type_iterators.get(&tid))
|
||||
}) {
|
||||
if let Some(iter_fn) = self
|
||||
.base_package
|
||||
.get_iterator(tid)
|
||||
.or_else(|| self.packages.get_iterator(tid))
|
||||
{
|
||||
// Add the loop variable
|
||||
let var_name = name.as_ref().clone();
|
||||
scope.push(var_name, ());
|
||||
|
@ -221,7 +221,7 @@ macro_rules! def_register {
|
||||
let fn_name = name.to_string();
|
||||
let func = make_func!(fn_name : f : map_dynamic ; $($par => $clone),*);
|
||||
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 func = make_func!(fn_name : f : map_identity ; $($par => $clone),*);
|
||||
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 func = make_func!(fn_name : f : map_result ; $($par => $clone),*);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ use crate::engine::{
|
||||
Engine, FnAny, FnCallArgs, FunctionsLib, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT,
|
||||
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::result::EvalAltResult;
|
||||
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
||||
@ -110,8 +110,8 @@ impl<'a> State<'a> {
|
||||
|
||||
/// Call a registered function
|
||||
fn call_fn(
|
||||
packages: &Vec<PackageLibrary>,
|
||||
functions: &HashMap<u64, Box<FnAny>>,
|
||||
packages: &PackagesCollection,
|
||||
base_package: &PackageStore,
|
||||
fn_name: &str,
|
||||
args: &mut FnCallArgs,
|
||||
pos: Position,
|
||||
@ -119,14 +119,9 @@ fn call_fn(
|
||||
// Search built-in's and external functions
|
||||
let hash = calc_fn_hash(fn_name, args.iter().map(|a| a.type_id()));
|
||||
|
||||
functions
|
||||
.get(&hash)
|
||||
.or_else(|| {
|
||||
packages
|
||||
.iter()
|
||||
.find(|p| p.functions.contains_key(&hash))
|
||||
.and_then(|p| p.functions.get(&hash))
|
||||
})
|
||||
base_package
|
||||
.get_function(hash)
|
||||
.or_else(|| packages.get_function(hash))
|
||||
.map(|func| func(args, pos))
|
||||
.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|
|
||||
result.or_else(|| {
|
||||
if !arg_for_type_of.is_empty() {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
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 array_basic;
|
||||
@ -61,6 +61,30 @@ impl PackageStore {
|
||||
pub fn new() -> Self {
|
||||
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.
|
||||
@ -70,3 +94,49 @@ pub type PackageLibrary = Rc<PackageStore>;
|
||||
/// Type which `Arc`-wraps a `PackageStore` to facilitate sharing library instances.
|
||||
#[cfg(feature = "sync")]
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user